@rubytech/create-sitedesk-code 0.1.509 → 0.1.511

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 (272) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-07-26-task-1902-account-owned-entry-declarations.md +555 -0
  3. package/payload/platform/docs/superpowers/plans/2026-07-26-task-2023-sidebar-sessions-async-reads.md +394 -0
  4. package/payload/platform/docs/superpowers/specs/2026-07-26-task-1902-account-owned-entry-declarations-design.md +232 -0
  5. package/payload/platform/docs/superpowers/specs/2026-07-26-task-2014-ui-suite-nondeterminism-design.md +169 -0
  6. package/payload/platform/plugins/admin/PLUGIN.md +1 -0
  7. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
  8. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +10 -0
  9. package/payload/platform/plugins/business-assistant/PLUGIN.md +1 -0
  10. package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -0
  11. package/payload/platform/plugins/cloudflare/mcp/__tests__/schema-exposed-dirs.test.ts +21 -0
  12. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  13. package/payload/platform/plugins/scheduling/PLUGIN.md +1 -0
  14. package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +112 -4
  15. package/payload/platform/scripts/lib/account-schema-owned-dirs.py +61 -32
  16. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  17. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +17 -30
  18. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  19. package/payload/platform/services/claude-session-manager/dist/config.d.ts +50 -4
  20. package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
  21. package/payload/platform/services/claude-session-manager/dist/config.js +58 -15
  22. package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
  23. package/payload/server/maxy-edge.js +20 -10
  24. package/payload/server/public/assets/AdminLoginScreens-CWMpccrR.css.br +0 -0
  25. package/payload/server/public/assets/AdminLoginScreens-CWMpccrR.css.gz +0 -0
  26. package/payload/server/public/assets/AdminLoginScreens-bksN0XPe.js +1 -0
  27. package/payload/server/public/assets/AdminLoginScreens-bksN0XPe.js.br +0 -0
  28. package/payload/server/public/assets/AdminLoginScreens-bksN0XPe.js.gz +0 -0
  29. package/payload/server/public/assets/AdminShell-BMPEWNZk.js.br +0 -0
  30. package/payload/server/public/assets/AdminShell-BMPEWNZk.js.gz +0 -0
  31. package/payload/server/public/assets/_baseFor-Be3EKK3K.js.br +0 -0
  32. package/payload/server/public/assets/_baseFor-Be3EKK3K.js.gz +0 -0
  33. package/payload/server/public/assets/activity-ByWYF5dC.js.br +0 -0
  34. package/payload/server/public/assets/activity-ByWYF5dC.js.gz +0 -0
  35. package/payload/server/public/assets/admin-Do53K90C.js +1 -0
  36. package/payload/server/public/assets/admin-Do53K90C.js.br +0 -0
  37. package/payload/server/public/assets/admin-Do53K90C.js.gz +0 -0
  38. package/payload/server/public/assets/agents-C0rTfrYd.js.br +0 -0
  39. package/payload/server/public/assets/agents-C0rTfrYd.js.gz +0 -0
  40. package/payload/server/public/assets/arc-DaI5MLTq.js.br +0 -0
  41. package/payload/server/public/assets/arc-DaI5MLTq.js.gz +0 -0
  42. package/payload/server/public/assets/architecture-YZFGNWBL-DWZIX5aV.js.br +0 -0
  43. package/payload/server/public/assets/architectureDiagram-Q4EWVU46-CBGVUEN9.js.br +0 -0
  44. package/payload/server/public/assets/architectureDiagram-Q4EWVU46-CBGVUEN9.js.gz +0 -0
  45. package/payload/server/public/assets/array-X0JlPOfd.js.br +0 -0
  46. package/payload/server/public/assets/blockDiagram-DXYQGD6D-DS6dS4GZ.js.br +0 -0
  47. package/payload/server/public/assets/blockDiagram-DXYQGD6D-DS6dS4GZ.js.gz +0 -0
  48. package/payload/server/public/assets/browser-4tTaem8N.js.br +0 -0
  49. package/payload/server/public/assets/browser-4tTaem8N.js.gz +0 -0
  50. package/payload/server/public/assets/c4Diagram-AHTNJAMY-hBSBUZPt.js.br +0 -0
  51. package/payload/server/public/assets/c4Diagram-AHTNJAMY-hBSBUZPt.js.gz +0 -0
  52. package/payload/server/public/assets/calendar-BEjnkKG1.js.br +0 -0
  53. package/payload/server/public/assets/calendar-BEjnkKG1.js.gz +0 -0
  54. package/payload/server/public/assets/channel-BEokjAeE.js.br +0 -0
  55. package/payload/server/public/assets/chat-DBgzjDIE.js.br +0 -0
  56. package/payload/server/public/assets/chat-DBgzjDIE.js.gz +0 -0
  57. package/payload/server/public/assets/chevron-right-CQfPGsFb.js.br +0 -0
  58. package/payload/server/public/assets/chunk-2KRD3SAO-B6koUoB7.js.br +0 -0
  59. package/payload/server/public/assets/chunk-2KRD3SAO-B6koUoB7.js.gz +0 -0
  60. package/payload/server/public/assets/chunk-336JU56O-BF6BRh8u.js.br +0 -0
  61. package/payload/server/public/assets/chunk-336JU56O-BF6BRh8u.js.gz +0 -0
  62. package/payload/server/public/assets/chunk-426QAEUC-pbQ4PWBU.js.br +0 -0
  63. package/payload/server/public/assets/chunk-426QAEUC-pbQ4PWBU.js.gz +0 -0
  64. package/payload/server/public/assets/chunk-4BX2VUAB-7sO95xR2.js.br +0 -0
  65. package/payload/server/public/assets/chunk-4BX2VUAB-7sO95xR2.js.gz +0 -0
  66. package/payload/server/public/assets/chunk-4TB4RGXK-GCTndJYx.js.br +0 -0
  67. package/payload/server/public/assets/chunk-4TB4RGXK-GCTndJYx.js.gz +0 -0
  68. package/payload/server/public/assets/chunk-55IACEB6-ggIJf_TC.js.br +0 -0
  69. package/payload/server/public/assets/chunk-55IACEB6-ggIJf_TC.js.gz +0 -0
  70. package/payload/server/public/assets/chunk-5FUZZQ4R-DeGmkimt.js.br +0 -0
  71. package/payload/server/public/assets/chunk-5FUZZQ4R-DeGmkimt.js.gz +0 -0
  72. package/payload/server/public/assets/chunk-5PVQY5BW-aFIQKk_U.js.br +0 -0
  73. package/payload/server/public/assets/chunk-5PVQY5BW-aFIQKk_U.js.gz +0 -0
  74. package/payload/server/public/assets/chunk-67CJDMHE-LS8rUbii.js.br +2 -0
  75. package/payload/server/public/assets/chunk-67CJDMHE-LS8rUbii.js.gz +0 -0
  76. package/payload/server/public/assets/chunk-7N4EOEYR-JKOVngS0.js.br +2 -0
  77. package/payload/server/public/assets/chunk-7N4EOEYR-JKOVngS0.js.gz +0 -0
  78. package/payload/server/public/assets/chunk-AA7GKIK3-CoXnTVK6.js.br +0 -0
  79. package/payload/server/public/assets/chunk-AA7GKIK3-CoXnTVK6.js.gz +0 -0
  80. package/payload/server/public/assets/chunk-BSJP7CBP-CcsqObFg.js.br +0 -0
  81. package/payload/server/public/assets/chunk-BSJP7CBP-CcsqObFg.js.gz +0 -0
  82. package/payload/server/public/assets/chunk-CIAEETIT-CpsybR7q.js.br +0 -0
  83. package/payload/server/public/assets/chunk-CIAEETIT-CpsybR7q.js.gz +0 -0
  84. package/payload/server/public/assets/chunk-CltuBf4Z.js.br +0 -0
  85. package/payload/server/public/assets/chunk-CltuBf4Z.js.gz +0 -0
  86. package/payload/server/public/assets/chunk-EDXVE4YY-BZ2I9PSq.js.br +0 -0
  87. package/payload/server/public/assets/chunk-EDXVE4YY-BZ2I9PSq.js.gz +0 -0
  88. package/payload/server/public/assets/chunk-ENJZ2VHE-DbTwt6OZ.js.br +0 -0
  89. package/payload/server/public/assets/chunk-ENJZ2VHE-DbTwt6OZ.js.gz +0 -0
  90. package/payload/server/public/assets/chunk-FMBD7UC4-D27VnSCa.js.br +0 -0
  91. package/payload/server/public/assets/chunk-FMBD7UC4-D27VnSCa.js.gz +0 -0
  92. package/payload/server/public/assets/chunk-FOC6F5B3-C0tU2UFl.js.br +0 -0
  93. package/payload/server/public/assets/chunk-FOC6F5B3-C0tU2UFl.js.gz +0 -0
  94. package/payload/server/public/assets/chunk-ICPOFSXX-UPPu2OIq.js.br +0 -0
  95. package/payload/server/public/assets/chunk-ICPOFSXX-UPPu2OIq.js.gz +0 -0
  96. package/payload/server/public/assets/chunk-K5T4RW27-DIKxqyYw.js.br +0 -0
  97. package/payload/server/public/assets/chunk-K5T4RW27-DIKxqyYw.js.gz +0 -0
  98. package/payload/server/public/assets/chunk-KGLVRYIC-CiL4YVLo.js.br +0 -0
  99. package/payload/server/public/assets/chunk-KGLVRYIC-CiL4YVLo.js.gz +0 -0
  100. package/payload/server/public/assets/chunk-LIHQZDEY-ejKezVlD.js.br +0 -0
  101. package/payload/server/public/assets/chunk-LIHQZDEY-ejKezVlD.js.gz +0 -0
  102. package/payload/server/public/assets/chunk-ORNJ4GCN-Cc0vqc-D.js.br +0 -0
  103. package/payload/server/public/assets/chunk-ORNJ4GCN-Cc0vqc-D.js.gz +0 -0
  104. package/payload/server/public/assets/chunk-OYMX7WX6-Drxn1qG0.js.br +0 -0
  105. package/payload/server/public/assets/chunk-OYMX7WX6-Drxn1qG0.js.gz +0 -0
  106. package/payload/server/public/assets/chunk-QZHKN3VN-Dhlh7Pkk.js.br +0 -0
  107. package/payload/server/public/assets/chunk-QZHKN3VN-Dhlh7Pkk.js.gz +0 -0
  108. package/payload/server/public/assets/chunk-U2HBQHQK-DnbQIkRP.js.br +0 -0
  109. package/payload/server/public/assets/chunk-U2HBQHQK-DnbQIkRP.js.gz +0 -0
  110. package/payload/server/public/assets/chunk-X2U36JSP-CauTSVWg.js.br +0 -0
  111. package/payload/server/public/assets/chunk-X2U36JSP-CauTSVWg.js.gz +0 -0
  112. package/payload/server/public/assets/chunk-XPW4576I-DZqqB9Zi.js.br +0 -0
  113. package/payload/server/public/assets/chunk-XPW4576I-DZqqB9Zi.js.gz +0 -0
  114. package/payload/server/public/assets/chunk-YZCP3GAM-BGHo4Li-.js.br +0 -0
  115. package/payload/server/public/assets/chunk-YZCP3GAM-BGHo4Li-.js.gz +0 -0
  116. package/payload/server/public/assets/chunk-ZZ45TVLE-DWGJKPd7.js.br +0 -0
  117. package/payload/server/public/assets/chunk-ZZ45TVLE-DWGJKPd7.js.gz +0 -0
  118. package/payload/server/public/assets/classDiagram-6PBFFD2Q-D2z_ZV1x.js.br +0 -0
  119. package/payload/server/public/assets/classDiagram-6PBFFD2Q-D2z_ZV1x.js.gz +0 -0
  120. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BJwJoNEK.js.br +0 -0
  121. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BJwJoNEK.js.gz +0 -0
  122. package/payload/server/public/assets/clock-Dn6FHB51.js.br +0 -0
  123. package/payload/server/public/assets/clock-Dn6FHB51.js.gz +0 -0
  124. package/payload/server/public/assets/clone-Bn7XXVhr.js.br +0 -0
  125. package/payload/server/public/assets/cose-bilkent-S5V4N54A-D-95BzXL.js.br +0 -0
  126. package/payload/server/public/assets/cose-bilkent-S5V4N54A-D-95BzXL.js.gz +0 -0
  127. package/payload/server/public/assets/cytoscape.esm-CI2IWMLB.js.br +0 -0
  128. package/payload/server/public/assets/cytoscape.esm-CI2IWMLB.js.gz +0 -0
  129. package/payload/server/public/assets/dagre-BZYNBHvT.js.br +0 -0
  130. package/payload/server/public/assets/dagre-BZYNBHvT.js.gz +0 -0
  131. package/payload/server/public/assets/dagre-KV5264BT-DyU4HQLQ.js.br +0 -0
  132. package/payload/server/public/assets/dagre-KV5264BT-DyU4HQLQ.js.gz +0 -0
  133. package/payload/server/public/assets/data-D_e6Vdfd.js.br +0 -0
  134. package/payload/server/public/assets/data-D_e6Vdfd.js.gz +0 -0
  135. package/payload/server/public/assets/defaultLocale-B6RGN4id.js.br +0 -0
  136. package/payload/server/public/assets/defaultLocale-B6RGN4id.js.gz +0 -0
  137. package/payload/server/public/assets/diagram-5BDNPKRD-CCttJ9XA.js.br +0 -0
  138. package/payload/server/public/assets/diagram-5BDNPKRD-CCttJ9XA.js.gz +0 -0
  139. package/payload/server/public/assets/diagram-G4DWMVQ6-DvkpgSLO.js.br +0 -0
  140. package/payload/server/public/assets/diagram-G4DWMVQ6-DvkpgSLO.js.gz +0 -0
  141. package/payload/server/public/assets/diagram-MMDJMWI5-DHmW5Y9k.js.br +0 -0
  142. package/payload/server/public/assets/diagram-MMDJMWI5-DHmW5Y9k.js.gz +0 -0
  143. package/payload/server/public/assets/diagram-TYMM5635-C6T4hwzO.js.br +0 -0
  144. package/payload/server/public/assets/diagram-TYMM5635-C6T4hwzO.js.gz +0 -0
  145. package/payload/server/public/assets/dist-QvbmK1IP.js.br +0 -0
  146. package/payload/server/public/assets/dist-QvbmK1IP.js.gz +0 -0
  147. package/payload/server/public/assets/erDiagram-SMLLAGMA-5v_o7s3T.js.br +0 -0
  148. package/payload/server/public/assets/erDiagram-SMLLAGMA-5v_o7s3T.js.gz +0 -0
  149. package/payload/server/public/assets/file-text-DMKw3nIk.js.br +0 -0
  150. package/payload/server/public/assets/file-text-DMKw3nIk.js.gz +0 -0
  151. package/payload/server/public/assets/flatten-BtIc9jX7.js.br +0 -0
  152. package/payload/server/public/assets/flatten-BtIc9jX7.js.gz +0 -0
  153. package/payload/server/public/assets/flowDiagram-DWJPFMVM-3UhCDsjt.js.br +0 -0
  154. package/payload/server/public/assets/flowDiagram-DWJPFMVM-3UhCDsjt.js.gz +0 -0
  155. package/payload/server/public/assets/ganttDiagram-T4ZO3ILL-F2zgHIIQ.js.br +0 -0
  156. package/payload/server/public/assets/ganttDiagram-T4ZO3ILL-F2zgHIIQ.js.gz +0 -0
  157. package/payload/server/public/assets/gitGraph-7Q5UKJZL-C-FvNTHZ.js.br +0 -0
  158. package/payload/server/public/assets/gitGraphDiagram-UUTBAWPF-oQc1N3dT.js.br +0 -0
  159. package/payload/server/public/assets/gitGraphDiagram-UUTBAWPF-oQc1N3dT.js.gz +0 -0
  160. package/payload/server/public/assets/graph-C3vW8lvw.js.br +0 -0
  161. package/payload/server/public/assets/graph-C3vW8lvw.js.gz +0 -0
  162. package/payload/server/public/assets/graph-labels-BZgd0L6n.js.br +0 -0
  163. package/payload/server/public/assets/graph-labels-BZgd0L6n.js.gz +0 -0
  164. package/payload/server/public/assets/graphlib-DY4-AT2Q.js.br +0 -0
  165. package/payload/server/public/assets/graphlib-DY4-AT2Q.js.gz +0 -0
  166. package/payload/server/public/assets/info-OMHHGYJF-BjLPgHAC.js.br +0 -0
  167. package/payload/server/public/assets/infoDiagram-42DDH7IO-CXNKLTui.js.br +0 -0
  168. package/payload/server/public/assets/infoDiagram-42DDH7IO-CXNKLTui.js.gz +0 -0
  169. package/payload/server/public/assets/init-BmUWJJHz.js.br +0 -0
  170. package/payload/server/public/assets/init-BmUWJJHz.js.gz +0 -0
  171. package/payload/server/public/assets/isEmpty-Bu4fZ8Kf.js.br +0 -0
  172. package/payload/server/public/assets/isEmpty-Bu4fZ8Kf.js.gz +0 -0
  173. package/payload/server/public/assets/ishikawaDiagram-UXIWVN3A-wJhSOkuw.js.br +0 -0
  174. package/payload/server/public/assets/ishikawaDiagram-UXIWVN3A-wJhSOkuw.js.gz +0 -0
  175. package/payload/server/public/assets/journeyDiagram-VCZTEJTY-DgadC6Pz.js.br +0 -0
  176. package/payload/server/public/assets/journeyDiagram-VCZTEJTY-DgadC6Pz.js.gz +0 -0
  177. package/payload/server/public/assets/kanban-definition-6JOO6SKY-Bs4nQqXI.js.br +0 -0
  178. package/payload/server/public/assets/kanban-definition-6JOO6SKY-Bs4nQqXI.js.gz +0 -0
  179. package/payload/server/public/assets/katex-BjZuzSQn.js.br +0 -0
  180. package/payload/server/public/assets/katex-BjZuzSQn.js.gz +0 -0
  181. package/payload/server/public/assets/line-Bnmxy1hO.js.br +0 -0
  182. package/payload/server/public/assets/line-Bnmxy1hO.js.gz +0 -0
  183. package/payload/server/public/assets/linear-RvwZxFzh.js.br +0 -0
  184. package/payload/server/public/assets/linear-RvwZxFzh.js.gz +0 -0
  185. package/payload/server/public/assets/maximize-2-la3IBA3M.js.br +0 -0
  186. package/payload/server/public/assets/maximize-2-la3IBA3M.js.gz +0 -0
  187. package/payload/server/public/assets/mermaid-parser.core-DeNV8RtA.js.br +0 -0
  188. package/payload/server/public/assets/mermaid-parser.core-DeNV8RtA.js.gz +0 -0
  189. package/payload/server/public/assets/mermaid.core-BU9IiSCP.js.br +0 -0
  190. package/payload/server/public/assets/mermaid.core-BU9IiSCP.js.gz +0 -0
  191. package/payload/server/public/assets/mindmap-definition-QFDTVHPH-D1PMUxxm.js.br +0 -0
  192. package/payload/server/public/assets/mindmap-definition-QFDTVHPH-D1PMUxxm.js.gz +0 -0
  193. package/payload/server/public/assets/{operator-RRRdqoRQ.js → operator-D9NgVL9_.js} +1 -1
  194. package/payload/server/public/assets/operator-D9NgVL9_.js.br +0 -0
  195. package/payload/server/public/assets/operator-D9NgVL9_.js.gz +0 -0
  196. package/payload/server/public/assets/ordinal-C2TEWKNu.js.br +0 -0
  197. package/payload/server/public/assets/ordinal-C2TEWKNu.js.gz +0 -0
  198. package/payload/server/public/assets/packet-4T2RLAQJ-BBAZASfb.js.br +0 -0
  199. package/payload/server/public/assets/page-BWFHRIAH.js.br +0 -0
  200. package/payload/server/public/assets/page-BWFHRIAH.js.gz +0 -0
  201. package/payload/server/public/assets/page-DC11gesX.js.br +0 -0
  202. package/payload/server/public/assets/page-DC11gesX.js.gz +0 -0
  203. package/payload/server/public/assets/path-CoPyR7c2.js.br +0 -0
  204. package/payload/server/public/assets/path-CoPyR7c2.js.gz +0 -0
  205. package/payload/server/public/assets/pdf-render-C257cidb.js.br +0 -0
  206. package/payload/server/public/assets/pdf-render-C257cidb.js.gz +0 -0
  207. package/payload/server/public/assets/pdf.worker.min-yatZIOMy.mjs.br +0 -0
  208. package/payload/server/public/assets/pdf.worker.min-yatZIOMy.mjs.gz +0 -0
  209. package/payload/server/public/assets/pie-ZZUOXDRM-CCJUnMeG.js.br +0 -0
  210. package/payload/server/public/assets/pieDiagram-DEJITSTG-BzdNzoKA.js.br +0 -0
  211. package/payload/server/public/assets/pieDiagram-DEJITSTG-BzdNzoKA.js.gz +0 -0
  212. package/payload/server/public/assets/preload-helper-BQrMkyGX.js.br +0 -0
  213. package/payload/server/public/assets/preload-helper-BQrMkyGX.js.gz +0 -0
  214. package/payload/server/public/assets/public-DQbbLHQN.js.br +0 -0
  215. package/payload/server/public/assets/public-DQbbLHQN.js.gz +0 -0
  216. package/payload/server/public/assets/quadrantDiagram-34T5L4WZ-oFr1MJRO.js.br +0 -0
  217. package/payload/server/public/assets/quadrantDiagram-34T5L4WZ-oFr1MJRO.js.gz +0 -0
  218. package/payload/server/public/assets/radar-PYXPWWZC-BsRU8Aep.js.br +0 -0
  219. package/payload/server/public/assets/reduce-BGpN5lgn.js.br +0 -0
  220. package/payload/server/public/assets/reduce-BGpN5lgn.js.gz +0 -0
  221. package/payload/server/public/assets/requirementDiagram-MS252O5E-C9QBQxDh.js.br +0 -0
  222. package/payload/server/public/assets/requirementDiagram-MS252O5E-C9QBQxDh.js.gz +0 -0
  223. package/payload/server/public/assets/rotate-ccw-OQD5si8N.js.br +0 -0
  224. package/payload/server/public/assets/rotate-ccw-OQD5si8N.js.gz +0 -0
  225. package/payload/server/public/assets/rough.esm-jSt7UMyi.js.br +0 -0
  226. package/payload/server/public/assets/rough.esm-jSt7UMyi.js.gz +0 -0
  227. package/payload/server/public/assets/routines-asrBGZUR.js.br +0 -0
  228. package/payload/server/public/assets/routines-asrBGZUR.js.gz +0 -0
  229. package/payload/server/public/assets/sankeyDiagram-XADWPNL6-c_y3bvVv.js.br +0 -0
  230. package/payload/server/public/assets/sankeyDiagram-XADWPNL6-c_y3bvVv.js.gz +0 -0
  231. package/payload/server/public/assets/sequenceDiagram-FGHM5R23-YwlCBPHE.js.br +0 -0
  232. package/payload/server/public/assets/sequenceDiagram-FGHM5R23-YwlCBPHE.js.gz +0 -0
  233. package/payload/server/public/assets/skills-D4ECwoxa.js.br +0 -0
  234. package/payload/server/public/assets/skills-D4ECwoxa.js.gz +0 -0
  235. package/payload/server/public/assets/src-C2WwTWSY.js.br +0 -0
  236. package/payload/server/public/assets/src-C2WwTWSY.js.gz +0 -0
  237. package/payload/server/public/assets/stateDiagram-FHFEXIEX-BFE3e-FM.js.br +0 -0
  238. package/payload/server/public/assets/stateDiagram-FHFEXIEX-BFE3e-FM.js.gz +0 -0
  239. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CpjB4ykI.js.br +4 -0
  240. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CpjB4ykI.js.gz +0 -0
  241. package/payload/server/public/assets/tasks-U3QdbUsO.js.br +0 -0
  242. package/payload/server/public/assets/tasks-U3QdbUsO.js.gz +0 -0
  243. package/payload/server/public/assets/time-entry-format-BgdTKgYr.js.br +0 -0
  244. package/payload/server/public/assets/time-entry-format-BgdTKgYr.js.gz +0 -0
  245. package/payload/server/public/assets/timeline-definition-GMOUNBTQ-azqhmRwZ.js.br +0 -0
  246. package/payload/server/public/assets/timeline-definition-GMOUNBTQ-azqhmRwZ.js.gz +0 -0
  247. package/payload/server/public/assets/treeView-SZITEDCU-BDzhKA6v.js.br +0 -0
  248. package/payload/server/public/assets/treemap-W4RFUUIX-epHpdeWa.js.br +0 -0
  249. package/payload/server/public/assets/triangle-alert-Ck_3VhT9.js.br +0 -0
  250. package/payload/server/public/assets/triangle-alert-Ck_3VhT9.js.gz +0 -0
  251. package/payload/server/public/assets/useCopyFeedback-BdUwyNpa.js.br +0 -0
  252. package/payload/server/public/assets/useCopyFeedback-BdUwyNpa.js.gz +0 -0
  253. package/payload/server/public/assets/useSubAccountSwitcher-CJKjEPNN.js.br +0 -0
  254. package/payload/server/public/assets/useSubAccountSwitcher-CJKjEPNN.js.gz +0 -0
  255. package/payload/server/public/assets/useSubAccountSwitcher-DOWQXDT8.css.br +0 -0
  256. package/payload/server/public/assets/useSubAccountSwitcher-DOWQXDT8.css.gz +0 -0
  257. package/payload/server/public/assets/useVoiceRecorder-ChnBrzbZ.js.br +0 -0
  258. package/payload/server/public/assets/useVoiceRecorder-ChnBrzbZ.js.gz +0 -0
  259. package/payload/server/public/assets/vennDiagram-DHZGUBPP-Da2RfFs8.js.br +0 -0
  260. package/payload/server/public/assets/vennDiagram-DHZGUBPP-Da2RfFs8.js.gz +0 -0
  261. package/payload/server/public/assets/wardley-RL74JXVD-DNSZCrxV.js.br +0 -0
  262. package/payload/server/public/assets/wardleyDiagram-NUSXRM2D-HdrdBYES.js.br +0 -0
  263. package/payload/server/public/assets/wardleyDiagram-NUSXRM2D-HdrdBYES.js.gz +0 -0
  264. package/payload/server/public/assets/wrench-Cpee3C3J.js.br +2 -0
  265. package/payload/server/public/assets/wrench-Cpee3C3J.js.gz +0 -0
  266. package/payload/server/public/assets/xychartDiagram-5P7HB3ND-DMk6rTcQ.js.br +0 -0
  267. package/payload/server/public/assets/xychartDiagram-5P7HB3ND-DMk6rTcQ.js.gz +0 -0
  268. package/payload/server/public/index.html +2 -2
  269. package/payload/server/public/operator.html +2 -2
  270. package/payload/server/server.js +524 -503
  271. package/payload/server/public/assets/AdminLoginScreens-8Jk7hnWH.js +0 -1
  272. package/payload/server/public/assets/admin-CnUWbKcx.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-sitedesk-code",
