mirror of
https://github.com/logancyang/obsidian-copilot.git
synced 2026-07-22 07:50:24 +00:00
Introduces a second ACP backend (claude-agent-acp) alongside opencode. To support more than one backend, AgentSessionManager now resolves backends lazily per session via a registry, and a new AgentModelPreloader probes each ready backend at startup so the picker can show models for inactive backends.
68 lines
2.5 KiB
TypeScript
68 lines
2.5 KiB
TypeScript
import { getSettings } from "@/settings/model";
|
|
import { AcpBackend, AcpSpawnDescriptor } from "@/agentMode/acp/types";
|
|
import * as path from "node:path";
|
|
|
|
/**
|
|
* Spawns the user-provided `claude-agent-acp` binary
|
|
* (`@agentclientprotocol/claude-agent-acp`). The package wraps the local
|
|
* `claude` CLI and exposes it as an ACP server over stdio. Authentication is
|
|
* inherited from `~/.claude/` — the user logs in with `claude auth login`
|
|
* outside the plugin and we just spawn the adapter; we deliberately do not
|
|
* pass `ANTHROPIC_API_KEY` so subscription accounts work transparently.
|
|
*
|
|
* Unlike OpenCode, Claude Code does not consume Copilot's `activeModels` or
|
|
* BYOK keys; its model list comes entirely from the agent's own
|
|
* `availableModels` stream (live or preloader-cached).
|
|
*/
|
|
export class ClaudeCodeBackend implements AcpBackend {
|
|
readonly id = "claude-code" as const;
|
|
readonly displayName = "Claude Code";
|
|
|
|
async buildSpawnDescriptor(_ctx: { vaultBasePath: string }): Promise<AcpSpawnDescriptor> {
|
|
const binaryPath = getSettings().agentMode?.backends?.["claude-code"]?.binaryPath;
|
|
if (!binaryPath) {
|
|
throw new Error(
|
|
"Claude Code binary path not configured. Open Agent Mode settings and set the path to claude-agent-acp."
|
|
);
|
|
}
|
|
return {
|
|
command: binaryPath,
|
|
args: [],
|
|
env: {
|
|
...process.env,
|
|
PATH: augmentPathForNodeShebang(binaryPath, process.env.PATH),
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* macOS GUI apps (Obsidian) inherit a minimal PATH that omits Homebrew and
|
|
* common Node installer locations. `claude-agent-acp` is a `#!/usr/bin/env
|
|
* node` script, so the spawn fails with `env: node: No such file or
|
|
* directory` unless we put `node` on PATH ourselves.
|
|
*
|
|
* We prepend the directory containing the binary (npm globals install the
|
|
* launcher script next to `node`) plus the well-known Homebrew / system
|
|
* prefixes, then keep the inherited PATH for everything else.
|
|
*/
|
|
function augmentPathForNodeShebang(binaryPath: string, inherited: string | undefined): string {
|
|
const sep = process.platform === "win32" ? ";" : ":";
|
|
const candidates = [
|
|
path.dirname(binaryPath),
|
|
"/opt/homebrew/bin",
|
|
"/usr/local/bin",
|
|
"/usr/bin",
|
|
"/bin",
|
|
];
|
|
const inheritedParts = (inherited ?? "").split(sep).filter(Boolean);
|
|
const seen = new Set<string>();
|
|
const merged: string[] = [];
|
|
for (const p of [...candidates, ...inheritedParts]) {
|
|
if (!seen.has(p)) {
|
|
seen.add(p);
|
|
merged.push(p);
|
|
}
|
|
}
|
|
return merged.join(sep);
|
|
}
|