@better-openclaw/core 1.0.24 → 1.0.25

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 (170) hide show
  1. package/dist/addon-stack.cjs +673 -0
  2. package/dist/addon-stack.cjs.map +1 -0
  3. package/dist/addon-stack.d.cts +23 -0
  4. package/dist/addon-stack.d.cts.map +1 -0
  5. package/dist/addon-stack.d.mts +23 -0
  6. package/dist/addon-stack.d.mts.map +1 -0
  7. package/dist/addon-stack.mjs +671 -0
  8. package/dist/addon-stack.mjs.map +1 -0
  9. package/dist/addon-stack.test.cjs +349 -0
  10. package/dist/addon-stack.test.cjs.map +1 -0
  11. package/dist/addon-stack.test.d.cts +1 -0
  12. package/dist/addon-stack.test.d.mts +1 -0
  13. package/dist/addon-stack.test.mjs +349 -0
  14. package/dist/addon-stack.test.mjs.map +1 -0
  15. package/dist/bare-metal-partition.test.cjs +20 -20
  16. package/dist/bare-metal-partition.test.cjs.map +1 -1
  17. package/dist/bare-metal-partition.test.mjs +2 -2
  18. package/dist/composer.cjs +4 -0
  19. package/dist/composer.cjs.map +1 -1
  20. package/dist/composer.d.cts +24 -1
  21. package/dist/composer.d.cts.map +1 -1
  22. package/dist/composer.d.mts +24 -1
  23. package/dist/composer.d.mts.map +1 -1
  24. package/dist/composer.mjs +1 -1
  25. package/dist/composer.mjs.map +1 -1
  26. package/dist/composer.snapshot.test.cjs +20 -20
  27. package/dist/composer.snapshot.test.cjs.map +1 -1
  28. package/dist/composer.snapshot.test.mjs +2 -2
  29. package/dist/composer.test.cjs +53 -53
  30. package/dist/composer.test.cjs.map +1 -1
  31. package/dist/composer.test.mjs +2 -2
  32. package/dist/deployers/strip-host-ports.test.cjs +26 -26
  33. package/dist/deployers/strip-host-ports.test.cjs.map +1 -1
  34. package/dist/deployers/strip-host-ports.test.mjs +1 -1
  35. package/dist/generate.cjs +2 -2
  36. package/dist/generate.mjs +3 -3
  37. package/dist/generate.test.cjs +55 -55
  38. package/dist/generate.test.cjs.map +1 -1
  39. package/dist/generate.test.mjs +1 -1
  40. package/dist/generators/bare-metal-install.test.cjs +18 -18
  41. package/dist/generators/bare-metal-install.test.cjs.map +1 -1
  42. package/dist/generators/bare-metal-install.test.mjs +1 -1
  43. package/dist/generators/caddy.test.cjs +13 -13
  44. package/dist/generators/caddy.test.cjs.map +1 -1
  45. package/dist/generators/caddy.test.mjs +1 -1
  46. package/dist/generators/clone-repos.test.cjs +27 -27
  47. package/dist/generators/clone-repos.test.cjs.map +1 -1
  48. package/dist/generators/clone-repos.test.mjs +1 -1
  49. package/dist/generators/env.test.cjs +17 -17
  50. package/dist/generators/env.test.cjs.map +1 -1
  51. package/dist/generators/env.test.mjs +1 -1
  52. package/dist/generators/health-check.test.cjs +39 -39
  53. package/dist/generators/health-check.test.cjs.map +1 -1
  54. package/dist/generators/health-check.test.mjs +1 -1
  55. package/dist/generators/scripts.test.cjs +39 -39
  56. package/dist/generators/scripts.test.cjs.map +1 -1
  57. package/dist/generators/scripts.test.mjs +1 -1
  58. package/dist/generators/traefik.test.cjs +32 -32
  59. package/dist/generators/traefik.test.cjs.map +1 -1
  60. package/dist/generators/traefik.test.mjs +1 -1
  61. package/dist/index.cjs +20 -4
  62. package/dist/index.d.cts +5 -4
  63. package/dist/index.d.mts +5 -4
  64. package/dist/index.mjs +7 -6
  65. package/dist/migrations.test.cjs +16 -16
  66. package/dist/migrations.test.cjs.map +1 -1
  67. package/dist/migrations.test.mjs +1 -1
  68. package/dist/presets/registry.test.cjs +14 -14
  69. package/dist/presets/registry.test.cjs.map +1 -1
  70. package/dist/presets/registry.test.mjs +1 -1
  71. package/dist/resolver.test.cjs +95 -95
  72. package/dist/resolver.test.cjs.map +1 -1
  73. package/dist/resolver.test.mjs +1 -1
  74. package/dist/{schema-eX44HhRp.d.mts → schema-CKBRu-Rt.d.cts} +295 -2
  75. package/dist/schema-CKBRu-Rt.d.cts.map +1 -0
  76. package/dist/{schema-tn5RK8CM.d.cts → schema-Dn-_Jpb6.d.mts} +295 -2
  77. package/dist/schema-Dn-_Jpb6.d.mts.map +1 -0
  78. package/dist/schema.cjs +138 -1
  79. package/dist/schema.cjs.map +1 -1
  80. package/dist/schema.d.cts +2 -2
  81. package/dist/schema.d.mts +2 -2
  82. package/dist/schema.mjs +130 -2
  83. package/dist/schema.mjs.map +1 -1
  84. package/dist/schema.test.cjs +86 -86
  85. package/dist/schema.test.cjs.map +1 -1
  86. package/dist/schema.test.mjs +1 -1
  87. package/dist/services/definitions/browserless.cjs +4 -1
  88. package/dist/services/definitions/browserless.cjs.map +1 -1
  89. package/dist/services/definitions/browserless.mjs +4 -1
  90. package/dist/services/definitions/browserless.mjs.map +1 -1
  91. package/dist/services/definitions/convex.cjs +43 -1
  92. package/dist/services/definitions/convex.cjs.map +1 -1
  93. package/dist/services/definitions/convex.mjs +43 -1
  94. package/dist/services/definitions/convex.mjs.map +1 -1
  95. package/dist/services/definitions/grafana.cjs +11 -1
  96. package/dist/services/definitions/grafana.cjs.map +1 -1
  97. package/dist/services/definitions/grafana.mjs +11 -1
  98. package/dist/services/definitions/grafana.mjs.map +1 -1
  99. package/dist/services/definitions/meilisearch.cjs +11 -1
  100. package/dist/services/definitions/meilisearch.cjs.map +1 -1
  101. package/dist/services/definitions/meilisearch.mjs +11 -1
  102. package/dist/services/definitions/meilisearch.mjs.map +1 -1
  103. package/dist/services/definitions/minio.cjs +3 -1
  104. package/dist/services/definitions/minio.cjs.map +1 -1
  105. package/dist/services/definitions/minio.mjs +3 -1
  106. package/dist/services/definitions/minio.mjs.map +1 -1
  107. package/dist/services/definitions/n8n.cjs +11 -1
  108. package/dist/services/definitions/n8n.cjs.map +1 -1
  109. package/dist/services/definitions/n8n.mjs +11 -1
  110. package/dist/services/definitions/n8n.mjs.map +1 -1
  111. package/dist/services/definitions/ollama.cjs +3 -1
  112. package/dist/services/definitions/ollama.cjs.map +1 -1
  113. package/dist/services/definitions/ollama.mjs +3 -1
  114. package/dist/services/definitions/ollama.mjs.map +1 -1
  115. package/dist/services/definitions/qdrant.cjs +3 -1
  116. package/dist/services/definitions/qdrant.cjs.map +1 -1
  117. package/dist/services/definitions/qdrant.mjs +3 -1
  118. package/dist/services/definitions/qdrant.mjs.map +1 -1
  119. package/dist/services/definitions/searxng.cjs +8 -1
  120. package/dist/services/definitions/searxng.cjs.map +1 -1
  121. package/dist/services/definitions/searxng.mjs +8 -1
  122. package/dist/services/definitions/searxng.mjs.map +1 -1
  123. package/dist/services/definitions/uptime-kuma.cjs +8 -1
  124. package/dist/services/definitions/uptime-kuma.cjs.map +1 -1
  125. package/dist/services/definitions/uptime-kuma.mjs +8 -1
  126. package/dist/services/definitions/uptime-kuma.mjs.map +1 -1
  127. package/dist/services/registry.test.cjs +36 -36
  128. package/dist/services/registry.test.cjs.map +1 -1
  129. package/dist/services/registry.test.mjs +1 -1
  130. package/dist/{vi.2VT5v0um-C_jmO7m2.mjs → test.CTcmp4Su-ClCHJ3FA.mjs} +6793 -6403
  131. package/dist/test.CTcmp4Su-ClCHJ3FA.mjs.map +1 -0
  132. package/dist/{vi.2VT5v0um-iVBt6Fyq.cjs → test.CTcmp4Su-DlzTarwH.cjs} +6793 -6403
  133. package/dist/test.CTcmp4Su-DlzTarwH.cjs.map +1 -0
  134. package/dist/track-analytics.test.cjs +28 -28
  135. package/dist/track-analytics.test.cjs.map +1 -1
  136. package/dist/track-analytics.test.mjs +1 -1
  137. package/dist/types.cjs.map +1 -1
  138. package/dist/types.d.cts +10 -2
  139. package/dist/types.d.cts.map +1 -1
  140. package/dist/types.d.mts +10 -2
  141. package/dist/types.d.mts.map +1 -1
  142. package/dist/types.mjs.map +1 -1
  143. package/dist/validator.test.cjs +15 -15
  144. package/dist/validator.test.cjs.map +1 -1
  145. package/dist/validator.test.mjs +2 -2
  146. package/dist/version-manager.test.cjs +37 -37
  147. package/dist/version-manager.test.cjs.map +1 -1
  148. package/dist/version-manager.test.mjs +1 -1
  149. package/package.json +4 -4
  150. package/src/__snapshots__/composer.snapshot.test.ts.snap +5 -0
  151. package/src/addon-stack.test.ts +490 -0
  152. package/src/addon-stack.ts +998 -0
  153. package/src/composer.ts +4 -4
  154. package/src/index.ts +20 -2
  155. package/src/schema.ts +183 -0
  156. package/src/services/definitions/browserless.ts +3 -0
  157. package/src/services/definitions/convex.ts +31 -0
  158. package/src/services/definitions/grafana.ts +9 -0
  159. package/src/services/definitions/meilisearch.ts +9 -0
  160. package/src/services/definitions/minio.ts +2 -0
  161. package/src/services/definitions/n8n.ts +9 -0
  162. package/src/services/definitions/ollama.ts +2 -0
  163. package/src/services/definitions/qdrant.ts +2 -0
  164. package/src/services/definitions/searxng.ts +3 -0
  165. package/src/services/definitions/uptime-kuma.ts +3 -0
  166. package/src/types.ts +18 -0
  167. package/dist/schema-eX44HhRp.d.mts.map +0 -1
  168. package/dist/schema-tn5RK8CM.d.cts.map +0 -1
  169. package/dist/vi.2VT5v0um-C_jmO7m2.mjs.map +0 -1
  170. package/dist/vi.2VT5v0um-iVBt6Fyq.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"composer.snapshot.test.cjs","names":["composeMultiFile","resolve","describe"],"sources":["../src/composer.snapshot.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { composeMultiFile } from \"./composer.js\";\nimport { resolve } from \"./resolver.js\";\n\nfunction generateForPreset(services: string[], skillPacks: string[] = []) {\n\tconst resolved = resolve({ services, skillPacks });\n\treturn composeMultiFile(resolved, {\n\t\tprojectName: \"test-stack\",\n\t\tproxy: \"none\",\n\t\tgpu: false,\n\t\tplatform: \"linux/amd64\",\n\t\tdeployment: \"local\",\n\t\topenclawVersion: \"latest\",\n\t});\n}\n\ndescribe(\"compose snapshot tests\", () => {\n\tit(\"minimal preset (redis only)\", () => {\n\t\tconst result = generateForPreset([\"redis\"]);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t});\n\n\tit(\"creator preset (ffmpeg + remotion + minio + redis)\", () => {\n\t\tconst result = generateForPreset([\"ffmpeg\", \"remotion\", \"minio\", \"redis\"], [\"video-creator\"]);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t\tif (result.files[\"docker-compose.media.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.media.yml\"]).toMatchSnapshot();\n\t\t}\n\t});\n\n\tit(\"researcher preset (qdrant + searxng + browserless + redis)\", () => {\n\t\tconst result = generateForPreset(\n\t\t\t[\"qdrant\", \"searxng\", \"browserless\", \"redis\"],\n\t\t\t[\"research-agent\"],\n\t\t);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t});\n\n\tit(\"devops preset (n8n + postgresql + redis + monitoring)\", () => {\n\t\tconst result = generateForPreset(\n\t\t\t[\"n8n\", \"postgresql\", \"redis\", \"uptime-kuma\", \"grafana\", \"prometheus\"],\n\t\t\t[\"dev-ops\"],\n\t\t);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t\tif (result.files[\"docker-compose.monitoring.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.monitoring.yml\"]).toMatchSnapshot();\n\t\t}\n\t});\n\n\tit(\"full preset (many services)\", () => {\n\t\tconst result = generateForPreset([\n\t\t\t\"redis\",\n\t\t\t\"postgresql\",\n\t\t\t\"qdrant\",\n\t\t\t\"n8n\",\n\t\t\t\"ffmpeg\",\n\t\t\t\"remotion\",\n\t\t\t\"minio\",\n\t\t\t\"caddy\",\n\t\t\t\"browserless\",\n\t\t\t\"searxng\",\n\t\t\t\"meilisearch\",\n\t\t\t\"uptime-kuma\",\n\t\t\t\"grafana\",\n\t\t\t\"prometheus\",\n\t\t\t\"ollama\",\n\t\t\t\"whisper\",\n\t\t\t\"gotify\",\n\t\t]);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t\texpect(result.profiles.length).toBeGreaterThan(0);\n\t\t// Verify multiple compose files were created\n\t\texpect(Object.keys(result.files).length).toBeGreaterThan(1);\n\t});\n\n\tit(\"multi-file output has correct profile assignments\", () => {\n\t\tconst result = generateForPreset([\"redis\", \"ollama\", \"open-webui\", \"grafana\", \"prometheus\"]);\n\t\t// AI services should be in the ai profile file\n\t\tif (result.files[\"docker-compose.ai.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.ai.yml\"]).toContain(\"profiles:\");\n\t\t}\n\t\t// Monitoring should be in the monitoring profile file\n\t\tif (result.files[\"docker-compose.monitoring.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.monitoring.yml\"]).toContain(\"profiles:\");\n\t\t}\n\t});\n});\n"],"mappings":";;;;AAIA,SAAS,kBAAkB,UAAoB,aAAuB,EAAE,EAAE;AAEzE,QAAOA,iBAAAA,iBADUC,iBAAAA,QAAQ;EAAE;EAAU;EAAY,CAAC,EAChB;EACjC,aAAa;EACb,OAAO;EACP,KAAK;EACL,UAAU;EACV,YAAY;EACZ,iBAAiB;EACjB,CAAC;;AAGHC,oBAAAA,SAAS,gCAAgC;AACxC,qBAAA,GAAG,qCAAqC;AAEvC,sBAAA,aADe,kBAAkB,CAAC,QAAQ,CAAC,CAC7B,MAAM,sBAAsB,CAAC,iBAAiB;GAC3D;AAEF,qBAAA,GAAG,4DAA4D;EAC9D,MAAM,SAAS,kBAAkB;GAAC;GAAU;GAAY;GAAS;GAAQ,EAAE,CAAC,gBAAgB,CAAC;AAC7F,sBAAA,aAAO,OAAO,MAAM,sBAAsB,CAAC,iBAAiB;AAC5D,MAAI,OAAO,MAAM,4BAChB,qBAAA,aAAO,OAAO,MAAM,4BAA4B,CAAC,iBAAiB;GAElE;AAEF,qBAAA,GAAG,oEAAoE;AAKtE,sBAAA,aAJe,kBACd;GAAC;GAAU;GAAW;GAAe;GAAQ,EAC7C,CAAC,iBAAiB,CAClB,CACa,MAAM,sBAAsB,CAAC,iBAAiB;GAC3D;AAEF,qBAAA,GAAG,+DAA+D;EACjE,MAAM,SAAS,kBACd;GAAC;GAAO;GAAc;GAAS;GAAe;GAAW;GAAa,EACtE,CAAC,UAAU,CACX;AACD,sBAAA,aAAO,OAAO,MAAM,sBAAsB,CAAC,iBAAiB;AAC5D,MAAI,OAAO,MAAM,iCAChB,qBAAA,aAAO,OAAO,MAAM,iCAAiC,CAAC,iBAAiB;GAEvE;AAEF,qBAAA,GAAG,qCAAqC;EACvC,MAAM,SAAS,kBAAkB;GAChC;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,CAAC;AACF,sBAAA,aAAO,OAAO,MAAM,sBAAsB,CAAC,iBAAiB;AAC5D,sBAAA,aAAO,OAAO,SAAS,OAAO,CAAC,gBAAgB,EAAE;AAEjD,sBAAA,aAAO,OAAO,KAAK,OAAO,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE;GAC1D;AAEF,qBAAA,GAAG,2DAA2D;EAC7D,MAAM,SAAS,kBAAkB;GAAC;GAAS;GAAU;GAAc;GAAW;GAAa,CAAC;AAE5F,MAAI,OAAO,MAAM,yBAChB,qBAAA,aAAO,OAAO,MAAM,yBAAyB,CAAC,UAAU,YAAY;AAGrE,MAAI,OAAO,MAAM,iCAChB,qBAAA,aAAO,OAAO,MAAM,iCAAiC,CAAC,UAAU,YAAY;GAE5E;EACD"}
