@better-openclaw/core 1.0.9 → 1.0.11

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 (75) hide show
  1. package/dist/bare-metal-partition.test.mjs +1 -1
  2. package/dist/composer.snapshot.test.mjs +1 -1
  3. package/dist/composer.test.mjs +1 -1
  4. package/dist/generate.d.mts.map +1 -1
  5. package/dist/generate.mjs +7 -1
  6. package/dist/generate.mjs.map +1 -1
  7. package/dist/generate.test.mjs +1 -1
  8. package/dist/generators/bare-metal-install.test.mjs +1 -1
  9. package/dist/generators/caddy.test.d.mts +1 -0
  10. package/dist/generators/caddy.test.mjs +45 -0
  11. package/dist/generators/caddy.test.mjs.map +1 -0
  12. package/dist/generators/env.test.d.mts +1 -0
  13. package/dist/generators/env.test.mjs +60 -0
  14. package/dist/generators/env.test.mjs.map +1 -0
  15. package/dist/generators/health-check.d.mts +18 -0
  16. package/dist/generators/health-check.d.mts.map +1 -0
  17. package/dist/generators/health-check.mjs +705 -0
  18. package/dist/generators/health-check.mjs.map +1 -0
  19. package/dist/generators/health-check.test.d.mts +1 -0
  20. package/dist/generators/health-check.test.mjs +85 -0
  21. package/dist/generators/health-check.test.mjs.map +1 -0
  22. package/dist/generators/scripts.test.d.mts +1 -0
  23. package/dist/generators/scripts.test.mjs +52 -0
  24. package/dist/generators/scripts.test.mjs.map +1 -0
  25. package/dist/generators/traefik.test.mjs +1 -1
  26. package/dist/generators/traefik.test.mjs.map +1 -1
  27. package/dist/index.d.mts +4 -2
  28. package/dist/index.mjs +3 -1
  29. package/dist/migrations.d.mts.map +1 -1
  30. package/dist/migrations.mjs.map +1 -1
  31. package/dist/migrations.test.mjs +1 -1
  32. package/dist/migrations.test.mjs.map +1 -1
  33. package/dist/presets/registry.test.mjs +1 -1
  34. package/dist/resolver.test.mjs +1 -1
  35. package/dist/schema.test.mjs +1 -1
  36. package/dist/services/definitions/convex.mjs.map +1 -1
  37. package/dist/services/definitions/desktop-environment.mjs.map +1 -1
  38. package/dist/services/definitions/index.d.mts +2 -2
  39. package/dist/services/definitions/index.mjs +3 -3
  40. package/dist/services/definitions/index.mjs.map +1 -1
  41. package/dist/services/definitions/mission-control.mjs.map +1 -1
  42. package/dist/services/definitions/stream-gateway.mjs.map +1 -1
  43. package/dist/services/registry.test.mjs +1 -1
  44. package/dist/skills/registry.d.mts.map +1 -1
  45. package/dist/skills/registry.mjs +498 -6
  46. package/dist/skills/registry.mjs.map +1 -1
  47. package/dist/skills/skill-manifest.d.mts +20 -0
  48. package/dist/skills/skill-manifest.d.mts.map +1 -0
  49. package/dist/skills/skill-manifest.mjs +28 -0
  50. package/dist/skills/skill-manifest.mjs.map +1 -0
  51. package/dist/validator.test.mjs +1 -1
  52. package/dist/version-manager.test.mjs +1 -1
  53. package/dist/version-manager.test.mjs.map +1 -1
  54. package/dist/{vi.2VT5v0um-Qk6MgAnK.mjs → vi.2VT5v0um-YSByewHe.mjs} +5 -5
  55. package/dist/{vi.2VT5v0um-Qk6MgAnK.mjs.map → vi.2VT5v0um-YSByewHe.mjs.map} +1 -1
  56. package/package.json +1 -1
  57. package/src/generate.ts +15 -3
  58. package/src/generators/caddy.test.ts +56 -0
  59. package/src/generators/env.test.ts +73 -0
  60. package/src/generators/health-check.test.ts +118 -0
  61. package/src/generators/health-check.ts +774 -0
  62. package/src/generators/scripts.test.ts +60 -0
  63. package/src/generators/traefik.test.ts +9 -17
  64. package/src/index.ts +12 -6
  65. package/src/migrations.test.ts +1 -1
  66. package/src/migrations.ts +1 -4
  67. package/src/services/definitions/convex.ts +2 -4
  68. package/src/services/definitions/desktop-environment.ts +1 -9
  69. package/src/services/definitions/index.ts +6 -6
  70. package/src/services/definitions/mission-control.ts +2 -4
  71. package/src/services/definitions/stream-gateway.ts +1 -2
  72. package/src/skills/registry.ts +336 -6
  73. package/src/skills/skill-manifest.ts +52 -0
  74. package/src/version-manager.test.ts +15 -4
  75. package/tsdown.config.ts +6 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-openclaw/core",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "private": false,
