@better-openclaw/core 1.0.0

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 (461) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-lint.log +360 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/dist/bare-metal-partition.d.ts +22 -0
  5. package/dist/bare-metal-partition.d.ts.map +1 -0
  6. package/dist/bare-metal-partition.js +49 -0
  7. package/dist/bare-metal-partition.js.map +1 -0
  8. package/dist/composer.d.ts +17 -0
  9. package/dist/composer.d.ts.map +1 -0
  10. package/dist/composer.js +305 -0
  11. package/dist/composer.js.map +1 -0
  12. package/dist/generate.d.ts +7 -0
  13. package/dist/generate.d.ts.map +1 -0
  14. package/dist/generate.js +218 -0
  15. package/dist/generate.js.map +1 -0
  16. package/dist/generators/bare-metal-install.d.ts +18 -0
  17. package/dist/generators/bare-metal-install.d.ts.map +1 -0
  18. package/dist/generators/bare-metal-install.js +228 -0
  19. package/dist/generators/bare-metal-install.js.map +1 -0
  20. package/dist/generators/caddy.d.ts +13 -0
  21. package/dist/generators/caddy.d.ts.map +1 -0
  22. package/dist/generators/caddy.js +85 -0
  23. package/dist/generators/caddy.js.map +1 -0
  24. package/dist/generators/env.d.ts +42 -0
  25. package/dist/generators/env.d.ts.map +1 -0
  26. package/dist/generators/env.js +276 -0
  27. package/dist/generators/env.js.map +1 -0
  28. package/dist/generators/grafana.d.ts +19 -0
  29. package/dist/generators/grafana.d.ts.map +1 -0
  30. package/dist/generators/grafana.js +247 -0
  31. package/dist/generators/grafana.js.map +1 -0
  32. package/dist/generators/n8n-workflows.d.ts +7 -0
  33. package/dist/generators/n8n-workflows.d.ts.map +1 -0
  34. package/dist/generators/n8n-workflows.js +78 -0
  35. package/dist/generators/n8n-workflows.js.map +1 -0
  36. package/dist/generators/native-services.d.ts +13 -0
  37. package/dist/generators/native-services.d.ts.map +1 -0
  38. package/dist/generators/native-services.js +85 -0
  39. package/dist/generators/native-services.js.map +1 -0
  40. package/dist/generators/postgres-init.d.ts +27 -0
  41. package/dist/generators/postgres-init.d.ts.map +1 -0
  42. package/dist/generators/postgres-init.js +119 -0
  43. package/dist/generators/postgres-init.js.map +1 -0
  44. package/dist/generators/prometheus.d.ts +10 -0
  45. package/dist/generators/prometheus.d.ts.map +1 -0
  46. package/dist/generators/prometheus.js +79 -0
  47. package/dist/generators/prometheus.js.map +1 -0
  48. package/dist/generators/readme.d.ts +21 -0
  49. package/dist/generators/readme.d.ts.map +1 -0
  50. package/dist/generators/readme.js +224 -0
  51. package/dist/generators/readme.js.map +1 -0
  52. package/dist/generators/scripts.d.ts +7 -0
  53. package/dist/generators/scripts.d.ts.map +1 -0
  54. package/dist/generators/scripts.js +352 -0
  55. package/dist/generators/scripts.js.map +1 -0
  56. package/dist/generators/skills.d.ts +10 -0
  57. package/dist/generators/skills.d.ts.map +1 -0
  58. package/dist/generators/skills.js +596 -0
  59. package/dist/generators/skills.js.map +1 -0
  60. package/dist/index.d.ts +24 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +27 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/presets/registry.d.ts +5 -0
  65. package/dist/presets/registry.d.ts.map +1 -0
  66. package/dist/presets/registry.js +121 -0
  67. package/dist/presets/registry.js.map +1 -0
  68. package/dist/resolver.d.ts +17 -0
  69. package/dist/resolver.d.ts.map +1 -0
  70. package/dist/resolver.js +254 -0
  71. package/dist/resolver.js.map +1 -0
  72. package/dist/schema.d.ts +2426 -0
  73. package/dist/schema.d.ts.map +1 -0
  74. package/dist/schema.js +259 -0
  75. package/dist/schema.js.map +1 -0
  76. package/dist/services/definitions/anything-llm.d.ts +3 -0
  77. package/dist/services/definitions/anything-llm.d.ts.map +1 -0
  78. package/dist/services/definitions/anything-llm.js +39 -0
  79. package/dist/services/definitions/anything-llm.js.map +1 -0
  80. package/dist/services/definitions/appflowy.d.ts +3 -0
  81. package/dist/services/definitions/appflowy.d.ts.map +1 -0
  82. package/dist/services/definitions/appflowy.js +39 -0
  83. package/dist/services/definitions/appflowy.js.map +1 -0
  84. package/dist/services/definitions/beszel.d.ts +3 -0
  85. package/dist/services/definitions/beszel.d.ts.map +1 -0
  86. package/dist/services/definitions/beszel.js +39 -0
  87. package/dist/services/definitions/beszel.js.map +1 -0
  88. package/dist/services/definitions/browserless.d.ts +3 -0
  89. package/dist/services/definitions/browserless.d.ts.map +1 -0
  90. package/dist/services/definitions/browserless.js +77 -0
  91. package/dist/services/definitions/browserless.js.map +1 -0
  92. package/dist/services/definitions/caddy.d.ts +3 -0
  93. package/dist/services/definitions/caddy.d.ts.map +1 -0
  94. package/dist/services/definitions/caddy.js +50 -0
  95. package/dist/services/definitions/caddy.js.map +1 -0
  96. package/dist/services/definitions/chromadb.d.ts +3 -0
  97. package/dist/services/definitions/chromadb.d.ts.map +1 -0
  98. package/dist/services/definitions/chromadb.js +61 -0
  99. package/dist/services/definitions/chromadb.js.map +1 -0
  100. package/dist/services/definitions/claude-code.d.ts +3 -0
  101. package/dist/services/definitions/claude-code.d.ts.map +1 -0
  102. package/dist/services/definitions/claude-code.js +49 -0
  103. package/dist/services/definitions/claude-code.js.map +1 -0
  104. package/dist/services/definitions/code-server.d.ts +3 -0
  105. package/dist/services/definitions/code-server.d.ts.map +1 -0
  106. package/dist/services/definitions/code-server.js +61 -0
  107. package/dist/services/definitions/code-server.js.map +1 -0
  108. package/dist/services/definitions/codex.d.ts +3 -0
  109. package/dist/services/definitions/codex.d.ts.map +1 -0
  110. package/dist/services/definitions/codex.js +41 -0
  111. package/dist/services/definitions/codex.js.map +1 -0
  112. package/dist/services/definitions/coolify.d.ts +3 -0
  113. package/dist/services/definitions/coolify.d.ts.map +1 -0
  114. package/dist/services/definitions/coolify.js +44 -0
  115. package/dist/services/definitions/coolify.js.map +1 -0
  116. package/dist/services/definitions/dify.d.ts +3 -0
  117. package/dist/services/definitions/dify.d.ts.map +1 -0
  118. package/dist/services/definitions/dify.js +75 -0
  119. package/dist/services/definitions/dify.js.map +1 -0
  120. package/dist/services/definitions/docsgpt.d.ts +3 -0
  121. package/dist/services/definitions/docsgpt.d.ts.map +1 -0
  122. package/dist/services/definitions/docsgpt.js +39 -0
  123. package/dist/services/definitions/docsgpt.js.map +1 -0
  124. package/dist/services/definitions/dokploy.d.ts +3 -0
  125. package/dist/services/definitions/dokploy.d.ts.map +1 -0
  126. package/dist/services/definitions/dokploy.js +44 -0
  127. package/dist/services/definitions/dokploy.js.map +1 -0
  128. package/dist/services/definitions/dozzle.d.ts +3 -0
  129. package/dist/services/definitions/dozzle.d.ts.map +1 -0
  130. package/dist/services/definitions/dozzle.js +33 -0
  131. package/dist/services/definitions/dozzle.js.map +1 -0
  132. package/dist/services/definitions/ffmpeg.d.ts +3 -0
  133. package/dist/services/definitions/ffmpeg.d.ts.map +1 -0
  134. package/dist/services/definitions/ffmpeg.js +63 -0
  135. package/dist/services/definitions/ffmpeg.js.map +1 -0
  136. package/dist/services/definitions/flowise.d.ts +3 -0
  137. package/dist/services/definitions/flowise.d.ts.map +1 -0
  138. package/dist/services/definitions/flowise.js +39 -0
  139. package/dist/services/definitions/flowise.js.map +1 -0
  140. package/dist/services/definitions/gemini-cli.d.ts +3 -0
  141. package/dist/services/definitions/gemini-cli.d.ts.map +1 -0
  142. package/dist/services/definitions/gemini-cli.js +41 -0
  143. package/dist/services/definitions/gemini-cli.js.map +1 -0
  144. package/dist/services/definitions/gitea.d.ts +3 -0
  145. package/dist/services/definitions/gitea.d.ts.map +1 -0
  146. package/dist/services/definitions/gitea.js +45 -0
  147. package/dist/services/definitions/gitea.js.map +1 -0
  148. package/dist/services/definitions/gotify.d.ts +3 -0
  149. package/dist/services/definitions/gotify.d.ts.map +1 -0
  150. package/dist/services/definitions/gotify.js +60 -0
  151. package/dist/services/definitions/gotify.js.map +1 -0
  152. package/dist/services/definitions/grafana.d.ts +3 -0
  153. package/dist/services/definitions/grafana.d.ts.map +1 -0
  154. package/dist/services/definitions/grafana.js +61 -0
  155. package/dist/services/definitions/grafana.js.map +1 -0
  156. package/dist/services/definitions/index.d.ts +68 -0
  157. package/dist/services/definitions/index.d.ts.map +1 -0
  158. package/dist/services/definitions/index.js +198 -0
  159. package/dist/services/definitions/index.js.map +1 -0
  160. package/dist/services/definitions/kimi.d.ts +3 -0
  161. package/dist/services/definitions/kimi.d.ts.map +1 -0
  162. package/dist/services/definitions/kimi.js +41 -0
  163. package/dist/services/definitions/kimi.js.map +1 -0
  164. package/dist/services/definitions/lasuite-meet-agents.d.ts +3 -0
  165. package/dist/services/definitions/lasuite-meet-agents.d.ts.map +1 -0
  166. package/dist/services/definitions/lasuite-meet-agents.js +26 -0
  167. package/dist/services/definitions/lasuite-meet-agents.js.map +1 -0
  168. package/dist/services/definitions/lasuite-meet-backend.d.ts +3 -0
  169. package/dist/services/definitions/lasuite-meet-backend.d.ts.map +1 -0
  170. package/dist/services/definitions/lasuite-meet-backend.js +118 -0
  171. package/dist/services/definitions/lasuite-meet-backend.js.map +1 -0
  172. package/dist/services/definitions/lasuite-meet-frontend.d.ts +3 -0
  173. package/dist/services/definitions/lasuite-meet-frontend.d.ts.map +1 -0
  174. package/dist/services/definitions/lasuite-meet-frontend.js +31 -0
  175. package/dist/services/definitions/lasuite-meet-frontend.js.map +1 -0
  176. package/dist/services/definitions/librechat.d.ts +3 -0
  177. package/dist/services/definitions/librechat.d.ts.map +1 -0
  178. package/dist/services/definitions/librechat.js +47 -0
  179. package/dist/services/definitions/librechat.js.map +1 -0
  180. package/dist/services/definitions/lightpanda.d.ts +3 -0
  181. package/dist/services/definitions/lightpanda.d.ts.map +1 -0
  182. package/dist/services/definitions/lightpanda.js +59 -0
  183. package/dist/services/definitions/lightpanda.js.map +1 -0
  184. package/dist/services/definitions/litellm.d.ts +3 -0
  185. package/dist/services/definitions/litellm.d.ts.map +1 -0
  186. package/dist/services/definitions/litellm.js +41 -0
  187. package/dist/services/definitions/litellm.js.map +1 -0
  188. package/dist/services/definitions/livekit.d.ts +3 -0
  189. package/dist/services/definitions/livekit.d.ts.map +1 -0
  190. package/dist/services/definitions/livekit.js +31 -0
  191. package/dist/services/definitions/livekit.js.map +1 -0
  192. package/dist/services/definitions/matomo.d.ts +3 -0
  193. package/dist/services/definitions/matomo.d.ts.map +1 -0
  194. package/dist/services/definitions/matomo.js +75 -0
  195. package/dist/services/definitions/matomo.js.map +1 -0
  196. package/dist/services/definitions/matrix-synapse.d.ts +3 -0
  197. package/dist/services/definitions/matrix-synapse.d.ts.map +1 -0
  198. package/dist/services/definitions/matrix-synapse.js +82 -0
  199. package/dist/services/definitions/matrix-synapse.js.map +1 -0
  200. package/dist/services/definitions/mattermost.d.ts +3 -0
  201. package/dist/services/definitions/mattermost.d.ts.map +1 -0
  202. package/dist/services/definitions/mattermost.js +59 -0
  203. package/dist/services/definitions/mattermost.js.map +1 -0
  204. package/dist/services/definitions/meilisearch.d.ts +3 -0
  205. package/dist/services/definitions/meilisearch.d.ts.map +1 -0
  206. package/dist/services/definitions/meilisearch.js +76 -0
  207. package/dist/services/definitions/meilisearch.js.map +1 -0
  208. package/dist/services/definitions/minio.d.ts +3 -0
  209. package/dist/services/definitions/minio.d.ts.map +1 -0
  210. package/dist/services/definitions/minio.js +98 -0
  211. package/dist/services/definitions/minio.js.map +1 -0
  212. package/dist/services/definitions/mixpost.d.ts +3 -0
  213. package/dist/services/definitions/mixpost.d.ts.map +1 -0
  214. package/dist/services/definitions/mixpost.js +82 -0
  215. package/dist/services/definitions/mixpost.js.map +1 -0
  216. package/dist/services/definitions/motion-canvas.d.ts +3 -0
  217. package/dist/services/definitions/motion-canvas.d.ts.map +1 -0
  218. package/dist/services/definitions/motion-canvas.js +48 -0
  219. package/dist/services/definitions/motion-canvas.js.map +1 -0
  220. package/dist/services/definitions/n8n.d.ts +3 -0
  221. package/dist/services/definitions/n8n.d.ts.map +1 -0
  222. package/dist/services/definitions/n8n.js +146 -0
  223. package/dist/services/definitions/n8n.js.map +1 -0
  224. package/dist/services/definitions/nocodb.d.ts +3 -0
  225. package/dist/services/definitions/nocodb.d.ts.map +1 -0
  226. package/dist/services/definitions/nocodb.js +39 -0
  227. package/dist/services/definitions/nocodb.js.map +1 -0
  228. package/dist/services/definitions/ntfy.d.ts +3 -0
  229. package/dist/services/definitions/ntfy.d.ts.map +1 -0
  230. package/dist/services/definitions/ntfy.js +61 -0
  231. package/dist/services/definitions/ntfy.js.map +1 -0
  232. package/dist/services/definitions/ollama.d.ts +3 -0
  233. package/dist/services/definitions/ollama.d.ts.map +1 -0
  234. package/dist/services/definitions/ollama.js +61 -0
  235. package/dist/services/definitions/ollama.js.map +1 -0
  236. package/dist/services/definitions/open-webui.d.ts +3 -0
  237. package/dist/services/definitions/open-webui.d.ts.map +1 -0
  238. package/dist/services/definitions/open-webui.js +47 -0
  239. package/dist/services/definitions/open-webui.js.map +1 -0
  240. package/dist/services/definitions/opencode.d.ts +3 -0
  241. package/dist/services/definitions/opencode.d.ts.map +1 -0
  242. package/dist/services/definitions/opencode.js +47 -0
  243. package/dist/services/definitions/opencode.js.map +1 -0
  244. package/dist/services/definitions/openpanel.d.ts +3 -0
  245. package/dist/services/definitions/openpanel.d.ts.map +1 -0
  246. package/dist/services/definitions/openpanel.js +41 -0
  247. package/dist/services/definitions/openpanel.js.map +1 -0
  248. package/dist/services/definitions/outline.d.ts +3 -0
  249. package/dist/services/definitions/outline.d.ts.map +1 -0
  250. package/dist/services/definitions/outline.js +68 -0
  251. package/dist/services/definitions/outline.js.map +1 -0
  252. package/dist/services/definitions/paperless-ngx.d.ts +3 -0
  253. package/dist/services/definitions/paperless-ngx.d.ts.map +1 -0
  254. package/dist/services/definitions/paperless-ngx.js +85 -0
  255. package/dist/services/definitions/paperless-ngx.js.map +1 -0
  256. package/dist/services/definitions/playwright-server.d.ts +3 -0
  257. package/dist/services/definitions/playwright-server.d.ts.map +1 -0
  258. package/dist/services/definitions/playwright-server.js +34 -0
  259. package/dist/services/definitions/playwright-server.js.map +1 -0
  260. package/dist/services/definitions/portainer.d.ts +3 -0
  261. package/dist/services/definitions/portainer.d.ts.map +1 -0
  262. package/dist/services/definitions/portainer.js +44 -0
  263. package/dist/services/definitions/portainer.js.map +1 -0
  264. package/dist/services/definitions/postgresql.d.ts +3 -0
  265. package/dist/services/definitions/postgresql.d.ts.map +1 -0
  266. package/dist/services/definitions/postgresql.js +83 -0
  267. package/dist/services/definitions/postgresql.js.map +1 -0
  268. package/dist/services/definitions/postiz.d.ts +3 -0
  269. package/dist/services/definitions/postiz.d.ts.map +1 -0
  270. package/dist/services/definitions/postiz.js +79 -0
  271. package/dist/services/definitions/postiz.js.map +1 -0
  272. package/dist/services/definitions/prometheus.d.ts +3 -0
  273. package/dist/services/definitions/prometheus.d.ts.map +1 -0
  274. package/dist/services/definitions/prometheus.js +47 -0
  275. package/dist/services/definitions/prometheus.js.map +1 -0
  276. package/dist/services/definitions/qdrant.d.ts +3 -0
  277. package/dist/services/definitions/qdrant.d.ts.map +1 -0
  278. package/dist/services/definitions/qdrant.js +75 -0
  279. package/dist/services/definitions/qdrant.js.map +1 -0
  280. package/dist/services/definitions/redis.d.ts +3 -0
  281. package/dist/services/definitions/redis.d.ts.map +1 -0
  282. package/dist/services/definitions/redis.js +90 -0
  283. package/dist/services/definitions/redis.js.map +1 -0
  284. package/dist/services/definitions/remotion.d.ts +3 -0
  285. package/dist/services/definitions/remotion.d.ts.map +1 -0
  286. package/dist/services/definitions/remotion.js +48 -0
  287. package/dist/services/definitions/remotion.js.map +1 -0
  288. package/dist/services/definitions/rocketchat.d.ts +3 -0
  289. package/dist/services/definitions/rocketchat.d.ts.map +1 -0
  290. package/dist/services/definitions/rocketchat.js +54 -0
  291. package/dist/services/definitions/rocketchat.js.map +1 -0
  292. package/dist/services/definitions/searxng.d.ts +3 -0
  293. package/dist/services/definitions/searxng.d.ts.map +1 -0
  294. package/dist/services/definitions/searxng.js +61 -0
  295. package/dist/services/definitions/searxng.js.map +1 -0
  296. package/dist/services/definitions/stable-diffusion.d.ts +3 -0
  297. package/dist/services/definitions/stable-diffusion.d.ts.map +1 -0
  298. package/dist/services/definitions/stable-diffusion.js +44 -0
  299. package/dist/services/definitions/stable-diffusion.js.map +1 -0
  300. package/dist/services/definitions/steel-browser.d.ts +3 -0
  301. package/dist/services/definitions/steel-browser.d.ts.map +1 -0
  302. package/dist/services/definitions/steel-browser.js +68 -0
  303. package/dist/services/definitions/steel-browser.js.map +1 -0
  304. package/dist/services/definitions/tailscale.d.ts +3 -0
  305. package/dist/services/definitions/tailscale.d.ts.map +1 -0
  306. package/dist/services/definitions/tailscale.js +62 -0
  307. package/dist/services/definitions/tailscale.js.map +1 -0
  308. package/dist/services/definitions/temporal.d.ts +3 -0
  309. package/dist/services/definitions/temporal.d.ts.map +1 -0
  310. package/dist/services/definitions/temporal.js +97 -0
  311. package/dist/services/definitions/temporal.js.map +1 -0
  312. package/dist/services/definitions/traefik.d.ts +3 -0
  313. package/dist/services/definitions/traefik.d.ts.map +1 -0
  314. package/dist/services/definitions/traefik.js +52 -0
  315. package/dist/services/definitions/traefik.js.map +1 -0
  316. package/dist/services/definitions/umami.d.ts +3 -0
  317. package/dist/services/definitions/umami.d.ts.map +1 -0
  318. package/dist/services/definitions/umami.js +41 -0
  319. package/dist/services/definitions/umami.js.map +1 -0
  320. package/dist/services/definitions/uptime-kuma.d.ts +3 -0
  321. package/dist/services/definitions/uptime-kuma.d.ts.map +1 -0
  322. package/dist/services/definitions/uptime-kuma.js +46 -0
  323. package/dist/services/definitions/uptime-kuma.js.map +1 -0
  324. package/dist/services/definitions/valkey.d.ts +3 -0
  325. package/dist/services/definitions/valkey.d.ts.map +1 -0
  326. package/dist/services/definitions/valkey.js +60 -0
  327. package/dist/services/definitions/valkey.js.map +1 -0
  328. package/dist/services/definitions/watchtower.d.ts +3 -0
  329. package/dist/services/definitions/watchtower.d.ts.map +1 -0
  330. package/dist/services/definitions/watchtower.js +41 -0
  331. package/dist/services/definitions/watchtower.js.map +1 -0
  332. package/dist/services/definitions/weaviate.d.ts +3 -0
  333. package/dist/services/definitions/weaviate.d.ts.map +1 -0
  334. package/dist/services/definitions/weaviate.js +89 -0
  335. package/dist/services/definitions/weaviate.js.map +1 -0
  336. package/dist/services/definitions/whisper.d.ts +3 -0
  337. package/dist/services/definitions/whisper.d.ts.map +1 -0
  338. package/dist/services/definitions/whisper.js +55 -0
  339. package/dist/services/definitions/whisper.js.map +1 -0
  340. package/dist/services/registry.d.ts +12 -0
  341. package/dist/services/registry.d.ts.map +1 -0
  342. package/dist/services/registry.js +28 -0
  343. package/dist/services/registry.js.map +1 -0
  344. package/dist/skills/registry.d.ts +7 -0
  345. package/dist/skills/registry.d.ts.map +1 -0
  346. package/dist/skills/registry.js +111 -0
  347. package/dist/skills/registry.js.map +1 -0
  348. package/dist/types.d.ts +60 -0
  349. package/dist/types.d.ts.map +1 -0
  350. package/dist/types.js +20 -0
  351. package/dist/types.js.map +1 -0
  352. package/dist/validator.d.ts +16 -0
  353. package/dist/validator.d.ts.map +1 -0
  354. package/dist/validator.js +142 -0
  355. package/dist/validator.js.map +1 -0
  356. package/dist/version-manager.d.ts +10 -0
  357. package/dist/version-manager.d.ts.map +1 -0
  358. package/dist/version-manager.js +60 -0
  359. package/dist/version-manager.js.map +1 -0
  360. package/package.json +37 -0
  361. package/src/__snapshots__/composer.snapshot.test.ts.snap +903 -0
  362. package/src/bare-metal-partition.test.ts +63 -0
  363. package/src/bare-metal-partition.ts +64 -0
  364. package/src/composer.snapshot.test.ts +87 -0
  365. package/src/composer.test.ts +224 -0
  366. package/src/composer.ts +403 -0
  367. package/src/generate.test.ts +349 -0
  368. package/src/generate.ts +259 -0
  369. package/src/generators/bare-metal-install.test.ts +43 -0
  370. package/src/generators/bare-metal-install.ts +249 -0
  371. package/src/generators/caddy.ts +99 -0
  372. package/src/generators/env.ts +405 -0
  373. package/src/generators/grafana.ts +255 -0
  374. package/src/generators/n8n-workflows.ts +88 -0
  375. package/src/generators/native-services.ts +103 -0
  376. package/src/generators/postgres-init.ts +137 -0
  377. package/src/generators/prometheus.ts +89 -0
  378. package/src/generators/readme.ts +274 -0
  379. package/src/generators/scripts.ts +362 -0
  380. package/src/generators/skills.ts +628 -0
  381. package/src/index.ts +118 -0
  382. package/src/presets/registry.test.ts +32 -0
  383. package/src/presets/registry.ts +126 -0
  384. package/src/resolver.test.ts +204 -0
  385. package/src/resolver.ts +282 -0
  386. package/src/schema.test.ts +295 -0
  387. package/src/schema.ts +307 -0
  388. package/src/services/definitions/anything-llm.ts +46 -0
  389. package/src/services/definitions/appflowy.ts +46 -0
  390. package/src/services/definitions/beszel.ts +46 -0
  391. package/src/services/definitions/browserless.ts +84 -0
  392. package/src/services/definitions/caddy.ts +57 -0
  393. package/src/services/definitions/chromadb.ts +68 -0
  394. package/src/services/definitions/claude-code.ts +56 -0
  395. package/src/services/definitions/code-server.ts +67 -0
  396. package/src/services/definitions/codex.ts +48 -0
  397. package/src/services/definitions/coolify.ts +51 -0
  398. package/src/services/definitions/dify.ts +82 -0
  399. package/src/services/definitions/docsgpt.ts +45 -0
  400. package/src/services/definitions/dokploy.ts +51 -0
  401. package/src/services/definitions/dozzle.ts +40 -0
  402. package/src/services/definitions/ffmpeg.ts +70 -0
  403. package/src/services/definitions/flowise.ts +45 -0
  404. package/src/services/definitions/gemini-cli.ts +48 -0
  405. package/src/services/definitions/gitea.ts +52 -0
  406. package/src/services/definitions/gotify.ts +67 -0
  407. package/src/services/definitions/grafana.ts +68 -0
  408. package/src/services/definitions/index.ts +200 -0
  409. package/src/services/definitions/kimi.ts +48 -0
  410. package/src/services/definitions/lasuite-meet-agents.ts +33 -0
  411. package/src/services/definitions/lasuite-meet-backend.ts +125 -0
  412. package/src/services/definitions/lasuite-meet-frontend.ts +38 -0
  413. package/src/services/definitions/librechat.ts +54 -0
  414. package/src/services/definitions/lightpanda.ts +61 -0
  415. package/src/services/definitions/litellm.ts +48 -0
  416. package/src/services/definitions/livekit.ts +38 -0
  417. package/src/services/definitions/matomo.ts +82 -0
  418. package/src/services/definitions/matrix-synapse.ts +89 -0
  419. package/src/services/definitions/mattermost.ts +67 -0
  420. package/src/services/definitions/meilisearch.ts +83 -0
  421. package/src/services/definitions/minio.ts +105 -0
  422. package/src/services/definitions/mixpost.ts +89 -0
  423. package/src/services/definitions/motion-canvas.ts +55 -0
  424. package/src/services/definitions/n8n.ts +153 -0
  425. package/src/services/definitions/nocodb.ts +46 -0
  426. package/src/services/definitions/ntfy.ts +68 -0
  427. package/src/services/definitions/ollama.ts +68 -0
  428. package/src/services/definitions/open-webui.ts +54 -0
  429. package/src/services/definitions/opencode.ts +54 -0
  430. package/src/services/definitions/openpanel.ts +48 -0
  431. package/src/services/definitions/outline.ts +75 -0
  432. package/src/services/definitions/paperless-ngx.ts +92 -0
  433. package/src/services/definitions/playwright-server.ts +41 -0
  434. package/src/services/definitions/portainer.ts +50 -0
  435. package/src/services/definitions/postgresql.ts +90 -0
  436. package/src/services/definitions/postiz.ts +86 -0
  437. package/src/services/definitions/prometheus.ts +54 -0
  438. package/src/services/definitions/qdrant.ts +82 -0
  439. package/src/services/definitions/redis.ts +99 -0
  440. package/src/services/definitions/remotion.ts +55 -0
  441. package/src/services/definitions/rocketchat.ts +61 -0
  442. package/src/services/definitions/searxng.ts +68 -0
  443. package/src/services/definitions/stable-diffusion.ts +50 -0
  444. package/src/services/definitions/steel-browser.ts +70 -0
  445. package/src/services/definitions/tailscale.ts +69 -0
  446. package/src/services/definitions/temporal.ts +104 -0
  447. package/src/services/definitions/traefik.ts +60 -0
  448. package/src/services/definitions/umami.ts +48 -0
  449. package/src/services/definitions/uptime-kuma.ts +53 -0
  450. package/src/services/definitions/valkey.ts +67 -0
  451. package/src/services/definitions/watchtower.ts +47 -0
  452. package/src/services/definitions/weaviate.ts +96 -0
  453. package/src/services/definitions/whisper.ts +62 -0
  454. package/src/services/registry.test.ts +98 -0
  455. package/src/services/registry.ts +37 -0
  456. package/src/skills/registry.ts +126 -0
  457. package/src/types.ts +123 -0
  458. package/src/validator.test.ts +66 -0
  459. package/src/validator.ts +166 -0
  460. package/src/version-manager.ts +65 -0
  461. package/tsconfig.json +9 -0
