clawup 1.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 +245 -0
- package/dist/adapters/api-adapter.d.ts +76 -0
- package/dist/adapters/api-adapter.js +250 -0
- package/dist/adapters/api-adapter.js.map +1 -0
- package/dist/adapters/cli-adapter.d.ts +15 -0
- package/dist/adapters/cli-adapter.js +208 -0
- package/dist/adapters/cli-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +22 -0
- package/dist/adapters/index.js +32 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/types.d.ts +135 -0
- package/dist/adapters/types.js +14 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/bin.d.ts +8 -0
- package/dist/bin.js +221 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/config.d.ts +21 -0
- package/dist/commands/config.js +323 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/deploy.d.ts +7 -0
- package/dist/commands/deploy.js +13 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/destroy.d.ts +7 -0
- package/dist/commands/destroy.js +13 -0
- package/dist/commands/destroy.js.map +1 -0
- package/dist/commands/init.d.ts +13 -0
- package/dist/commands/init.js +698 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +8 -0
- package/dist/commands/list.js +42 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/push.d.ts +7 -0
- package/dist/commands/push.js +19 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/redeploy.d.ts +7 -0
- package/dist/commands/redeploy.js +13 -0
- package/dist/commands/redeploy.js.map +1 -0
- package/dist/commands/secrets.d.ts +16 -0
- package/dist/commands/secrets.js +169 -0
- package/dist/commands/secrets.js.map +1 -0
- package/dist/commands/ssh.d.ts +9 -0
- package/dist/commands/ssh.js +108 -0
- package/dist/commands/ssh.js.map +1 -0
- package/dist/commands/status.d.ts +7 -0
- package/dist/commands/status.js +13 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +7 -0
- package/dist/commands/update.js +126 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.js +13 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/webhooks.d.ts +7 -0
- package/dist/commands/webhooks.js +13 -0
- package/dist/commands/webhooks.js.map +1 -0
- package/dist/lib/__tests__/identity.test.d.ts +1 -0
- package/dist/lib/__tests__/identity.test.js +186 -0
- package/dist/lib/__tests__/identity.test.js.map +1 -0
- package/dist/lib/__tests__/validate-agent.test.d.ts +1 -0
- package/dist/lib/__tests__/validate-agent.test.js +38 -0
- package/dist/lib/__tests__/validate-agent.test.js.map +1 -0
- package/dist/lib/config.d.ts +69 -0
- package/dist/lib/config.js +218 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +5 -0
- package/dist/lib/constants.js +29 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/exec.d.ts +24 -0
- package/dist/lib/exec.js +63 -0
- package/dist/lib/exec.js.map +1 -0
- package/dist/lib/prerequisites.d.ts +8 -0
- package/dist/lib/prerequisites.js +146 -0
- package/dist/lib/prerequisites.js.map +1 -0
- package/dist/lib/process.d.ts +18 -0
- package/dist/lib/process.js +37 -0
- package/dist/lib/process.js.map +1 -0
- package/dist/lib/pulumi.d.ts +37 -0
- package/dist/lib/pulumi.js +87 -0
- package/dist/lib/pulumi.js.map +1 -0
- package/dist/lib/tailscale.d.ts +75 -0
- package/dist/lib/tailscale.js +251 -0
- package/dist/lib/tailscale.js.map +1 -0
- package/dist/lib/tool-helpers.d.ts +15 -0
- package/dist/lib/tool-helpers.js +35 -0
- package/dist/lib/tool-helpers.js.map +1 -0
- package/dist/lib/ui.d.ts +26 -0
- package/dist/lib/ui.js +86 -0
- package/dist/lib/ui.js.map +1 -0
- package/dist/lib/update-check.d.ts +8 -0
- package/dist/lib/update-check.js +151 -0
- package/dist/lib/update-check.js.map +1 -0
- package/dist/lib/vendor.d.ts +34 -0
- package/dist/lib/vendor.js +128 -0
- package/dist/lib/vendor.js.map +1 -0
- package/dist/lib/workspace.d.ts +21 -0
- package/dist/lib/workspace.js +170 -0
- package/dist/lib/workspace.js.map +1 -0
- package/dist/tools/deploy.d.ts +16 -0
- package/dist/tools/deploy.js +181 -0
- package/dist/tools/deploy.js.map +1 -0
- package/dist/tools/destroy.d.ts +16 -0
- package/dist/tools/destroy.js +119 -0
- package/dist/tools/destroy.js.map +1 -0
- package/dist/tools/index.d.ts +20 -0
- package/dist/tools/index.js +34 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/push.d.ts +29 -0
- package/dist/tools/push.js +341 -0
- package/dist/tools/push.js.map +1 -0
- package/dist/tools/redeploy.d.ts +17 -0
- package/dist/tools/redeploy.js +181 -0
- package/dist/tools/redeploy.js.map +1 -0
- package/dist/tools/status.d.ts +16 -0
- package/dist/tools/status.js +205 -0
- package/dist/tools/status.js.map +1 -0
- package/dist/tools/validate.d.ts +16 -0
- package/dist/tools/validate.js +219 -0
- package/dist/tools/validate.js.map +1 -0
- package/dist/tools/webhooks.d.ts +17 -0
- package/dist/tools/webhooks.js +181 -0
- package/dist/tools/webhooks.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/infra/Pulumi.yaml +6 -0
- package/infra/dist/components/cloud-init.js +412 -0
- package/infra/dist/components/config-generator.js +254 -0
- package/infra/dist/components/hetzner-agent.js +162 -0
- package/infra/dist/components/index.js +18 -0
- package/infra/dist/components/openclaw-agent.js +287 -0
- package/infra/dist/components/shared.js +132 -0
- package/infra/dist/components/types.js +6 -0
- package/infra/dist/index.js +387 -0
- package/infra/dist/shared-vpc.js +167 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts +2 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js +124 -0
- package/infra/node_modules/@clawup/core/dist/__tests__/schemas.test.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts +32 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js +56 -0
- package/infra/node_modules/@clawup/core/dist/coding-agent-registry.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/constants.d.ts +137 -0
- package/infra/node_modules/@clawup/core/dist/constants.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/constants.js +314 -0
- package/infra/node_modules/@clawup/core/dist/constants.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts +25 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.js +46 -0
- package/infra/node_modules/@clawup/core/dist/dep-registry.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/deps.d.ts +18 -0
- package/infra/node_modules/@clawup/core/dist/deps.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/deps.js +39 -0
- package/infra/node_modules/@clawup/core/dist/deps.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/identity.d.ts +20 -0
- package/infra/node_modules/@clawup/core/dist/identity.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/identity.js +217 -0
- package/infra/node_modules/@clawup/core/dist/identity.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/index.d.ts +18 -0
- package/infra/node_modules/@clawup/core/dist/index.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/index.js +52 -0
- package/infra/node_modules/@clawup/core/dist/index.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts +13 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.js +24 -0
- package/infra/node_modules/@clawup/core/dist/plugin-registry.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts +74 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.js +45 -0
- package/infra/node_modules/@clawup/core/dist/schemas/identity.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts +6 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.js +13 -0
- package/infra/node_modules/@clawup/core/dist/schemas/index.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts +159 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.js +54 -0
- package/infra/node_modules/@clawup/core/dist/schemas/manifest.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/skills.d.ts +30 -0
- package/infra/node_modules/@clawup/core/dist/skills.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/skills.js +52 -0
- package/infra/node_modules/@clawup/core/dist/skills.js.map +1 -0
- package/infra/node_modules/@clawup/core/dist/types.d.ts +59 -0
- package/infra/node_modules/@clawup/core/dist/types.d.ts.map +1 -0
- package/infra/node_modules/@clawup/core/dist/types.js +30 -0
- package/infra/node_modules/@clawup/core/dist/types.js.map +1 -0
- package/infra/node_modules/@clawup/core/package.json +46 -0
- package/infra/package.json +12 -0
- package/package.json +43 -0
- package/scripts/postinstall.mjs +395 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Postinstall script for clawup CLI
|
|
5
|
+
*
|
|
6
|
+
* Downloads vendored binaries (Pulumi CLI, AWS CLI v2) for the current
|
|
7
|
+
* platform to cli/vendor/. Runs automatically after `npm install`.
|
|
8
|
+
*
|
|
9
|
+
* Versions and checksums are fetched dynamically:
|
|
10
|
+
* - Pulumi: latest release from GitHub API, checksums from release assets
|
|
11
|
+
* - AWS CLI: latest from AWS, checksums from .sha256 sidecar files
|
|
12
|
+
*
|
|
13
|
+
* If downloads fail (network issues, unsupported platform), the CLI
|
|
14
|
+
* falls back to system PATH binaries — this is not a fatal error.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from "node:fs";
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
import os from "node:os";
|
|
20
|
+
import https from "node:https";
|
|
21
|
+
import crypto from "node:crypto";
|
|
22
|
+
import { execSync } from "node:child_process";
|
|
23
|
+
|
|
24
|
+
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
25
|
+
const VENDOR_DIR = path.join(__dirname, "..", "vendor");
|
|
26
|
+
|
|
27
|
+
function getPlatform() {
|
|
28
|
+
const platform = process.platform;
|
|
29
|
+
const arch = process.arch;
|
|
30
|
+
|
|
31
|
+
let osName;
|
|
32
|
+
if (platform === "darwin") osName = "darwin";
|
|
33
|
+
else if (platform === "linux") osName = "linux";
|
|
34
|
+
else if (platform === "win32") osName = "windows";
|
|
35
|
+
else return null;
|
|
36
|
+
|
|
37
|
+
let archName;
|
|
38
|
+
if (arch === "x64") archName = "x64";
|
|
39
|
+
else if (arch === "arm64") archName = "arm64";
|
|
40
|
+
else return null;
|
|
41
|
+
|
|
42
|
+
return { os: osName, arch: archName };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Compute SHA256 hash of a file.
|
|
47
|
+
*/
|
|
48
|
+
function sha256File(filePath) {
|
|
49
|
+
const hash = crypto.createHash("sha256");
|
|
50
|
+
const data = fs.readFileSync(filePath);
|
|
51
|
+
hash.update(data);
|
|
52
|
+
return hash.digest("hex");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Verify SHA256 checksum of a downloaded file.
|
|
57
|
+
* Throws if checksum doesn't match.
|
|
58
|
+
*/
|
|
59
|
+
function verifyChecksum(filePath, expectedHash, label) {
|
|
60
|
+
if (!expectedHash) {
|
|
61
|
+
console.log(` ⚠ No checksum available for ${label} — skipping verification`);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const actualHash = sha256File(filePath);
|
|
65
|
+
if (actualHash !== expectedHash) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Checksum mismatch for ${label}!\n` +
|
|
68
|
+
` Expected: ${expectedHash}\n` +
|
|
69
|
+
` Got: ${actualHash}\n` +
|
|
70
|
+
` This could indicate a corrupted download or supply chain attack.\n` +
|
|
71
|
+
` Delete the file and retry, or install the CLI manually.`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
console.log(` ✓ Checksum verified for ${label}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Make an HTTPS GET request and return the response body as a string.
|
|
79
|
+
*/
|
|
80
|
+
function httpsGet(url) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const doRequest = (reqUrl, redirectCount = 0) => {
|
|
83
|
+
if (redirectCount > 5) {
|
|
84
|
+
reject(new Error("Too many redirects"));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
https.get(reqUrl, { headers: { "User-Agent": "clawup-postinstall" } }, (res) => {
|
|
88
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
89
|
+
res.resume();
|
|
90
|
+
doRequest(res.headers.location, redirectCount + 1);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (res.statusCode !== 200) {
|
|
94
|
+
res.resume();
|
|
95
|
+
reject(new Error(`HTTP ${res.statusCode} for ${reqUrl}`));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
let data = "";
|
|
99
|
+
res.on("data", (chunk) => (data += chunk));
|
|
100
|
+
res.on("end", () => resolve(data));
|
|
101
|
+
}).on("error", reject);
|
|
102
|
+
};
|
|
103
|
+
doRequest(url);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function download(url, destPath) {
|
|
108
|
+
return new Promise((resolve, reject) => {
|
|
109
|
+
const file = fs.createWriteStream(destPath);
|
|
110
|
+
const request = (reqUrl, redirectCount = 0) => {
|
|
111
|
+
if (redirectCount > 5) {
|
|
112
|
+
reject(new Error("Too many redirects"));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
https
|
|
116
|
+
.get(reqUrl, { headers: { "User-Agent": "clawup-postinstall" } }, (response) => {
|
|
117
|
+
if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
118
|
+
response.resume();
|
|
119
|
+
request(response.headers.location, redirectCount + 1);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (response.statusCode !== 200) {
|
|
123
|
+
response.resume();
|
|
124
|
+
reject(new Error(`HTTP ${response.statusCode} for ${reqUrl}`));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
response.pipe(file);
|
|
128
|
+
file.on("finish", () => {
|
|
129
|
+
file.close();
|
|
130
|
+
resolve();
|
|
131
|
+
});
|
|
132
|
+
})
|
|
133
|
+
.on("error", (err) => {
|
|
134
|
+
try { fs.unlinkSync(destPath); } catch {}
|
|
135
|
+
reject(err);
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
request(url);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Fetch the latest Pulumi version from GitHub releases API.
|
|
144
|
+
*/
|
|
145
|
+
async function getLatestPulumiVersion() {
|
|
146
|
+
const data = await httpsGet("https://api.github.com/repos/pulumi/pulumi/releases/latest");
|
|
147
|
+
const release = JSON.parse(data);
|
|
148
|
+
const version = release.tag_name.replace(/^v/, "");
|
|
149
|
+
console.log(` Resolved Pulumi latest version: v${version}`);
|
|
150
|
+
return version;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Fetch Pulumi checksums from the GitHub release checksums.txt asset.
|
|
155
|
+
* Returns a map of filename -> sha256 hash.
|
|
156
|
+
*/
|
|
157
|
+
async function getPulumiChecksums(version) {
|
|
158
|
+
const url = `https://github.com/pulumi/pulumi/releases/download/v${version}/pulumi-${version}-checksums.txt`;
|
|
159
|
+
try {
|
|
160
|
+
const data = await httpsGet(url);
|
|
161
|
+
const checksums = {};
|
|
162
|
+
for (const line of data.trim().split("\n")) {
|
|
163
|
+
const [hash, filename] = line.trim().split(/\s+/);
|
|
164
|
+
if (hash && filename) {
|
|
165
|
+
checksums[filename] = hash;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return checksums;
|
|
169
|
+
} catch (err) {
|
|
170
|
+
console.warn(` ⚠ Could not fetch Pulumi checksums: ${err.message}`);
|
|
171
|
+
return {};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getPulumiFilename(version, platform) {
|
|
176
|
+
const ext = platform.os === "windows" ? "zip" : "tar.gz";
|
|
177
|
+
return `pulumi-v${version}-${platform.os}-${platform.arch}.${ext}`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function getPulumiUrl(version, platform) {
|
|
181
|
+
return `https://get.pulumi.com/releases/sdk/${getPulumiFilename(version, platform)}`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getAwsCliUrl(platform) {
|
|
185
|
+
if (platform.os === "linux" && platform.arch === "x64") {
|
|
186
|
+
return "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip";
|
|
187
|
+
}
|
|
188
|
+
if (platform.os === "linux" && platform.arch === "arm64") {
|
|
189
|
+
return "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip";
|
|
190
|
+
}
|
|
191
|
+
if (platform.os === "darwin") {
|
|
192
|
+
return "https://awscli.amazonaws.com/AWSCLIV2.pkg";
|
|
193
|
+
}
|
|
194
|
+
if (platform.os === "windows") {
|
|
195
|
+
return "https://awscli.amazonaws.com/AWSCLIV2.msi";
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Fetch the SHA256 checksum for an AWS CLI download from the .sha256 sidecar.
|
|
202
|
+
*/
|
|
203
|
+
async function getAwsCliChecksum(url) {
|
|
204
|
+
try {
|
|
205
|
+
const data = await httpsGet(`${url}.sha256`);
|
|
206
|
+
// Format: "<hash> filename" or just the hash
|
|
207
|
+
const hash = data.trim().split(/\s+/)[0];
|
|
208
|
+
if (hash && /^[a-f0-9]{64}$/.test(hash)) {
|
|
209
|
+
return hash;
|
|
210
|
+
}
|
|
211
|
+
return null;
|
|
212
|
+
} catch {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function installPulumi(platform) {
|
|
218
|
+
// Resolve version dynamically
|
|
219
|
+
const version = await getLatestPulumiVersion();
|
|
220
|
+
const checksums = await getPulumiChecksums(version);
|
|
221
|
+
const filename = getPulumiFilename(version, platform);
|
|
222
|
+
const expectedChecksum = checksums[filename] || null;
|
|
223
|
+
const url = getPulumiUrl(version, platform);
|
|
224
|
+
const platformKey = `${platform.os}-${platform.arch}`;
|
|
225
|
+
const destDir = path.join(VENDOR_DIR, "pulumi");
|
|
226
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
227
|
+
|
|
228
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "clawup-pulumi-"));
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
if (platform.os === "windows") {
|
|
232
|
+
const zipPath = path.join(tmpDir, "pulumi.zip");
|
|
233
|
+
console.log(` Downloading Pulumi v${version} (${platformKey})...`);
|
|
234
|
+
await download(url, zipPath);
|
|
235
|
+
verifyChecksum(zipPath, expectedChecksum, `Pulumi v${version} (${platformKey})`);
|
|
236
|
+
|
|
237
|
+
execSync(`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${tmpDir}' -Force"`, {
|
|
238
|
+
stdio: "pipe",
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const extractedDir = path.join(tmpDir, "pulumi", "bin");
|
|
242
|
+
if (fs.existsSync(extractedDir)) {
|
|
243
|
+
for (const file of fs.readdirSync(extractedDir)) {
|
|
244
|
+
fs.copyFileSync(path.join(extractedDir, file), path.join(destDir, file));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
const tarPath = path.join(tmpDir, "pulumi.tar.gz");
|
|
249
|
+
console.log(` Downloading Pulumi v${version} (${platformKey})...`);
|
|
250
|
+
await download(url, tarPath);
|
|
251
|
+
verifyChecksum(tarPath, expectedChecksum, `Pulumi v${version} (${platformKey})`);
|
|
252
|
+
|
|
253
|
+
execSync(`tar xzf "${tarPath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
254
|
+
|
|
255
|
+
const extractedDir = path.join(tmpDir, "pulumi");
|
|
256
|
+
if (fs.existsSync(extractedDir)) {
|
|
257
|
+
for (const file of fs.readdirSync(extractedDir)) {
|
|
258
|
+
const srcPath = path.join(extractedDir, file);
|
|
259
|
+
const dstPath = path.join(destDir, file);
|
|
260
|
+
fs.copyFileSync(srcPath, dstPath);
|
|
261
|
+
fs.chmodSync(dstPath, 0o755);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Write version file for runtime reference
|
|
267
|
+
fs.writeFileSync(path.join(destDir, ".version"), version);
|
|
268
|
+
console.log(` ✓ Pulumi v${version} installed to vendor/pulumi/`);
|
|
269
|
+
} finally {
|
|
270
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function installAwsCli(platform) {
|
|
275
|
+
const url = getAwsCliUrl(platform);
|
|
276
|
+
if (!url) {
|
|
277
|
+
console.log(" AWS CLI: unsupported platform, skipping vendor install");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const platformKey = `${platform.os}-${platform.arch}`;
|
|
282
|
+
const destDir = path.join(VENDOR_DIR, "aws-cli");
|
|
283
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
284
|
+
|
|
285
|
+
// Fetch checksum from AWS .sha256 sidecar file
|
|
286
|
+
const expectedChecksum = await getAwsCliChecksum(url);
|
|
287
|
+
|
|
288
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "clawup-awscli-"));
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
if (platform.os === "linux") {
|
|
292
|
+
const zipPath = path.join(tmpDir, "awscli.zip");
|
|
293
|
+
console.log(` Downloading AWS CLI v2 (${platformKey})...`);
|
|
294
|
+
await download(url, zipPath);
|
|
295
|
+
verifyChecksum(zipPath, expectedChecksum, `AWS CLI v2 (${platformKey})`);
|
|
296
|
+
|
|
297
|
+
execSync(`unzip -q "${zipPath}" -d "${tmpDir}"`, { stdio: "pipe" });
|
|
298
|
+
|
|
299
|
+
const installDir = path.join(destDir, "v2");
|
|
300
|
+
execSync(
|
|
301
|
+
`"${tmpDir}/aws/install" --install-dir "${installDir}" --bin-dir "${destDir}" --update`,
|
|
302
|
+
{ stdio: "pipe" }
|
|
303
|
+
);
|
|
304
|
+
|
|
305
|
+
console.log(` ✓ AWS CLI v2 installed to vendor/aws-cli/`);
|
|
306
|
+
} else if (platform.os === "darwin") {
|
|
307
|
+
const pkgPath = path.join(tmpDir, "AWSCLIV2.pkg");
|
|
308
|
+
console.log(` Downloading AWS CLI v2 (${platformKey})...`);
|
|
309
|
+
await download(url, pkgPath);
|
|
310
|
+
verifyChecksum(pkgPath, expectedChecksum, `AWS CLI v2 (${platformKey})`);
|
|
311
|
+
|
|
312
|
+
const expandDir = path.join(tmpDir, "expanded");
|
|
313
|
+
execSync(`pkgutil --expand "${pkgPath}" "${expandDir}"`, { stdio: "pipe" });
|
|
314
|
+
|
|
315
|
+
const payloadDir = path.join(tmpDir, "payload");
|
|
316
|
+
fs.mkdirSync(payloadDir, { recursive: true });
|
|
317
|
+
|
|
318
|
+
const awsCliPkg = path.join(expandDir, "aws-cli.pkg");
|
|
319
|
+
if (fs.existsSync(path.join(awsCliPkg, "Payload"))) {
|
|
320
|
+
execSync(`cd "${payloadDir}" && cat "${awsCliPkg}/Payload" | cpio -idm 2>/dev/null || true`, {
|
|
321
|
+
stdio: "pipe",
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const awsBinSrc = path.join(payloadDir, "aws-cli", "aws");
|
|
326
|
+
if (fs.existsSync(awsBinSrc)) {
|
|
327
|
+
copyDirSync(path.join(payloadDir, "aws-cli"), destDir);
|
|
328
|
+
fs.chmodSync(path.join(destDir, "aws"), 0o755);
|
|
329
|
+
console.log(` ✓ AWS CLI v2 installed to vendor/aws-cli/`);
|
|
330
|
+
} else {
|
|
331
|
+
console.log(" AWS CLI: could not locate binary in .pkg payload, skipping");
|
|
332
|
+
}
|
|
333
|
+
} else if (platform.os === "windows") {
|
|
334
|
+
console.log(" AWS CLI: Windows uses MSI installer, skipping vendor install");
|
|
335
|
+
console.log(" Install from: https://awscli.amazonaws.com/AWSCLIV2.msi");
|
|
336
|
+
}
|
|
337
|
+
} finally {
|
|
338
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function copyDirSync(src, dest) {
|
|
343
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
344
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
345
|
+
const srcPath = path.join(src, entry.name);
|
|
346
|
+
const destPath = path.join(dest, entry.name);
|
|
347
|
+
if (entry.isDirectory()) {
|
|
348
|
+
copyDirSync(srcPath, destPath);
|
|
349
|
+
} else {
|
|
350
|
+
fs.copyFileSync(srcPath, destPath);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
async function main() {
|
|
356
|
+
// Skip in CI or if CLAWUP_SKIP_POSTINSTALL is set
|
|
357
|
+
if (process.env.CLAWUP_SKIP_POSTINSTALL || process.env.AGENT_ARMY_SKIP_POSTINSTALL || process.env.CI) {
|
|
358
|
+
console.log("clawup: skipping postinstall (CI or CLAWUP_SKIP_POSTINSTALL set)");
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const platform = getPlatform();
|
|
363
|
+
if (!platform) {
|
|
364
|
+
console.log(`clawup: unsupported platform (${process.platform}/${process.arch}), skipping vendor install`);
|
|
365
|
+
console.log(" Pulumi and AWS CLI must be installed manually.");
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
console.log(`clawup: installing vendored binaries (${platform.os}/${platform.arch})...`);
|
|
370
|
+
|
|
371
|
+
// Install Pulumi
|
|
372
|
+
try {
|
|
373
|
+
await installPulumi(platform);
|
|
374
|
+
} catch (err) {
|
|
375
|
+
console.warn(` ✗ Failed to install Pulumi: ${err instanceof Error ? err.message : String(err)}`);
|
|
376
|
+
console.warn(" The CLI will fall back to system PATH for Pulumi.");
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Install AWS CLI
|
|
380
|
+
try {
|
|
381
|
+
await installAwsCli(platform);
|
|
382
|
+
} catch (err) {
|
|
383
|
+
console.warn(` ✗ Failed to install AWS CLI: ${err instanceof Error ? err.message : String(err)}`);
|
|
384
|
+
console.warn(" The CLI will fall back to system PATH for AWS CLI.");
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
console.log("clawup: postinstall complete.");
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
main().catch((err) => {
|
|
391
|
+
// Non-fatal — the CLI will fall back to system PATH
|
|
392
|
+
console.warn(`clawup postinstall: ${err instanceof Error ? err.message : String(err)}`);
|
|
393
|
+
console.warn(" Vendored binaries may not be available. Falling back to system PATH.");
|
|
394
|
+
process.exit(0); // Exit 0 so npm install doesn't fail
|
|
395
|
+
});
|