5
5
  "description": "Core logic for better-openclaw: schemas, service registry, resolver, composer, validators and more",
6
6
  "packageManager": "pnpm@9.15.4",
package/src/generate.ts CHANGED
@@ -4,11 +4,12 @@ import {
4
4
  resolvedWithOnlyServices,
5
5
  } from "./bare-metal-partition.js";
6
6
  import { composeMultiFile } from "./composer.js";
7
+ import { StackConfigError, ValidationError } from "./errors.js";
7
8
  import { generateBareMetalInstall } from "./generators/bare-metal-install.js";
8
9
  import { generateCaddyfile } from "./generators/caddy.js";
9
10
  import { generateEnvFiles } from "./generators/env.js";
10
- import { generateTraefikConfig } from "./generators/traefik.js";
11
11
  import { generateGrafanaConfig, generateGrafanaDashboard } from "./generators/grafana.js";
12
+ import { generateHealthCheck } from "./generators/health-check.js";
12
13
  import { generateN8nWorkflows } from "./generators/n8n-workflows.js";
13
14
  import { generateNativeInstallScripts } from "./generators/native-services.js";
14
15
  import { generatePostgresInit } from "./generators/postgres-init.js";
@@ -16,6 +17,7 @@ import { generatePrometheusConfig } from "./generators/prometheus.js";
16
17
  import { generateReadme } from "./generators/readme.js";
17
18
  import { generateScripts } from "./generators/scripts.js";
18
19
  import { generateSkillFiles } from "./generators/skills.js";
20
+ import { generateTraefikConfig } from "./generators/traefik.js";
19
21
  import { migrateConfig } from "./migrations.js";
20
22
  import { resolve } from "./resolver.js";
21
23
  import type {
@@ -25,7 +27,6 @@ import type {
25
27
  Platform,
26
28
  ResolverInput,
27
29
  } from "./types.js";
28
- import { StackConfigError, ValidationError } from "./errors.js";
29
30
  import { validate } from "./validator.js";
30
31
 
31
32
  /** Resolver/compose only support linux image platforms; normalize for bare-metal (windows/macos). */
@@ -103,7 +104,9 @@ export function generate(rawInput: GenerationInput): GenerationResult {
103
104
  generateSecrets: input.generateSecrets,
104
105
  });
105
106
  if (!validation.valid) {
106
- throw new ValidationError(`Validation failed: ${validation.errors.map((e) => e.message).join("; ")}`);
107
+ throw new ValidationError(
108
+ `Validation failed: ${validation.errors.map((e) => e.message).join("; ")}`,
109
+ );
107
110
  }
108
111
 
109
112
  // 4. Generate all files
@@ -154,6 +157,15 @@ export function generate(rawInput: GenerationInput): GenerationResult {
154
157
  files[path] = content;
155
158
  }
156
159
 
160
+ // Health check scripts (dynamic, stack-specific)
161
+ const healthCheckFiles = generateHealthCheck(resolved, {
162
+ projectName: input.projectName,
163
+ deploymentType: input.deploymentType,
164
+ });
165
+ for (const [path, content] of Object.entries(healthCheckFiles)) {
166
+ files[path] = content;
167
+ }
168
+
157
169
  // n8n workflows
158
170
  const n8nWorkflows = generateN8nWorkflows(resolved);
