@rubytech/create-maxy-code 0.1.604 → 0.1.606

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 (256) hide show
  1. package/dist/__tests__/claude-trust-seed.test.js +125 -0
  2. package/dist/claude-trust-seed.js +52 -0
  3. package/dist/index.js +68 -33
  4. package/package.json +1 -1
  5. package/payload/platform/lib/routine-templates/dist/roster.d.ts +30 -2
  6. package/payload/platform/lib/routine-templates/dist/roster.d.ts.map +1 -1
  7. package/payload/platform/lib/routine-templates/dist/roster.js +76 -32
  8. package/payload/platform/lib/routine-templates/dist/roster.js.map +1 -1
  9. package/payload/platform/lib/routine-templates/src/__tests__/roster.test.ts +0 -0
  10. package/payload/platform/lib/routine-templates/src/__tests__/seed.test.ts +22 -1
  11. package/payload/platform/lib/routine-templates/src/roster.ts +108 -35
  12. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +18 -3
  13. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +10 -0
  14. package/payload/platform/plugins/connector/PLUGIN.md +9 -1
  15. package/payload/platform/plugins/connector/mcp/dist/__tests__/queue-descriptor.test.d.ts +2 -0
  16. package/payload/platform/plugins/connector/mcp/dist/__tests__/queue-descriptor.test.d.ts.map +1 -0
  17. package/payload/platform/plugins/connector/mcp/dist/__tests__/queue-descriptor.test.js +67 -0
  18. package/payload/platform/plugins/connector/mcp/dist/__tests__/queue-descriptor.test.js.map +1 -0
  19. package/payload/platform/plugins/connector/mcp/dist/index.js +36 -5
  20. package/payload/platform/plugins/connector/mcp/dist/index.js.map +1 -1
  21. package/payload/platform/plugins/connector/mcp/dist/lib/store.d.ts +35 -0
  22. package/payload/platform/plugins/connector/mcp/dist/lib/store.d.ts.map +1 -1
  23. package/payload/platform/plugins/connector/mcp/dist/lib/store.js +33 -0
  24. package/payload/platform/plugins/connector/mcp/dist/lib/store.js.map +1 -1
  25. package/payload/platform/plugins/connector/mcp/package.json +4 -2
  26. package/payload/platform/plugins/connector/mcp/vitest.config.ts +8 -0
  27. package/payload/platform/plugins/docs/references/admin-ui.md +15 -2
  28. package/payload/platform/plugins/docs/references/platform.md +2 -0
  29. package/payload/platform/plugins/email/PLUGIN.md +4 -0
  30. package/payload/platform/plugins/email/mcp/dist/sampler/__tests__/retention.test.d.ts +2 -0
  31. package/payload/platform/plugins/email/mcp/dist/sampler/__tests__/retention.test.d.ts.map +1 -0
  32. package/payload/platform/plugins/email/mcp/dist/sampler/__tests__/retention.test.js +233 -0
  33. package/payload/platform/plugins/email/mcp/dist/sampler/__tests__/retention.test.js.map +1 -0
  34. package/payload/platform/plugins/email/mcp/dist/sampler/main.js +19 -0
  35. package/payload/platform/plugins/email/mcp/dist/sampler/main.js.map +1 -1
  36. package/payload/platform/plugins/email/mcp/dist/sampler/retention-sources.d.ts +3 -0
  37. package/payload/platform/plugins/email/mcp/dist/sampler/retention-sources.d.ts.map +1 -0
  38. package/payload/platform/plugins/email/mcp/dist/sampler/retention-sources.js +146 -0
  39. package/payload/platform/plugins/email/mcp/dist/sampler/retention-sources.js.map +1 -0
  40. package/payload/platform/plugins/email/mcp/dist/sampler/retention.d.ts +150 -0
  41. package/payload/platform/plugins/email/mcp/dist/sampler/retention.d.ts.map +1 -0
  42. package/payload/platform/plugins/email/mcp/dist/sampler/retention.js +199 -0
  43. package/payload/platform/plugins/email/mcp/dist/sampler/retention.js.map +1 -0
  44. package/payload/platform/plugins/scheduling/PLUGIN.md +8 -1
  45. package/payload/platform/plugins/scheduling/mcp/dist/index.js +1 -1
  46. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
  47. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js +40 -0
  48. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/schedule-gate-write.test.js.map +1 -1
  49. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +322 -4
  50. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
  51. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
  52. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +21 -1
  53. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
  54. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +236 -6
  55. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
  56. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +452 -7
  57. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
  58. package/payload/platform/services/claude-session-manager/dist/claude-trust-census.d.ts +34 -0
  59. package/payload/platform/services/claude-session-manager/dist/claude-trust-census.d.ts.map +1 -0
  60. package/payload/platform/services/claude-session-manager/dist/claude-trust-census.js +83 -0
  61. package/payload/platform/services/claude-session-manager/dist/claude-trust-census.js.map +1 -0
  62. package/payload/platform/services/claude-session-manager/dist/index.js +13 -0
  63. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  64. package/payload/server/public/activity.html +6 -6
  65. package/payload/server/public/agents.html +5 -5
  66. package/payload/server/public/assets/AdminLoginScreens-DuQ3ax5U.js +1 -0
  67. package/payload/server/public/assets/AdminLoginScreens-DuQ3ax5U.js.br +0 -0
  68. package/payload/server/public/assets/AdminLoginScreens-DuQ3ax5U.js.gz +0 -0
  69. package/payload/server/public/assets/AdminShell-1HyATV_t.js +3 -0
  70. package/payload/server/public/assets/AdminShell-1HyATV_t.js.br +0 -0
  71. package/payload/server/public/assets/AdminShell-1HyATV_t.js.gz +0 -0
  72. package/payload/server/public/assets/activity-C2qWlcJ5.js +1 -0
  73. package/payload/server/public/assets/activity-C2qWlcJ5.js.br +0 -0
  74. package/payload/server/public/assets/activity-C2qWlcJ5.js.gz +0 -0
  75. package/payload/server/public/assets/admin-DqpfY8-t.js +1 -0
  76. package/payload/server/public/assets/admin-DqpfY8-t.js.br +0 -0
  77. package/payload/server/public/assets/admin-DqpfY8-t.js.gz +0 -0
  78. package/payload/server/public/assets/agents-DoGVAjIT.js +1 -0
  79. package/payload/server/public/assets/agents-DoGVAjIT.js.br +0 -0
  80. package/payload/server/public/assets/agents-DoGVAjIT.js.gz +0 -0
  81. package/payload/server/public/assets/{browser-CqDBcKwU.js → browser-DjqS897k.js} +1 -1
  82. package/payload/server/public/assets/browser-DjqS897k.js.br +0 -0
  83. package/payload/server/public/assets/browser-DjqS897k.js.gz +0 -0
  84. package/payload/server/public/assets/calendar-DJeOm0WS.js +1 -0
  85. package/payload/server/public/assets/calendar-DJeOm0WS.js.br +0 -0
  86. package/payload/server/public/assets/calendar-DJeOm0WS.js.gz +0 -0
  87. package/payload/server/public/assets/chat-BrRE0Dck.js +1 -0
  88. package/payload/server/public/assets/chat-BrRE0Dck.js.br +0 -0
  89. package/payload/server/public/assets/chat-BrRE0Dck.js.gz +0 -0
  90. package/payload/server/public/assets/chevron-left-D9z1aK3p.js +1 -0
  91. package/payload/server/public/assets/chevron-left-D9z1aK3p.js.br +0 -0
  92. package/payload/server/public/assets/clock-BqHWMICF.js +1 -0
  93. package/payload/server/public/assets/clock-BqHWMICF.js.br +0 -0
  94. package/payload/server/public/assets/clock-BqHWMICF.js.gz +0 -0
  95. package/payload/server/public/assets/copy-p9ZM9fnn.js +1 -0
  96. package/payload/server/public/assets/copy-p9ZM9fnn.js.br +0 -0
  97. package/payload/server/public/assets/copy-p9ZM9fnn.js.gz +0 -0
  98. package/payload/server/public/assets/data-CPsqW0qW.js +1 -0
  99. package/payload/server/public/assets/data-CPsqW0qW.js.br +0 -0
  100. package/payload/server/public/assets/data-CPsqW0qW.js.gz +0 -0
  101. package/payload/server/public/assets/{field-X4OVA3vx.js → field-WRk67lvr.js} +1 -1
  102. package/payload/server/public/assets/field-WRk67lvr.js.br +0 -0
  103. package/payload/server/public/assets/field-WRk67lvr.js.gz +0 -0
  104. package/payload/server/public/assets/file-text-BJDCb334.js +1 -0
  105. package/payload/server/public/assets/file-text-BJDCb334.js.br +0 -0
  106. package/payload/server/public/assets/file-text-BJDCb334.js.gz +0 -0
  107. package/payload/server/public/assets/{graph-l7tzHqvm.js → graph-CAU2xh2Z.js} +2 -2
  108. package/payload/server/public/assets/graph-CAU2xh2Z.js.br +0 -0
  109. package/payload/server/public/assets/graph-CAU2xh2Z.js.gz +0 -0
  110. package/payload/server/public/assets/graph-labels-CEDmX7qW.js +1 -0
  111. package/payload/server/public/assets/graph-labels-CEDmX7qW.js.br +0 -0
  112. package/payload/server/public/assets/graph-labels-CEDmX7qW.js.gz +0 -0
  113. package/payload/server/public/assets/{jsx-runtime-bq0g4NlA.css → jsx-runtime-hPFGo4rC.css} +1 -1
  114. package/payload/server/public/assets/jsx-runtime-hPFGo4rC.css.br +0 -0
  115. package/payload/server/public/assets/{jsx-runtime-bq0g4NlA.css.gz → jsx-runtime-hPFGo4rC.css.gz} +0 -0
  116. package/payload/server/public/assets/{operator-Dg-dwf7a.js → operator-1WFztEQA.js} +1 -1
  117. package/payload/server/public/assets/operator-1WFztEQA.js.br +0 -0
  118. package/payload/server/public/assets/operator-1WFztEQA.js.gz +0 -0
  119. package/payload/server/public/assets/page-B72XigcU.js +32 -0
  120. package/payload/server/public/assets/page-B72XigcU.js.br +0 -0
  121. package/payload/server/public/assets/page-B72XigcU.js.gz +0 -0
  122. package/payload/server/public/assets/page-nT8l_cX1.js +1 -0
  123. package/payload/server/public/assets/page-nT8l_cX1.js.br +0 -0
  124. package/payload/server/public/assets/page-nT8l_cX1.js.gz +0 -0
  125. package/payload/server/public/assets/play-CYqOCqm6.js +1 -0
  126. package/payload/server/public/assets/play-CYqOCqm6.js.br +0 -0
  127. package/payload/server/public/assets/play-CYqOCqm6.js.gz +0 -0
  128. package/payload/server/public/assets/public-DAea6w7w.js +1 -0
  129. package/payload/server/public/assets/public-DAea6w7w.js.br +0 -0
  130. package/payload/server/public/assets/public-DAea6w7w.js.gz +0 -0
  131. package/payload/server/public/assets/rotate-ccw-CqlRlGsY.js +1 -0
  132. package/payload/server/public/assets/rotate-ccw-CqlRlGsY.js.br +0 -0
  133. package/payload/server/public/assets/rotate-ccw-CqlRlGsY.js.gz +0 -0
  134. package/payload/server/public/assets/{routines-6fxZNacQ.js → routines-vy5xsyqx.js} +2 -2
  135. package/payload/server/public/assets/routines-vy5xsyqx.js.br +0 -0
  136. package/payload/server/public/assets/routines-vy5xsyqx.js.gz +0 -0
  137. package/payload/server/public/assets/{skills-51mqx-s5.js → skills-X7FTilVy.js} +1 -1
  138. package/payload/server/public/assets/skills-X7FTilVy.js.br +0 -0
  139. package/payload/server/public/assets/skills-X7FTilVy.js.gz +0 -0
  140. package/payload/server/public/assets/tasks-BXx_jk_p.js +3 -0
  141. package/payload/server/public/assets/tasks-BXx_jk_p.js.br +0 -0
  142. package/payload/server/public/assets/tasks-BXx_jk_p.js.gz +0 -0
  143. package/payload/server/public/assets/triangle-alert-CuWcGaRo.js +1 -0
  144. package/payload/server/public/assets/triangle-alert-CuWcGaRo.js.br +0 -0
  145. package/payload/server/public/assets/triangle-alert-CuWcGaRo.js.gz +0 -0
  146. package/payload/server/public/assets/{useCopyFeedback-BG7h37Rx.js → useCopyFeedback-DLSKs6r2.js} +1 -1
  147. package/payload/server/public/assets/useCopyFeedback-DLSKs6r2.js.br +0 -0
  148. package/payload/server/public/assets/useCopyFeedback-DLSKs6r2.js.gz +0 -0
  149. package/payload/server/public/assets/useMediaQuery-C_1CV_iW.js +6 -0
  150. package/payload/server/public/assets/useMediaQuery-C_1CV_iW.js.br +0 -0
  151. package/payload/server/public/assets/useMediaQuery-C_1CV_iW.js.gz +0 -0
  152. package/payload/server/public/assets/useVoiceRecorder-DBzM_HIx.js +2 -0
  153. package/payload/server/public/assets/useVoiceRecorder-DBzM_HIx.js.br +0 -0
  154. package/payload/server/public/assets/useVoiceRecorder-DBzM_HIx.js.gz +0 -0
  155. package/payload/server/public/assets/wrench-nDMQ6x-6.js +1 -0
  156. package/payload/server/public/assets/wrench-nDMQ6x-6.js.br +0 -0
  157. package/payload/server/public/assets/wrench-nDMQ6x-6.js.gz +0 -0
  158. package/payload/server/public/browser.html +5 -5
  159. package/payload/server/public/calendar.html +8 -8
  160. package/payload/server/public/chat.html +14 -14
  161. package/payload/server/public/data.html +12 -12
  162. package/payload/server/public/field.html +3 -3
  163. package/payload/server/public/graph.html +10 -10
  164. package/payload/server/public/index.html +14 -14
  165. package/payload/server/public/operator.html +16 -16
  166. package/payload/server/public/public.html +14 -14
  167. package/payload/server/public/routines.html +8 -8
  168. package/payload/server/public/skills.html +6 -6
  169. package/payload/server/public/tasks.html +7 -7
  170. package/payload/server/server.js +1 -1
  171. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js +0 -1
  172. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.br +0 -0
  173. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.gz +0 -0
  174. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js +0 -3
  175. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.br +0 -0
  176. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.gz +0 -0
  177. package/payload/server/public/assets/activity-CqgFwANo.js +0 -1
  178. package/payload/server/public/assets/activity-CqgFwANo.js.br +0 -0
  179. package/payload/server/public/assets/activity-CqgFwANo.js.gz +0 -0
  180. package/payload/server/public/assets/admin-K63n6ybW.js +0 -1
  181. package/payload/server/public/assets/admin-K63n6ybW.js.br +0 -0
  182. package/payload/server/public/assets/admin-K63n6ybW.js.gz +0 -0
  183. package/payload/server/public/assets/agents-cue5Zf8X.js +0 -1
  184. package/payload/server/public/assets/agents-cue5Zf8X.js.br +0 -0
  185. package/payload/server/public/assets/agents-cue5Zf8X.js.gz +0 -0
  186. package/payload/server/public/assets/browser-CqDBcKwU.js.br +0 -0
  187. package/payload/server/public/assets/browser-CqDBcKwU.js.gz +0 -0
  188. package/payload/server/public/assets/calendar-BgzuW5Rt.js +0 -1
  189. package/payload/server/public/assets/calendar-BgzuW5Rt.js.br +0 -0
  190. package/payload/server/public/assets/calendar-BgzuW5Rt.js.gz +0 -0
  191. package/payload/server/public/assets/chat-HYZViu2u.js +0 -1
  192. package/payload/server/public/assets/chat-HYZViu2u.js.br +0 -3
  193. package/payload/server/public/assets/chat-HYZViu2u.js.gz +0 -0
  194. package/payload/server/public/assets/chevron-left-C5FXH9r_.js +0 -1
  195. package/payload/server/public/assets/chevron-left-C5FXH9r_.js.br +0 -0
  196. package/payload/server/public/assets/clock-DxPtyejC.js +0 -1
  197. package/payload/server/public/assets/clock-DxPtyejC.js.br +0 -0
  198. package/payload/server/public/assets/clock-DxPtyejC.js.gz +0 -0
  199. package/payload/server/public/assets/copy-BNhZ0flH.js +0 -1
  200. package/payload/server/public/assets/copy-BNhZ0flH.js.br +0 -0
  201. package/payload/server/public/assets/copy-BNhZ0flH.js.gz +0 -0
  202. package/payload/server/public/assets/data-kCBB8Z4Z.js +0 -1
  203. package/payload/server/public/assets/data-kCBB8Z4Z.js.br +0 -0
  204. package/payload/server/public/assets/data-kCBB8Z4Z.js.gz +0 -0
  205. package/payload/server/public/assets/field-X4OVA3vx.js.br +0 -0
  206. package/payload/server/public/assets/field-X4OVA3vx.js.gz +0 -0
  207. package/payload/server/public/assets/file-text-BddO_2EI.js +0 -1
  208. package/payload/server/public/assets/file-text-BddO_2EI.js.br +0 -0
  209. package/payload/server/public/assets/file-text-BddO_2EI.js.gz +0 -0
  210. package/payload/server/public/assets/graph-l7tzHqvm.js.br +0 -0
  211. package/payload/server/public/assets/graph-l7tzHqvm.js.gz +0 -0
  212. package/payload/server/public/assets/graph-labels-CtFFq5W2.js +0 -1
  213. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.br +0 -0
  214. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.gz +0 -0
  215. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.br +0 -0
  216. package/payload/server/public/assets/operator-Dg-dwf7a.js.br +0 -7
  217. package/payload/server/public/assets/operator-Dg-dwf7a.js.gz +0 -0
  218. package/payload/server/public/assets/page-Ci1bfIbs.js +0 -1
  219. package/payload/server/public/assets/page-Ci1bfIbs.js.br +0 -0
  220. package/payload/server/public/assets/page-Ci1bfIbs.js.gz +0 -0
  221. package/payload/server/public/assets/page-Y9JmFq0Q.js +0 -32
  222. package/payload/server/public/assets/page-Y9JmFq0Q.js.br +0 -0
  223. package/payload/server/public/assets/page-Y9JmFq0Q.js.gz +0 -0
  224. package/payload/server/public/assets/play-BSZVGpQT.js +0 -1
  225. package/payload/server/public/assets/play-BSZVGpQT.js.br +0 -0
  226. package/payload/server/public/assets/play-BSZVGpQT.js.gz +0 -0
  227. package/payload/server/public/assets/public-m66FAza_.js +0 -1
  228. package/payload/server/public/assets/public-m66FAza_.js.br +0 -0
  229. package/payload/server/public/assets/public-m66FAza_.js.gz +0 -0
  230. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js +0 -1
  231. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.br +0 -0
  232. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.gz +0 -0
  233. package/payload/server/public/assets/routines-6fxZNacQ.js.br +0 -0
  234. package/payload/server/public/assets/routines-6fxZNacQ.js.gz +0 -0
  235. package/payload/server/public/assets/skills-51mqx-s5.js.br +0 -0
  236. package/payload/server/public/assets/skills-51mqx-s5.js.gz +0 -0
  237. package/payload/server/public/assets/tasks-D4y-Cwa3.js +0 -3
  238. package/payload/server/public/assets/tasks-D4y-Cwa3.js.br +0 -0
  239. package/payload/server/public/assets/tasks-D4y-Cwa3.js.gz +0 -0
  240. package/payload/server/public/assets/triangle-alert-BzCjDFts.js +0 -1
  241. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.br +0 -0
  242. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.gz +0 -0
  243. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.br +0 -2
  244. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.gz +0 -0
  245. package/payload/server/public/assets/useMediaQuery-CqwktQr_.js +0 -6
  246. package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.br +0 -0
  247. package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.gz +0 -0
  248. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js +0 -2
  249. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.br +0 -0
  250. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.gz +0 -0
  251. package/payload/server/public/assets/wrench-B2WKLLQG.js +0 -1
  252. package/payload/server/public/assets/wrench-B2WKLLQG.js.br +0 -0
  253. package/payload/server/public/assets/wrench-B2WKLLQG.js.gz +0 -0
  254. /package/payload/server/public/assets/{jsx-runtime-UK6hgBWO.js → jsx-runtime-CvVXOszc.js} +0 -0
  255. /package/payload/server/public/assets/{jsx-runtime-UK6hgBWO.js.br → jsx-runtime-CvVXOszc.js.br} +0 -0
  256. /package/payload/server/public/assets/{jsx-runtime-UK6hgBWO.js.gz → jsx-runtime-CvVXOszc.js.gz} +0 -0
