@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.
Files changed (75) hide show
  1. package/README.md +98 -12
  2. package/dist/apply-KYFPWI5U.js +27 -0
  3. package/dist/automation-RMAIBNVC.js +44 -0
  4. package/dist/bedrock-XVASJX2K.js +61 -0
  5. package/dist/{bootstrap-DMRPWJGN.js → bootstrap-HNGKY6WW.js} +11 -8
  6. package/dist/{chunk-N44K3LHE.js → chunk-2I7KCMXZ.js} +6 -4
  7. package/dist/{chunk-3WYA2QDM.js → chunk-2Z7J3ERQ.js} +1 -1
  8. package/dist/chunk-3OLUJPCB.js +36 -0
  9. package/dist/chunk-5XT5IAJK.js +69 -0
  10. package/dist/chunk-AEEMRFZV.js +24 -0
  11. package/dist/{chunk-YR3O2I3S.js → chunk-BSLIYB5Q.js} +6 -1
  12. package/dist/{chunk-AHAAEXWC.js → chunk-E4NJSJ54.js} +16 -93
  13. package/dist/chunk-FEK7VJAY.js +16 -0
  14. package/dist/{chunk-6TIYVHPX.js → chunk-GIEVAGEK.js} +7 -33
  15. package/dist/chunk-HSPHXG6W.js +67 -0
  16. package/dist/{chunk-GYV4KNW7.js → chunk-IVWP4QUJ.js} +133 -40
  17. package/dist/{chunk-AX74VXTV.js → chunk-KC3GC3PE.js} +58 -49
  18. package/dist/{chunk-UFRO4H5W.js → chunk-LBE6COC4.js} +56 -40
  19. package/dist/chunk-LEVIW2PV.js +890 -0
  20. package/dist/chunk-MC5ATCXS.js +108 -0
  21. package/dist/chunk-N4WZLWJ4.js +16 -0
  22. package/dist/{chunk-SBLQH2TJ.js → chunk-NUL5F6YV.js} +1 -1
  23. package/dist/chunk-RHOWYIWT.js +52 -0
  24. package/dist/{chunk-WHJMKDV7.js → chunk-STLRHLLV.js} +65 -12
  25. package/dist/chunk-V25QRZRB.js +45 -0
  26. package/dist/chunk-VOEJYRIK.js +33 -0
  27. package/dist/{providers-2OABPW2E.js → chunk-VUFMZEIM.js} +3 -2
  28. package/dist/chunk-W3OLNNJW.js +51 -0
  29. package/dist/cli-WLD3EBEM.js +11 -0
  30. package/dist/cli-auth-GD5SK7JU.js +13 -0
  31. package/dist/cli.js +518 -206
  32. package/dist/context-7EVC6W45.js +20 -0
  33. package/dist/docker-3PDO4TS7.js +12 -0
  34. package/dist/{firewall-T3NTPZJD.js → firewall-5VKZ4WBH.js} +22 -1
  35. package/dist/generate-I6YQ5V2T.js +29 -0
  36. package/dist/{harden-PCDK3UQ5.js → harden-72JMRT4E.js} +8 -5
  37. package/dist/index.d.ts +56 -0
  38. package/dist/known-hosts-file-I3Q3NBYQ.js +22 -0
  39. package/dist/{logs-P7YCKVF4.js → logs-5A7YYA53.js} +1 -1
  40. package/dist/{mcp-wire-BFEY2Y6H.js → mcp-wire-3SWBM7D6.js} +25 -15
  41. package/dist/models-AGTQWYDL.js +32 -0
  42. package/dist/network-args-PYJRJBYO.js +64 -0
  43. package/dist/{package-3HUW57XH.js → package-5BCMEBTE.js} +10 -3
  44. package/dist/passphrase-MJBE45N7.js +15 -0
  45. package/dist/{pool-EX4ZTA5P.js → pool-PIIKJ4L2.js} +3 -2
  46. package/dist/preflight-EF52S3WW.js +162 -0
  47. package/dist/preflight-MWWM5JT3.js +181 -0
  48. package/dist/preflight-TFD4N5ZU.js +141 -0
  49. package/dist/providers-FW6H6OPF.js +11 -0
  50. package/dist/ready-KDNRBNSU.js +95 -0
  51. package/dist/{remote-config-Z6IIZR3D.js → remote-config-3HZLUWEA.js} +3 -2
  52. package/dist/{runtime-LZ7NA53V.js → runtime-X3KW5TCP.js} +4 -2
  53. package/dist/server-GBA7BJGK.js +46 -0
  54. package/dist/ssh-VAI5DU5M.js +11 -0
  55. package/dist/ssh-key-DUO6OKOI.js +7 -0
  56. package/dist/stack-config-R4SPSUQZ.js +12 -0
  57. package/dist/{validate-BOQRWX4F.js → validate-YVI3BJ55.js} +1 -1
  58. package/dist/wait-WO72TRRQ.js +79 -0
  59. package/package.json +10 -3
  60. package/spec/mcp-tools.yaml +21 -2
  61. package/spec/models.yaml +14 -3
  62. package/spec/providers.schema.json +163 -28
  63. package/dist/apply-AM5HERE7.js +0 -19
  64. package/dist/automation-RULUSJBW.js +0 -30
  65. package/dist/aws-AMON7DA7.js +0 -265
  66. package/dist/azure-T4G6OBJQ.js +0 -273
  67. package/dist/chunk-CKSPROD5.js +0 -129
  68. package/dist/chunk-LU2V3LXA.js +0 -114
  69. package/dist/context-KHKWJJMC.js +0 -10
  70. package/dist/gcp-2JBTD7ZM.js +0 -204
  71. package/dist/generate-2XV2GSP2.js +0 -15
  72. package/dist/local-DXBEVZ5C.js +0 -47
  73. package/dist/server-A5AB67GQ.js +0 -36
  74. package/dist/ssh-B3NZAU4I.js +0 -8
  75. package/dist/{version-guard-GPSTCPT7.js → version-guard-XVYW5WFJ.js} +1 -1
