mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-10 12:37:55 +01:00
test(teams): provide company lookup in catalog service fixture
Match the saved-resource link lookup already present in the candidate. Preserve the missing-company rejection before import. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
c153d14f12
commit
8b5f90326d
1 file changed
+32
-22
@@ -3,6 +3,9 @@ import { readFile } from "node:fs/promises";
|
||||
import { parseFrontmatterMarkdown } from "@paperclipai/shared/frontmatter";
|
||||
import type { CatalogTeam } from "@paperclipai/shared";
|
||||
|
||||
const companyPrefix = vi.hoisted(() => vi.fn());
|
||||
const testDb = { select: () => ({ from: () => ({ where: () => ({ limit: companyPrefix }) }) }) };
|
||||
|
||||
const mockAgentService = vi.hoisted(() => ({
|
||||
getById: vi.fn(),
|
||||
list: vi.fn(),
|
||||
@@ -64,6 +67,7 @@ function agentWithCatalogTeam(originHash: string | null, extra: Record<string, u
|
||||
describe("teamsCatalogService", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
companyPrefix.mockResolvedValue([{ issuePrefix: "ACME" }]);
|
||||
mockAgentService.getById.mockResolvedValue({
|
||||
id: "manager-1",
|
||||
companyId: "company-1",
|
||||
@@ -102,7 +106,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("builds an inline portability source with catalog skill keys and target-manager reparenting", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const prepared = await svc.prepareCatalogTeamSource("company-1", "core-exec-team", {
|
||||
targetManagerAgentId: "manager-1",
|
||||
@@ -119,7 +123,7 @@ describe("teamsCatalogService", () => {
|
||||
it.each(["core-exec-team", "product-engineering", "product-design", "content-machine"])(
|
||||
"preserves %s role files and canonical skill references through catalog import",
|
||||
async (teamRef) => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
const prepared = await svc.prepareCatalogTeamSource("company-1", teamRef);
|
||||
expect(prepared.errors).toEqual([]);
|
||||
for (const slug of prepared.team.agentSlugs) {
|
||||
@@ -153,7 +157,7 @@ describe("teamsCatalogService", () => {
|
||||
mockAgentService.list.mockResolvedValue([
|
||||
{ id: "manager-1", companyId: "company-1", name: "CEO" },
|
||||
]);
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const prepared = await svc.prepareCatalogTeamSource("company-1", "core-exec-team", {
|
||||
targetManagerSlug: "ceo",
|
||||
@@ -165,7 +169,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("preserves package-declared Paperclip sidecar permissions while adding generated catalog provenance", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const prepared = await svc.prepareCatalogTeamSource("company-1", "product-engineering");
|
||||
|
||||
@@ -176,7 +180,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("preserves package sidecar permissions when generated target-manager metadata is merged onto the same root agent", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const prepared = await svc.prepareCatalogTeamSource("company-1", "product-engineering", {
|
||||
targetManagerAgentId: "manager-1",
|
||||
@@ -191,7 +195,7 @@ describe("teamsCatalogService", () => {
|
||||
|
||||
it("rejects missing target-manager slugs instead of emitting unresolved reparent metadata", async () => {
|
||||
mockAgentService.list.mockResolvedValue([]);
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await expect(
|
||||
svc.prepareCatalogTeamSource("company-1", "core-exec-team", {
|
||||
@@ -201,7 +205,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("previews through company portability in agent-safe mode", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const preview = await svc.previewCatalogTeamImport("company-1", "content-machine");
|
||||
|
||||
@@ -223,7 +227,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("forces catalog previews to exclude company metadata even when requested", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await svc.previewCatalogTeamImport("company-1", "content-machine", {
|
||||
include: { company: true, agents: false },
|
||||
@@ -254,7 +258,7 @@ describe("teamsCatalogService", () => {
|
||||
warnings: [],
|
||||
errors: ["Safe import does not allow process adapter type."],
|
||||
});
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await expect(svc.installCatalogTeam("company-1", "core-exec-team")).rejects.toMatchObject({ status: 422 });
|
||||
|
||||
@@ -264,7 +268,7 @@ describe("teamsCatalogService", () => {
|
||||
|
||||
it("does not install catalog skills when bundle import fails", async () => {
|
||||
mockCompanyPortabilityService.importBundle.mockRejectedValueOnce(new Error("import failed"));
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await expect(svc.installCatalogTeam("company-1", "core-exec-team")).rejects.toThrow("import failed");
|
||||
|
||||
@@ -272,9 +276,15 @@ describe("teamsCatalogService", () => {
|
||||
expect(mockCompanySkillService.importFromSource).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects a missing company before importing resources", async () => {
|
||||
companyPrefix.mockResolvedValueOnce([]);
|
||||
await expect(teamsCatalogService(testDb as any).installCatalogTeam("company-1", "core-exec-team")).rejects.toMatchObject({ status: 404 });
|
||||
expect(mockCompanyPortabilityService.importBundle).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("surfaces post-import catalog skill install failures as warnings", async () => {
|
||||
mockCompanySkillService.installFromCatalog.mockRejectedValueOnce(new Error("catalog unavailable"));
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const result = await svc.installCatalogTeam("company-1", "core-exec-team");
|
||||
|
||||
@@ -287,7 +297,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("injects safe claude_local adapter defaults for every bundled agent when no overrides are supplied", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await svc.installCatalogTeam("company-1", "core-exec-team");
|
||||
|
||||
@@ -303,7 +313,7 @@ describe("teamsCatalogService", () => {
|
||||
const previousDefault = process.env.PAPERCLIP_TEAMS_CATALOG_DEFAULT_ADAPTER_TYPE;
|
||||
process.env.PAPERCLIP_TEAMS_CATALOG_DEFAULT_ADAPTER_TYPE = "opencode_local";
|
||||
try {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await svc.installCatalogTeam("company-1", "core-exec-team");
|
||||
|
||||
@@ -323,7 +333,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("supplies safe adapter defaults for product-design and product-engineering installs", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await svc.installCatalogTeam("company-1", "product-design");
|
||||
const [designInput] = mockCompanyPortabilityService.importBundle.mock.calls.at(-1)!;
|
||||
@@ -341,7 +351,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("never sends a forbidden process adapter type from the default catalog path", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await svc.installCatalogTeam("company-1", "core-exec-team");
|
||||
|
||||
@@ -353,7 +363,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("preserves an explicit caller adapter override for the affected slug", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const callerOverrides = {
|
||||
cto: { adapterType: "opencode_local", adapterConfig: { model: "anthropic/claude-opus-4" } },
|
||||
@@ -375,7 +385,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("omits the default-adapter warning when every agent has an explicit override", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const result = await svc.installCatalogTeam("company-1", "core-exec-team", {
|
||||
adapterOverrides: {
|
||||
@@ -391,7 +401,7 @@ describe("teamsCatalogService", () => {
|
||||
});
|
||||
|
||||
it("passes install secretValues through to company portability import", async () => {
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
await svc.installCatalogTeam("company-1", "core-exec-team", {
|
||||
secretValues: { "agent:ceo:OPENAI_API_KEY": "sk-imported" },
|
||||
@@ -430,7 +440,7 @@ describe("teamsCatalogService", () => {
|
||||
agentWithCatalogTeam("sha256:stale-hash"),
|
||||
{ id: "no-provenance", companyId: "company-1", metadata: null },
|
||||
]);
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const installed = await svc.listInstalledCatalogTeams("company-1");
|
||||
|
||||
@@ -449,7 +459,7 @@ describe("teamsCatalogService", () => {
|
||||
|
||||
it("marks a team up to date when the installed originHash matches the catalog hash", async () => {
|
||||
mockAgentService.list.mockResolvedValue([agentWithCatalogTeam(CORE_EXEC_TEAM_HASH)]);
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const installed = await svc.listInstalledCatalogTeams("company-1");
|
||||
|
||||
@@ -465,7 +475,7 @@ describe("teamsCatalogService", () => {
|
||||
metadata: { paperclip: { catalogTeam: { catalogId: "paperclipai:bundled:gone:removed", originHash: "sha256:x" } } },
|
||||
},
|
||||
]);
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
const installed = await svc.listInstalledCatalogTeams("company-1");
|
||||
|
||||
@@ -476,7 +486,7 @@ describe("teamsCatalogService", () => {
|
||||
|
||||
it("returns an empty list when no agents carry catalog-team provenance", async () => {
|
||||
mockAgentService.list.mockResolvedValue([{ id: "a", companyId: "company-1", metadata: {} }]);
|
||||
const svc = teamsCatalogService({} as any);
|
||||
const svc = teamsCatalogService(testDb as any);
|
||||
|
||||
expect(await svc.listInstalledCatalogTeams("company-1")).toEqual([]);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user