Files
pi/scripts/build-binaries.sh
Armin Ronacher 8562bcf66a feat(coding-agent): codemode and MCP
This adds codemode and MCP support to pi. Codemode (packages/codemode) runs
model-written JavaScript in a QuickJS wasm VM inside a worker. From there the
script calls pi's tools as async functions, uses a per-session store, and can
read the model catalog and run classifiers. The codemode tool in coding-agent
is compatible with Codex's exec tool, and codemode.mode works like Codex's
tool modes (on or only). Large results are written to a JSON temp file. MCP
(packages/mcp) is a standalone client for stdio and streamable HTTP servers,
with OAuth.

The core only gets general mechanisms; codemode, tool_search and MCP are
built-in extensions that use them. Other extensions can replace these
built-ins. Tools declare an exposure: direct, model-only, codemode, deferred
or hidden. prepareLoadout() lets an orchestrating tool change which tool
declarations the model sees. ctx.executeTool() runs nested calls through
validation and the tool_call/tool_result hooks. Those calls emit events with
parentToolCallId and are recorded as bounded nestedCalls on the parent
result, which compaction and HTML export use. Tools can also return
structuredContent with an outputSchema, and can report errors with isError
instead of throwing. MCP servers come from mcp.json (global, or per project
after the project is trusted) or from pi.registerMcpServer(). They are
managed with /mcp and pi mcp list|login|logout, and their runtimes load on
first use.

Closes #10040
2026-09-29 09:12:50 +02:00

