@clawops/cli 1.3.0 → 1.5.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 +136 -0
- package/dist/{apply-DLNE2JYZ.js → apply-5RREMN3L.js} +3 -3
- package/dist/automation-RULUSJBW.js +0 -0
- package/dist/{aws-KQBWY43W.js → aws-FRE2JVAZ.js} +9 -4
- package/dist/{azure-4EJFVJZL.js → azure-PVC3AQVC.js} +11 -4
- package/dist/bootstrap-G4UZ2FKH.js +0 -0
- package/dist/chunk-3QJBNAHW.js +0 -0
- package/dist/chunk-4U3LTLWZ.js +0 -0
- package/dist/chunk-6ZFIFDBJ.js +0 -0
- package/dist/chunk-A2I76FTA.js +0 -0
- package/dist/chunk-BOPSG2LI.js +0 -0
- package/dist/chunk-CX5SL5HP.js +0 -0
- package/dist/{chunk-ZDPBBYYV.js → chunk-IVX62LFO.js} +2 -2
- package/dist/chunk-KGXPLI7W.js +0 -0
- package/dist/chunk-OIGTOLB3.js +0 -0
- package/dist/chunk-R5S6IXBE.js +771 -0
- package/dist/{chunk-JDN6PLH2.js → chunk-T5EX55GP.js} +3 -3
- package/dist/chunk-YTH4L2GN.js +0 -0
- package/dist/{chunk-UDNZUSKA.js → chunk-ZFNPM2WG.js} +1 -1
- package/dist/{chunk-JCUZU5BH.js → chunk-ZONXY3C6.js} +2 -2
- package/dist/chunk-ZVOEQCNW.js +0 -0
- package/dist/cli.js +207 -53
- package/dist/{context-M2RMDHX6.js → context-PSGEX2D7.js} +1 -1
- package/dist/errors-OK47MQFD.js +0 -0
- package/dist/firewall-YYDOWDDP.js +0 -0
- package/dist/{gcp-SKURG3L6.js → gcp-BXDTC6EK.js} +60 -17
- package/dist/{generate-U7PJ5LRG.js → generate-2QGKYR42.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-AFUTH62F.js → package-QLDA65A3.js} +2 -1
- package/dist/pool-FBFHATDG.js +0 -0
- package/dist/providers-2OABPW2E.js +0 -0
- package/dist/{remote-config-JQ77SRC2.js → remote-config-QF5TT7GU.js} +1 -1
- package/dist/secrets-SVZWNAPK.js +0 -0
- package/dist/{server-I62UES5V.js → server-LOL2NUJ2.js} +92 -19
- package/dist/ssh-IQXNME3D.js +0 -0
- package/dist/state-PRBIIN7I.js +0 -0
- package/dist/store-SDUR52Z5.js +0 -0
- package/dist/validate-T5M5EHSJ.js +0 -0
- package/package.json +27 -14
- package/dist/chunk-LVIIYY27.js +0 -266
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,52 @@ 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
|
+
|
|
36
|
+
## What's new in v1.4.0
|
|
37
|
+
|
|
38
|
+
**`clawops monitor`** — live dashboard for any deployed stack. Shows gateway health, container
|
|
39
|
+
status, CPU/memory, disk usage, and a rolling log tail. Refreshes on an interval with `[r]`,
|
|
40
|
+
toggles logs with `[l]`, and quits with `[q]`.
|
|
41
|
+
|
|
42
|
+
Run without `--stack` to get an **interactive stack picker** first — probes all registered stacks
|
|
43
|
+
in parallel, shows only running ones by default, and lets you toggle to a full list (`[a]`) where
|
|
44
|
+
not-deployed stacks can be deleted from the registry with `[d]`. Press `[s]` inside the dashboard
|
|
45
|
+
to go back to the picker.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
clawops monitor # interactive stack selection → dashboard
|
|
49
|
+
clawops monitor --stack prod # jump straight to a named stack
|
|
50
|
+
clawops monitor --stack prod | cat # one-shot snapshot for CI
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**`clawops_monitor` MCP tool** — same snapshot as a single structured JSON call, so Claude Code
|
|
54
|
+
and Cursor can check stack health without opening a terminal.
|
|
55
|
+
|
|
56
|
+
**`clawops stacks delete` guard** — now blocks deletion of a still-deployed stack and requires
|
|
57
|
+
`--force` to remove from the registry without tearing down cloud resources first.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
12
61
|
## Who this is for
|
|
13
62
|
|
|
14
63
|
- **OpenClaw users** who want the simplest path to self-hosting across cloud or local VMs, with
|
|
@@ -222,8 +271,11 @@ clawops down --yes # Destroy local-provider stack
|
|
|
222
271
|
| `backup` | Create or restore an OpenClaw state backup |
|
|
223
272
|
| `stacks` | List named stacks and their state |
|
|
224
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 |
|
|
225
276
|
| `mcp serve` | Start the embedded MCP server (stdio or HTTP) |
|
|
226
277
|
| `mcp install` | Interactively wire clawops into AI editors |
|
|
278
|
+
| `mcp wire` | Wire the gateway's AI as an MCP client of clawops |
|
|
227
279
|
| `help` | List all commands and global flags |
|
|
228
280
|
|
|
229
281
|
Full flag reference: `clawops <command> --help`
|
|
@@ -272,6 +324,18 @@ The wizard resolves the absolute binary path automatically so app launchers can
|
|
|
272
324
|
without inheriting your shell's `PATH`. See [Connect an AI editor](#connect-an-ai-editor) above
|
|
273
325
|
for manual config paths.
|
|
274
326
|
|
|
327
|
+
### Wire the gateway AI
|
|
328
|
+
|
|
329
|
+
The OpenClaw gateway runs its own AI agent. Once wired, that agent can call clawops directly
|
|
330
|
+
instead of guessing at infrastructure state:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
clawops mcp wire --stack prod # write MCP client entry into gateway config + restart
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Requires OpenClaw ≥ 2026.4 on the gateway. The `clawops setup` wizard offers this step
|
|
337
|
+
automatically after a successful deploy.
|
|
338
|
+
|
|
275
339
|
### Stdio mode (Claude Code / Cursor / VS Code)
|
|
276
340
|
|
|
277
341
|
Start the server manually or confirm your config is correct:
|
|
@@ -393,6 +457,78 @@ Key design decisions:
|
|
|
393
457
|
|
|
394
458
|
See [`docs/architecture.md`](docs/architecture.md) for a full narrative, and [`docs/decisions/`](docs/decisions/) for ADRs.
|
|
395
459
|
|
|
460
|
+
### Cloud provider stacks
|
|
461
|
+
|
|
462
|
+
Each cloud provider is an inline Pulumi program that creates the resources below. All three share the same outputs (`publicIp`, `gatewayUrl`, `sshHost`, `sshPort`, `sshUser`) consumed by the SSH and config-overlay layers.
|
|
463
|
+
|
|
464
|
+
#### AWS
|
|
465
|
+
|
|
466
|
+
```mermaid
|
|
467
|
+
flowchart LR
|
|
468
|
+
subgraph NET["Networking"]
|
|
469
|
+
VPC["VPC (10.0.0.0/16)"]
|
|
470
|
+
IGW[Internet Gateway]
|
|
471
|
+
SUBNET["Subnet (10.0.1.0/24)"]
|
|
472
|
+
RT[Route Table]
|
|
473
|
+
SG["Security Group (ports 22, 18789)"]
|
|
474
|
+
end
|
|
475
|
+
subgraph IAM["IAM"]
|
|
476
|
+
ROLE[IAM Role]
|
|
477
|
+
SSM[SSM Policy Attachment]
|
|
478
|
+
BED["Bedrock Policy Attachment (optional)"]
|
|
479
|
+
IP[Instance Profile]
|
|
480
|
+
end
|
|
481
|
+
subgraph COMPUTE["Compute"]
|
|
482
|
+
KP[EC2 Key Pair]
|
|
483
|
+
EC2["EC2 Instance (Ubuntu 22.04, IMDSv2)"]
|
|
484
|
+
EIP[Elastic IP]
|
|
485
|
+
end
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
[Detailed diagram →](docs/providers/aws.md#stack-diagram)
|
|
489
|
+
|
|
490
|
+
#### GCP
|
|
491
|
+
|
|
492
|
+
```mermaid
|
|
493
|
+
flowchart LR
|
|
494
|
+
subgraph NET["Networking"]
|
|
495
|
+
NW[VPC Network]
|
|
496
|
+
SN["Subnetwork (10.0.0.0/24)"]
|
|
497
|
+
FW1["Firewall: SSH port 22 (conditional)"]
|
|
498
|
+
FW2["Firewall: Gateway port 18789 (conditional)"]
|
|
499
|
+
ADDR[Static External IP]
|
|
500
|
+
end
|
|
501
|
+
subgraph COMPUTE["Compute"]
|
|
502
|
+
VM["Compute Instance (Debian 12, 20 GB)"]
|
|
503
|
+
end
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
[Detailed diagram →](docs/providers/gcp.md#stack-diagram)
|
|
507
|
+
|
|
508
|
+
#### Azure
|
|
509
|
+
|
|
510
|
+
```mermaid
|
|
511
|
+
flowchart LR
|
|
512
|
+
RG[Resource Group]
|
|
513
|
+
subgraph NET["Networking"]
|
|
514
|
+
VNET["Virtual Network (10.0.0.0/16)"]
|
|
515
|
+
SUBNET["Subnet (10.0.1.0/24)"]
|
|
516
|
+
NSG["Network Security Group (ports 22, 18789)"]
|
|
517
|
+
PIP["Public IP Address (Static)"]
|
|
518
|
+
NIC[Network Interface]
|
|
519
|
+
end
|
|
520
|
+
subgraph COMPUTE["Compute"]
|
|
521
|
+
VM["VM (Ubuntu 22.04, managed identity)"]
|
|
522
|
+
end
|
|
523
|
+
subgraph KV["Key Vault (optional)"]
|
|
524
|
+
VAULT["Key Vault (RBAC, name max 24 chars)"]
|
|
525
|
+
RA["Role Assignment (Secrets User)"]
|
|
526
|
+
SECRET["Secret: gateway-token"]
|
|
527
|
+
end
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
[Detailed diagram →](docs/providers/azure.md#stack-diagram)
|
|
531
|
+
|
|
396
532
|
---
|
|
397
533
|
|
|
398
534
|
## Development
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
applyPlan
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZONXY3C6.js";
|
|
5
5
|
import "./chunk-YTH4L2GN.js";
|
|
6
6
|
import "./chunk-6ZFIFDBJ.js";
|
|
7
7
|
import "./chunk-BOPSG2LI.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-T5EX55GP.js";
|
|
9
|
+
import "./chunk-ZFNPM2WG.js";
|
|
10
10
|
import "./chunk-A2I76FTA.js";
|
|
11
11
|
import "./chunk-CX5SL5HP.js";
|
|
12
12
|
import "./chunk-KGXPLI7W.js";
|
|
File without changes
|
|
@@ -142,6 +142,12 @@ var awsProgram = async () => {
|
|
|
142
142
|
iamInstanceProfile: instanceProfile.name,
|
|
143
143
|
keyName: keyPair.keyName,
|
|
144
144
|
userData: makeStartupScript(openclawVersion, bedrockEnabled),
|
|
145
|
+
// IMDSv2 with hopLimit=2 so Docker containers on this host can reach IMDS
|
|
146
|
+
// and obtain the instance role credentials (required for Bedrock access).
|
|
147
|
+
metadataOptions: {
|
|
148
|
+
httpTokens: "required",
|
|
149
|
+
httpPutResponseHopLimit: 2
|
|
150
|
+
},
|
|
145
151
|
tags: { Name: "clawops" }
|
|
146
152
|
});
|
|
147
153
|
const eip = new aws.ec2.Eip("clawops-eip", {
|
|
@@ -164,8 +170,7 @@ var awsProgram = async () => {
|
|
|
164
170
|
};
|
|
165
171
|
};
|
|
166
172
|
function makeStartupScript(openclawVersion, bedrockEnabled) {
|
|
167
|
-
const
|
|
168
|
-
const bedrockEnvFlag = bedrockEnabled ? " --env-file /etc/openclaw.env \\\\\n" : "";
|
|
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" : "";
|
|
169
174
|
return `#!/bin/bash
|
|
170
175
|
set -euo pipefail
|
|
171
176
|
|
|
@@ -175,7 +180,7 @@ mkdir -p /home/clawops/.ssh
|
|
|
175
180
|
chmod 700 /home/clawops/.ssh
|
|
176
181
|
chown clawops:clawops /home/clawops/.ssh
|
|
177
182
|
|
|
178
|
-
# Install Docker if not present (
|
|
183
|
+
# Install Docker if not present (AWS AMI is ubuntu-22.04)
|
|
179
184
|
if ! command -v docker &>/dev/null; then
|
|
180
185
|
export DEBIAN_FRONTEND=noninteractive
|
|
181
186
|
apt-get update -q
|
|
@@ -193,7 +198,7 @@ if ! command -v docker &>/dev/null; then
|
|
|
193
198
|
fi
|
|
194
199
|
|
|
195
200
|
usermod -aG docker clawops
|
|
196
|
-
|
|
201
|
+
|
|
197
202
|
# Pull OpenClaw image
|
|
198
203
|
OPENCLAW_VERSION="${openclawVersion}"
|
|
199
204
|
docker pull ghcr.io/openclaw/openclaw:\${OPENCLAW_VERSION}
|
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
import process2 from "process";
|
|
5
5
|
|
|
6
6
|
// src/providers/azure/program.ts
|
|
7
|
+
import { createHash } from "crypto";
|
|
7
8
|
var GATEWAY_PORT = 18789;
|
|
8
9
|
var SSH_PORT = 22;
|
|
9
10
|
var azureProgram = async () => {
|
|
10
|
-
const [pulumi, azure, { resolveIngressCidrs, detectEgressIp }] = await Promise.all([
|
|
11
|
+
const [pulumi, azure, random, { resolveIngressCidrs, detectEgressIp }] = await Promise.all([
|
|
11
12
|
import("@pulumi/pulumi"),
|
|
12
13
|
import("@pulumi/azure-native"),
|
|
14
|
+
import("@pulumi/random"),
|
|
13
15
|
import("./firewall-YYDOWDDP.js")
|
|
14
16
|
]);
|
|
15
17
|
const cfg = new pulumi.Config();
|
|
@@ -138,8 +140,9 @@ var azureProgram = async () => {
|
|
|
138
140
|
}
|
|
139
141
|
});
|
|
140
142
|
if (keyVaultEnabled) {
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
+
const safeName = stackName.replace(/[^a-zA-Z0-9-]/g, "-");
|
|
144
|
+
const rawKvName = `clawops-${safeName}-kv`;
|
|
145
|
+
const kvName = rawKvName.length > 24 ? `cl-${createHash("sha256").update(stackName).digest("hex").slice(0, 20)}` : rawKvName;
|
|
143
146
|
const kv = new azure.keyvault.Vault("clawops-kv", {
|
|
144
147
|
resourceGroupName: rg.name,
|
|
145
148
|
location: rg.location,
|
|
@@ -157,11 +160,15 @@ var azureProgram = async () => {
|
|
|
157
160
|
principalId: pulumi.output(vm.identity).apply((i) => i?.principalId ?? ""),
|
|
158
161
|
principalType: "ServicePrincipal"
|
|
159
162
|
});
|
|
163
|
+
const gatewayToken = new random.RandomPassword("clawops-kv-gateway-token", {
|
|
164
|
+
length: 32,
|
|
165
|
+
special: false
|
|
166
|
+
});
|
|
160
167
|
new azure.keyvault.Secret("clawops-gateway-token", {
|
|
161
168
|
resourceGroupName: rg.name,
|
|
162
169
|
vaultName: kv.name,
|
|
163
170
|
secretName: "gateway-token",
|
|
164
|
-
properties: { value:
|
|
171
|
+
properties: { value: gatewayToken.result }
|
|
165
172
|
});
|
|
166
173
|
}
|
|
167
174
|
const resolvedIp = pulumi.output(publicIp.ipAddress).apply((ip) => ip ?? "");
|
|
File without changes
|
package/dist/chunk-3QJBNAHW.js
CHANGED
|
File without changes
|
package/dist/chunk-4U3LTLWZ.js
CHANGED
|
File without changes
|
package/dist/chunk-6ZFIFDBJ.js
CHANGED
|
File without changes
|
package/dist/chunk-A2I76FTA.js
CHANGED
|
File without changes
|
package/dist/chunk-BOPSG2LI.js
CHANGED
|
File without changes
|
package/dist/chunk-CX5SL5HP.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-T5EX55GP.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-QLDA65A3.js");
|
|
49
49
|
const config = getConfig();
|
|
50
50
|
const instanceType = intent.instanceType ?? "small";
|
|
51
51
|
const openclawVersion = intent.openclawVersion ?? "latest";
|
package/dist/chunk-KGXPLI7W.js
CHANGED
|
File without changes
|
package/dist/chunk-OIGTOLB3.js
CHANGED
|
File without changes
|