@clawops/cli 2.0.0 → 2.0.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.
Files changed (75) hide show
  1. package/README.md +98 -12
  2. package/dist/apply-KYFPWI5U.js +27 -0
  3. package/dist/automation-RMAIBNVC.js +44 -0
  4. package/dist/bedrock-XVASJX2K.js +61 -0
  5. package/dist/{bootstrap-DMRPWJGN.js → bootstrap-HNGKY6WW.js} +11 -8
  6. package/dist/{chunk-N44K3LHE.js → chunk-2I7KCMXZ.js} +6 -4
  7. package/dist/{chunk-3WYA2QDM.js → chunk-2Z7J3ERQ.js} +1 -1
  8. package/dist/chunk-3OLUJPCB.js +36 -0
  9. package/dist/chunk-5XT5IAJK.js +69 -0
  10. package/dist/chunk-AEEMRFZV.js +24 -0
  11. package/dist/{chunk-YR3O2I3S.js → chunk-BSLIYB5Q.js} +6 -1
  12. package/dist/{chunk-AHAAEXWC.js → chunk-E4NJSJ54.js} +16 -93
  13. package/dist/chunk-FEK7VJAY.js +16 -0
  14. package/dist/{chunk-6TIYVHPX.js → chunk-GIEVAGEK.js} +7 -33
  15. package/dist/chunk-HSPHXG6W.js +67 -0
  16. package/dist/{chunk-GYV4KNW7.js → chunk-IVWP4QUJ.js} +133 -40
  17. package/dist/{chunk-AX74VXTV.js → chunk-KC3GC3PE.js} +58 -49
  18. package/dist/{chunk-UFRO4H5W.js → chunk-LBE6COC4.js} +56 -40
  19. package/dist/chunk-LEVIW2PV.js +890 -0
  20. package/dist/chunk-MC5ATCXS.js +108 -0
  21. package/dist/chunk-N4WZLWJ4.js +16 -0
  22. package/dist/{chunk-SBLQH2TJ.js → chunk-NUL5F6YV.js} +1 -1
  23. package/dist/chunk-RHOWYIWT.js +52 -0
  24. package/dist/{chunk-WHJMKDV7.js → chunk-STLRHLLV.js} +65 -12
  25. package/dist/chunk-V25QRZRB.js +45 -0
  26. package/dist/chunk-VOEJYRIK.js +33 -0
  27. package/dist/{providers-2OABPW2E.js → chunk-VUFMZEIM.js} +3 -2
  28. package/dist/chunk-W3OLNNJW.js +51 -0
  29. package/dist/cli-WLD3EBEM.js +11 -0
  30. package/dist/cli-auth-GD5SK7JU.js +13 -0
  31. package/dist/cli.js +518 -206
  32. package/dist/context-7EVC6W45.js +20 -0
  33. package/dist/docker-3PDO4TS7.js +12 -0
  34. package/dist/{firewall-T3NTPZJD.js → firewall-5VKZ4WBH.js} +22 -1
  35. package/dist/generate-I6YQ5V2T.js +29 -0
  36. package/dist/{harden-PCDK3UQ5.js → harden-72JMRT4E.js} +8 -5
  37. package/dist/index.d.ts +56 -0
  38. package/dist/known-hosts-file-I3Q3NBYQ.js +22 -0
  39. package/dist/{logs-P7YCKVF4.js → logs-5A7YYA53.js} +1 -1
  40. package/dist/{mcp-wire-BFEY2Y6H.js → mcp-wire-3SWBM7D6.js} +25 -15
  41. package/dist/models-AGTQWYDL.js +32 -0
  42. package/dist/network-args-PYJRJBYO.js +64 -0
  43. package/dist/{package-3HUW57XH.js → package-5BCMEBTE.js} +10 -3
  44. package/dist/passphrase-MJBE45N7.js +15 -0
  45. package/dist/{pool-EX4ZTA5P.js → pool-PIIKJ4L2.js} +3 -2
  46. package/dist/preflight-EF52S3WW.js +162 -0
  47. package/dist/preflight-MWWM5JT3.js +181 -0
  48. package/dist/preflight-TFD4N5ZU.js +141 -0
  49. package/dist/providers-FW6H6OPF.js +11 -0
  50. package/dist/ready-KDNRBNSU.js +95 -0
  51. package/dist/{remote-config-Z6IIZR3D.js → remote-config-3HZLUWEA.js} +3 -2
  52. package/dist/{runtime-LZ7NA53V.js → runtime-X3KW5TCP.js} +4 -2
  53. package/dist/server-GBA7BJGK.js +46 -0
  54. package/dist/ssh-VAI5DU5M.js +11 -0
  55. package/dist/ssh-key-DUO6OKOI.js +7 -0
  56. package/dist/stack-config-R4SPSUQZ.js +12 -0
  57. package/dist/{validate-BOQRWX4F.js → validate-YVI3BJ55.js} +1 -1
  58. package/dist/wait-WO72TRRQ.js +79 -0
  59. package/package.json +10 -3
  60. package/spec/mcp-tools.yaml +21 -2
  61. package/spec/models.yaml +14 -3
  62. package/spec/providers.schema.json +163 -28
  63. package/dist/apply-AM5HERE7.js +0 -19
  64. package/dist/automation-RULUSJBW.js +0 -30
  65. package/dist/aws-AMON7DA7.js +0 -265
  66. package/dist/azure-T4G6OBJQ.js +0 -273
  67. package/dist/chunk-CKSPROD5.js +0 -129
  68. package/dist/chunk-LU2V3LXA.js +0 -114
  69. package/dist/context-KHKWJJMC.js +0 -10
  70. package/dist/gcp-2JBTD7ZM.js +0 -204
  71. package/dist/generate-2XV2GSP2.js +0 -15
  72. package/dist/local-DXBEVZ5C.js +0 -47
  73. package/dist/server-A5AB67GQ.js +0 -36
  74. package/dist/ssh-B3NZAU4I.js +0 -8
  75. package/dist/{version-guard-GPSTCPT7.js → version-guard-XVYW5WFJ.js} +1 -1
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ buildContext,
4
+ loadAdapterModule
5
+ } from "./chunk-5XT5IAJK.js";
6
+ import "./chunk-LEVIW2PV.js";
7
+ import "./chunk-GIEVAGEK.js";
8
+ import "./chunk-VOEJYRIK.js";
9
+ import "./chunk-EI7CQQ7D.js";
10
+ import "./chunk-FEK7VJAY.js";
11
+ import "./chunk-RHOWYIWT.js";
12
+ import "./chunk-N4WZLWJ4.js";
13
+ import "./chunk-A2I76FTA.js";
14
+ import "./chunk-CX5SL5HP.js";
15
+ import "./chunk-KGXPLI7W.js";
16
+ import "./chunk-VUFMZEIM.js";
17
+ export {
18
+ buildContext,
19
+ loadAdapterModule
20
+ };
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ containerStatus,
4
+ inspectContainer,
5
+ looksLikeStillBooting
6
+ } from "./chunk-3OLUJPCB.js";
7
+ import "./chunk-NUDIHZEH.js";
8
+ export {
9
+ containerStatus,
10
+ inspectContainer,
11
+ looksLikeStillBooting
12
+ };
@@ -32,7 +32,10 @@ function resolveIngressCidrs(accessMode, allowedCidrs, portOverride, egressResul
32
32
  }
