@rubytech/create-siteoffice-code 0.1.256

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 (2573) hide show
  1. package/dist/__tests__/account-id-env.test.js +48 -0
  2. package/dist/__tests__/apt-resolve.test.js +179 -0
  3. package/dist/__tests__/brand-fonts.test.js +102 -0
  4. package/dist/__tests__/brew-install.test.js +151 -0
  5. package/dist/__tests__/brew-resolve.test.js +138 -0
  6. package/dist/__tests__/bundler-rewrite-platform-lib.test.js +68 -0
  7. package/dist/__tests__/cdp-port-no-silent-fallback.test.js +53 -0
  8. package/dist/__tests__/claude-ptys-slice.test.js +25 -0
  9. package/dist/__tests__/cloudflared-slice.test.js +19 -0
  10. package/dist/__tests__/entitlement-flag.test.js +43 -0
  11. package/dist/__tests__/init-logging.test.js +85 -0
  12. package/dist/__tests__/installer-settings-permissions.test.js +112 -0
  13. package/dist/__tests__/installer-specialist-registration.test.js +116 -0
  14. package/dist/__tests__/launchd-plist.test.js +195 -0
  15. package/dist/__tests__/macos-darwin-branch.test.js +85 -0
  16. package/dist/__tests__/macos-version.test.js +96 -0
  17. package/dist/__tests__/onboarding-state-readback.test.js +61 -0
  18. package/dist/__tests__/peer-brand-detect.test.js +103 -0
  19. package/dist/__tests__/platform-detect.test.js +50 -0
  20. package/dist/__tests__/platform-port-stamp.test.js +28 -0
  21. package/dist/__tests__/plugin-install.test.js +123 -0
  22. package/dist/__tests__/port-canonicalisation.test.js +200 -0
  23. package/dist/__tests__/preflight-port-classifier.test.js +330 -0
  24. package/dist/__tests__/premium-bundle-gate.test.js +59 -0
  25. package/dist/__tests__/premium-mcp-discover.test.js +127 -0
  26. package/dist/__tests__/rss-sampler-installer.test.js +27 -0
  27. package/dist/__tests__/samba-provision.test.js +226 -0
  28. package/dist/__tests__/snap-chromium.test.js +115 -0
  29. package/dist/__tests__/tier-flag.test.js +53 -0
  30. package/dist/apt-resolve.js +73 -0
  31. package/dist/brew-install.js +180 -0
  32. package/dist/brew-resolve.js +68 -0
  33. package/dist/bundler-rewrite-platform-lib.js +29 -0
  34. package/dist/index.js +4048 -0
  35. package/dist/init-logging.js +28 -0
  36. package/dist/launchd-plist.js +68 -0
  37. package/dist/lib/plugin-install.js +110 -0
  38. package/dist/lib/premium-mcp-discover.js +41 -0
  39. package/dist/macos-version.js +53 -0
  40. package/dist/onboarding-readback.js +27 -0
  41. package/dist/peer-brand-detect.js +39 -0
  42. package/dist/permissions-seed.js +76 -0
  43. package/dist/pinned-binaries.js +12 -0
  44. package/dist/platform-detect.js +36 -0
  45. package/dist/port-resolution.js +208 -0
  46. package/dist/preflight-port-classifier.js +222 -0
  47. package/dist/samba-provision.js +218 -0
  48. package/dist/snap-chromium.js +88 -0
  49. package/dist/specialist-registration.js +78 -0
  50. package/dist/tier-flag.js +85 -0
  51. package/dist/uninstall.js +947 -0
  52. package/package.json +35 -0
  53. package/payload/platform/.docs/search-surface-contract.md +58 -0
  54. package/payload/platform/config/brand-registry.json +28 -0
  55. package/payload/platform/config/brand.json +82 -0
  56. package/payload/platform/docs/superpowers/plans/2026-06-02-task-610-follower-202-retry.md +372 -0
  57. package/payload/platform/docs/superpowers/plans/2026-06-04-public-agent-knowledge-delivery.md +230 -0
  58. package/payload/platform/docs/superpowers/specs/2026-06-02-task-610-follower-202-retry-design.md +116 -0
  59. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.d.ts +2 -0
  60. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.d.ts.map +1 -0
  61. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.js +88 -0
  62. package/payload/platform/lib/account-enumeration/dist/__tests__/enumerate.test.js.map +1 -0
  63. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.d.ts +2 -0
  64. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.d.ts.map +1 -0
  65. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.js +55 -0
  66. package/payload/platform/lib/account-enumeration/dist/__tests__/validate-env.test.js.map +1 -0
  67. package/payload/platform/lib/account-enumeration/dist/index.d.ts +49 -0
  68. package/payload/platform/lib/account-enumeration/dist/index.d.ts.map +1 -0
  69. package/payload/platform/lib/account-enumeration/dist/index.js +109 -0
  70. package/payload/platform/lib/account-enumeration/dist/index.js.map +1 -0
  71. package/payload/platform/lib/account-enumeration/src/__tests__/enumerate.test.ts +94 -0
  72. package/payload/platform/lib/account-enumeration/src/__tests__/validate-env.test.ts +57 -0
  73. package/payload/platform/lib/account-enumeration/src/index.ts +140 -0
  74. package/payload/platform/lib/account-enumeration/tsconfig.json +8 -0
  75. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts +54 -0
  76. package/payload/platform/lib/admin-conversation-purge/dist/index.d.ts.map +1 -0
  77. package/payload/platform/lib/admin-conversation-purge/dist/index.js +84 -0
  78. package/payload/platform/lib/admin-conversation-purge/dist/index.js.map +1 -0
  79. package/payload/platform/lib/admin-conversation-purge/src/index.ts +120 -0
  80. package/payload/platform/lib/admin-conversation-purge/tsconfig.json +8 -0
  81. package/payload/platform/lib/admins-write/dist/index.d.ts +86 -0
  82. package/payload/platform/lib/admins-write/dist/index.d.ts.map +1 -0
  83. package/payload/platform/lib/admins-write/dist/index.js +245 -0
  84. package/payload/platform/lib/admins-write/dist/index.js.map +1 -0
  85. package/payload/platform/lib/admins-write/src/index.ts +305 -0
  86. package/payload/platform/lib/admins-write/tsconfig.json +8 -0
  87. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.d.ts +33 -0
  88. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.d.ts.map +1 -0
  89. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.js +119 -0
  90. package/payload/platform/lib/aeo-llms-txt-writer/dist/index.js.map +1 -0
  91. package/payload/platform/lib/aeo-llms-txt-writer/src/index.ts +172 -0
  92. package/payload/platform/lib/aeo-llms-txt-writer/tsconfig.json +8 -0
  93. package/payload/platform/lib/anthropic-key/dist/index.d.ts +22 -0
  94. package/payload/platform/lib/anthropic-key/dist/index.d.ts.map +1 -0
  95. package/payload/platform/lib/anthropic-key/dist/index.js +232 -0
  96. package/payload/platform/lib/anthropic-key/dist/index.js.map +1 -0
  97. package/payload/platform/lib/brand-templating/dist/index.d.ts +18 -0
  98. package/payload/platform/lib/brand-templating/dist/index.d.ts.map +1 -0
  99. package/payload/platform/lib/brand-templating/dist/index.js +69 -0
  100. package/payload/platform/lib/brand-templating/dist/index.js.map +1 -0
  101. package/payload/platform/lib/brand-templating/src/index.ts +76 -0
  102. package/payload/platform/lib/brand-templating/tsconfig.json +8 -0
  103. package/payload/platform/lib/device-url/dist/index.d.ts +44 -0
  104. package/payload/platform/lib/device-url/dist/index.d.ts.map +1 -0
  105. package/payload/platform/lib/device-url/dist/index.js +68 -0
  106. package/payload/platform/lib/device-url/dist/index.js.map +1 -0
  107. package/payload/platform/lib/device-url/src/index.ts +78 -0
  108. package/payload/platform/lib/device-url/tsconfig.json +8 -0
  109. package/payload/platform/lib/embed-client/dist/index.d.ts +4 -0
  110. package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -0
  111. package/payload/platform/lib/embed-client/dist/index.js +53 -0
  112. package/payload/platform/lib/embed-client/dist/index.js.map +1 -0
  113. package/payload/platform/lib/embed-client/src/index.ts +53 -0
  114. package/payload/platform/lib/embed-client/tsconfig.json +8 -0
  115. package/payload/platform/lib/entitlement/PUBKEY-HASH.txt +1 -0
  116. package/payload/platform/lib/entitlement/dist/canonicalize.d.ts +26 -0
  117. package/payload/platform/lib/entitlement/dist/canonicalize.d.ts.map +1 -0
  118. package/payload/platform/lib/entitlement/dist/canonicalize.js +54 -0
  119. package/payload/platform/lib/entitlement/dist/canonicalize.js.map +1 -0
  120. package/payload/platform/lib/entitlement/dist/index.d.ts +76 -0
  121. package/payload/platform/lib/entitlement/dist/index.d.ts.map +1 -0
  122. package/payload/platform/lib/entitlement/dist/index.js +293 -0
  123. package/payload/platform/lib/entitlement/dist/index.js.map +1 -0
  124. package/payload/platform/lib/entitlement/rubytech-pubkey.pem +3 -0
  125. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.d.ts +2 -0
  126. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.d.ts.map +1 -0
  127. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.js +97 -0
  128. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate-write.test.js.map +1 -0
  129. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.d.ts +2 -0
  130. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.d.ts.map +1 -0
  131. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.js +112 -0
  132. package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.js.map +1 -0
  133. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.d.ts +2 -0
  134. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.d.ts.map +1 -0
  135. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.js +163 -0
  136. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.js.map +1 -0
  137. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.d.ts +2 -0
  138. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.d.ts.map +1 -0
  139. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.js +89 -0
  140. package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cypher-parser.test.js.map +1 -0
  141. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.d.ts +2 -0
  142. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.d.ts.map +1 -0
  143. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.js +140 -0
  144. package/payload/platform/lib/graph-mcp/dist/__tests__/warnings-envelope.test.js.map +1 -0
  145. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.d.ts +37 -0
  146. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.d.ts.map +1 -0
  147. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.js +333 -0
  148. package/payload/platform/lib/graph-mcp/dist/cypher-rewrite-stamp.js.map +1 -0
  149. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.d.ts +85 -0
  150. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.d.ts.map +1 -0
  151. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.js +93 -0
  152. package/payload/platform/lib/graph-mcp/dist/cypher-shim-read.js.map +1 -0
  153. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.d.ts +71 -0
  154. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.d.ts.map +1 -0
  155. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.js +168 -0
  156. package/payload/platform/lib/graph-mcp/dist/cypher-shim-write.js.map +1 -0
  157. package/payload/platform/lib/graph-mcp/dist/cypher-validate.d.ts +50 -0
  158. package/payload/platform/lib/graph-mcp/dist/cypher-validate.d.ts.map +1 -0
  159. package/payload/platform/lib/graph-mcp/dist/cypher-validate.js +197 -0
  160. package/payload/platform/lib/graph-mcp/dist/cypher-validate.js.map +1 -0
  161. package/payload/platform/lib/graph-mcp/dist/index.d.ts +26 -0
  162. package/payload/platform/lib/graph-mcp/dist/index.d.ts.map +1 -0
  163. package/payload/platform/lib/graph-mcp/dist/index.js +845 -0
  164. package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -0
  165. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +76 -0
  166. package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -0
  167. package/payload/platform/lib/graph-mcp/dist/schema-cache.js +218 -0
  168. package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -0
  169. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.d.ts +42 -0
  170. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.d.ts.map +1 -0
  171. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.js +87 -0
  172. package/payload/platform/lib/graph-mcp/dist/schema-cypher-parser.js.map +1 -0
  173. package/payload/platform/lib/graph-mcp/src/__tests__/cypher-validate-write.test.ts +150 -0
  174. package/payload/platform/lib/graph-mcp/src/__tests__/cypher-validate.test.ts +141 -0
  175. package/payload/platform/lib/graph-mcp/src/__tests__/schema-cache.test.ts +169 -0
  176. package/payload/platform/lib/graph-mcp/src/__tests__/schema-cypher-parser.test.ts +99 -0
  177. package/payload/platform/lib/graph-mcp/src/__tests__/warnings-envelope.test.ts +151 -0
  178. package/payload/platform/lib/graph-mcp/src/cypher-rewrite-stamp.ts +349 -0
  179. package/payload/platform/lib/graph-mcp/src/cypher-shim-read.ts +141 -0
  180. package/payload/platform/lib/graph-mcp/src/cypher-shim-write.ts +240 -0
  181. package/payload/platform/lib/graph-mcp/src/cypher-validate.ts +249 -0
  182. package/payload/platform/lib/graph-mcp/src/index.ts +1074 -0
  183. package/payload/platform/lib/graph-mcp/src/schema-cache.ts +243 -0
  184. package/payload/platform/lib/graph-mcp/src/schema-cypher-parser.ts +84 -0
  185. package/payload/platform/lib/graph-mcp/tsconfig.json +8 -0
  186. package/payload/platform/lib/graph-search/dist/boosts.d.ts +39 -0
  187. package/payload/platform/lib/graph-search/dist/boosts.d.ts.map +1 -0
  188. package/payload/platform/lib/graph-search/dist/boosts.js +57 -0
  189. package/payload/platform/lib/graph-search/dist/boosts.js.map +1 -0
  190. package/payload/platform/lib/graph-search/dist/dedup.d.ts +29 -0
  191. package/payload/platform/lib/graph-search/dist/dedup.d.ts.map +1 -0
  192. package/payload/platform/lib/graph-search/dist/dedup.js +97 -0
  193. package/payload/platform/lib/graph-search/dist/dedup.js.map +1 -0
  194. package/payload/platform/lib/graph-search/dist/index.d.ts +355 -0
  195. package/payload/platform/lib/graph-search/dist/index.d.ts.map +1 -0
  196. package/payload/platform/lib/graph-search/dist/index.js +864 -0
  197. package/payload/platform/lib/graph-search/dist/index.js.map +1 -0
  198. package/payload/platform/lib/graph-search/dist/query-expansion.d.ts +37 -0
  199. package/payload/platform/lib/graph-search/dist/query-expansion.d.ts.map +1 -0
  200. package/payload/platform/lib/graph-search/dist/query-expansion.js +101 -0
  201. package/payload/platform/lib/graph-search/dist/query-expansion.js.map +1 -0
  202. package/payload/platform/lib/graph-search/dist/route.d.ts +29 -0
  203. package/payload/platform/lib/graph-search/dist/route.d.ts.map +1 -0
  204. package/payload/platform/lib/graph-search/dist/route.js +53 -0
  205. package/payload/platform/lib/graph-search/dist/route.js.map +1 -0
  206. package/payload/platform/lib/graph-search/dist/rrf-fusion.d.ts +31 -0
  207. package/payload/platform/lib/graph-search/dist/rrf-fusion.d.ts.map +1 -0
  208. package/payload/platform/lib/graph-search/dist/rrf-fusion.js +57 -0
  209. package/payload/platform/lib/graph-search/dist/rrf-fusion.js.map +1 -0
  210. package/payload/platform/lib/graph-search/src/__tests__/bm25-label-gate.test.ts +88 -0
  211. package/payload/platform/lib/graph-search/src/__tests__/bm25-only.test.ts +129 -0
  212. package/payload/platform/lib/graph-search/src/__tests__/bm25-strong-bypass-threshold.test.ts +126 -0
  213. package/payload/platform/lib/graph-search/src/__tests__/boosts.test.ts +59 -0
  214. package/payload/platform/lib/graph-search/src/__tests__/brochure-threshold.test.ts +136 -0
  215. package/payload/platform/lib/graph-search/src/__tests__/dedup.test.ts +83 -0
  216. package/payload/platform/lib/graph-search/src/__tests__/escape-and-normalise.test.ts +53 -0
  217. package/payload/platform/lib/graph-search/src/__tests__/expand-batch.test.ts +206 -0
  218. package/payload/platform/lib/graph-search/src/__tests__/fulltext-coverage.test.ts +357 -0
  219. package/payload/platform/lib/graph-search/src/__tests__/hybrid.test.ts +355 -0
  220. package/payload/platform/lib/graph-search/src/__tests__/route.test.ts +62 -0
  221. package/payload/platform/lib/graph-search/src/__tests__/rrf-fusion.test.ts +39 -0
  222. package/payload/platform/lib/graph-search/src/__tests__/vector-index-coverage.test.ts +198 -0
  223. package/payload/platform/lib/graph-search/src/__tests__/vector-threshold.test.ts +170 -0
  224. package/payload/platform/lib/graph-search/src/boosts.ts +61 -0
  225. package/payload/platform/lib/graph-search/src/dedup.ts +108 -0
  226. package/payload/platform/lib/graph-search/src/index.ts +1162 -0
  227. package/payload/platform/lib/graph-search/src/route.ts +70 -0
  228. package/payload/platform/lib/graph-search/src/rrf-fusion.ts +62 -0
  229. package/payload/platform/lib/graph-search/tsconfig.json +9 -0
  230. package/payload/platform/lib/graph-search/vitest.config.ts +9 -0
  231. package/payload/platform/lib/graph-style/dist/index.d.ts +80 -0
  232. package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -0
  233. package/payload/platform/lib/graph-style/dist/index.js +285 -0
  234. package/payload/platform/lib/graph-style/dist/index.js.map +1 -0
  235. package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +114 -0
  236. package/payload/platform/lib/graph-style/src/index.ts +299 -0
  237. package/payload/platform/lib/graph-style/tsconfig.json +9 -0
  238. package/payload/platform/lib/graph-style/vitest.config.ts +9 -0
  239. package/payload/platform/lib/graph-trash/dist/index.d.ts +106 -0
  240. package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -0
  241. package/payload/platform/lib/graph-trash/dist/index.js +340 -0
  242. package/payload/platform/lib/graph-trash/dist/index.js.map +1 -0
  243. package/payload/platform/lib/graph-trash/package.json +7 -0
  244. package/payload/platform/lib/graph-trash/src/index.ts +493 -0
  245. package/payload/platform/lib/graph-trash/tsconfig.json +8 -0
  246. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.d.ts +2 -0
  247. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.d.ts.map +1 -0
  248. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js +165 -0
  249. package/payload/platform/lib/graph-write/dist/__tests__/account-id-gate.test.js.map +1 -0
  250. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.d.ts +2 -0
  251. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.d.ts.map +1 -0
  252. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js +263 -0
  253. package/payload/platform/lib/graph-write/dist/__tests__/action-provenance-gate.test.js.map +1 -0
  254. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.d.ts +2 -0
  255. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.d.ts.map +1 -0
  256. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.js +147 -0
  257. package/payload/platform/lib/graph-write/dist/__tests__/audit.test.js.map +1 -0
  258. package/payload/platform/lib/graph-write/dist/audit.d.ts +84 -0
  259. package/payload/platform/lib/graph-write/dist/audit.d.ts.map +1 -0
  260. package/payload/platform/lib/graph-write/dist/audit.js +129 -0
  261. package/payload/platform/lib/graph-write/dist/audit.js.map +1 -0
  262. package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts +30 -0
  263. package/payload/platform/lib/graph-write/dist/conversation-provenance.d.ts.map +1 -0
  264. package/payload/platform/lib/graph-write/dist/conversation-provenance.js +88 -0
  265. package/payload/platform/lib/graph-write/dist/conversation-provenance.js.map +1 -0
  266. package/payload/platform/lib/graph-write/dist/index.d.ts +151 -0
  267. package/payload/platform/lib/graph-write/dist/index.d.ts.map +1 -0
  268. package/payload/platform/lib/graph-write/dist/index.js +377 -0
  269. package/payload/platform/lib/graph-write/dist/index.js.map +1 -0
  270. package/payload/platform/lib/graph-write/src/__tests__/account-id-gate.test.ts +189 -0
  271. package/payload/platform/lib/graph-write/src/__tests__/action-provenance-gate.test.ts +279 -0
  272. package/payload/platform/lib/graph-write/src/__tests__/audit.test.ts +162 -0
  273. package/payload/platform/lib/graph-write/src/audit.ts +182 -0
  274. package/payload/platform/lib/graph-write/src/conversation-provenance.ts +148 -0
  275. package/payload/platform/lib/graph-write/src/index.ts +491 -0
  276. package/payload/platform/lib/graph-write/tsconfig.json +8 -0
  277. package/payload/platform/lib/mcp-eager/dist/index.d.ts +61 -0
  278. package/payload/platform/lib/mcp-eager/dist/index.d.ts.map +1 -0
  279. package/payload/platform/lib/mcp-eager/dist/index.js +49 -0
  280. package/payload/platform/lib/mcp-eager/dist/index.js.map +1 -0
  281. package/payload/platform/lib/mcp-eager/package.json +7 -0
  282. package/payload/platform/lib/mcp-eager/src/index.ts +78 -0
  283. package/payload/platform/lib/mcp-eager/tsconfig.json +8 -0
  284. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts +53 -0
  285. package/payload/platform/lib/mcp-spawn-tee/dist/index.d.ts.map +1 -0
  286. package/payload/platform/lib/mcp-spawn-tee/dist/index.js +132 -0
  287. package/payload/platform/lib/mcp-spawn-tee/dist/index.js.map +1 -0
  288. package/payload/platform/lib/mcp-spawn-tee/src/index.ts +134 -0
  289. package/payload/platform/lib/mcp-spawn-tee/tsconfig.json +8 -0
  290. package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts +51 -0
  291. package/payload/platform/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -0
  292. package/payload/platform/lib/mcp-stderr-tee/dist/index.js +196 -0
  293. package/payload/platform/lib/mcp-stderr-tee/dist/index.js.map +1 -0
  294. package/payload/platform/lib/mcp-stderr-tee/package.json +7 -0
  295. package/payload/platform/lib/mcp-stderr-tee/src/index.ts +206 -0
  296. package/payload/platform/lib/mcp-stderr-tee/tsconfig.json +8 -0
  297. package/payload/platform/lib/models/dist/index.d.ts +7 -0
  298. package/payload/platform/lib/models/dist/index.d.ts.map +1 -0
  299. package/payload/platform/lib/models/dist/index.js +20 -0
  300. package/payload/platform/lib/models/dist/index.js.map +1 -0
  301. package/payload/platform/lib/models/src/index.ts +18 -0
  302. package/payload/platform/lib/models/tsconfig.json +8 -0
  303. package/payload/platform/lib/oauth-llm/dist/index.d.ts +116 -0
  304. package/payload/platform/lib/oauth-llm/dist/index.d.ts.map +1 -0
  305. package/payload/platform/lib/oauth-llm/dist/index.js +386 -0
  306. package/payload/platform/lib/oauth-llm/dist/index.js.map +1 -0
  307. package/payload/platform/lib/obsidian-parser/dist/index.d.ts +98 -0
  308. package/payload/platform/lib/obsidian-parser/dist/index.d.ts.map +1 -0
  309. package/payload/platform/lib/obsidian-parser/dist/index.js +480 -0
  310. package/payload/platform/lib/obsidian-parser/dist/index.js.map +1 -0
  311. package/payload/platform/lib/obsidian-parser/src/index.ts +572 -0
  312. package/payload/platform/lib/obsidian-parser/tsconfig.json +8 -0
  313. package/payload/platform/lib/persistent-components/dist/index.d.ts +20 -0
  314. package/payload/platform/lib/persistent-components/dist/index.d.ts.map +1 -0
  315. package/payload/platform/lib/persistent-components/dist/index.js +31 -0
  316. package/payload/platform/lib/persistent-components/dist/index.js.map +1 -0
  317. package/payload/platform/lib/persistent-components/src/index.ts +27 -0
  318. package/payload/platform/lib/persistent-components/tsconfig.json +8 -0
  319. package/payload/platform/lib/require-port-env/dist/index.d.ts +31 -0
  320. package/payload/platform/lib/require-port-env/dist/index.d.ts.map +1 -0
  321. package/payload/platform/lib/require-port-env/dist/index.js +52 -0
  322. package/payload/platform/lib/require-port-env/dist/index.js.map +1 -0
  323. package/payload/platform/lib/require-port-env/src/index.ts +56 -0
  324. package/payload/platform/lib/require-port-env/tsconfig.json +8 -0
  325. package/payload/platform/lib/screening-patterns/dist/index.d.ts +29 -0
  326. package/payload/platform/lib/screening-patterns/dist/index.d.ts.map +1 -0
  327. package/payload/platform/lib/screening-patterns/dist/index.js +48 -0
  328. package/payload/platform/lib/screening-patterns/dist/index.js.map +1 -0
  329. package/payload/platform/lib/task-secrets/dist/index.d.ts +40 -0
  330. package/payload/platform/lib/task-secrets/dist/index.d.ts.map +1 -0
  331. package/payload/platform/lib/task-secrets/dist/index.js +44 -0
  332. package/payload/platform/lib/task-secrets/dist/index.js.map +1 -0
  333. package/payload/platform/lib/task-secrets/src/__tests__/redact-secrets.test.ts +127 -0
  334. package/payload/platform/lib/task-secrets/src/index.ts +77 -0
  335. package/payload/platform/lib/task-secrets/tsconfig.json +9 -0
  336. package/payload/platform/lib/task-secrets/vitest.config.ts +9 -0
  337. package/payload/platform/neo4j/edge-annotations.json +158 -0
  338. package/payload/platform/neo4j/schema.cypher +1899 -0
  339. package/payload/platform/package-lock.json +4060 -0
  340. package/payload/platform/package.json +26 -0
  341. package/payload/platform/plugins/.claude-plugin/marketplace.json +158 -0
  342. package/payload/platform/plugins/admin/.claude-plugin/plugin.json +17 -0
  343. package/payload/platform/plugins/admin/PLUGIN.md +163 -0
  344. package/payload/platform/plugins/admin/hooks/__tests__/archive-ingest-surface-gate.test.sh +191 -0
  345. package/payload/platform/plugins/admin/hooks/__tests__/askuserquestion-investigate-gate.test.sh +176 -0
  346. package/payload/platform/plugins/admin/hooks/__tests__/hook-emit-stale-lock-ttl.test.sh +102 -0
  347. package/payload/platform/plugins/admin/hooks/__tests__/hook-emit.test.sh +75 -0
  348. package/payload/platform/plugins/admin/hooks/__tests__/pin-identity-gate.test.sh +96 -0
  349. package/payload/platform/plugins/admin/hooks/__tests__/post-tool-use-agent.test.sh +173 -0
  350. package/payload/platform/plugins/admin/hooks/__tests__/prompt-optimiser-directive.test.sh +70 -0
  351. package/payload/platform/plugins/admin/hooks/admin-authoring-observer.sh +155 -0
  352. package/payload/platform/plugins/admin/hooks/archive-ingest-surface-gate.sh +224 -0
  353. package/payload/platform/plugins/admin/hooks/askuserquestion-investigate-gate.sh +257 -0
  354. package/payload/platform/plugins/admin/hooks/lib/hook-emit.sh +143 -0
  355. package/payload/platform/plugins/admin/hooks/lib/maxy-mcp-plugins.txt +16 -0
  356. package/payload/platform/plugins/admin/hooks/mcp-tool-missing.sh +94 -0
  357. package/payload/platform/plugins/admin/hooks/pin-identity-gate.sh +136 -0
  358. package/payload/platform/plugins/admin/hooks/post-tool-use-agent.sh +155 -0
  359. package/payload/platform/plugins/admin/hooks/prompt-optimiser-directive.sh +52 -0
  360. package/payload/platform/plugins/admin/hooks/webfetch-preflight.mjs +363 -0
  361. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.d.ts +2 -0
  362. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.d.ts.map +1 -0
  363. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.js +79 -0
  364. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-authoring-skill-gate.test.js.map +1 -0
  365. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts +2 -0
  366. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.d.ts.map +1 -0
  367. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js +34 -0
  368. package/payload/platform/plugins/admin/mcp/dist/__tests__/admin-identity-authenticate.test.js.map +1 -0
  369. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.d.ts +2 -0
  370. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.d.ts.map +1 -0
  371. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js +130 -0
  372. package/payload/platform/plugins/admin/mcp/dist/__tests__/capabilities-here.test.js.map +1 -0
  373. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.d.ts +2 -0
  374. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.d.ts.map +1 -0
  375. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.js +91 -0
  376. package/payload/platform/plugins/admin/mcp/dist/__tests__/plugin-read-skill-resolution.test.js.map +1 -0
  377. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.d.ts +2 -0
  378. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.d.ts.map +1 -0
  379. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.js +98 -0
  380. package/payload/platform/plugins/admin/mcp/dist/__tests__/public-hostname.test.js.map +1 -0
  381. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.d.ts +2 -0
  382. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.d.ts.map +1 -0
  383. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.js +141 -0
  384. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load-required-inputs.test.js.map +1 -0
  385. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.d.ts +2 -0
  386. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.d.ts.map +1 -0
  387. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.js +88 -0
  388. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-load.test.js.map +1 -0
  389. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts +2 -0
  390. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.d.ts.map +1 -0
  391. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js +50 -0
  392. package/payload/platform/plugins/admin/mcp/dist/__tests__/skill-no-prescribed-role.test.js.map +1 -0
  393. package/payload/platform/plugins/admin/mcp/dist/index.d.ts +2 -0
  394. package/payload/platform/plugins/admin/mcp/dist/index.d.ts.map +1 -0
  395. package/payload/platform/plugins/admin/mcp/dist/index.js +3120 -0
  396. package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -0
  397. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.d.ts +14 -0
  398. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.d.ts.map +1 -0
  399. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.js +50 -0
  400. package/payload/platform/plugins/admin/mcp/dist/lib/catalogue-census.js.map +1 -0
  401. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.d.ts +5 -0
  402. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.d.ts.map +1 -0
  403. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.js +40 -0
  404. package/payload/platform/plugins/admin/mcp/dist/lib/neo4j.js.map +1 -0
  405. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts +39 -0
  406. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.d.ts.map +1 -0
  407. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js +249 -0
  408. package/payload/platform/plugins/admin/mcp/dist/lib/onboarding.js.map +1 -0
  409. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.d.ts +15 -0
  410. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.d.ts.map +1 -0
  411. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.js +73 -0
  412. package/payload/platform/plugins/admin/mcp/dist/lib/public-hostname.js.map +1 -0
  413. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts +44 -0
  414. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.d.ts.map +1 -0
  415. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js +187 -0
  416. package/payload/platform/plugins/admin/mcp/dist/skill-resolution.js.map +1 -0
  417. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts +6 -0
  418. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.d.ts.map +1 -0
  419. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js +32 -0
  420. package/payload/platform/plugins/admin/mcp/dist/tools/admin-identity-authenticate.js.map +1 -0
  421. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts +28 -0
  422. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.d.ts.map +1 -0
  423. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js +68 -0
  424. package/payload/platform/plugins/admin/mcp/dist/tools/capabilities-here.js.map +1 -0
  425. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.d.ts +34 -0
  426. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.d.ts.map +1 -0
  427. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.js +176 -0
  428. package/payload/platform/plugins/admin/mcp/dist/tools/publish-site.js.map +1 -0
  429. package/payload/platform/plugins/admin/mcp/package.json +23 -0
  430. package/payload/platform/plugins/admin/mcp/vitest.config.ts +9 -0
  431. package/payload/platform/plugins/admin/references/chat-ui-guide.md +31 -0
  432. package/payload/platform/plugins/admin/references/publish-site-routing.md +44 -0
  433. package/payload/platform/plugins/admin/skills/a4-print-documents/SKILL.md +241 -0
  434. package/payload/platform/plugins/admin/skills/access-manager/SKILL.md +30 -0
  435. package/payload/platform/plugins/admin/skills/access-manager/references/operations.md +154 -0
  436. package/payload/platform/plugins/admin/skills/admin-user-management/SKILL.md +49 -0
  437. package/payload/platform/plugins/admin/skills/business-profile/SKILL.md +53 -0
  438. package/payload/platform/plugins/admin/skills/capabilities-here/SKILL.md +31 -0
  439. package/payload/platform/plugins/admin/skills/datetime/SKILL.md +149 -0
  440. package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +404 -0
  441. package/payload/platform/plugins/admin/skills/file-presentation/SKILL.md +47 -0
  442. package/payload/platform/plugins/admin/skills/insight/SKILL.md +24 -0
  443. package/payload/platform/plugins/admin/skills/investigate/SKILL.md +318 -0
  444. package/payload/platform/plugins/admin/skills/plainly/SKILL.md +105 -0
  445. package/payload/platform/plugins/admin/skills/plainly/references/worked-examples.md +301 -0
  446. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3943 -0
  447. package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +99 -0
  448. package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +178 -0
  449. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +256 -0
  450. package/payload/platform/plugins/admin/skills/publish-site/SKILL.md +42 -0
  451. package/payload/platform/plugins/admin/skills/qr-code/SKILL.md +36 -0
  452. package/payload/platform/plugins/admin/skills/qr-code/references/data-formats.md +113 -0
  453. package/payload/platform/plugins/admin/skills/session-management/SKILL.md +62 -0
  454. package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +113 -0
  455. package/payload/platform/plugins/admin/skills/skill-builder/references/lean-pattern.md +110 -0
  456. package/payload/platform/plugins/admin/skills/skill-builder/references/pdf-generation.md +30 -0
  457. package/payload/platform/plugins/admin/skills/specialist-management/SKILL.md +45 -0
  458. package/payload/platform/plugins/admin/skills/stream-log-review/SKILL.md +71 -0
  459. package/payload/platform/plugins/admin/skills/stream-log-review/references/analysis-patterns.md +193 -0
  460. package/payload/platform/plugins/admin/skills/superpowers-sprint/SKILL.md +361 -0
  461. package/payload/platform/plugins/admin/skills/task/SKILL.md +314 -0
  462. package/payload/platform/plugins/admin/skills/unzip-attachment/SKILL.md +84 -0
  463. package/payload/platform/plugins/admin/skills/unzip-attachment/__tests__/preflight.sh +148 -0
  464. package/payload/platform/plugins/admin/skills/unzip-attachment/references/safety.md +116 -0
  465. package/payload/platform/plugins/admin/skills/update-knowledge/SKILL.md +52 -0
  466. package/payload/platform/plugins/admin/skills/upgrade/SKILL.md +34 -0
  467. package/payload/platform/plugins/aeo/.claude-plugin/plugin.json +17 -0
  468. package/payload/platform/plugins/aeo/PLUGIN.md +80 -0
  469. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts +2 -0
  470. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts.map +1 -0
  471. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js +121 -0
  472. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js.map +1 -0
  473. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts +2 -0
  474. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts.map +1 -0
  475. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js +129 -0
  476. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js.map +1 -0
  477. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts +2 -0
  478. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts.map +1 -0
  479. package/payload/platform/plugins/aeo/mcp/dist/index.js +189 -0
  480. package/payload/platform/plugins/aeo/mcp/dist/index.js.map +1 -0
  481. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts +27 -0
  482. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts.map +1 -0
  483. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js +274 -0
  484. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js.map +1 -0
  485. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts +5 -0
  486. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts.map +1 -0
  487. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js +38 -0
  488. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js.map +1 -0
  489. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts +48 -0
  490. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts.map +1 -0
  491. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js +254 -0
  492. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js.map +1 -0
  493. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts +25 -0
  494. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts.map +1 -0
  495. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js +78 -0
  496. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js.map +1 -0
  497. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts +18 -0
  498. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts.map +1 -0
  499. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js +56 -0
  500. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js.map +1 -0
  501. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts +9 -0
  502. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts.map +1 -0
  503. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js +11 -0
  504. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js.map +1 -0
  505. package/payload/platform/plugins/aeo/mcp/package.json +22 -0
  506. package/payload/platform/plugins/aeo/mcp/vitest.config.ts +9 -0
  507. package/payload/platform/plugins/aeo/skills/structured-answer/SKILL.md +53 -0
  508. package/payload/platform/plugins/browser/.claude-plugin/plugin.json +17 -0
  509. package/payload/platform/plugins/browser/PLUGIN.md +114 -0
  510. package/payload/platform/plugins/browser/mcp/dist/index.d.ts +2 -0
  511. package/payload/platform/plugins/browser/mcp/dist/index.d.ts.map +1 -0
  512. package/payload/platform/plugins/browser/mcp/dist/index.js +165 -0
  513. package/payload/platform/plugins/browser/mcp/dist/index.js.map +1 -0
  514. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts +98 -0
  515. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.d.ts.map +1 -0
  516. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js +455 -0
  517. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-actions.js.map +1 -0
  518. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts +44 -0
  519. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.d.ts.map +1 -0
  520. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js +89 -0
  521. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-render.js.map +1 -0
  522. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts +153 -0
  523. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.d.ts.map +1 -0
  524. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js +401 -0
  525. package/payload/platform/plugins/browser/mcp/dist/lib/cdp-session.js.map +1 -0
  526. package/payload/platform/plugins/browser/mcp/package.json +19 -0
  527. package/payload/platform/plugins/business-assistant/.claude-plugin/plugin.json +8 -0
  528. package/payload/platform/plugins/business-assistant/PLUGIN.md +62 -0
  529. package/payload/platform/plugins/business-assistant/references/crm.md +112 -0
  530. package/payload/platform/plugins/business-assistant/references/document-management.md +96 -0
  531. package/payload/platform/plugins/business-assistant/references/escalation.md +126 -0
  532. package/payload/platform/plugins/business-assistant/references/invoicing.md +163 -0
  533. package/payload/platform/plugins/business-assistant/references/profiling.md +50 -0
  534. package/payload/platform/plugins/business-assistant/references/quoting.md +56 -0
  535. package/payload/platform/plugins/business-assistant/references/scheduling.md +127 -0
  536. package/payload/platform/plugins/business-assistant/references/task-management.md +163 -0
  537. package/payload/platform/plugins/cloudflare/.claude-plugin/plugin.json +8 -0
  538. package/payload/platform/plugins/cloudflare/PLUGIN.md +61 -0
  539. package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts +2 -0
  540. package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts.map +1 -0
  541. package/payload/platform/plugins/cloudflare/mcp/dist/index.js +24 -0
  542. package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -0
  543. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +283 -0
  544. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -0
  545. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +1155 -0
  546. package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -0
  547. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts +90 -0
  548. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.d.ts.map +1 -0
  549. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js +551 -0
  550. package/payload/platform/plugins/cloudflare/mcp/dist/lib/setup-orchestrator.js.map +1 -0
  551. package/payload/platform/plugins/cloudflare/mcp/package.json +18 -0
  552. package/payload/platform/plugins/cloudflare/mcp/vitest.config.ts +10 -0
  553. package/payload/platform/plugins/cloudflare/references/api.md +166 -0
  554. package/payload/platform/plugins/cloudflare/references/d1-data-capture.md +157 -0
  555. package/payload/platform/plugins/cloudflare/references/dashboard-guide.md +173 -0
  556. package/payload/platform/plugins/cloudflare/references/hosting-sites.md +66 -0
  557. package/payload/platform/plugins/cloudflare/references/manual-setup.md +633 -0
  558. package/payload/platform/plugins/cloudflare/references/reset-guide.md +119 -0
  559. package/payload/platform/plugins/cloudflare/references/serving-published-sites.md +73 -0
  560. package/payload/platform/plugins/cloudflare/skills/cloudflare/SKILL.md +72 -0
  561. package/payload/platform/plugins/contacts/.claude-plugin/plugin.json +17 -0
  562. package/payload/platform/plugins/contacts/PLUGIN.md +62 -0
  563. package/payload/platform/plugins/contacts/mcp/dist/index.d.ts +2 -0
  564. package/payload/platform/plugins/contacts/mcp/dist/index.d.ts.map +1 -0
  565. package/payload/platform/plugins/contacts/mcp/dist/index.js +467 -0
  566. package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -0
  567. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts +5 -0
  568. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts.map +1 -0
  569. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js +40 -0
  570. package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js.map +1 -0
  571. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.d.ts +33 -0
  572. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.d.ts.map +1 -0
  573. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.js +53 -0
  574. package/payload/platform/plugins/contacts/mcp/dist/lib/resolve-person.js.map +1 -0
  575. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +23 -0
  576. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -0
  577. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +123 -0
  578. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -0
  579. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.d.ts +28 -0
  580. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.d.ts.map +1 -0
  581. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.js +39 -0
  582. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-delete.js.map +1 -0
  583. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.d.ts +52 -0
  584. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.d.ts.map +1 -0
  585. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js +181 -0
  586. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-erase.js.map +1 -0
  587. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.d.ts +52 -0
  588. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.d.ts.map +1 -0
  589. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.js +122 -0
  590. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-export.js.map +1 -0
  591. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts +23 -0
  592. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts.map +1 -0
  593. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js +49 -0
  594. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js.map +1 -0
  595. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +21 -0
  596. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -0
  597. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +70 -0
  598. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -0
  599. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts +14 -0
  600. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts.map +1 -0
  601. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js +43 -0
  602. package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js.map +1 -0
  603. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts +18 -0
  604. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.d.ts.map +1 -0
  605. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js +95 -0
  606. package/payload/platform/plugins/contacts/mcp/dist/tools/group-create.js.map +1 -0
  607. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.d.ts +15 -0
  608. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.d.ts.map +1 -0
  609. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js +72 -0
  610. package/payload/platform/plugins/contacts/mcp/dist/tools/group-manage.js.map +1 -0
  611. package/payload/platform/plugins/contacts/mcp/package.json +19 -0
  612. package/payload/platform/plugins/deep-research/.claude-plugin/plugin.json +8 -0
  613. package/payload/platform/plugins/deep-research/PLUGIN.md +19 -0
  614. package/payload/platform/plugins/deep-research/recipes/README.md +36 -0
  615. package/payload/platform/plugins/deep-research/skills/academic-verify/SKILL.md +75 -0
  616. package/payload/platform/plugins/deep-research/skills/book-mirror/SKILL.md +68 -0
  617. package/payload/platform/plugins/deep-research/skills/data-research/SKILL.md +108 -0
  618. package/payload/platform/plugins/deep-research/skills/deep-research/SKILL.md +46 -0
  619. package/payload/platform/plugins/deep-research/skills/deep-research/references/citation-styles.md +52 -0
  620. package/payload/platform/plugins/deep-research/skills/deep-research/references/research-modes.md +22 -0
  621. package/payload/platform/plugins/deep-research/skills/deep-research/references/search-strategy.md +24 -0
  622. package/payload/platform/plugins/deep-research/skills/strategic-reading/SKILL.md +69 -0
  623. package/payload/platform/plugins/docs/.claude-plugin/plugin.json +8 -0
  624. package/payload/platform/plugins/docs/PLUGIN.md +58 -0
  625. package/payload/platform/plugins/docs/references/access-control.md +84 -0
  626. package/payload/platform/plugins/docs/references/admin-identity-gate.md +81 -0
  627. package/payload/platform/plugins/docs/references/admin-session.md +177 -0
  628. package/payload/platform/plugins/docs/references/admin-ui.md +266 -0
  629. package/payload/platform/plugins/docs/references/aeo.md +87 -0
  630. package/payload/platform/plugins/docs/references/attachments.md +44 -0
  631. package/payload/platform/plugins/docs/references/cloudflare.md +102 -0
  632. package/payload/platform/plugins/docs/references/contacts-guide.md +94 -0
  633. package/payload/platform/plugins/docs/references/deployment.md +303 -0
  634. package/payload/platform/plugins/docs/references/getting-started.md +82 -0
  635. package/payload/platform/plugins/docs/references/graph.md +163 -0
  636. package/payload/platform/plugins/docs/references/internals.md +539 -0
  637. package/payload/platform/plugins/docs/references/investigate-and-task-skills.md +9 -0
  638. package/payload/platform/plugins/docs/references/linkedin-extension.md +49 -0
  639. package/payload/platform/plugins/docs/references/memory-guide.md +163 -0
  640. package/payload/platform/plugins/docs/references/neo4j.md +63 -0
  641. package/payload/platform/plugins/docs/references/outlook-guide.md +69 -0
  642. package/payload/platform/plugins/docs/references/platform.md +193 -0
  643. package/payload/platform/plugins/docs/references/plugins-guide.md +188 -0
  644. package/payload/platform/plugins/docs/references/projects-guide.md +94 -0
  645. package/payload/platform/plugins/docs/references/samba.md +80 -0
  646. package/payload/platform/plugins/docs/references/session-retrospective.md +14 -0
  647. package/payload/platform/plugins/docs/references/settings.md +82 -0
  648. package/payload/platform/plugins/docs/references/slides.md +31 -0
  649. package/payload/platform/plugins/docs/references/telegram-guide.md +58 -0
  650. package/payload/platform/plugins/docs/references/troubleshooting.md +289 -0
  651. package/payload/platform/plugins/docs/references/visitor-graph.md +83 -0
  652. package/payload/platform/plugins/docs/references/voice-mirror-guide.md +64 -0
  653. package/payload/platform/plugins/docs/superpowers/plans/2026-06-01-memory-edge.md +589 -0
  654. package/payload/platform/plugins/email/.claude-plugin/plugin.json +17 -0
  655. package/payload/platform/plugins/email/PLUGIN.md +98 -0
  656. package/payload/platform/plugins/email/mcp/dist/index.d.ts +2 -0
  657. package/payload/platform/plugins/email/mcp/dist/index.d.ts.map +1 -0
  658. package/payload/platform/plugins/email/mcp/dist/index.js +381 -0
  659. package/payload/platform/plugins/email/mcp/dist/index.js.map +1 -0
  660. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.d.ts +39 -0
  661. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.d.ts.map +1 -0
  662. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.js +0 -0
  663. package/payload/platform/plugins/email/mcp/dist/lib/attachment-archive.js.map +1 -0
  664. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts +19 -0
  665. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.d.ts.map +1 -0
  666. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js +64 -0
  667. package/payload/platform/plugins/email/mcp/dist/lib/attachment-resolve.js.map +1 -0
  668. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts +17 -0
  669. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.d.ts.map +1 -0
  670. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js +186 -0
  671. package/payload/platform/plugins/email/mcp/dist/lib/claude-bridge.js.map +1 -0
  672. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts +30 -0
  673. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.d.ts.map +1 -0
  674. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js +305 -0
  675. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-dispatch.js.map +1 -0
  676. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.d.ts +19 -0
  677. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.d.ts.map +1 -0
  678. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.js +51 -0
  679. package/payload/platform/plugins/email/mcp/dist/lib/conversation-archive-lookup.js.map +1 -0
  680. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts +89 -0
  681. package/payload/platform/plugins/email/mcp/dist/lib/credentials.d.ts.map +1 -0
  682. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js +245 -0
  683. package/payload/platform/plugins/email/mcp/dist/lib/credentials.js.map +1 -0
  684. package/payload/platform/plugins/email/mcp/dist/lib/embedding.d.ts +2 -0
  685. package/payload/platform/plugins/email/mcp/dist/lib/embedding.d.ts.map +1 -0
  686. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js +24 -0
  687. package/payload/platform/plugins/email/mcp/dist/lib/embedding.js.map +1 -0
  688. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts +29 -0
  689. package/payload/platform/plugins/email/mcp/dist/lib/graph.d.ts.map +1 -0
  690. package/payload/platform/plugins/email/mcp/dist/lib/graph.js +18 -0
  691. package/payload/platform/plugins/email/mcp/dist/lib/graph.js.map +1 -0
  692. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts +266 -0
  693. package/payload/platform/plugins/email/mcp/dist/lib/imap.d.ts.map +1 -0
  694. package/payload/platform/plugins/email/mcp/dist/lib/imap.js +770 -0
  695. package/payload/platform/plugins/email/mcp/dist/lib/imap.js.map +1 -0
  696. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts +23 -0
  697. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.d.ts.map +1 -0
  698. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js +15 -0
  699. package/payload/platform/plugins/email/mcp/dist/lib/ingest-batch.js.map +1 -0
  700. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.d.ts +5 -0
  701. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.d.ts.map +1 -0
  702. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.js +40 -0
  703. package/payload/platform/plugins/email/mcp/dist/lib/neo4j.js.map +1 -0
  704. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts +60 -0
  705. package/payload/platform/plugins/email/mcp/dist/lib/providers.d.ts.map +1 -0
  706. package/payload/platform/plugins/email/mcp/dist/lib/providers.js +675 -0
  707. package/payload/platform/plugins/email/mcp/dist/lib/providers.js.map +1 -0
  708. package/payload/platform/plugins/email/mcp/dist/lib/screening.d.ts +29 -0
  709. package/payload/platform/plugins/email/mcp/dist/lib/screening.d.ts.map +1 -0
  710. package/payload/platform/plugins/email/mcp/dist/lib/screening.js +105 -0
  711. package/payload/platform/plugins/email/mcp/dist/lib/screening.js.map +1 -0
  712. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts +25 -0
  713. package/payload/platform/plugins/email/mcp/dist/lib/smtp.d.ts.map +1 -0
  714. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js +78 -0
  715. package/payload/platform/plugins/email/mcp/dist/lib/smtp.js.map +1 -0
  716. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.d.ts +38 -0
  717. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.d.ts.map +1 -0
  718. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js +817 -0
  719. package/payload/platform/plugins/email/mcp/dist/scripts/email-auto-respond.js.map +1 -0
  720. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts +30 -0
  721. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.d.ts.map +1 -0
  722. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js +215 -0
  723. package/payload/platform/plugins/email/mcp/dist/scripts/email-fetch.js.map +1 -0
  724. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.d.ts +2 -0
  725. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.d.ts.map +1 -0
  726. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js +56 -0
  727. package/payload/platform/plugins/email/mcp/dist/scripts/send-transactional.js.map +1 -0
  728. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.d.ts +19 -0
  729. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.d.ts.map +1 -0
  730. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.js +151 -0
  731. package/payload/platform/plugins/email/mcp/dist/tools/email-auto-respond-config.js.map +1 -0
  732. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts +6 -0
  733. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.d.ts.map +1 -0
  734. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js +89 -0
  735. package/payload/platform/plugins/email/mcp/dist/tools/email-classify.js.map +1 -0
  736. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts +15 -0
  737. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.d.ts.map +1 -0
  738. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js +54 -0
  739. package/payload/platform/plugins/email/mcp/dist/tools/email-fetch.js.map +1 -0
  740. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.d.ts +24 -0
  741. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.d.ts.map +1 -0
  742. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.js +293 -0
  743. package/payload/platform/plugins/email/mcp/dist/tools/email-graph-query.js.map +1 -0
  744. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts +20 -0
  745. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.d.ts.map +1 -0
  746. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js +191 -0
  747. package/payload/platform/plugins/email/mcp/dist/tools/email-ingest.js.map +1 -0
  748. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.d.ts +15 -0
  749. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.d.ts.map +1 -0
  750. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.js +142 -0
  751. package/payload/platform/plugins/email/mcp/dist/tools/email-otp-extract.js.map +1 -0
  752. package/payload/platform/plugins/email/mcp/dist/tools/email-read.d.ts +14 -0
  753. package/payload/platform/plugins/email/mcp/dist/tools/email-read.d.ts.map +1 -0
  754. package/payload/platform/plugins/email/mcp/dist/tools/email-read.js +84 -0
  755. package/payload/platform/plugins/email/mcp/dist/tools/email-read.js.map +1 -0
  756. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts +11 -0
  757. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.d.ts.map +1 -0
  758. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js +74 -0
  759. package/payload/platform/plugins/email/mcp/dist/tools/email-reply.js.map +1 -0
  760. package/payload/platform/plugins/email/mcp/dist/tools/email-search.d.ts +15 -0
  761. package/payload/platform/plugins/email/mcp/dist/tools/email-search.d.ts.map +1 -0
  762. package/payload/platform/plugins/email/mcp/dist/tools/email-search.js +67 -0
  763. package/payload/platform/plugins/email/mcp/dist/tools/email-search.js.map +1 -0
  764. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts +11 -0
  765. package/payload/platform/plugins/email/mcp/dist/tools/email-send.d.ts.map +1 -0
  766. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js +37 -0
  767. package/payload/platform/plugins/email/mcp/dist/tools/email-send.js.map +1 -0
  768. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts +22 -0
  769. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.d.ts.map +1 -0
  770. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js +162 -0
  771. package/payload/platform/plugins/email/mcp/dist/tools/email-setup.js.map +1 -0
  772. package/payload/platform/plugins/email/mcp/dist/tools/email-status.d.ts +6 -0
  773. package/payload/platform/plugins/email/mcp/dist/tools/email-status.d.ts.map +1 -0
  774. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js +43 -0
  775. package/payload/platform/plugins/email/mcp/dist/tools/email-status.js.map +1 -0
  776. package/payload/platform/plugins/email/mcp/package.json +22 -0
  777. package/payload/platform/plugins/email/references/email-reference.md +144 -0
  778. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +184 -0
  779. package/payload/platform/plugins/email/skills/email-ingest/SKILL.md +87 -0
  780. package/payload/platform/plugins/graph/.claude-plugin/plugin.json +8 -0
  781. package/payload/platform/plugins/graph/PLUGIN.md +37 -0
  782. package/payload/platform/plugins/graph-viewer/.claude-plugin/plugin.json +8 -0
  783. package/payload/platform/plugins/graph-viewer/PLUGIN.md +56 -0
  784. package/payload/platform/plugins/graph-viewer/mcp/dist/index.d.ts +7 -0
  785. package/payload/platform/plugins/graph-viewer/mcp/dist/index.d.ts.map +1 -0
  786. package/payload/platform/plugins/graph-viewer/mcp/dist/index.js +70 -0
  787. package/payload/platform/plugins/graph-viewer/mcp/dist/index.js.map +1 -0
  788. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.d.ts +5 -0
  789. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.d.ts.map +1 -0
  790. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.js +43 -0
  791. package/payload/platform/plugins/graph-viewer/mcp/dist/lib/neo4j.js.map +1 -0
  792. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.d.ts +28 -0
  793. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.d.ts.map +1 -0
  794. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.js +73 -0
  795. package/payload/platform/plugins/graph-viewer/mcp/dist/render/draw.js.map +1 -0
  796. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.d.ts +40 -0
  797. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.d.ts.map +1 -0
  798. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.js +117 -0
  799. package/payload/platform/plugins/graph-viewer/mcp/dist/render/layout.js.map +1 -0
  800. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.d.ts +45 -0
  801. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.d.ts.map +1 -0
  802. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js +198 -0
  803. package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js.map +1 -0
  804. package/payload/platform/plugins/graph-viewer/mcp/package.json +25 -0
  805. package/payload/platform/plugins/graph-viewer/mcp/vitest.config.ts +8 -0
  806. package/payload/platform/plugins/graph-viewer/skills/render-graph/SKILL.md +38 -0
  807. package/payload/platform/plugins/linkedin-extension/.claude-plugin/plugin.json +8 -0
  808. package/payload/platform/plugins/linkedin-extension/PLUGIN.md +58 -0
  809. package/payload/platform/plugins/linkedin-extension/extension/README.md +44 -0
  810. package/payload/platform/plugins/linkedin-extension/extension/__tests__/fixtures/profile.html +34 -0
  811. package/payload/platform/plugins/linkedin-extension/extension/__tests__/fixtures/thread.html +36 -0
  812. package/payload/platform/plugins/linkedin-extension/extension/assets/pill.css +52 -0
  813. package/payload/platform/plugins/linkedin-extension/extension/background/sw.js +60 -0
  814. package/payload/platform/plugins/linkedin-extension/extension/content/extractors.js +127 -0
  815. package/payload/platform/plugins/linkedin-extension/extension/content/profile.js +82 -0
  816. package/payload/platform/plugins/linkedin-extension/extension/content/thread.js +84 -0
  817. package/payload/platform/plugins/linkedin-extension/extension/manifest.json +32 -0
  818. package/payload/platform/plugins/linkedin-extension/extension/options/options.html +33 -0
  819. package/payload/platform/plugins/linkedin-extension/extension/options/options.js +30 -0
  820. package/payload/platform/plugins/linkedin-extension/skills/linkedin-extension/SKILL.md +91 -0
  821. package/payload/platform/plugins/linkedin-import/.claude-plugin/plugin.json +8 -0
  822. package/payload/platform/plugins/linkedin-import/PLUGIN.md +27 -0
  823. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/SKILL.md +119 -0
  824. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/connections.md +135 -0
  825. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/profile.md +94 -0
  826. package/payload/platform/plugins/memory/.claude-plugin/plugin.json +17 -0
  827. package/payload/platform/plugins/memory/PLUGIN.md +291 -0
  828. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.mjs +616 -0
  829. package/payload/platform/plugins/memory/bin/conversation-archive-ingest.sh +106 -0
  830. package/payload/platform/plugins/memory/mcp/dist/index.d.ts +2 -0
  831. package/payload/platform/plugins/memory/mcp/dist/index.d.ts.map +1 -0
  832. package/payload/platform/plugins/memory/mcp/dist/index.js +2522 -0
  833. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -0
  834. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.d.ts +2 -0
  835. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.d.ts.map +1 -0
  836. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js +68 -0
  837. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-revision.test.js.map +1 -0
  838. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.d.ts +2 -0
  839. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.d.ts.map +1 -0
  840. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.js +90 -0
  841. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/compiled-truth-rewriter-operator-hint.test.js.map +1 -0
  842. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts +2 -0
  843. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.d.ts.map +1 -0
  844. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js +41 -0
  845. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/document-sectioniser.test.js.map +1 -0
  846. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts +2 -0
  847. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.d.ts.map +1 -0
  848. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js +90 -0
  849. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-embed-net.test.js.map +1 -0
  850. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.d.ts +2 -0
  851. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.d.ts.map +1 -0
  852. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.js +30 -0
  853. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-label.test.js.map +1 -0
  854. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.d.ts +2 -0
  855. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.d.ts.map +1 -0
  856. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.js +25 -0
  857. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/graph-write-gate-property.test.js.map +1 -0
  858. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts +2 -0
  859. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.d.ts.map +1 -0
  860. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js +62 -0
  861. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-delete-gate.test.js.map +1 -0
  862. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts +2 -0
  863. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts.map +1 -0
  864. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js +50 -0
  865. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js.map +1 -0
  866. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.d.ts +2 -0
  867. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.d.ts.map +1 -0
  868. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.js +154 -0
  869. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/live-schema-source.test.js.map +1 -0
  870. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts +2 -0
  871. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.d.ts.map +1 -0
  872. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js +226 -0
  873. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/llm-classifier.test.js.map +1 -0
  874. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.d.ts +2 -0
  875. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.d.ts.map +1 -0
  876. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.js +57 -0
  877. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/neo4j-password-path.test.js.map +1 -0
  878. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.d.ts +2 -0
  879. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.d.ts.map +1 -0
  880. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.js +24 -0
  881. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-backlinks.test.js.map +1 -0
  882. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.d.ts +2 -0
  883. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.d.ts.map +1 -0
  884. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.js +51 -0
  885. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-prune-revisions.test.js.map +1 -0
  886. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.d.ts +2 -0
  887. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.d.ts.map +1 -0
  888. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.js +51 -0
  889. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/phase-tag-normalisation.test.js.map +1 -0
  890. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.d.ts +2 -0
  891. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.d.ts.map +1 -0
  892. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.js +68 -0
  893. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/relative-date.test.js.map +1 -0
  894. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.d.ts +2 -0
  895. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.d.ts.map +1 -0
  896. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js +116 -0
  897. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/resolve-active-vertical.test.js.map +1 -0
  898. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts +2 -0
  899. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts.map +1 -0
  900. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +67 -0
  901. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -0
  902. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.d.ts +2 -0
  903. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.d.ts.map +1 -0
  904. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js +217 -0
  905. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-loader.test.js.map +1 -0
  906. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.d.ts +2 -0
  907. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.d.ts.map +1 -0
  908. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js +640 -0
  909. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-validator.test.js.map +1 -0
  910. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.d.ts +2 -0
  911. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.d.ts.map +1 -0
  912. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js +111 -0
  913. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/timeline-extractor.test.js.map +1 -0
  914. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.d.ts +2 -0
  915. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.d.ts.map +1 -0
  916. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js +79 -0
  917. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/typed-edge-schema.test.js.map +1 -0
  918. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts +2 -0
  919. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.d.ts.map +1 -0
  920. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js +27 -0
  921. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/vector-indexed-labels-drift.test.js.map +1 -0
  922. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.d.ts +37 -0
  923. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.d.ts.map +1 -0
  924. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.js +69 -0
  925. package/payload/platform/plugins/memory/mcp/dist/lib/attachments.js.map +1 -0
  926. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts +91 -0
  927. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.d.ts.map +1 -0
  928. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js +39 -0
  929. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-revision.js.map +1 -0
  930. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts +60 -0
  931. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.d.ts.map +1 -0
  932. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js +169 -0
  933. package/payload/platform/plugins/memory/mcp/dist/lib/compiled-truth-rewriter.js.map +1 -0
  934. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts +3 -0
  935. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.d.ts.map +1 -0
  936. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js +61 -0
  937. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/email.js.map +1 -0
  938. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts +7 -0
  939. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.d.ts.map +1 -0
  940. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js +36 -0
  941. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/index.js.map +1 -0
  942. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.d.ts +49 -0
  943. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.d.ts.map +1 -0
  944. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.js +35 -0
  945. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/timestamp-scanner.js.map +1 -0
  946. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts +47 -0
  947. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.d.ts.map +1 -0
  948. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js +38 -0
  949. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/types.js.map +1 -0
  950. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts +3 -0
  951. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.d.ts.map +1 -0
  952. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js +155 -0
  953. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/whatsapp-text.js.map +1 -0
  954. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.d.ts +3 -0
  955. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.d.ts.map +1 -0
  956. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js +101 -0
  957. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-normalisers/x-dm.js.map +1 -0
  958. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts +11 -0
  959. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.d.ts.map +1 -0
  960. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js +20 -0
  961. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/delta-cursor.js.map +1 -0
  962. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts +16 -0
  963. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.d.ts.map +1 -0
  964. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js +43 -0
  965. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/derive-keys.js.map +1 -0
  966. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts +16 -0
  967. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.d.ts.map +1 -0
  968. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js +60 -0
  969. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sender-bind.js.map +1 -0
  970. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts +9 -0
  971. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.d.ts.map +1 -0
  972. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js +32 -0
  973. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/sessionize.js.map +1 -0
  974. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts +3 -0
  975. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.d.ts.map +1 -0
  976. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js +29 -0
  977. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/to-turn-text.js.map +1 -0
  978. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.d.ts +8 -0
  979. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.d.ts.map +1 -0
  980. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.js +27 -0
  981. package/payload/platform/plugins/memory/mcp/dist/lib/conversation-pipeline/turn-text-cache-path.js.map +1 -0
  982. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts +45 -0
  983. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.d.ts.map +1 -0
  984. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js +125 -0
  985. package/payload/platform/plugins/memory/mcp/dist/lib/document-chunker.js.map +1 -0
  986. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.d.ts +9 -0
  987. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.d.ts.map +1 -0
  988. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.js +61 -0
  989. package/payload/platform/plugins/memory/mcp/dist/lib/document-hierarchy.js.map +1 -0
  990. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts +10 -0
  991. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.d.ts.map +1 -0
  992. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js +47 -0
  993. package/payload/platform/plugins/memory/mcp/dist/lib/document-sectioniser.js.map +1 -0
  994. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts +44 -0
  995. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.d.ts.map +1 -0
  996. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.js +14 -0
  997. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/index.js.map +1 -0
  998. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.d.ts +15 -0
  999. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.d.ts.map +1 -0
  1000. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.js +37 -0
  1001. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-backlinks.js.map +1 -0
  1002. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.d.ts +3 -0
  1003. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.d.ts.map +1 -0
  1004. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.js +16 -0
  1005. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-citation-audit.js.map +1 -0
  1006. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.d.ts +19 -0
  1007. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.d.ts.map +1 -0
  1008. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.js +39 -0
  1009. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-dead-edges.js.map +1 -0
  1010. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.d.ts +19 -0
  1011. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.d.ts.map +1 -0
  1012. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.js +42 -0
  1013. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-orphans.js.map +1 -0
  1014. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.d.ts +21 -0
  1015. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.d.ts.map +1 -0
  1016. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.js +27 -0
  1017. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-prune-revisions.js.map +1 -0
  1018. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.d.ts +18 -0
  1019. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.d.ts.map +1 -0
  1020. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.js +60 -0
  1021. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-stale-truth.js.map +1 -0
  1022. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.d.ts +25 -0
  1023. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.d.ts.map +1 -0
  1024. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.js +90 -0
  1025. package/payload/platform/plugins/memory/mcp/dist/lib/dream-cycle/phase-tag-normalisation.js.map +1 -0
  1026. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts +2 -0
  1027. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts.map +1 -0
  1028. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js +6 -0
  1029. package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js.map +1 -0
  1030. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.d.ts +36 -0
  1031. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.d.ts.map +1 -0
  1032. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.js +86 -0
  1033. package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.js.map +1 -0
  1034. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts +41 -0
  1035. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.d.ts.map +1 -0
  1036. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js +113 -0
  1037. package/payload/platform/plugins/memory/mcp/dist/lib/graph-prune.js.map +1 -0
  1038. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts +76 -0
  1039. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.d.ts.map +1 -0
  1040. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js +148 -0
  1041. package/payload/platform/plugins/memory/mcp/dist/lib/graph-write-gate.js.map +1 -0
  1042. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts +41 -0
  1043. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.d.ts.map +1 -0
  1044. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js +69 -0
  1045. package/payload/platform/plugins/memory/mcp/dist/lib/kd-classify-gate.js.map +1 -0
  1046. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts +18 -0
  1047. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.d.ts.map +1 -0
  1048. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js +31 -0
  1049. package/payload/platform/plugins/memory/mcp/dist/lib/label-delete-gate.js.map +1 -0
  1050. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts +18 -0
  1051. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts.map +1 -0
  1052. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js +35 -0
  1053. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js.map +1 -0
  1054. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.d.ts +119 -0
  1055. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.d.ts.map +1 -0
  1056. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.js +208 -0
  1057. package/payload/platform/plugins/memory/mcp/dist/lib/live-schema-source.js.map +1 -0
  1058. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts +248 -0
  1059. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.d.ts.map +1 -0
  1060. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js +824 -0
  1061. package/payload/platform/plugins/memory/mcp/dist/lib/llm-classifier.js.map +1 -0
  1062. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts +63 -0
  1063. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.d.ts.map +1 -0
  1064. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js +210 -0
  1065. package/payload/platform/plugins/memory/mcp/dist/lib/llm-ranker.js.map +1 -0
  1066. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.d.ts +65 -0
  1067. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.d.ts.map +1 -0
  1068. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js +182 -0
  1069. package/payload/platform/plugins/memory/mcp/dist/lib/log-ingest.js.map +1 -0
  1070. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +19 -0
  1071. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts.map +1 -0
  1072. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +76 -0
  1073. package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js.map +1 -0
  1074. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.d.ts +13 -0
  1075. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.d.ts.map +1 -0
  1076. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.js +191 -0
  1077. package/payload/platform/plugins/memory/mcp/dist/lib/relative-date.js.map +1 -0
  1078. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts +33 -0
  1079. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.d.ts.map +1 -0
  1080. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js +44 -0
  1081. package/payload/platform/plugins/memory/mcp/dist/lib/resolve-active-vertical.js.map +1 -0
  1082. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts +141 -0
  1083. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.d.ts.map +1 -0
  1084. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js +516 -0
  1085. package/payload/platform/plugins/memory/mcp/dist/lib/schema-loader.js.map +1 -0
  1086. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts +92 -0
  1087. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.d.ts.map +1 -0
  1088. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js +243 -0
  1089. package/payload/platform/plugins/memory/mcp/dist/lib/schema-validator.js.map +1 -0
  1090. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.d.ts +127 -0
  1091. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.d.ts.map +1 -0
  1092. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.js +56 -0
  1093. package/payload/platform/plugins/memory/mcp/dist/lib/section-types.js.map +1 -0
  1094. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts +19 -0
  1095. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.d.ts.map +1 -0
  1096. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js +179 -0
  1097. package/payload/platform/plugins/memory/mcp/dist/lib/timeline-extractor.js.map +1 -0
  1098. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts +35 -0
  1099. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.d.ts.map +1 -0
  1100. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js +28 -0
  1101. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-pass.js.map +1 -0
  1102. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.d.ts +29 -0
  1103. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.d.ts.map +1 -0
  1104. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js +142 -0
  1105. package/payload/platform/plugins/memory/mcp/dist/lib/typed-edge-schema.js.map +1 -0
  1106. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.d.ts +3 -0
  1107. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.d.ts.map +1 -0
  1108. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.js +12 -0
  1109. package/payload/platform/plugins/memory/mcp/dist/lib/uuid.js.map +1 -0
  1110. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.d.ts +22 -0
  1111. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.d.ts.map +1 -0
  1112. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.js +44 -0
  1113. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/_helpers/emit-capture.js.map +1 -0
  1114. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts +2 -0
  1115. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.d.ts.map +1 -0
  1116. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js +20 -0
  1117. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/build-text-representation-bound.test.js.map +1 -0
  1118. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts +2 -0
  1119. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.d.ts.map +1 -0
  1120. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js +68 -0
  1121. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights-emit.test.js.map +1 -0
  1122. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts +7 -0
  1123. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.d.ts.map +1 -0
  1124. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js +298 -0
  1125. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-derive-insights.test.js.map +1 -0
  1126. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.d.ts +2 -0
  1127. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.d.ts.map +1 -0
  1128. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.js +48 -0
  1129. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection-emit.test.js.map +1 -0
  1130. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.d.ts +2 -0
  1131. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.d.ts.map +1 -0
  1132. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js +184 -0
  1133. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-enrich-rejection.test.js.map +1 -0
  1134. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts +2 -0
  1135. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.d.ts.map +1 -0
  1136. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js +67 -0
  1137. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-archive-preference-embed.test.js.map +1 -0
  1138. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.d.ts +2 -0
  1139. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.d.ts.map +1 -0
  1140. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js +53 -0
  1141. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-memory-expunge-emit.test.js.map +1 -0
  1142. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts +2 -0
  1143. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.d.ts.map +1 -0
  1144. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js +75 -0
  1145. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-source-agnosticism.test.js.map +1 -0
  1146. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts +2 -0
  1147. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.d.ts.map +1 -0
  1148. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js +109 -0
  1149. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/conversation-normalisers-whatsapp-text.test.js.map +1 -0
  1150. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts +2 -0
  1151. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.d.ts.map +1 -0
  1152. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js +34 -0
  1153. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/embeddings-cap.test.js.map +1 -0
  1154. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.d.ts +2 -0
  1155. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.d.ts.map +1 -0
  1156. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.js +40 -0
  1157. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-add-emit.test.js.map +1 -0
  1158. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.d.ts +2 -0
  1159. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.d.ts.map +1 -0
  1160. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.js +39 -0
  1161. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/graph-prune-denylist-remove-emit.test.js.map +1 -0
  1162. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.d.ts +2 -0
  1163. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.d.ts.map +1 -0
  1164. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js +241 -0
  1165. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/log-ingest.test.js.map +1 -0
  1166. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts +2 -0
  1167. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.d.ts.map +1 -0
  1168. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js +61 -0
  1169. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-section-writer.test.js.map +1 -0
  1170. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts +2 -0
  1171. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.d.ts.map +1 -0
  1172. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js +88 -0
  1173. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write-emit.test.js.map +1 -0
  1174. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.d.ts +2 -0
  1175. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.d.ts.map +1 -0
  1176. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js +106 -0
  1177. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-archive-write.test.js.map +1 -0
  1178. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts +2 -0
  1179. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.d.ts.map +1 -0
  1180. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js +58 -0
  1181. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-classify-emit.test.js.map +1 -0
  1182. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.d.ts +2 -0
  1183. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.d.ts.map +1 -0
  1184. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js +129 -0
  1185. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-compiled-truth-history.test.js.map +1 -0
  1186. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts +2 -0
  1187. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.d.ts.map +1 -0
  1188. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js +64 -0
  1189. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-emit.test.js.map +1 -0
  1190. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts +2 -0
  1191. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.d.ts.map +1 -0
  1192. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js +141 -0
  1193. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-delete-reserved-label.test.js.map +1 -0
  1194. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.d.ts +2 -0
  1195. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.d.ts.map +1 -0
  1196. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.js +164 -0
  1197. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edge.test.js.map +1 -0
  1198. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts +2 -0
  1199. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.d.ts.map +1 -0
  1200. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js +70 -0
  1201. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-edit-attachment-emit.test.js.map +1 -0
  1202. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.d.ts +2 -0
  1203. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.d.ts.map +1 -0
  1204. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js +168 -0
  1205. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-admin-conversation.test.js.map +1 -0
  1206. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts +2 -0
  1207. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.d.ts.map +1 -0
  1208. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js +48 -0
  1209. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-emit.test.js.map +1 -0
  1210. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts +2 -0
  1211. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.d.ts.map +1 -0
  1212. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js +86 -0
  1213. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-empty-trash-reserved-label.test.js.map +1 -0
  1214. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.d.ts +2 -0
  1215. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.d.ts.map +1 -0
  1216. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.js +95 -0
  1217. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.js.map +1 -0
  1218. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.d.ts +2 -0
  1219. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.d.ts.map +1 -0
  1220. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.js +124 -0
  1221. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-chat-body-server-sliced.test.js.map +1 -0
  1222. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts +2 -0
  1223. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.d.ts.map +1 -0
  1224. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js +74 -0
  1225. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-emit.test.js.map +1 -0
  1226. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts +2 -0
  1227. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.d.ts.map +1 -0
  1228. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js +47 -0
  1229. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-extract-emit.test.js.map +1 -0
  1230. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.d.ts +2 -0
  1231. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.d.ts.map +1 -0
  1232. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.js +66 -0
  1233. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-inline-rewrite.test.js.map +1 -0
  1234. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.d.ts +2 -0
  1235. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.d.ts.map +1 -0
  1236. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.js +104 -0
  1237. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-section-properties-strip.test.js.map +1 -0
  1238. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts +2 -0
  1239. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.d.ts.map +1 -0
  1240. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js +65 -0
  1241. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-web-emit.test.js.map +1 -0
  1242. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts +2 -0
  1243. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.d.ts.map +1 -0
  1244. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js +175 -0
  1245. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest.test.js.map +1 -0
  1246. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.d.ts +2 -0
  1247. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.d.ts.map +1 -0
  1248. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js +135 -0
  1249. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js.map +1 -0
  1250. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts +2 -0
  1251. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.d.ts.map +1 -0
  1252. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js +43 -0
  1253. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex-emit.test.js.map +1 -0
  1254. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts +2 -0
  1255. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.d.ts.map +1 -0
  1256. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js +87 -0
  1257. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-reindex.test.js.map +1 -0
  1258. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts +2 -0
  1259. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.d.ts.map +1 -0
  1260. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js +65 -0
  1261. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-rename-attachment-emit.test.js.map +1 -0
  1262. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.d.ts +2 -0
  1263. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.d.ts.map +1 -0
  1264. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js +115 -0
  1265. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-report-tools.test.js.map +1 -0
  1266. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts +2 -0
  1267. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.d.ts.map +1 -0
  1268. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js +49 -0
  1269. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-restore-emit.test.js.map +1 -0
  1270. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts +2 -0
  1271. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.d.ts.map +1 -0
  1272. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js +128 -0
  1273. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-fields.test.js.map +1 -0
  1274. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts +2 -0
  1275. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.d.ts.map +1 -0
  1276. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js +34 -0
  1277. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-search-threshold.test.js.map +1 -0
  1278. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.d.ts +2 -0
  1279. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.d.ts.map +1 -0
  1280. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.js +125 -0
  1281. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-by-name.test.js.map +1 -0
  1282. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts +2 -0
  1283. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.d.ts.map +1 -0
  1284. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +79 -0
  1285. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -0
  1286. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.d.ts +2 -0
  1287. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.d.ts.map +1 -0
  1288. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.js +329 -0
  1289. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-operator-hint.test.js.map +1 -0
  1290. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.d.ts +2 -0
  1291. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.d.ts.map +1 -0
  1292. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.js +39 -0
  1293. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-compiled-truth-rejection.test.js.map +1 -0
  1294. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts +2 -0
  1295. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.d.ts.map +1 -0
  1296. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +81 -0
  1297. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -0
  1298. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.d.ts +2 -0
  1299. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.d.ts.map +1 -0
  1300. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.js +30 -0
  1301. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-timeline-learned-at.test.js.map +1 -0
  1302. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.d.ts +2 -0
  1303. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.d.ts.map +1 -0
  1304. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.js +62 -0
  1305. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-delete-emit.test.js.map +1 -0
  1306. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.d.ts +2 -0
  1307. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.d.ts.map +1 -0
  1308. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.js +76 -0
  1309. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-emit.test.js.map +1 -0
  1310. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.d.ts +2 -0
  1311. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.d.ts.map +1 -0
  1312. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js +88 -0
  1313. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-not-applicable.test.js.map +1 -0
  1314. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts +2 -0
  1315. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.d.ts.map +1 -0
  1316. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js +149 -0
  1317. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/profile-update-personfields-open.test.js.map +1 -0
  1318. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts +114 -0
  1319. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.d.ts.map +1 -0
  1320. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js +415 -0
  1321. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-derive-insights.js.map +1 -0
  1322. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.d.ts +41 -0
  1323. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.d.ts.map +1 -0
  1324. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.js +124 -0
  1325. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-enrich-rejection.js.map +1 -0
  1326. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts +43 -0
  1327. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.d.ts.map +1 -0
  1328. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js +96 -0
  1329. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-archive-list-chunks.js.map +1 -0
  1330. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts +8 -0
  1331. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.d.ts.map +1 -0
  1332. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js +15 -0
  1333. package/payload/platform/plugins/memory/mcp/dist/tools/conversation-memory-expunge.js.map +1 -0
  1334. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.d.ts +7 -0
  1335. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.d.ts.map +1 -0
  1336. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.js +32 -0
  1337. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-add.js.map +1 -0
  1338. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.d.ts +7 -0
  1339. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.d.ts.map +1 -0
  1340. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.js +7 -0
  1341. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-list.js.map +1 -0
  1342. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.d.ts +7 -0
  1343. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.d.ts.map +1 -0
  1344. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.js +31 -0
  1345. package/payload/platform/plugins/memory/mcp/dist/tools/graph-prune-denylist-remove.js.map +1 -0
  1346. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.d.ts +15 -0
  1347. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.d.ts.map +1 -0
  1348. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.js +64 -0
  1349. package/payload/platform/plugins/memory/mcp/dist/tools/image-fetch.js.map +1 -0
  1350. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts +6 -0
  1351. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.d.ts.map +1 -0
  1352. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js +73 -0
  1353. package/payload/platform/plugins/memory/mcp/dist/tools/kd-classify.js.map +1 -0
  1354. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts +202 -0
  1355. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.d.ts.map +1 -0
  1356. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js +1084 -0
  1357. package/payload/platform/plugins/memory/mcp/dist/tools/memory-archive-write.js.map +1 -0
  1358. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts +35 -0
  1359. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.d.ts.map +1 -0
  1360. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js +80 -0
  1361. package/payload/platform/plugins/memory/mcp/dist/tools/memory-brain-capture-recent.js.map +1 -0
  1362. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.d.ts +34 -0
  1363. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.d.ts.map +1 -0
  1364. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.js +62 -0
  1365. package/payload/platform/plugins/memory/mcp/dist/tools/memory-classify.js.map +1 -0
  1366. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts +41 -0
  1367. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.d.ts.map +1 -0
  1368. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js +73 -0
  1369. package/payload/platform/plugins/memory/mcp/dist/tools/memory-compiled-truth-history.js.map +1 -0
  1370. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts +65 -0
  1371. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts.map +1 -0
  1372. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js +151 -0
  1373. package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js.map +1 -0
  1374. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts +48 -0
  1375. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.d.ts.map +1 -0
  1376. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js +197 -0
  1377. package/payload/platform/plugins/memory/mcp/dist/tools/memory-dream-run.js.map +1 -0
  1378. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.d.ts +21 -0
  1379. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.d.ts.map +1 -0
  1380. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.js +51 -0
  1381. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edge.js.map +1 -0
  1382. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.d.ts +16 -0
  1383. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.d.ts.map +1 -0
  1384. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.js +95 -0
  1385. package/payload/platform/plugins/memory/mcp/dist/tools/memory-edit-attachment.js.map +1 -0
  1386. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts +50 -0
  1387. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.d.ts.map +1 -0
  1388. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js +104 -0
  1389. package/payload/platform/plugins/memory/mcp/dist/tools/memory-empty-trash.js.map +1 -0
  1390. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts +58 -0
  1391. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts.map +1 -0
  1392. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js +125 -0
  1393. package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js.map +1 -0
  1394. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.d.ts +37 -0
  1395. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.d.ts.map +1 -0
  1396. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.js +97 -0
  1397. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-extract.js.map +1 -0
  1398. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.d.ts +32 -0
  1399. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.d.ts.map +1 -0
  1400. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.js +116 -0
  1401. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest-web.js.map +1 -0
  1402. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts +194 -0
  1403. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -0
  1404. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +1273 -0
  1405. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -0
  1406. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.d.ts +19 -0
  1407. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.d.ts.map +1 -0
  1408. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.js +125 -0
  1409. package/payload/platform/plugins/memory/mcp/dist/tools/memory-list-attachments.js.map +1 -0
  1410. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.d.ts +16 -0
  1411. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.d.ts.map +1 -0
  1412. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js +56 -0
  1413. package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js.map +1 -0
  1414. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts +28 -0
  1415. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.d.ts.map +1 -0
  1416. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js +46 -0
  1417. package/payload/platform/plugins/memory/mcp/dist/tools/memory-node-exists.js.map +1 -0
  1418. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.d.ts +61 -0
  1419. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.d.ts.map +1 -0
  1420. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js +102 -0
  1421. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rank.js.map +1 -0
  1422. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.d.ts +12 -0
  1423. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.d.ts.map +1 -0
  1424. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.js +100 -0
  1425. package/payload/platform/plugins/memory/mcp/dist/tools/memory-read-attachment.js.map +1 -0
  1426. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts +9 -0
  1427. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -0
  1428. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +127 -0
  1429. package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -0
  1430. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.d.ts +13 -0
  1431. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.d.ts.map +1 -0
  1432. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.js +67 -0
  1433. package/payload/platform/plugins/memory/mcp/dist/tools/memory-rename-attachment.js.map +1 -0
  1434. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.d.ts +28 -0
  1435. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.d.ts.map +1 -0
  1436. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.js +64 -0
  1437. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-list.js.map +1 -0
  1438. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.d.ts +24 -0
  1439. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.d.ts.map +1 -0
  1440. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.js +49 -0
  1441. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-read-latest.js.map +1 -0
  1442. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts +34 -0
  1443. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.d.ts.map +1 -0
  1444. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js +99 -0
  1445. package/payload/platform/plugins/memory/mcp/dist/tools/memory-report-write.js.map +1 -0
  1446. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.d.ts +24 -0
  1447. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.d.ts.map +1 -0
  1448. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.js +47 -0
  1449. package/payload/platform/plugins/memory/mcp/dist/tools/memory-restore.js.map +1 -0
  1450. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts +29 -0
  1451. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.d.ts.map +1 -0
  1452. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js +67 -0
  1453. package/payload/platform/plugins/memory/mcp/dist/tools/memory-review-queue.js.map +1 -0
  1454. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +7 -0
  1455. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -0
  1456. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +184 -0
  1457. package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -0
  1458. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.d.ts +35 -0
  1459. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.d.ts.map +1 -0
  1460. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.js +73 -0
  1461. package/payload/platform/plugins/memory/mcp/dist/tools/memory-signals-recent.js.map +1 -0
  1462. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts +29 -0
  1463. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.d.ts.map +1 -0
  1464. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js +22 -0
  1465. package/payload/platform/plugins/memory/mcp/dist/tools/memory-typed-edge-pass.js.map +1 -0
  1466. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.d.ts +15 -0
  1467. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.d.ts.map +1 -0
  1468. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.js +45 -0
  1469. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update-by-name.js.map +1 -0
  1470. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts +16 -0
  1471. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -0
  1472. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +194 -0
  1473. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -0
  1474. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +47 -0
  1475. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -0
  1476. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +376 -0
  1477. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -0
  1478. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts +127 -0
  1479. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.d.ts.map +1 -0
  1480. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js +477 -0
  1481. package/payload/platform/plugins/memory/mcp/dist/tools/obsidian-vault-import.js.map +1 -0
  1482. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.d.ts +24 -0
  1483. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.d.ts.map +1 -0
  1484. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.js +35 -0
  1485. package/payload/platform/plugins/memory/mcp/dist/tools/profile-delete.js.map +1 -0
  1486. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.d.ts +46 -0
  1487. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.d.ts.map +1 -0
  1488. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js +423 -0
  1489. package/payload/platform/plugins/memory/mcp/dist/tools/profile-read.js.map +1 -0
  1490. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +65 -0
  1491. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -0
  1492. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +395 -0
  1493. package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -0
  1494. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts +30 -0
  1495. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.d.ts.map +1 -0
  1496. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js +130 -0
  1497. package/payload/platform/plugins/memory/mcp/dist/tools/session-retrospective-skip-rate.js.map +1 -0
  1498. package/payload/platform/plugins/memory/mcp/package.json +23 -0
  1499. package/payload/platform/plugins/memory/mcp/scripts/backfill-typed-edges.ts +72 -0
  1500. package/payload/platform/plugins/memory/mcp/scripts/boot-smoke.sh +69 -0
  1501. package/payload/platform/plugins/memory/mcp/scripts/generate-edge-docs.ts +75 -0
  1502. package/payload/platform/plugins/memory/mcp/scripts/graph/accept.sh +217 -0
  1503. package/payload/platform/plugins/memory/mcp/scripts/graph/fixture.cypher +59 -0
  1504. package/payload/platform/plugins/memory/mcp/vitest.config.ts +48 -0
  1505. package/payload/platform/plugins/memory/references/graph-primitives.md +394 -0
  1506. package/payload/platform/plugins/memory/references/schema-base.md +334 -0
  1507. package/payload/platform/plugins/memory/references/schema-construction.md +72 -0
  1508. package/payload/platform/plugins/memory/references/schema-creator.md +35 -0
  1509. package/payload/platform/plugins/memory/references/schema-estate-agent.md +110 -0
  1510. package/payload/platform/plugins/memory/references/schema-food-beverage.md +32 -0
  1511. package/payload/platform/plugins/memory/references/schema-hospitality.md +31 -0
  1512. package/payload/platform/plugins/memory/references/schema-logistics.md +30 -0
  1513. package/payload/platform/plugins/memory/references/schema-professional-services.md +33 -0
  1514. package/payload/platform/plugins/memory/references/schema-retail.md +33 -0
  1515. package/payload/platform/plugins/memory/references/schema-trades.md +36 -0
  1516. package/payload/platform/plugins/memory/references/transcript-formats/circleback.md +49 -0
  1517. package/payload/platform/plugins/memory/references/transcript-formats/granola.md +50 -0
  1518. package/payload/platform/plugins/memory/references/transcript-formats/otter.md +50 -0
  1519. package/payload/platform/plugins/memory/skills/archive-crawler/SKILL.md +67 -0
  1520. package/payload/platform/plugins/memory/skills/challenge/SKILL.md +52 -0
  1521. package/payload/platform/plugins/memory/skills/concept-synthesis/SKILL.md +79 -0
  1522. package/payload/platform/plugins/memory/skills/connect/SKILL.md +56 -0
  1523. package/payload/platform/plugins/memory/skills/conversation-archive/SKILL.md +193 -0
  1524. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +207 -0
  1525. package/payload/platform/plugins/memory/skills/conversation-archive-mcp/SKILL.md +170 -0
  1526. package/payload/platform/plugins/memory/skills/conversational-memory/SKILL.md +113 -0
  1527. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +331 -0
  1528. package/payload/platform/plugins/memory/skills/emerge/SKILL.md +87 -0
  1529. package/payload/platform/plugins/notion-import/.claude-plugin/plugin.json +8 -0
  1530. package/payload/platform/plugins/notion-import/PLUGIN.md +27 -0
  1531. package/payload/platform/plugins/notion-import/skills/notion-import/SKILL.md +114 -0
  1532. package/payload/platform/plugins/notion-import/skills/notion-import/references/attachments.md +55 -0
  1533. package/payload/platform/plugins/notion-import/skills/notion-import/references/databases.md +83 -0
  1534. package/payload/platform/plugins/notion-import/skills/notion-import/references/page-tree.md +61 -0
  1535. package/payload/platform/plugins/notion-import/skills/notion-import/references/workspace-export.md +41 -0
  1536. package/payload/platform/plugins/obsidian-import/.claude-plugin/plugin.json +8 -0
  1537. package/payload/platform/plugins/obsidian-import/PLUGIN.md +39 -0
  1538. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/SKILL.md +92 -0
  1539. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/attachments.md +80 -0
  1540. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/daily-notes.md +31 -0
  1541. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/vault-structure.md +46 -0
  1542. package/payload/platform/plugins/obsidian-import/skills/obsidian-import/references/wikilinks.md +70 -0
  1543. package/payload/platform/plugins/outlook/.claude-plugin/plugin.json +17 -0
  1544. package/payload/platform/plugins/outlook/PLUGIN.md +74 -0
  1545. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.d.ts +2 -0
  1546. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.d.ts.map +1 -0
  1547. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js +94 -0
  1548. package/payload/platform/plugins/outlook/mcp/dist/__tests__/graph-client.test.js.map +1 -0
  1549. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.d.ts +2 -0
  1550. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.d.ts.map +1 -0
  1551. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.js +31 -0
  1552. package/payload/platform/plugins/outlook/mcp/dist/__tests__/log.test.js.map +1 -0
  1553. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.d.ts +2 -0
  1554. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.d.ts.map +1 -0
  1555. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js +213 -0
  1556. package/payload/platform/plugins/outlook/mcp/dist/__tests__/pkce-flow.test.js.map +1 -0
  1557. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.d.ts +2 -0
  1558. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.d.ts.map +1 -0
  1559. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js +130 -0
  1560. package/payload/platform/plugins/outlook/mcp/dist/__tests__/token-store.test.js.map +1 -0
  1561. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts +65 -0
  1562. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.d.ts.map +1 -0
  1563. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js +261 -0
  1564. package/payload/platform/plugins/outlook/mcp/dist/auth/pkce-flow.js.map +1 -0
  1565. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts +61 -0
  1566. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.d.ts.map +1 -0
  1567. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js +170 -0
  1568. package/payload/platform/plugins/outlook/mcp/dist/auth/token-store.js.map +1 -0
  1569. package/payload/platform/plugins/outlook/mcp/dist/index.d.ts +18 -0
  1570. package/payload/platform/plugins/outlook/mcp/dist/index.d.ts.map +1 -0
  1571. package/payload/platform/plugins/outlook/mcp/dist/index.js +183 -0
  1572. package/payload/platform/plugins/outlook/mcp/dist/index.js.map +1 -0
  1573. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts +60 -0
  1574. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.d.ts.map +1 -0
  1575. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js +189 -0
  1576. package/payload/platform/plugins/outlook/mcp/dist/lib/graph-client.js.map +1 -0
  1577. package/payload/platform/plugins/outlook/mcp/dist/lib/log.d.ts +23 -0
  1578. package/payload/platform/plugins/outlook/mcp/dist/lib/log.d.ts.map +1 -0
  1579. package/payload/platform/plugins/outlook/mcp/dist/lib/log.js +53 -0
  1580. package/payload/platform/plugins/outlook/mcp/dist/lib/log.js.map +1 -0
  1581. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts +26 -0
  1582. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.d.ts.map +1 -0
  1583. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js +50 -0
  1584. package/payload/platform/plugins/outlook/mcp/dist/tools/account-register.js.map +1 -0
  1585. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.d.ts +12 -0
  1586. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.d.ts.map +1 -0
  1587. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.js +32 -0
  1588. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-event.js.map +1 -0
  1589. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.d.ts +59 -0
  1590. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.d.ts.map +1 -0
  1591. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.js +54 -0
  1592. package/payload/platform/plugins/outlook/mcp/dist/tools/calendar-list.js.map +1 -0
  1593. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.d.ts +14 -0
  1594. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.d.ts.map +1 -0
  1595. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.js +45 -0
  1596. package/payload/platform/plugins/outlook/mcp/dist/tools/contacts-list.js.map +1 -0
  1597. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts +15 -0
  1598. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.d.ts.map +1 -0
  1599. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js +48 -0
  1600. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-list.js.map +1 -0
  1601. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts +8 -0
  1602. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.d.ts.map +1 -0
  1603. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js +49 -0
  1604. package/payload/platform/plugins/outlook/mcp/dist/tools/mail-search.js.map +1 -0
  1605. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts +19 -0
  1606. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.d.ts.map +1 -0
  1607. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js +58 -0
  1608. package/payload/platform/plugins/outlook/mcp/dist/tools/mailbox-info.js.map +1 -0
  1609. package/payload/platform/plugins/outlook/mcp/package.json +20 -0
  1610. package/payload/platform/plugins/outlook/mcp/scripts/verify-doc-impl.sh +109 -0
  1611. package/payload/platform/plugins/outlook/references/auth.md +118 -0
  1612. package/payload/platform/plugins/outlook/references/graph-surfaces.md +114 -0
  1613. package/payload/platform/plugins/outlook/skills/outlook/SKILL.md +65 -0
  1614. package/payload/platform/plugins/projects/.claude-plugin/plugin.json +8 -0
  1615. package/payload/platform/plugins/projects/PLUGIN.md +90 -0
  1616. package/payload/platform/plugins/projects/references/investigation.md +63 -0
  1617. package/payload/platform/plugins/projects/references/retrospective.md +71 -0
  1618. package/payload/platform/plugins/projects/references/review.md +51 -0
  1619. package/payload/platform/plugins/projects/references/sprint.md +168 -0
  1620. package/payload/platform/plugins/prompt-optimiser/.claude-plugin/plugin.json +8 -0
  1621. package/payload/platform/plugins/prompt-optimiser/PLUGIN.md +14 -0
  1622. package/payload/platform/plugins/prompt-optimiser/skills/prompt-optimiser/SKILL.md +318 -0
  1623. package/payload/platform/plugins/replicate/.claude-plugin/plugin.json +17 -0
  1624. package/payload/platform/plugins/replicate/PLUGIN.md +49 -0
  1625. package/payload/platform/plugins/replicate/mcp/dist/index.d.ts +2 -0
  1626. package/payload/platform/plugins/replicate/mcp/dist/index.d.ts.map +1 -0
  1627. package/payload/platform/plugins/replicate/mcp/dist/index.js +125 -0
  1628. package/payload/platform/plugins/replicate/mcp/dist/index.js.map +1 -0
  1629. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.d.ts +15 -0
  1630. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.d.ts.map +1 -0
  1631. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.js +73 -0
  1632. package/payload/platform/plugins/replicate/mcp/dist/lib/replicate-key.js.map +1 -0
  1633. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.d.ts +14 -0
  1634. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.d.ts.map +1 -0
  1635. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.js +201 -0
  1636. package/payload/platform/plugins/replicate/mcp/dist/tools/image-generate.js.map +1 -0
  1637. package/payload/platform/plugins/replicate/mcp/package.json +21 -0
  1638. package/payload/platform/plugins/sales/.claude-plugin/plugin.json +8 -0
  1639. package/payload/platform/plugins/sales/PLUGIN.md +106 -0
  1640. package/payload/platform/plugins/sales/references/close-tracking.md +69 -0
  1641. package/payload/platform/plugins/sales/references/comparisons.md +99 -0
  1642. package/payload/platform/plugins/sales/references/competitive-positioning.md +51 -0
  1643. package/payload/platform/plugins/sales/references/faq.md +73 -0
  1644. package/payload/platform/plugins/sales/references/objection-handling.md +157 -0
  1645. package/payload/platform/plugins/sales/references/pricing.md +101 -0
  1646. package/payload/platform/plugins/scheduling/.claude-plugin/plugin.json +17 -0
  1647. package/payload/platform/plugins/scheduling/PLUGIN.md +153 -0
  1648. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.d.ts +2 -0
  1649. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.d.ts.map +1 -0
  1650. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.js +16 -0
  1651. package/payload/platform/plugins/scheduling/mcp/dist/__tests__/time-resolve-description.test.js.map +1 -0
  1652. package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts +2 -0
  1653. package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts.map +1 -0
  1654. package/payload/platform/plugins/scheduling/mcp/dist/index.js +440 -0
  1655. package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -0
  1656. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.d.ts +2 -0
  1657. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.d.ts.map +1 -0
  1658. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.js +119 -0
  1659. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/getUserTimezone.test.js.map +1 -0
  1660. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.d.ts +2 -0
  1661. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.d.ts.map +1 -0
  1662. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.js +19 -0
  1663. package/payload/platform/plugins/scheduling/mcp/dist/lib/embedding.js.map +1 -0
  1664. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts +80 -0
  1665. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.d.ts.map +1 -0
  1666. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js +410 -0
  1667. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics-graph-ingest.js.map +1 -0
  1668. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.d.ts +63 -0
  1669. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.d.ts.map +1 -0
  1670. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.js +471 -0
  1671. package/payload/platform/plugins/scheduling/mcp/dist/lib/ics.js.map +1 -0
  1672. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.d.ts +30 -0
  1673. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.d.ts.map +1 -0
  1674. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.js +89 -0
  1675. package/payload/platform/plugins/scheduling/mcp/dist/lib/neo4j.js.map +1 -0
  1676. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.d.ts +48 -0
  1677. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.d.ts.map +1 -0
  1678. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.js +140 -0
  1679. package/payload/platform/plugins/scheduling/mcp/dist/lib/time-format.js.map +1 -0
  1680. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts +24 -0
  1681. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.d.ts.map +1 -0
  1682. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +572 -0
  1683. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -0
  1684. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.d.ts +20 -0
  1685. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.d.ts.map +1 -0
  1686. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.js +63 -0
  1687. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-archive-ics.js.map +1 -0
  1688. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts +7 -0
  1689. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.d.ts.map +1 -0
  1690. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js +23 -0
  1691. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-cancel.js.map +1 -0
  1692. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts +25 -0
  1693. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -0
  1694. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +121 -0
  1695. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -0
  1696. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.d.ts +9 -0
  1697. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.d.ts.map +1 -0
  1698. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.js +77 -0
  1699. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.js.map +1 -0
  1700. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts +25 -0
  1701. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.d.ts.map +1 -0
  1702. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js +53 -0
  1703. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-get.js.map +1 -0
  1704. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.d.ts +8 -0
  1705. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.d.ts.map +1 -0
  1706. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.js +48 -0
  1707. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-import-ics.js.map +1 -0
  1708. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.d.ts +20 -0
  1709. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.d.ts.map +1 -0
  1710. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js +76 -0
  1711. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-list.js.map +1 -0
  1712. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts +18 -0
  1713. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.d.ts.map +1 -0
  1714. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js +167 -0
  1715. package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-update.js.map +1 -0
  1716. package/payload/platform/plugins/scheduling/mcp/package.json +23 -0
  1717. package/payload/platform/plugins/scheduling/mcp/vitest.config.ts +9 -0
  1718. package/payload/platform/plugins/scheduling/skills/briefing/SKILL.md +86 -0
  1719. package/payload/platform/plugins/scheduling/skills/daily-prep/SKILL.md +61 -0
  1720. package/payload/platform/plugins/slides/.claude-plugin/plugin.json +8 -0
  1721. package/payload/platform/plugins/slides/LICENSE +21 -0
  1722. package/payload/platform/plugins/slides/PLUGIN.md +18 -0
  1723. package/payload/platform/plugins/slides/PROVENANCE.md +40 -0
  1724. package/payload/platform/plugins/slides/commands/add-slide.md +29 -0
  1725. package/payload/platform/plugins/slides/commands/slides-claus.md +39 -0
  1726. package/payload/platform/plugins/slides/commands/slides-new-component.md +39 -0
  1727. package/payload/platform/plugins/slides/commands/slides-outline.md +43 -0
  1728. package/payload/platform/plugins/slides/commands/slides-review.md +52 -0
  1729. package/payload/platform/plugins/slides/commands/slides-theme.md +64 -0
  1730. package/payload/platform/plugins/slides/commands/slides.md +59 -0
  1731. package/payload/platform/plugins/slides/skills/deck-system/REFERENCE.md +581 -0
  1732. package/payload/platform/plugins/slides/skills/deck-system/SKILL.md +607 -0
  1733. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-board.md +426 -0
  1734. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-claus.md +185 -0
  1735. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-mbb.md +450 -0
  1736. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-product-launch.md +579 -0
  1737. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sales.md +464 -0
  1738. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING-sequoia.md +489 -0
  1739. package/payload/platform/plugins/slides/skills/deck-system/STORYTELLING.md +273 -0
  1740. package/payload/platform/plugins/slides/skills/deck-system/deck-craft.html +1371 -0
  1741. package/payload/platform/plugins/slides/skills/deck-system/deck-solid.html +1667 -0
  1742. package/payload/platform/plugins/slides/skills/deck-system/deck.html +1359 -0
  1743. package/payload/platform/plugins/substack-import/.claude-plugin/plugin.json +8 -0
  1744. package/payload/platform/plugins/substack-import/PLUGIN.md +34 -0
  1745. package/payload/platform/plugins/substack-import/skills/substack-import/SKILL.md +183 -0
  1746. package/payload/platform/plugins/substack-import/skills/substack-import/references/archive-shape.md +68 -0
  1747. package/payload/platform/plugins/substack-import/skills/substack-import/references/attachments.md +72 -0
  1748. package/payload/platform/plugins/substack-import/skills/substack-import/references/engagement.md +61 -0
  1749. package/payload/platform/plugins/substack-import/skills/substack-import/references/posts.md +80 -0
  1750. package/payload/platform/plugins/substack-import/skills/substack-import/references/subscribers.md +74 -0
  1751. package/payload/platform/plugins/telegram/.claude-plugin/plugin.json +17 -0
  1752. package/payload/platform/plugins/telegram/PLUGIN.md +53 -0
  1753. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts +2 -0
  1754. package/payload/platform/plugins/telegram/mcp/dist/index.d.ts.map +1 -0
  1755. package/payload/platform/plugins/telegram/mcp/dist/index.js +198 -0
  1756. package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -0
  1757. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts +41 -0
  1758. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts.map +1 -0
  1759. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js +70 -0
  1760. package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js.map +1 -0
  1761. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts +16 -0
  1762. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts.map +1 -0
  1763. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +68 -0
  1764. package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -0
  1765. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts +20 -0
  1766. package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -0
  1767. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +34 -0
  1768. package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -0
  1769. package/payload/platform/plugins/telegram/mcp/package.json +19 -0
  1770. package/payload/platform/plugins/telegram/references/setup-guide.md +50 -0
  1771. package/payload/platform/plugins/url-get/.claude-plugin/plugin.json +17 -0
  1772. package/payload/platform/plugins/url-get/PLUGIN.md +91 -0
  1773. package/payload/platform/plugins/url-get/mcp/dist/index.d.ts +9 -0
  1774. package/payload/platform/plugins/url-get/mcp/dist/index.d.ts.map +1 -0
  1775. package/payload/platform/plugins/url-get/mcp/dist/index.js +53 -0
  1776. package/payload/platform/plugins/url-get/mcp/dist/index.js.map +1 -0
  1777. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts +8 -0
  1778. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.d.ts.map +1 -0
  1779. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js +83 -0
  1780. package/payload/platform/plugins/url-get/mcp/dist/lib/summarise.js.map +1 -0
  1781. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts +21 -0
  1782. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.d.ts.map +1 -0
  1783. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js +133 -0
  1784. package/payload/platform/plugins/url-get/mcp/dist/tools/url-get.js.map +1 -0
  1785. package/payload/platform/plugins/url-get/mcp/package.json +22 -0
  1786. package/payload/platform/plugins/whatsapp/.claude-plugin/plugin.json +17 -0
  1787. package/payload/platform/plugins/whatsapp/PLUGIN.md +108 -0
  1788. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.d.ts +2 -0
  1789. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.d.ts.map +1 -0
  1790. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.js +58 -0
  1791. package/payload/platform/plugins/whatsapp/mcp/dist/__tests__/boot-without-env.test.js.map +1 -0
  1792. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts +14 -0
  1793. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.d.ts.map +1 -0
  1794. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js +42 -0
  1795. package/payload/platform/plugins/whatsapp/mcp/dist/call-api.js.map +1 -0
  1796. package/payload/platform/plugins/whatsapp/mcp/dist/index.d.ts +8 -0
  1797. package/payload/platform/plugins/whatsapp/mcp/dist/index.d.ts.map +1 -0
  1798. package/payload/platform/plugins/whatsapp/mcp/dist/index.js +489 -0
  1799. package/payload/platform/plugins/whatsapp/mcp/dist/index.js.map +1 -0
  1800. package/payload/platform/plugins/whatsapp/mcp/package.json +21 -0
  1801. package/payload/platform/plugins/whatsapp/mcp/vitest.config.ts +9 -0
  1802. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +256 -0
  1803. package/payload/platform/plugins/whatsapp/skills/connect-whatsapp/SKILL.md +82 -0
  1804. package/payload/platform/plugins/whatsapp/skills/manage-whatsapp-config/SKILL.md +93 -0
  1805. package/payload/platform/plugins/work/.claude-plugin/plugin.json +17 -0
  1806. package/payload/platform/plugins/work/.mcp.json +13 -0
  1807. package/payload/platform/plugins/work/PLUGIN.md +124 -0
  1808. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts +2 -0
  1809. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.d.ts.map +1 -0
  1810. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js +78 -0
  1811. package/payload/platform/plugins/work/mcp/dist/cli/project-create-cli.js.map +1 -0
  1812. package/payload/platform/plugins/work/mcp/dist/index.d.ts +2 -0
  1813. package/payload/platform/plugins/work/mcp/dist/index.d.ts.map +1 -0
  1814. package/payload/platform/plugins/work/mcp/dist/index.js +547 -0
  1815. package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -0
  1816. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts +7 -0
  1817. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.d.ts.map +1 -0
  1818. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js +24 -0
  1819. package/payload/platform/plugins/work/mcp/dist/lib/embeddings.js.map +1 -0
  1820. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.d.ts +5 -0
  1821. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.d.ts.map +1 -0
  1822. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.js +40 -0
  1823. package/payload/platform/plugins/work/mcp/dist/lib/neo4j.js.map +1 -0
  1824. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.d.ts +17 -0
  1825. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.d.ts.map +1 -0
  1826. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.js +76 -0
  1827. package/payload/platform/plugins/work/mcp/dist/tools/project-complete.js.map +1 -0
  1828. package/payload/platform/plugins/work/mcp/dist/tools/project-create.d.ts +29 -0
  1829. package/payload/platform/plugins/work/mcp/dist/tools/project-create.d.ts.map +1 -0
  1830. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js +235 -0
  1831. package/payload/platform/plugins/work/mcp/dist/tools/project-create.js.map +1 -0
  1832. package/payload/platform/plugins/work/mcp/dist/tools/project-get.d.ts +40 -0
  1833. package/payload/platform/plugins/work/mcp/dist/tools/project-get.d.ts.map +1 -0
  1834. package/payload/platform/plugins/work/mcp/dist/tools/project-get.js +125 -0
  1835. package/payload/platform/plugins/work/mcp/dist/tools/project-get.js.map +1 -0
  1836. package/payload/platform/plugins/work/mcp/dist/tools/project-list.d.ts +26 -0
  1837. package/payload/platform/plugins/work/mcp/dist/tools/project-list.d.ts.map +1 -0
  1838. package/payload/platform/plugins/work/mcp/dist/tools/project-list.js +81 -0
  1839. package/payload/platform/plugins/work/mcp/dist/tools/project-list.js.map +1 -0
  1840. package/payload/platform/plugins/work/mcp/dist/tools/project-update.d.ts +19 -0
  1841. package/payload/platform/plugins/work/mcp/dist/tools/project-update.d.ts.map +1 -0
  1842. package/payload/platform/plugins/work/mcp/dist/tools/project-update.js +102 -0
  1843. package/payload/platform/plugins/work/mcp/dist/tools/project-update.js.map +1 -0
  1844. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts +20 -0
  1845. package/payload/platform/plugins/work/mcp/dist/tools/session-list.d.ts.map +1 -0
  1846. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js +37 -0
  1847. package/payload/platform/plugins/work/mcp/dist/tools/session-list.js.map +1 -0
  1848. package/payload/platform/plugins/work/mcp/dist/tools/session-name.d.ts +12 -0
  1849. package/payload/platform/plugins/work/mcp/dist/tools/session-name.d.ts.map +1 -0
  1850. package/payload/platform/plugins/work/mcp/dist/tools/session-name.js +28 -0
  1851. package/payload/platform/plugins/work/mcp/dist/tools/session-name.js.map +1 -0
  1852. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.d.ts +16 -0
  1853. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.d.ts.map +1 -0
  1854. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.js +33 -0
  1855. package/payload/platform/plugins/work/mcp/dist/tools/work-complete.js.map +1 -0
  1856. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts +63 -0
  1857. package/payload/platform/plugins/work/mcp/dist/tools/work-create.d.ts.map +1 -0
  1858. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js +141 -0
  1859. package/payload/platform/plugins/work/mcp/dist/tools/work-create.js.map +1 -0
  1860. package/payload/platform/plugins/work/mcp/dist/tools/work-get.d.ts +19 -0
  1861. package/payload/platform/plugins/work/mcp/dist/tools/work-get.d.ts.map +1 -0
  1862. package/payload/platform/plugins/work/mcp/dist/tools/work-get.js +51 -0
  1863. package/payload/platform/plugins/work/mcp/dist/tools/work-get.js.map +1 -0
  1864. package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts +18 -0
  1865. package/payload/platform/plugins/work/mcp/dist/tools/work-list.d.ts.map +1 -0
  1866. package/payload/platform/plugins/work/mcp/dist/tools/work-list.js +66 -0
  1867. package/payload/platform/plugins/work/mcp/dist/tools/work-list.js.map +1 -0
  1868. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.d.ts +21 -0
  1869. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.d.ts.map +1 -0
  1870. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.js +54 -0
  1871. package/payload/platform/plugins/work/mcp/dist/tools/work-ready.js.map +1 -0
  1872. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.d.ts +12 -0
  1873. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.d.ts.map +1 -0
  1874. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.js +59 -0
  1875. package/payload/platform/plugins/work/mcp/dist/tools/work-relate.js.map +1 -0
  1876. package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts +32 -0
  1877. package/payload/platform/plugins/work/mcp/dist/tools/work-update.d.ts.map +1 -0
  1878. package/payload/platform/plugins/work/mcp/dist/tools/work-update.js +112 -0
  1879. package/payload/platform/plugins/work/mcp/dist/tools/work-update.js.map +1 -0
  1880. package/payload/platform/plugins/work/mcp/package.json +20 -0
  1881. package/payload/platform/plugins/work/skills/execute-task/SKILL.md +101 -0
  1882. package/payload/platform/plugins/workflows/.claude-plugin/plugin.json +17 -0
  1883. package/payload/platform/plugins/workflows/.mcp.json +12 -0
  1884. package/payload/platform/plugins/workflows/PLUGIN.md +160 -0
  1885. package/payload/platform/plugins/workflows/mcp/dist/index.d.ts +2 -0
  1886. package/payload/platform/plugins/workflows/mcp/dist/index.d.ts.map +1 -0
  1887. package/payload/platform/plugins/workflows/mcp/dist/index.js +440 -0
  1888. package/payload/platform/plugins/workflows/mcp/dist/index.js.map +1 -0
  1889. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.d.ts +38 -0
  1890. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.d.ts.map +1 -0
  1891. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.js +83 -0
  1892. package/payload/platform/plugins/workflows/mcp/dist/lib/active-runs.js.map +1 -0
  1893. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts +2 -0
  1894. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.d.ts.map +1 -0
  1895. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js +19 -0
  1896. package/payload/platform/plugins/workflows/mcp/dist/lib/embeddings.js.map +1 -0
  1897. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts +151 -0
  1898. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.d.ts.map +1 -0
  1899. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js +299 -0
  1900. package/payload/platform/plugins/workflows/mcp/dist/lib/llm-call.js.map +1 -0
  1901. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.d.ts +5 -0
  1902. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.d.ts.map +1 -0
  1903. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.js +40 -0
  1904. package/payload/platform/plugins/workflows/mcp/dist/lib/neo4j.js.map +1 -0
  1905. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts +66 -0
  1906. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.d.ts.map +1 -0
  1907. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js +187 -0
  1908. package/payload/platform/plugins/workflows/mcp/dist/lib/step-resolver.js.map +1 -0
  1909. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts +25 -0
  1910. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.d.ts.map +1 -0
  1911. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js +56 -0
  1912. package/payload/platform/plugins/workflows/mcp/dist/lib/validate-capabilities.js.map +1 -0
  1913. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts +33 -0
  1914. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -0
  1915. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +130 -0
  1916. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -0
  1917. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.d.ts +28 -0
  1918. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.d.ts.map +1 -0
  1919. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.js +57 -0
  1920. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-delete.js.map +1 -0
  1921. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts +51 -0
  1922. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.d.ts.map +1 -0
  1923. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js +382 -0
  1924. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-execute.js.map +1 -0
  1925. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts +24 -0
  1926. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.d.ts.map +1 -0
  1927. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js +48 -0
  1928. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-get.js.map +1 -0
  1929. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.d.ts +16 -0
  1930. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.d.ts.map +1 -0
  1931. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.js +44 -0
  1932. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-list.js.map +1 -0
  1933. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.d.ts +28 -0
  1934. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.d.ts.map +1 -0
  1935. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.js +71 -0
  1936. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-runs.js.map +1 -0
  1937. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts +11 -0
  1938. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.d.ts.map +1 -0
  1939. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js +150 -0
  1940. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-update.js.map +1 -0
  1941. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts +13 -0
  1942. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.d.ts.map +1 -0
  1943. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js +53 -0
  1944. package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-validate.js.map +1 -0
  1945. package/payload/platform/plugins/workflows/mcp/package.json +20 -0
  1946. package/payload/platform/plugins/workflows/mcp/test-runner.mjs +710 -0
  1947. package/payload/platform/plugins/workflows/mcp/test-workflows.sh +77 -0
  1948. package/payload/platform/plugins/workflows/skills/workflow-manager/SKILL.md +93 -0
  1949. package/payload/platform/plugins/x-import/.claude-plugin/plugin.json +8 -0
  1950. package/payload/platform/plugins/x-import/PLUGIN.md +33 -0
  1951. package/payload/platform/plugins/x-import/references/archive-shape.md +124 -0
  1952. package/payload/platform/plugins/x-import/references/transcript-shape.md +121 -0
  1953. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +123 -0
  1954. package/payload/platform/scripts/__tests__/agents-md-bootstrap.test.sh +111 -0
  1955. package/payload/platform/scripts/__tests__/first-token-creates-stream-log.test.sh +37 -0
  1956. package/payload/platform/scripts/__tests__/logs-read-prefix.sh +237 -0
  1957. package/payload/platform/scripts/__tests__/resume-tunnel.test.sh +251 -0
  1958. package/payload/platform/scripts/admin-conversation-recover.mjs +386 -0
  1959. package/payload/platform/scripts/admin-persist-audit.ts +211 -0
  1960. package/payload/platform/scripts/check-architecture-skill-no-drift.mjs +114 -0
  1961. package/payload/platform/scripts/check-canonical-tool-names.mjs +110 -0
  1962. package/payload/platform/scripts/check-cypher-int-params.mjs +277 -0
  1963. package/payload/platform/scripts/check-no-conversation-id-leaks.mjs +165 -0
  1964. package/payload/platform/scripts/check-no-direct-clipboard.mjs +54 -0
  1965. package/payload/platform/scripts/check-no-esm-require.mjs +138 -0
  1966. package/payload/platform/scripts/check-no-legacy-spawn-route.mjs +37 -0
  1967. package/payload/platform/scripts/check-no-task-id-leaks.mjs +110 -0
  1968. package/payload/platform/scripts/check-plugin-references.mjs +256 -0
  1969. package/payload/platform/scripts/check-plugin-tools-mcp-consistency.mjs +136 -0
  1970. package/payload/platform/scripts/check-roles-doc-completeness.mjs +96 -0
  1971. package/payload/platform/scripts/check-skill-frontmatter.mjs +139 -0
  1972. package/payload/platform/scripts/check-skill-load-coverage.mjs +100 -0
  1973. package/payload/platform/scripts/check-specialist-tool-surface.mjs +323 -0
  1974. package/payload/platform/scripts/conversation-id-allowlist.txt +142 -0
  1975. package/payload/platform/scripts/dedupe-userprofile-ghosts.sh +388 -0
  1976. package/payload/platform/scripts/generate-canonical-tool-names.mjs +63 -0
  1977. package/payload/platform/scripts/generate-entitlement-fixture.mjs +152 -0
  1978. package/payload/platform/scripts/identity-forbidden-token-check.mjs +88 -0
  1979. package/payload/platform/scripts/installer-device-verify.sh +249 -0
  1980. package/payload/platform/scripts/lib/agents-md-bootstrap.sh +49 -0
  1981. package/payload/platform/scripts/lib/canonical-tool-names.mjs +88 -0
  1982. package/payload/platform/scripts/lib/read-brand-json.sh +69 -0
  1983. package/payload/platform/scripts/lib/resolve-account-dir.sh +184 -0
  1984. package/payload/platform/scripts/log-adherence-check.sh +125 -0
  1985. package/payload/platform/scripts/logs-read-jsonl.test.sh +307 -0
  1986. package/payload/platform/scripts/logs-read.sh +980 -0
  1987. package/payload/platform/scripts/logs-read.test.sh +159 -0
  1988. package/payload/platform/scripts/redact-install-logs.sh +87 -0
  1989. package/payload/platform/scripts/resume-tunnel.sh +148 -0
  1990. package/payload/platform/scripts/rss-sampler.sh +58 -0
  1991. package/payload/platform/scripts/seed-neo4j.sh +193 -0
  1992. package/payload/platform/scripts/setup-account.sh +373 -0
  1993. package/payload/platform/scripts/smoke-boot-services.sh +413 -0
  1994. package/payload/platform/scripts/test-laptop-vnc-boot.sh +88 -0
  1995. package/payload/platform/scripts/verify-skill-tool-surface.sh +389 -0
  1996. package/payload/platform/scripts/vnc.sh +476 -0
  1997. package/payload/platform/scripts/wifi-provision-server/server.js +743 -0
  1998. package/payload/platform/scripts/wifi-provision.sh +492 -0
  1999. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts +39 -0
  2000. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.d.ts.map +1 -0
  2001. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js +133 -0
  2002. package/payload/platform/services/claude-session-manager/dist/admin-identity-audit.js.map +1 -0
  2003. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts +23 -0
  2004. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.d.ts.map +1 -0
  2005. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js +29 -0
  2006. package/payload/platform/services/claude-session-manager/dist/agent-identity-locator.js.map +1 -0
  2007. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.d.ts +4 -0
  2008. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.d.ts.map +1 -0
  2009. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.js +50 -0
  2010. package/payload/platform/services/claude-session-manager/dist/auth-snapshot.js.map +1 -0
  2011. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.d.ts +30 -0
  2012. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.d.ts.map +1 -0
  2013. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.js +86 -0
  2014. package/payload/platform/services/claude-session-manager/dist/brand-foreign-filter.js.map +1 -0
  2015. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.d.ts +7 -0
  2016. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.d.ts.map +1 -0
  2017. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts +5 -0
  2018. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -0
  2019. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +205 -0
  2020. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -0
  2021. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.js +23 -0
  2022. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.js.map +1 -0
  2023. package/payload/platform/services/claude-session-manager/dist/config.d.ts +55 -0
  2024. package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -0
  2025. package/payload/platform/services/claude-session-manager/dist/config.js +234 -0
  2026. package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -0
  2027. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts +150 -0
  2028. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -0
  2029. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +881 -0
  2030. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -0
  2031. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.d.ts +7 -0
  2032. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.d.ts.map +1 -0
  2033. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.js +90 -0
  2034. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.js.map +1 -0
  2035. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +40 -0
  2036. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -0
  2037. package/payload/platform/services/claude-session-manager/dist/http-server.js +1761 -0
  2038. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -0
  2039. package/payload/platform/services/claude-session-manager/dist/index.d.ts +2 -0
  2040. package/payload/platform/services/claude-session-manager/dist/index.d.ts.map +1 -0
  2041. package/payload/platform/services/claude-session-manager/dist/index.js +675 -0
  2042. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -0
  2043. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +43 -0
  2044. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -0
  2045. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +155 -0
  2046. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -0
  2047. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts +30 -0
  2048. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.d.ts.map +1 -0
  2049. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js +204 -0
  2050. package/payload/platform/services/claude-session-manager/dist/jsonl-observer.js.map +1 -0
  2051. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +41 -0
  2052. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -0
  2053. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +105 -0
  2054. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -0
  2055. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts +81 -0
  2056. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.d.ts.map +1 -0
  2057. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js +499 -0
  2058. package/payload/platform/services/claude-session-manager/dist/jsonl-tail.js.map +1 -0
  2059. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.d.ts +38 -0
  2060. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.d.ts.map +1 -0
  2061. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.js +131 -0
  2062. package/payload/platform/services/claude-session-manager/dist/mcp-tools-probe.js.map +1 -0
  2063. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.d.ts +20 -0
  2064. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.d.ts.map +1 -0
  2065. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.js +71 -0
  2066. package/payload/platform/services/claude-session-manager/dist/permission-mode-tail.js.map +1 -0
  2067. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts +40 -0
  2068. package/payload/platform/services/claude-session-manager/dist/pty-census.d.ts.map +1 -0
  2069. package/payload/platform/services/claude-session-manager/dist/pty-census.js +125 -0
  2070. package/payload/platform/services/claude-session-manager/dist/pty-census.js.map +1 -0
  2071. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +641 -0
  2072. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -0
  2073. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +2077 -0
  2074. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -0
  2075. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts +40 -0
  2076. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.d.ts.map +1 -0
  2077. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js +123 -0
  2078. package/payload/platform/services/claude-session-manager/dist/public-agent-reachability.js.map +1 -0
  2079. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.d.ts +33 -0
  2080. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.d.ts.map +1 -0
  2081. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.js +149 -0
  2082. package/payload/platform/services/claude-session-manager/dist/public-tool-audit.js.map +1 -0
  2083. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +157 -0
  2084. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -0
  2085. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +556 -0
  2086. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -0
  2087. package/payload/platform/services/claude-session-manager/dist/rc-life.d.ts +4 -0
  2088. package/payload/platform/services/claude-session-manager/dist/rc-life.d.ts.map +1 -0
  2089. package/payload/platform/services/claude-session-manager/dist/rc-life.js +16 -0
  2090. package/payload/platform/services/claude-session-manager/dist/rc-life.js.map +1 -0
  2091. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts +80 -0
  2092. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.d.ts.map +1 -0
  2093. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js +306 -0
  2094. package/payload/platform/services/claude-session-manager/dist/rc-script-spawn.js.map +1 -0
  2095. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts +28 -0
  2096. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -0
  2097. package/payload/platform/services/claude-session-manager/dist/reaper.js +118 -0
  2098. package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -0
  2099. package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +91 -0
  2100. package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -0
  2101. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +232 -0
  2102. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -0
  2103. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +49 -0
  2104. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -0
  2105. package/payload/platform/services/claude-session-manager/dist/session-store.js +52 -0
  2106. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -0
  2107. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.d.ts +28 -0
  2108. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.d.ts.map +1 -0
  2109. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.js +77 -0
  2110. package/payload/platform/services/claude-session-manager/dist/spawn-rate-limiter.js.map +1 -0
  2111. package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts +60 -0
  2112. package/payload/platform/services/claude-session-manager/dist/specialist-drift.d.ts.map +1 -0
  2113. package/payload/platform/services/claude-session-manager/dist/specialist-drift.js +203 -0
  2114. package/payload/platform/services/claude-session-manager/dist/specialist-drift.js.map +1 -0
  2115. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +151 -0
  2116. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -0
  2117. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +445 -0
  2118. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -0
  2119. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts +164 -0
  2120. package/payload/platform/services/claude-session-manager/dist/systemd-scope.d.ts.map +1 -0
  2121. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js +296 -0
  2122. package/payload/platform/services/claude-session-manager/dist/systemd-scope.js.map +1 -0
  2123. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts +83 -0
  2124. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts.map +1 -0
  2125. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js +345 -0
  2126. package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js.map +1 -0
  2127. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts +69 -0
  2128. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts.map +1 -0
  2129. package/payload/platform/services/claude-session-manager/dist/tool-surface.js +373 -0
  2130. package/payload/platform/services/claude-session-manager/dist/tool-surface.js.map +1 -0
  2131. package/payload/platform/services/claude-session-manager/dist/types.d.ts +41 -0
  2132. package/payload/platform/services/claude-session-manager/dist/types.d.ts.map +1 -0
  2133. package/payload/platform/services/claude-session-manager/dist/types.js +2 -0
  2134. package/payload/platform/services/claude-session-manager/dist/types.js.map +1 -0
  2135. package/payload/platform/services/claude-session-manager/dist/url-capture.d.ts +12 -0
  2136. package/payload/platform/services/claude-session-manager/dist/url-capture.d.ts.map +1 -0
  2137. package/payload/platform/services/claude-session-manager/dist/url-capture.js +79 -0
  2138. package/payload/platform/services/claude-session-manager/dist/url-capture.js.map +1 -0
  2139. package/payload/platform/services/claude-session-manager/dist/user-title-store.d.ts +39 -0
  2140. package/payload/platform/services/claude-session-manager/dist/user-title-store.d.ts.map +1 -0
  2141. package/payload/platform/services/claude-session-manager/dist/user-title-store.js +138 -0
  2142. package/payload/platform/services/claude-session-manager/dist/user-title-store.js.map +1 -0
  2143. package/payload/platform/services/claude-session-manager/package.json +22 -0
  2144. package/payload/platform/services/claude-session-manager/scripts/stash-cleanup.sh +410 -0
  2145. package/payload/platform/services/claude-session-manager/vitest.config.ts +14 -0
  2146. package/payload/platform/templates/account.json +12 -0
  2147. package/payload/platform/templates/agents/admin/AGENTS.md +23 -0
  2148. package/payload/platform/templates/agents/admin/IDENTITY.md +69 -0
  2149. package/payload/platform/templates/agents/admin/LEARNINGS.md +3 -0
  2150. package/payload/platform/templates/agents/admin/SOUL.md +1 -0
  2151. package/payload/platform/templates/agents/public/IDENTITY.md +19 -0
  2152. package/payload/platform/templates/specialists/.claude-plugin/plugin.json +4 -0
  2153. package/payload/platform/templates/specialists/agents/archive-ingest-operator.md +45 -0
  2154. package/payload/platform/templates/specialists/agents/citation-auditor.md +37 -0
  2155. package/payload/platform/templates/specialists/agents/coding-assistant.md +73 -0
  2156. package/payload/platform/templates/specialists/agents/compiled-truth-rewriter.md +42 -0
  2157. package/payload/platform/templates/specialists/agents/content-producer.md +65 -0
  2158. package/payload/platform/templates/specialists/agents/database-operator.md +29 -0
  2159. package/payload/platform/templates/specialists/agents/librarian.md +57 -0
  2160. package/payload/platform/templates/specialists/agents/personal-assistant.md +63 -0
  2161. package/payload/platform/templates/specialists/agents/project-manager.md +63 -0
  2162. package/payload/platform/templates/specialists/agents/public-session-reviewer.md +40 -0
  2163. package/payload/platform/templates/specialists/agents/research-assistant.md +73 -0
  2164. package/payload/platform/templates/specialists/agents/typed-edge-classifier.md +37 -0
  2165. package/payload/platform/templates/systemd/edge.service.template +38 -0
  2166. package/payload/platform/tsconfig.base.json +18 -0
  2167. package/payload/premium-plugins/.claude-plugin/marketplace.json +23 -0
  2168. package/payload/premium-plugins/teaching/.claude-plugin/plugin.json +8 -0
  2169. package/payload/premium-plugins/teaching/PLUGIN.md +58 -0
  2170. package/payload/premium-plugins/teaching/skills/interactive-tutor/SKILL.md +59 -0
  2171. package/payload/premium-plugins/teaching/skills/interactive-tutor/references/assessment.md +70 -0
  2172. package/payload/premium-plugins/teaching/skills/interactive-tutor/references/classroom-conduct.md +43 -0
  2173. package/payload/premium-plugins/teaching/skills/interactive-tutor/references/teaching-modes.md +83 -0
  2174. package/payload/premium-plugins/teaching/skills/lesson-planner/SKILL.md +48 -0
  2175. package/payload/premium-plugins/teaching/skills/lesson-planner/references/context-gathering.md +41 -0
  2176. package/payload/premium-plugins/teaching/skills/lesson-planner/references/plan-structure.md +94 -0
  2177. package/payload/premium-plugins/teaching/skills/study-pack-builder/SKILL.md +52 -0
  2178. package/payload/premium-plugins/teaching/skills/study-pack-builder/references/disaggregation.md +49 -0
  2179. package/payload/premium-plugins/teaching/skills/study-pack-builder/references/materials.md +116 -0
  2180. package/payload/premium-plugins/venture-studio/.claude-plugin/plugin.json +8 -0
  2181. package/payload/premium-plugins/venture-studio/PLUGIN.md +119 -0
  2182. package/payload/premium-plugins/venture-studio/bin/scaffold.sh +116 -0
  2183. package/payload/premium-plugins/venture-studio/skills/brand-pack/SKILL.md +256 -0
  2184. package/payload/premium-plugins/venture-studio/skills/brand-pack/references/color-psychology.md +118 -0
  2185. package/payload/premium-plugins/venture-studio/skills/investor-data-room/SKILL.md +376 -0
  2186. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/business-plan-template.md +64 -0
  2187. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/compliance-research-checklist.md +53 -0
  2188. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/data-room-structure.md +88 -0
  2189. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/deck-blueprint-template.md +39 -0
  2190. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/design-tokens-application.md +79 -0
  2191. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/html-pdf-pipeline.md +236 -0
  2192. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/internal-workings-scrub.md +33 -0
  2193. package/payload/premium-plugins/venture-studio/skills/investor-data-room/references/termsheet-template.md +88 -0
  2194. package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/index.html +1565 -0
  2195. package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/render-pdf.mjs +91 -0
  2196. package/payload/premium-plugins/venture-studio/skills/investor-data-room/templates/prospectus/term_sheet.html +715 -0
  2197. package/payload/premium-plugins/venture-studio/skills/office-hours/SKILL.md +587 -0
  2198. package/payload/premium-plugins/venture-studio/skills/prototype-host/SKILL.md +179 -0
  2199. package/payload/premium-plugins/venture-studio/skills/prototype-host/references/cloudflared-ingress-edit.md +81 -0
  2200. package/payload/premium-plugins/venture-studio/skills/prototype-host/references/scaffold-frameworks.md +60 -0
  2201. package/payload/premium-plugins/venture-studio/skills/prototype-host/references/systemd-user-service.md +104 -0
  2202. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/SKILL.md +336 -0
  2203. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/aarrr-metrics.md +275 -0
  2204. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/assumption-testing.md +93 -0
  2205. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/boolean-search.md +308 -0
  2206. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/build-measure-learn.md +262 -0
  2207. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/business-model-canvas.md +171 -0
  2208. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/commitment-signals.md +246 -0
  2209. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/design-thinking.md +183 -0
  2210. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/earlyvangelist.md +190 -0
  2211. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/first-principles.md +58 -0
  2212. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/fishbone.md +114 -0
  2213. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/five-whys.md +43 -0
  2214. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/ice-scoring.md +237 -0
  2215. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/innovation-accounting.md +290 -0
  2216. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/jtbd.md +105 -0
  2217. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/landing-page.md +361 -0
  2218. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/market-type.md +167 -0
  2219. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mom-test.md +193 -0
  2220. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/mvp-types.md +200 -0
  2221. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/og-images.md +239 -0
  2222. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pareto.md +103 -0
  2223. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/persona-development.md +291 -0
  2224. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pivot-types.md +225 -0
  2225. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/positioning-statement.md +179 -0
  2226. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/prd.md +363 -0
  2227. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/pre-mortem.md +74 -0
  2228. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/problem-validation.md +253 -0
  2229. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/product-market-fit.md +256 -0
  2230. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/research-synthesis.md +276 -0
  2231. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/three-engines-of-growth.md +248 -0
  2232. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/validation-tests.md +89 -0
  2233. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/value-proposition-canvas.md +121 -0
  2234. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/win-loss-analysis.md +242 -0
  2235. package/payload/premium-plugins/venture-studio/skills/zero-to-prototype/references/workflow-mapping.md +271 -0
  2236. package/payload/premium-plugins/writer-craft/.claude-plugin/plugin.json +17 -0
  2237. package/payload/premium-plugins/writer-craft/PLUGIN.md +134 -0
  2238. package/payload/premium-plugins/writer-craft/agents/writer-craft--manuscript-reviewer.md +96 -0
  2239. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts +51 -0
  2240. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -0
  2241. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js +196 -0
  2242. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/dist/index.js.map +1 -0
  2243. package/payload/premium-plugins/writer-craft/lib/mcp-stderr-tee/package.json +7 -0
  2244. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts +3 -0
  2245. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.d.ts.map +1 -0
  2246. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js +58 -0
  2247. package/payload/premium-plugins/writer-craft/mcp/dist/cli/ingest-session-text.js.map +1 -0
  2248. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts +3 -0
  2249. package/payload/premium-plugins/writer-craft/mcp/dist/index.d.ts.map +1 -0
  2250. package/payload/premium-plugins/writer-craft/mcp/dist/index.js +362 -0
  2251. package/payload/premium-plugins/writer-craft/mcp/dist/index.js.map +1 -0
  2252. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts +14 -0
  2253. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.d.ts.map +1 -0
  2254. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js +47 -0
  2255. package/payload/premium-plugins/writer-craft/mcp/dist/lib/neo4j.js.map +1 -0
  2256. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts +86 -0
  2257. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.d.ts.map +1 -0
  2258. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js +110 -0
  2259. package/payload/premium-plugins/writer-craft/mcp/dist/lib/voice-corpus.js.map +1 -0
  2260. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts +82 -0
  2261. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.d.ts.map +1 -0
  2262. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js +560 -0
  2263. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-distil-profile.js.map +1 -0
  2264. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts +19 -0
  2265. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.d.ts.map +1 -0
  2266. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js +123 -0
  2267. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-ingest-session-text.js.map +1 -0
  2268. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts +32 -0
  2269. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.d.ts.map +1 -0
  2270. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js +82 -0
  2271. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-record-feedback.js.map +1 -0
  2272. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts +47 -0
  2273. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.d.ts.map +1 -0
  2274. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js +160 -0
  2275. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-retrieve-conditioning.js.map +1 -0
  2276. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts +17 -0
  2277. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.d.ts.map +1 -0
  2278. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js +98 -0
  2279. package/payload/premium-plugins/writer-craft/mcp/dist/tools/voice-tag-content.js.map +1 -0
  2280. package/payload/premium-plugins/writer-craft/mcp/package-lock.json +1327 -0
  2281. package/payload/premium-plugins/writer-craft/mcp/package.json +19 -0
  2282. package/payload/premium-plugins/writer-craft/mcp/scripts/smoke.mjs +351 -0
  2283. package/payload/premium-plugins/writer-craft/mcp/src/index.ts +409 -0
  2284. package/payload/premium-plugins/writer-craft/mcp/src/lib/neo4j.ts +56 -0
  2285. package/payload/premium-plugins/writer-craft/mcp/src/lib/voice-corpus.ts +115 -0
  2286. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-distil-profile.ts +767 -0
  2287. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-ingest-session-text.ts +152 -0
  2288. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-record-feedback.ts +128 -0
  2289. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-retrieve-conditioning.ts +234 -0
  2290. package/payload/premium-plugins/writer-craft/mcp/src/tools/voice-tag-content.ts +139 -0
  2291. package/payload/premium-plugins/writer-craft/mcp/tsconfig.json +8 -0
  2292. package/payload/premium-plugins/writer-craft/skills/citation-style/SKILL.md +94 -0
  2293. package/payload/premium-plugins/writer-craft/skills/citation-style/references/book-and-chapter-models.md +77 -0
  2294. package/payload/premium-plugins/writer-craft/skills/citation-style/references/citation-rules.md +103 -0
  2295. package/payload/premium-plugins/writer-craft/skills/citation-style/references/journal-article-models.md +74 -0
  2296. package/payload/premium-plugins/writer-craft/skills/citation-style/references/other-source-models.md +146 -0
  2297. package/payload/premium-plugins/writer-craft/skills/citation-style/references/reference-list-rules.md +70 -0
  2298. package/payload/premium-plugins/writer-craft/skills/editorial-practice/SKILL.md +108 -0
  2299. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/copyediting.md +73 -0
  2300. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/developmental-editing.md +85 -0
  2301. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/genre-specific-editing.md +78 -0
  2302. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/line-editing.md +55 -0
  2303. package/payload/premium-plugins/writer-craft/skills/editorial-practice/references/self-editing.md +89 -0
  2304. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/SKILL.md +114 -0
  2305. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/audience-analysis.md +73 -0
  2306. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/crafting-persuasive-story.md +76 -0
  2307. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/persuasion-case-studies.md +67 -0
  2308. package/payload/premium-plugins/writer-craft/skills/persuasive-storytelling/references/transformation-framework.md +86 -0
  2309. package/payload/premium-plugins/writer-craft/skills/point-of-view/SKILL.md +97 -0
  2310. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/indirect-narration.md +72 -0
  2311. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/pov-types-and-voice.md +91 -0
  2312. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/protagonist-filter.md +71 -0
  2313. package/payload/premium-plugins/writer-craft/skills/point-of-view/references/tense-and-person.md +85 -0
  2314. package/payload/premium-plugins/writer-craft/skills/prose-craft/SKILL.md +100 -0
  2315. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/punctuation-and-grammar.md +72 -0
  2316. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/repetition.md +71 -0
  2317. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/sound-and-rhythm.md +64 -0
  2318. package/payload/premium-plugins/writer-craft/skills/prose-craft/references/word-economy.md +93 -0
  2319. package/payload/premium-plugins/writer-craft/skills/reader-engagement/SKILL.md +100 -0
  2320. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/cause-effect-setup-payoff.md +79 -0
  2321. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/conflict-escalation.md +81 -0
  2322. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/hooking-readers.md +67 -0
  2323. package/payload/premium-plugins/writer-craft/skills/reader-engagement/references/neurochemistry-of-engagement.md +94 -0
  2324. package/payload/premium-plugins/writer-craft/skills/review-manuscript/SKILL.md +111 -0
  2325. package/payload/premium-plugins/writer-craft/skills/review-manuscript/references/review-manuscript-checklist.md +119 -0
  2326. package/payload/premium-plugins/writer-craft/skills/review-prose/SKILL.md +99 -0
  2327. package/payload/premium-plugins/writer-craft/skills/review-prose/references/prose-review-checklist.md +112 -0
  2328. package/payload/premium-plugins/writer-craft/skills/review-scene/SKILL.md +99 -0
  2329. package/payload/premium-plugins/writer-craft/skills/review-scene/references/scene-analysis-framework.md +95 -0
  2330. package/payload/premium-plugins/writer-craft/skills/story-architecture/SKILL.md +106 -0
  2331. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/blueprinting-and-scene-cards.md +118 -0
  2332. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/inner-issue-and-protagonist-goal.md +66 -0
  2333. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/misbelief-desire-worldview.md +87 -0
  2334. package/payload/premium-plugins/writer-craft/skills/story-architecture/references/origin-scenes-and-escalation.md +82 -0
  2335. package/payload/premium-plugins/writer-craft/skills/story-blueprint/SKILL.md +133 -0
  2336. package/payload/premium-plugins/writer-craft/skills/story-blueprint/references/blueprinting-exercises.md +118 -0
  2337. package/payload/premium-plugins/writer-craft/skills/story-blueprint/references/blueprinting-process.md +128 -0
  2338. package/payload/premium-plugins/writer-craft/skills/voice-mirror/SKILL.md +228 -0
  2339. package/payload/server/adminuser-self-heal-YC47O34W.js +46 -0
  2340. package/payload/server/chunk-76HRO7NX.js +5684 -0
  2341. package/payload/server/chunk-HYQNUVGO.js +38 -0
  2342. package/payload/server/maxy-edge.js +814 -0
  2343. package/payload/server/package.json +11 -0
  2344. package/payload/server/public/assets/AdminShell-T-YknnBn.js +1 -0
  2345. package/payload/server/public/assets/AdminShell-qc_xy7Az.css +1 -0
  2346. package/payload/server/public/assets/Checkbox-DmDxpqVv.js +1 -0
  2347. package/payload/server/public/assets/_baseFor-Cs8Y-rGh.js +1 -0
  2348. package/payload/server/public/assets/admin-COUV-jgt.js +1 -0
  2349. package/payload/server/public/assets/admin-CWMpccrR.css +1 -0
  2350. package/payload/server/public/assets/arc-B2CweJq3.js +1 -0
  2351. package/payload/server/public/assets/architecture-YZFGNWBL-Dnn6Hc65.js +1 -0
  2352. package/payload/server/public/assets/architectureDiagram-Q4EWVU46-DP2o-MFV.js +36 -0
  2353. package/payload/server/public/assets/array-iHZP4KWJ.js +1 -0
  2354. package/payload/server/public/assets/blockDiagram-DXYQGD6D-DO4mcYDJ.js +132 -0
  2355. package/payload/server/public/assets/c4Diagram-AHTNJAMY-Sy1giHbj.js +10 -0
  2356. package/payload/server/public/assets/channel-CEpR_0rE.js +1 -0
  2357. package/payload/server/public/assets/chunk-2KRD3SAO-CKsCYCsN.js +1 -0
  2358. package/payload/server/public/assets/chunk-336JU56O-C0-P-aUF.js +2 -0
  2359. package/payload/server/public/assets/chunk-426QAEUC-DFjEt3Zb.js +1 -0
  2360. package/payload/server/public/assets/chunk-4BX2VUAB-B8bqAmBa.js +1 -0
  2361. package/payload/server/public/assets/chunk-4TB4RGXK-D1k0VSlW.js +206 -0
  2362. package/payload/server/public/assets/chunk-55IACEB6-B-p_QNqz.js +1 -0
  2363. package/payload/server/public/assets/chunk-5FUZZQ4R-D6U6tV_j.js +62 -0
  2364. package/payload/server/public/assets/chunk-5PVQY5BW-CYK76xfs.js +2 -0
  2365. package/payload/server/public/assets/chunk-67CJDMHE-BC9js-lf.js +1 -0
  2366. package/payload/server/public/assets/chunk-7N4EOEYR-4j2OqKkv.js +1 -0
  2367. package/payload/server/public/assets/chunk-AA7GKIK3-Coen-fXN.js +1 -0
  2368. package/payload/server/public/assets/chunk-BSJP7CBP-CAiOBvec.js +1 -0
  2369. package/payload/server/public/assets/chunk-CIAEETIT-AJzzpZVb.js +1 -0
  2370. package/payload/server/public/assets/chunk-DD-I1_y5.js +1 -0
  2371. package/payload/server/public/assets/chunk-EDXVE4YY-BL4BKozX.js +1 -0
  2372. package/payload/server/public/assets/chunk-ENJZ2VHE-mhAFG8UD.js +10 -0
  2373. package/payload/server/public/assets/chunk-FMBD7UC4-H231gZA_.js +15 -0
  2374. package/payload/server/public/assets/chunk-FOC6F5B3-Cl3ZZjYG.js +1 -0
  2375. package/payload/server/public/assets/chunk-ICPOFSXX-DOEzvzJa.js +122 -0
  2376. package/payload/server/public/assets/chunk-K5T4RW27-C_ipbUDD.js +94 -0
  2377. package/payload/server/public/assets/chunk-KGLVRYIC-CTsDNSCU.js +1 -0
  2378. package/payload/server/public/assets/chunk-LIHQZDEY-DvSXhkGf.js +1 -0
  2379. package/payload/server/public/assets/chunk-ORNJ4GCN-p574NOI7.js +1 -0
  2380. package/payload/server/public/assets/chunk-OYMX7WX6-BlEgFM6U.js +231 -0
  2381. package/payload/server/public/assets/chunk-QZHKN3VN-DpF06ZZQ.js +1 -0
  2382. package/payload/server/public/assets/chunk-U2HBQHQK-B2bDK0jv.js +70 -0
  2383. package/payload/server/public/assets/chunk-X2U36JSP-D69BxKFw.js +1 -0
  2384. package/payload/server/public/assets/chunk-XPW4576I-Dm-PcyUi.js +32 -0
  2385. package/payload/server/public/assets/chunk-YZCP3GAM-Be8RnXgx.js +1 -0
  2386. package/payload/server/public/assets/chunk-ZZ45TVLE-Ck8PCTa4.js +1 -0
  2387. package/payload/server/public/assets/classDiagram-6PBFFD2Q-CYbXvKLI.js +1 -0
  2388. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DEyHzRhq.js +1 -0
  2389. package/payload/server/public/assets/clone-y8gexbBy.js +1 -0
  2390. package/payload/server/public/assets/cormorant-cyrillic-300-normal-CzPHYadL.woff +0 -0
  2391. package/payload/server/public/assets/cormorant-cyrillic-300-normal-DFUoTmrg.woff2 +0 -0
  2392. package/payload/server/public/assets/cormorant-cyrillic-400-normal-C8QS47vb.woff2 +0 -0
  2393. package/payload/server/public/assets/cormorant-cyrillic-400-normal-D3EsxgFc.woff +0 -0
  2394. package/payload/server/public/assets/cormorant-cyrillic-500-normal-B7dJQtg-.woff +0 -0
  2395. package/payload/server/public/assets/cormorant-cyrillic-500-normal-BLlg2W5x.woff2 +0 -0
  2396. package/payload/server/public/assets/cormorant-cyrillic-ext-300-normal-BXl3lXsi.woff2 +0 -0
  2397. package/payload/server/public/assets/cormorant-cyrillic-ext-300-normal-DmxSOTe3.woff +0 -0
  2398. package/payload/server/public/assets/cormorant-cyrillic-ext-400-normal-Bgrpe4p1.woff +0 -0
  2399. package/payload/server/public/assets/cormorant-cyrillic-ext-400-normal-BlcaxZtM.woff2 +0 -0
  2400. package/payload/server/public/assets/cormorant-cyrillic-ext-500-normal-CdQuyvtc.woff +0 -0
  2401. package/payload/server/public/assets/cormorant-cyrillic-ext-500-normal-pZw22qtS.woff2 +0 -0
  2402. package/payload/server/public/assets/cormorant-latin-300-normal-CJ5dfen0.woff2 +0 -0
  2403. package/payload/server/public/assets/cormorant-latin-300-normal-DQZObO_3.woff +0 -0
  2404. package/payload/server/public/assets/cormorant-latin-400-normal-BGH8Vunh.woff2 +0 -0
  2405. package/payload/server/public/assets/cormorant-latin-400-normal-C3_-2Ua-.woff +0 -0
  2406. package/payload/server/public/assets/cormorant-latin-500-normal-Dj3SQ6fR.woff +0 -0
  2407. package/payload/server/public/assets/cormorant-latin-500-normal-EBdSCOD3.woff2 +0 -0
  2408. package/payload/server/public/assets/cormorant-latin-ext-300-normal-CkiUx0UG.woff +0 -0
  2409. package/payload/server/public/assets/cormorant-latin-ext-300-normal-De3D72RL.woff2 +0 -0
  2410. package/payload/server/public/assets/cormorant-latin-ext-400-normal-DuQ88yz3.woff2 +0 -0
  2411. package/payload/server/public/assets/cormorant-latin-ext-400-normal-DuXFa1Dr.woff +0 -0
  2412. package/payload/server/public/assets/cormorant-latin-ext-500-normal-AH9qog1s.woff2 +0 -0
  2413. package/payload/server/public/assets/cormorant-latin-ext-500-normal-DAuUCO41.woff +0 -0
  2414. package/payload/server/public/assets/cormorant-vietnamese-300-normal-BVqIp_mg.woff2 +0 -0
  2415. package/payload/server/public/assets/cormorant-vietnamese-300-normal-CEMS9Pw-.woff +0 -0
  2416. package/payload/server/public/assets/cormorant-vietnamese-400-normal-C-RiYxEf.woff2 +0 -0
  2417. package/payload/server/public/assets/cormorant-vietnamese-400-normal-DmUuA7Y2.woff +0 -0
  2418. package/payload/server/public/assets/cormorant-vietnamese-500-normal-DsPuwQHi.woff2 +0 -0
  2419. package/payload/server/public/assets/cormorant-vietnamese-500-normal-tGBW_mI7.woff +0 -0
  2420. package/payload/server/public/assets/cose-bilkent-S5V4N54A-CmkW2Eaj.js +1 -0
  2421. package/payload/server/public/assets/cytoscape.esm-BR2GOQ8_.js +321 -0
  2422. package/payload/server/public/assets/dagre-Dqp-ns8F.js +1 -0
  2423. package/payload/server/public/assets/dagre-KV5264BT-ZgWWXPLc.js +4 -0
  2424. package/payload/server/public/assets/data-gy6QH9c1.js +1 -0
  2425. package/payload/server/public/assets/defaultLocale-B9aLeOTg.js +1 -0
  2426. package/payload/server/public/assets/diagram-5BDNPKRD-CTX5-ScM.js +10 -0
  2427. package/payload/server/public/assets/diagram-G4DWMVQ6-BovIsO6H.js +24 -0
  2428. package/payload/server/public/assets/diagram-MMDJMWI5-DcETsQy-.js +43 -0
  2429. package/payload/server/public/assets/diagram-TYMM5635-yyq6peoZ.js +24 -0
  2430. package/payload/server/public/assets/dist-DB-VPj_8.js +1 -0
  2431. package/payload/server/public/assets/dm-sans-latin-400-normal-BwCSEQnW.woff +0 -0
  2432. package/payload/server/public/assets/dm-sans-latin-400-normal-CW0RaeGs.woff2 +0 -0
  2433. package/payload/server/public/assets/dm-sans-latin-500-normal-B9HHJjqV.woff2 +0 -0
  2434. package/payload/server/public/assets/dm-sans-latin-500-normal-Dr3UlScf.woff +0 -0
  2435. package/payload/server/public/assets/dm-sans-latin-ext-400-normal-BjWJ59Pq.woff +0 -0
  2436. package/payload/server/public/assets/dm-sans-latin-ext-400-normal-BtiwyxMk.woff2 +0 -0
  2437. package/payload/server/public/assets/dm-sans-latin-ext-500-normal-BJfUCQsA.woff2 +0 -0
  2438. package/payload/server/public/assets/dm-sans-latin-ext-500-normal-DR84L5F-.woff +0 -0
  2439. package/payload/server/public/assets/erDiagram-SMLLAGMA-CiNToftB.js +85 -0
  2440. package/payload/server/public/assets/flatten-BtFI066E.js +1 -0
  2441. package/payload/server/public/assets/flowDiagram-DWJPFMVM-Xnl3SpIM.js +162 -0
  2442. package/payload/server/public/assets/ganttDiagram-T4ZO3ILL-C1iyWe0f.js +292 -0
  2443. package/payload/server/public/assets/gitGraph-7Q5UKJZL-CNs-LD5i.js +1 -0
  2444. package/payload/server/public/assets/gitGraphDiagram-UUTBAWPF-D97pbMQb.js +106 -0
  2445. package/payload/server/public/assets/graph-labels-cZu4pK16.js +1 -0
  2446. package/payload/server/public/assets/graph-qz5tFKqU.js +51 -0
  2447. package/payload/server/public/assets/graphlib-Lq8ijgON.js +1 -0
  2448. package/payload/server/public/assets/info-OMHHGYJF-DsTNigSS.js +1 -0
  2449. package/payload/server/public/assets/infoDiagram-42DDH7IO-C_OarRTA.js +2 -0
  2450. package/payload/server/public/assets/init-BNFRgqHM.js +1 -0
  2451. package/payload/server/public/assets/inter-cyrillic-400-normal-HOLc17fK.woff +0 -0
  2452. package/payload/server/public/assets/inter-cyrillic-400-normal-obahsSVq.woff2 +0 -0
  2453. package/payload/server/public/assets/inter-cyrillic-500-normal-BasfLYem.woff2 +0 -0
  2454. package/payload/server/public/assets/inter-cyrillic-500-normal-CxZf_p3X.woff +0 -0
  2455. package/payload/server/public/assets/inter-cyrillic-ext-400-normal-BQZuk6qB.woff2 +0 -0
  2456. package/payload/server/public/assets/inter-cyrillic-ext-400-normal-DQukG94-.woff +0 -0
  2457. package/payload/server/public/assets/inter-cyrillic-ext-500-normal-B0yAr1jD.woff2 +0 -0
  2458. package/payload/server/public/assets/inter-cyrillic-ext-500-normal-BmqWE9Dz.woff +0 -0
  2459. package/payload/server/public/assets/inter-greek-400-normal-B4URO6DV.woff2 +0 -0
  2460. package/payload/server/public/assets/inter-greek-400-normal-q2sYcFCs.woff +0 -0
  2461. package/payload/server/public/assets/inter-greek-500-normal-BIZE56-Y.woff2 +0 -0
  2462. package/payload/server/public/assets/inter-greek-500-normal-Xzm54t5V.woff +0 -0
  2463. package/payload/server/public/assets/inter-greek-ext-400-normal-DGGRlc-M.woff2 +0 -0
  2464. package/payload/server/public/assets/inter-greek-ext-400-normal-KugGGMne.woff +0 -0
  2465. package/payload/server/public/assets/inter-greek-ext-500-normal-2j5mBUwD.woff +0 -0
  2466. package/payload/server/public/assets/inter-greek-ext-500-normal-C4iEst2y.woff2 +0 -0
  2467. package/payload/server/public/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  2468. package/payload/server/public/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  2469. package/payload/server/public/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  2470. package/payload/server/public/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  2471. package/payload/server/public/assets/inter-latin-ext-400-normal-77YHD8bZ.woff +0 -0
  2472. package/payload/server/public/assets/inter-latin-ext-400-normal-C1nco2VV.woff2 +0 -0
  2473. package/payload/server/public/assets/inter-latin-ext-500-normal-BxGbmqWO.woff +0 -0
  2474. package/payload/server/public/assets/inter-latin-ext-500-normal-CV4jyFjo.woff2 +0 -0
  2475. package/payload/server/public/assets/inter-vietnamese-400-normal-Bbgyi5SW.woff +0 -0
  2476. package/payload/server/public/assets/inter-vietnamese-400-normal-DMkecbls.woff2 +0 -0
  2477. package/payload/server/public/assets/inter-vietnamese-500-normal-DOriooB6.woff2 +0 -0
  2478. package/payload/server/public/assets/inter-vietnamese-500-normal-mJboJaSs.woff +0 -0
  2479. package/payload/server/public/assets/isEmpty-D6QovjYR.js +1 -0
  2480. package/payload/server/public/assets/ishikawaDiagram-UXIWVN3A-B8XBdjJn.js +70 -0
  2481. package/payload/server/public/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
  2482. package/payload/server/public/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
  2483. package/payload/server/public/assets/jetbrains-mono-cyrillic-500-normal-DJqRU3vO.woff +0 -0
  2484. package/payload/server/public/assets/jetbrains-mono-cyrillic-500-normal-DmUKJPL_.woff2 +0 -0
  2485. package/payload/server/public/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
  2486. package/payload/server/public/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
  2487. package/payload/server/public/assets/jetbrains-mono-greek-500-normal-D7SFKleX.woff +0 -0
  2488. package/payload/server/public/assets/jetbrains-mono-greek-500-normal-JpySY46c.woff2 +0 -0
  2489. package/payload/server/public/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
  2490. package/payload/server/public/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  2491. package/payload/server/public/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  2492. package/payload/server/public/assets/jetbrains-mono-latin-500-normal-CJOVTJB7.woff +0 -0
  2493. package/payload/server/public/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
  2494. package/payload/server/public/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
  2495. package/payload/server/public/assets/jetbrains-mono-latin-ext-500-normal-Cut-4mMH.woff2 +0 -0
  2496. package/payload/server/public/assets/jetbrains-mono-latin-ext-500-normal-ckzbgY84.woff +0 -0
  2497. package/payload/server/public/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
  2498. package/payload/server/public/assets/jetbrains-mono-vietnamese-500-normal-DNRqzVM1.woff +0 -0
  2499. package/payload/server/public/assets/journeyDiagram-VCZTEJTY-CZYbiOaQ.js +139 -0
  2500. package/payload/server/public/assets/kanban-definition-6JOO6SKY-B1PybFoh.js +89 -0
  2501. package/payload/server/public/assets/katex-B-EfS3nw.js +257 -0
  2502. package/payload/server/public/assets/line-D-tw3hHp.js +1 -0
  2503. package/payload/server/public/assets/linear-BHhXD3cd.js +1 -0
  2504. package/payload/server/public/assets/mermaid-parser.core-C9RAnysF.js +4 -0
  2505. package/payload/server/public/assets/mermaid.core-B532LT1r.js +11 -0
  2506. package/payload/server/public/assets/mindmap-definition-QFDTVHPH-DGlgeeTV.js +96 -0
  2507. package/payload/server/public/assets/newsreader-latin-300-normal-AOSWdb_s.woff +0 -0
  2508. package/payload/server/public/assets/newsreader-latin-300-normal-FGBQ0wlI.woff2 +0 -0
  2509. package/payload/server/public/assets/newsreader-latin-400-normal-BFBkh4jY.woff2 +0 -0
  2510. package/payload/server/public/assets/newsreader-latin-400-normal-gRTjlS2D.woff +0 -0
  2511. package/payload/server/public/assets/newsreader-latin-500-normal-B66TYsaK.woff2 +0 -0
  2512. package/payload/server/public/assets/newsreader-latin-500-normal-DFwuUcdu.woff +0 -0
  2513. package/payload/server/public/assets/newsreader-latin-ext-300-normal-CFtw49Zd.woff +0 -0
  2514. package/payload/server/public/assets/newsreader-latin-ext-300-normal-DRMzurxT.woff2 +0 -0
  2515. package/payload/server/public/assets/newsreader-latin-ext-400-normal-DYA1XoQK.woff +0 -0
  2516. package/payload/server/public/assets/newsreader-latin-ext-400-normal-svq1FPys.woff2 +0 -0
  2517. package/payload/server/public/assets/newsreader-latin-ext-500-normal-BNHmvKvI.woff2 +0 -0
  2518. package/payload/server/public/assets/newsreader-latin-ext-500-normal-CZruMFou.woff +0 -0
  2519. package/payload/server/public/assets/newsreader-vietnamese-300-normal-CsrIkm-V.woff +0 -0
  2520. package/payload/server/public/assets/newsreader-vietnamese-300-normal-D3VHEe81.woff2 +0 -0
  2521. package/payload/server/public/assets/newsreader-vietnamese-400-normal-BekUZro8.woff +0 -0
  2522. package/payload/server/public/assets/newsreader-vietnamese-400-normal-DdKr49mV.woff2 +0 -0
  2523. package/payload/server/public/assets/newsreader-vietnamese-500-normal-BEAbKU8A.woff +0 -0
  2524. package/payload/server/public/assets/newsreader-vietnamese-500-normal-CL6a8tp2.woff2 +0 -0
  2525. package/payload/server/public/assets/ordinal-Bl-aM5b9.js +1 -0
  2526. package/payload/server/public/assets/packet-4T2RLAQJ-DGES22b-.js +1 -0
  2527. package/payload/server/public/assets/path-DmWWdwp7.js +1 -0
  2528. package/payload/server/public/assets/pie-ZZUOXDRM-ChKeDbzt.js +1 -0
  2529. package/payload/server/public/assets/pieDiagram-DEJITSTG-DV9FIWko.js +30 -0
  2530. package/payload/server/public/assets/public-Bu2_Xi0a.js +35 -0
  2531. package/payload/server/public/assets/public-vnj7OhQj.css +1 -0
  2532. package/payload/server/public/assets/quadrantDiagram-34T5L4WZ-Betwya4l.js +7 -0
  2533. package/payload/server/public/assets/radar-PYXPWWZC-FGG5Fs7N.js +1 -0
  2534. package/payload/server/public/assets/reduce-BD4xUd2c.js +1 -0
  2535. package/payload/server/public/assets/requirementDiagram-MS252O5E-Cq3vODdg.js +84 -0
  2536. package/payload/server/public/assets/rough.esm-Ci7Kjt46.js +1 -0
  2537. package/payload/server/public/assets/sankeyDiagram-XADWPNL6-x8krXWcS.js +10 -0
  2538. package/payload/server/public/assets/sequenceDiagram-FGHM5R23-i-_uH-Yl.js +157 -0
  2539. package/payload/server/public/assets/src-C1jfwBq0.js +1 -0
  2540. package/payload/server/public/assets/stateDiagram-FHFEXIEX-il4KqSgI.js +1 -0
  2541. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-B6zNJ6Tv.js +1 -0
  2542. package/payload/server/public/assets/timeline-definition-GMOUNBTQ-DATdZkA5.js +120 -0
  2543. package/payload/server/public/assets/treeView-SZITEDCU-VAQQdbtf.js +1 -0
  2544. package/payload/server/public/assets/treemap-W4RFUUIX-DKchO3zI.js +1 -0
  2545. package/payload/server/public/assets/useSelectionMode-A5KItZ2T.js +13 -0
  2546. package/payload/server/public/assets/useSelectionMode-C-Ojh7W9.css +1 -0
  2547. package/payload/server/public/assets/vennDiagram-DHZGUBPP-BJh9tJTt.js +34 -0
  2548. package/payload/server/public/assets/wardley-RL74JXVD-CBGtx0bS.js +1 -0
  2549. package/payload/server/public/assets/wardleyDiagram-NUSXRM2D-EMN1Hdfg.js +20 -0
  2550. package/payload/server/public/assets/xychartDiagram-5P7HB3ND-DbUWXa7T.js +7 -0
  2551. package/payload/server/public/brand/claude.png +0 -0
  2552. package/payload/server/public/brand/favicon.ico +0 -0
  2553. package/payload/server/public/brand/maxy-black.png +0 -0
  2554. package/payload/server/public/brand/maxy-horizontal.png +0 -0
  2555. package/payload/server/public/brand/maxy-monochrome.png +0 -0
  2556. package/payload/server/public/brand/maxy-square.png +0 -0
  2557. package/payload/server/public/brand/maxy.png +0 -0
  2558. package/payload/server/public/brand/star.png +0 -0
  2559. package/payload/server/public/brand-constants.json +8 -0
  2560. package/payload/server/public/brand-defaults.css +12 -0
  2561. package/payload/server/public/consent.css +97 -0
  2562. package/payload/server/public/consent.js +259 -0
  2563. package/payload/server/public/data.html +19 -0
  2564. package/payload/server/public/favicon.ico +0 -0
  2565. package/payload/server/public/graph.html +20 -0
  2566. package/payload/server/public/index.html +21 -0
  2567. package/payload/server/public/privacy.html +129 -0
  2568. package/payload/server/public/public.html +19 -0
  2569. package/payload/server/public/robots.txt +5 -0
  2570. package/payload/server/public/v.js +244 -0
  2571. package/payload/server/public/vnc-popout.html +63 -0
  2572. package/payload/server/server-init.cjs +197 -0
  2573. package/payload/server/server.js +21128 -0
package/dist/index.js ADDED
@@ -0,0 +1,4048 @@
1
+ #!/usr/bin/env node
2
+ import { execFileSync, spawn, spawnSync } from "node:child_process";
3
+ import { existsSync, mkdirSync, writeFileSync, cpSync, readFileSync, rmSync, readdirSync, appendFileSync, openSync, closeSync, chmodSync, statSync, realpathSync } from "node:fs";
4
+ import { registerSpecialistAgentsAt, SpecialistSymlinkCollision } from "./specialist-registration.js";
5
+ import { seedBypassPermissionsSettings, assertBypassPermissionsSeed } from "./permissions-seed.js";
6
+ import { resolve, join, dirname } from "node:path";
7
+ import { randomBytes } from "node:crypto";
8
+ import { resolveInstallPortFromFs, buildMaxyUnitFile, buildClaudeSessionManagerUnitFile, buildClaudePtysSliceUnitFile, buildCloudflaredSliceUnitFile } from "./port-resolution.js";
9
+ import { validateTierFlag, validateEntitlementBase64, applyTierToAccountConfig, entitlementPath } from "./tier-flag.js";
10
+ import { parseOsRelease, isUbuntuLike as isUbuntuLikePure, parseAptCacheCandidate, decideAptResolution, } from "./apt-resolve.js";
11
+ import { findPeerBrandOnDefaultNeo4jPort } from "./peer-brand-detect.js";
12
+ import { runInitLogging } from "./init-logging.js";
13
+ import { requireSupportedPlatform } from "./platform-detect.js";
14
+ import { renderPlist } from "./launchd-plist.js";
15
+ import { installAllBrewPackages } from "./brew-install.js";
16
+ import { parseSwVers, isSupportedMacosVersion } from "./macos-version.js";
17
+ import { decideChromiumAction, isSnapConfinedPath } from "./snap-chromium.js";
18
+ import { classifyPortHolder } from "./preflight-port-classifier.js";
19
+ import { parsePluginList, computeInstallActions, parseExternalPlugins, } from "./lib/plugin-install.js";
20
+ import { findPremiumMcpDirs } from "./lib/premium-mcp-discover.js";
21
+ import { pickLanInterface, mergeSmbConf, formatSambaMarker, } from "./samba-provision.js";
22
+ import { networkInterfaces, userInfo } from "node:os";
23
+ const PAYLOAD_DIR = resolve(import.meta.dirname, "../payload");
24
+ // Brand manifest — read from payload to derive all brand-specific installation values.
25
+ // The bundler stamps brand.json into the payload at build time.
26
+ const BRAND_PATH = join(PAYLOAD_DIR, "platform", "config", "brand.json");
27
+ if (!existsSync(BRAND_PATH)) {
28
+ console.error("Setup failed: brand.json not found in payload (package may be corrupted)");
29
+ console.error("FATAL: brand.json not found in payload. Package may be corrupted.");
30
+ process.exit(1);
31
+ }
32
+ let BRAND;
33
+ try {
34
+ BRAND = JSON.parse(readFileSync(BRAND_PATH, "utf-8"));
35
+ }
36
+ catch (err) {
37
+ console.error(`Setup failed: failed to parse brand.json: ${err.message}`);
38
+ console.error(`FATAL: Failed to parse brand.json: ${err.message}`);
39
+ process.exit(1);
40
+ }
41
+ const INSTALL_DIR = resolve(process.env.HOME ?? "/root", BRAND.installDir);
42
+ const PERSIST_DIR = resolve(process.env.HOME ?? "/root", BRAND.configDir);
43
+ const LOG_DIR = join(PERSIST_DIR, "logs");
44
+ const LOG_FILE = join(LOG_DIR, `install-${new Date().toISOString().replace(/[:.]/g, "-")}.log`);
45
+ // every `claude plugin` shellout must read/write the per-brand
46
+ // CLAUDE_CONFIG_DIR that the systemd unit at port-resolution.ts:229,286 uses
47
+ // at runtime. Without this override, the installer writes marketplaces and
48
+ // enabledPlugins to $HOME/.claude/settings.json (user-default), and the
49
+ // PTY spawned by the session-manager sees an empty config dir — plugins
50
+ // the operator turned on are invisible to the agent.
51
+ const CLAUDE_CONFIG_DIR = join(PERSIST_DIR, ".claude");
52
+ function claudePluginEnv() {
53
+ return { ...process.env, CLAUDE_CONFIG_DIR };
54
+ }
55
+ /** Known brand hostnames in the Maxy ecosystem. Each brand ships a main unit
56
+ * (`<hostname>.service`) and a per-brand edge unit
57
+ * (`<hostname>-edge.service`). Peer-brand detection matches only these
58
+ * filenames — stale units,
59
+ * gnome-keyring disable markers, and unrelated user services are not peer
60
+ * evidence. When a third brand is added under `brands/`, append its hostname
61
+ * here AND in the matching constant in `uninstall.ts` (intentional duplication
62
+ * per `uninstall.ts:` "Shell helpers (duplicated from index.ts ...)" policy). */
63
+ const KNOWN_BRAND_HOSTNAMES = ["maxy", "maxy-code", "realagent", "realagent-code", "maxy-2", "maxy-3", "maxy-4"];
64
+ // The device's actual hostname — may differ from BRAND.hostname if the user customized it.
65
+ // Updated by installSystemDeps() after hostname setup; used for user-facing URLs.
66
+ let DEVICE_HOSTNAME = BRAND.hostname;
67
+ // absolute path to the non-snap Chromium binary chosen during
68
+ // installSystemDeps(). Defaults to /usr/bin/chromium so non-Linux installs
69
+ // (which never call ensureNonSnapChromium) and the systemd unit's
70
+ // PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH still see a sensible value. On Linux,
71
+ // installSystemDeps() always overwrites this — either /usr/bin/chromium (Pi
72
+ // Bookworm: real .deb) or /usr/bin/google-chrome-stable (Ubuntu Noble laptop:
73
+ // snap-confined chromium replaced). Read by writeChromiumBinaryPathFile()
74
+ // and threaded into buildMaxyUnitFile() so the chromium-binary.path config
75
+ // file, the systemd unit's PLAYWRIGHT env var, and vnc.sh's runtime resolver
76
+ // all agree on one absolute path.
77
+ let RESOLVED_CHROMIUM_BIN = "/usr/bin/chromium";
78
+ // npm flags tuned for Raspberry Pi — reduce parallelism, increase patience
79
+ const NPM_NET_FLAGS = [
80
+ "--fetch-retries=5",
81
+ "--fetch-retry-mintimeout=30000",
82
+ "--fetch-retry-maxtimeout=120000",
83
+ "--maxsockets=3",
84
+ ];
85
+ // ---------------------------------------------------------------------------
86
+ // Logging — timestamped to console AND persistent log file
87
+ // ---------------------------------------------------------------------------
88
+ function initLogging() {
89
+ runInitLogging({
90
+ logDir: LOG_DIR,
91
+ logFile: LOG_FILE,
92
+ persistDir: PERSIST_DIR,
93
+ headerLines: [
94
+ "",
95
+ "=".repeat(64),
96
+ ` ${BRAND.productName} Install Log — ${new Date().toISOString()}`,
97
+ ` Node ${process.version} | ${process.platform} ${process.arch}`,
98
+ "=".repeat(64),
99
+ "",
100
+ ],
101
+ });
102
+ }
103
+ function logFile(msg) {
104
+ try {
105
+ appendFileSync(LOG_FILE, `[${new Date().toISOString()}] ${msg}\n`);
106
+ }
107
+ catch { /* fs full */ }
108
+ }
109
+ // Mirror all console output into the log file
110
+ const _log = console.log;
111
+ const _err = console.error;
112
+ console.log = (...args) => { _log(...args); logFile(args.map(String).join(" ")); };
113
+ console.error = (...args) => { _err(...args); logFile(`[ERROR] ${args.map(String).join(" ")}`); };
114
+ // ---------------------------------------------------------------------------
115
+ // Diagnostics — system state snapshot for post-mortem analysis
116
+ // ---------------------------------------------------------------------------
117
+ function logDiagnostics(label) {
118
+ logFile(`\n--- Diagnostics: ${label} ---`);
119
+ if (!isLinux()) {
120
+ logFile(" (not Linux — limited diagnostics)");
121
+ return;
122
+ }
123
+ const run = (cmd, args) => {
124
+ const r = spawnSync(cmd, args, { encoding: "utf-8", stdio: "pipe", timeout: 10_000 });
125
+ return (r.stdout || r.stderr || "").trim();
126
+ };
127
+ logFile(`Disk:\n${run("df", ["-h", "/", "/tmp"])}`);
128
+ logFile(`Memory:\n${run("free", ["-h"])}`);
129
+ logFile(`Uptime: ${run("uptime", [])}`);
130
+ for (const host of ["registry.npmjs.org", "github.com"]) {
131
+ const dns = spawnSync("host", ["-W", "5", host], { encoding: "utf-8", stdio: "pipe", timeout: 10_000 });
132
+ logFile(`DNS ${host}: ${dns.status === 0 ? "OK" : "FAIL"} — ${(dns.stdout || dns.stderr || "").trim().split("\n")[0]}`);
133
+ }
134
+ const curl = spawnSync("curl", [
135
+ "-sf", "-o", "/dev/null",
136
+ "-w", "HTTP %{http_code} in %{time_total}s (dns: %{time_namelookup}s, connect: %{time_connect}s)",
137
+ "--connect-timeout", "10",
138
+ "https://registry.npmjs.org/",
139
+ ], { encoding: "utf-8", stdio: "pipe", timeout: 15_000 });
140
+ logFile(`Registry HTTP: ${curl.stdout?.trim() || `FAIL — ${curl.stderr?.trim()}`}`);
141
+ logFile(`--- End Diagnostics ---\n`);
142
+ }
143
+ /** Append the most recent npm debug log into our install log for post-mortem. */
144
+ function captureNpmDebugLog() {
145
+ const logsDir = resolve(process.env.HOME ?? "/root", ".npm/_logs");
146
+ if (!existsSync(logsDir))
147
+ return;
148
+ try {
149
+ const files = readdirSync(logsDir).filter(f => f.endsWith("-debug-0.log")).sort().reverse();
150
+ if (files[0]) {
151
+ const content = readFileSync(join(logsDir, files[0]), "utf-8");
152
+ logFile(`\n--- npm debug log: ${files[0]} (last 200 lines) ---`);
153
+ const lines = content.split("\n");
154
+ logFile(lines.slice(Math.max(0, lines.length - 200)).join("\n"));
155
+ logFile(`--- end npm debug log ---\n`);
156
+ }
157
+ }
158
+ catch { /* ignore */ }
159
+ }
160
+ // ---------------------------------------------------------------------------
161
+ // Helpers
162
+ // ---------------------------------------------------------------------------
163
+ function log(step, total, message) {
164
+ console.log(`[${step}/${total}] ${message}`);
165
+ }
166
+ function shell(command, args, options) {
167
+ const cmd = options?.sudo ? "sudo" : command;
168
+ const cmdArgs = options?.sudo ? [command, ...args] : args;
169
+ const start = Date.now();
170
+ // Redaction: callers handling secrets pass redact: true so the
171
+ // wrapper records the command name only, not the secret-bearing args. The
172
+ // child process still receives the real args via spawnSync below; only the
173
+ // install log line is sanitised. The grep-able audit shape stays:
174
+ // > sudo neo4j-admin dbms set-initial-password [REDACTED]
175
+ const loggedArgs = options?.redact
176
+ ? `${cmdArgs.slice(0, options?.sudo ? 4 : 3).join(" ")} [REDACTED]`
177
+ : cmdArgs.join(" ");
178
+ logFile(`> ${cmd} ${loggedArgs}${options?.cwd ? ` [cwd: ${options.cwd}]` : ""}`);
179
+ const result = spawnSync(cmd, cmdArgs, {
180
+ stdio: "inherit",
181
+ timeout: options?.timeout ?? 300_000,
182
+ cwd: options?.cwd,
183
+ env: options?.env,
184
+ });
185
+ const dur = ((Date.now() - start) / 1000).toFixed(1);
186
+ // bestEffort: tear-down ops on units/state that may or may not
187
+ // exist (stop/disable a system service we may never have started, reset-failed
188
+ // a freshly-created unit) log the non-zero exit but do not throw. Reserved
189
+ // for the "may not exist" pattern only — never use for ops that must succeed.
190
+ if (result.signal) {
191
+ logFile(` KILLED (${result.signal}) after ${dur}s`);
192
+ if (options?.bestEffort)
193
+ return;
194
+ throw new Error(`Command killed (${result.signal}) after ${dur}s: ${cmd} ${cmdArgs.join(" ")}`);
195
+ }
196
+ if (result.status !== 0) {
197
+ logFile(` ${options?.bestEffort ? "best-effort non-zero" : "FAILED"} (exit ${result.status}) after ${dur}s`);
198
+ if (options?.bestEffort)
199
+ return;
200
+ throw new Error(`Command failed (exit ${result.status}) after ${dur}s: ${cmd} ${cmdArgs.join(" ")}`);
201
+ }
202
+ logFile(` OK in ${dur}s`);
203
+ }
204
+ /** Wait until DNS resolves for a host. Returns true if recovered. */
205
+ function waitForDns(host, maxSec = 60) {
206
+ for (let elapsed = 0; elapsed < maxSec; elapsed += 5) {
207
+ const r = spawnSync("host", ["-W", "3", host], { stdio: "pipe", timeout: 5_000 });
208
+ if (r.status === 0) {
209
+ logFile(` DNS ${host}: recovered after ${elapsed}s`);
210
+ return true;
211
+ }
212
+ console.log(` DNS ${host} not resolving — waiting (${elapsed}s/${maxSec}s)...`);
213
+ spawnSync("sleep", ["5"]);
214
+ }
215
+ return false;
216
+ }
217
+ /** Retry a shell command with exponential backoff. Runs network diagnostics between attempts. */
218
+ function shellRetry(command, args, options, maxAttempts = 3, backoffSec = 20) {
219
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
220
+ try {
221
+ shell(command, args, options);
222
+ return;
223
+ }
224
+ catch (err) {
225
+ const msg = err instanceof Error ? err.message : String(err);
226
+ logFile(` Attempt ${attempt}/${maxAttempts} error: ${msg}`);
227
+ if (attempt === maxAttempts) {
228
+ console.error(` All ${maxAttempts} attempts failed.`);
229
+ logDiagnostics(`final failure — ${command}`);
230
+ if (command === "npm")
231
+ captureNpmDebugLog();
232
+ throw err;
233
+ }
234
+ const wait = backoffSec * attempt;
235
+ console.log(` Attempt ${attempt}/${maxAttempts} failed. Retrying in ${wait}s...`);
236
+ // On network errors, diagnose and wait for DNS recovery before retrying
237
+ if (/ETIMEDOUT|EAI_AGAIN|ECONNRESET|ENOTFOUND|ENETUNREACH/.test(msg)) {
238
+ console.log(" Network error — running diagnostics...");
239
+ logDiagnostics(`network failure — attempt ${attempt}`);
240
+ waitForDns("registry.npmjs.org");
241
+ }
242
+ if (command === "npm")
243
+ captureNpmDebugLog();
244
+ spawnSync("sleep", [String(wait)]);
245
+ }
246
+ }
247
+ }
248
+ function commandExists(cmd) {
249
+ try {
250
+ execFileSync("which", [cmd], { stdio: "pipe" });
251
+ return true;
252
+ }
253
+ catch {
254
+ return false;
255
+ }
256
+ }
257
+ function nodeVersion() {
258
+ try {
259
+ const v = execFileSync("node", ["-v"], { encoding: "utf-8" }).trim();
260
+ return parseInt(v.replace("v", "").split(".")[0], 10);
261
+ }
262
+ catch {
263
+ return 0;
264
+ }
265
+ }
266
+ function isLinux() {
267
+ return process.platform === "linux";
268
+ }
269
+ function isArm64() {
270
+ return process.arch === "arm64";
271
+ }
272
+ /** Check whether non-interactive sudo is available (passwordless or cached credentials). */
273
+ function canSudo() {
274
+ const result = spawnSync("sudo", ["-n", "true"], { stdio: "pipe", timeout: 5_000 });
275
+ return result.status === 0;
276
+ }
277
+ // verified-not-asserted apt-dep reconciliation.
278
+ // resolve package-name aliases before probing dpkg, so the
279
+ // post-install check no longer false-negatives when apt resolves a virtual
280
+ // name (e.g. Noble's `chromium` → `chromium-browser`).
281
+ // UBUNTU_ALIASES, parseOsRelease, isUbuntuLike, and decideAptResolution moved
282
+ // to./apt-resolve.ts. The pure logic lives there so a unit test
283
+ // can hit every branch without spawning real apt/dpkg or reading
284
+ // /etc/os-release. The thin wrappers below feed real spawn + fs results into
285
+ // that pure decision.
286
+ function readOsRelease() {
287
+ try {
288
+ return parseOsRelease(readFileSync("/etc/os-release", "utf-8"));
289
+ }
290
+ catch {
291
+ return {};
292
+ }
293
+ }
294
+ /** Summarise `apt-cache policy` output for diagnostics — one token per package. */
295
+ function aptCachePolicySummary(pkg) {
296
+ const r = spawnSync("apt-cache", ["policy", pkg], { stdio: "pipe", encoding: "utf-8", timeout: 5_000 });
297
+ if (r.status !== 0)
298
+ return "policy-spawn-failed";
299
+ const cand = parseAptCacheCandidate(r.stdout ?? "");
300
+ if (cand === null)
301
+ return "no-candidate-line";
302
+ return cand === "(none)" ? "candidate-none" : `candidate=${cand}`;
303
+ }
304
+ /**
305
+ * map an apt-level package name to the concrete name dpkg will
306
+ * record after install. Resolution order:
307
+ * 1. `dpkg -s pkg` exits 0 → name is concrete and installed; return pkg.
308
+ * 2. `apt-cache policy pkg` reports a real Candidate → concrete-but-missing;
309
+ * return pkg (apt-get install + post-check will use the same name).
310
+ * 3. `apt-cache policy pkg` reports `Candidate: (none)` and `pkg` is in
311
+ * UBUNTU_ALIASES on an Ubuntu-like host → return the alias. Log the
312
+ * resolution so the install log answers "what did apt resolve this to?".
313
+ * 4. Otherwise return pkg unchanged — the post-check will throw loudly,
314
+ * preserving the fail-loud contract for genuinely missing packages.
315
+ */
316
+ function resolveAptName(pkg) {
317
+ const dpkg = spawnSync("dpkg", ["-s", pkg], { stdio: "pipe", timeout: 5_000 });
318
+ const dpkgInstalled = dpkg.status === 0;
319
+ // Short-circuit: when dpkg already records the name as installed, skip the
320
+ // apt-cache + os-release work — `decideAptResolution` returns pkg unchanged
321
+ // anyway and the extra spawn would burn ~10 ms per already-installed
322
+ // package across every `pkgsMissing` pass.
323
+ if (dpkgInstalled)
324
+ return pkg;
325
+ const policy = spawnSync("apt-cache", ["policy", pkg], {
326
+ stdio: "pipe", encoding: "utf-8", timeout: 5_000,
327
+ });
328
+ const aptCandidate = policy.status === 0
329
+ ? parseAptCacheCandidate(policy.stdout ?? "")
330
+ : null;
331
+ const os = readOsRelease();
332
+ const decision = decideAptResolution({
333
+ pkg,
334
+ dpkgInstalled,
335
+ aptCandidate,
336
+ ubuntuLike: isUbuntuLikePure(os),
337
+ distro: `${os.ID ?? "unknown"}-${os.VERSION_CODENAME ?? "unknown"}`,
338
+ });
339
+ if (decision.log)
340
+ logFile(decision.log);
341
+ return decision.resolved;
342
+ }
343
+ /** Probe runtime binary presence on PATH (independent of dpkg-recorded state). */
344
+ function commandVPath(pkg) {
345
+ const r = spawnSync("which", [pkg], { stdio: "pipe", encoding: "utf-8", timeout: 5_000 });
346
+ return r.status === 0 ? (r.stdout ?? "").trim() || "missing" : "missing";
347
+ }
348
+ /** Probe snap-recorded state for a name (snap lives outside dpkg). */
349
+ function snapStatus(pkg) {
350
+ const r = spawnSync("snap", ["list", pkg], { stdio: "pipe", encoding: "utf-8", timeout: 5_000 });
351
+ if (r.status !== 0)
352
+ return "none";
353
+ const line = (r.stdout ?? "").split("\n").find((l) => l.startsWith(pkg));
354
+ return line ? line.split(/\s+/).slice(0, 2).join(" ") : "none";
355
+ }
356
+ /**
357
+ * Returns the subset of `pkgs` that are not currently installed, after
358
+ * alias resolution. Uses `dpkg -s <resolved>` per package (exit 0 = installed,
359
+ * any non-zero = missing) so we never parse dpkg's prose output for control
360
+ * flow (feedback_no_stdout_parsing_for_control_flow.md). The operator-facing
361
+ * name stays the original `pkg` — the resolution is logged but not renamed
362
+ * in the returned list, so diagnostics match what the installer declared.
363
+ */
364
+ function pkgsMissing(pkgs) {
365
+ return pkgs.filter((p) => {
366
+ const resolved = resolveAptName(p);
367
+ const r = spawnSync("dpkg", ["-s", resolved], { stdio: "pipe", timeout: 5_000 });
368
+ return r.status !== 0;
369
+ });
370
+ }
371
+ /**
372
+ * Install a logical group of apt packages, then verify each one landed in
373
+ * dpkg's installed state. The post-install `dpkg -s` probe catches the
374
+ * partial-failure class where `apt-get install` returns 0 but a package did
375
+ * not actually install — silent regressions that would otherwise only
376
+ * surface at runtime when the binary is missing.
377
+ *
378
+ * Resolves each package through `resolveAptName` before both the install
379
+ * command and the post-check, so alias packages pass through
380
+ * cleanly on distros where the apt-level name differs from the dpkg-recorded
381
+ * name (e.g. Noble's chromium → chromium-browser). Resolution is computed
382
+ * once per package and reused across install, post-check, and error
383
+ * diagnostics — three spawnSync chains per package, not nine on failure.
384
+ */
385
+ function installAptGroup(label, pkgs) {
386
+ const pairs = pkgs.map((original) => ({ original, resolved: resolveAptName(original) }));
387
+ logFile(` apt install (${label}): ${pairs.map((x) => x.resolved).join(" ")}`);
388
+ console.log(" [privileged] apt-get install");
389
+ shell("apt-get", ["install", "-y", ...pairs.map((x) => x.resolved)], { sudo: true });
390
+ const stillMissing = pairs.filter(({ resolved }) => {
391
+ const r = spawnSync("dpkg", ["-s", resolved], { stdio: "pipe", timeout: 5_000 });
392
+ return r.status !== 0;
393
+ });
394
+ if (stillMissing.length > 0) {
395
+ const diag = stillMissing.map(({ original, resolved }) => `${original} (resolved-name=${resolved}, apt-cache-policy=${aptCachePolicySummary(original)}, command-v=${commandVPath(original)}, snap-status=${snapStatus(resolved)})`).join("; ");
396
+ throw new Error(`apt-get install (${label}) returned 0 but packages are still not installed per dpkg -s: ${diag}`);
397
+ }
398
+ }
399
+ // ---------------------------------------------------------------------------
400
+ // Installation steps
401
+ // ---------------------------------------------------------------------------
402
+ const TOTAL = "11";
403
+ /**
404
+ * set macOS hostname via scutil. Three sequential `sudo scutil
405
+ * --set` calls (HostName, LocalHostName, ComputerName) — `hostnamectl` is
406
+ * Linux-only and `--hostname <h>` silently no-ops on darwin. All-or-nothing
407
+ * rollback within the 3-call batch: if any call fails, we restore the
408
+ * pre-batch values for the keys we already changed and re-throw. Full
409
+ * system-state rollback (avahi, /etc/hosts) is out of scope per the brief.
410
+ */
411
+ function setMacosHostnameViaScutil(hostname) {
412
+ const keys = ["HostName", "LocalHostName", "ComputerName"];
413
+ // Capture pre-batch values for rollback. Empty string is a legitimate
414
+ // scutil --get value (the key was never set) — preserve that as "" so
415
+ // rollback writes empty back rather than failing.
416
+ const previous = {};
417
+ for (const k of keys) {
418
+ const r = spawnSync("scutil", ["--get", k], { encoding: "utf-8", stdio: "pipe", timeout: 5_000 });
419
+ previous[k] = (r.stdout ?? "").trim();
420
+ }
421
+ const applied = [];
422
+ for (const k of keys) {
423
+ const r = spawnSync("sudo", ["scutil", "--set", k, hostname], { encoding: "utf-8", stdio: "inherit", timeout: 30_000 });
424
+ if (r.status !== 0) {
425
+ // Roll back any keys we already changed within this batch.
426
+ for (const done of applied) {
427
+ spawnSync("sudo", ["scutil", "--set", done, previous[done] ?? ""], { stdio: "inherit", timeout: 30_000 });
428
+ }
429
+ const stderr = r.stderr ? `: ${r.stderr.toString().trim()}` : "";
430
+ console.error(` [scutil] ${k} failed${stderr}`);
431
+ throw new Error(`scutil --set ${k} ${hostname} exited ${r.status}`);
432
+ }
433
+ applied.push(k);
434
+ }
435
+ console.log(` [scutil] HostName=${hostname} LocalHostName=${hostname} ComputerName=${hostname} set ok`);
436
+ }
437
+ /**
438
+ * detect snap-confined Chromium on Linux and install Google Chrome
439
+ * stable as the non-snap replacement. Runs after `installAptGroup("VNC stack")`
440
+ * inside `installSystemDeps`. Resolution rules live in `snap-chromium.ts`
441
+ * (pure decision); this wrapper does the spawnSync + apt-repo writes + post-
442
+ * install gate. Skipped on darwin (Maxy uses Playwright-managed Chromium per
443
+ * brew-install.ts) — RESOLVED_CHROMIUM_BIN keeps its `/usr/bin/chromium`
444
+ * default which is unused on darwin (no systemd unit).
445
+ *
446
+ * Detection: `command -v chromium` + `realpath`; an extra probe for
447
+ * `google-chrome-stable` covers re-run installs where a previous run already
448
+ * landed Chrome. Snap detection is the literal `snap` segment in the realpath
449
+ * (see isSnapConfinedPath in snap-chromium.ts) — covers the three real-world
450
+ * shapes (`/snap/bin/chromium`, `/snap/<rev>/usr/...`, `/usr/bin/snap` which
451
+ * is the snap launcher binary that `readlink -f` terminates at on Noble).
452
+ *
453
+ * Replacement: Google's signed apt repo (cryptographic verification via
454
+ * `signed-by=` GPG key) — the canonical pinned-deterministic source for
455
+ * Chrome stable. Pinning a specific Chrome version would require an out-of-
456
+ * band SHA-bump cadence and contradicts the apt-repo trust model.
457
+ *
458
+ * Post-install gate: spawn the resolved binary headless against a throwaway
459
+ * profile dir under persistDir, assert exit 0. The AppArmor denial that
460
+ * triggered the original denial was on SingletonLock writes which `--headless=new` still
461
+ * attempts, so the headless probe fires the same EACCES path that production
462
+ * VNC headed launches do — closing the post-fix-sibling-audit-skipped gap.
463
+ */
464
+ function ensureNonSnapChromium() {
465
+ if (process.platform !== "linux") {
466
+ logFile(` ensureNonSnapChromium skipped: platform=${process.platform}`);
467
+ return;
468
+ }
469
+ const which = (cmd) => {
470
+ const r = spawnSync("command", ["-v", cmd], { stdio: "pipe", encoding: "utf-8", shell: "/bin/bash", timeout: 5_000 });
471
+ if (r.status !== 0)
472
+ return null;
473
+ const out = (r.stdout ?? "").trim();
474
+ return out || null;
475
+ };
476
+ const realpath = (path) => {
477
+ if (!path)
478
+ return null;
479
+ try {
480
+ return realpathSync(path);
481
+ }
482
+ catch {
483
+ return null;
484
+ }
485
+ };
486
+ const whichChromium = which("chromium");
487
+ const whichGoogleChrome = which("google-chrome-stable");
488
+ const decision = decideChromiumAction({
489
+ platform: "linux",
490
+ whichChromium,
491
+ realpathChromium: realpath(whichChromium),
492
+ whichGoogleChrome,
493
+ realpathGoogleChrome: realpath(whichGoogleChrome),
494
+ });
495
+ logFile(` [snap-chromium] decision: ${decision.action} reason="${decision.reason}"`);
496
+ if (decision.action === "fail") {
497
+ throw new Error(`ensureNonSnapChromium: ${decision.reason}. apt install of \`chromium\` ran in installAptGroup(VNC stack) above; if its post-check passed but no chromium binary is on PATH, the system PATH is misconfigured.`);
498
+ }
499
+ if (decision.action === "install-google-chrome") {
500
+ console.log(" Detected snap-confined Chromium — installing Google Chrome stable...");
501
+ logFile(` [snap-chromium] installing google-chrome-stable from Google's signed apt repo`);
502
+ // Fetch + dearmor the signing key, write to /etc/apt/trusted.gpg.d/. Pipe
503
+ // composition runs through bash -c so the curl|gpg pipeline is one
504
+ // privileged command rather than two separate sudo escalations.
505
+ console.log(" [privileged] curl + gpg --dearmor (Google Chrome signing key)");
506
+ shell("bash", ["-c",
507
+ "set -euo pipefail; " +
508
+ "curl -fsSL https://dl.google.com/linux/linux_signing_key.pub | " +
509
+ "gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/google-chrome.gpg",
510
+ ], { sudo: true });
511
+ // Add the apt source list with `signed-by=` scoping so the key only
512
+ // verifies google-chrome-* packages, not arbitrary repo overrides. arch
513
+ // pinned to amd64 — Google does not ship arm64 Chrome for Linux.
514
+ console.log(" [privileged] tee /etc/apt/sources.list.d/google-chrome.list");
515
+ shell("bash", ["-c",
516
+ "echo 'deb [arch=amd64 signed-by=/etc/apt/trusted.gpg.d/google-chrome.gpg] " +
517
+ "http://dl.google.com/linux/chrome/deb/ stable main' " +
518
+ "> /etc/apt/sources.list.d/google-chrome.list",
519
+ ], { sudo: true });
520
+ console.log(" [privileged] apt-get update");
521
+ shell("apt-get", ["update"], { sudo: true });
522
+ installAptGroup("Google Chrome stable", ["google-chrome-stable"]);
523
+ // Re-resolve after install to capture the now-installed absolute path.
524
+ const postInstallWhich = which("google-chrome-stable");
525
+ if (!postInstallWhich) {
526
+ throw new Error("ensureNonSnapChromium: apt install of google-chrome-stable returned 0 and dpkg -s passed, but `command -v google-chrome-stable` is empty — PATH is broken.");
527
+ }
528
+ RESOLVED_CHROMIUM_BIN = postInstallWhich;
529
+ }
530
+ else {
531
+ // action === "use" — decision.resolvedPath is the existing non-snap binary
532
+ // (chromium or google-chrome-stable already installed).
533
+ if (!decision.resolvedPath) {
534
+ throw new Error(`ensureNonSnapChromium: action=use returned without resolvedPath — bug in snap-chromium.ts (input: chromium=${whichChromium} google-chrome=${whichGoogleChrome})`);
535
+ }
536
+ RESOLVED_CHROMIUM_BIN = decision.resolvedPath;
537
+ }
538
+ // Defensive: never persist a snap-confined path. If realpath of the resolved
539
+ // binary still lands under /snap/ (e.g. apt landed a snap package by mistake
540
+ // on a misconfigured device), throw before writeChromiumBinaryPathFile sees
541
+ // it — the runtime gate in vnc.sh would refuse anyway, but failing here
542
+ // surfaces the contract breach with the install context still in scope.
543
+ const finalRealpath = realpath(RESOLVED_CHROMIUM_BIN);
544
+ if (isSnapConfinedPath(finalRealpath)) {
545
+ throw new Error(`ensureNonSnapChromium: resolved Chromium binary ${RESOLVED_CHROMIUM_BIN} realpaths to ${finalRealpath} which is under /snap/ — refusing to persist.`);
546
+ }
547
+ console.log(` Chromium binary: ${RESOLVED_CHROMIUM_BIN} (realpath=${finalRealpath ?? "?"})`);
548
+ logFile(` [snap-chromium] resolved bin=${RESOLVED_CHROMIUM_BIN} realpath=${finalRealpath ?? "null"}`);
549
+ runChromiumPostInstallGate(RESOLVED_CHROMIUM_BIN);
550
+ }
551
+ /**
552
+ * post-install gate. Spawns the resolved Chromium binary headless
553
+ * against a throwaway profile dir under persistDir (`~/.{brand}/chromium-
554
+ * gate-profile/`). The AppArmor denial that triggered the task was on
555
+ * SingletonLock writes which `--headless=new` still attempts, so this probe
556
+ * fires the same EACCES path the headed VNC stack would. Cleans up the gate
557
+ * profile afterward — the live profile (`chromium-profile/`) is owned by
558
+ * vnc.sh's start_chrome and not touched here.
559
+ */
560
+ function runChromiumPostInstallGate(chromiumBin) {
561
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
562
+ const gateProfileDir = join(persistDir, "chromium-gate-profile");
563
+ mkdirSync(gateProfileDir, { recursive: true });
564
+ console.log(` Verifying ${chromiumBin} can write to ${gateProfileDir} (post-install gate)...`);
565
+ const r = spawnSync(chromiumBin, [
566
+ `--user-data-dir=${gateProfileDir}`,
567
+ "--headless=new",
568
+ "--disable-gpu",
569
+ "--no-sandbox",
570
+ "--disable-dev-shm-usage",
571
+ "--dump-dom",
572
+ "about:blank",
573
+ ], { stdio: "pipe", encoding: "utf-8", timeout: 30_000 });
574
+ // Cleanup before throwing on failure so successive runs start clean.
575
+ try {
576
+ rmSync(gateProfileDir, { recursive: true, force: true });
577
+ }
578
+ catch { /* best-effort */ }
579
+ if (r.status !== 0) {
580
+ const stderr = (r.stderr ?? "").slice(-2000);
581
+ const eaccesHit = /Permission denied/i.test(stderr) || /EACCES/i.test(stderr);
582
+ const taskRef = eaccesHit
583
+ ? "chromium-profile not writable (likely AppArmor denial on snap-confined binary). "
584
+ : "";
585
+ throw new Error(`${taskRef}Chromium post-install gate failed: ${chromiumBin} exited ${r.status} signal=${r.signal ?? "none"}. stderr:\n${stderr}`);
586
+ }
587
+ console.log(" Chromium post-install gate passed.");
588
+ logFile(` [snap-chromium] post-install gate ok: ${chromiumBin} exit=0`);
589
+ }
590
+ /**
591
+ * write the resolved Chromium absolute path to
592
+ * `<INSTALL_DIR>/platform/config/chromium-binary.path` so vnc.sh and
593
+ * writeChromiumWrapper read the same value. Called
594
+ * after deployPayload so the platform/config/ directory exists. Idempotent:
595
+ * re-running the installer with the same RESOLVED_CHROMIUM_BIN is a no-op
596
+ * write (writeFileSync overwrites in place).
597
+ */
598
+ function writeChromiumBinaryPathFile() {
599
+ if (process.platform !== "linux") {
600
+ logFile(` writeChromiumBinaryPathFile skipped: platform=${process.platform}`);
601
+ return;
602
+ }
603
+ const configDir = resolve(INSTALL_DIR, "platform/config");
604
+ mkdirSync(configDir, { recursive: true });
605
+ const target = join(configDir, "chromium-binary.path");
606
+ writeFileSync(target, RESOLVED_CHROMIUM_BIN + "\n", { mode: 0o644 });
607
+ console.log(` Wrote ${target} → ${RESOLVED_CHROMIUM_BIN}`);
608
+ logFile(` [snap-chromium] wrote ${target} contents=${RESOLVED_CHROMIUM_BIN}`);
609
+ }
610
+ function installSystemDeps() {
611
+ log("1", TOTAL, "System dependencies and network...");
612
+ const platform = requireSupportedPlatform(process.platform);
613
+ if (platform === "darwin") {
614
+ // darwin hostname via scutil when --hostname is supplied,
615
+ // otherwise preserve the existing system hostname.
616
+ if (HOSTNAME_FLAG) {
617
+ console.log(` Hostname: ${HOSTNAME_FLAG} (from --hostname flag)`);
618
+ logFile(` [create-maxy] darwin-hostname-mode=scutil-set value=${HOSTNAME_FLAG}`);
619
+ try {
620
+ setMacosHostnameViaScutil(HOSTNAME_FLAG);
621
+ DEVICE_HOSTNAME = HOSTNAME_FLAG;
622
+ }
623
+ catch (err) {
624
+ console.error(` WARNING: Failed to set hostname to '${HOSTNAME_FLAG}': ${err instanceof Error ? err.message : String(err)}`);
625
+ }
626
+ }
627
+ else {
628
+ // No flag — read the live LocalHostName so the printed URL matches mDNS
629
+ // resolution (`<LocalHostName>.local`). The `hostname` command on darwin
630
+ // returns the fully-qualified `<name>.local`, which would render the
631
+ // completion URL with a double `.local` suffix; scutil --get returns the
632
+ // bare token. No sudo, no system mutation.
633
+ const scutilGet = spawnSync("scutil", ["--get", "LocalHostName"], { encoding: "utf-8", stdio: "pipe", timeout: 5_000 });
634
+ const scutilName = ((scutilGet.stdout ?? "").trim());
635
+ if (scutilGet.status === 0 && scutilName.length > 0) {
636
+ DEVICE_HOSTNAME = scutilName;
637
+ console.log(` Hostname: ${DEVICE_HOSTNAME} (from scutil --get LocalHostName — no --hostname flag)`);
638
+ logFile(` [create-maxy] darwin-hostname-mode=scutil-get value=${DEVICE_HOSTNAME}`);
639
+ }
640
+ else {
641
+ // scutil failed or returned empty — fall back to BRAND.hostname so the
642
+ // completion URL at least matches the brand's documented .local name.
643
+ DEVICE_HOSTNAME = BRAND.hostname;
644
+ console.log(` Hostname: ${DEVICE_HOSTNAME} (brand fallback — scutil --get LocalHostName empty)`);
645
+ logFile(` [create-maxy] darwin-hostname-mode=brand-fallback value=${DEVICE_HOSTNAME} scutil-status=${scutilGet.status}`);
646
+ }
647
+ }
648
+ // macOS has no apt analogue for the VNC/WiFi-AP stacks
649
+ // (kiosk display + hostapd/dnsmasq are Pi-specific's
650
+ // out-of-scope note). mDNS is provided by the OS, so avahi-* drop out.
651
+ // Translate the remaining apt names through decideBrewResolution and
652
+ // let installAllBrewPackages handle the install + verify pattern.
653
+ const DARWIN_BASE_DEPS = ["curl", "git", "unzip", "jq", "poppler", "ffmpeg", "tesseract", "ocrmypdf"];
654
+ installAllBrewPackages(DARWIN_BASE_DEPS, logFile);
655
+ return;
656
+ }
657
+ const BASE_DEPS = ["curl", "git", "unzip", "jq", "avahi-daemon", "avahi-utils", "poppler-utils", "ffmpeg", "bind9-dnsutils", "tesseract-ocr", "ocrmypdf"];
658
+ // xterm is the *preferred* terminal-emulator binary for the VNC-rendered
659
+ // Terminal surface
660
+ // delegates window creation to the session's gnome-terminal-server,
661
+ // opening windows on the wrong display; xterm has no IPC layer and
662
+ // honours DISPLAY directly). Kept in the apt list unconditionally so
663
+ // vnc.sh's resolve_terminal_bin has a display-safe binary on every
664
+ // supported distro (Ubuntu 24.04 noble/universe, Debian 12 bookworm/main
665
+ // verified). xdotool backs the post-spawn display-membership
666
+ // assertion in vnc.sh check_window_on_display, closing the silent-fail
667
+ // class where PID is alive but no window is mapped on the target display.
668
+ const VNC_DEPS = ["tigervnc-standalone-server", "python3-websockify", "novnc", "xdg-utils", "chromium", "xterm", "xdotool"];
669
+ // retired the ttyd/tmux admin terminal stack — upgrades run via
670
+ // the action runner (systemd-run --user transient units) and no longer
671
+ // need a shared tmux session. `tmux` was only required by the retired
672
+ // byte-stream terminal; removing it shrinks the apt footprint.
673
+ const WIFI_DEPS = ["hostapd", "dnsmasq"];
674
+ const ALL_APT_DEPS = [...BASE_DEPS, ...VNC_DEPS, ...WIFI_DEPS];
675
+ // verify the "deps are present" assumption with `dpkg -s` instead
676
+ // of asserting it (feedback_loud_failures.md). The previous silent-skip
677
+ // branch was benign added xdotool (the first new apt dep
678
+ // since the skip path became load-bearing on user-password-sudo devices).
679
+ const missing = pkgsMissing(ALL_APT_DEPS);
680
+ if (missing.length === 0) {
681
+ logFile(` all system deps present per dpkg -s (${ALL_APT_DEPS.length} packages) — skipping apt install`);
682
+ console.log(` All ${ALL_APT_DEPS.length} system deps already installed — skipping apt install.`);
683
+ }
684
+ else {
685
+ const canEscalate = canSudo() || process.stdout.isTTY === true;
686
+ if (!canEscalate) {
687
+ const repair = `sudo apt-get install -y ${missing.join(" ")}`;
688
+ console.error(` MISSING ${missing.length} system deps per dpkg -s: ${missing.join(" ")}`);
689
+ console.error(` Non-interactive sudo is unavailable; cannot prompt for password from a non-TTY shell.`);
690
+ console.error(` Re-run this installer from an interactive shell, or repair manually:`);
691
+ console.error(` ${repair}`);
692
+ logFile(` FAIL: missing apt deps without interactive sudo: ${missing.join(",")}`);
693
+ throw new Error(`installSystemDeps: missing packages (${missing.join(", ")}) and sudo is unavailable non-interactively — repair with: ${repair}`);
694
+ }
695
+ console.log(` Missing apt deps (${missing.length}): ${missing.join(", ")}`);
696
+ console.log(` Installing via sudo apt-get — sudo may prompt for your password...`);
697
+ console.log(" [privileged] apt-get update");
698
+ shell("apt-get", ["update"], { sudo: true });
699
+ installAptGroup("base utilities", BASE_DEPS);
700
+ installAptGroup("VNC stack", VNC_DEPS);
701
+ installAptGroup("WiFi AP", WIFI_DEPS);
702
+ }
703
+ // replace snap-confined Chromium with Google Chrome stable on
704
+ // Linux laptops (Ubuntu Noble) where `/usr/bin/chromium` realpaths to the
705
+ // snap launcher. The snap AppArmor profile denies writes to hidden top-level
706
+ // paths under $HOME, so any write to `~/.{brand}/chromium-profile/SingletonLock`
707
+ // hits EACCES and Chromium never starts the CDP listener. Always sets
708
+ // RESOLVED_CHROMIUM_BIN even on Pi Bookworm (where the path is unchanged),
709
+ // so deployPayload's writeChromiumBinaryPathFile and installService's
710
+ // buildMaxyUnitFile both have a real absolute path to thread through.
711
+ ensureNonSnapChromium();
712
+ // Task 600 — provision swap so the OOM-killer has a buffer to work in
713
+ // instead of silently freezing the box. dphys-swapfile is the standard
714
+ // Raspberry Pi OS swap manager. CONF_MAXSWAP raised to 4096 so the
715
+ // operator can manually grow the swap file without reinstalling.
716
+ // Best-effort: a failure here warns but does not abort the install.
717
+ try {
718
+ console.log(" [privileged] apt-get install dphys-swapfile");
719
+ shell("apt-get", ["install", "-y", "dphys-swapfile"], { sudo: true, bestEffort: true });
720
+ const desiredSwapConf = "CONF_SWAPSIZE=2048\nCONF_MAXSWAP=4096\n";
721
+ const swapConfPath = "/etc/dphys-swapfile";
722
+ let swapCurrent = "";
723
+ if (existsSync(swapConfPath)) {
724
+ try {
725
+ swapCurrent = readFileSync(swapConfPath, "utf-8");
726
+ }
727
+ catch {
728
+ swapCurrent = "";
729
+ }
730
+ }
731
+ if (swapCurrent === desiredSwapConf) {
732
+ logFile(" swap: already configured (CONF_SWAPSIZE=2048 CONF_MAXSWAP=4096)");
733
+ }
734
+ else {
735
+ const swapTmpPath = `/tmp/dphys-swapfile.${process.pid}`;
736
+ writeFileSync(swapTmpPath, desiredSwapConf);
737
+ console.log(" [privileged] install /etc/dphys-swapfile (CONF_SWAPSIZE=2048 CONF_MAXSWAP=4096)");
738
+ shell("cp", [swapTmpPath, swapConfPath], { sudo: true });
739
+ spawnSync("rm", ["-f", swapTmpPath]);
740
+ console.log(" [privileged] systemctl restart dphys-swapfile");
741
+ shell("systemctl", ["restart", "dphys-swapfile"], { sudo: true, bestEffort: true });
742
+ logFile(" swap: configured CONF_SWAPSIZE=2048 CONF_MAXSWAP=4096 and restarted dphys-swapfile");
743
+ }
744
+ }
745
+ catch (err) {
746
+ console.error(` WARNING: failed to provision swap: ${err instanceof Error ? err.message : String(err)}`);
747
+ }
748
+ // Hostname resolution — four sources, in priority order:
749
+ // 1. --hostname flag (unconditional — the caller is the authority)
750
+ // 2. OS detection on same-brand upgrade (service exists → keep whatever is currently set)
751
+ // 3. OS preservation on multi-brand device (another brand's service detected → keep hostname)
752
+ // 4. BRAND.hostname on fresh install (brand default)
753
+ if (HOSTNAME_FLAG) {
754
+ // --hostname flag: set unconditionally, no detection, no preservation logic.
755
+ console.log(` Hostname: ${HOSTNAME_FLAG} (from --hostname flag)`);
756
+ try {
757
+ console.log(" [privileged] hostnamectl set-hostname");
758
+ shell("hostnamectl", ["set-hostname", HOSTNAME_FLAG], { sudo: true });
759
+ console.log(" [privileged] sed -i");
760
+ shell("sed", ["-i", `s/127\\.0\\.1\\.1.*$/127.0.1.1\\t${HOSTNAME_FLAG}/`, "/etc/hosts"], { sudo: true });
761
+ try {
762
+ console.log(" [privileged] sed -i");
763
+ shell("sed", ["-i", `s/^[#]*host-name=.*/host-name=${HOSTNAME_FLAG}/`, "/etc/avahi/avahi-daemon.conf"], { sudo: true });
764
+ console.log(` Avahi host-name: ${HOSTNAME_FLAG} (updated avahi-daemon.conf)`);
765
+ }
766
+ catch { /* avahi-daemon.conf may not exist — non-critical */ }
767
+ // Restart avahi-daemon so the new hostname takes effect immediately
768
+ // and any stale "maxytest-2" auto-renamed records from a previous
769
+ // boot's hostname-conflict cycle are withdrawn. Without this,
770
+ // avahi-resolve -n <hostname>.local times out from the device itself
771
+ // because the daemon is still advertising the previous identity.
772
+ try {
773
+ console.log(" [privileged] systemctl restart avahi-daemon");
774
+ shell("systemctl", ["restart", "avahi-daemon"], { sudo: true });
775
+ }
776
+ catch (err) {
777
+ console.error(` WARNING: avahi-daemon restart failed: ${err instanceof Error ? err.message : String(err)}`);
778
+ }
779
+ }
780
+ catch (err) {
781
+ console.error(` WARNING: Failed to set hostname to '${HOSTNAME_FLAG}': ${err instanceof Error ? err.message : String(err)}`);
782
+ }
783
+ DEVICE_HOSTNAME = HOSTNAME_FLAG;
784
+ }
785
+ else {
786
+ // No flag — fall back to detection (upgrade) or brand default (fresh install).
787
+ // Check for this brand's service (same-brand upgrade) and any other brand's service
788
+ // (multi-brand device). On a multi-brand device, hostname is a device-level concern
789
+ // set by the user or the first installer — subsequent brands must not overwrite it.
790
+ const systemdUserDir = resolve(process.env.HOME ?? "/root", ".config/systemd/user");
791
+ const serviceExists = existsSync(join(systemdUserDir, BRAND.serviceName));
792
+ // narrow peer detection to KNOWN_BRAND_HOSTNAMES. The previous
793
+ // predicate ("any *.service that isn't ours") matched stray user units
794
+ // such as a `gnome-keyring-daemon.service -> /dev/null` disable marker,
795
+ // silently flipping single-brand fresh installs into the "preserve hostname"
796
+ // branch. Mirrors the `peerBrandPresent` allowlist in `uninstall.ts`.
797
+ let otherBrandService = false;
798
+ if (!serviceExists) {
799
+ const peerUnits = KNOWN_BRAND_HOSTNAMES
800
+ .filter((h) => h !== BRAND.hostname)
801
+ .flatMap((h) => [`${h}.service`, `${h}-edge.service`]);
802
+ try {
803
+ const files = new Set(readdirSync(systemdUserDir));
804
+ otherBrandService = peerUnits.some((unit) => files.has(unit));
805
+ }
806
+ catch { /* directory may not exist on a fresh device — not an error */ }
807
+ }
808
+ // "raspberrypi" is the Pi factory default — it means "never configured,"
809
+ // not "the admin chose this hostname." Treat it the same as a fresh install.
810
+ const FACTORY_HOSTNAMES = ["raspberrypi", "localhost"];
811
+ let hostnameSetAttempted = false;
812
+ try {
813
+ const currentHostname = execFileSync("hostname", [], { encoding: "utf-8" }).trim();
814
+ const isFactory = FACTORY_HOSTNAMES.includes(currentHostname);
815
+ if (currentHostname === BRAND.hostname) {
816
+ console.log(` Hostname: ${currentHostname} (detected from OS)`);
817
+ }
818
+ else if (serviceExists && !isFactory) {
819
+ // Upgrade: admin-chosen hostname — preserve it.
820
+ console.log(` Hostname: ${currentHostname} (detected from OS — differs from brand '${BRAND.hostname}')`);
821
+ }
822
+ else if (otherBrandService && !isFactory) {
823
+ // Multi-brand: another brand set the hostname — preserve it.
824
+ console.log(` Hostname preserved: ${currentHostname} (another brand service detected)`);
825
+ }
826
+ else {
827
+ // Fresh install, OR a factory default that was never changed.
828
+ const reason = isFactory && serviceExists
829
+ ? `factory default '${currentHostname}' was never changed`
830
+ : `brand default — fresh install, was '${currentHostname}'`;
831
+ console.log(` Hostname: ${BRAND.hostname} (${reason})`);
832
+ hostnameSetAttempted = true;
833
+ try {
834
+ console.log(" [privileged] hostnamectl set-hostname");
835
+ shell("hostnamectl", ["set-hostname", BRAND.hostname], { sudo: true });
836
+ console.log(" [privileged] sed -i");
837
+ shell("sed", ["-i", `s/127\\.0\\.1\\.1.*$/127.0.1.1\\t${BRAND.hostname}/`, "/etc/hosts"], { sudo: true });
838
+ try {
839
+ console.log(" [privileged] sed -i");
840
+ shell("sed", ["-i", `s/^[#]*host-name=.*/host-name=${BRAND.hostname}/`, "/etc/avahi/avahi-daemon.conf"], { sudo: true });
841
+ console.log(` Avahi host-name: ${BRAND.hostname} (updated avahi-daemon.conf)`);
842
+ }
843
+ catch { /* avahi-daemon.conf may not exist — non-critical */ }
844
+ }
845
+ catch (err) {
846
+ console.error(` WARNING: Could not set hostname to '${BRAND.hostname}': ${err instanceof Error ? err.message : String(err)}`);
847
+ console.error(` After install, run: sudo hostnamectl set-hostname ${BRAND.hostname}`);
848
+ }
849
+ }
850
+ }
851
+ catch (err) {
852
+ console.error(` WARNING: Could not detect hostname: ${err instanceof Error ? err.message : String(err)}`);
853
+ }
854
+ // Read the actual hostname after any changes — used for user-facing URLs.
855
+ try {
856
+ DEVICE_HOSTNAME = execFileSync("hostname", [], { encoding: "utf-8" }).trim();
857
+ }
858
+ catch { /* fallback to brand — set at declaration */ }
859
+ // If we attempted to set the hostname but it didn't take, use the brand
860
+ // hostname for the completion URL. The user needs the URL that will work
861
+ // after a reboot or manual hostname fix — not the stale factory default.
862
+ if (hostnameSetAttempted && DEVICE_HOSTNAME !== BRAND.hostname) {
863
+ console.error(` WARNING: Hostname is still '${DEVICE_HOSTNAME}' — using '${BRAND.hostname}' for the completion URL.`);
864
+ DEVICE_HOSTNAME = BRAND.hostname;
865
+ }
866
+ }
867
+ // Avahi service file for LAN discovery
868
+ const avahiService = `<?xml version="1.0" standalone='no'?>
869
+ <!DOCTYPE service-group SYSTEM "avahi-service.dtd">
870
+ <service-group>
871
+ <name replace-wildcards="yes">${BRAND.productName} on %h</name>
872
+ <service>
873
+ <type>_http._tcp</type>
874
+ <port>${PORT}</port>
875
+ <txt-record>role=${BRAND.hostname}</txt-record>
876
+ </service>
877
+ </service-group>`;
878
+ const avahiTmpPath = `/tmp/${BRAND.hostname}-avahi.service`;
879
+ const avahiDestPath = `/etc/avahi/services/${BRAND.hostname}.service`;
880
+ try {
881
+ writeFileSync(avahiTmpPath, avahiService);
882
+ console.log(" [privileged] cp");
883
+ shell("cp", [avahiTmpPath, avahiDestPath], { sudo: true });
884
+ console.log(" [privileged] systemctl enable");
885
+ shell("systemctl", ["enable", "avahi-daemon"], { sudo: true });
886
+ console.log(" [privileged] systemctl restart");
887
+ shell("systemctl", ["restart", "avahi-daemon"], { sudo: true });
888
+ }
889
+ catch { /* not critical */ }
890
+ // Hostname collision detection: check if another device already claims this hostname.
891
+ // Avahi appends -2 on collision, which causes the agent to construct URLs to the wrong device.
892
+ try {
893
+ const resolveResult = spawnSync("avahi-resolve", ["-n", `${BRAND.hostname}.local`], {
894
+ encoding: "utf-8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"],
895
+ });
896
+ if (resolveResult.status === 0 && resolveResult.stdout.trim()) {
897
+ const resolvedIp = resolveResult.stdout.trim().split(/\s+/)[1];
898
+ // Get this device's IP addresses to compare
899
+ const hostnameResult = spawnSync("hostname", ["-I"], { encoding: "utf-8", timeout: 3000 });
900
+ const localIps = hostnameResult.stdout?.trim().split(/\s+/) ?? [];
901
+ if (resolvedIp && !localIps.includes(resolvedIp)) {
902
+ console.log(` WARNING: ${BRAND.hostname}.local already resolves to ${resolvedIp} — this device may get ${BRAND.hostname}-2.local`);
903
+ logFile(` WARNING: hostname collision detected — ${BRAND.hostname}.local resolves to ${resolvedIp}, local IPs: ${localIps.join(", ")}`);
904
+ }
905
+ }
906
+ }
907
+ catch { /* non-critical — avahi-resolve may not be ready yet */ }
908
+ // Disable WiFi power management — the Pi's WiFi driver aggressively sleeps
909
+ // the radio between transmissions, causing dropped DNS/mDNS packets and
910
+ // intermittent connection resets on LAN.
911
+ try {
912
+ const nmConfDir = "/etc/NetworkManager/conf.d";
913
+ const nmConfFile = join(nmConfDir, `${BRAND.hostname}-no-powersave.conf`);
914
+ if (existsSync("/usr/bin/nmcli") && !existsSync(nmConfFile)) {
915
+ console.log(" Disabling WiFi power save...");
916
+ writeFileSync(`/tmp/${BRAND.hostname}-no-powersave.conf`, "[connection]\nwifi.powersave = 2\n");
917
+ console.log(" [privileged] cp");
918
+ shell("cp", [`/tmp/${BRAND.hostname}-no-powersave.conf`, nmConfFile], { sudo: true });
919
+ spawnSync("sudo", ["systemctl", "restart", "NetworkManager"], { stdio: "pipe" });
920
+ }
921
+ }
922
+ catch { /* not critical — wired connections unaffected */ }
923
+ console.log(` Device reachable at http://${DEVICE_HOSTNAME}.local:${PORT}`);
924
+ }
925
+ function installNodejs() {
926
+ if (commandExists("node") && nodeVersion() >= 20) {
927
+ log("2", TOTAL, `Node.js v${nodeVersion()} already installed.`);
928
+ return;
929
+ }
930
+ log("2", TOTAL, "Installing Node.js...");
931
+ const platform = requireSupportedPlatform(process.platform);
932
+ if (platform === "darwin") {
933
+ // Pass the apt-side `nodejs` name; decideBrewResolution maps it to
934
+ // `node@22` per DARWIN_ALIASES so the cellar formula matches Maxy's
935
+ // pinned-binaries floor.
936
+ installAllBrewPackages(["nodejs"], logFile);
937
+ return;
938
+ }
939
+ spawnSync("bash", ["-c", "curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -"], { stdio: "inherit" });
940
+ console.log(" [privileged] apt-get install");
941
+ shell("apt-get", ["install", "-y", "nodejs"], { sudo: true });
942
+ }
943
+ function installClaudeCode() {
944
+ let needsInstall = true;
945
+ if (commandExists("claude")) {
946
+ try {
947
+ // `claude --version` prints "2.1.114 (Claude Code)" — extract the semver so
948
+ // the equality check against `npm view` (which returns bare "2.1.114") works.
949
+ const rawVersion = execFileSync("claude", ["--version"], { encoding: "utf-8", timeout: 10_000 }).trim();
950
+ const installed = rawVersion.match(/^(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)/)?.[1] ?? rawVersion;
951
+ let latest = null;
952
+ try {
953
+ latest = execFileSync("npm", ["view", "@anthropic-ai/claude-code", "version"], { encoding: "utf-8", timeout: 30_000 }).trim();
954
+ }
955
+ catch {
956
+ logFile(" Could not check latest version — will attempt install anyway");
957
+ }
958
+ if (latest && installed === latest) {
959
+ log("3", TOTAL, `Claude Code v${installed} already up to date.`);
960
+ needsInstall = false;
961
+ }
962
+ else {
963
+ log("3", TOTAL, `Upgrading Claude Code (${installed}${latest ? ` → ${latest}` : ""})...`);
964
+ }
965
+ }
966
+ catch {
967
+ log("3", TOTAL, "Claude Code found but version check failed. Reinstalling...");
968
+ }
969
+ }
970
+ else {
971
+ log("3", TOTAL, "Installing Claude Code...");
972
+ }
973
+ if (needsInstall) {
974
+ // `npm install -g` needs write access to the global prefix, which on Linux is
975
+ // root-owned by default — so we run it under sudo. When sudo requires a password
976
+ // and the installer is running non-interactively (e.g. systemd-run --scope on
977
+ // upgrade), sudo fails instantly. Skip the upgrade in that case; the running
978
+ // installation is assumed adequate. Matches the apt-get skip in step 1.
979
+ if (isLinux() && !canSudo()) {
980
+ console.log(" Skipping Claude Code upgrade (sudo unavailable non-interactively — keeping installed version)");
981
+ }
982
+ else {
983
+ console.log(" This may take 15–30 minutes on Raspberry Pi...");
984
+ console.log(" [privileged] npm install -g @anthropic-ai/claude-code@latest");
985
+ shellRetry("npm", ["install", "-g", ...NPM_NET_FLAGS, "--loglevel", "verbose", "@anthropic-ai/claude-code@latest"], { sudo: true, timeout: 2_400_000 }, // 40 min — Pi downloads can take 25+ min
986
+ 3, 30);
987
+ }
988
+ }
989
+ console.log(" Registering Claude plugin marketplaces...");
990
+ // pre-create the per-brand CLAUDE_CONFIG_DIR so the first
991
+ // `claude plugin marketplace add` has a directory to write into.
992
+ mkdirSync(CLAUDE_CONFIG_DIR, { recursive: true });
993
+ // Task 583 — seed the brand-scoped permissions block so claude.ai/code
994
+ // sessions short-circuit Stage 1 of the local matcher and never fall
995
+ // through to the Anthropic remote auto-classifier (which routes Agent
996
+ // dispatch to `ask` and surfaces a prompt no unattended operator clicks).
997
+ const permissionsSeed = seedBypassPermissionsSettings(CLAUDE_CONFIG_DIR);
998
+ logFile(`[install-permissions] action=${permissionsSeed.action} path=${permissionsSeed.path}`);
999
+ const marketplaceList = spawnSync("claude", ["plugin", "marketplace", "list"], { stdio: "pipe", encoding: "utf-8", env: claudePluginEnv() });
1000
+ if (marketplaceList.stderr)
1001
+ process.stderr.write(marketplaceList.stderr);
1002
+ const listed = marketplaceList.stdout ?? "";
1003
+ // register three Anthropic marketplaces uniformly with
1004
+ // [plugin-marketplace] observability. Each slug is grep-checked against
1005
+ // `marketplace list` for idempotence; failures log exit + first stderr
1006
+ // line but do not abort the installer (one marketplace's outage must not
1007
+ // block the others).
1008
+ // `slug` is the GitHub repo path passed to `marketplace add`. `marketplaceName`
1009
+ // is the marketplace's declared `name` from its .claude-plugin/marketplace.json —
1010
+ // what `marketplace list` prints and what `<plugin>@<marketplace>` resolves on
1011
+ // install. For FSI the two diverge: repo `anthropics/financial-services`,
1012
+ // marketplace name `claude-for-financial-services`. The idempotence check
1013
+ // greps the declared name to avoid substring false-positives.
1014
+ const MARKETPLACES = [
1015
+ { slug: "anthropics/claude-plugins-official", marketplaceName: "claude-plugins-official" },
1016
+ { slug: "anthropics/knowledge-work-plugins", marketplaceName: "knowledge-work-plugins" },
1017
+ { slug: "anthropics/financial-services", marketplaceName: "claude-for-financial-services" },
1018
+ ];
1019
+ for (const { slug, marketplaceName } of MARKETPLACES) {
1020
+ if (listed.includes(marketplaceName)) {
1021
+ logFile(`[plugin-marketplace] added ${slug} idempotent=true CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
1022
+ continue;
1023
+ }
1024
+ const add = spawnSync("claude", ["plugin", "marketplace", "add", slug], { stdio: "pipe", encoding: "utf-8", timeout: 60_000, env: claudePluginEnv() });
1025
+ if (add.status === 0) {
1026
+ logFile(`[plugin-marketplace] added ${slug} idempotent=false CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
1027
+ }
1028
+ else {
1029
+ const stderrShort = (add.stderr ?? "").split("\n")[0]?.slice(0, 200) ?? "";
1030
+ logFile(`[plugin-marketplace] ERROR add ${slug} exit=${add.status} stderr=${JSON.stringify(stderrShort)} CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
1031
+ }
1032
+ }
1033
+ console.log(" Configuring git to use HTTPS for GitHub (plugin install support)...");
1034
+ shell("git", ["config", "--global", "url.https://github.com/.insteadOf", "git@github.com:"]);
1035
+ // Remove the Playwright plugin if previously installed. The programmatic MCP
1036
+ // server in claude-agent.ts (with --cdp-endpoint) is the single correct path.
1037
+ // The plugin creates a shadow server that intermittently handles tool calls
1038
+ // without --cdp-endpoint, causing Chrome launch failures on ARM64.
1039
+ const pluginList = spawnSync("claude", ["plugin", "list"], { stdio: "pipe", encoding: "utf-8", env: claudePluginEnv() });
1040
+ if (pluginList.stdout?.includes("playwright")) {
1041
+ console.log(" Removing Playwright plugin (replaced by programmatic CDP server)...");
1042
+ spawnSync("claude", ["plugin", "uninstall", "playwright"], { stdio: "inherit", env: claudePluginEnv() });
1043
+ }
1044
+ // Ensure @playwright/mcp and all its dependencies (including playwright-core)
1045
+ // are cached. Wipe any stale npx cache for it first — killed installs on Pi
1046
+ // leave corrupt temp dirs that block subsequent npm operations.
1047
+ console.log(" Pre-caching Playwright MCP server...");
1048
+ const npxDir = resolve(process.env.HOME ?? "/root", ".npm/_npx");
1049
+ const findResult = spawnSync("find", [npxDir, "-path", "*/@playwright/mcp/package.json", "-print", "-quit"], {
1050
+ encoding: "utf-8", stdio: "pipe",
1051
+ });
1052
+ const existingCache = findResult.stdout?.trim();
1053
+ if (existingCache) {
1054
+ // Nuke the entire npx cache entry to avoid ENOTEMPTY errors
1055
+ const cacheEntry = resolve(existingCache, "../../..");
1056
+ spawnSync("rm", ["-rf", cacheEntry], { stdio: "pipe" });
1057
+ }
1058
+ // Fresh install — npx creates a clean cache with all deps
1059
+ const npxResult = spawnSync("npx", ["-y", "@playwright/mcp@latest", "--version"], {
1060
+ stdio: "pipe",
1061
+ timeout: 180000,
1062
+ encoding: "utf-8",
1063
+ });
1064
+ // Verify playwright-core landed
1065
+ const verifyResult = spawnSync("find", [npxDir, "-path", "*/playwright-core/package.json", "-print", "-quit"], {
1066
+ encoding: "utf-8", stdio: "pipe",
1067
+ });
1068
+ if (verifyResult.stdout?.trim()) {
1069
+ console.log(" Playwright MCP server cached with all dependencies.");
1070
+ }
1071
+ else {
1072
+ console.log(` Warning: Playwright MCP cache may be incomplete (browser automation may not work).${npxResult.stderr ? ` npx stderr: ${npxResult.stderr.slice(0, 200)}` : ""}`);
1073
+ }
1074
+ }
1075
+ function resetNeo4jAuth(port = DEFAULT_NEO4J_PORT, dataDir = "/var/lib/neo4j") {
1076
+ const password = randomBytes(24).toString("base64url");
1077
+ const dedicated = port !== DEFAULT_NEO4J_PORT;
1078
+ const serviceName = dedicated ? `neo4j-${BRAND.hostname}` : "neo4j";
1079
+ console.log(` Resetting Neo4j auth with fresh password (${serviceName})...`);
1080
+ spawnSync("sudo", ["systemctl", "stop", serviceName], { stdio: "inherit" });
1081
+ // Clear the system database (stores auth/roles) and dbms auth config.
1082
+ // The neo4j user database (graph data) is preserved.
1083
+ // set-initial-password only works before the system DB's first start,
1084
+ // so we must delete it to make Neo4j treat the next start as initial.
1085
+ spawnSync("sudo", ["rm", "-rf",
1086
+ `${dataDir}/data/dbms`,
1087
+ `${dataDir}/data/databases/system`,
1088
+ `${dataDir}/data/transactions/system`,
1089
+ ], { stdio: "inherit" });
1090
+ if (dedicated) {
1091
+ const confDir = `/etc/neo4j-${BRAND.hostname}`;
1092
+ // sudo env VAR=val passes the variable through sudo's env_reset
1093
+ spawnSync("sudo", ["env", `NEO4J_CONF=${confDir}`, "neo4j-admin", "dbms", "set-initial-password", "--", password], {
1094
+ stdio: "inherit",
1095
+ });
1096
+ }
1097
+ else {
1098
+ console.log(" [privileged] neo4j-admin dbms");
1099
+ shell("neo4j-admin", ["dbms", "set-initial-password", "--", password], { sudo: true, redact: true });
1100
+ }
1101
+ console.log(" [privileged] systemctl start");
1102
+ shell("systemctl", ["start", serviceName], { sudo: true });
1103
+ console.log(" Waiting for Neo4j to start...");
1104
+ for (let i = 0; i < 15; i++) {
1105
+ const check = spawnSync("cypher-shell", [
1106
+ "-u", "neo4j", "-p", password,
1107
+ "-a", `bolt://localhost:${port}`,
1108
+ "RETURN 1",
1109
+ ], { stdio: "pipe", timeout: 5000 });
1110
+ if (check.status === 0)
1111
+ break;
1112
+ spawnSync("sleep", ["2"]);
1113
+ }
1114
+ return password;
1115
+ }
1116
+ /**
1117
+ * scrub plaintext neo4j passwords from pre-fix install-*.log files.
1118
+ * Calls platform/scripts/redact-install-logs.sh against the installer's LOG_DIR.
1119
+ * The script is idempotent; re-running on clean logs is a no-op. Failures here
1120
+ * are non-fatal — credential redaction is best-effort cleanup, not a blocker
1121
+ * for installation.
1122
+ */
1123
+ function redactInstallLogs() {
1124
+ const script = resolve(INSTALL_DIR, "platform/scripts/redact-install-logs.sh");
1125
+ if (!existsSync(script)) {
1126
+ logFile("[redact-install-logs] script not found at " + script + " — skipping");
1127
+ return;
1128
+ }
1129
+ const r = spawnSync("bash", [script, "--dir", LOG_DIR], {
1130
+ stdio: "pipe",
1131
+ encoding: "utf-8",
1132
+ timeout: 30_000,
1133
+ });
1134
+ if (r.stdout)
1135
+ logFile(r.stdout.trim());
1136
+ if (r.status !== 0 && r.stderr)
1137
+ logFile("[redact-install-logs] WARN " + r.stderr.trim());
1138
+ }
1139
+ /** Check Neo4j has a working password. Called AFTER deploy so config is in place. */
1140
+ function ensureNeo4jPassword() {
1141
+ const passwordFile = join(INSTALL_DIR, "platform/config/.neo4j-password");
1142
+ const configDir = resolve(INSTALL_DIR, "platform/config");
1143
+ mkdirSync(configDir, { recursive: true });
1144
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
1145
+ const persistentPasswordFile = join(persistDir, ".neo4j-password");
1146
+ // Dedicated instances have their own auth database — password checks and resets
1147
+ // must target the dedicated port and data directory, not the shared instance.
1148
+ const dataDir = NEO4J_DEDICATED ? `/var/lib/neo4j-${BRAND.hostname}` : "/var/lib/neo4j";
1149
+ // 1. Same-brand check: if our own password file exists and works, done (upgrade path).
1150
+ if (existsSync(passwordFile)) {
1151
+ const existingPassword = readFileSync(passwordFile, "utf-8").trim();
1152
+ if (neo4jPasswordWorks(existingPassword, NEO4J_PORT)) {
1153
+ logFile(` Neo4j password: already configured (port ${NEO4J_PORT})`);
1154
+ return;
1155
+ }
1156
+ if (NEO4J_DEDICATED) {
1157
+ console.log(" Stored password doesn't match dedicated Neo4j instance.");
1158
+ }
1159
+ else {
1160
+ console.log(" Stored password doesn't match Neo4j. Resetting auth.");
1161
+ }
1162
+ }
1163
+ // 2. Fresh install or recovery: no working same-brand password. Generate and set a new one.
1164
+ // Brand isolation: never read another brand's.neo4j-password.
1165
+ if (!existsSync(passwordFile)) {
1166
+ console.log(" No Neo4j password file found. Setting initial password...");
1167
+ }
1168
+ // Reset auth and set a new password. Graph data is preserved —
1169
+ // only the auth config ({dataDir}/data/dbms/) is cleared.
1170
+ const hasData = existsSync(`${dataDir}/data/databases/neo4j`);
1171
+ if (hasData) {
1172
+ console.log(" Neo4j has existing data. Resetting auth only (data preserved)...");
1173
+ logFile(` Neo4j auth reset — clearing dbms auth in ${dataDir}, preserving databases + transactions`);
1174
+ }
1175
+ const password = resetNeo4jAuth(NEO4J_PORT, dataDir);
1176
+ writeFileSync(passwordFile, password, { mode: 0o600 });
1177
+ mkdirSync(persistDir, { recursive: true });
1178
+ writeFileSync(persistentPasswordFile, password, { mode: 0o600 });
1179
+ logFile(" Neo4j password: generated new");
1180
+ }
1181
+ /** Test a Neo4j password against the running instance on the given port. */
1182
+ function neo4jPasswordWorks(password, port = DEFAULT_NEO4J_PORT) {
1183
+ const check = spawnSync("cypher-shell", [
1184
+ "-u", "neo4j", "-p", password,
1185
+ "-a", `bolt://localhost:${port}`,
1186
+ "RETURN 1",
1187
+ ], { stdio: "pipe", timeout: 10000 });
1188
+ return check.status === 0;
1189
+ }
1190
+ function installNeo4j() {
1191
+ if (commandExists("neo4j")) {
1192
+ log("4", TOTAL, "Neo4j already installed.");
1193
+ return;
1194
+ }
1195
+ log("4", TOTAL, "Installing Neo4j Community Edition 5...");
1196
+ const platform = requireSupportedPlatform(process.platform);
1197
+ if (platform === "darwin") {
1198
+ // Homebrew's neo4j formula declares openjdk as a runtime dependency, so
1199
+ // Java is pulled in transitively — no separate openjdk install step.
1200
+ // Process supervision (launchd LaunchAgent) is owned; this
1201
+ // step ends after `brew install neo4j` + initial-password seeding so the
1202
+ // payload deploy step finds the shared password file.
1203
+ installAllBrewPackages(["neo4j"], logFile);
1204
+ // Generate strong random password — stored in persistent location (~/{configDir}/)
1205
+ const password = randomBytes(24).toString("base64url");
1206
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
1207
+ mkdirSync(persistDir, { recursive: true });
1208
+ writeFileSync(join(persistDir, ".neo4j-password"), password, { mode: 0o600 });
1209
+ const configDir = resolve(INSTALL_DIR, "platform/config");
1210
+ mkdirSync(configDir, { recursive: true });
1211
+ writeFileSync(join(configDir, ".neo4j-password"), password, { mode: 0o600 });
1212
+ // Persist Neo4j data under ~/.maxy/neo4j-data/ per the task brief, so a
1213
+ // brew uninstall (which removes the cellar) does not destroy the graph.
1214
+ const neo4jDataDir = resolve(process.env.HOME ?? "/root", BRAND.configDir, "neo4j-data");
1215
+ mkdirSync(neo4jDataDir, { recursive: true });
1216
+ shell("neo4j-admin", ["dbms", "set-initial-password", "--", password], { redact: true });
1217
+ // Start Neo4j under brew's launchd supervision. Linux path starts the
1218
+ // service via systemd a few lines below; without this start the darwin
1219
+ // brand server binds successfully but every Cypher write fails with
1220
+ // "Failed to connect to server" because nothing is listening on 7687.
1221
+ // `brew services start` is idempotent — if already running it no-ops,
1222
+ // and the LaunchAgent persists across reboots.
1223
+ const brewStart = spawnSync("brew", ["services", "start", "neo4j"], { stdio: "inherit" });
1224
+ if (brewStart.status !== 0) {
1225
+ throw new Error(`brew services start neo4j failed (exit ${brewStart.status}) — Neo4j must be running before the brand server starts or all graph writes will fail`);
1226
+ }
1227
+ console.log(" Neo4j installed and started via Homebrew launchd. Password stored securely.");
1228
+ return;
1229
+ }
1230
+ // Neo4j 5.x supports Java 17 and 21. Debian Bookworm ships 17, Trixie ships 21.
1231
+ // apt-cache policy shows "Candidate: (none)" when no installable version exists.
1232
+ const policyResult = spawnSync("apt-cache", ["policy", "openjdk-17-jre-headless"], { stdio: "pipe" });
1233
+ const policyOutput = policyResult.stdout?.toString() ?? "";
1234
+ const has17 = policyResult.status === 0 && !policyOutput.includes("Candidate: (none)");
1235
+ const javaPackage = has17 ? "openjdk-17-jre-headless" : "openjdk-21-jre-headless";
1236
+ console.log(` Installing Java (${javaPackage})...`);
1237
+ console.log(" [privileged] apt-get install");
1238
+ shell("apt-get", ["install", "-y", javaPackage], { sudo: true });
1239
+ spawnSync("bash", ["-c", "curl -fsSL https://debian.neo4j.com/neotechnology.gpg.key | sudo gpg --yes --dearmor -o /usr/share/keyrings/neo4j.gpg 2>/dev/null"], { stdio: "inherit" });
1240
+ spawnSync("bash", ["-c", 'echo "deb [signed-by=/usr/share/keyrings/neo4j.gpg] https://debian.neo4j.com stable 5" | sudo tee /etc/apt/sources.list.d/neo4j.list'], { stdio: "inherit" });
1241
+ console.log(" [privileged] apt-get update");
1242
+ shell("apt-get", ["update"], { sudo: true });
1243
+ console.log(" [privileged] apt-get install");
1244
+ shell("apt-get", ["install", "-y", "neo4j"], { sudo: true });
1245
+ console.log(" [privileged] sed -i");
1246
+ shell("sed", ["-i", "s/#server.default_listen_address=0.0.0.0/server.default_listen_address=127.0.0.1/", "/etc/neo4j/neo4j.conf"], { sudo: true });
1247
+ // Generate strong random password — stored in persistent location (~/{configDir}/)
1248
+ const password = randomBytes(24).toString("base64url");
1249
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
1250
+ mkdirSync(persistDir, { recursive: true });
1251
+ writeFileSync(join(persistDir, ".neo4j-password"), password, { mode: 0o600 });
1252
+ // Also write to install dir (will be there when deploy step runs)
1253
+ const configDir = resolve(INSTALL_DIR, "platform/config");
1254
+ mkdirSync(configDir, { recursive: true });
1255
+ writeFileSync(join(configDir, ".neo4j-password"), password, { mode: 0o600 });
1256
+ console.log(" [privileged] neo4j-admin dbms");
1257
+ shell("neo4j-admin", ["dbms", "set-initial-password", "--", password], { sudo: true, redact: true });
1258
+ console.log(" [privileged] systemctl enable");
1259
+ shell("systemctl", ["enable", "neo4j"], { sudo: true });
1260
+ console.log(" [privileged] systemctl start");
1261
+ shell("systemctl", ["start", "neo4j"], { sudo: true });
1262
+ console.log(" Neo4j started. Password stored securely.");
1263
+ }
1264
+ /**
1265
+ * does any peer brand on this host pin `NEO4J_URI=bolt://localhost:<default>`
1266
+ * in its `.env`? If yes, the apt-installed `neo4j.service` is its database and the
1267
+ * dedicated-unit installer must NOT stop+disable it. Returns the first matching
1268
+ * peer's hostname, or `null` when no peer pins the default port.
1269
+ *
1270
+ * Wraps the pure decision in `peer-brand-detect.ts` with the fs reads of
1271
+ * `~/.<peer>/.env`. Bias on read errors: if `.env` exists but is unreadable
1272
+ * (permissions, transient I/O), the wrapper treats that peer as a *potential*
1273
+ * dependency and short-circuits to the kept-active path. Disabling the system
1274
+ * unit on faulty evidence would silently kill the peer's database (the exact
1275
+ * failure mode the kept-active path prevents); a conservatively-skipped disable is recoverable
1276
+ * because the dedicated-unit bind check at the end of `setupDedicatedNeo4j`
1277
+ * fails loud if the system unit is actually free.
1278
+ */
1279
+ function peerBrandUsingSystemUnit() {
1280
+ const home = process.env.HOME ?? "/root";
1281
+ const peerEnvContents = [];
1282
+ for (const hostname of KNOWN_BRAND_HOSTNAMES) {
1283
+ if (hostname === BRAND.hostname) {
1284
+ peerEnvContents.push([hostname, null]);
1285
+ continue;
1286
+ }
1287
+ const envPath = resolve(home, `.${hostname}`, ".env");
1288
+ if (!existsSync(envPath)) {
1289
+ peerEnvContents.push([hostname, null]);
1290
+ continue;
1291
+ }
1292
+ try {
1293
+ peerEnvContents.push([hostname, readFileSync(envPath, "utf-8")]);
1294
+ }
1295
+ catch (err) {
1296
+ console.error(` WARNING: unable to read peer brand .env at ${envPath} — treating as potential dependency to avoid data loss: ${err instanceof Error ? err.message : String(err)}`);
1297
+ return hostname;
1298
+ }
1299
+ }
1300
+ return findPeerBrandOnDefaultNeo4jPort({
1301
+ currentBrandHostname: BRAND.hostname,
1302
+ defaultNeo4jPort: DEFAULT_NEO4J_PORT,
1303
+ peerEnvContents,
1304
+ });
1305
+ }
1306
+ /**
1307
+ * Create a dedicated Neo4j instance for this brand when NEO4J_DEDICATED is true.
1308
+ * Produces: separate config dir, data dir, log dir, systemd service, and password.
1309
+ * On upgrade (config already exists), skips conf creation — but always runs the
1310
+ * state-remediation block (stop/disable system unit, reset-failed
1311
+ * dedicated, start, verify) so a half-installed Pi recovers in-place without
1312
+ * manual systemctl. ensureNeo4jPassword() handles password verification on the
1313
+ * recovery path.
1314
+ *
1315
+ * on multi-brand hosts where a peer brand still depends on the apt
1316
+ * `neo4j.service` (port 7687), the stop+disable step is skipped — disabling
1317
+ * the system unit would kill the peer's database.
1318
+ */
1319
+ function setupDedicatedNeo4j() {
1320
+ if (!NEO4J_DEDICATED)
1321
+ return;
1322
+ const brandSuffix = BRAND.hostname; // e.g., "realagent"
1323
+ const confDir = `/etc/neo4j-${brandSuffix}`;
1324
+ const dataDir = `/var/lib/neo4j-${brandSuffix}`;
1325
+ const logDir = `/var/log/neo4j-${brandSuffix}`;
1326
+ const serviceName = `neo4j-${brandSuffix}`;
1327
+ const httpPort = NEO4J_PORT - 213; // Preserve standard 7687/7474 offset
1328
+ // Per-brand state (sed, mkdir, chown, unit-write) is idempotent and runs on
1329
+ // every install. Only the base-config copy and initial-password rotation are
1330
+ // gated to first install established that state remediation must
1331
+ // run every install extended the same principle to the conf and
1332
+ // unit emission so a half-installed host (broken unit missing NEO4J_HOME)
1333
+ // recovers on retry without an out-of-band manual reset.
1334
+ const confExists = spawnSync("test", ["-f", `${confDir}/neo4j.conf`], { stdio: "pipe" }).status === 0;
1335
+ if (confExists) {
1336
+ console.log(` Dedicated Neo4j instance for ${BRAND.productName} already configured at ${confDir} — re-applying per-brand state`);
1337
+ logFile(` Neo4j dedicated: existing config at ${confDir}, re-applying sed/mkdir/chown/unit on every install`);
1338
+ }
1339
+ else {
1340
+ console.log(` Setting up dedicated Neo4j instance for ${BRAND.productName} on bolt://localhost:${NEO4J_PORT}...`);
1341
+ // Pre-check: neo4j user must exist (created by the apt package)
1342
+ const neo4jUserCheck = spawnSync("id", ["neo4j"], { stdio: "pipe" });
1343
+ if (neo4jUserCheck.status !== 0) {
1344
+ throw new Error("Neo4j system user 'neo4j' not found. Is Neo4j installed via apt?");
1345
+ }
1346
+ // Pre-check: source config must exist
1347
+ if (!existsSync("/etc/neo4j/neo4j.conf")) {
1348
+ throw new Error("/etc/neo4j/neo4j.conf not found. Cannot create dedicated instance without base config.");
1349
+ }
1350
+ // Copy base config (first install only — sed runs unconditionally below)
1351
+ console.log(" [privileged] cp -r");
1352
+ shell("cp", ["-r", "/etc/neo4j", confDir], { sudo: true });
1353
+ }
1354
+ // Idempotent per-brand state — runs on every install.
1355
+ // Older Neo4j 5.x templates ship a SECOND commented occurrence of these
1356
+ // keys in the "Other Neo4j system properties" section. An in-place
1357
+ // `sed s|^#?key=.*|key=value|` matches both and writes duplicate active
1358
+ // lines; the 5.26.26 parser turns that into a fatal startup error.
1359
+ // Delete-all-then-append guarantees exactly one active line per key
1360
+ // regardless of how many commented occurrences the template ships.
1361
+ const confPath = `${confDir}/neo4j.conf`;
1362
+ const confKeys = [
1363
+ ["server.bolt.listen_address", `:${NEO4J_PORT}`],
1364
+ ["server.http.listen_address", `:${httpPort}`],
1365
+ ["server.directories.data", `${dataDir}/data`],
1366
+ ["server.directories.logs", logDir],
1367
+ ["server.directories.plugins", `${dataDir}/plugins`],
1368
+ ["server.directories.import", `${dataDir}/import`],
1369
+ ];
1370
+ for (const [key, value] of confKeys) {
1371
+ const keyRe = key.replace(/\./g, "\\.");
1372
+ console.log(" [privileged] sed -i (delete)");
1373
+ shell("sed", ["-i", `/^#\\?${keyRe}=/d`, confPath], { sudo: true });
1374
+ console.log(" [privileged] echo >>");
1375
+ shell("sh", ["-c", `echo '${key}=${value}' >> ${confPath}`], { sudo: true });
1376
+ }
1377
+ // Verify exactly one active line per key. Any n>1 aborts the install
1378
+ // BEFORE the systemd unit is written. n==0 means the append failed.
1379
+ const activeCounts = [];
1380
+ for (const [key] of confKeys) {
1381
+ const r = spawnSync("sudo", ["grep", "-c", `^${key}=`, confPath], { stdio: "pipe" });
1382
+ const n = parseInt((r.stdout?.toString() ?? "0").trim(), 10) || 0;
1383
+ activeCounts.push(`${key}:${n}`);
1384
+ if (n !== 1) {
1385
+ const msg = `[neo4j-conf] FATAL ${key} active_count=${n}`;
1386
+ console.error(` ${msg}`);
1387
+ logFile(` ${msg}`);
1388
+ throw new Error(msg);
1389
+ }
1390
+ }
1391
+ const summary = `[neo4j-conf] keys_active=${activeCounts.join(",")}`;
1392
+ console.log(` ${summary}`);
1393
+ logFile(` ${summary}`);
1394
+ console.log(" [privileged] mkdir -p");
1395
+ shell("mkdir", ["-p", `${dataDir}/data`, `${dataDir}/plugins`, `${dataDir}/import`, logDir], { sudo: true });
1396
+ console.log(" [privileged] chown -R");
1397
+ shell("chown", ["-R", "neo4j:neo4j", dataDir, logDir, confDir], { sudo: true });
1398
+ const serviceContent = `[Unit]
1399
+ Description=Neo4j Graph Database (${BRAND.productName})
1400
+ After=network-online.target
1401
+ Wants=network-online.target
1402
+
1403
+ [Service]
1404
+ ExecStart=/usr/bin/neo4j console
1405
+ Restart=on-failure
1406
+ User=neo4j
1407
+ Group=neo4j
1408
+ Environment="NEO4J_CONF=${confDir}" "NEO4J_HOME=${dataDir}"
1409
+ LimitNOFILE=60000
1410
+
1411
+ [Install]
1412
+ WantedBy=multi-user.target
1413
+ `;
1414
+ const tmpServicePath = `/tmp/${serviceName}.service`;
1415
+ writeFileSync(tmpServicePath, serviceContent);
1416
+ console.log(" [privileged] cp");
1417
+ shell("cp", [tmpServicePath, `/etc/systemd/system/${serviceName}.service`], { sudo: true });
1418
+ spawnSync("rm", ["-f", tmpServicePath]);
1419
+ logFile(` [neo4j] dedicated unit env: NEO4J_CONF=${confDir} NEO4J_HOME=${dataDir}`);
1420
+ if (!confExists) {
1421
+ // Set initial password before first start (first install only — rotation
1422
+ // on retry would brick an existing DB whose password is already stored).
1423
+ const password = randomBytes(24).toString("base64url");
1424
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
1425
+ mkdirSync(persistDir, { recursive: true });
1426
+ writeFileSync(join(persistDir, ".neo4j-password"), password, { mode: 0o600 });
1427
+ const configDir = resolve(INSTALL_DIR, "platform/config");
1428
+ mkdirSync(configDir, { recursive: true });
1429
+ writeFileSync(join(configDir, ".neo4j-password"), password, { mode: 0o600 });
1430
+ // sudo env VAR=val passes NEO4J_CONF through sudo's env_reset policy
1431
+ spawnSync("sudo", ["env", `NEO4J_CONF=${confDir}`, "neo4j-admin", "dbms", "set-initial-password", "--", password], {
1432
+ stdio: "inherit",
1433
+ });
1434
+ }
1435
+ // ============================================================================
1436
+ // unified state remediation + start + verify.
1437
+ //
1438
+ // Runs on both fresh and recovery paths. The dedicated unit and the apt
1439
+ // package's system unit both exec /usr/bin/neo4j console without overriding
1440
+ // NEO4J_HOME, so server.directories.run resolves to /var/lib/neo4j/run for
1441
+ // both — the launcher refuses with "Neo4j is already running (pid:N)" if
1442
+ // the system unit holds the PID file. Stopping the system unit first frees
1443
+ // the run-state; disabling prevents it returning at next boot. reset-failed
1444
+ // clears any prior start-limit-hit from a half-installed Pi.
1445
+ // ============================================================================
1446
+ spawnSync("sudo", ["systemctl", "daemon-reload"], { stdio: "inherit" });
1447
+ console.log(" [privileged] systemctl enable");
1448
+ shell("systemctl", ["enable", serviceName], { sudo: true });
1449
+ // skip stop+disable when a peer brand on this host still depends
1450
+ // on the apt `neo4j.service` (port 7687). Disabling it would kill the peer's
1451
+ // database reproducer on Neo's laptop. The kept-active path is
1452
+ // mutually exclusive with the disable path: exactly one log line per install.
1453
+ const peerOnSystemUnit = peerBrandUsingSystemUnit();
1454
+ if (peerOnSystemUnit !== null) {
1455
+ const keptActiveMsg = ` [neo4j] system unit kept active — peer brand ${peerOnSystemUnit} depends on port ${DEFAULT_NEO4J_PORT}`;
1456
+ console.log(keptActiveMsg);
1457
+ logFile(keptActiveMsg);
1458
+ }
1459
+ else {
1460
+ console.log(` [neo4j] disabling system unit (brand-dedicated active on port ${NEO4J_PORT})`);
1461
+ logFile(` [neo4j] disabling system unit (brand-dedicated active on port ${NEO4J_PORT})`);
1462
+ shell("systemctl", ["stop", "neo4j"], { sudo: true });
1463
+ shell("systemctl", ["disable", "neo4j"], { sudo: true });
1464
+ }
1465
+ console.log(` [neo4j] reset-failed ${serviceName} before start`);
1466
+ logFile(` [neo4j] reset-failed ${serviceName} before start`);
1467
+ shell("systemctl", ["reset-failed", serviceName], { sudo: true, bestEffort: true });
1468
+ console.log(" [privileged] systemctl start");
1469
+ shell("systemctl", ["start", serviceName], { sudo: true });
1470
+ // Verify the dedicated unit bound its port. Password verification is
1471
+ // ensureNeo4jPassword()'s job (called next in the install pipeline) — that
1472
+ // function tests the stored password against this port and resets auth if
1473
+ // the password no longer matches the running instance.
1474
+ console.log(` Waiting for dedicated Neo4j instance on port ${NEO4J_PORT}...`);
1475
+ let listening = false;
1476
+ const portMatch = new RegExp(`:${NEO4J_PORT}\\b`);
1477
+ for (let i = 0; i < 15; i++) {
1478
+ const portCheck = spawnSync("ss", ["-tln"], { stdio: "pipe", timeout: 5000 });
1479
+ if (portMatch.test(portCheck.stdout?.toString() ?? "")) {
1480
+ listening = true;
1481
+ break;
1482
+ }
1483
+ spawnSync("sleep", ["2"]);
1484
+ }
1485
+ if (!listening) {
1486
+ // Loud failure — no silent fallback to the system instance.
1487
+ const portCheck = spawnSync("ss", ["-tlnp"], { stdio: "pipe", timeout: 5000 });
1488
+ const portLines = (portCheck.stdout?.toString() ?? "").split("\n").filter((l) => l.includes(String(NEO4J_PORT)));
1489
+ const diagnostic = portLines.length > 0 ? portLines.join("; ") : "nothing listening on port";
1490
+ const journal = spawnSync("journalctl", ["-u", serviceName, "--since", "5 min ago"], { stdio: "pipe", timeout: 5000 });
1491
+ const journalTail = (journal.stdout?.toString() ?? "").split("\n").slice(-20).join("\n");
1492
+ logFile(` Neo4j dedicated: failed to bind port ${NEO4J_PORT} — ${diagnostic}`);
1493
+ throw new Error(`Dedicated Neo4j instance ${serviceName} did not bind bolt://localhost:${NEO4J_PORT} within 30s.\n` +
1494
+ `Port ${NEO4J_PORT}: ${diagnostic}\n` +
1495
+ `journalctl -u ${serviceName} --since "5 min ago" | tail -20:\n${journalTail}`);
1496
+ }
1497
+ logFile(` Neo4j dedicated: config=${confDir} data=${dataDir} service=${serviceName} bolt=:${NEO4J_PORT} http=:${httpPort}`);
1498
+ console.log(` Dedicated Neo4j instance ready on bolt://localhost:${NEO4J_PORT}`);
1499
+ }
1500
+ function ensureOllamaServing() {
1501
+ const check = () => spawnSync("curl", ["-sf", "http://localhost:11434/api/tags"], {
1502
+ stdio: "pipe", timeout: 5_000,
1503
+ });
1504
+ if (check().status === 0)
1505
+ return;
1506
+ // Log which ollama binary we're using and its version
1507
+ const which = spawnSync("which", ["ollama"], { stdio: "pipe" });
1508
+ const ollamaPath = which.stdout?.toString().trim() || "not found";
1509
+ logFile(` Ollama binary: ${ollamaPath}`);
1510
+ const version = spawnSync("ollama", ["--version"], { stdio: "pipe", timeout: 5_000 });
1511
+ logFile(` Ollama version: ${version.stdout?.toString().trim() || version.stderr?.toString().trim() || `exit ${version.status}`}`);
1512
+ // Check if systemd service exists
1513
+ const svcCheck = spawnSync("systemctl", ["cat", "ollama"], { stdio: "pipe", timeout: 5_000 });
1514
+ logFile(` Ollama systemd service: ${svcCheck.status === 0 ? "exists" : "not found"}`);
1515
+ // Check if port 11434 is already in use by something else
1516
+ const portCheck = spawnSync("ss", ["-tlnp"], { stdio: "pipe", timeout: 5_000 });
1517
+ const portLines = portCheck.stdout?.toString().split("\n").filter((l) => l.includes("11434")) || [];
1518
+ if (portLines.length > 0)
1519
+ logFile(` Port 11434 in use: ${portLines.join("; ")}`);
1520
+ console.log(" Starting Ollama server...");
1521
+ logFile(" Ollama server not responding — starting ollama serve");
1522
+ // Capture ollama serve output to a log file for diagnostics
1523
+ const ollamaLog = join(LOG_DIR, "ollama-serve.log");
1524
+ const logFd = openSync(ollamaLog, "a");
1525
+ const child = spawn("ollama", ["serve"], {
1526
+ stdio: ["ignore", logFd, logFd], detached: true,
1527
+ });
1528
+ child.unref();
1529
+ closeSync(logFd);
1530
+ logFile(` Spawned ollama serve (PID ${child.pid}), log: ${ollamaLog}`);
1531
+ for (let elapsed = 0; elapsed < 30; elapsed += 3) {
1532
+ spawnSync("sleep", ["3"]);
1533
+ // Check if process is still alive
1534
+ const alive = child.pid && spawnSync("kill", ["-0", String(child.pid)], { stdio: "pipe" }).status === 0;
1535
+ logFile(` Poll ${elapsed + 3}s: pid ${child.pid} alive=${alive}`);
1536
+ if (check().status === 0) {
1537
+ logFile(` Ollama server ready after ${elapsed + 3}s`);
1538
+ return;
1539
+ }
1540
+ if (!alive) {
1541
+ // Process died — read the log to find out why
1542
+ const serveLog = readFileSync(ollamaLog, "utf-8").slice(-2000);
1543
+ logFile(` Ollama serve exited. Log tail:\n${serveLog}`);
1544
+ console.error(` Ollama serve exited unexpectedly. Log: ${ollamaLog}`);
1545
+ throw new Error(`Ollama serve failed to start. Log: ${ollamaLog}\n${serveLog}`);
1546
+ }
1547
+ }
1548
+ // Timed out — include diagnostics
1549
+ const serveLog = readFileSync(ollamaLog, "utf-8").slice(-2000);
1550
+ logFile(` Ollama serve timed out after 30s. Log tail:\n${serveLog}`);
1551
+ throw new Error(`Ollama server did not respond within 30s. Log: ${ollamaLog}\n${serveLog}`);
1552
+ }
1553
+ function installOllama(embedModel) {
1554
+ if (!commandExists("ollama")) {
1555
+ log("5", TOTAL, "Installing Ollama...");
1556
+ spawnSync("bash", ["-c", "curl -fsSL https://ollama.ai/install.sh | sh"], { stdio: "inherit" });
1557
+ }
1558
+ else {
1559
+ log("5", TOTAL, "Ollama already installed.");
1560
+ }
1561
+ ensureOllamaServing();
1562
+ console.log(` Pulling ${embedModel} embedding model...`);
1563
+ logFile(` Pulling embedding model: ${embedModel}`);
1564
+ shellRetry("ollama", ["pull", embedModel], { timeout: 600_000 }, 3, 15);
1565
+ }
1566
+ // uv/uvx bootstrap. Required by the `graph` MCP server which
1567
+ // spawns `uvx mcp-neo4j-cypher@0.6.0 --transport stdio`. Idempotent: when
1568
+ // uvx is already on PATH (or under $HOME/.local/bin) we skip. Non-fatal on
1569
+ // failure — the installer continues; the graph server will loudly fail
1570
+ // at session start with a clear "uvx not found" error, which is retriable
1571
+ // via a second installer run with network access.
1572
+ function installUv() {
1573
+ if (commandExists("uvx")) {
1574
+ logFile(" uv: already installed");
1575
+ console.log(" uv/uvx already installed.");
1576
+ return;
1577
+ }
1578
+ console.log(" Installing uv (Python tool runner — required by Neo4j MCP server)...");
1579
+ logFile(" uv: installing via astral.sh installer");
1580
+ // astral.sh installer auto-confirms when stdin is not a TTY (our case under
1581
+ // systemd-run). Historically we passed `-y`, which the script rejects with
1582
+ // "unknown option -y" and causes uv to never install on upgrade.
1583
+ const result = spawnSync("bash", ["-c", "curl -LsSf https://astral.sh/uv/install.sh | sh"], { stdio: "inherit" });
1584
+ if (result.status !== 0) {
1585
+ console.error(` WARNING: uv install exited ${result.status} — graph MCP server will fail at session start until this is retried`);
1586
+ logFile(` WARNING: uv install failed with status ${result.status}`);
1587
+ return;
1588
+ }
1589
+ // The installer writes uvx to $HOME/.local/bin — add it to PATH for the
1590
+ // remainder of this install so commandExists("uvx") works downstream.
1591
+ const localBin = `${process.env.HOME}/.local/bin`;
1592
+ if (process.env.PATH && !process.env.PATH.includes(localBin)) {
1593
+ process.env.PATH = `${localBin}:${process.env.PATH}`;
1594
+ }
1595
+ if (commandExists("uvx")) {
1596
+ logFile(" uv: install succeeded; uvx on PATH");
1597
+ }
1598
+ else {
1599
+ console.error(" WARNING: uv installed but uvx not on PATH — check $HOME/.local/bin");
1600
+ }
1601
+ }
1602
+ function installCloudflared() {
1603
+ if (commandExists("cloudflared")) {
1604
+ log("6", TOTAL, "Cloudflared already installed.");
1605
+ return;
1606
+ }
1607
+ log("6", TOTAL, "Installing cloudflared...");
1608
+ const platform = requireSupportedPlatform(process.platform);
1609
+ if (platform === "darwin") {
1610
+ // Homebrew's `cloudflared` formula tracks the Cloudflare release stream;
1611
+ // tunnel-login flow stays unchanged (`feedback_no_api_token_route.md`).
1612
+ // `cloudflared service install` and `cloudflared tunnel route dns` are not
1613
+ // invoked by the installer on darwin — public reach is operator-driven
1614
+ // post-install (`cloudflared tunnel login` + follow-up tooling). The brew
1615
+ // install puts the binary on PATH so the operator can opt in later.
1616
+ logFile(` [create-maxy] darwin-cloudflare-skip=true reason="Mac laptop — no public hostname provisioned at install time"`);
1617
+ installAllBrewPackages(["cloudflared"], logFile);
1618
+ return;
1619
+ }
1620
+ const arch = isArm64() ? "arm64" : "amd64";
1621
+ const debPath = "/tmp/cloudflared.deb";
1622
+ shellRetry("curl", ["-fSL", "--progress-bar", `https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${arch}.deb`, "-o", debPath], { timeout: 120_000 }, 3, 10);
1623
+ console.log(" [privileged] dpkg -i");
1624
+ shell("dpkg", ["-i", debPath], { sudo: true });
1625
+ spawnSync("rm", ["-f", debPath]);
1626
+ }
1627
+ function installWhisperCpp() {
1628
+ const WHISPER_DIR = "/opt/whisper.cpp";
1629
+ const WHISPER_BINARY = join(WHISPER_DIR, "build/bin/whisper-cli");
1630
+ const WHISPER_MODEL = join(WHISPER_DIR, "models", "ggml-base.bin");
1631
+ if (existsSync(WHISPER_BINARY) && existsSync(WHISPER_MODEL)) {
1632
+ log("7", TOTAL, "whisper.cpp already installed.");
1633
+ return;
1634
+ }
1635
+ log("7", TOTAL, "Installing whisper.cpp (speech-to-text)...");
1636
+ if (!isLinux()) {
1637
+ console.log(" Skipping — install manually for your platform.");
1638
+ return;
1639
+ }
1640
+ // Build dependencies — cmake is required since whisper.cpp migrated from plain make
1641
+ console.log(" [privileged] apt-get install");
1642
+ shell("apt-get", ["install", "-y", "build-essential", "cmake"], { sudo: true });
1643
+ // Clone or update the repository
1644
+ if (!existsSync(WHISPER_DIR)) {
1645
+ console.log(" Cloning whisper.cpp...");
1646
+ console.log(" [privileged] git clone");
1647
+ shell("git", ["clone", "--depth", "1", "https://github.com/ggerganov/whisper.cpp.git", WHISPER_DIR], { sudo: true });
1648
+ }
1649
+ // Compile via cmake (whisper.cpp's Makefile is a thin cmake wrapper)
1650
+ console.log(" Compiling whisper.cpp (this takes a few minutes on Pi)...");
1651
+ console.log(" [privileged] cmake -B");
1652
+ shell("cmake", ["-B", "build"], { cwd: WHISPER_DIR, sudo: true, timeout: 120_000 });
1653
+ console.log(" [privileged] cmake --build");
1654
+ shell("cmake", ["--build", "build", "--config", "Release", "-j2"], { cwd: WHISPER_DIR, sudo: true, timeout: 600_000 });
1655
+ // Download the base model (~150MB)
1656
+ if (!existsSync(WHISPER_MODEL)) {
1657
+ console.log(" Downloading ggml-base model (~150MB)...");
1658
+ console.log(" [privileged] bash -c");
1659
+ shellRetry("bash", ["-c", `cd ${WHISPER_DIR} && bash models/download-ggml-model.sh base`], { sudo: true, timeout: 300_000 }, 3, 15);
1660
+ }
1661
+ console.log(" whisper.cpp installed successfully.");
1662
+ }
1663
+ /**
1664
+ * Provision the shared HMAC secret used to sign remote-session cookies
1665
+ *. Both `maxy-edge` and `maxy-ui` read this file; without it
1666
+ * they independently mint ephemeral secrets on first use and the
1667
+ * cross-process session namespace silently diverges again.
1668
+ *
1669
+ * First install: create the file (0600, 32-byte hex).
1670
+ * Upgrade: leave the existing file untouched — invalidating it here
1671
+ * would log every operator out on every upgrade.
1672
+ */
1673
+ function provisionRemoteSessionSecret() {
1674
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
1675
+ const credentialsDir = join(persistDir, "credentials");
1676
+ const secretFile = join(credentialsDir, "remote-session-secret");
1677
+ if (existsSync(secretFile)) {
1678
+ console.log(` [install] remote-session-secret exists — preserved`);
1679
+ return;
1680
+ }
1681
+ mkdirSync(credentialsDir, { recursive: true, mode: 0o700 });
1682
+ writeFileSync(secretFile, randomBytes(32).toString("hex"), { mode: 0o600 });
1683
+ console.log(` [install] remote-session-secret provisioned path=${secretFile}`);
1684
+ }
1685
+ // install-time admin-auth invariant. Walks every account.json
1686
+ // under accountsDir and compares its admins[] to the persistent users.json,
1687
+ // emitting one [install-invariant] line per divergence and one summary line.
1688
+ // Log-only (no install abort); future sprint can promote to refuse-or-degrade
1689
+ // once the deployed fleet is audited clean. Mirror of
1690
+ // checkAdminAuthInvariant() in platform/lib/admins-write/src/index.ts.
1691
+ function runInstallInvariantCheck(usersFile, accountsDir) {
1692
+ const TAG = "[install-invariant]";
1693
+ const usersUserIds = new Set();
1694
+ if (existsSync(usersFile)) {
1695
+ try {
1696
+ const raw = readFileSync(usersFile, "utf-8").trim();
1697
+ if (raw) {
1698
+ const users = JSON.parse(raw);
1699
+ for (const u of users) {
1700
+ if (typeof u.userId === "string")
1701
+ usersUserIds.add(u.userId);
1702
+ }
1703
+ }
1704
+ }
1705
+ catch (err) {
1706
+ const msg = err instanceof Error ? err.message : String(err);
1707
+ console.log(` ${TAG} users.json unreadable usersFile=${usersFile} error=${msg}`);
1708
+ }
1709
+ }
1710
+ const accountUserIds = new Set();
1711
+ let divergences = 0;
1712
+ if (existsSync(accountsDir)) {
1713
+ let entries = [];
1714
+ try {
1715
+ entries = readdirSync(accountsDir);
1716
+ }
1717
+ catch (err) {
1718
+ const msg = err instanceof Error ? err.message : String(err);
1719
+ console.log(` ${TAG} accounts-dir unreadable accountsDir=${accountsDir} error=${msg}`);
1720
+ console.log(` ${TAG} check complete divergences=0 (accounts-dir unreadable)`);
1721
+ return;
1722
+ }
1723
+ for (const entry of entries) {
1724
+ if (entry.startsWith("."))
1725
+ continue;
1726
+ const accountDir = join(accountsDir, entry);
1727
+ try {
1728
+ if (!statSync(accountDir).isDirectory())
1729
+ continue;
1730
+ }
1731
+ catch {
1732
+ continue;
1733
+ }
1734
+ const accountJsonPath = join(accountDir, "account.json");
1735
+ if (!existsSync(accountJsonPath))
1736
+ continue;
1737
+ let admins = [];
1738
+ try {
1739
+ const config = JSON.parse(readFileSync(accountJsonPath, "utf-8"));
1740
+ admins = (config.admins ?? []);
1741
+ }
1742
+ catch (err) {
1743
+ const msg = err instanceof Error ? err.message : String(err);
1744
+ console.log(` ${TAG} account.json unreadable source=${accountJsonPath} error=${msg}`);
1745
+ continue;
1746
+ }
1747
+ for (const a of admins) {
1748
+ if (typeof a.userId !== "string")
1749
+ continue;
1750
+ accountUserIds.add(a.userId);
1751
+ if (!usersUserIds.has(a.userId)) {
1752
+ const userIdShort = a.userId.slice(0, 8);
1753
+ console.log(` ${TAG} direction=account-without-users userId=${userIdShort} source=${accountJsonPath}`);
1754
+ divergences += 1;
1755
+ }
1756
+ }
1757
+ }
1758
+ }
1759
+ for (const uid of usersUserIds) {
1760
+ if (!accountUserIds.has(uid)) {
1761
+ const userIdShort = uid.slice(0, 8);
1762
+ console.log(` ${TAG} direction=users-without-account userId=${userIdShort} source=${usersFile}`);
1763
+ divergences += 1;
1764
+ }
1765
+ }
1766
+ console.log(` ${TAG} check complete divergences=${divergences}`);
1767
+ }
1768
+ function deployPayload() {
1769
+ log("8", TOTAL, `Deploying ${BRAND.productName}...`);
1770
+ if (!existsSync(PAYLOAD_DIR)) {
1771
+ throw new Error(`Payload not found at ${PAYLOAD_DIR}. Package may be corrupted.`);
1772
+ }
1773
+ // Persistent config lives at ~/{configDir}/ — survives rm -rf ~/{installDir}
1774
+ const persistentDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
1775
+ const persistentPasswordFile = join(persistentDir, ".neo4j-password");
1776
+ // users.json lives at <persistentDir>/users.json. Writers (paths.ts,
1777
+ // admin-add, set-pin, seed-neo4j.sh) target the persistent file directly —
1778
+ // see comment in platform/ui/app/lib/paths.ts.
1779
+ const persistentUsersFile = join(persistentDir, "users.json");
1780
+ // Claude Code OAuth credentials live at
1781
+ // `${persistDir}/.claude/.credentials.json`. The brand main service's
1782
+ // `claude` SDK subprocess and admin server read from there via the
1783
+ // Environment=CLAUDE_CONFIG_DIR= block in port-resolution.ts. Fresh
1784
+ // installs prompt the operator to run `claude /login`.
1785
+ const persistentClaudeDir = join(persistentDir, ".claude");
1786
+ mkdirSync(persistentClaudeDir, { recursive: true });
1787
+ // pre-populate the brand `.claude.json` so the manager's
1788
+ // PTY-spawned `claude --verbose --remote-control` boots straight into the
1789
+ // session URL without stopping at the first-run theme picker or the
1790
+ // workspace-trust dialog. Both prompts ate the manager's 30 s url-capture
1791
+ // window on 0.1.6 / 0.1.8 installs (Pi 192.168.88.16 verified). The two
1792
+ // markers required are:
1793
+ // - hasCompletedOnboarding: true (suppresses theme picker)
1794
+ // - projects[$HOME].hasTrustDialogAccepted: true
1795
+ // Existing fields (firstStartTime, oauthAccount, migrationVersion, …) are
1796
+ // preserved so a brand re-install does not clobber state written by claude
1797
+ // during the previous run.
1798
+ const claudeStateFile = join(persistentClaudeDir, ".claude.json");
1799
+ const homeWorkspace = process.env.HOME ?? "/root";
1800
+ let claudeState = {};
1801
+ if (existsSync(claudeStateFile)) {
1802
+ try {
1803
+ claudeState = JSON.parse(readFileSync(claudeStateFile, "utf-8"));
1804
+ }
1805
+ catch {
1806
+ claudeState = {};
1807
+ }
1808
+ }
1809
+ claudeState.hasCompletedOnboarding = true;
1810
+ claudeState.theme = claudeState.theme ?? "auto";
1811
+ const projects = (claudeState.projects ?? {});
1812
+ const homeEntry = projects[homeWorkspace] ?? {};
1813
+ homeEntry.hasTrustDialogAccepted = true;
1814
+ projects[homeWorkspace] = homeEntry;
1815
+ claudeState.projects = projects;
1816
+ writeFileSync(claudeStateFile, JSON.stringify(claudeState, null, 2) + "\n", { mode: 0o600 });
1817
+ console.log(` [install] claude-state primed: ${claudeStateFile} hasCompletedOnboarding=true trustedWorkspace=${homeWorkspace}`);
1818
+ // Brand isolation: installer does not read ~/.maxy/, ~/.cloudflared/, or
1819
+ // ~/.cloudflare/ on non-default brands. These are peer-brand or
1820
+ // shared-singleton paths.
1821
+ // Stop the running service before wiping directories (upgrade path).
1822
+ // The server holds open files in platform/ — rmSync fails with ENOTEMPTY if it's running.
1823
+ // darwin uses `launchctl bootout` instead of systemctl; bootout
1824
+ // returns synchronously when the agent has exited.
1825
+ if (requireSupportedPlatform(process.platform) === "darwin") {
1826
+ spawnSync("launchctl", ["bootout", `${gui()}/${launchdLabel()}`], { stdio: "pipe", timeout: 15_000 });
1827
+ }
1828
+ else {
1829
+ // systemctl stop returns when the main process exits, but ExecStopPost (e.g. VNC cleanup)
1830
+ // may still hold file handles. Poll is-active to wait for full deactivation.
1831
+ const svcName = BRAND.serviceName.replace(".service", "");
1832
+ spawnSync("systemctl", ["--user", "stop", svcName], { stdio: "pipe" });
1833
+ const MAX_STOP_WAIT = 5;
1834
+ for (let i = 0; i < MAX_STOP_WAIT; i++) {
1835
+ const result = spawnSync("systemctl", ["--user", "is-active", svcName], { stdio: "pipe" });
1836
+ const status = result.stdout?.toString().trim();
1837
+ if (status !== "active" && status !== "deactivating") {
1838
+ console.log(` Service stopped (${status || "not found"}).`);
1839
+ break;
1840
+ }
1841
+ if (i === MAX_STOP_WAIT - 1) {
1842
+ console.log(` [WARN] Service still ${status} after ${MAX_STOP_WAIT}s — proceeding with directory wipe.`);
1843
+ break;
1844
+ }
1845
+ spawnSync("sleep", ["1"]);
1846
+ }
1847
+ }
1848
+ // User data lives at {installDir}/data/ — outside the platform/ wipe zone.
1849
+ // Install path creates this fresh; runtime writers populate it on demand.
1850
+ mkdirSync(join(INSTALL_DIR, "data"), { recursive: true });
1851
+ // Wipe deployment directories to prevent stale files.
1852
+ // data/ is NOT wiped — it contains user data (accounts, uploads) that must survive.
1853
+ for (const dir of ["platform", "server", "maxy", "premium-plugins", "docs", ".claude"]) {
1854
+ const target = join(INSTALL_DIR, dir);
1855
+ if (existsSync(target)) {
1856
+ rmSync(target, { recursive: true, force: true });
1857
+ }
1858
+ }
1859
+ mkdirSync(INSTALL_DIR, { recursive: true });
1860
+ // Deploy payload
1861
+ cpSync(PAYLOAD_DIR, INSTALL_DIR, {
1862
+ recursive: true,
1863
+ force: true,
1864
+ });
1865
+ // Link persistent config into install directory
1866
+ const configDir = join(INSTALL_DIR, "platform/config");
1867
+ mkdirSync(configDir, { recursive: true });
1868
+ if (existsSync(persistentPasswordFile)) {
1869
+ cpSync(persistentPasswordFile, join(configDir, ".neo4j-password"));
1870
+ console.log(" Restored Neo4j password.");
1871
+ }
1872
+ // users.json is read directly from persistentDir by both
1873
+ // platform/ui/app/lib/paths.ts (USERS_FILE = MAXY_DIR/users.json) and the
1874
+ // admin MCP plugin (USERS_FILE = CONFIG_DIR/users.json). No copy into the
1875
+ // wipe zone. The line below observes the row count + userId prefixes so a
1876
+ // future regression is grep-detectable in the install log without any
1877
+ // runtime change.
1878
+ if (existsSync(persistentUsersFile)) {
1879
+ try {
1880
+ const raw = readFileSync(persistentUsersFile, "utf-8").trim();
1881
+ const rows = raw ? JSON.parse(raw) : [];
1882
+ const ids = rows
1883
+ .map(r => (typeof r.userId === "string" ? r.userId.slice(0, 8) : "?"))
1884
+ .join(",");
1885
+ console.log(` [install] users.json preserved: rows=${rows.length} userIds=${ids}`);
1886
+ }
1887
+ catch (err) {
1888
+ const msg = err instanceof Error ? err.message : String(err);
1889
+ console.log(` [install] users.json preserved: rows=? parse-failed error=${msg}`);
1890
+ }
1891
+ }
1892
+ else {
1893
+ console.log(" [install] users.json: no persistent file (fresh install — set-pin will create it)");
1894
+ }
1895
+ // install-time admin-auth invariant check. Walks every
1896
+ // data/accounts/*/account.json admins[] and compares to the persistent
1897
+ // users.json. Log-only (does NOT refuse install); the [install-invariant]
1898
+ // line surfaces the bug to the operator without bricking the device.
1899
+ // Inline rather than imported from platform/lib/admins-write because the
1900
+ // installer is its own npm package and doesn't bundle the platform lib.
1901
+ // Mirrors checkAdminAuthInvariant() in platform/lib/admins-write/src/index.ts;
1902
+ // future divergence between the two should be caught by the test suite.
1903
+ runInstallInvariantCheck(persistentUsersFile, join(INSTALL_DIR, "data", "accounts"));
1904
+ // Write version marker so the running platform knows which create-maxy produced this deployment
1905
+ const versionMarkerPath = join(configDir, `.${BRAND.hostname}-version`);
1906
+ writeFileSync(versionMarkerPath, PKG_VERSION, "utf-8");
1907
+ console.log(` [install] version-marker written path=${versionMarkerPath} version=${PKG_VERSION}`);
1908
+ console.log(` Deployed to ${INSTALL_DIR}`);
1909
+ }
1910
+ // register the local + external Claude Code plugins after the
1911
+ // payload is on disk. The bundler stamps `.claude-plugin/marketplace.json`
1912
+ // at each plugin-tree root (platform/plugins/, premium-plugins/real-agent/
1913
+ // plugins/, premium-plugins/) so this function discovers them generically
1914
+ // from the install directory rather than hardcoding names.
1915
+ //
1916
+ // Idempotent on every step: marketplace add is skipped when already in
1917
+ // `marketplace list`; `plugin install` is skipped when the plugin is
1918
+ // already in `plugin list` (matched by `<name>@<marketplace>` or by name
1919
+ // alone). One `[plugin-install] <name>@<src>
1920
+ // idempotent=<bool>` log line per attempt; failures log
1921
+ // `[plugin-install] ERROR <name>@<src> exit=<n> stderr=<short>` and do
1922
+ // NOT abort — one plugin failing must not block the rest, mirroring the
1923
+ // marketplace-add behaviour at src/index.ts:1018-1019.
1924
+ function registerLocalAndExternalPlugins() {
1925
+ console.log(" Registering local + external Claude Code plugins...");
1926
+ const localTrees = [];
1927
+ // The three known marketplace.json locations the bundler emits. Missing
1928
+ // ones are silently skipped (e.g. a brand that ships no premium plugins).
1929
+ const candidates = [
1930
+ join(INSTALL_DIR, "platform", "plugins"),
1931
+ join(INSTALL_DIR, "premium-plugins", "real-agent", "plugins"),
1932
+ join(INSTALL_DIR, "premium-plugins"),
1933
+ ];
1934
+ for (const dir of candidates) {
1935
+ const mkPath = join(dir, ".claude-plugin", "marketplace.json");
1936
+ if (!existsSync(mkPath))
1937
+ continue;
1938
+ try {
1939
+ const parsed = JSON.parse(readFileSync(mkPath, "utf-8"));
1940
+ if (typeof parsed.name === "string" && parsed.name.length > 0) {
1941
+ localTrees.push({ name: parsed.name, dir });
1942
+ }
1943
+ else {
1944
+ logFile(`[plugin-marketplace] ERROR malformed marketplace at ${mkPath} reason=no-name`);
1945
+ }
1946
+ }
1947
+ catch (err) {
1948
+ const msg = err instanceof Error ? err.message : String(err);
1949
+ logFile(`[plugin-marketplace] ERROR parse ${mkPath} error=${JSON.stringify(msg.slice(0, 200))}`);
1950
+ }
1951
+ }
1952
+ // Add each local marketplace. Idempotence via `marketplace list` grep.
1953
+ // every `claude plugin …` call carries CLAUDE_CONFIG_DIR so
1954
+ // marketplaces register into the per-brand config dir that the runtime
1955
+ // session-manager unit reads from.
1956
+ const mkList = spawnSync("claude", ["plugin", "marketplace", "list"], { stdio: "pipe", encoding: "utf-8", env: claudePluginEnv() });
1957
+ const mkListed = mkList.stdout ?? "";
1958
+ for (const { name, dir } of localTrees) {
1959
+ if (mkListed.includes(name)) {
1960
+ logFile(`[plugin-marketplace] added ${name} idempotent=true CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
1961
+ continue;
1962
+ }
1963
+ const add = spawnSync("claude", ["plugin", "marketplace", "add", dir], { stdio: "pipe", encoding: "utf-8", timeout: 60_000, env: claudePluginEnv() });
1964
+ if (add.status === 0) {
1965
+ logFile(`[plugin-marketplace] added ${name} source=${dir} idempotent=false CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
1966
+ }
1967
+ else {
1968
+ const stderrShort = (add.stderr ?? "").split("\n")[0]?.slice(0, 200) ?? "";
1969
+ logFile(`[plugin-marketplace] ERROR add ${name} source=${dir} exit=${add.status} stderr=${JSON.stringify(stderrShort)} CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
1970
+ }
1971
+ }
1972
+ // Build the desired plugin list = (every local marketplace's plugins) +
1973
+ // (brand.json#externalPlugins). The local entries' `marketplace` field
1974
+ // matches the marketplace.json `name`; the external entries declare
1975
+ // their own.
1976
+ const desired = [];
1977
+ for (const { name: mkName, dir } of localTrees) {
1978
+ const mkPath = join(dir, ".claude-plugin", "marketplace.json");
1979
+ try {
1980
+ const parsed = JSON.parse(readFileSync(mkPath, "utf-8"));
1981
+ for (const p of parsed.plugins ?? []) {
1982
+ if (typeof p.name === "string" && p.name.length > 0) {
1983
+ desired.push({ name: p.name, marketplace: mkName });
1984
+ }
1985
+ }
1986
+ }
1987
+ catch {
1988
+ // Already logged above.
1989
+ }
1990
+ }
1991
+ let externals = [];
1992
+ try {
1993
+ externals = parseExternalPlugins(BRAND.externalPlugins);
1994
+ }
1995
+ catch (err) {
1996
+ const msg = err instanceof Error ? err.message : String(err);
1997
+ logFile(`[plugin-install] ERROR brand.externalPlugins parse error=${JSON.stringify(msg.slice(0, 200))}`);
1998
+ }
1999
+ desired.push(...externals);
2000
+ // The directory-source marketplaces are exactly the local trees discovered
2001
+ // from on-disk marketplace.json above. Remote marketplaces (the Anthropic
2002
+ // ones, GitHub externals) are never in this set, so they keep version-pinned
2003
+ // idempotence. (Task 643.)
2004
+ const directorySourceMarketplaces = new Set(localTrees.map(t => t.name));
2005
+ // Snapshot what's installed to compute the install set.
2006
+ const pluginList = spawnSync("claude", ["plugin", "list"], { stdio: "pipe", encoding: "utf-8", env: claudePluginEnv() });
2007
+ const installed = parsePluginList(pluginList.stdout ?? "");
2008
+ const { toInstall, toResync, alreadyInstalled } = computeInstallActions(desired, installed, directorySourceMarketplaces);
2009
+ for (const ref of alreadyInstalled) {
2010
+ logFile(`[plugin-install] ${ref.name}@${ref.marketplace} idempotent=true`);
2011
+ }
2012
+ // Single source of truth for the install invocation, shared by the resync
2013
+ // and fresh-install loops so a future flag/timeout/scope change cannot drift
2014
+ // between them.
2015
+ const pluginInstall = (ref) => spawnSync("claude", ["plugin", "install", `${ref.name}@${ref.marketplace}`, "--scope", "user"], { stdio: "pipe", encoding: "utf-8", timeout: 120_000, env: claudePluginEnv() });
2016
+ // Resync directory-source plugins (Task 643). A directory marketplace
2017
+ // overwrites its tree in place on upgrade with no version bump, so the
2018
+ // runtime cache snapshot the session loads from (installed_plugins.json
2019
+ // `installPath`) freezes at first-install time — `plugin install` and
2020
+ // `plugin update` both short-circuit on the pinned version and never
2021
+ // re-copy. Uninstall then install is the only sequence that rebuilds the
2022
+ // snapshot from the live tree; `install` reads the directory source live.
2023
+ // The uninstall+install pair is not atomic: a failed reinstall leaves the
2024
+ // plugin deregistered, surfaced by the ERROR line below — hardening tracked
2025
+ // in Task 645.
2026
+ for (const ref of toResync) {
2027
+ spawnSync("claude", ["plugin", "uninstall", `${ref.name}@${ref.marketplace}`, "--scope", "user"], { stdio: "pipe", encoding: "utf-8", timeout: 120_000, env: claudePluginEnv() });
2028
+ const install = pluginInstall(ref);
2029
+ if (install.status === 0) {
2030
+ logFile(`[plugin-install] recache ${ref.name}@${ref.marketplace}`);
2031
+ }
2032
+ else {
2033
+ const stderrShort = (install.stderr ?? "").split("\n")[0]?.slice(0, 200) ?? "";
2034
+ logFile(`[plugin-install] ERROR recache ${ref.name}@${ref.marketplace} exit=${install.status} stderr=${JSON.stringify(stderrShort)}`);
2035
+ }
2036
+ }
2037
+ for (const ref of toInstall) {
2038
+ const install = pluginInstall(ref);
2039
+ if (install.status === 0) {
2040
+ logFile(`[plugin-install] ${ref.name}@${ref.marketplace} idempotent=false`);
2041
+ }
2042
+ else {
2043
+ const stderrShort = (install.stderr ?? "").split("\n")[0]?.slice(0, 200) ?? "";
2044
+ logFile(`[plugin-install] ERROR ${ref.name}@${ref.marketplace} exit=${install.status} stderr=${JSON.stringify(stderrShort)}`);
2045
+ }
2046
+ }
2047
+ // Cache-vs-live audit (Task 643). Prove the per-plugin cache snapshot the
2048
+ // runtime loads from now matches the live tree, so drift is a logged
2049
+ // post-condition rather than a "no such skill" surprise in a later session.
2050
+ // Read the authoritative load path from installed_plugins.json
2051
+ // (`installPath`) rather than reconstructing the cache path from a pinned
2052
+ // version string. Warn-only: a count mismatch is surfaced, not fatal — a
2053
+ // benign skill directory without a SKILL.md must not abort the install.
2054
+ const countSkills = (skillsDir) => {
2055
+ if (!existsSync(skillsDir))
2056
+ return 0;
2057
+ let n = 0;
2058
+ for (const entry of readdirSync(skillsDir)) {
2059
+ if (existsSync(join(skillsDir, entry, "SKILL.md")))
2060
+ n++;
2061
+ }
2062
+ return n;
2063
+ };
2064
+ let installedPluginsMap = {};
2065
+ try {
2066
+ const ipPath = join(CLAUDE_CONFIG_DIR, "plugins", "installed_plugins.json");
2067
+ const parsed = JSON.parse(readFileSync(ipPath, "utf-8"));
2068
+ installedPluginsMap = parsed.plugins ?? {};
2069
+ }
2070
+ catch {
2071
+ // No readable installed_plugins.json — audit reports cache-skills=0; any
2072
+ // failed install above already logged a recache/install ERROR line.
2073
+ }
2074
+ // `treeDirByMarketplace` is keyed on the directory-source marketplace names
2075
+ // (= `directorySourceMarketplaces`), so a present tree dir is itself the
2076
+ // directory-source test — no separate Set lookup needed.
2077
+ const treeDirByMarketplace = new Map(localTrees.map(t => [t.name, t.dir]));
2078
+ for (const ref of desired) {
2079
+ const treeDir = treeDirByMarketplace.get(ref.marketplace);
2080
+ if (!treeDir)
2081
+ continue;
2082
+ const liveSkills = countSkills(join(treeDir, ref.name, "skills"));
2083
+ // The resync installs at `--scope user`, so audit that scope's snapshot —
2084
+ // not whichever entry happens to be first, since a host may also carry a
2085
+ // stale project-scope entry for the same plugin.
2086
+ const entries = installedPluginsMap[`${ref.name}@${ref.marketplace}`] ?? [];
2087
+ const installPath = (entries.find(e => e.scope === "user") ?? entries[0])?.installPath;
2088
+ const cacheSkills = installPath ? countSkills(join(installPath, "skills")) : 0;
2089
+ logFile(`[plugin-install] audit ${ref.name}@${ref.marketplace} live-skills=${liveSkills} cache-skills=${cacheSkills}`);
2090
+ if (liveSkills !== cacheSkills) {
2091
+ logFile(`[plugin-install] WARN cache-drift ${ref.name}@${ref.marketplace} live-skills=${liveSkills} cache-skills=${cacheSkills}`);
2092
+ }
2093
+ }
2094
+ // post-install assertion. The per-brand CLAUDE_CONFIG_DIR is the
2095
+ // only surface the runtime session-manager reads from; if any expected
2096
+ // marketplace is missing under .claude/plugins/marketplaces/, the operator
2097
+ // will hit "Unknown skill: onboarding" at step 6 of the bring-up. Fail the
2098
+ // install loudly here rather than ship a broken PTY.
2099
+ //
2100
+ // Expected set = 3 Anthropic marketplace names (from the constant in
2101
+ // installClaudeCode) + every parsed localTrees name. Hardcoding the
2102
+ // Anthropic names keeps the assertion independent of `MARKETPLACES` scope.
2103
+ const expectedMarketplaces = new Set([
2104
+ "claude-plugins-official",
2105
+ "knowledge-work-plugins",
2106
+ "claude-for-financial-services",
2107
+ ...localTrees.map(t => t.name),
2108
+ ]);
2109
+ // `claude plugin marketplace list` is the authoritative source.
2110
+ // The `.claude/plugins/marketplaces/` directory only contains subdirs for
2111
+ // remote (git-cloned) marketplaces — local-source marketplaces registered
2112
+ // via `claude plugin marketplace add <directory-path>` live in user
2113
+ // settings and are visible only through `marketplace list`. Parsing the
2114
+ // CLI output covers both. The CLI emits each entry as two lines: the
2115
+ // leader-glyph name (` ❯ <name>`) followed by ` Source: …`, so the
2116
+ // name is on its own line — anchor on `❯` and require the following line
2117
+ // (after blanks) to start with `Source:` to confirm it is a marketplace
2118
+ // header, not a stray glyph in some other CLI panel.
2119
+ const listResult = spawnSync("claude", ["plugin", "marketplace", "list"], { stdio: "pipe", encoding: "utf-8", env: claudePluginEnv() });
2120
+ const listStdout = listResult.stdout ?? "";
2121
+ const listStderr = listResult.stderr ?? "";
2122
+ const stripAnsi = (s) => s.replace(/\x1b\[[0-9;]*[A-Za-z]/g, "");
2123
+ const parseMarketplaceList = (raw) => {
2124
+ const lines = stripAnsi(raw).split("\n");
2125
+ const names = [];
2126
+ for (let i = 0; i < lines.length; i++) {
2127
+ const nameMatch = lines[i].match(/^\s*❯\s+([A-Za-z0-9._-]+)\s*$/);
2128
+ if (!nameMatch)
2129
+ continue;
2130
+ let j = i + 1;
2131
+ while (j < lines.length && lines[j].trim() === "")
2132
+ j++;
2133
+ if (j < lines.length && /^\s*Source:/.test(lines[j])) {
2134
+ names.push(nameMatch[1]);
2135
+ }
2136
+ }
2137
+ return names;
2138
+ };
2139
+ const actualMarketplaces = parseMarketplaceList(listStdout);
2140
+ if (listResult.error || listResult.status !== 0 || actualMarketplaces.length === 0) {
2141
+ const errMsg = listResult.error ? listResult.error.message : `exit=${listResult.status}`;
2142
+ throw new Error(`Plugin registration produced no marketplaces — \`claude plugin marketplace list\` returned no parseable entries (${errMsg}). stdout=${JSON.stringify(listStdout)} stderr=${JSON.stringify(listStderr.split("\n")[0] ?? "")}. Check setup.log for [plugin-marketplace] ERROR lines.`);
2143
+ }
2144
+ const missing = [...expectedMarketplaces].filter(m => !actualMarketplaces.includes(m));
2145
+ if (missing.length > 0) {
2146
+ logFile(`[plugin-marketplace] assertion-fail expected=${JSON.stringify([...expectedMarketplaces])} actual=${JSON.stringify(actualMarketplaces)} missing=${JSON.stringify(missing)} CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
2147
+ throw new Error(`Plugin registration incomplete: expected marketplaces ${JSON.stringify([...expectedMarketplaces])} but \`claude plugin marketplace list\` returned ${JSON.stringify(actualMarketplaces)}. Missing: ${JSON.stringify(missing)}. Check setup.log for [plugin-marketplace] ERROR lines.`);
2148
+ }
2149
+ logFile(`[plugin-marketplace] assertion-source=claude-plugin-marketplace-list count=${actualMarketplaces.length} marketplaces=${JSON.stringify(actualMarketplaces)} CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
2150
+ // Task 583 — post-install assertion that the brand-scoped permissions
2151
+ // block survived install. Warn-only: a missing block does not abort the
2152
+ // install (consistent with the marketplace ERROR path that logs and
2153
+ // continues per-entry), but surfaces in setup.log for diagnosis.
2154
+ const permissionsAssert = assertBypassPermissionsSeed(CLAUDE_CONFIG_DIR);
2155
+ logFile(`[install-permissions] brand-settings=${permissionsAssert.status} path=${permissionsAssert.path}`);
2156
+ }
2157
+ function buildPlatform() {
2158
+ log("9", TOTAL, "Installing dependencies and building...");
2159
+ console.log(` Installing platform dependencies (${join(INSTALL_DIR, "platform")})...`);
2160
+ shellRetry("npm", ["install", ...NPM_NET_FLAGS], { cwd: join(INSTALL_DIR, "platform") }, 3, 15);
2161
+ // MCP server dist/ files are pre-compiled in the payload — no build step needed.
2162
+ // Server external dependencies (neo4j-driver, @whiskeysockets/baileys, zod, proper-lockfile) are listed in
2163
+ // server/package.json but NOT shipped as pre-built node_modules — npm pack silently
2164
+ // strips files from nested node_modules (e.g. rxjs/package.json), breaking require().
2165
+ // Install fresh on device to guarantee a complete dependency tree.
2166
+ //
2167
+ // On upgrade, wipe `node_modules` first so npm extracts a clean tree. Without
2168
+ // this, an interrupted previous install (network blip, operator cancellation,
2169
+ // power loss) can leave nested package.json files half-truncated — the most
2170
+ // common manifestation is `Error: Invalid package config .../rxjs/package.json`
2171
+ // at server startup, which loops the brand service indefinitely. The wipe
2172
+ // adds ~30 s to upgrades but eliminates a class of unrecoverable customer
2173
+ // states; reliability wins over speed for a one-shot install path.
2174
+ const serverNodeModules = join(INSTALL_DIR, "server", "node_modules");
2175
+ if (existsSync(serverNodeModules)) {
2176
+ console.log(" Wiping previous server/node_modules for a clean reinstall...");
2177
+ rmSync(serverNodeModules, { recursive: true, force: true });
2178
+ }
2179
+ console.log(` Installing server dependencies (${join(INSTALL_DIR, "server")})...`);
2180
+ shellRetry("npm", ["install", "--omit=dev", ...NPM_NET_FLAGS], { cwd: join(INSTALL_DIR, "server") }, 3, 15);
2181
+ // (maxy-code) — claude-session-manager has its own package.json
2182
+ // declaring hono + @hono/node-server + node-pty. node-pty is a native
2183
+ // binding; it MUST be installed on the Pi, not shipped pre-built (different
2184
+ // architecture between the build host and the Pi). Wipe + reinstall on
2185
+ // upgrade so a half-extracted previous install does not loop the unit.
2186
+ const csmDir = join(INSTALL_DIR, "platform", "services", "claude-session-manager");
2187
+ if (existsSync(csmDir)) {
2188
+ const csmNodeModules = join(csmDir, "node_modules");
2189
+ if (existsSync(csmNodeModules)) {
2190
+ console.log(" Wiping previous claude-session-manager/node_modules for a clean reinstall...");
2191
+ rmSync(csmNodeModules, { recursive: true, force: true });
2192
+ }
2193
+ console.log(` Installing claude-session-manager dependencies (${csmDir})...`);
2194
+ shellRetry("npm", ["install", "--omit=dev", ...NPM_NET_FLAGS], { cwd: csmDir }, 3, 15);
2195
+ }
2196
+ // Premium-plugin MCP servers (e.g. real-agent/loop) ship dist/ + package.json
2197
+ // in the payload but no node_modules — npm pack strips them, same reason as
2198
+ // server/. Discover every <installDir>/premium-plugins/<bundle>/plugins/<plugin>/mcp
2199
+ // and install --omit=dev there. dirs=0 in the summary line is itself a signal
2200
+ // when a brand ships premium plugins but the discovery glob is broken.
2201
+ const premiumMcpDirs = findPremiumMcpDirs(INSTALL_DIR);
2202
+ console.log(` [install] premium-mcp-install dirs=${premiumMcpDirs.length}`);
2203
+ for (const mcpDir of premiumMcpDirs) {
2204
+ const mcpNodeModules = join(mcpDir, "node_modules");
2205
+ if (existsSync(mcpNodeModules)) {
2206
+ console.log(` Wiping previous ${mcpDir}/node_modules for a clean reinstall...`);
2207
+ rmSync(mcpNodeModules, { recursive: true, force: true });
2208
+ }
2209
+ console.log(` Installing premium plugin MCP dependencies (${mcpDir})...`);
2210
+ shellRetry("npm", ["install", "--omit=dev", ...NPM_NET_FLAGS], { cwd: mcpDir }, 3, 15);
2211
+ }
2212
+ }
2213
+ function setupVncViewer() {
2214
+ if (!isLinux())
2215
+ return;
2216
+ const novncSrc = "/usr/share/novnc";
2217
+ const novncDest = join(INSTALL_DIR, "server/public/novnc");
2218
+ if (!existsSync(join(novncSrc, "core"))) {
2219
+ console.log(" noVNC not found — skipping VNC viewer setup.");
2220
+ return;
2221
+ }
2222
+ console.log(" Installing VNC viewer...");
2223
+ // Copy core/ and vendor/ (pako compression library) — both required by rfb.js
2224
+ cpSync(join(novncSrc, "core"), join(novncDest, "core"), { recursive: true, force: true });
2225
+ const vendorSrc = join(novncSrc, "vendor");
2226
+ if (existsSync(vendorSrc)) {
2227
+ cpSync(vendorSrc, join(novncDest, "vendor"), { recursive: true, force: true });
2228
+ }
2229
+ // Custom viewer: no toolbar, scales to fit, auto-connects with retry.
2230
+ //
2231
+ // Transport: same-origin WebSocket proxied through the Maxy server's
2232
+ // /websockify upgrade handler. The URL is built from location.protocol
2233
+ // and location.host so that:
2234
+ // - HTTP origin → ws://<host>:<port>/websockify (LAN)
2235
+ // - HTTPS origin → wss://<host>:<port>/websockify (Cloudflare tunnel)
2236
+ // This eliminates the mixed-content block that previously killed the
2237
+ // viewer when accessed via https://admin.maxy.bot.
2238
+ //
2239
+ // The viewer does NOT read a host/port from query string — those
2240
+ // parameters are ignored if present (kept for backward compatibility
2241
+ // with any cached callers) and the connection is always same-origin.
2242
+ //
2243
+ // A per-session correlation ID is generated client-side and included
2244
+ // in the WebSocket URL (?corrId=X) and in the POST to
2245
+ // /api/vnc/client-event so the server-side log can correlate the
2246
+ // noVNC disconnect reason to the specific WS upgrade entry.
2247
+ const html = `<!DOCTYPE html>
2248
+ <html>
2249
+ <head>
2250
+ <meta charset="utf-8">
2251
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
2252
+ <title>Connect Claude</title>
2253
+ <style>
2254
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
2255
+ html, body { width: 100%; height: 100%; background: #111; overflow: hidden; }
2256
+ #screen { position: relative; width: 100%; height: 100%; }
2257
+ #status {
2258
+ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
2259
+ color: #888; font-family: -apple-system, BlinkMacSystemFont, sans-serif;
2260
+ font-size: 14px; text-align: center; z-index: 10;
2261
+ transition: opacity 0.3s;
2262
+ }
2263
+ #status.hidden { opacity: 0; pointer-events: none; }
2264
+ .status-spinner {
2265
+ display: inline-block; width: 20px; height: 20px;
2266
+ border: 2px solid #444; border-top-color: #888; border-radius: 50%;
2267
+ animation: spin 0.8s linear infinite; margin-bottom: 8px;
2268
+ }
2269
+ @keyframes spin { to { transform: rotate(360deg); } }
2270
+ .status-reason { font-size: 12px; color: #666; margin-top: 6px; }
2271
+ </style>
2272
+ </head>
2273
+ <body>
2274
+ <div id="screen"></div>
2275
+ <div id="status">
2276
+ <div class="status-spinner"></div>
2277
+ <div>Connecting to browser…</div>
2278
+ <div class="status-reason"></div>
2279
+ </div>
2280
+ <script type="module">
2281
+ import RFB from '/novnc/core/rfb.js';
2282
+
2283
+ // Build a same-origin WebSocket URL. Protocol auto-matches the
2284
+ // parent page so https pages use wss and http pages use ws.
2285
+ const wsScheme = location.protocol === 'https:' ? 'wss:' : 'ws:';
2286
+ // Generate a client-side correlation ID. This ID is used only for
2287
+ // client-side log correlation (the server assigns its own corrId
2288
+ // on the upgrade handler so an attacker cannot forge server
2289
+ // internal ids). Base-36 random concatenation yields up to 16
2290
+ // chars — collision-free in practice for the 1-session-at-a-time
2291
+ // VNC use case.
2292
+ const corrId = (Math.random().toString(36).slice(2, 10) + Math.random().toString(36).slice(2, 10))
2293
+ .replace(/[^a-z0-9]/gi, '') || 'c' + Date.now().toString(36);
2294
+ const wsUrl = wsScheme + '//' + location.host + '/websockify?corrId=' + encodeURIComponent(corrId);
2295
+
2296
+ const screen = document.getElementById('screen');
2297
+ const status = document.getElementById('status');
2298
+ let retryCount = 0;
2299
+ const MAX_RETRIES = 30;
2300
+
2301
+ // Best-effort POST of a disconnect/error reason to the server so
2302
+ // the noVNC-observed failure mode ends up in vnc-boot.log alongside
2303
+ // the server-side proxy events. Network failures are swallowed —
2304
+ // this is a telemetry side channel, not a critical path.
2305
+ function reportClientEvent(phase, reason) {
2306
+ try {
2307
+ fetch('/api/vnc/client-event', {
2308
+ method: 'POST',
2309
+ credentials: 'same-origin',
2310
+ headers: { 'Content-Type': 'application/json' },
2311
+ body: JSON.stringify({ corrId: corrId, phase: phase, reason: reason || '' }),
2312
+ keepalive: true,
2313
+ }).catch(function() { /* swallow */ });
2314
+ } catch (e) { /* swallow */ }
2315
+ }
2316
+
2317
+ // Layer-6 beacon: emit event=rfb-connected and
2318
+ // event=rfb-error to the operator-grep lifecycle endpoint so
2319
+ // server.log shows the noVNC outcome alongside [device-url:click]
2320
+ // / [http] / [websockify]. Same-origin POST works whether the
2321
+ // iframe is parented by the React VNC viewer or by vnc-popout.html.
2322
+ function reportVncIframeEvent(event, fields) {
2323
+ try {
2324
+ var body = JSON.stringify(Object.assign(
2325
+ { event: event, surface: 'iframe' },
2326
+ fields || {},
2327
+ ));
2328
+ fetch('/api/admin/browser-iframe/event', {
2329
+ method: 'POST',
2330
+ credentials: 'same-origin',
2331
+ headers: { 'Content-Type': 'application/json' },
2332
+ body: body,
2333
+ keepalive: true,
2334
+ }).catch(function() { /* swallow */ });
2335
+ } catch (e) { /* swallow */ }
2336
+ }
2337
+ var connectStartedAt = 0;
2338
+
2339
+ function connect() {
2340
+ status.classList.remove('hidden');
2341
+ status.querySelector('.status-spinner').style.display = '';
2342
+ status.querySelector('div:nth-child(2)').textContent =
2343
+ retryCount > 0 ? 'Reconnecting… (' + retryCount + ')' : 'Connecting to browser…';
2344
+ status.querySelector('.status-reason').textContent = '';
2345
+ connectStartedAt = Date.now();
2346
+
2347
+ const rfb = new RFB(screen, wsUrl);
2348
+ rfb.scaleViewport = true;
2349
+ rfb.clipViewport = true;
2350
+ rfb.resizeSession = false;
2351
+ window.rfb = rfb;
2352
+
2353
+ rfb.addEventListener('connect', () => {
2354
+ status.classList.add('hidden');
2355
+ retryCount = 0;
2356
+ reportVncIframeEvent('rfb-connected', {
2357
+ durationMs: Date.now() - connectStartedAt,
2358
+ });
2359
+ });
2360
+
2361
+ rfb.addEventListener('disconnect', (e) => {
2362
+ status.classList.remove('hidden');
2363
+ const detail = e.detail || {};
2364
+ const reason = detail.reason || (detail.clean === false ? 'Connection refused' : '');
2365
+ reportClientEvent('disconnect', reason || (detail.clean === false ? 'unclean-close' : 'normal'));
2366
+ reportVncIframeEvent('rfb-error', {
2367
+ durationMs: Date.now() - connectStartedAt,
2368
+ errorCode: detail.clean === false ? 'unclean-close' : 'normal',
2369
+ message: reason || '',
2370
+ });
2371
+ const reasonEl = status.querySelector('.status-reason');
2372
+ if (retryCount < MAX_RETRIES) {
2373
+ retryCount++;
2374
+ const delay = Math.min(1000 * retryCount, 5000);
2375
+ status.querySelector('div:nth-child(2)').textContent = 'Reconnecting in ' + Math.ceil(delay/1000) + 's…';
2376
+ reasonEl.textContent = reason;
2377
+ setTimeout(connect, delay);
2378
+ } else {
2379
+ status.querySelector('.status-spinner').style.display = 'none';
2380
+ status.querySelector('div:nth-child(2)').textContent = 'Connection lost. Reload the page to retry.';
2381
+ reasonEl.textContent = reason;
2382
+ }
2383
+ });
2384
+
2385
+ // --- Clipboard bridge (local ↔ remote) ---
2386
+
2387
+ // Paste bridge: intercept Cmd/Ctrl+V in the capturing phase before
2388
+ // noVNC's keydown handler can call preventDefault(). noVNC v1.3.0
2389
+ // binds its handler with .bind(this) in the Keyboard constructor and
2390
+ // registers the bound reference via addEventListener — so monkey-
2391
+ // patching the unbound method on the instance is a no-op. A capturing-
2392
+ // phase listener on document fires before noVNC's target-phase handler
2393
+ // regardless of registration timing or internal structure.
2394
+ document.addEventListener('keydown', (e) => {
2395
+ if ((e.ctrlKey || e.metaKey) && (e.key === 'v' || e.key === 'V')) {
2396
+ e.stopImmediatePropagation();
2397
+ reportClientEvent('paste-bridge', 'keydown-intercepted');
2398
+ }
2399
+ }, true);
2400
+
2401
+ // Catch the paste event, sync text to VNC server clipboard, then
2402
+ // send Ctrl+V keystrokes so the remote app pastes the synced content.
2403
+ document.addEventListener('paste', (e) => {
2404
+ e.preventDefault();
2405
+ const text = (e.clipboardData || window.clipboardData)?.getData('text');
2406
+ if (!text || !window.rfb) {
2407
+ reportClientEvent('paste-bridge', 'empty-clipboard');
2408
+ return;
2409
+ }
2410
+ reportClientEvent('paste-bridge', 'paste-event text-length=' + text.length);
2411
+ window.rfb.clipboardPasteFrom(text);
2412
+ reportClientEvent('paste-bridge', 'clipboard-synced');
2413
+ setTimeout(() => {
2414
+ window.rfb.sendKey(0xFFE3, 'ControlLeft', true);
2415
+ window.rfb.sendKey(0x0076, 'v', true);
2416
+ window.rfb.sendKey(0x0076, 'v', false);
2417
+ window.rfb.sendKey(0xFFE3, 'ControlLeft', false);
2418
+ }, 50);
2419
+ });
2420
+
2421
+ // Copy bridge: when the remote clipboard changes, notify the parent frame.
2422
+ rfb.addEventListener('clipboard', (e) => {
2423
+ window.parent.postMessage({ type: 'vnc-clipboard', text: e.detail.text }, '*');
2424
+ });
2425
+ }
2426
+
2427
+ connect();
2428
+ </script>
2429
+ </body>
2430
+ </html>`;
2431
+ writeFileSync(join(INSTALL_DIR, "server/public/vnc-viewer.html"), html);
2432
+ console.log(" VNC viewer ready at /vnc-viewer.html");
2433
+ }
2434
+ function setupAccount() {
2435
+ log("10", TOTAL, "Setting up...");
2436
+ // Account-side setup runs first: creates the account dir, writes the
2437
+ // Claude Code project settings (hooks only — no permissions.allow),
2438
+ // installs specialist templates, seeds account.json. Then seed-neo4j.sh
2439
+ // applies the schema and MERGEs the root :LocalBusiness / owner
2440
+ // :AdminUser nodes. setup-account.sh has no Neo4j env dependency;
2441
+ // seed-neo4j.sh hard-exits without NEO4J_URI, so we derive the URI +
2442
+ // password (a missing password file is a hard error here — the
2443
+ // upstream ensureNeo4jPassword() would have thrown if it couldn't
2444
+ // reach the brand's Neo4j).
2445
+ const setupScript = join(INSTALL_DIR, "platform/scripts/setup-account.sh");
2446
+ if (existsSync(setupScript)) {
2447
+ shell("bash", [setupScript], { cwd: INSTALL_DIR });
2448
+ }
2449
+ const passwordFile = join(INSTALL_DIR, "platform/config/.neo4j-password");
2450
+ if (!existsSync(passwordFile)) {
2451
+ throw new Error(`Neo4j password file missing at ${passwordFile} — required by setup step.`);
2452
+ }
2453
+ const password = readFileSync(passwordFile, "utf-8").trim();
2454
+ const neo4jUri = `bolt://localhost:${NEO4J_PORT}`;
2455
+ const neo4jEnv = { ...process.env, NEO4J_URI: neo4jUri, NEO4J_PASSWORD: password };
2456
+ const seedScript = join(INSTALL_DIR, "platform/scripts/seed-neo4j.sh");
2457
+ if (existsSync(seedScript)) {
2458
+ console.log(` [neo4j] passing NEO4J_URI=${neo4jUri} to seed`);
2459
+ logFile(` [neo4j] passing NEO4J_URI=${neo4jUri} to seed`);
2460
+ shell("bash", [seedScript], { cwd: INSTALL_DIR, env: neo4jEnv });
2461
+ }
2462
+ // Task 165 — register every bundled specialist subagent at
2463
+ // $CLAUDE_CONFIG_DIR/agents/<name>.md. Claude Code's `--agent <name>`
2464
+ // discovery only resolves under this path; without these symlinks,
2465
+ // every `--agent database-operator` etc. silently runs as the admin
2466
+ // agent on admin IDENTITY/SOUL scaffolding. Symlinks (not copies) so
2467
+ // a `npx -y @rubytech/create-maxy-code` upgrade picks up template
2468
+ // changes without a second seed run.
2469
+ registerSpecialistAgents();
2470
+ // install-time defaults. Stamp `account.json` with the
2471
+ // brand's default plugin set + default outputStyle / thinkingView, and
2472
+ // write a minimal admin SOUL.md. The agent boots into a working state
2473
+ // with no onboarding state machine; the operator builds personality up
2474
+ // through use. The graph-write gate blocks user-domain writes
2475
+ // until AdminUser + LocalBusiness/personal-profile Person exist, so the
2476
+ // persona is elicited the first time the operator triggers a write.
2477
+ const accountId = resolveInstallAccountId();
2478
+ if (accountId) {
2479
+ writeInstallDefaults(accountId);
2480
+ }
2481
+ else {
2482
+ console.log(" [install-defaults] SKIPPED reason=no-account-discovered");
2483
+ }
2484
+ }
2485
+ function writeInstallDefaults(accountId) {
2486
+ const accountDir = join(INSTALL_DIR, "data/accounts", accountId);
2487
+ const accountJsonPath = join(accountDir, "account.json");
2488
+ const enabledPlugins = BRAND.plugins?.defaultEnabled ?? [];
2489
+ let config = {};
2490
+ if (existsSync(accountJsonPath)) {
2491
+ try {
2492
+ config = JSON.parse(readFileSync(accountJsonPath, "utf-8"));
2493
+ }
2494
+ catch (err) {
2495
+ console.error(` [install-defaults] account.json unreadable at ${accountJsonPath}: ${err.message}`);
2496
+ logFile(` [install-defaults] account.json unreadable: ${err.message}`);
2497
+ return;
2498
+ }
2499
+ }
2500
+ config.enabledPlugins = enabledPlugins;
2501
+ config.outputStyle = "default";
2502
+ config.thinkingView = "default";
2503
+ if (TIER_FLAG) {
2504
+ config = applyTierToAccountConfig(config, TIER_FLAG);
2505
+ }
2506
+ writeFileSync(accountJsonPath, JSON.stringify(config, null, 2) + "\n");
2507
+ console.log(` [install-defaults] account-json plugins=${enabledPlugins.length} outputStyle=default thinkingView=default`);
2508
+ logFile(` [install-defaults] account-json plugins=${enabledPlugins.length} outputStyle=default thinkingView=default`);
2509
+ if (TIER_FLAG) {
2510
+ const tierLine = ` [install-defaults] tier=${TIER_FLAG} mode=personal source=cli-flag`;
2511
+ console.log(tierLine);
2512
+ logFile(tierLine);
2513
+ }
2514
+ // Admin SOUL.md is user-controlled personalisation: create it from the
2515
+ // bundled template (with ${PRODUCT_NAME} substituted) on a fresh install,
2516
+ // and never overwrite it once it exists. The operator builds the agent's
2517
+ // personality up through use, so an existing SOUL must survive every
2518
+ // upgrade. Task 511: an unconditional write here reset SOUL to the 7-byte
2519
+ // template on every full install. Mirrors the public SOUL guard below and
2520
+ // the create-if-missing branch in setup-account.sh.
2521
+ const soulPath = join(accountDir, "agents/admin/SOUL.md");
2522
+ mkdirSync(dirname(soulPath), { recursive: true });
2523
+ if (existsSync(soulPath)) {
2524
+ const preservedBytes = statSync(soulPath).size;
2525
+ console.log(` [install-defaults] soul-md preserved path=${soulPath} bytes=${preservedBytes}`);
2526
+ logFile(` [install-defaults] soul-md preserved path=${soulPath} bytes=${preservedBytes}`);
2527
+ }
2528
+ else {
2529
+ const adminSoulTemplate = join(INSTALL_DIR, "platform/templates/agents/admin/SOUL.md");
2530
+ let soulContent;
2531
+ try {
2532
+ soulContent = readFileSync(adminSoulTemplate, "utf-8");
2533
+ }
2534
+ catch (err) {
2535
+ console.error(` [install-defaults] admin-soul template missing at ${adminSoulTemplate}: ${err.message}`);
2536
+ logFile(` [install-defaults] admin-soul template missing: ${err.message}`);
2537
+ return;
2538
+ }
2539
+ soulContent = soulContent.replace(/\$\{PRODUCT_NAME\}/g, BRAND.productName);
2540
+ writeFileSync(soulPath, soulContent);
2541
+ console.log(` [install-defaults] soul-md created path=${soulPath} bytes=${soulContent.length}`);
2542
+ logFile(` [install-defaults] soul-md created path=${soulPath} bytes=${soulContent.length}`);
2543
+ }
2544
+ // Public agent IDENTITY.md — the only template-seeded public file, always
2545
+ // overwritten (Rubytech-controlled toolless directive). Per Task 618/623,
2546
+ // each public agent's SOUL.md, KNOWLEDGE.md, and config.json are authored
2547
+ // client-side when the operator creates the agent through the admin UI;
2548
+ // they are not seeded from templates at install time. A public spawn for an
2549
+ // un-authored agent refuses as a dud (soul-empty / knowledge-missing), which
2550
+ // is the intended loud signal — do not re-introduce template SOUL/config
2551
+ // copies here (commit 82c5658d6 removed the template files).
2552
+ const publicDir = join(accountDir, "agents/public");
2553
+ mkdirSync(publicDir, { recursive: true });
2554
+ const publicTemplatesDir = join(INSTALL_DIR, "platform/templates/agents/public");
2555
+ const publicIdentityDst = join(publicDir, "IDENTITY.md");
2556
+ cpSync(join(publicTemplatesDir, "IDENTITY.md"), publicIdentityDst);
2557
+ console.log(` [install-defaults] public-identity path=${publicIdentityDst}`);
2558
+ logFile(` [install-defaults] public-identity path=${publicIdentityDst}`);
2559
+ }
2560
+ /**
2561
+ * Commercial-mode entitlement delivery (Task 240). Writes the decoded payload
2562
+ * bytes verbatim to ~/<BRAND.configDir>/entitlement.json. Signature and shape
2563
+ * validation happen at the verifier at session start (entitlement lib); the
2564
+ * installer is a dumb delivery channel — a malformed payload that survived
2565
+ * --entitlement-base64 parsing will be caught there and degrade the install
2566
+ * to anonymous-fallback, which is the correct loud-fail per doctrine.
2567
+ */
2568
+ function writeEntitlementFromFlag(payload) {
2569
+ const target = entitlementPath(process.env.HOME ?? "/root", BRAND.configDir);
2570
+ mkdirSync(dirname(target), { recursive: true });
2571
+ writeFileSync(target, payload);
2572
+ const line = ` [install-defaults] entitlement-delivered bytes=${payload.length} path=${target} source=cli-flag`;
2573
+ console.log(line);
2574
+ logFile(line);
2575
+ }
2576
+ // Task 394 — premium-bundle agents register through the native Claude Code
2577
+ // subagent registry via `.claude-plugin/plugin.json` manifests emitted by
2578
+ // scripts/generate-plugin-manifests.mjs at bundle time, not through a
2579
+ // parallel symlink channel. This function still wires the bundled platform
2580
+ // specialists (database-operator, project-manager, …) under
2581
+ // platform/templates/specialists/agents/, which are not part of a
2582
+ // registered plugin and rely on $CLAUDE_CONFIG_DIR/agents/ resolution.
2583
+ function registerSpecialistAgents() {
2584
+ try {
2585
+ registerSpecialistAgentsAt(join(INSTALL_DIR, "platform/templates/specialists/agents"), join(CLAUDE_CONFIG_DIR, "agents"), (line) => { console.log(line); logFile(line); });
2586
+ }
2587
+ catch (err) {
2588
+ if (err instanceof SpecialistSymlinkCollision) {
2589
+ console.error(`Setup failed: ${err.message}`);
2590
+ console.error(` Remove the file and re-run.`);
2591
+ process.exit(1);
2592
+ }
2593
+ throw err;
2594
+ }
2595
+ }
2596
+ // ---------------------------------------------------------------------------
2597
+ // Account discovery (shared by installService + the post-install summary)
2598
+ //
2599
+ // `installService` stamps `Environment=ACCOUNT_ID=` into the brand
2600
+ // systemd unit so the writeNodeWithEdges gate has a non-undefined identity to
2601
+ // compare against. Pulled from `INSTALL_DIR/data/accounts/<uuid>/account.json`
2602
+ // written by setup-account.sh during setupAccount(). One reader, one shape, one
2603
+ // source of truth.
2604
+ //
2605
+ // retired the installer's cron registration — `resolveInstallAccountId`
2606
+ // kept its second consumer (installService) and is referenced again at print
2607
+ // time for the post-install banner.
2608
+ // ---------------------------------------------------------------------------
2609
+ function resolveInstallAccountId() {
2610
+ const accountsDir = join(INSTALL_DIR, "data/accounts");
2611
+ if (!existsSync(accountsDir))
2612
+ return "";
2613
+ try {
2614
+ for (const d of readdirSync(accountsDir)) {
2615
+ if (existsSync(join(accountsDir, d, "account.json")))
2616
+ return d;
2617
+ }
2618
+ }
2619
+ catch { /* directory unreadable */ }
2620
+ return "";
2621
+ }
2622
+ // retired the ttyd/tmux/xterm admin terminal stack. Upgrades run
2623
+ // via the action runner — `systemd-run --user` transient units spawned by
2624
+ // POST /api/admin/actions/upgrade — whose lifetime is independent of
2625
+ // maxy-ui, achieving the invariant structurally rather than via
2626
+ // a peer edge service proxying a ttyd process. The installer no longer
2627
+ // provisions the ttyd binary, writes a tmux conf, or installs a ttyd
2628
+ // systemd unit. The corresponding admin UI (RemoteTerminal, TerminalOverlay,
2629
+ // xterm.js) was deleted in the same task.
2630
+ // reverse-DNS LaunchAgent label. Becomes both the plist's
2631
+ // <key>Label</key> value and the file basename
2632
+ // (`~/Library/LaunchAgents/com.rubytech.<hostname>.plist`). Per-brand so
2633
+ // installing brand B never displaces brand A's agent (mirrors the per-brand
2634
+ // systemd unit invariant).
2635
+ function launchdLabel() {
2636
+ return `com.rubytech.${BRAND.hostname}`;
2637
+ }
2638
+ function launchAgentsDir() {
2639
+ return resolve(process.env.HOME ?? "/", "Library/LaunchAgents");
2640
+ }
2641
+ function plistPath() {
2642
+ return join(launchAgentsDir(), `${launchdLabel()}.plist`);
2643
+ }
2644
+ function gui() {
2645
+ // launchd's gui domain is keyed on the user's UID. process.getuid is only
2646
+ // defined on POSIX (always present on darwin); typed conservatively.
2647
+ const uid = typeof process.getuid === "function" ? process.getuid() : 0;
2648
+ return `gui/${uid}`;
2649
+ }
2650
+ // darwin LaunchAgent supervisor. Mirrors the systemd-user body
2651
+ // below at the success-criteria level: process registered with the user's
2652
+ // session manager, KeepAlive respawns on crash, RunAtLoad starts the agent
2653
+ // on every login. Out-of-scope today: brew-resolved node path,
2654
+ // dedicated Neo4j on a non-default port. Falls back to /usr/local/bin/node
2655
+ // (homebrew Intel + manual Apple-silicon installs) will replace
2656
+ // this with the resolver.
2657
+ function installServiceDarwin() {
2658
+ const persistDir = resolve(process.env.HOME ?? "/", BRAND.configDir);
2659
+ const logsDir = join(persistDir, "logs");
2660
+ mkdirSync(logsDir, { recursive: true });
2661
+ // Mirror the Linux brand systemd unit's `Environment=` lines into .env.
2662
+ // Linux stamps every var explicitly on the unit; darwin has no systemd
2663
+ // EnvironmentFile primitive, so the wrapper sources .env before exec'ing
2664
+ // node. Any var the boot path or per-request handlers require (PORT,
2665
+ // MAXY_UI_INTERNAL_PORT, CLAUDE_SESSION_MANAGER_PORT, ACCOUNT_ID,
2666
+ // MAXY_PLATFORM_ROOT, NEO4J_URI, CLAUDE_CONFIG_DIR, NODE_ENV) must be
2667
+ // written here or the server hard-fails — boot-throw for module-init
2668
+ // consumers, per-request 500s for handlers like /api/admin/claude-sessions*
2669
+ // that requirePortEnv lazily on the manager port.
2670
+ // VNC/X11 vars (DISPLAY, RFB_PORT, WEBSOCKIFY_PORT, CDP_PORT) are Pi-only
2671
+ // and excluded — darwin runs no kiosk display stack.
2672
+ //
2673
+ // Darwin collapses the two-process model: Linux runs a separate
2674
+ // `maxy-edge.service` on 0.0.0.0:PORT that reverse-proxies into the brand
2675
+ // server on 127.0.0.1:MAXY_UI_INTERNAL_PORT, with edge surviving brand
2676
+ // restarts so the browser WebSocket stays connected. Edge also owns the
2677
+ // VNC websockify stack, which darwin doesn't have. On darwin the brand
2678
+ // server binds the public port directly:
2679
+ // HOSTNAME=0.0.0.0 → bind all interfaces (LAN reachable)
2680
+ // MAXY_UI_INTERNAL_PORT=PORT → same port, no +1 split
2681
+ // Tradeoff: no zero-downtime restarts; a brand restart drops live
2682
+ // websockets. Acceptable on a single-operator dev Mac.
2683
+ const installAccountId = resolveInstallAccountId();
2684
+ if (!installAccountId) {
2685
+ throw new Error(`installServiceDarwin: no account discovered at ${INSTALL_DIR}/data/accounts/<uuid>/account.json — ` +
2686
+ `setupAccount() (setup-account.sh) should have created one. Refusing to write .env ` +
2687
+ `without ACCOUNT_ID; the boot validator would FATAL on every kickstart.`);
2688
+ }
2689
+ const envPath = join(persistDir, ".env");
2690
+ try {
2691
+ let envContent = "";
2692
+ try {
2693
+ envContent = readFileSync(envPath, "utf-8");
2694
+ }
2695
+ catch { /* first install */ }
2696
+ for (const [key, value] of [
2697
+ ["NODE_ENV", "production"],
2698
+ ["DISPLAY_MODE", DISPLAY_MODE],
2699
+ ["EMBED_MODEL", EMBED_MODEL],
2700
+ ["EMBED_DIMENSIONS", String(EMBED_DIMS)],
2701
+ ["NEO4J_URI", `bolt://localhost:${NEO4J_PORT}`],
2702
+ ["PORT", String(PORT)],
2703
+ ["MAXY_UI_INTERNAL_PORT", String(PORT)],
2704
+ ["CLAUDE_SESSION_MANAGER_PORT", String(BRAND.claudeSessionManagerPort)],
2705
+ ["ACCOUNT_ID", installAccountId],
2706
+ ["MAXY_PLATFORM_ROOT", `${INSTALL_DIR}/platform`],
2707
+ ["CLAUDE_CONFIG_DIR", `${persistDir}/.claude`],
2708
+ ["HOSTNAME", "0.0.0.0"],
2709
+ ["KEEP_ALIVE_TIMEOUT", "61000"],
2710
+ // launchd hands the server a bare PATH (/usr/bin:/bin:/usr/sbin:/sbin)
2711
+ // that excludes the two Homebrew prefixes the `claude` binary lives in
2712
+ // under Apple Silicon and Intel. The wrapper sources this file with
2713
+ // `set -a; . "$envPath"; set +a`, so `$PATH` expands at source-time
2714
+ // against the bare launchd PATH and Homebrew prefixes get prepended for
2715
+ // every spawned descendant (claude-session-manager, MCP plugin spawns,
2716
+ // route-level spawn('claude', ...)). Task 386.
2717
+ ["PATH", "/opt/homebrew/bin:/usr/local/bin:$PATH"],
2718
+ ]) {
2719
+ const re = new RegExp(`^${key}=.*$`, "m");
2720
+ if (re.test(envContent)) {
2721
+ envContent = envContent.replace(re, `${key}=${value}`);
2722
+ }
2723
+ else {
2724
+ envContent = envContent.trimEnd() + (envContent.length > 0 ? "\n" : "") + `${key}=${value}\n`;
2725
+ }
2726
+ }
2727
+ writeFileSync(envPath, envContent);
2728
+ logFile(` .env: DISPLAY_MODE=${DISPLAY_MODE}, EMBED_MODEL=${EMBED_MODEL}, EMBED_DIMENSIONS=${EMBED_DIMS}, NEO4J_URI=bolt://localhost:${NEO4J_PORT}, PORT=${PORT}, MAXY_UI_INTERNAL_PORT=${PORT} (darwin-collapsed), CLAUDE_SESSION_MANAGER_PORT=${BRAND.claudeSessionManagerPort}, HOSTNAME=0.0.0.0, ACCOUNT_ID=${installAccountId.slice(0, 8)}…, CLAUDE_CONFIG_DIR=${persistDir}/.claude`);
2729
+ }
2730
+ catch (err) {
2731
+ console.error(` WARNING: failed to write .env to ${envPath}: ${err instanceof Error ? err.message : String(err)}`);
2732
+ }
2733
+ // Render the plist. The wrapper shell script reads .env before exec'ing
2734
+ // node so the runtime config (PORT, MAXY_PLATFORM_ROOT, NEO4J_URI) lands
2735
+ // in the child env. Without this, ProgramArguments executes node directly
2736
+ // and the .env values are unread — server binds the wrong port.
2737
+ const wrapperPath = join(persistDir, "launchd-wrapper.sh");
2738
+ // Resolve node binary at install time so the wrapper picks the right
2739
+ // path on both Intel (/usr/local/bin/node) and Apple Silicon
2740
+ // (/opt/homebrew/bin/node) — Homebrew's prefix differs by arch.
2741
+ const nodeProbe = spawnSync("command", ["-v", "node"], { encoding: "utf-8", shell: true });
2742
+ const nodeBin = (nodeProbe.stdout ?? "").trim() || "/usr/local/bin/node";
2743
+ const wrapperBody = [
2744
+ "#!/bin/bash",
2745
+ "# generated by create-maxy installService(). Reads.env then",
2746
+ "# execs node so launchd's child inherits PORT, NEO4J_URI, etc. Replaces",
2747
+ "# the systemd EnvironmentFile= directive that has no launchd analogue.",
2748
+ `set -a; [ -f "${envPath}" ] && . "${envPath}"; set +a`,
2749
+ `cd "${INSTALL_DIR}/server"`,
2750
+ `exec ${nodeBin} --require ./server-init.cjs server.js`,
2751
+ "",
2752
+ ].join("\n");
2753
+ writeFileSync(wrapperPath, wrapperBody);
2754
+ chmodSync(wrapperPath, 0o755);
2755
+ const label = launchdLabel();
2756
+ const plist = renderPlist({
2757
+ label,
2758
+ programArguments: ["/bin/bash", wrapperPath],
2759
+ stdoutPath: join(logsDir, "server.log"),
2760
+ stderrPath: join(logsDir, "server.log"),
2761
+ keepAlive: true,
2762
+ runAtLoad: true,
2763
+ workingDirectory: `${INSTALL_DIR}/server`,
2764
+ });
2765
+ mkdirSync(launchAgentsDir(), { recursive: true });
2766
+ const path = plistPath();
2767
+ writeFileSync(path, plist);
2768
+ logFile(` ${path} written (${plist.length} bytes)`);
2769
+ // Idempotent re-install: bootout the previous instance (if any) first so
2770
+ // the second `bootstrap` does not exit 5 ("already loaded"). Best-effort —
2771
+ // a missing service is the expected case on fresh installs.
2772
+ spawnSync("launchctl", ["bootout", `${gui()}/${label}`], { stdio: "pipe" });
2773
+ const bootstrap = spawnSync("launchctl", ["bootstrap", gui(), path], {
2774
+ stdio: "pipe",
2775
+ encoding: "utf-8",
2776
+ timeout: 15_000,
2777
+ });
2778
+ if (bootstrap.status === 0) {
2779
+ console.log(` [launchd] bootstrap ${gui()}/${label} ok`);
2780
+ logFile(` [launchd] bootstrap ${gui()}/${label} ok`);
2781
+ logFile(` [create-maxy] launchd-plist=${path} loaded=true`);
2782
+ }
2783
+ else {
2784
+ const stderr = (bootstrap.stderr ?? "").trim();
2785
+ console.error(` [launchd] bootstrap returned ${bootstrap.status}: ${stderr}`);
2786
+ logFile(` [launchd] bootstrap returned ${bootstrap.status}: ${stderr}`);
2787
+ logFile(` [create-maxy] launchd-plist=${path} loaded=false exit=${bootstrap.status}`);
2788
+ throw new Error(`launchctl bootstrap ${gui()} ${path} failed (exit ${bootstrap.status}): ${stderr}`);
2789
+ }
2790
+ // Wait for the server to come up.
2791
+ console.log(" Waiting for web server...");
2792
+ let webServerUp = false;
2793
+ for (let i = 0; i < 20; i++) {
2794
+ try {
2795
+ execFileSync("curl", ["-sf", `http://localhost:${PORT}`, "-o", "/dev/null"], { timeout: 3000 });
2796
+ webServerUp = true;
2797
+ break;
2798
+ }
2799
+ catch {
2800
+ spawnSync("sleep", ["2"]);
2801
+ }
2802
+ }
2803
+ if (!webServerUp) {
2804
+ console.log(` Server may still be starting. Check http://localhost:${PORT} in a moment.`);
2805
+ }
2806
+ }
2807
+ function installService() {
2808
+ log("11", TOTAL, `Starting ${BRAND.productName}...`);
2809
+ // Linux falls through to the systemd-user body below; darwin renders +
2810
+ // bootstraps a LaunchAgent and returns; unsupported throws the literal
2811
+ // refusal at requireSupportedPlatform.
2812
+ const platform = requireSupportedPlatform(process.platform);
2813
+ if (platform === "darwin") {
2814
+ installServiceDarwin();
2815
+ return;
2816
+ }
2817
+ // Persist UDP buffer sizes for cloudflared QUIC stability (applied on every boot via sysctl.d)
2818
+ const sysctlTmpPath = `/tmp/99-${BRAND.hostname}-quic.conf`;
2819
+ const sysctlDestPath = `/etc/sysctl.d/99-${BRAND.hostname}-quic.conf`;
2820
+ try {
2821
+ const sysctlConf = "net.core.rmem_max=7340032\nnet.core.wmem_max=7340032\n";
2822
+ writeFileSync(sysctlTmpPath, sysctlConf);
2823
+ console.log(" [privileged] cp");
2824
+ shell("cp", [sysctlTmpPath, sysctlDestPath], { sudo: true });
2825
+ spawnSync("rm", ["-f", sysctlTmpPath]);
2826
+ spawnSync("sudo", ["sysctl", "--system"], { stdio: "ignore", timeout: 10_000 });
2827
+ }
2828
+ catch { /* non-critical — values applied on next reboot */ }
2829
+ const serviceDir = resolve(process.env.HOME ?? "/root", ".config/systemd/user");
2830
+ mkdirSync(serviceDir, { recursive: true });
2831
+ // Create systemd user service
2832
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
2833
+ mkdirSync(join(persistDir, "logs"), { recursive: true });
2834
+ // Write install-time config to .env (systemd reads via EnvironmentFile).
2835
+ // Preserves existing .env content (e.g. PORT overrides) — only
2836
+ // replaces or appends each managed line.
2837
+ const envPath = join(persistDir, ".env");
2838
+ try {
2839
+ let envContent = "";
2840
+ try {
2841
+ envContent = readFileSync(envPath, "utf-8");
2842
+ }
2843
+ catch { /* first install */ }
2844
+ // DISPLAY_MODE
2845
+ if (/^DISPLAY_MODE=.*/m.test(envContent)) {
2846
+ envContent = envContent.replace(/^DISPLAY_MODE=.*/m, `DISPLAY_MODE=${DISPLAY_MODE}`);
2847
+ }
2848
+ else {
2849
+ envContent = envContent.trimEnd() + (envContent.length > 0 ? "\n" : "") + `DISPLAY_MODE=${DISPLAY_MODE}\n`;
2850
+ }
2851
+ // EMBED_MODEL
2852
+ if (/^EMBED_MODEL=.*/m.test(envContent)) {
2853
+ envContent = envContent.replace(/^EMBED_MODEL=.*/m, `EMBED_MODEL=${EMBED_MODEL}`);
2854
+ }
2855
+ else {
2856
+ envContent = envContent.trimEnd() + (envContent.length > 0 ? "\n" : "") + `EMBED_MODEL=${EMBED_MODEL}\n`;
2857
+ }
2858
+ // EMBED_DIMENSIONS
2859
+ if (/^EMBED_DIMENSIONS=.*/m.test(envContent)) {
2860
+ envContent = envContent.replace(/^EMBED_DIMENSIONS=.*/m, `EMBED_DIMENSIONS=${EMBED_DIMS}`);
2861
+ }
2862
+ else {
2863
+ envContent = envContent.trimEnd() + (envContent.length > 0 ? "\n" : "") + `EMBED_DIMENSIONS=${EMBED_DIMS}\n`;
2864
+ }
2865
+ // NEO4J_URI — always written so the platform connects to the correct instance.
2866
+ // For shared instances this is bolt://localhost:7687 (the default seed-neo4j.sh
2867
+ // would use anyway), but writing it explicitly makes the .env self-documenting
2868
+ // and ensures upgrade detection works for any future port change.
2869
+ const neo4jUri = `bolt://localhost:${NEO4J_PORT}`;
2870
+ if (/^NEO4J_URI=.*/m.test(envContent)) {
2871
+ envContent = envContent.replace(/^NEO4J_URI=.*/m, `NEO4J_URI=${neo4jUri}`);
2872
+ }
2873
+ else {
2874
+ envContent = envContent.trimEnd() + (envContent.length > 0 ? "\n" : "") + `NEO4J_URI=${neo4jUri}\n`;
2875
+ }
2876
+ writeFileSync(envPath, envContent);
2877
+ logFile(` .env: DISPLAY_MODE=${DISPLAY_MODE}, EMBED_MODEL=${EMBED_MODEL}, EMBED_DIMENSIONS=${EMBED_DIMS}, NEO4J_URI=${neo4jUri}`);
2878
+ }
2879
+ catch (err) {
2880
+ console.error(` WARNING: failed to write .env to ${envPath}: ${err instanceof Error ? err.message : String(err)}`);
2881
+ }
2882
+ // Propagate to child processes — seed-neo4j.sh reads both variables.
2883
+ process.env.EMBED_DIMENSIONS = String(EMBED_DIMS);
2884
+ process.env.NEO4J_URI = `bolt://localhost:${NEO4J_PORT}`;
2885
+ // maxy-ui runs on an internal-only port so a restart does not
2886
+ // drop the public TCP socket. maxy-edge.service owns the public port and
2887
+ // the VNC stack; maxy-ui sits behind it on 127.0.0.1:MAXY_UI_INTERNAL_PORT.
2888
+ // PORT + 1 (derived) avoids a fixed-port collision if the operator chose a
2889
+ // non-default --port.
2890
+ //
2891
+ // PORT in maxy.service's Environment block is the PUBLIC port,
2892
+ // not the internal one. Previously we wrote `Environment=PORT=<internal>`,
2893
+ // which collided with the install-time reader further down, which
2894
+ // correctly treats Environment=PORT= as public. The overload caused +1
2895
+ // drift per upgrade: each run read the internal value, treated it as
2896
+ // public, wrote internal = old_internal + 1. maxy-ui now binds
2897
+ // MAXY_UI_INTERNAL_PORT (with a fallback to PORT for mixed-state installs).
2898
+ const MAXY_UI_INTERNAL_PORT = PORT + 1;
2899
+ const edgeUnitShort = `${BRAND.hostname}-edge`;
2900
+ const edgeUnitName = `${edgeUnitShort}.service`;
2901
+ // Per-brand X display. Same value used for the edge unit's
2902
+ // DISPLAY env (stamped via __VNC_DISPLAY__ a few lines down) so the main
2903
+ // brand service and the edge service agree on which display Chromium runs.
2904
+ // brand.json (BRAND) is the single source of truth for
2905
+ // these fields at install time. The vncDisplay-derived offset rule lives
2906
+ // in the brand-creation tooling; at this point in the installer BRAND
2907
+ // already represents a parsed, validated brand manifest, and any missing
2908
+ // field is a brand-publish defect. Loud-fail rather than silently
2909
+ // substituting an offset (silent-fallback-masks-root-cause recurrence).
2910
+ if (typeof BRAND.vncDisplay !== "number") {
2911
+ console.error(`[create-maxy] error reason=cdp-port-unresolved brand=${BRAND.configDir} field=vncDisplay`);
2912
+ throw new Error(`brand.json missing required field: vncDisplay`);
2913
+ }
2914
+ const VNC_DISPLAY = BRAND.vncDisplay;
2915
+ for (const field of ["rfbPort", "websockifyPort", "cdpPort"]) {
2916
+ if (typeof BRAND[field] !== "number") {
2917
+ console.error(`[create-maxy] error reason=cdp-port-unresolved brand=${BRAND.configDir} field=${field}`);
2918
+ throw new Error(`brand.json missing required field: ${field}`);
2919
+ }
2920
+ }
2921
+ const RFB_PORT = BRAND.rfbPort;
2922
+ const WEBSOCKIFY_PORT_BRAND = BRAND.websockifyPort;
2923
+ const CDP_PORT_BRAND = BRAND.cdpPort;
2924
+ const CLAUDE_SESSION_MANAGER_PORT_BRAND = BRAND.claudeSessionManagerPort;
2925
+ // pre-flight — refuse to write service files if any of the
2926
+ // three brand-scoped ports is already held by a process that is NOT this
2927
+ // brand's own on-demand browser nor a peer brand's edge stack.
2928
+ //
2929
+ // Classification (chromium Xtigervnc + websockify) reads
2930
+ // `/proc/<pid>/cmdline` and applies a holder-specific argv anchor.
2931
+ // covered chromium-only via `--user-data-dir=` closed the gap on
2932
+ // Xtigervnc (no such flag — anchor on the `:N` display literal) and
2933
+ // websockify (anchor on bind port). Brand identities (configDir,
2934
+ // vncDisplay, websockifyPort) come from brand-registry.json which the
2935
+ // bundler stamps at build time from every brands/<brand>/brand.json.
2936
+ //
2937
+ // Decisions per holder:
2938
+ // OWN_BRAND — SIGTERM, recheck, SIGKILL on stragglers, exit-1 only if
2939
+ // the port is still held after both signals.
2940
+ // PEER_BRAND — log OK and return (per-brand port sets are disjoint).
2941
+ // UNRELATED — refuse to write service files; emit operator override.
2942
+ // macOS dev hosts (no ss) fall through the catch and skip pre-flight
2943
+ // entirely — the runtime check in vnc.sh covers Linux production.
2944
+ const ownBrand = {
2945
+ configDir: BRAND.configDir,
2946
+ vncDisplay: VNC_DISPLAY,
2947
+ websockifyPort: WEBSOCKIFY_PORT_BRAND,
2948
+ };
2949
+ // Peer registry — load from payload/platform/config/brand-registry.json
2950
+ // when present. Older bundles ship without the
2951
+ // registry; in that case peerBrands stays empty. PEER_BRAND classification
2952
+ // for Xtigervnc/websockify is a defence-in-depth case anyway (port sets
2953
+ // are disjoint), so the empty-list fallback is safe — peer
2954
+ // chromium will fall through to UNRELATED, matching earlier behaviour
2955
+ // for the only realistic scenario (a stale peer browser on the wrong CDP
2956
+ // port).
2957
+ const peerBrands = (() => {
2958
+ const registryPath = join(PAYLOAD_DIR, "platform", "config", "brand-registry.json");
2959
+ if (!existsSync(registryPath)) {
2960
+ logFile(` [preflight] brand-registry.json not in payload — peer matching disabled`);
2961
+ return [];
2962
+ }
2963
+ try {
2964
+ const raw = JSON.parse(readFileSync(registryPath, "utf-8"));
2965
+ const entries = [];
2966
+ for (const b of raw.brands ?? []) {
2967
+ if (b.hostname === BRAND.hostname)
2968
+ continue;
2969
+ if (typeof b.configDir !== "string" || typeof b.vncDisplay !== "number" || typeof b.websockifyPort !== "number")
2970
+ continue;
2971
+ entries.push({ configDir: b.configDir, vncDisplay: b.vncDisplay, websockifyPort: b.websockifyPort });
2972
+ }
2973
+ return entries;
2974
+ }
2975
+ catch (err) {
2976
+ logFile(` [preflight] brand-registry.json parse failed: ${err instanceof Error ? err.message : String(err)} — peer matching disabled`);
2977
+ return [];
2978
+ }
2979
+ })();
2980
+ const ssReadHolder = (port) => {
2981
+ return execFileSync("ss", ["-tlnpH", `sport = :${port}`], {
2982
+ encoding: "utf-8", timeout: 3000, stdio: ["ignore", "pipe", "ignore"],
2983
+ });
2984
+ };
2985
+ // Pass raw NUL-separated cmdline to the classifier so it can argv-anchor
2986
+ // on `--user-data-dir=`. Replacing NUL with space here would defeat that.
2987
+ const readCmdline = (pid) => readFileSync(`/proc/${pid}/cmdline`, "utf-8");
2988
+ const sleepMs = (ms) => { spawnSync("sleep", [(ms / 1000).toString()]); };
2989
+ // Tightly scoped variant for retry-path ss reads. Failures here (timeout,
2990
+ // ENOMEM, signal) are structural — never the macOS-no-ss case (we already
2991
+ // succeeded once) — so they get a structured exit, not a stack trace.
2992
+ const ssReadOrAbort = (label, port) => {
2993
+ try {
2994
+ return ssReadHolder(port);
2995
+ }
2996
+ catch (err) {
2997
+ console.error(` ERROR: [preflight] ${label}=${port} ss recheck failed: ${err instanceof Error ? err.message : String(err)}`);
2998
+ console.error(` Resolve manually before retrying.`);
2999
+ process.exit(1);
3000
+ }
3001
+ };
3002
+ // Distinguish ESRCH (process already gone — expected) from EPERM/EINVAL
3003
+ // (alarming — signals we can't deliver, possibly a recycled pid). Returns
3004
+ // true for clean kill or ESRCH, false otherwise (caller logs a warning).
3005
+ const killNoThrow = (pid, signal) => {
3006
+ try {
3007
+ process.kill(pid, signal);
3008
+ return true;
3009
+ }
3010
+ catch (err) {
3011
+ const code = err.code;
3012
+ if (code === "ESRCH")
3013
+ return true;
3014
+ logFile(` [preflight] kill(${pid}, ${signal}) failed code=${code ?? "unknown"}`);
3015
+ return false;
3016
+ }
3017
+ };
3018
+ const classify = (ssOutput) => classifyPortHolder({
3019
+ ssOutput, ownBrand, peerBrands, getCmdline: readCmdline,
3020
+ });
3021
+ // log line varies by detected holder so the operator can see
3022
+ // which OWN_BRAND stack is being killed. The kill loop is identical for
3023
+ // all three holders (SIGTERM → 300ms → recheck → SIGKILL → recheck), so
3024
+ // only the announce line differs.
3025
+ const ownBrandAnnounceLine = (label, port, c) => {
3026
+ if (c.holderType === "xtigervnc") {
3027
+ return ` [preflight] ${label}=${port} held by OWN brand Xtigervnc display=:${c.vncDisplay} pid=${c.pid} — sending SIGTERM`;
3028
+ }
3029
+ if (c.holderType === "websockify") {
3030
+ return ` [preflight] ${label}=${port} held by OWN brand websockify pid=${c.pid} — sending SIGTERM`;
3031
+ }
3032
+ // Default — chromium / unknown OWN_BRAND
3033
+ return ` [preflight] ${label}=${port} held by OWN brand process pid=${c.pid} profile=${c.profilePath} — sending SIGTERM`;
3034
+ };
3035
+ const checkInstallPortFree = (label, port) => {
3036
+ let firstSsOutput;
3037
+ try {
3038
+ firstSsOutput = ssReadHolder(port);
3039
+ }
3040
+ catch (err) {
3041
+ // ss may not be present on macOS dev hosts — skip the pre-flight there
3042
+ // rather than abort the install. The runtime check in vnc.sh covers
3043
+ // production-like Linux installs where this matters. This catch is
3044
+ // narrow on purpose: only the first ss invocation may legitimately
3045
+ // fail (binary missing); retry-path failures use ssReadOrAbort.
3046
+ logFile(` [preflight] ${label}=${port} check skipped: ${err instanceof Error ? err.message : String(err)}`);
3047
+ return;
3048
+ }
3049
+ let r = classify(firstSsOutput);
3050
+ // ENOENT race — process exited between ss and cmdline read. Port is
3051
+ // probably free now; one re-check resolves it deterministically.
3052
+ if (r.cmdlineReadFailed)
3053
+ r = classify(ssReadOrAbort(label, port));
3054
+ if (r.kind === "EMPTY")
3055
+ return;
3056
+ if (r.kind === "PEER_BRAND") {
3057
+ logFile(` [preflight] ${label}=${port} held by a peer brand's stack — OK (per-brand ports are disjoint by construction)`);
3058
+ return;
3059
+ }
3060
+ if (r.kind === "OWN_BRAND" && r.pid !== undefined) {
3061
+ logFile(ownBrandAnnounceLine(label, port, r));
3062
+ killNoThrow(r.pid, "SIGTERM");
3063
+ sleepMs(300);
3064
+ const after = classify(ssReadOrAbort(label, port));
3065
+ if (after.kind === "EMPTY") {
3066
+ logFile(` [preflight] ${label}=${port} freed`);
3067
+ return;
3068
+ }
3069
+ if (after.kind === "OWN_BRAND" && after.pid === r.pid) {
3070
+ logFile(` [preflight] ${label}=${port} survived SIGTERM — sending SIGKILL`);
3071
+ killNoThrow(r.pid, "SIGKILL");
3072
+ sleepMs(300);
3073
+ const final = classify(ssReadOrAbort(label, port));
3074
+ if (final.kind === "EMPTY") {
3075
+ logFile(` [preflight] ${label}=${port} freed`);
3076
+ return;
3077
+ }
3078
+ console.error(` ERROR: [preflight] ${label}=${port} OWN_BRAND auto-kill failed pid=${r.pid} — resolve manually before retrying.`);
3079
+ process.exit(1);
3080
+ }
3081
+ // A different OWN_BRAND pid took the port. The brand's user services
3082
+ // are respawning Chromium — installer cannot win this race. Stop the
3083
+ // services, then retry.
3084
+ if (after.kind === "OWN_BRAND") {
3085
+ console.error(` ERROR: [preflight] ${label}=${port} brand respawned a new OWN_BRAND pid (was ${r.pid}, now ${after.pid}).`);
3086
+ console.error(` Stop the brand's user services first: \`systemctl --user stop ${BRAND.hostname}-edge ${BRAND.hostname}\`, then re-run the installer.`);
3087
+ process.exit(1);
3088
+ }
3089
+ // PEER_BRAND or UNRELATED took the port post-kill — fall through to
3090
+ // those branches by re-classifying the surviving holder.
3091
+ r = after;
3092
+ if (r.kind === "EMPTY")
3093
+ return;
3094
+ if (r.kind === "PEER_BRAND") {
3095
+ logFile(` [preflight] ${label}=${port} now held by a peer brand's stack — OK`);
3096
+ return;
3097
+ }
3098
+ // r.kind === "UNRELATED" — fall through to the operator-override block.
3099
+ }
3100
+ // UNRELATED — preserve the operator-override path verbatim.
3101
+ console.error(` ERROR: [preflight:collision] brand=${BRAND.hostname} ${label}=${port} held by an unrelated process:`);
3102
+ console.error(` ${firstSsOutput.trim()}`);
3103
+ if (r.cmdline)
3104
+ console.error(` cmdline: ${r.cmdline}`);
3105
+ console.error(` Refusing to write service files; resolve the collision before retrying.`);
3106
+ console.error(` Operator override: edit brands/${BRAND.hostname}/brand.json, set/add \`${label}\` to a free port, re-bundle, re-install.`);
3107
+ process.exit(1);
3108
+ };
3109
+ checkInstallPortFree("rfbPort", RFB_PORT);
3110
+ checkInstallPortFree("websockifyPort", WEBSOCKIFY_PORT_BRAND);
3111
+ checkInstallPortFree("cdpPort", CDP_PORT_BRAND);
3112
+ // ACCOUNT_ID stamped into the brand unit so the writeNodeWithEdges
3113
+ // gate at platform/lib/graph-write/src/index.ts:170 has a real identity to
3114
+ // compare against (instead of process.env.ACCOUNT_ID === undefined). Resolved
3115
+ // here AFTER setupAccount() ran upstream — setup-account.sh wrote account.json,
3116
+ // so an empty resolution at this point is a corrupted install (e.g. the seed
3117
+ // failed silently, or accounts/ was wiped between setup and unit-write).
3118
+ const installAccountId = resolveInstallAccountId();
3119
+ if (!installAccountId) {
3120
+ throw new Error(`installService: no account discovered at ${INSTALL_DIR}/data/accounts/<uuid>/account.json — ` +
3121
+ `setupAccount() (setup-account.sh) should have created one. Refusing to write a systemd unit ` +
3122
+ `without ACCOUNT_ID; the boot validator would FATAL on every restart.`);
3123
+ }
3124
+ const serviceFile = buildMaxyUnitFile({
3125
+ productName: BRAND.productName,
3126
+ brandHostname: BRAND.hostname,
3127
+ neo4jDedicated: NEO4J_DEDICATED,
3128
+ installDir: INSTALL_DIR,
3129
+ persistDir,
3130
+ port: PORT,
3131
+ maxyUiInternalPort: MAXY_UI_INTERNAL_PORT,
3132
+ vncDisplay: VNC_DISPLAY,
3133
+ rfbPort: RFB_PORT,
3134
+ websockifyPort: WEBSOCKIFY_PORT_BRAND,
3135
+ cdpPort: CDP_PORT_BRAND,
3136
+ claudeSessionManagerPort: CLAUDE_SESSION_MANAGER_PORT_BRAND,
3137
+ chromiumBin: RESOLVED_CHROMIUM_BIN,
3138
+ accountId: installAccountId,
3139
+ });
3140
+ writeFileSync(join(serviceDir, BRAND.serviceName), serviceFile);
3141
+ // (maxy-code) — write the claude-session-manager unit. The main
3142
+ // brand unit Requires= + After= this one, so systemd starts it first.
3143
+ const claudeSessionManagerUnitName = `${BRAND.hostname}-claude-session-manager.service`;
3144
+ const claudeSessionManagerUnit = buildClaudeSessionManagerUnitFile({
3145
+ productName: BRAND.productName,
3146
+ brandHostname: BRAND.hostname,
3147
+ installDir: INSTALL_DIR,
3148
+ persistDir,
3149
+ claudeSessionManagerPort: CLAUDE_SESSION_MANAGER_PORT_BRAND,
3150
+ brandPort: PORT,
3151
+ maxyUiInternalPort: MAXY_UI_INTERNAL_PORT,
3152
+ accountId: installAccountId,
3153
+ cdpPort: CDP_PORT_BRAND,
3154
+ });
3155
+ writeFileSync(join(serviceDir, claudeSessionManagerUnitName), claudeSessionManagerUnit);
3156
+ logFile(` ${claudeSessionManagerUnitName}: CLAUDE_SESSION_MANAGER_PORT=${CLAUDE_SESSION_MANAGER_PORT_BRAND} MAXY_UI_INTERNAL_PORT=${MAXY_UI_INTERNAL_PORT}`);
3157
+ // Task 250 — write the brand-agnostic `claude-ptys.slice` unit. Every
3158
+ // brand's session manager drops its per-spawn scope units under this
3159
+ // slice. Writing it once per install is idempotent (the content is
3160
+ // identical across brands and across runs); subsequent brand installs
3161
+ // re-stamp the same content. No service restart is needed — `daemon-reload`
3162
+ // below picks it up.
3163
+ const claudePtysSliceName = "claude-ptys.slice";
3164
+ writeFileSync(join(serviceDir, claudePtysSliceName), buildClaudePtysSliceUnitFile());
3165
+ logFile(` ${claudePtysSliceName}: Task 250 slice for claude-session-*.scope cohort`);
3166
+ // Task 602 — write the brand-agnostic `cloudflared.slice` unit. Every
3167
+ // cloudflared-<brand>.scope spawned by resume-tunnel.sh drops under this
3168
+ // slice. Writing once per install is idempotent; daemon-reload below picks it up.
3169
+ const cloudflaredSliceName = "cloudflared.slice";
3170
+ writeFileSync(join(serviceDir, cloudflaredSliceName), buildCloudflaredSliceUnitFile());
3171
+ logFile(` ${cloudflaredSliceName}: Task 602 slice for cloudflared-*.scope cohort`);
3172
+ // Task 600 — per-brand RSS sampler: a long-running user service that
3173
+ // periodically writes per-claude.exe RSS + aggregate RSS to disk.
3174
+ // Named per-brand (BRAND.hostname prefix) so two brands on the same
3175
+ // device each own their own sampler writing to their own log path.
3176
+ const rssSamplerUnitName = `${BRAND.hostname}-rss-sampler.service`;
3177
+ const rssSamplerScriptPath = resolve(INSTALL_DIR, "platform/scripts/rss-sampler.sh");
3178
+ const rssSamplerLogPath = join(persistDir, "rss-sampler.log");
3179
+ const rssSamplerUnit = `[Unit]
3180
+ Description=${BRAND.productName} RSS Sampler
3181
+
3182
+ [Service]
3183
+ Type=simple
3184
+ ExecStart=/bin/bash ${rssSamplerScriptPath}
3185
+ Environment=LOG_PATH=${rssSamplerLogPath}
3186
+ Restart=on-failure
3187
+ RestartSec=10
3188
+
3189
+ [Install]
3190
+ WantedBy=default.target
3191
+ `;
3192
+ writeFileSync(join(serviceDir, rssSamplerUnitName), rssSamplerUnit);
3193
+ logFile(` rss-sampler installed: ${rssSamplerUnitName} LOG_PATH=${rssSamplerLogPath}`);
3194
+ // the edge service: always-on front door that owns the public
3195
+ // port (PORT) and the VNC stack (Xtigervnc + websockify). Its lifecycle is
3196
+ // independent of the main brand service, so an in-place upgrade triggered
3197
+ // from the admin terminal can restart the main brand service without
3198
+ // disconnecting the browser's remote terminal WebSocket.
3199
+ //
3200
+ // the unit is per-brand so two brands on the same device each
3201
+ // own their own edge listener on their own EDGE_PORT — installing brand B
3202
+ // never rewrites brand A's unit or steals brand A's public port. Upgrades
3203
+ // from pre-662 installs require the manual recovery paragraph in
3204
+ // .docs/deployment.md before re-running this installer; auto-migration is
3205
+ // intentionally scoped out.
3206
+ // VNC_DISPLAY (defined above for the main brand unit) is also stamped into
3207
+ // the edge unit so both services agree on the X display. Per-brand display
3208
+ // closes the cross-brand cookie leak documented.
3209
+ const edgeTemplatePath = resolve(INSTALL_DIR, "platform/templates/systemd/edge.service.template");
3210
+ if (existsSync(edgeTemplatePath)) {
3211
+ const edgeServiceContent = readFileSync(edgeTemplatePath, "utf-8")
3212
+ .replace(/__INSTALL_DIR__/g, INSTALL_DIR)
3213
+ .replace(/__EDGE_PORT__/g, String(PORT))
3214
+ .replace(/__MAXY_UI_PORT__/g, String(MAXY_UI_INTERNAL_PORT))
3215
+ .replace(/__PERSIST_DIR__/g, persistDir)
3216
+ .replace(/__VNC_DISPLAY__/g, String(VNC_DISPLAY))
3217
+ .replace(/__WEBSOCKIFY_PORT__/g, String(WEBSOCKIFY_PORT_BRAND))
3218
+ .replace(/__CDP_PORT__/g, String(CDP_PORT_BRAND))
3219
+ .replace(/__RFB_PORT__/g, String(RFB_PORT));
3220
+ writeFileSync(join(serviceDir, edgeUnitName), edgeServiceContent);
3221
+ logFile(` ${edgeUnitName}: EDGE_PORT=${PORT} MAXY_UI_PORT=${MAXY_UI_INTERNAL_PORT} VNC_DISPLAY=:${VNC_DISPLAY} RFB_PORT=${RFB_PORT} WEBSOCKIFY_PORT=${WEBSOCKIFY_PORT_BRAND} CDP_PORT=${CDP_PORT_BRAND}`);
3222
+ }
3223
+ else {
3224
+ console.error(` WARNING: edge.service.template missing at ${edgeTemplatePath} — VNC transport unavailable`);
3225
+ }
3226
+ // the unit declares Environment=PATH=%h/.local/bin:... so the graph
3227
+ // MCP shim's spawn("uvx", ...) resolves against uv's install location. Without
3228
+ // this line, the service inherits the default systemd-user PATH — which
3229
+ // excludes ~/.local/bin — and the shim exits ENOENT before any query lands.
3230
+ logFile(` ${BRAND.serviceName}: PATH env includes %h/.local/bin for uvx resolution`);
3231
+ // WiFi AP provisioning service — system-level (requires root for hostapd/dnsmasq).
3232
+ // Runs at boot to check connectivity. If no saved WiFi and no ethernet, activates
3233
+ // a temporary AP with a captive portal for first-time WiFi configuration.
3234
+ const currentUser = execFileSync("whoami", [], { encoding: "utf-8" }).trim();
3235
+ const wifiProvisionService = `[Unit]
3236
+ Description=${BRAND.productName} WiFi Provisioning
3237
+ After=NetworkManager.service
3238
+ Before=${BRAND.serviceName}
3239
+
3240
+ [Service]
3241
+ Type=simple
3242
+ ExecStart=/bin/bash ${INSTALL_DIR}/platform/scripts/wifi-provision.sh
3243
+ ExecStopPost=/bin/bash ${INSTALL_DIR}/platform/scripts/wifi-provision.sh cleanup
3244
+ Environment=MAXY_PLATFORM_ROOT=${INSTALL_DIR}/platform
3245
+ Environment=INSTALL_USER=${currentUser}
3246
+ Environment=INSTALL_HOME=${process.env.HOME ?? "/home/" + currentUser}
3247
+ TimeoutStartSec=300
3248
+ TimeoutStopSec=30
3249
+
3250
+ [Install]
3251
+ WantedBy=multi-user.target
3252
+ `;
3253
+ const systemServiceDir = "/etc/systemd/system";
3254
+ const wifiProvisionPath = join(systemServiceDir, "wifi-provision.service");
3255
+ try {
3256
+ const tmpPath = "/tmp/wifi-provision.service";
3257
+ writeFileSync(tmpPath, wifiProvisionService);
3258
+ console.log(" [privileged] cp");
3259
+ shell("cp", [tmpPath, wifiProvisionPath], { sudo: true });
3260
+ spawnSync("rm", ["-f", tmpPath]);
3261
+ spawnSync("sudo", ["systemctl", "daemon-reload"], { stdio: "inherit" });
3262
+ spawnSync("sudo", ["systemctl", "enable", "wifi-provision"], { stdio: "inherit" });
3263
+ logFile(" WiFi provisioning service installed and enabled");
3264
+ }
3265
+ catch (err) {
3266
+ console.error(` WARNING: Failed to install wifi-provision service: ${err instanceof Error ? err.message : String(err)}`);
3267
+ }
3268
+ // Disable hostapd and dnsmasq system services (we manage them manually
3269
+ // from wifi-provision.sh — the system services would conflict).
3270
+ spawnSync("sudo", ["systemctl", "stop", "hostapd"], { stdio: "ignore" });
3271
+ spawnSync("sudo", ["systemctl", "disable", "hostapd"], { stdio: "ignore" });
3272
+ spawnSync("sudo", ["systemctl", "stop", "dnsmasq"], { stdio: "ignore" });
3273
+ spawnSync("sudo", ["systemctl", "disable", "dnsmasq"], { stdio: "ignore" });
3274
+ // Enable lingering so user services run without login
3275
+ try {
3276
+ spawnSync("sudo", ["loginctl", "enable-linger", currentUser], { stdio: "inherit" });
3277
+ }
3278
+ catch { /* not critical */ }
3279
+ // Task 504: persist the systemd journal so per-unit lifecycle events
3280
+ // (SIGTERM/SIGKILL transitions, dependency-propagated stops, restart job
3281
+ // records) survive reboots and remain greppable via `journalctl --user -u
3282
+ // <brand>.service` after a restart loop quiets.
3283
+ //
3284
+ // Why a drop-in and not the Task-249 `mkdir /var/log/journal`: the directory
3285
+ // heuristic only takes effect under journald's default `Storage=auto`. A
3286
+ // base image (common on RPi to spare the SD card) that ships an explicit
3287
+ // `Storage=volatile` overrides directory existence, so the bare mkdir is a
3288
+ // no-op there — exactly the state observed on the realagent-code device. An
3289
+ // explicit `Storage=persistent` drop-in wins regardless of the base default,
3290
+ // and journald itself creates `/var/log/journal/<machine-id>` on restart, so
3291
+ // the mkdir is no longer needed.
3292
+ //
3293
+ // journald is one system instance, so the drop-in is host-wide with a neutral
3294
+ // filename — idempotent across brands and reinstalls. Restart journald only
3295
+ // when the drop-in content actually changes, to avoid churning the system
3296
+ // journal on every reinstall. Best-effort: a failure here warns, never aborts
3297
+ // the install.
3298
+ try {
3299
+ const journaldDropinDir = "/etc/systemd/journald.conf.d";
3300
+ const journaldDropinPath = `${journaldDropinDir}/10-maxy-persistent.conf`;
3301
+ const desiredJournaldConf = "[Journal]\nStorage=persistent\n";
3302
+ let journaldCurrent = "";
3303
+ if (existsSync(journaldDropinPath)) {
3304
+ try {
3305
+ journaldCurrent = readFileSync(journaldDropinPath, "utf-8");
3306
+ }
3307
+ catch {
3308
+ // Unreadable existing drop-in — treat as changed so we rewrite + restart.
3309
+ journaldCurrent = "";
3310
+ }
3311
+ }
3312
+ if (journaldCurrent === desiredJournaldConf) {
3313
+ logFile(` journald persistence: already active (${journaldDropinPath} matches Storage=persistent)`);
3314
+ }
3315
+ else {
3316
+ const journaldTmpPath = "/tmp/10-maxy-persistent.conf";
3317
+ writeFileSync(journaldTmpPath, desiredJournaldConf);
3318
+ console.log(" [privileged] install journald Storage=persistent drop-in");
3319
+ shell("mkdir", ["-p", journaldDropinDir], { sudo: true });
3320
+ shell("cp", [journaldTmpPath, journaldDropinPath], { sudo: true });
3321
+ spawnSync("rm", ["-f", journaldTmpPath]);
3322
+ console.log(" [privileged] systemctl restart systemd-journald");
3323
+ spawnSync("sudo", ["systemctl", "restart", "systemd-journald"], { stdio: "inherit", timeout: 15_000 });
3324
+ logFile(` journald persistence: enabled (wrote ${journaldDropinPath} Storage=persistent + restarted journald)`);
3325
+ }
3326
+ }
3327
+ catch (err) {
3328
+ console.error(` WARNING: failed to enable journald persistence: ${err instanceof Error ? err.message : String(err)}`);
3329
+ }
3330
+ // Task 504: capture the initiator of a brand-service restart so the next
3331
+ // recurrence of the restart loop is attributable to its source from
3332
+ // device-retained evidence. The brand admin process logs only that it
3333
+ // *received* SIGTERM (not the sender), and a JS signal handler cannot read
3334
+ // si_pid. auditd is the device-side primitive that names the initiator:
3335
+ //
3336
+ // - `kill` syscall with sig=15 (SIGTERM): names a process that sends
3337
+ // SIGTERM directly to the brand pid. For a systemd-managed stop the
3338
+ // sender is the user systemd manager itself, so this rule alone does NOT
3339
+ // name the upstream actor of a managed restart — but it does catch a
3340
+ // direct, non-systemd kill.
3341
+ // - `execve` of systemctl: names the pid/cgroup that drives a CLI restart
3342
+ // (`systemctl --user restart <unit>`), which is the upstream actor the
3343
+ // kill rule misses for the systemd-mediated path.
3344
+ // - Once auditd runs, systemd emits native SERVICE_START/SERVICE_STOP audit
3345
+ // records with no rule needed, covering a restart issued over raw D-Bus
3346
+ // (no systemctl binary, so the execve rule would miss it).
3347
+ //
3348
+ // Rules are deliberately narrow (SIGTERM + systemctl execve only) so audit
3349
+ // write volume stays bounded on a low-power device; auditd's default log
3350
+ // rotation bounds disk further. Everything here is best-effort: a box with no
3351
+ // apt mirror, or a kernel without audit support, warns and the install still
3352
+ // completes. Load via `augenrules --load` (merges rules.d into the running
3353
+ // daemon without a disruptive auditd restart).
3354
+ try {
3355
+ console.log(" [privileged] apt-get install auditd");
3356
+ shell("apt-get", ["install", "-y", "auditd"], { sudo: true, bestEffort: true });
3357
+ const auditRulesPath = "/etc/audit/rules.d/90-maxy-restart-forensics.rules";
3358
+ // Rule ordering matters: auditctl loads rules in file order, and a rule a
3359
+ // kernel rejects (the arch=b32 kill rule on an arm64 kernel without 32-bit
3360
+ // compat) must not sit ahead of rules that should load. So the b64 kill
3361
+ // rule and the systemctl watch come first; the b32 kill rule (the one that
3362
+ // may be rejected) comes last. The systemctl capture uses a file watch
3363
+ // (`-w … -p x`), the idiomatic form for "audit execution of this binary" —
3364
+ // it records the caller pid/cgroup and is arch-agnostic, avoiding the
3365
+ // invalid `arch`+`path`+`perm` field mix.
3366
+ const auditRules = [
3367
+ "# Maxy restart-loop forensics (Task 504) — name the initiator of a",
3368
+ "# brand-service restart on the next recurrence.",
3369
+ "# SIGTERM sender (a0=target pid, a1=signal).",
3370
+ "-a always,exit -F arch=b64 -S kill -F a1=15 -k maxy_sigterm",
3371
+ "# systemctl execution — names the caller pid/cgroup of a CLI restart.",
3372
+ "-w /usr/bin/systemctl -p x -k maxy_systemctl",
3373
+ "# b32 kill sibling last: a 32-bit-compat caller is still captured, and a",
3374
+ "# rejection on an arm64 kernel without compat cannot block the rules above.",
3375
+ "-a always,exit -F arch=b32 -S kill -F a1=15 -k maxy_sigterm",
3376
+ "",
3377
+ ].join("\n");
3378
+ const auditTmpPath = "/tmp/90-maxy-restart-forensics.rules";
3379
+ writeFileSync(auditTmpPath, auditRules);
3380
+ console.log(" [privileged] install auditd restart-forensics rules");
3381
+ shell("mkdir", ["-p", "/etc/audit/rules.d"], { sudo: true, bestEffort: true });
3382
+ shell("cp", [auditTmpPath, auditRulesPath], { sudo: true, bestEffort: true });
3383
+ spawnSync("rm", ["-f", auditTmpPath]);
3384
+ console.log(" [privileged] augenrules --load");
3385
+ shell("augenrules", ["--load"], { sudo: true, bestEffort: true });
3386
+ logFile(` auditd restart forensics: rules at ${auditRulesPath} (keys maxy_sigterm, maxy_systemctl) — verify on device with \`ausearch -k maxy_sigterm\``);
3387
+ }
3388
+ catch (err) {
3389
+ console.error(` WARNING: failed to install auditd restart forensics: ${err instanceof Error ? err.message : String(err)}`);
3390
+ }
3391
+ // Reload and (re)start.
3392
+ //
3393
+ // ordering: on upgrades, the old main brand service still holds
3394
+ // the public port (PORT). Stop it FIRST so the edge can bind that socket;
3395
+ // starting the edge first would race against the old main brand service
3396
+ // and fail with EADDRINUSE. Fresh installs: the stop is a no-op.
3397
+ const unitName = BRAND.serviceName.replace(".service", "");
3398
+ const claudeSessionManagerUnitShort = claudeSessionManagerUnitName.replace(".service", "");
3399
+ spawnSync("systemctl", ["--user", "stop", unitName], { stdio: "inherit" });
3400
+ spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "inherit" });
3401
+ spawnSync("systemctl", ["--user", "enable", edgeUnitShort], { stdio: "inherit" });
3402
+ spawnSync("systemctl", ["--user", "enable", claudeSessionManagerUnitShort], { stdio: "inherit" });
3403
+ spawnSync("systemctl", ["--user", "enable", unitName], { stdio: "inherit" });
3404
+ spawnSync("systemctl", ["--user", "enable", `${BRAND.hostname}-rss-sampler`], { stdio: "inherit" });
3405
+ // edge first: binds public port + starts VNC stack. Then claude-session-manager
3406
+ // (so the main brand unit's Requires= is satisfied). Then main brand service.
3407
+ // rss-sampler is independent — start last, failure is non-blocking.
3408
+ spawnSync("systemctl", ["--user", "restart", edgeUnitShort], { stdio: "inherit" });
3409
+ spawnSync("systemctl", ["--user", "restart", claudeSessionManagerUnitShort], { stdio: "inherit" });
3410
+ spawnSync("systemctl", ["--user", "restart", unitName], { stdio: "inherit" });
3411
+ spawnSync("systemctl", ["--user", "restart", `${BRAND.hostname}-rss-sampler`], { stdio: "inherit" });
3412
+ // Session manager runs in its own systemd user unit and can boot-fail silently
3413
+ // (e.g. mcp-block-missing). The web server below comes up regardless, so the
3414
+ // install terminal would otherwise report success while every API call 503s.
3415
+ // Surface the boot failure on the trusted surface and refuse to declare success.
3416
+ console.log(" Waiting for session manager...");
3417
+ let sessionManagerActive = false;
3418
+ for (let i = 0; i < 5; i++) {
3419
+ const probe = spawnSync("systemctl", ["--user", "is-active", claudeSessionManagerUnitShort], { stdio: "pipe", encoding: "utf-8" });
3420
+ if ((probe.stdout ?? "").trim() === "active") {
3421
+ sessionManagerActive = true;
3422
+ break;
3423
+ }
3424
+ spawnSync("sleep", ["2"]);
3425
+ }
3426
+ if (!sessionManagerActive) {
3427
+ const status = spawnSync("systemctl", ["--user", "status", claudeSessionManagerUnitShort, "--no-pager", "-n", "20"], { stdio: "pipe", encoding: "utf-8" });
3428
+ const statusOutput = `${status.stdout ?? ""}${status.stderr ?? ""}`.trimEnd();
3429
+ console.error(statusOutput);
3430
+ logFile(statusOutput);
3431
+ const failureLine = `Session manager (${claudeSessionManagerUnitShort}) failed to start. See above for boot-failed reason.`;
3432
+ console.error(failureLine);
3433
+ logFile(failureLine);
3434
+ process.exit(1);
3435
+ }
3436
+ // Wait for the server to come up
3437
+ console.log(" Waiting for web server...");
3438
+ let webServerUp = false;
3439
+ for (let i = 0; i < 20; i++) {
3440
+ try {
3441
+ execFileSync("curl", ["-sf", `http://localhost:${PORT}`, "-o", "/dev/null"], { timeout: 3000 });
3442
+ webServerUp = true;
3443
+ break;
3444
+ }
3445
+ catch {
3446
+ spawnSync("sleep", ["2"]);
3447
+ }
3448
+ }
3449
+ if (!webServerUp) {
3450
+ console.log(` Server may still be starting. Check http://${DEVICE_HOSTNAME}.local:${PORT} in a moment.`);
3451
+ }
3452
+ // Validate CDP: the programmatic Playwright MCP server connects to Chromium
3453
+ // via --cdp-endpoint http://127.0.0.1:9222. In virtual (VNC) mode, Chromium is
3454
+ // started by vnc.sh (ExecStartPre) before the web server — a failed probe here
3455
+ // indicates a genuine VNC boot failure and must fail the install loudly.
3456
+ // In native mode, Chromium is launched on-demand by the server and is not
3457
+ // expected to be bound at install time — the probe is skipped.
3458
+ if (DISPLAY_MODE === "native") {
3459
+ console.log(" [cdp-check] skipped reason=native-display (on-demand Chromium)");
3460
+ }
3461
+ else {
3462
+ console.log(` Verifying browser automation (CDP on port ${CDP_PORT_BRAND})...`);
3463
+ const cdpCheck = spawnSync("curl", ["-sf", `http://127.0.0.1:${CDP_PORT_BRAND}/json/version`, "-o", "/dev/null"], {
3464
+ timeout: 5000,
3465
+ stdio: "pipe",
3466
+ });
3467
+ if (cdpCheck.status === 0) {
3468
+ console.log(" Browser automation ready (CDP connected).");
3469
+ }
3470
+ else {
3471
+ const vncLogPath = resolve(process.env.HOME ?? "/root", BRAND.configDir, "logs/vnc-boot.log");
3472
+ let vncLog = "";
3473
+ try {
3474
+ vncLog = readFileSync(vncLogPath, "utf-8").slice(-2000);
3475
+ }
3476
+ catch {
3477
+ vncLog = `(no boot log found at ${vncLogPath})`;
3478
+ }
3479
+ console.error("");
3480
+ console.error(`Setup failed: Browser automation unavailable — CDP port ${CDP_PORT_BRAND} not responding`);
3481
+ console.error(` ERROR: Browser automation unavailable — CDP port ${CDP_PORT_BRAND} not responding.`);
3482
+ console.error(" Chromium should be started by vnc.sh (ExecStartPre). Check the boot log:");
3483
+ console.error("");
3484
+ console.error(vncLog);
3485
+ process.exit(1);
3486
+ }
3487
+ }
3488
+ }
3489
+ // ---------------------------------------------------------------------------
3490
+ // Samba provisioning. Runs after installService() so SMB never
3491
+ // blocks the admin server starting; pure decisions live in samba-provision.ts.
3492
+ //
3493
+ // Four steps, each emitting one [install-invariant] samba-provision-<step>
3494
+ // marker:
3495
+ // apt — install the `samba` package
3496
+ // conf — write the brand stanza + LAN-only globals to /etc/samba/smb.conf
3497
+ // user — smbpasswd the install-owner Linux user; deferred at install time
3498
+ // on fresh Pi installs (no plaintext PIN until the operator runs set-pin)
3499
+ // units — systemctl enable --now smbd nmbd
3500
+ //
3501
+ // The platform's set-pin route handler closes the deferral loop by running
3502
+ // `smbpasswd -a -s <install-owner>` inline whenever the PIN is set or
3503
+ // rotated. Install owner is the Unix user the installer is running as —
3504
+ // `admin` on a Pi/Hetzner box, `neo` (etc.) on a self-hosted laptop. It is
3505
+ // persisted to `~/.<brand>/.install-owner` so every later read uses the same
3506
+ // value the installer wrote.
3507
+ // ---------------------------------------------------------------------------
3508
+ function emitSambaMarker(step, state) {
3509
+ const line = formatSambaMarker(step, state);
3510
+ console.log(` ${line}`);
3511
+ logFile(` ${line}`);
3512
+ }
3513
+ function provisionSamba() {
3514
+ if (!isLinux()) {
3515
+ logFile(` samba-provision skipped: platform=${process.platform}`);
3516
+ return;
3517
+ }
3518
+ const brand = BRAND.hostname;
3519
+ const sharePath = INSTALL_DIR;
3520
+ // Install owner — the Unix user that owns this brand's install on the
3521
+ // device. On a Pi/Hetzner box this is `admin`; on a self-hosted laptop it
3522
+ // is the operator's Unix user (`neo` etc.). Persisted to a file next to
3523
+ // the other install identity (`.neo4j-password`, `.admin-pin`) so the
3524
+ // platform's set-pin route and the uninstall path read the same value the
3525
+ // installer wrote, rather than re-detecting at request time. Task 534.
3526
+ const installOwner = userInfo().username;
3527
+ const installOwnerPersistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
3528
+ mkdirSync(installOwnerPersistDir, { recursive: true });
3529
+ writeFileSync(join(installOwnerPersistDir, ".install-owner"), `${installOwner}\n`, { mode: 0o644 });
3530
+ // Step 1 — apt install samba. Precheck `dpkg -s samba` first; if the
3531
+ // package is already installed, skip apt entirely so the install does not
3532
+ // contend with `unattended-upgrades` for `/var/lib/dpkg/lock-frontend`
3533
+ // every time. Mirrors the [1/11] system-deps step.
3534
+ try {
3535
+ const dpkgCheck = spawnSync("dpkg", ["-s", "samba"], { stdio: "pipe", timeout: 5_000 });
3536
+ if (dpkgCheck.status === 0) {
3537
+ logFile(" samba already installed — skipping apt install.");
3538
+ emitSambaMarker("apt", "ok-already-installed");
3539
+ }
3540
+ else {
3541
+ installAptGroup("samba", ["samba"]);
3542
+ emitSambaMarker("apt", "ok");
3543
+ }
3544
+ }
3545
+ catch (err) {
3546
+ const stderr = err instanceof Error ? err.message : String(err);
3547
+ emitSambaMarker("apt", `fail: ${stderr}`);
3548
+ throw err;
3549
+ }
3550
+ // Step 2 — write the brand stanza into /etc/samba/smb.conf.
3551
+ const lanInterface = pickLanInterface(networkInterfaces());
3552
+ if (!lanInterface) {
3553
+ emitSambaMarker("conf", "fail: no non-loopback IPv4 interface");
3554
+ throw new Error("samba-provision: no LAN interface with IPv4 — cannot bind smbd safely");
3555
+ }
3556
+ const SMB_CONF = "/etc/samba/smb.conf";
3557
+ let existing = "";
3558
+ if (existsSync(SMB_CONF)) {
3559
+ try {
3560
+ const cat = spawnSync("sudo", ["cat", SMB_CONF], { encoding: "utf-8", stdio: "pipe", timeout: 5_000 });
3561
+ if (cat.status === 0)
3562
+ existing = cat.stdout ?? "";
3563
+ }
3564
+ catch { /* treat as empty */ }
3565
+ }
3566
+ const merged = mergeSmbConf({ existing, brand, sharePath, lanInterface, installOwner });
3567
+ try {
3568
+ const tee = spawnSync("sudo", ["tee", SMB_CONF], { input: merged, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 10_000 });
3569
+ if (tee.status !== 0) {
3570
+ throw new Error(`sudo tee ${SMB_CONF} exited ${tee.status}: ${(tee.stderr ?? "").trim()}`);
3571
+ }
3572
+ const testparm = spawnSync("sudo", ["testparm", "-s", "--suppress-prompt"], { stdio: "pipe", encoding: "utf-8", timeout: 10_000 });
3573
+ if (testparm.status !== 0) {
3574
+ throw new Error(`testparm rejected merged smb.conf: ${(testparm.stderr ?? "").trim()}`);
3575
+ }
3576
+ // Grant passwordless sudo to the install-owner Unix user for the two
3577
+ // smbpasswd invocations the platform's set-pin route makes (add-user-
3578
+ // with-stdin and remove-user). Without this, the user systemd-unit-
3579
+ // spawned admin server cannot sync the SMB password when the operator
3580
+ // sets/rotates the PIN. Scoped tight: only these two literal arg-vectors
3581
+ // are permitted; every other smbpasswd flavour still prompts. Principal
3582
+ // and `-a -s <user>` / `-x <user>` arguments are the install owner, not
3583
+ // a literal `admin`, so the grant works on a Pi (owner=admin) and on a
3584
+ // laptop (owner=neo) without divergence. Task 534.
3585
+ const SUDOERS = "/etc/sudoers.d/maxy-samba";
3586
+ const sudoersBody = "# maxy-code Samba provisioning (smbpasswd sync from platform set-pin route).\n" +
3587
+ `${installOwner} ALL=(root) NOPASSWD: /usr/bin/smbpasswd -a -s ${installOwner}, /usr/bin/smbpasswd -x ${installOwner}\n`;
3588
+ const sudoersTee = spawnSync("sudo", ["tee", SUDOERS], { input: sudoersBody, encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"], timeout: 5_000 });
3589
+ if (sudoersTee.status !== 0) {
3590
+ throw new Error(`sudo tee ${SUDOERS} exited ${sudoersTee.status}: ${(sudoersTee.stderr ?? "").trim()}`);
3591
+ }
3592
+ spawnSync("sudo", ["chmod", "0440", SUDOERS], { stdio: "pipe", timeout: 5_000 });
3593
+ const visudoCheck = spawnSync("sudo", ["visudo", "-c", "-f", SUDOERS], { stdio: "pipe", encoding: "utf-8", timeout: 5_000 });
3594
+ if (visudoCheck.status !== 0) {
3595
+ throw new Error(`visudo rejected ${SUDOERS}: ${(visudoCheck.stderr ?? "").trim()}`);
3596
+ }
3597
+ emitSambaMarker("conf", `ok lan=${lanInterface} owner=${installOwner}`);
3598
+ }
3599
+ catch (err) {
3600
+ const stderr = err instanceof Error ? err.message : String(err);
3601
+ emitSambaMarker("conf", `fail: ${stderr}`);
3602
+ throw err;
3603
+ }
3604
+ // Step 3 — smbpasswd for the install-owner Unix user. At install time the
3605
+ // plaintext PIN is not in any file on disk (users.json stores the SHA-256
3606
+ // hash only); the platform's set-pin route is responsible for syncing on
3607
+ // PIN set/rotate. Mark as deferred so the four-marker contract still fires
3608
+ // unbroken. Owner is recorded in the marker state so the install log shows
3609
+ // which Unix user the smbpasswd entry will target. Task 534.
3610
+ emitSambaMarker("user", `deferred reason=no-plaintext-pin-at-install owner=${installOwner} (set-pin route syncs)`);
3611
+ // Step 4 — enable + start smbd and nmbd.
3612
+ try {
3613
+ shell("systemctl", ["enable", "--now", "smbd", "nmbd"], { sudo: true, timeout: 30_000 });
3614
+ emitSambaMarker("units", "ok");
3615
+ }
3616
+ catch (err) {
3617
+ const stderr = err instanceof Error ? err.message : String(err);
3618
+ emitSambaMarker("units", `fail: ${stderr}`);
3619
+ throw err;
3620
+ }
3621
+ }
3622
+ // ---------------------------------------------------------------------------
3623
+ // Main
3624
+ // ---------------------------------------------------------------------------
3625
+ // Route to uninstall if --uninstall flag is present
3626
+ const _args = process.argv.slice(2);
3627
+ if (_args.includes("--uninstall")) {
3628
+ const { runUninstall } = await import("./uninstall.js");
3629
+ const exportIdx = _args.indexOf("--export-data");
3630
+ const exportPath = exportIdx !== -1 ? _args[exportIdx + 1] : undefined;
3631
+ const skipConfirm = _args.includes("--yes");
3632
+ if (exportIdx !== -1 && !exportPath) {
3633
+ console.error("Setup failed: --export-data requires a path argument");
3634
+ console.error("--export-data requires a path argument.");
3635
+ process.exit(1);
3636
+ }
3637
+ await runUninstall({ exportPath, skipConfirm });
3638
+ process.exit(0);
3639
+ }
3640
+ // ---------------------------------------------------------------------------
3641
+ // Port — install-time flag, not a brand attribute.
3642
+ //
3643
+ // Priority: --port flag > .env override > existing service file > default 19200.
3644
+ // systemd applies EnvironmentFile=-~/.{brand}/.env AFTER Environment=PORT,
3645
+ // so .env is the final runtime truth and must be checked first on upgrade.
3646
+ //
3647
+ // this block also performs one-shot port-drift recovery against
3648
+ // maxy-edge.service's Environment=EDGE_PORT=. See port-resolution.ts for the
3649
+ // pure logic; unit tests live at __tests__/port-canonicalisation.test.mjs.
3650
+ // ---------------------------------------------------------------------------
3651
+ let portFlag;
3652
+ const portIdx = _args.indexOf("--port");
3653
+ if (portIdx !== -1) {
3654
+ const raw = _args[portIdx + 1];
3655
+ const parsed = raw ? parseInt(raw, 10) : NaN;
3656
+ if (isNaN(parsed) || parsed < 1024 || parsed > 65535) {
3657
+ console.error(`Setup failed: --port requires a numeric value between 1024 and 65535 (got: ${raw ?? "nothing"})`);
3658
+ console.error(`Error: --port requires a numeric value between 1024 and 65535 (got: ${raw ?? "nothing"}).`);
3659
+ process.exit(1);
3660
+ }
3661
+ portFlag = parsed;
3662
+ }
3663
+ const _portResolution = resolveInstallPortFromFs({
3664
+ portFlag,
3665
+ persistDir: resolve(process.env.HOME ?? "/root", BRAND.configDir),
3666
+ serviceDir: resolve(process.env.HOME ?? "/root", ".config/systemd/user"),
3667
+ brandServiceFileName: BRAND.serviceName,
3668
+ brandEdgeServiceFileName: `${BRAND.hostname}-edge.service`,
3669
+ });
3670
+ let PORT = _portResolution.port;
3671
+ let PORT_SOURCE = _portResolution.source;
3672
+ for (const line of _portResolution.driftLogs)
3673
+ console.log(line);
3674
+ // ---------------------------------------------------------------------------
3675
+ // Hostname — install-time flag, not solely a brand attribute.
3676
+ //
3677
+ // Priority: --hostname flag > OS detection (same-brand upgrade) > OS preservation
3678
+ // (another brand's service detected) > BRAND.hostname (fresh install).
3679
+ // When --hostname is provided, it is set unconditionally — no detection, no preservation.
3680
+ // ---------------------------------------------------------------------------
3681
+ let HOSTNAME_FLAG;
3682
+ const hostnameIdx = _args.indexOf("--hostname");
3683
+ if (hostnameIdx !== -1) {
3684
+ const raw = _args[hostnameIdx + 1];
3685
+ if (!raw || raw.startsWith("--")) {
3686
+ console.error("Setup failed: --hostname requires a value");
3687
+ console.error("Error: --hostname requires a value (e.g. --hostname muvin).");
3688
+ process.exit(1);
3689
+ }
3690
+ // RFC 1123: lowercase alphanumeric + hyphens, max 63 chars, no leading/trailing hyphen
3691
+ if (!/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/.test(raw)) {
3692
+ console.error(`Setup failed: --hostname value '${raw}' is invalid`);
3693
+ console.error(`Error: --hostname value '${raw}' is invalid. Must be lowercase letters, digits, and hyphens only (max 63 chars, no leading/trailing hyphen).`);
3694
+ process.exit(1);
3695
+ }
3696
+ HOSTNAME_FLAG = raw;
3697
+ }
3698
+ // ---------------------------------------------------------------------------
3699
+ // Founder-side tier-set flags (Task 240).
3700
+ //
3701
+ // `--tier <solo|family|pro>` stamps account.json.tier directly when the brand
3702
+ // is personal-mode (today's default for both maxy-code and realagent-code).
3703
+ // `--entitlement-base64 <b64>` decodes a signed payload and writes it to
3704
+ // ~/<BRAND.configDir>/entitlement.json when the brand is commercial-mode.
3705
+ // The verifier at session start consumes whichever path the brand is on.
3706
+ //
3707
+ // Mode-mismatch combinations reject loudly at parse time — operator gets a
3708
+ // redirect message pointing at the correct flag. The installer is the sole
3709
+ // doctrine-sanctioned device-mutation channel; the admin agent has no tier-
3710
+ // upgrade surface by design.
3711
+ // ---------------------------------------------------------------------------
3712
+ let TIER_FLAG;
3713
+ let ENTITLEMENT_PAYLOAD;
3714
+ const tierIdx = _args.indexOf("--tier");
3715
+ if (tierIdx !== -1) {
3716
+ try {
3717
+ TIER_FLAG = validateTierFlag(_args[tierIdx + 1], BRAND.commercialMode === true);
3718
+ }
3719
+ catch (err) {
3720
+ const msg = err instanceof Error ? err.message : String(err);
3721
+ console.error(`Setup failed: ${msg}`);
3722
+ console.error(`Error: ${msg}`);
3723
+ process.exit(1);
3724
+ }
3725
+ }
3726
+ const entitlementIdx = _args.indexOf("--entitlement-base64");
3727
+ if (entitlementIdx !== -1) {
3728
+ try {
3729
+ ENTITLEMENT_PAYLOAD = validateEntitlementBase64(_args[entitlementIdx + 1], BRAND.commercialMode === true);
3730
+ }
3731
+ catch (err) {
3732
+ const msg = err instanceof Error ? err.message : String(err);
3733
+ console.error(`Setup failed: ${msg}`);
3734
+ console.error(`Error: ${msg}`);
3735
+ process.exit(1);
3736
+ }
3737
+ }
3738
+ let DISPLAY_MODE = "virtual";
3739
+ let DISPLAY_MODE_SOURCE = "default";
3740
+ const displayIdx = _args.indexOf("--display");
3741
+ if (displayIdx !== -1) {
3742
+ const raw = _args[displayIdx + 1];
3743
+ if (!raw || raw.startsWith("--")) {
3744
+ console.error("Setup failed: --display requires a value");
3745
+ console.error("Error: --display requires a value: native or virtual.");
3746
+ process.exit(1);
3747
+ }
3748
+ if (raw !== "native" && raw !== "virtual") {
3749
+ console.error(`Setup failed: --display value '${raw}' is invalid`);
3750
+ console.error(`Error: --display value '${raw}' is invalid. Must be 'native' or 'virtual'.`);
3751
+ process.exit(1);
3752
+ }
3753
+ DISPLAY_MODE = raw;
3754
+ DISPLAY_MODE_SOURCE = "--display flag";
3755
+ }
3756
+ else {
3757
+ // Upgrade detection: preserve existing DISPLAY_MODE from .env
3758
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
3759
+ const envPath = join(persistDir, ".env");
3760
+ let preservedFromEnv = false;
3761
+ try {
3762
+ if (existsSync(envPath)) {
3763
+ const envContent = readFileSync(envPath, "utf-8");
3764
+ const envMatch = envContent.match(/^DISPLAY_MODE=(native|virtual)$/m);
3765
+ if (envMatch) {
3766
+ DISPLAY_MODE = envMatch[1];
3767
+ DISPLAY_MODE_SOURCE = ".env (preserved)";
3768
+ preservedFromEnv = true;
3769
+ }
3770
+ }
3771
+ }
3772
+ catch { /* non-critical */ }
3773
+ // Darwin has no VNC/X11 stack — `virtual` mode is Pi-only (tigervnc +
3774
+ // websockify + novnc, none of which exist on macOS). A preserved
3775
+ // DISPLAY_MODE=virtual is never operator intent on darwin — it is the
3776
+ // legacy default from installers before 0.1.127, when `virtual` was the
3777
+ // only initial value written. The guard fires whenever the resolved
3778
+ // value is not already `native`, covering both fresh installs and
3779
+ // upgrades that inherited the legacy default.
3780
+ if (process.platform === "darwin" && DISPLAY_MODE !== "native") {
3781
+ DISPLAY_MODE_SOURCE = preservedFromEnv
3782
+ ? "darwin-auto (override-legacy-virtual)"
3783
+ : "darwin-auto (no VNC stack)";
3784
+ DISPLAY_MODE = "native";
3785
+ }
3786
+ }
3787
+ // ---------------------------------------------------------------------------
3788
+ // Embedding model — install-time flag, not a brand attribute.
3789
+ //
3790
+ // Controls which Ollama embedding model is pulled and the dimension count used
3791
+ // for Neo4j vector indexes. Dimensions are fixed at schema-creation time; changing
3792
+ // them later requires dropping and recreating all vector indexes.
3793
+ //
3794
+ // Priority: --embed-model flag > .env (upgrade) > default nomic-embed-text.
3795
+ // --embed-dimensions is required for models not in the curated lookup table.
3796
+ // --embed-dimensions without --embed-model is rejected (dimensions are model-specific).
3797
+ // ---------------------------------------------------------------------------
3798
+ const EMBED_MODEL_DIMS = {
3799
+ "nomic-embed-text": 768,
3800
+ "nomic-embed-text-v1.5": 768,
3801
+ "mxbai-embed-large": 1024,
3802
+ "snowflake-arctic-embed:335m": 768,
3803
+ };
3804
+ const DEFAULT_EMBED_MODEL = "nomic-embed-text";
3805
+ const DEFAULT_EMBED_DIMS = 768;
3806
+ let EMBED_MODEL = DEFAULT_EMBED_MODEL;
3807
+ let EMBED_DIMS = DEFAULT_EMBED_DIMS;
3808
+ let EMBED_SOURCE = "default";
3809
+ const embedModelIdx = _args.indexOf("--embed-model");
3810
+ const embedDimsIdx = _args.indexOf("--embed-dimensions");
3811
+ if (embedDimsIdx !== -1 && embedModelIdx === -1) {
3812
+ console.error("Setup failed: --embed-dimensions requires --embed-model");
3813
+ console.error("Error: --embed-dimensions requires --embed-model (dimensions are model-specific).");
3814
+ process.exit(1);
3815
+ }
3816
+ if (embedModelIdx !== -1) {
3817
+ const raw = _args[embedModelIdx + 1];
3818
+ if (!raw || raw.startsWith("--")) {
3819
+ console.error("Setup failed: --embed-model requires a value");
3820
+ console.error("Error: --embed-model requires a value (e.g. --embed-model mxbai-embed-large).");
3821
+ process.exit(1);
3822
+ }
3823
+ EMBED_MODEL = raw;
3824
+ EMBED_SOURCE = "--embed-model flag";
3825
+ if (embedDimsIdx !== -1) {
3826
+ // Explicit dimensions override the lookup table
3827
+ const rawDims = _args[embedDimsIdx + 1];
3828
+ const parsed = rawDims ? parseInt(rawDims, 10) : NaN;
3829
+ if (isNaN(parsed) || parsed <= 0) {
3830
+ console.error(`Setup failed: --embed-dimensions requires a positive integer (got: ${rawDims ?? "nothing"})`);
3831
+ console.error(`Error: --embed-dimensions requires a positive integer (got: ${rawDims ?? "nothing"}).`);
3832
+ process.exit(1);
3833
+ }
3834
+ EMBED_DIMS = parsed;
3835
+ }
3836
+ else if (EMBED_MODEL in EMBED_MODEL_DIMS) {
3837
+ // Known model — resolve dimensions from lookup table
3838
+ EMBED_DIMS = EMBED_MODEL_DIMS[EMBED_MODEL];
3839
+ }
3840
+ else {
3841
+ // Unknown model without explicit dimensions — cannot proceed
3842
+ console.error(`Setup failed: unknown embedding model '${EMBED_MODEL}'`);
3843
+ console.error(`Error: Unknown embedding model '${EMBED_MODEL}'.`);
3844
+ console.error("Known models and their dimensions:");
3845
+ for (const [model, dims] of Object.entries(EMBED_MODEL_DIMS)) {
3846
+ console.error(` ${model} — ${dims} dimensions`);
3847
+ }
3848
+ console.error("\nFor a custom model, pass --embed-dimensions N explicitly:");
3849
+ console.error(` npx -y @rubytech/create-maxy --embed-model ${EMBED_MODEL} --embed-dimensions 512`);
3850
+ process.exit(1);
3851
+ }
3852
+ }
3853
+ else {
3854
+ // No --embed-model flag: check .env for upgrade preservation
3855
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
3856
+ const envPath = join(persistDir, ".env");
3857
+ try {
3858
+ if (existsSync(envPath)) {
3859
+ const envContent = readFileSync(envPath, "utf-8");
3860
+ const modelMatch = envContent.match(/^EMBED_MODEL=(.+)$/m);
3861
+ const dimsMatch = envContent.match(/^EMBED_DIMENSIONS=(\d+)$/m);
3862
+ if (modelMatch) {
3863
+ EMBED_MODEL = modelMatch[1];
3864
+ EMBED_SOURCE = ".env (preserved)";
3865
+ if (dimsMatch) {
3866
+ EMBED_DIMS = parseInt(dimsMatch[1], 10);
3867
+ }
3868
+ else if (EMBED_MODEL in EMBED_MODEL_DIMS) {
3869
+ EMBED_DIMS = EMBED_MODEL_DIMS[EMBED_MODEL];
3870
+ }
3871
+ // Unknown model without dims in .env: keep DEFAULT_EMBED_DIMS — the schema
3872
+ // was created with whatever dims were configured at original install time.
3873
+ }
3874
+ }
3875
+ }
3876
+ catch { /* non-critical */ }
3877
+ }
3878
+ // ---------------------------------------------------------------------------
3879
+ // Neo4j port — multi-brand data isolation.
3880
+ //
3881
+ // Default Maxy brand: 7687 (shared system Neo4j instance). Branded builds ship
3882
+ // a dedicated port in brand.json (e.g. Real Agent = 7688) so installing a
3883
+ // second brand on the same device gets its own database by default.
3884
+ //
3885
+ // Priority: --neo4j-port flag > .env NEO4J_URI (upgrade preserve) > BRAND.neo4jPort > 7687.
3886
+ // ---------------------------------------------------------------------------
3887
+ const DEFAULT_NEO4J_PORT = 7687;
3888
+ let NEO4J_PORT = BRAND.neo4jPort ?? DEFAULT_NEO4J_PORT;
3889
+ let NEO4J_PORT_SOURCE = BRAND.neo4jPort ? "brand.json" : "default";
3890
+ const neo4jPortIdx = _args.indexOf("--neo4j-port");
3891
+ if (neo4jPortIdx !== -1) {
3892
+ const raw = _args[neo4jPortIdx + 1];
3893
+ const parsed = raw ? parseInt(raw, 10) : NaN;
3894
+ if (isNaN(parsed) || parsed < 1024 || parsed > 65535) {
3895
+ console.error(`Setup failed: --neo4j-port requires a numeric value between 1024 and 65535 (got: ${raw ?? "nothing"})`);
3896
+ console.error(`Error: --neo4j-port requires a numeric value between 1024 and 65535 (got: ${raw ?? "nothing"}).`);
3897
+ process.exit(1);
3898
+ }
3899
+ NEO4J_PORT = parsed;
3900
+ NEO4J_PORT_SOURCE = "--neo4j-port flag";
3901
+ }
3902
+ else {
3903
+ // Upgrade detection: check .env for NEO4J_URI=bolt://localhost:{port}.
3904
+ // Preserves an existing install's port even if brand.json now says different.
3905
+ const persistDir = resolve(process.env.HOME ?? "/root", BRAND.configDir);
3906
+ const envPath = join(persistDir, ".env");
3907
+ try {
3908
+ if (existsSync(envPath)) {
3909
+ const envContent = readFileSync(envPath, "utf-8");
3910
+ const uriMatch = envContent.match(/^NEO4J_URI=bolt:\/\/localhost:(\d+)$/m);
3911
+ if (uriMatch) {
3912
+ const envPort = parseInt(uriMatch[1], 10);
3913
+ if (envPort >= 1024 && envPort <= 65535) {
3914
+ NEO4J_PORT = envPort;
3915
+ NEO4J_PORT_SOURCE = ".env (preserved)";
3916
+ }
3917
+ }
3918
+ }
3919
+ }
3920
+ catch { /* non-critical */ }
3921
+ }
3922
+ // Dedicated = port differs from the default shared instance
3923
+ const NEO4J_DEDICATED = NEO4J_PORT !== DEFAULT_NEO4J_PORT;
3924
+ // ---------------------------------------------------------------------------
3925
+ // removed the per-brand ttyd port — the admin terminal stack
3926
+ // (ttyd, tmux, xterm.js) was retired in favour of the action runner that
3927
+ // spawns transient `systemd-run --user` units per upgrade or setup-tunnel
3928
+ // invocation. No TCP listener on the device needs to be reserved for an
3929
+ // interactive-shell surface any more.
3930
+ const PKG_VERSION = JSON.parse(readFileSync(resolve(import.meta.dirname, "../package.json"), "utf-8")).version;
3931
+ // ---------------------------------------------------------------------------
3932
+ // pre-flight platform refusal.
3933
+ //
3934
+ // Runs BEFORE initLogging() (LOG_DIR creation), port resolution, and any
3935
+ // brew/scutil/hostnamectl probe. Only Linux + darwin are supported;
3936
+ // on darwin, macOS major must be ≥ 14 (the floor required by Tasks 838/839).
3937
+ // Older macOS partially succeeds, then breaks at the supervisor or brew-cellar
3938
+ // layer with cryptic errors — refusing loudly here is the contract.
3939
+ //
3940
+ // Platform-header line is emitted on every install start so operators can grep
3941
+ // `[create-maxy] platform=` to confirm pre-flight ran. On darwin the line also
3942
+ // carries `macos=<v>` (token) so the macOS-14 floor check is visible.
3943
+ // ---------------------------------------------------------------------------
3944
+ const PLATFORM = requireSupportedPlatform(process.platform);
3945
+ let MACOS_VERSION = null;
3946
+ if (PLATFORM === "darwin") {
3947
+ const swVers = spawnSync("sw_vers", [], { encoding: "utf-8", stdio: "pipe", timeout: 5_000 });
3948
+ const parsed = parseSwVers(swVers.stdout ?? "");
3949
+ if (!parsed) {
3950
+ const head = (swVers.stdout ?? "").split("\n").slice(0, 2).join(" | ");
3951
+ console.error(`[create-maxy] sw_vers stdout malformed: ${head}`);
3952
+ console.error(`[create-maxy] platform=darwin macos=<unknown> — refusing: macOS 14+ required`);
3953
+ process.exit(1);
3954
+ }
3955
+ MACOS_VERSION = parsed.version;
3956
+ if (!isSupportedMacosVersion(MACOS_VERSION)) {
3957
+ console.error(`[create-maxy] platform=darwin macos=${MACOS_VERSION} — refusing: macOS 14+ required`);
3958
+ process.exit(1);
3959
+ }
3960
+ }
3961
+ // Platform-header — first log line. Operators grep `[create-maxy] platform=`
3962
+ // to confirm pre-flight ran. The /* macos=<v> */ token is the marker;
3963
+ // keep it on this same line so 3-way merges with parallel installer edits stay
3964
+ // mechanical (no rewrap, no split into two log lines).
3965
+ const PLATFORM_HEADER = `[create-maxy] platform=${PLATFORM} arch=${process.arch}` +
3966
+ (MACOS_VERSION ? ` macos=${MACOS_VERSION}` : ``) +
3967
+ ` version=${PKG_VERSION}`;
3968
+ // emit platform header and the resolved log/persist paths to
3969
+ // stdout BEFORE the log file is opened. If initLogging's mkdir or first
3970
+ // appendFileSync throws, the operator still sees brand/version/arch and the
3971
+ // exact path the log file SHOULD live at, instead of a silent exit between
3972
+ // the LOG_DIR mkdir and the first log write.
3973
+ console.log(PLATFORM_HEADER);
3974
+ console.log(`[create-maxy] log=${LOG_FILE} persist=${PERSIST_DIR}`);
3975
+ initLogging();
3976
+ console.log("================================================================");
3977
+ console.log(` ${BRAND.productName} — ${BRAND.tagline}. (${BRAND.hostname} v${PKG_VERSION})`);
3978
+ console.log("================================================================");
3979
+ console.log(` Install log: ${LOG_FILE}`);
3980
+ console.log(` Port: ${PORT} (${PORT_SOURCE})`);
3981
+ if (HOSTNAME_FLAG)
3982
+ console.log(` Hostname: ${HOSTNAME_FLAG} (from --hostname flag)`);
3983
+ console.log(` Display: ${DISPLAY_MODE} (${DISPLAY_MODE_SOURCE})`);
3984
+ console.log(` Embed model: ${EMBED_MODEL} (${EMBED_DIMS} dims, ${EMBED_SOURCE})`);
3985
+ console.log(` Neo4j: ${NEO4J_DEDICATED ? "dedicated" : "shared"} on bolt://localhost:${NEO4J_PORT} (${NEO4J_PORT_SOURCE})`);
3986
+ console.log("");
3987
+ logDiagnostics("pre-flight");
3988
+ logFile(` Neo4j instance: ${NEO4J_DEDICATED ? "dedicated" : "shared"} on bolt://localhost:${NEO4J_PORT}`);
3989
+ try {
3990
+ installSystemDeps();
3991
+ installNodejs();
3992
+ installClaudeCode();
3993
+ installNeo4j();
3994
+ setupDedicatedNeo4j();
3995
+ installOllama(EMBED_MODEL);
3996
+ installUv();
3997
+ installCloudflared();
3998
+ installWhisperCpp();
3999
+ deployPayload(); // Must happen before ensureNeo4jPassword — restores config backup
4000
+ // write the resolved Chromium absolute path into the deployed
4001
+ // platform/config/ so vnc.sh and writeChromiumWrapper read the same
4002
+ // value. Must run after deployPayload (config dir is
4003
+ // a payload subdirectory). Linux-only; no-op on darwin/non-linux.
4004
+ writeChromiumBinaryPathFile();
4005
+ // scrub plaintext neo4j passwords from any pre-fix install-*.log.
4006
+ // Idempotent — re-running on already-redacted logs is a no-op. Runs after
4007
+ // payload deploy so the bundled redact-install-logs.sh is on disk.
4008
+ redactInstallLogs();
4009
+ ensureNeo4jPassword(); // Now config/.neo4j-password is available if it existed before
4010
+ provisionRemoteSessionSecret(); // shared HMAC key readable by maxy-edge + maxy-ui
4011
+ buildPlatform();
4012
+ registerLocalAndExternalPlugins(); // install-time plugin registration
4013
+ setupVncViewer();
4014
+ setupAccount();
4015
+ if (ENTITLEMENT_PAYLOAD) {
4016
+ writeEntitlementFromFlag(ENTITLEMENT_PAYLOAD);
4017
+ }
4018
+ installService();
4019
+ // Samba on the LAN. Runs after the brand systemd unit is up so
4020
+ // SMB provisioning never blocks the admin server starting; loud-fail per
4021
+ // step. The smbpasswd `user` step is deferred at install time and synced
4022
+ // by the platform's /set-pin route when the operator sets a PIN.
4023
+ provisionSamba();
4024
+ console.log("");
4025
+ console.log("================================================================");
4026
+ console.log("");
4027
+ if (isLinux()) {
4028
+ console.log(` Same network (Pi / LAN): http://${DEVICE_HOSTNAME}.local:${PORT}`);
4029
+ console.log("");
4030
+ console.log(` Remote access (Hetzner / cloud) — on your local machine run:`);
4031
+ console.log(` ssh -L ${PORT}:localhost:${PORT} -L ${BRAND.websockifyPort}:localhost:${BRAND.websockifyPort} admin@<server-ipv4>`);
4032
+ console.log(` Then open:`);
4033
+ console.log(` Dashboard: http://localhost:${PORT}`);
4034
+ console.log(` VNC browser (Claude OAuth + Cloudflare): http://localhost:${BRAND.websockifyPort}/vnc.html`);
4035
+ }
4036
+ else {
4037
+ console.log(` Open in your browser: http://${DEVICE_HOSTNAME}.local:${PORT}`);
4038
+ }
4039
+ console.log("");
4040
+ console.log("================================================================");
4041
+ }
4042
+ catch (err) {
4043
+ console.error("");
4044
+ console.error(`Setup failed: ${err instanceof Error ? err.message : String(err)}`);
4045
+ console.error(` Full log: ${LOG_FILE}`);
4046
+ logDiagnostics("post-failure");
4047
+ process.exit(1);
4048
+ }