Files
paperclip/packages/shared/src/validators/issue.ts
Dotta 8cf85a5a50 Merge remote-tracking branch 'public-gh/master' into paperclip-subissues
* public-gh/master: (55 commits)
  fix(issue-documents): address greptile review
  Update packages/shared/src/validators/issue.ts
  feat(ui): add issue document copy and download actions
  fix(ui): unify new issue upload action
  feat(ui): stage issue files before create
  feat(ui): handle issue document edit conflicts
  fix(ui): refresh issue documents from live events
  feat(ui): deep link issue documents
  fix(ui): streamline issue document chrome
  fix(ui): collapse empty document and attachment states
  fix(ui): simplify document card body layout
  fix(issues): address document review comments
  feat(issues): add issue documents and inline editing
  docs: add agent evals framework plan
  fix(cli): quote env values with special characters
  Fix worktree seed source selection
  fix: address greptile follow-up
  docs: add paperclip skill tightening plan
  fix: isolate codex home in worktrees
  Add worktree UI branding
  ...

# Conflicts:
#	packages/db/src/migrations/meta/0028_snapshot.json
#	packages/db/src/migrations/meta/_journal.json
#	packages/shared/src/index.ts
#	server/src/routes/issues.ts
#	ui/src/api/issues.ts
#	ui/src/components/NewIssueDialog.tsx
#	ui/src/pages/IssueDetail.tsx
2026-03-14 12:24:40 -05:00

122 lines
4.4 KiB
TypeScript

import { z } from "zod";
import { ISSUE_PRIORITIES, ISSUE_STATUSES } from "../constants.js";
const executionWorkspaceStrategySchema = z
.object({
type: z.enum(["project_primary", "git_worktree", "adapter_managed", "cloud_sandbox"]).optional(),
baseRef: z.string().optional().nullable(),
branchTemplate: z.string().optional().nullable(),
worktreeParentDir: z.string().optional().nullable(),
provisionCommand: z.string().optional().nullable(),
teardownCommand: z.string().optional().nullable(),
})
.strict();
export const issueExecutionWorkspaceSettingsSchema = z
.object({
mode: z.enum(["inherit", "shared_workspace", "isolated_workspace", "operator_branch", "reuse_existing", "agent_default"]).optional(),
workspaceStrategy: executionWorkspaceStrategySchema.optional().nullable(),
workspaceRuntime: z.record(z.unknown()).optional().nullable(),
})
.strict();
export const issueAssigneeAdapterOverridesSchema = z
.object({
adapterConfig: z.record(z.unknown()).optional(),
useProjectWorkspace: z.boolean().optional(),
})
.strict();
export const createIssueSchema = z.object({
projectId: z.string().uuid().optional().nullable(),
projectWorkspaceId: z.string().uuid().optional().nullable(),
goalId: z.string().uuid().optional().nullable(),
parentId: z.string().uuid().optional().nullable(),
title: z.string().min(1),
description: z.string().optional().nullable(),
status: z.enum(ISSUE_STATUSES).optional().default("backlog"),
priority: z.enum(ISSUE_PRIORITIES).optional().default("medium"),
assigneeAgentId: z.string().uuid().optional().nullable(),
assigneeUserId: z.string().optional().nullable(),
requestDepth: z.number().int().nonnegative().optional().default(0),
billingCode: z.string().optional().nullable(),
assigneeAdapterOverrides: issueAssigneeAdapterOverridesSchema.optional().nullable(),
executionWorkspaceId: z.string().uuid().optional().nullable(),
executionWorkspacePreference: z.enum([
"inherit",
"shared_workspace",
"isolated_workspace",
"operator_branch",
"reuse_existing",
"agent_default",
]).optional().nullable(),
executionWorkspaceSettings: issueExecutionWorkspaceSettingsSchema.optional().nullable(),
labelIds: z.array(z.string().uuid()).optional(),
});
export type CreateIssue = z.infer<typeof createIssueSchema>;
export const createIssueLabelSchema = z.object({
name: z.string().trim().min(1).max(48),
color: z.string().regex(/^#(?:[0-9a-fA-F]{6})$/, "Color must be a 6-digit hex value"),
});
export type CreateIssueLabel = z.infer<typeof createIssueLabelSchema>;
export const updateIssueSchema = createIssueSchema.partial().extend({
comment: z.string().min(1).optional(),
hiddenAt: z.string().datetime().nullable().optional(),
});
export type UpdateIssue = z.infer<typeof updateIssueSchema>;
export type IssueExecutionWorkspaceSettings = z.infer<typeof issueExecutionWorkspaceSettingsSchema>;
export const checkoutIssueSchema = z.object({
agentId: z.string().uuid(),
expectedStatuses: z.array(z.enum(ISSUE_STATUSES)).nonempty(),
});
export type CheckoutIssue = z.infer<typeof checkoutIssueSchema>;
export const addIssueCommentSchema = z.object({
body: z.string().min(1),
reopen: z.boolean().optional(),
interrupt: z.boolean().optional(),
});
export type AddIssueComment = z.infer<typeof addIssueCommentSchema>;
export const linkIssueApprovalSchema = z.object({
approvalId: z.string().uuid(),
});
export type LinkIssueApproval = z.infer<typeof linkIssueApprovalSchema>;
export const createIssueAttachmentMetadataSchema = z.object({
issueCommentId: z.string().uuid().optional().nullable(),
});
export type CreateIssueAttachmentMetadata = z.infer<typeof createIssueAttachmentMetadataSchema>;
export const ISSUE_DOCUMENT_FORMATS = ["markdown"] as const;
export const issueDocumentFormatSchema = z.enum(ISSUE_DOCUMENT_FORMATS);
export const issueDocumentKeySchema = z
.string()
.trim()
.min(1)
.max(64)
.regex(/^[a-z0-9][a-z0-9_-]*$/, "Document key must be lowercase letters, numbers, _ or -");
export const upsertIssueDocumentSchema = z.object({
title: z.string().trim().max(200).nullable().optional(),
format: issueDocumentFormatSchema,
body: z.string().max(524288),
changeSummary: z.string().trim().max(500).nullable().optional(),
baseRevisionId: z.string().uuid().nullable().optional(),
});
export type IssueDocumentFormat = z.infer<typeof issueDocumentFormatSchema>;
export type UpsertIssueDocument = z.infer<typeof upsertIssueDocumentSchema>;