@better-openclaw/core 1.0.7 → 1.0.8
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/schema.d.mts +8 -0
- package/dist/schema.d.mts.map +1 -1
- package/dist/schema.mjs +3 -1
- package/dist/schema.mjs.map +1 -1
- package/dist/services/definitions/comfyui.d.mts +7 -0
- package/dist/services/definitions/comfyui.d.mts.map +1 -0
- package/dist/services/definitions/comfyui.mjs +83 -0
- package/dist/services/definitions/comfyui.mjs.map +1 -0
- package/dist/services/definitions/desktop-environment.d.mts +7 -0
- package/dist/services/definitions/desktop-environment.d.mts.map +1 -0
- package/dist/services/definitions/desktop-environment.mjs +153 -0
- package/dist/services/definitions/desktop-environment.mjs.map +1 -0
- package/dist/services/definitions/index.d.mts +4 -1
- package/dist/services/definitions/index.d.mts.map +1 -1
- package/dist/services/definitions/index.mjs +8 -2
- package/dist/services/definitions/index.mjs.map +1 -1
- package/dist/services/definitions/stream-gateway.d.mts +7 -0
- package/dist/services/definitions/stream-gateway.d.mts.map +1 -0
- package/dist/services/definitions/stream-gateway.mjs +133 -0
- package/dist/services/definitions/stream-gateway.mjs.map +1 -0
- package/dist/types.mjs +10 -0
- package/dist/types.mjs.map +1 -1
- package/package.json +1 -1
- package/src/schema.ts +2 -0
- package/src/services/definitions/comfyui.ts +90 -0
- package/src/services/definitions/desktop-environment.ts +163 -0
- package/src/services/definitions/index.ts +9 -0
- package/src/services/definitions/stream-gateway.ts +148 -0
- package/src/types.ts +2 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
//#region src/services/definitions/stream-gateway.ts
|
|
2
|
+
const streamGatewayDefinition = {
|
|
3
|
+
id: "stream-gateway",
|
|
4
|
+
name: "Stream Gateway",
|
|
5
|
+
description: "NGINX-RTMP relay server that receives a local RTMP stream (e.g. from OBS in the desktop-environment) and fans it out to YouTube, Twitch, TikTok, and Telegram simultaneously. Also serves an HLS preview on HTTP for local viewing.",
|
|
6
|
+
category: "streaming",
|
|
7
|
+
icon: "📺",
|
|
8
|
+
image: "tiangolo/nginx-rtmp",
|
|
9
|
+
imageTag: "latest",
|
|
10
|
+
ports: [{
|
|
11
|
+
host: 1935,
|
|
12
|
+
container: 1935,
|
|
13
|
+
description: "RTMP ingest (receives stream from OBS or ffmpeg)",
|
|
14
|
+
exposed: true
|
|
15
|
+
}, {
|
|
16
|
+
host: 8080,
|
|
17
|
+
container: 8080,
|
|
18
|
+
description: "HTTP server for HLS preview and stats",
|
|
19
|
+
exposed: true
|
|
20
|
+
}],
|
|
21
|
+
volumes: [{
|
|
22
|
+
name: "stream-gateway-hls",
|
|
23
|
+
containerPath: "/tmp/hls",
|
|
24
|
+
description: "HLS segment storage for live preview playback"
|
|
25
|
+
}],
|
|
26
|
+
environment: [
|
|
27
|
+
{
|
|
28
|
+
key: "YOUTUBE_STREAM_KEY",
|
|
29
|
+
defaultValue: "",
|
|
30
|
+
secret: true,
|
|
31
|
+
description: "YouTube Live stream key (leave empty to skip YouTube relay)",
|
|
32
|
+
required: false
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
key: "TWITCH_STREAM_KEY",
|
|
36
|
+
defaultValue: "",
|
|
37
|
+
secret: true,
|
|
38
|
+
description: "Twitch stream key (leave empty to skip Twitch relay)",
|
|
39
|
+
required: false
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: "TIKTOK_STREAM_URL",
|
|
43
|
+
defaultValue: "",
|
|
44
|
+
secret: true,
|
|
45
|
+
description: "Full TikTok RTMP URL from TikTok Studio (leave empty to skip TikTok relay)",
|
|
46
|
+
required: false
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: "TELEGRAM_STREAM_URL",
|
|
50
|
+
defaultValue: "",
|
|
51
|
+
secret: true,
|
|
52
|
+
description: "Full Telegram RTMPS URL including stream key (leave empty to skip Telegram relay)",
|
|
53
|
+
required: false
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
healthcheck: {
|
|
57
|
+
test: "curl -sf http://localhost:8080/health || exit 1",
|
|
58
|
+
interval: "15s",
|
|
59
|
+
timeout: "5s",
|
|
60
|
+
retries: 3
|
|
61
|
+
},
|
|
62
|
+
dependsOn: [],
|
|
63
|
+
restartPolicy: "unless-stopped",
|
|
64
|
+
networks: ["openclaw-network"],
|
|
65
|
+
deploy: { resources: {
|
|
66
|
+
limits: {
|
|
67
|
+
cpus: "2.0",
|
|
68
|
+
memory: "2G"
|
|
69
|
+
},
|
|
70
|
+
reservations: {
|
|
71
|
+
cpus: "0.5",
|
|
72
|
+
memory: "512M"
|
|
73
|
+
}
|
|
74
|
+
} },
|
|
75
|
+
skills: [],
|
|
76
|
+
openclawEnvVars: [
|
|
77
|
+
{
|
|
78
|
+
key: "STREAM_GATEWAY_HOST",
|
|
79
|
+
defaultValue: "stream-gateway",
|
|
80
|
+
secret: false,
|
|
81
|
+
description: "Hostname of the stream-gateway container",
|
|
82
|
+
required: true
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
key: "STREAM_GATEWAY_RTMP_PORT",
|
|
86
|
+
defaultValue: "1935",
|
|
87
|
+
secret: false,
|
|
88
|
+
description: "RTMP ingest port on the stream-gateway",
|
|
89
|
+
required: true
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
key: "STREAM_GATEWAY_HLS_PORT",
|
|
93
|
+
defaultValue: "8080",
|
|
94
|
+
secret: false,
|
|
95
|
+
description: "HTTP port for HLS preview on the stream-gateway",
|
|
96
|
+
required: true
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
docsUrl: "https://github.com/tiangolo/nginx-rtmp-docker",
|
|
100
|
+
tags: [
|
|
101
|
+
"streaming",
|
|
102
|
+
"rtmp",
|
|
103
|
+
"hls",
|
|
104
|
+
"relay",
|
|
105
|
+
"youtube",
|
|
106
|
+
"twitch",
|
|
107
|
+
"tiktok",
|
|
108
|
+
"telegram",
|
|
109
|
+
"obs",
|
|
110
|
+
"nginx"
|
|
111
|
+
],
|
|
112
|
+
maturity: "experimental",
|
|
113
|
+
requires: [],
|
|
114
|
+
recommends: ["desktop-environment"],
|
|
115
|
+
conflictsWith: [],
|
|
116
|
+
removalWarning: "⚠️ STREAMING KEYS REQUIRED: To relay to platforms you must provide at least one stream key. Without any keys configured the gateway will still accept RTMP input and serve HLS locally but nothing will be forwarded.",
|
|
117
|
+
minMemoryMB: 512,
|
|
118
|
+
gpuRequired: false,
|
|
119
|
+
nativeSupported: true,
|
|
120
|
+
nativeRecipes: [{
|
|
121
|
+
platform: "linux",
|
|
122
|
+
installSteps: ["command -v nginx >/dev/null 2>&1 || (command -v apt-get >/dev/null 2>&1 && sudo apt-get update -qq && sudo apt-get install -y -qq nginx libnginx-mod-rtmp ffmpeg)", "command -v nginx >/dev/null 2>&1 || (command -v dnf >/dev/null 2>&1 && sudo dnf install -y nginx nginx-mod-rtmp ffmpeg)"],
|
|
123
|
+
startCommand: "sudo systemctl start nginx",
|
|
124
|
+
stopCommand: "sudo systemctl stop nginx",
|
|
125
|
+
configPath: "/etc/nginx/nginx.conf",
|
|
126
|
+
configTemplate: "# Generated for OpenClaw bare-metal\nworker_processes auto;\nrtmp_auto_push on;\n\nevents { worker_connections 1024; }\n\nrtmp {\n server {\n listen 1935;\n chunk_size 4096;\n application live {\n live on;\n record off;\n hls on;\n hls_path /tmp/hls;\n hls_fragment 3;\n hls_playlist_length 60;\n }\n }\n}\n\nhttp {\n server {\n listen 8080;\n location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } root /tmp; add_header Cache-Control no-cache; }\n location /health { return 200 \"OK\"; }\n }\n}\n",
|
|
127
|
+
systemdUnit: "nginx"
|
|
128
|
+
}]
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
//#endregion
|
|
132
|
+
export { streamGatewayDefinition };
|
|
133
|
+
//# sourceMappingURL=stream-gateway.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-gateway.mjs","names":[],"sources":["../../../src/services/definitions/stream-gateway.ts"],"sourcesContent":["import type { ServiceDefinition } from \"../../types.js\";\n\nexport const streamGatewayDefinition: ServiceDefinition = {\n\tid: \"stream-gateway\",\n\tname: \"Stream Gateway\",\n\tdescription:\n\t\t\"NGINX-RTMP relay server that receives a local RTMP stream (e.g. from OBS in the desktop-environment) and fans it out to YouTube, Twitch, TikTok, and Telegram simultaneously. Also serves an HLS preview on HTTP for local viewing.\",\n\tcategory: \"streaming\",\n\ticon: \"📺\",\n\n\timage: \"tiangolo/nginx-rtmp\",\n\timageTag: \"latest\",\n\tports: [\n\t\t{\n\t\t\thost: 1935,\n\t\t\tcontainer: 1935,\n\t\t\tdescription: \"RTMP ingest (receives stream from OBS or ffmpeg)\",\n\t\t\texposed: true,\n\t\t},\n\t\t{\n\t\t\thost: 8080,\n\t\t\tcontainer: 8080,\n\t\t\tdescription: \"HTTP server for HLS preview and stats\",\n\t\t\texposed: true,\n\t\t},\n\t],\n\tvolumes: [\n\t\t{\n\t\t\tname: \"stream-gateway-hls\",\n\t\t\tcontainerPath: \"/tmp/hls\",\n\t\t\tdescription: \"HLS segment storage for live preview playback\",\n\t\t},\n\t],\n\tenvironment: [\n\t\t{\n\t\t\tkey: \"YOUTUBE_STREAM_KEY\",\n\t\t\tdefaultValue: \"\",\n\t\t\tsecret: true,\n\t\t\tdescription: \"YouTube Live stream key (leave empty to skip YouTube relay)\",\n\t\t\trequired: false,\n\t\t},\n\t\t{\n\t\t\tkey: \"TWITCH_STREAM_KEY\",\n\t\t\tdefaultValue: \"\",\n\t\t\tsecret: true,\n\t\t\tdescription: \"Twitch stream key (leave empty to skip Twitch relay)\",\n\t\t\trequired: false,\n\t\t},\n\t\t{\n\t\t\tkey: \"TIKTOK_STREAM_URL\",\n\t\t\tdefaultValue: \"\",\n\t\t\tsecret: true,\n\t\t\tdescription:\n\t\t\t\t\"Full TikTok RTMP URL from TikTok Studio (leave empty to skip TikTok relay)\",\n\t\t\trequired: false,\n\t\t},\n\t\t{\n\t\t\tkey: \"TELEGRAM_STREAM_URL\",\n\t\t\tdefaultValue: \"\",\n\t\t\tsecret: true,\n\t\t\tdescription:\n\t\t\t\t\"Full Telegram RTMPS URL including stream key (leave empty to skip Telegram relay)\",\n\t\t\trequired: false,\n\t\t},\n\t],\n\thealthcheck: {\n\t\ttest: \"curl -sf http://localhost:8080/health || exit 1\",\n\t\tinterval: \"15s\",\n\t\ttimeout: \"5s\",\n\t\tretries: 3,\n\t},\n\tdependsOn: [],\n\trestartPolicy: \"unless-stopped\",\n\tnetworks: [\"openclaw-network\"],\n\n\tdeploy: {\n\t\tresources: {\n\t\t\tlimits: { cpus: \"2.0\", memory: \"2G\" },\n\t\t\treservations: { cpus: \"0.5\", memory: \"512M\" },\n\t\t},\n\t},\n\n\tskills: [],\n\topenclawEnvVars: [\n\t\t{\n\t\t\tkey: \"STREAM_GATEWAY_HOST\",\n\t\t\tdefaultValue: \"stream-gateway\",\n\t\t\tsecret: false,\n\t\t\tdescription: \"Hostname of the stream-gateway container\",\n\t\t\trequired: true,\n\t\t},\n\t\t{\n\t\t\tkey: \"STREAM_GATEWAY_RTMP_PORT\",\n\t\t\tdefaultValue: \"1935\",\n\t\t\tsecret: false,\n\t\t\tdescription: \"RTMP ingest port on the stream-gateway\",\n\t\t\trequired: true,\n\t\t},\n\t\t{\n\t\t\tkey: \"STREAM_GATEWAY_HLS_PORT\",\n\t\t\tdefaultValue: \"8080\",\n\t\t\tsecret: false,\n\t\t\tdescription: \"HTTP port for HLS preview on the stream-gateway\",\n\t\t\trequired: true,\n\t\t},\n\t],\n\n\tdocsUrl: \"https://github.com/tiangolo/nginx-rtmp-docker\",\n\ttags: [\n\t\t\"streaming\",\n\t\t\"rtmp\",\n\t\t\"hls\",\n\t\t\"relay\",\n\t\t\"youtube\",\n\t\t\"twitch\",\n\t\t\"tiktok\",\n\t\t\"telegram\",\n\t\t\"obs\",\n\t\t\"nginx\",\n\t],\n\tmaturity: \"experimental\",\n\n\trequires: [],\n\trecommends: [\"desktop-environment\"],\n\tconflictsWith: [],\n\n\tremovalWarning:\n\t\t\"⚠️ STREAMING KEYS REQUIRED: To relay to platforms you must provide at least one stream key. Without any keys configured the gateway will still accept RTMP input and serve HLS locally but nothing will be forwarded.\",\n\tminMemoryMB: 512,\n\tgpuRequired: false,\n\n\tnativeSupported: true,\n\tnativeRecipes: [\n\t\t{\n\t\t\tplatform: \"linux\",\n\t\t\tinstallSteps: [\n\t\t\t\t\"command -v nginx >/dev/null 2>&1 || (command -v apt-get >/dev/null 2>&1 && sudo apt-get update -qq && sudo apt-get install -y -qq nginx libnginx-mod-rtmp ffmpeg)\",\n\t\t\t\t\"command -v nginx >/dev/null 2>&1 || (command -v dnf >/dev/null 2>&1 && sudo dnf install -y nginx nginx-mod-rtmp ffmpeg)\",\n\t\t\t],\n\t\t\tstartCommand: \"sudo systemctl start nginx\",\n\t\t\tstopCommand: \"sudo systemctl stop nginx\",\n\t\t\tconfigPath: \"/etc/nginx/nginx.conf\",\n\t\t\tconfigTemplate:\n\t\t\t\t'# Generated for OpenClaw bare-metal\\nworker_processes auto;\\nrtmp_auto_push on;\\n\\nevents { worker_connections 1024; }\\n\\nrtmp {\\n server {\\n listen 1935;\\n chunk_size 4096;\\n application live {\\n live on;\\n record off;\\n hls on;\\n hls_path /tmp/hls;\\n hls_fragment 3;\\n hls_playlist_length 60;\\n }\\n }\\n}\\n\\nhttp {\\n server {\\n listen 8080;\\n location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } root /tmp; add_header Cache-Control no-cache; }\\n location /health { return 200 \"OK\"; }\\n }\\n}\\n',\n\t\t\tsystemdUnit: \"nginx\",\n\t\t},\n\t],\n};\n"],"mappings":";AAEA,MAAa,0BAA6C;CACzD,IAAI;CACJ,MAAM;CACN,aACC;CACD,UAAU;CACV,MAAM;CAEN,OAAO;CACP,UAAU;CACV,OAAO,CACN;EACC,MAAM;EACN,WAAW;EACX,aAAa;EACb,SAAS;EACT,EACD;EACC,MAAM;EACN,WAAW;EACX,aAAa;EACb,SAAS;EACT,CACD;CACD,SAAS,CACR;EACC,MAAM;EACN,eAAe;EACf,aAAa;EACb,CACD;CACD,aAAa;EACZ;GACC,KAAK;GACL,cAAc;GACd,QAAQ;GACR,aAAa;GACb,UAAU;GACV;EACD;GACC,KAAK;GACL,cAAc;GACd,QAAQ;GACR,aAAa;GACb,UAAU;GACV;EACD;GACC,KAAK;GACL,cAAc;GACd,QAAQ;GACR,aACC;GACD,UAAU;GACV;EACD;GACC,KAAK;GACL,cAAc;GACd,QAAQ;GACR,aACC;GACD,UAAU;GACV;EACD;CACD,aAAa;EACZ,MAAM;EACN,UAAU;EACV,SAAS;EACT,SAAS;EACT;CACD,WAAW,EAAE;CACb,eAAe;CACf,UAAU,CAAC,mBAAmB;CAE9B,QAAQ,EACP,WAAW;EACV,QAAQ;GAAE,MAAM;GAAO,QAAQ;GAAM;EACrC,cAAc;GAAE,MAAM;GAAO,QAAQ;GAAQ;EAC7C,EACD;CAED,QAAQ,EAAE;CACV,iBAAiB;EAChB;GACC,KAAK;GACL,cAAc;GACd,QAAQ;GACR,aAAa;GACb,UAAU;GACV;EACD;GACC,KAAK;GACL,cAAc;GACd,QAAQ;GACR,aAAa;GACb,UAAU;GACV;EACD;GACC,KAAK;GACL,cAAc;GACd,QAAQ;GACR,aAAa;GACb,UAAU;GACV;EACD;CAED,SAAS;CACT,MAAM;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD,UAAU;CAEV,UAAU,EAAE;CACZ,YAAY,CAAC,sBAAsB;CACnC,eAAe,EAAE;CAEjB,gBACC;CACD,aAAa;CACb,aAAa;CAEb,iBAAiB;CACjB,eAAe,CACd;EACC,UAAU;EACV,cAAc,CACb,qKACA,0HACA;EACD,cAAc;EACd,aAAa;EACb,YAAY;EACZ,gBACC;EACD,aAAa;EACb,CACD;CACD"}
|
package/dist/types.mjs
CHANGED
|
@@ -84,6 +84,16 @@ const SERVICE_CATEGORIES = [
|
|
|
84
84
|
id: "communication",
|
|
85
85
|
name: "Notifications",
|
|
86
86
|
icon: "🔔"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "desktop",
|
|
90
|
+
name: "Desktop Environment",
|
|
91
|
+
icon: "🖥️"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "streaming",
|
|
95
|
+
name: "Streaming & Relay",
|
|
96
|
+
icon: "📺"
|
|
87
97
|
}
|
|
88
98
|
];
|
|
89
99
|
|
package/dist/types.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type { z } from \"zod\";\nimport type {\n\tAddedDependencySchema,\n\tApiErrorSchema,\n\tComposeOptionsSchema,\n\tDeploymentTargetSchema,\n\tDeploymentTypeSchema,\n\tDeploySchema,\n\tEnvVariableSchema,\n\tErrorSchema,\n\tGenerationInputSchema,\n\tHealthCheckSchema,\n\tMaturitySchema,\n\tNativePlatformSchema,\n\tNativeRecipeSchema,\n\tOutputFormatSchema,\n\tPlatformSchema,\n\tPortMappingSchema,\n\tPresetSchema,\n\tProxyTypeSchema,\n\tResolvedServiceSchema,\n\tResolverOutputSchema,\n\tResourceLimitsSchema,\n\tRestartPolicySchema,\n\tServiceCategorySchema,\n\tServiceDefinitionSchema,\n\tSkillBindingSchema,\n\tSkillPackSchema,\n\tValidateRequestSchema,\n\tValidateResponseSchema,\n\tVolumeMappingSchema,\n\tWarningSchema,\n} from \"./schema.js\";\n\n// ─── Inferred Types ─────────────────────────────────────────────────────────\n\nexport type ServiceCategory = z.infer<typeof ServiceCategorySchema>;\nexport type Maturity = z.infer<typeof MaturitySchema>;\nexport type Platform = z.infer<typeof PlatformSchema>;\nexport type RestartPolicy = z.infer<typeof RestartPolicySchema>;\nexport type ProxyType = z.infer<typeof ProxyTypeSchema>;\nexport type DeploymentTarget = z.infer<typeof DeploymentTargetSchema>;\nexport type DeploymentType = z.infer<typeof DeploymentTypeSchema>;\nexport type NativePlatform = z.infer<typeof NativePlatformSchema>;\nexport type NativeRecipe = z.infer<typeof NativeRecipeSchema>;\nexport type OutputFormat = z.infer<typeof OutputFormatSchema>;\n\nexport type PortMapping = z.infer<typeof PortMappingSchema>;\nexport type VolumeMapping = z.infer<typeof VolumeMappingSchema>;\nexport type EnvVariable = z.infer<typeof EnvVariableSchema>;\nexport type HealthCheck = z.infer<typeof HealthCheckSchema>;\nexport type ResourceLimits = z.infer<typeof ResourceLimitsSchema>;\nexport type Deploy = z.infer<typeof DeploySchema>;\nexport type SkillBinding = z.infer<typeof SkillBindingSchema>;\n\nexport type ServiceDefinition = z.infer<typeof ServiceDefinitionSchema>;\nexport type SkillPack = z.infer<typeof SkillPackSchema>;\nexport type Preset = z.infer<typeof PresetSchema>;\n\nexport type GenerationInput = z.infer<typeof GenerationInputSchema>;\nexport type ComposeOptions = z.infer<typeof ComposeOptionsSchema>;\nexport type ResolvedService = z.infer<typeof ResolvedServiceSchema>;\nexport type AddedDependency = z.infer<typeof AddedDependencySchema>;\nexport type Warning = z.infer<typeof WarningSchema>;\nexport type ResolverError = z.infer<typeof ErrorSchema>;\nexport type ResolverOutput = z.infer<typeof ResolverOutputSchema>;\n\nexport type ValidateRequest = z.infer<typeof ValidateRequestSchema>;\nexport type ValidateResponse = z.infer<typeof ValidateResponseSchema>;\nexport type ApiError = z.infer<typeof ApiErrorSchema>;\n\n// ─── Additional Types ───────────────────────────────────────────────────────\n\nexport interface ResolverInput {\n\tservices: string[];\n\tskillPacks: string[];\n\tproxy?: ProxyType;\n\tgpu?: boolean;\n\tplatform?: Platform;\n\tmonitoring?: boolean;\n}\n\nexport interface GeneratedFiles {\n\t[path: string]: string;\n}\n\nexport interface GenerationMetadata {\n\tserviceCount: number;\n\tskillCount: number;\n\testimatedMemoryMB: number;\n\tgeneratedAt: string;\n}\n\nexport interface GenerationResult {\n\tfiles: GeneratedFiles;\n\tmetadata: GenerationMetadata;\n}\n\nexport interface CategoryInfo {\n\tid: ServiceCategory;\n\tname: string;\n\ticon: string;\n}\n\nexport const SERVICE_CATEGORIES: CategoryInfo[] = [\n\t{ id: \"coding-agent\", name: \"AI Coding Agents\", icon: \"💻\" },\n\t{ id: \"ai-platform\", name: \"AI Platforms & Chat UIs\", icon: \"🧪\" },\n\t{ id: \"ai\", name: \"AI / Local Models\", icon: \"🤖\" },\n\t{ id: \"automation\", name: \"Automation & Workflows\", icon: \"🔄\" },\n\t{ id: \"vector-db\", name: \"Vector Databases\", icon: \"🧠\" },\n\t{ id: \"media\", name: \"Media & Video\", icon: \"🎬\" },\n\t{ id: \"social-media\", name: \"Social Media\", icon: \"📱\" },\n\t{ id: \"analytics\", name: \"Analytics\", icon: \"📊\" },\n\t{ id: \"knowledge\", name: \"Knowledge & Documents\", icon: \"📚\" },\n\t{ id: \"storage\", name: \"Object Storage\", icon: \"💾\" },\n\t{ id: \"database\", name: \"Databases & Caching\", icon: \"🗄️\" },\n\t{ id: \"dev-tools\", name: \"Developer Tools\", icon: \"🛠️\" },\n\t{ id: \"proxy\", name: \"Reverse Proxy\", icon: \"🌐\" },\n\t{ id: \"monitoring\", name: \"Monitoring\", icon: \"📡\" },\n\t{ id: \"browser\", name: \"Browser Automation\", icon: \"🌐\" },\n\t{ id: \"search\", name: \"Search\", icon: \"🔍\" },\n\t{ id: \"communication\", name: \"Notifications\", icon: \"🔔\" },\n];\n"],"mappings":";AAwGA,MAAa,qBAAqC;CACjD;EAAE,IAAI;EAAgB,MAAM;EAAoB,MAAM;EAAM;CAC5D;EAAE,IAAI;EAAe,MAAM;EAA2B,MAAM;EAAM;CAClE;EAAE,IAAI;EAAM,MAAM;EAAqB,MAAM;EAAM;CACnD;EAAE,IAAI;EAAc,MAAM;EAA0B,MAAM;EAAM;CAChE;EAAE,IAAI;EAAa,MAAM;EAAoB,MAAM;EAAM;CACzD;EAAE,IAAI;EAAS,MAAM;EAAiB,MAAM;EAAM;CAClD;EAAE,IAAI;EAAgB,MAAM;EAAgB,MAAM;EAAM;CACxD;EAAE,IAAI;EAAa,MAAM;EAAa,MAAM;EAAM;CAClD;EAAE,IAAI;EAAa,MAAM;EAAyB,MAAM;EAAM;CAC9D;EAAE,IAAI;EAAW,MAAM;EAAkB,MAAM;EAAM;CACrD;EAAE,IAAI;EAAY,MAAM;EAAuB,MAAM;EAAO;CAC5D;EAAE,IAAI;EAAa,MAAM;EAAmB,MAAM;EAAO;CACzD;EAAE,IAAI;EAAS,MAAM;EAAiB,MAAM;EAAM;CAClD;EAAE,IAAI;EAAc,MAAM;EAAc,MAAM;EAAM;CACpD;EAAE,IAAI;EAAW,MAAM;EAAsB,MAAM;EAAM;CACzD;EAAE,IAAI;EAAU,MAAM;EAAU,MAAM;EAAM;CAC5C;EAAE,IAAI;EAAiB,MAAM;EAAiB,MAAM;EAAM;CAC1D"}
|
|
1
|
+
{"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type { z } from \"zod\";\nimport type {\n\tAddedDependencySchema,\n\tApiErrorSchema,\n\tComposeOptionsSchema,\n\tDeploymentTargetSchema,\n\tDeploymentTypeSchema,\n\tDeploySchema,\n\tEnvVariableSchema,\n\tErrorSchema,\n\tGenerationInputSchema,\n\tHealthCheckSchema,\n\tMaturitySchema,\n\tNativePlatformSchema,\n\tNativeRecipeSchema,\n\tOutputFormatSchema,\n\tPlatformSchema,\n\tPortMappingSchema,\n\tPresetSchema,\n\tProxyTypeSchema,\n\tResolvedServiceSchema,\n\tResolverOutputSchema,\n\tResourceLimitsSchema,\n\tRestartPolicySchema,\n\tServiceCategorySchema,\n\tServiceDefinitionSchema,\n\tSkillBindingSchema,\n\tSkillPackSchema,\n\tValidateRequestSchema,\n\tValidateResponseSchema,\n\tVolumeMappingSchema,\n\tWarningSchema,\n} from \"./schema.js\";\n\n// ─── Inferred Types ─────────────────────────────────────────────────────────\n\nexport type ServiceCategory = z.infer<typeof ServiceCategorySchema>;\nexport type Maturity = z.infer<typeof MaturitySchema>;\nexport type Platform = z.infer<typeof PlatformSchema>;\nexport type RestartPolicy = z.infer<typeof RestartPolicySchema>;\nexport type ProxyType = z.infer<typeof ProxyTypeSchema>;\nexport type DeploymentTarget = z.infer<typeof DeploymentTargetSchema>;\nexport type DeploymentType = z.infer<typeof DeploymentTypeSchema>;\nexport type NativePlatform = z.infer<typeof NativePlatformSchema>;\nexport type NativeRecipe = z.infer<typeof NativeRecipeSchema>;\nexport type OutputFormat = z.infer<typeof OutputFormatSchema>;\n\nexport type PortMapping = z.infer<typeof PortMappingSchema>;\nexport type VolumeMapping = z.infer<typeof VolumeMappingSchema>;\nexport type EnvVariable = z.infer<typeof EnvVariableSchema>;\nexport type HealthCheck = z.infer<typeof HealthCheckSchema>;\nexport type ResourceLimits = z.infer<typeof ResourceLimitsSchema>;\nexport type Deploy = z.infer<typeof DeploySchema>;\nexport type SkillBinding = z.infer<typeof SkillBindingSchema>;\n\nexport type ServiceDefinition = z.infer<typeof ServiceDefinitionSchema>;\nexport type SkillPack = z.infer<typeof SkillPackSchema>;\nexport type Preset = z.infer<typeof PresetSchema>;\n\nexport type GenerationInput = z.infer<typeof GenerationInputSchema>;\nexport type ComposeOptions = z.infer<typeof ComposeOptionsSchema>;\nexport type ResolvedService = z.infer<typeof ResolvedServiceSchema>;\nexport type AddedDependency = z.infer<typeof AddedDependencySchema>;\nexport type Warning = z.infer<typeof WarningSchema>;\nexport type ResolverError = z.infer<typeof ErrorSchema>;\nexport type ResolverOutput = z.infer<typeof ResolverOutputSchema>;\n\nexport type ValidateRequest = z.infer<typeof ValidateRequestSchema>;\nexport type ValidateResponse = z.infer<typeof ValidateResponseSchema>;\nexport type ApiError = z.infer<typeof ApiErrorSchema>;\n\n// ─── Additional Types ───────────────────────────────────────────────────────\n\nexport interface ResolverInput {\n\tservices: string[];\n\tskillPacks: string[];\n\tproxy?: ProxyType;\n\tgpu?: boolean;\n\tplatform?: Platform;\n\tmonitoring?: boolean;\n}\n\nexport interface GeneratedFiles {\n\t[path: string]: string;\n}\n\nexport interface GenerationMetadata {\n\tserviceCount: number;\n\tskillCount: number;\n\testimatedMemoryMB: number;\n\tgeneratedAt: string;\n}\n\nexport interface GenerationResult {\n\tfiles: GeneratedFiles;\n\tmetadata: GenerationMetadata;\n}\n\nexport interface CategoryInfo {\n\tid: ServiceCategory;\n\tname: string;\n\ticon: string;\n}\n\nexport const SERVICE_CATEGORIES: CategoryInfo[] = [\n\t{ id: \"coding-agent\", name: \"AI Coding Agents\", icon: \"💻\" },\n\t{ id: \"ai-platform\", name: \"AI Platforms & Chat UIs\", icon: \"🧪\" },\n\t{ id: \"ai\", name: \"AI / Local Models\", icon: \"🤖\" },\n\t{ id: \"automation\", name: \"Automation & Workflows\", icon: \"🔄\" },\n\t{ id: \"vector-db\", name: \"Vector Databases\", icon: \"🧠\" },\n\t{ id: \"media\", name: \"Media & Video\", icon: \"🎬\" },\n\t{ id: \"social-media\", name: \"Social Media\", icon: \"📱\" },\n\t{ id: \"analytics\", name: \"Analytics\", icon: \"📊\" },\n\t{ id: \"knowledge\", name: \"Knowledge & Documents\", icon: \"📚\" },\n\t{ id: \"storage\", name: \"Object Storage\", icon: \"💾\" },\n\t{ id: \"database\", name: \"Databases & Caching\", icon: \"🗄️\" },\n\t{ id: \"dev-tools\", name: \"Developer Tools\", icon: \"🛠️\" },\n\t{ id: \"proxy\", name: \"Reverse Proxy\", icon: \"🌐\" },\n\t{ id: \"monitoring\", name: \"Monitoring\", icon: \"📡\" },\n\t{ id: \"browser\", name: \"Browser Automation\", icon: \"🌐\" },\n\t{ id: \"search\", name: \"Search\", icon: \"🔍\" },\n\t{ id: \"communication\", name: \"Notifications\", icon: \"🔔\" },\n\t{ id: \"desktop\", name: \"Desktop Environment\", icon: \"🖥️\" },\n\t{ id: \"streaming\", name: \"Streaming & Relay\", icon: \"📺\" },\n];\n"],"mappings":";AAwGA,MAAa,qBAAqC;CACjD;EAAE,IAAI;EAAgB,MAAM;EAAoB,MAAM;EAAM;CAC5D;EAAE,IAAI;EAAe,MAAM;EAA2B,MAAM;EAAM;CAClE;EAAE,IAAI;EAAM,MAAM;EAAqB,MAAM;EAAM;CACnD;EAAE,IAAI;EAAc,MAAM;EAA0B,MAAM;EAAM;CAChE;EAAE,IAAI;EAAa,MAAM;EAAoB,MAAM;EAAM;CACzD;EAAE,IAAI;EAAS,MAAM;EAAiB,MAAM;EAAM;CAClD;EAAE,IAAI;EAAgB,MAAM;EAAgB,MAAM;EAAM;CACxD;EAAE,IAAI;EAAa,MAAM;EAAa,MAAM;EAAM;CAClD;EAAE,IAAI;EAAa,MAAM;EAAyB,MAAM;EAAM;CAC9D;EAAE,IAAI;EAAW,MAAM;EAAkB,MAAM;EAAM;CACrD;EAAE,IAAI;EAAY,MAAM;EAAuB,MAAM;EAAO;CAC5D;EAAE,IAAI;EAAa,MAAM;EAAmB,MAAM;EAAO;CACzD;EAAE,IAAI;EAAS,MAAM;EAAiB,MAAM;EAAM;CAClD;EAAE,IAAI;EAAc,MAAM;EAAc,MAAM;EAAM;CACpD;EAAE,IAAI;EAAW,MAAM;EAAsB,MAAM;EAAM;CACzD;EAAE,IAAI;EAAU,MAAM;EAAU,MAAM;EAAM;CAC5C;EAAE,IAAI;EAAiB,MAAM;EAAiB,MAAM;EAAM;CAC1D;EAAE,IAAI;EAAW,MAAM;EAAuB,MAAM;EAAO;CAC3D;EAAE,IAAI;EAAa,MAAM;EAAqB,MAAM;EAAM;CAC1D"}
|
package/package.json
CHANGED
package/src/schema.ts
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { ServiceDefinition } from "../../types.js";
|
|
2
|
+
|
|
3
|
+
export const comfyuiDefinition: ServiceDefinition = {
|
|
4
|
+
id: "comfyui",
|
|
5
|
+
name: "ComfyUI",
|
|
6
|
+
description:
|
|
7
|
+
"Node-based visual workflow editor for Stable Diffusion and other generative AI models. Design complex image/video generation pipelines with a drag-and-drop graph UI and a powerful REST API.",
|
|
8
|
+
category: "ai",
|
|
9
|
+
icon: "🎨",
|
|
10
|
+
|
|
11
|
+
image: "ghcr.io/ai-dock/comfyui",
|
|
12
|
+
imageTag: "latest",
|
|
13
|
+
ports: [
|
|
14
|
+
{
|
|
15
|
+
host: 8188,
|
|
16
|
+
container: 8188,
|
|
17
|
+
description: "ComfyUI Web UI & API",
|
|
18
|
+
exposed: true,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
volumes: [
|
|
22
|
+
{
|
|
23
|
+
name: "comfyui-models",
|
|
24
|
+
containerPath: "/opt/ComfyUI/models",
|
|
25
|
+
description: "Model checkpoint, LoRA, VAE, and ControlNet files",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "comfyui-output",
|
|
29
|
+
containerPath: "/opt/ComfyUI/output",
|
|
30
|
+
description: "Generated images and output files",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "comfyui-custom-nodes",
|
|
34
|
+
containerPath: "/opt/ComfyUI/custom_nodes",
|
|
35
|
+
description: "Community custom node extensions",
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
environment: [],
|
|
39
|
+
healthcheck: {
|
|
40
|
+
test: "curl -f http://localhost:8188/system_stats || exit 1",
|
|
41
|
+
interval: "30s",
|
|
42
|
+
timeout: "10s",
|
|
43
|
+
retries: 3,
|
|
44
|
+
startPeriod: "60s",
|
|
45
|
+
},
|
|
46
|
+
dependsOn: [],
|
|
47
|
+
restartPolicy: "unless-stopped",
|
|
48
|
+
networks: ["openclaw-network"],
|
|
49
|
+
|
|
50
|
+
skills: [{ skillId: "comfyui-generate", autoInstall: true }],
|
|
51
|
+
openclawEnvVars: [
|
|
52
|
+
{
|
|
53
|
+
key: "COMFYUI_HOST",
|
|
54
|
+
defaultValue: "comfyui",
|
|
55
|
+
secret: false,
|
|
56
|
+
description: "ComfyUI hostname for OpenClaw",
|
|
57
|
+
required: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
key: "COMFYUI_PORT",
|
|
61
|
+
defaultValue: "8188",
|
|
62
|
+
secret: false,
|
|
63
|
+
description: "ComfyUI API port for OpenClaw",
|
|
64
|
+
required: true,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
|
|
68
|
+
docsUrl: "https://github.com/comfyanonymous/ComfyUI",
|
|
69
|
+
selfHostedDocsUrl: "https://github.com/comfyanonymous/ComfyUI",
|
|
70
|
+
tags: [
|
|
71
|
+
"image-generation",
|
|
72
|
+
"ai-art",
|
|
73
|
+
"stable-diffusion",
|
|
74
|
+
"workflow",
|
|
75
|
+
"node-editor",
|
|
76
|
+
"text-to-image",
|
|
77
|
+
"comfyui",
|
|
78
|
+
],
|
|
79
|
+
maturity: "experimental",
|
|
80
|
+
|
|
81
|
+
requires: [],
|
|
82
|
+
recommends: ["ollama"],
|
|
83
|
+
conflictsWith: [],
|
|
84
|
+
|
|
85
|
+
removalWarning:
|
|
86
|
+
"⚠️ GPU INFRASTRUCTURE REQUIRED: ComfyUI requires an NVIDIA GPU with CUDA support and the NVIDIA Container Toolkit (nvidia-docker2) installed on the host. Without GPU acceleration, image generation will be extremely slow (minutes per image). Ensure your deployment target has adequate GPU resources (minimum 4 GB VRAM, 8 GB+ recommended) before adding this service.",
|
|
87
|
+
|
|
88
|
+
minMemoryMB: 4096,
|
|
89
|
+
gpuRequired: true,
|
|
90
|
+
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import type { ServiceDefinition } from "../../types.js";
|
|
2
|
+
|
|
3
|
+
export const desktopEnvironmentDefinition: ServiceDefinition = {
|
|
4
|
+
id: "desktop-environment",
|
|
5
|
+
name: "Desktop Environment",
|
|
6
|
+
description:
|
|
7
|
+
"Isolated KasmVNC-based Linux desktop that gives AI agents full computer-use capabilities — screen vision, mouse/keyboard control, file management, and application launching (VS Code, Chrome, Firefox). OBS Studio is pre-installed for optional recording or live-streaming.",
|
|
8
|
+
category: "desktop",
|
|
9
|
+
icon: "🖥️",
|
|
10
|
+
|
|
11
|
+
image: "kasmweb/core-ubuntu-jammy",
|
|
12
|
+
imageTag: "1.16.0",
|
|
13
|
+
ports: [
|
|
14
|
+
{
|
|
15
|
+
host: 6901,
|
|
16
|
+
container: 6901,
|
|
17
|
+
description: "KasmVNC web interface (browser-based desktop access)",
|
|
18
|
+
exposed: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
host: 5900,
|
|
22
|
+
container: 5900,
|
|
23
|
+
description: "VNC protocol port (native VNC clients)",
|
|
24
|
+
exposed: false,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
host: 4455,
|
|
28
|
+
container: 4455,
|
|
29
|
+
description: "OBS WebSocket control port (when OBS is running)",
|
|
30
|
+
exposed: false,
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
volumes: [
|
|
34
|
+
{
|
|
35
|
+
name: "desktop-config",
|
|
36
|
+
containerPath: "/home/kasm-user",
|
|
37
|
+
description: "Desktop user home with config persistence",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "desktop-workspace",
|
|
41
|
+
containerPath: "/home/kasm-user/workspace",
|
|
42
|
+
description: "Shared workspace directory for files and projects",
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
environment: [
|
|
46
|
+
{
|
|
47
|
+
key: "VNC_PW",
|
|
48
|
+
defaultValue: "changeme",
|
|
49
|
+
secret: true,
|
|
50
|
+
description: "Password for VNC / KasmVNC web access",
|
|
51
|
+
required: true,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
key: "VNC_RESOLUTION",
|
|
55
|
+
defaultValue: "1920x1080",
|
|
56
|
+
secret: false,
|
|
57
|
+
description: "Desktop screen resolution (WidthxHeight)",
|
|
58
|
+
required: false,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: "SSL_VNC_ONLY",
|
|
62
|
+
defaultValue: "false",
|
|
63
|
+
secret: false,
|
|
64
|
+
description:
|
|
65
|
+
"When false, allows HTTP/WS connections without SSL (useful for local/Docker networking)",
|
|
66
|
+
required: false,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
key: "OBS_WS_PORT",
|
|
70
|
+
defaultValue: "4455",
|
|
71
|
+
secret: false,
|
|
72
|
+
description: "OBS WebSocket port (used when OBS is launched manually)",
|
|
73
|
+
required: false,
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
key: "OBS_PASSWORD",
|
|
77
|
+
defaultValue: "changeme",
|
|
78
|
+
secret: true,
|
|
79
|
+
description: "OBS WebSocket password (used when OBS is launched manually)",
|
|
80
|
+
required: false,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
healthcheck: {
|
|
84
|
+
test: "curl -sfk https://localhost:6901/ > /dev/null || curl -sf http://localhost:6901/ > /dev/null || exit 1",
|
|
85
|
+
interval: "10s",
|
|
86
|
+
timeout: "10s",
|
|
87
|
+
retries: 6,
|
|
88
|
+
startPeriod: "60s",
|
|
89
|
+
},
|
|
90
|
+
dependsOn: [],
|
|
91
|
+
restartPolicy: "unless-stopped",
|
|
92
|
+
networks: ["openclaw-network"],
|
|
93
|
+
|
|
94
|
+
deploy: {
|
|
95
|
+
resources: {
|
|
96
|
+
limits: { cpus: "4.0", memory: "8G" },
|
|
97
|
+
reservations: { cpus: "2.0", memory: "4G" },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
skills: [{ skillId: "desktop-use", autoInstall: true }],
|
|
102
|
+
openclawEnvVars: [
|
|
103
|
+
{
|
|
104
|
+
key: "DESKTOP_HOST",
|
|
105
|
+
defaultValue: "desktop-environment",
|
|
106
|
+
secret: false,
|
|
107
|
+
description: "Hostname of the desktop-environment container",
|
|
108
|
+
required: true,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
key: "DESKTOP_VNC_PORT",
|
|
112
|
+
defaultValue: "6901",
|
|
113
|
+
secret: false,
|
|
114
|
+
description: "KasmVNC web port",
|
|
115
|
+
required: true,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
key: "DESKTOP_VNC_PASSWORD",
|
|
119
|
+
defaultValue: "${VNC_PW}",
|
|
120
|
+
secret: true,
|
|
121
|
+
description: "VNC password (references service password)",
|
|
122
|
+
required: true,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
|
|
126
|
+
docsUrl: "https://www.kasmweb.com/docs/latest/index.html",
|
|
127
|
+
tags: [
|
|
128
|
+
"computer-use",
|
|
129
|
+
"vnc",
|
|
130
|
+
"desktop",
|
|
131
|
+
"screen-capture",
|
|
132
|
+
"automation",
|
|
133
|
+
"obs",
|
|
134
|
+
"kasm",
|
|
135
|
+
],
|
|
136
|
+
maturity: "experimental",
|
|
137
|
+
|
|
138
|
+
requires: [],
|
|
139
|
+
recommends: ["stream-gateway"],
|
|
140
|
+
conflictsWith: [],
|
|
141
|
+
|
|
142
|
+
removalWarning:
|
|
143
|
+
"⚠️ HEAVY RESOURCE USAGE: The desktop environment requires at least 4 GB RAM (8 GB recommended) and 2+ CPU cores. It runs a full Linux desktop with XFCE inside KasmVNC. OBS Studio is pre-installed but NOT auto-started — launch it manually or via agent tools when needed. Ensure your deployment target can handle these resources alongside other services.",
|
|
144
|
+
minMemoryMB: 4096,
|
|
145
|
+
gpuRequired: false,
|
|
146
|
+
|
|
147
|
+
nativeSupported: true,
|
|
148
|
+
nativeRecipes: [
|
|
149
|
+
{
|
|
150
|
+
platform: "linux",
|
|
151
|
+
installSteps: [
|
|
152
|
+
"command -v Xvfb >/dev/null 2>&1 || (command -v apt-get >/dev/null 2>&1 && sudo apt-get update -qq && sudo apt-get install -y -qq xvfb xfce4 xfce4-terminal tigervnc-standalone-server scrot xdotool xclip)",
|
|
153
|
+
"command -v obs >/dev/null 2>&1 || (sudo add-apt-repository -y ppa:obsproject/obs-studio && sudo apt-get update -qq && sudo apt-get install -y -qq obs-studio)",
|
|
154
|
+
],
|
|
155
|
+
startCommand:
|
|
156
|
+
"vncserver :1 -geometry 1920x1080 -depth 24 -localhost no 2>/dev/null || Xvfb :1 -screen 0 1920x1080x24 &",
|
|
157
|
+
stopCommand: "vncserver -kill :1 2>/dev/null; killall Xvfb 2>/dev/null",
|
|
158
|
+
configPath: "/etc/vnc/xstartup",
|
|
159
|
+
configTemplate:
|
|
160
|
+
"#!/bin/sh\n# Generated for OpenClaw bare-metal desktop\nexport DISPLAY=:1\nstartxfce4 &\n",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
};
|
|
@@ -6,10 +6,12 @@ export { caddyDefinition } from "./caddy.js";
|
|
|
6
6
|
export { chromadbDefinition } from "./chromadb.js";
|
|
7
7
|
export { claudeCodeDefinition } from "./claude-code.js";
|
|
8
8
|
export { codeServerDefinition } from "./code-server.js";
|
|
9
|
+
export { comfyuiDefinition } from "./comfyui.js";
|
|
9
10
|
export { convexDefinition } from "./convex.js";
|
|
10
11
|
export { convexDashboardDefinition } from "./convex-dashboard.js";
|
|
11
12
|
export { codexDefinition } from "./codex.js";
|
|
12
13
|
export { coolifyDefinition } from "./coolify.js";
|
|
14
|
+
export { desktopEnvironmentDefinition } from "./desktop-environment.js";
|
|
13
15
|
export { difyDefinition } from "./dify.js";
|
|
14
16
|
export { docsgptDefinition } from "./docsgpt.js";
|
|
15
17
|
export { dokployDefinition } from "./dokploy.js";
|
|
@@ -57,6 +59,7 @@ export { rocketchatDefinition } from "./rocketchat.js";
|
|
|
57
59
|
export { searxngDefinition } from "./searxng.js";
|
|
58
60
|
export { stableDiffusionDefinition } from "./stable-diffusion.js";
|
|
59
61
|
export { steelBrowserDefinition } from "./steel-browser.js";
|
|
62
|
+
export { streamGatewayDefinition } from "./stream-gateway.js";
|
|
60
63
|
export { tailscaleDefinition } from "./tailscale.js";
|
|
61
64
|
export { temporalDefinition } from "./temporal.js";
|
|
62
65
|
export { traefikDefinition } from "./traefik.js";
|
|
@@ -77,10 +80,12 @@ import { caddyDefinition } from "./caddy.js";
|
|
|
77
80
|
import { chromadbDefinition } from "./chromadb.js";
|
|
78
81
|
import { claudeCodeDefinition } from "./claude-code.js";
|
|
79
82
|
import { codeServerDefinition } from "./code-server.js";
|
|
83
|
+
import { comfyuiDefinition } from "./comfyui.js";
|
|
80
84
|
import { convexDefinition } from "./convex.js";
|
|
81
85
|
import { convexDashboardDefinition } from "./convex-dashboard.js";
|
|
82
86
|
import { codexDefinition } from "./codex.js";
|
|
83
87
|
import { coolifyDefinition } from "./coolify.js";
|
|
88
|
+
import { desktopEnvironmentDefinition } from "./desktop-environment.js";
|
|
84
89
|
import { difyDefinition } from "./dify.js";
|
|
85
90
|
import { docsgptDefinition } from "./docsgpt.js";
|
|
86
91
|
import { dokployDefinition } from "./dokploy.js";
|
|
@@ -128,6 +133,7 @@ import { rocketchatDefinition } from "./rocketchat.js";
|
|
|
128
133
|
import { searxngDefinition } from "./searxng.js";
|
|
129
134
|
import { stableDiffusionDefinition } from "./stable-diffusion.js";
|
|
130
135
|
import { steelBrowserDefinition } from "./steel-browser.js";
|
|
136
|
+
import { streamGatewayDefinition } from "./stream-gateway.js";
|
|
131
137
|
import { tailscaleDefinition } from "./tailscale.js";
|
|
132
138
|
import { temporalDefinition } from "./temporal.js";
|
|
133
139
|
import { traefikDefinition } from "./traefik.js";
|
|
@@ -173,6 +179,7 @@ export const allServiceDefinitions: ServiceDefinition[] = [
|
|
|
173
179
|
rocketchatDefinition,
|
|
174
180
|
mattermostDefinition,
|
|
175
181
|
stableDiffusionDefinition,
|
|
182
|
+
comfyuiDefinition,
|
|
176
183
|
playwrightServerDefinition,
|
|
177
184
|
openWebuiDefinition,
|
|
178
185
|
librechatDefinition,
|
|
@@ -209,4 +216,6 @@ export const allServiceDefinitions: ServiceDefinition[] = [
|
|
|
209
216
|
lasuiteMeetBackendDefinition,
|
|
210
217
|
lasuiteMeetFrontendDefinition,
|
|
211
218
|
lasuiteMeetAgentsDefinition,
|
|
219
|
+
desktopEnvironmentDefinition,
|
|
220
|
+
streamGatewayDefinition,
|
|
212
221
|
];
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { ServiceDefinition } from "../../types.js";
|
|
2
|
+
|
|
3
|
+
export const streamGatewayDefinition: ServiceDefinition = {
|
|
4
|
+
id: "stream-gateway",
|
|
5
|
+
name: "Stream Gateway",
|
|
6
|
+
description:
|
|
7
|
+
"NGINX-RTMP relay server that receives a local RTMP stream (e.g. from OBS in the desktop-environment) and fans it out to YouTube, Twitch, TikTok, and Telegram simultaneously. Also serves an HLS preview on HTTP for local viewing.",
|
|
8
|
+
category: "streaming",
|
|
9
|
+
icon: "📺",
|
|
10
|
+
|
|
11
|
+
image: "tiangolo/nginx-rtmp",
|
|
12
|
+
imageTag: "latest",
|
|
13
|
+
ports: [
|
|
14
|
+
{
|
|
15
|
+
host: 1935,
|
|
16
|
+
container: 1935,
|
|
17
|
+
description: "RTMP ingest (receives stream from OBS or ffmpeg)",
|
|
18
|
+
exposed: true,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
host: 8080,
|
|
22
|
+
container: 8080,
|
|
23
|
+
description: "HTTP server for HLS preview and stats",
|
|
24
|
+
exposed: true,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
volumes: [
|
|
28
|
+
{
|
|
29
|
+
name: "stream-gateway-hls",
|
|
30
|
+
containerPath: "/tmp/hls",
|
|
31
|
+
description: "HLS segment storage for live preview playback",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
environment: [
|
|
35
|
+
{
|
|
36
|
+
key: "YOUTUBE_STREAM_KEY",
|
|
37
|
+
defaultValue: "",
|
|
38
|
+
secret: true,
|
|
39
|
+
description: "YouTube Live stream key (leave empty to skip YouTube relay)",
|
|
40
|
+
required: false,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: "TWITCH_STREAM_KEY",
|
|
44
|
+
defaultValue: "",
|
|
45
|
+
secret: true,
|
|
46
|
+
description: "Twitch stream key (leave empty to skip Twitch relay)",
|
|
47
|
+
required: false,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
key: "TIKTOK_STREAM_URL",
|
|
51
|
+
defaultValue: "",
|
|
52
|
+
secret: true,
|
|
53
|
+
description:
|
|
54
|
+
"Full TikTok RTMP URL from TikTok Studio (leave empty to skip TikTok relay)",
|
|
55
|
+
required: false,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "TELEGRAM_STREAM_URL",
|
|
59
|
+
defaultValue: "",
|
|
60
|
+
secret: true,
|
|
61
|
+
description:
|
|
62
|
+
"Full Telegram RTMPS URL including stream key (leave empty to skip Telegram relay)",
|
|
63
|
+
required: false,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
healthcheck: {
|
|
67
|
+
test: "curl -sf http://localhost:8080/health || exit 1",
|
|
68
|
+
interval: "15s",
|
|
69
|
+
timeout: "5s",
|
|
70
|
+
retries: 3,
|
|
71
|
+
},
|
|
72
|
+
dependsOn: [],
|
|
73
|
+
restartPolicy: "unless-stopped",
|
|
74
|
+
networks: ["openclaw-network"],
|
|
75
|
+
|
|
76
|
+
deploy: {
|
|
77
|
+
resources: {
|
|
78
|
+
limits: { cpus: "2.0", memory: "2G" },
|
|
79
|
+
reservations: { cpus: "0.5", memory: "512M" },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
skills: [],
|
|
84
|
+
openclawEnvVars: [
|
|
85
|
+
{
|
|
86
|
+
key: "STREAM_GATEWAY_HOST",
|
|
87
|
+
defaultValue: "stream-gateway",
|
|
88
|
+
secret: false,
|
|
89
|
+
description: "Hostname of the stream-gateway container",
|
|
90
|
+
required: true,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: "STREAM_GATEWAY_RTMP_PORT",
|
|
94
|
+
defaultValue: "1935",
|
|
95
|
+
secret: false,
|
|
96
|
+
description: "RTMP ingest port on the stream-gateway",
|
|
97
|
+
required: true,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
key: "STREAM_GATEWAY_HLS_PORT",
|
|
101
|
+
defaultValue: "8080",
|
|
102
|
+
secret: false,
|
|
103
|
+
description: "HTTP port for HLS preview on the stream-gateway",
|
|
104
|
+
required: true,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
|
|
108
|
+
docsUrl: "https://github.com/tiangolo/nginx-rtmp-docker",
|
|
109
|
+
tags: [
|
|
110
|
+
"streaming",
|
|
111
|
+
"rtmp",
|
|
112
|
+
"hls",
|
|
113
|
+
"relay",
|
|
114
|
+
"youtube",
|
|
115
|
+
"twitch",
|
|
116
|
+
"tiktok",
|
|
117
|
+
"telegram",
|
|
118
|
+
"obs",
|
|
119
|
+
"nginx",
|
|
120
|
+
],
|
|
121
|
+
maturity: "experimental",
|
|
122
|
+
|
|
123
|
+
requires: [],
|
|
124
|
+
recommends: ["desktop-environment"],
|
|
125
|
+
conflictsWith: [],
|
|
126
|
+
|
|
127
|
+
removalWarning:
|
|
128
|
+
"⚠️ STREAMING KEYS REQUIRED: To relay to platforms you must provide at least one stream key. Without any keys configured the gateway will still accept RTMP input and serve HLS locally but nothing will be forwarded.",
|
|
129
|
+
minMemoryMB: 512,
|
|
130
|
+
gpuRequired: false,
|
|
131
|
+
|
|
132
|
+
nativeSupported: true,
|
|
133
|
+
nativeRecipes: [
|
|
134
|
+
{
|
|
135
|
+
platform: "linux",
|
|
136
|
+
installSteps: [
|
|
137
|
+
"command -v nginx >/dev/null 2>&1 || (command -v apt-get >/dev/null 2>&1 && sudo apt-get update -qq && sudo apt-get install -y -qq nginx libnginx-mod-rtmp ffmpeg)",
|
|
138
|
+
"command -v nginx >/dev/null 2>&1 || (command -v dnf >/dev/null 2>&1 && sudo dnf install -y nginx nginx-mod-rtmp ffmpeg)",
|
|
139
|
+
],
|
|
140
|
+
startCommand: "sudo systemctl start nginx",
|
|
141
|
+
stopCommand: "sudo systemctl stop nginx",
|
|
142
|
+
configPath: "/etc/nginx/nginx.conf",
|
|
143
|
+
configTemplate:
|
|
144
|
+
'# Generated for OpenClaw bare-metal\nworker_processes auto;\nrtmp_auto_push on;\n\nevents { worker_connections 1024; }\n\nrtmp {\n server {\n listen 1935;\n chunk_size 4096;\n application live {\n live on;\n record off;\n hls on;\n hls_path /tmp/hls;\n hls_fragment 3;\n hls_playlist_length 60;\n }\n }\n}\n\nhttp {\n server {\n listen 8080;\n location /hls { types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } root /tmp; add_header Cache-Control no-cache; }\n location /health { return 200 "OK"; }\n }\n}\n',
|
|
145
|
+
systemdUnit: "nginx",
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
};
|