mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 05:02:07 +00:00
parent
ef8c950357
commit
3db5715de4
4 changed files with 133 additions and 23 deletions
84
package-lock.json
generated
84
package-lock.json
generated
|
|
@ -3949,6 +3949,16 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
"version": "2.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript/native-preview": {
|
||||
"version": "7.0.0-dev.20260120.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260120.1.tgz",
|
||||
|
|
@ -4436,6 +4446,15 @@
|
|||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
|
|
@ -4932,7 +4951,6 @@
|
|||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
|
|
@ -5176,6 +5194,41 @@
|
|||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/extract-zip": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
|
||||
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"get-stream": "^5.1.0",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"bin": {
|
||||
"extract-zip": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.17.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@types/yauzl": "^2.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/extract-zip/node_modules/get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
|
|
@ -5243,6 +5296,15 @@
|
|||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fd-slicer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
"integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
|
|
@ -6643,7 +6705,6 @@
|
|||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
|
|
@ -6859,6 +6920,12 @@
|
|||
"@napi-rs/canvas": "^0.1.81"
|
||||
}
|
||||
},
|
||||
"node_modules/pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pi-extension-custom-provider-anthropic": {
|
||||
"resolved": "packages/coding-agent/examples/extensions/custom-provider-anthropic",
|
||||
"link": true
|
||||
|
|
@ -7042,7 +7109,6 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
|
||||
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
|
|
@ -8253,7 +8319,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
|
|
@ -8340,6 +8405,16 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
"integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yoctocolors": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz",
|
||||
|
|
@ -8465,6 +8540,7 @@
|
|||
"chalk": "^5.5.0",
|
||||
"cli-highlight": "^2.1.11",
|
||||
"diff": "^8.0.2",
|
||||
"extract-zip": "^2.0.1",
|
||||
"file-type": "^21.1.1",
|
||||
"glob": "^13.0.1",
|
||||
"hosted-git-info": "^9.0.2",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
- Fixed offline startup hangs by adding offline startup behavior and network timeouts during managed tool setup ([#1631](https://github.com/badlogic/pi-mono/pull/1631) by [@mcollina](https://github.com/mcollina))
|
||||
- Fixed Windows VT input initialization in ESM by loading koffi via createRequire, avoiding runtime and bundling issues in end-user environments ([#1627](https://github.com/badlogic/pi-mono/pull/1627) by [@kaste](https://github.com/kaste))
|
||||
- Fixed managed `fd`/`rg` bootstrap on Windows in Git Bash by using `extract-zip` for `.zip` archives, searching extracted layouts more robustly, and isolating extraction temp directories to avoid concurrent download races ([#1348](https://github.com/badlogic/pi-mono/issues/1348))
|
||||
|
||||
## [0.55.0] - 2026-02-24
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
"chalk": "^5.5.0",
|
||||
"cli-highlight": "^2.1.11",
|
||||
"diff": "^8.0.2",
|
||||
"extract-zip": "^2.0.1",
|
||||
"file-type": "^21.1.1",
|
||||
"glob": "^13.0.1",
|
||||
"hosted-git-info": "^9.0.2",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import chalk from "chalk";
|
||||
import { spawnSync } from "child_process";
|
||||
import { chmodSync, createWriteStream, existsSync, mkdirSync, renameSync, rmSync } from "fs";
|
||||
import extractZip from "extract-zip";
|
||||
import { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "fs";
|
||||
import { arch, platform } from "os";
|
||||
import { join } from "path";
|
||||
import { Readable } from "stream";
|
||||
|
|
@ -130,6 +131,28 @@ async function downloadFile(url: string, dest: string): Promise<void> {
|
|||
await finished(Readable.fromWeb(response.body as any).pipe(fileStream));
|
||||
}
|
||||
|
||||
function findBinaryRecursively(rootDir: string, binaryFileName: string): string | null {
|
||||
const stack: string[] = [rootDir];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const currentDir = stack.pop();
|
||||
if (!currentDir) continue;
|
||||
|
||||
const entries = readdirSync(currentDir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
const fullPath = join(currentDir, entry.name);
|
||||
if (entry.isFile() && entry.name === binaryFileName) {
|
||||
return fullPath;
|
||||
}
|
||||
if (entry.isDirectory()) {
|
||||
stack.push(fullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Download and install a tool
|
||||
async function downloadTool(tool: "fd" | "rg"): Promise<string> {
|
||||
const config = TOOLS[tool];
|
||||
|
|
@ -158,33 +181,42 @@ async function downloadTool(tool: "fd" | "rg"): Promise<string> {
|
|||
// Download
|
||||
await downloadFile(downloadUrl, archivePath);
|
||||
|
||||
// Extract
|
||||
const extractDir = join(TOOLS_DIR, "extract_tmp");
|
||||
// Extract into a unique temp directory. fd and rg downloads can run concurrently
|
||||
// during startup, so sharing a fixed directory causes races.
|
||||
const extractDir = join(
|
||||
TOOLS_DIR,
|
||||
`extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
|
||||
);
|
||||
mkdirSync(extractDir, { recursive: true });
|
||||
|
||||
try {
|
||||
// Use tar for both .tar.gz and .zip extraction. Windows 10+ ships bsdtar
|
||||
// which handles both formats, avoiding the need for `unzip` (not available
|
||||
// on Windows by default).
|
||||
const extractResult = assetName.endsWith(".tar.gz")
|
||||
? spawnSync("tar", ["xzf", archivePath, "-C", extractDir], { stdio: "pipe" })
|
||||
: assetName.endsWith(".zip")
|
||||
? spawnSync("tar", ["xf", archivePath, "-C", extractDir], { stdio: "pipe" })
|
||||
: null;
|
||||
|
||||
if (!extractResult || extractResult.error || extractResult.status !== 0) {
|
||||
const errMsg = extractResult?.error?.message ?? extractResult?.stderr?.toString().trim() ?? "unknown error";
|
||||
throw new Error(`Failed to extract ${assetName}: ${errMsg}`);
|
||||
if (assetName.endsWith(".tar.gz")) {
|
||||
const extractResult = spawnSync("tar", ["xzf", archivePath, "-C", extractDir], { stdio: "pipe" });
|
||||
if (extractResult.error || extractResult.status !== 0) {
|
||||
const errMsg = extractResult.error?.message ?? extractResult.stderr?.toString().trim() ?? "unknown error";
|
||||
throw new Error(`Failed to extract ${assetName}: ${errMsg}`);
|
||||
}
|
||||
} else if (assetName.endsWith(".zip")) {
|
||||
await extractZip(archivePath, { dir: extractDir });
|
||||
} else {
|
||||
throw new Error(`Unsupported archive format: ${assetName}`);
|
||||
}
|
||||
|
||||
// Find the binary in extracted files
|
||||
// Find the binary in extracted files. Some archives contain files directly
|
||||
// at root, others nest under a versioned subdirectory.
|
||||
const binaryFileName = config.binaryName + binaryExt;
|
||||
const extractedDir = join(extractDir, assetName.replace(/\.(tar\.gz|zip)$/, ""));
|
||||
const extractedBinary = join(extractedDir, config.binaryName + binaryExt);
|
||||
const extractedBinaryCandidates = [join(extractedDir, binaryFileName), join(extractDir, binaryFileName)];
|
||||
let extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync(candidate));
|
||||
|
||||
if (existsSync(extractedBinary)) {
|
||||
if (!extractedBinary) {
|
||||
extractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? undefined;
|
||||
}
|
||||
|
||||
if (extractedBinary) {
|
||||
renameSync(extractedBinary, binaryPath);
|
||||
} else {
|
||||
throw new Error(`Binary not found in archive: ${extractedBinary}`);
|
||||
throw new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);
|
||||
}
|
||||
|
||||
// Make executable (Unix only)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue