Files
paperclip/server/src/__tests__/adapter-registry.test.ts
T
Pawla Abdul 0dfb93e898 test+docs: add capability flag tests and documentation
Tests:
- adapter-registry: verify capability flags are exposed, undefined when
  unset, and correctly declared on built-in claude_local adapter
- adapter-routes: verify GET /api/adapters includes capabilities object,
  correct flags for codex_local/process/cursor, and derived supportsSkills

Documentation:
- docs/adapters/creating-an-adapter.md: new "Capability Flags" section
  documenting all flags, their defaults, and usage example for external
  adapter plugins

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-13 01:26:42 +00:00

189 lines
6.1 KiB
TypeScript

import { describe, expect, it, beforeEach, afterEach, vi } from "vitest";
import type { ServerAdapterModule } from "../adapters/index.js";
import {
detectAdapterModel,
findActiveServerAdapter,
findServerAdapter,
listAdapterModels,
registerServerAdapter,
requireServerAdapter,
unregisterServerAdapter,
} from "../adapters/index.js";
import { setOverridePaused } from "../adapters/registry.js";
const externalAdapter: ServerAdapterModule = {
type: "external_test",
execute: async () => ({
exitCode: 0,
signal: null,
timedOut: false,
}),
testEnvironment: async () => ({
adapterType: "external_test",
status: "pass",
checks: [],
testedAt: new Date(0).toISOString(),
}),
models: [{ id: "external-model", label: "External Model" }],
supportsLocalAgentJwt: false,
};
describe("server adapter registry", () => {
beforeEach(() => {
unregisterServerAdapter("external_test");
unregisterServerAdapter("claude_local");
setOverridePaused("claude_local", false);
});
afterEach(() => {
unregisterServerAdapter("external_test");
unregisterServerAdapter("claude_local");
setOverridePaused("claude_local", false);
});
it("registers external adapters and exposes them through lookup helpers", async () => {
expect(findServerAdapter("external_test")).toBeNull();
registerServerAdapter(externalAdapter);
expect(requireServerAdapter("external_test")).toBe(externalAdapter);
expect(await listAdapterModels("external_test")).toEqual([
{ id: "external-model", label: "External Model" },
]);
});
it("removes external adapters when unregistered", () => {
registerServerAdapter(externalAdapter);
unregisterServerAdapter("external_test");
expect(findServerAdapter("external_test")).toBeNull();
expect(() => requireServerAdapter("external_test")).toThrow(
"Unknown adapter type: external_test",
);
});
it("allows external plugin to override a built-in adapter type", () => {
// claude_local is always built-in
const builtIn = findServerAdapter("claude_local");
expect(builtIn).not.toBeNull();
const plugin: ServerAdapterModule = {
type: "claude_local",
execute: async () => ({
exitCode: 0,
signal: null,
timedOut: false,
}),
testEnvironment: async () => ({
adapterType: "claude_local",
status: "pass",
checks: [],
testedAt: new Date(0).toISOString(),
}),
models: [{ id: "plugin-model", label: "Plugin Override" }],
supportsLocalAgentJwt: false,
};
registerServerAdapter(plugin);
// Plugin wins
const resolved = requireServerAdapter("claude_local");
expect(resolved).toBe(plugin);
expect(resolved.models).toEqual([
{ id: "plugin-model", label: "Plugin Override" },
]);
});
it("exposes capability flags from registered adapters", () => {
const adapterWithCaps: ServerAdapterModule = {
type: "external_test",
execute: async () => ({ exitCode: 0, signal: null, timedOut: false }),
testEnvironment: async () => ({
adapterType: "external_test",
status: "pass" as const,
checks: [],
testedAt: new Date(0).toISOString(),
}),
supportsLocalAgentJwt: true,
supportsInstructionsBundle: true,
instructionsPathKey: "customPathKey",
requiresMaterializedRuntimeSkills: true,
};
registerServerAdapter(adapterWithCaps);
const resolved = findActiveServerAdapter("external_test");
expect(resolved).not.toBeNull();
expect(resolved!.supportsInstructionsBundle).toBe(true);
expect(resolved!.instructionsPathKey).toBe("customPathKey");
expect(resolved!.requiresMaterializedRuntimeSkills).toBe(true);
expect(resolved!.supportsLocalAgentJwt).toBe(true);
});
it("returns undefined for capability flags on adapters that do not set them", () => {
registerServerAdapter(externalAdapter);
const resolved = findActiveServerAdapter("external_test");
expect(resolved).not.toBeNull();
expect(resolved!.supportsInstructionsBundle).toBeUndefined();
expect(resolved!.instructionsPathKey).toBeUndefined();
expect(resolved!.requiresMaterializedRuntimeSkills).toBeUndefined();
});
it("built-in claude_local adapter declares capability flags", () => {
const adapter = findActiveServerAdapter("claude_local");
expect(adapter).not.toBeNull();
expect(adapter!.supportsInstructionsBundle).toBe(true);
expect(adapter!.instructionsPathKey).toBe("instructionsFilePath");
expect(adapter!.requiresMaterializedRuntimeSkills).toBe(false);
expect(adapter!.supportsLocalAgentJwt).toBe(true);
});
it("switches active adapter behavior back to the builtin when an override is paused", async () => {
const builtIn = findServerAdapter("claude_local");
expect(builtIn).not.toBeNull();
const detectModel = vi.fn(async () => ({
model: "plugin-model",
provider: "plugin-provider",
source: "plugin-source",
}));
const plugin: ServerAdapterModule = {
type: "claude_local",
execute: async () => ({
exitCode: 0,
signal: null,
timedOut: false,
}),
testEnvironment: async () => ({
adapterType: "claude_local",
status: "pass",
checks: [],
testedAt: new Date(0).toISOString(),
}),
models: [{ id: "plugin-model", label: "Plugin Override" }],
detectModel,
supportsLocalAgentJwt: false,
};
registerServerAdapter(plugin);
expect(findActiveServerAdapter("claude_local")).toBe(plugin);
expect(await listAdapterModels("claude_local")).toEqual([
{ id: "plugin-model", label: "Plugin Override" },
]);
expect(await detectAdapterModel("claude_local")).toMatchObject({
model: "plugin-model",
provider: "plugin-provider",
});
expect(setOverridePaused("claude_local", true)).toBe(true);
expect(findActiveServerAdapter("claude_local")).not.toBe(plugin);
expect(await listAdapterModels("claude_local")).toEqual(builtIn?.models ?? []);
expect(await detectAdapterModel("claude_local")).toBeNull();
expect(detectModel).toHaveBeenCalledTimes(1);
});
});