@rubytech/create-sitedesk-code 0.1.532 → 0.1.534
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +12 -7
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +15 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
- package/payload/platform/plugins/docs/references/calendar-booking.md +9 -6
- package/payload/platform/plugins/email/mcp/dist/__tests__/signature.test.js +40 -1
- package/payload/platform/plugins/email/mcp/dist/__tests__/signature.test.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/compose.js +4 -1
- package/payload/platform/plugins/email/mcp/dist/lib/compose.js.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/signature.d.ts +27 -0
- package/payload/platform/plugins/email/mcp/dist/lib/signature.d.ts.map +1 -1
- package/payload/platform/plugins/email/mcp/dist/lib/signature.js +62 -2
- package/payload/platform/plugins/email/mcp/dist/lib/signature.js.map +1 -1
- package/payload/platform/plugins/memory/skills/preference-audit/SKILL.md +11 -1
- package/payload/platform/plugins/whatsapp/PLUGIN.md +12 -2
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js +73 -6
- package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +9 -1
- package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +27 -1
- package/payload/platform/scripts/__tests__/vnc-cdp-liveness.test.sh +14 -12
- package/payload/platform/scripts/vnc.sh +24 -19
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.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 +35 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +13 -4
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.d.ts +1 -1
- package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.js +46 -3
- package/payload/platform/services/claude-session-manager/dist/preference-reconciliation-audit.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +9 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/specialist-roster.d.ts +12 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-roster.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-roster.js +75 -0
- package/payload/platform/services/claude-session-manager/dist/specialist-roster.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +10 -2
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/server/{chunk-UH6GCQO4.js → chunk-4QCYFTAI.js} +276 -19
- package/payload/server/{manager-H34562SN.js → manager-ZNHQQCED.js} +1 -1
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/AdminLoginScreens-BGVleg5q.js +1 -0
- package/payload/server/public/assets/AdminLoginScreens-BGVleg5q.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BGVleg5q.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-CMZZr5Oz.js +2 -0
- package/payload/server/public/assets/AdminShell-CMZZr5Oz.js.br +0 -0
- package/payload/server/public/assets/AdminShell-CMZZr5Oz.js.gz +0 -0
- package/payload/server/public/assets/CdpScreencastSurface-S7UeohE2.js +1 -0
- package/payload/server/public/assets/CdpScreencastSurface-S7UeohE2.js.br +0 -0
- package/payload/server/public/assets/CdpScreencastSurface-S7UeohE2.js.gz +0 -0
- package/payload/server/public/assets/{activity-ClI-RgJu.js → activity-Di0Rg9lb.js} +1 -1
- package/payload/server/public/assets/activity-Di0Rg9lb.js.br +0 -0
- package/payload/server/public/assets/activity-Di0Rg9lb.js.gz +0 -0
- package/payload/server/public/assets/admin-B89fhBS0.js +1 -0
- package/payload/server/public/assets/admin-B89fhBS0.js.br +0 -0
- package/payload/server/public/assets/admin-B89fhBS0.js.gz +0 -0
- package/payload/server/public/assets/{agents-BO8YBj8d.js → agents-CZTshBkV.js} +1 -1
- package/payload/server/public/assets/agents-CZTshBkV.js.br +0 -0
- package/payload/server/public/assets/agents-CZTshBkV.js.gz +0 -0
- package/payload/server/public/assets/{browser-Bj8oTG5R.js → browser-CIbMHtt-.js} +1 -1
- package/payload/server/public/assets/browser-CIbMHtt-.js.br +0 -0
- package/payload/server/public/assets/browser-CIbMHtt-.js.gz +0 -0
- package/payload/server/public/assets/calendar-BkZcebIa.js +1 -0
- package/payload/server/public/assets/calendar-BkZcebIa.js.br +0 -0
- package/payload/server/public/assets/calendar-BkZcebIa.js.gz +0 -0
- package/payload/server/public/assets/chat-C6EOth0E.js +1 -0
- package/payload/server/public/assets/chat-C6EOth0E.js.br +1 -0
- package/payload/server/public/assets/chat-C6EOth0E.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-DiJkQOqd.js +1 -0
- package/payload/server/public/assets/chevron-right-DOO-559P.js +1 -0
- package/payload/server/public/assets/chevron-right-DOO-559P.js.br +0 -0
- package/payload/server/public/assets/clock-D-z9DPIi.js +1 -0
- package/payload/server/public/assets/clock-D-z9DPIi.js.br +0 -0
- package/payload/server/public/assets/clock-D-z9DPIi.js.gz +0 -0
- package/payload/server/public/assets/data-2fHKgEQR.js +1 -0
- package/payload/server/public/assets/data-2fHKgEQR.js.br +0 -0
- package/payload/server/public/assets/data-2fHKgEQR.js.gz +0 -0
- package/payload/server/public/assets/{file-download-Di_s0_4w.js → file-download-CKfAhT9F.js} +1 -1
- package/payload/server/public/assets/file-download-CKfAhT9F.js.br +0 -0
- package/payload/server/public/assets/file-download-CKfAhT9F.js.gz +0 -0
- package/payload/server/public/assets/{file-text-CP1KIrJV.js → file-text-BdMnzZ8u.js} +1 -1
- package/payload/server/public/assets/file-text-BdMnzZ8u.js.br +0 -0
- package/payload/server/public/assets/file-text-BdMnzZ8u.js.gz +0 -0
- package/payload/server/public/assets/{graph-BCMscnCV.js → graph-DzB4KiCO.js} +2 -2
- package/payload/server/public/assets/graph-DzB4KiCO.js.br +0 -0
- package/payload/server/public/assets/graph-DzB4KiCO.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-CgP17xHK.js → graph-labels-CMlGzab-.js} +1 -1
- package/payload/server/public/assets/graph-labels-CMlGzab-.js.br +0 -0
- package/payload/server/public/assets/graph-labels-CMlGzab-.js.gz +0 -0
- package/payload/server/public/assets/{maximize-2-DkQzDv-g.js → maximize-2-Cw95Fq0m.js} +1 -1
- package/payload/server/public/assets/maximize-2-Cw95Fq0m.js.br +0 -0
- package/payload/server/public/assets/maximize-2-Cw95Fq0m.js.gz +0 -0
- package/payload/server/public/assets/operator-YhRt7hhB.js +1 -0
- package/payload/server/public/assets/operator-YhRt7hhB.js.br +0 -0
- package/payload/server/public/assets/operator-YhRt7hhB.js.gz +0 -0
- package/payload/server/public/assets/page-DRipsKnx.js +32 -0
- package/payload/server/public/assets/page-DRipsKnx.js.br +0 -0
- package/payload/server/public/assets/page-DRipsKnx.js.gz +0 -0
- package/payload/server/public/assets/page-iEvYrvW4.js +1 -0
- package/payload/server/public/assets/page-iEvYrvW4.js.br +0 -0
- package/payload/server/public/assets/page-iEvYrvW4.js.gz +0 -0
- package/payload/server/public/assets/public-wBScNSFk.js +1 -0
- package/payload/server/public/assets/public-wBScNSFk.js.br +0 -0
- package/payload/server/public/assets/public-wBScNSFk.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-DPw0vXC0.js → rotate-ccw-BjIYVGss.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-BjIYVGss.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-BjIYVGss.js.gz +0 -0
- package/payload/server/public/assets/{routines-CwiiYpfK.js → routines-DP0XOp9h.js} +1 -1
- package/payload/server/public/assets/routines-DP0XOp9h.js.br +0 -0
- package/payload/server/public/assets/routines-DP0XOp9h.js.gz +0 -0
- package/payload/server/public/assets/{skills-0FOjKUM-.js → skills-B6e7L3GG.js} +1 -1
- package/payload/server/public/assets/skills-B6e7L3GG.js.br +0 -0
- package/payload/server/public/assets/skills-B6e7L3GG.js.gz +0 -0
- package/payload/server/public/assets/tasks-CRoG5MpL.js +3 -0
- package/payload/server/public/assets/tasks-CRoG5MpL.js.br +0 -0
- package/payload/server/public/assets/tasks-CRoG5MpL.js.gz +0 -0
- package/payload/server/public/assets/{time-entry-format-B6fX_19a.js → time-entry-format-C9clyq98.js} +1 -1
- package/payload/server/public/assets/time-entry-format-C9clyq98.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-C9clyq98.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert-vAaSDhVq.js → triangle-alert-CZlka7Nl.js} +1 -1
- package/payload/server/public/assets/triangle-alert-CZlka7Nl.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-CZlka7Nl.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-BvIRgs7W.js → useCopyFeedback-DoQhfr0S.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-DoQhfr0S.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-DoQhfr0S.js.gz +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-DM5Y9eio.css → useSubAccountSwitcher-BDQ8Wsdt.css} +1 -1
- package/payload/server/public/assets/useSubAccountSwitcher-BDQ8Wsdt.css.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-DM5Y9eio.css.gz → useSubAccountSwitcher-BDQ8Wsdt.css.gz} +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-BEwQMRMo.js → useSubAccountSwitcher-DOo5uRtZ.js} +2 -2
- package/payload/server/public/assets/useSubAccountSwitcher-DOo5uRtZ.js.br +0 -0
- package/payload/server/public/assets/{useSubAccountSwitcher-BEwQMRMo.js.gz → useSubAccountSwitcher-DOo5uRtZ.js.gz} +0 -0
- package/payload/server/public/assets/useVoiceRecorder-Cei46RSJ.js +2 -0
- package/payload/server/public/assets/useVoiceRecorder-Cei46RSJ.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-Cei46RSJ.js.gz +0 -0
- package/payload/server/public/assets/{wrench-BNBtwT2p.js → wrench-DCIBZT1Z.js} +1 -1
- package/payload/server/public/assets/wrench-DCIBZT1Z.js.br +2 -0
- package/payload/server/public/assets/wrench-DCIBZT1Z.js.gz +0 -0
- package/payload/server/public/browser.html +5 -5
- package/payload/server/public/calendar.html +7 -7
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +16 -16
- package/payload/server/public/operator.html +15 -15
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +7 -7
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +1612 -883
- package/payload/server/public/assets/AdminLoginScreens-7Czw3MAC.js +0 -1
- package/payload/server/public/assets/AdminLoginScreens-7Czw3MAC.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-7Czw3MAC.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-D5GApZ_n.js +0 -2
- package/payload/server/public/assets/AdminShell-D5GApZ_n.js.br +0 -0
- package/payload/server/public/assets/AdminShell-D5GApZ_n.js.gz +0 -0
- package/payload/server/public/assets/CdpScreencastSurface-BbekDUFw.js +0 -1
- package/payload/server/public/assets/CdpScreencastSurface-BbekDUFw.js.br +0 -0
- package/payload/server/public/assets/CdpScreencastSurface-BbekDUFw.js.gz +0 -0
- package/payload/server/public/assets/activity-ClI-RgJu.js.br +0 -0
- package/payload/server/public/assets/activity-ClI-RgJu.js.gz +0 -0
- package/payload/server/public/assets/admin-svtCmBPk.js +0 -1
- package/payload/server/public/assets/admin-svtCmBPk.js.br +0 -0
- package/payload/server/public/assets/admin-svtCmBPk.js.gz +0 -0
- package/payload/server/public/assets/agents-BO8YBj8d.js.br +0 -0
- package/payload/server/public/assets/agents-BO8YBj8d.js.gz +0 -0
- package/payload/server/public/assets/browser-Bj8oTG5R.js.br +0 -0
- package/payload/server/public/assets/browser-Bj8oTG5R.js.gz +0 -0
- package/payload/server/public/assets/calendar-CrkSY8U7.js +0 -1
- package/payload/server/public/assets/calendar-CrkSY8U7.js.br +0 -0
- package/payload/server/public/assets/calendar-CrkSY8U7.js.gz +0 -0
- package/payload/server/public/assets/chat-Bvxoni2e.js +0 -1
- package/payload/server/public/assets/chat-Bvxoni2e.js.br +0 -0
- package/payload/server/public/assets/chat-Bvxoni2e.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-CdUzxzeB.js +0 -1
- package/payload/server/public/assets/chevron-left-CdUzxzeB.js.br +0 -0
- package/payload/server/public/assets/chevron-right-CKGwd-M0.js +0 -1
- package/payload/server/public/assets/chevron-right-CKGwd-M0.js.br +0 -0
- package/payload/server/public/assets/clock-Cf8Oe9qi.js +0 -1
- package/payload/server/public/assets/clock-Cf8Oe9qi.js.br +0 -0
- package/payload/server/public/assets/clock-Cf8Oe9qi.js.gz +0 -0
- package/payload/server/public/assets/data-DF0Pstdp.js +0 -1
- package/payload/server/public/assets/data-DF0Pstdp.js.br +0 -1
- package/payload/server/public/assets/data-DF0Pstdp.js.gz +0 -0
- package/payload/server/public/assets/file-download-Di_s0_4w.js.br +0 -0
- package/payload/server/public/assets/file-download-Di_s0_4w.js.gz +0 -0
- package/payload/server/public/assets/file-text-CP1KIrJV.js.br +0 -1
- package/payload/server/public/assets/file-text-CP1KIrJV.js.gz +0 -0
- package/payload/server/public/assets/graph-BCMscnCV.js.br +0 -0
- package/payload/server/public/assets/graph-BCMscnCV.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-CgP17xHK.js.br +0 -0
- package/payload/server/public/assets/graph-labels-CgP17xHK.js.gz +0 -0
- package/payload/server/public/assets/maximize-2-DkQzDv-g.js.br +0 -0
- package/payload/server/public/assets/maximize-2-DkQzDv-g.js.gz +0 -0
- package/payload/server/public/assets/operator-CLbCar9e.js +0 -1
- package/payload/server/public/assets/operator-CLbCar9e.js.br +0 -0
- package/payload/server/public/assets/operator-CLbCar9e.js.gz +0 -0
- package/payload/server/public/assets/page-CNJl3tWT.js +0 -1
- package/payload/server/public/assets/page-CNJl3tWT.js.br +0 -0
- package/payload/server/public/assets/page-CNJl3tWT.js.gz +0 -0
- package/payload/server/public/assets/page-CPVUAwb8.js +0 -32
- package/payload/server/public/assets/page-CPVUAwb8.js.br +0 -0
- package/payload/server/public/assets/page-CPVUAwb8.js.gz +0 -0
- package/payload/server/public/assets/public-DQea3Ybz.js +0 -1
- package/payload/server/public/assets/public-DQea3Ybz.js.br +0 -0
- package/payload/server/public/assets/public-DQea3Ybz.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-DPw0vXC0.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-DPw0vXC0.js.gz +0 -0
- package/payload/server/public/assets/routines-CwiiYpfK.js.br +0 -0
- package/payload/server/public/assets/routines-CwiiYpfK.js.gz +0 -0
- package/payload/server/public/assets/skills-0FOjKUM-.js.br +0 -0
- package/payload/server/public/assets/skills-0FOjKUM-.js.gz +0 -0
- package/payload/server/public/assets/tasks-BUVsPEGm.js +0 -3
- package/payload/server/public/assets/tasks-BUVsPEGm.js.br +0 -0
- package/payload/server/public/assets/tasks-BUVsPEGm.js.gz +0 -0
- package/payload/server/public/assets/time-entry-format-B6fX_19a.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-B6fX_19a.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert-vAaSDhVq.js.br +0 -0
- package/payload/server/public/assets/triangle-alert-vAaSDhVq.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-BvIRgs7W.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-BvIRgs7W.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-BEwQMRMo.js.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-DM5Y9eio.css.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-CiDOh8PG.js +0 -2
- package/payload/server/public/assets/useVoiceRecorder-CiDOh8PG.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-CiDOh8PG.js.gz +0 -0
- package/payload/server/public/assets/wrench-BNBtwT2p.js.br +0 -0
- package/payload/server/public/assets/wrench-BNBtwT2p.js.gz +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: platform-architecture
|
|
3
3
|
description: Use when grounding any documented-surface claim about what SiteDesk ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
|
|
4
|
-
content-hash: sha256:
|
|
4
|
+
content-hash: sha256:843a8b76531a2b4c403f24b3942df4996de963a4e3e05020bf70d3b0b19a3f39
|
|
5
5
|
brand: sitedesk-code
|
|
6
6
|
product-name: SiteDesk
|
|
7
7
|
---
|
|
@@ -2763,15 +2763,18 @@ SiteDesk gives you a calendar of your schedule and a public page where people ca
|
|
|
2763
2763
|
|
|
2764
2764
|
## The admin calendar
|
|
2765
2765
|
|
|
2766
|
-
Open `/calendar` on your SiteDesk address (the same sign-in as the dashboard). It shows your schedule in
|
|
2766
|
+
Open `/calendar` on your SiteDesk address (the same sign-in as the dashboard). It shows your schedule in five views:
|
|
2767
2767
|
|
|
2768
|
-
- **
|
|
2769
|
-
- **
|
|
2770
|
-
- **
|
|
2768
|
+
- **Schedule** is a plain list of what is coming up, thirty days at a time, grouped by day. Every entry shows its time, title, place, who is attending, and what kind of entry it is, all on the row. Days with nothing on them are left out. This is the view the calendar opens on.
|
|
2769
|
+
- **Day** and **Week** show an hour grid with each timed entry as a block. The block always shows the title; it adds the time underneath when the entry is long enough for a second line to fit (about three quarters of an hour in Week, a little over half an hour in Day). The title comes first because the block's position in the grid already tells you when it is.
|
|
2770
|
+
- **Month** shows the familiar month grid with up to three entries per day. Each chip gives its whole width to the title. When a day holds more, **+2 more** is a button that opens that day.
|
|
2771
|
+
- **Year** shows twelve small months. A day with something on it carries the number of entries, and clicking a month opens it.
|
|
2771
2772
|
|
|
2772
|
-
Use **Today** and the arrows to move around, and the view buttons to switch. The calendar reads everything time-bound in your graph: meetings imported from a calendar export or created by a booking, appointments SiteDesk schedules for you in chat, and tasks that have a due date (shown on their day).
|
|
2773
|
+
Use **Today** and the arrows to move around, and the view buttons to switch. In Schedule the arrows move a whole thirty days, so you can step back into the past as well as forward. The calendar reads everything time-bound in your graph: meetings imported from a calendar export or created by a booking, appointments SiteDesk schedules for you in chat, and tasks that have a due date (shown on their day).
|
|
2773
2774
|
|
|
2774
|
-
|
|
2775
|
+
Hover over any entry in Day, Week or Month, or reach it with the Tab key, and a small card shows what the row itself has no room for: the full title, the start and end time, the place, who is attending, and the kind of entry. You do not have to open anything to see this. On the Year view the same card appears, but on hover only, not by keyboard. Schedule needs no card, since its rows already carry all of it.
|
|
2776
|
+
|
|
2777
|
+
Click any entry to open its details, where you can also edit it: the full title, time, location, and who is attending, with each attendee on its own line (name, and email beneath it). For a booked meeting you can also edit its title, time, or location, or delete it, and the grid updates straight away. You can **Download** a booked meeting as a calendar file (`.ics`) to add it to Apple, Google, or Outlook calendars; when the meeting has attendees, Download asks whether to include them in the file before it saves, and a meeting with no attendees downloads straight away. The private note is never written into the downloaded file, since the file can travel outside your admin. In the edit view you can add an attendee (give a name, an email, or both) and remove one; adding someone who is already a contact reuses that contact rather than making a duplicate, and removing them takes them off the meeting but keeps the contact. The edit view also has a private note for that meeting, a place for your own reminders that only you and your team ever see; it never appears on the public booking page or anywhere outside your admin. Appointments SiteDesk schedules and due-dated tasks are shown for detail only and are changed where they are created, not here. New meetings are still made by a booking or by asking SiteDesk in chat, not from the calendar.
|
|
2775
2778
|
|
|
2776
2779
|
Everything on the calendar comes from records the rest of SiteDesk already uses, scoped to your account.
|
|
2777
2780
|
|
|
@@ -3358,6 +3361,8 @@ either is a regression.
|
|
|
3358
3361
|
|
|
3359
3362
|
**WhatsApp reader is read/write (WhatsApp-Web surface).** A WhatsApp store conversation in the operator Conversations reader (`OperatorConversations`) and the admin root channel viewer (`app/page.tsx`) no longer opens the plain read-only DM chrome — it opens `app/whatsapp/WhatsappWebConversation.tsx`, a WhatsApp-Web-styled surface: a conversation header, the delivered-only store transcript reskinned green/white under a `.wa-web` root class, and a reply composer (`app/whatsapp/ReplyComposer.tsx`). The operator can type text, insert emoji (a codepoint-data picker — no OS input, so the `check-no-emoji-in-jsx` gate stays green), record a voice note (MediaRecorder → the existing audio send path), attach a file **from device storage** (a modal browsing the DATA_ROOT tree via `GET /api/admin/files`, sent by reference — the OS file dialog is no longer the reader's picker), reply to a specific message (a per-bubble affordance that quotes the original in the composer and threads natively on WhatsApp), and search the loaded transcript (a header control that filters to matching turns and highlights the match). The header carries only that Search control — the former Video / Phone / menu icons are gone, because no call or presence data exists behind them. Sent files honour the webchat allowlist (`SUPPORTED_MIME_SET` / 50 MB / 5 files); a device-file reference is authorised server-side (`authorizeReplyFileRef`) against the send's own account (the conversation owner) **or** the session's pinned account (`getAccountIdForSession` — the exact scope the DeviceFilePicker used to offer it), so a house/managing-admin session can attach a managed-client file the picker listed. Because a reply sends bytes OUT to an external WhatsApp recipient, any other account, a `public` partition, and any install-wide / non-account path are refused fail-closed; the cross-account admission's authority is the session's pinned account, never the caller-supplied body `accountId` (the own-account admission matches the body `accountId`, which the route already trusts via `isValidAccountId` and the existing-conversation guard). A scope refusal returns a distinct HTTP 403 reason (`file-ref-cross-account` / `file-ref-public` / `file-ref-foreign`) and copy, never "device file not found" (reserved for a genuine resolve/stat miss). Per-ref `[wa-manual-send] op=reply-file-ref … via=own|session|deny reason=<…> ok=<bool>` logs the decision before any send; `via=deny ok=true` is the exfiltration signature that must never appear. **Send is reply-only and DM-only:** `POST /api/whatsapp-reader/reply` (`requireAdminSession`) refuses any target with no existing stored conversation (`reason=no-existing-conversation`, HTTP 403) — a cold first-contact send bans the account, so the composer is never a cold-contact path, enforced server-side — and refuses `@g.us` groups (`reason=group-send-blocked`), matching the agent's observe-only group invariant; a group thread shows a read-only note in place of the composer. The endpoint is the sole store writer for a manual send: right after each send resolves it appends the record itself, stamped `origin:'operator-manual'` (attributed "You", distinct from an assistant reply), because the Baileys echo that normally persists the store is gated on message text (`manager.ts:906`) and would leave an uncaptioned media send delivered-but-invisible. The record's `messageId` matches the echo's derivation so the async text echo's own persist dedups to a no-op; the send is confirmed by re-read (`op=recorded present=<bool>`). A sent send does not spawn an assistant turn (echo dispatch stays suppressed). Attachments deliver as WhatsApp media/documents and render **inline** in the store reader (image thumbnail / pdf preview / audio player / download chip), because the manual-send path records the message with the servable `attachmentId`. The `.wa-web` skin is scoped to WhatsApp store threads only, so `/chat`, the admin agent session view, and the public visitor webchat are unchanged; the visitor webchat gains no send capability. The in-bubble delivered-tick is cosmetic (no read-receipt data is stored); inbound bubbles keep their sender name so group threads stay attributable, and both directions carry a WhatsApp callout tail (`.wa-web`-scoped only). Non-WhatsApp reader rows (Telegram/webchat session JSONLs) keep the plain read-only `Transcript`. Observability rides `[wa-manual-send]` lines correlated by a per-request `sendId`. **Composer sizing matches the webchat composer:** the reply textarea auto-grows to fit multi-line content (measured from `scrollHeight`, clamped to a one-row minimum and a `viewport/3` maximum, scrollable past the cap with the scrollbar hidden), and a top-border grab handle drags (pointer) or nudges (ArrowUp/ArrowDown, keyboard-focusable) to an explicit height in the same clamp; a manual drag pins the height and overrides auto-grow until the field is cleared, which releases it back to auto-grow. A completed manual resize logs `[operator-ui] op=wa-composer-resize mode=drag|key h=<px>`; a bare click on the handle (no drag) logs nothing.
|
|
3360
3363
|
|
|
3364
|
+
**Shared locations show a map.** When someone shares a location on WhatsApp, the conversation shows a small map with a pin on the spot, above the coordinates themselves. Selecting the map opens the full map on OpenStreetMap in a new tab. A location shared as a place name with no coordinates shows the name only, because there is no point to put a pin on. The map images are fetched by your browser from OpenStreetMap, so the shared coordinates reach that service when a location bubble is on screen.
|
|
3365
|
+
|
|
3361
3366
|
**`/chat` live activity line.** While a turn is in flight the transcript tail shows one ephemeral `ChatActivity` line (mounted only while `busy`, admin/operator only). It tracks real activity, not a timer: while a `Task` subagent runs it shows that subagent's headline (`agentType · description`, prefixed `N agents ·` when ≥2 are concurrent), sourced from `agent-<hex>.meta.json` via named `activity` SSE events the admin reader pushes from the session's `subagents/` dir; with no subagent active it shows a neutral word that advances only on a real turn arrival. The line carries a turn-elapsed clock and flips to a `stalled` state once nothing has been written for 5 minutes (`now − lastEmitAt`), so the operator can tell a wedge from progress without SSH. It is never added to the persisted timeline. Detail and the `[webchat-activity]` observability live in [`admin-webchat-native-channel.md`](../../../.docs/admin-webchat-native-channel.md).
|
|
3362
3367
|
|
|
3363
3368
|
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the native webchat gateway's public spawn (`handleInbound` → `buildPublicWebchatSpawnRequest` → `managerSpawn`) to the manager `POST /public-spawn` body as `name`. `/spawn` validates it with `validateUserTitle` and, for `role=public` only, writes it into `UserTitleStore` so it occupies the operator-rename tier and wins over `ai-title`. Admin (`/rc-spawn`) and WhatsApp titling are unchanged. Observability: every public spawn logs `[spawn] role=public … title="…"` (or `title=missing`); the manager's row builder emits `[public-title] sessionId=… unexpected titleSource=<ai|null>` on the next list read for any public row that did not resolve from the user tier.
|
|
@@ -9,6 +9,21 @@ Invoked by the admin agent directly.
|
|
|
9
9
|
|
|
10
10
|
This is the platform's release timeline, newest first. Each entry shows the date it shipped and the version it shipped in, so you can tell the operator how current their install is. To compare, read the installed version from `capabilities-here` and match it against the versions below. Keep answers high level and in plain English; this is a summary, not a full commit log.
|
|
11
11
|
|
|
12
|
+
## 2026-07-31 (0.1.534)
|
|
13
|
+
|
|
14
|
+
- A shared WhatsApp location now shows as a map with its coordinates, and the assistant can follow a live location as it updates.
|
|
15
|
+
- You can register a named party, such as a supplier or subcontractor, so their messages are recognised and they can be messaged directly.
|
|
16
|
+
- The assistant can notify an account's manager, with the recipients worked out on the server rather than supplied by the caller.
|
|
17
|
+
- Asking about a WhatsApp conversation without naming an account now means your own account rather than the main one.
|
|
18
|
+
- Signing in now runs on the device's own display, fixing a sign-in that could not complete.
|
|
19
|
+
|
|
20
|
+
## 2026-07-31 (0.1.533)
|
|
21
|
+
|
|
22
|
+
- WhatsApp sending now goes out on the account's own connection, and settings changes apply to the account making them rather than always the main one. Each outbound line names the account it went out on.
|
|
23
|
+
- Each account can now hold its own WhatsApp reply policy, with the main account's used only where an account has not set one. Every incoming message records which of the two decided it.
|
|
24
|
+
- A scheduled message is now refused if the event's account does not match where it would be sent, with standing checks for a seat set up under the wrong account.
|
|
25
|
+
- The calendar now shows enough on each entry to recognise it, with a new Schedule view, titles first in the month grid, and a hover card.
|
|
26
|
+
|
|
12
27
|
## 2026-07-31 (0.1.532)
|
|
13
28
|
|
|
14
29
|
- One phone number can now be both a house admin and an account manager. Which account an incoming message belongs to is decided by the number it was sent to, not by which list the sender happens to be on.
|
|
@@ -83,6 +83,8 @@ either is a regression.
|
|
|
83
83
|
|
|
84
84
|
**WhatsApp reader is read/write (WhatsApp-Web surface).** A WhatsApp store conversation in the operator Conversations reader (`OperatorConversations`) and the admin root channel viewer (`app/page.tsx`) no longer opens the plain read-only DM chrome — it opens `app/whatsapp/WhatsappWebConversation.tsx`, a WhatsApp-Web-styled surface: a conversation header, the delivered-only store transcript reskinned green/white under a `.wa-web` root class, and a reply composer (`app/whatsapp/ReplyComposer.tsx`). The operator can type text, insert emoji (a codepoint-data picker — no OS input, so the `check-no-emoji-in-jsx` gate stays green), record a voice note (MediaRecorder → the existing audio send path), attach a file **from device storage** (a modal browsing the DATA_ROOT tree via `GET /api/admin/files`, sent by reference — the OS file dialog is no longer the reader's picker), reply to a specific message (a per-bubble affordance that quotes the original in the composer and threads natively on WhatsApp), and search the loaded transcript (a header control that filters to matching turns and highlights the match). The header carries only that Search control — the former Video / Phone / menu icons are gone, because no call or presence data exists behind them. Sent files honour the webchat allowlist (`SUPPORTED_MIME_SET` / 50 MB / 5 files); a device-file reference is authorised server-side (`authorizeReplyFileRef`) against the send's own account (the conversation owner) **or** the session's pinned account (`getAccountIdForSession` — the exact scope the DeviceFilePicker used to offer it), so a house/managing-admin session can attach a managed-client file the picker listed. Because a reply sends bytes OUT to an external WhatsApp recipient, any other account, a `public` partition, and any install-wide / non-account path are refused fail-closed; the cross-account admission's authority is the session's pinned account, never the caller-supplied body `accountId` (the own-account admission matches the body `accountId`, which the route already trusts via `isValidAccountId` and the existing-conversation guard). A scope refusal returns a distinct HTTP 403 reason (`file-ref-cross-account` / `file-ref-public` / `file-ref-foreign`) and copy, never "device file not found" (reserved for a genuine resolve/stat miss). Per-ref `[wa-manual-send] op=reply-file-ref … via=own|session|deny reason=<…> ok=<bool>` logs the decision before any send; `via=deny ok=true` is the exfiltration signature that must never appear. **Send is reply-only and DM-only:** `POST /api/whatsapp-reader/reply` (`requireAdminSession`) refuses any target with no existing stored conversation (`reason=no-existing-conversation`, HTTP 403) — a cold first-contact send bans the account, so the composer is never a cold-contact path, enforced server-side — and refuses `@g.us` groups (`reason=group-send-blocked`), matching the agent's observe-only group invariant; a group thread shows a read-only note in place of the composer. The endpoint is the sole store writer for a manual send: right after each send resolves it appends the record itself, stamped `origin:'operator-manual'` (attributed "You", distinct from an assistant reply), because the Baileys echo that normally persists the store is gated on message text (`manager.ts:906`) and would leave an uncaptioned media send delivered-but-invisible. The record's `messageId` matches the echo's derivation so the async text echo's own persist dedups to a no-op; the send is confirmed by re-read (`op=recorded present=<bool>`). A sent send does not spawn an assistant turn (echo dispatch stays suppressed). Attachments deliver as WhatsApp media/documents and render **inline** in the store reader (image thumbnail / pdf preview / audio player / download chip), because the manual-send path records the message with the servable `attachmentId`. The `.wa-web` skin is scoped to WhatsApp store threads only, so `/chat`, the admin agent session view, and the public visitor webchat are unchanged; the visitor webchat gains no send capability. The in-bubble delivered-tick is cosmetic (no read-receipt data is stored); inbound bubbles keep their sender name so group threads stay attributable, and both directions carry a WhatsApp callout tail (`.wa-web`-scoped only). Non-WhatsApp reader rows (Telegram/webchat session JSONLs) keep the plain read-only `Transcript`. Observability rides `[wa-manual-send]` lines correlated by a per-request `sendId`. **Composer sizing matches the webchat composer:** the reply textarea auto-grows to fit multi-line content (measured from `scrollHeight`, clamped to a one-row minimum and a `viewport/3` maximum, scrollable past the cap with the scrollbar hidden), and a top-border grab handle drags (pointer) or nudges (ArrowUp/ArrowDown, keyboard-focusable) to an explicit height in the same clamp; a manual drag pins the height and overrides auto-grow until the field is cleared, which releases it back to auto-grow. A completed manual resize logs `[operator-ui] op=wa-composer-resize mode=drag|key h=<px>`; a bare click on the handle (no drag) logs nothing.
|
|
85
85
|
|
|
86
|
+
**Shared locations show a map.** When someone shares a location on WhatsApp, the conversation shows a small map with a pin on the spot, above the coordinates themselves. Selecting the map opens the full map on OpenStreetMap in a new tab. A location shared as a place name with no coordinates shows the name only, because there is no point to put a pin on. The map images are fetched by your browser from OpenStreetMap, so the shared coordinates reach that service when a location bubble is on screen.
|
|
87
|
+
|
|
86
88
|
**`/chat` live activity line.** While a turn is in flight the transcript tail shows one ephemeral `ChatActivity` line (mounted only while `busy`, admin/operator only). It tracks real activity, not a timer: while a `Task` subagent runs it shows that subagent's headline (`agentType · description`, prefixed `N agents ·` when ≥2 are concurrent), sourced from `agent-<hex>.meta.json` via named `activity` SSE events the admin reader pushes from the session's `subagents/` dir; with no subagent active it shows a neutral word that advances only on a real turn arrival. The line carries a turn-elapsed clock and flips to a `stalled` state once nothing has been written for 5 minutes (`now − lastEmitAt`), so the operator can tell a wedge from progress without SSH. It is never added to the persisted timeline. Detail and the `[webchat-activity]` observability live in [`admin-webchat-native-channel.md`](../../../.docs/admin-webchat-native-channel.md).
|
|
87
89
|
|
|
88
90
|
**maxy title for public sessions.** A `role=public` webchat spawn never produces a useful Claude Code `ai-title` (an anonymous one-line visitor turn), so every public row would otherwise read identically. The webchat route (`chat.ts`) composes a deterministic title — `Web · <senderId[:8]>[ · <personId>] · <UTC YYYY-MM-DD HH:mm>` (personId present only for gated visitors) — and threads it through the native webchat gateway's public spawn (`handleInbound` → `buildPublicWebchatSpawnRequest` → `managerSpawn`) to the manager `POST /public-spawn` body as `name`. `/spawn` validates it with `validateUserTitle` and, for `role=public` only, writes it into `UserTitleStore` so it occupies the operator-rename tier and wins over `ai-title`. Admin (`/rc-spawn`) and WhatsApp titling are unchanged. Observability: every public spawn logs `[spawn] role=public … title="…"` (or `title=missing`); the manager's row builder emits `[public-title] sessionId=… unexpected titleSource=<ai|null>` on the next list read for any public row that did not resolve from the user tier.
|
|
@@ -4,15 +4,18 @@ SiteDesk gives you a calendar of your schedule and a public page where people ca
|
|
|
4
4
|
|
|
5
5
|
## The admin calendar
|
|
6
6
|
|
|
7
|
-
Open `/calendar` on your SiteDesk address (the same sign-in as the dashboard). It shows your schedule in
|
|
7
|
+
Open `/calendar` on your SiteDesk address (the same sign-in as the dashboard). It shows your schedule in five views:
|
|
8
8
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
9
|
+
- **Schedule** is a plain list of what is coming up, thirty days at a time, grouped by day. Every entry shows its time, title, place, who is attending, and what kind of entry it is, all on the row. Days with nothing on them are left out. This is the view the calendar opens on.
|
|
10
|
+
- **Day** and **Week** show an hour grid with each timed entry as a block. The block always shows the title; it adds the time underneath when the entry is long enough for a second line to fit (about three quarters of an hour in Week, a little over half an hour in Day). The title comes first because the block's position in the grid already tells you when it is.
|
|
11
|
+
- **Month** shows the familiar month grid with up to three entries per day. Each chip gives its whole width to the title. When a day holds more, **+2 more** is a button that opens that day.
|
|
12
|
+
- **Year** shows twelve small months. A day with something on it carries the number of entries, and clicking a month opens it.
|
|
12
13
|
|
|
13
|
-
Use **Today** and the arrows to move around, and the view buttons to switch. The calendar reads everything time-bound in your graph: meetings imported from a calendar export or created by a booking, appointments SiteDesk schedules for you in chat, and tasks that have a due date (shown on their day).
|
|
14
|
+
Use **Today** and the arrows to move around, and the view buttons to switch. In Schedule the arrows move a whole thirty days, so you can step back into the past as well as forward. The calendar reads everything time-bound in your graph: meetings imported from a calendar export or created by a booking, appointments SiteDesk schedules for you in chat, and tasks that have a due date (shown on their day).
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Hover over any entry in Day, Week or Month, or reach it with the Tab key, and a small card shows what the row itself has no room for: the full title, the start and end time, the place, who is attending, and the kind of entry. You do not have to open anything to see this. On the Year view the same card appears, but on hover only, not by keyboard. Schedule needs no card, since its rows already carry all of it.
|
|
17
|
+
|
|
18
|
+
Click any entry to open its details, where you can also edit it: the full title, time, location, and who is attending, with each attendee on its own line (name, and email beneath it). For a booked meeting you can also edit its title, time, or location, or delete it, and the grid updates straight away. You can **Download** a booked meeting as a calendar file (`.ics`) to add it to Apple, Google, or Outlook calendars; when the meeting has attendees, Download asks whether to include them in the file before it saves, and a meeting with no attendees downloads straight away. The private note is never written into the downloaded file, since the file can travel outside your admin. In the edit view you can add an attendee (give a name, an email, or both) and remove one; adding someone who is already a contact reuses that contact rather than making a duplicate, and removing them takes them off the meeting but keeps the contact. The edit view also has a private note for that meeting, a place for your own reminders that only you and your team ever see; it never appears on the public booking page or anywhere outside your admin. Appointments SiteDesk schedules and due-dated tasks are shown for detail only and are changed where they are created, not here. New meetings are still made by a booking or by asking SiteDesk in chat, not from the calendar.
|
|
16
19
|
|
|
17
20
|
Everything on the calendar comes from records the rest of SiteDesk already uses, scoped to your account.
|
|
18
21
|
|
|
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { mkdtempSync, writeFileSync, rmSync, realpathSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
|
-
import { loadSignature, applySignature, htmlFromPlainText, formatSignatureNote, } from '../lib/signature.js';
|
|
5
|
+
import { loadSignature, applySignature, htmlFromPlainText, formatSignatureNote, rootTypography, } from '../lib/signature.js';
|
|
6
6
|
describe('Task 1952 — email signature load + apply', () => {
|
|
7
7
|
let dir = '';
|
|
8
8
|
beforeEach(() => { dir = realpathSync(mkdtempSync(join(tmpdir(), 'sig-'))); });
|
|
@@ -129,4 +129,43 @@ describe('Task 2193 — htmlFromPlainText', () => {
|
|
|
129
129
|
expect(htmlFromPlainText('')).toBe('<p></p>');
|
|
130
130
|
});
|
|
131
131
|
});
|
|
132
|
+
// Task 2237 — the wrap div carried font-family alone, taken from
|
|
133
|
+
// email-signature.font. The GLS asset styles its own text at 12px/#000000, so a
|
|
134
|
+
// derived body rendered at the client default (~16px) beside a 12px signature:
|
|
135
|
+
// the mismatch the operator flagged three times. STYLED_ASSET is that asset's
|
|
136
|
+
// real root element, verbatim from the account directory.
|
|
137
|
+
const STYLED_ASSET = '<table cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.4;color:#000000;">\n<tr><td>Regards,</td></tr></table>';
|
|
138
|
+
describe('Task 2237 — rootTypography', () => {
|
|
139
|
+
it('copies only the four typography properties, dropping border-collapse', () => {
|
|
140
|
+
expect(rootTypography(STYLED_ASSET)).toBe('font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.4;color:#000000');
|
|
141
|
+
});
|
|
142
|
+
it('returns null when the root declares no style', () => {
|
|
143
|
+
expect(rootTypography('<table><tr><td>hi</td></tr></table>')).toBeNull();
|
|
144
|
+
});
|
|
145
|
+
it('returns null when the style carries no typography', () => {
|
|
146
|
+
expect(rootTypography('<div style="border-collapse:collapse;">x</div>')).toBeNull();
|
|
147
|
+
});
|
|
148
|
+
it('returns null for an absent asset', () => {
|
|
149
|
+
expect(rootTypography(null)).toBeNull();
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
describe('Task 2237 — applySignature wrap', () => {
|
|
153
|
+
it("wraps a derived body in the asset's own typography", () => {
|
|
154
|
+
const out = applySignature({ body: 'Hello' }, { text: null, html: STYLED_ASSET, font: 'Arial, Helvetica, sans-serif' });
|
|
155
|
+
expect(out.html).toContain('<div style="font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:1.4;color:#000000">');
|
|
156
|
+
expect(out.derivedHtml).toBe(true);
|
|
157
|
+
expect(out.wrap).toEqual({ family: true, size: true, lineHeight: true, color: true, assetStyled: true });
|
|
158
|
+
});
|
|
159
|
+
it('falls back to family-only when the asset declares no root style', () => {
|
|
160
|
+
const out = applySignature({ body: 'Hello' }, { text: null, html: '<p>Regards</p>', font: 'Georgia, serif' });
|
|
161
|
+
expect(out.html).toContain('<div style="font-family: Georgia, serif">');
|
|
162
|
+
expect(out.wrap).toEqual({ family: true, size: false, lineHeight: false, color: false, assetStyled: false });
|
|
163
|
+
});
|
|
164
|
+
it('derives nothing and wraps nothing when no html signature is stored', () => {
|
|
165
|
+
const out = applySignature({ body: 'Hello' }, { text: 'Regards', html: null, font: 'Georgia, serif' });
|
|
166
|
+
expect(out.html).toBeUndefined();
|
|
167
|
+
expect(out.derivedHtml).toBe(false);
|
|
168
|
+
expect(out.wrap.assetStyled).toBe(false);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
132
171
|
//# sourceMappingURL=signature.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature.test.js","sourceRoot":"","sources":["../../src/__tests__/signature.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC1E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EACL,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"signature.test.js","sourceRoot":"","sources":["../../src/__tests__/signature.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/lib/compose.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAkC,MAAM,WAAW,CAAC;AAG7E,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAExB,6FAA6F;AAC7F,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CASxF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/lib/compose.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAkC,MAAM,WAAW,CAAC;AAG7E,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAExB,6FAA6F;AAC7F,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CASxF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,aAAa,CAAC,CA0ExB"}
|
|
@@ -76,7 +76,10 @@ export async function composeDraft(config, password, accountId, params) {
|
|
|
76
76
|
const assetNote = sigDir ? join(sigDir, SIGNATURE_BASENAME) : "none";
|
|
77
77
|
// Task 2193 — the parts are reported separately. One flag set from either part
|
|
78
78
|
// could not tell a plain-text draft from a branded one.
|
|
79
|
-
|
|
79
|
+
// Task 2237 — the wrap fields are read back off the composed html, not the
|
|
80
|
+
// inputs. `assetStyled=true` with `wrapSize=false` is the font mismatch that
|
|
81
|
+
// shipped three times: a body at the client default beside a 12px signature.
|
|
82
|
+
console.error(`[email-draft] op=signature accountId=${accountId.slice(0, 8)} text=${signed.textApplied} html=${signed.htmlApplied} derivedHtml=${signed.derivedHtml} wrapFamily=${signed.wrap.family} wrapSize=${signed.wrap.size} wrapLineHeight=${signed.wrap.lineHeight} wrapColor=${signed.wrap.color} assetStyled=${signed.wrap.assetStyled} asset=${assetNote}`);
|
|
80
83
|
const sendOptions = {
|
|
81
84
|
to: params.to,
|
|
82
85
|
subject: resolvedSubject,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/lib/compose.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/lib/compose.ts"],"names":[],"mappings":"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"}
|
|
@@ -75,6 +75,32 @@ export interface SignatureFlags {
|
|
|
75
75
|
* by the caller. */
|
|
76
76
|
derivedHtml: boolean;
|
|
77
77
|
}
|
|
78
|
+
/** Which typography the composed wrap actually carries. Task 2237 — measured on
|
|
79
|
+
* the emitted div, not inferred from the inputs, so the log cannot claim a
|
|
80
|
+
* property that never landed. */
|
|
81
|
+
export interface WrapFlags {
|
|
82
|
+
family: boolean;
|
|
83
|
+
size: boolean;
|
|
84
|
+
lineHeight: boolean;
|
|
85
|
+
color: boolean;
|
|
86
|
+
/** The stored `.html` declares a style attribute on its root element. */
|
|
87
|
+
assetStyled: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Task 2237 — the typography declared on the stored HTML signature's root
|
|
91
|
+
* element, as a CSS declaration list.
|
|
92
|
+
*
|
|
93
|
+
* Task 2193 wrapped a derived body in `font-family` alone, taken from
|
|
94
|
+
* `email-signature.font`. The GLS asset styles its own text at 12px/#000000, so
|
|
95
|
+
* a derived body rendered at the client default (~16px) beside a 12px signature
|
|
96
|
+
* — the mismatch the operator flagged three times. Copying the asset's own
|
|
97
|
+
* declarations makes body and signature agree by construction, for every
|
|
98
|
+
* account, without widening the `.font` contract to carry a size.
|
|
99
|
+
*
|
|
100
|
+
* Returns null when there is no asset, no root style attribute, or no
|
|
101
|
+
* typography in it; the caller then falls back to the family-only wrap.
|
|
102
|
+
*/
|
|
103
|
+
export declare function rootTypography(html: string | null): string | null;
|
|
78
104
|
/**
|
|
79
105
|
* Append the signature to a draft's body/html deterministically, with no model
|
|
80
106
|
* judgement. The plain-text signature is appended to body whenever present.
|
|
@@ -97,6 +123,7 @@ export declare function applySignature(input: {
|
|
|
97
123
|
}, sig: Signature): {
|
|
98
124
|
body: string;
|
|
99
125
|
html?: string;
|
|
126
|
+
wrap: WrapFlags;
|
|
100
127
|
} & SignatureFlags;
|
|
101
128
|
/**
|
|
102
129
|
* Task 2193 — the signature sentence both draft tools append to their result.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/lib/signature.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAUD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CASvE;AAED;uEACuE;AACvE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAQD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,cAAc,GACpB,mBAAmB,CA8BrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,WAAW,EAAE,OAAO,CAAC;IACrB,wDAAwD;IACxD,WAAW,EAAE,OAAO,CAAC;IACrB;yBACqB;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACtC,GAAG,EAAE,SAAS,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,
|
|
1
|
+
{"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/lib/signature.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAUD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CASvE;AAED;uEACuE;AACvE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oDAAoD;IACpD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAQD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,cAAc,GACpB,mBAAmB,CA8BrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,WAAW,EAAE,OAAO,CAAC;IACrB,wDAAwD;IACxD,WAAW,EAAE,OAAO,CAAC;IACrB;yBACqB;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAOD;;kCAEkC;AAClC,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,yEAAyE;IACzE,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAgBjE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACtC,GAAG,EAAE,SAAS,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG,cAAc,CA4CnE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAcjE"}
|
|
@@ -112,6 +112,45 @@ export function htmlFromPlainText(text) {
|
|
|
112
112
|
.map((paragraph) => `<p>${paragraph.replace(/\n/g, "<br>")}</p>`)
|
|
113
113
|
.join("");
|
|
114
114
|
}
|
|
115
|
+
/** The typography the wrap div may copy from the stored signature asset.
|
|
116
|
+
* An allowlist, not the whole style attribute: the real GLS asset root also
|
|
117
|
+
* declares `border-collapse:collapse`, which is layout, not typography. */
|
|
118
|
+
const TYPOGRAPHY_PROPERTIES = ["font-family", "font-size", "line-height", "color"];
|
|
119
|
+
/**
|
|
120
|
+
* Task 2237 — the typography declared on the stored HTML signature's root
|
|
121
|
+
* element, as a CSS declaration list.
|
|
122
|
+
*
|
|
123
|
+
* Task 2193 wrapped a derived body in `font-family` alone, taken from
|
|
124
|
+
* `email-signature.font`. The GLS asset styles its own text at 12px/#000000, so
|
|
125
|
+
* a derived body rendered at the client default (~16px) beside a 12px signature
|
|
126
|
+
* — the mismatch the operator flagged three times. Copying the asset's own
|
|
127
|
+
* declarations makes body and signature agree by construction, for every
|
|
128
|
+
* account, without widening the `.font` contract to carry a size.
|
|
129
|
+
*
|
|
130
|
+
* Returns null when there is no asset, no root style attribute, or no
|
|
131
|
+
* typography in it; the caller then falls back to the family-only wrap.
|
|
132
|
+
*/
|
|
133
|
+
export function rootTypography(html) {
|
|
134
|
+
if (html === null)
|
|
135
|
+
return null;
|
|
136
|
+
const root = html.match(/<[a-zA-Z][^>]*\sstyle\s*=\s*"([^"]*)"/);
|
|
137
|
+
if (!root)
|
|
138
|
+
return null;
|
|
139
|
+
const kept = [];
|
|
140
|
+
for (const declaration of root[1].split(";")) {
|
|
141
|
+
const colon = declaration.indexOf(":");
|
|
142
|
+
if (colon < 0)
|
|
143
|
+
continue;
|
|
144
|
+
const property = declaration.slice(0, colon).trim().toLowerCase();
|
|
145
|
+
const value = declaration.slice(colon + 1).trim();
|
|
146
|
+
if (value.length === 0)
|
|
147
|
+
continue;
|
|
148
|
+
if (TYPOGRAPHY_PROPERTIES.includes(property)) {
|
|
149
|
+
kept.push(`${property}:${value}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return kept.length > 0 ? kept.join(";") : null;
|
|
153
|
+
}
|
|
115
154
|
/**
|
|
116
155
|
* Append the signature to a draft's body/html deterministically, with no model
|
|
117
156
|
* judgement. The plain-text signature is appended to body whenever present.
|
|
@@ -134,6 +173,17 @@ export function applySignature(input, sig) {
|
|
|
134
173
|
let textApplied = false;
|
|
135
174
|
let htmlApplied = false;
|
|
136
175
|
let derivedHtml = false;
|
|
176
|
+
// Task 2237 — the asset's own root typography wins over the family-only
|
|
177
|
+
// `.font` wrap, so body and signature render alike. `.font` stays the
|
|
178
|
+
// fallback for an asset that declares no root style.
|
|
179
|
+
const typography = rootTypography(sig.html);
|
|
180
|
+
const wrap = {
|
|
181
|
+
family: false,
|
|
182
|
+
size: false,
|
|
183
|
+
lineHeight: false,
|
|
184
|
+
color: false,
|
|
185
|
+
assetStyled: typography !== null,
|
|
186
|
+
};
|
|
137
187
|
if (sig.text !== null) {
|
|
138
188
|
body = `${body}\n\n${sig.text}`;
|
|
139
189
|
textApplied = true;
|
|
@@ -147,11 +197,21 @@ export function applySignature(input, sig) {
|
|
|
147
197
|
html = `${html}${sig.html}`;
|
|
148
198
|
htmlApplied = true;
|
|
149
199
|
}
|
|
150
|
-
if (
|
|
200
|
+
if (typography !== null) {
|
|
201
|
+
html = `<div style="${typography}">${html}</div>`;
|
|
202
|
+
// Read back off the string actually emitted. No allowlisted property
|
|
203
|
+
// contains another as a substring, so these matches are exact.
|
|
204
|
+
wrap.family = typography.includes("font-family:");
|
|
205
|
+
wrap.size = typography.includes("font-size:");
|
|
206
|
+
wrap.lineHeight = typography.includes("line-height:");
|
|
207
|
+
wrap.color = typography.includes("color:");
|
|
208
|
+
}
|
|
209
|
+
else if (sig.font !== null) {
|
|
151
210
|
html = `<div style="font-family: ${sig.font}">${html}</div>`;
|
|
211
|
+
wrap.family = true;
|
|
152
212
|
}
|
|
153
213
|
}
|
|
154
|
-
return { body, html, textApplied, htmlApplied, derivedHtml };
|
|
214
|
+
return { body, html, textApplied, htmlApplied, derivedHtml, wrap };
|
|
155
215
|
}
|
|
156
216
|
/**
|
|
157
217
|
* Task 2193 — the signature sentence both draft tools append to their result.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/lib/signature.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/lib/signature.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,7 +38,11 @@ A preference is invariant-class when its value describes a document layout, a na
|
|
|
38
38
|
|
|
39
39
|
A preference is soft when it is a genuine standing choice with no owning skill to enforce it: a contact, a timezone, a one-invoice-per-message rule, a skip-size numeral, a no-proactive-reminders rule. Soft preferences stay in the injected store.
|
|
40
40
|
|
|
41
|
-
For every invariant, the plan names the owning skill and whether that skill already applies it deterministically or a migration is still pending. A preference whose owning skill you cannot name is reported as unassigned rather than silently left in place.
|
|
41
|
+
For every invariant, the plan names the owning skill and whether that skill already applies it deterministically or a migration is still pending. A preference whose owning skill you cannot name is reported as unassigned rather than silently left in place.
|
|
42
|
+
|
|
43
|
+
Naming an owner is not enough to retire a preference. Before retiring, confirm the named owner actually applies the rule's substance, and name the template, tool step or asset that enforces it. A preference whose owner is named but unverified is reported as `unassigned` and stays stored: an unenforced invariant deleted from the store is enforced nowhere at all.
|
|
44
|
+
|
|
45
|
+
The email signature is the worked instance, and it is narrower than it looks. `email-draft` and `email-draft-edit` apply the account's saved signature asset deterministically, so a preference restating the *signature's own* contents is retired once the asset is in place. A preference about the *body* the signature sits under — its font, size, line height or colour — has no such owner: the asset styles itself, not the message body. Retiring one of those deletes the only copy of the rule. That is not hypothetical: on 2026-07-24 this audit retired a confidence-1.0 body-font rule into a signature-template preference carrying no font content, and the mismatch it prevented shipped twice more before anyone noticed.
|
|
42
46
|
|
|
43
47
|
## Dry run first, always
|
|
44
48
|
|
|
@@ -57,6 +61,12 @@ Close every audit with one line, whether it was a dry run or applied:
|
|
|
57
61
|
|
|
58
62
|
`[preference-audit] account=<id> reworded=<n> merged=<n> retired=<n> restated-to-capability=<n>`
|
|
59
63
|
|
|
64
|
+
Every retirement additionally emits one line, so the decision survives the deletion it describes:
|
|
65
|
+
|
|
66
|
+
`[preference-audit] op=retire account=<id8> key=<k> owner=<skill> ownerVerified=<bool>`
|
|
67
|
+
|
|
68
|
+
`ownerVerified=false` is a rule retired to an owner that does not apply it. That line is the alarm, and it is visible at the moment it happens rather than when someone notices the rule stopped being followed.
|
|
69
|
+
|
|
60
70
|
Count what the plan proposes on a dry run, and what was applied on a real run.
|
|
61
71
|
|
|
62
72
|
The classification pass emits its own line on the audit's periodic tick, so an invariant-shaped preference accumulating unmigrated surfaces on its own and not only on demand:
|
|
@@ -46,6 +46,10 @@ tools:
|
|
|
46
46
|
publicAllowlist: false
|
|
47
47
|
adminAllowlist: false
|
|
48
48
|
riskClass: external
|
|
49
|
+
- name: whatsapp-notify-manager
|
|
50
|
+
publicAllowlist: true
|
|
51
|
+
adminAllowlist: true
|
|
52
|
+
riskClass: external
|
|
49
53
|
- name: whatsapp-reply
|
|
50
54
|
publicAllowlist: false
|
|
51
55
|
adminAllowlist: false
|
|
@@ -106,7 +110,9 @@ A native admin channel session runs a per-sender `whatsapp-channel` MCP server (
|
|
|
106
110
|
|
|
107
111
|
## Agent-initiated admin send
|
|
108
112
|
|
|
109
|
-
`whatsapp-send-admin` is the one outbound path that does **not** require a bound inbound conversation, so a webchat session or a scheduled run can push a text summary over WhatsApp. It is hard-gated to the cold-send-ban carve-out: the destination must already be a **registered recipient** — on the house `whatsapp.adminPhones` list (managed via `whatsapp-config add-admin-phone`)
|
|
113
|
+
`whatsapp-send-admin` is the one outbound path that does **not** require a bound inbound conversation, so a webchat session or a scheduled run can push a text summary over WhatsApp. It is hard-gated to the cold-send-ban carve-out: the destination must already be a **registered recipient** — on the house `whatsapp.adminPhones` list (managed via `whatsapp-config add-admin-phone`), a registered account manager in `whatsapp.accountManagers` (managed via `whatsapp-config add-account-manager`), **or** a registered party in `whatsapp.registeredParties` (managed via `whatsapp-config add-registered-party`, logged `via=registered-party`). A registered party is admitted on the same grounds as an account manager: an operator-registered destination is not a cold stranger, and being public on the inbound path does not make an outbound send cold. Both lists are read from the socket-owning house account (`resolveAccount`), and the send rides the **calling session's own** paired socket: a sub-account session transmits on its own line, an unsigned caller falls back to the house line, and a session whose account has no socket gets a 503 naming the key miss rather than a silent fall-back to the house. A destination in neither list is refused with `[whatsapp:outbound] op=send-refused reason=not-admin-phone` and no send is attempted — never a cold first contact. An **account-manager** phone (in `accountManagers`, which may overlap `adminPhones` — a phone can hold both roles, and the number it messaged decides its inbound scope) **is** a valid `send-admin` destination regardless of its binding mode: the operator registered it, so it is not a cold stranger. `passive` governs the manager's **inbound** behaviour only (no auto-reply, intake-only) and never gates this outbound send. A successful send logs its admit basis and both accounts (`op=send-admin-ok via=admin-phone|account-manager callerAccount=… socketAccount=…`), and every `[whatsapp:outbound]` line carries `account=`. A send that carries no caller identity falls back to the house socket, emits `op=outbound-caller-unsigned` at WARN and increments `outboundSocketReconcile.unsignedFallbacks` on `GET /api/whatsapp/status`, because a send on the wrong line is otherwise a successful write with no event. The two accounts on the success line are for a human to read and are deliberately not compared: they are different namespaces, since the house connection's key is the credential dirname while the caller is a platform UUID. Delivery reuses `sendTextMessage`, so the sent id is tracked for echo suppression and the send is recorded as outbound activity. Text only; for files use the bound `reply-document` surface.
|
|
114
|
+
|
|
115
|
+
`whatsapp-notify-manager` is the only WhatsApp tool a **public** session may call. It exists so a session handling a stranger's message can tell the operator without being handed a general send. It takes **no recipient**: the destination is computed on the server as every `whatsapp.accountManagers` key whose bound account equals the calling session's own account, so text authored by an unknown sender can never choose or influence who is contacted. The caller supplies only `senderDisplay`, `summary` and `draftLocation`, which are placed verbatim into a fixed message shape and never interpreted. It refuses with `no-registered-manager` when no manager binds to the calling account, rather than falling back to the house admin list or the house socket, and the send rides the calling account's own paired socket exactly as `whatsapp-send-admin` does. This is precisely why `whatsapp-send-admin` stays `publicAllowlist: false`: it accepts a caller-chosen destination and a free-form body, which is the shape an injected instruction would exploit.
|
|
110
116
|
|
|
111
117
|
## Self-chat command lane
|
|
112
118
|
|
|
@@ -128,7 +134,11 @@ Every `messages.upsert` event (both `notify` and `append`, both `fromMe` directi
|
|
|
128
134
|
|
|
129
135
|
**Sub-account recall.** Recall is account-scoped as a read-time projection: a sub-account session sees only the house-store threads whose counterparty is one of its bound account-manager phones (the same filter the operator dashboard uses, shared via `counterpartyBoundToSubAccount`). The write path and the store key are unchanged — messages stay house-keyed; "sub-account scope" is a projection, not a move. `whatsapp-conversation-graph-state` defaults its `accountId` to the calling session's own `ACCOUNT_ID`, so a sub-account recalls its own history with no argument while the house admin may still pass any account id explicitly. Body search is not restored by this projection (it has been absent since the on-disk store cutover).
|
|
130
136
|
|
|
131
|
-
**
|
|
137
|
+
**Three inbound sender classes.** A DM reaching a paired number is one of three things. An **operator** is a phone on the house `adminPhones` list or a registered account manager; both get an admin session. A **registered party** is a known non-operator counterparty — a driver, a supplier, a contractor — registered with `add-registered-party` against the account whose number they message; they get the **public** agent, carrying an operator-chosen `party` label, and are never granted admin. Anyone else is an unknown visitor and takes whatever the account's DM policy allows. The registration applies only on the registered account's **own** number: reached on the house number a registered party takes the house DM policy like any stranger, which is deliberate — a counterparty must not reach a sub-account through the house line. The label rides to the spawned session's environment as `WA_SENDER_PARTY` and appears on the `[whatsapp:manager] inbound` line as `party=`; the platform never interprets it, so what a label means is the account's own skill to decide. A phone cannot hold a party registration **and** an admin or manager registration at once: either write is refused `party-registration-shadowed`, because the operator arms are checked first and the party registration would sit unreachable. A registration that is shadowed later out of band (a hand-edited `account.json`) emits `[whatsapp:manager] op=registered-party-shadowed` on the next inbound and is counted by `registeredPartyReconcile` on `GET /api/whatsapp/status`, alongside a registration naming a deleted account. Because a registered party is public, they inherit the two public-only dispatch gates: managed-service mode suppresses their turn, and a message outside business hours gets the after-hours auto-reply rather than a dispatch.
|
|
138
|
+
|
|
139
|
+
**Config action authority.** The three registered-party actions (`add-registered-party`, `remove-registered-party`, `list-registered-parties`) scope to the caller exactly as the three account-manager actions below do: any session may register a counterparty on its **own** account, `list` returns only that account's registrations, and naming another account is refused 403. The three account-manager actions (`add-account-manager`, `remove-account-manager`, `list-account-managers`) are per-account **bindings** and scope to the caller: any session may bind a phone to its **own** account, `list` returns only that account's bindings, and naming another account is refused 403 with `reason: "binding-account-scope-mismatch"`. Removing a phone that holds no binding is refused for the same reason, because there is no binding value to prove the phone is yours. A house admin is unrestricted and unfiltered on all three. Every other action on this route is install-wide and stays house-only. The bindings are written to the house `account.json` regardless of who wrote them, because that is the file the inbound gate reads and `purgeNonSocketAccountManagersAtBoot` deletes a map written anywhere else.
|
|
140
|
+
|
|
141
|
+
**Caller-scope enforcement.** The three read tools — `whatsapp-conversation-graph-state`, `whatsapp-conversations`, `whatsapp-messages` — and `whatsapp-send-admin` forward the caller's own account (`ACCOUNT_ID`) and its house-admin scope (`HOUSE_ADMIN_SCOPE`) to the route as headers, distinct from the caller-controlled `accountId` argument. The route enforces caller-scope: a house admin reads any account; any other session (a sub-account, or a specialist under any account) may read only its own account and gets a 403 if it passes a different `accountId`. This closes the override where a sub-account could pass an explicit house or sibling id and read that store. It defends only the loopback route against the agent-controlled argument; the route still trusts localhost, so forging these headers on a direct loopback call remains possible — closing that is a separate, tracked follow-up.
|
|
132
142
|
|
|
133
143
|
## Skills
|
|
134
144
|
|