@better-openclaw/core 1.0.23 → 1.0.24

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 (254) hide show
  1. package/dist/bare-metal-partition.test.cjs +3 -4
  2. package/dist/bare-metal-partition.test.cjs.map +1 -1
  3. package/dist/bare-metal-partition.test.mjs +3 -4
  4. package/dist/bare-metal-partition.test.mjs.map +1 -1
  5. package/dist/composer.cjs +13 -1
  6. package/dist/composer.cjs.map +1 -1
  7. package/dist/composer.d.cts.map +1 -1
  8. package/dist/composer.d.mts.map +1 -1
  9. package/dist/composer.mjs +13 -1
  10. package/dist/composer.mjs.map +1 -1
  11. package/dist/composer.snapshot.test.cjs +1 -1
  12. package/dist/composer.snapshot.test.mjs +1 -1
  13. package/dist/composer.test.cjs +3 -2
  14. package/dist/composer.test.cjs.map +1 -1
  15. package/dist/composer.test.mjs +3 -2
  16. package/dist/composer.test.mjs.map +1 -1
  17. package/dist/deployers/strip-host-ports.test.cjs +1 -1
  18. package/dist/deployers/strip-host-ports.test.mjs +1 -1
  19. package/dist/generate.cjs +6 -2
  20. package/dist/generate.cjs.map +1 -1
  21. package/dist/generate.d.cts.map +1 -1
  22. package/dist/generate.d.mts.map +1 -1
  23. package/dist/generate.mjs +6 -2
  24. package/dist/generate.mjs.map +1 -1
  25. package/dist/generate.test.cjs +2 -2
  26. package/dist/generate.test.cjs.map +1 -1
  27. package/dist/generate.test.mjs +2 -2
  28. package/dist/generate.test.mjs.map +1 -1
  29. package/dist/generators/bare-metal-install.test.cjs +1 -1
  30. package/dist/generators/bare-metal-install.test.mjs +1 -1
  31. package/dist/generators/caddy.test.cjs +1 -1
  32. package/dist/generators/caddy.test.mjs +1 -1
  33. package/dist/generators/clone-repos.cjs +140 -0
  34. package/dist/generators/clone-repos.cjs.map +1 -0
  35. package/dist/generators/clone-repos.d.cts +11 -0
  36. package/dist/generators/clone-repos.d.cts.map +1 -0
  37. package/dist/generators/clone-repos.d.mts +11 -0
  38. package/dist/generators/clone-repos.d.mts.map +1 -0
  39. package/dist/generators/clone-repos.mjs +139 -0
  40. package/dist/generators/clone-repos.mjs.map +1 -0
  41. package/dist/generators/clone-repos.test.cjs +140 -0
  42. package/dist/generators/clone-repos.test.cjs.map +1 -0
  43. package/dist/generators/clone-repos.test.d.cts +1 -0
  44. package/dist/generators/clone-repos.test.d.mts +1 -0
  45. package/dist/generators/clone-repos.test.mjs +141 -0
  46. package/dist/generators/clone-repos.test.mjs.map +1 -0
  47. package/dist/generators/env.test.cjs +1 -1
  48. package/dist/generators/env.test.mjs +1 -1
  49. package/dist/generators/health-check.test.cjs +1 -1
  50. package/dist/generators/health-check.test.mjs +1 -1
  51. package/dist/generators/postgres-init.cjs +20 -0
  52. package/dist/generators/postgres-init.cjs.map +1 -1
  53. package/dist/generators/postgres-init.d.cts.map +1 -1
  54. package/dist/generators/postgres-init.d.mts.map +1 -1
  55. package/dist/generators/postgres-init.mjs +20 -0
  56. package/dist/generators/postgres-init.mjs.map +1 -1
  57. package/dist/generators/scripts.cjs +332 -3
  58. package/dist/generators/scripts.cjs.map +1 -1
  59. package/dist/generators/scripts.d.cts +3 -1
  60. package/dist/generators/scripts.d.cts.map +1 -1
  61. package/dist/generators/scripts.d.mts +3 -1
  62. package/dist/generators/scripts.d.mts.map +1 -1
  63. package/dist/generators/scripts.mjs +332 -3
  64. package/dist/generators/scripts.mjs.map +1 -1
  65. package/dist/generators/scripts.test.cjs +39 -5
  66. package/dist/generators/scripts.test.cjs.map +1 -1
  67. package/dist/generators/scripts.test.mjs +39 -5
  68. package/dist/generators/scripts.test.mjs.map +1 -1
  69. package/dist/generators/stack-manifest.cjs +1 -0
  70. package/dist/generators/stack-manifest.cjs.map +1 -1
  71. package/dist/generators/stack-manifest.d.cts +3 -2
  72. package/dist/generators/stack-manifest.d.cts.map +1 -1
  73. package/dist/generators/stack-manifest.d.mts +3 -2
  74. package/dist/generators/stack-manifest.d.mts.map +1 -1
  75. package/dist/generators/stack-manifest.mjs +1 -0
  76. package/dist/generators/stack-manifest.mjs.map +1 -1
  77. package/dist/generators/traefik.test.cjs +1 -1
  78. package/dist/generators/traefik.test.mjs +1 -1
  79. package/dist/index.cjs +8 -1
  80. package/dist/index.d.cts +5 -3
  81. package/dist/index.d.mts +5 -3
  82. package/dist/index.mjs +5 -3
  83. package/dist/migrations.test.cjs +1 -1
  84. package/dist/migrations.test.mjs +1 -1
  85. package/dist/presets/registry.cjs.map +1 -1
  86. package/dist/presets/registry.d.cts.map +1 -1
  87. package/dist/presets/registry.d.mts.map +1 -1
  88. package/dist/presets/registry.mjs.map +1 -1
  89. package/dist/presets/registry.test.cjs +1 -1
  90. package/dist/presets/registry.test.mjs +1 -1
  91. package/dist/resolver.cjs +8 -0
  92. package/dist/resolver.cjs.map +1 -1
  93. package/dist/resolver.mjs +9 -1
  94. package/dist/resolver.mjs.map +1 -1
  95. package/dist/resolver.test.cjs +47 -12
  96. package/dist/resolver.test.cjs.map +1 -1
  97. package/dist/resolver.test.mjs +47 -12
  98. package/dist/resolver.test.mjs.map +1 -1
  99. package/dist/{schema-B4c64P8N.d.cts → schema-eX44HhRp.d.mts} +62 -8
  100. package/dist/schema-eX44HhRp.d.mts.map +1 -0
  101. package/dist/{schema-CXNhYci1.d.mts → schema-tn5RK8CM.d.cts} +62 -8
  102. package/dist/schema-tn5RK8CM.d.cts.map +1 -0
  103. package/dist/schema.cjs +22 -4
  104. package/dist/schema.cjs.map +1 -1
  105. package/dist/schema.d.cts +2 -2
  106. package/dist/schema.d.mts +2 -2
  107. package/dist/schema.mjs +21 -5
  108. package/dist/schema.mjs.map +1 -1
  109. package/dist/schema.test.cjs +1 -1
  110. package/dist/schema.test.mjs +1 -1
  111. package/dist/services/definitions/apptension-saas.cjs +87 -0
  112. package/dist/services/definitions/apptension-saas.cjs.map +1 -0
  113. package/dist/services/definitions/apptension-saas.d.cts +7 -0
  114. package/dist/services/definitions/apptension-saas.d.cts.map +1 -0
  115. package/dist/services/definitions/apptension-saas.d.mts +7 -0
  116. package/dist/services/definitions/apptension-saas.d.mts.map +1 -0
  117. package/dist/services/definitions/apptension-saas.mjs +86 -0
  118. package/dist/services/definitions/apptension-saas.mjs.map +1 -0
  119. package/dist/services/definitions/boxyhq-saas.cjs +88 -0
  120. package/dist/services/definitions/boxyhq-saas.cjs.map +1 -0
  121. package/dist/services/definitions/boxyhq-saas.d.cts +7 -0
  122. package/dist/services/definitions/boxyhq-saas.d.cts.map +1 -0
  123. package/dist/services/definitions/boxyhq-saas.d.mts +7 -0
  124. package/dist/services/definitions/boxyhq-saas.d.mts.map +1 -0
  125. package/dist/services/definitions/boxyhq-saas.mjs +87 -0
  126. package/dist/services/definitions/boxyhq-saas.mjs.map +1 -0
  127. package/dist/services/definitions/cmsaas-starter.cjs +86 -0
  128. package/dist/services/definitions/cmsaas-starter.cjs.map +1 -0
  129. package/dist/services/definitions/cmsaas-starter.d.cts +7 -0
  130. package/dist/services/definitions/cmsaas-starter.d.cts.map +1 -0
  131. package/dist/services/definitions/cmsaas-starter.d.mts +7 -0
  132. package/dist/services/definitions/cmsaas-starter.d.mts.map +1 -0
  133. package/dist/services/definitions/cmsaas-starter.mjs +85 -0
  134. package/dist/services/definitions/cmsaas-starter.mjs.map +1 -0
  135. package/dist/services/definitions/index.cjs +51 -36
  136. package/dist/services/definitions/index.cjs.map +1 -1
  137. package/dist/services/definitions/index.d.cts +30 -25
  138. package/dist/services/definitions/index.d.cts.map +1 -1
  139. package/dist/services/definitions/index.d.mts +30 -25
  140. package/dist/services/definitions/index.d.mts.map +1 -1
  141. package/dist/services/definitions/index.mjs +47 -37
  142. package/dist/services/definitions/index.mjs.map +1 -1
  143. package/dist/services/definitions/ixartz-saas.cjs +88 -0
  144. package/dist/services/definitions/ixartz-saas.cjs.map +1 -0
  145. package/dist/services/definitions/ixartz-saas.d.cts +7 -0
  146. package/dist/services/definitions/ixartz-saas.d.cts.map +1 -0
  147. package/dist/services/definitions/ixartz-saas.d.mts +7 -0
  148. package/dist/services/definitions/ixartz-saas.d.mts.map +1 -0
  149. package/dist/services/definitions/ixartz-saas.mjs +87 -0
  150. package/dist/services/definitions/ixartz-saas.mjs.map +1 -0
  151. package/dist/services/definitions/mission-control.cjs +16 -2
  152. package/dist/services/definitions/mission-control.cjs.map +1 -1
  153. package/dist/services/definitions/mission-control.mjs +16 -2
  154. package/dist/services/definitions/mission-control.mjs.map +1 -1
  155. package/dist/services/definitions/open-saas.cjs +81 -0
  156. package/dist/services/definitions/open-saas.cjs.map +1 -0
  157. package/dist/services/definitions/open-saas.d.cts +7 -0
  158. package/dist/services/definitions/open-saas.d.cts.map +1 -0
  159. package/dist/services/definitions/open-saas.d.mts +7 -0
  160. package/dist/services/definitions/open-saas.d.mts.map +1 -0
  161. package/dist/services/definitions/open-saas.mjs +80 -0
  162. package/dist/services/definitions/open-saas.mjs.map +1 -0
  163. package/dist/services/registry.cjs +3 -0
  164. package/dist/services/registry.cjs.map +1 -1
  165. package/dist/services/registry.d.cts.map +1 -1
  166. package/dist/services/registry.d.mts.map +1 -1
  167. package/dist/services/registry.mjs +3 -0
  168. package/dist/services/registry.mjs.map +1 -1
  169. package/dist/services/registry.test.cjs +8 -1
  170. package/dist/services/registry.test.cjs.map +1 -1
  171. package/dist/services/registry.test.mjs +8 -1
  172. package/dist/services/registry.test.mjs.map +1 -1
  173. package/dist/{skill-manifest-BVUXU0__.mjs → skill-manifest-6XhrhWsG.mjs} +49 -1
  174. package/dist/{skill-manifest--IgY9REK.cjs.map → skill-manifest-6XhrhWsG.mjs.map} +1 -1
  175. package/dist/{skill-manifest--IgY9REK.cjs → skill-manifest-B8znSsym.cjs} +49 -1
  176. package/dist/{skill-manifest-BVUXU0__.mjs.map → skill-manifest-B8znSsym.cjs.map} +1 -1
  177. package/dist/skills/registry.cjs +3 -3
  178. package/dist/skills/registry.cjs.map +1 -1
  179. package/dist/skills/registry.mjs +3 -3
  180. package/dist/skills/registry.mjs.map +1 -1
  181. package/dist/skills/skill-manifest.cjs +1 -1
  182. package/dist/skills/skill-manifest.mjs +1 -1
  183. package/dist/track-analytics.cjs +50 -0
  184. package/dist/track-analytics.cjs.map +1 -0
  185. package/dist/track-analytics.d.cts +34 -0
  186. package/dist/track-analytics.d.cts.map +1 -0
  187. package/dist/track-analytics.d.mts +34 -0
  188. package/dist/track-analytics.d.mts.map +1 -0
  189. package/dist/track-analytics.mjs +48 -0
  190. package/dist/track-analytics.mjs.map +1 -0
  191. package/dist/track-analytics.test.cjs +91 -0
  192. package/dist/track-analytics.test.cjs.map +1 -0
  193. package/dist/track-analytics.test.d.cts +1 -0
  194. package/dist/track-analytics.test.d.mts +1 -0
  195. package/dist/track-analytics.test.mjs +92 -0
  196. package/dist/track-analytics.test.mjs.map +1 -0
  197. package/dist/types.cjs +7 -0
  198. package/dist/types.cjs.map +1 -1
  199. package/dist/types.d.cts +4 -2
  200. package/dist/types.d.cts.map +1 -1
  201. package/dist/types.d.mts +4 -2
  202. package/dist/types.d.mts.map +1 -1
  203. package/dist/types.mjs +7 -0
  204. package/dist/types.mjs.map +1 -1
  205. package/dist/validator.test.cjs +1 -1
  206. package/dist/validator.test.mjs +1 -1
  207. package/dist/version-manager.cjs +1 -1
  208. package/dist/version-manager.cjs.map +1 -1
  209. package/dist/version-manager.mjs +1 -1
  210. package/dist/version-manager.mjs.map +1 -1
  211. package/dist/version-manager.test.cjs +7 -5
  212. package/dist/version-manager.test.cjs.map +1 -1
  213. package/dist/version-manager.test.mjs +7 -5
  214. package/dist/version-manager.test.mjs.map +1 -1
  215. package/dist/{vi.2VT5v0um-DvC3SVNc.mjs → vi.2VT5v0um-C_jmO7m2.mjs} +5 -5
  216. package/dist/{vi.2VT5v0um-DvC3SVNc.mjs.map → vi.2VT5v0um-C_jmO7m2.mjs.map} +1 -1
  217. package/dist/{vi.2VT5v0um-CRqXre87.cjs → vi.2VT5v0um-iVBt6Fyq.cjs} +5 -5
  218. package/dist/{vi.2VT5v0um-CRqXre87.cjs.map → vi.2VT5v0um-iVBt6Fyq.cjs.map} +1 -1
  219. package/package.json +1 -1
  220. package/src/__snapshots__/composer.snapshot.test.ts.snap +155 -0
  221. package/src/bare-metal-partition.test.ts +4 -3
  222. package/src/composer.test.ts +4 -2
  223. package/src/composer.ts +20 -1
  224. package/src/generate.test.ts +2 -1
  225. package/src/generate.ts +10 -1
  226. package/src/generators/clone-repos.test.ts +154 -0
  227. package/src/generators/clone-repos.ts +159 -0
  228. package/src/generators/postgres-init.ts +17 -0
  229. package/src/generators/scripts.test.ts +52 -4
  230. package/src/generators/scripts.ts +351 -3
  231. package/src/generators/stack-manifest.ts +4 -2
  232. package/src/index.ts +8 -0
  233. package/src/presets/registry.ts +241 -329
  234. package/src/resolver.test.ts +53 -15
  235. package/src/resolver.ts +13 -1
  236. package/src/schema.ts +33 -4
  237. package/src/services/definitions/apptension-saas.ts +84 -0
  238. package/src/services/definitions/boxyhq-saas.ts +84 -0
  239. package/src/services/definitions/cmsaas-starter.ts +84 -0
  240. package/src/services/definitions/index.ts +90 -70
  241. package/src/services/definitions/ixartz-saas.ts +84 -0
  242. package/src/services/definitions/mission-control.ts +19 -2
  243. package/src/services/definitions/open-saas.ts +79 -0
  244. package/src/services/registry.test.ts +8 -0
  245. package/src/services/registry.ts +7 -0
  246. package/src/skills/manifest.json +64 -0
  247. package/src/skills/registry.ts +3 -3
  248. package/src/track-analytics.test.ts +82 -0
  249. package/src/track-analytics.ts +76 -0
  250. package/src/types.ts +11 -0
  251. package/src/version-manager.test.ts +10 -5
  252. package/src/version-manager.ts +1 -1
  253. package/dist/schema-B4c64P8N.d.cts.map +0 -1
  254. package/dist/schema-CXNhYci1.d.mts.map +0 -1
