@clawops/cli 1.5.0 → 1.6.0

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 CHANGED
@@ -277,6 +277,7 @@ clawops down --yes # Destroy local-provider stack
277
277
  | `mcp install` | Interactively wire clawops into AI editors |
278
278
  | `mcp wire` | Wire the gateway's AI as an MCP client of clawops |
279
279
  | `help` | List all commands and global flags |
280
+ | `bug` | Open a pre-filled GitHub issue with system context from `doctor` |
280
281
 
281
282
  Full flag reference: `clawops <command> --help`
282
283
 
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  applyPlan
4
- } from "./chunk-ZONXY3C6.js";
4
+ } from "./chunk-QHGFENYR.js";
5
5
  import "./chunk-YTH4L2GN.js";
6
6
  import "./chunk-6ZFIFDBJ.js";
7
7
  import "./chunk-BOPSG2LI.js";
8
- import "./chunk-T5EX55GP.js";
8
+ import "./chunk-QI75OVJK.js";
9
9
  import "./chunk-ZFNPM2WG.js";
10
10
  import "./chunk-A2I76FTA.js";
11
11
  import "./chunk-CX5SL5HP.js";
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ makeStartupScript
4
+ } from "./chunk-XKT42M34.js";
2
5
 
3
6
  // src/providers/aws/index.ts
4
7
  import process2 from "process";