@@ -0,0 +1,125 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { seedClaudeTrust, formatTrustSeedLine } from "../claude-trust-seed.js";
4
+ const ROOT = "/home/neo/maxy-code/data/accounts";
5
+ const A = `${ROOT}/aaa`;
6
+ const B = `${ROOT}/bbb`;
7
+ test("seeds every account directory that exists, alongside $HOME", () => {
8
+ const r = seedClaudeTrust({
9
+ state: {},
10
+ homeWorkspace: "/home/neo",
11
+ accountsRoot: ROOT,
12
+ accountDirs: [A, B],
13
+ });
14
+ const projects = r.state.projects;
15
+ assert.equal(projects["/home/neo"].hasTrustDialogAccepted, true);
16
+ assert.equal(projects[A].hasTrustDialogAccepted, true);
17
+ assert.equal(projects[B].hasTrustDialogAccepted, true);
18
+ assert.equal(r.state.hasCompletedOnboarding, true);
19
+ assert.deepEqual({ accounts: r.accounts, seeded: r.seeded, alreadyTrusted: r.alreadyTrusted, stale: r.stale }, { accounts: 2, seeded: 2, alreadyTrusted: 0, stale: 0 });
20
+ });
21
+ test("preserves other keys on an account entry and counts an existing true as already-set", () => {
22
+ const r = seedClaudeTrust({
23
+ state: {
24
+ numStartups: 519,
25
+ projects: {
26
+ [A]: { hasTrustDialogAccepted: true, exampleFilesGenerated: true },
27
+ [B]: { hasTrustDialogAccepted: false, lastCost: 1.5 },
28
+ },
29
+ },
30
+ homeWorkspace: "/home/neo",
31
+ accountsRoot: ROOT,
32
+ accountDirs: [A, B],
33
+ });
34
+ const projects = r.state.projects;
35
+ assert.equal(r.state.numStartups, 519);
36
+ assert.equal(projects[A].exampleFilesGenerated, true);
37
+ assert.equal(projects[B].lastCost, 1.5);
38
+ assert.equal(projects[B].hasTrustDialogAccepted, true);
39
+ assert.equal(r.alreadyTrusted, 1);
40
+ assert.equal(r.seeded, 1);
41
+ });
42
+ test("an entry whose directory is gone keeps its value and counts as stale", () => {
43
+ const gone = `${ROOT}/deleted`;
44
+ const r = seedClaudeTrust({
45
+ state: { projects: { [gone]: { hasTrustDialogAccepted: false } } },
46
+ homeWorkspace: "/home/neo",
47
+ accountsRoot: ROOT,
48
+ accountDirs: [A],
49
+ });
50
+ const projects = r.state.projects;
51
+ assert.equal(projects[gone].hasTrustDialogAccepted, false);
52
+ assert.equal(r.stale, 1);
53
+ assert.equal(r.accounts, 1);
54
+ });
55
+ // The CLI records an entry for any directory a session ran in, so an account's
56
+ // own subdirectories sit under the accounts root too. Counting them as stale
57
+ // accounts would inflate the field for every operator who worked inside one.
58
+ test("a subdirectory of a live account is not counted as a stale account", () => {
59
+ const r = seedClaudeTrust({
60
+ state: {
61
+ projects: {
62
+ [A]: { hasTrustDialogAccepted: true },
63
+ [`${A}/sites/portal`]: { hasTrustDialogAccepted: true },
64
+ },
65
+ },
66
+ homeWorkspace: "/home/neo",
67
+ accountsRoot: ROOT,
68
+ accountDirs: [A],
69
+ });
70
+ assert.equal(r.stale, 0);
71
+ });
72
+ test("no account directories is accounts=0, not a throw", () => {
73
+ const r = seedClaudeTrust({
74
+ state: {},
75
+ homeWorkspace: "/home/neo",
76
+ accountsRoot: ROOT,
77
+ accountDirs: [],
78
+ });
79
+ assert.equal(r.accounts, 0);
80
+ assert.equal(r.state.projects["/home/neo"] !== undefined, true);
81
+ });
82
+ // deployPayload() runs before setupAccount(), so on a FRESH install the first
83
+ // pass sees no accounts directory at all and the account that setupAccount
84
+ // then creates would never be trusted. The installer therefore primes twice;
85
+ // this pins the shape that second pass depends on.
86
+ test("fresh-install shape: an empty first pass then a second pass seeds the new account", () => {
87
+ const first = seedClaudeTrust({
88
+ state: {},
89
+ homeWorkspace: "/home/neo",
90
+ accountsRoot: ROOT,
91
+ accountDirs: [],
92
+ });
93
+ assert.equal(first.accounts, 0);
94
+ assert.equal(first.seeded, 0);
95
+ const second = seedClaudeTrust({
96
+ state: first.state,
97
+ homeWorkspace: "/home/neo",
98
+ accountsRoot: ROOT,
99
+ accountDirs: [A],
100
+ });
101
+ const projects = second.state.projects;
102
+ assert.equal(projects[A].hasTrustDialogAccepted, true);
103
+ assert.equal(second.accounts, 1);
104
+ assert.equal(second.seeded, 1);
105
+ assert.equal(projects["/home/neo"].hasTrustDialogAccepted, true);
106
+ });
107
+ test("the install line names which pass ran", () => {
108
+ const r = seedClaudeTrust({
109
+ state: {},
110
+ homeWorkspace: "/home/neo",
111
+ accountsRoot: ROOT,
112
+ accountDirs: [A],
113
+ });
114
+ const line = formatTrustSeedLine("/cfg/.claude.json", "/home/neo", r, "none", "post-account");
115
+ assert.equal(line, " [install] op=claude-trust-seed phase=post-account file=/cfg/.claude.json home=/home/neo" +
116
+ " accounts=1 seeded=1 alreadyTrusted=0 stale=0 error=none");
117
+ });
118
+ test("second run over the first run's output is byte-identical", () => {
119
+ const input = { state: {}, homeWorkspace: "/home/neo", accountsRoot: ROOT, accountDirs: [A, B] };
120
+ const first = seedClaudeTrust(input);
121
+ const second = seedClaudeTrust({ ...input, state: first.state });
122
+ assert.equal(JSON.stringify(second.state), JSON.stringify(first.state));
123
+ assert.equal(second.seeded, 0);
124
+ assert.equal(second.alreadyTrusted, 2);
125
+ });
@@ -0,0 +1,52 @@
1
+ // Task 2720 — Claude Code scopes folder trust to the git repository root, and
2
+ // provision-account-dir.sh gives every account directory its own repo, so
3
+ // trusting $HOME does not reach them. An untrusted workspace halts the
4
+ // PTY-spawned `claude --remote-control` on the folder-trust dialog before it
5
+ // binds, which reads downstream as `op=bind-signal-absent … pidFileSeen=false`
6
+ // and, because /rc-spawn answers 200, reaches the operator as silence.
7
+ //
8
+ // Pure so the counts and the preservation invariant are testable without a
9
+ // filesystem; the caller owns the read and the write.
10
+ export function seedClaudeTrust(input) {
11
+ const state = input.state;
12
+ state.hasCompletedOnboarding = true;
13
+ state.theme = state.theme ?? "auto";
14
+ const projects = (state.projects ?? {});
15
+ const homeEntry = projects[input.homeWorkspace] ?? {};
16
+ homeEntry.hasTrustDialogAccepted = true;
17
+ projects[input.homeWorkspace] = homeEntry;
18
+ let seeded = 0;
19
+ let alreadyTrusted = 0;
20
+ for (const dir of input.accountDirs) {
21
+ const entry = projects[dir] ?? {};
22
+ if (entry.hasTrustDialogAccepted === true) {
23
+ alreadyTrusted += 1;
24
+ }
25
+ else {
26
+ entry.hasTrustDialogAccepted = true;
27
+ seeded += 1;
28
+ }
29
+ projects[dir] = entry;
30
+ }
31
+ // A deleted account cannot be spawned into, so its entry is left exactly as
32
+ // the CLI wrote it. Counting it separately keeps the install line's
33
+ // `seeded + alreadyTrusted === accounts` invariant meaningful.
34
+ //
35
+ // Direct children only. The CLI records an entry for ANY directory a session
36
+ // ran in, so an account's own subdirectory (a `sites/<project>` tree, say)
37
+ // also sits under this prefix; counting those as stale accounts would inflate
38
+ // the field every time somebody worked inside an account.
39
+ const onDisk = new Set(input.accountDirs);
40
+ const prefix = `${input.accountsRoot}/`;
41
+ const stale = Object.keys(projects).filter((k) => k.startsWith(prefix) && !k.slice(prefix.length).includes("/") && !onDisk.has(k)).length;
42
+ state.projects = projects;
43
+ return { state, accounts: input.accountDirs.length, seeded, alreadyTrusted, stale };
44
+ }
45
+ /** `phase` distinguishes the two passes: `deploy` seeds an upgrade's existing
46
+ * accounts, `post-account` seeds the directory a fresh install just created.
47
+ * Without it the two lines are byte-identical and the operator cannot tell
48
+ * which pass did the work. */
49
+ export function formatTrustSeedLine(file, home, r, error, phase) {
50
+ return (` [install] op=claude-trust-seed phase=${phase} file=${file} home=${home} accounts=${r.accounts}` +
51
+ ` seeded=${r.seeded} alreadyTrusted=${r.alreadyTrusted} stale=${r.stale} error=${error}`);
52
+ }
package/dist/index.js CHANGED
@@ -27,6 +27,7 @@ import { parseSwVers, isSupportedMacosVersion } from "./macos-version.js";
27
27
  import { decideChromiumAction, isSnapConfinedPath } from "./snap-chromium.js";