159
171
  for (const [path, content] of Object.entries(n8nWorkflows)) {
@@ -0,0 +1,56 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { generate } from "../generate.js";
3
+
4
+ describe("generateCaddyfile (via generate)", () => {
5
+ const baseInput = {
6
+ projectName: "caddy-test",
7
+ services: ["redis", "n8n"],
8
+ skillPacks: [] as string[],
9
+ proxy: "caddy" as const,
10
+ domain: "example.com",
11
+ gpu: false,
12
+ platform: "linux/amd64" as const,
13
+ deployment: "local" as const,
14
+ generateSecrets: true,
15
+ openclawVersion: "latest",
16
+ };
17
+
18
+ it("generates Caddyfile when proxy is caddy", () => {
19
+ const result = generate(baseInput);
20
+
21
+ expect(result.files).toHaveProperty("caddy/Caddyfile");
22
+ expect(result.files["caddy/Caddyfile"]!.length).toBeGreaterThan(0);
23
+ });
24
+
25
+ it("does not generate Caddyfile when proxy is none", () => {
26
+ const result = generate({
27
+ ...baseInput,
28
+ proxy: "none",
29
+ });
30
+
31
+ expect(result.files).not.toHaveProperty("caddy/Caddyfile");
32
+ });
33
+
34
+ it("Caddyfile contains the domain", () => {
35
+ const result = generate(baseInput);
36
+ const caddyfile = result.files["caddy/Caddyfile"]!;
37
+
38
+ expect(caddyfile).toContain("example.com");
39
+ });
40
+
41
+ it("Caddyfile includes reverse proxy directives for services with exposed ports", () => {
42
+ const result = generate(baseInput);
43
+ const caddyfile = result.files["caddy/Caddyfile"]!;
44
+
45
+ // Should reference n8n since it has exposed ports
46
+ expect(caddyfile).toContain("n8n");
47
+ });
48
+
49
+ it("Caddyfile includes TLS configuration", () => {
50
+ const result = generate(baseInput);
51
+ const caddyfile = result.files["caddy/Caddyfile"]!;
52
+
53
+ // Caddy auto-enables TLS, so should reference HTTPS or TLS
54
+ expect(caddyfile.length).toBeGreaterThan(50);
55
+ });
56
+ });
@@ -0,0 +1,73 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { generate } from "../generate.js";
3
+
4
+ describe("generateEnvFiles (via generate)", () => {
5
+ const baseInput = {
6
+ projectName: "env-test",
7
+ services: ["redis"],
8
+ skillPacks: [] as string[],
9
+ proxy: "none" as const,
10
+ gpu: false,
11
+ platform: "linux/amd64" as const,
12
+ deployment: "local" as const,
13
+ generateSecrets: true,
14
+ openclawVersion: "latest",
15
+ };
16
+
17
+ it("generates .env and .env.example files", () => {
18
+ const result = generate(baseInput);
19
+
20
+ expect(result.files).toHaveProperty(".env");
21
+ expect(result.files).toHaveProperty(".env.example");
22
+ });
23
+
24
+ it(".env.example has empty values for secrets", () => {
25
+ const result = generate(baseInput);
26
+ const envExample = result.files[".env.example"]!;
27
+
28
+ // .env.example should have placeholder empty values for secrets
29
+ expect(envExample).toContain("REDIS_PASSWORD=");
30
+ });
31
+
32
+ it(".env has populated secret values when generateSecrets is true", () => {
33
+ const result = generate(baseInput);
34
+ const env = result.files[".env"]!;
35
+
36
+ // Find REDIS_PASSWORD line and check it has a value
37
+ const redisLine = env.split("\n").find((l) => l.startsWith("REDIS_PASSWORD="));
38
+ expect(redisLine).toBeDefined();
39
+ // Value should not be empty
40
+ const value = redisLine!.split("=")[1];
41
+ expect(value!.length).toBeGreaterThan(0);
42
+ });
43
+
44
+ it("env files contain service-specific variables", () => {
45
+ const result = generate({
46
+ ...baseInput,
47
+ services: ["redis", "postgresql", "n8n"],
48
+ });
49
+ const env = result.files[".env"]!;
50
+
51
+ expect(env).toContain("REDIS_PASSWORD");
52
+ expect(env).toContain("POSTGRES_PASSWORD");
53
+ });
54
+
55
+ it("env files group variables by service with comments", () => {
56
+ const result = generate(baseInput);
57
+ const envExample = result.files[".env.example"]!;
58
+
59
+ // Should have comment sections
60
+ expect(envExample).toContain("#");
61
+ });
62
+
63
+ it(".env references domain when proxy is set", () => {
64
+ const result = generate({
65
+ ...baseInput,
66
+ proxy: "caddy",
67
+ domain: "example.com",
68
+ });
69
+ const env = result.files[".env"]!;
70
+
71
+ expect(env).toContain("example.com");
72
+ });
73
+ });
@@ -0,0 +1,118 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { generate } from "../generate.js";
3
+
4
+ describe("generateHealthCheck (via generate)", () => {
5
+ const baseInput = {
6
+ projectName: "health-test",
7
+ services: ["redis", "postgresql"],
8
+ skillPacks: [] as string[],
9
+ proxy: "none" as const,
10
+ gpu: false,
11
+ platform: "linux/amd64" as const,
12
+ deployment: "local" as const,
13
+ generateSecrets: true,
14
+ openclawVersion: "latest",
15
+ };
16
+
17
+ it("generates health-check.sh and health-check.ps1", () => {
18
+ const result = generate(baseInput);
19
+
20
+ expect(result.files).toHaveProperty("scripts/health-check.sh");
21
+ expect(result.files).toHaveProperty("scripts/health-check.ps1");
22
+ });
23
+
24
+ it("health-check.sh contains project name", () => {
25
+ const result = generate(baseInput);
26
+ const sh = result.files["scripts/health-check.sh"]!;
27
+
28
+ expect(sh).toContain("health-test");
29
+ });
30
+
31
+ it("health-check.sh contains service-specific checks for each resolved service", () => {
32
+ const result = generate(baseInput);
33
+ const sh = result.files["scripts/health-check.sh"]!;
34
+
35
+ expect(sh).toContain("redis");
36
+ expect(sh).toContain("postgresql");
37
+ });
38
+
39
+ it("health-check.sh includes port checks for exposed ports", () => {
40
+ const result = generate(baseInput);
41
+ const sh = result.files["scripts/health-check.sh"]!;
42
+
43
+ // Redis exposes port 6379, PostgreSQL exposes 5432
44
+ expect(sh).toContain("6379");
45
+ expect(sh).toContain("5432");
46
+ });
47
+
48
+ it("health-check.sh has usage/help docs", () => {
49
+ const result = generate(baseInput);
50
+ const sh = result.files["scripts/health-check.sh"]!;
51
+
52
+ expect(sh).toContain("--quick");
53
+ expect(sh).toContain("--json");
54
+ expect(sh).toContain("--verbose");
55
+ });
56
+
57
+ it("health-check.sh starts with shebang", () => {
58
+ const result = generate(baseInput);
59
+ const sh = result.files["scripts/health-check.sh"]!;
60
+
61
+ expect(sh.startsWith("#!/usr/bin/env bash")).toBe(true);
62
+ });
63
+
64
+ it("health-check.ps1 contains project name", () => {
65
+ const result = generate(baseInput);
66
+ const ps1 = result.files["scripts/health-check.ps1"]!;
67
+
68
+ expect(ps1).toContain("health-test");
69
+ });
70
+
71
+ it("health-check.ps1 contains service checks", () => {
72
+ const result = generate(baseInput);
73
+ const ps1 = result.files["scripts/health-check.ps1"]!;
74
+
75
+ expect(ps1).toContain("redis");
76
+ expect(ps1).toContain("postgresql");
77
+ });
78
+
79
+ it("health-check.ps1 includes PowerShell-style parameters", () => {
80
+ const result = generate(baseInput);
81
+ const ps1 = result.files["scripts/health-check.ps1"]!;
82
+
83
+ expect(ps1).toContain("[switch]$Quick");
84
+ expect(ps1).toContain("[switch]$Json");
85
+ });
86
+
87
+ it("health check scripts include all resolved services including dependencies", () => {
88
+ const result = generate({
89
+ ...baseInput,
90
+ services: ["postiz"], // postiz depends on redis and postgresql
91
+ });
92
+ const sh = result.files["scripts/health-check.sh"]!;
93
+
94
+ expect(sh).toContain("postiz");
95
+ // Dependencies should be auto-resolved and included
96
+ expect(sh).toContain("redis");
97
+ expect(sh).toContain("postgresql");
98
+ });
99
+
100
+ it("health check script includes health check commands when service defines one", () => {
101
+ const result = generate(baseInput);
102
+ const sh = result.files["scripts/health-check.sh"]!;
103
+
104
+ // Redis has a healthcheck command (redis-cli ping)
105
+ expect(sh).toContain("check_health_cmd");
106
+ });
107
+
108
+ it("health check scripts contain the phase structure", () => {
109
+ const result = generate(baseInput);
110
+ const sh = result.files["scripts/health-check.sh"]!;
111
+
112
+ expect(sh).toContain("Phase 1");
113
+ expect(sh).toContain("phase_environment");
114
+ expect(sh).toContain("check_container");
115
+ expect(sh).toContain("check_port");
116
+ expect(sh).toContain("phase_logs");
117
+ });
118
+ });