@@ -52,6 +52,23 @@ const DB_REQUIREMENTS: Record<string, Omit<DbRequirement, "serviceId" | "service
52
52
  openpanel: { dbName: "openpanel", dbUser: "openpanel", passwordEnvVar: "OPENPANEL_DB_PASSWORD" },
53
53
  usesend: { dbName: "usesend", dbUser: "usesend", passwordEnvVar: "USESEND_DB_PASSWORD" },
54
54
  nextcloud: { dbName: "nextcloud", dbUser: "nextcloud", passwordEnvVar: "NEXTCLOUD_DB_PASSWORD" },
55
+ // ── SaaS Boilerplates ────────────────────────────────────────────────────
56
+ "open-saas": { dbName: "opensaas", dbUser: "opensaas", passwordEnvVar: "OPENSAAS_DB_PASSWORD" },
57
+ "apptension-saas": {
58
+ dbName: "apptensionsaas",
59
+ dbUser: "apptensionsaas",
60
+ passwordEnvVar: "APPTENSION_SAAS_DB_PASSWORD",
61
+ },
62
+ "boxyhq-saas": {
63
+ dbName: "boxyhqsaas",
64
+ dbUser: "boxyhqsaas",
65
+ passwordEnvVar: "BOXYHQ_SAAS_DB_PASSWORD",
66
+ },
67
+ "ixartz-saas": {
68
+ dbName: "ixartzsaas",
69
+ dbUser: "ixartzsaas",
70
+ passwordEnvVar: "IXARTZ_SAAS_DB_PASSWORD",
71
+ },
55
72
  };
