feat: redesign Feishu project console

This commit is contained in:
2026-07-13 16:52:45 +08:00
parent 82f57317df
commit 69837bd50c
34 changed files with 1738 additions and 978 deletions
@@ -60,7 +60,10 @@ describe("Organization Agent configuration management", () => {
expect(role.tools).toEqual(["read_file", "write_file", "cph_build"]);
expect(role.skillBindings.map((binding) => binding.skill.name)).toEqual(["outline", "typst"]);
await expect(prisma.agentSession.findUniqueOrThrow({ where: { id: "session-old-role-config" } }))
.resolves.toMatchObject({ archivedAt: expect.any(Date) });
.resolves.toMatchObject({
archivedAt: expect.any(Date),
metadata: expect.objectContaining({ userResumable: false }),
});
});
it("rejects unknown, disabled and cross-Organization skills", async () => {
@@ -81,6 +84,40 @@ describe("Organization Agent configuration management", () => {
})).rejects.toThrow("active skills not found in organization");
});
it("switches the Organization default role atomically", async () => {
await configuration.upsertRole({
organizationId: DEFAULT_ORG_ID,
roleId: "review",
label: "审校",
tools: ["read_file"],
isDefault: true,
});
await expect(prisma.organizationAgentRole.findMany({
where: { organizationId: DEFAULT_ORG_ID, isDefault: true, disabledAt: null },
select: { roleId: true },
})).resolves.toEqual([{ roleId: "review" }]);
await expect(configuration.upsertRole({
organizationId: DEFAULT_ORG_ID,
roleId: "review",
label: "审校",
isDefault: false,
})).rejects.toThrow("cannot unset the active default role without selecting a replacement");
});
it("rejects a zero-default committed state at the database boundary", async () => {
await expect(prisma.organizationAgentRole.updateMany({
where: { organizationId: DEFAULT_ORG_ID, isDefault: true, disabledAt: null },
data: { isDefault: false },
})).rejects.toThrow("must have exactly one active default Agent role");
});
it("rejects creating an Organization without its default role in the same transaction", async () => {
await expect(prisma.organization.create({
data: { id: "org_without_role", slug: "without-role", name: "Without Role" },
})).rejects.toThrow("must have exactly one active default Agent role");
});
async function makeSkill(parent: string, name: string): Promise<string> {
const source = join(parent, "sources", name);
await mkdir(source, { recursive: true });