Files
msd-core/tests/fixtures/pi-host-plugin.cjs
Tom Boucher 79d7657eff feat(#2102): make pi a first-class installable runtime + fix its dispatch (ADR-1239)
Net-new EoS/pi installable runtime — purely additive (no prior runtime==='pi'
branches). pi is a bun-runtime programmatic-CLI whose /gsd command is registered
by a native ExtensionAPI extension and dispatches through the embedded engine.

Stage 1 (install plumbing):
- capabilities/pi/capability.json: full hostIntegration descriptor (imperative /
  slash-programmatic / active-model / native-extension / bun) + hostBehaviors
  {nativePlugin, pluginOnlyInstall}.
- --pi flag + interactive-menu renumber (All 17->18); pi added to RUNTIME_FLAG_IDS,
  RUNTIME_LABELS, RUNTIME_META, allRuntimes/runtimeMap, model-catalog defaults.
- Install mirrors OpenCode: pi installs the gsd.cjs extension + the shared engine
  payload (gsd-core + scripts + config markers) + the shared hooks bundle (spawned
  by the extension at lifecycle events, like OpenCode's plugin). pluginOnlyInstall
  EXCLUDES declarative command/agent/skill markdown, which pi has no host-read
  surface for (its /gsd is programmatic). _installNativePluginIfDeclared (extracted
  from the opencode-family path) copies pi/gsd.cjs -> ~/.pi/agent/extensions/gsd.cjs
  (global) / .pi/extensions/ (local). pi added to package.json files.
- Golden: new pi.json (320 files: extension + engine + 27-file hooks bundle, no
  markdown); the 16 other fixtures + claude-local change only by the shared
  model-catalog hash line.

Stage 2 (real dispatch + upgrades):
- Shared dispatchGsdCommand() (shell-command-projection): bounded, no-throw
  subprocess-shim to gsd-tools.cjs (the only full-surface dispatch path; no
  in-process full-hub factory exists). Fixes pi/gsd.cjs's createHub()-no-args bug
  (every dispatch was UnknownCommand) AND the identical bug in mcp-server.cts's
  gsd_invoke_command, which a vacuous unknown-family-only test had masked (now has
  a real dispatch regression test).
- pi/gsd.cjs: /gsd handler now (args, ctx) - tokenizes (quote-aware, via the
  shipped hooks/lib/git-cmd.js) + dispatches real family/subcommand (not hardcoded
  query/help); gsd_invoke gets a TypeBox (JSON-schema-fallback) parameters schema +
  consumes params; getArgumentCompletions; before_provider_request active-model
  steering (fail-open on null resolution); functional session_start /
  before_agent_start / session_before_compact hook bridges (spawn the shipped GSD
  hook scripts).
- EXTENSION_EVENT_SURFACES.pi expanded from ['tool_call'] to the full 30-event
  vocabulary.

Docs (host-integration matrix + how-to) + changeset (Added).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 21:07:38 -04:00

71 lines
3.0 KiB
JavaScript

'use strict';
/**
* Reference pi host-plugin for GSD (ADR-1239 Phase D / #1682 Slice 3).
*
* pi (pi.dev) is a Programmatic-CLI host whose TS extensions implement the
* ExtensionAPI (`@earendil-works/pi-coding-agent`): registerTool /
* registerCommand / registerShortcut / registerFlag / pi.on(event, …). This
* reference plugin binds GSD's command + tool + event surface to pi via the
* IMPERATIVE adapter path — the programmatic-cli peer of the OpenCode worked
* binding.
*
* Shipped as CommonJS with a recorded-mock-friendly signature so it is
* behaviorally testable without a live pi runtime. The default export matches
* pi's extension entry shape: `export default function (pi: ExtensionAPI) { … }`.
*
* #2102 Stage 2: registerCommand takes `handler(args, ctx)` (args is the raw
* string after the command) — NOT `execute(ctx)`, which the original #1682
* cut used. gsd_invoke's `execute` takes pi's real 5-arg tool-execute
* signature `(toolCallId, params, signal, onUpdate, ctx)`. See pi/gsd.cjs for
* the full production binding this reference fixture mirrors.
*
* NOTE: this is the reference binding that proves the ExtensionAPI imperative
* adapter (#1682 AC), kept as a mock-friendly fixture independent of the real
* `pi/gsd.cjs` extension. Full `--pi` installable-runtime integration
* (descriptor + installer wiring + golden parity 16→17) shipped in #2102
* Stage 1 — see capabilities/pi/capability.json and
* tests/fixtures/golden-install-parity/pi.json.
*
* @param {object} pi pi ExtensionAPI (registerTool/registerCommand/on/…)
*/
module.exports = function gsdPiPlugin(pi) {
if (!pi || typeof pi !== 'object') {
throw new TypeError('gsdPiPlugin: pi ExtensionAPI is required');
}
// Command surface: `/gsd` invokes the GSD command-routing hub via the
// imperative adapter (createImperativeAdapter({runtime:'pi'}) + dispatch).
pi.registerCommand('gsd', {
description: 'Invoke a GSD command via the embedded engine (imperative adapter).',
handler: async function (args, ctx) {
void args;
void ctx;
// Engine dispatch is wired by the host at load (createImperativeAdapter).
// Kept declarative in the reference; the real binding (pi/gsd.cjs)
// dispatches through gsd-tools.cjs via dispatchGsdCommand.
},
});
// Tool surface: a `gsd_invoke` tool mirroring the companion-MCP tool surface
// (interface point 1) so the model can call GSD commands programmatically.
pi.registerTool({
name: 'gsd_invoke',
description: 'Invoke a GSD command family/subcommand through the engine.',
execute: async function (toolCallId, params, signal, onUpdate, ctx) {
void toolCallId;
void params;
void signal;
void onUpdate;
void ctx;
return 'ok';
},
});
// Event surface: observe tool calls — the pi subset hook surface (peer of the
// OpenCode opencode-subset). Attachment point for the GSD hook bridge.
pi.on('tool_call', async function /* event */ () {
/* GSD hook bridge attachment point (PreToolUse/PostToolUse mapping). */
});
};