// api.ts から分割(挙動不変): ツールカタログ。 import { BASE } from './client'; // --- Tools --- /** * Runtime tool catalog entry. Mirrors `ToolCatalogEntry` exported by * `src/bridge/tools-api.ts` (server side). See design doc step 4: * docs/superpowers/specs/2026-05-21-settings-ui-and-config-restructure-design.md */ export interface ToolCatalogEntry { name: string; source: 'builtin' | 'meta' | 'mcp'; /** * Coarse grouping for UI. For builtin/meta tools this is a module name * (e.g. 'core', 'web'). For MCP tools the server uses `mcp:`. */ category: string; /** MCP server id (only set when source === 'mcp'). */ serverId?: string; /** Whether the tool can be invoked right now. */ available: boolean; /** Human-readable explanation when `available` is false. */ reason?: string; /** * - 'global' → meta tools auto-injected by the agent loop (always available) * - 'piece' → builtin tool gated by the workspace tool policy (Settings → Tools) * - 'user' → per-user resource (MCP / SSH) */ scope: 'global' | 'piece' | 'user'; } export async function fetchTools(): Promise { const res = await fetch(`${BASE}/tools`); if (!res.ok) throw new Error('Failed to fetch tools'); const data = (await res.json()) as { tools?: unknown }; if (!Array.isArray(data.tools)) return []; // Server may still occasionally serve the legacy flat-string shape (e.g. // during a transient mismatch / proxy / cache). Filter to only well-formed // catalog entries so the UI never crashes; legacy strings are dropped. return data.tools.filter( (t): t is ToolCatalogEntry => typeof t === 'object' && t !== null && typeof (t as { name?: unknown }).name === 'string', ); }