33
33
  async function detectEgressIp(checkUrl) {
34
34
  try {
35
- const res = await fetch(checkUrl, { signal: AbortSignal.timeout(3e3) });
35
+ const res = await fetch(checkUrl, {
36
+ signal: AbortSignal.timeout(3e3),
37
+ headers: { accept: "text/plain" }
38
+ });
36
39
  if (!res.ok) {
37
40
  return { ok: false, error: `HTTP ${res.status} from ${checkUrl}` };
38
41
  }
@@ -40,11 +43,28 @@ async function detectEgressIp(checkUrl) {
40
43
  if (!ip) {
41
44
  return { ok: false, error: `empty response from ${checkUrl}` };
42
45
  }
46
+ if (!isIpAddress(ip)) {
47
+ return {
48
+ ok: false,
49
+ error: `${checkUrl} did not return an IP address (got ${summarise(ip)})`
50
+ };
51
+ }
43
52
  return { ok: true, ip };
44
53
  } catch (err) {
45
54
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
46
55
  }
47
56
  }
57
+ function isIpAddress(value) {
58
+ const v = value.trim();
59
+ if (/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.test(v)) {
60
+ return v.split(".").every((o) => Number(o) <= 255);
61
+ }
62
+ return /^[0-9a-fA-F:]+$/.test(v) && v.includes(":");
63
+ }
64
+ function summarise(body) {
65
+ const oneLine = body.replace(/\s+/g, " ").trim();
66
+ return oneLine.length > 40 ? `${oneLine.slice(0, 40)}\u2026` : oneLine;
67
+ }
48
68
  function resolveGatewayIngressCidrs(publishGateway, accessMode, allowedCidrs, portOverride, egressResult) {
49
69
  if (publishGateway !== "all") return [];
50
70
  return resolveIngressCidrs(accessMode, allowedCidrs, portOverride, egressResult);
@@ -55,6 +75,7 @@ function resolveGatewayPort(raw, fallback) {
55
75
  }
56
76
  export {
57
77
  detectEgressIp,
78
+ isIpAddress,
58
79
  resolveGatewayIngressCidrs,
59
80
  resolveGatewayPort,
60
81
  resolveIngressCidrs
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ INSTANCE_ALIASES,
4
+ generatePlan,
5
+ isInstanceAlias,
6
+ parseDiffForTest,
7
+ planId
8
+ } from "./chunk-STLRHLLV.js";
9
+ import "./chunk-BSLIYB5Q.js";
10
+ import "./chunk-5XT5IAJK.js";
11
+ import "./chunk-JW5A7E3X.js";
12
+ import "./chunk-LEVIW2PV.js";
13
+ import "./chunk-GIEVAGEK.js";
14
+ import "./chunk-VOEJYRIK.js";
15
+ import "./chunk-EI7CQQ7D.js";
16
+ import "./chunk-FEK7VJAY.js";
17
+ import "./chunk-RHOWYIWT.js";
18
+ import "./chunk-N4WZLWJ4.js";
19
+ import "./chunk-A2I76FTA.js";
20
+ import "./chunk-CX5SL5HP.js";
21
+ import "./chunk-KGXPLI7W.js";
22
+ import "./chunk-VUFMZEIM.js";
23
+ export {
24
+ INSTANCE_ALIASES,
25
+ generatePlan,
26
+ isInstanceAlias,
27
+ parseDiffForTest,
28
+ planId
29
+ };
@@ -2,16 +2,19 @@
2
2
  import {
3
3
  acquireSession,
4
4
  drainPool
5
- } from "./chunk-3WYA2QDM.js";
6
- import "./chunk-AHAAEXWC.js";
7
- import "./chunk-KGXPLI7W.js";
5
+ } from "./chunk-2Z7J3ERQ.js";
6
+ import "./chunk-E4NJSJ54.js";
7
+ import "./chunk-MC5ATCXS.js";
8
8
  import {
9
- GATEWAY_PORT,
10
9
  PUBLISH_INSPECT_CMD,
11
10
  publishForRestart,
12
11
  publishedGatewayPort
13
- } from "./chunk-6TIYVHPX.js";
12
+ } from "./chunk-GIEVAGEK.js";
13
+ import {
14
+ GATEWAY_PORT
15
+ } from "./chunk-VOEJYRIK.js";
14
16
  import "./chunk-EI7CQQ7D.js";
