/**
 * Custom Tool Loader — user-defined agent tools (STU-48).
 *
 * Scans one or more tool directories for subdirectories containing a tool.js
 * entrypoint. Each tool.js must export a default object with:
 *
 *   {
 *     name:        string       — unique tool identifier
 *     description: string       — shown to the agent
 *     parameters:  JSON Schema  — input validation
 *     execute:     async (toolCallId, params, context) => { content, details }
 *   }
 *
 * Directories are processed in order — first occurrence of a name wins,
 * so workspace-level tools override app-bundled tools.
 *
 * context provides: { workspaceManager, gitUser }
 */
import { existsSync, readdirSync } from 'fs';
import { join } from 'path';
import { log } from '../../utils/log.js';
export async function loadCustomTools(toolsDirs, context) {
    const tools = [];
    const seen = new Set();
    for (const dir of toolsDirs) {
        if (!existsSync(dir))
            continue;
        let entries;
        try {
            entries = readdirSync(dir);
        }
        catch {
            continue;
        }
        for (const entry of entries) {
            if (entry.startsWith('.'))
                continue;
            const toolPath = join(dir, entry, 'tool.js');
            if (!existsSync(toolPath))
                continue;
            try {
                const mod = await import(toolPath);
                const tool = mod.default ?? mod;
                if (!tool || typeof tool !== 'object') {
                    log.warn(`Custom tool at ${toolPath}: does not export an object — skipping`);
                    continue;
                }
                if (typeof tool.name !== 'string' || !tool.name) {
                    log.warn(`Custom tool at ${toolPath}: missing required field "name" — skipping`);
                    continue;
                }
                if (typeof tool.execute !== 'function') {
                    log.warn(`Custom tool at ${toolPath}: missing required field "execute" — skipping`);
                    continue;
                }
                // First occurrence wins (workspace overrides app-bundled)
                if (seen.has(tool.name))
                    continue;
                seen.add(tool.name);
                // Wrap execute to inject context as third argument
                const originalExecute = tool.execute.bind(tool);
                tools.push({
                    ...tool,
                    execute: (toolCallId, params) => originalExecute(toolCallId, params, context),
                });
            }
            catch (err) {
                log.warn(`Failed to load custom tool from ${toolPath}:`, err);
            }
        }
    }
    return tools;
}
//# sourceMappingURL=tool-loader.js.map