190 lines
5.1 KiB
TypeScript
190 lines
5.1 KiB
TypeScript
/**
|
||
* sproutclaw / mengya 命令安装扩展
|
||
*
|
||
* 在 Linux 和 Windows 上分别创建/更新以下命令:
|
||
* - mengya:源码版(Linux: ./pi-test.sh,Windows: pi-test.bat)
|
||
* - sproutclaw:构建版(Linux: ./pi-built.sh,Windows: pi-built.bat)
|
||
*
|
||
* Linux 命令安装到 /usr/local/bin/。
|
||
* Windows 批处理文件创建在项目根目录,需要把项目根目录加入 PATH 后全局使用。
|
||
*
|
||
* 命令 /install-commands 可随时手动重装。
|
||
*/
|
||
|
||
import { existsSync, writeFileSync, chmodSync, readFileSync } from "node:fs";
|
||
import { dirname, join } from "node:path";
|
||
import { fileURLToPath } from "node:url";
|
||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||
|
||
const extensionDir = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
||
const SPROUTCLAW_DIR = dirname(dirname(dirname(dirname(extensionDir))));
|
||
const LINUX_BIN_DIR = "/usr/local/bin";
|
||
|
||
// ---------------------------- Linux scripts ----------------------------
|
||
|
||
function linuxMengyaScript(): string {
|
||
return `#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
cd "${SPROUTCLAW_DIR}"
|
||
exec ./pi-test.sh "$@"
|
||
`;
|
||
}
|
||
|
||
function linuxSproutclawScript(): string {
|
||
return `#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
cd "${SPROUTCLAW_DIR}"
|
||
|
||
case "\${1:-}" in
|
||
\tbuild)
|
||
\t\tshift
|
||
\t\texec npm run build "$@"
|
||
\t\t;;
|
||
\trun)
|
||
\t\tshift
|
||
\t\texec ./pi-built.sh "$@"
|
||
\t\t;;
|
||
\thelp|-h|--help)
|
||
\t\tcat <<'EOF'
|
||
sproutclaw - SproutClaw pi 构建版启动器
|
||
|
||
用法:
|
||
sproutclaw 启动 pi(构建版)
|
||
sproutclaw run [args] 同 sproutclaw
|
||
sproutclaw build 从源码构建所有包
|
||
|
||
其余参数透传给 pi,例如: sproutclaw --version
|
||
EOF
|
||
\t\t;;
|
||
\t*)
|
||
\t\texec ./pi-built.sh "$@"
|
||
\t\t;;
|
||
esac
|
||
`;
|
||
}
|
||
|
||
// ---------------------------- Windows scripts ----------------------------
|
||
|
||
function windowsMengyaBat(): string {
|
||
return `@echo off
|
||
setlocal
|
||
set "SCRIPT_DIR=%~dp0"
|
||
if "%SCRIPT_DIR:~-1%"=="\" set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
|
||
if not defined PI_CODING_AGENT_DIR (
|
||
set "PI_CODING_AGENT_DIR=%SCRIPT_DIR%\.pi\agent"
|
||
)
|
||
call "%SCRIPT_DIR%\pi-test.bat" %*
|
||
exit /b %ERRORLEVEL%
|
||
`;
|
||
}
|
||
|
||
function windowsSproutclawBat(): string {
|
||
return `@echo off
|
||
setlocal
|
||
set "SCRIPT_DIR=%~dp0"
|
||
if "%SCRIPT_DIR:~-1%"=="\" set "SCRIPT_DIR=%SCRIPT_DIR:~0,-1%"
|
||
if not defined PI_CODING_AGENT_DIR (
|
||
set "PI_CODING_AGENT_DIR=%SCRIPT_DIR%\.pi\agent"
|
||
)
|
||
|
||
if "%~1"=="" goto run
|
||
if /I "%~1"=="run" (
|
||
shift
|
||
goto run
|
||
)
|
||
if /I "%~1"=="build" (
|
||
shift
|
||
npm run build %*
|
||
exit /b %ERRORLEVEL%
|
||
)
|
||
if /I "%~1"=="help" goto help
|
||
if "%~1"=="-h" goto help
|
||
if "%~1"=="--help" goto help
|
||
|
||
:run
|
||
call "%SCRIPT_DIR%\pi-built.bat" %*
|
||
exit /b %ERRORLEVEL%
|
||
|
||
:help
|
||
echo sproutclaw - SproutClaw pi 构建版启动器
|
||
echo.
|
||
echo 用法:
|
||
echo sproutclaw 启动 pi(构建版)
|
||
echo sproutclaw run [args] 同 sproutclaw
|
||
echo sproutclaw build 从源码构建所有包
|
||
echo.
|
||
echo 其余参数透传给 pi,例如: sproutclaw --version
|
||
exit /b 0
|
||
`;
|
||
}
|
||
|
||
// ---------------------------- Install helpers ----------------------------
|
||
|
||
function writeIfChanged(path: string, content: string, mode?: number): boolean {
|
||
if (existsSync(path)) {
|
||
try {
|
||
const current = readFileSync(path, "utf-8");
|
||
if (current === content) return false;
|
||
} catch {
|
||
// Rewrite unreadable or invalid files below.
|
||
}
|
||
}
|
||
writeFileSync(path, content, "utf-8");
|
||
if (mode !== undefined) chmodSync(path, mode);
|
||
return true;
|
||
}
|
||
|
||
function installLinuxCommands(): string[] {
|
||
const created: string[] = [];
|
||
if (writeIfChanged(join(LINUX_BIN_DIR, "mengya"), linuxMengyaScript(), 0o755)) {
|
||
created.push("/usr/local/bin/mengya");
|
||
}
|
||
if (writeIfChanged(join(LINUX_BIN_DIR, "sproutclaw"), linuxSproutclawScript(), 0o755)) {
|
||
created.push("/usr/local/bin/sproutclaw");
|
||
}
|
||
return created;
|
||
}
|
||
|
||
function installWindowsCommands(): string[] {
|
||
const created: string[] = [];
|
||
if (writeIfChanged(join(SPROUTCLAW_DIR, "mengya.bat"), windowsMengyaBat())) {
|
||
created.push(join(SPROUTCLAW_DIR, "mengya.bat"));
|
||
}
|
||
if (writeIfChanged(join(SPROUTCLAW_DIR, "sproutclaw.bat"), windowsSproutclawBat())) {
|
||
created.push(join(SPROUTCLAW_DIR, "sproutclaw.bat"));
|
||
}
|
||
return created;
|
||
}
|
||
|
||
// ---------------------------- Extension entry ----------------------------
|
||
|
||
export default function (pi: ExtensionAPI) {
|
||
const isWindows = process.platform === "win32";
|
||
|
||
function install(): string[] {
|
||
return isWindows ? installWindowsCommands() : installLinuxCommands();
|
||
}
|
||
|
||
const created = install();
|
||
for (const path of created) {
|
||
console.log(`[sproutclaw-setup] Created/updated ${path}`);
|
||
}
|
||
|
||
pi.registerCommand("install-commands", {
|
||
description: isWindows
|
||
? "Install mengya.bat (source) and sproutclaw.bat (built) to the repo root"
|
||
: "Install mengya (source) and sproutclaw (built) to /usr/local/bin",
|
||
handler: async (_args, ctx) => {
|
||
const paths = install();
|
||
if (paths.length > 0) {
|
||
ctx.ui.notify(`Installed/updated ${paths.length} command(s):\n${paths.join("\n")}`, "success");
|
||
} else {
|
||
ctx.ui.notify("Commands already up to date", "info");
|
||
}
|
||
if (isWindows) {
|
||
ctx.ui.notify(`请把项目目录加入 PATH 以全局使用:\n${SPROUTCLAW_DIR}`, "info");
|
||
}
|
||
},
|
||
});
|
||
}
|