56
73
 
57
74
  /**
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
2
2
  import { generateScripts } from "./scripts.js";
3
3
 
4
4
  describe("generateScripts", () => {
5
- it("generates all 5 expected scripts", () => {
5
+ it("generates all 10 expected scripts (5 bash + 5 PowerShell)", () => {
6
6
  const result = generateScripts();
7
7
 
8
8
  const expectedScripts = [
@@ -11,6 +11,11 @@ describe("generateScripts", () => {
11
11
  "scripts/update.sh",
12
12
  "scripts/backup.sh",
13
13
  "scripts/status.sh",
14
+ "scripts/start.ps1",
15
+ "scripts/stop.ps1",
16
+ "scripts/update.ps1",
17
+ "scripts/backup.ps1",
18
+ "scripts/status.ps1",
14
19
  ];
15
20
 
16
21
  for (const script of expectedScripts) {
@@ -50,11 +55,54 @@ describe("generateScripts", () => {
50
55
  expect(result["scripts/status.sh"]).toContain("ps");
51
56
  });
52
57
 
53
- it("all scripts start with bash shebang", () => {
58
+ it("all bash scripts start with shebang", () => {
54
59
  const result = generateScripts();
55
60
 
56
- for (const [, content] of Object.entries(result)) {
57
- expect(content.startsWith("#!/")).toBe(true);
61
+ for (const [path, content] of Object.entries(result)) {
62
+ if (path.endsWith(".sh")) {
63
+ expect(content.startsWith("#!/")).toBe(true);
64
+ }
58
65
  }
59
66
  });
67
+
68
+ it("all PowerShell scripts start with #Requires", () => {
69
+ const result = generateScripts();
70
+
71
+ for (const [path, content] of Object.entries(result)) {
72
+ if (path.endsWith(".ps1")) {
73
+ expect(content.startsWith("#Requires")).toBe(true);
74
+ }
75
+ }
76
+ });
77
+
78
+ it("start.ps1 calls docker compose up", () => {
79
+ const result = generateScripts();
80
+ expect(result["scripts/start.ps1"]).toContain("docker compose");
81
+ expect(result["scripts/start.ps1"]).toContain("up");
82
+ });
83
+
84
+ it("stop.ps1 calls docker compose down", () => {
85
+ const result = generateScripts();
86
+ expect(result["scripts/stop.ps1"]).toContain("docker compose");
87
+ expect(result["scripts/stop.ps1"]).toContain("down");
88
+ });
89
+
90
+ it("update.ps1 calls docker compose pull", () => {
91
+ const result = generateScripts();
92
+ expect(result["scripts/update.ps1"]).toContain("docker compose");
93
+ expect(result["scripts/update.ps1"]).toContain("pull");
94
+ });
95
+
96
+ it("backup.ps1 references volumes or backup", () => {
97
+ const result = generateScripts();
98
+ const backup = result["scripts/backup.ps1"]!;
99
+ expect(backup).toBeDefined();
100
+ expect(backup.length).toBeGreaterThan(50);
101
+ });
102
+
103
+ it("status.ps1 calls docker compose ps", () => {
104
+ const result = generateScripts();
105
+ expect(result["scripts/status.ps1"]).toContain("docker compose");
106
+ expect(result["scripts/status.ps1"]).toContain("ps");
107
+ });
60
108
  });
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Returns a map of file paths (relative to project root) to file contents.
5
5
  */