28
28
  import { classifyPortHolder } from "./preflight-port-classifier.js";
29
29
  import { memoryControllerMissing, cmdlineAlreadyPatched, patchCmdline } from "./cgroup-memory-controller.js";
30
+ import { seedClaudeTrust, formatTrustSeedLine } from "./claude-trust-seed.js";
30
31
  import { parsePluginList, computeInstallActions, parseExternalPlugins, findUnregisteredResyncs, discoverMarketplaceCandidateDirs, } from "./lib/plugin-install.js";
31
32
  import { findPremiumMcpDirs } from "./lib/premium-mcp-discover.js";
32
33
  import { pickBindDecision, pickEdgeBindDecision, formatEdgeBindDecision, pickWebsockifyBind, formatWebsockifyBindFile, mergeSmbConf, formatSambaMarker, SAMBA_ENABLE_UNITS, } from "./samba-provision.js";
@@ -2488,6 +2489,67 @@ function runInstallInvariantCheck(usersFile, accountsDir) {
2488
2489
  }
2489
2490
  console.log(` ${TAG} check complete divergences=${divergences}`);
2490
2491
  }
2492
+ // pre-populate the brand `.claude.json` so the manager's PTY-spawned
2493
+ // `claude --verbose --remote-control` boots straight into the session URL
2494
+ // without stopping at the first-run theme picker or the workspace-trust
2495
+ // dialog. Both prompts ate the manager's 30 s url-capture window on
2496
+ // 0.1.6 / 0.1.8 installs (Pi 192.168.88.16 verified). The markers required:
2497
+ // - hasCompletedOnboarding: true (suppresses theme picker)
2498
+ // - projects[<dir>].hasTrustDialogAccepted: true, for $HOME AND for every
2499
+ // account directory (Task 2720). Claude Code scopes folder trust to the
2500
+ // git repository root, and provision-account-dir.sh gives each account
2501
+ // directory its own repo, so $HOME's trust does not reach them. Seeding
2502
+ // $HOME alone left every spawn halted on the trust dialog.
2503
+ // Existing fields (firstStartTime, oauthAccount, migrationVersion, …) are
2504
+ // preserved so a brand re-install does not clobber state written by claude
2505
+ // during the previous run.
2506
+ //
2507
+ // Called TWICE, and both calls are load-bearing. `deploy` runs inside
2508
+ // deployPayload, which is where an upgrade's already-existing account
2509
+ // directories are seeded; `post-account` runs after setupAccount(), which is
2510
+ // the only point a FRESH install has an account directory on disk at all.
2511
+ // Running deploy alone would leave every fresh install untrusted and hang its
2512
+ // first session. The transform is idempotent, so the second pass rewrites
2513
+ // nothing the first already did (`seeded=0` when there was nothing new).
2514
+ function primeClaudeState(phase) {
2515
+ const persistentDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
2516
+ const persistentClaudeDir = join(persistentDir, ".claude");
2517
+ mkdirSync(persistentClaudeDir, { recursive: true });
2518
+ const claudeStateFile = join(persistentClaudeDir, ".claude.json");
2519
+ const homeWorkspace = process.env.HOME ?? "/root";
2520
+ let claudeState = {};
2521
+ if (existsSync(claudeStateFile)) {
2522
+ try {
2523
+ claudeState = JSON.parse(readFileSync(claudeStateFile, "utf-8"));
2524
+ }
2525
+ catch {
2526
+ claudeState = {};
2527
+ }
2528
+ }
2529
+ // An absent accounts directory is a first install, not an error; a listing
2530
+ // that throws is reported on the line rather than aborting the install.
2531
+ const accountsRoot = join(INSTALL_DIR, "data/accounts");
2532
+ let accountDirs = [];
2533
+ let seedError = "none";
2534
+ try {
2535
+ if (existsSync(accountsRoot)) {
2536
+ accountDirs = readdirSync(accountsRoot, { withFileTypes: true })
2537
+ .filter((e) => e.isDirectory())
2538
+ .map((e) => join(accountsRoot, e.name));
2539
+ }
2540
+ }
2541
+ catch (err) {
2542
+ seedError = err instanceof Error ? err.message : String(err);
2543
+ }
2544
+ const seedResult = seedClaudeTrust({
2545
+ state: claudeState,
2546
+ homeWorkspace,
2547
+ accountsRoot,
2548
+ accountDirs,
2549
+ });
2550
+ writeFileSync(claudeStateFile, JSON.stringify(seedResult.state, null, 2) + "\n", { mode: 0o600 });
2551
+ console.log(formatTrustSeedLine(claudeStateFile, homeWorkspace, seedResult, seedError, phase));
2552
+ }
2491
2553
  function deployPayload() {
2492
2554
  log("8", TOTAL, `Deploying ${BRAND.productName}...`);
2493
2555
  if (!existsSync(PAYLOAD_DIR)) {
@@ -2511,39 +2573,8 @@ function deployPayload() {
2511
2573
  // `claude` SDK subprocess and admin server read from there via the
2512
2574
  // Environment=CLAUDE_CONFIG_DIR= block in port-resolution.ts. Fresh
2513
2575
  // installs prompt the operator to run `claude /login`.
2514
- const persistentClaudeDir = join(persistentDir, ".claude");
2515
- mkdirSync(persistentClaudeDir, { recursive: true });
2516
- // pre-populate the brand `.claude.json` so the manager's
2517
- // PTY-spawned `claude --verbose --remote-control` boots straight into the
2518
- // session URL without stopping at the first-run theme picker or the
2519
- // workspace-trust dialog. Both prompts ate the manager's 30 s url-capture
2520
- // window on 0.1.6 / 0.1.8 installs (Pi 192.168.88.16 verified). The two
2521
- // markers required are:
2522
- // - hasCompletedOnboarding: true (suppresses theme picker)
2523
- // - projects[$HOME].hasTrustDialogAccepted: true
2524
- // Existing fields (firstStartTime, oauthAccount, migrationVersion, …) are
2525
- // preserved so a brand re-install does not clobber state written by claude
2526
- // during the previous run.
2527
- const claudeStateFile = join(persistentClaudeDir, ".claude.json");
2528
- const homeWorkspace = process.env.HOME ?? "/root";
2529
- let claudeState = {};
2530
- if (existsSync(claudeStateFile)) {
2531
- try {
2532
- claudeState = JSON.parse(readFileSync(claudeStateFile, "utf-8"));
2533
- }
2534
- catch {
2535
- claudeState = {};
2536
- }
2537
- }
2538
- claudeState.hasCompletedOnboarding = true;
2539
- claudeState.theme = claudeState.theme ?? "auto";
2540
- const projects = (claudeState.projects ?? {});
2541
- const homeEntry = projects[homeWorkspace] ?? {};
2542
- homeEntry.hasTrustDialogAccepted = true;
2543
- projects[homeWorkspace] = homeEntry;
2544
- claudeState.projects = projects;
2545
- writeFileSync(claudeStateFile, JSON.stringify(claudeState, null, 2) + "\n", { mode: 0o600 });
2546
- console.log(` [install] claude-state primed: ${claudeStateFile} hasCompletedOnboarding=true trustedWorkspace=${homeWorkspace}`);
2576
+ // primeClaudeState creates that directory, so there is no separate mkdir here.
2577
+ primeClaudeState("deploy");
2547
2578
  // Brand isolation: installer does not read ~/.maxy/, ~/.cloudflared/, or
2548
2579
  // ~/.cloudflare/ on non-default brands. These are peer-brand or
2549
2580
  // shared-singleton paths.
@@ -5458,6 +5489,10 @@ try {
5458
5489
  registerLocalAndExternalPlugins(); // install-time plugin registration
5459
5490
  setupVncViewer();
5460
5491
  setupAccount();
5492
+ // Task 2720 — the account directory only exists from here on a fresh
5493
+ // install, and provision-account-dir.sh has just made it a git repo root,
5494
+ // so this is the pass that trusts it. Idempotent on the upgrade path.
5495
+ primeClaudeState("post-account");
5461
5496
  if (ENTITLEMENT_PAYLOAD) {
5462
5497
  writeEntitlementFromFlag(ENTITLEMENT_PAYLOAD);
5463
5498
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.604",
3
+ "version": "0.1.606",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -34,7 +34,7 @@
34
34
  * routine's prompt only when the stored `routineTemplateVersion` is BELOW this
35
35
  * and no operator has edited the row, so an unbumped edit ships to new installs
36
36
  * and never reaches existing ones — bump it in the same commit as the edit. */
37
- export declare const ROUTINE_TEMPLATE_VERSION = 6;
37
+ export declare const ROUTINE_TEMPLATE_VERSION = 10;
38
38
  /**
39
39
  * Task 2379 — the check shapes a shipped template may name.
40
40
  *
@@ -92,7 +92,35 @@ export interface RoutineGraphUnflaggedCheck {
92
92
  readonly type: "graph-unflagged";
93
93
  readonly label: "ConversationArchive" | "Section";
94
94
  }
95
- export type RoutineGateCheck = RoutineMailCheck | RoutineD1Check | RoutineWhatsappCheck | RoutineCalendarCheck | RoutineTelegramCheck | RoutineGraphCheck | RoutineGraphUnflaggedCheck;
95
+ /** Task 2689 the memory sweep's own state: its two review queues, and whether
96
+ * it has stopped running. No fields, because an account has exactly one sweep
97
+ * and one of each queue. What is compared is a digest, so the routine wakes
98
+ * when a queue moves or the sweep goes silent, never merely because the sweep
99
+ * ran again — it runs hourly and this routine is weekly. */
100
+ /** Task 2688 — records changed in a connector this account registered, since
101
+ * the routine last woke.
102
+ *
103
+ * `scope` is a KIND of connector, never a name: the account describes the
104
+ * queue once, on the connector's own registry record, and the template names
105
+ * only which kind it watches. That is what lets a shipped template gate on a
106
+ * third-party system at all, since it can carry no per-account value (Task
107
+ * 2389). A connector that is not registered, or whose credential is refused,
108
+ * answers quiet, so the routine no-ops rather than erroring every fire. */
109
+ export interface RoutineConnectorCheck {
110
+ readonly type: "connector";
111
+ readonly scope: "operational" | "accounting";
112
+ }
113
+ export interface RoutineSweepCheck {
114
+ readonly type: "sweep";
115
+ }
116
+ /** Task 2689 — growth under the account's own directory since the last accepted
117
+ * wake. `minGrowthBytes` is a size rather than per-account data, so a shipped
118
+ * template may name it and still be correct on every install. */
119
+ export interface RoutineFilesystemCheck {
120
+ readonly type: "filesystem";
121
+ readonly minGrowthBytes?: number;
122
+ }
123
+ export type RoutineGateCheck = RoutineMailCheck | RoutineD1Check | RoutineWhatsappCheck | RoutineCalendarCheck | RoutineTelegramCheck | RoutineGraphCheck | RoutineGraphUnflaggedCheck | RoutineConnectorCheck | RoutineSweepCheck | RoutineFilesystemCheck;
96
124
  /** The plugin and the tool are constants for every roster gate, so a template
97
125
  * carries neither. `hasWork` is true when ANY check is true. */
98
126
  export interface RoutineGate {
@@ -1 +1 @@
1
- {"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;gFAGgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9C;AACD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;CACtC;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACD;iDACiD;AACjD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AACD;2EAC2E;AAC3E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;CAChC;AACD;;;;;;;;;;;6DAW6D;AAC7D,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,qBAAqB,GAAG,SAAS,CAAC;CACnD;AACD,MAAM,MAAM,gBAAgB,GACxB,gBAAgB,GAChB,cAAc,GACd,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,GACpB,iBAAiB,GACjB,0BAA0B,CAAC;AAE/B;iEACiE;AACjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAC9C;AAWD;;;;;;;;;;;4DAW4D;AAC5D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAkBnE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAE1D;AAED,MAAM,WAAW,eAAe;IAC9B;;mEAE+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;6EAGyE;IACzE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;wEACoE;IACpE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;2CAIuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B;;;+DAG2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;2BAO2B;AAC3B,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAI/D;AA8KD;;;;;;;;iFAQiF;AACjF,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAiIpD,CAAC;AAEF;;6DAE6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAqC,CAAC"}
1
+ {"version":3,"file":"roster.d.ts","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"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"}
@@ -40,7 +40,7 @@ exports.isClassified = isClassified;
40
40
  * routine's prompt only when the stored `routineTemplateVersion` is BELOW this
41
41
  * and no operator has edited the row, so an unbumped edit ships to new installs
42
42
  * and never reaches existing ones — bump it in the same commit as the edit. */
43
- exports.ROUTINE_TEMPLATE_VERSION = 6;
43
+ exports.ROUTINE_TEMPLATE_VERSION = 10;
44
44
  // Task 2663 — `GATE_COMMIT_TOKEN` is deleted. It stood in for a
45
45
  // `scheduling-gate` call the routine's own turn made to advance its watermark,
46
46
  // and the whole reason it had to be a token was that a template cannot write the
@@ -74,10 +74,23 @@ function isWatermarkedCheck(check) {
74
74
  //
75
75
  // Task 2681 — `graph` compares an ISO `updatedAt` against a stored one, so a
76
76
  // commitless graph gate reports work on every fire exactly as a mail one does.
77
+ //
78
+ // Task 2688 — `connector` holds one position PER registered connector, and
79
+ // compares each against the instant that connector's queue was last read, so
80
+ // it is watermarked for the same reason.
81
+ //
82
+ // Task 2689 — `sweep` compares a digest and `filesystem` compares a byte
83
+ // count, both against a stored value, so both belong here for the same
84
+ // reason. Their positions are promoted by the dispatcher on an accepted wake,
85
+ // which is what makes "since the last report" literal rather than "since the
86
+ // last fire".
77
87
  return (check.type === "mail" ||
78
88
  check.type === "calendar" ||
79
89
  check.type === "telegram" ||
80
- check.type === "graph");
90
+ check.type === "graph" ||
91
+ check.type === "connector" ||
92
+ check.type === "sweep" ||
93
+ check.type === "filesystem");
81
94
  }
82
95
  function gateNeedsCommit(gate) {
83
96
  return gate.checks.some(isWatermarkedCheck);
@@ -142,17 +155,6 @@ Tomorrow: list tomorrow's appointments with outlook-calendar-list or google-cale
142
155
  Say what is unfinished and what tomorrow looks like, in that order, in plain sentences. Do not congratulate, do not summarise the day back, do not pad the message to look thorough.
143
156
 
144
157
  If nothing is waiting, nothing is overdue and tomorrow is empty, end the turn without replying.`;
145
- const APPOINTMENT_REMINDER = `Remind the people attending an appointment that is coming up, so nobody is reminded twice and nobody is missed.
146
-
147
- Call capabilities-here first. If neither a mail plugin nor a messaging channel is enabled, end the turn without replying.
148
-
149
- Find appointments starting within the next reminder window with schedule-list, and read each one's attendees. Resolve each attendee to a person and a contact route with contact-lookup. An attendee you cannot resolve to a route is not a failure to work around: leave them, and say so at the end.
150
-
151
- Send each attendee one reminder on the route they are already reachable on: email-send for a mailbox, whatsapp-reply or the Telegram message tool for a messaging thread that already exists. Carry the time, the place and what the appointment is about. Do not open a new conversation with someone who has never messaged the business.
152
-
153
- Send at most one reminder per attendee per appointment. Before sending, check the appointment's notes for a reminder already recorded, and record the one you send there.
154
-
155
- Reply with one line naming who was reminded and who could not be reached. If no appointment falls in the window, end the turn without replying.`;
156
158
  const COMMITMENT_CHASE = `Find the promises the business has made and not kept, and the promises made to it that nobody has kept.
157
159
 
158
160
  Call capabilities-here first and use only the surfaces it reports.
@@ -269,7 +271,20 @@ exports.ROUTINE_ROSTER = [
269
271
  description: "Sends one morning message covering what needs a decision, what is time-bound and what changed overnight; stays silent when there is nothing worth saying.",
270
272
  recurrence: "30 7 * * 1-5",
271
273
  prompt: START_OF_DAY,
272
- gateless: "A morning briefing is judgement every fire, so a gate would either always pass or suppress the briefing.",
274
+ // Task 2686 the briefing's two gateable arms. `Section` rather than
275
+ // `ConversationArchive` on every email-driven row here: sections are written
276
+ // per ingest, so a reply into a thread this routine already flagged arrives
277
+ // as a fresh unflagged node, while the archive is MERGEd per thread and
278
+ // would stay flagged — muting the routine on the traffic it exists to read.
279
+ // The check names a label and not a source, so any ingested content wakes
280
+ // these rows, which over-wakes and never mutes. The briefing's third arm,
281
+ // open and overdue work, has no check type: Task 2714.
282
+ gate: {
283
+ checks: [
284
+ { type: "graph-unflagged", label: "Section" },
285
+ { type: "graph", scope: "appointments" },
286
+ ],
287
+ },
273
288
  },
274
289
  {
275
290
  key: "inbound-check",
@@ -277,7 +292,10 @@ exports.ROUTINE_ROSTER = [
277
292
  description: "Triages mail that arrived since the last check and writes replies for you to approve; it never sends anything itself.",
278
293
  recurrence: "*/30 9-17 * * 1-5",
279
294
  prompt: INBOUND_CHECK,
280
- gateless: "Conditional on new mail, but the mail check matches an exact mailbox address and no shipped template can name one (Task 2389).",
295
+ // Task 2686 the mail check still cannot name a mailbox, but the sampler
296
+ // puts every inbound message in the graph, so the unflagged-section check
297
+ // reaches the same mail without per-account data.
298
+ gate: { checks: [{ type: "graph-unflagged", label: "Section" }] },
281
299
  },
282
300
  {
283
301
  key: "telegram-inbound-check",
@@ -290,18 +308,18 @@ exports.ROUTINE_ROSTER = [
290
308
  {
291
309
  key: "end-of-day",
292
310
  name: "End of day wrap-up",
293
- description: "Closes the day with your unsent drafts, overdue work and tomorrow's diary; says nothing when all three are empty.",
311
+ description: "Closes the day with your unsent drafts, overdue work and tomorrow's diary, once new mail or a diary change has woken it.",
294
312
  recurrence: "0 18 * * 1-5",
295
313
  prompt: END_OF_DAY,
296
- gateless: "A wrap-up is judgement every fire, so no cheap check stands in for reading the three surfaces it reports.",
297
- },
298
- {
299
- key: "appointment-reminder",
300
- name: "Appointment reminders",
301
- description: "Reminds each attendee once before a booked appointment, on a route they already use; it never opens a conversation with a stranger.",
302
- recurrence: "0 * * * *",
303
- prompt: APPOINTMENT_REMINDER,
304
- gateless: "Conditional on an appointment falling in the window, but no check type reads appointments held in the graph (Task 2389).",
314
+ // Task 2686 — the wrap-up wakes on new mail or a diary change. Its other two
315
+ // surfaces, unsent drafts and overdue work, have no check type, so a day
316
+ // whose only outstanding item is one of those is silent until Task 2714.
317
+ gate: {
318
+ checks: [
319
+ { type: "graph-unflagged", label: "Section" },
320
+ { type: "graph", scope: "appointments" },
321
+ ],
322
+ },
305
323
  },
306
324
  {
307
325
  key: "commitment-chase",
@@ -309,7 +327,11 @@ exports.ROUTINE_ROSTER = [
309
327
  description: "Surfaces promises the business made and did not keep, and promises made to it that nobody kept; it reports them rather than chasing them.",
310
328
  recurrence: "0 10 * * 2",
311
329
  prompt: COMMITMENT_CHASE,
312
- gateless: "Whether a promise has been dropped is the judgement itself, so no check can answer it more cheaply.",
330
+ // Task 2686 a dropped promise is a judgement, but the correspondence it
331
+ // judges is not: this wakes when inbound mail it has not read is in the
332
+ // graph. Its outbound arm reads sent mail, which the sampler does not ingest
333
+ // and no shipped template can name a mailbox for: Task 2715.
334
+ gate: { checks: [{ type: "graph-unflagged", label: "Section" }] },
313
335
  },
314
336
  {
315
337
  key: "calendar-reconcile",
@@ -327,7 +349,9 @@ exports.ROUTINE_ROSTER = [
327
349
  description: "Reconciles the people you correspond with against the people on record, creating and updating contacts; it never merges two records that might be two people.",
328
350
  recurrence: "45 6 * * 1-5",
329
351
  prompt: CONTACT_RECONCILE,
330
- gateless: "Conditional on new correspondence, but no check type reads correspondence (Task 2389).",
352
+ // Task 2686 correspondence is readable now: the sampler writes it and the
353
+ // unflagged-section check counts what this routine has not reconciled.
354
+ gate: { checks: [{ type: "graph-unflagged", label: "Section" }] },
331
355
  },
332
356
  {
333
357
  key: "crm-reconcile",
@@ -335,7 +359,9 @@ exports.ROUTINE_ROSTER = [
335
359
  description: "Brings across what changed in whichever operational system this business runs; it reads only and never writes back to that system.",
336
360
  recurrence: "0 3 * * *",
337
361
  prompt: CRM_RECONCILE,
338
- gateless: "Conditional on connector movement, but no check type reads a connector queue (Task 2389).",
362
+ // Task 2688 wakes when a connector the account registered as its
363
+ // operational system holds records changed since the last accepted wake.
364
+ gate: { checks: [{ type: "connector", scope: "operational" }] },
339
365
  },
340
366
  {
341
367
  key: "finance-reconcile",
@@ -343,7 +369,10 @@ exports.ROUTINE_ROSTER = [
343
369
  description: "Reconciles the accounting system against the internal ledger and reports what does not agree; it never adjusts an entry to make the two sides match.",
344
370
  recurrence: "0 4 * * 1",
345
371
  prompt: FINANCE_RECONCILE,
346
- gateless: "Conditional on accounting movement, but no check type reads an accounting ledger (Task 2389).",
372
+ // Task 2688 wakes on movement in the connector the account registered as
373
+ // its accounting system. A connector that is absent or whose credential is
374
+ // refused answers quiet, so this no-ops rather than erroring every fire.
375
+ gate: { checks: [{ type: "connector", scope: "accounting" }] },
347
376
  },
348
377
  {
349
378
  key: "weekly-digest",
@@ -351,7 +380,15 @@ exports.ROUTINE_ROSTER = [
351
380
  description: "Writes the week in three paragraphs at most: what changed, what is stuck, and what next week turns on.",
352
381
  recurrence: "0 16 * * 5",
353
382
  prompt: WEEKLY_DIGEST,
354
- gateless: "A digest is judgement every fire, and a gate would suppress the report it exists to send.",
383
+ // Task 2686 a week with no correspondence and no diary movement has
384
+ // nothing to report movement on, so the digest is silent rather than
385
+ // writing three paragraphs about a week in which nothing happened.
386
+ gate: {
387
+ checks: [
388
+ { type: "graph-unflagged", label: "Section" },
389
+ { type: "graph", scope: "appointments" },
390
+ ],
391
+ },
355
392
  },
356
393
  {
357
394
  key: "channel-link-check",
@@ -367,7 +404,11 @@ exports.ROUTINE_ROSTER = [
367
404
  description: "Reports what the hourly graph sweep last did and what is waiting for review; it reads only and never runs the sweep itself.",
368
405
  recurrence: "0 9 * * 1",
369
406
  prompt: GRAPH_HEALTH,
370
- gateless: "Reports the sweep's state every fire by design, so there is nothing conditional to check.",
407
+ // Task 2689 — the sweep's state IS the delta. The digest carries the two
408
+ // review-queue counts and whether the sweep has stopped writing reports,
409
+ // never the newest report's identity: the sweep runs hourly, so a digest
410
+ // that moved on every run would make this weekly routine wake every fire.
411
+ gate: { checks: [{ type: "sweep" }] },
371
412
  },
372
413
  {
373
414
  key: "filesystem-health",
@@ -375,7 +416,10 @@ exports.ROUTINE_ROSTER = [
375
416
  description: "Reports what has grown under the account directory and which paths are worth attention; it deletes nothing.",
376
417
  recurrence: "0 9 * * 1",
377
418
  prompt: FILESYSTEM_HEALTH,
378
- gateless: "Reports what has grown every fire by design, so there is nothing conditional to check.",
419
+ // Task 2689 64 MiB of growth under the account directory since the last
420
+ // report. What has ACCUMULATED is the question, so an account that is large
421
+ // and stable has nothing new to say and the routine stays silent.
422
+ gate: { checks: [{ type: "filesystem", minGrowthBytes: 67108864 }] },
379
423
  },
380
424
  ];
381
425
  /** Every roster key, in roster order. The scheduling heartbeat's `op=roster`
@@ -1 +1 @@
1
- {"version":3,"file":"roster.js","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"roster.js","sourceRoot":"","sources":["../src/roster.ts"],"names":[],"mappings":"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"}
@@ -415,7 +415,28 @@ describe("gate seeding", () => {
415
415
  expect(byKey.get("channel-link-check")).toBe('[{"type":"whatsapp","scope":"status"}]');
416
416
  expect(byKey.get("calendar-reconcile")).toBe('[{"type":"calendar","connector":"account"},{"type":"graph","scope":"appointments"}]');
417
417
  expect(byKey.get("telegram-inbound-check")).toBe('[{"type":"telegram","scope":"inbound"}]');
418
- expect(byKey.get("weekly-digest")).toBeNull();
418
+ // Task 2686 — weekly-digest is gated now, so the null example moved to a row
419
+ // that is still gateless, and the digest's own two checks are asserted here.
420
+ expect(byKey.get("weekly-digest")).toBe(
421
+ '[{"type":"graph-unflagged","label":"Section"},{"type":"graph","scope":"appointments"}]',
422
+ );
423
+ expect(byKey.get("inbound-check")).toBe('[{"type":"graph-unflagged","label":"Section"}]');
424
+ // Task 2689 — the gateless example is DERIVED rather than named. 2686 gated
425
+ // six rows and moved this assertion onto `graph-health`; 2689 gated
426
+ // `graph-health` and `filesystem-health`, so it moved again. Every row still
427
+ // carrying a reason is a target of 2687 or 2688, so naming one would break
428
+ // on their landing too. When 2691 removes the field, the `!` here throws and
429
+ // points at the assertion that has to go with it.
430
+ // Task 2688 — there is no gateless row left to sample. 2686 gated six rows
431
+ // and moved this assertion onto `graph-health`; 2689 gated `graph-health`
432
+ // and `filesystem-health`, so it moved again; 2687 withdrew
433
+ // `appointment-reminder` and 2688 gated the last two, which leaves the
434
+ // shipped roster carrying no `gateless` reason at all. The seed's null arm
435
+ // is now unreachable from this roster and dies with the field in Task 2691,
436
+ // so what is asserted here is the fact that replaced it: every shipped row
437
+ // seeds serialised checks, and none seeds null.
438
+ expect(ROUTINE_ROSTER.filter((r) => r.gate == null)).toEqual([]);
439
+ expect([...byKey.values()].filter((v) => v === null)).toEqual([]);
419
440
  });
420
441
 
421
442
  it("serialises the checks in exactly one place", () => {