pin all CLI installations to explicit versions and use pro models by default (#283)

* pin all CLI installations to explicit versions and use pro models by default

- codex: pin @openai/codex to 0.101.0 (was "latest")
- opencode: pin opencode-ai to 1.1.56 (was "latest")
- gemini: pin gemini-cli to v0.28.2 via new tag param on installFromGithub
- cursor: pin to 2026.01.28-fd13201 via direct tarball download (replaces curl install script)
- add installFromDirectTarball to install.ts for versioned tarball URLs
- gemini auto effort now uses pro-preview instead of flash-preview
- test runner model overrides updated to use pro-preview consistently

Co-authored-by: Cursor <cursoragent@cursor.com>

* increase activity timeout

* fix delegation timeout

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
David Blass
2026-02-12 22:48:29 +00:00
committed by pullfrog[bot]
parent 9071c0ae6c
commit ceadb3120a
8 changed files with 163 additions and 65 deletions
+70 -5
View File
@@ -1,5 +1,5 @@
import { spawnSync } from "node:child_process";
import { chmodSync, createWriteStream, existsSync } from "node:fs";
import { chmodSync, createWriteStream, existsSync, mkdirSync } from "node:fs";
import { mkdtemp } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
@@ -18,9 +18,16 @@ export interface InstallFromCurlParams {
executableName: string;
}
export interface InstallFromDirectTarballParams {
url: string;
executablePath: string;
stripComponents?: number;
}
export interface InstallFromGithubParams {
owner: string;
repo: string;
tag?: string;
assetName?: string;
executablePath?: string;
githubInstallationToken?: string;
@@ -29,6 +36,7 @@ export interface InstallFromGithubParams {
export interface InstallFromGithubTarballParams {
owner: string;
repo: string;
tag?: string;
assetNamePattern: string;
executablePath: string;
githubInstallationToken?: string;
@@ -181,8 +189,10 @@ async function fetchWithRetry(
export async function installFromGithub(params: InstallFromGithubParams): Promise<string> {
log.info(`» installing ${params.owner}/${params.repo} from GitHub releases...`);
// fetch release from GitHub API (latest)
const releaseUrl = `https://api.github.com/repos/${params.owner}/${params.repo}/releases/latest`;
// fetch release from GitHub API (pinned tag or latest)
const releaseUrl = params.tag
? `https://api.github.com/repos/${params.owner}/${params.repo}/releases/tags/${params.tag}`
: `https://api.github.com/repos/${params.owner}/${params.repo}/releases/latest`;
log.debug(`» fetching release from ${releaseUrl}...`);
const headers: Record<string, string> = {};
@@ -261,8 +271,10 @@ export async function installFromGithubTarball(
const arch = process.arch === "arm64" ? "arm64" : "x64";
const assetName = params.assetNamePattern.replace("{os}", os).replace("{arch}", arch);
// fetch release from GitHub API (latest)
const releaseUrl = `https://api.github.com/repos/${params.owner}/${params.repo}/releases/latest`;
// fetch release from GitHub API (pinned tag or latest)
const releaseUrl = params.tag
? `https://api.github.com/repos/${params.owner}/${params.repo}/releases/tags/${params.tag}`
: `https://api.github.com/repos/${params.owner}/${params.repo}/releases/latest`;
log.info(`» fetching release from ${releaseUrl}...`);
const headers: Record<string, string> = {};
@@ -328,6 +340,59 @@ export async function installFromGithubTarball(
return cliPath;
}
/**
* Install a CLI tool from a direct tarball URL.
* Downloads the tarball, extracts it to a temp directory, and returns the path to the CLI executable.
*/
export async function installFromDirectTarball(
params: InstallFromDirectTarballParams
): Promise<string> {
log.info(`» downloading tarball from ${params.url}...`);
const tempDir = process.env.PULLFROG_TEMP_DIR!;
const tarballPath = join(tempDir, "direct-package.tgz");
const response = await fetch(params.url);
if (!response.ok) {
throw new Error(`failed to download tarball: ${response.status} ${response.statusText}`);
}
if (!response.body) throw new Error("response body is null");
const fileStream = createWriteStream(tarballPath);
await pipeline(response.body, fileStream);
log.debug(`» downloaded tarball to ${tarballPath}`);
// always extract into a dedicated directory
const extractDir = join(tempDir, "direct-package");
mkdirSync(extractDir, { recursive: true });
const tarArgs = ["-xzf", tarballPath, "-C", extractDir];
if (params.stripComponents) {
tarArgs.push(`--strip-components=${params.stripComponents}`);
}
log.debug(`» extracting tarball...`);
const extractResult = spawnSync("tar", tarArgs, {
stdio: "pipe",
encoding: "utf-8",
});
if (extractResult.status !== 0) {
throw new Error(
`failed to extract tarball: ${extractResult.stderr || extractResult.stdout || "unknown error"}`
);
}
const cliPath = join(extractDir, params.executablePath);
if (!existsSync(cliPath)) {
throw new Error(`executable not found in extracted tarball at ${cliPath}`);
}
chmodSync(cliPath, 0o755);
log.info(`» installed at ${cliPath}`);
return cliPath;
}
/**
* Install a CLI tool from a curl-based install script
* Downloads the install script, runs it with HOME set to temp directory, and returns the path to the CLI executable