1
+ {"version":3,"file":"composer.snapshot.test.cjs","names":["composeMultiFile","resolve","describe"],"sources":["../src/composer.snapshot.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { composeMultiFile } from \"./composer.js\";\nimport { resolve } from \"./resolver.js\";\n\nfunction generateForPreset(services: string[], skillPacks: string[] = []) {\n\tconst resolved = resolve({ services, skillPacks });\n\treturn composeMultiFile(resolved, {\n\t\tprojectName: \"test-stack\",\n\t\tproxy: \"none\",\n\t\tgpu: false,\n\t\tplatform: \"linux/amd64\",\n\t\tdeployment: \"local\",\n\t\topenclawVersion: \"latest\",\n\t});\n}\n\ndescribe(\"compose snapshot tests\", () => {\n\tit(\"minimal preset (redis only)\", () => {\n\t\tconst result = generateForPreset([\"redis\"]);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t});\n\n\tit(\"creator preset (ffmpeg + remotion + minio + redis)\", () => {\n\t\tconst result = generateForPreset([\"ffmpeg\", \"remotion\", \"minio\", \"redis\"], [\"video-creator\"]);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t\tif (result.files[\"docker-compose.media.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.media.yml\"]).toMatchSnapshot();\n\t\t}\n\t});\n\n\tit(\"researcher preset (qdrant + searxng + browserless + redis)\", () => {\n\t\tconst result = generateForPreset(\n\t\t\t[\"qdrant\", \"searxng\", \"browserless\", \"redis\"],\n\t\t\t[\"research-agent\"],\n\t\t);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t});\n\n\tit(\"devops preset (n8n + postgresql + redis + monitoring)\", () => {\n\t\tconst result = generateForPreset(\n\t\t\t[\"n8n\", \"postgresql\", \"redis\", \"uptime-kuma\", \"grafana\", \"prometheus\"],\n\t\t\t[\"dev-ops\"],\n\t\t);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t\tif (result.files[\"docker-compose.monitoring.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.monitoring.yml\"]).toMatchSnapshot();\n\t\t}\n\t});\n\n\tit(\"full preset (many services)\", () => {\n\t\tconst result = generateForPreset([\n\t\t\t\"redis\",\n\t\t\t\"postgresql\",\n\t\t\t\"qdrant\",\n\t\t\t\"n8n\",\n\t\t\t\"ffmpeg\",\n\t\t\t\"remotion\",\n\t\t\t\"minio\",\n\t\t\t\"caddy\",\n\t\t\t\"browserless\",\n\t\t\t\"searxng\",\n\t\t\t\"meilisearch\",\n\t\t\t\"uptime-kuma\",\n\t\t\t\"grafana\",\n\t\t\t\"prometheus\",\n\t\t\t\"ollama\",\n\t\t\t\"whisper\",\n\t\t\t\"gotify\",\n\t\t]);\n\t\texpect(result.files[\"docker-compose.yml\"]).toMatchSnapshot();\n\t\texpect(result.profiles.length).toBeGreaterThan(0);\n\t\t// Verify multiple compose files were created\n\t\texpect(Object.keys(result.files).length).toBeGreaterThan(1);\n\t});\n\n\tit(\"multi-file output has correct profile assignments\", () => {\n\t\tconst result = generateForPreset([\"redis\", \"ollama\", \"open-webui\", \"grafana\", \"prometheus\"]);\n\t\t// AI services should be in the ai profile file\n\t\tif (result.files[\"docker-compose.ai.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.ai.yml\"]).toContain(\"profiles:\");\n\t\t}\n\t\t// Monitoring should be in the monitoring profile file\n\t\tif (result.files[\"docker-compose.monitoring.yml\"]) {\n\t\t\texpect(result.files[\"docker-compose.monitoring.yml\"]).toContain(\"profiles:\");\n\t\t}\n\t});\n});\n"],"mappings":";;;;AAIA,SAAS,kBAAkB,UAAoB,aAAuB,EAAE,EAAE;AAEzE,QAAOA,iBAAAA,iBADUC,iBAAAA,QAAQ;EAAE;EAAU;EAAY,CAAC,EAChB;EACjC,aAAa;EACb,OAAO;EACP,KAAK;EACL,UAAU;EACV,YAAY;EACZ,iBAAiB;EACjB,CAAC;;AAGHC,sBAAAA,SAAS,gCAAgC;AACxC,uBAAA,GAAG,qCAAqC;AAEvC,wBAAA,aADe,kBAAkB,CAAC,QAAQ,CAAC,CAC7B,MAAM,sBAAsB,CAAC,iBAAiB;GAC3D;AAEF,uBAAA,GAAG,4DAA4D;EAC9D,MAAM,SAAS,kBAAkB;GAAC;GAAU;GAAY;GAAS;GAAQ,EAAE,CAAC,gBAAgB,CAAC;AAC7F,wBAAA,aAAO,OAAO,MAAM,sBAAsB,CAAC,iBAAiB;AAC5D,MAAI,OAAO,MAAM,4BAChB,uBAAA,aAAO,OAAO,MAAM,4BAA4B,CAAC,iBAAiB;GAElE;AAEF,uBAAA,GAAG,oEAAoE;AAKtE,wBAAA,aAJe,kBACd;GAAC;GAAU;GAAW;GAAe;GAAQ,EAC7C,CAAC,iBAAiB,CAClB,CACa,MAAM,sBAAsB,CAAC,iBAAiB;GAC3D;AAEF,uBAAA,GAAG,+DAA+D;EACjE,MAAM,SAAS,kBACd;GAAC;GAAO;GAAc;GAAS;GAAe;GAAW;GAAa,EACtE,CAAC,UAAU,CACX;AACD,wBAAA,aAAO,OAAO,MAAM,sBAAsB,CAAC,iBAAiB;AAC5D,MAAI,OAAO,MAAM,iCAChB,uBAAA,aAAO,OAAO,MAAM,iCAAiC,CAAC,iBAAiB;GAEvE;AAEF,uBAAA,GAAG,qCAAqC;EACvC,MAAM,SAAS,kBAAkB;GAChC;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,CAAC;AACF,wBAAA,aAAO,OAAO,MAAM,sBAAsB,CAAC,iBAAiB;AAC5D,wBAAA,aAAO,OAAO,SAAS,OAAO,CAAC,gBAAgB,EAAE;AAEjD,wBAAA,aAAO,OAAO,KAAK,OAAO,MAAM,CAAC,OAAO,CAAC,gBAAgB,EAAE;GAC1D;AAEF,uBAAA,GAAG,2DAA2D;EAC7D,MAAM,SAAS,kBAAkB;GAAC;GAAS;GAAU;GAAc;GAAW;GAAa,CAAC;AAE5F,MAAI,OAAO,MAAM,yBAChB,uBAAA,aAAO,OAAO,MAAM,yBAAyB,CAAC,UAAU,YAAY;AAGrE,MAAI,OAAO,MAAM,iCAChB,uBAAA,aAAO,OAAO,MAAM,iCAAiC,CAAC,UAAU,YAAY;GAE5E;EACD"}
@@ -1,6 +1,6 @@
1
- import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-C_jmO7m2.mjs";
2
- import { resolve } from "./resolver.mjs";
1
+ import { n as describe, r as it, t as globalExpect } from "./test.CTcmp4Su-ClCHJ3FA.mjs";
3
2
  import { composeMultiFile } from "./composer.mjs";
