import { type Router as ExpressRouter } from "express"; import type { AgentScaffoldResponse } from "../shared/types.js"; export interface AgentScaffoldDeps { /** * Every directory an agent may be created IN: the project roots the studio * knows about, plus the branching directories the Project axis renders * between a root and an agent. Same list `agent-move.ts` moves into * (`moveTargetDirs`), and for the same reason — "a directory the rail can * show" and "a directory this route will write into" must be one list, or * creation and drag disagree about what a project is. */ listProjectDirs: () => string[] | Promise; /** * The registered agent at this absolute path, or null. Consulted before the * `lstat` purely so the refusal can NAME what is in the way ("an agent * called x") instead of describing a directory. */ resolveAgent: (agentPath: string) => { name: string; path: string; } | null; /** * Creates the project. Injected so the co-located test can exercise every * guard without npm, git, or the registry on the far side of them — and so * the route stays the thing under test rather than `@sapiom/agent-core`. */ scaffoldAgent: (opts: { targetDir: string; template: string; }) => Promise<{ dependenciesInstalled: boolean; }>; /** * Applied AFTER the project is on disk, BEFORE the response. The * integrator's job: rescan the project root so the registry holds the new * agent and `workflows.changed` is broadcast. It runs before the response * because that ordering IS the criterion — the agent is in the rail before * the caller can open a session on it, so "did it work?" is never a question * the user answers by reading a terminal. */ onScaffolded: (agentDir: string) => Promise; } /** * The route's OWN refusal, from the filesystem rather than from the registry — * a message when the directory must not be created, null when it may. * * `lstat`, not `stat`: a dangling symlink sitting at the destination is still * something the user put there, and `scaffold` would happily create through it. */ export declare function refuseScaffoldOnDisk(target: string, projectLabel: string): Promise; /** * POST /api/agents/scaffold { root, name, template? } -> AgentScaffoldResponse * * 400 — a malformed body, a name that is not one folder segment, a template * that is not a plain segment, a root that is not an absolute path. * 409 — a refusal, with the reason in `error` so the dialog shows it verbatim: * a root the studio doesn't show as a project, or a name already taken there. * 500 — the scaffold itself failed; the directory it may have created is * removed first, so the retry meets the same clean state the first attempt did. */ export declare class ScaffoldError extends Error { readonly status: number; constructor(status: number, message: string); } /** One guarded implementation for the agent dialog and first-run launch. */ export declare function scaffoldAgentProject(deps: AgentScaffoldDeps, input: { root?: unknown; name?: unknown; template?: unknown; }): Promise; export declare function createAgentScaffoldRouter(deps: AgentScaffoldDeps): ExpressRouter; //# sourceMappingURL=scaffold.d.ts.map