17
+ import "./chunk-KGXPLI7W.js";
15
18
 
16
19
  // src/harden/types.ts
17
20
  var SENTINEL_DIR = "/etc/clawops/hardening";
package/dist/index.d.ts CHANGED
@@ -47,6 +47,62 @@ interface ProviderAdapter {
47
47
  stateBackendUrl(bucket: string): string;
48
48
  /** Validate provider-specific config (env vars, profiles) at startup. */
49
49
  validateConfig(): Promise<ValidationResult>;
50
+ /**
51
+ * Account-level setup this provider needs before anything can be provisioned.
52
+ *
53
+ * Not infrastructure: enabling an API or creating a state bucket happens outside the
54
+ * Pulumi program, because the state backend has to exist before Pulumi can run at all.
55
+ * Optional — a provider with nothing to check omits it.
56
+ */
57
+ preflight?(opts: PreflightOpts): Promise<PreflightCheck[]>;
58
+ }
59
+ interface PreflightOpts {
60
+ /** Where the stack will be deployed, when that changes what must be enabled. */
61
+ region?: string;
62
+ /** State backend bucket or container, when the check covers it. */
63
+ bucket?: string;
64
+ /**
65
+ * The machine size about to be deployed, when the caller knows it.
66
+ *
67
+ * Azure offers SKU families per subscription, so "is this size available here" can only be
68
+ * answered about a specific size. Without this the check falls back to the provider's
69
+ * default alias, which is right for a default deploy and wrong for anyone passing
70
+ * --instance-type: a deployment using an available size would be reported as broken.
71
+ */
72
+ instanceType?: string;
73
+ signal?: AbortSignal;
74
+ }
75
+ interface PreflightCheck {
76
+ /** Stable kebab-case id, e.g. "compute-api-enabled". */
77
+ id: string;
78
+ /** What is being checked, in the operator's terms. */
79
+ label: string;
80
+ ok: boolean;
81
+ /**
82
+ * clawops could not put the question — a denied read permission, an API that would not
83
+ * answer. Neither a pass nor a failure: the operator's account may be perfectly set up, and
84
+ * saying so would be a claim clawops cannot make.
85
+ *
86
+ * Dropping the check instead is worse. An operator whose credentials lack a read permission
87
+ * then sees one fewer line than everyone else and never learns why. The detail field carries
88
+ * the reason, and doctor renders these as warnings rather than failing the report over a
89
+ * question it could not ask.
90
+ */
91
+ unknown?: boolean;
92
+ /** Why it failed, and what it means — shown when ok is false. */
93
+ detail?: string;
94
+ /**
95
+ * Applies the fix. Absent when clawops cannot fix it: a missing permission or an unpaid
96
+ * billing account is not clawops's to resolve, and pretending otherwise wastes a prompt.
97
+ */
98
+ fix?: () => Promise<void>;
99
+ /**
100
+ * What the fix changes in the operator's cloud account.
101
+ *
102
+ * Shown in the prompt, and required alongside fix(): consent to 'fix it' is not consent to
103
+ * something unnamed.
104
+ */
105
+ mutates?: string;
50
106
  }