3
+ import { resolve } from "./resolver.mjs";
4
4
  //#region src/composer.snapshot.test.ts
5
5
  function generateForPreset(services, skillPacks = []) {
6
6
  return composeMultiFile(resolve({
@@ -1,7 +1,7 @@
1
1
  require("./skills-BlzpHmpH.cjs");
2
- const require_vi_2VT5v0um = require("./vi.2VT5v0um-iVBt6Fyq.cjs");
3
- const require_resolver = require("./resolver.cjs");
2
+ const require_test_CTcmp4Su = require("./test.CTcmp4Su-DlzTarwH.cjs");
4
3
  const require_composer = require("./composer.cjs");
4
+ const require_resolver = require("./resolver.cjs");
5
5
  let yaml = require("yaml");
6
6
  //#region src/composer.test.ts
7
7
  const defaultOptions = {
@@ -12,58 +12,58 @@ const defaultOptions = {
12
12
  deployment: "local",
13
13
  openclawVersion: "latest"
14
14
  };
15
- require_vi_2VT5v0um.describe("compose", () => {
16
- require_vi_2VT5v0um.it("generates minimal stack with just OpenClaw gateway when no companions", () => {
15
+ require_test_CTcmp4Su.describe("compose", () => {
16
+ require_test_CTcmp4Su.it("generates minimal stack with just OpenClaw gateway when no companions", () => {
17
17
  const parsed = (0, yaml.parse)(require_composer.compose(require_resolver.resolve({
18
18
  services: [],
19
19
  skillPacks: []
20
20
  }), defaultOptions));
21
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("openclaw-gateway");
22
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].image).toContain("ghcr.io/openclaw/openclaw");
23
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].environment.HOME).toBe("/home/node");
24
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].environment.TERM).toBe("xterm-256color");
21
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("openclaw-gateway");
22
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].image).toContain("ghcr.io/openclaw/openclaw");
23
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].environment.HOME).toBe("/home/node");
24
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].environment.TERM).toBe("xterm-256color");
25
25
  const gwVolumes = parsed.services["openclaw-gateway"].volumes;
26
- require_vi_2VT5v0um.globalExpect(gwVolumes.some((v) => v.includes(".openclaw"))).toBe(true);
27
- require_vi_2VT5v0um.globalExpect(parsed.networks).toHaveProperty("openclaw-network");
28
- require_vi_2VT5v0um.globalExpect(parsed.networks["openclaw-network"].driver).toBe("bridge");
29
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("openclaw-cli");
30
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("convex");
31
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("mission-control");
32
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].restart).toBe("unless-stopped");
26
+ require_test_CTcmp4Su.globalExpect(gwVolumes.some((v) => v.includes(".openclaw"))).toBe(true);
27
+ require_test_CTcmp4Su.globalExpect(parsed.networks).toHaveProperty("openclaw-network");
28
+ require_test_CTcmp4Su.globalExpect(parsed.networks["openclaw-network"].driver).toBe("bridge");
29
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("openclaw-cli");
30
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("convex");
31
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("mission-control");
32
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].restart).toBe("unless-stopped");
33
33
  });
