- test(FN-2370): complete Step 3 — align qa-check template expectation - test(FN-2370): complete Step 2 — add regression coverage for addComment diagnostics - test(FN-2370): complete Step 2 — cover addComment warning regressions - feat(FN-2370): complete Step 1 — log addComment best-effort failures - feat(FN-2369): merge fusion/fn-2369 - feat(prompts): require lint alongside tests and typecheck in agent instructions - perf(test): parallelize harder — unlock worker count, split build-output, bump workspace concurrency - fix(core): recognize legacy kb-* backups and canonicalize .kb/backups settings - refactor: eliminate remaining 15 any warnings and ratchet rule to error - refactor: eliminate ~400 no-explicit-any warnings across the workspace - feat(core): add getErrorMessage helper for narrowing unknown errors - refactor: fix and tighten mechanical lint rules - chore(eslint): fix pre-existing errors surfaced by wider .cjs match - chore(eslint): promote @typescript-eslint/no-unused-vars from warn to error - refactor(dashboard,desktop,engine): remove unused imports, props, and locals - refactor(core): remove unused imports, helpers, and dead migration constant - refactor(cli): remove unused imports and variables - refactor: adapt resource loader and tool wiring to pi-coding-agent 0.70 - fix: adapt to AgentState.error → errorMessage rename - refactor: migrate @sinclair/typebox imports to typebox 1.x - refactor: migrate to ModelRegistry.create factory - chore: bump pi-coding-agent + pi-ai to 0.70.0 - refactor: remove legacy kb compatibility - feat: add "Anthropic — via Claude CLI" as a first-class provider - test(FN-2358): harden clean-worktree CI verification tests - fix(FN-2352): add structured terminal websocket diagnostics - fix: use live merge-base for task diff scope - feat: backfill Claude skills when useClaudeCli toggle flips on - fix: prevent nested .fusion/.fusion dir from PluginStore path bug
110 lines
3.4 KiB
TypeScript
110 lines
3.4 KiB
TypeScript
/**
|
|
* Pi extension entry point for pi-claude-cli.
|
|
*
|
|
* Registers a custom provider that routes LLM calls through the Claude Code CLI
|
|
* subprocess using stream-json NDJSON protocol.
|
|
*/
|
|
|
|
import { getModels } from "@mariozechner/pi-ai";
|
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
import { streamViaCli } from "./src/provider.js";
|
|
import {
|
|
validateCliPresence,
|
|
validateCliAuth,
|
|
killAllProcesses,
|
|
} from "./src/process-manager.js";
|
|
import { getCustomToolDefs, writeMcpConfig } from "./src/mcp-config.js";
|
|
|
|
// Kill all active Claude subprocesses on process exit to prevent orphans
|
|
process.on("exit", killAllProcesses);
|
|
|
|
const PROVIDER_ID = "pi-claude-cli";
|
|
|
|
let mcpConfigPath: string | undefined;
|
|
let mcpConfigResolved = false;
|
|
|
|
/**
|
|
* Lazily generate MCP config on first request (not at load time).
|
|
* pi.getAllTools() fails during extension loading; this defers it
|
|
* until the pi runtime is fully initialized.
|
|
*
|
|
* Only locks (sets mcpConfigResolved) when getAllTools() returns a
|
|
* real array — if it returns undefined/null (registry not ready),
|
|
* we retry on the next request. Once the registry is ready we
|
|
* commit to the result even if there are zero custom tools.
|
|
*
|
|
* Uses warn-don't-block: failure logs a warning but does not
|
|
* prevent the provider from functioning (built-ins still work).
|
|
*/
|
|
function ensureMcpConfig(pi: ExtensionAPI): string | undefined {
|
|
if (mcpConfigResolved) return mcpConfigPath;
|
|
try {
|
|
const allTools = pi.getAllTools();
|
|
|
|
// Registry not ready yet — don't lock, retry on next call
|
|
if (!Array.isArray(allTools)) {
|
|
return mcpConfigPath;
|
|
}
|
|
|
|
// Registry is ready — lock regardless of whether custom tools exist
|
|
mcpConfigResolved = true;
|
|
|
|
const toolDefs = getCustomToolDefs(pi);
|
|
if (toolDefs.length > 0) {
|
|
mcpConfigPath = writeMcpConfig(toolDefs);
|
|
console.error(
|
|
`[pi-claude-cli] MCP config generated with ${toolDefs.length} custom tool(s)`,
|
|
);
|
|
}
|
|
} catch (err) {
|
|
console.warn(
|
|
"[pi-claude-cli] MCP config generation failed, custom tools unavailable:",
|
|
err,
|
|
);
|
|
}
|
|
return mcpConfigPath;
|
|
}
|
|
|
|
export default function (pi: ExtensionAPI) {
|
|
try {
|
|
// Startup validation
|
|
validateCliPresence(); // throws if CLI not on PATH
|
|
validateCliAuth(); // warns if not authenticated
|
|
|
|
const models = getModels("anthropic").map((model) => ({
|
|
id: model.id,
|
|
name: model.name,
|
|
reasoning: model.reasoning,
|
|
input: model.input,
|
|
cost: model.cost,
|
|
contextWindow: model.contextWindow,
|
|
maxTokens: model.maxTokens,
|
|
}));
|
|
|
|
// Ensure all registered tools are active so pi can execute them.
|
|
// Some tools (find, grep, ls) are registered but not activated by default.
|
|
pi.on("session_start", async () => {
|
|
const allTools = pi.getAllTools();
|
|
if (Array.isArray(allTools)) {
|
|
pi.setActiveTools(allTools.map((t: { name: string }) => t.name));
|
|
}
|
|
});
|
|
|
|
pi.registerProvider(PROVIDER_ID, {
|
|
baseUrl: "pi-claude-cli",
|
|
apiKey: "unused",
|
|
api: "pi-claude-cli",
|
|
models,
|
|
streamSimple: (model, context, options) => {
|
|
const configPath = ensureMcpConfig(pi);
|
|
return streamViaCli(model, context, {
|
|
...options,
|
|
mcpConfigPath: configPath,
|
|
});
|
|
},
|
|
});
|
|
} catch (err) {
|
|
console.error(`[pi-claude-cli] Failed to register provider:`, err);
|
|
}
|
|
}
|