canary-test-cli 5.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/bin/canary.js +30 -0
- package/package.json +24 -0
- package/scripts/install.js +73 -0
package/bin/canary.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { execFileSync } = require("node:child_process");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const fs = require("node:fs");
|
|
7
|
+
|
|
8
|
+
function getBinaryPath(platform) {
|
|
9
|
+
const name = platform === "win32" ? "canary.exe" : "canary";
|
|
10
|
+
return path.join(__dirname, name);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function main() {
|
|
14
|
+
const binaryPath = getBinaryPath(process.platform);
|
|
15
|
+
if (!fs.existsSync(binaryPath)) {
|
|
16
|
+
process.stderr.write(
|
|
17
|
+
`canary binary not found at ${binaryPath}.\n` +
|
|
18
|
+
`Try reinstalling: volta install canary-test-cli\n`
|
|
19
|
+
);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
execFileSync(binaryPath, process.argv.slice(2), { stdio: "inherit" });
|
|
24
|
+
} catch (err) {
|
|
25
|
+
process.exit(err.status ?? 1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { getBinaryPath };
|
|
30
|
+
if (require.main === module) main();
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "canary-test-cli",
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "Canary — AI-powered test automation agent",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/bop-clocktower/canary.git"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"canary": "./bin/canary.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"postinstall": "node scripts/install.js",
|
|
15
|
+
"test": "node --test scripts/__tests__/install.test.js scripts/__tests__/canary.test.js"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"bin/",
|
|
22
|
+
"scripts/install.js"
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const https = require("node:https");
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
|
|
8
|
+
const SUPPORTED = {
|
|
9
|
+
"linux-x64": true,
|
|
10
|
+
"darwin-arm64": true,
|
|
11
|
+
"win32-x64": true,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function getPlatformKey(platform, arch) {
|
|
15
|
+
const key = `${platform}-${arch}`;
|
|
16
|
+
if (!SUPPORTED[key]) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`Unsupported platform: ${key}. Supported: ${Object.keys(SUPPORTED).join(", ")}`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return key;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getBinaryName(platformKey) {
|
|
25
|
+
return platformKey.startsWith("win32")
|
|
26
|
+
? `canary-${platformKey}.exe`
|
|
27
|
+
: `canary-${platformKey}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getDownloadUrl(version, binaryName) {
|
|
31
|
+
return `https://github.com/bop-clocktower/canary/releases/download/v${version}/${binaryName}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function download(url, destPath, redirectsLeft = 5) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
if (redirectsLeft === 0) return reject(new Error("Too many redirects"));
|
|
37
|
+
https.get(url, (res) => {
|
|
38
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
39
|
+
res.resume(); // drain redirect response to free the socket
|
|
40
|
+
return resolve(download(res.headers.location, destPath, redirectsLeft - 1));
|
|
41
|
+
}
|
|
42
|
+
if (res.statusCode !== 200) {
|
|
43
|
+
return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`));
|
|
44
|
+
}
|
|
45
|
+
const file = fs.createWriteStream(destPath);
|
|
46
|
+
res.pipe(file);
|
|
47
|
+
file.on("finish", () => file.close(resolve));
|
|
48
|
+
file.on("error", reject);
|
|
49
|
+
}).on("error", reject);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function main() {
|
|
54
|
+
const pkg = require("../package.json");
|
|
55
|
+
const version = pkg.version;
|
|
56
|
+
const platformKey = getPlatformKey(process.platform, process.arch);
|
|
57
|
+
const binaryName = getBinaryName(platformKey);
|
|
58
|
+
const url = getDownloadUrl(version, binaryName);
|
|
59
|
+
const destDir = path.join(__dirname, "..", "bin");
|
|
60
|
+
const destName = process.platform === "win32" ? "canary.exe" : "canary";
|
|
61
|
+
const destPath = path.join(destDir, destName);
|
|
62
|
+
|
|
63
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
64
|
+
|
|
65
|
+
process.stdout.write(`Downloading canary ${version} for ${platformKey}...\n`);
|
|
66
|
+
await download(url, destPath);
|
|
67
|
+
fs.chmodSync(destPath, 0o755);
|
|
68
|
+
process.stdout.write(`Done. Binary at: ${destPath}\n`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Export pure functions for testing; run main() only when executed directly.
|
|
72
|
+
module.exports = { getPlatformKey, getBinaryName, getDownloadUrl };
|
|
73
|
+
if (require.main === module) main().catch((e) => { process.stderr.write(e.message + "\n"); process.exit(1); });
|