34
- require_vi_2VT5v0um.it("generates Redis companion with proper gateway depends_on", () => {
34
+ require_test_CTcmp4Su.it("generates Redis companion with proper gateway depends_on", () => {
35
35
  const parsed = (0, yaml.parse)(require_composer.compose(require_resolver.resolve({
36
36
  services: ["redis"],
37
37
  skillPacks: []
38
38
  }), defaultOptions));
39
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("openclaw-gateway");
40
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("redis");
41
- require_vi_2VT5v0um.globalExpect(parsed.services.redis.image).toBe("redis:8-alpine");
42
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].depends_on).toHaveProperty("redis");
43
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].depends_on.redis.condition).toBe("service_healthy");
44
- require_vi_2VT5v0um.globalExpect(parsed.services.redis.healthcheck).toBeDefined();
45
- require_vi_2VT5v0um.globalExpect(parsed.services.redis.healthcheck.test).toContain("redis-cli ping");
46
- require_vi_2VT5v0um.globalExpect(parsed.services.redis.restart).toBe("unless-stopped");
47
- require_vi_2VT5v0um.globalExpect(parsed.services.redis.networks).toContain("openclaw-network");
48
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].environment).toHaveProperty("REDIS_HOST");
49
- require_vi_2VT5v0um.globalExpect(parsed.services["openclaw-gateway"].environment.REDIS_HOST).toBe("redis");
39
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("openclaw-gateway");
40
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("redis");
41
+ require_test_CTcmp4Su.globalExpect(parsed.services.redis.image).toBe("redis:8-alpine");
42
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].depends_on).toHaveProperty("redis");
43
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].depends_on.redis.condition).toBe("service_healthy");
44
+ require_test_CTcmp4Su.globalExpect(parsed.services.redis.healthcheck).toBeDefined();
45
+ require_test_CTcmp4Su.globalExpect(parsed.services.redis.healthcheck.test).toContain("redis-cli ping");
46
+ require_test_CTcmp4Su.globalExpect(parsed.services.redis.restart).toBe("unless-stopped");
47
+ require_test_CTcmp4Su.globalExpect(parsed.services.redis.networks).toContain("openclaw-network");
48
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].environment).toHaveProperty("REDIS_HOST");
49
+ require_test_CTcmp4Su.globalExpect(parsed.services["openclaw-gateway"].environment.REDIS_HOST).toBe("redis");
50
50
  });
