diff --git a/packages/coding-agent/src/config.ts b/packages/coding-agent/src/config.ts index 817b6ea1..0dd06a2b 100644 --- a/packages/coding-agent/src/config.ts +++ b/packages/coding-agent/src/config.ts @@ -142,11 +142,16 @@ export function getSettingsPath(): string { return join(getAgentDir(), "settings.json"); } -/** Get path to tools directory */ +/** Get path to tools directory (deprecated, use extensions/ for JS/TS tools) */ export function getToolsDir(): string { return join(getAgentDir(), "tools"); } +/** Get path to managed binaries directory (fd, rg) */ +export function getBinDir(): string { + return join(getAgentDir(), "bin"); +} + /** Get path to prompt templates directory */ export function getPromptsDir(): string { return join(getAgentDir(), "prompts"); diff --git a/packages/coding-agent/src/migrations.ts b/packages/coding-agent/src/migrations.ts index 7f99774a..3febdd09 100644 --- a/packages/coding-agent/src/migrations.ts +++ b/packages/coding-agent/src/migrations.ts @@ -3,9 +3,9 @@ */ import chalk from "chalk"; -import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from "fs"; +import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs"; import { dirname, join } from "path"; -import { CONFIG_DIR_NAME, getAgentDir } from "./config.js"; +import { CONFIG_DIR_NAME, getAgentDir, getBinDir } from "./config.js"; const MIGRATION_GUIDE_URL = "https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration"; @@ -152,6 +152,50 @@ function migrateCommandsToPrompts(baseDir: string, label: string): boolean { return false; } +/** + * Move fd/rg binaries from tools/ to bin/ if they exist. + */ +function migrateToolsToBin(): void { + const agentDir = getAgentDir(); + const toolsDir = join(agentDir, "tools"); + const binDir = getBinDir(); + + if (!existsSync(toolsDir)) return; + + const binaries = ["fd", "rg", "fd.exe", "rg.exe"]; + let movedAny = false; + + for (const bin of binaries) { + const oldPath = join(toolsDir, bin); + const newPath = join(binDir, bin); + + if (existsSync(oldPath)) { + if (!existsSync(binDir)) { + mkdirSync(binDir, { recursive: true }); + } + if (!existsSync(newPath)) { + try { + renameSync(oldPath, newPath); + movedAny = true; + } catch { + // Ignore errors + } + } else { + // Target exists, just delete the old one + try { + rmSync?.(oldPath, { force: true }); + } catch { + // Ignore + } + } + } + } + + if (movedAny) { + console.log(chalk.green(`Migrated managed binaries tools/ → bin/`)); + } +} + /** * Check for deprecated hooks/ and tools/ directories. * Note: tools/ may contain fd/rg binaries extracted by pi, so only warn if it has other files. @@ -169,7 +213,16 @@ function checkDeprecatedExtensionDirs(baseDir: string, label: string): string[] // Check if tools/ contains anything other than fd/rg (which are auto-extracted binaries) try { const entries = readdirSync(toolsDir); - const customTools = entries.filter((e) => e !== "fd" && e !== "rg" && e !== "fd.exe" && e !== "rg.exe"); + const customTools = entries.filter((e) => { + const lower = e.toLowerCase(); + return ( + lower !== "fd" && + lower !== "rg" && + lower !== "fd.exe" && + lower !== "rg.exe" && + !e.startsWith(".") // Ignore .DS_Store and other hidden files + ); + }); if (customTools.length > 0) { warnings.push( `${label} tools/ directory contains custom tools. Custom tools have been merged into extensions.`, @@ -240,6 +293,7 @@ export function runMigrations(cwd: string = process.cwd()): { } { const migratedAuthProviders = migrateAuthToAuthJson(); migrateSessionsFromAgentRoot(); + migrateToolsToBin(); const deprecationWarnings = migrateExtensionSystem(cwd); return { migratedAuthProviders, deprecationWarnings }; } diff --git a/packages/coding-agent/src/utils/tools-manager.ts b/packages/coding-agent/src/utils/tools-manager.ts index e969950c..ebb4ca10 100644 --- a/packages/coding-agent/src/utils/tools-manager.ts +++ b/packages/coding-agent/src/utils/tools-manager.ts @@ -5,9 +5,9 @@ import { arch, platform } from "os"; import { join } from "path"; import { Readable } from "stream"; import { finished } from "stream/promises"; -import { APP_NAME, getToolsDir } from "../config.js"; +import { APP_NAME, getBinDir } from "../config.js"; -const TOOLS_DIR = getToolsDir(); +const TOOLS_DIR = getBinDir(); interface ToolConfig { name: string;