@clawops/cli 1.4.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 +40 -0
- package/dist/{apply-5RREMN3L.js → apply-SI3JKS4Z.js} +2 -2
- package/dist/automation-RULUSJBW.js +0 -0
- package/dist/{aws-FRE2JVAZ.js → aws-D7Y6LCGK.js} +52 -90
- package/dist/{azure-PVC3AQVC.js → azure-JQAMNVHN.js} +15 -56
- package/dist/{bootstrap-G4UZ2FKH.js → bootstrap-RY4VOSDJ.js} +2 -2
- package/dist/chunk-3QJBNAHW.js +0 -0
- package/dist/chunk-6ZFIFDBJ.js +0 -0
- package/dist/{chunk-UAA6YOOP.js → chunk-72FF7IK2.js} +2 -2
- package/dist/chunk-A2I76FTA.js +0 -0
- package/dist/chunk-BOPSG2LI.js +0 -0
- package/dist/{chunk-JYQZJMD3.js → chunk-C5NDLOK2.js} +41 -33
- package/dist/chunk-CX5SL5HP.js +0 -0
- package/dist/{chunk-4U3LTLWZ.js → chunk-GJEF6UQA.js} +1 -0
- package/dist/chunk-KGXPLI7W.js +0 -0
- package/dist/{chunk-ZVOEQCNW.js → chunk-LCKD7L7X.js} +1 -1
- package/dist/chunk-OIGTOLB3.js +0 -0
- package/dist/{chunk-ZONXY3C6.js → chunk-QHGFENYR.js} +2 -2
- package/dist/{chunk-T5EX55GP.js → chunk-QI75OVJK.js} +3 -3
- package/dist/chunk-XKT42M34.js +72 -0
- package/dist/chunk-YTH4L2GN.js +0 -0
- package/dist/chunk-ZFNPM2WG.js +0 -0
- package/dist/cli.js +311 -54
- package/dist/{context-PSGEX2D7.js → context-KPKBOWOP.js} +1 -1
- package/dist/errors-OK47MQFD.js +0 -0
- package/dist/firewall-XQGO7HWK.js +51 -0
- package/dist/{gcp-BXDTC6EK.js → gcp-6FT2A45S.js} +14 -63
- package/dist/{generate-Z7DBMANX.js → generate-YV7226Q7.js} +2 -2
- package/dist/js-yaml-PTEEG4FO.js +0 -0
- package/dist/local-DXBEVZ5C.js +0 -0
- package/dist/mcp-apps-KY44ED3Y.js +0 -0
- package/dist/mcp-wire-ZWIYMLEW.js +45 -0
- package/dist/outputs-DJHBY7EE.js +0 -0
- package/dist/overlay-store-ADZPD7EU.js +0 -0
- package/dist/{package-WAJRGBBM.js → package-EW3FS257.js} +1 -1
- package/dist/{pool-FBFHATDG.js → pool-JZGKPP6K.js} +2 -2
- package/dist/providers-2OABPW2E.js +0 -0
- package/dist/remote-config-QF5TT7GU.js +0 -0
- package/dist/secrets-SVZWNAPK.js +0 -0
- package/dist/{server-IWLZJ4EU.js → server-3DEZHUWB.js} +9 -9
- package/dist/{ssh-IQXNME3D.js → ssh-E2AMBPZY.js} +1 -1
- package/dist/state-PRBIIN7I.js +0 -0
- package/dist/store-SDUR52Z5.js +0 -0
- package/dist/validate-T5M5EHSJ.js +0 -0
- package/package.json +26 -14
- package/dist/firewall-YYDOWDDP.js +0 -36
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# clawops
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@clawops/cli)
|
|
4
|
+
[](https://www.npmjs.com/package/@clawops/cli)
|
|
5
|
+
|
|
3
6
|
MCP-native infrastructure ops for OpenClaw — with read-only mode, destructive-action confirmation, and audit logs built in.
|
|
4
7
|
|
|
5
8
|
**clawops** is a CLI and [MCP](https://modelcontextprotocol.io/) server for deploying and operating
|
|
@@ -9,6 +12,27 @@ and Cursor drive them through typed MCP tools with explicit safety controls.
|
|
|
9
12
|
|
|
10
13
|
---
|
|
11
14
|
|
|
15
|
+
## What's new in v1.5.0
|
|
16
|
+
|
|
17
|
+
**`clawops mcp wire`** — wire the OpenClaw gateway's own AI as an MCP client of clawops.
|
|
18
|
+
Once wired, in-conversation commands like "check if my stack is healthy" or "show me the last 20
|
|
19
|
+
log lines" invoke the real `clawops` CLI rather than having the gateway AI guess.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
clawops mcp wire # wire the default stack
|
|
23
|
+
clawops mcp wire --stack prod # target a named stack
|
|
24
|
+
clawops mcp wire --force # bypass gateway version check
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Version-gated: requires OpenClaw ≥ 2026.4 on the gateway side. If the version is older, the
|
|
28
|
+
command surfaces a clear upgrade prompt and exits cleanly.
|
|
29
|
+
|
|
30
|
+
The `clawops setup` wizard now also asks at the end of a successful deploy:
|
|
31
|
+
*"Should the OpenClaw gateway's AI also be able to manage this stack?"* — accepting wires the
|
|
32
|
+
client automatically over the same SSH session.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
12
36
|
## What's new in v1.4.0
|
|
13
37
|
|
|
14
38
|
**`clawops monitor`** — live dashboard for any deployed stack. Shows gateway health, container
|
|
@@ -247,9 +271,13 @@ clawops down --yes # Destroy local-provider stack
|
|
|
247
271
|
| `backup` | Create or restore an OpenClaw state backup |
|
|
248
272
|
| `stacks` | List named stacks and their state |
|
|
249
273
|
| `doctor` | Check Node version, config, SSH key, provider credentials, and Pulumi home |
|
|
274
|
+
| `secret` | Manage secrets: `list`, `set`, `delete`, `rotate`, `audit` |
|
|
275
|
+
| `monitor` | Live dashboard: gateway health, container stats, log tail, stack picker |
|
|
250
276
|
| `mcp serve` | Start the embedded MCP server (stdio or HTTP) |
|
|
251
277
|
| `mcp install` | Interactively wire clawops into AI editors |
|
|
278
|
+
| `mcp wire` | Wire the gateway's AI as an MCP client of clawops |
|
|
252
279
|
| `help` | List all commands and global flags |
|
|
280
|
+
| `bug` | Open a pre-filled GitHub issue with system context from `doctor` |
|
|
253
281
|
|
|
254
282
|
Full flag reference: `clawops <command> --help`
|
|
255
283
|
|
|
@@ -297,6 +325,18 @@ The wizard resolves the absolute binary path automatically so app launchers can
|
|
|
297
325
|
without inheriting your shell's `PATH`. See [Connect an AI editor](#connect-an-ai-editor) above
|
|
298
326
|
for manual config paths.
|
|
299
327
|
|
|
328
|
+
### Wire the gateway AI
|
|
329
|
+
|
|
330
|
+
The OpenClaw gateway runs its own AI agent. Once wired, that agent can call clawops directly
|
|
331
|
+
instead of guessing at infrastructure state:
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
clawops mcp wire --stack prod # write MCP client entry into gateway config + restart
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Requires OpenClaw ≥ 2026.4 on the gateway. The `clawops setup` wizard offers this step
|
|
338
|
+
automatically after a successful deploy.
|
|
339
|
+
|
|
300
340
|
### Stdio mode (Claude Code / Cursor / VS Code)
|
|
301
341
|
|
|
302
342
|
Start the server manually or confirm your config is correct:
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
applyPlan
|
|
4
|
-
} from "./chunk-
|
|
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-
|
|
8
|
+
import "./chunk-QI75OVJK.js";
|
|
9
9
|
import "./chunk-ZFNPM2WG.js";
|
|
10
10
|
import "./chunk-A2I76FTA.js";
|
|
11
11
|
import "./chunk-CX5SL5HP.js";
|
|
File without changes
|
|
@@ -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-
|
|
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
|
|
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,
|
|
37
|
-
const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs,
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
84
|
-
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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.
|
|
122
|
+
new aws.iam.RolePolicy("clawops-bedrock-invoke", {
|
|
116
123
|
role: role.name,
|
|
117
|
-
|
|
118
|
-
|
|
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
|
|
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:
|
|
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-
|
|
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
|
|
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,
|
|
41
|
-
const gatewayIngressCidrs = resolveIngressCidrs(accessMode, allowedCidrs, gatewayCidrs,
|
|
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
|
-
|
|
129
|
-
|
|
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:
|
|
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 = {
|
package/dist/chunk-3QJBNAHW.js
CHANGED
|
File without changes
|
package/dist/chunk-6ZFIFDBJ.js
CHANGED
|
File without changes
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-YTH4L2GN.js";
|
|
5
5
|
import {
|
|
6
6
|
buildContext
|
|
7
|
-
} from "./chunk-
|
|
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-
|
|
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";
|
package/dist/chunk-A2I76FTA.js
CHANGED
|
File without changes
|
package/dist/chunk-BOPSG2LI.js
CHANGED
|
File without changes
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
buildContext
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QI75OVJK.js";
|
|
5
5
|
import {
|
|
6
6
|
acquireSession,
|
|
7
7
|
drainPool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LCKD7L7X.js";
|
|
9
9
|
import {
|
|
10
10
|
OPENCLAW_CONFIG,
|
|
11
11
|
atomicWriteConfig,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
|
|
18
18
|
// src/cli/commands/monitor.ts
|
|
19
19
|
import { defineCommand } from "citty";
|
|
20
|
-
import
|
|
20
|
+
import process2 from "process";
|
|
21
21
|
|
|
22
22
|
// src/output/human.ts
|
|
23
23
|
import chalk from "chalk";
|
|
@@ -37,6 +37,12 @@ function info(msg) {
|
|
|
37
37
|
function spinner(text) {
|
|
38
38
|
return ora(text).start();
|
|
39
39
|
}
|
|
40
|
+
var REPO_URL = "https://github.com/dfridkin/clawops";
|
|
41
|
+
function printCta() {
|
|
42
|
+
process.stdout.write(
|
|
43
|
+
"\n" + chalk.dim(" Thank you for using clawops! If it has been useful, star the project:") + "\n" + chalk.dim(" " + REPO_URL) + "\n\n" + chalk.dim(" Found a bug? Open an issue:") + "\n" + chalk.dim(" " + REPO_URL + "/issues") + "\n\n"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
40
46
|
|
|
41
47
|
// src/cli/commands/monitor.ts
|
|
42
48
|
var GATEWAY_PORT = 18789;
|
|
@@ -148,7 +154,7 @@ function renderSnapshot(snap, opts) {
|
|
|
148
154
|
return lines.join("\n");
|
|
149
155
|
}
|
|
150
156
|
async function probeEntries() {
|
|
151
|
-
const { buildContext: buildContext2 } = await import("./context-
|
|
157
|
+
const { buildContext: buildContext2 } = await import("./context-KPKBOWOP.js");
|
|
152
158
|
const { getConfig } = await import("./store-SDUR52Z5.js");
|
|
153
159
|
const config = getConfig();
|
|
154
160
|
if (!config) return [];
|
|
@@ -228,7 +234,7 @@ async function deleteFromRegistry(name) {
|
|
|
228
234
|
setConfig(updated);
|
|
229
235
|
}
|
|
230
236
|
async function runStackMenu(ac, setKeyHandler, noColor) {
|
|
231
|
-
|
|
237
|
+
process2.stdout.write("\x1B[2J\x1B[H\n Checking stacks...\n");
|
|
232
238
|
const entries = await probeEntries();
|
|
233
239
|
if (ac.signal.aborted) return null;
|
|
234
240
|
let selectedIdx = 0;
|
|
@@ -238,7 +244,7 @@ async function runStackMenu(ac, setKeyHandler, noColor) {
|
|
|
238
244
|
return showAll ? entries : entries.filter((e) => e.deployed);
|
|
239
245
|
}
|
|
240
246
|
function redraw() {
|
|
241
|
-
|
|
247
|
+
process2.stdout.write("\x1B[2J\x1B[H" + renderMenu(entries, selectedIdx, showAll, noColor, confirmDelete));
|
|
242
248
|
}
|
|
243
249
|
redraw();
|
|
244
250
|
return new Promise((resolve) => {
|
|
@@ -317,7 +323,7 @@ async function runDashboard(session, stackName, opts, ac, setKeyHandler, menuMod
|
|
|
317
323
|
noColor: opts.noColor,
|
|
318
324
|
menuMode
|
|
319
325
|
});
|
|
320
|
-
|
|
326
|
+
process2.stdout.write("\x1B[2J\x1B[H" + out + "\n");
|
|
321
327
|
}
|
|
322
328
|
async function doRefresh() {
|
|
323
329
|
cancelRefresh();
|
|
@@ -327,7 +333,7 @@ async function runDashboard(session, stackName, opts, ac, setKeyHandler, menuMod
|
|
|
327
333
|
redraw();
|
|
328
334
|
} catch (err) {
|
|
329
335
|
if (!ac.signal.aborted) {
|
|
330
|
-
|
|
336
|
+
process2.stdout.write("\x1B[2J\x1B[H Error gathering snapshot: " + (err instanceof Error ? err.message : String(err)) + "\n");
|
|
331
337
|
}
|
|
332
338
|
}
|
|
333
339
|
if (!ac.signal.aborted) scheduleRefresh();
|
|
@@ -373,20 +379,20 @@ var monitor_default = defineCommand({
|
|
|
373
379
|
async run({ args }) {
|
|
374
380
|
const intervalSec = Math.max(2, parseInt(String(args.interval ?? "10"), 10) || 10);
|
|
375
381
|
const tailLines = Math.max(1, parseInt(String(args.tail ?? "10"), 10) || 10);
|
|
376
|
-
const isTTY = Boolean(
|
|
382
|
+
const isTTY = Boolean(process2.stdout.isTTY);
|
|
377
383
|
const noColor = Boolean(args["no-color"]) || !isTTY;
|
|
378
|
-
const { buildContext: buildContext2 } = await import("./context-
|
|
379
|
-
const { acquireSession: acquireSession2, drainPool: drainPool2 } = await import("./pool-
|
|
384
|
+
const { buildContext: buildContext2 } = await import("./context-KPKBOWOP.js");
|
|
385
|
+
const { acquireSession: acquireSession2, drainPool: drainPool2 } = await import("./pool-JZGKPP6K.js");
|
|
380
386
|
const ac = new AbortController();
|
|
381
|
-
|
|
382
|
-
|
|
387
|
+
process2.on("SIGINT", () => ac.abort());
|
|
388
|
+
process2.on("SIGTERM", () => ac.abort());
|
|
383
389
|
if (args.stack) {
|
|
384
390
|
const ctx = buildContext2(args);
|
|
385
391
|
let conn;
|
|
386
392
|
if (ctx.adapter.name === "local") {
|
|
387
393
|
if (!ctx.localState) {
|
|
388
394
|
failure("Stack is not bootstrapped. Run `clawops up` first.");
|
|
389
|
-
|
|
395
|
+
process2.exit(4);
|
|
390
396
|
}
|
|
391
397
|
const ls = ctx.localState;
|
|
392
398
|
conn = { host: ls.sshHost, port: ls.sshPort, user: ls.sshUser, privateKeyPath: ls.privateKeyPath, knownHostsPath: ls.knownHostsPath };
|
|
@@ -399,7 +405,7 @@ var monitor_default = defineCommand({
|
|
|
399
405
|
);
|
|
400
406
|
if (!outputs["publicIp"]) {
|
|
401
407
|
failure("Stack has no outputs. Run `clawops up` first.");
|
|
402
|
-
|
|
408
|
+
process2.exit(4);
|
|
403
409
|
}
|
|
404
410
|
const base = extractBaseOutputs(outputs);
|
|
405
411
|
conn = ctx.adapter.getConnectionInfo({
|
|
@@ -412,7 +418,7 @@ var monitor_default = defineCommand({
|
|
|
412
418
|
const { session: session2, release: release2 } = await acquireSession2({ ...conn, signal: ac.signal });
|
|
413
419
|
try {
|
|
414
420
|
const snap = await gatherSnapshot(session2, ac.signal, tailLines);
|
|
415
|
-
|
|
421
|
+
process2.stdout.write(
|
|
416
422
|
renderSnapshot(snap, { stackName: ctx.stackName, intervalSec, showLogs: true, noColor }) + "\n"
|
|
417
423
|
);
|
|
418
424
|
} finally {
|
|
@@ -422,21 +428,21 @@ var monitor_default = defineCommand({
|
|
|
422
428
|
return;
|
|
423
429
|
}
|
|
424
430
|
const { session, release } = await acquireSession2({ ...conn, signal: ac.signal });
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
431
|
+
process2.stdin.setRawMode(true);
|
|
432
|
+
process2.stdin.resume();
|
|
433
|
+
process2.stdin.setEncoding("utf8");
|
|
434
|
+
process2.stdout.write("\x1B[?25l");
|
|
429
435
|
let keyHandler2 = () => {
|
|
430
436
|
};
|
|
431
|
-
|
|
437
|
+
process2.stdin.on("data", (key) => keyHandler2(key));
|
|
432
438
|
try {
|
|
433
439
|
await runDashboard(session, ctx.stackName, { intervalSec, tailLines, noColor }, ac, (fn) => {
|
|
434
440
|
keyHandler2 = fn;
|
|
435
441
|
}, false);
|
|
436
442
|
} finally {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
443
|
+
process2.stdin.setRawMode(false);
|
|
444
|
+
process2.stdin.pause();
|
|
445
|
+
process2.stdout.write("\x1B[?25h\n");
|
|
440
446
|
release();
|
|
441
447
|
drainPool2();
|
|
442
448
|
}
|
|
@@ -444,15 +450,15 @@ var monitor_default = defineCommand({
|
|
|
444
450
|
}
|
|
445
451
|
if (!isTTY) {
|
|
446
452
|
failure("Pass --stack <name> or run in a TTY for interactive stack selection.");
|
|
447
|
-
|
|
453
|
+
process2.exit(2);
|
|
448
454
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
455
|
+
process2.stdin.setRawMode(true);
|
|
456
|
+
process2.stdin.resume();
|
|
457
|
+
process2.stdin.setEncoding("utf8");
|
|
458
|
+
process2.stdout.write("\x1B[?25l");
|
|
453
459
|
let keyHandler = () => {
|
|
454
460
|
};
|
|
455
|
-
|
|
461
|
+
process2.stdin.on("data", (key) => keyHandler(key));
|
|
456
462
|
try {
|
|
457
463
|
while (!ac.signal.aborted) {
|
|
458
464
|
const stackName = await runStackMenu(ac, (fn) => {
|
|
@@ -497,9 +503,9 @@ var monitor_default = defineCommand({
|
|
|
497
503
|
}
|
|
498
504
|
}
|
|
499
505
|
} finally {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
506
|
+
process2.stdin.setRawMode(false);
|
|
507
|
+
process2.stdin.pause();
|
|
508
|
+
process2.stdout.write("\x1B[?25h\n");
|
|
503
509
|
}
|
|
504
510
|
}
|
|
505
511
|
});
|
|
@@ -750,6 +756,8 @@ export {
|
|
|
750
756
|
warn,
|
|
751
757
|
info,
|
|
752
758
|
spinner,
|
|
759
|
+
REPO_URL,
|
|
760
|
+
printCta,
|
|
753
761
|
resolveConn,
|
|
754
762
|
errText,
|
|
755
763
|
okText,
|
package/dist/chunk-CX5SL5HP.js
CHANGED
|
File without changes
|