fix(server): preserve issue labels and wake resumed assignees

This commit is contained in:
Dotta committed 2026-04-14 11:54:44 -05:00
1 parent 0c3120d372
commit d0af94b4d6
3 files changed
+72 -2

No files matched your search

@@ -2283,6 +2283,72 @@ describe("company portability", () => {
expect(materializedFiles["AGENTS.md"]).not.toContain('name: "ClaudeCoder"');
});
it("preserves issue labelIds through export and import round-trip", async () => {
const portability = companyPortabilityService({} as any);
projectSvc.list.mockResolvedValue([
{
id: "project-1",
name: "Launch",
urlKey: "launch",
description: null,
status: "active",
leadAgentId: null,
metadata: null,
defaultProjectWorkspaceId: null,
},
]);
projectSvc.listWorkspaces.mockResolvedValue([]);
issueSvc.list.mockResolvedValue([
{
id: "issue-1",
identifier: "PAP-1",
title: "Labelled task",
description: "Has labels",
projectId: "project-1",
projectWorkspaceId: null,
assigneeAgentId: null,
status: "todo",
priority: "high",
labelIds: ["label-a", "label-b"],
billingCode: null,
executionWorkspaceSettings: null,
assigneeAdapterOverrides: null,
},
]);
const exported = await portability.exportBundle("company-1", {
include: { company: true, agents: false, projects: true, issues: true },
});
const extension = asTextFile(exported.files[".paperclip.yaml"]);
expect(extension).toContain("labelIds:");
expect(extension).toContain("label-a");
expect(extension).toContain("label-b");
companySvc.create.mockResolvedValue({ id: "company-imported", name: "Imported" });
accessSvc.ensureMembership.mockResolvedValue(undefined);
agentSvc.list.mockResolvedValue([]);
projectSvc.list.mockResolvedValue([]);
projectSvc.create.mockResolvedValue({ id: "project-imported", name: "Launch", urlKey: "launch" });
issueSvc.create.mockResolvedValue({ id: "issue-imported", title: "Labelled task" });
await portability.importBundle({
source: { type: "inline", rootPath: exported.rootPath, files: exported.files },
include: { company: true, agents: false, projects: true, issues: true },
target: { mode: "new_company", newCompanyName: "Imported" },
agents: "all",
collisionStrategy: "rename",
}, "user-1");
expect(issueSvc.create).toHaveBeenCalledWith(
"company-imported",
expect.objectContaining({
labelIds: ["label-a", "label-b"],
}),
);
});
it("strips root AGENTS frontmatter when importing a nested agent entry path", async () => {
const portability = companyPortabilityService({} as any);
+5 -1
View File
@@ -1739,6 +1739,10 @@ export function issueRoutes(
existing.status === "backlog" &&
issue.status !== "backlog" &&
req.body.status !== undefined;
const statusChangedFromBlockedToTodo =
existing.status === "blocked" &&
issue.status === "todo" &&
req.body.status !== undefined;
const previousExecutionState = parseIssueExecutionState(existing.executionState);
const nextExecutionState = parseIssueExecutionState(issue.executionState);
const executionStageWakeup = buildExecutionStageWakeup({
@@ -1792,7 +1796,7 @@ export function issueRoutes(
});
}
if (!assigneeChanged && statusChangedFromBacklog && issue.assigneeAgentId) {
if (!assigneeChanged && (statusChangedFromBacklog || statusChangedFromBlockedToTodo) && issue.assigneeAgentId) {
addWakeup(issue.assigneeAgentId, {
source: "automation",
triggerDetail: "system",
+1 -1
View File
@@ -4388,7 +4388,7 @@ export function companyPortabilityService(db: Db, storage?: StorageService) {
billingCode: manifestIssue.billingCode,
assigneeAdapterOverrides: manifestIssue.assigneeAdapterOverrides,
executionWorkspaceSettings: manifestIssue.executionWorkspaceSettings,
labelIds: [],
labelIds: manifestIssue.labelIds ?? [],
});
}
}