@clawops/cli 2.2.1 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -4
- package/dist/{apply-F5SQ2ZOS.js → apply-TXPUNOGW.js} +9 -9
- package/dist/{automation-NBYQ6MFZ.js → automation-VDKLZMJI.js} +1 -1
- package/dist/{backup-flows-NDP5JTR3.js → backup-flows-THPX2D7S.js} +1 -1
- package/dist/{bootstrap-32TZXVDF.js → bootstrap-L3P5E4D7.js} +2 -2
- package/dist/{chunk-PASAVVNS.js → chunk-47CGHUVT.js} +1 -1
- package/dist/{chunk-E6BRQK67.js → chunk-4SEFKZRL.js} +1 -1
- package/dist/{chunk-PCSX6Y3U.js → chunk-66CUJFXK.js} +2 -2
- package/dist/{chunk-AX65JMDZ.js → chunk-7LLVIQ7G.js} +12 -9
- package/dist/{chunk-55UMO37O.js → chunk-CHPMOE4T.js} +1 -1
- package/dist/{chunk-LV7UO5CG.js → chunk-G2ROJXYJ.js} +2 -2
- package/dist/{chunk-GFIR2IIJ.js → chunk-GYMAC4MW.js} +47 -28
- package/dist/{chunk-T6OCPTTR.js → chunk-LIAXA43Z.js} +14 -8
- package/dist/{chunk-Y3N63PDS.js → chunk-ORBZGTNX.js} +93 -60
- package/dist/{chunk-OUQVKIIA.js → chunk-PNRFFYOA.js} +14 -14
- package/dist/{chunk-755X5OGS.js → chunk-Q56AM57B.js} +4 -1
- package/dist/{chunk-4MHDW2NB.js → chunk-QRF4OWG4.js} +1 -1
- package/dist/{chunk-AVERNLUY.js → chunk-SQPHNVCF.js} +6 -6
- package/dist/{chunk-RDUKRIRC.js → chunk-U3NRKBDW.js} +1 -1
- package/dist/cli.js +111 -72
- package/dist/{context-EHSLWKSH.js → context-4KTM4DKH.js} +5 -5
- package/dist/{flows-6B2I6TRW.js → flows-6YEJGHCK.js} +7 -7
- package/dist/{generate-4JWTMOLQ.js → generate-XJWEQKT6.js} +9 -7
- package/dist/{harden-UHAOVQMZ.js → harden-7O553IOK.js} +5 -5
- package/dist/{init-HOPXDNWY.js → init-DYOLZX65.js} +2 -2
- package/dist/{mcp-wire-7MGEAMZH.js → mcp-wire-NAKI2WME.js} +21 -21
- package/dist/{migrate-flow-24XA4GZL.js → migrate-flow-4XQUUFMH.js} +2 -2
- package/dist/{package-ESYPCIES.js → package-HRMX7K3C.js} +1 -1
- package/dist/policy-AZGFCQNV.js +42 -0
- package/dist/{remote-config-OZYBMBSK.js → remote-config-V2WXIXIF.js} +1 -1
- package/dist/{server-Y2EDRUDL.js → server-FR5LUAOI.js} +21 -21
- package/dist/setup-policy-HTO2KSZR.js +90 -0
- package/dist/{stack-config-ICQ5YHUL.js → stack-config-3E7KWFPI.js} +2 -2
- package/dist/{stack-delete-NTIGKWUF.js → stack-delete-SNPMLWMD.js} +2 -2
- package/dist/{state-AKZP2S4T.js → state-KG6K5QZC.js} +2 -2
- package/dist/{store-YOLQYXMB.js → store-BTQOOIJH.js} +1 -1
- package/dist/{tailscale-cutover-V42HO5UM.js → tailscale-cutover-XTMGDM5H.js} +2 -2
- package/dist/{validate-DZE6LFEB.js → validate-CRXX7OYF.js} +1 -1
- package/package.json +1 -1
- package/spec/errors.yaml +5 -3
- package/spec/mcp-tools.yaml +4 -3
- package/dist/{chunk-UAJJEDCJ.js → chunk-AGSNTIYZ.js} +0 -0
- package/dist/{chunk-YPVWF7IA.js → chunk-HSGKK3RF.js} +3 -3
- package/dist/{ready-IJEUBFVX.js → ready-4H3NNEYQ.js} +3 -3
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ and Cursor drive them through typed MCP tools with explicit safety controls.
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
-
**What's new:** [2.
|
|
17
|
+
**What's new:** [2.3.1 release notes](#whats-new-in-231) below, and the full history
|
|
18
18
|
in [CHANGELOG.md](CHANGELOG.md).
|
|
19
19
|
|
|
20
20
|
---
|
|
@@ -262,7 +262,7 @@ clawops down --yes # Destroy local-provider stack
|
|
|
262
262
|
|
|
263
263
|
| Command | Description |
|
|
264
264
|
|---|---|
|
|
265
|
-
| `setup` | First-run wizard: guided LLM, integrations, and deploy-plan generation |
|
|
265
|
+
| `setup` | First-run wizard: guided LLM, integrations, spending limits, and deploy-plan generation |
|
|
266
266
|
| `init` | Register a stack in `~/.clawops/config.json` without provisioning. Additive, existing stacks are kept; `--force` is needed only to overwrite one |
|
|
267
267
|
| `up` | Provision or update stack (`--dry-run` for preview, `--gateway-port` for a non-default port) |
|
|
268
268
|
| `down` | Destroy local-provider stack (requires `--yes`; `--dry-run` shows current outputs) |
|
|
@@ -397,7 +397,7 @@ Do not bind to a non-loopback address without additional authentication controls
|
|
|
397
397
|
| `clawops_harden` | cli | Apply hardening modules; join or leave a tailnet (elicits confirmation) |
|
|
398
398
|
| `clawops_init` | cli | Register a stack and write `~/.clawops/config.json` (no cloud resources) |
|
|
399
399
|
| `clawops_workflow_deploy_app` | workflow | End-to-end deploy: plan → confirm → apply → status |
|
|
400
|
-
| `clawops_workflow_recover` | workflow |
|
|
400
|
+
| `clawops_workflow_recover` | workflow | Diagnose an unhealthy stack: status, failed health checks, recent logs, and which tool fixes what |
|
|
401
401
|
| `clawops_task_status` | cli | Poll a long-running task |
|
|
402
402
|
|
|
403
403
|
Tools in the `read` toolset are also available in `--read-only` mode; the table's Toolset column shows the primary toolset. All other toolsets require full mode.
|
|
@@ -442,6 +442,24 @@ Config lives at `~/.clawops/config.json` (override with `$CLAWOPS_HOME`).
|
|
|
442
442
|
| Azure | `AZURE_CLIENT_ID` / `AZURE_CLIENT_SECRET` or `az login` |
|
|
443
443
|
| Local | SSH host + key configured in `stacks[name].localOpts` |
|
|
444
444
|
|
|
445
|
+
### Spending limits
|
|
446
|
+
|
|
447
|
+
An optional `policy` block limits what clawops will deploy from this machine, whichever tool asks:
|
|
448
|
+
|
|
449
|
+
```json
|
|
450
|
+
"policy": {
|
|
451
|
+
"allowedInstanceTypes": { "aws": ["micro", "small"] },
|
|
452
|
+
"maxStacks": 3
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
`plan`, `apply` and `up` refuse a server size outside `allowedInstanceTypes` for that provider
|
|
457
|
+
(a clawops size or the provider's own type; `small` and `t3.small` are the same on AWS), and
|
|
458
|
+
`init` refuses a new stack beyond `maxStacks`. Every MCP tool that deploys is held to the same
|
|
459
|
+
limits, in the same words, and no tool can change them. `clawops setup` asks whether to set
|
|
460
|
+
them, then offers only the sizes you allowed. The limit lives here rather than in the plan
|
|
461
|
+
because a plan is what an agent writes.
|
|
462
|
+
|
|
445
463
|
---
|
|
446
464
|
|
|
447
465
|
## Known limitations
|
|
@@ -576,7 +594,7 @@ pnpm dev doctor # verify toolchain
|
|
|
576
594
|
```bash
|
|
577
595
|
pnpm dev # run CLI from src/ via tsx
|
|
578
596
|
pnpm build # tsup → dist/
|
|
579
|
-
pnpm test # vitest (
|
|
597
|
+
pnpm test # vitest (2122 tests, ~13s)
|
|
580
598
|
pnpm test:changed # vitest --changed (fast edit loop)
|
|
581
599
|
pnpm test:integration # Docker-based SSH integration tests
|
|
582
600
|
pnpm test:e2e:local # builds, then bootstrap, the host-touching MCP tools and a 1.x migration, in systemd containers
|
|
@@ -635,6 +653,47 @@ Use `pnpm changeset` to record a release note before merging a `feat` or `fix`.
|
|
|
635
653
|
|
|
636
654
|
---
|
|
637
655
|
|
|
656
|
+
## What's new in 2.3.1
|
|
657
|
+
|
|
658
|
+
A security fix. **Upgrade if you set gateway config through MCP.**
|
|
659
|
+
|
|
660
|
+
- **Before:** `clawops_config_set` wrote the value you set to the audit log
|
|
661
|
+
(`~/.clawops/mcp-audit.log`) in clear and redacted the config path instead. Setting
|
|
662
|
+
`models.providers.openai.apiKey` through an agent therefore logged the API key. The
|
|
663
|
+
confirmation prompt showed the value too.
|
|
664
|
+
- **Now:** the value is redacted whenever its path names a secret, and secret fields inside a
|
|
665
|
+
JSON object value are redacted one by one. Paths are logged as written. See
|
|
666
|
+
[redaction](docs/security/redaction.md#config-paths-and-values).
|
|
667
|
+
- **Existing logs are not rewritten.** If you used `clawops_config_set` for a secret before
|
|
668
|
+
2.3.1, check your audit log and rotate that secret.
|
|
669
|
+
|
|
670
|
+
## What's new in 2.3
|
|
671
|
+
|
|
672
|
+
Spending limits that an agent cannot lift, and a run of fixes from the backlog.
|
|
673
|
+
|
|
674
|
+
### Spending limits
|
|
675
|
+
|
|
676
|
+
- An optional `policy` block in `~/.clawops/config.json` limits the server sizes clawops may
|
|
677
|
+
deploy on each provider and the number of deployments it may manage. `plan`, `apply` and `up`
|
|
678
|
+
refuse a size outside the list; `init` refuses a stack beyond the cap.
|
|
679
|
+
- Every MCP tool that deploys is held to the same limits, in the same words, and no tool can
|
|
680
|
+
change them. Confirmation is something an agent can answer for itself; this is not.
|
|
681
|
+
- `clawops setup` asks whether to set them, then offers only the sizes you allowed. See
|
|
682
|
+
[Spending limits](#spending-limits).
|
|
683
|
+
|
|
684
|
+
### Fixes
|
|
685
|
+
|
|
686
|
+
- **The setup wizard's plan asked the cloud for a machine called `small`.** It wrote the clawops
|
|
687
|
+
size where the provider's own type belongs. It now maps it, as `clawops plan` does.
|
|
688
|
+
- **`clawops_workflow_recover` runs the stack's health checks, and recommends only real tools.** It
|
|
689
|
+
ran two of the four steps it described and finished by suggesting `clawops refresh`, which does
|
|
690
|
+
not exist.
|
|
691
|
+
- **The MCP audit log redacts credential arguments.** `GOOGLE_APPLICATION_CREDENTIALS` was named
|
|
692
|
+
sensitive in `spec/errors.yaml` and logged in the clear. A test now fails when the spec and the
|
|
693
|
+
code disagree on an error class, its exit code, or a redaction pattern (#185).
|
|
694
|
+
|
|
695
|
+
---
|
|
696
|
+
|
|
638
697
|
## What's new in 2.2
|
|
639
698
|
|
|
640
699
|
Recovery is a flag, agents can reach every command they need, and SSH failures say what failed.
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
applyPlan
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-7LLVIQ7G.js";
|
|
5
5
|
import "./chunk-BOPSG2LI.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-PASAVVNS.js";
|
|
8
|
-
import "./chunk-55UMO37O.js";
|
|
6
|
+
import "./chunk-CHPMOE4T.js";
|
|
9
7
|
import "./chunk-AEEMRFZV.js";
|
|
10
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-AGSNTIYZ.js";
|
|
9
|
+
import "./chunk-47CGHUVT.js";
|
|
10
|
+
import "./chunk-SQPHNVCF.js";
|
|
11
11
|
import "./chunk-6ZFIFDBJ.js";
|
|
12
12
|
import "./chunk-WPZIJONN.js";
|
|
13
|
-
import "./chunk-YPVWF7IA.js";
|
|
14
13
|
import "./chunk-JW5A7E3X.js";
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-HSGKK3RF.js";
|
|
16
15
|
import "./chunk-N5ZYUTZS.js";
|
|
17
16
|
import "./chunk-VOEJYRIK.js";
|
|
18
17
|
import "./chunk-EI7CQQ7D.js";
|
|
19
18
|
import "./chunk-FEK7VJAY.js";
|
|
20
19
|
import "./chunk-RHOWYIWT.js";
|
|
21
20
|
import "./chunk-N4WZLWJ4.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
21
|
+
import "./chunk-U3NRKBDW.js";
|
|
22
|
+
import "./chunk-GYMAC4MW.js";
|
|
24
23
|
import "./chunk-KGXPLI7W.js";
|
|
24
|
+
import "./chunk-VUFMZEIM.js";
|
|
25
25
|
export {
|
|
26
26
|
applyPlan
|
|
27
27
|
};
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
import "./chunk-EI7CQQ7D.js";
|
|
15
15
|
import {
|
|
16
16
|
writeLocalState
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-U3NRKBDW.js";
|
|
18
|
+
import "./chunk-GYMAC4MW.js";
|
|
19
19
|
import {
|
|
20
20
|
ProviderError
|
|
21
21
|
} from "./chunk-KGXPLI7W.js";
|
|
@@ -44,7 +44,7 @@ async function validatePlanConfig(plan) {
|
|
|
44
44
|
]);
|
|
45
45
|
const { loadVersionSpec } = await import("./versions-W5LRQCAJ.js");
|
|
46
46
|
const spec = loadVersionSpec(yaml);
|
|
47
|
-
const { deepMerge } = await import("./remote-config-
|
|
47
|
+
const { deepMerge } = await import("./remote-config-V2WXIXIF.js");
|
|
48
48
|
const merged = deepMerge(
|
|
49
49
|
{ gateway: { mode: "local" } },
|
|
50
50
|
overlay
|
|
@@ -136,7 +136,7 @@ var SYNTHESISED_CONFIG = JSON.stringify({
|
|
|
136
136
|
channels: {}
|
|
137
137
|
});
|
|
138
138
|
async function prepareMigration(args) {
|
|
139
|
-
const { buildContext } = await import("./context-
|
|
139
|
+
const { buildContext } = await import("./context-4KTM4DKH.js");
|
|
140
140
|
const { guardOpenclawVersion, defaultOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
|
|
141
141
|
const version = args.openclawVersion ? await guardOpenclawVersion(args.openclawVersion) : await defaultOpenclawVersion();
|
|
142
142
|
const ctx = buildContext({ stack: args.stack });
|
|
@@ -230,8 +230,8 @@ async function stageRestore(session, opts) {
|
|
|
230
230
|
async function activateStaged(session, staged, opts = {}) {
|
|
231
231
|
const { signal } = opts;
|
|
232
232
|
const hostExec = (command) => execPrivileged(session, command, signal);
|
|
233
|
-
const { restartGateway } = await import("./remote-config-
|
|
234
|
-
const { waitForGateway } = await import("./ready-
|
|
233
|
+
const { restartGateway } = await import("./remote-config-V2WXIXIF.js");
|
|
234
|
+
const { waitForGateway } = await import("./ready-4H3NNEYQ.js");
|
|
235
235
|
opts.onPhase?.("activating");
|
|
236
236
|
const chown = await hostExec(`chown -R ${CONTAINER_UID}:${CONTAINER_UID} ${staged.statePath}`);
|
|
237
237
|
if (chown.code !== 0) {
|
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
import {
|
|
3
3
|
resolveSecrets
|
|
4
4
|
} from "./chunk-BOPSG2LI.js";
|
|
5
|
+
import {
|
|
6
|
+
writeStackConfig
|
|
7
|
+
} from "./chunk-CHPMOE4T.js";
|
|
5
8
|
import {
|
|
6
9
|
atomicWriteConfig,
|
|
7
10
|
deepMerge,
|
|
8
11
|
readRemoteConfig,
|
|
9
12
|
restartGateway
|
|
10
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-AGSNTIYZ.js";
|
|
11
14
|
import {
|
|
12
15
|
validatePlan
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import {
|
|
15
|
-
writeStackConfig
|
|
16
|
-
} from "./chunk-55UMO37O.js";
|
|
16
|
+
} from "./chunk-47CGHUVT.js";
|
|
17
17
|
import {
|
|
18
18
|
buildContext
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-SQPHNVCF.js";
|
|
20
20
|
import {
|
|
21
21
|
saveOverlay
|
|
22
22
|
} from "./chunk-6ZFIFDBJ.js";
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
import {
|
|
27
27
|
getConfig,
|
|
28
28
|
setConfig
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-GYMAC4MW.js";
|
|
30
30
|
import {
|
|
31
31
|
UsageError
|
|
32
32
|
} from "./chunk-KGXPLI7W.js";
|
|
@@ -48,13 +48,16 @@ ${validation.errors.join("\n")}`
|
|
|
48
48
|
}
|
|
49
49
|
const { guardOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
|
|
50
50
|
await guardOpenclawVersion(plan.spec.openclaw.version);
|
|
51
|
+
const { enforceInstanceType } = await import("./policy-AZGFCQNV.js");
|
|
52
|
+
const { getConfig: getConfig2 } = await import("./store-BTQOOIJH.js");
|
|
53
|
+
await enforceInstanceType(getConfig2(), plan.spec.provider, plan.spec.instanceType);
|
|
51
54
|
const ctx = buildContext({
|
|
52
55
|
stack: plan.spec.stackName,
|
|
53
56
|
provider: plan.spec.provider
|
|
54
57
|
});
|
|
55
58
|
const stack = await ctx.getStack();
|
|
56
59
|
const { guardPrivateOnlyApply } = await import("./private-only-DIA26I2E.js");
|
|
57
|
-
const { probeSsh } = await import("./tailscale-cutover-
|
|
60
|
+
const { probeSsh } = await import("./tailscale-cutover-XTMGDM5H.js");
|
|
58
61
|
await guardPrivateOnlyApply(plan, ctx, opts?.probeTailnet ?? ((conn2) => probeSsh(conn2, opts?.signal)));
|
|
59
62
|
await writeStackConfig(stack, plan);
|
|
60
63
|
if (plan.metadata.stackVersion !== void 0) {
|
|
@@ -93,7 +96,7 @@ The diff you reviewed may no longer reflect what will be applied.
|
|
|
93
96
|
signal: opts?.signal,
|
|
94
97
|
onProgress: (line) => reportProgress(opts, line)
|
|
95
98
|
});
|
|
96
|
-
const { waitForGateway } = await import("./ready-
|
|
99
|
+
const { waitForGateway } = await import("./ready-4H3NNEYQ.js");
|
|
97
100
|
try {
|
|
98
101
|
await waitForGateway(readySession, {
|
|
99
102
|
signal: opts?.signal,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
requireConfig,
|
|
4
4
|
setConfig
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GYMAC4MW.js";
|
|
6
6
|
|
|
7
7
|
// src/config/stack-delete.ts
|
|
8
8
|
function forgetNotice(name) {
|
|
@@ -47,7 +47,7 @@ async function checkStackDelete(name, opts) {
|
|
|
47
47
|
return { ok: true, name, isDefault, warnings };
|
|
48
48
|
}
|
|
49
49
|
async function isStackDeployed(name) {
|
|
50
|
-
const { buildContext } = await import("./context-
|
|
50
|
+
const { buildContext } = await import("./context-4KTM4DKH.js");
|
|
51
51
|
const ctx = buildContext({ stack: name });
|
|
52
52
|
if (ctx.adapter.name === "local") return !!ctx.localState;
|
|
53
53
|
const stack = await ctx.getStack();
|
|
@@ -10,46 +10,64 @@ import { randomUUID } from "crypto";
|
|
|
10
10
|
import os from "os";
|
|
11
11
|
import path from "path";
|
|
12
12
|
import process from "process";
|
|
13
|
+
import { z as z2 } from "zod";
|
|
14
|
+
|
|
15
|
+
// src/config/policy-schema.ts
|
|
13
16
|
import { z } from "zod";
|
|
14
|
-
var
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
var PolicySchema = z.object({
|
|
18
|
+
/**
|
|
19
|
+
* Per provider, the instance types clawops may deploy. A clawops size (`micro`, `small`,
|
|
20
|
+
* `medium`, `large`) or a provider-native type; sizes are compared after the provider maps
|
|
21
|
+
* them, so `small` and `t3.small` are the same entry on AWS. A provider with no entry is
|
|
22
|
+
* unrestricted.
|
|
23
|
+
*/
|
|
24
|
+
allowedInstanceTypes: z.record(z.array(z.string()).min(1)).optional(),
|
|
25
|
+
/** How many stacks this config may hold. Absent = no cap. */
|
|
26
|
+
maxStacks: z.number().int().positive().optional()
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// src/config/store.ts
|
|
30
|
+
var CredentialsRefSchema = z2.object({
|
|
31
|
+
source: z2.enum(["env", "cli-profile", "file", "instance-metadata"]),
|
|
32
|
+
envVars: z2.array(z2.string()).optional(),
|
|
33
|
+
profileName: z2.string().optional()
|
|
18
34
|
});
|
|
19
|
-
var LocalOptsSchema =
|
|
20
|
-
host:
|
|
21
|
-
sshUser:
|
|
22
|
-
sshPort:
|
|
23
|
-
sshKeyPath:
|
|
35
|
+
var LocalOptsSchema = z2.object({
|
|
36
|
+
host: z2.string(),
|
|
37
|
+
sshUser: z2.string(),
|
|
38
|
+
sshPort: z2.number(),
|
|
39
|
+
sshKeyPath: z2.string()
|
|
24
40
|
});
|
|
25
|
-
var TailscaleOverrideSchema =
|
|
26
|
-
ip:
|
|
27
|
-
hostname:
|
|
41
|
+
var TailscaleOverrideSchema = z2.object({
|
|
42
|
+
ip: z2.string(),
|
|
43
|
+
hostname: z2.string().optional(),
|
|
28
44
|
/** When the address was verified, ISO 8601. */
|
|
29
|
-
verifiedAt:
|
|
45
|
+
verifiedAt: z2.string(),
|
|
30
46
|
/** Set once --private-only has closed the public ports, so revert knows to reopen them. */
|
|
31
|
-
privateOnly:
|
|
47
|
+
privateOnly: z2.boolean().optional()
|
|
32
48
|
});
|
|
33
|
-
var StackConfigSchema =
|
|
34
|
-
provider:
|
|
35
|
-
stateUrl:
|
|
36
|
-
region:
|
|
49
|
+
var StackConfigSchema = z2.object({
|
|
50
|
+
provider: z2.string(),
|
|
51
|
+
stateUrl: z2.string(),
|
|
52
|
+
region: z2.string().optional(),
|
|
37
53
|
credentialsRef: CredentialsRefSchema,
|
|
38
54
|
localOpts: LocalOptsSchema.optional(),
|
|
39
55
|
tailscale: TailscaleOverrideSchema.optional()
|
|
40
56
|
});
|
|
41
|
-
var ClawopsConfigSchema =
|
|
42
|
-
version:
|
|
43
|
-
defaults:
|
|
44
|
-
stack:
|
|
45
|
-
provider:
|
|
57
|
+
var ClawopsConfigSchema = z2.object({
|
|
58
|
+
version: z2.literal(1),
|
|
59
|
+
defaults: z2.object({
|
|
60
|
+
stack: z2.string(),
|
|
61
|
+
provider: z2.string()
|
|
46
62
|
}),
|
|
47
|
-
stacks:
|
|
48
|
-
ssh:
|
|
49
|
-
keyPath:
|
|
50
|
-
knownHostsPath:
|
|
63
|
+
stacks: z2.record(StackConfigSchema),
|
|
64
|
+
ssh: z2.object({
|
|
65
|
+
keyPath: z2.string(),
|
|
66
|
+
knownHostsPath: z2.string()
|
|
51
67
|
}),
|
|
52
|
-
mcp:
|
|
68
|
+
mcp: z2.object({ auditLogPath: z2.string() }).optional(),
|
|
69
|
+
/** The operator's spending policy; see ./policy.ts. */
|
|
70
|
+
policy: PolicySchema.optional()
|
|
53
71
|
});
|
|
54
72
|
function getConfigDir() {
|
|
55
73
|
return process.env["CLAWOPS_HOME"] ?? path.join(os.homedir(), ".clawops");
|
|
@@ -92,6 +110,7 @@ function setConfig(config) {
|
|
|
92
110
|
}
|
|
93
111
|
|
|
94
112
|
export {
|
|
113
|
+
PolicySchema,
|
|
95
114
|
getConfigDir,
|
|
96
115
|
getConfigPath,
|
|
97
116
|
getConfig,
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
} from "./chunk-POYS3EVQ.js";
|
|
5
5
|
import {
|
|
6
6
|
validatePlan
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-47CGHUVT.js";
|
|
8
8
|
import {
|
|
9
9
|
buildContext,
|
|
10
10
|
loadAdapterModule
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-SQPHNVCF.js";
|
|
12
12
|
import {
|
|
13
13
|
getConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-GYMAC4MW.js";
|
|
15
15
|
import {
|
|
16
16
|
StateError,
|
|
17
17
|
UsageError
|
|
@@ -62,9 +62,12 @@ async function resolveInstanceType(intent) {
|
|
|
62
62
|
`[clawops] note: "${requested}" is not a clawops size (${INSTANCE_ALIASES.join(", ")}), so it is passed to ${intent.provider} as written.
|
|
63
63
|
`
|
|
64
64
|
);
|
|
65
|
-
return requested;
|
|
66
65
|
}
|
|
67
|
-
|
|
66
|
+
return nativeInstanceType(intent.provider, requested);
|
|
67
|
+
}
|
|
68
|
+
async function nativeInstanceType(provider, requested) {
|
|
69
|
+
if (!isInstanceAlias(requested)) return requested;
|
|
70
|
+
const adapter = await loadAdapterModule(provider);
|
|
68
71
|
return adapter.normalizeInstanceType(requested);
|
|
69
72
|
}
|
|
70
73
|
var parseDiffForTest = parseDiff;
|
|
@@ -74,9 +77,11 @@ async function generatePlan(intent, _opts) {
|
|
|
74
77
|
"plan/apply is not supported for the local provider. Use `clawops up` directly."
|
|
75
78
|
);
|
|
76
79
|
}
|
|
77
|
-
const { version } = await import("./package-
|
|
80
|
+
const { version } = await import("./package-HRMX7K3C.js");
|
|
78
81
|
const config = getConfig();
|
|
79
82
|
const instanceType = await resolveInstanceType(intent);
|
|
83
|
+
const { enforceInstanceType } = await import("./policy-AZGFCQNV.js");
|
|
84
|
+
await enforceInstanceType(config, intent.provider, instanceType);
|
|
80
85
|
const { guardOpenclawVersion, defaultOpenclawVersion } = await import("./version-guard-XVYW5WFJ.js");
|
|
81
86
|
const openclawVersion = await guardOpenclawVersion(
|
|
82
87
|
intent.openclawVersion ?? await defaultOpenclawVersion()
|
|
@@ -126,7 +131,7 @@ A plan is only as good as the state it was computed against, so this is not a pl
|
|
|
126
131
|
);
|
|
127
132
|
}
|
|
128
133
|
try {
|
|
129
|
-
const { writeStackConfig } = await import("./stack-config-
|
|
134
|
+
const { writeStackConfig } = await import("./stack-config-3E7KWFPI.js");
|
|
130
135
|
await writeStackConfig(stack, plan);
|
|
131
136
|
const outputLines = [];
|
|
132
137
|
const preview = await stack.preview({
|
|
@@ -154,7 +159,7 @@ A plan is only as good as the state it was computed against, so this is not a pl
|
|
|
154
159
|
throw new Error(`Generated plan failed schema validation:
|
|
155
160
|
${validation.errors.join("\n")}`);
|
|
156
161
|
}
|
|
157
|
-
const { validatePlanConfig, validatePlanNetwork } = await import("./validate-
|
|
162
|
+
const { validatePlanConfig, validatePlanNetwork } = await import("./validate-CRXX7OYF.js");
|
|
158
163
|
const cfgCheck = await validatePlanConfig(plan);
|
|
159
164
|
for (const w of cfgCheck.warnings) process.stderr.write(`[clawops] warning: ${w}
|
|
160
165
|
`);
|
|
@@ -186,6 +191,7 @@ function expandHome(p) {
|
|
|
186
191
|
export {
|
|
187
192
|
INSTANCE_ALIASES,
|
|
188
193
|
isInstanceAlias,
|
|
194
|
+
nativeInstanceType,
|
|
189
195
|
parseDiffForTest,
|
|
190
196
|
generatePlan,
|
|
191
197
|
planId
|