51
107
 
52
108
  export type { BaseStackOutputs, ConnectionInfo, CredentialSource, InstanceAlias, ProviderAdapter, ProviderName, PulumiFn, StackOutputs, StateBackendScheme, ValidationResult };
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ withoutHost
4
+ } from "./chunk-MC5ATCXS.js";
5
+
6
+ // src/transport/known-hosts-file.ts
7
+ import { readFileSync, writeFileSync } from "fs";
8
+ function forgetHost(knownHostsPath, host, port) {
9
+ let content;
10
+ try {
11
+ content = readFileSync(knownHostsPath, "utf-8");
12
+ } catch {
13
+ return false;
14
+ }
15
+ const next = withoutHost(content, host, port);
16
+ if (next === content) return false;
17
+ writeFileSync(knownHostsPath, next, "utf-8");
18
+ return true;
19
+ }
20
+ export {
21
+ forgetHost
22
+ };
@@ -5,7 +5,7 @@ import {
5
5
  chooseLogSource,
6
6
  containerLogsCommand,
7
7
  gatewayLogsCommand
8
- } from "./chunk-SBLQH2TJ.js";
8
+ } from "./chunk-NUL5F6YV.js";
9
9
  export {
10
10
  GATEWAY_LOGS_PROBE,
11
11
  agentAuditCommand,
@@ -1,30 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MCP_HTTP_PORT
4
- } from "./chunk-AX74VXTV.js";
5
- import "./chunk-UFRO4H5W.js";
6
- import "./chunk-N44K3LHE.js";
7
- import "./chunk-3QJBNAHW.js";
8
- import "./chunk-WHJMKDV7.js";
9
- import "./chunk-YR3O2I3S.js";
10
- import "./chunk-6ZFIFDBJ.js";
11
- import "./chunk-3WYA2QDM.js";
12
- import "./chunk-AHAAEXWC.js";
4
+ } from "./chunk-KC3GC3PE.js";
5
+ import "./chunk-LBE6COC4.js";
13
6
  import "./chunk-BOPSG2LI.js";