3
- "version": "0.1.509",
3
+ "version": "0.1.511",
4
4
  "description": "Install SiteDesk — automated back office for independent building contractors",
5
5
  "bin": {
6
6
  "create-sitedesk-code": "./dist/index.js"
@@ -0,0 +1,555 @@
1
+ # Task 1902 account-owned entry declarations Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Every account-root entry the platform or a shipped skill creates is declared by the plugin that owns it, files included, so the standing `op=strays` line names only debris.
6
+
7
+ **Architecture:** `account-schema-owned-dirs.py` gains a second frontmatter key, `account-owned-files`, whose names union into the same `allowed-top-level` block as declared dirs. Nine names move onto six plugin manifests, and the seven file entries in the reconcile's `PROTECTED_TOP_LEVEL` constant are deleted, so the account's own `SCHEMA.md` is the only thing holding them.
8
+
9
+ **Tech Stack:** Python 3 (no deps), bash test harness with hand-rolled asserts, TypeScript with vitest, markdown frontmatter.
10
+
11
+ **Spec:** [`../specs/2026-07-26-task-1902-account-owned-entry-declarations-design.md`](../specs/2026-07-26-task-1902-account-owned-entry-declarations-design.md). Task: [`.tasks/pending/1902-account-owned-entry-declarations-are-incomplete.md`](../../../../.tasks/pending/1902-account-owned-entry-declarations-are-incomplete.md).
12
+
13
+ ## Global Constraints
14
+
15
+ - Every path below is relative to `maxy-code/`. Run every command from `maxy-code/`.
16
+ - A declaration is one single-line JSON array in a PLUGIN.md frontmatter. The resolver's regex captures to end of line (`account-schema-owned-dirs.py:120`), so a multi-line array parses as truncated JSON and is silently skipped.
17
+ - A malformed declaration is skipped and every other declaration still merges. Never let one bad manifest abort the merge.
18
+ - The plugin-owned descriptive region renders a directory as `` - `name/` — description `` and a file as `` - `name` — description ``. The trailing slash is load-bearing: three parsers (`platform/lib/account-schema-regions/src/index.ts:65`, `platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs:42-43`) anchor on it to tell a bucket from anything else. A file must never gain one.
19
+ - Commit trailers on every commit:
20
+ ```
21
+ Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
22
+ Session: 1ff53443-54dd-48a5-9e70-5ef72fd19588
23
+ ```
24
+
25
+ ---
26
+
27
+ ### Task 1: Resolver parses and merges `account-owned-files`
28
+
29
+ **Files:**
30
+ - Modify: `platform/scripts/lib/account-schema-owned-dirs.py:104-172` (`_parse_plugin_md`, `resolve`), `:286-377` (`merge`), `:380-391` (`reconcile`)
31
+ - Test: `platform/scripts/__tests__/account-schema-owned-dirs.test.sh`
32
+
33
+ **Interfaces:**
34
+ - Consumes: nothing from earlier tasks.
35
+ - Produces: `resolve(project_dir)` returns `[{"name": str, "kind": "dir" | "file", "description": str, "plugin": str}]` in declaration order, deduped on `name`, first declarer winning. Every later task reads `name` and `kind`; the old `dir` key is gone.
36
+
37
+ - [ ] **Step 1: Write the failing test**
38
+
39
+ Append to `platform/scripts/__tests__/account-schema-owned-dirs.test.sh`, immediately before the final `echo "PASS=$PASS FAIL=$FAIL"` line:
40
+
41
+ ```bash
42
+ # --- account-owned-files: a declared file joins the same allowed block ---
43
+ # The block is a flat list of names and already carries SCHEMA.md and
44
+ # account.json, so a file needs no second surface. A second plugin declares a
45
+ # malformed value: its key is skipped and the valid declaration still merges.
46
+ TF="$(mktemp -d)"
47
+ mkdir -p "$TF/platform/plugins/filer" "$TF/platform/plugins/broken" \
48
+ "$TF/platform/config" "$TF/platform/templates/account-schema"
49
+ cp "$REAL_TEMPLATE" "$TF/platform/templates/account-schema/SCHEMA.md"
50
+ printf '{"installDir":"files-brand","shipsPremiumBundles":[]}\n' > "$TF/platform/config/brand.json"
51
+ printf -- '---\nname: filer\naccount-owned-files: [{"file": "x.json", "description": "Filer index."}]\n---\n' \
52
+ > "$TF/platform/plugins/filer/PLUGIN.md"
53
+ printf -- '---\nname: broken\naccount-owned-files: [{"file": "y.json"\n---\n' \
54
+ > "$TF/platform/plugins/broken/PLUGIN.md"
55
+ A_TF="$(mktemp -d)"; cp "$TF/platform/templates/account-schema/SCHEMA.md" "$A_TF/SCHEMA.md"
56
+ export PROJECT_DIR="$TF/platform"
57
+ OUT_TF="$(merge_owned_dirs_into_schema "$A_TF")"
58
+ ALLOWED_TF="$(awk '/^```allowed-top-level$/{f=1;next} /^```$/{f=0} f' "$A_TF/SCHEMA.md")"
59
+ assert_grep "x.json" "$ALLOWED_TF" "files-allowlist-has-x"
60
+ assert_nogrep "y.json" "$ALLOWED_TF" "files-malformed-skipped"
61
+ assert_grep "added=x.json" "$OUT_TF" "files-added-logged"
62
+ # A file renders without the trailing slash a dir gets; three parsers read that
63
+ # slash to tell a bucket from anything else.
64
+ assert_grep '- `x.json` — Filer index.' "$(cat "$A_TF/SCHEMA.md")" "files-region-no-slash"
65
+ assert_nogrep '- `x.json/`' "$(cat "$A_TF/SCHEMA.md")" "files-region-not-a-dir"
66
+ RC_TF="$(PROJECT_DIR="$PROJECT_DIR" python3 "$PLAT_SCRIPTS/lib/account-schema-owned-dirs.py" reconcile "$A_TF")"
67
+ assert_grep "ownedFile=x.json present=true" "$RC_TF" "files-reconcile-line"
68
+ B_TF="$(shasum "$A_TF/SCHEMA.md" | awk '{print $1}')"
69
+ merge_owned_dirs_into_schema "$A_TF" >/dev/null
70
+ assert_eq "$(shasum "$A_TF/SCHEMA.md" | awk '{print $1}')" "$B_TF" "files-idempotent"
71
+
72
+ # A dir declaration keeps its slash and its ownedDir= reconcile line.
73
+ TD="$(mktemp -d)"
74
+ mkdir -p "$TD/platform/plugins/dirred" "$TD/platform/config" "$TD/platform/templates/account-schema"
75
+ cp "$REAL_TEMPLATE" "$TD/platform/templates/account-schema/SCHEMA.md"
76
+ printf '{"installDir":"dirs-brand","shipsPremiumBundles":[]}\n' > "$TD/platform/config/brand.json"
77
+ printf -- '---\nname: dirred\naccount-owned-dirs: [{"dir": "widgets", "description": "Widget workspace."}]\n---\n' \
78
+ > "$TD/platform/plugins/dirred/PLUGIN.md"
79
+ A_TD="$(mktemp -d)"; cp "$TD/platform/templates/account-schema/SCHEMA.md" "$A_TD/SCHEMA.md"
80
+ export PROJECT_DIR="$TD/platform"
81
+ merge_owned_dirs_into_schema "$A_TD" >/dev/null
82
+ assert_grep '- `widgets/` — Widget workspace.' "$(cat "$A_TD/SCHEMA.md")" "dirs-region-keeps-slash"
83
+ RC_TD="$(PROJECT_DIR="$PROJECT_DIR" python3 "$PLAT_SCRIPTS/lib/account-schema-owned-dirs.py" reconcile "$A_TD")"
84
+ assert_grep "ownedDir=widgets present=true" "$RC_TD" "dirs-reconcile-line"
85
+ ```
86
+
87
+ - [ ] **Step 2: Run test to verify it fails**
88
+
89
+ Run: `bash platform/scripts/__tests__/account-schema-owned-dirs.test.sh`
90
+ Expected: FAIL, listing `files-allowlist-has-x`, `files-added-logged`, `files-region-no-slash`, `files-reconcile-line`. `dirs-*` cases pass already.
91
+
92
+ - [ ] **Step 3: Write minimal implementation**
93
+
94
+ In `platform/scripts/lib/account-schema-owned-dirs.py`, replace the docstring's declaration example (lines 5-7) with both keys:
95
+
96
+ ```python
97
+ A plugin declares owned top-level account entries in its PLUGIN.md frontmatter,
98
+ by kind:
99
+
100
+ account-owned-dirs: [{"dir": "quoting", "description": "..."}]
101
+ account-owned-files: [{"file": "data-portal.json", "description": "..."}]
102
+ ```
103
+
104
+ Replace the owned-parsing block of `_parse_plugin_md` (lines 105, 119-130) with:
105
+
106
+ ```python
107
+ """Return (name, [ {name, kind, description} ]) from a PLUGIN.md, or (None, []).
108
+ Two frontmatter keys, one list: `account-owned-dirs` yields kind='dir',
109
+ `account-owned-files` yields kind='file'. A key whose value is not a JSON
110
+ array of objects is skipped whole; the other key and every other plugin
111
+ still merge, because one hand-edited manifest must never empty the set."""
112
+ owned = []
113
+ for key, field, kind in (("account-owned-dirs", "dir", "dir"),
114
+ ("account-owned-files", "file", "file")):
115
+ om = re.search(r"^" + key + r":\s*(.+)$", fm, re.MULTILINE)
116
+ if not om:
117
+ continue
118
+ try:
119
+ for e in json.loads(om.group(1).strip()):
120
+ n = (e.get(field) or "").strip()
121
+ if n:
122
+ owned.append({"name": n, "kind": kind,
123
+ "description": (e.get("description") or "").strip()})
124
+ except Exception:
125
+ continue
126
+ return name, owned
127
+ ```
128
+
129
+ Replace `resolve` (lines 160-172) with:
130
+
131
+ ```python
132
+ def resolve(project_dir):
133
+ """Union of owned-entry declarations. First declarer of a name wins its
134
+ owner label + description, whichever kind it declared."""
135
+ seen = {}
136
+ order = []
137
+ for path in _plugin_md_paths(project_dir):
138
+ name, owned = _parse_plugin_md(path)
139
+ for e in owned:
140
+ if e["name"] in seen:
141
+ continue
142
+ seen[e["name"]] = {"name": e["name"], "kind": e["kind"],
143
+ "description": e["description"], "plugin": name or "unknown"}
144
+ order.append(e["name"])
145
+ return [seen[n] for n in order]
146
+ ```
147
+
148
+ In `merge`, replace the three `e["dir"]` reads. Line 307 becomes:
149
+
150
+ ```python
151
+ target = FIXED_SEED | {e["name"] for e in owned} | {b["dir"] for b in domain if _is_root(b["owner"])}
152
+ ```
153
+
154
+ Lines 321-324 become:
155
+
156
+ ```python
157
+ for e in owned:
158
+ if e["name"] not in present and e["name"] not in insert:
159
+ insert.append(e["name"])
160
+ added.append(e["name"])
161
+ ```
162
+
163
+ Lines 343-345 (the region body) become:
164
+
165
+ ```python
166
+ for e in owned:
167
+ desc = e["description"] or f"Owned by the {e['plugin']} plugin."
168
+ head = f"{e['name']}/" if e["kind"] == "dir" else e["name"]
169
+ region.append(f"- `{head}` — {desc}")
170
+ ```
171
+
172
+ Line 348 becomes:
173
+
174
+ ```python
175
+ owned_dirs = {e["name"] for e in owned if e["kind"] == "dir"}
176
+ ```
177
+
178
+ In `reconcile`, replace lines 389-391 with:
179
+
180
+ ```python
181
+ for e in owned:
182
+ is_present = "true" if e["name"] in present else "false"
183
+ label = "ownedDir" if e["kind"] == "dir" else "ownedFile"
184
+ print(f"brand={brand} plugin={e['plugin']} {label}={e['name']} present={is_present}")
185
+ ```
186
+
187
+ - [ ] **Step 4: Run test to verify it passes**
188
+
189
+ Run: `bash platform/scripts/__tests__/account-schema-owned-dirs.test.sh`
190
+ Expected: `FAIL=0`.
191
+
192
+ - [ ] **Step 5: Mutation check**
193
+
194
+ Delete the `("account-owned-files", "file", "file")` tuple from the loop in `_parse_plugin_md`, re-run the suite, and confirm the four `files-*` cases fail. Restore the tuple and confirm `FAIL=0` again.
195
+
196
+ - [ ] **Step 6: Commit**
197
+
198
+ ```bash
199
+ git add platform/scripts/lib/account-schema-owned-dirs.py platform/scripts/__tests__/account-schema-owned-dirs.test.sh
200
+ git commit -m "feat(account-schema): declare account-owned files, not only dirs"
201
+ ```
202
+
203
+ ---
204
+
205
+ ### Task 2: Pin that a declared file is not a bucket
206
+
207
+ **Files:**
208
+ - Test: `platform/ui/server/lib/__tests__/account-schema-regions.test.ts`
209
+
210
+ **Interfaces:**
211
+ - Consumes: the region line shape Task 1 produces (`` - `x.json` — desc ``).
212
+ - Produces: nothing. This task adds no production code; it pins existing behaviour that Task 1 now depends on.
213
+
214
+ The two region parsers already require a trailing slash inside the backticks (`account-schema-regions/src/index.ts:65`, `schema-exposed-dirs.mjs:42-43`), so a file line yields no bucket. That is correct and must stay correct: `pluginOwned` feeds the `/data` page grouping and the public data-portal exposure set, and a file leaking into either would put a control-plane file in front of a client.
215
+
216
+ - [ ] **Step 1: Write the test**
217
+
218
+ Add to `platform/ui/server/lib/__tests__/account-schema-regions.test.ts`, inside the existing describe block for `parseSchemaRegions`:
219
+
220
+ ```ts
221
+ it('does not read a declared file as a plugin-owned bucket', () => {
222
+ // Task 1902 — the plugin-owned region now carries file lines. `pluginOwned`
223
+ // feeds the /data grouping and the public exposure set, so a file must not
224
+ // enter it. The trailing slash inside the backticks is the discriminator.
225
+ const schema = [
226
+ '```allowed-top-level',
227
+ 'projects',
228
+ 'data-portal.json',
229
+ '```',
230
+ '',
231
+ '<!-- plugin-owned-dirs:start -->',
232
+ '- `pages/` — Cloudflare Pages deploy staging.',
233
+ '- `data-portal.json` — the account data-portal index.',
234
+ '<!-- plugin-owned-dirs:end -->',
235
+ ].join('\n')
236
+ const r = parseSchemaRegions(schema)
237
+ expect(r.pluginOwned).toEqual(['pages'])
238
+ expect(r.allowedTopLevel).toContain('data-portal.json')
239
+ })
240
+ ```
241
+
242
+ - [ ] **Step 2: Run the test**
243
+
244
+ Run: `cd platform/ui && npx vitest run server/lib/__tests__/account-schema-regions.test.ts`
245
+ Expected: PASS. This case pins current behaviour rather than driving new code, so it passes on first run.
246
+
247
+ - [ ] **Step 3: Mutation check**
248
+
249
+ In `platform/lib/account-schema-regions/src/index.ts:65`, change `DIR_LINE` to `/^-\s+`([^`]+?)\/?`/` so the slash becomes optional. Re-run the test and confirm it fails with `pluginOwned` holding `data-portal.json`. Revert the regex and confirm it passes.
250
+
251
+ - [ ] **Step 4: Commit**
252
+
253
+ ```bash
254
+ git add platform/ui/server/lib/__tests__/account-schema-regions.test.ts
255
+ git commit -m "test(account-schema): pin that a declared file is not a plugin-owned bucket"
256
+ ```
257
+
258
+ ---
259
+
260
+ ### Task 3: Declare the nine entries on their owning plugins
261
+
262
+ **Files:**
263
+ - Modify: `platform/plugins/business-assistant/PLUGIN.md`, `platform/plugins/cloudflare/PLUGIN.md`, `platform/plugins/scheduling/PLUGIN.md`, `platform/plugins/whatsapp/PLUGIN.md`, `platform/plugins/telegram/PLUGIN.md`, `platform/plugins/admin/PLUGIN.md`
264
+ - Test: `platform/scripts/__tests__/account-schema-owned-dirs.test.sh`
265
+
266
+ **Interfaces:**
267
+ - Consumes: `account-owned-files` parsing from Task 1.
268
+ - Produces: nine names in every account's merged `allowed-top-level` block: `e-sign`, `data-portal.json`, `calendar-availability.json`, `wa-channel-bindings.json`, `telegram-channel-bindings.json`, `webchat-channel-bindings.json`, `canonical-webchat-session.json`, `session-titles.json`, `agents-disabled.json`. Task 4 deletes the constant that holds seven of them today.
269
+
270
+ - [ ] **Step 1: Write the failing test**
271
+
272
+ Append to `platform/scripts/__tests__/account-schema-owned-dirs.test.sh`, before the final `echo "PASS=$PASS FAIL=$FAIL"`:
273
+
274
+ ```bash
275
+ # --- shipped declarations reach an account's allowed block ---
276
+ # Symlink the real plugin dirs so the case exercises the shipped PLUGIN.md
277
+ # frontmatter, the same way the Task 1891 pages/archive case does.
278
+ T_SHIP="$(make_tree '[]')"
279
+ for _p in business-assistant cloudflare scheduling whatsapp telegram admin; do
280
+ ln -s "$REAL_PROJECT_DIR/plugins/$_p" "$T_SHIP/platform/plugins/$_p"
281
+ done
282
+ A_SHIP="$(make_account "$T_SHIP")"
283
+ export PROJECT_DIR="$T_SHIP/platform"
284
+ merge_owned_dirs_into_schema "$A_SHIP" >/dev/null
285
+ ALLOWED_SHIP="$(awk '/^```allowed-top-level$/{f=1;next} /^```$/{f=0} f' "$A_SHIP/SCHEMA.md")"
286
+ for _n in e-sign data-portal.json calendar-availability.json wa-channel-bindings.json \
287
+ telegram-channel-bindings.json webchat-channel-bindings.json \
288
+ canonical-webchat-session.json session-titles.json agents-disabled.json; do
289
+ assert_grep "$_n" "$ALLOWED_SHIP" "ship-allow-$_n"
290
+ done
291
+ ```
292
+
293
+ - [ ] **Step 2: Run test to verify it fails**
294
+
295
+ Run: `bash platform/scripts/__tests__/account-schema-owned-dirs.test.sh`
296
+ Expected: FAIL, listing all nine `ship-allow-*` cases.
297
+
298
+ - [ ] **Step 3: Add the declarations**
299
+
300
+ Each is one new line inside the frontmatter. Insert each immediately before the anchor line named for that file.
301
+
302
+ `platform/plugins/business-assistant/PLUGIN.md`, before the `metadata:` line (line 4):
303
+
304
+ ```
305
+ account-owned-dirs: [{"dir": "e-sign", "description": "Per-document e-sign workspace: the render-once base.pdf, its base.sha256, and the per-signer stamped copies. Written by the e-sign skill; its internal structure is skill-owned and recreated on the next document."}]
306
+ ```
307
+
308
+ `platform/plugins/cloudflare/PLUGIN.md`, before the `tools: []` line (line 4):
309
+
310
+ ```
311
+ account-owned-files: [{"file": "data-portal.json", "description": "The account's data-portal folder index, written by bin/portal-index-push.mjs on every push."}]
312
+ ```
313
+
314
+ `platform/plugins/scheduling/PLUGIN.md`, before the `tools:` line (line 4):
315
+
316
+ ```
317
+ account-owned-files: [{"file": "calendar-availability.json", "description": "The booking page's availability config, written by the publish-availability script and read by the live booking page."}]
318
+ ```
319
+
320
+ `platform/plugins/whatsapp/PLUGIN.md`, before the `tools:` line (line 4):
321
+
322
+ ```
323
+ account-owned-files: [{"file": "wa-channel-bindings.json", "description": "Routes this account's inbound WhatsApp messages. Written by the session manager's wa-channel-store."}]
324
+ ```
325
+
326
+ `platform/plugins/telegram/PLUGIN.md`, before the `tools:` line (line 5):
327
+
328
+ ```
329
+ account-owned-files: [{"file": "telegram-channel-bindings.json", "description": "Routes this account's inbound Telegram messages. Written by the session manager's telegram-channel-store."}]
330
+ ```
331
+
332
+ `platform/plugins/admin/PLUGIN.md`, before the `tools:` line (line 5):
333
+
334
+ ```
335
+ account-owned-files: [{"file": "webchat-channel-bindings.json", "description": "Routes this account's inbound admin webchat messages. Written by the session manager's webchat-channel-store."}, {"file": "canonical-webchat-session.json", "description": "Pins the account's canonical webchat session. Written by the admin UI server."}, {"file": "session-titles.json", "description": "Operator renames of sessions. Written by the session manager's title stores."}, {"file": "agents-disabled.json", "description": "Names the agents the operator switched off. Written by the admin agents route and seeded at provision."}]
336
+ ```
337
+
338
+ - [ ] **Step 4: Run test to verify it passes**
339
+
340
+ Run: `bash platform/scripts/__tests__/account-schema-owned-dirs.test.sh`
341
+ Expected: `FAIL=0`.
342
+
343
+ - [ ] **Step 5: Verify each manifest still parses as one declaration**
344
+
345
+ Run:
346
+
347
+ ```bash
348
+ PROJECT_DIR="$PWD/platform" python3 platform/scripts/lib/account-schema-owned-dirs.py resolve | python3 -m json.tool | grep -c '"name"'
349
+ ```
350
+
351
+ Expected: `11`. The repo tree carries no `platform/config/brand.json` (it is written at bundle time), so `_read_brand` resolves no premium bundles and the set is exactly the nine new names plus `archive` (memory) and `pages` (storage-broker). A lower count means one manifest's JSON is truncated and was silently skipped.
352
+
353
+ - [ ] **Step 6: Commit**
354
+
355
+ ```bash
356
+ git add platform/plugins/business-assistant/PLUGIN.md platform/plugins/cloudflare/PLUGIN.md platform/plugins/scheduling/PLUGIN.md platform/plugins/whatsapp/PLUGIN.md platform/plugins/telegram/PLUGIN.md platform/plugins/admin/PLUGIN.md platform/scripts/__tests__/account-schema-owned-dirs.test.sh
357
+ git commit -m "feat(plugins): declare the account-root entries each plugin owns"
358
+ ```
359
+
360
+ ---
361
+
362
+ ### Task 4: Shrink `PROTECTED_TOP_LEVEL` to the account's own machinery
363
+
364
+ **Files:**
365
+ - Modify: `platform/services/claude-session-manager/src/account-dir-schema-reconcile.ts:37-75`
366
+ - Test: `platform/services/claude-session-manager/src/__tests__/account-dir-schema-reconcile.test.ts:36-49` (the `seedAccount` helper), `:193-215` and `:310-325` (the two belt tests)
367
+
368
+ **Interfaces:**
369
+ - Consumes: the nine declarations from Task 3, which reach an account through its `SCHEMA.md`.
370
+ - Produces: `PROTECTED_TOP_LEVEL` holding exactly `.git`, `.claude`, `.quarantine`, `SCHEMA.md`, `account.json`, `AGENTS.md`. `seedAccount(id, extraAllowed?)` gains an optional second parameter appending names to the seeded allowed block.
371
+
372
+ - [ ] **Step 1: Write the failing tests**
373
+
374
+ In `platform/services/claude-session-manager/src/__tests__/account-dir-schema-reconcile.test.ts`, replace the `seedAccount` signature and its schema write (lines 36-39) with:
375
+
376
+ ```ts
377
+ function seedAccount(id: string, extraAllowed: string[] = []): string {
378
+ const dir = join(root, id)
379
+ mkdirSync(dir, { recursive: true })
380
+ // Task 1902 — a reprovisioned account's allowed block carries the names its
381
+ // plugins declare, so a test about strays seeds the schema the reconcile
382
+ // actually reads rather than a constant that no longer holds them.
383
+ const schema = extraAllowed.length
384
+ ? SCHEMA.replace('\n```\n', `\n${extraAllowed.join('\n')}\n\`\`\`\n`)
385
+ : SCHEMA
386
+ writeFileSync(join(dir, 'SCHEMA.md'), schema)
387
+ ```
388
+
389
+ Replace the body and comment of the test at line 193 (`never counts platform-written control-plane root files absent from the allowed block`) with:
390
+
391
+ ```ts
392
+ it('never counts control-plane root files the account schema declares', () => {
393
+ // Each of these is declared by the plugin whose feature owns it (Task 1902),
394
+ // so a reprovisioned account carries them in its allowed block and the
395
+ // reconcile reads them from there. Before the declarations existed a
396
+ // hand-maintained constant held them, extended once per casualty:
397
+ // calendar-availability.json was Task 1877, after quarantining it froze a
398
+ // live booking page. A genuine operator stray alongside them is still named.
399
+ const controlFiles = [
400
+ 'calendar-availability.json',
401
+ 'wa-channel-bindings.json',
402
+ 'webchat-channel-bindings.json',
403
+ 'telegram-channel-bindings.json',
404
+ 'canonical-webchat-session.json',
405
+ 'session-titles.json',
406
+ ]
407
+ const dir = seedAccount('acct-control-files', controlFiles)
408
+ for (const f of controlFiles) writeFileSync(join(dir, f), '{}')
409
+ mkdirSync(join(dir, 'workers')) // a genuine operator stray
410
+ const c = reconcileAccount(dir)
411
+ expect(c.strayTopLevel).toBe(1)
412
+ expect(c.strayNames).toEqual(['workers'])
413
+ for (const f of controlFiles) expect(existsSync(join(dir, f))).toBe(true)
414
+ })
415
+
416
+ it('counts a control-plane file as a stray when the schema has not been re-merged', () => {
417
+ // The stated consequence of retiring the constant (Task 1902): an account
418
+ // whose SCHEMA.md predates the declarations reports these files. setup-account.sh
419
+ // runs the all-accounts merge on every install, so the window is one upgrade
420
+ // wide, and the reconcile's ownedFile= lines name any account it has not reached.
421
+ const dir = seedAccount('acct-stale-schema')
422
+ writeFileSync(join(dir, 'session-titles.json'), '{}')
423
+ const c = reconcileAccount(dir)
424
+ expect(c.strayNames).toEqual(['session-titles.json'])
425
+ })
426
+ ```
427
+
428
+ Replace the seed line of the test at line 315 (`does not count the disabled store itself as a stray`) with:
429
+
430
+ ```ts
431
+ const acct = seedAccount('has-store', ['agents-disabled.json'])
432
+ ```
433
+
434
+ and replace the comment above that test with:
435
+
436
+ ```ts
437
+ // The store is a platform-written account-root file declared by the admin
438
+ // plugin (Task 1902), so a reprovisioned account carries it in its allowed
439
+ // block. Without the declaration every account with a disabled agent reports
440
+ // a permanent false stray on the line whose whole point is to name only what
441
+ // an operator must act on.
442
+ ```
443
+
444
+ - [ ] **Step 2: Run tests to verify the new one fails**
445
+
446
+ Run: `cd platform/services/claude-session-manager && npx vitest run src/__tests__/account-dir-schema-reconcile.test.ts`
447
+ Expected: FAIL on `counts a control-plane file as a stray when the schema has not been re-merged`, with `strayNames` empty, because `PROTECTED_TOP_LEVEL` still holds `session-titles.json`. The two rewritten tests pass already, since a declared name in the allowed block is honoured whether or not the constant also holds it.
448
+
449
+ - [ ] **Step 3: Shrink the constant**
450
+
451
+ In `platform/services/claude-session-manager/src/account-dir-schema-reconcile.ts`, replace the `PROTECTED_TOP_LEVEL` doc comment and set (lines 37-75) with:
452
+
453
+ ```ts
454
+ /** The account's own machinery, which the reconcile NEVER counts as a stray
455
+ * whatever that account's SCHEMA.md allowed set says. provision-account-dir.sh
456
+ * makes the account dir a git root (`.git`) and writes its hook-enforcement
457
+ * settings into `.claude/`; the account's identity lives in account.json;
458
+ * AGENTS.md and SCHEMA.md are refreshed on every provision. An account carrying
459
+ * a stale, hand-edited or older-template schema must not be reported every run
460
+ * for machinery it is required to have.
461
+ *
462
+ * Feature files at the account root are NOT here. Each is declared by the plugin
463
+ * whose feature owns it (Task 1902, `account-owned-files` in PLUGIN.md
464
+ * frontmatter), unioned into the account's allowed block by
465
+ * platform/scripts/lib/account-schema-owned-dirs.py, and read from there. The
466
+ * constant used to hold seven of them and was extended once per casualty
467
+ * (calendar-availability.json was Task 1877, agents-disabled.json Task 1996),
468
+ * which is the growth this replaces. setup-account.sh runs the all-accounts
469
+ * merge on every install, so a declaration reaches existing accounts, and the
470
+ * reconcile's ownedFile= lines name any account it has not reached. */
471
+ const PROTECTED_TOP_LEVEL = new Set([
472
+ '.git',
473
+ '.claude',
474
+ QUARANTINE_DIR,
475
+ 'SCHEMA.md',
476
+ 'account.json',
477
+ 'AGENTS.md',
478
+ ])
479
+ ```
480
+
481
+ - [ ] **Step 4: Run tests to verify they pass**
482
+
483
+ Run: `cd platform/services/claude-session-manager && npx vitest run`
484
+ Expected: all files pass. If another suite fails naming one of the seven files, that suite seeds an account schema without the declaration and needs the same `extraAllowed` treatment.
485
+
486
+ - [ ] **Step 5: Mutation check**
487
+
488
+ Add `'session-titles.json'` back to `PROTECTED_TOP_LEVEL`, re-run, and confirm `counts a control-plane file as a stray when the schema has not been re-merged` fails. Remove it and confirm the suite passes.
489
+
490
+ - [ ] **Step 6: Commit**
491
+
492
+ ```bash
493
+ git add platform/services/claude-session-manager/src/account-dir-schema-reconcile.ts platform/services/claude-session-manager/src/__tests__/account-dir-schema-reconcile.test.ts
494
+ git commit -m "refactor(fs-reconcile): let declarations hold the control-plane root files"
495
+ ```
496
+
497
+ ---
498
+
499
+ ### Task 5: Sync the doc that describes the merge
500
+
501
+ **Files:**
502
+ - Modify: `.docs/data-portal-folder-index.md:76-80`
503
+
504
+ **Interfaces:**
505
+ - Consumes: the merge behaviour from Tasks 1 and 3.
506
+ - Produces: nothing consumed by code.
507
+
508
+ `.docs/data-portal-folder-index.md` is the authoritative description of how the allowed set is built. It says the set is `fixed-seed ∪ plugin-owned ∪ ontology-buckets` and describes plugin-owned as dirs.
509
+
510
+ - [ ] **Step 1: Edit the doc**
511
+
512
+ Replace the first paragraph of the section `## The allowed set is reconciled, not appended` (the sentence beginning `Each `merge()` rebuilds`) with:
513
+
514
+ ```markdown
515
+ Each `merge()` rebuilds the `allowed-top-level` list to `fixed-seed ∪
516
+ plugin-owned ∪ ontology-buckets`, so it tracks the current vertical ontology
517
+ instead of growing forever. Plugin-owned covers both kinds: a plugin declares a
518
+ directory with `account-owned-dirs` and a file with `account-owned-files`
519
+ (Task 1902), and both land as bare names in the same flat list, which already
520
+ carries `SCHEMA.md` and `account.json`. Only the descriptive region tells them
521
+ apart, by the trailing slash a directory gets and a file does not, which is what
522
+ keeps a declared file out of the `/data` page grouping and the public exposure
523
+ set. The fixed seed is the base template names plus `.quarantine`; it is
524
+ prune-protection only and never adds a missing entry.
525
+ ```
526
+
527
+ - [ ] **Step 2: Verify no other doc claims dirs only**
528
+
529
+ Run: `/usr/bin/grep -rn "account-owned-dirs" .docs platform/plugins/docs README.md`
530
+ Expected: hits only in `.docs/data-portal-folder-index.md` (the sentence just written) and in spec or plan files under `platform/docs/superpowers/`, which are historical records and stay as written.
531
+
532
+ - [ ] **Step 3: Commit**
533
+
534
+ ```bash
535
+ git add .docs/data-portal-folder-index.md
536
+ git commit -m "docs: the allowed set unions declared files as well as dirs"
537
+ ```
538
+
539
+ ---
540
+
541
+ ## Verification (whole plan)
542
+
543
+ - [ ] `bash platform/scripts/__tests__/account-schema-owned-dirs.test.sh` reports `FAIL=0`.
544
+ - [ ] `cd platform/services/claude-session-manager && npx vitest run` passes.
545
+ - [ ] `cd platform/ui && npx vitest run server/lib/__tests__/account-schema-regions.test.ts server/lib/__tests__/account-root-groups-parity.test.ts` passes.
546
+ - [ ] `cd platform/services/claude-session-manager && npx tsc --noEmit` reports no errors.
547
+ - [ ] Both mutation checks (Task 1 Step 5, Task 4 Step 5) fail as described and are reverted.
548
+
549
+ ## Out of scope
550
+
551
+ Reprovisioning the laptop and the two device checks that need it: task
552
+ [`2027-reprovision-laptop-accounts-after-1902-declarations.md`](../../../../.tasks/pending/2027-reprovision-laptop-accounts-after-1902-declarations.md).
553
+ Declaring `clients`, `workers`, `specs`, `templates`, `sites-staging` or `repo`,
554
+ which no shipped component writes. Relocating agent work product, which is Task
555
+ 1894.