@rubytech/create-maxy-code 0.1.478 → 0.1.480

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 (252) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1789-reseat-channel-row-fork.md +1244 -0
  3. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1818-loop-gate-app-routes.md +462 -0
  4. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1819-top-level-label-allowlist.md +321 -0
  5. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1829-platform-ui-typecheck.md +830 -0
  6. package/payload/platform/docs/superpowers/plans/2026-07-20-task-1831-data-portal-class-derived-allowlist.md +2177 -0
  7. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1789-reseat-channel-row-fork-design.md +201 -0
  8. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1818-loop-gate-app-routes-design.md +217 -0
  9. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1819-top-level-label-allowlist-design.md +80 -0
  10. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1829-platform-ui-typecheck-design.md +163 -0
  11. package/payload/platform/docs/superpowers/specs/2026-07-20-task-1831-data-portal-class-derived-allowlist-design.md +163 -0
  12. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
  13. package/payload/platform/lib/graph-style/dist/index.js +22 -0
  14. package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
  15. package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +6 -0
  16. package/payload/platform/lib/graph-style/src/index.ts +20 -0
  17. package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +155 -12
  18. package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
  19. package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +3 -0
  20. package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
  21. package/payload/platform/lib/storage-broker/dist/cf-exec.js +68 -28
  22. package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
  23. package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +194 -16
  24. package/payload/platform/lib/storage-broker/src/cf-exec.ts +74 -29
  25. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +13 -1
  26. package/payload/platform/plugins/cloudflare/PLUGIN.md +26 -1
  27. package/payload/platform/plugins/cloudflare/bin/d1-http.mjs +80 -0
  28. package/payload/platform/plugins/cloudflare/bin/portal-enrol.mjs +17 -2
  29. package/payload/platform/plugins/cloudflare/bin/portal-index-push.mjs +357 -0
  30. package/payload/platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs +103 -0
  31. package/payload/platform/plugins/cloudflare/mcp/__tests__/authorize.test.ts +2 -2
  32. package/payload/platform/plugins/cloudflare/mcp/__tests__/d1-http.test.ts +96 -0
  33. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-directory-listing.test.ts +120 -0
  34. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-enrol.test.ts +59 -4
  35. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-push.test.ts +176 -0
  36. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-state-contract.test.ts +75 -0
  37. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-indexed-download.test.ts +131 -0
  38. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-sign.test.ts +68 -0
  39. package/payload/platform/plugins/cloudflare/mcp/__tests__/schema-exposed-dirs.test.ts +88 -0
  40. package/payload/platform/plugins/cloudflare/mcp/__tests__/template-config.test.ts +39 -0
  41. package/payload/platform/plugins/cloudflare/skills/data-portal/SKILL.md +68 -1
  42. package/payload/platform/plugins/cloudflare/skills/data-portal/schema.sql +30 -1
  43. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/portal-sign.mjs +87 -0
  44. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/session.ts +8 -4
  45. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/_lib/types.ts +10 -0
  46. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/download.ts +107 -1
  47. package/payload/platform/plugins/cloudflare/skills/data-portal/template/functions/api/files.ts +82 -2
  48. package/payload/platform/plugins/cloudflare/skills/data-portal/template/index.html +9 -0
  49. package/payload/platform/plugins/cloudflare/skills/data-portal/template/portal.css +56 -0
  50. package/payload/platform/plugins/cloudflare/skills/data-portal/template/portal.js +98 -2
  51. package/payload/platform/plugins/cloudflare/skills/data-portal/template/wrangler.toml +12 -0
  52. package/payload/platform/plugins/docs/references/cloudflare.md +12 -0
  53. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js +41 -1
  54. package/payload/platform/plugins/outlook/mcp/dist/__tests__/device-flow.test.js.map +1 -1
  55. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js +249 -2
  56. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js.map +1 -1
  57. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js +127 -3
  58. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js.map +1 -1
  59. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts +17 -0
  60. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.d.ts.map +1 -1
  61. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js +26 -1
  62. package/payload/platform/plugins/outlook/mcp/dist/auth/device-flow.js.map +1 -1
  63. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts +37 -1
  64. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts.map +1 -1
  65. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js +126 -5
  66. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js.map +1 -1
  67. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +18 -0
  68. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -1
  69. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +123 -18
  70. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -1
  71. package/payload/platform/plugins/outlook/references/auth.md +45 -2
  72. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.d.ts +2 -0
  73. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.d.ts.map +1 -0
  74. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.js +66 -0
  75. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/portal-index-audit.test.js.map +1 -0
  76. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.d.ts +41 -0
  77. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.d.ts.map +1 -0
  78. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.js +75 -0
  79. package/payload/platform/plugins/scheduling/mcp/dist/lib/portal-index-audit.js.map +1 -0
  80. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +122 -0
  81. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  82. package/payload/server/{chunk-3XLLTG6R.js → chunk-REWXLAPC.js} +30 -10
  83. package/payload/server/package.json +1 -1
  84. package/payload/server/public/activity.html +7 -6
  85. package/payload/server/public/assets/{AdminLoginScreens-DR5eLF-a.js → AdminLoginScreens-DXYJWXaX.js} +1 -1
  86. package/payload/server/public/assets/AdminShell-UDgNN4CA.js +2 -0
  87. package/payload/server/public/assets/Checkbox-C08Ulc_a.js +1 -0
  88. package/payload/server/public/assets/activity-06gsRDVv.js +1 -0
  89. package/payload/server/public/assets/admin-BhiHyORH.js +1 -0
  90. package/payload/server/public/assets/{arc-BrHWN2Kr.js → arc-BHXuzTwg.js} +1 -1
  91. package/payload/server/public/assets/architecture-YZFGNWBL-Ct5q6ks1.js +1 -0
  92. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Clt9NOr0.js → architectureDiagram-Q4EWVU46-DsN_vxau.js} +1 -1
  93. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BOe_jmXi.js → blockDiagram-DXYQGD6D-CvNat1uB.js} +1 -1
  94. package/payload/server/public/assets/browser-Cz4IKS47.js +1 -0
  95. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-B64FaKMV.js → c4Diagram-AHTNJAMY-E9yqTPTW.js} +1 -1
  96. package/payload/server/public/assets/calendar-D0xtNqH8.js +1 -0
  97. package/payload/server/public/assets/channel-PE9vBKEQ.js +1 -0
  98. package/payload/server/public/assets/chat-DwLJ830n.js +1 -0
  99. package/payload/server/public/assets/chevron-left-Cv-TFuEf.js +1 -0
  100. package/payload/server/public/assets/{chunk-2KRD3SAO-BGAUfWvM.js → chunk-2KRD3SAO-DpzI_0EY.js} +1 -1
  101. package/payload/server/public/assets/{chunk-336JU56O-PFi6uQZ0.js → chunk-336JU56O-eR_I9Eu4.js} +2 -2
  102. package/payload/server/public/assets/chunk-426QAEUC-BDNZtJsz.js +1 -0
  103. package/payload/server/public/assets/{chunk-4BX2VUAB-CkxXXCiF.js → chunk-4BX2VUAB-D-6xk1t8.js} +1 -1
  104. package/payload/server/public/assets/{chunk-4TB4RGXK-B-7tN4IA.js → chunk-4TB4RGXK-BkqUcFpL.js} +1 -1
  105. package/payload/server/public/assets/{chunk-55IACEB6-CBkNmqrt.js → chunk-55IACEB6-ChCl2pSP.js} +1 -1
  106. package/payload/server/public/assets/{chunk-5FUZZQ4R-wa9ujn7i.js → chunk-5FUZZQ4R-DasGsg54.js} +1 -1
  107. package/payload/server/public/assets/{chunk-5PVQY5BW-DIk-xBaE.js → chunk-5PVQY5BW-DXlHUX1h.js} +1 -1
  108. package/payload/server/public/assets/{chunk-67CJDMHE-BbMV1lgW.js → chunk-67CJDMHE-BZfVpTsE.js} +1 -1
  109. package/payload/server/public/assets/{chunk-7N4EOEYR-C49Mv-nQ.js → chunk-7N4EOEYR-C6U5TIgT.js} +1 -1
  110. package/payload/server/public/assets/{chunk-AA7GKIK3-Dy_pJOp_.js → chunk-AA7GKIK3-CA7cVDmw.js} +1 -1
  111. package/payload/server/public/assets/{chunk-BSJP7CBP-Ce-OmPqn.js → chunk-BSJP7CBP-DxN2GC3p.js} +1 -1
  112. package/payload/server/public/assets/{chunk-CIAEETIT-tnjq-APC.js → chunk-CIAEETIT-C0-4wA8y.js} +1 -1
  113. package/payload/server/public/assets/{chunk-EDXVE4YY-Bvv_deZ2.js → chunk-EDXVE4YY--kyb1rLc.js} +1 -1
  114. package/payload/server/public/assets/{chunk-ENJZ2VHE-CmxCPKyU.js → chunk-ENJZ2VHE-FBN6hR7V.js} +1 -1
  115. package/payload/server/public/assets/{chunk-FMBD7UC4-Top6y08S.js → chunk-FMBD7UC4-Lpge4M5g.js} +1 -1
  116. package/payload/server/public/assets/{chunk-FOC6F5B3-B9LPNCUS.js → chunk-FOC6F5B3-CM1rwOou.js} +1 -1
  117. package/payload/server/public/assets/{chunk-ICPOFSXX-Bi-_c351.js → chunk-ICPOFSXX-JdYLY3yu.js} +2 -2
  118. package/payload/server/public/assets/{chunk-K5T4RW27-DAnRM04h.js → chunk-K5T4RW27-DCUblGBr.js} +1 -1
  119. package/payload/server/public/assets/{chunk-KGLVRYIC-C0QYcbLe.js → chunk-KGLVRYIC-BP_cide2.js} +1 -1
  120. package/payload/server/public/assets/{chunk-LIHQZDEY-BjvA5ykt.js → chunk-LIHQZDEY-DjMa1lOl.js} +1 -1
  121. package/payload/server/public/assets/{chunk-ORNJ4GCN-Cs46Gj7z.js → chunk-ORNJ4GCN-D51eJAoV.js} +1 -1
  122. package/payload/server/public/assets/{chunk-OYMX7WX6-BBpimab5.js → chunk-OYMX7WX6-4hWIO544.js} +1 -1
  123. package/payload/server/public/assets/chunk-QZHKN3VN-B_Hris8x.js +1 -0
  124. package/payload/server/public/assets/{chunk-U2HBQHQK-CQUSBHoK.js → chunk-U2HBQHQK-BwdQf9cS.js} +1 -1
  125. package/payload/server/public/assets/{chunk-X2U36JSP-Dm8TevG0.js → chunk-X2U36JSP-DmDxwLOg.js} +1 -1
  126. package/payload/server/public/assets/{chunk-XPW4576I-B10QuxYb.js → chunk-XPW4576I-JQyAB7ND.js} +1 -1
  127. package/payload/server/public/assets/{chunk-YZCP3GAM-vaGsu4Wk.js → chunk-YZCP3GAM-BonLdCzI.js} +1 -1
  128. package/payload/server/public/assets/{chunk-ZZ45TVLE-D1Qi22bL.js → chunk-ZZ45TVLE-BXKB2wSk.js} +1 -1
  129. package/payload/server/public/assets/classDiagram-6PBFFD2Q-D8Q05iMI.js +1 -0
  130. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-Dm3hAxfm.js +1 -0
  131. package/payload/server/public/assets/clone-C-wOwvpY.js +1 -0
  132. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-CRDvLRXs.js → cose-bilkent-S5V4N54A-BDnd4Blw.js} +1 -1
  133. package/payload/server/public/assets/{dagre-CEmqJTt3.js → dagre-BmexzuER.js} +1 -1
  134. package/payload/server/public/assets/{dagre-KV5264BT-LXMTo7Fp.js → dagre-KV5264BT-D4WVuwPj.js} +1 -1
  135. package/payload/server/public/assets/data-DUDJfnjI.js +1 -0
  136. package/payload/server/public/assets/{diagram-5BDNPKRD-zyis6nPt.js → diagram-5BDNPKRD-Bbf4mT8a.js} +1 -1
  137. package/payload/server/public/assets/{diagram-G4DWMVQ6-BiU0XAAD.js → diagram-G4DWMVQ6-BpqVTUmx.js} +1 -1
  138. package/payload/server/public/assets/{diagram-MMDJMWI5-rGFiz1SX.js → diagram-MMDJMWI5-DY-k5k6r.js} +1 -1
  139. package/payload/server/public/assets/{diagram-TYMM5635-B0wak1ZJ.js → diagram-TYMM5635-CXHxwacS.js} +1 -1
  140. package/payload/server/public/assets/{erDiagram-SMLLAGMA-D8AUxLyX.js → erDiagram-SMLLAGMA-BNKEc3l8.js} +1 -1
  141. package/payload/server/public/assets/{flatten-naJ5PJ4f.js → flatten-jn8bZgcI.js} +1 -1
  142. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BtdUf68b.js → flowDiagram-DWJPFMVM-CbAeuJsi.js} +1 -1
  143. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-C-lkzDmf.js → ganttDiagram-T4ZO3ILL-CeeNnL4l.js} +1 -1
  144. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BBHsY16R.js +1 -0
  145. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-DRUKumq2.js → gitGraphDiagram-UUTBAWPF-DG8RCtfg.js} +1 -1
  146. package/payload/server/public/assets/{graph-DRloNic4.js → graph-BAoktBcx.js} +19 -19
  147. package/payload/server/public/assets/graph-labels-LeIhl7ZG.js +1 -0
  148. package/payload/server/public/assets/{graphlib-zRsaoFEC.js → graphlib-BkDExPQi.js} +1 -1
  149. package/payload/server/public/assets/info-OMHHGYJF-C1j5I_zx.js +1 -0
  150. package/payload/server/public/assets/infoDiagram-42DDH7IO-ZWkwHWEu.js +2 -0
  151. package/payload/server/public/assets/{isEmpty-Bnpg7b8f.js → isEmpty-Dkk6_L-B.js} +1 -1
  152. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-BguMgoR8.js → ishikawaDiagram-UXIWVN3A-D_iMHV64.js} +1 -1
  153. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CXhyK1n-.js → journeyDiagram-VCZTEJTY-BvPRpulx.js} +1 -1
  154. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-C0UCWVx-.js → kanban-definition-6JOO6SKY-CkWaXWo2.js} +1 -1
  155. package/payload/server/public/assets/{line--uhS9YDE.js → line-BGQT9unx.js} +1 -1
  156. package/payload/server/public/assets/{linear-CAOWPodQ.js → linear-DzrYI8-8.js} +1 -1
  157. package/payload/server/public/assets/{maximize-2-CzDaBugs.js → maximize-2-2MgPSwlx.js} +1 -1
  158. package/payload/server/public/assets/{mermaid-parser.core-D6kPx7vc.js → mermaid-parser.core-DrMY7FMe.js} +2 -2
  159. package/payload/server/public/assets/{mermaid.core-CTd4DS6O.js → mermaid.core-BWdf6fZ7.js} +3 -3
  160. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-_AyvyG8C.js → mindmap-definition-QFDTVHPH-CgqM9h97.js} +1 -1
  161. package/payload/server/public/assets/operator-CZifmNhp.js +1 -0
  162. package/payload/server/public/assets/{ordinal-Wx4m9zHk.js → ordinal-DuJYM7p1.js} +1 -1
  163. package/payload/server/public/assets/packet-4T2RLAQJ-CGiTbe0N.js +1 -0
  164. package/payload/server/public/assets/{page-ef-6rRPL.js → page-B4kllGd_.js} +6 -6
  165. package/payload/server/public/assets/page-DbfE7QwJ.js +1 -0
  166. package/payload/server/public/assets/{pdf-render-CeX6d2v7.js → pdf-render-riHufgrn.js} +1 -1
  167. package/payload/server/public/assets/pie-ZZUOXDRM-BrK023dE.js +1 -0
  168. package/payload/server/public/assets/{pieDiagram-DEJITSTG-6TsUDkkQ.js → pieDiagram-DEJITSTG-BeUGoYS7.js} +1 -1
  169. package/payload/server/public/assets/public-VtmyYz8E.js +1 -0
  170. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CWw9gOI4.js → quadrantDiagram-34T5L4WZ-CX82WgKy.js} +1 -1
  171. package/payload/server/public/assets/radar-PYXPWWZC-p7NRamXX.js +1 -0
  172. package/payload/server/public/assets/{reduce-BUmc8RDR.js → reduce-COyotL2V.js} +1 -1
  173. package/payload/server/public/assets/{requirementDiagram-MS252O5E-DCOlxNvx.js → requirementDiagram-MS252O5E-CzqebQXj.js} +1 -1
  174. package/payload/server/public/assets/{rotate-ccw-DXEKUhXP.js → rotate-ccw-DaZdB2cz.js} +1 -1
  175. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-CW4Xbir3.js → sankeyDiagram-XADWPNL6-CaHi1yzU.js} +1 -1
  176. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-vhb_pBLG.js → sequenceDiagram-FGHM5R23-BF2AeiKW.js} +1 -1
  177. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Cb1WExEX.js → stateDiagram-FHFEXIEX-DtUCA8Ih.js} +1 -1
  178. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-a4FvB3L8.js +1 -0
  179. package/payload/server/public/assets/tasks-CvqVDbfO.js +1 -0
  180. package/payload/server/public/assets/{time-entry-format-CsYAjplS.js → time-entry-format-TD-PPEIu.js} +1 -1
  181. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BAHTf_AF.js → timeline-definition-GMOUNBTQ-D3Q1YrKY.js} +1 -1
  182. package/payload/server/public/assets/treeView-SZITEDCU-CoWk8VoG.js +1 -0
  183. package/payload/server/public/assets/treemap-W4RFUUIX-BhWeGj8Y.js +1 -0
  184. package/payload/server/public/assets/{triangle-alert-0lSBIUg-.js → triangle-alert-BaLhVNnn.js} +1 -1
  185. package/payload/server/public/assets/useCopyFeedback-BhjPzRa3.js +1 -0
  186. package/payload/server/public/assets/useSubAccountSwitcher-CWRpVt1-.css +1 -0
  187. package/payload/server/public/assets/{useSubAccountSwitcher-BZnzc5C3.js → useSubAccountSwitcher-HEVLb6Z9.js} +2 -2
  188. package/payload/server/public/assets/useVoiceRecorder-CfGgj3vm.js +2 -0
  189. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DtEttvW4.js → vennDiagram-DHZGUBPP-DnjzQDGf.js} +1 -1
  190. package/payload/server/public/assets/wardley-RL74JXVD-C0q3Hqng.js +1 -0
  191. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-K06y6CVJ.js → wardleyDiagram-NUSXRM2D-T3WHrUvi.js} +1 -1
  192. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-D66c40lp.js → xychartDiagram-5P7HB3ND-2Efyv4h2.js} +1 -1
  193. package/payload/server/public/brand-defaults.css +1 -0
  194. package/payload/server/public/browser.html +4 -5
  195. package/payload/server/public/calendar.html +5 -6
  196. package/payload/server/public/chat.html +12 -13
  197. package/payload/server/public/data.html +11 -12
  198. package/payload/server/public/graph.html +10 -11
  199. package/payload/server/public/index.html +14 -15
  200. package/payload/server/public/operator.html +14 -15
  201. package/payload/server/public/privacy.html +1 -0
  202. package/payload/server/public/public.html +12 -13
  203. package/payload/server/public/tasks.html +7 -5
  204. package/payload/server/public/vnc-popout.html +1 -0
  205. package/payload/server/server.js +833 -389
  206. package/payload/server/{src-XQ63FPRE.js → src-JJ6PHO5I.js} +1 -1
  207. package/payload/server/public/assets/AdminShell-D9zaUxPd.js +0 -2
  208. package/payload/server/public/assets/Checkbox-DcbbAIe5.js +0 -1
  209. package/payload/server/public/assets/activity-C9P5NjEZ.js +0 -1
  210. package/payload/server/public/assets/admin-D2KLZnQW.js +0 -1
  211. package/payload/server/public/assets/architecture-YZFGNWBL-CZQzGRSM.js +0 -1
  212. package/payload/server/public/assets/browser-CDWqEiCD.js +0 -1
  213. package/payload/server/public/assets/calendar-BG7fOpbB.js +0 -1
  214. package/payload/server/public/assets/channel-zDUAN9Ks.js +0 -1
  215. package/payload/server/public/assets/chat-RyH-WYQC.js +0 -1
  216. package/payload/server/public/assets/chevron-left-DmXCr6nB.js +0 -1
  217. package/payload/server/public/assets/chunk-426QAEUC-iJnqNRug.js +0 -1
  218. package/payload/server/public/assets/chunk-QZHKN3VN-Qlc2PFAj.js +0 -1
  219. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CFsKL52p.js +0 -1
  220. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BWBUUCiO.js +0 -1
  221. package/payload/server/public/assets/clone-h5XhkDUL.js +0 -1
  222. package/payload/server/public/assets/data-BaY_LkLR.js +0 -1
  223. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CBZPQJLj.js +0 -1
  224. package/payload/server/public/assets/graph-labels-DD-GqS4v.js +0 -1
  225. package/payload/server/public/assets/info-OMHHGYJF-1vIoX-kP.js +0 -1
  226. package/payload/server/public/assets/infoDiagram-42DDH7IO-KHcXRaan.js +0 -2
  227. package/payload/server/public/assets/operator-BZeeyait.js +0 -1
  228. package/payload/server/public/assets/packet-4T2RLAQJ-CTU0gCGb.js +0 -1
  229. package/payload/server/public/assets/page-B0obcg3b.js +0 -1
  230. package/payload/server/public/assets/pie-ZZUOXDRM-D-EEHxhC.js +0 -1
  231. package/payload/server/public/assets/public-9D3MMOkC.js +0 -1
  232. package/payload/server/public/assets/radar-PYXPWWZC-DHXATZGB.js +0 -1
  233. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CxOIKvXh.js +0 -1
  234. package/payload/server/public/assets/tasks-BB0L7e5a.js +0 -1
  235. package/payload/server/public/assets/treeView-SZITEDCU-CC7ouMFd.js +0 -1
  236. package/payload/server/public/assets/treemap-W4RFUUIX-CaCg27im.js +0 -1
  237. package/payload/server/public/assets/useCopyFeedback-jTBQ2h0V.js +0 -1
  238. package/payload/server/public/assets/useSelectionMode-BooArySZ.js +0 -1
  239. package/payload/server/public/assets/useSubAccountSwitcher-D9knHOKq.css +0 -1
  240. package/payload/server/public/assets/useVoiceRecorder-PUT8q_sm.js +0 -2
  241. package/payload/server/public/assets/wardley-RL74JXVD-bMPsqQZ7.js +0 -1
  242. /package/payload/server/public/assets/{_baseFor-k8hYPe-U.js → _baseFor-Bjj9It3Q.js} +0 -0
  243. /package/payload/server/public/assets/{array-BFDiaBgf.js → array-BrrxEo12.js} +0 -0
  244. /package/payload/server/public/assets/{cytoscape.esm-Ch0xptA4.js → cytoscape.esm-CTWJxUxo.js} +0 -0
  245. /package/payload/server/public/assets/{defaultLocale-ZeknFqNe.js → defaultLocale-CFDbRV4k.js} +0 -0
  246. /package/payload/server/public/assets/{dist-B2N0v8hZ.js → dist-BATfy7Sn.js} +0 -0
  247. /package/payload/server/public/assets/{init-0VJVrkRJ.js → init-dXCzGgLP.js} +0 -0
  248. /package/payload/server/public/assets/{katex-Br7bH10N.js → katex-CHA1JFYJ.js} +0 -0
  249. /package/payload/server/public/assets/{path-INs8XTPH.js → path-CCRpdXhK.js} +0 -0
  250. /package/payload/server/public/assets/{preload-helper-D_sPnjeL.js → preload-helper-CH6UZRzu.js} +0 -0
  251. /package/payload/server/public/assets/{rough.esm-DU9bZLvZ.js → rough.esm-Bud4g4fh.js} +0 -0
  252. /package/payload/server/public/assets/{src-DHSQDYx-.js → src-DNdBRXXx.js} +0 -0
