@clawops/cli 1.7.9 → 2.0.1
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 +504 -76
- package/dist/apply-KYFPWI5U.js +27 -0
- package/dist/automation-RMAIBNVC.js +44 -0
- package/dist/bedrock-XVASJX2K.js +61 -0
- package/dist/{bootstrap-HL4DNUNG.js → bootstrap-HNGKY6WW.js} +31 -19
- package/dist/bootstrap.sh.tmpl +51 -31
- package/dist/channels-KBUR42IU.js +53 -0
- package/dist/chunk-2I7KCMXZ.js +142 -0
- package/dist/{chunk-DQDAWNGB.js → chunk-2Z7J3ERQ.js} +1 -1
- package/dist/chunk-3OLUJPCB.js +36 -0
- package/dist/chunk-5XT5IAJK.js +69 -0
- package/dist/chunk-AEEMRFZV.js +24 -0
- package/dist/chunk-BSLIYB5Q.js +106 -0
- package/dist/{chunk-3XK66DKK.js → chunk-E4NJSJ54.js} +57 -93
- package/dist/chunk-FEK7VJAY.js +16 -0
- package/dist/{chunk-UKTP332Z.js → chunk-GAZPPSKU.js} +6 -7
- package/dist/chunk-GIEVAGEK.js +126 -0
- package/dist/chunk-HSPHXG6W.js +67 -0
- package/dist/chunk-IVWP4QUJ.js +901 -0
- package/dist/{chunk-PVUVI35Y.js → chunk-JW5A7E3X.js} +5 -1
- package/dist/{chunk-GZN7PKP4.js → chunk-KC3GC3PE.js} +328 -121
- package/dist/chunk-LBE6COC4.js +244 -0
- package/dist/chunk-LEVIW2PV.js +890 -0
- package/dist/chunk-LT4XMO5D.js +50 -0
- package/dist/chunk-MC5ATCXS.js +108 -0
- package/dist/chunk-N4WZLWJ4.js +16 -0
- package/dist/chunk-NUDIHZEH.js +55 -0
- package/dist/chunk-NUL5F6YV.js +56 -0
- package/dist/chunk-RHOWYIWT.js +52 -0
- package/dist/chunk-STLRHLLV.js +193 -0
- 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-W3OLNNJW.js +51 -0
- package/dist/cli-WLD3EBEM.js +11 -0
- package/dist/cli-auth-GD5SK7JU.js +13 -0
- package/dist/cli.js +1296 -695
- package/dist/config-validate-K2N6XLDX.js +76 -0
- package/dist/context-7EVC6W45.js +20 -0
- package/dist/docker-3PDO4TS7.js +12 -0
- package/dist/{firewall-XQGO7HWK.js → firewall-5VKZ4WBH.js} +32 -1
- package/dist/generate-I6YQ5V2T.js +29 -0
- package/dist/{harden-URPXLSVF.js → harden-72JMRT4E.js} +51 -11
- package/dist/health-5CCOXYGG.js +11 -0
- package/dist/index.d.ts +56 -0
- package/dist/known-hosts-file-I3Q3NBYQ.js +22 -0
- package/dist/logs-5A7YYA53.js +15 -0
- package/dist/{mcp-wire-7E5JQY47.js → mcp-wire-3SWBM7D6.js} +32 -16
- package/dist/models-AGTQWYDL.js +32 -0
- package/dist/network-args-PYJRJBYO.js +64 -0
- package/dist/{package-5AR4ZPK4.js → package-5BCMEBTE.js} +11 -4
- package/dist/passphrase-MJBE45N7.js +15 -0
- package/dist/plugins-DTST3OER.js +49 -0
- package/dist/{pool-QGFQRMGU.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/privileged-JFA6LLTV.js +17 -0
- package/dist/providers-FW6H6OPF.js +11 -0
- package/dist/ready-KDNRBNSU.js +95 -0
- package/dist/{remote-config-QDLN4UMG.js → remote-config-3HZLUWEA.js} +4 -3
- package/dist/runtime-X3KW5TCP.js +44 -0
- package/dist/server-GBA7BJGK.js +46 -0
- package/dist/spec-path-KQOOIQCA.js +9 -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/upgrade-ULD4KFYC.js +88 -0
- package/dist/validate-YVI3BJ55.js +14 -0
- package/dist/{version-guard-VUCNZXQS.js → version-guard-XVYW5WFJ.js} +2 -2
- package/dist/{versions-2UVAT6PQ.js → versions-W5LRQCAJ.js} +2 -2
- package/dist/wait-WO72TRRQ.js +79 -0
- package/package.json +11 -4
- package/spec/deploy-plan.schema.json +114 -25
- package/spec/integrations.yaml +135 -28
- package/spec/mcp-tools.yaml +89 -37
- package/spec/models.yaml +23 -3
- package/spec/openclaw-2.0.config.schema.json +1 -0
- package/spec/openclaw-versions.yaml +116 -27
- package/spec/providers.schema.json +163 -28
- package/dist/apply-F3KY2HTB.js +0 -17
- package/dist/automation-RULUSJBW.js +0 -30
- package/dist/aws-L4RR2LSE.js +0 -254
- package/dist/azure-7OXQENQL.js +0 -262
- package/dist/chunk-35WVQY3X.js +0 -122
- package/dist/chunk-6X45DDGH.js +0 -42
- package/dist/chunk-A4QR4TXW.js +0 -120
- package/dist/chunk-C5X375RO.js +0 -85
- package/dist/chunk-FNS56UQY.js +0 -741
- package/dist/chunk-P5LKWRPL.js +0 -114
- package/dist/chunk-SEZMVVAS.js +0 -156
- package/dist/context-5LCUG2QR.js +0 -10
- package/dist/gcp-UG6AWPIZ.js +0 -193
- package/dist/generate-OAGYT3VH.js +0 -15
- package/dist/local-DXBEVZ5C.js +0 -47
- package/dist/server-FIZCOLHL.js +0 -32
- package/dist/ssh-CNJNLM3E.js +0 -8
- package/dist/validate-CFQ4FH2T.js +0 -10
package/dist/aws-L4RR2LSE.js
DELETED
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
makeStartupScript
|
|
4
|
-
} from "./chunk-C5X375RO.js";
|
|
5
|
-
|
|
6
|
-
// src/providers/aws/index.ts
|
|
7
|
-
import process2 from "process";
|
|
8
|
-
|
|
9
|
-
// src/providers/aws/program.ts
|
|
10
|
-
var GATEWAY_PORT = 18789;
|
|
11
|
-
var SSH_PORT = 22;
|
|
12
|
-
var awsProgram = async () => {
|
|
13
|
-
const [pulumi, aws, { resolveIngressCidrs, detectEgressIp }] = await Promise.all([
|
|
14
|
-
import("@pulumi/pulumi"),
|
|
15
|
-
import("@pulumi/aws"),
|
|
16
|
-
import("./firewall-XQGO7HWK.js")
|
|
17
|
-
]);
|
|
18
|
-
const cfg = new pulumi.Config();
|
|
19
|
-
const instanceType = cfg.get("instanceType") ?? "t3.small";
|
|
20
|
-
const region = cfg.get("region") ?? "us-east-1";
|
|
21
|
-
const openclawVersion = cfg.get("openclawVersion") ?? "latest";
|
|
22
|
-
const accessMode = cfg.get("accessMode") ?? "restricted";
|
|
23
|
-
const allowedCidrs = cfg.get("allowedCidrs") ?? "";
|
|
24
|
-
const sshCidrs = cfg.get("sshCidrs") ?? "";
|
|
25
|
-
const gatewayCidrs = cfg.get("gatewayCidrs") ?? "";
|
|
26
|
-
const bedrockEnabled = cfg.get("bedrockEnabled") === "true";
|
|
27
|
-
const pinnedAmiId = cfg.get("amiId");
|
|
28
|
-
const sshPublicKey = cfg.get("sshPublicKey");
|
|
29
|
-
if (!sshPublicKey) {
|
|
30
|
-
throw new Error(
|
|
31
|
-
'Stack config "sshPublicKey" is required for the AWS adapter. Set it with: pulumi config set --stack <name> sshPublicKey "ssh-ed25519 ..."'
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
const egressResult = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : { ok: true, ip: "" };
|
|
35
|
-
if (accessMode === "open") {
|
|
36
|
-
process.stderr.write(
|
|
37
|
-
"[clawops] WARNING: accessMode=open allows 0.0.0.0/0 on SSH and gateway ports. Only use this for development/sandbox stacks.\n"
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
|
|
41
|
-
const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, egressResult);
|
|
42
|
-
const vpc = new aws.ec2.Vpc("clawops-vpc", {
|
|
43
|
-
cidrBlock: "10.0.0.0/16",
|
|
44
|
-
enableDnsHostnames: true,
|
|
45
|
-
enableDnsSupport: true,
|
|
46
|
-
tags: { Name: "clawops" }
|
|
47
|
-
});
|
|
48
|
-
const igw = new aws.ec2.InternetGateway("clawops-igw", {
|
|
49
|
-
tags: { Name: "clawops" }
|
|
50
|
-
});
|
|
51
|
-
new aws.ec2.InternetGatewayAttachment("clawops-igw-attach", {
|
|
52
|
-
vpcId: vpc.id,
|
|
53
|
-
internetGatewayId: igw.id
|
|
54
|
-
});
|
|
55
|
-
const subnet = new aws.ec2.Subnet("clawops-subnet", {
|
|
56
|
-
vpcId: vpc.id,
|
|
57
|
-
cidrBlock: "10.0.1.0/24",
|
|
58
|
-
mapPublicIpOnLaunch: false,
|
|
59
|
-
availabilityZone: pulumi.interpolate`${region}a`,
|
|
60
|
-
tags: { Name: "clawops" }
|
|
61
|
-
});
|
|
62
|
-
const routeTable = new aws.ec2.RouteTable("clawops-rt", {
|
|
63
|
-
vpcId: vpc.id,
|
|
64
|
-
tags: { Name: "clawops" }
|
|
65
|
-
});
|
|
66
|
-
new aws.ec2.Route("clawops-route", {
|
|
67
|
-
routeTableId: routeTable.id,
|
|
68
|
-
destinationCidrBlock: "0.0.0.0/0",
|
|
69
|
-
gatewayId: igw.id
|
|
70
|
-
});
|
|
71
|
-
new aws.ec2.RouteTableAssociation("clawops-rta", {
|
|
72
|
-
subnetId: subnet.id,
|
|
73
|
-
routeTableId: routeTable.id
|
|
74
|
-
});
|
|
75
|
-
const sg = new aws.ec2.SecurityGroup("clawops-sg", {
|
|
76
|
-
vpcId: vpc.id,
|
|
77
|
-
description: "clawops managed security group",
|
|
78
|
-
tags: { Name: "clawops" }
|
|
79
|
-
});
|
|
80
|
-
sshIngressCidrs.forEach((cidr, i) => {
|
|
81
|
-
new aws.vpc.SecurityGroupIngressRule(`clawops-sg-ssh-${i}`, {
|
|
82
|
-
securityGroupId: sg.id,
|
|
83
|
-
ipProtocol: "tcp",
|
|
84
|
-
fromPort: SSH_PORT,
|
|
85
|
-
toPort: SSH_PORT,
|
|
86
|
-
cidrIpv4: cidr,
|
|
87
|
-
tags: { Name: `clawops-ssh-${i}` }
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
gatewayIngressCidrs.forEach((cidr, i) => {
|
|
91
|
-
new aws.vpc.SecurityGroupIngressRule(`clawops-sg-gw-${i}`, {
|
|
92
|
-
securityGroupId: sg.id,
|
|
93
|
-
ipProtocol: "tcp",
|
|
94
|
-
fromPort: GATEWAY_PORT,
|
|
95
|
-
toPort: GATEWAY_PORT,
|
|
96
|
-
cidrIpv4: cidr,
|
|
97
|
-
tags: { Name: `clawops-gateway-${i}` }
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
new aws.vpc.SecurityGroupEgressRule("clawops-sg-egress", {
|
|
101
|
-
securityGroupId: sg.id,
|
|
102
|
-
ipProtocol: "-1",
|
|
103
|
-
cidrIpv4: "0.0.0.0/0",
|
|
104
|
-
tags: { Name: "clawops-egress" }
|
|
105
|
-
});
|
|
106
|
-
const role = new aws.iam.Role("clawops-role", {
|
|
107
|
-
assumeRolePolicy: JSON.stringify({
|
|
108
|
-
Version: "2012-10-17",
|
|
109
|
-
Statement: [{
|
|
110
|
-
Effect: "Allow",
|
|
111
|
-
Principal: { Service: "ec2.amazonaws.com" },
|
|
112
|
-
Action: "sts:AssumeRole"
|
|
113
|
-
}]
|
|
114
|
-
}),
|
|
115
|
-
tags: { Name: "clawops" }
|
|
116
|
-
});
|
|
117
|
-
new aws.iam.RolePolicyAttachment("clawops-ssm", {
|
|
118
|
-
role: role.name,
|
|
119
|
-
policyArn: "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
|
|
120
|
-
});
|
|
121
|
-
if (bedrockEnabled) {
|
|
122
|
-
new aws.iam.RolePolicy("clawops-bedrock-invoke", {
|
|
123
|
-
role: role.name,
|
|
124
|
-
policy: JSON.stringify({
|
|
125
|
-
Version: "2012-10-17",
|
|
126
|
-
Statement: [{
|
|
127
|
-
Effect: "Allow",
|
|
128
|
-
Action: [
|
|
129
|
-
"bedrock:InvokeModel",
|
|
130
|
-
"bedrock:InvokeModelWithResponseStream"
|
|
131
|
-
],
|
|
132
|
-
Resource: "*"
|
|
133
|
-
}]
|
|
134
|
-
})
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
const instanceProfile = new aws.iam.InstanceProfile("clawops-profile", {
|
|
138
|
-
role: role.name
|
|
139
|
-
});
|
|
140
|
-
const keyPair = new aws.ec2.KeyPair("clawops-keypair", {
|
|
141
|
-
publicKey: sshPublicKey,
|
|
142
|
-
tags: { Name: "clawops" }
|
|
143
|
-
});
|
|
144
|
-
const amiId = pinnedAmiId ?? (await aws.ec2.getAmi({
|
|
145
|
-
mostRecent: true,
|
|
146
|
-
owners: ["099720109477"],
|
|
147
|
-
// Canonical
|
|
148
|
-
filters: [
|
|
149
|
-
{ name: "name", values: ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] },
|
|
150
|
-
{ name: "virtualization-type", values: ["hvm"] }
|
|
151
|
-
]
|
|
152
|
-
})).id;
|
|
153
|
-
process.stderr.write(`[clawops] Using AMI: ${amiId}
|
|
154
|
-
`);
|
|
155
|
-
const instance = new aws.ec2.Instance("clawops-instance", {
|
|
156
|
-
ami: amiId,
|
|
157
|
-
instanceType,
|
|
158
|
-
subnetId: subnet.id,
|
|
159
|
-
vpcSecurityGroupIds: [sg.id],
|
|
160
|
-
iamInstanceProfile: instanceProfile.name,
|
|
161
|
-
keyName: keyPair.keyName,
|
|
162
|
-
userData: makeStartupScript({ openclawVersion, os: "ubuntu", bedrockEnabled }),
|
|
163
|
-
// IMDSv2 with hopLimit=2 so Docker containers on this host can reach IMDS
|
|
164
|
-
// and obtain the instance role credentials (required for Bedrock access).
|
|
165
|
-
metadataOptions: {
|
|
166
|
-
httpTokens: "required",
|
|
167
|
-
httpPutResponseHopLimit: 2
|
|
168
|
-
},
|
|
169
|
-
tags: { Name: "clawops" }
|
|
170
|
-
});
|
|
171
|
-
const eip = new aws.ec2.Eip("clawops-eip", {
|
|
172
|
-
domain: "vpc",
|
|
173
|
-
tags: { Name: "clawops" }
|
|
174
|
-
});
|
|
175
|
-
new aws.ec2.EipAssociation("clawops-eip-assoc", {
|
|
176
|
-
instanceId: instance.id,
|
|
177
|
-
allocationId: eip.id
|
|
178
|
-
});
|
|
179
|
-
return {
|
|
180
|
-
instanceId: instance.id,
|
|
181
|
-
publicIp: eip.publicIp,
|
|
182
|
-
gatewayUrl: pulumi.interpolate`https://${eip.publicIp}:${GATEWAY_PORT}`,
|
|
183
|
-
sshHost: eip.publicIp,
|
|
184
|
-
sshPort: SSH_PORT,
|
|
185
|
-
sshUser: "ubuntu",
|
|
186
|
-
region,
|
|
187
|
-
provisionedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
188
|
-
};
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
// src/providers/aws/index.ts
|
|
192
|
-
var INSTANCE_TYPE_MAP = {
|
|
193
|
-
micro: "t3.micro",
|
|
194
|
-
small: "t3.small",
|
|
195
|
-
medium: "t3.medium",
|
|
196
|
-
large: "t3.large",
|
|
197
|
-
gpu: "g4dn.xlarge"
|
|
198
|
-
};
|
|
199
|
-
var awsAdapter = {
|
|
200
|
-
name: "aws",
|
|
201
|
-
get program() {
|
|
202
|
-
return awsProgram;
|
|
203
|
-
},
|
|
204
|
-
getConnectionInfo(outputs) {
|
|
205
|
-
return {
|
|
206
|
-
host: String(outputs["sshHost"] ?? ""),
|
|
207
|
-
port: Number(outputs["sshPort"] ?? 22),
|
|
208
|
-
user: String(outputs["sshUser"] ?? "ubuntu"),
|
|
209
|
-
privateKeyPath: String(outputs["privateKeyPath"] ?? ""),
|
|
210
|
-
knownHostsPath: String(outputs["knownHostsPath"] ?? "")
|
|
211
|
-
};
|
|
212
|
-
},
|
|
213
|
-
normalizeInstanceType(alias) {
|
|
214
|
-
const mapped = INSTANCE_TYPE_MAP[alias];
|
|
215
|
-
if (!mapped) throw new Error(`Unknown instance alias: ${alias}`);
|
|
216
|
-
return mapped;
|
|
217
|
-
},
|
|
218
|
-
defaultRegion() {
|
|
219
|
-
return "us-east-1";
|
|
220
|
-
},
|
|
221
|
-
stateBackendUrl(bucket) {
|
|
222
|
-
return `s3://${bucket}`;
|
|
223
|
-
},
|
|
224
|
-
async validateConfig() {
|
|
225
|
-
const errors = [];
|
|
226
|
-
const hasProfile = Boolean(process2.env["AWS_PROFILE"]);
|
|
227
|
-
const hasKeyId = Boolean(process2.env["AWS_ACCESS_KEY_ID"]);
|
|
228
|
-
const hasOidc = Boolean(process2.env["AWS_ROLE_ARN"] && process2.env["AWS_WEB_IDENTITY_TOKEN_FILE"]);
|
|
229
|
-
if (!hasProfile && !hasKeyId && !hasOidc) {
|
|
230
|
-
const onAws = await checkImds();
|
|
231
|
-
if (!onAws) {
|
|
232
|
-
errors.push(
|
|
233
|
-
"No AWS credentials found. Set AWS_PROFILE, AWS_ACCESS_KEY_ID, or AWS_ROLE_ARN + AWS_WEB_IDENTITY_TOKEN_FILE, or run on an EC2 instance with an IAM instance role."
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return { ok: errors.length === 0, errors };
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
async function checkImds() {
|
|
241
|
-
try {
|
|
242
|
-
const res = await fetch(
|
|
243
|
-
"http://169.254.169.254/latest/meta-data/instance-id",
|
|
244
|
-
{ signal: AbortSignal.timeout(1e3) }
|
|
245
|
-
);
|
|
246
|
-
return res.ok;
|
|
247
|
-
} catch {
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
var aws_default = awsAdapter;
|
|
252
|
-
export {
|
|
253
|
-
aws_default as default
|
|
254
|
-
};
|
package/dist/azure-7OXQENQL.js
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
makeStartupScript
|
|
4
|
-
} from "./chunk-C5X375RO.js";
|
|
5
|
-
|
|
6
|
-
// src/providers/azure/index.ts
|
|
7
|
-
import process2 from "process";
|
|
8
|
-
|
|
9
|
-
// src/providers/azure/program.ts
|
|
10
|
-
import { createHash } from "crypto";
|
|
11
|
-
var GATEWAY_PORT = 18789;
|
|
12
|
-
var SSH_PORT = 22;
|
|
13
|
-
var azureProgram = async () => {
|
|
14
|
-
const [pulumi, azure, random, { resolveIngressCidrs, detectEgressIp }] = await Promise.all([
|
|
15
|
-
import("@pulumi/pulumi"),
|
|
16
|
-
import("@pulumi/azure-native"),
|
|
17
|
-
import("@pulumi/random"),
|
|
18
|
-
import("./firewall-XQGO7HWK.js")
|
|
19
|
-
]);
|
|
20
|
-
const cfg = new pulumi.Config();
|
|
21
|
-
const stackName = pulumi.getStack();
|
|
22
|
-
const instanceType = cfg.get("instanceType") ?? "Standard_B2s";
|
|
23
|
-
const location = cfg.get("region") ?? "eastus";
|
|
24
|
-
const openclawVersion = cfg.get("openclawVersion") ?? "latest";
|
|
25
|
-
const accessMode = cfg.get("accessMode") ?? "restricted";
|
|
26
|
-
const allowedCidrs = cfg.get("allowedCidrs") ?? "";
|
|
27
|
-
const sshCidrs = cfg.get("sshCidrs") ?? "";
|
|
28
|
-
const gatewayCidrs = cfg.get("gatewayCidrs") ?? "";
|
|
29
|
-
const keyVaultEnabled = cfg.get("keyVaultEnabled") === "true";
|
|
30
|
-
const resourceGroupName = cfg.get("resourceGroupName") ?? `clawops-${stackName}`;
|
|
31
|
-
const sshPublicKey = cfg.get("sshPublicKey");
|
|
32
|
-
if (!sshPublicKey) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
'Stack config "sshPublicKey" is required for the Azure adapter. Set it with: pulumi config set --stack <name> sshPublicKey "ssh-ed25519 ..."'
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
const clientConfig = await azure.authorization.getClientConfig({});
|
|
38
|
-
const egressResult = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : { ok: true, ip: "" };
|
|
39
|
-
if (accessMode === "open") {
|
|
40
|
-
process.stderr.write(
|
|
41
|
-
"[clawops] WARNING: accessMode=open allows 0.0.0.0/0 on SSH and gateway ports. Only use this for development/sandbox stacks.\n"
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
|
|
45
|
-
const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, egressResult);
|
|
46
|
-
const rg = new azure.resources.ResourceGroup("clawops-rg", {
|
|
47
|
-
resourceGroupName,
|
|
48
|
-
location
|
|
49
|
-
});
|
|
50
|
-
const vnet = new azure.network.VirtualNetwork("clawops-vnet", {
|
|
51
|
-
resourceGroupName: rg.name,
|
|
52
|
-
location: rg.location,
|
|
53
|
-
addressSpace: { addressPrefixes: ["10.0.0.0/16"] }
|
|
54
|
-
});
|
|
55
|
-
const subnet = new azure.network.Subnet("clawops-subnet", {
|
|
56
|
-
resourceGroupName: rg.name,
|
|
57
|
-
virtualNetworkName: vnet.name,
|
|
58
|
-
addressPrefix: "10.0.1.0/24"
|
|
59
|
-
});
|
|
60
|
-
const securityRules = [];
|
|
61
|
-
let priority = 100;
|
|
62
|
-
for (const cidr of sshIngressCidrs) {
|
|
63
|
-
securityRules.push({
|
|
64
|
-
name: `allow-ssh-${priority}`,
|
|
65
|
-
priority: priority++,
|
|
66
|
-
direction: "Inbound",
|
|
67
|
-
access: "Allow",
|
|
68
|
-
protocol: "Tcp",
|
|
69
|
-
sourceAddressPrefix: cidr,
|
|
70
|
-
sourcePortRange: "*",
|
|
71
|
-
destinationAddressPrefix: "*",
|
|
72
|
-
destinationPortRange: String(SSH_PORT)
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
for (const cidr of gatewayIngressCidrs) {
|
|
76
|
-
securityRules.push({
|
|
77
|
-
name: `allow-gateway-${priority}`,
|
|
78
|
-
priority: priority++,
|
|
79
|
-
direction: "Inbound",
|
|
80
|
-
access: "Allow",
|
|
81
|
-
protocol: "Tcp",
|
|
82
|
-
sourceAddressPrefix: cidr,
|
|
83
|
-
sourcePortRange: "*",
|
|
84
|
-
destinationAddressPrefix: "*",
|
|
85
|
-
destinationPortRange: String(GATEWAY_PORT)
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
const nsg = new azure.network.NetworkSecurityGroup("clawops-nsg", {
|
|
89
|
-
resourceGroupName: rg.name,
|
|
90
|
-
location: rg.location,
|
|
91
|
-
securityRules
|
|
92
|
-
});
|
|
93
|
-
const publicIp = new azure.network.PublicIPAddress("clawops-pip", {
|
|
94
|
-
resourceGroupName: rg.name,
|
|
95
|
-
location: rg.location,
|
|
96
|
-
publicIPAllocationMethod: "Static",
|
|
97
|
-
sku: { name: "Standard" }
|
|
98
|
-
});
|
|
99
|
-
const nic = new azure.network.NetworkInterface("clawops-nic", {
|
|
100
|
-
resourceGroupName: rg.name,
|
|
101
|
-
location: rg.location,
|
|
102
|
-
networkSecurityGroup: { id: nsg.id },
|
|
103
|
-
ipConfigurations: [{
|
|
104
|
-
name: "clawops-ipconfig",
|
|
105
|
-
subnet: { id: subnet.id },
|
|
106
|
-
publicIPAddress: { id: publicIp.id },
|
|
107
|
-
privateIPAllocationMethod: "Dynamic"
|
|
108
|
-
}]
|
|
109
|
-
});
|
|
110
|
-
const vm = new azure.compute.VirtualMachine("clawops-vm", {
|
|
111
|
-
resourceGroupName: rg.name,
|
|
112
|
-
location: rg.location,
|
|
113
|
-
hardwareProfile: { vmSize: instanceType },
|
|
114
|
-
identity: { type: "SystemAssigned" },
|
|
115
|
-
osProfile: {
|
|
116
|
-
adminUsername: "clawops",
|
|
117
|
-
computerName: "clawops",
|
|
118
|
-
customData: Buffer.from(makeStartupScript({ openclawVersion, os: "ubuntu" })).toString("base64"),
|
|
119
|
-
linuxConfiguration: {
|
|
120
|
-
disablePasswordAuthentication: true,
|
|
121
|
-
ssh: {
|
|
122
|
-
publicKeys: [{
|
|
123
|
-
keyData: sshPublicKey,
|
|
124
|
-
path: "/home/clawops/.ssh/authorized_keys"
|
|
125
|
-
}]
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
storageProfile: {
|
|
130
|
-
imageReference: {
|
|
131
|
-
publisher: "Canonical",
|
|
132
|
-
// Ubuntu 22.04 LTS — Canonical migrated from the legacy 'UbuntuServer'
|
|
133
|
-
// offer to this naming scheme. 22_04-lts-gen2 is available in all regions.
|
|
134
|
-
offer: "0001-com-ubuntu-server-jammy",
|
|
135
|
-
sku: "22_04-lts-gen2",
|
|
136
|
-
version: "latest"
|
|
137
|
-
},
|
|
138
|
-
osDisk: {
|
|
139
|
-
createOption: "FromImage",
|
|
140
|
-
managedDisk: { storageAccountType: "Premium_LRS" },
|
|
141
|
-
diskSizeGB: 30
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
networkProfile: {
|
|
145
|
-
networkInterfaces: [{ id: nic.id, primary: true }]
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
if (keyVaultEnabled) {
|
|
149
|
-
const safeName = stackName.replace(/[^a-zA-Z0-9-]/g, "-");
|
|
150
|
-
const rawKvName = `clawops-${safeName}-kv`;
|
|
151
|
-
const kvName = rawKvName.length > 24 ? `cl-${createHash("sha256").update(stackName).digest("hex").slice(0, 20)}` : rawKvName;
|
|
152
|
-
const kv = new azure.keyvault.Vault("clawops-kv", {
|
|
153
|
-
resourceGroupName: rg.name,
|
|
154
|
-
location: rg.location,
|
|
155
|
-
vaultName: kvName,
|
|
156
|
-
properties: {
|
|
157
|
-
sku: { family: "A", name: "standard" },
|
|
158
|
-
tenantId: pulumi.output(vm.identity).apply((i) => i?.tenantId ?? ""),
|
|
159
|
-
enableRbacAuthorization: true
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
const kvSecretsUserRoleId = `/subscriptions/${clientConfig.subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6`;
|
|
163
|
-
new azure.authorization.RoleAssignment("clawops-kv-role", {
|
|
164
|
-
scope: kv.id,
|
|
165
|
-
roleDefinitionId: kvSecretsUserRoleId,
|
|
166
|
-
principalId: pulumi.output(vm.identity).apply((i) => i?.principalId ?? ""),
|
|
167
|
-
principalType: "ServicePrincipal"
|
|
168
|
-
});
|
|
169
|
-
const gatewayToken = new random.RandomPassword("clawops-kv-gateway-token", {
|
|
170
|
-
length: 32,
|
|
171
|
-
special: false
|
|
172
|
-
});
|
|
173
|
-
new azure.keyvault.Secret("clawops-gateway-token", {
|
|
174
|
-
resourceGroupName: rg.name,
|
|
175
|
-
vaultName: kv.name,
|
|
176
|
-
secretName: "gateway-token",
|
|
177
|
-
properties: { value: gatewayToken.result }
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
const resolvedIp = pulumi.output(publicIp.ipAddress).apply((ip) => ip ?? "");
|
|
181
|
-
return {
|
|
182
|
-
instanceId: vm.id,
|
|
183
|
-
publicIp: resolvedIp,
|
|
184
|
-
gatewayUrl: pulumi.interpolate`https://${resolvedIp}:${GATEWAY_PORT}`,
|
|
185
|
-
sshHost: resolvedIp,
|
|
186
|
-
sshPort: SSH_PORT,
|
|
187
|
-
sshUser: "clawops",
|
|
188
|
-
region: location,
|
|
189
|
-
provisionedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
190
|
-
};
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
// src/providers/azure/index.ts
|
|
194
|
-
var INSTANCE_TYPE_MAP = {
|
|
195
|
-
micro: "Standard_B1s",
|
|
196
|
-
small: "Standard_B2s",
|
|
197
|
-
medium: "Standard_B4ms",
|
|
198
|
-
large: "Standard_B8ms",
|
|
199
|
-
gpu: "Standard_NC6s_v3"
|
|
200
|
-
};
|
|
201
|
-
var azureAdapter = {
|
|
202
|
-
name: "azure",
|
|
203
|
-
get program() {
|
|
204
|
-
return azureProgram;
|
|
205
|
-
},
|
|
206
|
-
getConnectionInfo(outputs) {
|
|
207
|
-
return {
|
|
208
|
-
host: String(outputs["sshHost"] ?? ""),
|
|
209
|
-
port: Number(outputs["sshPort"] ?? 22),
|
|
210
|
-
user: String(outputs["sshUser"] ?? "clawops"),
|
|
211
|
-
privateKeyPath: String(outputs["privateKeyPath"] ?? ""),
|
|
212
|
-
knownHostsPath: String(outputs["knownHostsPath"] ?? "")
|
|
213
|
-
};
|
|
214
|
-
},
|
|
215
|
-
normalizeInstanceType(alias) {
|
|
216
|
-
const mapped = INSTANCE_TYPE_MAP[alias];
|
|
217
|
-
if (!mapped) throw new Error(`Unknown instance alias: ${alias}`);
|
|
218
|
-
return mapped;
|
|
219
|
-
},
|
|
220
|
-
defaultRegion() {
|
|
221
|
-
return "eastus";
|
|
222
|
-
},
|
|
223
|
-
stateBackendUrl(bucket) {
|
|
224
|
-
return `azblob://${bucket}`;
|
|
225
|
-
},
|
|
226
|
-
async validateConfig() {
|
|
227
|
-
const errors = [];
|
|
228
|
-
const clientId = process2.env["AZURE_CLIENT_ID"];
|
|
229
|
-
const tenantId = process2.env["AZURE_TENANT_ID"];
|
|
230
|
-
const clientSecret = process2.env["AZURE_CLIENT_SECRET"];
|
|
231
|
-
const federatedToken = process2.env["AZURE_FEDERATED_TOKEN_FILE"];
|
|
232
|
-
const hasServicePrincipal = Boolean(clientId && tenantId && clientSecret);
|
|
233
|
-
const hasOidc = Boolean(clientId && tenantId && federatedToken);
|
|
234
|
-
if (!hasServicePrincipal && !hasOidc) {
|
|
235
|
-
const onAzure = await checkImds();
|
|
236
|
-
if (!onAzure) {
|
|
237
|
-
errors.push(
|
|
238
|
-
"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."
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return { ok: errors.length === 0, errors };
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
async function checkImds() {
|
|
246
|
-
try {
|
|
247
|
-
const res = await fetch(
|
|
248
|
-
"http://169.254.169.254/metadata/instance?api-version=2021-02-01",
|
|
249
|
-
{
|
|
250
|
-
headers: { Metadata: "true" },
|
|
251
|
-
signal: AbortSignal.timeout(1e3)
|
|
252
|
-
}
|
|
253
|
-
);
|
|
254
|
-
return res.ok;
|
|
255
|
-
} catch {
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
var azure_default = azureAdapter;
|
|
260
|
-
export {
|
|
261
|
-
azure_default as default
|
|
262
|
-
};
|
package/dist/chunk-35WVQY3X.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
saveOverlay
|
|
4
|
-
} from "./chunk-6ZFIFDBJ.js";
|
|
5
|
-
import {
|
|
6
|
-
resolveSecrets
|
|
7
|
-
} from "./chunk-BOPSG2LI.js";
|
|
8
|
-
import {
|
|
9
|
-
validatePlan
|
|
10
|
-
} from "./chunk-6X45DDGH.js";
|
|
11
|
-
import {
|
|
12
|
-
atomicWriteConfig,
|
|
13
|
-
deepMerge,
|
|
14
|
-
readRemoteConfig,
|
|
15
|
-
restartGateway
|
|
16
|
-
} from "./chunk-SEZMVVAS.js";
|
|
17
|
-
import {
|
|
18
|
-
buildContext
|
|
19
|
-
} from "./chunk-P5LKWRPL.js";
|
|
20
|
-
import {
|
|
21
|
-
UsageError
|
|
22
|
-
} from "./chunk-KGXPLI7W.js";
|
|
23
|
-
|
|
24
|
-
// src/plan/apply.ts
|
|
25
|
-
async function applyPlan(plan, opts) {
|
|
26
|
-
const validation = validatePlan(plan);
|
|
27
|
-
if (!validation.ok) {
|
|
28
|
-
throw new UsageError(
|
|
29
|
-
`Invalid deploy plan:
|
|
30
|
-
${validation.errors.join("\n")}`
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
if (plan.spec.provider === "local") {
|
|
34
|
-
throw new UsageError(
|
|
35
|
-
"plan/apply is not supported for the local provider. Use `clawops up` directly."
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
const { guardOpenclawVersion } = await import("./version-guard-VUCNZXQS.js");
|
|
39
|
-
await guardOpenclawVersion(plan.spec.openclaw.version);
|
|
40
|
-
const ctx = buildContext({
|
|
41
|
-
stack: plan.spec.stackName,
|
|
42
|
-
provider: plan.spec.provider
|
|
43
|
-
});
|
|
44
|
-
const stack = await ctx.getStack();
|
|
45
|
-
await stack.setConfig("instanceType", { value: plan.spec.instanceType });
|
|
46
|
-
if (plan.spec.region) {
|
|
47
|
-
await stack.setConfig("region", { value: plan.spec.region });
|
|
48
|
-
}
|
|
49
|
-
await stack.setConfig("openclawVersion", { value: plan.spec.openclaw.version });
|
|
50
|
-
const modelProvider = plan.spec.openclaw.config?.["models"]?.["provider"];
|
|
51
|
-
if (modelProvider === "bedrock") {
|
|
52
|
-
await stack.setConfig("bedrockEnabled", { value: "true" });
|
|
53
|
-
}
|
|
54
|
-
if (plan.metadata.stackVersion !== void 0) {
|
|
55
|
-
const currentInfo = await stack.info();
|
|
56
|
-
if (currentInfo !== void 0 && currentInfo.version !== plan.metadata.stackVersion) {
|
|
57
|
-
process.stderr.write(
|
|
58
|
-
`
|
|
59
|
-
Warning: stack "${plan.spec.stackName}" has changed since this plan was generated (plan version: ${plan.metadata.stackVersion}, current: ${currentInfo.version}).
|
|
60
|
-
The diff you reviewed may no longer reflect what will be applied.
|
|
61
|
-
|
|
62
|
-
`
|
|
63
|
-
);
|
|
64
|
-
if (opts?.confirmDrift) {
|
|
65
|
-
await opts.confirmDrift();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const start = Date.now();
|
|
70
|
-
const result = await stack.up({ onOutput: opts?.onOutput, signal: opts?.signal });
|
|
71
|
-
const outputs = Object.fromEntries(
|
|
72
|
-
Object.entries(result.outputs).map(([k, v]) => [k, v.value])
|
|
73
|
-
);
|
|
74
|
-
const changeSummary = {};
|
|
75
|
-
if (result.summary.resourceChanges) {
|
|
76
|
-
for (const [op, count] of Object.entries(result.summary.resourceChanges)) {
|
|
77
|
-
changeSummary[op] = count;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const hasOverlay = plan.spec.openclaw.config !== void 0 || plan.spec.openclaw.channels !== void 0;
|
|
81
|
-
if (hasOverlay) {
|
|
82
|
-
await applyConfigOverlay(plan, outputs, ctx, opts?.signal);
|
|
83
|
-
}
|
|
84
|
-
return {
|
|
85
|
-
outputs,
|
|
86
|
-
changeSummary,
|
|
87
|
-
durationMs: Date.now() - start
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
async function applyConfigOverlay(plan, outputs, ctx, signal) {
|
|
91
|
-
const { connect } = await import("./ssh-CNJNLM3E.js");
|
|
92
|
-
const connInfo = ctx.adapter.getConnectionInfo(outputs);
|
|
93
|
-
const session = await connect({
|
|
94
|
-
host: connInfo.host,
|
|
95
|
-
port: connInfo.port,
|
|
96
|
-
user: connInfo.user,
|
|
97
|
-
privateKeyPath: connInfo.privateKeyPath,
|
|
98
|
-
knownHostsPath: connInfo.knownHostsPath,
|
|
99
|
-
signal
|
|
100
|
-
});
|
|
101
|
-
try {
|
|
102
|
-
const remote = await readRemoteConfig(session, signal);
|
|
103
|
-
const configOverlay = plan.spec.openclaw.config ?? {};
|
|
104
|
-
const resolvedOverlay = resolveSecrets(
|
|
105
|
-
configOverlay,
|
|
106
|
-
plan.spec.secrets ?? []
|
|
107
|
-
);
|
|
108
|
-
const merged = deepMerge(remote, {
|
|
109
|
-
...resolvedOverlay,
|
|
110
|
-
...plan.spec.openclaw.channels !== void 0 ? { channels: plan.spec.openclaw.channels } : {}
|
|
111
|
-
});
|
|
112
|
-
await atomicWriteConfig(session, merged, signal);
|
|
113
|
-
await restartGateway(session, signal);
|
|
114
|
-
saveOverlay(plan.spec.stackName, configOverlay, plan.spec.secrets ?? []);
|
|
115
|
-
} finally {
|
|
116
|
-
session.close();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export {
|
|
121
|
-
applyPlan
|
|
122
|
-
};
|
package/dist/chunk-6X45DDGH.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
resolveSpecDir
|
|
4
|
-
} from "./chunk-PVUVI35Y.js";
|
|
5
|
-
|
|
6
|
-
// src/plan/validate.ts
|
|
7
|
-
import Ajv from "ajv/dist/2020";
|
|
8
|
-
import addFormats from "ajv-formats";
|
|
9
|
-
import { readFileSync } from "fs";
|
|
10
|
-
import { join } from "path";
|
|
11
|
-
var _validate;
|
|
12
|
-
function getValidator() {
|
|
13
|
-
if (_validate) return _validate;
|
|
14
|
-
const ajv = new Ajv({ strict: false });
|
|
15
|
-
addFormats(ajv);
|
|
16
|
-
const schema = JSON.parse(
|
|
17
|
-
readFileSync(join(resolveSpecDir(), "deploy-plan.schema.json"), "utf-8")
|
|
18
|
-
);
|
|
19
|
-
_validate = ajv.compile(schema);
|
|
20
|
-
return _validate;
|
|
21
|
-
}
|
|
22
|
-
function validatePlan(plan) {
|
|
23
|
-
const validate = getValidator();
|
|
24
|
-
const ok = validate(plan);
|
|
25
|
-
if (ok) return { ok: true, errors: [] };
|
|
26
|
-
const errors = (validate.errors ?? []).map(
|
|
27
|
-
(e) => `${e.instancePath} ${e.message ?? ""}`.trim()
|
|
28
|
-
);
|
|
29
|
-
return { ok: false, errors };
|
|
30
|
-
}
|
|
31
|
-
function assertValidPlan(plan) {
|
|
32
|
-
const result = validatePlan(plan);
|
|
33
|
-
if (!result.ok) {
|
|
34
|
-
throw new Error(`Invalid deploy plan:
|
|
35
|
-
${result.errors.join("\n")}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
validatePlan,
|
|
41
|
-
assertValidPlan
|
|
42
|
-
};
|