@rubytech/create-maxy-code 0.1.357 → 0.1.359

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/dist/__tests__/claude-ptys-slice.test.js +36 -1
  2. package/dist/__tests__/neo4j-pidfile-scrub.test.js +103 -0
  3. package/dist/index.js +42 -7
  4. package/dist/neo4j-pidfile-scrub.js +90 -0
  5. package/dist/port-resolution.js +18 -1
  6. package/package.json +1 -1
  7. package/payload/platform/package-lock.json +237 -0
  8. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js +79 -1
  9. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js.map +1 -1
  10. package/payload/platform/plugins/admin/mcp/dist/index.js +17 -3
  11. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
  12. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts +16 -0
  13. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts.map +1 -1
  14. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js +52 -0
  15. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js.map +1 -1
  16. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +61 -1
  17. package/payload/platform/plugins/cloudflare/PLUGIN.md +7 -1
  18. package/payload/platform/plugins/cloudflare/bin/__tests__/cf-token.test.sh +195 -0
  19. package/payload/platform/plugins/cloudflare/bin/cf-token.sh +157 -0
  20. package/payload/platform/plugins/cloudflare/references/api.md +2 -0
  21. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +14 -0
  22. package/payload/platform/plugins/cloudflare/skills/site-deploy/SKILL.md +10 -1
  23. package/payload/platform/plugins/docs/PLUGIN.md +2 -0
  24. package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
  25. package/payload/platform/plugins/docs/references/claudeai-connectors.md +45 -0
  26. package/payload/platform/plugins/docs/references/cloudflare.md +6 -0
  27. package/payload/platform/plugins/docs/references/troubleshooting.md +2 -0
  28. package/payload/platform/plugins/email/.claude-plugin/plugin.json +1 -1
  29. package/payload/platform/plugins/email/PLUGIN.md +7 -3
  30. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.d.ts +2 -0
  31. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.d.ts.map +1 -0
  32. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.js +99 -0
  33. package/payload/platform/plugins/email/mcp/dist/__tests__/body-extract.test.js.map +1 -0
  34. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.d.ts +2 -0
  35. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.d.ts.map +1 -0
  36. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.js +32 -0
  37. package/payload/platform/plugins/email/mcp/dist/__tests__/compose-draft-id.test.js.map +1 -0
  38. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js +64 -6
  39. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft-edit.test.js.map +1 -1
  40. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js +12 -0
  41. package/payload/platform/plugins/email/mcp/dist/__tests__/email-draft.test.js.map +1 -1
  42. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.d.ts +2 -0
  43. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.d.ts.map +1 -0
  44. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.js +58 -0
  45. package/payload/platform/plugins/email/mcp/dist/__tests__/email-status.test.js.map +1 -0
  46. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js +94 -9
  47. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-drafts.test.js.map +1 -1
  48. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js +109 -1
  49. package/payload/platform/plugins/email/mcp/dist/__tests__/imap-probe.test.js.map +1 -1
  50. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js +4 -0
  51. package/payload/platform/plugins/email/mcp/dist/__tests__/mail-options.test.js.map +1 -1
  52. package/payload/platform/plugins/email/mcp/dist/index.js +39 -2
  53. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -1
  54. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts +5 -0
  55. package/payload/platform/plugins/email/mcp/dist/lib/compose.d.ts.map +1 -1
  56. package/payload/platform/plugins/email/mcp/dist/lib/compose.js +8 -1
  57. package/payload/platform/plugins/email/mcp/dist/lib/compose.js.map +1 -1
  58. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +13 -0
  59. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -1
  60. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +35 -0
  61. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -1
  62. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +83 -30
  63. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -1
  64. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +327 -112
  65. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -1
  66. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts +19 -0
  67. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.d.ts.map +1 -1
  68. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js +33 -0
  69. package/payload/platform/plugins/email/mcp/dist/lib/setup-probe.js.map +1 -1
  70. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +6 -0
  71. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -1
  72. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +4 -0
  73. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -1
  74. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts +8 -1
  75. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.d.ts.map +1 -1
  76. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js +10 -6
  77. package/payload/platform/plugins/email/mcp/dist/tools/email-draft-edit.js.map +1 -1
  78. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.d.ts.map +1 -1
  79. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js +4 -2
  80. package/payload/platform/plugins/email/mcp/dist/tools/email-draft.js.map +1 -1
  81. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.d.ts +15 -0
  82. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.d.ts.map +1 -0
  83. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.js +29 -0
  84. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch-body.js.map +1 -0
  85. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -1
  86. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +11 -1
  87. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -1
  88. package/payload/platform/plugins/email/mcp/dist/tools/email-status.d.ts.map +1 -1
  89. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js +24 -1
  90. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js.map +1 -1
  91. package/payload/platform/plugins/email/mcp/package.json +2 -0
  92. package/payload/platform/plugins/email/references/email-reference.md +30 -3
  93. package/payload/platform/scripts/rss-sampler.sh +21 -0
  94. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  95. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  96. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  97. package/payload/platform/services/claude-session-manager/dist/connector-auth.d.ts +31 -0
  98. package/payload/platform/services/claude-session-manager/dist/connector-auth.d.ts.map +1 -0
  99. package/payload/platform/services/claude-session-manager/dist/connector-auth.js +49 -0
  100. package/payload/platform/services/claude-session-manager/dist/connector-auth.js.map +1 -0
  101. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +24 -0
  102. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  103. package/payload/platform/services/claude-session-manager/dist/http-server.js +214 -17
  104. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  105. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +13 -5
  106. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  107. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +46 -11
  108. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  109. package/payload/platform/services/webchat-channel/dist/instructions.d.ts +1 -0
  110. package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
  111. package/payload/platform/services/webchat-channel/dist/instructions.js +28 -0
  112. package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
  113. package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
  114. package/payload/platform/services/webchat-channel/dist/server.js +75 -5
  115. package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
  116. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  117. package/payload/server/public/assets/{AdminLoginScreens-BW1UgfoI.js → AdminLoginScreens-tHyAPNnQ.js} +1 -1
  118. package/payload/server/public/assets/AdminShell-Ce9izNVZ.js +1 -0
  119. package/payload/server/public/assets/{Checkbox-O1qvMk_u.js → Checkbox-Cq6SJJlX.js} +1 -1
  120. package/payload/server/public/assets/OperatorConversations-BERW_hUa.css +1 -0
  121. package/payload/server/public/assets/OperatorConversations-m2lz6Ss7.js +9 -0
  122. package/payload/server/public/assets/admin-D9iMgdbN.js +1 -0
  123. package/payload/server/public/assets/{arc-DpkSQNto.js → arc-Crkz45LN.js} +1 -1
  124. package/payload/server/public/assets/architecture-YZFGNWBL-Dma4Bgha.js +1 -0
  125. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Bw7Yq8O9.js → architectureDiagram-Q4EWVU46-C9JThHgP.js} +1 -1
  126. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BBtJQFSz.js → blockDiagram-DXYQGD6D-DpsV_HXT.js} +1 -1
  127. package/payload/server/public/assets/{browser-CySvj140.js → browser-CZWi0EAP.js} +1 -1
  128. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-JAMgxzOr.js → c4Diagram-AHTNJAMY-CTm_6aKi.js} +1 -1
  129. package/payload/server/public/assets/calendar-DUAh-_kx.js +1 -0
  130. package/payload/server/public/assets/channel-B_-5bau1.js +1 -0
  131. package/payload/server/public/assets/chat-DHuibPfc.js +1 -0
  132. package/payload/server/public/assets/{chunk-2KRD3SAO-eDugsc2L.js → chunk-2KRD3SAO-1KSJW1q6.js} +1 -1
  133. package/payload/server/public/assets/{chunk-336JU56O-BXfECwdC.js → chunk-336JU56O-C3t08Ip-.js} +2 -2
  134. package/payload/server/public/assets/chunk-426QAEUC-Dirxdwjh.js +1 -0
  135. package/payload/server/public/assets/{chunk-4BX2VUAB-CByVeKCY.js → chunk-4BX2VUAB-kl1ze33n.js} +1 -1
  136. package/payload/server/public/assets/{chunk-4TB4RGXK-CpY0DcUB.js → chunk-4TB4RGXK-DxpoDoHg.js} +1 -1
  137. package/payload/server/public/assets/{chunk-55IACEB6-C3YxgyIb.js → chunk-55IACEB6-WM9VJzha.js} +1 -1
  138. package/payload/server/public/assets/{chunk-5FUZZQ4R-Bc0d7j8A.js → chunk-5FUZZQ4R-CLH63ZH3.js} +1 -1
  139. package/payload/server/public/assets/{chunk-5PVQY5BW-CTUGMRIa.js → chunk-5PVQY5BW-DCTb8IAT.js} +1 -1
  140. package/payload/server/public/assets/{chunk-67CJDMHE-CbdPnpLd.js → chunk-67CJDMHE-BSYzyaoH.js} +1 -1
  141. package/payload/server/public/assets/{chunk-7N4EOEYR-Cjl2kevz.js → chunk-7N4EOEYR-CarJ7O2P.js} +1 -1
  142. package/payload/server/public/assets/{chunk-AA7GKIK3-BgozIh5p.js → chunk-AA7GKIK3-DTNLyBpH.js} +1 -1
  143. package/payload/server/public/assets/{chunk-BSJP7CBP-6Ufq45NW.js → chunk-BSJP7CBP-BFmHflHY.js} +1 -1
  144. package/payload/server/public/assets/{chunk-CIAEETIT-BhhYuMnA.js → chunk-CIAEETIT-BpjG0IzU.js} +1 -1
  145. package/payload/server/public/assets/{chunk-EDXVE4YY-BfaJ3yDD.js → chunk-EDXVE4YY-2fSowhlW.js} +1 -1
  146. package/payload/server/public/assets/{chunk-ENJZ2VHE-C7-hIGVC.js → chunk-ENJZ2VHE-ClcranGV.js} +1 -1
  147. package/payload/server/public/assets/{chunk-FMBD7UC4-BQvvyocF.js → chunk-FMBD7UC4-DLq4BItQ.js} +1 -1
  148. package/payload/server/public/assets/{chunk-FOC6F5B3-C6rBDOxH.js → chunk-FOC6F5B3-B9QI3Guz.js} +1 -1
  149. package/payload/server/public/assets/{chunk-ICPOFSXX-BjOJvkVa.js → chunk-ICPOFSXX-BAr-Mv1Z.js} +2 -2
  150. package/payload/server/public/assets/{chunk-K5T4RW27-kKowRHhn.js → chunk-K5T4RW27-8PvAHasY.js} +1 -1
  151. package/payload/server/public/assets/{chunk-KGLVRYIC-bAEV_5eH.js → chunk-KGLVRYIC--aGaDRH5.js} +1 -1
  152. package/payload/server/public/assets/{chunk-LIHQZDEY-BLvsQAfg.js → chunk-LIHQZDEY-BrWj7mw2.js} +1 -1
  153. package/payload/server/public/assets/{chunk-ORNJ4GCN-BzYZfPZ7.js → chunk-ORNJ4GCN-kYQmkMTi.js} +1 -1
  154. package/payload/server/public/assets/{chunk-OYMX7WX6-CL7WRw42.js → chunk-OYMX7WX6-CIsryCWH.js} +1 -1
  155. package/payload/server/public/assets/chunk-QZHKN3VN-Duipo1kI.js +1 -0
  156. package/payload/server/public/assets/{chunk-U2HBQHQK-BdcVGjau.js → chunk-U2HBQHQK-68X653e3.js} +1 -1
  157. package/payload/server/public/assets/{chunk-X2U36JSP-C0CL_Jin.js → chunk-X2U36JSP-v3v9soX3.js} +1 -1
  158. package/payload/server/public/assets/{chunk-XPW4576I-CsV7CUxH.js → chunk-XPW4576I-CW5DPpop.js} +1 -1
  159. package/payload/server/public/assets/{chunk-YZCP3GAM-Cj0_fLkR.js → chunk-YZCP3GAM-B1VP7Rl2.js} +1 -1
  160. package/payload/server/public/assets/{chunk-ZZ45TVLE-DLuquyoY.js → chunk-ZZ45TVLE-DiJrujNY.js} +1 -1
  161. package/payload/server/public/assets/classDiagram-6PBFFD2Q-B3kX5SuB.js +1 -0
  162. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-D761c7Lr.js +1 -0
  163. package/payload/server/public/assets/clone-BrhFv6Tb.js +1 -0
  164. package/payload/server/public/assets/{cose-bilkent-S5V4N54A-BU3EOLXX.js → cose-bilkent-S5V4N54A-BscXxLMc.js} +1 -1
  165. package/payload/server/public/assets/{dagre-KV5264BT-CoCAYhFc.js → dagre-KV5264BT-DVgGlTQ1.js} +1 -1
  166. package/payload/server/public/assets/{dagre-BRq8C9NU.js → dagre-MBv6WlCS.js} +1 -1
  167. package/payload/server/public/assets/data-CoOcAR_2.js +1 -0
  168. package/payload/server/public/assets/{diagram-5BDNPKRD-DBy5GNaQ.js → diagram-5BDNPKRD-BmhCaO0a.js} +1 -1
  169. package/payload/server/public/assets/{diagram-G4DWMVQ6-l93MsBLv.js → diagram-G4DWMVQ6-ChU9L8vz.js} +1 -1
  170. package/payload/server/public/assets/{diagram-MMDJMWI5-BIfXkVlL.js → diagram-MMDJMWI5-Oy409Zc_.js} +1 -1
  171. package/payload/server/public/assets/{diagram-TYMM5635-BuTJLBny.js → diagram-TYMM5635-Cn1YByqk.js} +1 -1
  172. package/payload/server/public/assets/{erDiagram-SMLLAGMA-BwPxWDbP.js → erDiagram-SMLLAGMA-e17yfLvr.js} +1 -1
  173. package/payload/server/public/assets/{flatten-DtM0XAMt.js → flatten-Cl1Bc3dR.js} +1 -1
  174. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BhPtHXMR.js → flowDiagram-DWJPFMVM-Dqt7sCVZ.js} +1 -1
  175. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BlXjprdD.js → ganttDiagram-T4ZO3ILL-B4IhwS2r.js} +1 -1
  176. package/payload/server/public/assets/gitGraph-7Q5UKJZL-BCQAqtLy.js +1 -0
  177. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BW36BDiu.js → gitGraphDiagram-UUTBAWPF-BDw-PKcI.js} +1 -1
  178. package/payload/server/public/assets/{graph-uFhGyOZR.js → graph-Dc_votDd.js} +3 -3
  179. package/payload/server/public/assets/{graph-labels-BNnhRQqM.js → graph-labels-jqagxwhW.js} +1 -1
  180. package/payload/server/public/assets/{graphlib-Bjg3Tq-k.js → graphlib-DPIYk_sg.js} +1 -1
  181. package/payload/server/public/assets/info-OMHHGYJF-qU7hK50T.js +1 -0
  182. package/payload/server/public/assets/infoDiagram-42DDH7IO-KGdcJeTs.js +2 -0
  183. package/payload/server/public/assets/{isEmpty-D__iH1WQ.js → isEmpty-D1pGOD1J.js} +1 -1
  184. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CmB-bA_O.js → ishikawaDiagram-UXIWVN3A-BRIHsB3G.js} +1 -1
  185. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-Bt1fJKmc.js → journeyDiagram-VCZTEJTY-aKNgmoHd.js} +1 -1
  186. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DVbksz_J.js → kanban-definition-6JOO6SKY-cwBwT-nm.js} +1 -1
  187. package/payload/server/public/assets/{line-BX2Ugx3B.js → line-DVtVRzUA.js} +1 -1
  188. package/payload/server/public/assets/{linear-Bdc-QJWI.js → linear-DtoOFPO2.js} +1 -1
  189. package/payload/server/public/assets/{mermaid-parser.core-qv1e-J5x.js → mermaid-parser.core-G7YD_zO3.js} +2 -2
  190. package/payload/server/public/assets/{mermaid.core-C_d9YQX_.js → mermaid.core-DpFyndHm.js} +3 -3
  191. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DwKGvF14.js → mindmap-definition-QFDTVHPH-CYXK_Pvz.js} +1 -1
  192. package/payload/server/public/assets/operator-KYXcuQ4Y.js +1 -0
  193. package/payload/server/public/assets/{ordinal-BRQ5CzZY.js → ordinal-CBZeH4Yp.js} +1 -1
  194. package/payload/server/public/assets/packet-4T2RLAQJ-DiU2yS9m.js +1 -0
  195. package/payload/server/public/assets/page-Cfsv97nq.js +32 -0
  196. package/payload/server/public/assets/pie-ZZUOXDRM-zHUKKlVv.js +1 -0
  197. package/payload/server/public/assets/{pieDiagram-DEJITSTG-dUvQC_4S.js → pieDiagram-DEJITSTG-DFo4N6WH.js} +1 -1
  198. package/payload/server/public/assets/{public-DgltXhnD.js → public-49guEjCh.js} +1 -1
  199. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CebX_oPa.js → quadrantDiagram-34T5L4WZ-BlH5iIhl.js} +1 -1
  200. package/payload/server/public/assets/radar-PYXPWWZC-BUnVoaPg.js +1 -0
  201. package/payload/server/public/assets/{reduce-CkcXOmmJ.js → reduce-PuPlFPRX.js} +1 -1
  202. package/payload/server/public/assets/{requirementDiagram-MS252O5E-h2euIqGj.js → requirementDiagram-MS252O5E-D5WLty8A.js} +1 -1
  203. package/payload/server/public/assets/rotate-ccw-CyR5o3Nq.js +1 -0
  204. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DCii3fkF.js → sankeyDiagram-XADWPNL6-vB85IxHG.js} +1 -1
  205. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CQSGYmlq.js → sequenceDiagram-FGHM5R23-Cxraa0Ee.js} +1 -1
  206. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CVtU0iXH.js → stateDiagram-FHFEXIEX-BBPssYBx.js} +1 -1
  207. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BWmmUwDt.js +1 -0
  208. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ChvsBltI.js → timeline-definition-GMOUNBTQ-Bgk6PT62.js} +1 -1
  209. package/payload/server/public/assets/treeView-SZITEDCU-C3Y-Q52h.js +1 -0
  210. package/payload/server/public/assets/treemap-W4RFUUIX-Dk0qZpAg.js +1 -0
  211. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-e-EZiiba.js → vennDiagram-DHZGUBPP-B-APTs3L.js} +1 -1
  212. package/payload/server/public/assets/wardley-RL74JXVD-BAWI02OA.js +1 -0
  213. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-4JaRn1s5.js → wardleyDiagram-NUSXRM2D-CkXJSs_i.js} +1 -1
  214. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-kxwmCNuM.js → xychartDiagram-5P7HB3ND-BkyshPMV.js} +1 -1
  215. package/payload/server/public/browser.html +4 -4
  216. package/payload/server/public/calendar.html +4 -4
  217. package/payload/server/public/chat.html +7 -6
  218. package/payload/server/public/data.html +4 -4
  219. package/payload/server/public/graph.html +7 -6
  220. package/payload/server/public/index.html +6 -6
  221. package/payload/server/public/operator.html +9 -8
  222. package/payload/server/public/public.html +7 -6
  223. package/payload/server/server.js +244 -24
  224. package/payload/server/public/assets/AdminShell-CDQDkT1R.js +0 -1
  225. package/payload/server/public/assets/OperatorConversations-CVH-FoJo.css +0 -1
  226. package/payload/server/public/assets/OperatorConversations-jqaPCHwB.js +0 -9
  227. package/payload/server/public/assets/admin-BkYc54bi.js +0 -1
  228. package/payload/server/public/assets/architecture-YZFGNWBL-Csj53u5T.js +0 -1
  229. package/payload/server/public/assets/calendar-DgP7lal2.js +0 -1
  230. package/payload/server/public/assets/channel-BUQUAUts.js +0 -1
  231. package/payload/server/public/assets/chat-gls5aV50.js +0 -1
  232. package/payload/server/public/assets/chunk-426QAEUC-CdknReB2.js +0 -1
  233. package/payload/server/public/assets/chunk-QZHKN3VN-8tHoEDE9.js +0 -1
  234. package/payload/server/public/assets/classDiagram-6PBFFD2Q-BEGZ3DLg.js +0 -1
  235. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DsLxnm5U.js +0 -1
  236. package/payload/server/public/assets/clone-uiXbH_kh.js +0 -1
  237. package/payload/server/public/assets/data-CbI8-CX3.js +0 -1
  238. package/payload/server/public/assets/gitGraph-7Q5UKJZL-D_2KrZoP.js +0 -1
  239. package/payload/server/public/assets/info-OMHHGYJF-BP2TNwQ4.js +0 -1
  240. package/payload/server/public/assets/infoDiagram-42DDH7IO-D1kDtBOY.js +0 -2
  241. package/payload/server/public/assets/operator-DeCk_qYw.js +0 -1
  242. package/payload/server/public/assets/packet-4T2RLAQJ-BDg8fde8.js +0 -1
  243. package/payload/server/public/assets/page-jGwq-DpW.js +0 -32
  244. package/payload/server/public/assets/pie-ZZUOXDRM-CXDyYMkZ.js +0 -1
  245. package/payload/server/public/assets/radar-PYXPWWZC-xen_zv8F.js +0 -1
  246. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BywcXjtb.js +0 -1
  247. package/payload/server/public/assets/treeView-SZITEDCU-2FBf_1It.js +0 -1
  248. package/payload/server/public/assets/treemap-W4RFUUIX-BDdb30P-.js +0 -1
  249. package/payload/server/public/assets/wardley-RL74JXVD-BLq5MxjR.js +0 -1
  250. /package/payload/server/public/assets/{_baseFor-SRtUHe7G.js → _baseFor-brRjpUOX.js} +0 -0
  251. /package/payload/server/public/assets/{array-BpsnM-Py.js → array-BGFCBI0e.js} +0 -0
  252. /package/payload/server/public/assets/{cytoscape.esm-D4Rl1H5h.js → cytoscape.esm-TvRJ2tGX.js} +0 -0
  253. /package/payload/server/public/assets/{defaultLocale-C7sQPl-O.js → defaultLocale-CRZydyG6.js} +0 -0
  254. /package/payload/server/public/assets/{dist-CtUNt3w8.js → dist-B0CkUodR.js} +0 -0
  255. /package/payload/server/public/assets/{init-BydxaDEV.js → init-B8gtcn7T.js} +0 -0
  256. /package/payload/server/public/assets/{katex-B0fVeDx4.js → katex-RxgSu_dy.js} +0 -0
  257. /package/payload/server/public/assets/{path-jlWYQ2i9.js → path-DZF-JdEe.js} +0 -0
  258. /package/payload/server/public/assets/{preload-helper-uTix4PVD.js → preload-helper-CQ36nxok.js} +0 -0
  259. /package/payload/server/public/assets/{rough.esm-c4PR5shF.js → rough.esm-6CnTHTkH.js} +0 -0
  260. /package/payload/server/public/assets/{src-48kCpScq.js → src-CR_MU8uy.js} +0 -0
