@clawops/cli 2.0.0 → 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 +98 -12
- package/dist/apply-KYFPWI5U.js +27 -0
- package/dist/automation-RMAIBNVC.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-5XT5IAJK.js +69 -0
- 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-GYV4KNW7.js → chunk-IVWP4QUJ.js} +133 -40
- package/dist/{chunk-AX74VXTV.js → chunk-KC3GC3PE.js} +58 -49
- package/dist/{chunk-UFRO4H5W.js → chunk-LBE6COC4.js} +56 -40
- 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-RHOWYIWT.js +52 -0
- package/dist/{chunk-WHJMKDV7.js → chunk-STLRHLLV.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-W3OLNNJW.js +51 -0
- package/dist/cli-WLD3EBEM.js +11 -0
- package/dist/cli-auth-GD5SK7JU.js +13 -0
- package/dist/cli.js +518 -206
- package/dist/context-7EVC6W45.js +20 -0
- package/dist/docker-3PDO4TS7.js +12 -0
- package/dist/{firewall-T3NTPZJD.js → firewall-5VKZ4WBH.js} +22 -1
- package/dist/generate-I6YQ5V2T.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-3SWBM7D6.js} +25 -15
- package/dist/models-AGTQWYDL.js +32 -0
- package/dist/network-args-PYJRJBYO.js +64 -0
- package/dist/{package-3HUW57XH.js → package-5BCMEBTE.js} +10 -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-GBA7BJGK.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 +10 -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/spec/mcp-tools.yaml
CHANGED
|
@@ -291,10 +291,29 @@ tools:
|
|
|
291
291
|
description: Defaults to provider configured for this stack
|
|
292
292
|
region: { type: string, optional: true }
|
|
293
293
|
instanceType:
|
|
294
|
-
type:
|
|
295
|
-
values: [micro, small, medium, large, gpu]
|
|
294
|
+
type: string
|
|
296
295
|
optional: true
|
|
297
296
|
default: small
|
|
297
|
+
description: |
|
|
298
|
+
A clawops size (micro|small|medium|large|gpu) or a provider-native machine type.
|
|
299
|
+
Not an enum: Azure offers SKU families per subscription, and an account offered
|
|
300
|
+
none of the five sizes clawops names would otherwise have no way to deploy.
|
|
301
|
+
sshCidr:
|
|
302
|
+
type: string
|
|
303
|
+
optional: true
|
|
304
|
+
description: |
|
|
305
|
+
CIDR(s) allowed to reach SSH, comma-separated, or 'auto' for the caller's own
|
|
306
|
+
address. Omitted means none, and nothing will be able to connect — including
|
|
307
|
+
every clawops day-two command.
|
|
308
|
+
gatewayCidr:
|
|
309
|
+
type: string
|
|
310
|
+
optional: true
|
|
311
|
+
description: CIDR(s) allowed to reach the gateway port. Requires publishGateway=all.
|
|
312
|
+
publishGateway:
|
|
313
|
+
type: enum
|
|
314
|
+
values: [loopback, all]
|
|
315
|
+
optional: true
|
|
316
|
+
description: Which interface the gateway binds. 'all' serves plaintext HTTP.
|
|
298
317
|
openclawVersion: { type: string, optional: true, description: "semver or 'stable'/'dev'" }
|
|
299
318
|
dryRun: { type: boolean, optional: true, default: false }
|
|
300
319
|
output:
|
package/spec/models.yaml
CHANGED
|
@@ -60,9 +60,20 @@ providers:
|
|
|
60
60
|
- id: bedrock
|
|
61
61
|
displayName: AWS Bedrock
|
|
62
62
|
credentialSource: aws-profile
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
63
|
+
# Bedrock is a plugin provider, so OpenClaw does not resolve its transport on its own:
|
|
64
|
+
# without `api` the call routes through the OpenAI-compatible transport and fails with
|
|
65
|
+
# "requires an explicit base URL". Bundled providers do resolve it — `anthropic` selects
|
|
66
|
+
# anthropic-messages with nothing in the config — so this key is set here and nowhere
|
|
67
|
+
# else. See docs/spikes/SP-12-bedrock-config-shape.md.
|
|
68
|
+
api: bedrock-converse-stream
|
|
69
|
+
# No API key — credentials come from the EC2 instance role via IMDS, resolved by the AWS
|
|
70
|
+
# SDK chain at call time. The old `AWS_PROFILE=default` env-file mechanism is obsolete
|
|
71
|
+
# (SP-08); so is the `auth: "aws-sdk"` marker as a *requirement* — Bedrock was reached
|
|
72
|
+
# with it absent (SP-12 §4) — though clawops still writes it to document the auth route.
|
|
73
|
+
#
|
|
74
|
+
# modelId below is the FOUNDATION model id. Bedrock refuses these for on-demand
|
|
75
|
+
# inference; clawops resolves each to a regional inference profile at plan time, because
|
|
76
|
+
# the right profile depends on the deployment region and cannot be written down here.
|
|
66
77
|
iamPolicy: AmazonBedrockFullAccess
|
|
67
78
|
iamNote: >
|
|
68
79
|
Credentials are provided by the EC2 instance role. clawops attaches
|
|
@@ -4,25 +4,46 @@
|
|
|
4
4
|
"title": "ProviderAdapter",
|
|
5
5
|
"description": "Contract every cloud provider adapter must satisfy. Source of truth for src/providers/types.ts (generated). Per R-meta-1.",
|
|
6
6
|
"type": "object",
|
|
7
|
-
"required": [
|
|
7
|
+
"required": [
|
|
8
|
+
"name",
|
|
9
|
+
"credentials",
|
|
10
|
+
"regions",
|
|
11
|
+
"instanceTypes",
|
|
12
|
+
"stateBackend",
|
|
13
|
+
"operations"
|
|
14
|
+
],
|
|
8
15
|
"properties": {
|
|
9
16
|
"name": {
|
|
10
17
|
"type": "string",
|
|
11
|
-
"enum": [
|
|
18
|
+
"enum": [
|
|
19
|
+
"aws",
|
|
20
|
+
"gcp",
|
|
21
|
+
"azure",
|
|
22
|
+
"local"
|
|
23
|
+
],
|
|
12
24
|
"description": "Lowercase provider id"
|
|
13
25
|
},
|
|
14
26
|
"credentials": {
|
|
15
27
|
"type": "object",
|
|
16
28
|
"description": "How this provider's credentials are sourced (R6: never in tool args)",
|
|
17
|
-
"required": [
|
|
29
|
+
"required": [
|
|
30
|
+
"source"
|
|
31
|
+
],
|
|
18
32
|
"properties": {
|
|
19
33
|
"source": {
|
|
20
|
-
"enum": [
|
|
34
|
+
"enum": [
|
|
35
|
+
"env",
|
|
36
|
+
"cli-profile",
|
|
37
|
+
"file",
|
|
38
|
+
"instance-metadata"
|
|
39
|
+
],
|
|
21
40
|
"description": "Credential resolution mechanism"
|
|
22
41
|
},
|
|
23
42
|
"envVars": {
|
|
24
43
|
"type": "array",
|
|
25
|
-
"items": {
|
|
44
|
+
"items": {
|
|
45
|
+
"type": "string"
|
|
46
|
+
},
|
|
26
47
|
"description": "Environment variables checked at startup (e.g., AWS_PROFILE)"
|
|
27
48
|
},
|
|
28
49
|
"profileName": {
|
|
@@ -37,7 +58,9 @@
|
|
|
37
58
|
},
|
|
38
59
|
"regions": {
|
|
39
60
|
"type": "array",
|
|
40
|
-
"items": {
|
|
61
|
+
"items": {
|
|
62
|
+
"type": "string"
|
|
63
|
+
},
|
|
41
64
|
"minItems": 1,
|
|
42
65
|
"description": "Region IDs supported by this adapter (e.g., us-east-1, us-central1, eastus)"
|
|
43
66
|
},
|
|
@@ -47,28 +70,59 @@
|
|
|
47
70
|
"description": "Mapping from clawops aliases to provider-native instance types",
|
|
48
71
|
"items": {
|
|
49
72
|
"type": "object",
|
|
50
|
-
"required": [
|
|
73
|
+
"required": [
|
|
74
|
+
"alias",
|
|
75
|
+
"nativeId",
|
|
76
|
+
"vcpu",
|
|
77
|
+
"memoryGB",
|
|
78
|
+
"arch"
|
|
79
|
+
],
|
|
51
80
|
"properties": {
|
|
52
81
|
"alias": {
|
|
53
|
-
"enum": [
|
|
82
|
+
"enum": [
|
|
83
|
+
"micro",
|
|
84
|
+
"small",
|
|
85
|
+
"medium",
|
|
86
|
+
"large",
|
|
87
|
+
"gpu"
|
|
88
|
+
],
|
|
54
89
|
"description": "Normalized clawops alias"
|
|
55
90
|
},
|
|
56
91
|
"nativeId": {
|
|
57
92
|
"type": "string",
|
|
58
93
|
"description": "Provider-native instance type (e.g., t3.small, e2-small, Standard_B2s)"
|
|
59
94
|
},
|
|
60
|
-
"vcpu": {
|
|
61
|
-
|
|
62
|
-
|
|
95
|
+
"vcpu": {
|
|
96
|
+
"type": "number",
|
|
97
|
+
"minimum": 1
|
|
98
|
+
},
|
|
99
|
+
"memoryGB": {
|
|
100
|
+
"type": "number",
|
|
101
|
+
"minimum": 0.5
|
|
102
|
+
},
|
|
103
|
+
"arch": {
|
|
104
|
+
"enum": [
|
|
105
|
+
"x86_64",
|
|
106
|
+
"arm64"
|
|
107
|
+
]
|
|
108
|
+
}
|
|
63
109
|
}
|
|
64
110
|
}
|
|
65
111
|
},
|
|
66
112
|
"stateBackend": {
|
|
67
113
|
"type": "object",
|
|
68
|
-
"required": [
|
|
114
|
+
"required": [
|
|
115
|
+
"scheme",
|
|
116
|
+
"urlPattern"
|
|
117
|
+
],
|
|
69
118
|
"properties": {
|
|
70
119
|
"scheme": {
|
|
71
|
-
"enum": [
|
|
120
|
+
"enum": [
|
|
121
|
+
"s3",
|
|
122
|
+
"gs",
|
|
123
|
+
"azblob",
|
|
124
|
+
"file"
|
|
125
|
+
],
|
|
72
126
|
"description": "Pulumi state backend URL scheme"
|
|
73
127
|
},
|
|
74
128
|
"urlPattern": {
|
|
@@ -79,41 +133,122 @@
|
|
|
79
133
|
},
|
|
80
134
|
"operations": {
|
|
81
135
|
"type": "object",
|
|
82
|
-
"required": [
|
|
136
|
+
"required": [
|
|
137
|
+
"provision",
|
|
138
|
+
"destroy",
|
|
139
|
+
"describe"
|
|
140
|
+
],
|
|
83
141
|
"description": "Lifecycle operations every adapter must implement",
|
|
84
142
|
"properties": {
|
|
85
|
-
"provision": {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"
|
|
143
|
+
"provision": {
|
|
144
|
+
"$ref": "#/$defs/Operation"
|
|
145
|
+
},
|
|
146
|
+
"destroy": {
|
|
147
|
+
"$ref": "#/$defs/Operation"
|
|
148
|
+
},
|
|
149
|
+
"describe": {
|
|
150
|
+
"$ref": "#/$defs/Operation"
|
|
151
|
+
},
|
|
152
|
+
"refresh": {
|
|
153
|
+
"$ref": "#/$defs/Operation"
|
|
154
|
+
}
|
|
89
155
|
}
|
|
90
156
|
},
|
|
91
157
|
"supportedOpenclawVersions": {
|
|
92
158
|
"type": "object",
|
|
93
159
|
"properties": {
|
|
94
|
-
"min": {
|
|
95
|
-
|
|
96
|
-
|
|
160
|
+
"min": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"description": "semver, e.g., 2026.4.5"
|
|
163
|
+
},
|
|
164
|
+
"max": {
|
|
165
|
+
"type": "string"
|
|
166
|
+
},
|
|
167
|
+
"tested": {
|
|
168
|
+
"type": "array",
|
|
169
|
+
"items": {
|
|
170
|
+
"type": "string"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"preflight": {
|
|
176
|
+
"type": "object",
|
|
177
|
+
"description": "Account-level setup a provider needs before anything can be provisioned, and which clawops can detect and offer to fix. These are not infrastructure \u2014 enabling an API or creating a state bucket happens outside the Pulumi program, because the state backend must exist before Pulumi can run at all. Detected in `doctor`; the setup wizard PROMPTS before changing anything in someone's cloud account.",
|
|
178
|
+
"required": [
|
|
179
|
+
"checks"
|
|
180
|
+
],
|
|
181
|
+
"properties": {
|
|
182
|
+
"checks": {
|
|
183
|
+
"type": "array",
|
|
184
|
+
"description": "What must be true before a first deploy.",
|
|
185
|
+
"items": {
|
|
186
|
+
"$ref": "#/$defs/PreflightCheck"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
97
189
|
}
|
|
98
190
|
}
|
|
99
191
|
},
|
|
100
192
|
"$defs": {
|
|
101
193
|
"Operation": {
|
|
102
194
|
"type": "object",
|
|
103
|
-
"required": [
|
|
195
|
+
"required": [
|
|
196
|
+
"estimatedDurationSec",
|
|
197
|
+
"idempotent",
|
|
198
|
+
"destructive"
|
|
199
|
+
],
|
|
104
200
|
"properties": {
|
|
105
201
|
"estimatedDurationSec": {
|
|
106
202
|
"type": "object",
|
|
107
203
|
"properties": {
|
|
108
|
-
"min": {
|
|
109
|
-
|
|
110
|
-
|
|
204
|
+
"min": {
|
|
205
|
+
"type": "number"
|
|
206
|
+
},
|
|
207
|
+
"max": {
|
|
208
|
+
"type": "number"
|
|
209
|
+
},
|
|
210
|
+
"median": {
|
|
211
|
+
"type": "number"
|
|
212
|
+
}
|
|
111
213
|
},
|
|
112
214
|
"description": "Used by R12 to pick streaming tier (sync / progress / Tasks)"
|
|
113
215
|
},
|
|
114
|
-
"idempotent": {
|
|
115
|
-
|
|
116
|
-
|
|
216
|
+
"idempotent": {
|
|
217
|
+
"type": "boolean"
|
|
218
|
+
},
|
|
219
|
+
"destructive": {
|
|
220
|
+
"type": "boolean"
|
|
221
|
+
},
|
|
222
|
+
"supportsCancellation": {
|
|
223
|
+
"type": "boolean",
|
|
224
|
+
"default": true
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"PreflightCheck": {
|
|
229
|
+
"type": "object",
|
|
230
|
+
"required": [
|
|
231
|
+
"id",
|
|
232
|
+
"label",
|
|
233
|
+
"remediable"
|
|
234
|
+
],
|
|
235
|
+
"properties": {
|
|
236
|
+
"id": {
|
|
237
|
+
"type": "string",
|
|
238
|
+
"description": "Stable kebab-case id, e.g. `compute-api-enabled`"
|
|
239
|
+
},
|
|
240
|
+
"label": {
|
|
241
|
+
"type": "string",
|
|
242
|
+
"description": "What is being checked, in the operator's terms"
|
|
243
|
+
},
|
|
244
|
+
"remediable": {
|
|
245
|
+
"type": "boolean",
|
|
246
|
+
"description": "Whether clawops can fix it after asking. False means it can only be reported \u2014 a missing permission or an unpaid billing account is not clawops's to resolve."
|
|
247
|
+
},
|
|
248
|
+
"mutates": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"description": "What the fix changes in the operator's account, shown in the prompt. Required when remediable is true: consent to 'fix it' is not consent to something unnamed."
|
|
251
|
+
}
|
|
117
252
|
}
|
|
118
253
|
}
|
|
119
254
|
}
|
package/dist/apply-AM5HERE7.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
applyPlan
|
|
4
|
-
} from "./chunk-UFRO4H5W.js";
|
|
5
|
-
import "./chunk-N44K3LHE.js";
|
|
6
|
-
import "./chunk-YR3O2I3S.js";
|
|
7
|
-
import "./chunk-6ZFIFDBJ.js";
|
|
8
|
-
import "./chunk-BOPSG2LI.js";
|
|
9
|
-
import "./chunk-LU2V3LXA.js";
|
|
10
|
-
import "./chunk-NUDIHZEH.js";
|
|
11
|
-
import "./chunk-JW5A7E3X.js";
|
|
12
|
-
import "./chunk-A2I76FTA.js";
|
|
13
|
-
import "./chunk-CX5SL5HP.js";
|
|
14
|
-
import "./chunk-KGXPLI7W.js";
|
|
15
|
-
import "./chunk-6TIYVHPX.js";
|
|
16
|
-
import "./chunk-EI7CQQ7D.js";
|
|
17
|
-
export {
|
|
18
|
-
applyPlan
|
|
19
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
getConfigDir
|
|
4
|
-
} from "./chunk-CX5SL5HP.js";
|
|
5
|
-
import "./chunk-KGXPLI7W.js";
|
|
6
|
-
|
|
7
|
-
// src/pulumi/automation.ts
|
|
8
|
-
import path from "path";
|
|
9
|
-
import { LocalWorkspace } from "@pulumi/pulumi/automation";
|
|
10
|
-
async function getOrCreateStack(opts) {
|
|
11
|
-
const configDir = opts.configDir ?? getConfigDir();
|
|
12
|
-
return await LocalWorkspace.createOrSelectStack(
|
|
13
|
-
{
|
|
14
|
-
stackName: opts.stack,
|
|
15
|
-
projectName: "clawops",
|
|
16
|
-
program: opts.program
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
pulumiHome: path.join(configDir, ".pulumi"),
|
|
20
|
-
envVars: {
|
|
21
|
-
PULUMI_BACKEND_URL: opts.stateUrl,
|
|
22
|
-
PULUMI_SKIP_UPDATE_CHECK: "1"
|
|
23
|
-
// R6: cloud credentials inherited from process.env, never set here
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
export {
|
|
29
|
-
getOrCreateStack
|
|
30
|
-
};
|
package/dist/aws-AMON7DA7.js
DELETED
|
@@ -1,265 +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/aws/index.ts
|
|
11
|
-
import process2 from "process";
|
|
12
|
-
|
|
13
|
-
// src/providers/aws/program.ts
|
|
14
|
-
var SSH_PORT = 22;
|
|
15
|
-
var awsProgram = async () => {
|
|
16
|
-
const [pulumi, aws, { resolveIngressCidrs, resolveGatewayIngressCidrs, resolveGatewayPort, detectEgressIp }] = await Promise.all([
|
|
17
|
-
import("@pulumi/pulumi"),
|
|
18
|
-
import("@pulumi/aws"),
|
|
19
|
-
import("./firewall-T3NTPZJD.js")
|
|
20
|
-
]);
|
|
21
|
-
const cfg = new pulumi.Config();
|
|
22
|
-
const instanceType = cfg.get("instanceType") ?? "t3.small";
|
|
23
|
-
const region = cfg.get("region") ?? "us-east-1";
|
|
24
|
-
const openclawVersion = cfg.get("openclawVersion") ?? "latest";
|
|
25
|
-
const publishGateway = cfg.get("publishGateway") === "all" ? "all" : "loopback";
|
|
26
|
-
const gatewayPort = resolveGatewayPort(cfg.get("gatewayPort"), GATEWAY_PORT);
|
|
27
|
-
const accessMode = cfg.get("accessMode") ?? "restricted";
|
|
28
|
-
const allowedCidrs = cfg.get("allowedCidrs") ?? "";
|
|
29
|
-
const sshCidrs = cfg.get("sshCidrs") ?? "";
|
|
30
|
-
const gatewayCidrs = cfg.get("gatewayCidrs") ?? "";
|
|
31
|
-
const bedrockEnabled = cfg.get("bedrockEnabled") === "true";
|
|
32
|
-
const pinnedAmiId = cfg.get("amiId");
|
|
33
|
-
const sshPublicKey = cfg.get("sshPublicKey");
|
|
34
|
-
if (!sshPublicKey) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
'Stack config "sshPublicKey" is required for the AWS adapter. Set it with: pulumi config set --stack <name> sshPublicKey "ssh-ed25519 ..."'
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
const egressResult = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : { ok: true, ip: "" };
|
|
40
|
-
if (accessMode === "open") {
|
|
41
|
-
process.stderr.write(
|
|
42
|
-
"[clawops] WARNING: accessMode=open allows 0.0.0.0/0 on SSH and gateway ports. Only use this for development/sandbox stacks.\n"
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
|
|
46
|
-
const gatewayIngressCidrs = resolveGatewayIngressCidrs(
|
|
47
|
-
publishGateway,
|
|
48
|
-
accessMode,
|
|
49
|
-
allowedCidrs,
|
|
50
|
-
gatewayCidrs,
|
|
51
|
-
egressResult
|
|
52
|
-
);
|
|
53
|
-
const vpc = new aws.ec2.Vpc("clawops-vpc", {
|
|
54
|
-
cidrBlock: "10.0.0.0/16",
|
|
55
|
-
enableDnsHostnames: true,
|
|
56
|
-
enableDnsSupport: true,
|
|
57
|
-
tags: { Name: "clawops" }
|
|
58
|
-
});
|
|
59
|
-
const igw = new aws.ec2.InternetGateway("clawops-igw", {
|
|
60
|
-
tags: { Name: "clawops" }
|
|
61
|
-
});
|
|
62
|
-
new aws.ec2.InternetGatewayAttachment("clawops-igw-attach", {
|
|
63
|
-
vpcId: vpc.id,
|
|
64
|
-
internetGatewayId: igw.id
|
|
65
|
-
});
|
|
66
|
-
const subnet = new aws.ec2.Subnet("clawops-subnet", {
|
|
67
|
-
vpcId: vpc.id,
|
|
68
|
-
cidrBlock: "10.0.1.0/24",
|
|
69
|
-
mapPublicIpOnLaunch: false,
|
|
70
|
-
availabilityZone: pulumi.interpolate`${region}a`,
|
|
71
|
-
tags: { Name: "clawops" }
|
|
72
|
-
});
|
|
73
|
-
const routeTable = new aws.ec2.RouteTable("clawops-rt", {
|
|
74
|
-
vpcId: vpc.id,
|
|
75
|
-
tags: { Name: "clawops" }
|
|
76
|
-
});
|
|
77
|
-
new aws.ec2.Route("clawops-route", {
|
|
78
|
-
routeTableId: routeTable.id,
|
|
79
|
-
destinationCidrBlock: "0.0.0.0/0",
|
|
80
|
-
gatewayId: igw.id
|
|
81
|
-
});
|
|
82
|
-
new aws.ec2.RouteTableAssociation("clawops-rta", {
|
|
83
|
-
subnetId: subnet.id,
|
|
84
|
-
routeTableId: routeTable.id
|
|
85
|
-
});
|
|
86
|
-
const sg = new aws.ec2.SecurityGroup("clawops-sg", {
|
|
87
|
-
vpcId: vpc.id,
|
|
88
|
-
description: "clawops managed security group",
|
|
89
|
-
tags: { Name: "clawops" }
|
|
90
|
-
});
|
|
91
|
-
sshIngressCidrs.forEach((cidr, i) => {
|
|
92
|
-
new aws.vpc.SecurityGroupIngressRule(`clawops-sg-ssh-${i}`, {
|
|
93
|
-
securityGroupId: sg.id,
|
|
94
|
-
ipProtocol: "tcp",
|
|
95
|
-
fromPort: SSH_PORT,
|
|
96
|
-
toPort: SSH_PORT,
|
|
97
|
-
cidrIpv4: cidr,
|
|
98
|
-
tags: { Name: `clawops-ssh-${i}` }
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
gatewayIngressCidrs.forEach((cidr, i) => {
|
|
102
|
-
new aws.vpc.SecurityGroupIngressRule(`clawops-sg-gw-${i}`, {
|
|
103
|
-
securityGroupId: sg.id,
|
|
104
|
-
ipProtocol: "tcp",
|
|
105
|
-
fromPort: gatewayPort,
|
|
106
|
-
toPort: gatewayPort,
|
|
107
|
-
cidrIpv4: cidr,
|
|
108
|
-
tags: { Name: `clawops-gateway-${i}` }
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
new aws.vpc.SecurityGroupEgressRule("clawops-sg-egress", {
|
|
112
|
-
securityGroupId: sg.id,
|
|
113
|
-
ipProtocol: "-1",
|
|
114
|
-
cidrIpv4: "0.0.0.0/0",
|
|
115
|
-
tags: { Name: "clawops-egress" }
|
|
116
|
-
});
|
|
117
|
-
const role = new aws.iam.Role("clawops-role", {
|
|
118
|
-
assumeRolePolicy: JSON.stringify({
|
|
119
|
-
Version: "2012-10-17",
|
|
120
|
-
Statement: [{
|
|
121
|
-
Effect: "Allow",
|
|
122
|
-
Principal: { Service: "ec2.amazonaws.com" },
|
|
123
|
-
Action: "sts:AssumeRole"
|
|
124
|
-
}]
|
|
125
|
-
}),
|
|
126
|
-
tags: { Name: "clawops" }
|
|
127
|
-
});
|
|
128
|
-
new aws.iam.RolePolicyAttachment("clawops-ssm", {
|
|
129
|
-
role: role.name,
|
|
130
|
-
policyArn: "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
|
|
131
|
-
});
|
|
132
|
-
if (bedrockEnabled) {
|
|
133
|
-
new aws.iam.RolePolicy("clawops-bedrock-invoke", {
|
|
134
|
-
role: role.name,
|
|
135
|
-
policy: JSON.stringify({
|
|
136
|
-
Version: "2012-10-17",
|
|
137
|
-
Statement: [{
|
|
138
|
-
Effect: "Allow",
|
|
139
|
-
Action: [
|
|
140
|
-
"bedrock:InvokeModel",
|
|
141
|
-
"bedrock:InvokeModelWithResponseStream"
|
|
142
|
-
],
|
|
143
|
-
Resource: "*"
|
|
144
|
-
}]
|
|
145
|
-
})
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
const instanceProfile = new aws.iam.InstanceProfile("clawops-profile", {
|
|
149
|
-
role: role.name
|
|
150
|
-
});
|
|
151
|
-
const keyPair = new aws.ec2.KeyPair("clawops-keypair", {
|
|
152
|
-
publicKey: sshPublicKey,
|
|
153
|
-
tags: { Name: "clawops" }
|
|
154
|
-
});
|
|
155
|
-
const amiId = pinnedAmiId ?? (await aws.ec2.getAmi({
|
|
156
|
-
mostRecent: true,
|
|
157
|
-
owners: ["099720109477"],
|
|
158
|
-
// Canonical
|
|
159
|
-
filters: [
|
|
160
|
-
{ name: "name", values: ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] },
|
|
161
|
-
{ name: "virtualization-type", values: ["hvm"] }
|
|
162
|
-
]
|
|
163
|
-
})).id;
|
|
164
|
-
process.stderr.write(`[clawops] Using AMI: ${amiId}
|
|
165
|
-
`);
|
|
166
|
-
const instance = new aws.ec2.Instance("clawops-instance", {
|
|
167
|
-
ami: amiId,
|
|
168
|
-
instanceType,
|
|
169
|
-
subnetId: subnet.id,
|
|
170
|
-
vpcSecurityGroupIds: [sg.id],
|
|
171
|
-
iamInstanceProfile: instanceProfile.name,
|
|
172
|
-
keyName: keyPair.keyName,
|
|
173
|
-
userData: makeStartupScript({ openclawVersion, os: "ubuntu", bedrockEnabled, publishGateway, gatewayPort }),
|
|
174
|
-
// IMDSv2 with hopLimit=2 so Docker containers on this host can reach IMDS
|
|
175
|
-
// and obtain the instance role credentials (required for Bedrock access).
|
|
176
|
-
metadataOptions: {
|
|
177
|
-
httpTokens: "required",
|
|
178
|
-
httpPutResponseHopLimit: 2
|
|
179
|
-
},
|
|
180
|
-
tags: { Name: "clawops" }
|
|
181
|
-
});
|
|
182
|
-
const eip = new aws.ec2.Eip("clawops-eip", {
|
|
183
|
-
domain: "vpc",
|
|
184
|
-
tags: { Name: "clawops" }
|
|
185
|
-
});
|
|
186
|
-
new aws.ec2.EipAssociation("clawops-eip-assoc", {
|
|
187
|
-
instanceId: instance.id,
|
|
188
|
-
allocationId: eip.id
|
|
189
|
-
});
|
|
190
|
-
return {
|
|
191
|
-
instanceId: instance.id,
|
|
192
|
-
publicIp: eip.publicIp,
|
|
193
|
-
gatewayUrl: pulumi.interpolate`https://${eip.publicIp}:${gatewayPort}`,
|
|
194
|
-
sshHost: eip.publicIp,
|
|
195
|
-
sshPort: SSH_PORT,
|
|
196
|
-
sshUser: "ubuntu",
|
|
197
|
-
region,
|
|
198
|
-
provisionedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
199
|
-
};
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
// src/providers/aws/index.ts
|
|
203
|
-
var INSTANCE_TYPE_MAP = {
|
|
204
|
-
micro: "t3.micro",
|
|
205
|
-
small: "t3.small",
|
|
206
|
-
medium: "t3.medium",
|
|
207
|
-
large: "t3.large",
|
|
208
|
-
gpu: "g4dn.xlarge"
|
|
209
|
-
};
|
|
210
|
-
var awsAdapter = {
|
|
211
|
-
name: "aws",
|
|
212
|
-
get program() {
|
|
213
|
-
return awsProgram;
|
|
214
|
-
},
|
|
215
|
-
getConnectionInfo(outputs) {
|
|
216
|
-
return {
|
|
217
|
-
host: String(outputs["sshHost"] ?? ""),
|
|
218
|
-
port: Number(outputs["sshPort"] ?? 22),
|
|
219
|
-
user: String(outputs["sshUser"] ?? "ubuntu"),
|
|
220
|
-
privateKeyPath: String(outputs["privateKeyPath"] ?? ""),
|
|
221
|
-
knownHostsPath: String(outputs["knownHostsPath"] ?? "")
|
|
222
|
-
};
|
|
223
|
-
},
|
|
224
|
-
normalizeInstanceType(alias) {
|
|
225
|
-
const mapped = INSTANCE_TYPE_MAP[alias];
|
|
226
|
-
if (!mapped) throw new Error(`Unknown instance alias: ${alias}`);
|
|
227
|
-
return mapped;
|
|
228
|
-
},
|
|
229
|
-
defaultRegion() {
|
|
230
|
-
return "us-east-1";
|
|
231
|
-
},
|
|
232
|
-
stateBackendUrl(bucket) {
|
|
233
|
-
return `s3://${bucket}`;
|
|
234
|
-
},
|
|
235
|
-
async validateConfig() {
|
|
236
|
-
const errors = [];
|
|
237
|
-
const hasProfile = Boolean(process2.env["AWS_PROFILE"]);
|
|
238
|
-
const hasKeyId = Boolean(process2.env["AWS_ACCESS_KEY_ID"]);
|
|
239
|
-
const hasOidc = Boolean(process2.env["AWS_ROLE_ARN"] && process2.env["AWS_WEB_IDENTITY_TOKEN_FILE"]);
|
|
240
|
-
if (!hasProfile && !hasKeyId && !hasOidc) {
|
|
241
|
-
const onAws = await checkImds();
|
|
242
|
-
if (!onAws) {
|
|
243
|
-
errors.push(
|
|
244
|
-
"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."
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return { ok: errors.length === 0, errors };
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
async function checkImds() {
|
|
252
|
-
try {
|
|
253
|
-
const res = await fetch(
|
|
254
|
-
"http://169.254.169.254/latest/meta-data/instance-id",
|
|
255
|
-
{ signal: AbortSignal.timeout(1e3) }
|
|
256
|
-
);
|
|
257
|
-
return res.ok;
|
|
258
|
-
} catch {
|
|
259
|
-
return false;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
var aws_default = awsAdapter;
|
|
263
|
-
export {
|
|
264
|
-
aws_default as default
|
|
265
|
-
};
|