@clawops/cli 1.7.8 → 2.0.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 +412 -70
- package/dist/{apply-F3KY2HTB.js → apply-AM5HERE7.js} +8 -6
- package/dist/{aws-L4RR2LSE.js → aws-AMON7DA7.js} +20 -9
- package/dist/{azure-7OXQENQL.js → azure-T4G6OBJQ.js} +19 -8
- package/dist/{bootstrap-HL4DNUNG.js → bootstrap-DMRPWJGN.js} +28 -19
- package/dist/bootstrap.sh.tmpl +51 -31
- package/dist/channels-KBUR42IU.js +53 -0
- package/dist/{chunk-DQDAWNGB.js → chunk-3WYA2QDM.js} +1 -1
- package/dist/chunk-6TIYVHPX.js +152 -0
- package/dist/{chunk-3XK66DKK.js → chunk-AHAAEXWC.js} +41 -0
- package/dist/{chunk-QQNKBTYZ.js → chunk-AX74VXTV.js} +292 -94
- package/dist/{chunk-C5X375RO.js → chunk-CKSPROD5.js} +59 -15
- package/dist/{chunk-UKTP332Z.js → chunk-GAZPPSKU.js} +6 -7
- package/dist/{chunk-FNS56UQY.js → chunk-GYV4KNW7.js} +319 -252
- package/dist/{chunk-PVUVI35Y.js → chunk-JW5A7E3X.js} +5 -1
- package/dist/chunk-LT4XMO5D.js +50 -0
- package/dist/{chunk-P5LKWRPL.js → chunk-LU2V3LXA.js} +3 -3
- package/dist/chunk-N44K3LHE.js +140 -0
- package/dist/chunk-NUDIHZEH.js +55 -0
- package/dist/chunk-SBLQH2TJ.js +56 -0
- package/dist/chunk-UFRO4H5W.js +228 -0
- package/dist/{chunk-RAAONHW3.js → chunk-WHJMKDV7.js} +24 -4
- package/dist/chunk-YR3O2I3S.js +101 -0
- package/dist/cli.js +866 -577
- package/dist/config-validate-K2N6XLDX.js +76 -0
- package/dist/{context-5LCUG2QR.js → context-KHKWJJMC.js} +1 -1
- package/dist/{firewall-XQGO7HWK.js → firewall-T3NTPZJD.js} +10 -0
- package/dist/{gcp-UG6AWPIZ.js → gcp-2JBTD7ZM.js} +19 -8
- package/dist/{generate-ELD7QF5Z.js → generate-2XV2GSP2.js} +4 -4
- package/dist/{harden-URPXLSVF.js → harden-PCDK3UQ5.js} +48 -11
- package/dist/health-5CCOXYGG.js +11 -0
- package/dist/logs-P7YCKVF4.js +15 -0
- package/dist/{mcp-wire-ZMIVFAUC.js → mcp-wire-BFEY2Y6H.js} +23 -17
- package/dist/{package-QYZFN3FP.js → package-3HUW57XH.js} +3 -3
- package/dist/plugins-DTST3OER.js +49 -0
- package/dist/{pool-QGFQRMGU.js → pool-EX4ZTA5P.js} +2 -2
- package/dist/privileged-JFA6LLTV.js +17 -0
- package/dist/{remote-config-QDLN4UMG.js → remote-config-Z6IIZR3D.js} +3 -3
- package/dist/runtime-LZ7NA53V.js +42 -0
- package/dist/{server-FWTOSSZP.js → server-A5AB67GQ.js} +16 -12
- package/dist/spec-path-KQOOIQCA.js +9 -0
- package/dist/{ssh-CNJNLM3E.js → ssh-B3NZAU4I.js} +1 -1
- package/dist/upgrade-ULD4KFYC.js +88 -0
- package/dist/validate-BOQRWX4F.js +14 -0
- package/dist/{version-guard-VUCNZXQS.js → version-guard-GPSTCPT7.js} +3 -3
- package/dist/{versions-2UVAT6PQ.js → versions-W5LRQCAJ.js} +2 -2
- package/package.json +3 -3
- package/spec/deploy-plan.schema.json +114 -25
- package/spec/integrations.yaml +135 -28
- package/spec/mcp-tools.yaml +68 -35
- package/spec/models.yaml +9 -0
- package/spec/openclaw-2.0.config.schema.json +1 -0
- package/spec/openclaw-versions.yaml +116 -27
- package/dist/chunk-35WVQY3X.js +0 -122
- package/dist/chunk-6X45DDGH.js +0 -42
- package/dist/chunk-SEZMVVAS.js +0 -156
- package/dist/validate-CFQ4FH2T.js +0 -10
|
@@ -1,37 +1,117 @@
|
|
|
1
1
|
# OpenClaw Version Compatibility Matrix
|
|
2
2
|
# Enforced by src/openclaw/versions.ts — `doctor`, `plan`, `up` and `apply` refuse
|
|
3
|
-
# an OpenClaw version outside
|
|
3
|
+
# an OpenClaw version outside `support`. Update via /openclaw-config skill.
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# it from this line produces a crash-looping gateway (exit 78). Use clawops 2.x instead.
|
|
5
|
+
# `support.min`, `support.max` and `support.recommended` are LIVE. Nothing reads
|
|
6
|
+
# `runtime`, `quirks`, `incompatible` or `tested`; they are documentation and the
|
|
7
|
+
# machine-readable source WO-38 will build the runtime contract from.
|
|
9
8
|
|
|
10
9
|
version: 1
|
|
11
10
|
|
|
12
|
-
#
|
|
11
|
+
# Which release line this checkout is. Flipping this to "2.x" is gated by a test
|
|
12
|
+
# (tests/openclaw/line-interlock.test.ts) that fails until the runtime actually
|
|
13
|
+
# implements the 2.0 contract — see `runtime` below.
|
|
14
|
+
line: "2.x"
|
|
15
|
+
|
|
16
|
+
# Minimum and maximum versions clawops supports.
|
|
17
|
+
#
|
|
18
|
+
# Flipped to the 2.x range by WO-40, once the runtime could actually honour it: the
|
|
19
|
+
# config directory is mounted writable, provisioning writes gateway.mode, and
|
|
20
|
+
# --allow-unconfigured is gone. tests/openclaw/line-interlock.test.ts holds those
|
|
21
|
+
# together — setting `line: "2.x"` fails until each is true.
|
|
22
|
+
#
|
|
23
|
+
# The floor is 2026.9.2 rather than 2026.9.1 because the official Bedrock provider
|
|
24
|
+
# plugin declares "requires plugin API >=2026.9.2" and refuses to install on 9.1.
|
|
13
25
|
support:
|
|
14
|
-
min: "2026.
|
|
15
|
-
max: "
|
|
16
|
-
recommended: "2026.
|
|
26
|
+
min: "2026.9.2"
|
|
27
|
+
max: "" # no upper bound: this line tracks the 2.x runtime contract
|
|
28
|
+
recommended: "2026.9.2"
|
|
29
|
+
|
|
30
|
+
# The 2.0 runtime contract, measured against ghcr.io/openclaw/openclaw:2026.9.1.
|
|
31
|
+
# See docs/spikes/SP-10-openclaw-2.0-startup-contract.md for how each was observed.
|
|
32
|
+
# WO-38 consumes this; today nothing reads it.
|
|
33
|
+
runtime:
|
|
34
|
+
# 2026.9.2, not 2026.9.1: the official Bedrock provider plugin declares
|
|
35
|
+
# "requires plugin API >=2026.9.2" and refuses to install on 9.1. SP-10b §3.
|
|
36
|
+
targetMin: "2026.9.2"
|
|
37
|
+
image: "ghcr.io/openclaw/openclaw"
|
|
38
|
+
variants: [standard, slim, browser] # `-slim`, `-browser` tag suffixes
|
|
39
|
+
# Mount the config DIRECTORY, never the file. OpenClaw writes config by atomic
|
|
40
|
+
# rename, and renaming over a bind-mounted file fails EBUSY regardless of :ro.
|
|
41
|
+
# Verified — `plugins install` cannot record a plugin against a file mount. SP-10b §4.
|
|
42
|
+
configDir: "/cfg"
|
|
43
|
+
configPath: "/cfg/config.json" # via OPENCLAW_CONFIG_PATH
|
|
44
|
+
# The OpenClaw release spec/openclaw-2.0.config.schema.json was captured from.
|
|
45
|
+
# Validation compares the deployed version against this: a config key the schema
|
|
46
|
+
# does not know is an ERROR on an older-or-equal runtime and a WARNING on a newer
|
|
47
|
+
# one, because there it more likely means the schema is stale than the config wrong.
|
|
48
|
+
configSchemaCapturedFrom: "2026.9.2"
|
|
49
|
+
configMount: directory
|
|
50
|
+
gatewayPort: 18789
|
|
51
|
+
env:
|
|
52
|
+
configPath: OPENCLAW_CONFIG_PATH
|
|
53
|
+
token: OPENCLAW_GATEWAY_TOKEN
|
|
54
|
+
stateDir: OPENCLAW_STATE_DIR
|
|
55
|
+
startup:
|
|
56
|
+
# Verified: without gateway.mode the gateway exits 78 unless --allow-unconfigured
|
|
57
|
+
# is passed. Setting the mode is the supported answer; the flag exists to bypass a
|
|
58
|
+
# check for "suspicious or clobbered config", so clawops should not rely on it.
|
|
59
|
+
requiresGatewayMode: true
|
|
60
|
+
gatewayMode: "local" # schema accepts local|remote
|
|
61
|
+
allowUnconfigured: false # what 2.x should pass — i.e. do not pass it
|
|
62
|
+
exitCodeOnBlockedStart: 78
|
|
63
|
+
# Provider plugins are not all bundled. A configured-but-missing plugin is
|
|
64
|
+
# auto-installed from ClawHub on first boot, after which the gateway refuses to
|
|
65
|
+
# report ready and exits 1 ("startup convergence"); the next boot succeeds.
|
|
66
|
+
# The install lands in the container's writable layer, so it is lost — and refetched —
|
|
67
|
+
# on every container replacement, which is what clawops's restart path does.
|
|
68
|
+
plugins:
|
|
69
|
+
bundledSourceRoot: "/app/dist/extensions"
|
|
70
|
+
# Two different paths, and the difference matters. An explicit
|
|
71
|
+
# `openclaw plugins install` lands beside the config, so it persists with the
|
|
72
|
+
# config directory clawops already keeps as host state — no extra volume. The
|
|
73
|
+
# startup auto-install instead writes to the container's writable layer, which is
|
|
74
|
+
# lost on every container replacement. Pre-install; do not rely on auto-install.
|
|
75
|
+
installedPath: "<configDir>/extensions"
|
|
76
|
+
autoInstallPath: "/app/npm/projects" # ephemeral — container layer
|
|
77
|
+
convergenceRestartRequired: true # only when auto-installing at startup
|
|
78
|
+
# Reconcile configured providers against loaded plugins. `plugins doctor` is NOT
|
|
79
|
+
# usable for this: it never names a missing provider and exits 1 on duplicate-id
|
|
80
|
+
# warnings during normal operation. SP-10b §1-2.
|
|
81
|
+
verifyCommand: "openclaw plugins list --json"
|
|
82
|
+
verifyField: providerIds
|
|
83
|
+
providers:
|
|
84
|
+
amazon-bedrock:
|
|
85
|
+
bundled: false
|
|
86
|
+
package: "@openclaw/amazon-bedrock-provider"
|
|
87
|
+
install: "openclaw plugins install clawhub:@openclaw/amazon-bedrock-provider"
|
|
88
|
+
requiresEgress: true
|
|
89
|
+
# With no egress the gateway starts cleanly WITHOUT the provider — a healthy
|
|
90
|
+
# deployment missing the model backend it was configured for. clawops defaults
|
|
91
|
+
# to deny-all egress, so this is the default outcome, not an edge case.
|
|
92
|
+
silentlyAbsentWithoutEgress: true
|
|
93
|
+
ollama: { bundled: true }
|
|
94
|
+
anthropic: { bundled: true }
|
|
95
|
+
openai: { bundled: true }
|
|
17
96
|
|
|
18
|
-
# Provider-specific quirks discovered through testing
|
|
19
97
|
quirks:
|
|
20
|
-
- id:
|
|
98
|
+
- id: openclaw-2-provider-plugin-install
|
|
21
99
|
description: |
|
|
22
|
-
OpenClaw
|
|
23
|
-
|
|
24
|
-
|
|
100
|
+
OpenClaw 2.0 does not bundle every model provider. A provider named in
|
|
101
|
+
models.providers whose plugin is missing is installed from ClawHub during
|
|
102
|
+
startup convergence; the gateway then exits 1 and requires one restart. With no
|
|
103
|
+
network egress the gateway starts successfully but without the provider.
|
|
25
104
|
affected:
|
|
26
|
-
versions: ">=2026.
|
|
105
|
+
versions: ">=2026.8.1"
|
|
27
106
|
providers: [aws]
|
|
28
107
|
configs: [openclaw.models.providers.amazon-bedrock]
|
|
29
108
|
workaround: |
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
109
|
+
Install the plugin at provisioning time, before the first gateway start:
|
|
110
|
+
openclaw plugins install clawhub:@openclaw/amazon-bedrock-provider
|
|
111
|
+
and/or persist /app/npm/projects so a container replacement does not refetch it.
|
|
112
|
+
Verify after deploy rather than trusting a healthy gateway: a missing provider
|
|
113
|
+
does not fail the health check.
|
|
114
|
+
discoveredFrom: docs/spikes/SP-10-openclaw-2.0-startup-contract.md
|
|
35
115
|
|
|
36
116
|
- id: pnpm-pulumi-hoisting
|
|
37
117
|
description: |
|
|
@@ -43,25 +123,34 @@ quirks:
|
|
|
43
123
|
providers: ["*"]
|
|
44
124
|
workaround: See docs/decisions/0003-pulumi-pnpm.md
|
|
45
125
|
|
|
46
|
-
#
|
|
126
|
+
# Retired: `aws-bedrock-aws-profile` (AWS_PROFILE in the systemd EnvironmentFile).
|
|
127
|
+
# It described a native/systemd install; clawops is Docker-only per ADR 0013, and on
|
|
128
|
+
# 2.0 the Bedrock question is plugin installation, not credential resolution.
|
|
129
|
+
|
|
47
130
|
tested:
|
|
48
131
|
- openclawVersion: "2026.4.5"
|
|
49
132
|
providers: [aws, gcp, local]
|
|
50
133
|
nodeVersions: ["20.x", "22.x"]
|
|
51
134
|
lastTestedAt: "2026-04-15"
|
|
135
|
+
- openclawVersion: "2026.9.1"
|
|
136
|
+
providers: [] # runtime contract characterised only; no deploy path yet
|
|
137
|
+
nodeVersions: ["24.x"]
|
|
138
|
+
lastTestedAt: "2026-09-06"
|
|
139
|
+
notes: "SP-10 — startup contract, plugin install behaviour, config schema capture."
|
|
52
140
|
|
|
53
|
-
# Known incompatible combinations
|
|
54
141
|
incompatible:
|
|
55
142
|
- openclawVersionRange: "<2026.4.5"
|
|
56
143
|
reason: "Below clawops's declared minimum support. Earlier OpenClaw versions used different config paths and channel registration semantics."
|
|
57
144
|
- openclawVersionRange: ">=2026.8.1"
|
|
58
145
|
reason: |
|
|
59
|
-
OpenClaw 2.0 changed the container runtime contract. Verified
|
|
60
|
-
|
|
61
|
-
|
|
146
|
+
OpenClaw 2.0 changed the container runtime contract. Verified on 2026.8.1 and
|
|
147
|
+
re-verified on 2026.9.1:
|
|
148
|
+
- Without gateway.mode the gateway exits 78 unless --allow-unconfigured is
|
|
149
|
+
passed; clawops writes no mode.
|
|
62
150
|
- Sessions, transcripts and credentials moved into SQLite under the state
|
|
63
151
|
directory, which this line does not mount => total state loss on restart.
|
|
64
|
-
- Provider plugins
|
|
65
|
-
|
|
152
|
+
- Provider plugins are not all bundled. A configured provider whose plugin is
|
|
153
|
+
missing is fetched at startup, costing a convergence restart — or is silently
|
|
154
|
+
absent when egress is denied, which is clawops's default.
|
|
66
155
|
Use clawops 2.x, which targets OpenClaw >= 2026.9.1.
|
|
67
156
|
useInstead: "@clawops/cli@2"
|
package/dist/chunk-35WVQY3X.js
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
saveOverlay
|
|
4
|
-
} from "./chunk-6ZFIFDBJ.js";
|
|
5
|
-
import {
|
|
6
|
-
resolveSecrets
|
|
7
|
-
} from "./chunk-BOPSG2LI.js";
|
|
8
|
-
import {
|
|
9
|
-
validatePlan
|
|
10
|
-
} from "./chunk-6X45DDGH.js";
|
|
11
|
-
import {
|
|
12
|
-
atomicWriteConfig,
|
|
13
|
-
deepMerge,
|
|
14
|
-
readRemoteConfig,
|
|
15
|
-
restartGateway
|
|
16
|
-
} from "./chunk-SEZMVVAS.js";
|
|
17
|
-
import {
|
|
18
|
-
buildContext
|
|
19
|
-
} from "./chunk-P5LKWRPL.js";
|
|
20
|
-
import {
|
|
21
|
-
UsageError
|
|
22
|
-
} from "./chunk-KGXPLI7W.js";
|
|
23
|
-
|
|
24
|
-
// src/plan/apply.ts
|
|
25
|
-
async function applyPlan(plan, opts) {
|
|
26
|
-
const validation = validatePlan(plan);
|
|
27
|
-
if (!validation.ok) {
|
|
28
|
-
throw new UsageError(
|
|
29
|
-
`Invalid deploy plan:
|
|
30
|
-
${validation.errors.join("\n")}`
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
if (plan.spec.provider === "local") {
|
|
34
|
-
throw new UsageError(
|
|
35
|
-
"plan/apply is not supported for the local provider. Use `clawops up` directly."
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
const { guardOpenclawVersion } = await import("./version-guard-VUCNZXQS.js");
|
|
39
|
-
await guardOpenclawVersion(plan.spec.openclaw.version);
|
|
40
|
-
const ctx = buildContext({
|
|
41
|
-
stack: plan.spec.stackName,
|
|
42
|
-
provider: plan.spec.provider
|
|
43
|
-
});
|
|
44
|
-
const stack = await ctx.getStack();
|
|
45
|
-
await stack.setConfig("instanceType", { value: plan.spec.instanceType });
|
|
46
|
-
if (plan.spec.region) {
|
|
47
|
-
await stack.setConfig("region", { value: plan.spec.region });
|
|
48
|
-
}
|
|
49
|
-
await stack.setConfig("openclawVersion", { value: plan.spec.openclaw.version });
|
|
50
|
-
const modelProvider = plan.spec.openclaw.config?.["models"]?.["provider"];
|
|
51
|
-
if (modelProvider === "bedrock") {
|
|
52
|
-
await stack.setConfig("bedrockEnabled", { value: "true" });
|
|
53
|
-
}
|
|
54
|
-
if (plan.metadata.stackVersion !== void 0) {
|
|
55
|
-
const currentInfo = await stack.info();
|
|
56
|
-
if (currentInfo !== void 0 && currentInfo.version !== plan.metadata.stackVersion) {
|
|
57
|
-
process.stderr.write(
|
|
58
|
-
`
|
|
59
|
-
Warning: stack "${plan.spec.stackName}" has changed since this plan was generated (plan version: ${plan.metadata.stackVersion}, current: ${currentInfo.version}).
|
|
60
|
-
The diff you reviewed may no longer reflect what will be applied.
|
|
61
|
-
|
|
62
|
-
`
|
|
63
|
-
);
|
|
64
|
-
if (opts?.confirmDrift) {
|
|
65
|
-
await opts.confirmDrift();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const start = Date.now();
|
|
70
|
-
const result = await stack.up({ onOutput: opts?.onOutput, signal: opts?.signal });
|
|
71
|
-
const outputs = Object.fromEntries(
|
|
72
|
-
Object.entries(result.outputs).map(([k, v]) => [k, v.value])
|
|
73
|
-
);
|
|
74
|
-
const changeSummary = {};
|
|
75
|
-
if (result.summary.resourceChanges) {
|
|
76
|
-
for (const [op, count] of Object.entries(result.summary.resourceChanges)) {
|
|
77
|
-
changeSummary[op] = count;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
const hasOverlay = plan.spec.openclaw.config !== void 0 || plan.spec.openclaw.channels !== void 0;
|
|
81
|
-
if (hasOverlay) {
|
|
82
|
-
await applyConfigOverlay(plan, outputs, ctx, opts?.signal);
|
|
83
|
-
}
|
|
84
|
-
return {
|
|
85
|
-
outputs,
|
|
86
|
-
changeSummary,
|
|
87
|
-
durationMs: Date.now() - start
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
async function applyConfigOverlay(plan, outputs, ctx, signal) {
|
|
91
|
-
const { connect } = await import("./ssh-CNJNLM3E.js");
|
|
92
|
-
const connInfo = ctx.adapter.getConnectionInfo(outputs);
|
|
93
|
-
const session = await connect({
|
|
94
|
-
host: connInfo.host,
|
|
95
|
-
port: connInfo.port,
|
|
96
|
-
user: connInfo.user,
|
|
97
|
-
privateKeyPath: connInfo.privateKeyPath,
|
|
98
|
-
knownHostsPath: connInfo.knownHostsPath,
|
|
99
|
-
signal
|
|
100
|
-
});
|
|
101
|
-
try {
|
|
102
|
-
const remote = await readRemoteConfig(session, signal);
|
|
103
|
-
const configOverlay = plan.spec.openclaw.config ?? {};
|
|
104
|
-
const resolvedOverlay = resolveSecrets(
|
|
105
|
-
configOverlay,
|
|
106
|
-
plan.spec.secrets ?? []
|
|
107
|
-
);
|
|
108
|
-
const merged = deepMerge(remote, {
|
|
109
|
-
...resolvedOverlay,
|
|
110
|
-
...plan.spec.openclaw.channels !== void 0 ? { channels: plan.spec.openclaw.channels } : {}
|
|
111
|
-
});
|
|
112
|
-
await atomicWriteConfig(session, merged, signal);
|
|
113
|
-
await restartGateway(session, signal);
|
|
114
|
-
saveOverlay(plan.spec.stackName, configOverlay, plan.spec.secrets ?? []);
|
|
115
|
-
} finally {
|
|
116
|
-
session.close();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export {
|
|
121
|
-
applyPlan
|
|
122
|
-
};
|
package/dist/chunk-6X45DDGH.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
resolveSpecDir
|
|
4
|
-
} from "./chunk-PVUVI35Y.js";
|
|
5
|
-
|
|
6
|
-
// src/plan/validate.ts
|
|
7
|
-
import Ajv from "ajv/dist/2020";
|
|
8
|
-
import addFormats from "ajv-formats";
|
|
9
|
-
import { readFileSync } from "fs";
|
|
10
|
-
import { join } from "path";
|
|
11
|
-
var _validate;
|
|
12
|
-
function getValidator() {
|
|
13
|
-
if (_validate) return _validate;
|
|
14
|
-
const ajv = new Ajv({ strict: false });
|
|
15
|
-
addFormats(ajv);
|
|
16
|
-
const schema = JSON.parse(
|
|
17
|
-
readFileSync(join(resolveSpecDir(), "deploy-plan.schema.json"), "utf-8")
|
|
18
|
-
);
|
|
19
|
-
_validate = ajv.compile(schema);
|
|
20
|
-
return _validate;
|
|
21
|
-
}
|
|
22
|
-
function validatePlan(plan) {
|
|
23
|
-
const validate = getValidator();
|
|
24
|
-
const ok = validate(plan);
|
|
25
|
-
if (ok) return { ok: true, errors: [] };
|
|
26
|
-
const errors = (validate.errors ?? []).map(
|
|
27
|
-
(e) => `${e.instancePath} ${e.message ?? ""}`.trim()
|
|
28
|
-
);
|
|
29
|
-
return { ok: false, errors };
|
|
30
|
-
}
|
|
31
|
-
function assertValidPlan(plan) {
|
|
32
|
-
const result = validatePlan(plan);
|
|
33
|
-
if (!result.ok) {
|
|
34
|
-
throw new Error(`Invalid deploy plan:
|
|
35
|
-
${result.errors.join("\n")}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
validatePlan,
|
|
41
|
-
assertValidPlan
|
|
42
|
-
};
|
package/dist/chunk-SEZMVVAS.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
err,
|
|
4
|
-
ok
|
|
5
|
-
} from "./chunk-EI7CQQ7D.js";
|
|
6
|
-
|
|
7
|
-
// src/openclaw/run-flags.ts
|
|
8
|
-
var CONFIG_MOUNT_PATH = "/app/config.json";
|
|
9
|
-
var GATEWAY_PORT = 18789;
|
|
10
|
-
var CONFIG_PATH_ENV = `-e OPENCLAW_CONFIG_PATH=${CONFIG_MOUNT_PATH}`;
|
|
11
|
-
var ADD_HOST_FLAG = "--add-host=host.docker.internal:host-gateway";
|
|
12
|
-
var PORT_PIN = `--port ${GATEWAY_PORT}`;
|
|
13
|
-
var COMMON_RUN_FLAGS = `${CONFIG_PATH_ENV} ${ADD_HOST_FLAG}`;
|
|
14
|
-
var ENV_FILE_PATH = "/home/clawops/openclaw.env";
|
|
15
|
-
var IMAGE_INSPECT_CMD = `docker inspect openclaw --format '{{.Config.Image}}'`;
|
|
16
|
-
function imageForRestart(inspectStdout) {
|
|
17
|
-
const image = inspectStdout.trim();
|
|
18
|
-
if (!image || image.includes("Error") || !image.includes(":")) {
|
|
19
|
-
return err(
|
|
20
|
-
"No running OpenClaw container found, so there is no image version to reuse. Deploy one with `clawops up --openclaw-version <version>`. clawops does not fall back to `latest` or `stable` here: both now point at OpenClaw 2.0, which this release line does not support."
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
return ok(image);
|
|
24
|
-
}
|
|
25
|
-
function versionOf(image) {
|
|
26
|
-
return image.split(":")[1] ?? "unknown";
|
|
27
|
-
}
|
|
28
|
-
function gatewayRunCommand(opts) {
|
|
29
|
-
const { image, configPath, envFilePath = ENV_FILE_PATH, pathPrefix = "" } = opts;
|
|
30
|
-
const envFileArg = `$([ -s ${envFilePath} ] && echo --env-file ${envFilePath})`;
|
|
31
|
-
return pathPrefix + [
|
|
32
|
-
"docker stop openclaw 2>/dev/null || true",
|
|
33
|
-
"docker rm openclaw 2>/dev/null || true",
|
|
34
|
-
`docker run -d --name openclaw --restart unless-stopped -p ${GATEWAY_PORT}:${GATEWAY_PORT} ${COMMON_RUN_FLAGS} ${envFileArg} -v ${configPath}:${CONFIG_MOUNT_PATH}:ro ${image} node openclaw.mjs gateway run --allow-unconfigured ${PORT_PIN}`
|
|
35
|
-
].join(" && ");
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// src/plan/remote-config.ts
|
|
39
|
-
var OPENCLAW_CONFIG_LINUX = "/home/clawops/openclaw.json";
|
|
40
|
-
var OPENCLAW_CONFIG_MACOS = "~/.config/openclaw/config.json";
|
|
41
|
-
var OPENCLAW_CONFIG = OPENCLAW_CONFIG_LINUX;
|
|
42
|
-
var OPENCLAW_TMP = "/tmp/clawops-config.json.tmp";
|
|
43
|
-
async function detectOS(session, signal) {
|
|
44
|
-
const result = await session.exec("uname -s", signal);
|
|
45
|
-
return result.stdout.trim() === "Darwin" ? "Darwin" : "Linux";
|
|
46
|
-
}
|
|
47
|
-
function configPathForOS(os) {
|
|
48
|
-
return os === "Darwin" ? OPENCLAW_CONFIG_MACOS : OPENCLAW_CONFIG_LINUX;
|
|
49
|
-
}
|
|
50
|
-
async function execWithFallbackSudo(session, cmd, signal) {
|
|
51
|
-
const result = await session.exec(cmd, signal);
|
|
52
|
-
if (result.code === 0) return result;
|
|
53
|
-
return session.exec(`sudo -n bash -c "${cmd}"`, signal);
|
|
54
|
-
}
|
|
55
|
-
async function readRemoteConfig(session, signal) {
|
|
56
|
-
const os = await detectOS(session, signal);
|
|
57
|
-
const configPath = configPathForOS(os);
|
|
58
|
-
const result = os === "Darwin" ? await session.exec(`cat ${configPath}`, signal) : await execWithFallbackSudo(session, `cat ${configPath}`, signal);
|
|
59
|
-
if (result.code !== 0) {
|
|
60
|
-
throw new Error(`Cannot read ${configPath}: ${result.stderr}`);
|
|
61
|
-
}
|
|
62
|
-
try {
|
|
63
|
-
return JSON.parse(result.stdout);
|
|
64
|
-
} catch {
|
|
65
|
-
throw new Error(`Cannot parse ${configPath}: invalid JSON`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function normaliseGatewayPort(cfg) {
|
|
69
|
-
const gateway = cfg["gateway"];
|
|
70
|
-
if (!gateway || typeof gateway !== "object" || Array.isArray(gateway)) return void 0;
|
|
71
|
-
const g = gateway;
|
|
72
|
-
const current = g["port"];
|
|
73
|
-
if (typeof current === "number" && current !== GATEWAY_PORT) {
|
|
74
|
-
g["port"] = GATEWAY_PORT;
|
|
75
|
-
return current;
|
|
76
|
-
}
|
|
77
|
-
if (current === void 0) g["port"] = GATEWAY_PORT;
|
|
78
|
-
return void 0;
|
|
79
|
-
}
|
|
80
|
-
async function atomicWriteConfig(session, cfg, signal) {
|
|
81
|
-
const os = await detectOS(session, signal);
|
|
82
|
-
const configPath = configPathForOS(os);
|
|
83
|
-
const json = JSON.stringify(cfg, null, 2);
|
|
84
|
-
const b64 = Buffer.from(json, "utf-8").toString("base64");
|
|
85
|
-
const chown = os === "Linux" ? ` && chown clawops:clawops ${configPath}` : "";
|
|
86
|
-
const cmd = `echo '${b64}' | base64 -d > ${OPENCLAW_TMP} && mv ${OPENCLAW_TMP} ${configPath}` + chown;
|
|
87
|
-
const result = os === "Darwin" ? await session.exec(cmd, signal) : await execWithFallbackSudo(session, cmd, signal);
|
|
88
|
-
if (result.code !== 0) {
|
|
89
|
-
throw new Error(`Failed to write config: ${result.stderr}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async function restartGateway(session, signal) {
|
|
93
|
-
const os = await detectOS(session, signal);
|
|
94
|
-
const configPath = configPathForOS(os);
|
|
95
|
-
const pathPrefix = os === "Darwin" ? 'export PATH="/usr/local/bin:/opt/homebrew/bin:/Applications/Docker.app/Contents/Resources/bin:$PATH" && ' : "";
|
|
96
|
-
const imgCmd = `${pathPrefix}${IMAGE_INSPECT_CMD}`;
|
|
97
|
-
const imgResult = os === "Darwin" ? await session.exec(imgCmd, signal) : await execWithFallbackSudo(session, imgCmd, signal);
|
|
98
|
-
const resolved = imageForRestart(imgResult.stdout);
|
|
99
|
-
if (!resolved.ok) throw new Error(resolved.error);
|
|
100
|
-
const image = resolved.value;
|
|
101
|
-
const restartCmd = gatewayRunCommand({
|
|
102
|
-
image,
|
|
103
|
-
configPath,
|
|
104
|
-
pathPrefix
|
|
105
|
-
});
|
|
106
|
-
const result = os === "Darwin" ? await session.exec(restartCmd, signal) : await execWithFallbackSudo(session, restartCmd, signal);
|
|
107
|
-
if (result.code !== 0) {
|
|
108
|
-
throw new Error(`Gateway restart failed: ${result.stderr}`);
|
|
109
|
-
}
|
|
110
|
-
const healthy = await waitForGateway(session, pathPrefix, signal);
|
|
111
|
-
if (!healthy) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
`Gateway restarted but did not become healthy on port ${GATEWAY_PORT}. The previous container has already been replaced; inspect it with \`docker logs openclaw\`. If the newly-applied config is at fault, revert it and restart \u2014 before v1.7.2 this config was never applied, so a value that has sat unused may now be taking effect.`
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
async function waitForGateway(session, pathPrefix, signal, attempts = 15) {
|
|
118
|
-
const probe = `${pathPrefix}curl -fsS -m 3 http://127.0.0.1:${GATEWAY_PORT}/healthz >/dev/null 2>&1 && echo ok || echo waiting`;
|
|
119
|
-
for (let i = 0; i < attempts; i++) {
|
|
120
|
-
if (signal?.aborted) return false;
|
|
121
|
-
const r = await session.exec(probe, signal);
|
|
122
|
-
if (r.stdout.trim().endsWith("ok")) return true;
|
|
123
|
-
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
124
|
-
}
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
function deepMerge(base, overlay) {
|
|
128
|
-
const result = { ...base };
|
|
129
|
-
for (const [key, val] of Object.entries(overlay)) {
|
|
130
|
-
if (val !== null && typeof val === "object" && !Array.isArray(val) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
|
|
131
|
-
result[key] = deepMerge(
|
|
132
|
-
result[key],
|
|
133
|
-
val
|
|
134
|
-
);
|
|
135
|
-
} else {
|
|
136
|
-
result[key] = val;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export {
|
|
143
|
-
IMAGE_INSPECT_CMD,
|
|
144
|
-
imageForRestart,
|
|
145
|
-
versionOf,
|
|
146
|
-
gatewayRunCommand,
|
|
147
|
-
OPENCLAW_CONFIG_LINUX,
|
|
148
|
-
OPENCLAW_CONFIG_MACOS,
|
|
149
|
-
OPENCLAW_CONFIG,
|
|
150
|
-
OPENCLAW_TMP,
|
|
151
|
-
readRemoteConfig,
|
|
152
|
-
normaliseGatewayPort,
|
|
153
|
-
atomicWriteConfig,
|
|
154
|
-
restartGateway,
|
|
155
|
-
deepMerge
|
|
156
|
-
};
|