Files
Julius Brussee 216e685646 feat(cli): wire pi as a native host — wrap, enable, doctor, conformance
Pi joins every host surface: NativeAgent unions, capability matrix (incl.
post_tool_rewrite; PostToolUseFailure now returns raw responses for pi and
opencode), native-hook output contracts, Go validAgent +
directOutputRewriteAgent, doctor/status/enable/disable/expectedRoute rows,
and the porcelain agent list (visible cap 7 → 8: '+1 more' rendered longer
than the id it hid).

Wrap door: buildPiWrapArgs prepends the profile-declared loader flag plus the
bundled extension (CAVEMAN_PI_EXTENSION → dist/caveman-pi-extension.mjs),
stamps CAVEMAN_PI_HOOK_CMD + CAVE_GATEWAY_URL, and skips the generic base-URL
env spray — pi routing is extension-side, behind its recovery gate. Missing
asset fails open to a direct launch with a warning; the bundler script fails
the build instead of silently shipping without the asset.

Enable door: journaled write of banner + baked hook invocation + bundle to
~/.pi/agent/extensions/caveman-native.js (Pi auto-discovers only .ts/.js;
.mjs would journal fine and never load). settings.json stays byte-identical.
Status/doctor: pi route health = on-disk artifact ends with the currently
shipped bundle (catches stale bundles after CLI upgrades; the gateway is
resolved at runtime by the extension through the same chain as gatewayURL(),
so enable-time route recording would only manufacture false drift).
hooks install/uninstall pi exit 0 and point at enable/disable — the rewrite
surface ships inside the native extension.

Conformance: pi joins the matrix — a real wrap through the real proxy build
compresses via /w/pi/openai/v1 with a CCR handle booked under agent_slug=pi,
and the stub refuses to run if wrap failed open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ez7w7BBtKrMZCiZz9ea4cb
2026-08-20 04:14:48 +02:00

24 lines
759 B
JavaScript

import { build } from "esbuild";
import { existsSync } from "node:fs";
import { fileURLToPath } from "node:url";
const entry = fileURLToPath(new URL("../../pi-extension/src/index.ts", import.meta.url));
const outfile = fileURLToPath(new URL("../dist/caveman-pi-extension.mjs", import.meta.url));
if (!existsSync(entry)) {
// A silent skip here ships a CLI whose `enable pi`/`wrap pi` asset does not
// exist while every build stays green — fail the build instead.
console.error("pi extension bundle FAILED: packages/pi-extension/src/index.ts not found");
process.exit(1);
}
await build({
entryPoints: [entry],
outfile,
bundle: true,
format: "esm",
platform: "node",
target: "node22",
external: ["@earendil-works/*", "typebox"],
});