feat: builtin thin agent plugins (pi/omp/claude/codex/opencode) + bili plugin install CLI - #173
Conversation
- src/agent/shared.ts: proxy detection (/bili/ prefix, BILLION_CONTEXT_PROXY, kill switch), manifest fetch, tool forwarding, status fetch - src/agent/pi.ts: pi/omp extension factory, zero runtime deps, registers manifest tools at session_start, stamps x-bili-plugin* headers - src/plugin-install.ts: bili plugin install/remove/list for 5 hosts with backup+idempotency; PI_CODING_AGENT_DIR respected - tests: 7 new tests (460 total green)
pi replaces the boot session while the awaited manifest fetch is in flight; registerTool on the captured ctx then throws. Register per session id instead, catch staleness and defer, and retry from before_provider_headers (fires per request with a live ctx) as the safety net.
- pi/omp ToolResult contract: {content:[{type:"text",text}],isError?}
(crashed pi live when forwarding tool output)
- strict /bili/ detection (first path segment + /https?:// next), protocol check
- registration: per-session-id single-flight, 10s retry throttle,
before_provider_headers fallback, hostile host shape defense
- AbortSignal passthrough, explicit timeout errors, args default
- createBiliPlugin(agent) factory; omp reports omp, custom agents supported
- plugin install: OPENCODE_CONFIG/OMP_CONFIG are file paths, CODEX_HOME/
CLAUDE_CONFIG_DIR are dirs; refuse to overwrite broken/non-object JSON;
installers throw -> CLI exits 1; omp YAML flow-style/multi-key/column-0
guards + quoted-entry removal; pi stale node_modules entries cleaned;
codex line-regex table match; claude exec 15s timeout
- cli: --origin/--agent flags, non-empty value validation, plugin-register
agent param + 5s timeout, HELP covers mcp/plugin-register
…tamped proxy origin
- mcp.ts: fetch manifest lazily on first tools/list instead of
fetch+exit(1) at startup; codex spawns MCP children with a sanitized
env, so a missing BILI_MCP_PROXY used to resolve the dead default
origin and kill the handshake ("connection closed: initialize
response") before stdin was ever attached. initialize now always
responds; tools/list reports a JSON-RPC error when the proxy is
unreachable instead of dropping the server for the whole session.
- plugin-install codex/claude/opencode: stamp the resolved proxy origin
(BILI_MCP_PROXY env > proxy-origin file > default) into the MCP
config at install time (TOML env block / claude -e flag / opencode
environment field); reinstalling codex refreshes a stale origin.
- verified live: codex exec spawns bili MCP, lists mcp__bili__* tools,
and completes an acp_status tools/call round-trip through the proxy.
- drop stray .bili-coop-build-stamp; .gitignore entry now matches the actual harness filename (was .bili-thin-build-stamp) - plugin list: per-row try/catch so one broken host config (e.g. ~/.claude.json) no longer crashes bili plugin list - mcp: forwardTool gets a 60s timeout (wrapped as a readable error), register fetch a 5s timeout; proxy origin resolved per request so a restarted proxy on a new port self-heals - requireDistFile warning: process.stderr.write instead of console.error (AGENTS.md: console.error only in cli.ts/index.ts) - tests: plugin list survives broken config; mcp forwardTool timeout
The roundtrip test asserted the installed extension path with a forward-slash-only regex (dist\/agent\/omp\.js), which cannot match on windows-latest where the path uses backslashes (D:\a\...\dist\agent\omp.js). Use dist[\/]agent[\/]omp\.js so the assertion passes on both platforms.
|
The design here is the strongest of the open PRs — one shared protocol client ( 1. The claude test is environment-dependent and fails on any machine with the
Suggested fix: honor the env var as the command — 2. if (overrides.BILI_MCP_PROXY) process.env.BILI_MCP_PROXY = overrides.BILI_MCP_PROXY;(same for Minor nits (non-blocking):
|
Blockers: - claude install/remove now honor CLAUDE as the binary path; tests inject a missing stub so the failure-path assertion no longer depends on the claude CLI being absent from the machine running the suite. - `bili plugin install <agent> --origin` was silently dropped: the plugin branch returns before the generic overrides->process.env merge, so a stale ~/.local/state/billion-context/proxy-origin discovery file won. Apply the flag to the env before dispatching the subcommand. Nits: - drop dead retryTimer field on RegisterState; cache empty session ids so hosts without a sessionManager stop refetching the manifest per request. - fetchJson: an already-aborted external signal never fires "abort"; forward the state immediately instead of waiting out the timeout. - claude remove is a no-op when nothing is installed (matches other agents). - proxy-origin discovery file: respect --host (collapse wildcard/localhost binds to 127.0.0.1, bracket bare IPv6 literals) instead of hardcoding. Tests: 467/467 pass, typecheck clean; --origin end-to-end verified against a stale state file (9999 wins over 46657).
|
Addressed both blockers and the nits in 30fbefb: Blockers
Nits: dead Local: 467/467 tests + typecheck clean. |
What
Ships the per-agent builtin plugin layer discussed in the 内外呼应 track: a thin (~100 line) extension per host family that registers the proxy's ACP tools natively and forwards executes to the proxy. Zero acp-kernel in the plugin — the proxy stays the single engine, so no kernel-version skew is possible.
Files
src/agent/shared.ts— proxy discovery (/bili/ URL prefix, BILLION_CONTEXT_PROXY env, BILLION_CONTEXT_PLUGIN=0 kill switch) + manifest/tool-forward/status clientsrc/agent/pi.ts/src/agent/omp.ts— pi & omp ExtensionAPI factory (same API shape); stamps x-bili-plugin/-conversation/-context-window headers on provider requests; registers manifest tools at session_start with retry throttle; ToolResult content-block contract per pi-stable typessrc/plugin-install.ts— per-host installers (pi settings.json packages, omp config.yml extensions, codex config.toml [mcp_servers.bili] with env-stamped proxy origin, claude mcp add -e, opencode mcp.bili environment); all idempotent with .bili-bak backupsrc/mcp.ts— lazy manifest fetch on first tools/list (no more fetch+exit at startup), 5s timeoutsrc/cli.ts,tsup.config.ts(dist/agent/pi.js + omp.js entries),package.jsonpi manifest fieldtests/plugin-agent.test.ts— 11 tests: discovery variants, hostile host shapes, throttle dedupe, install/remove roundtrips for all 5 hosts under fake HOMEs (broken-config refusal, flow-style YAML, TOML table surgery, stale-origin refresh)Live verification (this machine, isolated HOMEs)
Notable bugs found during live testing (all fixed here)
{content:[{type:"text",text}],isError}— a plain{output}shape crashed the agent mid-session.module.exports.defaultor pi/omp silently skip the extension.Full test suite 464/464, typecheck clean, build ok.