@better-openclaw/core 1.0.18 → 1.0.20
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/.github/dependabot.yml +32 -0
- package/.github/workflows/ci.yml +8 -8
- package/.github/workflows/publish-core.yml +3 -3
- package/SECURITY.md +62 -0
- package/dist/deployers/coolify.cjs +44 -39
- package/dist/deployers/coolify.cjs.map +1 -1
- package/dist/deployers/coolify.mjs +44 -39
- package/dist/deployers/coolify.mjs.map +1 -1
- package/dist/deployers/dokploy.cjs +34 -30
- package/dist/deployers/dokploy.cjs.map +1 -1
- package/dist/deployers/dokploy.mjs +34 -30
- package/dist/deployers/dokploy.mjs.map +1 -1
- package/dist/port-scanner.cjs +1 -1
- package/dist/port-scanner.cjs.map +1 -1
- package/dist/port-scanner.mjs +1 -1
- package/dist/port-scanner.mjs.map +1 -1
- package/dist/services/definitions/usesend.cjs +4 -4
- package/dist/services/definitions/usesend.cjs.map +1 -1
- package/dist/services/definitions/usesend.mjs +4 -4
- package/dist/services/definitions/usesend.mjs.map +1 -1
- package/package.json +3 -4
- package/src/__snapshots__/composer.snapshot.test.ts.snap +248 -38
- package/src/deployers/coolify.ts +26 -27
- package/src/deployers/dokploy.ts +19 -20
- package/src/port-scanner.ts +1 -1
- package/src/services/definitions/usesend.ts +4 -4
package/src/deployers/coolify.ts
CHANGED
|
@@ -139,29 +139,28 @@ export class CoolifyDeployer implements PaasDeployer {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
async deploy(input: DeployInput): Promise<DeployResult> {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
];
|
|
142
|
+
const step1: DeployStep = { step: "Discover server", status: "pending" };
|
|
143
|
+
const step2: DeployStep = { step: "Create project", status: "pending" };
|
|
144
|
+
const step3: DeployStep = { step: "Create compose service", status: "pending" };
|
|
145
|
+
const step4: DeployStep = { step: "Set environment variables", status: "pending" };
|
|
146
|
+
const step5: DeployStep = { step: "Trigger deployment", status: "pending" };
|
|
147
|
+
const steps: DeployStep[] = [step1, step2, step3, step4, step5];
|
|
149
148
|
|
|
150
149
|
const result: DeployResult = { success: false, steps };
|
|
151
150
|
|
|
152
151
|
try {
|
|
153
152
|
// Step 1: Discover default server
|
|
154
|
-
|
|
153
|
+
step1.status = "running";
|
|
155
154
|
const servers = await coolifyFetch<CoolifyServer[]>(input.target, "/servers");
|
|
156
155
|
if (!servers || servers.length === 0) {
|
|
157
156
|
throw new Error("No servers found in Coolify instance");
|
|
158
157
|
}
|
|
159
|
-
const server = servers[0];
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
const server = servers[0] as CoolifyServer;
|
|
159
|
+
step1.status = "done";
|
|
160
|
+
step1.detail = `Server: ${server.name} (${server.ip})`;
|
|
162
161
|
|
|
163
162
|
// Step 2: Create project
|
|
164
|
-
|
|
163
|
+
step2.status = "running";
|
|
165
164
|
const project = await coolifyFetch<CoolifyProject>(input.target, "/projects", {
|
|
166
165
|
method: "POST",
|
|
167
166
|
body: {
|
|
@@ -170,8 +169,8 @@ export class CoolifyDeployer implements PaasDeployer {
|
|
|
170
169
|
},
|
|
171
170
|
});
|
|
172
171
|
result.projectId = project.uuid;
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
step2.status = "done";
|
|
173
|
+
step2.detail = `Project: ${project.uuid}`;
|
|
175
174
|
|
|
176
175
|
// Get the default environment
|
|
177
176
|
const projectDetail = await coolifyFetch<CoolifyProject>(
|
|
@@ -185,7 +184,7 @@ export class CoolifyDeployer implements PaasDeployer {
|
|
|
185
184
|
}
|
|
186
185
|
|
|
187
186
|
// Step 3: Create compose service with docker_compose_raw
|
|
188
|
-
|
|
187
|
+
step3.status = "running";
|
|
189
188
|
const service = await coolifyFetch<CoolifyService>(input.target, "/services", {
|
|
190
189
|
method: "POST",
|
|
191
190
|
body: {
|
|
@@ -200,11 +199,11 @@ export class CoolifyDeployer implements PaasDeployer {
|
|
|
200
199
|
},
|
|
201
200
|
});
|
|
202
201
|
result.composeId = service.uuid;
|
|
203
|
-
|
|
204
|
-
|
|
202
|
+
step3.status = "done";
|
|
203
|
+
step3.detail = `Service: ${service.uuid}`;
|
|
205
204
|
|
|
206
205
|
// Step 4: Set environment variables
|
|
207
|
-
|
|
206
|
+
step4.status = "running";
|
|
208
207
|
const envVars = parseEnvContent(input.envContent);
|
|
209
208
|
if (envVars.length > 0) {
|
|
210
209
|
await coolifyFetch(input.target, `/services/${service.uuid}/envs`, {
|
|
@@ -212,26 +211,26 @@ export class CoolifyDeployer implements PaasDeployer {
|
|
|
212
211
|
body: envVars,
|
|
213
212
|
});
|
|
214
213
|
}
|
|
215
|
-
|
|
216
|
-
|
|
214
|
+
step4.status = "done";
|
|
215
|
+
step4.detail = `${envVars.length} variables set`;
|
|
217
216
|
|
|
218
217
|
// Step 5: Trigger deployment
|
|
219
|
-
|
|
218
|
+
step5.status = "running";
|
|
220
219
|
const deployments = await coolifyFetch<{ deployments: CoolifyDeployment[] }>(
|
|
221
220
|
input.target,
|
|
222
221
|
`/deploy?uuid=${service.uuid}&force=true`,
|
|
223
222
|
);
|
|
224
|
-
|
|
225
|
-
|
|
223
|
+
step5.status = "done";
|
|
224
|
+
step5.detail = deployments?.deployments?.[0]?.deployment_uuid ?? "Deployment triggered";
|
|
226
225
|
|
|
227
226
|
result.success = true;
|
|
228
227
|
const base = input.target.instanceUrl.replace(/\/+$/, "");
|
|
229
228
|
result.dashboardUrl = `${base}/project/${project.uuid}`;
|
|
230
229
|
} catch (err) {
|
|
231
|
-
const
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
-
|
|
230
|
+
const failedStep = steps.find((s) => s.status === "running");
|
|
231
|
+
if (failedStep) {
|
|
232
|
+
failedStep.status = "error";
|
|
233
|
+
failedStep.detail = err instanceof Error ? err.message : String(err);
|
|
235
234
|
}
|
|
236
235
|
result.error = err instanceof Error ? err.message : String(err);
|
|
237
236
|
}
|
package/src/deployers/dokploy.ts
CHANGED
|
@@ -87,18 +87,17 @@ export class DokployDeployer implements PaasDeployer {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
async deploy(input: DeployInput): Promise<DeployResult> {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
];
|
|
90
|
+
const step1: DeployStep = { step: "Create project", status: "pending" };
|
|
91
|
+
const step2: DeployStep = { step: "Create compose stack", status: "pending" };
|
|
92
|
+
const step3: DeployStep = { step: "Set environment variables", status: "pending" };
|
|
93
|
+
const step4: DeployStep = { step: "Trigger deployment", status: "pending" };
|
|
94
|
+
const steps: DeployStep[] = [step1, step2, step3, step4];
|
|
96
95
|
|
|
97
96
|
const result: DeployResult = { success: false, steps };
|
|
98
97
|
|
|
99
98
|
try {
|
|
100
99
|
// Step 1: Create project
|
|
101
|
-
|
|
100
|
+
step1.status = "running";
|
|
102
101
|
const project = await dokployFetch<DokployProject>(input.target, "project.create", {
|
|
103
102
|
method: "POST",
|
|
104
103
|
body: {
|
|
@@ -107,8 +106,8 @@ export class DokployDeployer implements PaasDeployer {
|
|
|
107
106
|
},
|
|
108
107
|
});
|
|
109
108
|
result.projectId = project.projectId;
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
step1.status = "done";
|
|
110
|
+
step1.detail = `Project ID: ${project.projectId}`;
|
|
112
111
|
|
|
113
112
|
// Get the default environment ID
|
|
114
113
|
const projectDetail = await dokployFetch<DokployProject>(
|
|
@@ -121,7 +120,7 @@ export class DokployDeployer implements PaasDeployer {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
// Step 2: Create compose stack
|
|
124
|
-
|
|
123
|
+
step2.status = "running";
|
|
125
124
|
const compose = await dokployFetch<DokployCompose>(input.target, "compose.create", {
|
|
126
125
|
method: "POST",
|
|
127
126
|
body: {
|
|
@@ -131,11 +130,11 @@ export class DokployDeployer implements PaasDeployer {
|
|
|
131
130
|
},
|
|
132
131
|
});
|
|
133
132
|
result.composeId = compose.composeId;
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
step2.status = "done";
|
|
134
|
+
step2.detail = `Compose ID: ${compose.composeId}`;
|
|
136
135
|
|
|
137
136
|
// Step 3: Set environment variables
|
|
138
|
-
|
|
137
|
+
step3.status = "running";
|
|
139
138
|
await dokployFetch(input.target, "compose.update", {
|
|
140
139
|
method: "POST",
|
|
141
140
|
body: {
|
|
@@ -143,10 +142,10 @@ export class DokployDeployer implements PaasDeployer {
|
|
|
143
142
|
env: input.envContent,
|
|
144
143
|
},
|
|
145
144
|
});
|
|
146
|
-
|
|
145
|
+
step3.status = "done";
|
|
147
146
|
|
|
148
147
|
// Step 4: Trigger deployment
|
|
149
|
-
|
|
148
|
+
step4.status = "running";
|
|
150
149
|
await dokployFetch(input.target, "compose.deploy", {
|
|
151
150
|
method: "POST",
|
|
152
151
|
body: {
|
|
@@ -155,16 +154,16 @@ export class DokployDeployer implements PaasDeployer {
|
|
|
155
154
|
description: input.description ?? "Deployed via OpenClaw web builder",
|
|
156
155
|
},
|
|
157
156
|
});
|
|
158
|
-
|
|
157
|
+
step4.status = "done";
|
|
159
158
|
|
|
160
159
|
result.success = true;
|
|
161
160
|
const base = input.target.instanceUrl.replace(/\/+$/, "");
|
|
162
161
|
result.dashboardUrl = `${base}/dashboard/project/${project.projectId}`;
|
|
163
162
|
} catch (err) {
|
|
164
|
-
const
|
|
165
|
-
if (
|
|
166
|
-
|
|
167
|
-
|
|
163
|
+
const failedStep = steps.find((s) => s.status === "running");
|
|
164
|
+
if (failedStep) {
|
|
165
|
+
failedStep.status = "error";
|
|
166
|
+
failedStep.detail = err instanceof Error ? err.message : String(err);
|
|
168
167
|
}
|
|
169
168
|
result.error = err instanceof Error ? err.message : String(err);
|
|
170
169
|
}
|
package/src/port-scanner.ts
CHANGED
|
@@ -63,7 +63,7 @@ async function isPortAvailable(port: number): Promise<boolean> {
|
|
|
63
63
|
const canBind = await new Promise<boolean>((resolve) => {
|
|
64
64
|
const server = net.createServer();
|
|
65
65
|
|
|
66
|
-
server.once("error", (
|
|
66
|
+
server.once("error", (_err: NodeJS.ErrnoException) => {
|
|
67
67
|
// EACCES / EADDRINUSE / EPERM = port is reserved or in use
|
|
68
68
|
resolve(false);
|
|
69
69
|
});
|
|
@@ -36,28 +36,28 @@ export const usesendDefinition: ServiceDefinition = {
|
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
key: "AWS_ACCESS_KEY",
|
|
39
|
-
defaultValue: "",
|
|
39
|
+
defaultValue: "your-aws-access-key",
|
|
40
40
|
secret: true,
|
|
41
41
|
description: "AWS access key for SES/SNS",
|
|
42
42
|
required: true,
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
key: "AWS_SECRET_KEY",
|
|
46
|
-
defaultValue: "",
|
|
46
|
+
defaultValue: "your-aws-secret-key",
|
|
47
47
|
secret: true,
|
|
48
48
|
description: "AWS secret key for SES/SNS",
|
|
49
49
|
required: true,
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
key: "GITHUB_ID",
|
|
53
|
-
defaultValue: "",
|
|
53
|
+
defaultValue: "your-github-oauth-client-id",
|
|
54
54
|
secret: false,
|
|
55
55
|
description: "GitHub OAuth app client ID",
|
|
56
56
|
required: true,
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
key: "GITHUB_SECRET",
|
|
60
|
-
defaultValue: "",
|
|
60
|
+
defaultValue: "your-github-oauth-client-secret",
|
|
61
61
|
secret: true,
|
|
62
62
|
description: "GitHub OAuth app client secret",
|
|
63
63
|
required: true,
|