chore(deps): Kill small dependencies (#4467)
This commit is contained in:
87
packages/coding-agent/src/utils/ansi.ts
Normal file
87
packages/coding-agent/src/utils/ansi.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
export function stripAnsi(value: string): string {
|
||||
let output = "";
|
||||
let index = 0;
|
||||
|
||||
while (index < value.length) {
|
||||
const code = value.charCodeAt(index);
|
||||
|
||||
if (code === 0x1b) {
|
||||
const next = value[index + 1];
|
||||
|
||||
if (next === "[") {
|
||||
index = skipCsi(value, index + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next === "]" || next === "P" || next === "^" || next === "_") {
|
||||
index = skipStringControl(value, index + 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next && "()*+-./#".includes(next)) {
|
||||
index = Math.min(index + 3, value.length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next && isEscFinalByte(next.charCodeAt(0))) {
|
||||
index += 2;
|
||||
continue;
|
||||
}
|
||||
} else if (code === 0x9b) {
|
||||
index = skipCsi(value, index + 1);
|
||||
continue;
|
||||
} else if (code === 0x9d || code === 0x90 || code === 0x9e || code === 0x9f) {
|
||||
index = skipStringControl(value, index + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
output += value[index];
|
||||
index++;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
function isEscFinalByte(code: number): boolean {
|
||||
return (
|
||||
(code >= 0x30 && code <= 0x39) ||
|
||||
(code >= 0x41 && code <= 0x50) ||
|
||||
(code >= 0x52 && code <= 0x54) ||
|
||||
code === 0x5a ||
|
||||
code === 0x63 ||
|
||||
(code >= 0x66 && code <= 0x6e) ||
|
||||
(code >= 0x71 && code <= 0x75) ||
|
||||
code === 0x79 ||
|
||||
code === 0x3d ||
|
||||
code === 0x3e ||
|
||||
code === 0x3c ||
|
||||
code === 0x7e
|
||||
);
|
||||
}
|
||||
|
||||
function skipCsi(value: string, start: number): number {
|
||||
let index = start;
|
||||
while (index < value.length) {
|
||||
const code = value.charCodeAt(index);
|
||||
index++;
|
||||
if (code >= 0x40 && code <= 0x7e) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return value.length;
|
||||
}
|
||||
|
||||
function skipStringControl(value: string, start: number): number {
|
||||
let index = start;
|
||||
while (index < value.length) {
|
||||
const code = value.charCodeAt(index);
|
||||
if (code === 0x07 || code === 0x9c) {
|
||||
return index + 1;
|
||||
}
|
||||
if (code === 0x1b && value[index + 1] === "\\") {
|
||||
return index + 2;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return value.length;
|
||||
}
|
||||
@@ -1,30 +1,74 @@
|
||||
import { open } from "node:fs/promises";
|
||||
import { fileTypeFromBuffer } from "file-type";
|
||||
|
||||
const IMAGE_MIME_TYPES = new Set(["image/jpeg", "image/png", "image/gif", "image/webp"]);
|
||||
const IMAGE_TYPE_SNIFF_BYTES = 4100;
|
||||
const PNG_SIGNATURE = [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a];
|
||||
|
||||
const FILE_TYPE_SNIFF_BYTES = 4100;
|
||||
export function detectSupportedImageMimeType(buffer: Uint8Array): string | null {
|
||||
if (startsWith(buffer, [0xff, 0xd8, 0xff])) {
|
||||
return buffer[3] === 0xf7 ? null : "image/jpeg";
|
||||
}
|
||||
if (startsWith(buffer, PNG_SIGNATURE)) {
|
||||
return isPng(buffer) && !isAnimatedPng(buffer) ? "image/png" : null;
|
||||
}
|
||||
if (startsWithAscii(buffer, 0, "GIF")) {
|
||||
return "image/gif";
|
||||
}
|
||||
if (startsWithAscii(buffer, 0, "RIFF") && startsWithAscii(buffer, 8, "WEBP")) {
|
||||
return "image/webp";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function detectSupportedImageMimeTypeFromFile(filePath: string): Promise<string | null> {
|
||||
const fileHandle = await open(filePath, "r");
|
||||
try {
|
||||
const buffer = Buffer.alloc(FILE_TYPE_SNIFF_BYTES);
|
||||
const { bytesRead } = await fileHandle.read(buffer, 0, FILE_TYPE_SNIFF_BYTES, 0);
|
||||
if (bytesRead === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fileType = await fileTypeFromBuffer(buffer.subarray(0, bytesRead));
|
||||
if (!fileType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!IMAGE_MIME_TYPES.has(fileType.mime)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fileType.mime;
|
||||
const buffer = Buffer.alloc(IMAGE_TYPE_SNIFF_BYTES);
|
||||
const { bytesRead } = await fileHandle.read(buffer, 0, IMAGE_TYPE_SNIFF_BYTES, 0);
|
||||
return detectSupportedImageMimeType(buffer.subarray(0, bytesRead));
|
||||
} finally {
|
||||
await fileHandle.close();
|
||||
}
|
||||
}
|
||||
|
||||
function isPng(buffer: Uint8Array): boolean {
|
||||
return (
|
||||
buffer.length >= 16 && readUint32BE(buffer, PNG_SIGNATURE.length) === 13 && startsWithAscii(buffer, 12, "IHDR")
|
||||
);
|
||||
}
|
||||
|
||||
function isAnimatedPng(buffer: Uint8Array): boolean {
|
||||
let offset = PNG_SIGNATURE.length;
|
||||
while (offset + 8 <= buffer.length) {
|
||||
const chunkLength = readUint32BE(buffer, offset);
|
||||
const chunkTypeOffset = offset + 4;
|
||||
if (startsWithAscii(buffer, chunkTypeOffset, "acTL")) return true;
|
||||
if (startsWithAscii(buffer, chunkTypeOffset, "IDAT")) return false;
|
||||
|
||||
const nextOffset = offset + 8 + chunkLength + 4;
|
||||
if (nextOffset <= offset || nextOffset > buffer.length) return false;
|
||||
offset = nextOffset;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function readUint32BE(buffer: Uint8Array, offset: number): number {
|
||||
return (
|
||||
(buffer[offset] ?? 0) * 0x1000000 +
|
||||
((buffer[offset + 1] ?? 0) << 16) +
|
||||
((buffer[offset + 2] ?? 0) << 8) +
|
||||
(buffer[offset + 3] ?? 0)
|
||||
);
|
||||
}
|
||||
|
||||
function startsWith(buffer: Uint8Array, bytes: number[]): boolean {
|
||||
if (buffer.length < bytes.length) return false;
|
||||
return bytes.every((byte, index) => buffer[index] === byte);
|
||||
}
|
||||
|
||||
function startsWithAscii(buffer: Uint8Array, offset: number, text: string): boolean {
|
||||
if (buffer.length < offset + text.length) return false;
|
||||
for (let index = 0; index < text.length; index++) {
|
||||
if (buffer[offset + index] !== text.charCodeAt(index)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import chalk from "chalk";
|
||||
import { spawnSync } from "child_process";
|
||||
import extractZip from "extract-zip";
|
||||
import { type SpawnSyncReturns, spawnSync } from "child_process";
|
||||
import { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "fs";
|
||||
import { arch, platform } from "os";
|
||||
import { join } from "path";
|
||||
@@ -159,6 +158,85 @@ function findBinaryRecursively(rootDir: string, binaryFileName: string): string
|
||||
return null;
|
||||
}
|
||||
|
||||
function formatSpawnFailure(result: SpawnSyncReturns<Buffer>): string {
|
||||
if (result.error?.message) {
|
||||
return result.error.message;
|
||||
}
|
||||
const stderr = result.stderr?.toString().trim();
|
||||
if (stderr) {
|
||||
return stderr;
|
||||
}
|
||||
const stdout = result.stdout?.toString().trim();
|
||||
if (stdout) {
|
||||
return stdout;
|
||||
}
|
||||
return `exit status ${result.status ?? "unknown"}`;
|
||||
}
|
||||
|
||||
function runExtractionCommand(command: string, args: string[]): string | null {
|
||||
const result = spawnSync(command, args, { stdio: "pipe" });
|
||||
if (!result.error && result.status === 0) {
|
||||
return null;
|
||||
}
|
||||
return `${command}: ${formatSpawnFailure(result)}`;
|
||||
}
|
||||
|
||||
function extractTarGzArchive(archivePath: string, extractDir: string, assetName: string): void {
|
||||
const failure = runExtractionCommand("tar", ["xzf", archivePath, "-C", extractDir]);
|
||||
if (failure) {
|
||||
throw new Error(`Failed to extract ${assetName}: ${failure}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getWindowsTarCommand(): string {
|
||||
const systemRoot = process.env.SystemRoot ?? process.env.WINDIR;
|
||||
if (systemRoot) {
|
||||
const systemTar = join(systemRoot, "System32", "tar.exe");
|
||||
if (existsSync(systemTar)) {
|
||||
return systemTar;
|
||||
}
|
||||
}
|
||||
return "tar.exe";
|
||||
}
|
||||
|
||||
function extractZipArchive(archivePath: string, extractDir: string, assetName: string): void {
|
||||
const failures: string[] = [];
|
||||
|
||||
if (platform() === "win32") {
|
||||
// Windows ships bsdtar as tar.exe, which supports zip files. Prefer the
|
||||
// System32 binary over Git Bash's GNU tar, which does not handle zip archives.
|
||||
const tarFailure = runExtractionCommand(getWindowsTarCommand(), ["xf", archivePath, "-C", extractDir]);
|
||||
if (!tarFailure) return;
|
||||
failures.push(tarFailure);
|
||||
|
||||
const script =
|
||||
"& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }";
|
||||
const powershellFailure = runExtractionCommand("powershell.exe", [
|
||||
"-NoLogo",
|
||||
"-NoProfile",
|
||||
"-NonInteractive",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-Command",
|
||||
script,
|
||||
archivePath,
|
||||
extractDir,
|
||||
]);
|
||||
if (!powershellFailure) return;
|
||||
failures.push(powershellFailure);
|
||||
} else {
|
||||
const unzipFailure = runExtractionCommand("unzip", ["-q", archivePath, "-d", extractDir]);
|
||||
if (!unzipFailure) return;
|
||||
failures.push(unzipFailure);
|
||||
|
||||
const tarFailure = runExtractionCommand("tar", ["xf", archivePath, "-C", extractDir]);
|
||||
if (!tarFailure) return;
|
||||
failures.push(tarFailure);
|
||||
}
|
||||
|
||||
throw new Error(`Failed to extract ${assetName}: ${failures.join("; ")}`);
|
||||
}
|
||||
|
||||
// Download and install a tool
|
||||
async function downloadTool(tool: "fd" | "rg"): Promise<string> {
|
||||
const config = TOOLS[tool];
|
||||
@@ -197,13 +275,9 @@ async function downloadTool(tool: "fd" | "rg"): Promise<string> {
|
||||
|
||||
try {
|
||||
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}`);
|
||||
}
|
||||
extractTarGzArchive(archivePath, extractDir, assetName);
|
||||
} else if (assetName.endsWith(".zip")) {
|
||||
await extractZip(archivePath, { dir: extractDir });
|
||||
extractZipArchive(archivePath, extractDir, assetName);
|
||||
} else {
|
||||
throw new Error(`Unsupported archive format: ${assetName}`);
|
||||
}
|
||||
|
||||
44
packages/coding-agent/src/utils/uuid.ts
Normal file
44
packages/coding-agent/src/utils/uuid.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { randomBytes } from "node:crypto";
|
||||
|
||||
let lastTimestamp = -Infinity;
|
||||
let sequence = 0;
|
||||
|
||||
export function uuidv7(): string {
|
||||
const random = randomBytes(16);
|
||||
const timestamp = Date.now();
|
||||
|
||||
if (timestamp > lastTimestamp) {
|
||||
sequence = (random[6] << 23) | (random[7] << 16) | (random[8] << 8) | random[9];
|
||||
lastTimestamp = timestamp;
|
||||
} else {
|
||||
sequence = (sequence + 1) | 0;
|
||||
if (sequence === 0) {
|
||||
lastTimestamp++;
|
||||
}
|
||||
}
|
||||
|
||||
const bytes = new Uint8Array(16);
|
||||
bytes[0] = (lastTimestamp / 0x10000000000) & 0xff;
|
||||
bytes[1] = (lastTimestamp / 0x100000000) & 0xff;
|
||||
bytes[2] = (lastTimestamp / 0x1000000) & 0xff;
|
||||
bytes[3] = (lastTimestamp / 0x10000) & 0xff;
|
||||
bytes[4] = (lastTimestamp / 0x100) & 0xff;
|
||||
bytes[5] = lastTimestamp & 0xff;
|
||||
bytes[6] = 0x70 | ((sequence >>> 28) & 0x0f);
|
||||
bytes[7] = (sequence >>> 20) & 0xff;
|
||||
bytes[8] = 0x80 | ((sequence >>> 14) & 0x3f);
|
||||
bytes[9] = (sequence >>> 6) & 0xff;
|
||||
bytes[10] = ((sequence << 2) & 0xff) | (random[10] & 0x03);
|
||||
bytes[11] = random[11];
|
||||
bytes[12] = random[12];
|
||||
bytes[13] = random[13];
|
||||
bytes[14] = random[14];
|
||||
bytes[15] = random[15];
|
||||
|
||||
return formatUuid(bytes);
|
||||
}
|
||||
|
||||
function formatUuid(bytes: Uint8Array): string {
|
||||
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
|
||||
return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
|
||||
}
|
||||
Reference in New Issue
Block a user