import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { apiGuideTool } from "./tools/api-guide.js"; import { apiFetchTool } from "./tools/api-fetch.js"; import { apiLearnTool } from "./tools/api-learn.js"; import { apiProbeTool } from "./tools/api-probe.js"; import { apiScaffoldTool } from "./tools/api-scaffold.js"; import { apiStoreTool } from "./tools/api-store.js"; import { oauthMintTool } from "./tools/oauth-mint.js"; import initApiToggle from "./core/api-toggle.js"; import { registerPortalProjection } from "./core/portal-projection.js"; import { invalidateCache, loadAllGuides } from "./core/guide-store.js"; import { cleanupAllSpill } from "./core/response-spill.js"; import { resetToggleModuleState } from "./core/api-toggle.js"; import { resetDisabledHelpers } from "./core/local-helpers.js"; export default function (pi: ExtensionAPI): void { // --- Ensure idempotent re-invocation ---------------------------- // pi reuses the cached extension factory on /resume (same cwd), // which re-invokes this function with the same module-level // singletons. Reset them here so the second load is safe. resetToggleModuleState(); resetDisabledHelpers(); // ── Register tools ─────────────────────────────────────────── pi.registerTool(apiGuideTool); pi.registerTool(apiFetchTool); pi.registerTool(apiLearnTool); pi.registerTool(apiProbeTool); pi.registerTool(apiScaffoldTool); pi.registerTool(apiStoreTool); pi.registerTool(oauthMintTool); // ── Register /api command and session hooks ───────────────── initApiToggle(pi); // ── Portal co-install integration ──────────────────────────── // Register host's guide projection with portal if co-installed. // Runtime feature-detect — no static portal import. registerPortalProjection(); // session_start ensures registration even if host loads before portal. pi.on("session_start", async (_event, ctx) => { registerPortalProjection(); // Clear the guide-store cache so a folder rename (fixing the divergence // check's "mv" instruction) made between sessions is picked up — // regardless of whether pi re-evaluates the module or re-calls the entry // function with persisted module-level state (the /resume path). invalidateCache(); // Trigger a fresh scan with the UI notify channel so the schema-gate // banner + per-guide warnings render through the Text component (wraps // long lines, honors newlines) instead of raw console.warn (truncates // + merges with the status bar). No-op on a warm cache; every later // command/tool call hits the cached scan, so this is the single // load-time warning point. loadAllGuides(ctx.ui.notify); }); // ── Response spill cleanup ───────────────────────────────── pi.on("session_shutdown", async () => { cleanupAllSpill(); }); // cleanupAllSpill() on shutdown + eviction cap bounds disk use. // Add per-session cleanup if cross-conversation leaks are observed. }