@clawops/cli 2.0.0 → 2.0.2
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/README.md +99 -12
- package/dist/apply-WOUTUUQH.js +27 -0
- package/dist/automation-UKRM3BD2.js +44 -0
- package/dist/bedrock-XVASJX2K.js +61 -0
- package/dist/{bootstrap-DMRPWJGN.js → bootstrap-HNGKY6WW.js} +11 -8
- package/dist/{chunk-N44K3LHE.js → chunk-2I7KCMXZ.js} +6 -4
- package/dist/{chunk-3WYA2QDM.js → chunk-2Z7J3ERQ.js} +1 -1
- package/dist/chunk-3OLUJPCB.js +36 -0
- package/dist/{chunk-GYV4KNW7.js → chunk-5TXCUOZV.js} +133 -40
- package/dist/chunk-AEEMRFZV.js +24 -0
- package/dist/{chunk-YR3O2I3S.js → chunk-BSLIYB5Q.js} +6 -1
- package/dist/{chunk-AHAAEXWC.js → chunk-E4NJSJ54.js} +16 -93
- package/dist/chunk-FEK7VJAY.js +16 -0
- package/dist/{chunk-6TIYVHPX.js → chunk-GIEVAGEK.js} +7 -33
- package/dist/chunk-HSPHXG6W.js +67 -0
- package/dist/chunk-LEVIW2PV.js +890 -0
- package/dist/chunk-MC5ATCXS.js +108 -0
- package/dist/chunk-N4WZLWJ4.js +16 -0
- package/dist/{chunk-SBLQH2TJ.js → chunk-NUL5F6YV.js} +1 -1
- package/dist/chunk-PSOSBJVO.js +51 -0
- package/dist/{chunk-AX74VXTV.js → chunk-RATEIAFU.js} +58 -49
- package/dist/chunk-RHOWYIWT.js +52 -0
- package/dist/{chunk-WHJMKDV7.js → chunk-SDZKCICH.js} +65 -12
- package/dist/chunk-V25QRZRB.js +45 -0
- package/dist/chunk-VOEJYRIK.js +33 -0
- package/dist/{providers-2OABPW2E.js → chunk-VUFMZEIM.js} +3 -2
- package/dist/chunk-WTZ2CT35.js +69 -0
- package/dist/{chunk-UFRO4H5W.js → chunk-ZMMRIWFS.js} +56 -40
- package/dist/cli-NH7VUNOU.js +11 -0
- package/dist/cli-auth-GD5SK7JU.js +13 -0
- package/dist/cli.js +518 -206
- package/dist/context-M4JBBIAV.js +20 -0
- package/dist/docker-3PDO4TS7.js +12 -0
- package/dist/{firewall-T3NTPZJD.js → firewall-5VKZ4WBH.js} +22 -1
- package/dist/generate-J6MIJGII.js +29 -0
- package/dist/{harden-PCDK3UQ5.js → harden-72JMRT4E.js} +8 -5
- package/dist/index.d.ts +56 -0
- package/dist/known-hosts-file-I3Q3NBYQ.js +22 -0
- package/dist/{logs-P7YCKVF4.js → logs-5A7YYA53.js} +1 -1
- package/dist/{mcp-wire-BFEY2Y6H.js → mcp-wire-NTGL5ITF.js} +25 -15
- package/dist/models-AGTQWYDL.js +32 -0
- package/dist/network-args-PYJRJBYO.js +64 -0
- package/dist/{package-3HUW57XH.js → package-3A6BOALU.js} +11 -3
- package/dist/passphrase-MJBE45N7.js +15 -0
- package/dist/{pool-EX4ZTA5P.js → pool-PIIKJ4L2.js} +3 -2
- package/dist/preflight-EF52S3WW.js +162 -0
- package/dist/preflight-MWWM5JT3.js +181 -0
- package/dist/preflight-TFD4N5ZU.js +141 -0
- package/dist/providers-FW6H6OPF.js +11 -0
- package/dist/ready-KDNRBNSU.js +95 -0
- package/dist/{remote-config-Z6IIZR3D.js → remote-config-3HZLUWEA.js} +3 -2
- package/dist/{runtime-LZ7NA53V.js → runtime-X3KW5TCP.js} +4 -2
- package/dist/server-RWM2JI3D.js +46 -0
- package/dist/ssh-VAI5DU5M.js +11 -0
- package/dist/ssh-key-DUO6OKOI.js +7 -0
- package/dist/stack-config-R4SPSUQZ.js +12 -0
- package/dist/{validate-BOQRWX4F.js → validate-YVI3BJ55.js} +1 -1
- package/dist/wait-WO72TRRQ.js +79 -0
- package/package.json +11 -3
- package/spec/mcp-tools.yaml +21 -2
- package/spec/models.yaml +14 -3
- package/spec/providers.schema.json +163 -28
- package/dist/apply-AM5HERE7.js +0 -19
- package/dist/automation-RULUSJBW.js +0 -30
- package/dist/aws-AMON7DA7.js +0 -265
- package/dist/azure-T4G6OBJQ.js +0 -273
- package/dist/chunk-CKSPROD5.js +0 -129
- package/dist/chunk-LU2V3LXA.js +0 -114
- package/dist/context-KHKWJJMC.js +0 -10
- package/dist/gcp-2JBTD7ZM.js +0 -204
- package/dist/generate-2XV2GSP2.js +0 -15
- package/dist/local-DXBEVZ5C.js +0 -47
- package/dist/server-A5AB67GQ.js +0 -36
- package/dist/ssh-B3NZAU4I.js +0 -8
- package/dist/{version-guard-GPSTCPT7.js → version-guard-XVYW5WFJ.js} +1 -1
package/dist/azure-T4G6OBJQ.js
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
makeStartupScript
|
|
4
|
-
} from "./chunk-CKSPROD5.js";
|
|
5
|
-
import {
|
|
6
|
-
GATEWAY_PORT
|
|
7
|
-
} from "./chunk-6TIYVHPX.js";
|
|
8
|
-
import "./chunk-EI7CQQ7D.js";
|
|
9
|
-
|
|
10
|
-
// src/providers/azure/index.ts
|
|
11
|
-
import process2 from "process";
|
|
12
|
-
|
|
13
|
-
// src/providers/azure/program.ts
|
|
14
|
-
import { createHash } from "crypto";
|
|
15
|
-
var SSH_PORT = 22;
|
|
16
|
-
var azureProgram = async () => {
|
|
17
|
-
const [pulumi, azure, random, { resolveIngressCidrs, resolveGatewayIngressCidrs, resolveGatewayPort, detectEgressIp }] = await Promise.all([
|
|
18
|
-
import("@pulumi/pulumi"),
|
|
19
|
-
import("@pulumi/azure-native"),
|
|
20
|
-
import("@pulumi/random"),
|
|
21
|
-
import("./firewall-T3NTPZJD.js")
|
|
22
|
-
]);
|
|
23
|
-
const cfg = new pulumi.Config();
|
|
24
|
-
const stackName = pulumi.getStack();
|
|
25
|
-
const instanceType = cfg.get("instanceType") ?? "Standard_B2s";
|
|
26
|
-
const location = cfg.get("region") ?? "eastus";
|
|
27
|
-
const openclawVersion = cfg.get("openclawVersion") ?? "latest";
|
|
28
|
-
const publishGateway = cfg.get("publishGateway") === "all" ? "all" : "loopback";
|
|
29
|
-
const gatewayPort = resolveGatewayPort(cfg.get("gatewayPort"), GATEWAY_PORT);
|
|
30
|
-
const accessMode = cfg.get("accessMode") ?? "restricted";
|
|
31
|
-
const allowedCidrs = cfg.get("allowedCidrs") ?? "";
|
|
32
|
-
const sshCidrs = cfg.get("sshCidrs") ?? "";
|
|
33
|
-
const gatewayCidrs = cfg.get("gatewayCidrs") ?? "";
|
|
34
|
-
const keyVaultEnabled = cfg.get("keyVaultEnabled") === "true";
|
|
35
|
-
const resourceGroupName = cfg.get("resourceGroupName") ?? `clawops-${stackName}`;
|
|
36
|
-
const sshPublicKey = cfg.get("sshPublicKey");
|
|
37
|
-
if (!sshPublicKey) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
'Stack config "sshPublicKey" is required for the Azure adapter. Set it with: pulumi config set --stack <name> sshPublicKey "ssh-ed25519 ..."'
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
const clientConfig = await azure.authorization.getClientConfig({});
|
|
43
|
-
const egressResult = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : { ok: true, ip: "" };
|
|
44
|
-
if (accessMode === "open") {
|
|
45
|
-
process.stderr.write(
|
|
46
|
-
"[clawops] WARNING: accessMode=open allows 0.0.0.0/0 on SSH and gateway ports. Only use this for development/sandbox stacks.\n"
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
|
|
50
|
-
const gatewayIngressCidrs = resolveGatewayIngressCidrs(
|
|
51
|
-
publishGateway,
|
|
52
|
-
accessMode,
|
|
53
|
-
allowedCidrs,
|
|
54
|
-
gatewayCidrs,
|
|
55
|
-
egressResult
|
|
56
|
-
);
|
|
57
|
-
const rg = new azure.resources.ResourceGroup("clawops-rg", {
|
|
58
|
-
resourceGroupName,
|
|
59
|
-
location
|
|
60
|
-
});
|
|
61
|
-
const vnet = new azure.network.VirtualNetwork("clawops-vnet", {
|
|
62
|
-
resourceGroupName: rg.name,
|
|
63
|
-
location: rg.location,
|
|
64
|
-
addressSpace: { addressPrefixes: ["10.0.0.0/16"] }
|
|
65
|
-
});
|
|
66
|
-
const subnet = new azure.network.Subnet("clawops-subnet", {
|
|
67
|
-
resourceGroupName: rg.name,
|
|
68
|
-
virtualNetworkName: vnet.name,
|
|
69
|
-
addressPrefix: "10.0.1.0/24"
|
|
70
|
-
});
|
|
71
|
-
const securityRules = [];
|
|
72
|
-
let priority = 100;
|
|
73
|
-
for (const cidr of sshIngressCidrs) {
|
|
74
|
-
securityRules.push({
|
|
75
|
-
name: `allow-ssh-${priority}`,
|
|
76
|
-
priority: priority++,
|
|
77
|
-
direction: "Inbound",
|
|
78
|
-
access: "Allow",
|
|
79
|
-
protocol: "Tcp",
|
|
80
|
-
sourceAddressPrefix: cidr,
|
|
81
|
-
sourcePortRange: "*",
|
|
82
|
-
destinationAddressPrefix: "*",
|
|
83
|
-
destinationPortRange: String(SSH_PORT)
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
for (const cidr of gatewayIngressCidrs) {
|
|
87
|
-
securityRules.push({
|
|
88
|
-
name: `allow-gateway-${priority}`,
|
|
89
|
-
priority: priority++,
|
|
90
|
-
direction: "Inbound",
|
|
91
|
-
access: "Allow",
|
|
92
|
-
protocol: "Tcp",
|
|
93
|
-
sourceAddressPrefix: cidr,
|
|
94
|
-
sourcePortRange: "*",
|
|
95
|
-
destinationAddressPrefix: "*",
|
|
96
|
-
destinationPortRange: String(gatewayPort)
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
const nsg = new azure.network.NetworkSecurityGroup("clawops-nsg", {
|
|
100
|
-
resourceGroupName: rg.name,
|
|
101
|
-
location: rg.location,
|
|
102
|
-
securityRules
|
|
103
|
-
});
|
|
104
|
-
const publicIp = new azure.network.PublicIPAddress("clawops-pip", {
|
|
105
|
-
resourceGroupName: rg.name,
|
|
106
|
-
location: rg.location,
|
|
107
|
-
publicIPAllocationMethod: "Static",
|
|
108
|
-
sku: { name: "Standard" }
|
|
109
|
-
});
|
|
110
|
-
const nic = new azure.network.NetworkInterface("clawops-nic", {
|
|
111
|
-
resourceGroupName: rg.name,
|
|
112
|
-
location: rg.location,
|
|
113
|
-
networkSecurityGroup: { id: nsg.id },
|
|
114
|
-
ipConfigurations: [{
|
|
115
|
-
name: "clawops-ipconfig",
|
|
116
|
-
subnet: { id: subnet.id },
|
|
117
|
-
publicIPAddress: { id: publicIp.id },
|
|
118
|
-
privateIPAllocationMethod: "Dynamic"
|
|
119
|
-
}]
|
|
120
|
-
});
|
|
121
|
-
const vm = new azure.compute.VirtualMachine("clawops-vm", {
|
|
122
|
-
resourceGroupName: rg.name,
|
|
123
|
-
location: rg.location,
|
|
124
|
-
hardwareProfile: { vmSize: instanceType },
|
|
125
|
-
identity: { type: "SystemAssigned" },
|
|
126
|
-
osProfile: {
|
|
127
|
-
adminUsername: "clawops",
|
|
128
|
-
computerName: "clawops",
|
|
129
|
-
customData: Buffer.from(makeStartupScript({ openclawVersion, os: "ubuntu", publishGateway, gatewayPort })).toString("base64"),
|
|
130
|
-
linuxConfiguration: {
|
|
131
|
-
disablePasswordAuthentication: true,
|
|
132
|
-
ssh: {
|
|
133
|
-
publicKeys: [{
|
|
134
|
-
keyData: sshPublicKey,
|
|
135
|
-
path: "/home/clawops/.ssh/authorized_keys"
|
|
136
|
-
}]
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
storageProfile: {
|
|
141
|
-
imageReference: {
|
|
142
|
-
publisher: "Canonical",
|
|
143
|
-
// Ubuntu 22.04 LTS — Canonical migrated from the legacy 'UbuntuServer'
|
|
144
|
-
// offer to this naming scheme. 22_04-lts-gen2 is available in all regions.
|
|
145
|
-
offer: "0001-com-ubuntu-server-jammy",
|
|
146
|
-
sku: "22_04-lts-gen2",
|
|
147
|
-
version: "latest"
|
|
148
|
-
},
|
|
149
|
-
osDisk: {
|
|
150
|
-
createOption: "FromImage",
|
|
151
|
-
managedDisk: { storageAccountType: "Premium_LRS" },
|
|
152
|
-
diskSizeGB: 30
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
networkProfile: {
|
|
156
|
-
networkInterfaces: [{ id: nic.id, primary: true }]
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
if (keyVaultEnabled) {
|
|
160
|
-
const safeName = stackName.replace(/[^a-zA-Z0-9-]/g, "-");
|
|
161
|
-
const rawKvName = `clawops-${safeName}-kv`;
|
|
162
|
-
const kvName = rawKvName.length > 24 ? `cl-${createHash("sha256").update(stackName).digest("hex").slice(0, 20)}` : rawKvName;
|
|
163
|
-
const kv = new azure.keyvault.Vault("clawops-kv", {
|
|
164
|
-
resourceGroupName: rg.name,
|
|
165
|
-
location: rg.location,
|
|
166
|
-
vaultName: kvName,
|
|
167
|
-
properties: {
|
|
168
|
-
sku: { family: "A", name: "standard" },
|
|
169
|
-
tenantId: pulumi.output(vm.identity).apply((i) => i?.tenantId ?? ""),
|
|
170
|
-
enableRbacAuthorization: true
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
const kvSecretsUserRoleId = `/subscriptions/${clientConfig.subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6`;
|
|
174
|
-
new azure.authorization.RoleAssignment("clawops-kv-role", {
|
|
175
|
-
scope: kv.id,
|
|
176
|
-
roleDefinitionId: kvSecretsUserRoleId,
|
|
177
|
-
principalId: pulumi.output(vm.identity).apply((i) => i?.principalId ?? ""),
|
|
178
|
-
principalType: "ServicePrincipal"
|
|
179
|
-
});
|
|
180
|
-
const gatewayToken = new random.RandomPassword("clawops-kv-gateway-token", {
|
|
181
|
-
length: 32,
|
|
182
|
-
special: false
|
|
183
|
-
});
|
|
184
|
-
new azure.keyvault.Secret("clawops-gateway-token", {
|
|
185
|
-
resourceGroupName: rg.name,
|
|
186
|
-
vaultName: kv.name,
|
|
187
|
-
secretName: "gateway-token",
|
|
188
|
-
properties: { value: gatewayToken.result }
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
const resolvedIp = pulumi.output(publicIp.ipAddress).apply((ip) => ip ?? "");
|
|
192
|
-
return {
|
|
193
|
-
instanceId: vm.id,
|
|
194
|
-
publicIp: resolvedIp,
|
|
195
|
-
gatewayUrl: pulumi.interpolate`https://${resolvedIp}:${gatewayPort}`,
|
|
196
|
-
sshHost: resolvedIp,
|
|
197
|
-
sshPort: SSH_PORT,
|
|
198
|
-
sshUser: "clawops",
|
|
199
|
-
region: location,
|
|
200
|
-
provisionedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
201
|
-
};
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
// src/providers/azure/index.ts
|
|
205
|
-
var INSTANCE_TYPE_MAP = {
|
|
206
|
-
micro: "Standard_B1s",
|
|
207
|
-
small: "Standard_B2s",
|
|
208
|
-
medium: "Standard_B4ms",
|
|
209
|
-
large: "Standard_B8ms",
|
|
210
|
-
gpu: "Standard_NC6s_v3"
|
|
211
|
-
};
|
|
212
|
-
var azureAdapter = {
|
|
213
|
-
name: "azure",
|
|
214
|
-
get program() {
|
|
215
|
-
return azureProgram;
|
|
216
|
-
},
|
|
217
|
-
getConnectionInfo(outputs) {
|
|
218
|
-
return {
|
|
219
|
-
host: String(outputs["sshHost"] ?? ""),
|
|
220
|
-
port: Number(outputs["sshPort"] ?? 22),
|
|
221
|
-
user: String(outputs["sshUser"] ?? "clawops"),
|
|
222
|
-
privateKeyPath: String(outputs["privateKeyPath"] ?? ""),
|
|
223
|
-
knownHostsPath: String(outputs["knownHostsPath"] ?? "")
|
|
224
|
-
};
|
|
225
|
-
},
|
|
226
|
-
normalizeInstanceType(alias) {
|
|
227
|
-
const mapped = INSTANCE_TYPE_MAP[alias];
|
|
228
|
-
if (!mapped) throw new Error(`Unknown instance alias: ${alias}`);
|
|
229
|
-
return mapped;
|
|
230
|
-
},
|
|
231
|
-
defaultRegion() {
|
|
232
|
-
return "eastus";
|
|
233
|
-
},
|
|
234
|
-
stateBackendUrl(bucket) {
|
|
235
|
-
return `azblob://${bucket}`;
|
|
236
|
-
},
|
|
237
|
-
async validateConfig() {
|
|
238
|
-
const errors = [];
|
|
239
|
-
const clientId = process2.env["AZURE_CLIENT_ID"];
|
|
240
|
-
const tenantId = process2.env["AZURE_TENANT_ID"];
|
|
241
|
-
const clientSecret = process2.env["AZURE_CLIENT_SECRET"];
|
|
242
|
-
const federatedToken = process2.env["AZURE_FEDERATED_TOKEN_FILE"];
|
|
243
|
-
const hasServicePrincipal = Boolean(clientId && tenantId && clientSecret);
|
|
244
|
-
const hasOidc = Boolean(clientId && tenantId && federatedToken);
|
|
245
|
-
if (!hasServicePrincipal && !hasOidc) {
|
|
246
|
-
const onAzure = await checkImds();
|
|
247
|
-
if (!onAzure) {
|
|
248
|
-
errors.push(
|
|
249
|
-
"No Azure credentials found. Set AZURE_CLIENT_ID + AZURE_TENANT_ID + AZURE_CLIENT_SECRET (service principal), or AZURE_CLIENT_ID + AZURE_TENANT_ID + AZURE_FEDERATED_TOKEN_FILE (OIDC), or run on an Azure VM with a managed identity."
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return { ok: errors.length === 0, errors };
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
async function checkImds() {
|
|
257
|
-
try {
|
|
258
|
-
const res = await fetch(
|
|
259
|
-
"http://169.254.169.254/metadata/instance?api-version=2021-02-01",
|
|
260
|
-
{
|
|
261
|
-
headers: { Metadata: "true" },
|
|
262
|
-
signal: AbortSignal.timeout(1e3)
|
|
263
|
-
}
|
|
264
|
-
);
|
|
265
|
-
return res.ok;
|
|
266
|
-
} catch {
|
|
267
|
-
return false;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
var azure_default = azureAdapter;
|
|
271
|
-
export {
|
|
272
|
-
azure_default as default
|
|
273
|
-
};
|
package/dist/chunk-CKSPROD5.js
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
CONFIG_FILENAME,
|
|
4
|
-
CONTAINER_UID,
|
|
5
|
-
GATEWAY_PORT,
|
|
6
|
-
STATE_DIR_HOST_LINUX,
|
|
7
|
-
gatewayRunCommand
|
|
8
|
-
} from "./chunk-6TIYVHPX.js";
|
|
9
|
-
|
|
10
|
-
// src/providers/startup.ts
|
|
11
|
-
function makeStartupScript(opts) {
|
|
12
|
-
const {
|
|
13
|
-
openclawVersion,
|
|
14
|
-
os,
|
|
15
|
-
bedrockEnabled = false,
|
|
16
|
-
publishGateway = "loopback",
|
|
17
|
-
gatewayPort = GATEWAY_PORT
|
|
18
|
-
} = opts;
|
|
19
|
-
const dockerDistro = os === "ubuntu" ? "ubuntu" : "debian";
|
|
20
|
-
const bedrockEnvBlock = bedrockEnabled ? makeBedrockEnvBlock() : "";
|
|
21
|
-
return `#!/bin/bash
|
|
22
|
-
set -euo pipefail
|
|
23
|
-
|
|
24
|
-
# \u2500\u2500 User setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
25
|
-
id -u clawops &>/dev/null || useradd -m -s /bin/bash clawops
|
|
26
|
-
mkdir -p /home/clawops/.ssh
|
|
27
|
-
chmod 700 /home/clawops/.ssh
|
|
28
|
-
chown clawops:clawops /home/clawops/.ssh
|
|
29
|
-
|
|
30
|
-
# \u2500\u2500 Docker installation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
31
|
-
if ! command -v docker &>/dev/null; then
|
|
32
|
-
export DEBIAN_FRONTEND=noninteractive
|
|
33
|
-
apt-get update -q
|
|
34
|
-
apt-get install -y -q ca-certificates curl gnupg lsb-release
|
|
35
|
-
install -m 0755 -d /etc/apt/keyrings
|
|
36
|
-
curl -fsSL https://download.docker.com/linux/${dockerDistro}/gpg \\
|
|
37
|
-
-o /etc/apt/keyrings/docker.asc
|
|
38
|
-
chmod a+r /etc/apt/keyrings/docker.asc
|
|
39
|
-
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \\
|
|
40
|
-
https://download.docker.com/linux/${dockerDistro} $(lsb_release -cs) stable" \\
|
|
41
|
-
> /etc/apt/sources.list.d/docker.list
|
|
42
|
-
apt-get update -q
|
|
43
|
-
apt-get install -y -q \\
|
|
44
|
-
docker-ce \\
|
|
45
|
-
docker-ce-cli \\
|
|
46
|
-
containerd.io \\
|
|
47
|
-
docker-buildx-plugin \\
|
|
48
|
-
docker-compose-plugin
|
|
49
|
-
systemctl enable --now docker
|
|
50
|
-
fi
|
|
51
|
-
|
|
52
|
-
usermod -aG docker clawops
|
|
53
|
-
|
|
54
|
-
# \u2500\u2500 OpenClaw image \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
55
|
-
OPENCLAW_VERSION="${openclawVersion}"
|
|
56
|
-
docker pull ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION}
|
|
57
|
-
|
|
58
|
-
# \u2500\u2500 Gateway auth token \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
59
|
-
# OpenClaw refuses a non-loopback bind without auth, and in a container it always
|
|
60
|
-
# binds 0.0.0.0. Without a token the gateway exits 78 and restart-loops.
|
|
61
|
-
OPENCLAW_ENV_FILE=/home/clawops/openclaw.env
|
|
62
|
-
if [ ! -s "\${OPENCLAW_ENV_FILE}" ]; then
|
|
63
|
-
OPENCLAW_TOKEN=$(openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \\n')
|
|
64
|
-
printf 'OPENCLAW_GATEWAY_TOKEN=%s\\n' "\${OPENCLAW_TOKEN}" > "\${OPENCLAW_ENV_FILE}"
|
|
65
|
-
chmod 600 "\${OPENCLAW_ENV_FILE}"
|
|
66
|
-
chown clawops:clawops "\${OPENCLAW_ENV_FILE}"
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
# \u2500\u2500 State directory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
70
|
-
# One directory holds config, the SQLite state and any plugins installed below.
|
|
71
|
-
# Owned NUMERICALLY by the uid the container runs as: useradd clawops gets 1001 on
|
|
72
|
-
# Ubuntu 24.04 (the ubuntu user already holds 1000), and a 1001-owned state dir makes the
|
|
73
|
-
# gateway exit 1 with EACCES on its own SQLite WAL. There is no degraded mode.
|
|
74
|
-
OPENCLAW_STATE_DIR=${STATE_DIR_HOST_LINUX}
|
|
75
|
-
OPENCLAW_CONFIG="\${OPENCLAW_STATE_DIR}/${CONFIG_FILENAME}"
|
|
76
|
-
mkdir -p "\${OPENCLAW_STATE_DIR}"
|
|
77
|
-
|
|
78
|
-
# Migrate a pre-2.0 deployment: the config used to be a bare file in the service user's
|
|
79
|
-
# home. Without this an in-place upgrade comes up with no configuration at all. Guarded on
|
|
80
|
-
# the target being absent, so re-running provisioning never clobbers a later edit.
|
|
81
|
-
OPENCLAW_LEGACY_CONFIG=/home/clawops/openclaw.json
|
|
82
|
-
if [ -f "\${OPENCLAW_LEGACY_CONFIG}" ] && [ ! -f "\${OPENCLAW_CONFIG}" ]; then
|
|
83
|
-
cp -p "\${OPENCLAW_LEGACY_CONFIG}" "\${OPENCLAW_CONFIG}"
|
|
84
|
-
mv "\${OPENCLAW_LEGACY_CONFIG}" "\${OPENCLAW_LEGACY_CONFIG}.migrated"
|
|
85
|
-
echo "clawops: migrated config from \${OPENCLAW_LEGACY_CONFIG}"
|
|
86
|
-
OPENCLAW_MIGRATED=1
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
# \u2500\u2500 Default config (apply.ts will overwrite with plan overlay) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
90
|
-
if [ ! -f "\${OPENCLAW_CONFIG}" ]; then
|
|
91
|
-
cat > "\${OPENCLAW_CONFIG}" <<'OPENCLAWJSON'
|
|
92
|
-
{"meta":{"lastTouchedVersion":"2026.9"},"gateway":{"mode":"local","port":${gatewayPort},"auth":{"mode":"token"}},"models":{},"channels":{}}
|
|
93
|
-
OPENCLAWJSON
|
|
94
|
-
fi
|
|
95
|
-
|
|
96
|
-
# Numeric, and last, so it covers the config and anything migrated above.
|
|
97
|
-
chown -R ${CONTAINER_UID}:${CONTAINER_UID} "\${OPENCLAW_STATE_DIR}"
|
|
98
|
-
|
|
99
|
-
# A 1.x config has no gateway.mode, and clawops no longer passes --allow-unconfigured \u2014
|
|
100
|
-
# so a migrated deployment would exit 78 with "existing config is missing gateway.mode".
|
|
101
|
-
# Normalised with OpenClaw's own tooling rather than by editing JSON in shell: it is
|
|
102
|
-
# schema-aware, writes atomically, and applies OpenClaw's internal config migrations at the
|
|
103
|
-
# same time. Runs after the chown so the container can write.
|
|
104
|
-
if [ "\${OPENCLAW_MIGRATED:-0}" = "1" ]; then
|
|
105
|
-
docker run --rm -v "\${OPENCLAW_STATE_DIR}":/home/node/.openclaw \\
|
|
106
|
-
ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION} \\
|
|
107
|
-
openclaw config set gateway.mode local || \\
|
|
108
|
-
echo "clawops: WARNING could not set gateway.mode; gateway may refuse to start" >&2
|
|
109
|
-
fi
|
|
110
|
-
|
|
111
|
-
# \u2500\u2500 Start OpenClaw container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
112
|
-
# Built by src/openclaw/runtime.ts, so this cannot drift from the restart paths.
|
|
113
|
-
${gatewayRunCommand({
|
|
114
|
-
image: "ghcr.io/openclaw/openclaw:${OPENCLAW_VERSION}",
|
|
115
|
-
stateDir: '"${OPENCLAW_STATE_DIR}"',
|
|
116
|
-
envFilePath: '"${OPENCLAW_ENV_FILE}"',
|
|
117
|
-
extraArgs: bedrockEnvBlock.trim(),
|
|
118
|
-
publish: publishGateway,
|
|
119
|
-
port: gatewayPort
|
|
120
|
-
})}
|
|
121
|
-
`;
|
|
122
|
-
}
|
|
123
|
-
function makeBedrockEnvBlock() {
|
|
124
|
-
return ' -e AWS_DEFAULT_REGION=$( \\\n IMDS_TOKEN=$(curl -sf -X PUT \\\n "http://169.254.169.254/latest/api/token" \\\n -H "X-aws-ec2-metadata-token-ttl-seconds: 60") && \\\n curl -sf \\\n -H "X-aws-ec2-metadata-token: ${IMDS_TOKEN}" \\\n "http://169.254.169.254/latest/meta-data/placement/region" \\\n || echo us-east-1) \\\n';
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export {
|
|
128
|
-
makeStartupScript
|
|
129
|
-
};
|
package/dist/chunk-LU2V3LXA.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
readLocalState
|
|
4
|
-
} from "./chunk-A2I76FTA.js";
|
|
5
|
-
import {
|
|
6
|
-
getConfigDir,
|
|
7
|
-
requireConfig
|
|
8
|
-
} from "./chunk-CX5SL5HP.js";
|
|
9
|
-
import {
|
|
10
|
-
UsageError
|
|
11
|
-
} from "./chunk-KGXPLI7W.js";
|
|
12
|
-
|
|
13
|
-
// src/cli/context.ts
|
|
14
|
-
function buildContext(args) {
|
|
15
|
-
const config = requireConfig();
|
|
16
|
-
const stackName = typeof args.stack === "string" ? args.stack : config.defaults.stack;
|
|
17
|
-
const providerName = typeof args.provider === "string" ? args.provider : config.stacks[stackName]?.provider ?? config.defaults.provider;
|
|
18
|
-
const adapter = loadProvider(providerName);
|
|
19
|
-
const localState = providerName === "local" ? readLocalState(stackName) : void 0;
|
|
20
|
-
let stackCache = null;
|
|
21
|
-
return {
|
|
22
|
-
config,
|
|
23
|
-
adapter,
|
|
24
|
-
stackName,
|
|
25
|
-
localState,
|
|
26
|
-
async getStack() {
|
|
27
|
-
if (providerName === "local") {
|
|
28
|
-
throw new UsageError(
|
|
29
|
-
"The local provider does not use Pulumi stacks. Use `clawops up` to bootstrap the host instead."
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
if (stackCache) return stackCache;
|
|
33
|
-
const stackConfig = config.stacks[stackName];
|
|
34
|
-
if (!stackConfig) {
|
|
35
|
-
throw new UsageError(
|
|
36
|
-
`Stack "${stackName}" not found in config. Run \`clawops init\` or use \`--stack\` to specify a different stack.`
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
const { getOrCreateStack } = await import("./automation-RULUSJBW.js");
|
|
40
|
-
stackCache = await getOrCreateStack({
|
|
41
|
-
stack: stackName,
|
|
42
|
-
stateUrl: stackConfig.stateUrl,
|
|
43
|
-
program: adapter.program,
|
|
44
|
-
configDir: getConfigDir()
|
|
45
|
-
});
|
|
46
|
-
return stackCache;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
function loadProvider(name) {
|
|
51
|
-
return makeProviderProxy(name);
|
|
52
|
-
}
|
|
53
|
-
function makeProviderProxy(name) {
|
|
54
|
-
let resolved = null;
|
|
55
|
-
const resolve = async () => {
|
|
56
|
-
if (resolved) return resolved;
|
|
57
|
-
switch (name) {
|
|
58
|
-
case "gcp": {
|
|
59
|
-
const mod = await import("./gcp-2JBTD7ZM.js");
|
|
60
|
-
resolved = mod.default;
|
|
61
|
-
return resolved;
|
|
62
|
-
}
|
|
63
|
-
case "aws": {
|
|
64
|
-
const mod = await import("./aws-AMON7DA7.js");
|
|
65
|
-
resolved = mod.default;
|
|
66
|
-
return resolved;
|
|
67
|
-
}
|
|
68
|
-
case "azure": {
|
|
69
|
-
const mod = await import("./azure-T4G6OBJQ.js");
|
|
70
|
-
resolved = mod.default;
|
|
71
|
-
return resolved;
|
|
72
|
-
}
|
|
73
|
-
case "local": {
|
|
74
|
-
const mod = await import("./local-DXBEVZ5C.js");
|
|
75
|
-
resolved = mod.default;
|
|
76
|
-
return resolved;
|
|
77
|
-
}
|
|
78
|
-
default:
|
|
79
|
-
throw new UsageError(
|
|
80
|
-
`Provider "${name}" is not yet supported. Supported providers: gcp, aws, azure, local`
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
return {
|
|
85
|
-
name,
|
|
86
|
-
get program() {
|
|
87
|
-
return async () => {
|
|
88
|
-
const adapter = await resolve();
|
|
89
|
-
return adapter.program();
|
|
90
|
-
};
|
|
91
|
-
},
|
|
92
|
-
getConnectionInfo: (outputs) => {
|
|
93
|
-
if (!resolved) throw new UsageError("Provider not yet loaded. Call getStack() first.");
|
|
94
|
-
return resolved.getConnectionInfo(outputs);
|
|
95
|
-
},
|
|
96
|
-
normalizeInstanceType: (alias) => {
|
|
97
|
-
if (!resolved) throw new UsageError("Provider not yet loaded. Call getStack() first.");
|
|
98
|
-
return resolved.normalizeInstanceType(alias);
|
|
99
|
-
},
|
|
100
|
-
defaultRegion: () => {
|
|
101
|
-
if (!resolved) throw new UsageError("Provider not yet loaded. Call getStack() first.");
|
|
102
|
-
return resolved.defaultRegion();
|
|
103
|
-
},
|
|
104
|
-
stateBackendUrl: (bucket) => {
|
|
105
|
-
if (!resolved) throw new UsageError("Provider not yet loaded. Call getStack() first.");
|
|
106
|
-
return resolved.stateBackendUrl(bucket);
|
|
107
|
-
},
|
|
108
|
-
validateConfig: () => resolve().then((a) => a.validateConfig())
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export {
|
|
113
|
-
buildContext
|
|
114
|
-
};
|