@rubytech/create-maxy-code 0.1.342 → 0.1.344

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/config/brand.json +4 -1
  3. package/payload/platform/neo4j/schema.cypher +9 -5
  4. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
  5. package/payload/platform/plugins/admin/PLUGIN.md +4 -1
  6. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-hostname.test.d.ts +2 -0
  7. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-hostname.test.d.ts.map +1 -0
  8. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-hostname.test.js +175 -0
  9. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-hostname.test.js.map +1 -0
  10. package/payload/platform/plugins/admin/mcp/dist/index.js +33 -0
  11. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  12. package/payload/platform/plugins/admin/mcp/dist/lib/admin-hostname.d.ts +15 -0
  13. package/payload/platform/plugins/admin/mcp/dist/lib/admin-hostname.d.ts.map +1 -0
  14. package/payload/platform/plugins/admin/mcp/dist/lib/admin-hostname.js +86 -0
  15. package/payload/platform/plugins/admin/mcp/dist/lib/admin-hostname.js.map +1 -0
  16. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +90 -1
  17. package/payload/platform/plugins/cloudflare/skills/calendar-site/SKILL.md +82 -0
  18. package/payload/platform/plugins/cloudflare/skills/calendar-site/template/functions/api/book.ts +112 -0
  19. package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/booking.css +100 -0
  20. package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/booking.js +155 -0
  21. package/payload/platform/plugins/cloudflare/skills/calendar-site/template/public/index.html +47 -0
  22. package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +18 -0
  23. package/payload/platform/plugins/cloudflare/skills/calendar-site/template/wrangler.toml +14 -0
  24. package/payload/platform/plugins/docs/PLUGIN.md +1 -0
  25. package/payload/platform/plugins/docs/references/admin-ui.md +26 -0
  26. package/payload/platform/plugins/docs/references/calendar-booking.md +56 -0
  27. package/payload/platform/plugins/docs/references/internals.md +2 -0
  28. package/payload/platform/plugins/scheduling/PLUGIN.md +23 -0
  29. package/payload/platform/plugins/scheduling/mcp/dist/index.js +19 -5
  30. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  31. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.d.ts +2 -0
  32. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.d.ts.map +1 -0
  33. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.js +45 -0
  34. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-notify.test.js.map +1 -0
  35. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.d.ts +2 -0
  36. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.d.ts.map +1 -0
  37. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +89 -0
  38. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -0
  39. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-write.test.d.ts +2 -0
  40. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-write.test.d.ts.map +1 -0
  41. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-write.test.js +118 -0
  42. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/meeting-write.test.js.map +1 -0
  43. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-classify.test.d.ts +2 -0
  44. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-classify.test.d.ts.map +1 -0
  45. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-classify.test.js +59 -0
  46. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/schedule-classify.test.js.map +1 -0
  47. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.d.ts +22 -0
  48. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.d.ts.map +1 -0
  49. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.js +31 -0
  50. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-notify.js.map +1 -0
  51. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +28 -0
  52. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -0
  53. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +70 -0
  54. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -0
  55. package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.d.ts +35 -0
  56. package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.d.ts.map +1 -0
  57. package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.js +123 -0
  58. package/payload/platform/plugins/scheduling/mcp/dist/lib/meeting-write.js.map +1 -0
  59. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-classify.d.ts +23 -0
  60. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-classify.d.ts.map +1 -0
  61. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-classify.js +38 -0
  62. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-classify.js.map +1 -0
  63. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts +21 -0
  64. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts.map +1 -0
  65. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +280 -0
  66. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -0
  67. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +11 -1
  68. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
  69. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +34 -2
  70. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
  71. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  72. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  73. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  74. package/payload/platform/templates/specialists/agents/personal-assistant.md +2 -0
  75. package/payload/server/{chunk-5BG6CHGH.js → chunk-QAKVFSEJ.js} +15 -0
  76. package/payload/server/maxy-edge.js +1 -1
  77. package/payload/server/public/assets/{AdminLoginScreens-Brx8CmXN.js → AdminLoginScreens-CZqsFfP0.js} +1 -1
  78. package/payload/server/public/assets/AdminShell-DnhBRZv5.js +1 -0
  79. package/payload/server/public/assets/{Checkbox-aePjWzRH.js → Checkbox-D0FwyuVg.js} +1 -1
  80. package/payload/server/public/assets/{OperatorConversations-BMIZQR9t.css → OperatorConversations-BG9GrxQU.css} +1 -1
  81. package/payload/server/public/assets/OperatorConversations-dt0q8mjv.js +9 -0
  82. package/payload/server/public/assets/admin-CCzmqd1F.js +1 -0
  83. package/payload/server/public/assets/{arc-CxLB9WCE.js → arc-DpkSQNto.js} +1 -1
  84. package/payload/server/public/assets/architecture-YZFGNWBL-Csj53u5T.js +1 -0
  85. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-D-EdJPSY.js → architectureDiagram-Q4EWVU46-Bw7Yq8O9.js} +1 -1
  86. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CXx9RgCm.js → blockDiagram-DXYQGD6D-BBtJQFSz.js} +1 -1
  87. package/payload/server/public/assets/{browser-Bp5kGgyr.js → browser-kmrJq69n.js} +1 -1
  88. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-RFBXEe0B.js → c4Diagram-AHTNJAMY-JAMgxzOr.js} +1 -1
  89. package/payload/server/public/assets/calendar-BWf5qrIH.js +1 -0
  90. package/payload/server/public/assets/channel-BUQUAUts.js +1 -0
  91. package/payload/server/public/assets/chat-C2e06_q0.js +1 -0
  92. package/payload/server/public/assets/{chunk-2KRD3SAO-DBqAFwK9.js → chunk-2KRD3SAO-eDugsc2L.js} +1 -1
  93. package/payload/server/public/assets/{chunk-336JU56O-DdnFEz6R.js → chunk-336JU56O-BXfECwdC.js} +2 -2
  94. package/payload/server/public/assets/chunk-426QAEUC-CdknReB2.js +1 -0
  95. package/payload/server/public/assets/{chunk-4BX2VUAB-cnw-3Gbs.js → chunk-4BX2VUAB-CByVeKCY.js} +1 -1
  96. package/payload/server/public/assets/{chunk-4TB4RGXK-BnqJ0bDc.js → chunk-4TB4RGXK-CpY0DcUB.js} +1 -1
  97. package/payload/server/public/assets/{chunk-55IACEB6-BwyHvvzo.js → chunk-55IACEB6-C3YxgyIb.js} +1 -1
  98. package/payload/server/public/assets/{chunk-5FUZZQ4R-DXA9U02I.js → chunk-5FUZZQ4R-Bc0d7j8A.js} +1 -1
  99. package/payload/server/public/assets/{chunk-5PVQY5BW-D78bZ_8D.js → chunk-5PVQY5BW-CTUGMRIa.js} +1 -1
  100. package/payload/server/public/assets/{chunk-67CJDMHE-CtE_Mgv7.js → chunk-67CJDMHE-CbdPnpLd.js} +1 -1
  101. package/payload/server/public/assets/{chunk-7N4EOEYR-CUZDaySl.js → chunk-7N4EOEYR-Cjl2kevz.js} +1 -1
  102. package/payload/server/public/assets/{chunk-AA7GKIK3-CYQ3jO4X.js → chunk-AA7GKIK3-BgozIh5p.js} +1 -1
  103. package/payload/server/public/assets/{chunk-BSJP7CBP-BbA_HyTR.js → chunk-BSJP7CBP-6Ufq45NW.js} +1 -1
  104. package/payload/server/public/assets/{chunk-CIAEETIT-D7_YqRhG.js → chunk-CIAEETIT-BhhYuMnA.js} +1 -1
  105. package/payload/server/public/assets/{chunk-EDXVE4YY-B23LrtSw.js → chunk-EDXVE4YY-BfaJ3yDD.js} +1 -1
  106. package/payload/server/public/assets/{chunk-ENJZ2VHE-D3fTHYKN.js → chunk-ENJZ2VHE-C7-hIGVC.js} +1 -1
  107. package/payload/server/public/assets/{chunk-FMBD7UC4-DFAA2tyh.js → chunk-FMBD7UC4-BQvvyocF.js} +1 -1
  108. package/payload/server/public/assets/{chunk-FOC6F5B3-BF4IHvlI.js → chunk-FOC6F5B3-C6rBDOxH.js} +1 -1
  109. package/payload/server/public/assets/{chunk-ICPOFSXX-DBUGemHy.js → chunk-ICPOFSXX-BjOJvkVa.js} +2 -2
  110. package/payload/server/public/assets/{chunk-K5T4RW27-rMMs08Eh.js → chunk-K5T4RW27-kKowRHhn.js} +1 -1
  111. package/payload/server/public/assets/{chunk-KGLVRYIC-BD2r8R2G.js → chunk-KGLVRYIC-bAEV_5eH.js} +1 -1
  112. package/payload/server/public/assets/{chunk-LIHQZDEY-D4sYTTwM.js → chunk-LIHQZDEY-BLvsQAfg.js} +1 -1
  113. package/payload/server/public/assets/{chunk-ORNJ4GCN-CAs_uFzb.js → chunk-ORNJ4GCN-BzYZfPZ7.js} +1 -1
  114. package/payload/server/public/assets/{chunk-OYMX7WX6-Fkp-2ORc.js → chunk-OYMX7WX6-CL7WRw42.js} +1 -1
  115. package/payload/server/public/assets/chunk-QZHKN3VN-8tHoEDE9.js +1 -0
  116. package/payload/server/public/assets/{chunk-U2HBQHQK-D_pxZh25.js → chunk-U2HBQHQK-BdcVGjau.js} +1 -1
  117. package/payload/server/public/assets/{chunk-X2U36JSP-CeVmvvRf.js → chunk-X2U36JSP-C0CL_Jin.js} +1 -1
  118. package/payload/server/public/assets/{chunk-XPW4576I-iWP54fKp.js → chunk-XPW4576I-CsV7CUxH.js} +1 -1
  119. package/payload/server/public/assets/{chunk-YZCP3GAM-CNtbWJNN.js → chunk-YZCP3GAM-Cj0_fLkR.js} +1 -1
  120. package/payload/server/public/assets/{chunk-ZZ45TVLE-BmlFjU_9.js → chunk-ZZ45TVLE-DLuquyoY.js} +1 -1
  121. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BEGZ3DLg.js +1 -0
  122. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DsLxnm5U.js +1 -0
  123. package/payload/server/public/assets/clone-uiXbH_kh.js +1 -0
  124. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-C7YmF1Pg.js → cose-bilkent-S5V4N54A-BU3EOLXX.js} +1 -1
  125. package/payload/server/public/assets/{dagre-BAmiDDtR.js → dagre-BRq8C9NU.js} +1 -1
  126. package/payload/server/public/assets/{dagre-KV5264BT-Ca3ESJhc.js → dagre-KV5264BT-CoCAYhFc.js} +1 -1
  127. package/payload/server/public/assets/data-CZKWSjEH.js +1 -0
  128. package/payload/server/public/assets/{diagram-5BDNPKRD-BgT1ORf2.js → diagram-5BDNPKRD-DBy5GNaQ.js} +1 -1
  129. package/payload/server/public/assets/{diagram-G4DWMVQ6-BTaUIiem.js → diagram-G4DWMVQ6-l93MsBLv.js} +1 -1
  130. package/payload/server/public/assets/{diagram-MMDJMWI5-Bdb2g6Uo.js → diagram-MMDJMWI5-BIfXkVlL.js} +1 -1
  131. package/payload/server/public/assets/{diagram-TYMM5635-CkLGC0zZ.js → diagram-TYMM5635-BuTJLBny.js} +1 -1
  132. package/payload/server/public/assets/{dist-Bkbhs3jw.js → dist-CtUNt3w8.js} +1 -1
  133. package/payload/server/public/assets/{erDiagram-SMLLAGMA-D_sj4DMg.js → erDiagram-SMLLAGMA-BwPxWDbP.js} +1 -1
  134. package/payload/server/public/assets/{flatten-E2Sr0FeD.js → flatten-DtM0XAMt.js} +1 -1
  135. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-iLERoZTe.js → flowDiagram-DWJPFMVM-BhPtHXMR.js} +1 -1
  136. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-D60hjMBy.js → ganttDiagram-T4ZO3ILL-BlXjprdD.js} +1 -1
  137. package/payload/server/public/assets/gitGraph-7Q5UKJZL-D_2KrZoP.js +1 -0
  138. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-Di0XM6fi.js → gitGraphDiagram-UUTBAWPF-BW36BDiu.js} +1 -1
  139. package/payload/server/public/assets/{graph-Bnsvbnkf.js → graph-BxErrIf_.js} +3 -3
  140. package/payload/server/public/assets/{graph-labels-jduMtwXb.js → graph-labels-Ch5_g_JF.js} +1 -1
  141. package/payload/server/public/assets/{graphlib-C8fUP7uV.js → graphlib-Bjg3Tq-k.js} +1 -1
  142. package/payload/server/public/assets/info-OMHHGYJF-BP2TNwQ4.js +1 -0
  143. package/payload/server/public/assets/infoDiagram-42DDH7IO-D1kDtBOY.js +2 -0
  144. package/payload/server/public/assets/{isEmpty-CLz-UprQ.js → isEmpty-D__iH1WQ.js} +1 -1
  145. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CwgI4B5Z.js → ishikawaDiagram-UXIWVN3A-CmB-bA_O.js} +1 -1
  146. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CxBu-tze.js → journeyDiagram-VCZTEJTY-Bt1fJKmc.js} +1 -1
  147. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-D2qlheA5.js → kanban-definition-6JOO6SKY-DVbksz_J.js} +1 -1
  148. package/payload/server/public/assets/{line-Bdod7uzQ.js → line-BX2Ugx3B.js} +1 -1
  149. package/payload/server/public/assets/{linear-BiVe6QzC.js → linear-Bdc-QJWI.js} +1 -1
  150. package/payload/server/public/assets/{mermaid-parser.core-xZN7hC6M.js → mermaid-parser.core-qv1e-J5x.js} +2 -2
  151. package/payload/server/public/assets/{mermaid.core-D0IylAac.js → mermaid.core-C_d9YQX_.js} +3 -3
  152. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-J_Szhwf1.js → mindmap-definition-QFDTVHPH-DwKGvF14.js} +1 -1
  153. package/payload/server/public/assets/operator-CdlBsCdn.js +1 -0
  154. package/payload/server/public/assets/{ordinal-5RtyPJVt.js → ordinal-BRQ5CzZY.js} +1 -1
  155. package/payload/server/public/assets/packet-4T2RLAQJ-BDg8fde8.js +1 -0
  156. package/payload/server/public/assets/{page-BT9hkXHm.js → page-DzsVxvM6.js} +3 -3
  157. package/payload/server/public/assets/pie-ZZUOXDRM-CXDyYMkZ.js +1 -0
  158. package/payload/server/public/assets/{pieDiagram-DEJITSTG-CV5DxUVx.js → pieDiagram-DEJITSTG-dUvQC_4S.js} +1 -1
  159. package/payload/server/public/assets/{public-DvL1Zov1.js → public-BzVhn2va.js} +1 -1
  160. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BsFMVizF.js → quadrantDiagram-34T5L4WZ-CebX_oPa.js} +1 -1
  161. package/payload/server/public/assets/radar-PYXPWWZC-xen_zv8F.js +1 -0
  162. package/payload/server/public/assets/{reduce-B3Mw_0s1.js → reduce-CkcXOmmJ.js} +1 -1
  163. package/payload/server/public/assets/{requirementDiagram-MS252O5E-C5eRRvGc.js → requirementDiagram-MS252O5E-h2euIqGj.js} +1 -1
  164. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-CJYv5gpw.js → sankeyDiagram-XADWPNL6-DCii3fkF.js} +1 -1
  165. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-B25563_2.js → sequenceDiagram-FGHM5R23-CQSGYmlq.js} +1 -1
  166. package/payload/server/public/assets/{src-BKOAoFQc.js → src-48kCpScq.js} +1 -1
  167. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-BLyNJYOA.js → stateDiagram-FHFEXIEX-CVtU0iXH.js} +1 -1
  168. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BywcXjtb.js +1 -0
  169. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-D-HgOM6Q.js → timeline-definition-GMOUNBTQ-ChvsBltI.js} +1 -1
  170. package/payload/server/public/assets/treeView-SZITEDCU-2FBf_1It.js +1 -0
  171. package/payload/server/public/assets/treemap-W4RFUUIX-BDdb30P-.js +1 -0
  172. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-Cw1JElYp.js → vennDiagram-DHZGUBPP-e-EZiiba.js} +1 -1
  173. package/payload/server/public/assets/wardley-RL74JXVD-BLq5MxjR.js +1 -0
  174. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-BqMWzEko.js → wardleyDiagram-NUSXRM2D-4JaRn1s5.js} +1 -1
  175. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-DBp71TLT.js → xychartDiagram-5P7HB3ND-kxwmCNuM.js} +1 -1
  176. package/payload/server/public/brand/maxy-app-icon-192.png +0 -0
  177. package/payload/server/public/brand/maxy-app-icon-512.png +0 -0
  178. package/payload/server/public/brand/maxy-app-icon-maskable-512.png +0 -0
  179. package/payload/server/public/browser.html +5 -5
  180. package/payload/server/public/calendar.html +17 -0
  181. package/payload/server/public/chat.html +8 -8
  182. package/payload/server/public/data.html +5 -5
  183. package/payload/server/public/graph.html +7 -7
  184. package/payload/server/public/index.html +8 -8
  185. package/payload/server/public/operator.html +10 -10
  186. package/payload/server/public/public.html +8 -8
  187. package/payload/server/server.js +623 -190
  188. package/payload/server/public/assets/AdminShell-CHZMDX2u.js +0 -1
  189. package/payload/server/public/assets/OperatorConversations-DpjPPIOp.js +0 -9
  190. package/payload/server/public/assets/admin-DIDvfti6.js +0 -1
  191. package/payload/server/public/assets/architecture-YZFGNWBL-DN-MYxff.js +0 -1
  192. package/payload/server/public/assets/channel-y27xl53N.js +0 -1
  193. package/payload/server/public/assets/chat-C0IWx7FL.js +0 -1
  194. package/payload/server/public/assets/chunk-426QAEUC-D8Iwaegm.js +0 -1
  195. package/payload/server/public/assets/chunk-QZHKN3VN-qHqDpwz3.js +0 -1
  196. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DgVoYWhO.js +0 -1
  197. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-C0WNP3uN.js +0 -1
  198. package/payload/server/public/assets/clone-D50F_pvg.js +0 -1
  199. package/payload/server/public/assets/data-RsMye_06.js +0 -1
  200. package/payload/server/public/assets/gitGraph-7Q5UKJZL-D-L2yzYf.js +0 -1
  201. package/payload/server/public/assets/info-OMHHGYJF-BQn6jndO.js +0 -1
  202. package/payload/server/public/assets/infoDiagram-42DDH7IO-BwMdbiXg.js +0 -2
  203. package/payload/server/public/assets/operator-9K-TElDd.js +0 -1
  204. package/payload/server/public/assets/packet-4T2RLAQJ-DmkQBx4h.js +0 -1
  205. package/payload/server/public/assets/pie-ZZUOXDRM-DDnxYUBm.js +0 -1
  206. package/payload/server/public/assets/radar-PYXPWWZC-7H4k0ChM.js +0 -1
  207. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BSVuxZxz.js +0 -1
  208. package/payload/server/public/assets/treeView-SZITEDCU-BLXWTQtW.js +0 -1
  209. package/payload/server/public/assets/treemap-W4RFUUIX-DiePDF5d.js +0 -1
  210. package/payload/server/public/assets/wardley-RL74JXVD-OSUWK5LN.js +0 -1
  211. /package/payload/server/public/assets/{_baseFor-DVaNaTfF.js → _baseFor-SRtUHe7G.js} +0 -0
  212. /package/payload/server/public/assets/{admin-types-CJrGd46U.js → admin-types-Dg11L4MQ.js} +0 -0
  213. /package/payload/server/public/assets/{array-8_H1156C.js → array-BpsnM-Py.js} +0 -0
  214. /package/payload/server/public/assets/{chunk-Pqm5yXtL.js → chunk-CAM3fms7.js} +0 -0
  215. /package/payload/server/public/assets/{cytoscape.esm-h10p_6j-.js → cytoscape.esm-D4Rl1H5h.js} +0 -0
  216. /package/payload/server/public/assets/{defaultLocale-pD7tFa1r.js → defaultLocale-C7sQPl-O.js} +0 -0
  217. /package/payload/server/public/assets/{init-CwJ4b81e.js → init-BydxaDEV.js} +0 -0
  218. /package/payload/server/public/assets/{katex-DJPjIBAI.js → katex-B0fVeDx4.js} +0 -0
  219. /package/payload/server/public/assets/{path-CK8wrAxY.js → path-jlWYQ2i9.js} +0 -0
  220. /package/payload/server/public/assets/{preload-helper-Bf_JiD2A.js → preload-helper-uTix4PVD.js} +0 -0
  221. /package/payload/server/public/assets/{rough.esm-Dwml_la6.js → rough.esm-c4PR5shF.js} +0 -0
