@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.
- package/dist/bare-metal-partition.test.mjs +1 -1
- package/dist/composer.snapshot.test.mjs +1 -1
- package/dist/composer.test.mjs +1 -1
- package/dist/generate.d.mts.map +1 -1
- package/dist/generate.mjs +7 -1
- package/dist/generate.mjs.map +1 -1
- package/dist/generate.test.mjs +1 -1
- package/dist/generators/bare-metal-install.test.mjs +1 -1
- package/dist/generators/caddy.test.d.mts +1 -0
- package/dist/generators/caddy.test.mjs +45 -0
- package/dist/generators/caddy.test.mjs.map +1 -0
- package/dist/generators/env.test.d.mts +1 -0
- package/dist/generators/env.test.mjs +60 -0
- package/dist/generators/env.test.mjs.map +1 -0
- package/dist/generators/health-check.d.mts +18 -0
- package/dist/generators/health-check.d.mts.map +1 -0
- package/dist/generators/health-check.mjs +705 -0
- package/dist/generators/health-check.mjs.map +1 -0
- package/dist/generators/health-check.test.d.mts +1 -0
- package/dist/generators/health-check.test.mjs +85 -0
- package/dist/generators/health-check.test.mjs.map +1 -0
- package/dist/generators/scripts.test.d.mts +1 -0
- package/dist/generators/scripts.test.mjs +52 -0
- package/dist/generators/scripts.test.mjs.map +1 -0
- package/dist/generators/traefik.test.mjs +1 -1
- package/dist/generators/traefik.test.mjs.map +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +3 -1
- package/dist/migrations.d.mts.map +1 -1
- package/dist/migrations.mjs.map +1 -1
- package/dist/migrations.test.mjs +1 -1
- package/dist/migrations.test.mjs.map +1 -1
- package/dist/presets/registry.test.mjs +1 -1
- package/dist/resolver.test.mjs +1 -1
- package/dist/schema.test.mjs +1 -1
- package/dist/services/definitions/convex.mjs.map +1 -1
- package/dist/services/definitions/desktop-environment.mjs.map +1 -1
- package/dist/services/definitions/index.d.mts +2 -2
- package/dist/services/definitions/index.mjs +3 -3
- package/dist/services/definitions/index.mjs.map +1 -1
- package/dist/services/definitions/mission-control.mjs.map +1 -1
- package/dist/services/definitions/stream-gateway.mjs.map +1 -1
- package/dist/services/registry.test.mjs +1 -1
- package/dist/skills/registry.d.mts.map +1 -1
- package/dist/skills/registry.mjs +498 -6
- package/dist/skills/registry.mjs.map +1 -1
- package/dist/skills/skill-manifest.d.mts +20 -0
- package/dist/skills/skill-manifest.d.mts.map +1 -0
- package/dist/skills/skill-manifest.mjs +28 -0
- package/dist/skills/skill-manifest.mjs.map +1 -0
- package/dist/validator.test.mjs +1 -1
- package/dist/version-manager.test.mjs +1 -1
- package/dist/version-manager.test.mjs.map +1 -1
- package/dist/{vi.2VT5v0um-Qk6MgAnK.mjs → vi.2VT5v0um-YSByewHe.mjs} +5 -5
- package/dist/{vi.2VT5v0um-Qk6MgAnK.mjs.map → vi.2VT5v0um-YSByewHe.mjs.map} +1 -1
- package/package.json +1 -1
- package/src/generate.ts +15 -3
- package/src/generators/caddy.test.ts +56 -0
- package/src/generators/env.test.ts +73 -0
- package/src/generators/health-check.test.ts +118 -0
- package/src/generators/health-check.ts +774 -0
- package/src/generators/scripts.test.ts +60 -0
- package/src/generators/traefik.test.ts +9 -17
- package/src/index.ts +12 -6
- package/src/migrations.test.ts +1 -1
- package/src/migrations.ts +1 -4
- package/src/services/definitions/convex.ts +2 -4
- package/src/services/definitions/desktop-environment.ts +1 -9
- package/src/services/definitions/index.ts +6 -6
- package/src/services/definitions/mission-control.ts +2 -4
- package/src/services/definitions/stream-gateway.ts +1 -2
- package/src/skills/registry.ts +336 -6
- package/src/skills/skill-manifest.ts +52 -0
- package/src/version-manager.test.ts +15 -4
- package/tsdown.config.ts +6 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-
|
|
1
|
+
import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-YSByewHe.mjs";
|
|
2
2
|
import { partitionBareMetal, platformToNativePlatform, resolvedWithOnlyServices } from "./bare-metal-partition.mjs";
|
|
3
3
|
import { resolve } from "./resolver.mjs";
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-
|
|
1
|
+
import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-YSByewHe.mjs";
|
|
2
2
|
import { resolve } from "./resolver.mjs";
|
|
3
3
|
import { composeMultiFile } from "./composer.mjs";
|
|
4
4
|
|
package/dist/composer.test.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-
|
|
1
|
+
import { n as describe, r as it, t as globalExpect } from "./vi.2VT5v0um-YSByewHe.mjs";
|
|
2
2
|
import { resolve } from "./resolver.mjs";
|
|
3
3
|
import { compose } from "./composer.mjs";
|
|
4
4
|
import { parse } from "yaml";
|
package/dist/generate.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.mts","names":[],"sources":["../src/generate.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"generate.d.mts","names":[],"sources":["../src/generate.ts"],"mappings":";;;;;AAyCA;;iBAAgB,QAAA,CAAS,QAAA,EAAU,eAAA,GAAkB,gBAAA;AAAA,iBAsNrC,mBAAA,CAAoB,QAAA,EAAD,cAAA"}
|
package/dist/generate.mjs
CHANGED
|
@@ -6,14 +6,15 @@ import { generateBareMetalInstall } from "./generators/bare-metal-install.mjs";
|
|
|
6
6
|
import { generateCaddyfile } from "./generators/caddy.mjs";
|
|
7
7
|
import { generatePostgresInit } from "./generators/postgres-init.mjs";
|
|
8
8
|
import { generateEnvFiles } from "./generators/env.mjs";
|
|
9
|
-
import { generateTraefikConfig } from "./generators/traefik.mjs";
|
|
10
9
|
import { generateGrafanaConfig, generateGrafanaDashboard } from "./generators/grafana.mjs";
|
|
10
|
+
import { generateHealthCheck } from "./generators/health-check.mjs";
|
|
11
11
|
import { generateN8nWorkflows } from "./generators/n8n-workflows.mjs";
|
|
12
12
|
import { generateNativeInstallScripts } from "./generators/native-services.mjs";
|
|
13
13
|
import { generatePrometheusConfig } from "./generators/prometheus.mjs";
|
|
14
14
|
import { generateReadme } from "./generators/readme.mjs";
|
|
15
15
|
import { generateScripts } from "./generators/scripts.mjs";
|
|
16
16
|
import { generateSkillFiles } from "./generators/skills.mjs";
|
|
17
|
+
import { generateTraefikConfig } from "./generators/traefik.mjs";
|
|
17
18
|
import { migrateConfig } from "./migrations.mjs";
|
|
18
19
|
import { validate } from "./validator.mjs";
|
|
19
20
|
|
|
@@ -98,6 +99,11 @@ function generate(rawInput) {
|
|
|
98
99
|
});
|
|
99
100
|
const scripts = generateScripts();
|
|
100
101
|
for (const [path, content] of Object.entries(scripts)) files[path] = content;
|
|
102
|
+
const healthCheckFiles = generateHealthCheck(resolved, {
|
|
103
|
+
projectName: input.projectName,
|
|
104
|
+
deploymentType: input.deploymentType
|
|
105
|
+
});
|
|
106
|
+
for (const [path, content] of Object.entries(healthCheckFiles)) files[path] = content;
|
|
101
107
|
const n8nWorkflows = generateN8nWorkflows(resolved);
|
|
102
108
|
for (const [path, content] of Object.entries(n8nWorkflows)) files[path] = content;
|
|
103
109
|
const postgresInit = generatePostgresInit(resolved);
|
package/dist/generate.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.mjs","names":[],"sources":["../src/generate.ts"],"sourcesContent":["import {\n\tpartitionBareMetal,\n\tplatformToNativePlatform,\n\tresolvedWithOnlyServices,\n} from \"./bare-metal-partition.js\";\nimport { composeMultiFile } from \"./composer.js\";\nimport { generateBareMetalInstall } from \"./generators/bare-metal-install.js\";\nimport { generateCaddyfile } from \"./generators/caddy.js\";\nimport { generateEnvFiles } from \"./generators/env.js\";\nimport { generateTraefikConfig } from \"./generators/traefik.js\";\nimport { generateGrafanaConfig, generateGrafanaDashboard } from \"./generators/grafana.js\";\nimport { generateN8nWorkflows } from \"./generators/n8n-workflows.js\";\nimport { generateNativeInstallScripts } from \"./generators/native-services.js\";\nimport { generatePostgresInit } from \"./generators/postgres-init.js\";\nimport { generatePrometheusConfig } from \"./generators/prometheus.js\";\nimport { generateReadme } from \"./generators/readme.js\";\nimport { generateScripts } from \"./generators/scripts.js\";\nimport { generateSkillFiles } from \"./generators/skills.js\";\nimport { migrateConfig } from \"./migrations.js\";\nimport { resolve } from \"./resolver.js\";\nimport type {\n\tGeneratedFiles,\n\tGenerationInput,\n\tGenerationResult,\n\tPlatform,\n\tResolverInput,\n} from \"./types.js\";\nimport { StackConfigError, ValidationError } from \"./errors.js\";\nimport { validate } from \"./validator.js\";\n\n/** Resolver/compose only support linux image platforms; normalize for bare-metal (windows/macos). */\nfunction getComposePlatform(platform: Platform): \"linux/amd64\" | \"linux/arm64\" {\n\tif (platform === \"linux/amd64\" || platform === \"linux/arm64\") return platform;\n\treturn \"linux/amd64\";\n}\n\n/**\n * Main orchestration function: takes generation input, resolves dependencies,\n * generates all files, validates, and returns the complete file tree.\n */\nexport function generate(rawInput: GenerationInput): GenerationResult {\n\t// Apply config migrations if needed\n\tconst input = migrateConfig(rawInput as Record<string, unknown>) as GenerationInput;\n\n\tconst composePlatform = getComposePlatform(input.platform);\n\n\t// 1. Resolve dependencies\n\tconst resolverInput: ResolverInput = {\n\t\tservices: input.services,\n\t\tskillPacks: input.skillPacks,\n\t\tproxy: input.proxy,\n\t\tgpu: input.gpu,\n\t\tplatform: composePlatform,\n\t\tmonitoring: input.monitoring,\n\t};\n\tconst resolved = resolve(resolverInput);\n\n\tif (!resolved.isValid) {\n\t\tthrow new StackConfigError(\n\t\t\t`Invalid stack configuration: ${resolved.errors.map((e) => e.message).join(\"; \")}`,\n\t\t);\n\t}\n\n\tconst isBareMetal = input.deploymentType === \"bare-metal\";\n\tlet resolvedForCompose = resolved;\n\tlet nativeIds = new Set<string>();\n\tlet nativeServices: typeof resolved.services = [];\n\tlet dockerOnlyServices: typeof resolved.services = [];\n\n\tif (isBareMetal) {\n\t\tconst partition = partitionBareMetal(resolved, input.platform);\n\t\tnativeServices = partition.nativeServices;\n\t\tdockerOnlyServices = partition.dockerOnlyServices;\n\t\tnativeIds = partition.nativeIds;\n\t\tif (nativeServices.length > 0) {\n\t\t\tresolvedForCompose = resolvedWithOnlyServices(resolved, dockerOnlyServices);\n\t\t}\n\t}\n\n\t// 2. Generate Docker Compose YAML (multi-file)\n\t// Compute Traefik labels before composing (labels get injected into docker-compose services)\n\tlet traefikOutput: ReturnType<typeof generateTraefikConfig> | undefined;\n\tif (input.proxy === \"traefik\" && input.domain) {\n\t\ttraefikOutput = generateTraefikConfig(resolvedForCompose, input.domain);\n\t}\n\n\tconst composeOptions = {\n\t\tprojectName: input.projectName,\n\t\tproxy: input.proxy,\n\t\tdomain: input.domain,\n\t\tgpu: input.gpu,\n\t\tplatform: composePlatform,\n\t\tdeployment: input.deployment,\n\t\topenclawVersion: input.openclawVersion,\n\t\tbareMetalNativeHost: isBareMetal && nativeIds.size > 0,\n\t\ttraefikLabels: traefikOutput?.serviceLabels,\n\t};\n\tconst composeResult = composeMultiFile(resolvedForCompose, composeOptions);\n\n\t// 3. Validate (using the base docker-compose.yml)\n\tconst validation = validate(resolvedForCompose, composeResult.files[\"docker-compose.yml\"] ?? \"\", {\n\t\tdomain: input.domain,\n\t\tgenerateSecrets: input.generateSecrets,\n\t});\n\tif (!validation.valid) {\n\t\tthrow new ValidationError(`Validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`);\n\t}\n\n\t// 4. Generate all files\n\tconst files: GeneratedFiles = {};\n\n\t// Docker Compose (multi-file output)\n\tfor (const [filename, content] of Object.entries(composeResult.files)) {\n\t\tfiles[filename] = content;\n\t}\n\n\t// Environment files (when bare-metal with native services, host vars use host.docker.internal)\n\tconst envFiles = generateEnvFiles(resolved, {\n\t\tgenerateSecrets: input.generateSecrets,\n\t\tdomain: input.domain,\n\t\topenclawVersion: input.openclawVersion,\n\t\tnativeServiceIds: isBareMetal ? nativeIds : undefined,\n\t});\n\tfiles[\".env.example\"] = envFiles.envExample;\n\tfiles[\".env\"] = envFiles.env;\n\n\t// .gitignore\n\tfiles[\".gitignore\"] = [\n\t\t\".env\",\n\t\t\".env.local\",\n\t\t\".env.*.local\",\n\t\t\"*.log\",\n\t\t\"docker-compose.override.yml\",\n\t].join(\"\\n\");\n\n\t// Skills\n\tconst skillFiles = generateSkillFiles(resolved);\n\tfor (const [path, content] of Object.entries(skillFiles)) {\n\t\tfiles[path] = content;\n\t}\n\n\t// README\n\tfiles[\"README.md\"] = generateReadme(resolved, {\n\t\tprojectName: input.projectName,\n\t\tdomain: input.domain,\n\t\tproxy: input.proxy,\n\t\tdeploymentType: input.deploymentType,\n\t\thasNativeServices: isBareMetal && nativeServices.length > 0,\n\t});\n\n\t// Scripts\n\tconst scripts = generateScripts();\n\tfor (const [path, content] of Object.entries(scripts)) {\n\t\tfiles[path] = content;\n\t}\n\n\t// n8n workflows\n\tconst n8nWorkflows = generateN8nWorkflows(resolved);\n\tfor (const [path, content] of Object.entries(n8nWorkflows)) {\n\t\tfiles[path] = content;\n\t}\n\n\t// PostgreSQL init script (creates per-service databases and users)\n\tconst postgresInit = generatePostgresInit(resolved);\n\tif (postgresInit) {\n\t\tfiles[\"postgres/init-databases.sh\"] = postgresInit;\n\t}\n\n\t// Caddy config\n\tif (input.proxy === \"caddy\" && input.domain) {\n\t\tfiles[\"caddy/Caddyfile\"] = generateCaddyfile(resolved, input.domain);\n\t}\n\n\t// Traefik config (labels are already injected via composeOptions.traefikLabels)\n\tif (traefikOutput) {\n\t\tfiles[\"traefik/traefik.yml\"] = traefikOutput.staticConfig;\n\t}\n\n\t// Prometheus config\n\tconst hasPrometheus = resolved.services.some((s) => s.definition.id === \"prometheus\");\n\tif (hasPrometheus) {\n\t\tfiles[\"prometheus/prometheus.yml\"] = generatePrometheusConfig(resolved);\n\t}\n\n\t// Grafana config\n\tconst hasGrafana = resolved.services.some((s) => s.definition.id === \"grafana\");\n\tif (hasGrafana) {\n\t\tconst grafanaFiles = generateGrafanaConfig();\n\t\tfor (const [path, content] of Object.entries(grafanaFiles)) {\n\t\t\tfiles[path] = content;\n\t\t}\n\t\t// Grafana dashboard\n\t\tfiles[\"config/grafana/dashboards/openclaw-stack-overview.json\"] = generateGrafanaDashboard();\n\t}\n\n\t// Docker Compose override (empty template)\n\tfiles[\"docker-compose.override.yml\"] = [\n\t\t\"# Local overrides for docker-compose.yml\",\n\t\t\"# This file is gitignored — use it for personal port changes, extra volumes, etc.\",\n\t\t\"services: {}\",\n\t\t\"\",\n\t].join(\"\\n\");\n\n\t// SERVICES.md documentation\n\tfiles[\"docs/SERVICES.md\"] = generateServicesDoc(resolved);\n\n\t// Bare-metal: native install scripts + top-level installer\n\tif (isBareMetal) {\n\t\tif (nativeServices.length > 0) {\n\t\t\tconst nativePlatform = platformToNativePlatform(input.platform);\n\t\t\tconst nativeScripts = generateNativeInstallScripts({\n\t\t\t\tnativeServices,\n\t\t\t\tplatform: nativePlatform,\n\t\t\t\tprojectName: input.projectName,\n\t\t\t});\n\t\t\tfor (const [path, content] of Object.entries(nativeScripts)) {\n\t\t\t\tfiles[path] = content;\n\t\t\t}\n\t\t}\n\t\tconst bareMetalFiles = generateBareMetalInstall({\n\t\t\tplatform: input.platform,\n\t\t\tprojectName: input.projectName,\n\t\t\thasNativeServices: nativeServices.length > 0,\n\t\t});\n\t\tfor (const [path, content] of Object.entries(bareMetalFiles)) {\n\t\t\tfiles[path] = content;\n\t\t}\n\t}\n\n\t// 5. Calculate metadata\n\tconst skillCount = resolved.services.reduce((sum, s) => sum + s.definition.skills.length, 0);\n\n\treturn {\n\t\tfiles,\n\t\tmetadata: {\n\t\t\tserviceCount: resolved.services.length,\n\t\t\tskillCount,\n\t\t\testimatedMemoryMB: resolved.estimatedMemoryMB,\n\t\t\tgeneratedAt: new Date().toISOString(),\n\t\t},\n\t};\n}\n\nexport function generateServicesDoc(resolved: import(\"./types.js\").ResolverOutput): string {\n\tconst lines: string[] = [\n\t\t\"# Service Reference\",\n\t\t\"\",\n\t\t\"This document describes all companion services in your OpenClaw stack.\",\n\t\t\"\",\n\t];\n\n\tfor (const svc of resolved.services) {\n\t\tconst def = svc.definition;\n\t\tlines.push(`## ${def.icon} ${def.name}`);\n\t\tlines.push(\"\");\n\t\tlines.push(def.description);\n\t\tlines.push(\"\");\n\t\tlines.push(`- **Image**: \\`${def.image}:${def.imageTag}\\``);\n\t\tlines.push(`- **Category**: ${def.category}`);\n\t\tlines.push(`- **Maturity**: ${def.maturity}`);\n\t\tif (def.minMemoryMB) {\n\t\t\tlines.push(`- **Min Memory**: ${def.minMemoryMB}MB`);\n\t\t}\n\t\tif (def.ports.length > 0) {\n\t\t\tlines.push(\"- **Ports**:\");\n\t\t\tfor (const p of def.ports) {\n\t\t\t\tlines.push(\n\t\t\t\t\t` - \\`${p.container}\\` — ${p.description}${p.exposed ? \"\" : \" (internal only)\"}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tlines.push(`- **Docs**: ${def.docsUrl}`);\n\t\tlines.push(\"\");\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generate.mjs","names":[],"sources":["../src/generate.ts"],"sourcesContent":["import {\n\tpartitionBareMetal,\n\tplatformToNativePlatform,\n\tresolvedWithOnlyServices,\n} from \"./bare-metal-partition.js\";\nimport { composeMultiFile } from \"./composer.js\";\nimport { StackConfigError, ValidationError } from \"./errors.js\";\nimport { generateBareMetalInstall } from \"./generators/bare-metal-install.js\";\nimport { generateCaddyfile } from \"./generators/caddy.js\";\nimport { generateEnvFiles } from \"./generators/env.js\";\nimport { generateGrafanaConfig, generateGrafanaDashboard } from \"./generators/grafana.js\";\nimport { generateHealthCheck } from \"./generators/health-check.js\";\nimport { generateN8nWorkflows } from \"./generators/n8n-workflows.js\";\nimport { generateNativeInstallScripts } from \"./generators/native-services.js\";\nimport { generatePostgresInit } from \"./generators/postgres-init.js\";\nimport { generatePrometheusConfig } from \"./generators/prometheus.js\";\nimport { generateReadme } from \"./generators/readme.js\";\nimport { generateScripts } from \"./generators/scripts.js\";\nimport { generateSkillFiles } from \"./generators/skills.js\";\nimport { generateTraefikConfig } from \"./generators/traefik.js\";\nimport { migrateConfig } from \"./migrations.js\";\nimport { resolve } from \"./resolver.js\";\nimport type {\n\tGeneratedFiles,\n\tGenerationInput,\n\tGenerationResult,\n\tPlatform,\n\tResolverInput,\n} from \"./types.js\";\nimport { validate } from \"./validator.js\";\n\n/** Resolver/compose only support linux image platforms; normalize for bare-metal (windows/macos). */\nfunction getComposePlatform(platform: Platform): \"linux/amd64\" | \"linux/arm64\" {\n\tif (platform === \"linux/amd64\" || platform === \"linux/arm64\") return platform;\n\treturn \"linux/amd64\";\n}\n\n/**\n * Main orchestration function: takes generation input, resolves dependencies,\n * generates all files, validates, and returns the complete file tree.\n */\nexport function generate(rawInput: GenerationInput): GenerationResult {\n\t// Apply config migrations if needed\n\tconst input = migrateConfig(rawInput as Record<string, unknown>) as GenerationInput;\n\n\tconst composePlatform = getComposePlatform(input.platform);\n\n\t// 1. Resolve dependencies\n\tconst resolverInput: ResolverInput = {\n\t\tservices: input.services,\n\t\tskillPacks: input.skillPacks,\n\t\tproxy: input.proxy,\n\t\tgpu: input.gpu,\n\t\tplatform: composePlatform,\n\t\tmonitoring: input.monitoring,\n\t};\n\tconst resolved = resolve(resolverInput);\n\n\tif (!resolved.isValid) {\n\t\tthrow new StackConfigError(\n\t\t\t`Invalid stack configuration: ${resolved.errors.map((e) => e.message).join(\"; \")}`,\n\t\t);\n\t}\n\n\tconst isBareMetal = input.deploymentType === \"bare-metal\";\n\tlet resolvedForCompose = resolved;\n\tlet nativeIds = new Set<string>();\n\tlet nativeServices: typeof resolved.services = [];\n\tlet dockerOnlyServices: typeof resolved.services = [];\n\n\tif (isBareMetal) {\n\t\tconst partition = partitionBareMetal(resolved, input.platform);\n\t\tnativeServices = partition.nativeServices;\n\t\tdockerOnlyServices = partition.dockerOnlyServices;\n\t\tnativeIds = partition.nativeIds;\n\t\tif (nativeServices.length > 0) {\n\t\t\tresolvedForCompose = resolvedWithOnlyServices(resolved, dockerOnlyServices);\n\t\t}\n\t}\n\n\t// 2. Generate Docker Compose YAML (multi-file)\n\t// Compute Traefik labels before composing (labels get injected into docker-compose services)\n\tlet traefikOutput: ReturnType<typeof generateTraefikConfig> | undefined;\n\tif (input.proxy === \"traefik\" && input.domain) {\n\t\ttraefikOutput = generateTraefikConfig(resolvedForCompose, input.domain);\n\t}\n\n\tconst composeOptions = {\n\t\tprojectName: input.projectName,\n\t\tproxy: input.proxy,\n\t\tdomain: input.domain,\n\t\tgpu: input.gpu,\n\t\tplatform: composePlatform,\n\t\tdeployment: input.deployment,\n\t\topenclawVersion: input.openclawVersion,\n\t\tbareMetalNativeHost: isBareMetal && nativeIds.size > 0,\n\t\ttraefikLabels: traefikOutput?.serviceLabels,\n\t};\n\tconst composeResult = composeMultiFile(resolvedForCompose, composeOptions);\n\n\t// 3. Validate (using the base docker-compose.yml)\n\tconst validation = validate(resolvedForCompose, composeResult.files[\"docker-compose.yml\"] ?? \"\", {\n\t\tdomain: input.domain,\n\t\tgenerateSecrets: input.generateSecrets,\n\t});\n\tif (!validation.valid) {\n\t\tthrow new ValidationError(\n\t\t\t`Validation failed: ${validation.errors.map((e) => e.message).join(\"; \")}`,\n\t\t);\n\t}\n\n\t// 4. Generate all files\n\tconst files: GeneratedFiles = {};\n\n\t// Docker Compose (multi-file output)\n\tfor (const [filename, content] of Object.entries(composeResult.files)) {\n\t\tfiles[filename] = content;\n\t}\n\n\t// Environment files (when bare-metal with native services, host vars use host.docker.internal)\n\tconst envFiles = generateEnvFiles(resolved, {\n\t\tgenerateSecrets: input.generateSecrets,\n\t\tdomain: input.domain,\n\t\topenclawVersion: input.openclawVersion,\n\t\tnativeServiceIds: isBareMetal ? nativeIds : undefined,\n\t});\n\tfiles[\".env.example\"] = envFiles.envExample;\n\tfiles[\".env\"] = envFiles.env;\n\n\t// .gitignore\n\tfiles[\".gitignore\"] = [\n\t\t\".env\",\n\t\t\".env.local\",\n\t\t\".env.*.local\",\n\t\t\"*.log\",\n\t\t\"docker-compose.override.yml\",\n\t].join(\"\\n\");\n\n\t// Skills\n\tconst skillFiles = generateSkillFiles(resolved);\n\tfor (const [path, content] of Object.entries(skillFiles)) {\n\t\tfiles[path] = content;\n\t}\n\n\t// README\n\tfiles[\"README.md\"] = generateReadme(resolved, {\n\t\tprojectName: input.projectName,\n\t\tdomain: input.domain,\n\t\tproxy: input.proxy,\n\t\tdeploymentType: input.deploymentType,\n\t\thasNativeServices: isBareMetal && nativeServices.length > 0,\n\t});\n\n\t// Scripts\n\tconst scripts = generateScripts();\n\tfor (const [path, content] of Object.entries(scripts)) {\n\t\tfiles[path] = content;\n\t}\n\n\t// Health check scripts (dynamic, stack-specific)\n\tconst healthCheckFiles = generateHealthCheck(resolved, {\n\t\tprojectName: input.projectName,\n\t\tdeploymentType: input.deploymentType,\n\t});\n\tfor (const [path, content] of Object.entries(healthCheckFiles)) {\n\t\tfiles[path] = content;\n\t}\n\n\t// n8n workflows\n\tconst n8nWorkflows = generateN8nWorkflows(resolved);\n\tfor (const [path, content] of Object.entries(n8nWorkflows)) {\n\t\tfiles[path] = content;\n\t}\n\n\t// PostgreSQL init script (creates per-service databases and users)\n\tconst postgresInit = generatePostgresInit(resolved);\n\tif (postgresInit) {\n\t\tfiles[\"postgres/init-databases.sh\"] = postgresInit;\n\t}\n\n\t// Caddy config\n\tif (input.proxy === \"caddy\" && input.domain) {\n\t\tfiles[\"caddy/Caddyfile\"] = generateCaddyfile(resolved, input.domain);\n\t}\n\n\t// Traefik config (labels are already injected via composeOptions.traefikLabels)\n\tif (traefikOutput) {\n\t\tfiles[\"traefik/traefik.yml\"] = traefikOutput.staticConfig;\n\t}\n\n\t// Prometheus config\n\tconst hasPrometheus = resolved.services.some((s) => s.definition.id === \"prometheus\");\n\tif (hasPrometheus) {\n\t\tfiles[\"prometheus/prometheus.yml\"] = generatePrometheusConfig(resolved);\n\t}\n\n\t// Grafana config\n\tconst hasGrafana = resolved.services.some((s) => s.definition.id === \"grafana\");\n\tif (hasGrafana) {\n\t\tconst grafanaFiles = generateGrafanaConfig();\n\t\tfor (const [path, content] of Object.entries(grafanaFiles)) {\n\t\t\tfiles[path] = content;\n\t\t}\n\t\t// Grafana dashboard\n\t\tfiles[\"config/grafana/dashboards/openclaw-stack-overview.json\"] = generateGrafanaDashboard();\n\t}\n\n\t// Docker Compose override (empty template)\n\tfiles[\"docker-compose.override.yml\"] = [\n\t\t\"# Local overrides for docker-compose.yml\",\n\t\t\"# This file is gitignored — use it for personal port changes, extra volumes, etc.\",\n\t\t\"services: {}\",\n\t\t\"\",\n\t].join(\"\\n\");\n\n\t// SERVICES.md documentation\n\tfiles[\"docs/SERVICES.md\"] = generateServicesDoc(resolved);\n\n\t// Bare-metal: native install scripts + top-level installer\n\tif (isBareMetal) {\n\t\tif (nativeServices.length > 0) {\n\t\t\tconst nativePlatform = platformToNativePlatform(input.platform);\n\t\t\tconst nativeScripts = generateNativeInstallScripts({\n\t\t\t\tnativeServices,\n\t\t\t\tplatform: nativePlatform,\n\t\t\t\tprojectName: input.projectName,\n\t\t\t});\n\t\t\tfor (const [path, content] of Object.entries(nativeScripts)) {\n\t\t\t\tfiles[path] = content;\n\t\t\t}\n\t\t}\n\t\tconst bareMetalFiles = generateBareMetalInstall({\n\t\t\tplatform: input.platform,\n\t\t\tprojectName: input.projectName,\n\t\t\thasNativeServices: nativeServices.length > 0,\n\t\t});\n\t\tfor (const [path, content] of Object.entries(bareMetalFiles)) {\n\t\t\tfiles[path] = content;\n\t\t}\n\t}\n\n\t// 5. Calculate metadata\n\tconst skillCount = resolved.services.reduce((sum, s) => sum + s.definition.skills.length, 0);\n\n\treturn {\n\t\tfiles,\n\t\tmetadata: {\n\t\t\tserviceCount: resolved.services.length,\n\t\t\tskillCount,\n\t\t\testimatedMemoryMB: resolved.estimatedMemoryMB,\n\t\t\tgeneratedAt: new Date().toISOString(),\n\t\t},\n\t};\n}\n\nexport function generateServicesDoc(resolved: import(\"./types.js\").ResolverOutput): string {\n\tconst lines: string[] = [\n\t\t\"# Service Reference\",\n\t\t\"\",\n\t\t\"This document describes all companion services in your OpenClaw stack.\",\n\t\t\"\",\n\t];\n\n\tfor (const svc of resolved.services) {\n\t\tconst def = svc.definition;\n\t\tlines.push(`## ${def.icon} ${def.name}`);\n\t\tlines.push(\"\");\n\t\tlines.push(def.description);\n\t\tlines.push(\"\");\n\t\tlines.push(`- **Image**: \\`${def.image}:${def.imageTag}\\``);\n\t\tlines.push(`- **Category**: ${def.category}`);\n\t\tlines.push(`- **Maturity**: ${def.maturity}`);\n\t\tif (def.minMemoryMB) {\n\t\t\tlines.push(`- **Min Memory**: ${def.minMemoryMB}MB`);\n\t\t}\n\t\tif (def.ports.length > 0) {\n\t\t\tlines.push(\"- **Ports**:\");\n\t\t\tfor (const p of def.ports) {\n\t\t\t\tlines.push(\n\t\t\t\t\t` - \\`${p.container}\\` — ${p.description}${p.exposed ? \"\" : \" (internal only)\"}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tlines.push(`- **Docs**: ${def.docsUrl}`);\n\t\tlines.push(\"\");\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n"],"mappings":"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"}
|
package/dist/generate.test.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as describe, r as it, t as globalExpect } from "../vi.2VT5v0um-
|
|
1
|
+
import { n as describe, r as it, t as globalExpect } from "../vi.2VT5v0um-YSByewHe.mjs";
|
|
2
2
|
import { generateBareMetalInstall } from "./bare-metal-install.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/generators/bare-metal-install.test.ts
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { n as describe, r as it, t as globalExpect } from "../vi.2VT5v0um-YSByewHe.mjs";
|
|
2
|
+
import { generate } from "../generate.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/generators/caddy.test.ts
|
|
5
|
+
describe("generateCaddyfile (via generate)", () => {
|
|
6
|
+
const baseInput = {
|
|
7
|
+
projectName: "caddy-test",
|
|
8
|
+
services: ["redis", "n8n"],
|
|
9
|
+
skillPacks: [],
|
|
10
|
+
proxy: "caddy",
|
|
11
|
+
domain: "example.com",
|
|
12
|
+
gpu: false,
|
|
13
|
+
platform: "linux/amd64",
|
|
14
|
+
deployment: "local",
|
|
15
|
+
generateSecrets: true,
|
|
16
|
+
openclawVersion: "latest"
|
|
17
|
+
};
|
|
18
|
+
it("generates Caddyfile when proxy is caddy", () => {
|
|
19
|
+
const result = generate(baseInput);
|
|
20
|
+
globalExpect(result.files).toHaveProperty("caddy/Caddyfile");
|
|
21
|
+
globalExpect(result.files["caddy/Caddyfile"].length).toBeGreaterThan(0);
|
|
22
|
+
});
|
|
23
|
+
it("does not generate Caddyfile when proxy is none", () => {
|
|
24
|
+
globalExpect(generate({
|
|
25
|
+
...baseInput,
|
|
26
|
+
proxy: "none"
|
|
27
|
+
}).files).not.toHaveProperty("caddy/Caddyfile");
|
|
28
|
+
});
|
|
29
|
+
it("Caddyfile contains the domain", () => {
|
|
30
|
+
const caddyfile = generate(baseInput).files["caddy/Caddyfile"];
|
|
31
|
+
globalExpect(caddyfile).toContain("example.com");
|
|
32
|
+
});
|
|
33
|
+
it("Caddyfile includes reverse proxy directives for services with exposed ports", () => {
|
|
34
|
+
const caddyfile = generate(baseInput).files["caddy/Caddyfile"];
|
|
35
|
+
globalExpect(caddyfile).toContain("n8n");
|
|
36
|
+
});
|
|
37
|
+
it("Caddyfile includes TLS configuration", () => {
|
|
38
|
+
const caddyfile = generate(baseInput).files["caddy/Caddyfile"];
|
|
39
|
+
globalExpect(caddyfile.length).toBeGreaterThan(50);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { };
|
|
45
|
+
//# sourceMappingURL=caddy.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caddy.test.mjs","names":[],"sources":["../../src/generators/caddy.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { generate } from \"../generate.js\";\n\ndescribe(\"generateCaddyfile (via generate)\", () => {\n\tconst baseInput = {\n\t\tprojectName: \"caddy-test\",\n\t\tservices: [\"redis\", \"n8n\"],\n\t\tskillPacks: [] as string[],\n\t\tproxy: \"caddy\" as const,\n\t\tdomain: \"example.com\",\n\t\tgpu: false,\n\t\tplatform: \"linux/amd64\" as const,\n\t\tdeployment: \"local\" as const,\n\t\tgenerateSecrets: true,\n\t\topenclawVersion: \"latest\",\n\t};\n\n\tit(\"generates Caddyfile when proxy is caddy\", () => {\n\t\tconst result = generate(baseInput);\n\n\t\texpect(result.files).toHaveProperty(\"caddy/Caddyfile\");\n\t\texpect(result.files[\"caddy/Caddyfile\"]!.length).toBeGreaterThan(0);\n\t});\n\n\tit(\"does not generate Caddyfile when proxy is none\", () => {\n\t\tconst result = generate({\n\t\t\t...baseInput,\n\t\t\tproxy: \"none\",\n\t\t});\n\n\t\texpect(result.files).not.toHaveProperty(\"caddy/Caddyfile\");\n\t});\n\n\tit(\"Caddyfile contains the domain\", () => {\n\t\tconst result = generate(baseInput);\n\t\tconst caddyfile = result.files[\"caddy/Caddyfile\"]!;\n\n\t\texpect(caddyfile).toContain(\"example.com\");\n\t});\n\n\tit(\"Caddyfile includes reverse proxy directives for services with exposed ports\", () => {\n\t\tconst result = generate(baseInput);\n\t\tconst caddyfile = result.files[\"caddy/Caddyfile\"]!;\n\n\t\t// Should reference n8n since it has exposed ports\n\t\texpect(caddyfile).toContain(\"n8n\");\n\t});\n\n\tit(\"Caddyfile includes TLS configuration\", () => {\n\t\tconst result = generate(baseInput);\n\t\tconst caddyfile = result.files[\"caddy/Caddyfile\"]!;\n\n\t\t// Caddy auto-enables TLS, so should reference HTTPS or TLS\n\t\texpect(caddyfile.length).toBeGreaterThan(50);\n\t});\n});\n"],"mappings":";;;;AAGA,SAAS,0CAA0C;CAClD,MAAM,YAAY;EACjB,aAAa;EACb,UAAU,CAAC,SAAS,MAAM;EAC1B,YAAY,EAAE;EACd,OAAO;EACP,QAAQ;EACR,KAAK;EACL,UAAU;EACV,YAAY;EACZ,iBAAiB;EACjB,iBAAiB;EACjB;AAED,IAAG,iDAAiD;EACnD,MAAM,SAAS,SAAS,UAAU;AAElC,eAAO,OAAO,MAAM,CAAC,eAAe,kBAAkB;AACtD,eAAO,OAAO,MAAM,mBAAoB,OAAO,CAAC,gBAAgB,EAAE;GACjE;AAEF,IAAG,wDAAwD;AAM1D,eALe,SAAS;GACvB,GAAG;GACH,OAAO;GACP,CAAC,CAEY,MAAM,CAAC,IAAI,eAAe,kBAAkB;GACzD;AAEF,IAAG,uCAAuC;EAEzC,MAAM,YADS,SAAS,UAAU,CACT,MAAM;AAE/B,eAAO,UAAU,CAAC,UAAU,cAAc;GACzC;AAEF,IAAG,qFAAqF;EAEvF,MAAM,YADS,SAAS,UAAU,CACT,MAAM;AAG/B,eAAO,UAAU,CAAC,UAAU,MAAM;GACjC;AAEF,IAAG,8CAA8C;EAEhD,MAAM,YADS,SAAS,UAAU,CACT,MAAM;AAG/B,eAAO,UAAU,OAAO,CAAC,gBAAgB,GAAG;GAC3C;EACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { n as describe, r as it, t as globalExpect } from "../vi.2VT5v0um-YSByewHe.mjs";
|
|
2
|
+
import { generate } from "../generate.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/generators/env.test.ts
|
|
5
|
+
describe("generateEnvFiles (via generate)", () => {
|
|
6
|
+
const baseInput = {
|
|
7
|
+
projectName: "env-test",
|
|
8
|
+
services: ["redis"],
|
|
9
|
+
skillPacks: [],
|
|
10
|
+
proxy: "none",
|
|
11
|
+
gpu: false,
|
|
12
|
+
platform: "linux/amd64",
|
|
13
|
+
deployment: "local",
|
|
14
|
+
generateSecrets: true,
|
|
15
|
+
openclawVersion: "latest"
|
|
16
|
+
};
|
|
17
|
+
it("generates .env and .env.example files", () => {
|
|
18
|
+
const result = generate(baseInput);
|
|
19
|
+
globalExpect(result.files).toHaveProperty(".env");
|
|
20
|
+
globalExpect(result.files).toHaveProperty(".env.example");
|
|
21
|
+
});
|
|
22
|
+
it(".env.example has empty values for secrets", () => {
|
|
23
|
+
const envExample = generate(baseInput).files[".env.example"];
|
|
24
|
+
globalExpect(envExample).toContain("REDIS_PASSWORD=");
|
|
25
|
+
});
|
|
26
|
+
it(".env has populated secret values when generateSecrets is true", () => {
|
|
27
|
+
const redisLine = generate(baseInput).files[".env"].split("\n").find((l) => l.startsWith("REDIS_PASSWORD="));
|
|
28
|
+
globalExpect(redisLine).toBeDefined();
|
|
29
|
+
const value = redisLine.split("=")[1];
|
|
30
|
+
globalExpect(value.length).toBeGreaterThan(0);
|
|
31
|
+
});
|
|
32
|
+
it("env files contain service-specific variables", () => {
|
|
33
|
+
const env = generate({
|
|
34
|
+
...baseInput,
|
|
35
|
+
services: [
|
|
36
|
+
"redis",
|
|
37
|
+
"postgresql",
|
|
38
|
+
"n8n"
|
|
39
|
+
]
|
|
40
|
+
}).files[".env"];
|
|
41
|
+
globalExpect(env).toContain("REDIS_PASSWORD");
|
|
42
|
+
globalExpect(env).toContain("POSTGRES_PASSWORD");
|
|
43
|
+
});
|
|
44
|
+
it("env files group variables by service with comments", () => {
|
|
45
|
+
const envExample = generate(baseInput).files[".env.example"];
|
|
46
|
+
globalExpect(envExample).toContain("#");
|
|
47
|
+
});
|
|
48
|
+
it(".env references domain when proxy is set", () => {
|
|
49
|
+
const env = generate({
|
|
50
|
+
...baseInput,
|
|
51
|
+
proxy: "caddy",
|
|
52
|
+
domain: "example.com"
|
|
53
|
+
}).files[".env"];
|
|
54
|
+
globalExpect(env).toContain("example.com");
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { };
|
|
60
|
+
//# sourceMappingURL=env.test.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.test.mjs","names":[],"sources":["../../src/generators/env.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { generate } from \"../generate.js\";\n\ndescribe(\"generateEnvFiles (via generate)\", () => {\n\tconst baseInput = {\n\t\tprojectName: \"env-test\",\n\t\tservices: [\"redis\"],\n\t\tskillPacks: [] as string[],\n\t\tproxy: \"none\" as const,\n\t\tgpu: false,\n\t\tplatform: \"linux/amd64\" as const,\n\t\tdeployment: \"local\" as const,\n\t\tgenerateSecrets: true,\n\t\topenclawVersion: \"latest\",\n\t};\n\n\tit(\"generates .env and .env.example files\", () => {\n\t\tconst result = generate(baseInput);\n\n\t\texpect(result.files).toHaveProperty(\".env\");\n\t\texpect(result.files).toHaveProperty(\".env.example\");\n\t});\n\n\tit(\".env.example has empty values for secrets\", () => {\n\t\tconst result = generate(baseInput);\n\t\tconst envExample = result.files[\".env.example\"]!;\n\n\t\t// .env.example should have placeholder empty values for secrets\n\t\texpect(envExample).toContain(\"REDIS_PASSWORD=\");\n\t});\n\n\tit(\".env has populated secret values when generateSecrets is true\", () => {\n\t\tconst result = generate(baseInput);\n\t\tconst env = result.files[\".env\"]!;\n\n\t\t// Find REDIS_PASSWORD line and check it has a value\n\t\tconst redisLine = env.split(\"\\n\").find((l) => l.startsWith(\"REDIS_PASSWORD=\"));\n\t\texpect(redisLine).toBeDefined();\n\t\t// Value should not be empty\n\t\tconst value = redisLine!.split(\"=\")[1];\n\t\texpect(value!.length).toBeGreaterThan(0);\n\t});\n\n\tit(\"env files contain service-specific variables\", () => {\n\t\tconst result = generate({\n\t\t\t...baseInput,\n\t\t\tservices: [\"redis\", \"postgresql\", \"n8n\"],\n\t\t});\n\t\tconst env = result.files[\".env\"]!;\n\n\t\texpect(env).toContain(\"REDIS_PASSWORD\");\n\t\texpect(env).toContain(\"POSTGRES_PASSWORD\");\n\t});\n\n\tit(\"env files group variables by service with comments\", () => {\n\t\tconst result = generate(baseInput);\n\t\tconst envExample = result.files[\".env.example\"]!;\n\n\t\t// Should have comment sections\n\t\texpect(envExample).toContain(\"#\");\n\t});\n\n\tit(\".env references domain when proxy is set\", () => {\n\t\tconst result = generate({\n\t\t\t...baseInput,\n\t\t\tproxy: \"caddy\",\n\t\t\tdomain: \"example.com\",\n\t\t});\n\t\tconst env = result.files[\".env\"]!;\n\n\t\texpect(env).toContain(\"example.com\");\n\t});\n});\n"],"mappings":";;;;AAGA,SAAS,yCAAyC;CACjD,MAAM,YAAY;EACjB,aAAa;EACb,UAAU,CAAC,QAAQ;EACnB,YAAY,EAAE;EACd,OAAO;EACP,KAAK;EACL,UAAU;EACV,YAAY;EACZ,iBAAiB;EACjB,iBAAiB;EACjB;AAED,IAAG,+CAA+C;EACjD,MAAM,SAAS,SAAS,UAAU;AAElC,eAAO,OAAO,MAAM,CAAC,eAAe,OAAO;AAC3C,eAAO,OAAO,MAAM,CAAC,eAAe,eAAe;GAClD;AAEF,IAAG,mDAAmD;EAErD,MAAM,aADS,SAAS,UAAU,CACR,MAAM;AAGhC,eAAO,WAAW,CAAC,UAAU,kBAAkB;GAC9C;AAEF,IAAG,uEAAuE;EAKzE,MAAM,YAJS,SAAS,UAAU,CACf,MAAM,QAGH,MAAM,KAAK,CAAC,MAAM,MAAM,EAAE,WAAW,kBAAkB,CAAC;AAC9E,eAAO,UAAU,CAAC,aAAa;EAE/B,MAAM,QAAQ,UAAW,MAAM,IAAI,CAAC;AACpC,eAAO,MAAO,OAAO,CAAC,gBAAgB,EAAE;GACvC;AAEF,IAAG,sDAAsD;EAKxD,MAAM,MAJS,SAAS;GACvB,GAAG;GACH,UAAU;IAAC;IAAS;IAAc;IAAM;GACxC,CAAC,CACiB,MAAM;AAEzB,eAAO,IAAI,CAAC,UAAU,iBAAiB;AACvC,eAAO,IAAI,CAAC,UAAU,oBAAoB;GACzC;AAEF,IAAG,4DAA4D;EAE9D,MAAM,aADS,SAAS,UAAU,CACR,MAAM;AAGhC,eAAO,WAAW,CAAC,UAAU,IAAI;GAChC;AAEF,IAAG,kDAAkD;EAMpD,MAAM,MALS,SAAS;GACvB,GAAG;GACH,OAAO;GACP,QAAQ;GACR,CAAC,CACiB,MAAM;AAEzB,eAAO,IAAI,CAAC,UAAU,cAAc;GACnC;EACD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ResolverOutput } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/generators/health-check.d.ts
|
|
4
|
+
interface HealthCheckOptions {
|
|
5
|
+
projectName: string;
|
|
6
|
+
deploymentType?: "docker" | "bare-metal";
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Generates stack-specific health check and verification scripts.
|
|
10
|
+
*
|
|
11
|
+
* Each generated script is dynamic — it contains the exact service names,
|
|
12
|
+
* ports, and health check commands from the resolved stack so users get
|
|
13
|
+
* a precise, zero-configuration verifier.
|
|
14
|
+
*/
|
|
15
|
+
declare function generateHealthCheck(resolved: ResolverOutput, options: HealthCheckOptions): Record<string, string>;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { generateHealthCheck };
|
|
18
|
+
//# sourceMappingURL=health-check.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-check.d.mts","names":[],"sources":["../../src/generators/health-check.ts"],"mappings":";;;UAIU,kBAAA;EACT,WAAA;EACA,cAAA;AAAA;;;;AAYD;;;;iBAAgB,mBAAA,CACf,QAAA,EAAU,cAAA,EACV,OAAA,EAAS,kBAAA,GACP,MAAA"}
|