14
- import "./chunk-LU2V3LXA.js";
15
- import "./chunk-GYV4KNW7.js";
16
- import "./chunk-SBLQH2TJ.js";
17
- import "./chunk-LT4XMO5D.js";
7
+ import "./chunk-6ZFIFDBJ.js";
8
+ import "./chunk-3QJBNAHW.js";
9
+ import "./chunk-2I7KCMXZ.js";
10
+ import "./chunk-HSPHXG6W.js";
11
+ import "./chunk-AEEMRFZV.js";
12
+ import "./chunk-STLRHLLV.js";
13
+ import "./chunk-BSLIYB5Q.js";
14
+ import "./chunk-2Z7J3ERQ.js";
15
+ import "./chunk-E4NJSJ54.js";
16
+ import "./chunk-MC5ATCXS.js";
17
+ import "./chunk-5XT5IAJK.js";
18
+ import "./chunk-IVWP4QUJ.js";
19
+ import "./chunk-NUL5F6YV.js";
20
+ import "./chunk-3OLUJPCB.js";
18
21
  import {
19
22
  execPrivileged
20
23
  } from "./chunk-NUDIHZEH.js";
21
24
  import "./chunk-JW5A7E3X.js";
25
+ import "./chunk-LT4XMO5D.js";
26
+ import "./chunk-LEVIW2PV.js";
27
+ import "./chunk-GIEVAGEK.js";
28
+ import "./chunk-VOEJYRIK.js";
29
+ import "./chunk-EI7CQQ7D.js";
30
+ import "./chunk-FEK7VJAY.js";
31
+ import "./chunk-RHOWYIWT.js";
22
32
  import "./chunk-Q7NQY5HV.js";
33
+ import "./chunk-N4WZLWJ4.js";
23
34
  import "./chunk-A2I76FTA.js";
24
35
  import "./chunk-CX5SL5HP.js";
25
36
  import "./chunk-KGXPLI7W.js";
26
- import "./chunk-6TIYVHPX.js";
27
- import "./chunk-EI7CQQ7D.js";
37
+ import "./chunk-VUFMZEIM.js";
28
38
 
29
39
  // src/cli/mcp-wire.ts
30
40
  var GATEWAY_MCP_NAME = "clawops";
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/openclaw/models.ts
4
+ function providerKeyOf(provider) {
5
+ const fromPath = provider.configPath?.split(".").pop();
6
+ return fromPath && fromPath.length > 0 ? fromPath : provider.id;
7
+ }
8
+ function buildModelsBlock(opts) {
9
+ const { provider, model, apiKeyRef, baseUrl, region } = opts;
10
+ const key = providerKeyOf(provider);
11
+ const modelId = opts.resolvedModelId ?? model.modelId ?? model.id;
12
+ const entry = {};
13
+ if (provider.api) entry["api"] = provider.api;
14
+ if (region) entry["region"] = region;
15
+ if (apiKeyRef) entry["apiKey"] = apiKeyRef;
16
+ if (baseUrl) entry["baseUrl"] = baseUrl;
17
+ if (provider.credentialSource === "aws-profile") {
18
+ entry["auth"] = "aws-sdk";
19
+ }
20
+ entry["models"] = [
21
+ {
22
+ id: modelId,
23
+ name: model.displayName,
24
+ ...provider.api ? { api: provider.api } : {}
25
+ }
26
+ ];
27
+ return { providers: { [key]: entry } };
28
+ }
29
+ export {
30
+ buildModelsBlock,
31
+ providerKeyOf
32
+ };
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ UsageError
4
+ } from "./chunk-KGXPLI7W.js";
5
+
6
+ // src/plan/network-args.ts
7
+ function isCidr(value) {
8
+ const v = value.trim();
9
+ if (v.includes(":")) return true;
10
+ return /^(\d{1,3}\.){3}\d{1,3}\/(3[0-2]|[12]?\d)$/.test(v);
11
+ }
12
+ function parseCidrList(flag, value) {
13
+ const parts = value.split(",").map((s) => s.trim()).filter((s) => s !== "");
14
+ for (const p of parts) {
15
+ if (!isCidr(p)) {
16
+ throw new UsageError(
17
+ `${flag}: "${p}" is not a CIDR. Use an address and a prefix, e.g. 203.0.113.4/32.`
18
+ );
19
+ }
20
+ }
21
+ return parts;
22
+ }
23
+ function parsePublishGateway(value) {
24
+ const v = value.trim();
25
+ if (v === "loopback" || v === "all") return v;
26
+ throw new UsageError(`--publish-gateway: expected "loopback" or "all", got "${v}".`);
27
+ }
28
+ async function resolveNetworkFlags(flags, deps) {
29
+ const resolved = { allowedSshCidrs: [], allowedGatewayCidrs: [] };
30
+ for (const [flag, raw, key] of [
31
+ ["--ssh-cidr", flags.sshCidr, "allowedSshCidrs"],
32
+ ["--gateway-cidr", flags.gatewayCidr, "allowedGatewayCidrs"]
33
+ ]) {
34
+ if (raw === void 0) continue;
35
+ resolved[key] = raw.trim() === "auto" ? [await autoCidr(flag, deps.detectEgressIp)] : parseCidrList(flag, raw);
36
+ }
37
+ if (flags.publishGateway !== void 0) {
38
+ resolved.publishGateway = parsePublishGateway(flags.publishGateway);
39
+ }
40
+ return resolved;
41
+ }
42
+ async function autoCidr(flag, detect) {
43
+ const result = await detect();
44
+ if (!result.ok || result.ip.trim() === "") {
45
+ const why = result.ok ? "the lookup returned an empty address" : result.error;
46
+ throw new UsageError(
47
+ `${flag} auto: could not detect this machine's public IP \u2014 ${why}. Pass the CIDR explicitly, e.g. 203.0.113.4/32.`
48
+ );
49
+ }
50
+ const ip = result.ip.trim();
51
+ const cidr = ip.includes("/") ? ip : `${ip}/32`;
52
+ if (!isCidr(cidr)) {
53
+ throw new UsageError(
54
+ `${flag} auto: the detected address "${ip}" is not usable as a CIDR. Pass the CIDR explicitly, e.g. 203.0.113.4/32.`
55
+ );
56
+ }
57
+ return cidr;
58
+ }
59
+ export {
60
+ isCidr,
61
+ parseCidrList,
62
+ parsePublishGateway,
63
+ resolveNetworkFlags
64
+ };
@@ -2,7 +2,7 @@
2
2
 