@@ -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: enum
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
- # No API key — uses EC2 instance role (AmazonBedrockFullAccess) via IMDS.
64
- # The Pulumi program attaches AmazonBedrockFullAccess to the instance profile
65
- # and passes AWS_PROFILE=default into the container via --env-file.
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": ["name", "credentials", "regions", "instanceTypes", "stateBackend", "operations"],
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": ["aws", "gcp", "azure", "local"],
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": ["source"],
29
+ "required": [
30
+ "source"
31
+ ],
18
32
  "properties": {
19
33
  "source": {
20
- "enum": ["env", "cli-profile", "file", "instance-metadata"],
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": { "type": "string" },
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": { "type": "string" },
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": ["alias", "nativeId", "vcpu", "memoryGB", "arch"],
73
+ "required": [
74
+ "alias",
75
+ "nativeId",
76
+ "vcpu",
77
+ "memoryGB",
78
+ "arch"
79
+ ],
51
80
  "properties": {
52
81
  "alias": {
53
- "enum": ["micro", "small", "medium", "large", "gpu"],
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": { "type": "number", "minimum": 1 },
61
- "memoryGB": { "type": "number", "minimum": 0.5 },
62
- "arch": { "enum": ["x86_64", "arm64"] }
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": ["scheme", "urlPattern"],
114
+ "required": [
115
+ "scheme",
116
+ "urlPattern"
117
+ ],
69
118
  "properties": {
70
119
  "scheme": {
71
- "enum": ["s3", "gs", "azblob", "file"],
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": ["provision", "destroy", "describe"],
136
+ "required": [
137
+ "provision",
138
+ "destroy",
139
+ "describe"
140
+ ],
83
141
  "description": "Lifecycle operations every adapter must implement",
84
142
  "properties": {
85
- "provision": { "$ref": "#/$defs/Operation" },
86
- "destroy": { "$ref": "#/$defs/Operation" },
87
- "describe": { "$ref": "#/$defs/Operation" },
88
- "refresh": { "$ref": "#/$defs/Operation" }
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": { "type": "string", "description": "semver, e.g., 2026.4.5" },
95
- "max": { "type": "string" },
96
- "tested": { "type": "array", "items": { "type": "string" } }
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": ["estimatedDurationSec", "idempotent", "destructive"],
195
+ "required": [
196
+ "estimatedDurationSec",
197
+ "idempotent",
198
+ "destructive"
199
+ ],
104
200
  "properties": {
105
201
  "estimatedDurationSec": {
106
202
  "type": "object",
107
203
  "properties": {
108
- "min": { "type": "number" },
109
- "max": { "type": "number" },
110
- "median": { "type": "number" }
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": { "type": "boolean" },
115
- "destructive": { "type": "boolean" },
116
- "supportsCancellation": { "type": "boolean", "default": true }
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
  }
@@ -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
- };
@@ -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
- };