feat(skills): add cross-platform install fallback for non-brew environments (#17687)

Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 3ed4850838
Co-authored-by: mcrolly <60803337+mcrolly@users.noreply.github.com>
Co-authored-by: sebslight <19554889+sebslight@users.noreply.github.com>
Reviewed-by: @sebslight
This commit is contained in:
McRolly NWANGWU
2026-02-15 21:25:26 -06:00
committed by GitHub
parent 9df21da129
commit d19b746928
8 changed files with 384 additions and 17 deletions

View File

@@ -275,10 +275,15 @@ export async function installSkill(params: SkillInstallRequest): Promise<SkillIn
const brewExe = hasBinary("brew") ? "brew" : resolveBrewExecutable();
if (spec.kind === "brew" && !brewExe) {
const formula = spec.formula ?? "this package";
const hint =
process.platform === "linux"
? `Homebrew is not installed. Install it from https://brew.sh or install "${formula}" manually using your system package manager (e.g. apt, dnf, pacman).`
: "Homebrew is not installed. Install it from https://brew.sh";
return withWarnings(
{
ok: false,
message: "brew not installed",
message: `brew not installed${hint}`,
stdout: "",
stderr: "",
code: null,
@@ -307,7 +312,8 @@ export async function installSkill(params: SkillInstallRequest): Promise<SkillIn
return withWarnings(
{
ok: false,
message: "uv not installed (install via brew)",
message:
"uv not installed — install manually: https://docs.astral.sh/uv/getting-started/installation/",
stdout: "",
stderr: "",
code: null,
@@ -350,11 +356,145 @@ export async function installSkill(params: SkillInstallRequest): Promise<SkillIn
warnings,
);
}
} else if (hasBinary("apt-get")) {
const aptInstallArgv = ["apt-get", "install", "-y", "golang-go"];
const aptUpdateArgv = ["apt-get", "update", "-qq"];
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
if (isRoot) {
try {
// Best effort: fresh containers often need package indexes populated.
await runCommandWithTimeout(aptUpdateArgv, { timeoutMs });
} catch {
// ignore and continue; install command will return actionable stderr on failure
}
let aptResult;
try {
aptResult = await runCommandWithTimeout(aptInstallArgv, { timeoutMs });
} catch (err) {
const stderr = err instanceof Error ? err.message : String(err);
return withWarnings(
{
ok: false,
message:
"go not installed — automatic install via apt failed. Install manually: https://go.dev/doc/install",
stdout: "",
stderr,
code: null,
},
warnings,
);
}
if (aptResult.code !== 0) {
return withWarnings(
{
ok: false,
message:
"go not installed — automatic install via apt failed. Install manually: https://go.dev/doc/install",
stdout: aptResult.stdout.trim(),
stderr: aptResult.stderr.trim(),
code: aptResult.code,
},
warnings,
);
}
} else {
// Check for non-interactive sudo before attempting apt — avoids hanging
// in containers or environments where sudo is missing or requires a password.
if (!hasBinary("sudo")) {
return withWarnings(
{
ok: false,
message:
"go not installed — apt-get is available but sudo is not installed. Install manually: https://go.dev/doc/install",
stdout: "",
stderr: "",
code: null,
},
warnings,
);
}
let sudoCheck;
try {
sudoCheck = await runCommandWithTimeout(["sudo", "-n", "true"], {
timeoutMs: 5_000,
});
} catch (err) {
const stderr = err instanceof Error ? err.message : String(err);
return withWarnings(
{
ok: false,
message:
"go not installed — apt-get is available but sudo is not usable (missing or requires a password). Install manually: https://go.dev/doc/install",
stdout: "",
stderr,
code: null,
},
warnings,
);
}
if (sudoCheck.code !== 0) {
return withWarnings(
{
ok: false,
message:
"go not installed — apt-get is available but sudo is not usable (missing or requires a password). Install manually: https://go.dev/doc/install",
stdout: sudoCheck.stdout.trim(),
stderr: sudoCheck.stderr.trim(),
code: sudoCheck.code,
},
warnings,
);
}
try {
// Best effort: fresh containers often need package indexes populated.
await runCommandWithTimeout(["sudo", ...aptUpdateArgv], { timeoutMs });
} catch {
// ignore and continue; install command will return actionable stderr on failure
}
let aptResult;
try {
aptResult = await runCommandWithTimeout(["sudo", ...aptInstallArgv], {
timeoutMs,
});
} catch (err) {
const stderr = err instanceof Error ? err.message : String(err);
return withWarnings(
{
ok: false,
message:
"go not installed — automatic install via apt failed. Install manually: https://go.dev/doc/install",
stdout: "",
stderr,
code: null,
},
warnings,
);
}
if (aptResult.code !== 0) {
return withWarnings(
{
ok: false,
message:
"go not installed — automatic install via apt failed. Install manually: https://go.dev/doc/install",
stdout: aptResult.stdout.trim(),
stderr: aptResult.stderr.trim(),
code: aptResult.code,
},
warnings,
);
}
}
} else {
return withWarnings(
{
ok: false,
message: "go not installed (install via brew)",
message: "go not installed install manually: https://go.dev/doc/install",
stdout: "",
stderr: "",
code: null,