@@ -0,0 +1,349 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parse } from "yaml";
3
+ import { generate } from "./generate.js";
4
+
5
+ describe("generate (end-to-end)", () => {
6
+ it("generates a minimal stack (redis only)", () => {
7
+ const result = generate({
8
+ projectName: "test-stack",
9
+ services: ["redis"],
10
+ skillPacks: [],
11
+ proxy: "none",
12
+ gpu: false,
13
+ platform: "linux/amd64",
14
+ deployment: "local",
15
+ generateSecrets: true,
16
+ openclawVersion: "latest",
17
+ });
18
+
19
+ // Core files must be present
20
+ expect(result.files).toHaveProperty("docker-compose.yml");
21
+ expect(result.files).toHaveProperty(".env.example");
22
+ expect(result.files).toHaveProperty(".env");
23
+ expect(result.files).toHaveProperty("README.md");
24
+
25
+ // docker-compose.yml must be valid YAML
26
+ const composed = parse(result.files["docker-compose.yml"]!);
27
+ expect(composed).toHaveProperty("services");
28
+
29
+ // .env.example should reference REDIS_PASSWORD
30
+ expect(result.files[".env.example"]).toContain("REDIS_PASSWORD");
31
+
32
+ // README should mention the project name
33
+ expect(result.files["README.md"]).toContain("test-stack");
34
+
35
+ // At least one service resolved
36
+ expect(result.metadata.serviceCount).toBeGreaterThanOrEqual(1);
37
+ });
38
+
39
+ it("generates research-agent stack from skill pack", () => {
40
+ const result = generate({
41
+ projectName: "research-stack",
42
+ services: [],
43
+ skillPacks: ["research-agent"],
44
+ proxy: "none",
45
+ gpu: false,
46
+ platform: "linux/amd64",
47
+ deployment: "local",
48
+ generateSecrets: true,
49
+ openclawVersion: "latest",
50
+ });
51
+
52
+ // Skill SKILL.md files for each skill in the research-agent pack
53
+ expect(result.files).toHaveProperty("openclaw/workspace/skills/qdrant-memory/SKILL.md");
54
+ expect(result.files).toHaveProperty("openclaw/workspace/skills/searxng-search/SKILL.md");
55
+ expect(result.files).toHaveProperty("openclaw/workspace/skills/browserless-browse/SKILL.md");
56
+
57
+ // docker-compose.yml should contain the expected services
58
+ const composed = parse(result.files["docker-compose.yml"]!);
59
+ expect(composed.services).toHaveProperty("qdrant");
60
+ expect(composed.services).toHaveProperty("searxng");
61
+ expect(composed.services).toHaveProperty("browserless");
62
+ });
63
+
64
+ it("generates full preset stack", () => {
65
+ const fullServices = [
66
+ "redis",
67
+ "postgresql",
68
+ "qdrant",
69
+ "n8n",
70
+ "ffmpeg",
71
+ "remotion",
72
+ "minio",
73
+ "caddy",
74
+ "browserless",
75
+ "searxng",
76
+ "meilisearch",
77
+ "uptime-kuma",
78
+ "grafana",
79
+ "prometheus",
80
+ "ollama",
81
+ "whisper",
82
+ "gotify",
83
+ ];
84
+
85
+ const result = generate({
86
+ projectName: "full-stack",
87
+ services: fullServices,
88
+ skillPacks: [
89
+ "video-creator",
90
+ "research-agent",
91
+ "social-media",
92
+ "dev-ops",
93
+ "knowledge-base",
94
+ "local-ai",
95
+ ],
96
+ proxy: "caddy",
97
+ domain: "example.com",
98
+ gpu: false,
99
+ platform: "linux/amd64",
100
+ deployment: "local",
101
+ generateSecrets: true,
102
+ openclawVersion: "latest",
103
+ });
104
+
105
+ // Should have many files
106
+ const fileCount = Object.keys(result.files).length;
107
+ expect(fileCount).toBeGreaterThan(10);
108
+
109
+ // Should include the start script
110
+ expect(result.files).toHaveProperty("scripts/start.sh");
111
+
112
+ // Should not throw (it already didn't if we got here)
113
+ expect(result.metadata.serviceCount).toBeGreaterThan(5);
114
+ });
115
+
116
+ it("generates caddy config when proxy is caddy", () => {
117
+ const result = generate({
118
+ projectName: "caddy-stack",
119
+ services: ["redis"],
120
+ skillPacks: [],
121
+ proxy: "caddy",
122
+ domain: "example.com",
123
+ gpu: false,
124
+ platform: "linux/amd64",
125
+ deployment: "local",
126
+ generateSecrets: true,
127
+ openclawVersion: "latest",
128
+ });
129
+
130
+ expect(result.files).toHaveProperty("caddy/Caddyfile");
131
+ expect(result.files["caddy/Caddyfile"]!.length).toBeGreaterThan(0);
132
+ });
133
+
134
+ it("generates prometheus config when monitoring enabled", () => {
135
+ const result = generate({
136
+ projectName: "monitored-stack",
137
+ services: [],
138
+ skillPacks: [],
139
+ proxy: "none",
140
+ gpu: false,
141
+ platform: "linux/amd64",
142
+ deployment: "local",
143
+ generateSecrets: true,
144
+ openclawVersion: "latest",
145
+ monitoring: true,
146
+ });
147
+
148
+ expect(result.files).toHaveProperty("prometheus/prometheus.yml");
149
+ // Verify it's valid YAML
150
+ const promConfig = parse(result.files["prometheus/prometheus.yml"]!);
151
+ expect(promConfig).toBeDefined();
152
+ });
153
+
154
+ it("generates La Suite Meet stack with all expected services", () => {
155
+ const lasuiteMeetServices = [
156
+ "postgresql",
157
+ "redis",
158
+ "livekit",
159
+ "lasuite-meet-backend",
160
+ "lasuite-meet-frontend",
161
+ "lasuite-meet-agents",
162
+ ];
163
+ const result = generate({
164
+ projectName: "lasuite-meet-stack",
165
+ services: lasuiteMeetServices,
166
+ skillPacks: [],
167
+ proxy: "none",
168
+ gpu: false,
169
+ platform: "linux/amd64",
170
+ deployment: "local",
171
+ generateSecrets: true,
172
+ openclawVersion: "latest",
173
+ });
174
+
175
+ // Services may be split across main and profile compose files
176
+ const allServiceIds = new Set<string>();
177
+ for (const [filename, content] of Object.entries(result.files)) {
178
+ if (filename.endsWith(".yml") && content) {
179
+ const doc = parse(content);
180
+ if (doc?.services && typeof doc.services === "object") {
181
+ for (const id of Object.keys(doc.services)) {
182
+ allServiceIds.add(id);
183
+ }
184
+ }
185
+ }
186
+ }
187
+ for (const id of lasuiteMeetServices) {
188
+ expect(allServiceIds.has(id), `missing service ${id}`).toBe(true);
189
+ }
190
+ expect(result.metadata.serviceCount).toBe(lasuiteMeetServices.length);
191
+ });
192
+
193
+ it("generates bare-metal installer for Windows (install.ps1)", () => {
194
+ const result = generate({
195
+ projectName: "win-stack",
196
+ services: ["redis"],
197
+ skillPacks: [],
198
+ proxy: "none",
199
+ gpu: false,
200
+ platform: "windows/amd64",
201
+ deployment: "local",
202
+ deploymentType: "bare-metal",
203
+ generateSecrets: true,
204
+ openclawVersion: "latest",
205
+ });
206
+ expect(result.files).toHaveProperty("install.ps1");
207
+ expect(result.files["install.ps1"]).toContain("docker compose");
208
+ expect(result.files["install.ps1"]).toContain("PowerShell");
209
+ });
210
+
211
+ it("generates bare-metal installer for Linux/macOS (install.sh)", () => {
212
+ const result = generate({
213
+ projectName: "linux-stack",
214
+ services: ["redis"],
215
+ skillPacks: [],
216
+ proxy: "none",
217
+ gpu: false,
218
+ platform: "linux/amd64",
219
+ deployment: "local",
220
+ deploymentType: "bare-metal",
221
+ generateSecrets: true,
222
+ openclawVersion: "latest",
223
+ });
224
+ expect(result.files).toHaveProperty("install.sh");
225
+ expect(result.files["install.sh"]).toContain("docker");
226
+ expect(result.files["install.sh"]).toContain("compose");
227
+ });
228
+
229
+ it("bare-metal with redis on Linux: native script, compose excludes redis, gateway has extra_hosts", () => {
230
+ const result = generate({
231
+ projectName: "bare-metal-redis",
232
+ services: ["redis"],
233
+ skillPacks: [],
234
+ proxy: "none",
235
+ gpu: false,
236
+ platform: "linux/amd64",
237
+ deployment: "local",
238
+ deploymentType: "bare-metal",
239
+ generateSecrets: true,
240
+ openclawVersion: "latest",
241
+ });
242
+
243
+ // Native install script for Linux
244
+ expect(result.files).toHaveProperty("native/install-linux.sh");
245
+ expect(result.files["native/install-linux.sh"]).toContain("redis");
246
+
247
+ // Docker compose must NOT include redis (native); only gateway/openclaw
248
+ const composed = parse(result.files["docker-compose.yml"]!);
249
+ expect(composed.services).not.toHaveProperty("redis");
250
+ expect(composed.services).toHaveProperty("openclaw-gateway");
251
+
252
+ // Gateway must have extra_hosts for host.docker.internal
253
+ const gateway = composed.services["openclaw-gateway"];
254
+ expect(gateway).toBeDefined();
255
+ expect(gateway.extra_hosts).toBeDefined();
256
+ expect(
257
+ (gateway.extra_hosts as string[]).some(
258
+ (h: string) => h.includes("host.docker.internal") && h.includes("host-gateway"),
259
+ ),
260
+ ).toBe(true);
261
+
262
+ // .env should set REDIS_HOST to host.docker.internal for gateway to reach native Redis
263
+ expect(result.files[".env"]).toContain("REDIS_HOST=host.docker.internal");
264
+ });
265
+
266
+ it("throws on conflicting services", () => {
267
+ expect(() =>
268
+ generate({
269
+ projectName: "conflict-stack",
270
+ services: ["redis", "valkey"],
271
+ skillPacks: [],
272
+ proxy: "none",
273
+ gpu: false,
274
+ platform: "linux/amd64",
275
+ deployment: "local",
276
+ generateSecrets: true,
277
+ openclawVersion: "latest",
278
+ }),
279
+ ).toThrow();
280
+ });
281
+
282
+ it("generates scripts directory", () => {
283
+ const result = generate({
284
+ projectName: "scripts-stack",
285
+ services: ["redis"],
286
+ skillPacks: [],
287
+ proxy: "none",
288
+ gpu: false,
289
+ platform: "linux/amd64",
290
+ deployment: "local",
291
+ generateSecrets: true,
292
+ openclawVersion: "latest",
293
+ });
294
+
295
+ const expectedScripts = [
296
+ "scripts/start.sh",
297
+ "scripts/stop.sh",
298
+ "scripts/update.sh",
299
+ "scripts/backup.sh",
300
+ "scripts/status.sh",
301
+ ];
302
+
303
+ for (const script of expectedScripts) {
304
+ expect(result.files).toHaveProperty(script);
305
+ expect(result.files[script]!.length).toBeGreaterThan(0);
306
+ }
307
+ });
308
+
309
+ it("all generated .env.example vars have comments", () => {
310
+ const result = generate({
311
+ projectName: "env-comments-stack",
312
+ services: ["redis", "qdrant", "n8n"],
313
+ skillPacks: [],
314
+ proxy: "none",
315
+ gpu: false,
316
+ platform: "linux/amd64",
317
+ deployment: "local",
318
+ generateSecrets: true,
319
+ openclawVersion: "latest",
320
+ });
321
+
322
+ const envExample = result.files[".env.example"]!;
323
+ const lines = envExample.split("\n");
324
+
325
+ // Walk through lines: every non-empty, non-comment KEY=VALUE line should
326
+ // have a preceding comment line (starting with #).
327
+ for (let i = 0; i < lines.length; i++) {
328
+ const line = lines[i]!.trim();
329
+ if (line === "" || line.startsWith("#")) continue;
330
+
331
+ // This line looks like KEY=VALUE
332
+ if (line.includes("=")) {
333
+ // There must be a comment somewhere before it (look backwards for a # line)
334
+ let foundComment = false;
335
+ for (let j = i - 1; j >= 0; j--) {
336
+ const prev = lines[j]!.trim();
337
+ if (prev === "") continue; // skip blank lines
338
+ if (prev.startsWith("#")) {
339
+ foundComment = true;
340
+ break;
341
+ }
342
+ // Hit another non-comment, non-empty line — no comment found
343
+ break;
344
+ }
345
+ expect(foundComment).toBe(true);
346
+ }
347
+ }
348
+ });
349
+ });
@@ -0,0 +1,259 @@
1
+ import {
2
+ partitionBareMetal,
3
+ platformToNativePlatform,
4
+ resolvedWithOnlyServices,
5
+ } from "./bare-metal-partition.js";
6
+ import { composeMultiFile } from "./composer.js";
7
+ import { generateBareMetalInstall } from "./generators/bare-metal-install.js";
8
+ import { generateCaddyfile } from "./generators/caddy.js";
9
+ import { generateEnvFiles } from "./generators/env.js";
10
+ import { generateGrafanaConfig, generateGrafanaDashboard } from "./generators/grafana.js";
11
+ import { generateN8nWorkflows } from "./generators/n8n-workflows.js";
12
+ import { generateNativeInstallScripts } from "./generators/native-services.js";
13
+ import { generatePostgresInit } from "./generators/postgres-init.js";
14
+ import { generatePrometheusConfig } from "./generators/prometheus.js";
15
+ import { generateReadme } from "./generators/readme.js";
16
+ import { generateScripts } from "./generators/scripts.js";
17
+ import { generateSkillFiles } from "./generators/skills.js";
18
+ import { resolve } from "./resolver.js";
19
+ import type {
20
+ GeneratedFiles,
21
+ GenerationInput,
22
+ GenerationResult,
23
+ Platform,
24
+ ResolverInput,
25
+ } from "./types.js";
26
+ import { validate } from "./validator.js";
27
+
28
+ /** Resolver/compose only support linux image platforms; normalize for bare-metal (windows/macos). */
29
+ function getComposePlatform(platform: Platform): "linux/amd64" | "linux/arm64" {
30
+ if (platform === "linux/amd64" || platform === "linux/arm64") return platform;
31
+ return "linux/amd64";
32
+ }
33
+
34
+ /**
35
+ * Main orchestration function: takes generation input, resolves dependencies,
36
+ * generates all files, validates, and returns the complete file tree.
37
+ */
38
+ export function generate(input: GenerationInput): GenerationResult {
39
+ const composePlatform = getComposePlatform(input.platform);
40
+
41
+ // 1. Resolve dependencies
42
+ const resolverInput: ResolverInput = {
43
+ services: input.services,
44
+ skillPacks: input.skillPacks,
45
+ proxy: input.proxy,
46
+ gpu: input.gpu,
47
+ platform: composePlatform,
48
+ monitoring: input.monitoring,
49
+ };
50
+ const resolved = resolve(resolverInput);
51
+
52
+ if (!resolved.isValid) {
53
+ throw new Error(
54
+ `Invalid stack configuration: ${resolved.errors.map((e) => e.message).join("; ")}`,
55
+ );
56
+ }
57
+
58
+ const isBareMetal = input.deploymentType === "bare-metal";
59
+ let resolvedForCompose = resolved;
60
+ let nativeIds = new Set<string>();
61
+ let nativeServices: typeof resolved.services = [];
62
+ let dockerOnlyServices: typeof resolved.services = [];
63
+
64
+ if (isBareMetal) {
65
+ const partition = partitionBareMetal(resolved, input.platform);
66
+ nativeServices = partition.nativeServices;
67
+ dockerOnlyServices = partition.dockerOnlyServices;
68
+ nativeIds = partition.nativeIds;
69
+ if (nativeServices.length > 0) {
70
+ resolvedForCompose = resolvedWithOnlyServices(resolved, dockerOnlyServices);
71
+ }
72
+ }
73
+
74
+ // 2. Generate Docker Compose YAML (multi-file)
75
+ const composeOptions = {
76
+ projectName: input.projectName,
77
+ proxy: input.proxy,
78
+ domain: input.domain,
79
+ gpu: input.gpu,
80
+ platform: composePlatform,
81
+ deployment: input.deployment,
82
+ openclawVersion: input.openclawVersion,
83
+ bareMetalNativeHost: isBareMetal && nativeIds.size > 0,
84
+ };
85
+ const composeResult = composeMultiFile(resolvedForCompose, composeOptions);
86
+
87
+ // 3. Validate (using the base docker-compose.yml)
88
+ const validation = validate(resolvedForCompose, composeResult.files["docker-compose.yml"] ?? "", {
89
+ domain: input.domain,
90
+ generateSecrets: input.generateSecrets,
91
+ });
92
+ if (!validation.valid) {
93
+ throw new Error(`Validation failed: ${validation.errors.map((e) => e.message).join("; ")}`);
94
+ }
95
+
96
+ // 4. Generate all files
97
+ const files: GeneratedFiles = {};
98
+
99
+ // Docker Compose (multi-file output)
100
+ for (const [filename, content] of Object.entries(composeResult.files)) {
101
+ files[filename] = content;
102
+ }
103
+
104
+ // Environment files (when bare-metal with native services, host vars use host.docker.internal)
105
+ const envFiles = generateEnvFiles(resolved, {
106
+ generateSecrets: input.generateSecrets,
107
+ domain: input.domain,
108
+ openclawVersion: input.openclawVersion,
109
+ nativeServiceIds: isBareMetal ? nativeIds : undefined,
110
+ });
111
+ files[".env.example"] = envFiles.envExample;
112
+ files[".env"] = envFiles.env;
113
+
114
+ // .gitignore
115
+ files[".gitignore"] = [
116
+ ".env",
117
+ ".env.local",
118
+ ".env.*.local",
119
+ "*.log",
120
+ "docker-compose.override.yml",
121
+ ].join("\n");
122
+
123
+ // Skills
124
+ const skillFiles = generateSkillFiles(resolved);
125
+ for (const [path, content] of Object.entries(skillFiles)) {
126
+ files[path] = content;
127
+ }
128
+
129
+ // README
130
+ files["README.md"] = generateReadme(resolved, {
131
+ projectName: input.projectName,
132
+ domain: input.domain,
133
+ proxy: input.proxy,
134
+ deploymentType: input.deploymentType,
135
+ hasNativeServices: isBareMetal && nativeServices.length > 0,
136
+ });
137
+
138
+ // Scripts
139
+ const scripts = generateScripts();
140
+ for (const [path, content] of Object.entries(scripts)) {
141
+ files[path] = content;
142
+ }
143
+
144
+ // n8n workflows
145
+ const n8nWorkflows = generateN8nWorkflows(resolved);
146
+ for (const [path, content] of Object.entries(n8nWorkflows)) {
147
+ files[path] = content;
148
+ }
149
+
150
+ // PostgreSQL init script (creates per-service databases and users)
151
+ const postgresInit = generatePostgresInit(resolved);
152
+ if (postgresInit) {
153
+ files["postgres/init-databases.sh"] = postgresInit;
154
+ }
155
+
156
+ // Caddy config
157
+ if (input.proxy === "caddy" && input.domain) {
158
+ files["caddy/Caddyfile"] = generateCaddyfile(resolved, input.domain);
159
+ }
160
+
161
+ // Prometheus config
162
+ const hasPrometheus = resolved.services.some((s) => s.definition.id === "prometheus");
163
+ if (hasPrometheus) {
164
+ files["prometheus/prometheus.yml"] = generatePrometheusConfig(resolved);
165
+ }
166
+
167
+ // Grafana config
168
+ const hasGrafana = resolved.services.some((s) => s.definition.id === "grafana");
169
+ if (hasGrafana) {
170
+ const grafanaFiles = generateGrafanaConfig();
171
+ for (const [path, content] of Object.entries(grafanaFiles)) {
172
+ files[path] = content;
173
+ }
174
+ // Grafana dashboard
175
+ files["config/grafana/dashboards/openclaw-stack-overview.json"] = generateGrafanaDashboard();
176
+ }
177
+
178
+ // Docker Compose override (empty template)
179
+ files["docker-compose.override.yml"] = [
180
+ "# Local overrides for docker-compose.yml",
181
+ "# This file is gitignored — use it for personal port changes, extra volumes, etc.",
182
+ "services: {}",
183
+ "",
184
+ ].join("\n");
185
+
186
+ // SERVICES.md documentation
187
+ files["docs/SERVICES.md"] = generateServicesDoc(resolved);
188
+
189
+ // Bare-metal: native install scripts + top-level installer
190
+ if (isBareMetal) {
191
+ if (nativeServices.length > 0) {
192
+ const nativePlatform = platformToNativePlatform(input.platform);
193
+ const nativeScripts = generateNativeInstallScripts({
194
+ nativeServices,
195
+ platform: nativePlatform,
196
+ projectName: input.projectName,
197
+ });
198
+ for (const [path, content] of Object.entries(nativeScripts)) {
199
+ files[path] = content;
200
+ }
201
+ }
202
+ const bareMetalFiles = generateBareMetalInstall({
203
+ platform: input.platform,
204
+ projectName: input.projectName,
205
+ hasNativeServices: nativeServices.length > 0,
206
+ });
207
+ for (const [path, content] of Object.entries(bareMetalFiles)) {
208
+ files[path] = content;
209
+ }
210
+ }
211
+
212
+ // 5. Calculate metadata
213
+ const skillCount = resolved.services.reduce((sum, s) => sum + s.definition.skills.length, 0);
214
+
215
+ return {
216
+ files,
217
+ metadata: {
218
+ serviceCount: resolved.services.length,
219
+ skillCount,
220
+ estimatedMemoryMB: resolved.estimatedMemoryMB,
221
+ generatedAt: new Date().toISOString(),
222
+ },
223
+ };
224
+ }
225
+
226
+ function generateServicesDoc(resolved: import("./types.js").ResolverOutput): string {
227
+ const lines: string[] = [
228
+ "# Service Reference",
229
+ "",
230
+ "This document describes all companion services in your OpenClaw stack.",
231
+ "",
232
+ ];
233
+
234
+ for (const svc of resolved.services) {
235
+ const def = svc.definition;
236
+ lines.push(`## ${def.icon} ${def.name}`);
237
+ lines.push("");
238
+ lines.push(def.description);
239
+ lines.push("");
240
+ lines.push(`- **Image**: \`${def.image}:${def.imageTag}\``);
241
+ lines.push(`- **Category**: ${def.category}`);
242
+ lines.push(`- **Maturity**: ${def.maturity}`);
243
+ if (def.minMemoryMB) {
244
+ lines.push(`- **Min Memory**: ${def.minMemoryMB}MB`);
245
+ }
246
+ if (def.ports.length > 0) {
247
+ lines.push("- **Ports**:");
248
+ for (const p of def.ports) {
249
+ lines.push(
250
+ ` - \`${p.container}\` — ${p.description}${p.exposed ? "" : " (internal only)"}`,
251
+ );
252
+ }
253
+ }
254
+ lines.push(`- **Docs**: ${def.docsUrl}`);
255
+ lines.push("");
256
+ }
257
+
258
+ return lines.join("\n");
259
+ }
@@ -0,0 +1,43 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { generateBareMetalInstall } from "./bare-metal-install.js";
3
+
4
+ describe("generateBareMetalInstall", () => {
5
+ it("returns install.ps1 for windows/amd64", () => {
6
+ const result = generateBareMetalInstall({
7
+ platform: "windows/amd64",
8
+ projectName: "my-stack",
9
+ });
10
+ expect(result).toHaveProperty("install.ps1");
11
+ expect(Object.keys(result)).toHaveLength(1);
12
+ expect(result["install.ps1"]).toContain("docker compose");
13
+ expect(result["install.ps1"]).toContain("PowerShell");
14
+ });
15
+
16
+ it("returns install.sh for linux/amd64", () => {
17
+ const result = generateBareMetalInstall({
18
+ platform: "linux/amd64",
19
+ projectName: "my-stack",
20
+ });
21
+ expect(result).toHaveProperty("install.sh");
22
+ expect(Object.keys(result)).toHaveLength(1);
23
+ expect(result["install.sh"]).toContain("docker");
24
+ expect(result["install.sh"]).toContain("compose");
25
+ });
26
+
27
+ it("returns install.sh for linux/arm64", () => {
28
+ const result = generateBareMetalInstall({
29
+ platform: "linux/arm64",
30
+ projectName: "my-stack",
31
+ });
32
+ expect(result).toHaveProperty("install.sh");
33
+ expect(result["install.sh"]).toContain("docker");
34
+ });
35
+
36
+ it("returns install.sh for macos/amd64 and macos/arm64", () => {
37
+ for (const platform of ["macos/amd64", "macos/arm64"] as const) {
38
+ const result = generateBareMetalInstall({ platform, projectName: "my-stack" });
39
+ expect(result).toHaveProperty("install.sh");
40
+ expect(result["install.sh"]).toContain("Docker");
41
+ }
42
+ });
43
+ });