diff --git a/src/server/config-schema.test.ts b/src/server/config-schema.test.ts new file mode 100644 index 0000000..3f62027 --- /dev/null +++ b/src/server/config-schema.test.ts @@ -0,0 +1,56 @@ +import { describe, it, expect } from "vitest"; +import { getConfigSchema } from "./config-schema.js"; + +interface ConfigFieldSchema { + key: string; + label: string; + type: string; + default?: unknown; + options?: { label: string; value: string }[]; +} + +describe("getConfigSchema", () => { + it("returns a non-empty schema", () => { + const schema = getConfigSchema(); + expect(schema.fields.length).toBeGreaterThan(0); + }); + + it("does not include platform-provided fields", () => { + const schema = getConfigSchema(); + const keys = schema.fields.map((f: ConfigFieldSchema) => f.key); + // These fields are provided by the platform and should not be duplicated + expect(keys).not.toContain("model"); + expect(keys).not.toContain("effort"); + expect(keys).not.toContain("instructionsFilePath"); + expect(keys).not.toContain("timeoutSec"); + expect(keys).not.toContain("graceSec"); + }); + + it("maxTurnsPerRun defaults to 1000", () => { + const schema = getConfigSchema(); + const field = schema.fields.find((f: ConfigFieldSchema) => f.key === "maxTurnsPerRun"); + expect(field).toBeDefined(); + expect(field!.type).toBe("number"); + expect(field!.default).toBe(1000); + }); + + it("dangerouslySkipPermissions defaults to true", () => { + const schema = getConfigSchema(); + const field = schema.fields.find((f: ConfigFieldSchema) => f.key === "dangerouslySkipPermissions"); + expect(field).toBeDefined(); + expect(field!.type).toBe("toggle"); + expect(field!.default).toBe(true); + }); + + it("has imagePullPolicy as select with correct options", () => { + const schema = getConfigSchema(); + const field = schema.fields.find((f: ConfigFieldSchema) => f.key === "imagePullPolicy"); + expect(field).toBeDefined(); + expect(field!.type).toBe("select"); + expect(field!.options).toEqual([ + { label: "IfNotPresent", value: "IfNotPresent" }, + { label: "Always", value: "Always" }, + { label: "Never", value: "Never" }, + ]); + }); +}); diff --git a/src/server/config-schema.ts b/src/server/config-schema.ts index 0c151d3..98265bf 100644 --- a/src/server/config-schema.ts +++ b/src/server/config-schema.ts @@ -23,8 +23,17 @@ interface AdapterConfigSchema { } export function getConfigSchema(): AdapterConfigSchema { + // model, effort, instructionsFilePath, timeoutSec, graceSec are provided + // by the platform UI and must not be duplicated here. const fields: ConfigFieldSchema[] = [ // Core Claude fields + { + type: "number", + key: "maxTurnsPerRun", + label: "Max Turns Per Run", + hint: "Maximum number of agentic turns (tool calls) per heartbeat run. 0 means unlimited.", + default: 1000, + }, { type: "toggle", key: "dangerouslySkipPermissions",