@rubytech/create-maxy-code 0.1.357 → 0.1.359

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 (260) hide show
  1. package/dist/__tests__/claude-ptys-slice.test.js +36 -1
  2. package/dist/__tests__/neo4j-pidfile-scrub.test.js +103 -0
  3. package/dist/index.js +42 -7
  4. package/dist/neo4j-pidfile-scrub.js +90 -0
  5. package/dist/port-resolution.js +18 -1
  6. package/package.json +1 -1
  7. package/payload/platform/package-lock.json +237 -0
  8. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js +79 -1
  9. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js.map +1 -1
  10. package/payload/platform/plugins/admin/mcp/dist/index.js +17 -3
  11. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  12. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts +16 -0
  13. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js +52 -0
  15. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js.map +1 -1
  16. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +61 -1
  17. package/payload/platform/plugins/cloudflare/PLUGIN.md +7 -1
  18. package/payload/platform/plugins/cloudflare/bin/__tests__/cf-token.test.sh +195 -0
  19. package/payload/platform/plugins/cloudflare/bin/cf-token.sh +157 -0
  20. package/payload/platform/plugins/cloudflare/references/api.md +2 -0
  21. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +14 -0
  22. package/payload/platform/plugins/cloudflare/skills/site-deploy/SKILL.md +10 -1
  23. package/payload/platform/plugins/docs/PLUGIN.md +2 -0
  24. package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
  25. package/payload/platform/plugins/docs/references/claudeai-connectors.md +45 -0
  26. package/payload/platform/plugins/docs/references/cloudflare.md +6 -0
  27. package/payload/platform/plugins/docs/references/troubleshooting.md +2 -0
  28. package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
  29. package/payload/platform/plugins/email/PLUGIN.md +7 -3
  30. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.d.ts +2 -0
  31. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.d.ts.map +1 -0
  32. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.js +99 -0
  33. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.js.map +1 -0
  34. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.d.ts +2 -0
  35. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.d.ts.map +1 -0
  36. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.js +32 -0
  37. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.js.map +1 -0
  38. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js +64 -6
  39. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js.map +1 -1
  40. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js +12 -0
  41. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js.map +1 -1
  42. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.d.ts +2 -0
  43. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.d.ts.map +1 -0
  44. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.js +58 -0
  45. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.js.map +1 -0
  46. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +94 -9
  47. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
  48. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js +109 -1
  49. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js.map +1 -1
  50. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js +4 -0
  51. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js.map +1 -1
  52. package/payload/platform/plugins/email/mcp/dist/index.js +39 -2
  53. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  54. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts +5 -0
  55. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts.map +1 -1
  56. package/payload/platform/plugins/email/mcp/dist/lib/compose.js +8 -1
  57. package/payload/platform/plugins/email/mcp/dist/lib/compose.js.map +1 -1
  58. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +13 -0
  59. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -1
  60. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +35 -0
  61. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -1
  62. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +83 -30
  63. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  64. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +327 -112
  65. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  66. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts +19 -0
  67. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts.map +1 -1
  68. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js +33 -0
  69. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js.map +1 -1
  70. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +6 -0
  71. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
  72. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +4 -0
  73. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
  74. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts +8 -1
  75. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts.map +1 -1
  76. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js +10 -6
  77. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js.map +1 -1
  78. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts.map +1 -1
  79. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js +4 -2
  80. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js.map +1 -1
  81. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.d.ts +15 -0
  82. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.d.ts.map +1 -0
  83. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.js +29 -0
  84. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.js.map +1 -0
  85. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  86. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +11 -1
  87. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  88. package/payload/platform/plugins/email/mcp/dist/tools/email-status.d.ts.map +1 -1
  89. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js +24 -1
  90. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js.map +1 -1
  91. package/payload/platform/plugins/email/mcp/package.json +2 -0
  92. package/payload/platform/plugins/email/references/email-reference.md +30 -3
  93. package/payload/platform/scripts/rss-sampler.sh +21 -0
  94. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  95. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  96. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  97. package/payload/platform/services/claude-session-manager/dist/connector-auth.d.ts +31 -0
  98. package/payload/platform/services/claude-session-manager/dist/connector-auth.d.ts.map +1 -0
  99. package/payload/platform/services/claude-session-manager/dist/connector-auth.js +49 -0
  100. package/payload/platform/services/claude-session-manager/dist/connector-auth.js.map +1 -0
  101. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +24 -0
  102. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  103. package/payload/platform/services/claude-session-manager/dist/http-server.js +214 -17
  104. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  105. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +13 -5
  106. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  107. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +46 -11
  108. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  109. package/payload/platform/services/webchat-channel/dist/instructions.d.ts +1 -0
  110. package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
  111. package/payload/platform/services/webchat-channel/dist/instructions.js +28 -0
  112. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
  113. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
  114. package/payload/platform/services/webchat-channel/dist/server.js +75 -5
  115. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
  116. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  117. package/payload/server/public/assets/{AdminLoginScreens-BW1UgfoI.js → AdminLoginScreens-tHyAPNnQ.js} +1 -1
  118. package/payload/server/public/assets/AdminShell-Ce9izNVZ.js +1 -0
  119. package/payload/server/public/assets/{Checkbox-O1qvMk_u.js → Checkbox-Cq6SJJlX.js} +1 -1
  120. package/payload/server/public/assets/OperatorConversations-BERW_hUa.css +1 -0
  121. package/payload/server/public/assets/OperatorConversations-m2lz6Ss7.js +9 -0
  122. package/payload/server/public/assets/admin-D9iMgdbN.js +1 -0
  123. package/payload/server/public/assets/{arc-DpkSQNto.js → arc-Crkz45LN.js} +1 -1
  124. package/payload/server/public/assets/architecture-YZFGNWBL-Dma4Bgha.js +1 -0
  125. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Bw7Yq8O9.js → architectureDiagram-Q4EWVU46-C9JThHgP.js} +1 -1
  126. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BBtJQFSz.js → blockDiagram-DXYQGD6D-DpsV_HXT.js} +1 -1
  127. package/payload/server/public/assets/{browser-CySvj140.js → browser-CZWi0EAP.js} +1 -1
  128. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-JAMgxzOr.js → c4Diagram-AHTNJAMY-CTm_6aKi.js} +1 -1
  129. package/payload/server/public/assets/calendar-DUAh-_kx.js +1 -0
  130. package/payload/server/public/assets/channel-B_-5bau1.js +1 -0
  131. package/payload/server/public/assets/chat-DHuibPfc.js +1 -0
  132. package/payload/server/public/assets/{chunk-2KRD3SAO-eDugsc2L.js → chunk-2KRD3SAO-1KSJW1q6.js} +1 -1
  133. package/payload/server/public/assets/{chunk-336JU56O-BXfECwdC.js → chunk-336JU56O-C3t08Ip-.js} +2 -2
  134. package/payload/server/public/assets/chunk-426QAEUC-Dirxdwjh.js +1 -0
  135. package/payload/server/public/assets/{chunk-4BX2VUAB-CByVeKCY.js → chunk-4BX2VUAB-kl1ze33n.js} +1 -1
  136. package/payload/server/public/assets/{chunk-4TB4RGXK-CpY0DcUB.js → chunk-4TB4RGXK-DxpoDoHg.js} +1 -1
  137. package/payload/server/public/assets/{chunk-55IACEB6-C3YxgyIb.js → chunk-55IACEB6-WM9VJzha.js} +1 -1
  138. package/payload/server/public/assets/{chunk-5FUZZQ4R-Bc0d7j8A.js → chunk-5FUZZQ4R-CLH63ZH3.js} +1 -1
  139. package/payload/server/public/assets/{chunk-5PVQY5BW-CTUGMRIa.js → chunk-5PVQY5BW-DCTb8IAT.js} +1 -1
  140. package/payload/server/public/assets/{chunk-67CJDMHE-CbdPnpLd.js → chunk-67CJDMHE-BSYzyaoH.js} +1 -1
  141. package/payload/server/public/assets/{chunk-7N4EOEYR-Cjl2kevz.js → chunk-7N4EOEYR-CarJ7O2P.js} +1 -1
  142. package/payload/server/public/assets/{chunk-AA7GKIK3-BgozIh5p.js → chunk-AA7GKIK3-DTNLyBpH.js} +1 -1
  143. package/payload/server/public/assets/{chunk-BSJP7CBP-6Ufq45NW.js → chunk-BSJP7CBP-BFmHflHY.js} +1 -1
  144. package/payload/server/public/assets/{chunk-CIAEETIT-BhhYuMnA.js → chunk-CIAEETIT-BpjG0IzU.js} +1 -1
  145. package/payload/server/public/assets/{chunk-EDXVE4YY-BfaJ3yDD.js → chunk-EDXVE4YY-2fSowhlW.js} +1 -1
  146. package/payload/server/public/assets/{chunk-ENJZ2VHE-C7-hIGVC.js → chunk-ENJZ2VHE-ClcranGV.js} +1 -1
  147. package/payload/server/public/assets/{chunk-FMBD7UC4-BQvvyocF.js → chunk-FMBD7UC4-DLq4BItQ.js} +1 -1
  148. package/payload/server/public/assets/{chunk-FOC6F5B3-C6rBDOxH.js → chunk-FOC6F5B3-B9QI3Guz.js} +1 -1
  149. package/payload/server/public/assets/{chunk-ICPOFSXX-BjOJvkVa.js → chunk-ICPOFSXX-BAr-Mv1Z.js} +2 -2
  150. package/payload/server/public/assets/{chunk-K5T4RW27-kKowRHhn.js → chunk-K5T4RW27-8PvAHasY.js} +1 -1
  151. package/payload/server/public/assets/{chunk-KGLVRYIC-bAEV_5eH.js → chunk-KGLVRYIC--aGaDRH5.js} +1 -1
  152. package/payload/server/public/assets/{chunk-LIHQZDEY-BLvsQAfg.js → chunk-LIHQZDEY-BrWj7mw2.js} +1 -1
  153. package/payload/server/public/assets/{chunk-ORNJ4GCN-BzYZfPZ7.js → chunk-ORNJ4GCN-kYQmkMTi.js} +1 -1
  154. package/payload/server/public/assets/{chunk-OYMX7WX6-CL7WRw42.js → chunk-OYMX7WX6-CIsryCWH.js} +1 -1
  155. package/payload/server/public/assets/chunk-QZHKN3VN-Duipo1kI.js +1 -0
  156. package/payload/server/public/assets/{chunk-U2HBQHQK-BdcVGjau.js → chunk-U2HBQHQK-68X653e3.js} +1 -1
  157. package/payload/server/public/assets/{chunk-X2U36JSP-C0CL_Jin.js → chunk-X2U36JSP-v3v9soX3.js} +1 -1
  158. package/payload/server/public/assets/{chunk-XPW4576I-CsV7CUxH.js → chunk-XPW4576I-CW5DPpop.js} +1 -1
  159. package/payload/server/public/assets/{chunk-YZCP3GAM-Cj0_fLkR.js → chunk-YZCP3GAM-B1VP7Rl2.js} +1 -1
  160. package/payload/server/public/assets/{chunk-ZZ45TVLE-DLuquyoY.js → chunk-ZZ45TVLE-DiJrujNY.js} +1 -1
  161. package/payload/server/public/assets/classDiagram-6PBFFD2Q-B3kX5SuB.js +1 -0
  162. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D761c7Lr.js +1 -0
  163. package/payload/server/public/assets/clone-BrhFv6Tb.js +1 -0
  164. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BU3EOLXX.js → cose-bilkent-S5V4N54A-BscXxLMc.js} +1 -1
  165. package/payload/server/public/assets/{dagre-KV5264BT-CoCAYhFc.js → dagre-KV5264BT-DVgGlTQ1.js} +1 -1
  166. package/payload/server/public/assets/{dagre-BRq8C9NU.js → dagre-MBv6WlCS.js} +1 -1
  167. package/payload/server/public/assets/data-CoOcAR_2.js +1 -0
  168. package/payload/server/public/assets/{diagram-5BDNPKRD-DBy5GNaQ.js → diagram-5BDNPKRD-BmhCaO0a.js} +1 -1
  169. package/payload/server/public/assets/{diagram-G4DWMVQ6-l93MsBLv.js → diagram-G4DWMVQ6-ChU9L8vz.js} +1 -1
  170. package/payload/server/public/assets/{diagram-MMDJMWI5-BIfXkVlL.js → diagram-MMDJMWI5-Oy409Zc_.js} +1 -1
  171. package/payload/server/public/assets/{diagram-TYMM5635-BuTJLBny.js → diagram-TYMM5635-Cn1YByqk.js} +1 -1
  172. package/payload/server/public/assets/{erDiagram-SMLLAGMA-BwPxWDbP.js → erDiagram-SMLLAGMA-e17yfLvr.js} +1 -1
  173. package/payload/server/public/assets/{flatten-DtM0XAMt.js → flatten-Cl1Bc3dR.js} +1 -1
  174. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BhPtHXMR.js → flowDiagram-DWJPFMVM-Dqt7sCVZ.js} +1 -1
  175. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BlXjprdD.js → ganttDiagram-T4ZO3ILL-B4IhwS2r.js} +1 -1
  176. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BCQAqtLy.js +1 -0
  177. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BW36BDiu.js → gitGraphDiagram-UUTBAWPF-BDw-PKcI.js} +1 -1
  178. package/payload/server/public/assets/{graph-uFhGyOZR.js → graph-Dc_votDd.js} +3 -3
  179. package/payload/server/public/assets/{graph-labels-BNnhRQqM.js → graph-labels-jqagxwhW.js} +1 -1
  180. package/payload/server/public/assets/{graphlib-Bjg3Tq-k.js → graphlib-DPIYk_sg.js} +1 -1
  181. package/payload/server/public/assets/info-OMHHGYJF-qU7hK50T.js +1 -0
  182. package/payload/server/public/assets/infoDiagram-42DDH7IO-KGdcJeTs.js +2 -0
  183. package/payload/server/public/assets/{isEmpty-D__iH1WQ.js → isEmpty-D1pGOD1J.js} +1 -1
  184. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CmB-bA_O.js → ishikawaDiagram-UXIWVN3A-BRIHsB3G.js} +1 -1
  185. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-Bt1fJKmc.js → journeyDiagram-VCZTEJTY-aKNgmoHd.js} +1 -1
  186. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DVbksz_J.js → kanban-definition-6JOO6SKY-cwBwT-nm.js} +1 -1
  187. package/payload/server/public/assets/{line-BX2Ugx3B.js → line-DVtVRzUA.js} +1 -1
  188. package/payload/server/public/assets/{linear-Bdc-QJWI.js → linear-DtoOFPO2.js} +1 -1
  189. package/payload/server/public/assets/{mermaid-parser.core-qv1e-J5x.js → mermaid-parser.core-G7YD_zO3.js} +2 -2
  190. package/payload/server/public/assets/{mermaid.core-C_d9YQX_.js → mermaid.core-DpFyndHm.js} +3 -3
  191. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DwKGvF14.js → mindmap-definition-QFDTVHPH-CYXK_Pvz.js} +1 -1
  192. package/payload/server/public/assets/operator-KYXcuQ4Y.js +1 -0
  193. package/payload/server/public/assets/{ordinal-BRQ5CzZY.js → ordinal-CBZeH4Yp.js} +1 -1
  194. package/payload/server/public/assets/packet-4T2RLAQJ-DiU2yS9m.js +1 -0
  195. package/payload/server/public/assets/page-Cfsv97nq.js +32 -0
  196. package/payload/server/public/assets/pie-ZZUOXDRM-zHUKKlVv.js +1 -0
  197. package/payload/server/public/assets/{pieDiagram-DEJITSTG-dUvQC_4S.js → pieDiagram-DEJITSTG-DFo4N6WH.js} +1 -1
  198. package/payload/server/public/assets/{public-DgltXhnD.js → public-49guEjCh.js} +1 -1
  199. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CebX_oPa.js → quadrantDiagram-34T5L4WZ-BlH5iIhl.js} +1 -1
  200. package/payload/server/public/assets/radar-PYXPWWZC-BUnVoaPg.js +1 -0
  201. package/payload/server/public/assets/{reduce-CkcXOmmJ.js → reduce-PuPlFPRX.js} +1 -1
  202. package/payload/server/public/assets/{requirementDiagram-MS252O5E-h2euIqGj.js → requirementDiagram-MS252O5E-D5WLty8A.js} +1 -1
  203. package/payload/server/public/assets/rotate-ccw-CyR5o3Nq.js +1 -0
  204. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DCii3fkF.js → sankeyDiagram-XADWPNL6-vB85IxHG.js} +1 -1
  205. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CQSGYmlq.js → sequenceDiagram-FGHM5R23-Cxraa0Ee.js} +1 -1
  206. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CVtU0iXH.js → stateDiagram-FHFEXIEX-BBPssYBx.js} +1 -1
  207. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BWmmUwDt.js +1 -0
  208. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ChvsBltI.js → timeline-definition-GMOUNBTQ-Bgk6PT62.js} +1 -1
  209. package/payload/server/public/assets/treeView-SZITEDCU-C3Y-Q52h.js +1 -0
  210. package/payload/server/public/assets/treemap-W4RFUUIX-Dk0qZpAg.js +1 -0
  211. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-e-EZiiba.js → vennDiagram-DHZGUBPP-B-APTs3L.js} +1 -1
  212. package/payload/server/public/assets/wardley-RL74JXVD-BAWI02OA.js +1 -0
  213. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-4JaRn1s5.js → wardleyDiagram-NUSXRM2D-CkXJSs_i.js} +1 -1
  214. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-kxwmCNuM.js → xychartDiagram-5P7HB3ND-BkyshPMV.js} +1 -1
  215. package/payload/server/public/browser.html +4 -4
  216. package/payload/server/public/calendar.html +4 -4
  217. package/payload/server/public/chat.html +7 -6
  218. package/payload/server/public/data.html +4 -4
  219. package/payload/server/public/graph.html +7 -6
  220. package/payload/server/public/index.html +6 -6
  221. package/payload/server/public/operator.html +9 -8
  222. package/payload/server/public/public.html +7 -6
  223. package/payload/server/server.js +244 -24
  224. package/payload/server/public/assets/AdminShell-CDQDkT1R.js +0 -1
  225. package/payload/server/public/assets/OperatorConversations-CVH-FoJo.css +0 -1
  226. package/payload/server/public/assets/OperatorConversations-jqaPCHwB.js +0 -9
  227. package/payload/server/public/assets/admin-BkYc54bi.js +0 -1
  228. package/payload/server/public/assets/architecture-YZFGNWBL-Csj53u5T.js +0 -1
  229. package/payload/server/public/assets/calendar-DgP7lal2.js +0 -1
  230. package/payload/server/public/assets/channel-BUQUAUts.js +0 -1
  231. package/payload/server/public/assets/chat-gls5aV50.js +0 -1
  232. package/payload/server/public/assets/chunk-426QAEUC-CdknReB2.js +0 -1
  233. package/payload/server/public/assets/chunk-QZHKN3VN-8tHoEDE9.js +0 -1
  234. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BEGZ3DLg.js +0 -1
  235. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DsLxnm5U.js +0 -1
  236. package/payload/server/public/assets/clone-uiXbH_kh.js +0 -1
  237. package/payload/server/public/assets/data-CbI8-CX3.js +0 -1
  238. package/payload/server/public/assets/gitGraph-7Q5UKJZL-D_2KrZoP.js +0 -1
  239. package/payload/server/public/assets/info-OMHHGYJF-BP2TNwQ4.js +0 -1
  240. package/payload/server/public/assets/infoDiagram-42DDH7IO-D1kDtBOY.js +0 -2
  241. package/payload/server/public/assets/operator-DeCk_qYw.js +0 -1
  242. package/payload/server/public/assets/packet-4T2RLAQJ-BDg8fde8.js +0 -1
  243. package/payload/server/public/assets/page-jGwq-DpW.js +0 -32
  244. package/payload/server/public/assets/pie-ZZUOXDRM-CXDyYMkZ.js +0 -1
  245. package/payload/server/public/assets/radar-PYXPWWZC-xen_zv8F.js +0 -1
  246. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BywcXjtb.js +0 -1
  247. package/payload/server/public/assets/treeView-SZITEDCU-2FBf_1It.js +0 -1
  248. package/payload/server/public/assets/treemap-W4RFUUIX-BDdb30P-.js +0 -1
  249. package/payload/server/public/assets/wardley-RL74JXVD-BLq5MxjR.js +0 -1
  250. /package/payload/server/public/assets/{_baseFor-SRtUHe7G.js → _baseFor-brRjpUOX.js} +0 -0
  251. /package/payload/server/public/assets/{array-BpsnM-Py.js → array-BGFCBI0e.js} +0 -0
  252. /package/payload/server/public/assets/{cytoscape.esm-D4Rl1H5h.js → cytoscape.esm-TvRJ2tGX.js} +0 -0
  253. /package/payload/server/public/assets/{defaultLocale-C7sQPl-O.js → defaultLocale-CRZydyG6.js} +0 -0
  254. /package/payload/server/public/assets/{dist-CtUNt3w8.js → dist-B0CkUodR.js} +0 -0
  255. /package/payload/server/public/assets/{init-BydxaDEV.js → init-B8gtcn7T.js} +0 -0
  256. /package/payload/server/public/assets/{katex-B0fVeDx4.js → katex-RxgSu_dy.js} +0 -0
  257. /package/payload/server/public/assets/{path-jlWYQ2i9.js → path-DZF-JdEe.js} +0 -0
  258. /package/payload/server/public/assets/{preload-helper-uTix4PVD.js → preload-helper-CQ36nxok.js} +0 -0
  259. /package/payload/server/public/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
  260. /package/payload/server/public/assets/{src-48kCpScq.js → src-CR_MU8uy.js} +0 -0
