import { readdirSync } from "node:fs"; import { join } from "node:path"; import type { FastifyInstance } from "fastify"; import type { PiModel } from "../pi/list-models.js"; export type ListModelsFn = () => Promise; /** * List YAML workspace configs found in /workspaces/*.yaml. * Returns [{name, file}] — no database credentials or secrets. */ export function listWorkspaces(harnessDir: string): { name: string; file: string }[] { const dir = join(harnessDir, "workspaces"); let entries: string[]; try { entries = readdirSync(dir); } catch { return []; } return entries .filter((f) => f.endsWith(".yaml") || f.endsWith(".yml")) .map((f) => ({ name: f.replace(/\.ya?ml$/, ""), file: f })); } export function metaRoutes( app: FastifyInstance, deps: { harnessDir: string; listModels?: ListModelsFn }, ): void { app.get("/workspaces", async () => { return listWorkspaces(deps.harnessDir); }); app.get("/models", async () => { const fn = deps.listModels ?? (async () => []); try { return { models: await fn() }; } catch { // Graceful fallback: Pi may not be running; don't crash the server. return { models: [] as PiModel[] }; } }); }