@@ -0,0 +1,15 @@
1
+ export type AdminHostnameSource = "cloudflared-config.yml";
2
+ export interface AdminHostnameHit {
3
+ hostname: string;
4
+ isApex: boolean;
5
+ source: AdminHostnameSource;
6
+ }
7
+ export interface AdminHostnameMiss {
8
+ hostname: null;
9
+ isApex: null;
10
+ source: null;
11
+ reason: "no-admin-host";
12
+ }
13
+ export type AdminHostnameResult = AdminHostnameHit | AdminHostnameMiss;
14
+ export declare function resolveAdminHostname(configDir: string): AdminHostnameResult;
15
+ //# sourceMappingURL=admin-hostname.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-hostname.d.ts","sourceRoot":"","sources":["../../src/lib/admin-hostname.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,mBAAmB,GAAG,wBAAwB,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,IAAI,CAAC;IACf,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAuDvE,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,CAU3E"}
@@ -0,0 +1,86 @@
1
+ // admin-hostname resolver — the admin-host twin of public-hostname.ts.
2
+ //
3
+ // Where public-hostname returns the operator's public-facing host, this
4
+ // returns the admin host: the surface that serves /calendar and the rest of
5
+ // the admin shell behind sign-in. The two are different hosts, often on
6
+ // different base domains (public `maxy.chat`, admin `admin.maxy.bot`), so the
7
+ // admin host can never be string-derived from the public one. It is read from
8
+ // the same files cloudflared and platform/ui/server already trust to route.
9
+ //
10
+ // The admin host is defined exactly as classifyHost() defines it in
11
+ // platform/ui/server/public-host-gate.ts: the ingress hostname that routes to
12
+ // the brand UI over http and is neither public (public. prefix or an
13
+ // alias-domains.json entry) nor operator (an operator-domains.json entry).
14
+ // Only http:// ingress rules are considered, so ssh:// and tcp:// rows (off-LAN
15
+ // SSH/SMB) can never be mistaken for the admin host. When more than one
16
+ // admin-class host exists, the first in file order wins — admin is listed
17
+ // first by every documented config.
18
+ import { existsSync, readFileSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ function isExcluded(host) {
21
+ return host === "localhost" || host.endsWith(".local");
22
+ }
23
+ // Apex = single domain (e.g. "maxy.bot"), with optional `www.` prefix stripped.
24
+ function isApex(host) {
25
+ const stripped = host.startsWith("www.") ? host.slice(4) : host;
26
+ return stripped.split(".").length === 2;
27
+ }
28
+ // Read the ingress hostnames whose service is an http:// URL — the brand UI
29
+ // surfaces. cloudflared writes each rule as a `- hostname:` line followed by a
30
+ // `service:` line; the catch-all `- service: http_status:404` carries no
31
+ // hostname. ssh:// and tcp:// rows are dropped here so they never reach the
32
+ // admin-class filter.
33
+ function readUiIngressHostnames(configDir) {
34
+ const path = join(configDir, "cloudflared", "config.yml");
35
+ if (!existsSync(path))
36
+ return [];
37
+ let yaml;
38
+ try {
39
+ yaml = readFileSync(path, "utf-8");
40
+ }
41
+ catch {
42
+ return [];
43
+ }
44
+ const hosts = [];
45
+ let pendingHost = null;
46
+ for (const line of yaml.split("\n")) {
47
+ const hostMatch = line.match(/^\s*-\s*hostname:\s*(\S+)/);
48
+ if (hostMatch) {
49
+ pendingHost = hostMatch[1];
50
+ continue;
51
+ }
52
+ const serviceMatch = line.match(/^\s*service:\s*(\S+)/);
53
+ if (serviceMatch && pendingHost) {
54
+ if (serviceMatch[1].startsWith("http://"))
55
+ hosts.push(pendingHost);
56
+ pendingHost = null;
57
+ }
58
+ }
59
+ return hosts.filter((h) => !isExcluded(h));
60
+ }
61
+ function readStringArray(configDir, file) {
62
+ const path = join(configDir, file);
63
+ if (!existsSync(path))
64
+ return new Set();
65
+ try {
66
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
67
+ if (!Array.isArray(parsed))
68
+ return new Set();
69
+ return new Set(parsed.filter((h) => typeof h === "string" && h.length > 0));
70
+ }
71
+ catch {
72
+ return new Set();
73
+ }
74
+ }
75
+ export function resolveAdminHostname(configDir) {
76
+ const uiHosts = readUiIngressHostnames(configDir);
77
+ const alias = readStringArray(configDir, "alias-domains.json");
78
+ const operator = readStringArray(configDir, "operator-domains.json");
79
+ const isPublic = (h) => h.startsWith("public.") || alias.has(h);
80
+ const chosen = uiHosts.find((h) => !isPublic(h) && !operator.has(h));
81
+ if (chosen !== undefined) {
82
+ return { hostname: chosen, isApex: isApex(chosen), source: "cloudflared-config.yml" };
83
+ }
84
+ return { hostname: null, isApex: null, source: null, reason: "no-admin-host" };
85
+ }
86
+ //# sourceMappingURL=admin-hostname.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-hostname.js","sourceRoot":"","sources":["../../src/lib/admin-hostname.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Maxy 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:7276f9a571c11e5350ab9a29cdc60f6416f4f0b685f58679217efff1b53413e9
4
+ content-hash: sha256:08b7c50d9eb3edfd9739f7ab91977b7fd28aacdfc0024d1fad41ddd067f8cdc5
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -1880,6 +1880,67 @@ A QuickBooks connection goes stale if it sits unused for about 100 days, or if y
1880
1880
 
1881
1881
  Switching your Intuit app from sandbox to production requires passing Intuit's own production security review. That is between you and Intuit; it is not something the agent does for you.
1882
1882
 
1883
+ ---
1884
+ # Calendar and Booking
1885
+ Source: https://docs.getmaxy.com/calendar-booking.md
1886
+
1887
+ # Calendar and booking
1888
+
1889
+ Maxy gives you a calendar of your schedule and a public page where people can book time with you. The calendar and the booking page are two sides of the same data: a booking someone makes shows up on your calendar straight away.
1890
+
1891
+ ## The admin calendar
1892
+
1893
+ Open `/calendar` on your Maxy address (the same sign-in as the dashboard). It shows your schedule in four views:
1894
+
1895
+ - **Day** and **Week** show an hour grid with each timed entry as a block.
1896
+ - **Month** shows the familiar month grid with a few entries per day.
1897
+ - **Year** shows twelve small months; days with something on them carry a dot, and clicking a month opens it.
1898
+
1899
+ 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 Maxy schedules for you in chat, and tasks that have a due date (shown on their day). The view is read-only: it shows your schedule, it does not create or edit it.
1900
+
1901
+ Everything on the calendar comes from records the rest of Maxy already uses, scoped to your account.
1902
+
1903
+ ## The public booking page
1904
+
1905
+ The booking page is a separate, public site on its own web address (for example `book.yourdomain.com`). A visitor sees only open time slots, never the titles or details of your existing meetings. They pick a slot, enter their name, email, and an optional note, and submit. That is the whole flow, like a simple Calendly.
1906
+
1907
+ The page is hosted on Cloudflare so it keeps working and keeps taking bookings even if your Maxy device is briefly offline. Each submission is stored safely at the edge first, then turned into a meeting on your calendar shortly after.
1908
+
1909
+ ## Putting the booking page live
1910
+
1911
+ Ask the admin to run the **calendar-site** skill ("put up a booking link" or "deploy the booking site"). It will ask for:
1912
+
1913
+ - your **time zone**,
1914
+ - the **meeting length** (for example 30 minutes),
1915
+ - a **buffer** between meetings (for example 10 minutes),
1916
+ - your **weekly availability** (which days and hours you take bookings),
1917
+ - the **web address** the booking page should use.
1918
+
1919
+ It writes those settings, builds the page, puts it live on that address, and checks that a test booking is captured. To change your availability later, run the same skill again with the new numbers.
1920
+
1921
+ ## How a booking becomes a meeting
1922
+
1923
+ 1. A visitor submits a booking on the public page.
1924
+ 2. The booking is saved immediately at the edge (so it is never lost).
1925
+ 3. Your Maxy device picks it up on a short cycle, creates a `:Meeting` for it, and links the visitor as a contact.
1926
+ 4. You are notified by email (and by WhatsApp only if you already have a thread with the agent; it never starts a new WhatsApp conversation).
1927
+ 5. The new meeting appears on your `/calendar`.
1928
+
1929
+ This usually completes within a couple of minutes of the booking.
1930
+
1931
+ ## If a booking does not show up
1932
+
1933
+ Bookings are reconciled on a cycle and the system audits itself each run. In the device logs:
1934
+
1935
+ - `[calendar-booking]` lines trace one booking through submit, write, notify, and done.
1936
+ - `[calendar-reconcile]` lines report two health numbers per account: `pendingUnreconciled` (bookings captured but not yet turned into meetings) and `orphanMeetings` (booking meetings with no matching saved booking).
1937
+
1938
+ A `pendingUnreconciled` number that stays above zero across several runs means the reconcile step is stuck and is worth investigating. To read them: `journalctl --user -u <brand-service> | grep -E '\[calendar-booking\]|\[calendar-reconcile\]'`, then filter by one booking id for its full story. The edge half of a booking (before your device sees it) is in the Cloudflare Pages function logs.
1939
+
1940
+ ## What this does not do
1941
+
1942
+ One meeting type only (one length, one weekly window, one buffer). No syncing to Google or iCloud calendars: your meetings in Maxy are the source of truth. No rescheduling or cancellation links, reminders, or visitor time-zone selection. The booking page shows availability live from your device, so while your device is offline the page can still take a booking but may not show fresh open times until it is back.
1943
+
1883
1944
  ---
1884
1945
  # LinkedIn Extension
1885
1946
  Source: https://docs.getmaxy.com/linkedin-extension.md
@@ -2650,6 +2711,32 @@ Two endpoints, two surfaces, two restart-survival roles:
2650
2711
  string. Hosted on `maxy-edge.service` so the Software Update modal
2651
2712
  can read it while the brand service is mid-restart.
2652
2713
 
2714
+ ## Installable PWA
2715
+
2716
+ The admin (`index.html`), operator (`operator.html`), and chat (`chat.html`)
2717
+ shells are installable. Each links its own webmanifest (`/manifest-admin`,
2718
+ `/manifest-operator`, `/manifest-chat`) whose `icons` declare an explicit
2719
+ `192x192` and `512x512` `any` entry plus a `512x512` `maskable` entry, and an
2720
+ `apple-touch-icon`. These all point at an **opaque, padded** app icon baked on a
2721
+ white tile — never the transparent brand mark, because iOS/macOS composite a
2722
+ transparent app icon onto black. The opaque icons ship per brand
2723
+ (`assets.appIcon` / `appIcon192` / `maskableIcon`); `manifest`
2724
+ `background_color` only paints the splash screen, so the tile background is
2725
+ baked into the PNG. The maskable variant carries a wider safe zone so Android's
2726
+ circular crop never clips the mark.
2727
+
2728
+ The sign-in page is installable too. The remote-auth gate redirects every
2729
+ unauthenticated request to it, so a fresh device installs from there; the page
2730
+ links the admin manifest and the opaque `apple-touch-icon` so the install adopts
2731
+ the brand name and icon instead of a monogram generated from the title. The
2732
+ sign-in page registers no service worker — only the authenticated shells do.
2733
+
2734
+ A boot census logs `[pwa-census] surfaces=3 manifest-linked=3 icons-present=3`
2735
+ when every shell links its manifest and the app-icon files are present; a missing
2736
+ or mis-named icon asset shows `icons-present<3`, and a dropped head injection
2737
+ shows `manifest-linked<3`. The graph, data, and browser shells are intentionally
2738
+ non-installable.
2739
+
2653
2740
  ## Related references
2654
2741
 
2655
2742
  - [`platform.md`](platform.md) — UI layout, session reconcile model,
@@ -3253,6 +3340,8 @@ Maxy hosts a generic per-account static-tree publish surface at `https://public.
3253
3340
 
3254
3341
  **Deterministic public-hostname surface.** The `<public-host>` half of the URL the operator pastes is resolved by the `mcp__plugin_admin_admin__public-hostname` MCP tool. It reads `<configDir>/cloudflared/config.yml` (ingress list) then falls back to `<configDir>/alias-domains.json` — the same two files `cloudflared` and `platform/ui/server/index.ts`'s `isPublicHost()` already trust to route. Returns `{hostname, isApex, source}` on hit (`source` is `"cloudflared-config.yml"` or `"alias-domains.json"`), or `{hostname:null, source:null, reason:"no-tunnel"}` on miss. Tiebreak: apex wins over subdomain (single-label, or `www.<apex>` stripped). `publish-site` step 6 calls it after the move and emits the full URL (`https://<hostname><path-slug>`) in the same turn. Graph queries are no longer involved — any earlier graph-backed resolver returned `(none)` on accounts bootstrapped without `cloudflare-task-tracker.ts` writes (laptop Real Agent, manual `cloudflared` setup), the `llm-framing-deterministic` recurrence class. The graph-mcp shim additionally runs a sequential envelope-warning probe on every read response — when Neo4j emits `gql_status` codes matching `^0[12]N5\d$` (e.g. `01N52` "property does not exist"), the shim stitches them into a prefix content block on the response so property-name misses surface to the agent inline instead of returning silent `[]`. Probe failure is best-effort: the upstream response forwards unchanged with `[mcp:graph] probe-error`.
3255
3342
 
3343
+ **Deterministic admin-hostname surface.** The admin shell — `/calendar` and every other authenticated route — is served only on the admin host, never the public host (`/calendar` returns `404 Not found` on a public host). The `mcp__plugin_admin_admin__admin-hostname` MCP tool is the admin-host twin of `public-hostname`: it resolves the host an operator should be pointed at for an admin-surface URL. It reads `<configDir>/cloudflared/config.yml` ingress, keeps only rules whose `service:` is an `http://` URL (so `ssh://`/`tcp://` off-LAN rows are excluded), and returns the first such hostname that is neither public (`public.` prefix or a `<configDir>/alias-domains.json` entry) nor operator (a `<configDir>/operator-domains.json` entry) — exactly the admin class of `classifyHost()` in `platform/ui/server/public-host-gate.ts`. Returns `{hostname, isApex, source:"cloudflared-config.yml"}` on hit, or `{hostname:null, source:null, reason:"no-admin-host"}` on miss. The admin host is often a different base domain from the public host (public `maxy.chat`, admin `admin.maxy.bot`), so it can never be string-derived from the public one — the `calendar-site` skill calls this tool to surface the admin `/calendar` link instead of guessing.
3344
+
3256
3345
  ### Cross-tab session rotation
3257
3346
 
3258
3347
  When you click "New conversation" in the chat tab, Maxy mints a fresh admin session key on the server and clears the old one. Sibling admin tabs (`/graph`, `/data`) opened in the same browser keep working without re-login: the chat tab broadcasts the new key on a same-origin channel so each sibling tab updates its captured key instantly, and any in-flight admin request that 401s with the rotation-orphan code retries once after re-reading the latest key from per-tab storage. If neither path recovers (browser locked down, second 401 after retry, session expired), the tab shows a single banner — "Your admin session was renewed in another tab. Click to reload." — and one click sends you back through login. No silent 401s; no re-clicking through the same trash icon hoping it sticks. See `.docs/web-chat.md` "Cross-tab rotation contract" for the wire-level `code` taxonomy and observability surfaces.
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: calendar-site
3
+ description: Stand up a public "book time with me" page on a custom domain, backed by the account calendar. This is the skill behind "give me a booking link", "put up a Calendly-style page", "let people book a call with me", "deploy the booking site", and "set my availability for bookings". It writes the account availability window (one duration, one weekly window, one buffer), assembles the booking page plus its D1 capture into the canonical Pages tree, provisions the D1 bookings table, deploys to Cloudflare Pages via the site-deploy skill on the booking domain, and gates done on a live booking page whose open slots load from the brand tunnel and whose test submission lands in D1. The admin calendar that shows the resulting meetings is served separately at /calendar on the admin host (resolve it with the admin-hostname tool, never the public host, which 404s /calendar) and needs no deploy. Admin-run; holds Bash and the account secrets surface.
4
+ ---
5
+
6
+ # Stand up a calendar booking site
7
+
8
+ Run by the admin/main session, the surface that holds `Bash` and reads the account secrets file. This skill composes `cloudflare:site-deploy` for the Pages deploy and adds the two things a booking site needs that a plain landing page does not: the account availability config the platform reads to compute open slots, and a `bookings` D1 table written by the booking page rather than a contact form.
9
+
10
+ This is an outcome contract, not a copy of the Pages mechanics. The deploy, custom-domain attach, token discipline, and live done-gate are owned by `site-deploy`; read it with `plugin-read` before deploying. The D1 mechanics live in `references/d1-data-capture.md` and the token discipline in `references/api.md`; read those before issuing their commands.
11
+
12
+ ## What this skill produces, and what it does not
13
+
14
+ - It produces the **public booking page** on a custom domain (the booking domain), backed by a D1 `bookings` table.
15
+ - It writes the **availability config** the platform free/busy endpoint reads.
16
+ - It does **not** deploy the admin calendar. The four-view admin calendar (Day, Week, Month, Year) is served by the install itself at `https://<admin-host>/calendar`, behind the existing admin sign-in. The `<admin-host>` is **not** the public host; `/calendar` 404s on the public host. Resolve the admin host with the `admin-hostname` tool (the admin-host twin of `public-hostname`; it reads the cloudflared ingress and returns the host that is neither public nor operator), then point the operator at `https://<admin-host>/calendar` once the booking site is live. There is nothing to deploy for it.
17
+
18
+ ## The two routes and why only one is deployed
19
+
20
+ A booking visitor and the admin look at the booking from opposite sides — the visitor sees only free/busy, the admin sees the booked meeting in full alongside the rest of their schedule:
21
+
22
+ | Surface | Where it lives | Gate | Reads |
23
+ |---|---|---|---|
24
+ | Admin calendar (4 views) | the install, at `/calendar` on the admin host (resolve via `admin-hostname`) | admin sign-in | every time-bound item for the account — booked and imported meetings, agent-scheduled appointments, and tasks with a due date |
25
+ | Public booking page | Cloudflare Pages, on the booking domain | open | free/busy only, never any meeting detail |
26
+
27
+ Only the public page is deployed here, because it must stay reachable and keep capturing bookings even when the install device is briefly offline. The admin calendar is dynamic, account-scoped, and authenticated, so it is served by the install over the tunnel and is same-origin with its data. Do not try to put the admin calendar on Pages.
28
+
29
+ ## Set the availability window first
30
+
31
+ The public page shows open slots computed as the weekly window minus busy `:Meeting` intervals minus a buffer. Those inputs live in one file the platform reads:
32
+
33
+ ```
34
+ <accountDir>/calendar-availability.json
35
+ ```
36
+
37
+ Collect from the operator, then write the file: the account `timezone` (IANA), the meeting `durationMins`, the `bufferMins` between meetings, and the `weekly` window as `{ mon: [["09:00","17:00"]], ... }` with an empty array for days that are closed. Add the `apiBase` (the brand tunnel origin that serves free/busy, `https://<brand-tunnel-domain>`), the `bookingDomain` (the custom domain the page will answer on), and `bookingDbName` (the D1 database name chosen below). Re-running this skill with new numbers is how availability is changed later; there is no separate editor.
38
+
39
+ ## Assemble the canonical tree
40
+
41
+ Copy the skill template into the one canonical Pages source path `site-deploy` expects:
42
+
43
+ ```
44
+ <accountDir>/pages/<project>/
45
+ ```
46
+
47
+ The template ships `public/index.html`, `public/booking.js`, `public/booking.css`, `functions/api/book.ts`, `wrangler.toml`, and `schema.sql`. Two substitutions make it concrete: set the `<meta name="api-base">` content in `public/index.html` to the `apiBase` value (the booking page fetches free/busy cross-origin from the brand tunnel), and fill `wrangler.toml`'s `__PROJECT_NAME__`, `__D1_DATABASE_NAME__`, and `__D1_DATABASE_ID__` from the project name and the database created below. Leave no `__...__` placeholder in the assembled tree.
48
+
49
+ ## Provision the D1 bookings table
50
+
51
+ This is a `bookings` table, not the `leads` table of a contact form, so the booking-specific schema ships with the template. Load the stable `<brand>-pages-d1` token from the account secrets file, minting it once only if absent and persisting it, exactly as `references/api.md` and `references/d1-data-capture.md` prescribe; the token needs both Pages Edit and D1 Edit. Create the database, record its id into `wrangler.toml`, and apply `schema.sql` to the remote database. The token is never written into the tree, never committed, never echoed.
52
+
53
+ ## Deploy through site-deploy
54
+
55
+ Hand the assembled tree to `cloudflare:site-deploy`: it builds nothing for a static tree, runs `wrangler pages deploy public --project-name <project> --branch=main`, attaches the booking domain (creating the DNS record with the `<brand>-dns` token when the attach leaves validation pending), and reuses the same per-scope token. Everything in `site-deploy`'s auth, custom-domain, and DNS guidance applies unchanged.
56
+
57
+ ## Done-gate
58
+
59
+ Done is a live behavioural signal on the booking domain, surfaced verbatim:
60
+
61
+ - The booking domain returns `HTTP/2 200` on a cache-busted request.
62
+ - The page's free/busy call succeeds: `curl` the brand tunnel free/busy endpoint and confirm it returns a `slots` array and carries no meeting title, description, or location field. A `404` here means availability was not written; a blocked or unauthenticated response means the free/busy path is not reachable on the brand host.
63
+
64
+ ```bash
65
+ curl -s "https://<brand-tunnel-domain>/api/calendar/free-busy?from=$(date -u +%Y-%m-%dT00:00:00Z)&to=$(date -u -v+14d +%Y-%m-%dT00:00:00Z)" | head -c 400
66
+ ```
67
+
68
+ - A test submission lands in D1 unswept, reusing the same token and database name already loaded:
69
+
70
+ ```bash
71
+ curl -sS -X POST -H 'content-type: application/json' \
72
+ -d '{"slotStart":"2026-01-01T09:00:00Z","slotEnd":"2026-01-01T09:30:00Z","name":"verify","email":"verify@example.com"}' \
73
+ "https://<booking-domain>/api/book" -i | head -1
74
+ CLOUDFLARE_API_TOKEN="${PAGES_D1}" wrangler d1 execute <db-name> --remote --command \
75
+ "SELECT bookingId FROM bookings WHERE swept = 0;"
76
+ ```
77
+
78
+ The install reconciles accepted rows into `:Meeting` nodes on its own interval, so the test submission will appear in the admin calendar at `/calendar` within a couple of minutes and can be removed there or left as proof. Tell the operator the booking link (the booking domain) and the admin calendar link (`https://<admin-host>/calendar`, with `<admin-host>` resolved via the `admin-hostname` tool, not the public host) in the result.
79
+
80
+ ## Tool discipline
81
+
82
+ The permitted surface is `wrangler`, `curl`, and the Cloudflare API via Bash following the cloudflare references, using the reused per-scope token. Do not mint a fresh token per deploy, do not drive the dashboard with a browser, do not synthesise `wrangler` flags from web search, and never write or echo a token. When a step fails, report the exact output with secrets redacted, name the failing URL or command, and stop.
@@ -0,0 +1,112 @@
1
+ // Booking capture Pages Function (calendar-site skill).
2
+ //
3
+ // Served at POST /api/book on the booking domain. Writes the submission
4
+ // straight to D1 so capture survives a brief Pi outage — the platform reconcile
5
+ // pass turns accepted rows into Neo4j :Meeting nodes later. Emits the
6
+ // [calendar-booking] submit + d1-write lifeline (Cloudflare Pages captures
7
+ // console output).
8
+ //
9
+ // The handler is split so its logic is verifiable without the Pages runtime:
10
+ // processBooking takes an injected DB + logger and returns the HTTP shape.
11
+
12
+ interface D1Result {
13
+ meta?: { changes?: number }
14
+ }
15
+ interface D1PreparedStatement {
16
+ bind: (...values: unknown[]) => D1PreparedStatement
17
+ run: () => Promise<D1Result>
18
+ }
19
+ interface D1Database {
20
+ prepare: (query: string) => D1PreparedStatement
21
+ }
22
+ interface BookingEnv {
23
+ DB: D1Database
24
+ }
25
+
26
+ interface BookingBody {
27
+ slotStart?: unknown
28
+ slotEnd?: unknown
29
+ name?: unknown
30
+ email?: unknown
31
+ note?: unknown
32
+ company?: unknown // honeypot — real users never fill this
33
+ }
34
+
35
+ type Logger = (line: string) => void
36
+
37
+ function isNonEmptyString(v: unknown): v is string {
38
+ return typeof v === 'string' && v.trim().length > 0
39
+ }
40
+
41
+ // Field caps so a malicious POST cannot store an unbounded blob in D1.
42
+ const MAX = { name: 200, email: 320, note: 2000, slot: 40 }
43
+
44
+ function isIsoTimestamp(v: unknown): v is string {
45
+ return typeof v === 'string' && v.length <= MAX.slot && !Number.isNaN(Date.parse(v))
46
+ }
47
+
48
+ export async function processBooking(
49
+ body: BookingBody,
50
+ env: BookingEnv,
51
+ log: Logger,
52
+ newId: () => string,
53
+ ): Promise<{ status: number; payload: Record<string, unknown> }> {
54
+ // Honeypot: a populated `company` field means a bot. Return ok (so the bot
55
+ // sees success) but write nothing.
56
+ if (isNonEmptyString(body.company)) {
57
+ return { status: 200, payload: { ok: true } }
58
+ }
59
+
60
+ if (
61
+ !isIsoTimestamp(body.slotStart) ||
62
+ !isIsoTimestamp(body.slotEnd) ||
63
+ !isNonEmptyString(body.name) ||
64
+ !isNonEmptyString(body.email)
65
+ ) {
66
+ return { status: 400, payload: { ok: false, error: 'name, email, and ISO slotStart/slotEnd are required' } }
67
+ }
68
+ if (body.name.length > MAX.name || body.email.length > MAX.email) {
69
+ return { status: 400, payload: { ok: false, error: 'name or email too long' } }
70
+ }
71
+
72
+ const bookingId = newId()
73
+ const note = isNonEmptyString(body.note) ? body.note.slice(0, MAX.note) : ''
74
+ const createdAt = new Date().toISOString()
75
+ log(`[calendar-booking] op=submit bookingId=${bookingId} slotStart=${body.slotStart} email=${body.email}`)
76
+
77
+ const result = await env.DB.prepare(
78
+ `INSERT INTO bookings (bookingId, slotStart, slotEnd, name, email, note, status, createdAt, swept)
79
+ VALUES (?, ?, ?, ?, ?, ?, 'accepted', ?, 0)`,
80
+ )
81
+ .bind(bookingId, body.slotStart, body.slotEnd, body.name, body.email, note, createdAt)
82
+ .run()
83
+
84
+ const rowsWritten = result.meta?.changes ?? 0
85
+ log(`[calendar-booking] op=d1-write bookingId=${bookingId} rowsWritten=${rowsWritten}`)
86
+
87
+ if (rowsWritten < 1) {
88
+ return { status: 500, payload: { ok: false, error: 'capture failed' } }
89
+ }
90
+ return { status: 200, payload: { ok: true, bookingId } }
91
+ }
92
+
93
+ interface PagesContext {
94
+ request: Request
95
+ env: BookingEnv
96
+ }
97
+
98
+ export async function onRequestPost(context: PagesContext): Promise<Response> {
99
+ let body: BookingBody
100
+ try {
101
+ body = (await context.request.json()) as BookingBody
102
+ } catch {
103
+ return Response.json({ ok: false, error: 'invalid JSON' }, { status: 400 })
104
+ }
105
+ const { status, payload } = await processBooking(
106
+ body,
107
+ context.env,
108
+ (line) => console.log(line),
109
+ () => crypto.randomUUID(),
110
+ )
111
+ return Response.json(payload, { status })
112
+ }
@@ -0,0 +1,100 @@
1
+ /* Public booking page (calendar-site skill). Clean single-column Calendly-style
2
+ layout. Self-contained — no shared tokens, since this ships to Cloudflare
3
+ Pages, not the admin shell. The skill may overlay brand colors. */
4
+ :root {
5
+ --bk-bg: #f6f6f4;
6
+ --bk-card: #ffffff;
7
+ --bk-ink: #1d1d1f;
8
+ --bk-muted: #6b6b70;
9
+ --bk-line: #e3e3e0;
10
+ --bk-accent: #4b6358;
11
+ --bk-accent-ink: #ffffff;
12
+ --bk-radius: 12px;
13
+ }
14
+
15
+ * { box-sizing: border-box; }
16
+
17
+ body {
18
+ margin: 0;
19
+ background: var(--bk-bg);
20
+ color: var(--bk-ink);
21
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
22
+ display: flex;
23
+ justify-content: center;
24
+ padding: 32px 16px;
25
+ }
26
+
27
+ .bk-card {
28
+ width: 100%;
29
+ max-width: 520px;
30
+ background: var(--bk-card);
31
+ border: 1px solid var(--bk-line);
32
+ border-radius: var(--bk-radius);
33
+ padding: 28px;
34
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
35
+ }
36
+
37
+ .bk-title { margin: 0 0 4px; font-size: 1.6rem; }
38
+ .bk-sub { margin: 0 0 20px; color: var(--bk-muted); }
39
+ .bk-status { margin: 8px 0; color: var(--bk-muted); }
40
+
41
+ .bk-day { margin-bottom: 20px; }
42
+ .bk-day-title { font-size: 0.95rem; margin: 0 0 8px; color: var(--bk-ink); }
43
+ .bk-day-slots { display: flex; flex-wrap: wrap; gap: 8px; }
44
+
45
+ .bk-slot {
46
+ border: 1px solid var(--bk-accent);
47
+ background: transparent;
48
+ color: var(--bk-accent);
49
+ border-radius: 8px;
50
+ padding: 8px 14px;
51
+ font-size: 0.9rem;
52
+ cursor: pointer;
53
+ }
54
+ .bk-slot:hover { background: var(--bk-accent); color: var(--bk-accent-ink); }
55
+
56
+ .bk-form { display: flex; flex-direction: column; gap: 14px; }
57
+ .bk-chosen { font-weight: 600; margin: 0 0 4px; }
58
+ .bk-label { display: flex; flex-direction: column; gap: 4px; font-size: 0.85rem; color: var(--bk-muted); }
59
+ .bk-input {
60
+ border: 1px solid var(--bk-line);
61
+ border-radius: 8px;
62
+ padding: 10px 12px;
63
+ font-size: 1rem;
64
+ color: var(--bk-ink);
65
+ font-family: inherit;
66
+ }
67
+ .bk-input:focus { outline: 2px solid var(--bk-accent); border-color: var(--bk-accent); }
68
+
69
+ /* honeypot — visually and from the layout removed, still in the DOM for bots */
70
+ .bk-hp {
71
+ position: absolute;
72
+ left: -9999px;
73
+ width: 1px;
74
+ height: 1px;
75
+ opacity: 0;
76
+ }
77
+
78
+ .bk-actions { display: flex; justify-content: space-between; gap: 12px; margin-top: 4px; }
79
+ .bk-back {
80
+ background: transparent;
81
+ border: 1px solid var(--bk-line);
82
+ border-radius: 8px;
83
+ padding: 10px 16px;
84
+ cursor: pointer;
85
+ color: var(--bk-muted);
86
+ }
87
+ .bk-submit {
88
+ background: var(--bk-accent);
89
+ color: var(--bk-accent-ink);
90
+ border: none;
91
+ border-radius: 8px;
92
+ padding: 10px 20px;
93
+ font-size: 1rem;
94
+ cursor: pointer;
95
+ }
96
+ .bk-submit:disabled { opacity: 0.6; cursor: default; }
97
+
98
+ .bk-done { text-align: center; padding: 16px 0; }
99
+ .bk-done-title { margin: 0 0 8px; font-size: 1.3rem; }
100
+ .bk-done-msg { color: var(--bk-muted); margin: 0; }