@@ -1,3 +1,10 @@
1
+ export type ClaudeAiConnectorState = "connected" | "needs-auth" | "unreachable";
2
+ export interface ClaudeAiConnector {
3
+ /** The connector's claude.ai display name, prefix included, e.g.
4
+ * "claude.ai Zoom for Claude" — the exact string `claude mcp login` expects. */
5
+ name: string;
6
+ state: ClaudeAiConnectorState;
7
+ }
1
8
  export interface CapabilitiesHereInput {
2
9
  accountId: string;
3
10
  accountConfigPath: string;
@@ -5,6 +12,13 @@ export interface CapabilitiesHereInput {
5
12
  platformRoot: string;
6
13
  premiumPluginsRoot: string;
7
14
  claudeConfigDir: string;
15
+ /** Task 1160 — returns the raw combined output of `claude mcp list` run under
16
+ * the brand config dir. Injected by the adapter (index.ts) so this function
17
+ * stays a pure resolver and so the subprocess never runs in unit tests. When
18
+ * omitted, no connectors are enumerated and nothing is spawned. The provider
19
+ * itself must never throw; this resolver also guards it, degrading to an empty
20
+ * connector list on any failure. */
21
+ listConnectorsRaw?: () => Promise<string>;
8
22
  }
9
23
  export interface CapabilitiesHereResult {
10
24
  accountId: string;
@@ -18,11 +32,13 @@ export interface CapabilitiesHereResult {
18
32
  name: string;
19
33
  }>;
20
34
  registeredAgentTypes: string[];
35
+ claudeAiConnectors: ClaudeAiConnector[];
21
36
  brand: {
22
37
  productName: string | null;
23
38
  shipsPremiumBundles: string[];
24
39
  };
25
40
  capturedAt: string;
26
41
  }
42
+ export declare function parseClaudeAiConnectors(mcpListOutput: string): ClaudeAiConnector[];
27
43
  export declare function resolveCapabilitiesHere(input: CapabilitiesHereInput, nowIso: string): Promise<CapabilitiesHereResult>;
28
44
  //# sourceMappingURL=capabilities-here.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities-here.d.ts","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B,EAAE,MAAM,EAAE,CAAC;IACvC,2BAA2B,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;KAC/B,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AA0BD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,qBAAqB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,sBAAsB,CAAC,CAgDjC"}
1
+ {"version":3,"file":"capabilities-here.d.ts","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,CAAC;AAEhF,MAAM,WAAW,iBAAiB;IAChC;qFACiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,sBAAsB,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;yCAKqC;IACrC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4BAA4B,EAAE,MAAM,EAAE,CAAC;IACvC,2BAA2B,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrE,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,KAAK,EAAE;QACL,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;KAC/B,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAwBlF;AAuCD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,qBAAqB,EAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,sBAAsB,CAAC,CAmDjC"}
@@ -1,6 +1,56 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { existsSync, readdirSync, statSync } from "node:fs";
3
3
  import { resolve, join } from "node:path";
4
+ // Task 1160 — parse the claude.ai connectors out of `claude mcp list` output.
5
+ // claude.ai connectors are account-synced (not stably enumerable on disk), so the
6
+ // CLI's list is the canonical source of which connectors exist for this client and
7
+ // their per-client auth state. Each connector row has the shape
8
+ // `claude.ai <Display Name>: <url> - <status>`; non-claude.ai rows are ignored.
9
+ // Status is matched on words, not glyphs, because the glyph varies (✔ vs ✓) across
10
+ // CLI builds. Only names and status words are read — no token material. Pure.
11
+ export function parseClaudeAiConnectors(mcpListOutput) {
12
+ const out = [];
13
+ for (const rawLine of mcpListOutput.split("\n")) {
14
+ const line = rawLine.trim();
15
+ if (!line.startsWith("claude.ai "))
16
+ continue;
17
+ const nameEnd = line.indexOf(": ");
18
+ const statusStart = line.lastIndexOf(" - ");
19
+ if (nameEnd < 0 || statusStart < 0 || statusStart < nameEnd)
20
+ continue;
21
+ const name = line.slice(0, nameEnd).trim();
22
+ // Skip a row with no display component (`claude.ai : ...`): the bare prefix is
23
+ // not a connector `claude mcp login` could target, so it must not be surfaced.
24
+ if (name === "claude.ai")
25
+ continue;
26
+ const status = line.slice(statusStart + 3);
27
+ let state;
28
+ // Match the whole word "connected" so "Disconnected" / "Failed to connect" do
29
+ // not read as connected; anything that is neither needs-auth nor connected is
30
+ // not usable, so it maps to unreachable.
31
+ if (/needs authentication/i.test(status))
32
+ state = "needs-auth";
33
+ else if (/\bconnected\b/i.test(status))
34
+ state = "connected";
35
+ else
36
+ state = "unreachable";
37
+ out.push({ name, state });
38
+ }
39
+ out.sort((a, b) => a.name.localeCompare(b.name));
40
+ return out;
41
+ }
42
+ async function resolveClaudeAiConnectors(listConnectorsRaw) {
43
+ if (!listConnectorsRaw)
44
+ return [];
45
+ try {
46
+ return parseClaudeAiConnectors(await listConnectorsRaw());
47
+ }
48
+ catch {
49
+ // The provider should never throw, but a connector-blind capabilities result
50
+ // is far better than a thrown discovery call. Degrade to empty.
51
+ return [];
52
+ }
53
+ }
4
54
  function listSpecialistFiles(dir) {
5
55
  if (!existsSync(dir))
6
56
  return [];
@@ -52,6 +102,7 @@ export async function resolveCapabilitiesHere(input, nowIso) {
52
102
  installedPremiumSpecialists.push({ bundle, name });
53
103
  }
54
104
  const registeredAgentTypes = listAgentRegistry(resolve(input.claudeConfigDir, "agents"));
105
+ const claudeAiConnectors = await resolveClaudeAiConnectors(input.listConnectorsRaw);
55
106
  return {
56
107
  accountId: input.accountId,
57
108
  tier,
@@ -61,6 +112,7 @@ export async function resolveCapabilitiesHere(input, nowIso) {
61
112
  installedPlatformSpecialists,
62
113
  installedPremiumSpecialists,
63
114
  registeredAgentTypes,
115
+ claudeAiConnectors,
64
116
  brand: { productName, shipsPremiumBundles },
65
117
  capturedAt: nowIso,
66
118
  };
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities-here.js","sourceRoot":"","sources":["../../src/tools/capabilities-here.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"capabilities-here.js","sourceRoot":"","sources":["../../src/tools/capabilities-here.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:7cdf605d8c40fcc1e028ad43fe5411edcd9c422101aa9a3d6564a83798ad243a
4
+ content-hash: sha256:6f90b00dd8971be316fca8e109765ec840a220d06f1cb4f1aabecefb9da17916
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -1123,6 +1123,12 @@ The most common cause is wrong nameservers on the domain. The domain must use Cl
1123
1123
  - 5 failed login attempts → 15-minute lockout — wait for expiry.
1124
1124
  - The remote password is set during Cloudflare Tunnel onboarding — the agent asks for one in chat and stores it deterministically. The browser form at `/__remote-auth/setup` remains available for resets on the local network.
1125
1125
 
1126
+ ### Large `/data` upload fails with a connection error
1127
+
1128
+ - Cloudflare proxies a request body of at most ~100 MB on the current plan. A single upload larger than that is cut at the edge before it reaches the server, so the browser sees a connection error rather than a clean size rejection.
1129
+ - The `/data` page handles this itself: files over 95 MB are split into ~48 MB parts and sent one at a time under the cap, and the server reassembles them. No plan change or dashboard action is needed for uploads up to the 2 GB app ceiling.
1130
+ - Raising the proxied body limit is a paid-plan change made on the Cloudflare dashboard, not something the agent does.
1131
+
1126
1132
  ## What the agent does and does not do
1127
1133
 
1128
1134
  **Does:** invokes `cloudflared` directly via Bash, following `plugins/cloudflare/references/manual-setup.md` step by step; quotes click-paths from the reference files verbatim; verifies external reachability with `curl -I` and surfaces the response.
@@ -1709,6 +1715,56 @@ A 25-component design system (title slides, metric cards, quotes, comparison tab
1709
1715
 
1710
1716
  This is a frozen, vendored copy of the open-source Slides™ framework (MIT). It ships installed and available on every account; enable it per session like any other plugin if it is not already active.
1711
1717
 
1718
+ ---
1719
+ # Connectors
1720
+ Source: https://docs.getmaxy.com/connectors.md
1721
+
1722
+ # claude.ai connectors
1723
+
1724
+ claude.ai connectors (Zoom, Dropbox, GitHub, Google Calendar, and the rest you add on claude.ai) work
1725
+ inside your admin chat once they are authorised for this Maxy client. This page explains why a
1726
+ connector you already added can still say it needs authentication, and how to fix it without leaving
1727
+ the chat.
1728
+
1729
+ ## Asking for a connector by name
1730
+
1731
+ You can ask the agent to use a connector you added on claude.ai by name — "can we connect my Zoom
1732
+ account?", "save this to Dropbox", "check my Microsoft 365 calendar". The agent knows which connectors
1733
+ are loaded for this client and whether each one is ready or still needs the one-off authentication
1734
+ below, so it will reach for the connector rather than telling you it has no such integration. If a
1735
+ connector you added is not yet authenticated for this client, the agent offers you the authentication
1736
+ step straight away instead of dead-ending.
1737
+
1738
+ ## Why a connector can still need authentication
1739
+
1740
+ A claude.ai connector is authorised per client, not per account. Approving a connector in the
1741
+ claude.ai web app authorises the web app only. Your Maxy admin chat is a separate client, so the first
1742
+ time it uses a connector that client has to be authorised too. This is a one-off step per connector.
1743
+
1744
+ That is why some connectors work straight away while a newly added one does not. A connector you used
1745
+ before was already authorised for this client; a brand new one has only been approved in the web app.
1746
+
1747
+ ## How to authenticate one from the chat
1748
+
1749
+ When the agent tries a connector that has not been authorised for this client, it will tell you the
1750
+ connector needs authentication and hand you a link. You do not need a terminal and you do not need to
1751
+ run anything yourself.
1752
+
1753
+ 1. The agent gives you an authorisation link.
1754
+ 2. Open the link and approve the connector on claude.ai (sign in with the same account you use for
1755
+ your connectors).
1756
+ 3. Tell the agent you have approved it.
1757
+ 4. The agent reconnects your chat session. Send your next message and the connector is ready to use.
1758
+
1759
+ If a connector still reports that it needs authentication after you have approved it and the session
1760
+ has reconnected, that is unexpected. Tell your installer so they can look into it.
1761
+
1762
+ ## What this is not
1763
+
1764
+ This is about Anthropic's claude.ai connectors, which authenticate per client. It is separate from the
1765
+ Maxy connector plugin, which registers ordinary REST APIs with credentials Maxy holds. The two are
1766
+ unrelated.
1767
+
1712
1768
  ---
1713
1769
  # Telegram
1714
1770
  Source: https://docs.getmaxy.com/telegram-guide.md
@@ -2466,6 +2522,8 @@ either is a regression.
2466
2522
 
2467
2523
  **`/chat` empty-state greeting panel.** While the admin webchat has no conversation JSONL yet (`GET /api/webchat/session` → `projectDir:null`), `app/chat/page.tsx` renders a "What's up next, {givenName}?" greeting (given name = first whitespace token of the admin session's `userName`) above two read-only lists from `GET /api/webchat/greeting` (`server/routes/webchat-greeting.ts`, `requireAdminSession`-gated, `accountId`-scoped): the next 5 upcoming `:Event` rows (`eventStatus IN ['scheduled','due']`, future `COALESCE(nextRun, startDate)`, soonest first) and the outstanding `:Task` rows (`status IN ['pending','active','running']`, 5 shown + `+N more`). Read failure returns HTTP 200 `{ ok: false }` and the page shows the headline alone — the panel never blocks the composer. A third section, **Your specialists**, shows the account's installed roster — every `*.md` under `data/accounts/<accountId>/specialists/agents/`, core and `--`-prefixed premium files alike — shown by frontmatter `name` + `summary` (fallback `description`), empty dir → "No specialists installed". The roster read (`app/lib/claude-agent/specialist-roster.ts`) is isolated from the graph fallback: malformed files are skipped (`op=specialist-skipped file=<name> reason=<…>`), a whole-roster failure degrades to `specialists: []` inside the `ok: true` payload (`op=specialists-read-failed`). Logs: `[webchat:greeting] op=read account=<id8> events=<n> tasks=<n> specialists=<n> ms=<n>` / `op=read-failed reason=…`; client warns `[admin-ui] greeting-unavailable …`. The full webchat architecture lives in `.docs/admin-webchat-native-channel.md`.
2468
2524
 
2525
+ **`/chat` Conversations flyout + zero-sessions splash.** The admin `/chat` `HeaderMenu` carries a **Conversations** item (rendered only when `onOpenConversations` is wired, which scopes it to `/chat`) that opens an in-chat session-management pane (`app/chat/SessionList.tsx`) hosted by `chat/page.tsx` — distinct from, and sharing endpoints with, the `Sidebar` Sessions list (which stays hidden on narrow viewports). It enumerates the admin's own webchat sessions via `GET /api/admin/sidebar-sessions` (carries the per-row `live` marker and `archived` flag, install-wide), lists them newest-first with the live one marked and archived rows folded under a collapsible subsection, and offers per-row resume (`/chat?session=<id>`), rename, archive/unarchive, two-tap delete, an **End** control on the live row (`session-stop`), plus a New-session control (`session-rc-spawn`) and a copyable full id. When the canonical pointer is `known:false` (`canonical-empty`) and enumeration returns zero rows, the surface renders a splash (brand logo + New session) instead of a dead bootstrap thread; a freshly-spawned New session is `known:true`, so its greeting is preserved. Client breadcrumbs: `[chat-conversations] op=enumerate owned=<n>` and `op=action name=<open|rename|archive|delete|stop> sessionId=<id8>` (`op=action-failed … status=…` on a non-2xx). Detail lives in `.docs/admin-webchat-native-channel.md` ("Conversations flyout + zero-sessions splash").
2526
+
2469
2527
  **`/chat` Claude-desktop transcript presentation.** The admin webchat keeps the shared `Transcript` shell (stream, follow-tail) but injects a /chat-only item renderer via the component's optional `renderItems` prop: `renderChatTimeline` in `app/chat/transcript-render.tsx`. Presentation: operator turns render as a right-aligned grey bubble showing the message text and, beneath it, a subtle always-visible time-of-day stamp (no label); delivered agent replies render as plain prose with the same time-of-day stamp beneath (the reply-document filename line stays, as prose); the stamp is HH:MM from the turn's `ts` (locale-formatted, right-aligned inside the operator bubble, left-aligned under agent prose), and a turn whose `ts` is null/unparseable shows no stamp, never an empty line — so only delivered operator and agent-reply turns are stamped, while tool runs, the collapsed "Thinking" block, and the agent-error banner stay time-free; a maximal consecutive run of `tool-call`/`tool-result` turns renders as one collapsed grey one-liner ("Used N tools ›") whose expansion shows every call and result payload — a lone call still gets the one-liner, and prose or a directive row ends a run. The WhatsApp reader (`/whatsapp`) omits the prop and keeps the default `renderTimeline`, so its rendering is unchanged; both presentations are test-pinned (`app/whatsapp/__tests__/Transcript-*.test.tsx`, `app/chat/__tests__/transcript-render.test.tsx`). **Day-divider:** both renderers insert a centered `.day-divider` row between two consecutive timeline items on different local calendar days (label `Today`/`Yesterday`, else `Sat 14 Jun 2026`), so a thread spanning midnight is never an ambiguous run of HH:MM; the first dated item gets a leading divider, a null/unparseable `ts` marks no boundary, dividers are computed over the filtered `visibleItems`, and in `/chat` a day crossover flushes any open tool/think run first so a collapsed run never spans it. Per-bubble HH:MM stamps are unchanged. Shared helpers `dayKey`/`dayLabel`/`itemTs`/`DayDivider` live in `app/whatsapp/Transcript.tsx`.
2470
2528
 
2471
2529
  **`/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).
@@ -4179,6 +4237,8 @@ tail -200 ~/.maxy/logs/maxy-ui.log | rg '\[remote-auth\].*resolvedKind='
4179
4237
 
4180
4238
  **If a background task goes silent and the chat shows "A background task went silent — K of M completed":** Maxy's subagent stopped emitting progress for over 2 minutes. Tap "Continue" — the next turn resumes the prior session and reads a synthetic tool_result describing what completed before the pause, so the agent re-plans without losing the work it had done. Most stalls are upstream API latency rather than the subagent's approach failing — the resume-first path treats both correctly. Greppable post-deploy invariants: `[stall-recovery] kind=subagent_stalled … completed=<K>/? handoff=resume-first` followed by `[stall-resume] consumed kind=subagent_stalled toolUseId=<8>` on the next turn. If the button reads "Start over" instead, the parent's pending tool_use_id was not captured — the fallback path took over; the prior conversation is preserved as a `<recovery-context>` block in the cold-started session.
4181
4239
 
4240
+ **The stop button is stuck and the spinner never clears.** If the chat shows a stop button and a working spinner that never resolves, and the session dot is grey (not live), the agent process for that session was killed mid-turn (most often the device ran low on memory). There is no live turn to interrupt, so the old behaviour left you stranded. Now it self-heals: within a few seconds the spinner clears on its own and the composer shows "The agent stopped. Send a message to resume." Pressing stop clears it immediately. Either way, just send your next message — the session resumes from where it left off. Greppable post-deploy invariants: the manager logs `[rc-life] op=turn-aborted reason=child-exit-mid-turn` on the death and `[webchat-interrupt] op=dead-child-recovered` if you press stop; the browser console logs `[admin-ui] op=phantom-turn-cleared` (self-heal) or `[admin-ui] op=stop-dead-child` (stop press). If a session keeps dying mid-turn, the device is memory-constrained — that is a capacity concern, separate from this recovery.
4241
+
4182
4242
  **Agent searches the filesystem after uploading a zip.** If you uploaded a zip and the agent burns several turns running `find` / `Glob` instead of unzipping, that is the symptom of the recovery-retry attachment-context regression (now closed by the recovery context preservation contract in `.docs/agents.md`). Greppable confirmation is the `[context-overflow-recovery] retry … attachmentsCarried=<n>` line in the conversation stream log. If you see `[context-overflow-recovery] WARN attachment-context-lost`, the regression has returned — surface to support.
4183
4243
 
4184
4244
  **Turn budget exhausted with a horizontal rule separating two assistant turns.** When Maxy reaches its turn budget and the doubled retry also runs out, the chat now shows a one-paragraph assistant message that opens with `error_max_turns turns=A→B` (initial budget → final budget) followed by the recovery copy: "I reached my turn budget of N before I could finish this request. Try sending a smaller or more focused request, or ask me to use higher effort." That message is persisted to the graph, so the next page-refresh still shows it. The thin horizontal rule labelled "Session restored after timeout." that appears above your following turn signals that the prior turn forced a cold SDK-session restart inside the same conversation (pool eviction) — the agent's response after the rule is from a fresh SDK session even though the conversation thread is unchanged. Greppable post-deploy invariants: `[context-overflow-recovery] exhausted cause=max-turns-interrupted` count equals `[admin-persist] writer=persistMessageExhaust outcome=ok` count for the same sessionId window, and one `[session-store] storeAgentSessionId` line marks the cold-restart that drove the on-screen rule.
@@ -25,7 +25,7 @@ Each installation has its own Cloudflare account. Two auth paths serve two opera
25
25
 
26
26
  ## Operator-facing surface
27
27
 
28
- The plugin registers no agent-facing MCP tools. Every Cloudflare operation is the agent invoking `cloudflared` or `wrangler` directly via Bash, or calling the Cloudflare API with a reused per-scope narrow token, with stdout/stderr streamed verbatim into the PTY chat (secrets redacted). The OAuth URL printed by `cloudflared tunnel login` is linkified by the native PTY; the operator clicks it in their own browser. There is no shell-script wrapper, no orchestrator state machine, no MCP-tool surface.
28
+ The plugin registers no agent-facing MCP tools. Every Cloudflare operation is the agent invoking `cloudflared` or `wrangler` directly via Bash, or calling the Cloudflare API with a reused per-scope narrow token, with stdout/stderr streamed verbatim into the PTY chat (secrets redacted). The OAuth URL printed by `cloudflared tunnel login` is linkified by the native PTY; the operator clicks it in their own browser. The one shell helper is [bin/cf-token.sh](bin/cf-token.sh), a deterministic per-scope token resolver that faithfully relays the Cloudflare token API (it invents no flags and drives no dashboard); there is no wrapper around `cloudflared` or `wrangler`, no orchestrator state machine, no MCP-tool surface.
29
29
 
30
30
  ### Skills
31
31
 
@@ -48,6 +48,12 @@ The plugin registers no agent-facing MCP tools. Every Cloudflare operation is th
48
48
 
49
49
  The agent loads these references on demand via `plugin-read` as the conversation requires. They are not auto-injected into the system prompt.
50
50
 
51
+ ### Helper
52
+
53
+ | Helper | Purpose |
54
+ |---|---|
55
+ | [bin/cf-token.sh](bin/cf-token.sh) | Deterministic per-scope token resolver. `bash bin/cf-token.sh <scope> <secrets-file>` (scope: `pages`, `d1`, `dns`, `access`) reads the master's `cfat_`/`cfut_` prefix, routes verify/`permission_groups`/mint to the matching endpoint family, reuses a persisted token or mints once if absent (no expiry), verifies through the transient post-mint window, persists to the secrets file, and prints only the secrets key name on stdout (never a token value). It removes the endpoint-routing decision from the agent, which is what the false-negative `Invalid API Token` / `9109` failures turned on. curl + jq only; exit-code gated. |
56
+
51
57
  ### Success contract
52
58
 
53
59
  The setup-done claim only fires when `curl -I https://<hostname>` issued from outside the local network returns `HTTP/2 200` (or `HTTP/1.1 200 OK`) and the response is surfaced verbatim in chat. No state file, no service-active claim, no `cloudflared` exit code substitutes for the live HTTP response. When the curl returns anything else, the agent diagnoses with `cloudflared tunnel info <tunnelId>` and `systemctl --user status cloudflared-${BRAND}.service`, cites the relevant step in `references/reset-guide.md`, and stops.
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env bash
2
+ # Regression test for cf-token.sh. Stubs curl via a PATH shim backed by a state
3
+ # file so mint -> verify sequencing and the post-mint 10000 window are simulated
4
+ # offline. No live Cloudflare account is touched.
5
+ #
6
+ # Covers:
7
+ # 1. cfat_ master mints pages-d1, routes verify/perm/mint to /accounts/...
8
+ # 2. cfut_ master routes to /user/... and never to /accounts/...
9
+ # 3. an already-persisted canonical key is reused with no mint call
10
+ # 4. a legacy key (CF_PAGES_TOKEN) is reused and reported as the used key
11
+ # 5. the post-mint 10000 window is retried, then verify passes
12
+ # 6. access poison duplicate-id: first id 10000 on functional read -> alt id
13
+ # 7. an unrecognised master prefix fails closed
14
+ # 8. a real failure (non-transient verify code) exits non-zero, code surfaced
15
+ # 9/10. no token value ever reaches stdout/stderr; stdout is exactly the key
16
+ set -u
17
+
18
+ HELPER="$(cd "$(dirname "$0")/.." && pwd)/cf-token.sh"
19
+ [ -x "$HELPER" ] || { echo "FAIL: $HELPER not executable" >&2; exit 1; }
20
+
21
+ PASS=0; FAIL=0
22
+ SECRET_VALUE="cfat_minted_SECRET_do_not_leak_0123456789" # fake minted token value
23
+
24
+ ok() { echo "PASS: $1"; PASS=$((PASS+1)); }
25
+ bad() { echo "FAIL: $1" >&2; FAIL=$((FAIL+1)); }
26
+
27
+ # Build a scratch sandbox: a fake-curl dir on PATH + an account-style secrets file.
28
+ # $1 = master token value (its prefix selects cfat_/cfut_ routing).
29
+ setup() {
30
+ SANDBOX=$(mktemp -d)
31
+ BIN="$SANDBOX/bin"; mkdir -p "$BIN"
32
+ SDIR="$SANDBOX/acme-code/data/accounts/acc123/secrets"; mkdir -p "$SDIR"
33
+ SECRETS="$SDIR/cloudflare.env"
34
+ ( umask 077; printf 'CLOUDFLARE_API_TOKEN=%s\nCLOUDFLARE_ACCOUNT_ID=%s\n' "$1" "acc123" > "$SECRETS" )
35
+ : > "$SANDBOX/curl.log"
36
+ install_default_curl
37
+ PATH="$BIN:$PATH"; export PATH
38
+ }
39
+ teardown() { rm -rf "$SANDBOX"; }
40
+
41
+ # Default fake curl: a healthy account with all permission groups; mint -> value;
42
+ # verify -> active; functional access read -> ok.
43
+ install_default_curl() {
44
+ cat > "$BIN/curl" <<CURL
45
+ #!/usr/bin/env bash
46
+ SB="\$(cd "\$(dirname "\$0")/.." && pwd)"
47
+ echo "\$@" >> "\$SB/curl.log"
48
+ url=""; for a in "\$@"; do case "\$a" in https://*) url="\$a";; esac; done
49
+ case "\$url" in
50
+ *"/tokens/permission_groups"*)
51
+ echo '{"success":true,"result":[{"id":"pg_pages","name":"Cloudflare Pages Write"},{"id":"pg_d1","name":"D1 Write"},{"id":"pg_dns","name":"DNS Write"},{"id":"pg_acc1","name":"Access: Apps and Policies Write"},{"id":"pg_acc2","name":"Access: Apps and Policies Write"}]}'
52
+ ;;
53
+ *"/tokens/verify"*) echo '{"success":true,"result":{"status":"active"}}';;
54
+ *"/tokens"*) echo '{"success":true,"result":{"id":"tok1","value":"'"$SECRET_VALUE"'"}}';;
55
+ *"/access/apps"*) echo '{"success":true,"result":[]}';;
56
+ *) echo '{"success":false,"errors":[{"code":9999,"message":"unmapped"}]}';;
57
+ esac
58
+ CURL
59
+ chmod +x "$BIN/curl"
60
+ }
61
+
62
+ # Run the helper. $1 name $2 scope $3 expected_exit. Sets OUT/ERR/RC.
63
+ run() {
64
+ local name="$1" scope="$2" exp="$3" of ef
65
+ of=$(mktemp); ef=$(mktemp)
66
+ CF_BACKOFF_SECONDS=0 bash "$HELPER" "$scope" "$SECRETS" >"$of" 2>"$ef"
67
+ RC=$?
68
+ OUT=$(cat "$of"); ERR=$(cat "$ef"); rm -f "$of" "$ef"
69
+ [ "$RC" -eq "$exp" ] && ok "$name (exit=$RC)" || { bad "$name (exit=$RC want $exp)"; echo " stderr: $ERR" >&2; }
70
+ }
71
+
72
+ no_leak() { # assert no fake token value appears in OUT or ERR
73
+ if printf '%s%s' "$OUT" "$ERR" | grep -qE "SECRET|BADtoken|GOODtoken"; then bad "$1 leaked a token value"
74
+ else ok "$1 no token leak"; fi
75
+ }
76
+
77
+ # ---------------------------------------------------------------------------
78
+ # 1. cfat_ master mints pages-d1, routes to /accounts/...
79
+ setup "cfat_master_abc"
80
+ run "cfat pages mint" pages 0
81
+ grep -q "/accounts/acc123/tokens" "$SANDBOX/curl.log" && ok "cfat routes accounts" || bad "cfat routing"
82
+ [ "$OUT" = "CF_PAGES_D1_TOKEN" ] && ok "stdout is canonical key" || bad "stdout='$OUT'"
83
+ grep -q "^CF_PAGES_D1_TOKEN=" "$SECRETS" && ok "persisted canonical key" || bad "not persisted"
84
+ echo "$ERR" | grep -q "op=resolve scope=pages master=cfat action=mint result=active code=0" && ok "mint lifeline verbatim" || bad "lifeline: $ERR"
85
+ no_leak "cfat mint"
86
+ teardown
87
+
88
+ # 2. cfut_ master routes to /user/... only
89
+ setup "cfut_master_xyz"
90
+ run "cfut pages mint" pages 0
91
+ grep -q "/user/tokens" "$SANDBOX/curl.log" && ok "cfut routes user" || bad "cfut routing"
92
+ grep -q "/accounts/acc123/tokens" "$SANDBOX/curl.log" && bad "cfut hit account endpoint" || ok "no account route for cfut"
93
+ echo "$ERR" | grep -q "master=cfut" && ok "cfut lifeline tag" || bad "lifeline tag: $ERR"
94
+ teardown
95
+
96
+ # 3. reuse: pre-persist canonical key -> no mint POST
97
+ setup "cfat_master_abc"
98
+ ( umask 077; printf 'CF_PAGES_D1_TOKEN=%s\n' "cfat_already_here" >> "$SECRETS" )
99
+ run "reuse no mint" pages 0
100
+ grep -q -- "-X POST" "$SANDBOX/curl.log" && bad "reuse path minted" || ok "reuse no mint call"
101
+ echo "$ERR" | grep -q "action=reuse result=active" && ok "reuse lifeline" || bad "reuse lifeline: $ERR"
102
+ [ "$OUT" = "CF_PAGES_D1_TOKEN" ] && ok "reuse reports canonical key" || bad "reuse out='$OUT'"
103
+ teardown
104
+
105
+ # 4. legacy key reuse: CF_PAGES_TOKEN present -> reused, reported as legacy key
106
+ setup "cfat_master_abc"
107
+ ( umask 077; printf 'CF_PAGES_TOKEN=%s\n' "cfat_legacy_here" >> "$SECRETS" )
108
+ run "legacy reuse" pages 0
109
+ grep -q -- "-X POST" "$SANDBOX/curl.log" && bad "legacy reuse minted" || ok "legacy reuse no mint"
110
+ [ "$OUT" = "CF_PAGES_TOKEN" ] && ok "reports legacy key" || bad "legacy out='$OUT'"
111
+ teardown
112
+
113
+ # 5. post-mint 10000 window then active
114
+ setup "cfat_master_abc"
115
+ cat > "$BIN/curl" <<'CURL'
116
+ #!/usr/bin/env bash
117
+ SB="$(cd "$(dirname "$0")/.." && pwd)"
118
+ echo "$@" >> "$SB/curl.log"
119
+ url=""; for a in "$@"; do case "$a" in https://*) url="$a";; esac; done
120
+ case "$url" in
121
+ *"/permission_groups"*) echo '{"success":true,"result":[{"id":"pg_pages","name":"Pages Write"},{"id":"pg_d1","name":"D1 Write"}]}';;
122
+ *"/tokens/verify"*)
123
+ n=$(cat "$SB/vcount" 2>/dev/null || echo 0); n=$((n+1)); echo "$n" > "$SB/vcount"
124
+ if [ "$n" -ge 3 ]; then echo '{"success":true,"result":{"status":"active"}}'
125
+ else echo '{"success":false,"errors":[{"code":10000,"message":"Authentication error"}]}'; fi;;
126
+ *"/tokens"*) echo '{"success":true,"result":{"value":"cfat_minted_SECRET_do_not_leak_0123456789"}}';;
127
+ *) echo '{"success":false,"errors":[{"code":9999}]}';;
128
+ esac
129
+ CURL
130
+ chmod +x "$BIN/curl"; : > "$SANDBOX/vcount"
131
+ run "10000 retry then active" pages 0
132
+ no_leak "10000 retry"
133
+ teardown
134
+
135
+ # 6. access poison id: first candidate's functional read returns 10000, second is fine
136
+ setup "cfat_master_abc"
137
+ cat > "$BIN/curl" <<'CURL'
138
+ #!/usr/bin/env bash
139
+ SB="$(cd "$(dirname "$0")/.." && pwd)"
140
+ echo "$@" >> "$SB/curl.log"
141
+ url=""; data=""; hdr=""; prev=""
142
+ for a in "$@"; do
143
+ case "$a" in https://*) url="$a";; esac
144
+ [ "$prev" = "--data" ] && data="$a"
145
+ [ "$prev" = "-H" ] && hdr="$hdr $a"
146
+ prev="$a"
147
+ done
148
+ case "$url" in
149
+ *"/permission_groups"*) echo '{"success":true,"result":[{"id":"acc_bad","name":"Access: Apps and Policies Write"},{"id":"acc_good","name":"Access: Apps and Policies Write"}]}';;
150
+ *"/tokens/verify"*) echo '{"success":true,"result":{"status":"active"}}';;
151
+ *"/tokens"*)
152
+ case "$data" in
153
+ *acc_bad*) echo '{"success":true,"result":{"value":"cfat_BADtoken_0"}}';;
154
+ *acc_good*) echo '{"success":true,"result":{"value":"cfat_GOODtoken_1"}}';;
155
+ *) echo '{"success":true,"result":{"value":"cfat_x"}}';; esac;;
156
+ *"/access/apps"*)
157
+ case "$hdr" in *BADtoken*) echo '{"success":false,"errors":[{"code":10000}]}';;
158
+ *) echo '{"success":true,"result":[]}';; esac;;
159
+ *) echo '{"success":false,"errors":[{"code":9999}]}';;
160
+ esac
161
+ CURL
162
+ chmod +x "$BIN/curl"
163
+ run "access poison retried to good id" access 0
164
+ grep -q "acc_good" "$SANDBOX/curl.log" && ok "minted with good id" || bad "never tried good id"
165
+ no_leak "access poison"
166
+ teardown
167
+
168
+ # 7. unknown prefix -> fail closed
169
+ setup "v1.0-legacyapikeystyle"
170
+ run "unknown prefix fail closed" pages 1
171
+ grep -q -- "-X POST" "$SANDBOX/curl.log" && bad "unknown prefix still minted" || ok "unknown prefix no mint"
172
+ teardown
173
+
174
+ # 8. real failure: verify returns a non-transient code -> non-zero, surfaced, masked
175
+ setup "cfat_master_abc"
176
+ cat > "$BIN/curl" <<'CURL'
177
+ #!/usr/bin/env bash
178
+ SB="$(cd "$(dirname "$0")/.." && pwd)"
179
+ echo "$@" >> "$SB/curl.log"
180
+ url=""; for a in "$@"; do case "$a" in https://*) url="$a";; esac; done
181
+ case "$url" in
182
+ *"/permission_groups"*) echo '{"success":true,"result":[{"id":"pg_pages","name":"Pages Write"},{"id":"pg_d1","name":"D1 Write"}]}';;
183
+ *"/tokens/verify"*) echo '{"success":false,"errors":[{"code":1001,"message":"bad"}]}';;
184
+ *"/tokens"*) echo '{"success":true,"result":{"value":"cfat_minted_SECRET_do_not_leak_0123456789"}}';;
185
+ *) echo '{"success":false,"errors":[{"code":9999}]}';;
186
+ esac
187
+ CURL
188
+ chmod +x "$BIN/curl"
189
+ run "real failure non-zero" pages 1
190
+ echo "$ERR" | grep -q "code=1001" && ok "failure code surfaced" || bad "code not surfaced: $ERR"
191
+ no_leak "real failure"
192
+ teardown
193
+
194
+ echo "----"; echo "PASS=$PASS FAIL=$FAIL"
195
+ [ "$FAIL" -eq 0 ]
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env bash
2
+ # cf-token.sh - deterministic Cloudflare per-scope token resolver.
3
+ #
4
+ # Owns the cfat_/cfut_ prefix decision and the mint-or-reuse state machine that
5
+ # api.md "Token type - route endpoints by prefix" and "Provisioning and reusing
6
+ # a stable per-scope token" describe, so the agent never guesses a token
7
+ # endpoint. curl + jq only (the cloudflare skill binds API calls to curl/jq).
8
+ #
9
+ # Usage: cf-token.sh <scope> <secrets-file>
10
+ # scope in {pages, d1, dns, access}
11
+ # Output: stdout = the secrets key name holding the active token (never a value).
12
+ # stderr = a [cf-token] lifeline and, on failure, the endpoint + code.
13
+ # Exit: 0 when the scope token is active/reused and persisted; non-zero else.
14
+ set -u
15
+
16
+ API="https://api.cloudflare.com/client/v4"
17
+ BACKOFF="${CF_BACKOFF_SECONDS:-3}"
18
+ RETRIES="${CF_VERIFY_RETRIES:-10}"
19
+
20
+ die() { echo "[cf-token] error: $*" >&2; exit 1; }
21
+
22
+ scope="${1:-}"; secrets="${2:-}"
23
+ case "$scope" in pages|d1|dns|access) ;; *) die "unknown scope '${scope}'; use pages|d1|dns|access";; esac
24
+ [ -n "$secrets" ] && [ -r "$secrets" ] || die "secrets file not readable: '${secrets}'"
25
+
26
+ # Load credentials (api.md load-credentials pre-flight). :? aborts if unset/empty,
27
+ # so a credential-unloaded call can never reach the API.
28
+ set -a; . "$secrets"; set +a
29
+ : "${CLOUDFLARE_API_TOKEN:?credentials not loaded - source the secrets file before any call}"
30
+ : "${CLOUDFLARE_ACCOUNT_ID:?account id not loaded - source the secrets file before any call}"
31
+ ACC="$CLOUDFLARE_ACCOUNT_ID"
32
+
33
+ # Brand for the minted token name: CF_TOKEN_BRAND overrides; else the <brand>-code
34
+ # path segment of the secrets file; else fail closed (no guessed name).
35
+ brand="${CF_TOKEN_BRAND:-}"
36
+ if [ -z "$brand" ]; then
37
+ case "$secrets" in
38
+ */*-code/*) brand="$(printf '%s\n' "$secrets" | tr '/' '\n' | grep -E -- '-code$' | head -1)";;
39
+ esac
40
+ fi
41
+ [ -n "$brand" ] || die "cannot derive brand from path; set CF_TOKEN_BRAND"
42
+
43
+ # Scope table - resolved by case, never inferred.
44
+ legacy=""
45
+ case "$scope" in
46
+ pages|d1) suffix="pages-d1"; key="CF_PAGES_D1_TOKEN"; legacy="CF_PAGES_TOKEN"
47
+ # per-group regexes separated by ';' (each may use '|' internally)
48
+ regexes="pages.*(write|edit);d1.*(write|edit)"; res='{"com.cloudflare.api.account.'"$ACC"'":"*"}';;
49
+ dns) suffix="dns"; key="CF_DNS_TOKEN"
50
+ regexes="dns.*(write|edit)"; res='{"com.cloudflare.api.account.zone.*":"*"}';;
51
+ access) suffix="access"; key="CF_ACCESS_TOKEN"
52
+ regexes="access.*apps.*polic.*(write|edit)"; res='{"com.cloudflare.api.account.'"$ACC"'":"*"}';;
53
+ esac
54
+ name="${brand}-${suffix}"
55
+
56
+ read_key() { grep -m1 "^$1=" "$secrets" 2>/dev/null | cut -d= -f2-; }
57
+ prefix_tag() { case "$CLOUDFLARE_API_TOKEN" in cfat_*) echo cfat;; cfut_*) echo cfut;; *) echo other;; esac; }
58
+
59
+ # --- Reuse path: a persisted token is already active (api.md). No verify, no mint.
60
+ existing="$(read_key "$key")"; used_key="$key"
61
+ if [ -z "$existing" ] && [ -n "$legacy" ]; then
62
+ existing="$(read_key "$legacy")"; [ -n "$existing" ] && used_key="$legacy"
63
+ fi
64
+ if [ -n "$existing" ]; then
65
+ echo "[cf-token] op=resolve scope=${scope} master=$(prefix_tag) action=reuse result=active code=0" >&2
66
+ printf '%s\n' "$used_key"; exit 0
67
+ fi
68
+
69
+ # --- Mint path: route strictly by master prefix. Any other prefix fails closed.
70
+ case "$CLOUDFLARE_API_TOKEN" in
71
+ cfat_*) base="$API/accounts/$ACC"; mtag=cfat;;
72
+ cfut_*) base="$API/user"; mtag=cfut;;
73
+ *) echo "[cf-token] op=resolve scope=${scope} master=other action=mint result=error code=0" >&2
74
+ die "unrecognised master token prefix (not cfat_/cfut_); refusing to guess an endpoint";;
75
+ esac
76
+
77
+ api_get() { curl -sS -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" "$1"; }
78
+
79
+ # Resolve permission-group id(s) by name regex (case-insensitive).
80
+ pg_json="$(api_get "${base}/tokens/permission_groups")"
81
+ echo "$pg_json" | jq -e '.success==true' >/dev/null 2>&1 || {
82
+ code=$(echo "$pg_json" | jq -r '.errors[0].code // "?"')
83
+ echo "[cf-token] op=resolve scope=${scope} master=${mtag} action=mint result=error code=${code}" >&2
84
+ die "permission_groups failed at ${base}/tokens/permission_groups code=${code}"
85
+ }
86
+
87
+ collect_ids() { echo "$pg_json" | jq -r --arg re "$1" '.result[] | select(.name|test($re;"i")) | .id'; }
88
+
89
+ mint_with() { # $1 = json permission_groups array -> echoes minted token value or empty
90
+ local body
91
+ body=$(jq -cn --arg n "$name" --argjson res "$res" --argjson pg "$1" \
92
+ '{name:$n, policies:[{effect:"allow", resources:$res, permission_groups:$pg}]}')
93
+ curl -sS -X POST -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
94
+ -H "Content-Type: application/json" "${base}/tokens" --data "$body" \
95
+ | jq -r '.result.value // empty'
96
+ }
97
+
98
+ verify_token() { # $1 token -> echoes "active" or the failing code; retries transient 10000
99
+ local i s
100
+ s=""
101
+ for i in $(seq 1 "$RETRIES"); do
102
+ s=$(curl -sS -H "Authorization: Bearer $1" "${base}/tokens/verify" \
103
+ | jq -r '.result.status // (.errors[0].code | tostring) // "error"')
104
+ [ "$s" = "active" ] && { echo active; return 0; }
105
+ [ "$s" = "10000" ] && { sleep "$BACKOFF"; continue; }
106
+ echo "$s"; return 1
107
+ done
108
+ echo "$s"; return 1
109
+ }
110
+
111
+ finish() { # $1 token value -> persist under canonical key, report, exit 0
112
+ ( umask 077; printf '%s=%s\n' "$key" "$1" >> "$secrets" )
113
+ echo "[cf-token] op=resolve scope=${scope} master=${mtag} action=mint result=active code=0" >&2
114
+ printf '%s\n' "$key"; exit 0
115
+ }
116
+
117
+ if [ "$scope" = "access" ]; then
118
+ # The "Access: Apps and Policies Write" group can resolve to more than one id;
119
+ # the wrong one yields a token that returns 10000 on every call, reads included.
120
+ # Try each candidate, mint+verify, then a functional read; keep the one that works.
121
+ candidates="$(collect_ids "$regexes")"
122
+ [ -n "$candidates" ] || {
123
+ echo "[cf-token] op=resolve scope=access master=${mtag} action=mint result=error code=0" >&2
124
+ die "no permission group matched /${regexes}/"; }
125
+ for cid in $candidates; do
126
+ tok=$(mint_with "$(jq -cn --arg id "$cid" '[{id:$id}]')")
127
+ [ -n "$tok" ] || continue
128
+ st=$(verify_token "$tok"); [ "$st" = "active" ] || continue
129
+ fn=$(curl -sS -H "Authorization: Bearer $tok" "${base}/access/apps" \
130
+ | jq -r '.success // (.errors[0].code|tostring)')
131
+ [ "$fn" = "true" ] && finish "$tok"
132
+ # else poison id - try the next candidate
133
+ done
134
+ echo "[cf-token] op=resolve scope=access master=${mtag} action=mint result=error code=10000" >&2
135
+ die "every Access permission-group candidate returned 10000 on a functional read (poison id)"
136
+ else
137
+ pg_array='[]'
138
+ OLDIFS=$IFS; IFS=';'
139
+ for rx in $regexes; do
140
+ id=$(collect_ids "$rx" | head -1)
141
+ [ -n "$id" ] || {
142
+ IFS=$OLDIFS
143
+ echo "[cf-token] op=resolve scope=${scope} master=${mtag} action=mint result=error code=0" >&2
144
+ die "no permission group matched /${rx}/"; }
145
+ pg_array=$(echo "$pg_array" | jq -c --arg id "$id" '. + [{id:$id}]')
146
+ done
147
+ IFS=$OLDIFS
148
+ tok=$(mint_with "$pg_array")
149
+ [ -n "$tok" ] || {
150
+ echo "[cf-token] op=resolve scope=${scope} master=${mtag} action=mint result=error code=0" >&2
151
+ die "mint returned no token value at ${base}/tokens"; }
152
+ st=$(verify_token "$tok")
153
+ [ "$st" = "active" ] || {
154
+ echo "[cf-token] op=resolve scope=${scope} master=${mtag} action=mint result=error code=${st}" >&2
155
+ die "verify failed code=${st} at ${base}/tokens/verify"; }
156
+ finish "$tok"
157
+ fi