3
3
  // package.json
4
4
  var name = "@clawops/cli";
5
- var version = "2.0.0";
5
+ var version = "2.0.1";
6
6
  var description = "Deploy and manage self-hosted OpenClaw instances across clouds";
7
7
  var type = "module";
8
8
  var bin = {
@@ -36,18 +36,23 @@ var scripts = {
36
36
  "test:pulumi": "vitest run tests/providers/aws/program.test.ts tests/providers/azure/program.test.ts",
37
37
  "test:changed": "vitest --changed",
38
38
  "test:integration": "vitest run --config vitest.integration.config.ts",
39
+ "test:cloud": "bash scripts/e2e/cloud.sh",
39
40
  typecheck: "NODE_OPTIONS=--max-old-space-size=4096 tsc --noEmit",
40
41
  lint: "eslint --max-warnings=0 src tests scripts",
41
42
  "gen:schemas": "tsx scripts/gen-schemas.ts",
42
43
  changeset: "changeset",
43
44
  release: "pnpm build && changeset publish",
44
- "test:mutation": "node scripts/dev/mutation-check.mjs"
45
+ "test:mutation": "node scripts/dev/mutation-check.mjs",
46
+ graph: "node scripts/dev/graph.mjs"
45
47
  };
46
48
  var dependencies = {
49
+ "@aws-sdk/client-bedrock": "^3.1063.0",
47
50
  "@aws-sdk/client-cloudwatch-logs": "^3.1063.0",
48
51
  "@aws-sdk/client-ec2": "^3.1063.0",
49
52
  "@aws-sdk/client-guardduty": "^3.1063.0",
50
53
  "@aws-sdk/client-iam": "^3.1063.0",
54
+ "@aws-sdk/client-s3": "3.1132.0",
55
+ "@aws-sdk/client-sts": "3.1132.0",
51
56
  "@modelcontextprotocol/sdk": "^1.0.0",
52
57
  "@pulumi/aws": "^6.0.0",
53
58
  "@pulumi/azure-native": "^2.0.0",
@@ -61,6 +66,7 @@ var dependencies = {
61
66
  chalk: "^5.0.0",
62
67
  citty: "^0.1.0",
63
68
  conf: "^12.0.0",
69
+ "google-auth-library": "^11.0.2",
64
70
  inquirer: "^9.0.0",
65
71
  ora: "^8.0.0",
66
72
  ssh2: "^1.0.0",
@@ -85,7 +91,8 @@ var devDependencies = {
85
91
  };
86
92
  var pnpm = {
87
93
  overrides: {
88
- "@pulumi/pulumi": "^3.0.0"
94
+ "@pulumi/pulumi": "^3.0.0",
95
+ "@smithy/types": "4.14.3"
89
96
  },
90
97
  onlyBuiltDependencies: [
91
98
  "@pulumi/command",
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ PASSPHRASE_FILE,
4
+ ensurePassphrase,
5
+ passphraseInEnvironment,
6
+ passphrasePath,
7
+ passphraseStatus
8
+ } from "./chunk-V25QRZRB.js";
9
+ export {
10
+ PASSPHRASE_FILE,
11
+ ensurePassphrase,
12
+ passphraseInEnvironment,
13
+ passphrasePath,
14
+ passphraseStatus
15
+ };
@@ -2,8 +2,9 @@
2
2
  import {
3
3
  acquireSession,
4
4
  drainPool
5
- } from "./chunk-3WYA2QDM.js";
6
- import "./chunk-AHAAEXWC.js";
5
+ } from "./chunk-2Z7J3ERQ.js";
6
+ import "./chunk-E4NJSJ54.js";
7
+ import "./chunk-MC5ATCXS.js";
7
8
  import "./chunk-KGXPLI7W.js";
8
9
  export {
9
10
  acquireSession,
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/providers/gcp/preflight.ts
4
+ import process from "process";
5
+ import path from "path";
6
+ import { readFileSync } from "fs";
7
+ var REQUIRED_APIS = [
8
+ { service: "compute.googleapis.com", why: "Instance, Network, Subnetwork, Firewall, Address" },
9
+ { service: "storage.googleapis.com", why: "the GCS state backend" }
10
+ ];
11
+ async function accessToken() {
12
+ try {
13
+ const { GoogleAuth } = await import("google-auth-library");
14
+ const auth = new GoogleAuth({ scopes: ["https://www.googleapis.com/auth/cloud-platform"] });
15
+ const client = await auth.getClient();
16
+ const token = await client.getAccessToken();
17
+ return typeof token === "string" ? token : token.token ?? void 0;
18
+ } catch {
19
+ return void 0;
20
+ }
21
+ }
22
+ function resolveProjectId() {
23
+ return process.env["GOOGLE_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"] ?? process.env["CLOUDSDK_CORE_PROJECT"] ?? gcloudConfiguredProject() ?? void 0;
24
+ }
25
+ function gcloudConfiguredProject() {
26
+ try {
27
+ const home = process.env["HOME"] ?? process.env["USERPROFILE"];
28
+ const dir = process.env["CLOUDSDK_CONFIG"] ?? (home ? path.join(home, ".config", "gcloud") : void 0);
29
+ if (!dir) return void 0;
30
+ const active = process.env["CLOUDSDK_ACTIVE_CONFIG_NAME"] ?? readFileSync(path.join(dir, "active_config"), "utf-8").trim() ?? "default";
31
+ if (!active) return void 0;
32
+ const ini = readFileSync(path.join(dir, "configurations", `config_${active}`), "utf-8");
33
+ return projectFromIni(ini);
34
+ } catch {
35
+ return void 0;
36
+ }
37
+ }
38
+ function projectFromIni(ini) {
39
+ let section = "";
40
+ for (const line of ini.split(/\r?\n/)) {
41
+ const trimmed = line.trim();
42
+ if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith(";")) continue;
43
+ const header = /^\[(.+)\]$/.exec(trimmed);
44
+ if (header) {
45
+ section = header[1]?.trim() ?? "";
46
+ continue;
47
+ }
48
+ if (section !== "core") continue;
49
+ const eq = trimmed.indexOf("=");
50
+ if (eq === -1) continue;
51
+ if (trimmed.slice(0, eq).trim() !== "project") continue;
52
+ const value = trimmed.slice(eq + 1).trim();
53
+ return value === "" ? void 0 : value;
54
+ }
55
+ return void 0;
56
+ }
57
+ async function gcpPreflight(opts = {}) {
58
+ const checks = [];
59
+ const project = resolveProjectId();
60
+ checks.push({
61
+ id: "project-resolved",
62
+ label: "GCP project is set",
63
+ ok: Boolean(project),
64
+ detail: project ? `Deploying into ${project}` : "No project resolved. Run `gcloud config set project <id>`, or set GOOGLE_PROJECT."
65
+ });
66
+ if (!project) return checks;
67
+ const token = await accessToken();
68
+ if (!token) {
69
+ checks.push({
70
+ id: "adc-usable",
71
+ label: "Application Default Credentials resolve",
72
+ ok: false,
73
+ detail: "Could not obtain a token from ADC. Run `gcloud auth application-default login` \u2014 `gcloud auth login` alone authenticates the CLI and leaves ADC unset."
74
+ });
75
+ return checks;
76
+ }
77
+ const enabled = await enabledServices(project, token, opts.signal);
78
+ for (const api of REQUIRED_APIS) {
79
+ const on = enabled?.has(api.service) ?? false;
80
+ checks.push({
81
+ id: `api-${api.service.split(".")[0]}`,
82
+ label: `${api.service} enabled`,
83
+ ok: on,
84
+ detail: on ? void 0 : `Needed for ${api.why}. Nothing can be provisioned without it.`,
85
+ mutates: on ? void 0 : `Enables ${api.service} on project ${project}`,
86
+ fix: on ? void 0 : async () => {
87
+ await enableService(project, api.service, token);
88
+ }
89
+ });
90
+ }
91
+ if (opts.bucket) {
92
+ const exists = await bucketExists(opts.bucket, token, opts.signal);
93
+ checks.push({
94
+ id: "state-bucket",
95
+ label: `State bucket gs://${opts.bucket} exists`,
96
+ ok: exists,
97
+ detail: exists ? void 0 : "Pulumi needs its state backend before it can run, so clawops cannot create this as part of a deploy.",
98
+ mutates: exists ? void 0 : `Creates bucket gs://${opts.bucket} in project ${project}${opts.region ? ` (${opts.region})` : ""}, with versioning on`,
99
+ fix: exists ? void 0 : async () => {
100
+ await createBucket(opts.bucket, project, token, opts.region);
101
+ }
102
+ });
103
+ }
104
+ return checks;
105
+ }
106
+ async function enabledServices(project, token, signal) {
107
+ try {
108
+ const out = /* @__PURE__ */ new Set();
109
+ let pageToken;
110
+ do {
111
+ const url = `https://serviceusage.googleapis.com/v1/projects/${project}/services?filter=state:ENABLED&pageSize=200${pageToken ? `&pageToken=${pageToken}` : ""}`;
112
+ const res = await fetch(url, { headers: { authorization: `Bearer ${token}` }, signal });
113
+ if (!res.ok) return void 0;
114
+ const body = await res.json();
115
+ for (const s of body.services ?? []) if (s.config?.name) out.add(s.config.name);
116
+ pageToken = body.nextPageToken;
117
+ } while (pageToken);
118
+ return out;
119
+ } catch {
120
+ return void 0;
121
+ }
122
+ }
123
+ async function enableService(project, service, token) {
124
+ const res = await fetch(
125
+ `https://serviceusage.googleapis.com/v1/projects/${project}/services/${service}:enable`,
126
+ { method: "POST", headers: { authorization: `Bearer ${token}` } }
127
+ );
128
+ if (!res.ok) {
129
+ throw new Error(`Could not enable ${service}: ${res.status} ${await res.text()}`);
130
+ }
131
+ }
132
+ async function bucketExists(bucket, token, signal) {
133
+ const res = await fetch(`https://storage.googleapis.com/storage/v1/b/${bucket}`, {
134
+ headers: { authorization: `Bearer ${token}` },
135
+ signal
136
+ });
137
+ return res.ok;
138
+ }
139
+ async function createBucket(bucket, project, token, region) {
140
+ const res = await fetch(
141
+ `https://storage.googleapis.com/storage/v1/b?project=${project}`,
142
+ {
143
+ method: "POST",
144
+ headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
145
+ body: JSON.stringify({
146
+ name: bucket,
147
+ location: (region ?? "US").toUpperCase(),
148
+ // Versioning on, because this holds Pulumi state: a corrupted or truncated write
149
+ // with no history is a stack that can no longer be updated or destroyed.
150
+ versioning: { enabled: true },
151
+ iamConfiguration: { uniformBucketLevelAccess: { enabled: true } }
152
+ })
153
+ }
154
+ );
155
+ if (!res.ok) throw new Error(`Could not create gs://${bucket}: ${res.status} ${await res.text()}`);
156
+ }
157
+ export {
158
+ gcloudConfiguredProject,
159
+ gcpPreflight,
160
+ projectFromIni,
161
+ resolveProjectId
162
+ };