diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 38fa619499f..b42f0bdd588 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -847,11 +847,6 @@ export { } from "./document-anchors.js"; export { - buildExternalObjectScopedIdentityKey, - buildExternalObjectMentionSourceKey, - canonicalizeExternalObjectUrl, - extractExternalObjectCanonicalUrls, - findExternalObjectUrlMatches, formatExternalObjectMentionSourceLabel, type ExternalObjectCanonicalIdentity, type ExternalObjectCanonicalUrl, diff --git a/server/src/__tests__/external-object-routes.test.ts b/server/src/__tests__/external-object-routes.test.ts index eabefa6d95e..24e80643365 100644 --- a/server/src/__tests__/external-object-routes.test.ts +++ b/server/src/__tests__/external-object-routes.test.ts @@ -14,6 +14,7 @@ const mockIssueService = vi.hoisted(() => ({ })); const mockAccessService = vi.hoisted(() => ({ + decide: vi.fn(), hasPermission: vi.fn(), })); @@ -40,9 +41,20 @@ function registerRouteMocks() { instanceSettingsService: () => mockInstanceSettingsService, })); + vi.doMock("../services/task-watchdog-scope.js", () => ({ + TASK_WATCHDOG_ORIGIN_KIND: "task_watchdog", + resolveTaskWatchdogMutationScope: vi.fn(async () => ({ kind: "none" })), + taskWatchdogScopeAllowsIssueMutation: vi.fn(async () => ({ kind: "none" })), + })); + vi.doMock("../services/index.js", () => ({ accessService: () => mockAccessService, agentService: () => mockAgentService, + companyService: () => ({ + getById: vi.fn(async () => null), + }), + companySearchService: () => ({}), + documentAnnotationService: () => ({}), documentService: () => ({}), executionWorkspaceService: () => ({}), feedbackService: () => ({}), @@ -55,6 +67,7 @@ function registerRouteMocks() { cancelRun: vi.fn(async () => null), }), issueApprovalService: () => ({}), + issueRecoveryActionService: () => ({}), issueReferenceService: () => ({ listIssueReferenceSummary: async () => ({ outbound: [], inbound: [] }), }), @@ -147,6 +160,10 @@ describe("external object routes", () => { mockIssueService.getById.mockResolvedValue(makeIssue()); mockIssueService.assertCheckoutOwner.mockResolvedValue({ adoptedFromRunId: null }); mockAccessService.hasPermission.mockResolvedValue(false); + mockAccessService.decide.mockImplementation(async ({ action }: { action: string }) => ({ + allowed: action === "issue:mutate", + explanation: "Denied by test mock", + })); mockAgentService.list.mockResolvedValue([ { id: ownerAgentId, companyId, reportsTo: null, permissions: { canCreateAgents: false } }, { id: peerAgentId, companyId, reportsTo: null, permissions: { canCreateAgents: false } }, diff --git a/ui/src/components/CommentThread.external-references.test.tsx b/ui/src/components/CommentThread.external-references.test.tsx index 2458bdb7543..3f65b6e658b 100644 --- a/ui/src/components/CommentThread.external-references.test.tsx +++ b/ui/src/components/CommentThread.external-references.test.tsx @@ -63,6 +63,9 @@ describe("CommentThread external object decoration (integration)", () => { issueId: "issue-1", authorAgentId: null, authorUserId: "user-1", + authorType: "user", + presentation: null, + metadata: null, body: [ "Tracked: https://github.com/example/repo/pull/77", "Untracked: https://elsewhere.example.com/page", diff --git a/ui/src/components/CommentThread.test.tsx b/ui/src/components/CommentThread.test.tsx index f42a4112763..427d5f62ea6 100644 --- a/ui/src/components/CommentThread.test.tsx +++ b/ui/src/components/CommentThread.test.tsx @@ -423,6 +423,9 @@ describe("CommentThread", () => { issueId: "issue-1", authorAgentId: null, authorUserId: "user-1", + authorType: "user", + presentation: null, + metadata: null, body: "See https://github.com/example/repo/pull/42 for context.", createdAt: new Date("2026-03-11T11:00:00.000Z"), updatedAt: new Date("2026-03-11T11:00:00.000Z"), diff --git a/ui/src/components/IssueDocumentsSection.tsx b/ui/src/components/IssueDocumentsSection.tsx index 2e7e858e356..ffa59eb3fc8 100644 --- a/ui/src/components/IssueDocumentsSection.tsx +++ b/ui/src/components/IssueDocumentsSection.tsx @@ -763,6 +763,7 @@ export function IssueDocumentsSection({ }, [autosaveState, commitDraft, documentConflict, draft, markDocumentDirty, resetAutosaveState, sortedDocuments]); const documentBodyShellClassName = "mt-3"; + const documentBodyPaddingClassName = ""; const documentBodyContentClassName = "paperclip-edit-in-place-content min-h-[220px] text-[15px] leading-7"; const toggleFoldedDocument = (key: string) => { setFoldedDocumentKeys((current) => diff --git a/ui/src/components/IssueThreadInteractionCard.tsx b/ui/src/components/IssueThreadInteractionCard.tsx index 3ccaa9f0a3d..508caf133dc 100644 --- a/ui/src/components/IssueThreadInteractionCard.tsx +++ b/ui/src/components/IssueThreadInteractionCard.tsx @@ -1997,7 +1997,6 @@ export function IssueThreadInteractionCard({ onAcceptInteraction={onAcceptInteraction} onRejectInteraction={onRejectInteraction} onUploadImage={onUploadImage} - onUploadImage={onUploadImage} externalReferences={externalReferences} /> )} diff --git a/ui/src/components/SidebarProjects.tsx b/ui/src/components/SidebarProjects.tsx index 43244dc2ba4..8351a13d231 100644 --- a/ui/src/components/SidebarProjects.tsx +++ b/ui/src/components/SidebarProjects.tsx @@ -234,7 +234,6 @@ function SortableProjectItem(props: ProjectItemProps) { transition, isDragging, } = useSortable({ id: props.project.id }); - } = useSortable({ id: props.project.id }); return (