51
- require_vi_2VT5v0um.it("generates parseable YAML for a multi-service stack", () => {
51
+ require_test_CTcmp4Su.it("generates parseable YAML for a multi-service stack", () => {
52
52
  const yaml$1 = require_composer.compose(require_resolver.resolve({
53
53
  services: ["redis", "n8n"],
54
54
  skillPacks: []
55
55
  }), defaultOptions);
56
- require_vi_2VT5v0um.globalExpect(() => (0, yaml.parse)(yaml$1)).not.toThrow();
56
+ require_test_CTcmp4Su.globalExpect(() => (0, yaml.parse)(yaml$1)).not.toThrow();
57
57
  const parsed = (0, yaml.parse)(yaml$1);
58
- require_vi_2VT5v0um.globalExpect(parsed).toHaveProperty("services");
59
- require_vi_2VT5v0um.globalExpect(parsed).toHaveProperty("volumes");
60
- require_vi_2VT5v0um.globalExpect(parsed).toHaveProperty("networks");
61
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("openclaw-gateway");
62
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("redis");
63
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("n8n");
64
- require_vi_2VT5v0um.globalExpect(parsed.services).toHaveProperty("postgresql");
58
+ require_test_CTcmp4Su.globalExpect(parsed).toHaveProperty("services");
59
+ require_test_CTcmp4Su.globalExpect(parsed).toHaveProperty("volumes");
60
+ require_test_CTcmp4Su.globalExpect(parsed).toHaveProperty("networks");
61
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("openclaw-gateway");
62
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("redis");
63
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("n8n");
64
+ require_test_CTcmp4Su.globalExpect(parsed.services).toHaveProperty("postgresql");
65
65
  });
66
- require_vi_2VT5v0um.it("includes all service volumes in top-level volumes section", () => {
66
+ require_test_CTcmp4Su.it("includes all service volumes in top-level volumes section", () => {
67
67
  const resolved = require_resolver.resolve({
68
68
  services: ["redis", "n8n"],
69
69
  skillPacks: []
@@ -71,11 +71,11 @@ require_vi_2VT5v0um.describe("compose", () => {
71
71
  const parsed = (0, yaml.parse)(require_composer.compose(resolved, defaultOptions));
72
72
  const serviceVolumeNames = /* @__PURE__ */ new Set();
73
73
  for (const rs of resolved.services) for (const vol of rs.definition.volumes) serviceVolumeNames.add(vol.name);
74
- for (const volName of serviceVolumeNames) require_vi_2VT5v0um.globalExpect(parsed.volumes).toHaveProperty(volName);
74
+ for (const volName of serviceVolumeNames) require_test_CTcmp4Su.globalExpect(parsed.volumes).toHaveProperty(volName);
75
75
  const gwVols = parsed.services["openclaw-gateway"].volumes;
76
- require_vi_2VT5v0um.globalExpect(gwVols.some((v) => v.includes(".openclaw"))).toBe(true);
76
+ require_test_CTcmp4Su.globalExpect(gwVols.some((v) => v.includes(".openclaw"))).toBe(true);
77
77
  });
78
- require_vi_2VT5v0um.it("includes GPU passthrough when gpu=true and service requires it", () => {
78
+ require_test_CTcmp4Su.it("includes GPU passthrough when gpu=true and service requires it", () => {
79
79
  const resolved = require_resolver.resolve({
80
80
  services: ["ollama"],
81
81
  skillPacks: []
@@ -93,14 +93,14 @@ require_vi_2VT5v0um.describe("compose", () => {
93
93
  ...defaultOptions,
94
94
  gpu: true
95
95
  })).services.ollama;
96
- require_vi_2VT5v0um.globalExpect(ollamaService.deploy).toBeDefined();
97
- require_vi_2VT5v0um.globalExpect(ollamaService.deploy.resources.reservations.devices).toEqual([{
96
+ require_test_CTcmp4Su.globalExpect(ollamaService.deploy).toBeDefined();
97
+ require_test_CTcmp4Su.globalExpect(ollamaService.deploy.resources.reservations.devices).toEqual([{
98
98
  driver: "nvidia",
99
99
  count: "all",
100
100
  capabilities: ["gpu"]
101
101
  }]);
102
102
  });
103
- require_vi_2VT5v0um.it("does not include GPU passthrough when gpu=false", () => {
103
+ require_test_CTcmp4Su.it("does not include GPU passthrough when gpu=false", () => {
104
104
  const resolved = require_resolver.resolve({
105
105
  services: ["ollama"],
106
106
  skillPacks: []
@@ -118,9 +118,9 @@ require_vi_2VT5v0um.describe("compose", () => {
118
118
  ...defaultOptions,
119
119
  gpu: false
120
120
  })).services.ollama;
121
- require_vi_2VT5v0um.globalExpect(ollamaService.deploy?.resources?.reservations?.devices).toBeUndefined();
121
+ require_test_CTcmp4Su.globalExpect(ollamaService.deploy?.resources?.reservations?.devices).toBeUndefined();
122
122
  });
123
- require_vi_2VT5v0um.it("does not map internal-only ports to host", () => {
123
+ require_test_CTcmp4Su.it("does not map internal-only ports to host", () => {
124
124
  const resolved = require_resolver.resolve({
125
125
  services: ["redis"],
126
126
  skillPacks: []
@@ -140,25 +140,25 @@ require_vi_2VT5v0um.describe("compose", () => {
140
140
  }
141
141
  }))
142
142
  }, defaultOptions)).services.redis.ports;
143
- require_vi_2VT5v0um.globalExpect(redisPorts).toHaveLength(1);
144
- require_vi_2VT5v0um.globalExpect(redisPorts[0]).toContain("6379");
145
- require_vi_2VT5v0um.globalExpect(redisPorts[0]).not.toContain("16379");
143
+ require_test_CTcmp4Su.globalExpect(redisPorts).toHaveLength(1);
144
+ require_test_CTcmp4Su.globalExpect(redisPorts[0]).toContain("6379");
145
+ require_test_CTcmp4Su.globalExpect(redisPorts[0]).not.toContain("16379");
146
146
  });
147
- require_vi_2VT5v0um.it("uses service_started condition for services without healthcheck", () => {
147
+ require_test_CTcmp4Su.it("uses service_started condition for services without healthcheck", () => {
148
148
  const resolved = require_resolver.resolve({
149
149
  services: ["minio"],
150
150
  skillPacks: []
151
151
  });
152
152
  const gatewayDeps = (0, yaml.parse)(require_composer.compose(resolved, defaultOptions)).services["openclaw-gateway"].depends_on;
153
- for (const [id, dep] of Object.entries(gatewayDeps)) if (resolved.services.find((s) => s.definition.id === id)?.definition.healthcheck) require_vi_2VT5v0um.globalExpect(dep.condition).toBe("service_healthy");
154
- else require_vi_2VT5v0um.globalExpect(dep.condition).toBe("service_started");
153
+ for (const [id, dep] of Object.entries(gatewayDeps)) if (resolved.services.find((s) => s.definition.id === id)?.definition.healthcheck) require_test_CTcmp4Su.globalExpect(dep.condition).toBe("service_healthy");
154
+ else require_test_CTcmp4Su.globalExpect(dep.condition).toBe("service_started");
155
155
  });
156
- require_vi_2VT5v0um.it("gateway is always the first service in the output", () => {
156
+ require_test_CTcmp4Su.it("gateway is always the first service in the output", () => {
157
157
  const parsed = (0, yaml.parse)(require_composer.compose(require_resolver.resolve({
158
158
  services: ["redis", "ollama"],
159
159
  skillPacks: []
160
160
  }), defaultOptions));
161
- require_vi_2VT5v0um.globalExpect(Object.keys(parsed.services)[0]).toBe("openclaw-gateway");
161
+ require_test_CTcmp4Su.globalExpect(Object.keys(parsed.services)[0]).toBe("openclaw-gateway");
162
162
  });
163
163
  });
164
164
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"composer.test.cjs","names":["describe","compose","resolve","yaml"],"sources":["../src/composer.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { parse } from \"yaml\";\nimport { compose } from \"./composer.js\";\nimport { resolve } from \"./resolver.js\";\nimport type { ComposeOptions, ResolverOutput } from \"./types.js\";\n\nconst defaultOptions: ComposeOptions = {\n\tprojectName: \"test-project\",\n\tproxy: \"none\",\n\tgpu: false,\n\tplatform: \"linux/amd64\",\n\tdeployment: \"local\",\n\topenclawVersion: \"latest\",\n};\n\ndescribe(\"compose\", () => {\n\tit(\"generates minimal stack with just OpenClaw gateway when no companions\", () => {\n\t\tconst resolved = resolve({ services: [], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should have the gateway service\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-gateway\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].image).toContain(\"ghcr.io/openclaw/openclaw\");\n\n\t\t// Gateway should have core environment\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment.HOME).toBe(\"/home/node\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment.TERM).toBe(\"xterm-256color\");\n\n\t\t// Gateway uses bind-mount volumes (not named volumes in top-level volumes section)\n\t\tconst gwVolumes = parsed.services[\"openclaw-gateway\"].volumes as string[];\n\t\texpect(gwVolumes.some((v: string) => v.includes(\".openclaw\"))).toBe(true);\n\n\t\t// Should have network\n\t\texpect(parsed.networks).toHaveProperty(\"openclaw-network\");\n\t\texpect(parsed.networks[\"openclaw-network\"].driver).toBe(\"bridge\");\n\n\t\t// Should have CLI companion service\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-cli\");\n\n\t\t// Gateway should have depends_on for mandatory services (convex, mission-control, tailscale)\n\t\t// Even with no user-selected services, mandatory services are always present\n\t\texpect(parsed.services).toHaveProperty(\"convex\");\n\t\texpect(parsed.services).toHaveProperty(\"mission-control\");\n\n\t\t// Gateway should have restart policy\n\t\texpect(parsed.services[\"openclaw-gateway\"].restart).toBe(\"unless-stopped\");\n\t});\n\n\tit(\"generates Redis companion with proper gateway depends_on\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should have gateway and redis services\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-gateway\");\n\t\texpect(parsed.services).toHaveProperty(\"redis\");\n\n\t\t// Redis service should have correct image\n\t\texpect(parsed.services.redis.image).toBe(\"redis:8-alpine\");\n\n\t\t// Gateway depends_on should include redis with service_healthy (redis has healthcheck)\n\t\texpect(parsed.services[\"openclaw-gateway\"].depends_on).toHaveProperty(\"redis\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].depends_on.redis.condition).toBe(\"service_healthy\");\n\n\t\t// Redis should have a healthcheck\n\t\texpect(parsed.services.redis.healthcheck).toBeDefined();\n\t\texpect(parsed.services.redis.healthcheck.test).toContain(\"redis-cli ping\");\n\n\t\t// Redis should have restart policy\n\t\texpect(parsed.services.redis.restart).toBe(\"unless-stopped\");\n\n\t\t// Redis should be on openclaw-network\n\t\texpect(parsed.services.redis.networks).toContain(\"openclaw-network\");\n\n\t\t// Gateway environment should include redis-related openclawEnvVars\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment).toHaveProperty(\"REDIS_HOST\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment.REDIS_HOST).toBe(\"redis\");\n\t});\n\n\tit(\"generates parseable YAML for a multi-service stack\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\", \"n8n\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\n\t\t// Should not throw when parsing\n\t\texpect(() => parse(yaml)).not.toThrow();\n\n\t\tconst parsed = parse(yaml);\n\t\texpect(parsed).toHaveProperty(\"services\");\n\t\texpect(parsed).toHaveProperty(\"volumes\");\n\t\texpect(parsed).toHaveProperty(\"networks\");\n\n\t\t// Should have gateway + redis + n8n + postgresql (n8n requires postgresql)\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-gateway\");\n\t\texpect(parsed.services).toHaveProperty(\"redis\");\n\t\texpect(parsed.services).toHaveProperty(\"n8n\");\n\t\texpect(parsed.services).toHaveProperty(\"postgresql\");\n\t});\n\n\tit(\"includes all service volumes in top-level volumes section\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\", \"n8n\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Collect all volume names from all resolved services\n\t\tconst serviceVolumeNames = new Set<string>();\n\t\tfor (const rs of resolved.services) {\n\t\t\tfor (const vol of rs.definition.volumes) {\n\t\t\t\tserviceVolumeNames.add(vol.name);\n\t\t\t}\n\t\t}\n\n\t\t// All service volumes must appear in top-level volumes\n\t\tfor (const volName of serviceVolumeNames) {\n\t\t\texpect(parsed.volumes).toHaveProperty(volName);\n\t\t}\n\n\t\t// Gateway uses bind-mount volumes (not in top-level volumes section)\n\t\tconst gwVols = parsed.services[\"openclaw-gateway\"].volumes as string[];\n\t\texpect(gwVols.some((v: string) => v.includes(\".openclaw\"))).toBe(true);\n\t});\n\n\tit(\"includes GPU passthrough when gpu=true and service requires it\", () => {\n\t\tconst resolved = resolve({ services: [\"ollama\"], skillPacks: [] });\n\n\t\t// Modify resolved output to simulate a GPU-required service\n\t\tconst gpuResolved: ResolverOutput = {\n\t\t\t...resolved,\n\t\t\tservices: resolved.services.map((s) => ({\n\t\t\t\t...s,\n\t\t\t\tdefinition: { ...s.definition, gpuRequired: true },\n\t\t\t})),\n\t\t};\n\n\t\tconst yaml = compose(gpuResolved, { ...defaultOptions, gpu: true });\n\t\tconst parsed = parse(yaml);\n\n\t\t// Ollama service should have GPU device reservation\n\t\tconst ollamaService = parsed.services.ollama;\n\t\texpect(ollamaService.deploy).toBeDefined();\n\t\texpect(ollamaService.deploy.resources.reservations.devices).toEqual([\n\t\t\t{\n\t\t\t\tdriver: \"nvidia\",\n\t\t\t\tcount: \"all\",\n\t\t\t\tcapabilities: [\"gpu\"],\n\t\t\t},\n\t\t]);\n\t});\n\n\tit(\"does not include GPU passthrough when gpu=false\", () => {\n\t\tconst resolved = resolve({ services: [\"ollama\"], skillPacks: [] });\n\n\t\t// Even if service requires GPU, gpu option is false\n\t\tconst gpuResolved: ResolverOutput = {\n\t\t\t...resolved,\n\t\t\tservices: resolved.services.map((s) => ({\n\t\t\t\t...s,\n\t\t\t\tdefinition: { ...s.definition, gpuRequired: true },\n\t\t\t})),\n\t\t};\n\n\t\tconst yaml = compose(gpuResolved, { ...defaultOptions, gpu: false });\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should NOT have deploy with GPU devices\n\t\tconst ollamaService = parsed.services.ollama;\n\t\texpect(ollamaService.deploy?.resources?.reservations?.devices).toBeUndefined();\n\t});\n\n\tit(\"does not map internal-only ports to host\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\"], skillPacks: [] });\n\n\t\t// Modify redis to have an internal-only port\n\t\tconst modifiedResolved: ResolverOutput = {\n\t\t\t...resolved,\n\t\t\tservices: resolved.services.map((s) => ({\n\t\t\t\t...s,\n\t\t\t\tdefinition: {\n\t\t\t\t\t...s.definition,\n\t\t\t\t\tports: [\n\t\t\t\t\t\t...s.definition.ports,\n\t\t\t\t\t\t{ host: 16379, container: 16379, description: \"Redis cluster bus\", exposed: false },\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t})),\n\t\t};\n\n\t\tconst yaml = compose(modifiedResolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should only have the exposed port, not the internal one\n\t\tconst redisPorts = parsed.services.redis.ports;\n\t\texpect(redisPorts).toHaveLength(1);\n\t\texpect(redisPorts[0]).toContain(\"6379\");\n\t\texpect(redisPorts[0]).not.toContain(\"16379\");\n\t});\n\n\tit(\"uses service_started condition for services without healthcheck\", () => {\n\t\tconst resolved = resolve({ services: [\"minio\"], skillPacks: [] });\n\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Minio may or may not have a healthcheck – the gateway depends_on\n\t\t// condition should reflect the definition accurately\n\t\tconst gatewayDeps = parsed.services[\"openclaw-gateway\"].depends_on;\n\t\tfor (const [id, dep] of Object.entries(gatewayDeps)) {\n\t\t\tconst svc = resolved.services.find((s) => s.definition.id === id);\n\t\t\tif (svc?.definition.healthcheck) {\n\t\t\t\texpect((dep as { condition: string }).condition).toBe(\"service_healthy\");\n\t\t\t} else {\n\t\t\t\texpect((dep as { condition: string }).condition).toBe(\"service_started\");\n\t\t\t}\n\t\t}\n\t});\n\n\tit(\"gateway is always the first service in the output\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\", \"ollama\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// First key in services should be openclaw-gateway\n\t\tconst serviceKeys = Object.keys(parsed.services);\n\t\texpect(serviceKeys[0]).toBe(\"openclaw-gateway\");\n\t});\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"composer.test.cjs","names":["describe","compose","resolve","yaml"],"sources":["../src/composer.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { parse } from \"yaml\";\nimport { compose } from \"./composer.js\";\nimport { resolve } from \"./resolver.js\";\nimport type { ComposeOptions, ResolverOutput } from \"./types.js\";\n\nconst defaultOptions: ComposeOptions = {\n\tprojectName: \"test-project\",\n\tproxy: \"none\",\n\tgpu: false,\n\tplatform: \"linux/amd64\",\n\tdeployment: \"local\",\n\topenclawVersion: \"latest\",\n};\n\ndescribe(\"compose\", () => {\n\tit(\"generates minimal stack with just OpenClaw gateway when no companions\", () => {\n\t\tconst resolved = resolve({ services: [], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should have the gateway service\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-gateway\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].image).toContain(\"ghcr.io/openclaw/openclaw\");\n\n\t\t// Gateway should have core environment\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment.HOME).toBe(\"/home/node\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment.TERM).toBe(\"xterm-256color\");\n\n\t\t// Gateway uses bind-mount volumes (not named volumes in top-level volumes section)\n\t\tconst gwVolumes = parsed.services[\"openclaw-gateway\"].volumes as string[];\n\t\texpect(gwVolumes.some((v: string) => v.includes(\".openclaw\"))).toBe(true);\n\n\t\t// Should have network\n\t\texpect(parsed.networks).toHaveProperty(\"openclaw-network\");\n\t\texpect(parsed.networks[\"openclaw-network\"].driver).toBe(\"bridge\");\n\n\t\t// Should have CLI companion service\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-cli\");\n\n\t\t// Gateway should have depends_on for mandatory services (convex, mission-control, tailscale)\n\t\t// Even with no user-selected services, mandatory services are always present\n\t\texpect(parsed.services).toHaveProperty(\"convex\");\n\t\texpect(parsed.services).toHaveProperty(\"mission-control\");\n\n\t\t// Gateway should have restart policy\n\t\texpect(parsed.services[\"openclaw-gateway\"].restart).toBe(\"unless-stopped\");\n\t});\n\n\tit(\"generates Redis companion with proper gateway depends_on\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should have gateway and redis services\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-gateway\");\n\t\texpect(parsed.services).toHaveProperty(\"redis\");\n\n\t\t// Redis service should have correct image\n\t\texpect(parsed.services.redis.image).toBe(\"redis:8-alpine\");\n\n\t\t// Gateway depends_on should include redis with service_healthy (redis has healthcheck)\n\t\texpect(parsed.services[\"openclaw-gateway\"].depends_on).toHaveProperty(\"redis\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].depends_on.redis.condition).toBe(\"service_healthy\");\n\n\t\t// Redis should have a healthcheck\n\t\texpect(parsed.services.redis.healthcheck).toBeDefined();\n\t\texpect(parsed.services.redis.healthcheck.test).toContain(\"redis-cli ping\");\n\n\t\t// Redis should have restart policy\n\t\texpect(parsed.services.redis.restart).toBe(\"unless-stopped\");\n\n\t\t// Redis should be on openclaw-network\n\t\texpect(parsed.services.redis.networks).toContain(\"openclaw-network\");\n\n\t\t// Gateway environment should include redis-related openclawEnvVars\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment).toHaveProperty(\"REDIS_HOST\");\n\t\texpect(parsed.services[\"openclaw-gateway\"].environment.REDIS_HOST).toBe(\"redis\");\n\t});\n\n\tit(\"generates parseable YAML for a multi-service stack\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\", \"n8n\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\n\t\t// Should not throw when parsing\n\t\texpect(() => parse(yaml)).not.toThrow();\n\n\t\tconst parsed = parse(yaml);\n\t\texpect(parsed).toHaveProperty(\"services\");\n\t\texpect(parsed).toHaveProperty(\"volumes\");\n\t\texpect(parsed).toHaveProperty(\"networks\");\n\n\t\t// Should have gateway + redis + n8n + postgresql (n8n requires postgresql)\n\t\texpect(parsed.services).toHaveProperty(\"openclaw-gateway\");\n\t\texpect(parsed.services).toHaveProperty(\"redis\");\n\t\texpect(parsed.services).toHaveProperty(\"n8n\");\n\t\texpect(parsed.services).toHaveProperty(\"postgresql\");\n\t});\n\n\tit(\"includes all service volumes in top-level volumes section\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\", \"n8n\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Collect all volume names from all resolved services\n\t\tconst serviceVolumeNames = new Set<string>();\n\t\tfor (const rs of resolved.services) {\n\t\t\tfor (const vol of rs.definition.volumes) {\n\t\t\t\tserviceVolumeNames.add(vol.name);\n\t\t\t}\n\t\t}\n\n\t\t// All service volumes must appear in top-level volumes\n\t\tfor (const volName of serviceVolumeNames) {\n\t\t\texpect(parsed.volumes).toHaveProperty(volName);\n\t\t}\n\n\t\t// Gateway uses bind-mount volumes (not in top-level volumes section)\n\t\tconst gwVols = parsed.services[\"openclaw-gateway\"].volumes as string[];\n\t\texpect(gwVols.some((v: string) => v.includes(\".openclaw\"))).toBe(true);\n\t});\n\n\tit(\"includes GPU passthrough when gpu=true and service requires it\", () => {\n\t\tconst resolved = resolve({ services: [\"ollama\"], skillPacks: [] });\n\n\t\t// Modify resolved output to simulate a GPU-required service\n\t\tconst gpuResolved: ResolverOutput = {\n\t\t\t...resolved,\n\t\t\tservices: resolved.services.map((s) => ({\n\t\t\t\t...s,\n\t\t\t\tdefinition: { ...s.definition, gpuRequired: true },\n\t\t\t})),\n\t\t};\n\n\t\tconst yaml = compose(gpuResolved, { ...defaultOptions, gpu: true });\n\t\tconst parsed = parse(yaml);\n\n\t\t// Ollama service should have GPU device reservation\n\t\tconst ollamaService = parsed.services.ollama;\n\t\texpect(ollamaService.deploy).toBeDefined();\n\t\texpect(ollamaService.deploy.resources.reservations.devices).toEqual([\n\t\t\t{\n\t\t\t\tdriver: \"nvidia\",\n\t\t\t\tcount: \"all\",\n\t\t\t\tcapabilities: [\"gpu\"],\n\t\t\t},\n\t\t]);\n\t});\n\n\tit(\"does not include GPU passthrough when gpu=false\", () => {\n\t\tconst resolved = resolve({ services: [\"ollama\"], skillPacks: [] });\n\n\t\t// Even if service requires GPU, gpu option is false\n\t\tconst gpuResolved: ResolverOutput = {\n\t\t\t...resolved,\n\t\t\tservices: resolved.services.map((s) => ({\n\t\t\t\t...s,\n\t\t\t\tdefinition: { ...s.definition, gpuRequired: true },\n\t\t\t})),\n\t\t};\n\n\t\tconst yaml = compose(gpuResolved, { ...defaultOptions, gpu: false });\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should NOT have deploy with GPU devices\n\t\tconst ollamaService = parsed.services.ollama;\n\t\texpect(ollamaService.deploy?.resources?.reservations?.devices).toBeUndefined();\n\t});\n\n\tit(\"does not map internal-only ports to host\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\"], skillPacks: [] });\n\n\t\t// Modify redis to have an internal-only port\n\t\tconst modifiedResolved: ResolverOutput = {\n\t\t\t...resolved,\n\t\t\tservices: resolved.services.map((s) => ({\n\t\t\t\t...s,\n\t\t\t\tdefinition: {\n\t\t\t\t\t...s.definition,\n\t\t\t\t\tports: [\n\t\t\t\t\t\t...s.definition.ports,\n\t\t\t\t\t\t{ host: 16379, container: 16379, description: \"Redis cluster bus\", exposed: false },\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t})),\n\t\t};\n\n\t\tconst yaml = compose(modifiedResolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Should only have the exposed port, not the internal one\n\t\tconst redisPorts = parsed.services.redis.ports;\n\t\texpect(redisPorts).toHaveLength(1);\n\t\texpect(redisPorts[0]).toContain(\"6379\");\n\t\texpect(redisPorts[0]).not.toContain(\"16379\");\n\t});\n\n\tit(\"uses service_started condition for services without healthcheck\", () => {\n\t\tconst resolved = resolve({ services: [\"minio\"], skillPacks: [] });\n\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// Minio may or may not have a healthcheck – the gateway depends_on\n\t\t// condition should reflect the definition accurately\n\t\tconst gatewayDeps = parsed.services[\"openclaw-gateway\"].depends_on;\n\t\tfor (const [id, dep] of Object.entries(gatewayDeps)) {\n\t\t\tconst svc = resolved.services.find((s) => s.definition.id === id);\n\t\t\tif (svc?.definition.healthcheck) {\n\t\t\t\texpect((dep as { condition: string }).condition).toBe(\"service_healthy\");\n\t\t\t} else {\n\t\t\t\texpect((dep as { condition: string }).condition).toBe(\"service_started\");\n\t\t\t}\n\t\t}\n\t});\n\n\tit(\"gateway is always the first service in the output\", () => {\n\t\tconst resolved = resolve({ services: [\"redis\", \"ollama\"], skillPacks: [] });\n\t\tconst yaml = compose(resolved, defaultOptions);\n\t\tconst parsed = parse(yaml);\n\n\t\t// First key in services should be openclaw-gateway\n\t\tconst serviceKeys = Object.keys(parsed.services);\n\t\texpect(serviceKeys[0]).toBe(\"openclaw-gateway\");\n\t});\n});\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-C_jmO7m2.mjs";
2
- import { resolve } from "./resolver.mjs";
1
+ import { n as describe, r as it, t as globalExpect } from "./test.CTcmp4Su-ClCHJ3FA.mjs";
3
2
  import { compose } from "./composer.mjs";
3
+ import { resolve } from "./resolver.mjs";
4
4
  import { parse } from "yaml";
5
5
  //#region src/composer.test.ts
6
6
  const defaultOptions = {
@@ -1,8 +1,8 @@
1
- const require_vi_2VT5v0um = require("../vi.2VT5v0um-iVBt6Fyq.cjs");
1
+ const require_test_CTcmp4Su = require("../test.CTcmp4Su-DlzTarwH.cjs");
2
2
  const require_deployers_strip_host_ports = require("./strip-host-ports.cjs");
3
3
  //#region src/deployers/strip-host-ports.test.ts
4
- require_vi_2VT5v0um.describe("stripHostPorts", () => {
5
- require_vi_2VT5v0um.it("strips host port from short syntax (host:container)", () => {
4
+ require_test_CTcmp4Su.describe("stripHostPorts", () => {
5
+ require_test_CTcmp4Su.it("strips host port from short syntax (host:container)", () => {
6
6
  const result = require_deployers_strip_host_ports.stripHostPorts(`
7
7
  services:
8
8
  web:
@@ -11,11 +11,11 @@ services:
11
11
  - "8080:80"
12
12
  - "443:443"
13
13
  `);
14
- require_vi_2VT5v0um.globalExpect(result).toContain("\"80\"");
15
- require_vi_2VT5v0um.globalExpect(result).toContain("\"443\"");
16
- require_vi_2VT5v0um.globalExpect(result).not.toContain("8080");
14
+ require_test_CTcmp4Su.globalExpect(result).toContain("\"80\"");
15
+ require_test_CTcmp4Su.globalExpect(result).toContain("\"443\"");
16
+ require_test_CTcmp4Su.globalExpect(result).not.toContain("8080");
17
17
  });
18
- require_vi_2VT5v0um.it("strips host IP and port from extended short syntax", () => {
18
+ require_test_CTcmp4Su.it("strips host IP and port from extended short syntax", () => {
19
19
  const result = require_deployers_strip_host_ports.stripHostPorts(`
20
20
  services:
21
21
  web:
@@ -23,11 +23,11 @@ services:
23
23
  ports:
24
24
  - "0.0.0.0:8080:80"
25
25
  `);
26
- require_vi_2VT5v0um.globalExpect(result).toContain("\"80\"");
27
- require_vi_2VT5v0um.globalExpect(result).not.toContain("8080");
28
- require_vi_2VT5v0um.globalExpect(result).not.toContain("0.0.0.0");
26
+ require_test_CTcmp4Su.globalExpect(result).toContain("\"80\"");
27
+ require_test_CTcmp4Su.globalExpect(result).not.toContain("8080");
28
+ require_test_CTcmp4Su.globalExpect(result).not.toContain("0.0.0.0");
29
29
  });
30
- require_vi_2VT5v0um.it("preserves protocol suffix", () => {
30
+ require_test_CTcmp4Su.it("preserves protocol suffix", () => {
31
31
  const result = require_deployers_strip_host_ports.stripHostPorts(`
32
32
  services:
33
33
  web:
@@ -36,13 +36,13 @@ services:
36
36
  - "8080:80/tcp"
37
37
  - "5353:53/udp"
38
38
  `);
39
- require_vi_2VT5v0um.globalExpect(result).toContain("80/tcp");
40
- require_vi_2VT5v0um.globalExpect(result).toContain("53/udp");
41
- require_vi_2VT5v0um.globalExpect(result).not.toContain("8080");
42
- require_vi_2VT5v0um.globalExpect(result).not.toContain("5353");
39
+ require_test_CTcmp4Su.globalExpect(result).toContain("80/tcp");
40
+ require_test_CTcmp4Su.globalExpect(result).toContain("53/udp");
41
+ require_test_CTcmp4Su.globalExpect(result).not.toContain("8080");
42
+ require_test_CTcmp4Su.globalExpect(result).not.toContain("5353");
43
43
  });
44
- require_vi_2VT5v0um.it("keeps container-only ports unchanged", () => {
45
- require_vi_2VT5v0um.globalExpect(require_deployers_strip_host_ports.stripHostPorts(`
44
+ require_test_CTcmp4Su.it("keeps container-only ports unchanged", () => {
45
+ require_test_CTcmp4Su.globalExpect(require_deployers_strip_host_ports.stripHostPorts(`
46
46
  services:
47
47
  web:
48
48
  image: nginx
@@ -50,7 +50,7 @@ services:
50
50
  - "80"
51
51
  `)).toContain("\"80\"");
52
52
  });
53
- require_vi_2VT5v0um.it("handles multiple services", () => {
53
+ require_test_CTcmp4Su.it("handles multiple services", () => {
54
54
  const result = require_deployers_strip_host_ports.stripHostPorts(`
55
55
  services:
56
56
  web:
@@ -66,17 +66,17 @@ services:
66
66
  ports:
67
67
  - "8888:8080"
68
68
  `);
69
- require_vi_2VT5v0um.globalExpect(result).toContain("\"80\"");
70
- require_vi_2VT5v0um.globalExpect(result).toContain("\"6379\"");
71
- require_vi_2VT5v0um.globalExpect(result).toContain("\"8080\"");
72
- require_vi_2VT5v0um.globalExpect(result).not.toContain("8888");
69
+ require_test_CTcmp4Su.globalExpect(result).toContain("\"80\"");
70
+ require_test_CTcmp4Su.globalExpect(result).toContain("\"6379\"");
71
+ require_test_CTcmp4Su.globalExpect(result).toContain("\"8080\"");
72
+ require_test_CTcmp4Su.globalExpect(result).not.toContain("8888");
73
73
  });
74
- require_vi_2VT5v0um.it("returns original YAML if no services section", () => {
74
+ require_test_CTcmp4Su.it("returns original YAML if no services section", () => {
75
75
  const yaml = `version: "3"`;
76
- require_vi_2VT5v0um.globalExpect(require_deployers_strip_host_ports.stripHostPorts(yaml)).toBe(yaml);
76
+ require_test_CTcmp4Su.globalExpect(require_deployers_strip_host_ports.stripHostPorts(yaml)).toBe(yaml);
77
77
  });
78
- require_vi_2VT5v0um.it("handles services with no ports", () => {
79
- require_vi_2VT5v0um.globalExpect(require_deployers_strip_host_ports.stripHostPorts(`
78
+ require_test_CTcmp4Su.it("handles services with no ports", () => {
79
+ require_test_CTcmp4Su.globalExpect(require_deployers_strip_host_ports.stripHostPorts(`
80
80
  services:
81
81
  web:
82
82
  image: nginx
@@ -1 +1 @@
1
- {"version":3,"file":"strip-host-ports.test.cjs","names":["describe","stripHostPorts"],"sources":["../../src/deployers/strip-host-ports.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { stripHostPorts } from \"./strip-host-ports.js\";\n\ndescribe(\"stripHostPorts\", () => {\n\tit(\"strips host port from short syntax (host:container)\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"8080:80\"\n - \"443:443\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t\texpect(result).toContain('\"443\"');\n\t\texpect(result).not.toContain(\"8080\");\n\t});\n\n\tit(\"strips host IP and port from extended short syntax\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"0.0.0.0:8080:80\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t\texpect(result).not.toContain(\"8080\");\n\t\texpect(result).not.toContain(\"0.0.0.0\");\n\t});\n\n\tit(\"preserves protocol suffix\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"8080:80/tcp\"\n - \"5353:53/udp\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain(\"80/tcp\");\n\t\texpect(result).toContain(\"53/udp\");\n\t\texpect(result).not.toContain(\"8080\");\n\t\texpect(result).not.toContain(\"5353\");\n\t});\n\n\tit(\"keeps container-only ports unchanged\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"80\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t});\n\n\tit(\"handles multiple services\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"8080:80\"\n redis:\n image: redis\n ports:\n - \"6379:6379\"\n searxng:\n image: searxng/searxng\n ports:\n - \"8888:8080\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t\texpect(result).toContain('\"6379\"');\n\t\texpect(result).toContain('\"8080\"');\n\t\texpect(result).not.toContain(\"8888\");\n\t});\n\n\tit(\"returns original YAML if no services section\", () => {\n\t\tconst yaml = `version: \"3\"`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toBe(yaml);\n\t});\n\n\tit(\"handles services with no ports\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain(\"nginx\");\n\t});\n});\n"],"mappings":";;;AAGAA,oBAAAA,SAAS,wBAAwB;AAChC,qBAAA,GAAG,6DAA6D;EAS/D,MAAM,SAASC,mCAAAA,eARF;;;;;;;EAQsB;AACnC,sBAAA,aAAO,OAAO,CAAC,UAAU,SAAO;AAChC,sBAAA,aAAO,OAAO,CAAC,UAAU,UAAQ;AACjC,sBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;GACnC;AAEF,qBAAA,GAAG,4DAA4D;EAQ9D,MAAM,SAASA,mCAAAA,eAPF;;;;;;EAOsB;AACnC,sBAAA,aAAO,OAAO,CAAC,UAAU,SAAO;AAChC,sBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;AACpC,sBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,UAAU;GACtC;AAEF,qBAAA,GAAG,mCAAmC;EASrC,MAAM,SAASA,mCAAAA,eARF;;;;;;;EAQsB;AACnC,sBAAA,aAAO,OAAO,CAAC,UAAU,SAAS;AAClC,sBAAA,aAAO,OAAO,CAAC,UAAU,SAAS;AAClC,sBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;AACpC,sBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;GACnC;AAEF,qBAAA,GAAG,8CAA8C;AAShD,sBAAA,aADeA,mCAAAA,eAPF;;;;;;EAOsB,CACrB,CAAC,UAAU,SAAO;GAC/B;AAEF,qBAAA,GAAG,mCAAmC;EAgBrC,MAAM,SAASA,mCAAAA,eAfF;;;;;;;;;;;;;;EAesB;AACnC,sBAAA,aAAO,OAAO,CAAC,UAAU,SAAO;AAChC,sBAAA,aAAO,OAAO,CAAC,UAAU,WAAS;AAClC,sBAAA,aAAO,OAAO,CAAC,UAAU,WAAS;AAClC,sBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;GACnC;AAEF,qBAAA,GAAG,sDAAsD;EACxD,MAAM,OAAO;AAEb,sBAAA,aADeA,mCAAAA,eAAe,KAAK,CACrB,CAAC,KAAK,KAAK;GACxB;AAEF,qBAAA,GAAG,wCAAwC;AAO1C,sBAAA,aADeA,mCAAAA,eALF;;;;EAKsB,CACrB,CAAC,UAAU,QAAQ;GAChC;EACD"}
1
+ {"version":3,"file":"strip-host-ports.test.cjs","names":["describe","stripHostPorts"],"sources":["../../src/deployers/strip-host-ports.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { stripHostPorts } from \"./strip-host-ports.js\";\n\ndescribe(\"stripHostPorts\", () => {\n\tit(\"strips host port from short syntax (host:container)\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"8080:80\"\n - \"443:443\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t\texpect(result).toContain('\"443\"');\n\t\texpect(result).not.toContain(\"8080\");\n\t});\n\n\tit(\"strips host IP and port from extended short syntax\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"0.0.0.0:8080:80\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t\texpect(result).not.toContain(\"8080\");\n\t\texpect(result).not.toContain(\"0.0.0.0\");\n\t});\n\n\tit(\"preserves protocol suffix\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"8080:80/tcp\"\n - \"5353:53/udp\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain(\"80/tcp\");\n\t\texpect(result).toContain(\"53/udp\");\n\t\texpect(result).not.toContain(\"8080\");\n\t\texpect(result).not.toContain(\"5353\");\n\t});\n\n\tit(\"keeps container-only ports unchanged\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"80\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t});\n\n\tit(\"handles multiple services\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n ports:\n - \"8080:80\"\n redis:\n image: redis\n ports:\n - \"6379:6379\"\n searxng:\n image: searxng/searxng\n ports:\n - \"8888:8080\"\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain('\"80\"');\n\t\texpect(result).toContain('\"6379\"');\n\t\texpect(result).toContain('\"8080\"');\n\t\texpect(result).not.toContain(\"8888\");\n\t});\n\n\tit(\"returns original YAML if no services section\", () => {\n\t\tconst yaml = `version: \"3\"`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toBe(yaml);\n\t});\n\n\tit(\"handles services with no ports\", () => {\n\t\tconst yaml = `\nservices:\n web:\n image: nginx\n`;\n\t\tconst result = stripHostPorts(yaml);\n\t\texpect(result).toContain(\"nginx\");\n\t});\n});\n"],"mappings":";;;AAGAA,sBAAAA,SAAS,wBAAwB;AAChC,uBAAA,GAAG,6DAA6D;EAS/D,MAAM,SAASC,mCAAAA,eARF;;;;;;;EAQsB;AACnC,wBAAA,aAAO,OAAO,CAAC,UAAU,SAAO;AAChC,wBAAA,aAAO,OAAO,CAAC,UAAU,UAAQ;AACjC,wBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;GACnC;AAEF,uBAAA,GAAG,4DAA4D;EAQ9D,MAAM,SAASA,mCAAAA,eAPF;;;;;;EAOsB;AACnC,wBAAA,aAAO,OAAO,CAAC,UAAU,SAAO;AAChC,wBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;AACpC,wBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,UAAU;GACtC;AAEF,uBAAA,GAAG,mCAAmC;EASrC,MAAM,SAASA,mCAAAA,eARF;;;;;;;EAQsB;AACnC,wBAAA,aAAO,OAAO,CAAC,UAAU,SAAS;AAClC,wBAAA,aAAO,OAAO,CAAC,UAAU,SAAS;AAClC,wBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;AACpC,wBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;GACnC;AAEF,uBAAA,GAAG,8CAA8C;AAShD,wBAAA,aADeA,mCAAAA,eAPF;;;;;;EAOsB,CACrB,CAAC,UAAU,SAAO;GAC/B;AAEF,uBAAA,GAAG,mCAAmC;EAgBrC,MAAM,SAASA,mCAAAA,eAfF;;;;;;;;;;;;;;EAesB;AACnC,wBAAA,aAAO,OAAO,CAAC,UAAU,SAAO;AAChC,wBAAA,aAAO,OAAO,CAAC,UAAU,WAAS;AAClC,wBAAA,aAAO,OAAO,CAAC,UAAU,WAAS;AAClC,wBAAA,aAAO,OAAO,CAAC,IAAI,UAAU,OAAO;GACnC;AAEF,uBAAA,GAAG,sDAAsD;EACxD,MAAM,OAAO;AAEb,wBAAA,aADeA,mCAAAA,eAAe,KAAK,CACrB,CAAC,KAAK,KAAK;GACxB;AAEF,uBAAA,GAAG,wCAAwC;AAO1C,wBAAA,aADeA,mCAAAA,eALF;;;;EAKsB,CACrB,CAAC,UAAU,QAAQ;GAChC;EACD"}
@@ -1,4 +1,4 @@
1
- import { n as describe, r as it, t as globalExpect } from "../vi.2VT5v0um-C_jmO7m2.mjs";
1
+ import { n as describe, r as it, t as globalExpect } from "../test.CTcmp4Su-ClCHJ3FA.mjs";
2
2
  import { stripHostPorts } from "./strip-host-ports.mjs";
3
3
  //#region src/deployers/strip-host-ports.test.ts
4
4
  describe("stripHostPorts", () => {
package/dist/generate.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_skills = require("./skills-BlzpHmpH.cjs");
3
- const require_bare_metal_partition = require("./bare-metal-partition.cjs");
4
- const require_resolver = require("./resolver.cjs");
5
3
  const require_generators_postgres_init = require("./generators/postgres-init.cjs");
6
4
  const require_composer = require("./composer.cjs");
5
+ const require_resolver = require("./resolver.cjs");
6
+ const require_bare_metal_partition = require("./bare-metal-partition.cjs");
7
7
  const require_errors = require("./errors.cjs");
8
8
  const require_generators_bare_metal_install = require("./generators/bare-metal-install.cjs");
9
9
  const require_generators_caddy = require("./generators/caddy.cjs");
package/dist/generate.mjs CHANGED
@@ -1,7 +1,8 @@
1
- import { partitionBareMetal, platformToNativePlatform, resolvedWithOnlyServices } from "./bare-metal-partition.mjs";
2
- import { resolve } from "./resolver.mjs";
3
1
  import { generatePostgresInit } from "./generators/postgres-init.mjs";
4
2
  import { composeMultiFile } from "./composer.mjs";
3
+ import { generateSkillFiles } from "./generators/skills.mjs";
4
+ import { resolve } from "./resolver.mjs";
5
+ import { partitionBareMetal, platformToNativePlatform, resolvedWithOnlyServices } from "./bare-metal-partition.mjs";
5
6
  import { StackConfigError, ValidationError } from "./errors.mjs";
6
7
  import { generateBareMetalInstall } from "./generators/bare-metal-install.mjs";
7
8
  import { generateCaddyfile } from "./generators/caddy.mjs";
@@ -18,7 +19,6 @@ import { generateOpenClawConfig } from "./generators/openclaw-json.mjs";
18
19
  import { generatePrometheusConfig } from "./generators/prometheus.mjs";
19
20
  import { generateReadme } from "./generators/readme.mjs";
20
21
  import { generateScripts } from "./generators/scripts.mjs";
21
- import { generateSkillFiles } from "./generators/skills.mjs";
22
22
  import { generateStackManifest } from "./generators/stack-manifest.mjs";
23
23
  import { generateTraefikConfig } from "./generators/traefik.mjs";
24
24
  import { migrateConfig } from "./migrations.mjs";