@@ -10,7 +13,7 @@ var awsProgram = async () => {
10
13
  const [pulumi, aws, { resolveIngressCidrs, detectEgressIp }] = await Promise.all([
11
14
  import("@pulumi/pulumi"),
12
15
  import("@pulumi/aws"),
13
- import("./firewall-YYDOWDDP.js")
16
+ import("./firewall-XQGO7HWK.js")
14
17
  ]);
15
18
  const cfg = new pulumi.Config();
16
19
  const instanceType = cfg.get("instanceType") ?? "t3.small";
@@ -21,20 +24,21 @@ var awsProgram = async () => {
21
24
  const sshCidrs = cfg.get("sshCidrs") ?? "";
22
25
  const gatewayCidrs = cfg.get("gatewayCidrs") ?? "";
23
26
  const bedrockEnabled = cfg.get("bedrockEnabled") === "true";
27
+ const pinnedAmiId = cfg.get("amiId");
24
28
  const sshPublicKey = cfg.get("sshPublicKey");
25
29
  if (!sshPublicKey) {
26
30
  throw new Error(
27
31
  'Stack config "sshPublicKey" is required for the AWS adapter. Set it with: pulumi config set --stack <name> sshPublicKey "ssh-ed25519 ..."'
28
32
  );
29
33
  }
30
- const detectedIp = accessMode === "auto" ? await detectEgressIp("https://checkip.amazonaws.com") : "";
34
+ const egressResult = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : { ok: true, ip: "" };
31
35
  if (accessMode === "open") {
32
36
  process.stderr.write(
33
37
  "[clawops] WARNING: accessMode=open allows 0.0.0.0/0 on SSH and gateway ports. Only use this for development/sandbox stacks.\n"
34
38
  );
35
39
  }
36
- const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, detectedIp);
37
- const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, detectedIp);
40
+ const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
41
+ const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, egressResult);
38
42
  const vpc = new aws.ec2.Vpc("clawops-vpc", {
39
43
  cidrBlock: "10.0.0.0/16",
40
44
  enableDnsHostnames: true,
@@ -68,33 +72,36 @@ var awsProgram = async () => {
68
72
  subnetId: subnet.id,
69
73
  routeTableId: routeTable.id
70
74
  });
71
- const ingressRules = [
72
- ...sshIngressCidrs.map((cidr) => ({
73
- protocol: "tcp",
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",
74
84
  fromPort: SSH_PORT,
75
85
  toPort: SSH_PORT,
76
- cidrBlocks: [cidr],
77
- description: "SSH"
78
- })),
79
- ...gatewayIngressCidrs.map((cidr) => ({
80
- protocol: "tcp",
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",
81
94
  fromPort: GATEWAY_PORT,
82
95
  toPort: GATEWAY_PORT,
83
- cidrBlocks: [cidr],
84
- description: "OpenClaw gateway"
85
- }))
86
- ];
87
- const sg = new aws.ec2.SecurityGroup("clawops-sg", {
88
- vpcId: vpc.id,
89
- ingress: ingressRules,
90
- egress: [{
91
- protocol: "-1",
92
- fromPort: 0,
93
- toPort: 0,
94
- cidrBlocks: ["0.0.0.0/0"],
95
- description: "Allow all egress"
96
- }],
97
- tags: { Name: "clawops" }
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" }
98
105
  });
99
106
  const role = new aws.iam.Role("clawops-role", {
100
107
  assumeRolePolicy: JSON.stringify({
@@ -112,10 +119,19 @@ var awsProgram = async () => {
112
119
  policyArn: "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
113
120
  });
114
121
  if (bedrockEnabled) {
115
- new aws.iam.RolePolicyAttachment("clawops-bedrock", {
122
+ new aws.iam.RolePolicy("clawops-bedrock-invoke", {
116
123
  role: role.name,
117
- // FullAccess required for bedrock:InvokeModel — ReadOnly only covers describe/list.
118
- policyArn: "arn:aws:iam::aws:policy/AmazonBedrockFullAccess"
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
+ })
119
135
  });
120
136
  }
121
137
  const instanceProfile = new aws.iam.InstanceProfile("clawops-profile", {
@@ -125,7 +141,7 @@ var awsProgram = async () => {
125
141
  publicKey: sshPublicKey,
126
142
  tags: { Name: "clawops" }
127
143
  });
128
- const ami = await aws.ec2.getAmi({
144
+ const amiId = pinnedAmiId ?? (await aws.ec2.getAmi({
129
145
  mostRecent: true,
130
146
  owners: ["099720109477"],
131
147
  // Canonical
@@ -133,15 +149,17 @@ var awsProgram = async () => {
133
149
  { name: "name", values: ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] },
134
150
  { name: "virtualization-type", values: ["hvm"] }
135
151
  ]
136
- });
152
+ })).id;
153
+ process.stderr.write(`[clawops] Using AMI: ${amiId}
154
+ `);
137
155
  const instance = new aws.ec2.Instance("clawops-instance", {
138
- ami: ami.id,
156
+ ami: amiId,
139
157
  instanceType,
140
158
  subnetId: subnet.id,
141
159
  vpcSecurityGroupIds: [sg.id],
142
160
  iamInstanceProfile: instanceProfile.name,
143
161
  keyName: keyPair.keyName,
144
- userData: makeStartupScript(openclawVersion, bedrockEnabled),
162
+ userData: makeStartupScript({ openclawVersion, os: "ubuntu", bedrockEnabled }),
145
163
  // IMDSv2 with hopLimit=2 so Docker containers on this host can reach IMDS
146
164
  // and obtain the instance role credentials (required for Bedrock access).
147
165
  metadataOptions: {
@@ -169,62 +187,6 @@ var awsProgram = async () => {
169
187
  provisionedAt: (/* @__PURE__ */ new Date()).toISOString()
170
188
  };
171
189
  };
172
- function makeStartupScript(openclawVersion, bedrockEnabled) {
173
- const bedrockEnvFlag = bedrockEnabled ? " -e AWS_DEFAULT_REGION=$(curl -sf http://169.254.169.254/latest/meta-data/placement/region || echo us-east-1) \\\n" : "";
174
- return `#!/bin/bash
175
- set -euo pipefail
176
-
177
- # Create clawops user with SSH access
178
- id -u clawops &>/dev/null || useradd -m -s /bin/bash clawops
179
- mkdir -p /home/clawops/.ssh
180
- chmod 700 /home/clawops/.ssh
181
- chown clawops:clawops /home/clawops/.ssh
182
-
183
- # Install Docker if not present (AWS AMI is ubuntu-22.04)
184
- if ! command -v docker &>/dev/null; then
185
- export DEBIAN_FRONTEND=noninteractive
186
- apt-get update -q
187
- apt-get install -y -q ca-certificates curl gnupg lsb-release
188
- install -m 0755 -d /etc/apt/keyrings
189
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg \\
190
- | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
191
- chmod a+r /etc/apt/keyrings/docker.gpg
192
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \\
193
- https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \\
194
- > /etc/apt/sources.list.d/docker.list
195
- apt-get update -q
196
- apt-get install -y -q docker-ce docker-ce-cli containerd.io
197
- systemctl enable --now docker
198
- fi
199
-
200
- usermod -aG docker clawops
201
-
202
- # Pull OpenClaw image
203
- OPENCLAW_VERSION="${openclawVersion}"
204
- docker pull ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION}
205
-
206
- # Create default openclaw.json if not present
207
- # apply.ts will overwrite this with the plan's config overlay post-provisioning.
208
- OPENCLAW_CONFIG=/home/clawops/openclaw.json
209
- if [ ! -f "\${OPENCLAW_CONFIG}" ]; then
210
- cat > "\${OPENCLAW_CONFIG}" <<'OPENCLAWJSON'
211
- {"meta":{"lastTouchedVersion":"2026.4"},"gateway":{"port":18789,"auth":{"mode":"token"}},"models":{},"channels":{}}
212
- OPENCLAWJSON
213
- chown clawops:clawops "\${OPENCLAW_CONFIG}"
214
- fi
215
-
216
- # Start OpenClaw container
217
- docker stop openclaw 2>/dev/null || true
218
- docker rm openclaw 2>/dev/null || true
219
- docker run -d \\
220
- --name openclaw \\
221
- --restart unless-stopped \\
222
- -p ${GATEWAY_PORT}:${GATEWAY_PORT} \\
223
- -v "\${OPENCLAW_CONFIG}":/app/config.json:ro \\
224
- ${bedrockEnvFlag} ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION} \\
225
- node openclaw.mjs gateway run --allow-unconfigured
226
- `;
227
- }
228
190
 
229
191
  // src/providers/aws/index.ts
230
192
  var INSTANCE_TYPE_MAP = {
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ makeStartupScript
4
+ } from "./chunk-XKT42M34.js";
2
5
 
3
6
  // src/providers/azure/index.ts
4
7
  import process2 from "process";
@@ -12,7 +15,7 @@ var azureProgram = async () => {
12
15
  import("@pulumi/pulumi"),
13
16
  import("@pulumi/azure-native"),
14
17
  import("@pulumi/random"),
15
- import("./firewall-YYDOWDDP.js")
18
+ import("./firewall-XQGO7HWK.js")
16
19
  ]);
17
20
  const cfg = new pulumi.Config();
18
21
  const stackName = pulumi.getStack();
@@ -31,14 +34,15 @@ var azureProgram = async () => {
31
34
  'Stack config "sshPublicKey" is required for the Azure adapter. Set it with: pulumi config set --stack <name> sshPublicKey "ssh-ed25519 ..."'
32
35
  );
33
36
  }
34
- const detectedIp = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : "";
37
+ const clientConfig = await azure.authorization.getClientConfig({});
38
+ const egressResult = accessMode === "auto" ? await detectEgressIp("https://ifconfig.me") : { ok: true, ip: "" };
35
39
  if (accessMode === "open") {
36
40
  process.stderr.write(
37
41
  "[clawops] WARNING: accessMode=open allows 0.0.0.0/0 on SSH and gateway ports. Only use this for development/sandbox stacks.\n"
38
42
  );
39
43
  }
40
- const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, detectedIp);
41
- const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, detectedIp);
44
+ const sshIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, sshCidrs, egressResult);
45
+ const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs, egressResult);
42
46
  const rg = new azure.resources.ResourceGroup("clawops-rg", {
43
47
  resourceGroupName,
44
48
  location
@@ -111,7 +115,7 @@ var azureProgram = async () => {
111
115
  osProfile: {
112
116
  adminUsername: "clawops",
113
117
  computerName: "clawops",
114
- customData: Buffer.from(makeStartupScript(openclawVersion)).toString("base64"),
118
+ customData: Buffer.from(makeStartupScript({ openclawVersion, os: "ubuntu" })).toString("base64"),
115
119
  linuxConfiguration: {
116
120
  disablePasswordAuthentication: true,
117
121
  ssh: {
@@ -125,8 +129,10 @@ var azureProgram = async () => {
125
129
  storageProfile: {
126
130
  imageReference: {
127
131
  publisher: "Canonical",
128
- offer: "UbuntuServer",
129
- sku: "22.04-LTS",
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",
130
136
  version: "latest"
131
137
  },
132
138
  osDisk: {
@@ -153,10 +159,10 @@ var azureProgram = async () => {
153
159
  enableRbacAuthorization: true
154
160
  }
155
161
  });
162
+ const kvSecretsUserRoleId = `/subscriptions/${clientConfig.subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6`;
156
163
  new azure.authorization.RoleAssignment("clawops-kv-role", {
157
164
  scope: kv.id,
158
- roleDefinitionId: "/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6",
159
- // Key Vault Secrets User
165
+ roleDefinitionId: kvSecretsUserRoleId,
160
166
  principalId: pulumi.output(vm.identity).apply((i) => i?.principalId ?? ""),
161
167
  principalType: "ServicePrincipal"
162
168
  });
@@ -183,53 +189,6 @@ var azureProgram = async () => {
183
189
  provisionedAt: (/* @__PURE__ */ new Date()).toISOString()
184
190
  };
185
191
  };
186
- function makeStartupScript(openclawVersion) {
187
- return `#!/bin/bash
188
- set -euo pipefail
189
-
190
- # Install Docker if not present
191
- if ! command -v docker &>/dev/null; then
192
- apt-get update -q
193
- apt-get install -y -q ca-certificates curl gnupg lsb-release
194
- install -m 0755 -d /etc/apt/keyrings
195
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg \\
196
- | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
197
- chmod a+r /etc/apt/keyrings/docker.gpg
198
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \\
199
- https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \\
200
- > /etc/apt/sources.list.d/docker.list
201
- apt-get update -q
202
- apt-get install -y -q docker-ce docker-ce-cli containerd.io
203
- systemctl enable --now docker
204
- fi
205
-
206
- usermod -aG docker clawops
207
-
208
- # Pull OpenClaw image
209
- OPENCLAW_VERSION="${openclawVersion}"
210
- docker pull ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION}
211
-
212
- # Create default openclaw.json if not present
213
- OPENCLAW_CONFIG=/home/clawops/openclaw.json
214
- if [ ! -f "\${OPENCLAW_CONFIG}" ]; then
215
- cat > "\${OPENCLAW_CONFIG}" <<'OPENCLAWJSON'
216
- {"meta":{"lastTouchedVersion":"2026.4"},"gateway":{"port":18789,"auth":{"mode":"token"}},"models":{},"channels":{}}
217
- OPENCLAWJSON
218
- chown clawops:clawops "\${OPENCLAW_CONFIG}"
219
- fi
220
-
221
- # Start OpenClaw container
222
- docker stop openclaw 2>/dev/null || true
223
- docker rm openclaw 2>/dev/null || true
224
- docker run -d \\
225
- --name openclaw \\
226
- --restart unless-stopped \\
227
- -p 18789:18789 \\
228
- -v "\${OPENCLAW_CONFIG}":/app/config.json:ro \\
229
- ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION} \\
230
- node openclaw.mjs gateway run --allow-unconfigured
231
- `;
232
- }
233
192
 
234
193
  // src/providers/azure/index.ts
235
194
  var INSTANCE_TYPE_MAP = {
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  acquireSession
4
- } from "./chunk-ZVOEQCNW.js";
5
- import "./chunk-4U3LTLWZ.js";
4
+ } from "./chunk-LCKD7L7X.js";
5
+ import "./chunk-GJEF6UQA.js";
6
6
  import {
7
7
  writeLocalState
8
8
  } from "./chunk-A2I76FTA.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-YTH4L2GN.js";
5
5
  import {
6
6
  buildContext
7
- } from "./chunk-T5EX55GP.js";
7
+ } from "./chunk-QI75OVJK.js";
8
8
  import {
9
9
  getConfig
10
10
  } from "./chunk-CX5SL5HP.js";
@@ -45,7 +45,7 @@ async function generatePlan(intent, _opts) {
45
45
  "plan/apply is not supported for the local provider. Use `clawops up` directly."
46
46
  );
47
47
  }
48
- const { version } = await import("./package-QLDA65A3.js");
48
+ const { version } = await import("./package-EW3FS257.js");
49
49
  const config = getConfig();
50
50
  const instanceType = intent.instanceType ?? "small";
51
51
  const openclawVersion = intent.openclawVersion ?? "latest";
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildContext
4
- } from "./chunk-T5EX55GP.js";
4
+ } from "./chunk-QI75OVJK.js";
5
5
  import {
6
6
  acquireSession,
7
7
  drainPool
8
- } from "./chunk-ZVOEQCNW.js";
8
+ } from "./chunk-LCKD7L7X.js";
9
9
  import {
10
10
  OPENCLAW_CONFIG,
11
11
  atomicWriteConfig,
@@ -154,7 +154,7 @@ function renderSnapshot(snap, opts) {
154
154
  return lines.join("\n");
155
155
  }
156
156
  async function probeEntries() {
157
- const { buildContext: buildContext2 } = await import("./context-PSGEX2D7.js");
157
+ const { buildContext: buildContext2 } = await import("./context-KPKBOWOP.js");
158
158
  const { getConfig } = await import("./store-SDUR52Z5.js");
159
159
  const config = getConfig();
160
160
  if (!config) return [];
@@ -381,8 +381,8 @@ var monitor_default = defineCommand({
381
381
  const tailLines = Math.max(1, parseInt(String(args.tail ?? "10"), 10) || 10);
382
382
  const isTTY = Boolean(process2.stdout.isTTY);
383
383
  const noColor = Boolean(args["no-color"]) || !isTTY;
384
- const { buildContext: buildContext2 } = await import("./context-PSGEX2D7.js");
385
- const { acquireSession: acquireSession2, drainPool: drainPool2 } = await import("./pool-FBFHATDG.js");
384
+ const { buildContext: buildContext2 } = await import("./context-KPKBOWOP.js");
385
+ const { acquireSession: acquireSession2, drainPool: drainPool2 } = await import("./pool-JZGKPP6K.js");
386
386
  const ac = new AbortController();
387
387
  process2.on("SIGINT", () => ac.abort());
388
388
  process2.on("SIGTERM", () => ac.abort());
@@ -756,6 +756,7 @@ export {
756
756
  warn,
757
757
  info,
758
758
  spinner,
759
+ REPO_URL,
759
760
  printCta,
760
761
  resolveConn,
761
762
  errText,
@@ -92,6 +92,7 @@ var Ssh2Session = class {
92
92
  server.close();
93
93
  };
94
94
  server.on("error", (err) => {
95
+ closeAll();
95
96
  const msg = err.code === "EADDRINUSE" ? `Port ${localPort} is already in use` : `Tunnel server error: ${err.message}`;
96
97
  reject(new NetworkError(msg));
97
98
  });
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  connect
4
- } from "./chunk-4U3LTLWZ.js";
4
+ } from "./chunk-GJEF6UQA.js";
5
5
  import {
6
6
  NetworkError
7
7
  } from "./chunk-KGXPLI7W.js";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-BOPSG2LI.js";
11
11
  import {
12
12
  buildContext
13
- } from "./chunk-T5EX55GP.js";
13
+ } from "./chunk-QI75OVJK.js";
14
14
  import {
15
15
  atomicWriteConfig,
16
16
  deepMerge,
@@ -86,7 +86,7 @@ The diff you reviewed may no longer reflect what will be applied.
86
86
  };
87
87
  }
88
88
  async function applyConfigOverlay(plan, outputs, ctx, signal) {
89
- const { connect } = await import("./ssh-IQXNME3D.js");
89
+ const { connect } = await import("./ssh-E2AMBPZY.js");
90
90
  const connInfo = ctx.adapter.getConnectionInfo(outputs);
91
91
  const session = await connect({
92
92
  host: connInfo.host,
@@ -56,17 +56,17 @@ function makeProviderProxy(name) {
56
56
  if (resolved) return resolved;
57
57
  switch (name) {
58
58
  case "gcp": {
59
- const mod = await import("./gcp-BXDTC6EK.js");
59
+ const mod = await import("./gcp-6FT2A45S.js");
60
60
  resolved = mod.default;
61
61
  return resolved;
62
62
  }
63
63
  case "aws": {
64
- const mod = await import("./aws-FRE2JVAZ.js");
64
+ const mod = await import("./aws-D7Y6LCGK.js");
65
65
  resolved = mod.default;
66
66
  return resolved;
67
67
  }
68
68
  case "azure": {
69
- const mod = await import("./azure-PVC3AQVC.js");
69
+ const mod = await import("./azure-JQAMNVHN.js");
70
70
  resolved = mod.default;
71
71
  return resolved;
72
72
  }
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/providers/startup.ts
4
+ function makeStartupScript(opts) {
5
+ const { openclawVersion, os, bedrockEnabled = false } = opts;
6
+ const dockerDistro = os === "ubuntu" ? "ubuntu" : "debian";
7
+ const bedrockEnvBlock = bedrockEnabled ? makeBedrockEnvBlock() : "";
8
+ return `#!/bin/bash
9
+ set -euo pipefail
10
+
11
+ # \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
12
+ id -u clawops &>/dev/null || useradd -m -s /bin/bash clawops
13
+ mkdir -p /home/clawops/.ssh
14
+ chmod 700 /home/clawops/.ssh
15
+ chown clawops:clawops /home/clawops/.ssh
16
+
17
+ # \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
18
+ if ! command -v docker &>/dev/null; then
19
+ export DEBIAN_FRONTEND=noninteractive
20
+ apt-get update -q
21
+ apt-get install -y -q ca-certificates curl gnupg lsb-release
22
+ install -m 0755 -d /etc/apt/keyrings
23
+ curl -fsSL https://download.docker.com/linux/${dockerDistro}/gpg \\
24
+ -o /etc/apt/keyrings/docker.asc
25
+ chmod a+r /etc/apt/keyrings/docker.asc
26
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \\
27
+ https://download.docker.com/linux/${dockerDistro} $(lsb_release -cs) stable" \\
28
+ > /etc/apt/sources.list.d/docker.list
29
+ apt-get update -q
30
+ apt-get install -y -q \\
31
+ docker-ce \\
32
+ docker-ce-cli \\
33
+ containerd.io \\
34
+ docker-buildx-plugin \\
35
+ docker-compose-plugin
36
+ systemctl enable --now docker
37
+ fi
38
+
39
+ usermod -aG docker clawops
40
+
41
+ # \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
42
+ OPENCLAW_VERSION="${openclawVersion}"
43
+ docker pull ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION}
44
+
45
+ # \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
46
+ OPENCLAW_CONFIG=/home/clawops/openclaw.json
47
+ if [ ! -f "\${OPENCLAW_CONFIG}" ]; then
48
+ cat > "\${OPENCLAW_CONFIG}" <<'OPENCLAWJSON'
49
+ {"meta":{"lastTouchedVersion":"2026.4"},"gateway":{"port":18789,"auth":{"mode":"token"}},"models":{},"channels":{}}
50
+ OPENCLAWJSON
51
+ chown clawops:clawops "\${OPENCLAW_CONFIG}"
52
+ fi
53
+
54
+ # \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
55
+ docker stop openclaw 2>/dev/null || true
56
+ docker rm openclaw 2>/dev/null || true
57
+ docker run -d \\
58
+ --name openclaw \\
59
+ --restart unless-stopped \\
60
+ -p 18789:18789 \\
61
+ -v "\${OPENCLAW_CONFIG}":/app/config.json:ro \\
62
+ ${bedrockEnvBlock} ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION} \\
63
+ node openclaw.mjs gateway run --allow-unconfigured
64
+ `;
65
+ }
66
+ function makeBedrockEnvBlock() {
67
+ 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';
68
+ }
69
+
70
+ export {
71
+ makeStartupScript
72
+ };