@@ -6,7 +6,13 @@
6
6
  // slice un-enabled after install).
7
7
  import test from "node:test";
8
8
  import assert from "node:assert/strict";
9
- import { buildClaudePtysSliceUnitFile } from "../port-resolution.js";
9
+ import { buildClaudePtysSliceUnitFile, resolveClaudePtysSliceMemoryHigh } from "../port-resolution.js";
10
+ const GiB = 1024 ** 3;
11
+ const memHighMiB = (unit) => {
12
+ const m = unit.match(/^MemoryHigh=(\d+)M$/m);
13
+ assert.ok(m, "unit must carry a MemoryHigh=<n>M line");
14
+ return Number(m[1]);
15
+ };
10
16
  test("buildClaudePtysSliceUnitFile emits a valid systemd slice unit", () => {
11
17
  const unit = buildClaudePtysSliceUnitFile();
12
18
  assert.match(unit, /^\[Unit\]$/m);
@@ -23,3 +29,32 @@ test("buildClaudePtysSliceUnitFile output has no per-brand or per-install templa
23
29
  assert.doesNotMatch(unit, /\$\{/);
24
30
  assert.doesNotMatch(unit, /__[A-Z_]+__/);
25
31
  });
32
+ // Task 1176 — the slice carries a soft MemoryHigh sized to the host so the
33
+ // session cohort absorbs reclaim pressure (throttle/swap within the slice)
34
+ // before the box exhausts RAM and the kernel kills the brand server. The
35
+ // value is total RAM minus a ~2.7GB fixed floor (neo4j + server +
36
+ // edge/manager/chrome), clamped to a 2GiB minimum. MemoryHigh (soft), never
37
+ // MemoryMax (hard — would just relocate the OOM kill inside the slice).
38
+ test("resolveClaudePtysSliceMemoryHigh scales with host RAM and clamps tiny hosts", () => {
39
+ const low = resolveClaudePtysSliceMemoryHigh(8 * GiB);
40
+ const high = resolveClaudePtysSliceMemoryHigh(16 * GiB);
41
+ assert.match(low, /^\d+M$/);
42
+ assert.match(high, /^\d+M$/);
43
+ // 8GB host: total minus 2.7GB floor lands in the 4-6 GiB band.
44
+ const lowMiB = Number(low.replace("M", ""));
45
+ assert.ok(lowMiB > 4000 && lowMiB < 6000, `8GB MemoryHigh out of band: ${low}`);
46
+ // A 16GB host gets a strictly larger ceiling than an 8GB host.
47
+ assert.ok(Number(high.replace("M", "")) > lowMiB);
48
+ // Tiny host clamps to the 2GiB floor rather than emitting a near-zero or
49
+ // negative MemoryHigh.
50
+ assert.equal(resolveClaudePtysSliceMemoryHigh(1 * GiB), "2048M");
51
+ });
52
+ test("buildClaudePtysSliceUnitFile carries a MemoryHigh line under [Slice] that scales with RAM", () => {
53
+ const low = buildClaudePtysSliceUnitFile(8 * GiB);
54
+ const high = buildClaudePtysSliceUnitFile(16 * GiB);
55
+ // MemoryHigh appears, and after the [Slice] header.
56
+ assert.match(low, /^MemoryHigh=\d+M$/m);
57
+ assert.ok(low.indexOf("[Slice]") < low.indexOf("MemoryHigh="), "MemoryHigh must be inside [Slice]");
58
+ // The 16GB unit's ceiling exceeds the 8GB unit's.
59
+ assert.ok(memHighMiB(high) > memHighMiB(low));
60
+ });
@@ -0,0 +1,103 @@
1
+ // Contract grid for resolveNeo4jPidfileScrub (the pure decision behind the
2
+ // install-time per-boot scrub provisioning) plus a behaviour grid for the
3
+ // shipped SCRUB_SCRIPT run against crafted PIDs. The wrapper in index.ts owns
4
+ // the privileged fs/systemctl; this suite is decision + script only, no sudo.
5
+ //
6
+ // The load-bearing guarantee: the scrub NEVER removes a pidfile that names a
7
+ // live Neo4j process, and ALWAYS removes one whose PID is dead or reused by an
8
+ // unrelated process. Runs via Node's built-in test runner (codebase convention,
9
+ // see neo4j-teardown.test.ts).
10
+ import test from "node:test";
11
+ import assert from "node:assert/strict";
12
+ import { mkdtempSync, writeFileSync, existsSync, rmSync } from "node:fs";
13
+ import { tmpdir } from "node:os";
14
+ import { join } from "node:path";
15
+ import { spawnSync, spawn } from "node:child_process";
16
+ import { resolveNeo4jPidfileScrub, SCRUB_SCRIPT, SCRUB_SCRIPT_PATH } from "../neo4j-pidfile-scrub.js";
17
+ // ---- resolve grid (pure) ----
18
+ test("default brand (port 7687) → apt neo4j unit + /var/lib/neo4j/run pidfile", () => {
19
+ const plan = resolveNeo4jPidfileScrub({ brandHostname: "maxy-code", neo4jPort: 7687 });
20
+ assert.notEqual(plan, null);
21
+ assert.equal(plan.unit, "neo4j");
22
+ assert.equal(plan.pidfile, "/var/lib/neo4j/run/neo4j.pid");
23
+ assert.equal(plan.dropinPath, "/etc/systemd/system/neo4j.service.d/10-maxy-pidfile-scrub.conf");
24
+ assert.match(plan.dropinContent, /ExecStartPre=\+\/usr\/local\/lib\/maxy-neo4j-pidfile-scrub\.sh \/var\/lib\/neo4j\/run\/neo4j\.pid/);
25
+ assert.equal(plan.scriptPath, SCRUB_SCRIPT_PATH);
26
+ });
27
+ test("dedicated brand (custom port) → neo4j-<host> unit + per-brand run pidfile", () => {
28
+ const plan = resolveNeo4jPidfileScrub({ brandHostname: "sitedesk-code", neo4jPort: 7689 });
29
+ assert.notEqual(plan, null);
30
+ assert.equal(plan.unit, "neo4j-sitedesk-code");
31
+ assert.equal(plan.pidfile, "/var/lib/neo4j-sitedesk-code/run/neo4j.pid");
32
+ assert.equal(plan.dropinPath, "/etc/systemd/system/neo4j-sitedesk-code.service.d/10-maxy-pidfile-scrub.conf");
33
+ // dedicated drop-in never names the shared run-dir pidfile
34
+ assert.doesNotMatch(plan.dropinContent, /\/var\/lib\/neo4j\/run\//);
35
+ });
36
+ test("unreadable port (undefined) → null (never guess the unit)", () => {
37
+ assert.equal(resolveNeo4jPidfileScrub({ brandHostname: "sitedesk-code", neo4jPort: undefined }), null);
38
+ });
39
+ test("dedicated port with empty hostname → null (cannot form a unit)", () => {
40
+ assert.equal(resolveNeo4jPidfileScrub({ brandHostname: "", neo4jPort: 7689 }), null);
41
+ });
42
+ // ---- script behaviour (writes SCRUB_SCRIPT to disk, runs against crafted PIDs) ----
43
+ function runScrub(pidfile) {
44
+ const dir = mkdtempSync(join(tmpdir(), "scrub-"));
45
+ const script = join(dir, "scrub.sh");
46
+ writeFileSync(script, SCRUB_SCRIPT, { mode: 0o755 });
47
+ const r = spawnSync("sh", [script, pidfile], { encoding: "utf8" });
48
+ rmSync(dir, { recursive: true, force: true });
49
+ return { stdout: r.stdout ?? "", status: r.status ?? -1 };
50
+ }
51
+ test("absent pidfile → no-op, exit 0", () => {
52
+ const r = runScrub("/no/such/pidfile");
53
+ assert.equal(r.status, 0);
54
+ assert.match(r.stdout, /no-op .*reason=absent/);
55
+ });
56
+ test("unparseable pidfile → removed, exit 0", () => {
57
+ const dir = mkdtempSync(join(tmpdir(), "scrub-pf-"));
58
+ const pf = join(dir, "neo4j.pid");
59
+ writeFileSync(pf, "not-a-number\n");
60
+ const r = runScrub(pf);
61
+ assert.equal(r.status, 0);
62
+ assert.match(r.stdout, /removed .*reason=unparseable/);
63
+ assert.equal(existsSync(pf), false);
64
+ rmSync(dir, { recursive: true, force: true });
65
+ });
66
+ test("dead PID → removed, exit 0", () => {
67
+ const dir = mkdtempSync(join(tmpdir(), "scrub-pf-"));
68
+ const pf = join(dir, "neo4j.pid");
69
+ // 999999 is above the default pid_max on Linux and unused on darwin — dead.
70
+ writeFileSync(pf, "999999\n");
71
+ const r = runScrub(pf);
72
+ assert.equal(r.status, 0);
73
+ assert.match(r.stdout, /removed .*reason=dead/);
74
+ assert.equal(existsSync(pf), false);
75
+ rmSync(dir, { recursive: true, force: true });
76
+ });
77
+ test("alive non-neo4j PID → removed, exit 0", async () => {
78
+ const dir = mkdtempSync(join(tmpdir(), "scrub-pf-"));
79
+ const pf = join(dir, "neo4j.pid");
80
+ const proc = spawn("sleep", ["30"]); // argv has no 'neo4j'
81
+ await new Promise((r) => setTimeout(r, 100));
82
+ writeFileSync(pf, String(proc.pid) + "\n");
83
+ const r = runScrub(pf);
84
+ proc.kill("SIGKILL");
85
+ assert.equal(r.status, 0);
86
+ assert.match(r.stdout, /removed .*reason=alive-other/);
87
+ assert.equal(existsSync(pf), false);
88
+ rmSync(dir, { recursive: true, force: true });
89
+ });
90
+ test("alive Neo4j-cmdline PID → no-op, exit 0 (Linux only — needs /proc)", { skip: process.platform !== "linux" }, async () => {
91
+ const dir = mkdtempSync(join(tmpdir(), "scrub-pf-"));
92
+ const pf = join(dir, "neo4j.pid");
93
+ // a long-lived process whose argv contains 'neo4j' ($0 = the stub name)
94
+ const proc = spawn("sh", ["-c", "sleep 30", "neo4j-jvm-stub"]);
95
+ await new Promise((r) => setTimeout(r, 100));
96
+ writeFileSync(pf, String(proc.pid) + "\n");
97
+ const r = runScrub(pf);
98
+ proc.kill("SIGKILL");
99
+ assert.equal(r.status, 0);
100
+ assert.match(r.stdout, /no-op .*reason=live-neo4j/);
101
+ assert.equal(existsSync(pf), true); // never removes a live neo4j's pidfile
102
+ rmSync(dir, { recursive: true, force: true });
103
+ });
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { resolveInstallPortFromFs, buildMaxyUnitFile, buildClaudeSessionManagerU
9
9
  import { validateTierFlag, validateEntitlementBase64, applyTierToAccountConfig, entitlementPath } from "./tier-flag.js";
10
10
  import { parseOsRelease, isUbuntuLike as isUbuntuLikePure, parseAptCacheCandidate, decideAptResolution, } from "./apt-resolve.js";
11
11
  import { findPeerBrandOnDefaultNeo4jPort } from "./peer-brand-detect.js";
12
+ import { resolveNeo4jPidfileScrub } from "./neo4j-pidfile-scrub.js";
12
13
  import { runInitLogging } from "./init-logging.js";
13
14
  import { requireSupportedPlatform, detectPlatform } from "./platform-detect.js";
14
15
  import { protectCommands, unprotectCommands, lsattrShowsImmutable } from "./install-immutability.js";
@@ -1515,13 +1516,16 @@ WantedBy=multi-user.target
1515
1516
  // ============================================================================
1516
1517
  // unified state remediation + start + verify.
1517
1518
  //
1518
- // Runs on both fresh and recovery paths. The dedicated unit and the apt
1519
- // package's system unit both exec /usr/bin/neo4j console without overriding
1520
- // NEO4J_HOME, so server.directories.run resolves to /var/lib/neo4j/run for
1521
- // both the launcher refuses with "Neo4j is already running (pid:N)" if
1522
- // the system unit holds the PID file. Stopping the system unit first frees
1523
- // the run-state; disabling prevents it returning at next boot. reset-failed
1524
- // clears any prior start-limit-hit from a half-installed Pi.
1519
+ // Runs on both fresh and recovery paths. The apt system unit leaves
1520
+ // NEO4J_HOME unset so its run dir is /var/lib/neo4j/run; the dedicated unit
1521
+ // sets NEO4J_HOME=<per-brand data dir> so server.directories.run resolves
1522
+ // per-brand to <data dir>/run no collision with the system unit's pidfile.
1523
+ // Either way the launcher refuses with "Neo4j is already running (pid:N)" if
1524
+ // a stale run-dir pidfile names a still-live PID. Stopping the system unit
1525
+ // first frees its run-state; disabling prevents it returning at next boot.
1526
+ // reset-failed clears any prior start-limit-hit from a half-installed Pi.
1527
+ // (The per-boot scrub from provisionNeo4jPidfileScrub auto-clears the
1528
+ // reused-PID case on every subsequent boot.)
1525
1529
  // ============================================================================
1526
1530
  spawnSync("sudo", ["systemctl", "daemon-reload"], { stdio: "inherit" });
1527
1531
  console.log(" [privileged] systemctl enable");
@@ -1599,6 +1603,36 @@ WantedBy=multi-user.target
1599
1603
  logFile(` Neo4j dedicated: config=${confDir} data=${dataDir} service=${serviceName} bolt=:${NEO4J_PORT} http=:${httpPort}`);
1600
1604
  console.log(` Dedicated Neo4j instance ready on bolt://localhost:${NEO4J_PORT}`);
1601
1605
  }
1606
+ // Provision the per-boot stale-pidfile scrub drop-in for whichever Neo4j unit
1607
+ // this brand uses. The drop-in's ExecStartPre runs the host-shared scrub script
1608
+ // before each unit start, removing a stale run-dir pidfile whose PID is not a
1609
+ // live Neo4j (the reused-PID case that browns-out a Pi into a non-starting
1610
+ // Neo4j after an unclean reboot). Idempotent: fixed paths, overwritten each
1611
+ // install, never appended. Linux-only — a no-op on darwin/dev hosts.
1612
+ function provisionNeo4jPidfileScrub() {
1613
+ if (process.platform !== "linux")
1614
+ return;
1615
+ const plan = resolveNeo4jPidfileScrub({ brandHostname: BRAND.hostname, neo4jPort: NEO4J_PORT });
1616
+ if (plan === null) {
1617
+ logFile(` [neo4j] pidfile-scrub: no plan (port=${NEO4J_PORT} hostname=${BRAND.hostname}) — skipped`);
1618
+ return;
1619
+ }
1620
+ // pid-namespaced staging paths so two co-resident brand installs never race
1621
+ // on a shared /tmp file (matches the file's other tmp-staging idioms).
1622
+ const tmpScript = `/tmp/maxy-neo4j-pidfile-scrub.${process.pid}.sh`;
1623
+ writeFileSync(tmpScript, plan.scriptContent);
1624
+ shell("cp", [tmpScript, plan.scriptPath], { sudo: true });
1625
+ shell("chmod", ["0755", plan.scriptPath], { sudo: true });
1626
+ spawnSync("rm", ["-f", tmpScript]);
1627
+ shell("mkdir", ["-p", plan.dropinDir], { sudo: true });
1628
+ const tmpDropin = `/tmp/10-maxy-pidfile-scrub.${process.pid}.conf`;
1629
+ writeFileSync(tmpDropin, plan.dropinContent);
1630
+ shell("cp", [tmpDropin, plan.dropinPath], { sudo: true });
1631
+ spawnSync("rm", ["-f", tmpDropin]);
1632
+ spawnSync("sudo", ["systemctl", "daemon-reload"], { stdio: "inherit" });
1633
+ console.log(` [neo4j] pidfile-scrub armed for ${plan.unit} (ExecStartPre scrubs ${plan.pidfile})`);
1634
+ logFile(` [neo4j] pidfile-scrub armed unit=${plan.unit} pidfile=${plan.pidfile} dropin=${plan.dropinPath} script=${plan.scriptPath}`);
1635
+ }
1602
1636
  function ensureOllamaServing() {
1603
1637
  const check = () => spawnSync("curl", ["-sf", "http://localhost:11434/api/tags"], {
1604
1638
  stdio: "pipe", timeout: 5_000,
@@ -4347,6 +4381,7 @@ try {
4347
4381
  installClaudeCode();
4348
4382
  installNeo4j();
4349
4383
  setupDedicatedNeo4j();
4384
+ provisionNeo4jPidfileScrub();
4350
4385
  installOllama(EMBED_MODEL);
4351
4386
  installUv();
4352
4387
  installCloudflared();
@@ -0,0 +1,90 @@
1
+ // Pure per-boot Neo4j stale-pidfile scrub resolution + the scrub script body.
2
+ // Mirrors neo4j-teardown.ts: inputs in, plan out, no fs/systemctl. The installer
3
+ // wrapper (provisionNeo4jPidfileScrub in index.ts) owns the privileged writes.
4
+ //
5
+ // Why: after an unclean reboot the neo4j launcher refuses to start with
6
+ // "Neo4j is already running (pid:N)" when the run-dir pidfile names a PID that
7
+ // is alive but reused by an unrelated process (the launcher's kill -0 liveness
8
+ // check false-positives). The scrub runs as the unit's ExecStartPre and removes
9
+ // the pidfile IFF the PID it names is not a live Neo4j process, so the next boot
10
+ // recovers with no human action. It never removes a pidfile naming a live Neo4j.
11
+ import { SHARED_NEO4J_PORT, resolveDedicatedNeo4jTeardown } from "./neo4j-teardown.js";
12
+ /** Host-shared scrub script path. Stateless and parameterised by the pidfile
13
+ * path, so one copy serves the apt unit and any dedicated unit. */
14
+ export const SCRUB_SCRIPT_PATH = "/usr/local/lib/maxy-neo4j-pidfile-scrub.sh";
15
+ const DROPIN_BASENAME = "10-maxy-pidfile-scrub.conf";
16
+ /** The scrub script body. POSIX sh. $1 = the run-dir pidfile path. Always exits
17
+ * 0 — an ExecStartPre that fails would block the unit from starting. Emits one
18
+ * line per run naming the action, pidfile, PID, and what the PID was. */
19
+ export const SCRUB_SCRIPT = `#!/bin/sh
20
+ # Maxy per-boot Neo4j stale-pidfile scrub. ExecStartPre for the brand's Neo4j
21
+ # unit. Removes the run-dir pidfile IFF the PID it names is not a live Neo4j
22
+ # process, so an unclean reboot that left a stale pidfile (whose PID may have
23
+ # been reused by an unrelated process) does not make the launcher false-positive
24
+ # "Neo4j is already running". Never removes a pidfile naming a live Neo4j.
25
+ # Always exits 0 so it cannot block unit start.
26
+ set -u
27
+ PIDFILE="\${1:-}"
28
+ emit() { echo "neo4j-pidfile-scrub $1 pidfile=\${PIDFILE:-<none>} pid=$2 reason=$3"; }
29
+
30
+ if [ -z "$PIDFILE" ]; then emit no-op '<none>' no-pidfile-arg; exit 0; fi
31
+ if [ ! -e "$PIDFILE" ]; then emit no-op '<none>' absent; exit 0; fi
32
+
33
+ PID="$(tr -d '[:space:]' < "$PIDFILE" 2>/dev/null)"
34
+ case "$PID" in
35
+ ''|*[!0-9]*) emit removed "\${PID:-<empty>}" unparseable; rm -f "$PIDFILE"; exit 0 ;;
36
+ esac
37
+
38
+ if ! kill -0 "$PID" 2>/dev/null; then
39
+ emit removed "$PID" dead
40
+ rm -f "$PIDFILE"
41
+ exit 0
42
+ fi
43
+
44
+ CMD="$(tr '\\0' ' ' < "/proc/$PID/cmdline" 2>/dev/null)"
45
+ case "$CMD" in
46
+ *neo4j*) emit no-op "$PID" live-neo4j; exit 0 ;;
47
+ *) emit removed "$PID" alive-other; rm -f "$PIDFILE"; exit 0 ;;
48
+ esac
49
+ `;
50
+ /**
51
+ * Resolve the per-boot scrub plan for a brand's Neo4j unit, or `null` when no
52
+ * unit can be safely targeted:
53
+ * - `neo4jPort === undefined`: unreadable port — never guess the unit.
54
+ * - dedicated port with empty `brandHostname`: no `neo4j-<host>` unit exists.
55
+ * A default-brand port (7687) targets the shared apt `neo4j` unit; any other
56
+ * port targets the brand-dedicated `neo4j-<hostname>` unit, whose run dir lives
57
+ * under its per-brand `NEO4J_HOME` (`<dataDir>/run`). The dedicated unit name +
58
+ * data dir are taken from `resolveDedicatedNeo4jTeardown` so install, uninstall,
59
+ * and this scrub share one derivation and never drift.
60
+ */
61
+ export function resolveNeo4jPidfileScrub(args) {
62
+ const { brandHostname, neo4jPort } = args;
63
+ if (neo4jPort === undefined)
64
+ return null;
65
+ let unit;
66
+ let pidfile;
67
+ if (neo4jPort === SHARED_NEO4J_PORT) {
68
+ unit = "neo4j";
69
+ pidfile = "/var/lib/neo4j/run/neo4j.pid";
70
+ }
71
+ else {
72
+ // Dedicated brand: reuse the teardown resolver's unit/dataDir derivation
73
+ // (returns null on empty hostname) rather than re-deriving the names here.
74
+ const dedicated = resolveDedicatedNeo4jTeardown({ brandHostname, neo4jPort });
75
+ if (dedicated === null)
76
+ return null;
77
+ unit = dedicated.service;
78
+ pidfile = `${dedicated.dataDir}/run/neo4j.pid`;
79
+ }
80
+ const dropinDir = `/etc/systemd/system/${unit}.service.d`;
81
+ return {
82
+ unit,
83
+ pidfile,
84
+ dropinDir,
85
+ dropinPath: `${dropinDir}/${DROPIN_BASENAME}`,
86
+ dropinContent: `[Service]\nExecStartPre=+${SCRUB_SCRIPT_PATH} ${pidfile}\n`,
87
+ scriptPath: SCRUB_SCRIPT_PATH,
88
+ scriptContent: SCRUB_SCRIPT,
89
+ };
90
+ }
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
+ import os from "node:os";
3
4
  const PORT_RE = /^PORT=(\d+)/m;
4
5
  const ENV_PORT_RE = /^Environment=PORT=(\d+)/m;
5
6
  const ENV_EDGE_PORT_RE = /^Environment=EDGE_PORT=(\d+)/m;
@@ -174,13 +175,29 @@ WantedBy=default.target
174
175
  // `~/.config/systemd/user/claude-ptys.slice` and runs
175
176
  // `systemctl --user daemon-reload` so the new unit is picked up.
176
177
  // ---------------------------------------------------------------------------
177
- export function buildClaudePtysSliceUnitFile() {
178
+ // Task 1176 — the slice carries a soft MemoryHigh so the session cohort
179
+ // absorbs reclaim pressure (throttle/swap within the slice) before the box
180
+ // exhausts RAM and the kernel kills the brand server. The value is total
181
+ // RAM minus a fixed ~2.7GB floor (neo4j + brand server + edge/manager/chrome
182
+ // must stay resident), clamped to a 2GiB minimum so a small host still emits
183
+ // a valid, non-trivial ceiling. MemoryHigh is a SOFT reclaim threshold —
184
+ // never MemoryMax, which would hard-kill within the slice and just relocate
185
+ // the failure.
186
+ const SLICE_FLOOR_BYTES = Math.round(2.7 * 1024 ** 3);
187
+ const SLICE_MIN_HIGH_BYTES = 2 * 1024 ** 3;
188
+ export function resolveClaudePtysSliceMemoryHigh(totalMemBytes) {
189
+ const high = Math.max(totalMemBytes - SLICE_FLOOR_BYTES, SLICE_MIN_HIGH_BYTES);
190
+ return `${Math.round(high / 1024 ** 2)}M`;
191
+ }
192
+ export function buildClaudePtysSliceUnitFile(totalMemBytes = os.totalmem()) {
193
+ const memoryHigh = resolveClaudePtysSliceMemoryHigh(totalMemBytes);
178
194
  return `[Unit]
179
195
  Description=Claude Code PTY sessions (Task 250)
180
196
  Documentation=https://github.com/rubytech/maxy-code/blob/main/.tasks/archive/250-claude-ptys-survive-manager-restart-via-systemd-scope-per-pty.md
181
197
  Before=shutdown.target
182
198
 
183
199
  [Slice]
200
+ MemoryHigh=${memoryHigh}
184
201
 
185
202
  [Install]
186
203
  WantedBy=default.target
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.357",
3
+ "version": "0.1.359",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"