feat: expose workspace registry API

This commit is contained in:
2026-08-04 01:01:57 +02:00
parent 49fa7030a5
commit f95a18ab0d
9 changed files with 829 additions and 50 deletions
+2 -34
View File
@@ -85,40 +85,8 @@ test("POST /sessions/:id/sql/preview returns 500 when thtRunner throws", async (
expect(res.json()).toMatchObject({ error: /boom/ });
});
// ---------------------------------------------------------------------------
// Meta routes
// ---------------------------------------------------------------------------
test("GET /workspaces lists yaml files from ../harness/workspaces", async () => {
// The real ../harness/workspaces directory contains *.yaml files.
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {
thtRunner: {} as any,
});
const res = await app.inject({ method: "GET", url: "/workspaces" });
expect(res.statusCode).toBe(200);
const body = res.json() as { name: string; file: string }[];
expect(Array.isArray(body)).toBe(true);
// ../harness/workspaces has at least one yaml (tht-test.yaml / tht.example.yaml)
expect(body.length).toBeGreaterThan(0);
for (const w of body) {
expect(typeof w.name).toBe("string");
expect(w.name).not.toContain(".yaml"); // name strips extension
expect(w.file).toMatch(/\.ya?ml$/);
}
});
test("GET /workspaces returns [] when harnessDir has no workspaces subdir", async () => {
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "/nonexistent-harness-dir" }), {
thtRunner: {} as any,
});
const res = await app.inject({ method: "GET", url: "/workspaces" });
expect(res.statusCode).toBe(200);
expect(res.json()).toEqual([]);
});
// Workspace registry route coverage lives in routes-workspaces.test.ts. `/workspaces` no longer
// reads legacy harness files: the Git registry is the single shared source of truth.
test("GET /models returns {models:[...]} from injected listModels stub", async () => {
const app = buildApp(loadConfig({ THT_HARNESS_DIR: "../harness" }), {