200 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Build pi binaries for all platforms locally.
# Mirrors .github/workflows/build-binaries.yml
#
# Usage:
# ./scripts/build-binaries.sh [--skip-install] [--skip-build] [--offline-model-data] [--platform <platform>] [--out <dir>]
#
# Options:
# --skip-install Skip npm ci
# --skip-build Skip the package build
# --offline-model-data Build with bundled model data instead of refreshing it
# --platform <name> Build only for specified platform (darwin-arm64, darwin-x64, linux-x64, linux-arm64, windows-x64, windows-arm64)
# --out <dir> Output directory (default: packages/coding-agent/binaries)
#
# Output:
# packages/coding-agent/binaries/
# pi-darwin-arm64.tar.gz
# pi-darwin-x64.tar.gz
# pi-linux-x64.tar.gz
# pi-linux-arm64.tar.gz
# pi-windows-x64.zip
# pi-windows-arm64.zip
set -euo pipefail
cd "$(dirname "$0")/.."
SKIP_INSTALL=false
SKIP_BUILD=false
OFFLINE_MODEL_DATA=false
PLATFORM=""
OUTPUT_DIR=""
while [[ $# -gt 0 ]]; do
case $1 in
--skip-install)
SKIP_INSTALL=true
shift
;;
--skip-build)
SKIP_BUILD=true
shift
;;
--offline-model-data)
OFFLINE_MODEL_DATA=true
shift
;;
--platform)
PLATFORM="$2"
shift 2
;;
--out)
OUTPUT_DIR="$2"
shift 2
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
# Validate platform if specified
if [[ -n "$PLATFORM" ]]; then
case "$PLATFORM" in
darwin-arm64|darwin-x64|linux-x64|linux-arm64|windows-x64|windows-arm64)
;;
*)
echo "Invalid platform: $PLATFORM"
echo "Valid platforms: darwin-arm64, darwin-x64, linux-x64, linux-arm64, windows-x64, windows-arm64"
exit 1
;;
esac
fi
if [[ -z "$OUTPUT_DIR" ]]; then
OUTPUT_DIR="packages/coding-agent/binaries"
fi
if [[ "$OUTPUT_DIR" != /* ]]; then
OUTPUT_DIR="$(pwd)/$OUTPUT_DIR"
fi
if [[ "$SKIP_INSTALL" == "false" ]]; then
echo "==> Installing dependencies..."
npm ci --ignore-scripts
else
echo "==> Skipping npm ci (--skip-install)"
fi
if [[ "$SKIP_BUILD" == "false" ]]; then
if [[ "$OFFLINE_MODEL_DATA" == "true" ]]; then
echo "==> Building all packages with bundled model data..."
npm run build:offline
else
echo "==> Building all packages..."
npm run build
fi
else
echo "==> Skipping package build (--skip-build)"
fi
echo "==> Building binaries..."
cd packages/coding-agent
# Clean previous builds
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"/{darwin-arm64,darwin-x64,linux-x64,linux-arm64,windows-x64,windows-arm64}
# Determine which platforms to build
if [[ -n "$PLATFORM" ]]; then
PLATFORMS=("$PLATFORM")
else
PLATFORMS=(darwin-arm64 darwin-x64 linux-x64 linux-arm64 windows-x64 windows-arm64)
fi
for platform in "${PLATFORMS[@]}"; do
echo "Building for $platform..."
bun_target="bun-$platform"
if [[ "$platform" == *-x64 ]]; then
bun_target="${bun_target}-baseline"
fi
# Bun compiled executables only embed worker scripts when they are passed as
# explicit build entrypoints. Bun places them at their path relative to the
# common directory of all entrypoints, so the main entry must stay in dist/
# for the worker URLs in src/config.ts to resolve.
#
# Disable cwd bunfig.toml autoload so project preload scripts cannot crash the
# standalone binary before pi starts (see #7684).
if [[ "$platform" == windows-* ]]; then
bun build --compile --no-compile-autoload-bunfig --target="$bun_target" ./dist/bun/cli.js ./src/utils/image-resize-worker.ts ./src/extensions/codemode/worker.ts --outfile "$OUTPUT_DIR/$platform/pi.exe"
else
bun build --compile --no-compile-autoload-bunfig --target="$bun_target" ./dist/bun/cli.js ./src/utils/image-resize-worker.ts ./src/extensions/codemode/worker.ts --outfile "$OUTPUT_DIR/$platform/pi"
fi
done
echo "==> Creating release archives..."
# Copy shared files to each platform directory
for platform in "${PLATFORMS[@]}"; do
cp package.json "$OUTPUT_DIR/$platform/"
cp README.md "$OUTPUT_DIR/$platform/"
cp CHANGELOG.md "$OUTPUT_DIR/$platform/"
cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm "$OUTPUT_DIR/$platform/"
mkdir -p "$OUTPUT_DIR/$platform/theme"
cp dist/modes/interactive/theme/*.json "$OUTPUT_DIR/$platform/theme/"
mkdir -p "$OUTPUT_DIR/$platform/assets"
cp dist/modes/interactive/assets/* "$OUTPUT_DIR/$platform/assets/"
cp -r dist/core/export-html "$OUTPUT_DIR/$platform/"
cp -r docs "$OUTPUT_DIR/$platform/"
cp -r examples "$OUTPUT_DIR/$platform/"
# Copy the selected architecture's native platform helpers next to the executable.
native_platform="${platform/windows-/win32-}"
native_path="native/${native_platform%-*}/prebuilds"
mkdir -p "$OUTPUT_DIR/$platform/$native_path"
cp -R "../tui/$native_path/$native_platform" "$OUTPUT_DIR/$platform/$native_path/"
done
# Create archives
cd "$OUTPUT_DIR"
for platform in "${PLATFORMS[@]}"; do
if [[ "$platform" == windows-* ]]; then
# Windows (zip)
echo "Creating pi-$platform.zip..."
(cd "$platform" && zip -r ../pi-$platform.zip .)
else
# Unix platforms (tar.gz) - use wrapper directory for mise compatibility
echo "Creating pi-$platform.tar.gz..."
mv "$platform" pi && tar -czf pi-$platform.tar.gz pi && mv pi "$platform"
fi
done
# Extract archives for easy local testing
echo "==> Extracting archives for testing..."
for platform in "${PLATFORMS[@]}"; do
rm -rf "$platform"
if [[ "$platform" == windows-* ]]; then
mkdir -p "$platform" && (cd "$platform" && unzip -q ../pi-$platform.zip)
else
tar -xzf pi-$platform.tar.gz && mv pi "$platform"
fi
done
echo ""
echo "==> Build complete!"
echo "Archives available in $OUTPUT_DIR/"
ls -lh *.tar.gz *.zip 2>/dev/null || true
echo ""
echo "Extracted directories for testing:"
for platform in "${PLATFORMS[@]}"; do
if [[ "$platform" == windows-* ]]; then
echo " $OUTPUT_DIR/$platform/pi.exe"
else
echo " $OUTPUT_DIR/$platform/pi"
fi
done