andycode 0.3.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/install.js +128 -0
- package/package.json +42 -0
- package/run.js +30 -0
package/install.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const https = require("https");
|
|
7
|
+
const { execSync } = require("child_process");
|
|
8
|
+
|
|
9
|
+
// ── Configuration ──────────────────────────────────────────────────────
|
|
10
|
+
const REPO = "andysama-work/andy-code-bin";
|
|
11
|
+
const BIN_DIR = path.join(__dirname, "bin");
|
|
12
|
+
const VERSION = require("./package.json").version;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Map Node.js os.platform() + os.arch() to release artifact names.
|
|
16
|
+
* Must match the matrix in .github/workflows/release.yml
|
|
17
|
+
*/
|
|
18
|
+
const PLATFORM_MAP = {
|
|
19
|
+
"linux-x64": { artifact: "andycode-linux-x64", ext: ".tar.gz", binary: "andycode" },
|
|
20
|
+
"darwin-arm64": { artifact: "andycode-darwin-arm64", ext: ".tar.gz", binary: "andycode" },
|
|
21
|
+
"win32-x64": { artifact: "andycode-windows-x64", ext: ".zip", binary: "andycode.exe" },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
function getPlatformKey() {
|
|
27
|
+
const platform = process.platform;
|
|
28
|
+
const arch = process.arch;
|
|
29
|
+
return `${platform}-${arch}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Follow redirects (GitHub releases redirect to S3/CDN).
|
|
34
|
+
* Returns a Promise<Buffer>.
|
|
35
|
+
*/
|
|
36
|
+
const MAX_REDIRECTS = 10;
|
|
37
|
+
|
|
38
|
+
function download(url, redirectCount = 0) {
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
if (redirectCount > MAX_REDIRECTS) {
|
|
41
|
+
return reject(new Error(`Too many redirects (>${MAX_REDIRECTS}) for ${url}`));
|
|
42
|
+
}
|
|
43
|
+
https.get(url, { headers: { "User-Agent": "andycode-npm-installer" } }, (res) => {
|
|
44
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
45
|
+
return download(res.headers.location, redirectCount + 1).then(resolve, reject);
|
|
46
|
+
}
|
|
47
|
+
if (res.statusCode !== 200) {
|
|
48
|
+
return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
|
|
49
|
+
}
|
|
50
|
+
const chunks = [];
|
|
51
|
+
res.on("data", (c) => chunks.push(c));
|
|
52
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
53
|
+
res.on("error", reject);
|
|
54
|
+
}).on("error", reject);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function extractTarGz(buffer, destDir) {
|
|
59
|
+
// Write to temp file, then extract with tar
|
|
60
|
+
const tmp = path.join(destDir, "_download.tar.gz");
|
|
61
|
+
fs.writeFileSync(tmp, buffer);
|
|
62
|
+
execSync(`tar xzf "${tmp}" -C "${destDir}"`, { stdio: "ignore" });
|
|
63
|
+
fs.unlinkSync(tmp);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function extractZip(buffer, destDir) {
|
|
67
|
+
const tmp = path.join(destDir, "_download.zip");
|
|
68
|
+
fs.writeFileSync(tmp, buffer);
|
|
69
|
+
if (process.platform === "win32") {
|
|
70
|
+
execSync(
|
|
71
|
+
`powershell -NoProfile -Command "Expand-Archive -Force -Path '${tmp}' -DestinationPath '${destDir}'"`,
|
|
72
|
+
{ stdio: "ignore" }
|
|
73
|
+
);
|
|
74
|
+
} else {
|
|
75
|
+
execSync(`unzip -o "${tmp}" -d "${destDir}"`, { stdio: "ignore" });
|
|
76
|
+
}
|
|
77
|
+
fs.unlinkSync(tmp);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Main ───────────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
async function main() {
|
|
83
|
+
const key = getPlatformKey();
|
|
84
|
+
const info = PLATFORM_MAP[key];
|
|
85
|
+
|
|
86
|
+
if (!info) {
|
|
87
|
+
console.error(`[andycode] Unsupported platform: ${key}`);
|
|
88
|
+
console.error(`[andycode] Supported: ${Object.keys(PLATFORM_MAP).join(", ")}`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${info.artifact}${info.ext}`;
|
|
93
|
+
console.log(`[andycode] Downloading ${info.artifact}${info.ext} ...`);
|
|
94
|
+
console.log(`[andycode] URL: ${url}`);
|
|
95
|
+
|
|
96
|
+
// Ensure bin directory exists
|
|
97
|
+
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const buffer = await download(url);
|
|
101
|
+
console.log(`[andycode] Downloaded ${(buffer.length / 1024 / 1024).toFixed(1)} MB`);
|
|
102
|
+
|
|
103
|
+
if (info.ext === ".tar.gz") {
|
|
104
|
+
extractTarGz(buffer, BIN_DIR);
|
|
105
|
+
} else {
|
|
106
|
+
extractZip(buffer, BIN_DIR);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Make binary executable on Unix
|
|
110
|
+
const binPath = path.join(BIN_DIR, info.binary);
|
|
111
|
+
if (process.platform !== "win32") {
|
|
112
|
+
fs.chmodSync(binPath, 0o755);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!fs.existsSync(binPath)) {
|
|
116
|
+
throw new Error(`Binary not found after extraction: ${binPath}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`[andycode] Installed successfully: ${binPath}`);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.error(`[andycode] Installation failed: ${err.message}`);
|
|
122
|
+
console.error(`[andycode] You can manually download from:`);
|
|
123
|
+
console.error(`[andycode] https://github.com/${REPO}/releases/tag/v${VERSION}`);
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "andycode",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Andy Code — AI-powered coding agent for the terminal",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/andysama-work/andy-code-bin.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/andysama-work/andy-code-bin",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"ai",
|
|
13
|
+
"coding-agent",
|
|
14
|
+
"terminal",
|
|
15
|
+
"cli",
|
|
16
|
+
"llm",
|
|
17
|
+
"deepseek",
|
|
18
|
+
"openai"
|
|
19
|
+
],
|
|
20
|
+
"bin": {
|
|
21
|
+
"andycode": "./run.js"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"postinstall": "node install.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"install.js",
|
|
28
|
+
"run.js"
|
|
29
|
+
],
|
|
30
|
+
"os": [
|
|
31
|
+
"linux",
|
|
32
|
+
"darwin",
|
|
33
|
+
"win32"
|
|
34
|
+
],
|
|
35
|
+
"cpu": [
|
|
36
|
+
"x64",
|
|
37
|
+
"arm64"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=16"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/run.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { spawn } = require("child_process");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
|
|
8
|
+
const BIN_DIR = path.join(__dirname, "bin");
|
|
9
|
+
const BINARY = process.platform === "win32" ? "andycode.exe" : "andycode";
|
|
10
|
+
const binPath = path.join(BIN_DIR, BINARY);
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(binPath)) {
|
|
13
|
+
console.error(`[andycode] Binary not found: ${binPath}`);
|
|
14
|
+
console.error(`[andycode] Run "npm rebuild andycode" or reinstall the package.`);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const child = spawn(binPath, process.argv.slice(2), {
|
|
19
|
+
stdio: "inherit",
|
|
20
|
+
env: process.env,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
child.on("error", (err) => {
|
|
24
|
+
console.error(`[andycode] Failed to start: ${err.message}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
child.on("exit", (code) => {
|
|
29
|
+
process.exit(code ?? 1);
|
|
30
|
+
});
|