run_installer
run_installer
Runs a downloaded installer file (.pkg/.dmg on macOS; .msi/.exe on Windows) to (re)install a software application. Use after download_installer when the user has confirmed they want to proceed with installation. Requires admin privileges, which the privileged helper daemon supplies for non-admin users.
Metadata
Name
run_installer
Updated
3 weeks ago
Source
Risk
High
Requires consent
true
Affected scope
system
Code
/**
* mcp/skills/runInstaller.ts — run_installer skill
*
* Executes a downloaded installer file (.pkg/.dmg on macOS;
* .msi/.exe on Windows) to (re)install a software application.
* Use after `download_installer` (Skill #8 Step 6) when the user has
* confirmed they want to proceed with installation.
*
* Privilege model
* ---------------
* Installation requires admin / LocalSystem privilege to write into
* /Applications, /Library/, C:\Program Files, etc. The agent runs as
* the standard user; G4 routes this tool through the privileged helper
* daemon (Workstream B v2 + fast-follow) so non-admin users complete
* the install end-to-end without an interactive password prompt. When
* the helper is unavailable (HELPER_DAEMON_ENABLED=false / not
* installed / unreachable), the call denies with helper-error /
* helper-unavailable / scope-boundary and the agent falls back to the
* "ask the user to run the installer manually" path.
*
* Platform strategy
* -----------------
* macOS .pkg `installer -pkg <path> -target /`
* macOS .dmg mount via `hdiutil`, copy .app to /Applications, eject
* Windows .msi `msiexec /i <path> /qn /norestart`
* Windows .exe Start-Process with /S silent flag
*
* Smoke test
* npx tsx -r dotenv/config mcp/skills/runInstaller.ts
*/
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
import { z } from "zod";
// -- Meta ---------------------------------------------------------------------
export const meta = {
name: "run_installer",
description:
"Runs a downloaded installer file (.pkg/.dmg on macOS; .msi/.exe on " +
"Windows) to (re)install a software application. Use after " +
"download_installer when the user has confirmed they want to " +
"proceed with installation. Requires admin privileges, which the " +
"privileged helper daemon supplies for non-admin users.",
riskLevel: "high",
destructive: true,
requiresConsent: true,
supportsDryRun: true,
affectedScope: ["system"],
auditRequired: true,
escalationHint: {
darwin:
"sudo installer -pkg <path>.pkg -target / # for .pkg; .dmg requires hdiutil mount + cp + eject",
win32:
"msiexec /i <path>.msi /qn /norestart # for .msi; .exe varies per vendor (try /S for silent install)",
},
schema: {
installer_path: z
.string()
.min(1)
.describe(
"Absolute path to the installer file on disk. Typically the " +
"filePath returned by a prior download_installer call.",
),
installer_type: z
.enum(["pkg", "dmg", "msi", "exe"])
.optional()
.describe(
"Installer type. When omitted, auto-detected from the file " +
"extension. Must match the platform (pkg/dmg → macOS; " +
"msi/exe → Windows).",
),
dryRun: z
.boolean()
.optional()
.describe(
"If true, validate the installer + show what would run, but do " +
"not execute. Default: true (G4 dry-run-first policy).",
),
},
} as const;
// -- Types --------------------------------------------------------------------
interface RunInstallerResult {
installerPath: string;
installerType: "pkg" | "dmg" | "msi" | "exe";
dryRun: boolean;
/** The exact command string the helper / sudo would execute. Echoed
* in dry-run mode so the consent gate can show it to the user. */
plannedCommand: string;
/** Set after a real run; absent in dry-run mode. */
exitCode?: number;
/** Set after a real run; absent in dry-run mode. */
durationMs?: number;
message: string;
}
// -- Helpers ------------------------------------------------------------------
function detectInstallerType(installerPath: string): "pkg" | "dmg" | "msi" | "exe" {
const ext = path.extname(installerPath).toLowerCase().replace(/^\./, "");
if (ext === "pkg" || ext === "dmg" || ext === "msi" || ext === "exe") {
return ext;
}
throw new Error(
`Cannot detect installer type from extension '.${ext}' — supply installerType explicitly`,
);
}
function plannedCommandFor(
type: "pkg" | "dmg" | "msi" | "exe",
installerPath: string,
): string {
switch (type) {
case "pkg":
return `installer -pkg \