6
- export function generateScripts(): Record<string, string> {
6
+ export function generateScripts(options?: { hasGitServices?: boolean }): Record<string, string> {
7
+ const hasGit = options?.hasGitServices ?? false;
7
8
  const files: Record<string, string> = {};
8
9
 
9
10
  // ── scripts/start.sh ────────────────────────────────────────────────────
@@ -136,6 +137,14 @@ if [ "$EMPTY_SECRETS" -gt 0 ]; then
136
137
  echo ""
137
138
  fi
138
139
 
140
+ # ── Clone git-based repositories (if any) ────────────────────────────────────
141
+
142
+ if [ -f "$SCRIPT_DIR/clone-repos.sh" ]; then
143
+ info "Cloning/updating SaaS boilerplate repositories..."
144
+ bash "$SCRIPT_DIR/clone-repos.sh"
145
+ ok "Repositories ready."
146
+ fi
147
+
139
148
  # ── Pull and start ───────────────────────────────────────────────────────────
140
149
 
141
150
  echo ""
@@ -144,7 +153,7 @@ docker compose pull --quiet 2>/dev/null || docker compose pull
144
153
 
145
154
  echo ""
146
155
  info "Starting services..."
147
- docker compose up -d --remove-orphans
156
+ docker compose up -d --remove-orphans${hasGit ? " --build" : ""}
148
157
 
149
158
  # ── Health-check loop ────────────────────────────────────────────────────────
150
159
 
@@ -243,13 +252,19 @@ cd "$PROJECT_DIR"
243
252
  echo "🐾 OpenClaw — Updating services..."
244
253
  echo ""
245
254
 
255
+ # Update git-based repositories (if any)
256
+ if [ -f "$SCRIPT_DIR/clone-repos.sh" ]; then
257
+ echo "📂 Updating SaaS boilerplate repositories..."
258
+ bash "$SCRIPT_DIR/clone-repos.sh"
259
+ fi
260
+
246
261
  # Pull latest images
247
262
  echo "📦 Pulling latest images..."
248
263
  docker compose pull
249
264
 
250
265
  echo ""
251
266
  echo "🔄 Restarting services with new images..."
252
- docker compose up -d --remove-orphans
267
+ docker compose up -d --remove-orphans${hasGit ? " --build" : ""}
253
268
 
254
269
  echo ""
255
270
  echo "⏳ Waiting for services to stabilize..."
@@ -356,6 +371,339 @@ echo "── Network ───────────────────
356
371
  echo ""
357
372
 
358
373
  docker network ls --filter "name=openclaw" --format "table {{.Name}}\\t{{.Driver}}\\t{{.Scope}}" 2>/dev/null || true
374
+ `;
375
+
376
+ // ═══════════════════════════════════════════════════════════════════════
377
+ // PowerShell equivalents
378
+ // ═══════════════════════════════════════════════════════════════════════
379
+
380
+ // ── scripts/start.ps1 ───────────────────────────────────────────────────
381
+
382
+ files["scripts/start.ps1"] = `#Requires -Version 5.1
383
+ <#
384
+ .SYNOPSIS
385
+ OpenClaw Start Script — validates prerequisites, auto-generates secrets,
386
+ creates required directories, and starts all services via Docker Compose.
387
+ #>
388
+
389
+ $ErrorActionPreference = 'Stop'
390
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
391
+ $ProjectDir = Split-Path -Parent $ScriptDir
392
+ Set-Location $ProjectDir
393
+
394
+ function Info { param($Msg) Write-Host " i $Msg" -ForegroundColor Cyan }
395
+ function Ok { param($Msg) Write-Host " + $Msg" -ForegroundColor Green }
396
+ function Warn { param($Msg) Write-Host " ! $Msg" -ForegroundColor Yellow }
397
+ function Err { param($Msg) Write-Host " x $Msg" -ForegroundColor Red }
398
+
399
+ Write-Host ""
400
+ Write-Host "OpenClaw - Starting services..." -ForegroundColor White
401
+ Write-Host ""
402
+
403
+ # ── Prerequisite checks ─────────────────────────────────────────────────
404
+ if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
405
+ Err "Docker is not installed. Please install Docker Desktop."
406
+ Write-Host " https://docs.docker.com/desktop/install/windows-install/"
407
+ exit 1
408
+ }
409
+
410
+ $composeCheck = docker compose version 2>&1
411
+ if ($LASTEXITCODE -ne 0) {
412
+ Err "Docker Compose (v2) is not available."
413
+ Write-Host " https://docs.docker.com/compose/install/"
414
+ exit 1
415
+ }
416
+
417
+ $dockerInfo = docker info 2>&1
418
+ if ($LASTEXITCODE -ne 0) {
419
+ Err "Docker daemon is not running. Please start Docker Desktop."
420
+ exit 1
421
+ }
422
+
423
+ # ── Source .env if it exists ─────────────────────────────────────────────
424
+ if (Test-Path ".env") {
425
+ Info "Loading existing .env file..."
426
+ Get-Content ".env" | ForEach-Object {
427
+ if ($_ -match '^([^#=]+)=(.*)$') {
428
+ [Environment]::SetEnvironmentVariable($Matches[1].Trim(), $Matches[2].Trim(), 'Process')
429
+ }
430
+ }
431
+ } else {
432
+ Warn ".env file not found - will create one from .env.example if available."
433
+ if (Test-Path ".env.example") {
434
+ Copy-Item ".env.example" ".env"
435
+ Info "Created .env from .env.example"
436
+ Get-Content ".env" | ForEach-Object {
437
+ if ($_ -match '^([^#=]+)=(.*)$') {
438
+ [Environment]::SetEnvironmentVariable($Matches[1].Trim(), $Matches[2].Trim(), 'Process')
439
+ }
440
+ }
441
+ }
442
+ }
443
+
444
+ # ── Auto-generate OPENCLAW_GATEWAY_TOKEN if missing ──────────────────────
445
+ if (-not $env:OPENCLAW_GATEWAY_TOKEN) {
446
+ Info "Generating OPENCLAW_GATEWAY_TOKEN..."
447
+ $bytes = New-Object byte[] 32
448
+ [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
449
+ $env:OPENCLAW_GATEWAY_TOKEN = ($bytes | ForEach-Object { $_.ToString("x2") }) -join ''
450
+
451
+ if (Test-Path ".env") {
452
+ $envContent = Get-Content ".env" -Raw
453
+ if ($envContent -match '(?m)^OPENCLAW_GATEWAY_TOKEN=') {
454
+ $envContent = $envContent -replace '(?m)^OPENCLAW_GATEWAY_TOKEN=.*', "OPENCLAW_GATEWAY_TOKEN=$($env:OPENCLAW_GATEWAY_TOKEN)"
455
+ Set-Content ".env" $envContent -NoNewline
456
+ } else {
457
+ Add-Content ".env" "OPENCLAW_GATEWAY_TOKEN=$($env:OPENCLAW_GATEWAY_TOKEN)"
458
+ }
459
+ }
460
+ Ok "Gateway token generated and saved."
461
+ }
462
+
463
+ # ── Apply defaults ───────────────────────────────────────────────────────
464
+ if (-not $env:OPENCLAW_VERSION) { $env:OPENCLAW_VERSION = "latest" }
465
+ if (-not $env:OPENCLAW_GATEWAY_PORT) { $env:OPENCLAW_GATEWAY_PORT = "18789" }
466
+ if (-not $env:OPENCLAW_BRIDGE_PORT) { $env:OPENCLAW_BRIDGE_PORT = "18790" }
467
+ if (-not $env:OPENCLAW_GATEWAY_BIND) { $env:OPENCLAW_GATEWAY_BIND = "lan" }
468
+ if (-not $env:OPENCLAW_CONFIG_DIR) { $env:OPENCLAW_CONFIG_DIR = "./openclaw/config" }
469
+ if (-not $env:OPENCLAW_WORKSPACE_DIR) { $env:OPENCLAW_WORKSPACE_DIR = "./openclaw/workspace" }
470
+
471
+ # ── Create required host directories ────────────────────────────────────
472
+ Info "Ensuring host directories exist..."
473
+ New-Item -ItemType Directory -Force -Path $env:OPENCLAW_CONFIG_DIR | Out-Null
474
+ New-Item -ItemType Directory -Force -Path $env:OPENCLAW_WORKSPACE_DIR | Out-Null
475
+ Ok "Directories ready: $($env:OPENCLAW_CONFIG_DIR), $($env:OPENCLAW_WORKSPACE_DIR)"
476
+
477
+ # ── Clone git-based repositories (if any) ─────────────────────────────
478
+ $cloneScript = Join-Path $ScriptDir "clone-repos.ps1"
479
+ if (Test-Path $cloneScript) {
480
+ Info "Cloning/updating SaaS boilerplate repositories..."
481
+ & $cloneScript
482
+ Ok "Repositories ready."
483
+ }
484
+
485
+ # ── Pull and start ───────────────────────────────────────────────────────
486
+ Write-Host ""
487
+ Info "Pulling latest images..."
488
+ docker compose pull 2>$null
489
+ if ($LASTEXITCODE -ne 0) { docker compose pull }
490
+
491
+ Write-Host ""
492
+ Info "Starting services..."
493
+ docker compose up -d --remove-orphans${hasGit ? " --build" : ""}
494
+
495
+ # ── Health-check loop ────────────────────────────────────────────────────
496
+ Write-Host ""
497
+ Info "Waiting for services to become healthy..."
498
+ Start-Sleep -Seconds 5
499
+
500
+ $retries = 0
501
+ $maxRetries = 30
502
+ while ($retries -lt $maxRetries) {
503
+ $psOutput = docker compose ps --format json 2>$null
504
+ $unhealthy = ($psOutput | Select-String -Pattern '"unhealthy"' -SimpleMatch).Count
505
+ $starting = ($psOutput | Select-String -Pattern '"starting"' -SimpleMatch).Count
506
+ if ($unhealthy -eq 0 -and $starting -eq 0) { break }
507
+ $retries++
508
+ Start-Sleep -Seconds 2
509
+ }
510
+
511
+ Write-Host ""
512
+ docker compose ps
513
+ Write-Host ""
514
+
515
+ if ($retries -ge $maxRetries) {
516
+ Warn "Some services may still be starting. Check: docker compose ps"
517
+ } else {
518
+ Ok "All services are running!"
519
+ }
520
+
521
+ # ── Print service URLs & token ───────────────────────────────────────────
522
+ $gatewayHost = if ($env:OPENCLAW_GATEWAY_BIND -eq "lan") { "0.0.0.0" } else { "localhost" }
523
+
524
+ Write-Host ""
525
+ Write-Host "==============================================================================="
526
+ Write-Host " OpenClaw is ready!"
527
+ Write-Host "==============================================================================="
528
+ Write-Host ""
529
+ Write-Host " Gateway URL: http://\${gatewayHost}:$($env:OPENCLAW_GATEWAY_PORT)"
530
+ Write-Host " Bridge (WebSocket): ws://\${gatewayHost}:$($env:OPENCLAW_BRIDGE_PORT)"
531
+ Write-Host " Config directory: $($env:OPENCLAW_CONFIG_DIR)"
532
+ Write-Host " Workspace directory: $($env:OPENCLAW_WORKSPACE_DIR)"
533
+ Write-Host ""
534
+ Write-Host " Gateway Token: $($env:OPENCLAW_GATEWAY_TOKEN)"
535
+ Write-Host ""
536
+ Write-Host " Manage:"
537
+ Write-Host " Stop: .\\scripts\\stop.ps1"
538
+ Write-Host " Status: .\\scripts\\status.ps1"
539
+ Write-Host " Update: .\\scripts\\update.ps1"
540
+ Write-Host " Logs: docker compose logs -f"
541
+ Write-Host ""
542
+ Write-Host "==============================================================================="
543
+ `;
544
+
545
+ // ── scripts/stop.ps1 ────────────────────────────────────────────────────
546
+
547
+ files["scripts/stop.ps1"] = `#Requires -Version 5.1
548
+ <#
549
+ .SYNOPSIS
550
+ OpenClaw Stop Script — gracefully stops all services.
551
+ #>
552
+
553
+ $ErrorActionPreference = 'Stop'
554
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
555
+ $ProjectDir = Split-Path -Parent $ScriptDir
556
+ Set-Location $ProjectDir
557
+
558
+ Write-Host ""
559
+ Write-Host "OpenClaw - Stopping services..." -ForegroundColor White
560
+ Write-Host ""
561
+
562
+ docker compose down --timeout 30
563
+
564
+ Write-Host ""
565
+ Write-Host " + All services stopped." -ForegroundColor Green
566
+ `;
567
+
568
+ // ── scripts/update.ps1 ──────────────────────────────────────────────────
569
+
570
+ files["scripts/update.ps1"] = `#Requires -Version 5.1
571
+ <#
572
+ .SYNOPSIS
573
+ OpenClaw Update Script — pulls latest images and restarts services.
574
+ #>
575
+
576
+ $ErrorActionPreference = 'Stop'
577
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
578
+ $ProjectDir = Split-Path -Parent $ScriptDir
579
+ Set-Location $ProjectDir
580
+
581
+ Write-Host ""
582
+ Write-Host "OpenClaw - Updating services..." -ForegroundColor White
583
+ Write-Host ""
584
+
585
+ # Update git-based repositories (if any)
586
+ $cloneScript = Join-Path $ScriptDir "clone-repos.ps1"
587
+ if (Test-Path $cloneScript) {
588
+ Write-Host " Updating SaaS boilerplate repositories..." -ForegroundColor Cyan
589
+ & $cloneScript
590
+ }
591
+
592
+ Write-Host " Pulling latest images..." -ForegroundColor Cyan
593
+ docker compose pull
594
+
595
+ Write-Host ""
596
+ Write-Host " Restarting services with new images..." -ForegroundColor Cyan
597
+ docker compose up -d --remove-orphans${hasGit ? " --build" : ""}
598
+
599
+ Write-Host ""
600
+ Write-Host " Waiting for services to stabilize..." -ForegroundColor Cyan
601
+ Start-Sleep -Seconds 10
602
+
603
+ docker compose ps
604
+
605
+ Write-Host ""
606
+ Write-Host " + Update complete!" -ForegroundColor Green
607
+ `;
608
+
609
+ // ── scripts/backup.ps1 ──────────────────────────────────────────────────
610
+
611
+ files["scripts/backup.ps1"] = `#Requires -Version 5.1
612
+ <#
613
+ .SYNOPSIS
614
+ OpenClaw Backup Script — backs up all named Docker volumes to a timestamped directory.
615
+ #>
616
+
617
+ $ErrorActionPreference = 'Stop'
618
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
619
+ $ProjectDir = Split-Path -Parent $ScriptDir
620
+ Set-Location $ProjectDir
621
+
622
+ $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
623
+ $backupDir = Join-Path $ProjectDir "backups\\$timestamp"
624
+ New-Item -ItemType Directory -Force -Path $backupDir | Out-Null
625
+
626
+ Write-Host ""
627
+ Write-Host "OpenClaw - Backing up volumes..." -ForegroundColor White
628
+ Write-Host " Backup directory: $backupDir"
629
+ Write-Host ""
630
+
631
+ # Get project name from docker compose
632
+ $projectName = "openclaw"
633
+ try {
634
+ $configJson = docker compose config --format json 2>$null | ConvertFrom-Json
635
+ if ($configJson.name) { $projectName = $configJson.name }
636
+ } catch {}
637
+
638
+ # List all volumes for this project
639
+ $volumes = docker volume ls --filter "name=$projectName" --format "{{.Name}}" 2>$null
640
+ if (-not $volumes) {
641
+ Write-Host " ! No volumes found for project: $projectName" -ForegroundColor Yellow
642
+ Write-Host " Trying to list all openclaw volumes..."
643
+ $volumes = docker volume ls --filter "name=openclaw" --format "{{.Name}}" 2>$null
644
+ }
645
+
646
+ if (-not $volumes) {
647
+ Write-Host " x No volumes found to back up." -ForegroundColor Red
648
+ exit 1
649
+ }
650
+
651
+ $backedUp = 0
652
+ foreach ($volume in $volumes) {
653
+ $vol = $volume.Trim()
654
+ if (-not $vol) { continue }
655
+ Write-Host " Backing up: $vol" -ForegroundColor Cyan
656
+ docker run --rm -v "\${vol}:/source:ro" -v "\${backupDir}:/backup" alpine tar czf "/backup/$vol.tar.gz" -C /source .
657
+ $size = (Get-Item (Join-Path $backupDir "$vol.tar.gz")).Length / 1MB
658
+ Write-Host " + $vol ($([math]::Round($size, 1))MB)" -ForegroundColor Green
659
+ $backedUp++
660
+ }
661
+
662
+ $totalSize = ((Get-ChildItem $backupDir -Recurse | Measure-Object -Property Length -Sum).Sum) / 1MB
663
+ Write-Host ""
664
+ Write-Host " + Backed up $backedUp volume(s) ($([math]::Round($totalSize, 1))MB total)" -ForegroundColor Green
665
+ Write-Host " Location: $backupDir"
666
+ `;
667
+
668
+ // ── scripts/status.ps1 ──────────────────────────────────────────────────
669
+
670
+ files["scripts/status.ps1"] = `#Requires -Version 5.1
671
+ <#
672
+ .SYNOPSIS
673
+ OpenClaw Status Script — shows the current status of all services.
674
+ #>
675
+
676
+ $ErrorActionPreference = 'Stop'
677
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
678
+ $ProjectDir = Split-Path -Parent $ScriptDir
679
+ Set-Location $ProjectDir
680
+
681
+ Write-Host ""
682
+ Write-Host "OpenClaw - Service Status" -ForegroundColor White
683
+ Write-Host ""
684
+
685
+ # Show compose status
686
+ docker compose ps
687
+
688
+ Write-Host ""
689
+ Write-Host "-- Resource Usage ----------------------------------------------------------"
690
+ Write-Host ""
691
+
692
+ try { docker compose top 2>$null } catch {}
693
+
694
+ Write-Host ""
695
+ Write-Host "-- Disk Usage --------------------------------------------------------------"
696
+ Write-Host ""
697
+
698
+ try { docker system df 2>$null } catch {}
699
+
700
+ Write-Host ""
701
+ Write-Host "-- Network -----------------------------------------------------------------"
702
+ Write-Host ""
703
+
704
+ try {
705
+ docker network ls --filter "name=openclaw" --format "table {{.Name}}\\t{{.Driver}}\\t{{.Scope}}" 2>$null
706
+ } catch {}
359
707
  `;
360
708
 
361
709
  return files;
@@ -13,8 +13,9 @@ export interface StackManifestService {
13
13
  name: string;
14
14
  category: string;
15
15
  icon: string;
16
- image: string;
17
- imageTag: string;
16
+ image?: string;
17
+ imageTag?: string;
18
+ gitRepoUrl?: string;
18
19
  ports: { container: number; host?: number; exposed: boolean; description: string }[];
19
20
  docsUrl: string;
20
21
  addedBy: string;
@@ -72,6 +73,7 @@ export function generateStackManifest(
72
73
  icon: def.icon,
73
74
  image: def.image,
74
75
  imageTag: def.imageTag,
76
+ gitRepoUrl: def.gitSource?.repoUrl,
75
77
  ports: def.ports.map((p) => ({
76
78
  container: p.container,
77
79
  host: p.host,
package/src/index.ts CHANGED
@@ -28,6 +28,7 @@ export {
28
28
  export { StackConfigError, ValidationError } from "./errors.js";
29
29
  export { generate, generateServicesDoc } from "./generate.js";
30
30
  export { generateCaddyfile } from "./generators/caddy.js";
31
+ export { generateCloneScripts } from "./generators/clone-repos.js";
31
32
  export type { EnvVarGroup } from "./generators/env.js";
32
33
  export { generateEnvFiles, getStructuredEnvVars } from "./generators/env.js";
33
34
  export {
@@ -44,6 +45,9 @@ export { generatePrometheusConfig } from "./generators/prometheus.js";
44
45
  export { generateReadme } from "./generators/readme.js";
45
46
  export { generateScripts } from "./generators/scripts.js";
46
47
  export { generateSkillFiles } from "./generators/skills.js";
48
+ // ─── Analytics ─────────────────────────────────────────────────────────────
49
+ export type { AnalyticsPayload } from "./track-analytics.js";
50
+ export { buildAnalyticsPayload, trackAnalytics } from "./track-analytics.js";
47
51
  export type {
48
52
  StackManifest,
49
53
  StackManifestService,
@@ -69,6 +73,7 @@ export { resolve } from "./resolver.js";
69
73
  export {
70
74
  AddedDependencySchema,
71
75
  ApiErrorSchema,
76
+ BuildContextSchema,
72
77
  ComposeOptionsSchema,
73
78
  DeploymentTargetSchema,
74
79
  DeploymentTypeSchema,
@@ -77,6 +82,7 @@ export {
77
82
  EnvVariableSchema,
78
83
  ErrorSchema,
79
84
  GenerationInputSchema,
85
+ GitSourceSchema,
80
86
  HealthCheckSchema,
81
87
  MaturitySchema,
82
88
  NativePlatformSchema,
@@ -127,6 +133,7 @@ export type {
127
133
  AddedDependency,
128
134
  AiProvider,
129
135
  ApiError,
136
+ BuildContext,
130
137
  CategoryInfo,
131
138
  ComposeOptions,
132
139
  Deploy,
@@ -138,6 +145,7 @@ export type {
138
145
  GenerationInput,
139
146
  GenerationMetadata,
140
147
  GenerationResult,
148
+ GitSource,
141
149
  GsdRuntime,
142
150
  HealthCheck,
143
151
  Maturity,