@@ -0,0 +1,830 @@
1
+ # Task 1829 — package-wide typecheck for `platform/ui` (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:** Make a type error anywhere in `platform/ui` fail the build, with an empty ignore list.
6
+
7
+ **Architecture:** The gate is built first and used as the measuring instrument for every
8
+ subsequent task — it starts red at 70 errors and each task drives the count down. It is wired into
9
+ `prebuild` only in the final task, so the build is never left broken mid-plan. Every error is
10
+ removed at source; none is suppressed.
11
+
12
+ **Tech Stack:** TypeScript 5.7, `tsc --noEmit`, Node 22.22.0, vitest 4, plain `.mjs` gate scripts
13
+ invoked from `prebuild`.
14
+
15
+ ## Global Constraints
16
+
17
+ - Work in `maxy-code/platform/ui` inside the worktree at
18
+ `/Users/neo/getmaxy/maxy-code/.claude/worktrees/task-1829-platform-ui-typecheck`.
19
+ - Node 22.22.0. Confirm with `node -v` before any `tsc` or `vitest` run.
20
+ - `platform/node_modules` and `platform/ui/node_modules` are symlinks into the parent checkout.
21
+ Never run `npm install` in `platform/ui` — it would mutate the parent's dependency tree. The
22
+ neo4j-driver change in Task 2 is applied to the shadow tree instead; the recipe is in that task.
23
+ - The sibling `platform/lib/*/dist` artefacts must exist before `tsc` runs. `npm run build:lib`
24
+ from `platform/` produces them, clean, in about 24 seconds.
25
+ - Baseline: **80 errors**, measured after `build:lib` with `platform/ui` still resolving
26
+ neo4j-driver to v6. Task 2 takes it to 70. Every task states the count it must leave behind, and
27
+ they chain: 80 → 70 → 62 → 59 → 20 → 0.
28
+ - No error is ever silenced with `@ts-ignore`, `@ts-expect-error`, `any`, or a `tsconfig` exclusion.
29
+ If a fix looks like it needs one, stop and raise it.
30
+ - Commit after each task with a `Session: 25c26868-c975-4386-b247-a6aa53f33090` trailer and
31
+ `Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>`.
32
+
33
+ ---
34
+
35
+ ### Task 1: The gate script — the failing test
36
+
37
+ Build the instrument before the work. It must be observed red at 70 before anything is fixed.
38
+
39
+ **Files:**
40
+ - Create: `platform/ui/scripts/check-types.mjs`
41
+ - Modify: `platform/ui/package.json` (add `typecheck` script only; prebuild is untouched until Task 9)
42
+
43
+ **Interfaces:**
44
+ - Produces: `scripts/check-types.mjs`, runnable as `node scripts/check-types.mjs` from
45
+ `platform/ui`. Exit 0 when `tsc --noEmit` emits no diagnostic; exit 1 otherwise.
46
+
47
+ - [ ] **Step 1: Write the gate**
48
+
49
+ Create `platform/ui/scripts/check-types.mjs`:
50
+
51
+ ```javascript
52
+ #!/usr/bin/env node
53
+
54
+ // Task 1829 — prebuild gate: the whole package must typecheck.
55
+ //
56
+ // Nothing in platform/ui ran the TypeScript compiler until this gate existed.
57
+ // `npm run build` is `vite build && tsup`, both esbuild-backed, and esbuild
58
+ // strips types without reading them. There is no lint script and no CI job that
59
+ // runs the compiler, so a type error in this package shipped.
60
+ //
61
+ // This replaces scripts/check-loop-contract-types.mjs (Task 1825), which ran the
62
+ // compiler and then discarded every error outside six named files. That was the
63
+ // right scope for one page's contract and the wrong shape for a package: six
64
+ // files were gated and roughly three hundred were not. Two gates asserting the
65
+ // same invariant at different scopes is the drift 1825 exists to prevent, so
66
+ // that gate is deleted rather than kept alongside this one.
67
+ //
68
+ // THE IGNORE LIST IS EMPTY, and this gate says so on every run. A gate that
69
+ // starts life with a long ignore list is a gate nobody trusts. The ignored count
70
+ // is printed so that if one is ever added, its growth is visible in build logs
71
+ // rather than inferred.
72
+
73
+ import { spawnSync } from 'node:child_process'
74
+ import { existsSync } from 'node:fs'
75
+ import { resolve, dirname } from 'node:path'
76
+ import { fileURLToPath } from 'node:url'
77
+
78
+ const UI_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
79
+
80
+ // Pre-flight 1: the sibling lib artefacts this package imports.
81
+ //
82
+ // platform/ui imports built sibling libs by relative path into `dist/`. Those
83
+ // are build outputs, gitignored, and absent in a fresh clone or worktree. With
84
+ // them missing the compiler reports fourteen unresolved-import errors that look
85
+ // like source defects and are not — the fix is a build order, not a code change.
86
+ // Checking the artefacts directly turns that into one actionable line.
87
+ const REQUIRED_LIB_DISTS = ['active-rules', 'graph-style', 'graph-trash', 'graph-write', 'ledger-core']
88
+ const missingDists = REQUIRED_LIB_DISTS.filter(
89
+ (lib) => !existsSync(resolve(UI_ROOT, '..', 'lib', lib, 'dist', 'index.js')),
90
+ )
91
+ if (missingDists.length > 0) {
92
+ console.error(
93
+ `[check-types] error lib-dist-missing libs=${missingDists.join(',')}\n` +
94
+ ' These are build outputs, not source. Run `npm run build:lib` from platform/ first.\n' +
95
+ ' Without them tsc reports unresolved-import errors that are a build order problem,\n' +
96
+ ' not a type error, and this gate will not guess which it is looking at.',
97
+ )
98
+ process.exit(1)
99
+ }
100
+
101
+ // Pre-flight 2: the compiler itself.
102
+ const tsc = resolve(UI_ROOT, 'node_modules', '.bin', 'tsc')
103
+ if (!existsSync(tsc)) {
104
+ console.error(
105
+ `[check-types] error tsc-not-found path=${tsc}\n` +
106
+ ' Run `npm install` in platform/ui. This gate cannot check types without the compiler.',
107
+ )
108
+ process.exit(1)
109
+ }
110
+
111
+ const run = spawnSync(tsc, ['--noEmit'], { cwd: UI_ROOT, encoding: 'utf8' })
112
+
113
+ if (run.error) {
114
+ console.error(`[check-types] error tsc-spawn-failed ${run.error.message}`)
115
+ process.exit(1)
116
+ }
117
+
118
+ // tsc writes diagnostics to stdout. A per-file diagnostic is
119
+ // `path(line,col): error TSxxxx: msg`. A configuration or invocation failure
120
+ // (TS5058, TS18003, a malformed tsconfig) has no `path(line,col)` prefix, and
121
+ // when tsc cannot find a project at all it prints help text and emits no
122
+ // diagnostics whatsoever.
123
+ //
124
+ // That distinction is what stops this gate passing blind, and exit status cannot
125
+ // carry it: tsc exits 2 on a normal run that found type errors, and 1 when it
126
+ // cannot locate tsconfig.json. A gate keyed on the status code would read the
127
+ // catastrophe as the milder case. What separates them is whether the compiler
128
+ // produced any parseable diagnostic — a run that found nothing to say AND failed
129
+ // did not typecheck anything.
130
+ const DIAGNOSTIC = /^(.+?)\((\d+),(\d+)\): error TS\d+: /
131
+ const lines = `${run.stdout ?? ''}${run.stderr ?? ''}`.split('\n')
132
+ const errorLines = lines.filter((l) => DIAGNOSTIC.test(l))
133
+ const fatalLines = lines.filter((l) => / error TS\d+: /.test(l) && !DIAGNOSTIC.test(l))
134
+
135
+ if (fatalLines.length > 0) {
136
+ console.error('[check-types] error tsc-configuration-failed')
137
+ for (const l of fatalLines) console.error(` ${l}`)
138
+ console.error(
139
+ '\n The compiler reported an error with no source location, which means it failed before\n' +
140
+ ' typechecking rather than while typechecking. The package has NOT been checked.',
141
+ )
142
+ process.exit(1)
143
+ }
144
+
145
+ if (run.status !== 0 && errorLines.length === 0) {
146
+ console.error(
147
+ `[check-types] error tsc-produced-no-diagnostics status=${run.status}\n` +
148
+ ' tsc exited non-zero and emitted no parseable diagnostic, so it did not typecheck the\n' +
149
+ ' package — most likely tsconfig.json is missing or the invocation is wrong. The package\n' +
150
+ ' has NOT been checked.',
151
+ )
152
+ if (run.stdout) console.error(` first output line: ${run.stdout.split('\n')[0]}`)
153
+ process.exit(1)
154
+ }
155
+
156
+ if (errorLines.length > 0) {
157
+ console.error(`[check-types] FAIL errors=${errorLines.length} ignored=0`)
158
+ for (const l of errorLines) console.error(` ${l}`)
159
+ console.error(
160
+ '\n platform/ui does not typecheck. Fix the type — do not widen it, cast it away, or add\n' +
161
+ ' an ignore entry to this gate.',
162
+ )
163
+ process.exit(1)
164
+ }
165
+
166
+ console.log(`[check-types] ok errors=0 ignored=0 tsc-status=${run.status}`)
167
+ ```
168
+
169
+ - [ ] **Step 2: Add the `typecheck` script**
170
+
171
+ In `platform/ui/package.json`, add to `scripts`, immediately after `"tokens"`:
172
+
173
+ ```json
174
+ "typecheck": "node scripts/check-types.mjs",
175
+ ```
176
+
177
+ Leave `prebuild` alone. It still ends in `check-loop-contract-types.mjs` until Task 9.
178
+
179
+ - [ ] **Step 3: Restore the v6 driver so the baseline is honest**
180
+
181
+ The investigation left `platform/ui/node_modules` as a shadow tree with the v6 driver omitted, to
182
+ prove the downgrade clears 10 errors without installing into the parent. Task 2 is where that
183
+ becomes real. For this task's baseline, put it back to the plain parent symlink:
184
+
185
+ ```bash
186
+ cd maxy-code/platform/ui
187
+ rm -rf node_modules
188
+ ln -sfn /Users/neo/getmaxy/maxy-code/platform/ui/node_modules node_modules
189
+ node -p "require.resolve('neo4j-driver', {paths:[process.cwd()+'/app/lib']})"
190
+ ```
191
+ Expected: the resolve path ends `platform/ui/node_modules/neo4j-driver/lib/index.js` — the v6 copy.
192
+
193
+ - [ ] **Step 4: Build the sibling libs, then run the gate to verify it fails**
194
+
195
+ Run:
196
+ ```bash
197
+ cd maxy-code/platform && npm run build:lib
198
+ cd ../ui && npm run typecheck
199
+ ```
200
+ Expected: exit 1, first line `[check-types] FAIL errors=80 ignored=0`.
201
+
202
+ If the count is not 80, stop — the baseline has moved and the rest of this plan's counts are wrong.
203
+
204
+ - [ ] **Step 5: Verify the dist pre-flight fires**
205
+
206
+ Run:
207
+ ```bash
208
+ mv ../lib/graph-style/dist ../lib/graph-style/dist.bak && npm run typecheck; echo "exit=$?"
209
+ mv ../lib/graph-style/dist.bak ../lib/graph-style/dist
210
+ ```
211
+ Expected: exit 1, `[check-types] error lib-dist-missing libs=graph-style`, and no tsc diagnostics printed.
212
+
213
+ - [ ] **Step 6: Commit**
214
+
215
+ ```bash
216
+ git add maxy-code/platform/ui/scripts/check-types.mjs maxy-code/platform/ui/package.json
217
+ git commit -m "feat(1829): package-wide typecheck gate, not yet wired into prebuild"
218
+ ```
219
+
220
+ ---
221
+
222
+ ### Task 2: Align `neo4j-driver` onto v5 — clears 10
223
+
224
+ `platform/ui` declares `^6.0.1`; the seventeen other packages and everything `platform/lib/*`
225
+ compiles against declare `^5.28.1`. `platform/ui` hands v5-typed lib functions its v6 `Session`
226
+ objects, which is the eight `TS2739` and two `TS2345`.
227
+
228
+ **Files:**
229
+ - Modify: `platform/ui/package.json:39`
230
+
231
+ **Interfaces:**
232
+ - Produces: `platform/ui` resolving `neo4j-driver` to the same 5.28.3 copy at
233
+ `platform/node_modules` that `platform/lib/*` compiles against.
234
+
235
+ - [ ] **Step 1: Change the declared version**
236
+
237
+ In `platform/ui/package.json`, change:
238
+
239
+ ```json
240
+ "neo4j-driver": "^6.0.1",
241
+ ```
242
+ to:
243
+ ```json
244
+ "neo4j-driver": "^5.28.1",
245
+ ```
246
+
247
+ - [ ] **Step 2: Make the installed tree match the declaration**
248
+
249
+ `npm install` here would write into the parent checkout, because `platform/ui/node_modules` is a
250
+ symlink to it. Build a shadow instead: a real directory of per-entry symlinks into the parent, with
251
+ the three v6 driver packages omitted so resolution walks up to `platform/node_modules` and finds
252
+ 5.28.3. This is worktree-local and leaves the parent untouched.
253
+
254
+ ```bash
255
+ cd maxy-code/platform/ui
256
+ P=/Users/neo/getmaxy/maxy-code
257
+ rm node_modules && mkdir node_modules
258
+ for e in "$P/platform/ui/node_modules"/*; do
259
+ b=$(basename "$e")
260
+ case "$b" in neo4j-driver|neo4j-driver-core|neo4j-driver-bolt-connection) continue;; esac
261
+ ln -s "$e" "node_modules/$b"
262
+ done
263
+ for e in "$P/platform/ui/node_modules"/.[!.]*; do
264
+ ln -s "$e" "node_modules/$(basename "$e")" 2>/dev/null || true
265
+ done
266
+ node -p "require.resolve('neo4j-driver', {paths:[process.cwd()+'/app/lib']})"
267
+ ```
268
+ Expected: the resolve path ends `platform/node_modules/neo4j-driver/lib/index.js`.
269
+
270
+ This shadow is a worktree artefact, not a deliverable. On a real checkout the equivalent is
271
+ `npm install` honouring the changed `package.json`. Say so in the debrief — the landed change is one
272
+ line of `package.json`, and whoever installs next gets v5 from npm.
273
+
274
+ - [ ] **Step 3: Run the gate**
275
+
276
+ Run: `npm run typecheck`
277
+ Expected: exit 1, `[check-types] FAIL errors=70 ignored=0`. Confirm no `TS2739` or `TS2345`
278
+ mentioning `neo4j-driver-core` remains.
279
+
280
+ - [ ] **Step 4: Verify against a running Neo4j, not just the compiler**
281
+
282
+ A dependency change that only ever passed a typecheck has not been shown to work. Exercise the
283
+ driver against the live database:
284
+
285
+ ```bash
286
+ cd maxy-code/platform/ui
287
+ npx vitest run app/lib/__tests__/graph-write-gate.test.ts app/lib/__tests__/graph-health-audits.test.ts
288
+ ```
289
+ Expected: all pass.
290
+
291
+ Then drive a real query through the v5 driver using the same API surface `platform/ui` uses
292
+ (`neo4j.driver`, `neo4j.auth`, `neo4j.int`, `session.run`):
293
+
294
+ ```bash
295
+ node --input-type=module -e "
296
+ import neo4j from 'neo4j-driver'
297
+ const uri = process.env.NEO4J_URI ?? 'bolt://127.0.0.1:7687'
298
+ const d = neo4j.driver(uri, neo4j.auth.basic(process.env.NEO4J_USER ?? 'neo4j', process.env.NEO4J_PASSWORD))
299
+ const s = d.session()
300
+ const r = await s.run('RETURN \$n AS n', { n: neo4j.int(42) })
301
+ console.log('driver', neo4j.driver.name ? 'ok' : 'ok', 'value=', r.records[0].get('n').toString())
302
+ await s.close(); await d.close()
303
+ "
304
+ ```
305
+ Expected: `value= 42`. If the local Neo4j is not running or credentials are absent, say so
306
+ explicitly in the debrief rather than recording this step as passed.
307
+
308
+ - [ ] **Step 5: Commit**
309
+
310
+ ```bash
311
+ git add maxy-code/platform/ui/package.json
312
+ git commit -m "fix(1829): align platform/ui onto neo4j-driver v5, matching the libs it calls"
313
+ ```
314
+
315
+ ---
316
+
317
+ ### Task 3: Production type-truth fixes — clears 8
318
+
319
+ Three of these are defects the compiler found, not annotations. Read each before changing it.
320
+
321
+ **Files:**
322
+ - Modify: `platform/ui/app/components/ChannelIcon.tsx:8,14`
323
+ - Modify: `platform/ui/app/Sidebar.tsx:1499`
324
+ - Modify: `platform/ui/app/lib/webchat/gateway/webchat-gateway.ts:83`
325
+ - Modify: `platform/ui/server/routes/admin/sidebar-sessions.ts:283`
326
+ - Modify: `platform/ui/server/routes/admin/sessions.ts:638,667,702`
327
+ - Modify: `platform/ui/server/routes/whatsapp-reader.ts:1144`
328
+
329
+ - [ ] **Step 1: Fix the `ChannelIcon` crash**
330
+
331
+ `GLYPHS` is `Record<ReaderChannel, …>` but holds two of the three channels. `ReaderChannel` is
332
+ `'whatsapp' | 'telegram' | 'webchat'`. A webchat row at `Sidebar.tsx:1499` makes `GLYPHS['webchat']`
333
+ undefined and `g.fill` throw.
334
+
335
+ Do not invent a webchat brand path. `ChannelIcon` renders brand glyphs by design, which is why
336
+ `BRAND_CHANNELS` in the same file maps only two. Narrow its type instead.
337
+
338
+ In `app/components/ChannelIcon.tsx`, add the brand-channel type above `GLYPHS` and use it:
339
+
340
+ ```tsx
341
+ // ChannelIcon renders inlined brand marks, and only WhatsApp and Telegram have
342
+ // one. Webchat and any future channel are the SessionChannelBadge's job — it
343
+ // routes webchat to a globe and unknown tokens to a neutral bubble. Typing
344
+ // GLYPHS as Record<ReaderChannel, …> claimed a webchat glyph existed; it did
345
+ // not, and a webchat row reaching here threw on `g.fill`.
346
+ type BrandChannel = Extract<ReaderChannel, 'whatsapp' | 'telegram'>
347
+
348
+ const GLYPHS: Record<BrandChannel, { fill: string; path: string; label: string }> = {
349
+ ```
350
+
351
+ and change the component's prop type:
352
+
353
+ ```tsx
354
+ export function ChannelIcon({ channel, size = 16 }: { channel: BrandChannel; size?: number }) {
355
+ ```
356
+
357
+ and the badge's lookup map, which was already brand-only in fact:
358
+
359
+ ```tsx
360
+ const BRAND_CHANNELS: Record<string, BrandChannel> = { whatsapp: 'whatsapp', telegram: 'telegram' }
361
+ ```
362
+
363
+ - [ ] **Step 2: Route the conversation row through the badge**
364
+
365
+ `Sidebar.tsx:1499` passes `c.channel`, typed `ReaderChannel`, which now no longer fits.
366
+ `SessionChannelBadge` is the component built for the all-three case and delegates brand channels to
367
+ `ChannelIcon` at the same size, so whatsapp and telegram render unchanged.
368
+
369
+ In `app/Sidebar.tsx:1499`, change:
370
+
371
+ ```tsx
372
+ <ChannelIcon channel={c.channel} size={14} />
373
+ ```
374
+ to:
375
+ ```tsx
376
+ <SessionChannelBadge channel={c.channel} size={14} />
377
+ ```
378
+
379
+ `SessionChannelBadge` is already imported on line 6. Leave line 1031 alone — it maps over
380
+ `READER_CHANNELS`, which is whatsapp+telegram, and that call site is correct.
381
+
382
+ - [ ] **Step 3: Widen `dispatchFor` to match the reviewer it calls**
383
+
384
+ The shared type at `app/lib/channel-pty-bridge/public-session-end-review.ts:41` is
385
+ `'eviction' | 'exit'`. The local callback type narrowed it to `'eviction'`, so the documented
386
+ public-exit path at line 422 could not be expressed. The type is the bug; the value is correct.
387
+
388
+ In `app/lib/webchat/gateway/webchat-gateway.ts:83`, change:
389
+
390
+ ```ts
391
+ dispatchFor: 'eviction'
392
+ ```
393
+ to:
394
+ ```ts
395
+ dispatchFor: 'eviction' | 'exit'
396
+ ```
397
+
398
+ - [ ] **Step 4: Fix the `port` type**
399
+
400
+ `requirePortEnv` returns a number; the local was declared `string`. It is only interpolated into a
401
+ URL, so runtime is unaffected, but the declaration is a lie.
402
+
403
+ In `server/routes/admin/sidebar-sessions.ts`, change `let port: string` to:
404
+
405
+ ```ts
406
+ let port: number
407
+ ```
408
+
409
+ - [ ] **Step 5: Annotate the five implicit-`any` parameters**
410
+
411
+ These are callback params on arrays whose element type the compiler can already see; they only
412
+ needed writing down. Read each line and give the parameter the element type in scope — do not
413
+ reach for `any`.
414
+
415
+ - `server/routes/admin/sessions.ts:638` — params `c` and `i`
416
+ - `server/routes/admin/sessions.ts:667` — param `c`
417
+ - `server/routes/admin/sessions.ts:702` — param `c`
418
+ - `server/routes/whatsapp-reader.ts:1144` — param `r`
419
+
420
+ - [ ] **Step 6: Run the gate**
421
+
422
+ Run: `npm run typecheck`
423
+ Expected: exit 1, `[check-types] FAIL errors=62 ignored=0`, and no remaining diagnostic in a file
424
+ outside `__tests__`. Every error left in the package is now in a test file.
425
+
426
+ - [ ] **Step 7: Prove the ChannelIcon fix with a test**
427
+
428
+ Add to `app/components/__tests__/ChannelIcon.test.tsx`:
429
+
430
+ ```tsx
431
+ it('renders a webchat row through the badge without throwing', () => {
432
+ const { container } = render(<SessionChannelBadge channel="webchat" size={14} />)
433
+ expect(container.querySelector('.channel-icon')).not.toBeNull()
434
+ })
435
+ ```
436
+
437
+ Import `SessionChannelBadge` alongside `ChannelIcon` on line 4.
438
+
439
+ Run: `npx vitest run app/components/__tests__/ChannelIcon.test.tsx`
440
+ Expected: PASS.
441
+
442
+ - [ ] **Step 8: Commit**
443
+
444
+ ```bash
445
+ git add maxy-code/platform/ui/app maxy-code/platform/ui/server
446
+ git commit -m "fix(1829): production type defects — ChannelIcon webchat crash, dispatchFor, port type"
447
+ ```
448
+
449
+ ---
450
+
451
+ ### Task 4: Contract drift the tests exposed — clears 3
452
+
453
+ In both of these the test is right about the wire and the type is wrong. Fix the type.
454
+
455
+ **Files:**
456
+ - Modify: `platform/ui/app/Sidebar.tsx:49-60`
457
+ - Modify: `platform/ui/server/routes/channel/__tests__/schedule-inject.test.ts:180,186`
458
+
459
+ - [ ] **Step 1: Add the fields the 503 refusal actually sends**
460
+
461
+ `server/routes/admin/claude-sessions.ts:115` returns
462
+ `{ error: 'claude-auth-dead', auth_status: auth.status, expiresAt: auth.expiresAt ?? null }`.
463
+ `RcSpawnResponseBody` declares neither `auth_status` nor `expiresAt`, so
464
+ `resolveRcSpawnOutcome.test.ts:69` — which passes the real body — does not typecheck.
465
+
466
+ In `app/Sidebar.tsx`, add to `RcSpawnResponseBody` before the closing brace:
467
+
468
+ ```ts
469
+ /** Task 1407 — the 503 claude-auth-dead refusal (refuseIfClaudeAuthDead,
470
+ * server/routes/admin/claude-sessions.ts) carries the token's health and
471
+ * expiry alongside `error`. Both were on the wire and absent from this type,
472
+ * so a caller reading them had no compiler help. */
473
+ auth_status?: string
474
+ expiresAt?: string | null
475
+ ```
476
+
477
+ - [ ] **Step 2: Make the no-seat assertions non-vacuous**
478
+
479
+ `schedule-inject.test.ts:180,186` assert `.scheduledSessionId` is undefined on the inbound. No
480
+ inbound type declares that property and no source file mentions it, so the assertion is true by
481
+ construction and would stay true if the route started threading a seat under any other name. It
482
+ tests nothing.
483
+
484
+ The intent (Task 1746: no per-firing seat is threaded) is worth keeping. Express it against the
485
+ object so it stays meaningful if the field is ever added.
486
+
487
+ Change line 180 to:
488
+
489
+ ```ts
490
+ expect('scheduledSessionId' in (waHandleInbound.mock.calls[0][0] as object)).toBe(false)
491
+ ```
492
+
493
+ and line 186 to:
494
+
495
+ ```ts
496
+ expect('scheduledSessionId' in (tgHandleInbound.mock.calls[0][0] as object)).toBe(false)
497
+ ```
498
+
499
+ - [ ] **Step 3: Run the gate and the touched tests**
500
+
501
+ Run:
502
+ ```bash
503
+ npm run typecheck
504
+ npx vitest run app/__tests__/resolveRcSpawnOutcome.test.ts server/routes/channel/__tests__/schedule-inject.test.ts
505
+ ```
506
+ Expected: gate reports `errors=59`; both test files pass.
507
+
508
+ - [ ] **Step 4: Commit**
509
+
510
+ ```bash
511
+ git add maxy-code/platform/ui/app/Sidebar.tsx maxy-code/platform/ui/server/routes/channel/__tests__/schedule-inject.test.ts
512
+ git commit -m "fix(1829): type the auth-refusal wire fields, de-vacuum the no-seat assertions"
513
+ ```
514
+
515
+ ---
516
+
517
+ ### Task 5: Type the mock implementations — clears 39
518
+
519
+ One root cause produces most of the remaining errors: `vi.fn()` given an implementation that
520
+ declares no parameters. The mock's type becomes `Mock<() => R>`, so `.mock.calls[0]` is the empty
521
+ tuple `[]` (`TS2493` on any index, `TS2339` on any property of the resulting `never`), and any
522
+ callback over `.mock.calls` gets an implicit-`any` parameter (`TS7006`). Casting the resulting
523
+ `undefined` is `TS2352`.
524
+
525
+ The fix is the same everywhere: declare the parameters the caller actually passes. That is
526
+ truthful — the production call site already passes them — and it makes every downstream index and
527
+ callback infer correctly.
528
+
529
+ **Files:**
530
+ - Modify: `app/components/__tests__/SessionReseatControl.test.tsx` (5)
531
+ - Modify: `app/lib/__tests__/graph-write-gate.test.ts` (8)
532
+ - Modify: `app/components/__tests__/UsageModal.test.tsx` (2)
533
+ - Modify: `app/tasks/__tests__/tasks-page.test.tsx` (4)
534
+ - Modify: `app/whatsapp/__tests__/ReplyComposer.test.tsx` (2)
535
+ - Modify: `app/__tests__/AdminShell-operator-conversations.test.tsx` (2)
536
+ - Modify: `app/lib/__tests__/adminuser-self-heal.test.ts` (4)
537
+ - Modify: `app/lib/__tests__/graph-health-audits.test.ts` (3)
538
+ - Modify: `app/lib/whatsapp/__tests__/baileys-debug-window.test.ts` (3)
539
+ - Modify: `server/routes/admin/__tests__/browser-launch.test.ts` (6)
540
+
541
+ - [ ] **Step 1: Type the fetch-shaped mocks**
542
+
543
+ Wherever a mock stands in for `adminFetch` or `fetch` and the test later reads `mock.calls[0][1]`,
544
+ declare both parameters. In `app/components/__tests__/SessionReseatControl.test.tsx:30`, change:
545
+
546
+ ```tsx
547
+ const adminFetch = vi.fn(async () => new Response(JSON.stringify({ target: '/chat?session=new' }), { status: 200 }))
548
+ ```
549
+ to:
550
+ ```tsx
551
+ const adminFetch = vi.fn(async (_url: string, _init?: RequestInit) =>
552
+ new Response(JSON.stringify({ target: '/chat?session=new' }), { status: 200 }))
553
+ ```
554
+
555
+ This clears the three `TS2493` and two `TS2339` in that file, and the `init!` non-null assertion on
556
+ line 45 becomes correct rather than accidental. Apply the same shape to the identical mocks in
557
+ `UsageModal.test.tsx`, `tasks-page.test.tsx` and `ReplyComposer.test.tsx`, matching each call site's
558
+ real argument list — `tasks-page` and `ReplyComposer` currently infer `[url: string]`, so they need
559
+ the second parameter added.
560
+
561
+ - [ ] **Step 2: Type the console-spy mocks**
562
+
563
+ Wherever a test reads `logSpy.mock.calls.map((c) => String(c[0]))`, the spy's parameters are
564
+ unstated. Declare them so `c` infers. In `app/lib/__tests__/graph-write-gate.test.ts`, the spy
565
+ should be created as:
566
+
567
+ ```ts
568
+ const logSpy = vi.spyOn(console, 'error').mockImplementation((..._args: unknown[]) => {})
569
+ ```
570
+
571
+ The six `TS7006` in that file then resolve without touching the assertions. Apply the same to
572
+ `graph-health-audits.test.ts`, `baileys-debug-window.test.ts`, `browser-launch.test.ts`,
573
+ `adminuser-self-heal.test.ts` and `AdminShell-operator-conversations.test.tsx`.
574
+
575
+ - [ ] **Step 3: Type the Neo4j session mock**
576
+
577
+ `graph-write-gate.test.ts:201` destructures `session.run.mock.calls[0]`. Give `makeSession`'s `run`
578
+ its real parameters:
579
+
580
+ ```ts
581
+ run: vi.fn(async (_cypher: string, _params?: Record<string, unknown>) => ({ records: [] as unknown[] })),
582
+ ```
583
+
584
+ - [ ] **Step 4: Run the gate**
585
+
586
+ Run: `npm run typecheck`
587
+ Expected: exit 1, `[check-types] FAIL errors=20 ignored=0`.
588
+
589
+ - [ ] **Step 5: Run every touched test file**
590
+
591
+ Run:
592
+ ```bash
593
+ npx vitest run app/components/__tests__/SessionReseatControl.test.tsx app/lib/__tests__/graph-write-gate.test.ts \
594
+ app/components/__tests__/UsageModal.test.tsx app/tasks/__tests__/tasks-page.test.tsx \
595
+ app/whatsapp/__tests__/ReplyComposer.test.tsx app/__tests__/AdminShell-operator-conversations.test.tsx \
596
+ app/lib/__tests__/adminuser-self-heal.test.ts app/lib/__tests__/graph-health-audits.test.ts \
597
+ app/lib/whatsapp/__tests__/baileys-debug-window.test.ts server/routes/admin/__tests__/browser-launch.test.ts
598
+ ```
599
+ Expected: all pass. A mock that now declares parameters must still receive the same arguments — if
600
+ an assertion breaks, the mock's declared shape is wrong, not the assertion.
601
+
602
+ - [ ] **Step 6: Commit**
603
+
604
+ ```bash
605
+ git add maxy-code/platform/ui/app maxy-code/platform/ui/server
606
+ git commit -m "test(1829): declare mock parameters so call-tuple reads typecheck"
607
+ ```
608
+
609
+ ---
610
+
611
+ ### Task 6: Stale fixtures and handler types — clears 20
612
+
613
+ These are not one root cause. Each is a fixture or handler that drifted from the type it stands in
614
+ for.
615
+
616
+ **Files:**
617
+ - Modify: `app/components/__tests__/session-list-lite.test.tsx` (8)
618
+ - Modify: `app/lib/channel-pty-bridge/__tests__/follower.test.ts` (8)
619
+ - Modify: `app/lib/whatsapp/gateway/__tests__/wa-gateway-source.test.ts` (3)
620
+ - Modify: `app/lib/__tests__/power-health.test.ts` (1)
621
+
622
+ - [ ] **Step 1: Add the two props the session-list fixture lost**
623
+
624
+ All eight `TS2739` are the same fixture missing `newPermMode` and `setNewPermMode`, which the
625
+ component gained and the fixture never followed. Find the shared props object in
626
+ `session-list-lite.test.tsx` and add both, matching the types the component declares. If the
627
+ fixture is repeated inline at each of lines 28, 35, 43, 50, 67, 73, 80 and 86, hoist it to one
628
+ `const baseProps` first and spread it — eight copies of one fixture is why this drifted.
629
+
630
+ - [ ] **Step 2: Fix the follower handler types**
631
+
632
+ Six `TS2322` at lines 216, 254, 273 and 299 are `Type 'number' is not assignable to type
633
+ 'void | Promise<void>'` — a handler written as a concise arrow returning a number
634
+ (`() => someCounter++`). Wrap the body in braces so it returns void.
635
+
636
+ The four at lines 218, 256, 301 and 354 are `RecordingHandler` not assignable to
637
+ `FileDeliveryHandler`. Read both types before changing anything: if `RecordingHandler` is the
638
+ test's own recording double, give it the `FileDeliveryHandler` signature rather than casting it.
639
+
640
+ - [ ] **Step 3: Fix the wa-gateway-source mock**
641
+
642
+ Lines 53 and 54 cast `EnsureChannelSessionInput` to `Record<string, unknown>`, which the compiler
643
+ rejects as non-overlapping. Line 98 assigns a `Mock<(i: Record<string, unknown>) => Promise<void>>`
644
+ where an `EnsureTelegramSession…` signature is required. Type the mock with the real input type
645
+ instead of `Record<string, unknown>`, which removes all three.
646
+
647
+ - [ ] **Step 4: Fix the power-health runner fixture**
648
+
649
+ Line 118 adds a `status` key to an object literal typed
650
+ `{ runner: (c: string, a: string[]) => string | null }`. Read what the test intends: if `status` is
651
+ genuinely part of the fixture's contract, add it to the type; if it is a leftover, remove it.
652
+
653
+ - [ ] **Step 5: Run the gate**
654
+
655
+ Run: `npm run typecheck`
656
+ Expected: exit 0, `[check-types] ok errors=0 ignored=0 tsc-status=0`.
657
+
658
+ This is the first green run. If it is not zero, the remaining diagnostics are listed by the gate —
659
+ do not proceed to Task 7 until it is.
660
+
661
+ - [ ] **Step 6: Run every touched test file**
662
+
663
+ Run:
664
+ ```bash
665
+ npx vitest run app/components/__tests__/session-list-lite.test.tsx \
666
+ app/lib/channel-pty-bridge/__tests__/follower.test.ts \
667
+ app/lib/whatsapp/gateway/__tests__/wa-gateway-source.test.ts app/lib/__tests__/power-health.test.ts
668
+ ```
669
+ Expected: all pass.
670
+
671
+ - [ ] **Step 7: Commit**
672
+
673
+ ```bash
674
+ git add maxy-code/platform/ui/app
675
+ git commit -m "test(1829): refresh stale fixtures and handler signatures"
676
+ ```
677
+
678
+ ---
679
+
680
+ ### Task 7: Prove the gate catches a real error — the mutation check
681
+
682
+ A gate that has only ever been seen passing has not been shown to work. The load-bearing case is an
683
+ error in a file the narrow 1825 gate never covered.
684
+
685
+ - [ ] **Step 1: Introduce a deliberate error outside the old gate's six files**
686
+
687
+ `app/lib/file-index.ts` is not in `CONTRACT_FILES`. Add an implicit-`any` parameter to it — pick any
688
+ callback and strip its annotation, or append:
689
+
690
+ ```ts
691
+ export function __gateProbe(rows) {
692
+ return rows.length
693
+ }
694
+ ```
695
+
696
+ - [ ] **Step 2: Observe the gate fail on it**
697
+
698
+ Run: `npm run typecheck; echo "exit=$?"`
699
+ Expected: exit 1, `[check-types] FAIL errors=1 ignored=0`, and the listed diagnostic names
700
+ `app/lib/file-index.ts` with `TS7006`.
701
+
702
+ - [ ] **Step 3: Confirm the OLD gate would have missed it**
703
+
704
+ Run: `node scripts/check-loop-contract-types.mjs; echo "exit=$?"`
705
+ Expected: exit 0, `[loop-contract] ok … package-errors-ignored=1`. This is the whole reason the task
706
+ exists — record the output in the debrief.
707
+
708
+ - [ ] **Step 4: Remove the error and observe the gate pass**
709
+
710
+ Delete the probe, then run: `npm run typecheck; echo "exit=$?"`
711
+ Expected: exit 0, `[check-types] ok errors=0 ignored=0`.
712
+
713
+ - [ ] **Step 5: Confirm the gate does not pass blind**
714
+
715
+ Point it at a tree where tsc cannot run:
716
+
717
+ ```bash
718
+ mv tsconfig.json tsconfig.json.bak && npm run typecheck; echo "exit=$?"
719
+ mv tsconfig.json.bak tsconfig.json
720
+ ```
721
+ Expected: exit 1, and the message is `tsc-configuration-failed` or `tsc-produced-no-diagnostics` —
722
+ not `ok`. Record which branch fired.
723
+
724
+ - [ ] **Step 6: Commit nothing**
725
+
726
+ This task changes no tracked file. Confirm with `git status --porcelain` that the tree is clean
727
+ before moving on. If the probe or the tsconfig rename is still on disk, undo it now.
728
+
729
+ ---
730
+
731
+ ### Task 8: Retire the narrow gate and wire the wide one
732
+
733
+ **Files:**
734
+ - Delete: `platform/ui/scripts/check-loop-contract-types.mjs`
735
+ - Modify: `platform/ui/package.json` (`prebuild`)
736
+
737
+ - [ ] **Step 1: Swap the prebuild gate**
738
+
739
+ In `platform/ui/package.json`, in the `prebuild` chain, change the final entry from:
740
+
741
+ ```
742
+ && node scripts/check-loop-contract-types.mjs
743
+ ```
744
+ to:
745
+ ```
746
+ && node scripts/check-types.mjs
747
+ ```
748
+
749
+ - [ ] **Step 2: Delete the narrow gate**
750
+
751
+ ```bash
752
+ git rm maxy-code/platform/ui/scripts/check-loop-contract-types.mjs
753
+ ```
754
+
755
+ The loop-row contract is not lost. `check-types.mjs` compiles all six of its `CONTRACT_FILES` along
756
+ with the rest of the package, so every invariant 1825 asserted is still a build failure — now
757
+ without a second gate that could drift from the first.
758
+
759
+ - [ ] **Step 3: Verify no reference to the deleted gate survives**
760
+
761
+ Run: `/usr/bin/grep -rn "check-loop-contract-types" maxy-code/ --exclude-dir=node_modules`
762
+ Expected: hits only in `.tasks/` and `platform/docs/superpowers/` prose. Zero hits in
763
+ `package.json` or any script.
764
+
765
+ - [ ] **Step 4: Run the full build**
766
+
767
+ Run: `cd maxy-code/platform/ui && npm run build`
768
+ Expected: all nineteen prebuild gates pass, `[check-types] ok errors=0 ignored=0` among them, then
769
+ vite and tsup complete and `postbuild` passes.
770
+
771
+ - [ ] **Step 5: Commit**
772
+
773
+ ```bash
774
+ git add maxy-code/platform/ui/package.json
775
+ git commit -m "feat(1829): wire the package-wide gate into prebuild, retire the narrow one"
776
+ ```
777
+
778
+ ---
779
+
780
+ ### Task 9: Run the package's own test suite
781
+
782
+ The plan changed twenty test files and one dependency major version. The gate proves types; only the
783
+ suite proves behaviour.
784
+
785
+ - [ ] **Step 1: Run the full suite**
786
+
787
+ Run: `cd maxy-code/platform/ui && npx vitest run`
788
+ Expected: exit 0.
789
+
790
+ Do not dismiss a failure here as a worktree artefact. As of 2026-07 the worktree suite is
791
+ trustworthy — verify any failure against the parent checkout on `main` before calling it
792
+ environmental, and if it is real, fix it before landing.
793
+
794
+ - [ ] **Step 2: Record the count**
795
+
796
+ Note the file and test totals for the debrief.
797
+
798
+ ---
799
+
800
+ ### Task 10: File the follow-up for the rest of the platform
801
+
802
+ `platform/lib/*` and `platform/plugins/*` still typecheck nowhere. The task scopes them out, and a
803
+ prose deferral becomes a silent regression.
804
+
805
+ - [ ] **Step 1: Mint a task number**
806
+
807
+ Scan the worktrees, not just `main` — parallel sprints take numbers concurrently:
808
+
809
+ ```bash
810
+ ls /Users/neo/getmaxy/maxy-code/.tasks/*/ /Users/neo/getmaxy/maxy-code/.claude/worktrees/*/maxy-code/.tasks/*/ 2>/dev/null \
811
+ | /usr/bin/grep -oE '^1[89][0-9]{2}' | sort -n | tail -3
812
+ ```
813
+
814
+ - [ ] **Step 2: Write the task file**
815
+
816
+ Create `maxy-code/.tasks/backlog/<NNNN>-<slug>.md` describing: the other platform packages run no
817
+ typechecker; `platform/ui` now has `scripts/check-types.mjs` as the working shape to copy; each
818
+ package has its own error population that needs the same triage-then-gate treatment; and that the
819
+ `neo4j-driver` v5/v6 split is now uniform at v5 so a future v6 move is a single coordinated bump.
820
+ Task files nest to `##`, never `###`.
821
+
822
+ - [ ] **Step 3: Add a Ready row to LANES**
823
+
824
+ Edit `/Users/neo/getmaxy/maxy-code/.tasks/LANES.md` — use the absolute path, since a bare
825
+ `.tasks/LANES.md` from the worktree root resolves to the legacy parent tracker.
826
+
827
+ - [ ] **Step 4: Commit**
828
+
829
+ Fold this into the Task 1829 archive commit in the sprint's land phase rather than committing it
830
+ alone.