2026-02-16 13:31:47 -06:00
|
|
|
import { z } from "zod";
|
2026-04-06 08:40:38 -05:00
|
|
|
import {
|
|
|
|
|
ISSUE_EXECUTION_DECISION_OUTCOMES,
|
|
|
|
|
ISSUE_EXECUTION_POLICY_MODES,
|
|
|
|
|
ISSUE_EXECUTION_STAGE_TYPES,
|
|
|
|
|
ISSUE_EXECUTION_STATE_STATUSES,
|
|
|
|
|
ISSUE_PRIORITIES,
|
|
|
|
|
ISSUE_STATUSES,
|
|
|
|
|
} from "../constants.js";
|
2026-02-16 13:31:47 -06:00
|
|
|
|
2026-04-02 12:09:02 -05:00
|
|
|
export const ISSUE_EXECUTION_WORKSPACE_PREFERENCES = [
|
|
|
|
|
"inherit",
|
|
|
|
|
"shared_workspace",
|
|
|
|
|
"isolated_workspace",
|
|
|
|
|
"operator_branch",
|
|
|
|
|
"reuse_existing",
|
|
|
|
|
"agent_default",
|
|
|
|
|
] as const;
|
|
|
|
|
|
2026-03-10 09:03:31 -05:00
|
|
|
const executionWorkspaceStrategySchema = z
|
|
|
|
|
.object({
|
2026-03-13 17:12:25 -05:00
|
|
|
type: z.enum(["project_primary", "git_worktree", "adapter_managed", "cloud_sandbox"]).optional(),
|
2026-03-10 09:03:31 -05:00
|
|
|
baseRef: z.string().optional().nullable(),
|
|
|
|
|
branchTemplate: z.string().optional().nullable(),
|
|
|
|
|
worktreeParentDir: z.string().optional().nullable(),
|
2026-03-10 12:42:36 -05:00
|
|
|
provisionCommand: z.string().optional().nullable(),
|
|
|
|
|
teardownCommand: z.string().optional().nullable(),
|
2026-03-10 09:03:31 -05:00
|
|
|
})
|
|
|
|
|
.strict();
|
|
|
|
|
|
|
|
|
|
export const issueExecutionWorkspaceSettingsSchema = z
|
|
|
|
|
.object({
|
2026-04-02 12:09:02 -05:00
|
|
|
mode: z.enum(ISSUE_EXECUTION_WORKSPACE_PREFERENCES).optional(),
|
2026-03-10 09:03:31 -05:00
|
|
|
workspaceStrategy: executionWorkspaceStrategySchema.optional().nullable(),
|
|
|
|
|
workspaceRuntime: z.record(z.unknown()).optional().nullable(),
|
|
|
|
|
})
|
|
|
|
|
.strict();
|
|
|
|
|
|
2026-02-26 10:32:44 -06:00
|
|
|
export const issueAssigneeAdapterOverridesSchema = z
|
|
|
|
|
.object({
|
|
|
|
|
adapterConfig: z.record(z.unknown()).optional(),
|
|
|
|
|
useProjectWorkspace: z.boolean().optional(),
|
|
|
|
|
})
|
|
|
|
|
.strict();
|
|
|
|
|
|
2026-04-06 08:40:38 -05:00
|
|
|
const issueExecutionStagePrincipalBaseSchema = z.object({
|
|
|
|
|
type: z.enum(["agent", "user"]),
|
|
|
|
|
agentId: z.string().uuid().optional().nullable(),
|
|
|
|
|
userId: z.string().optional().nullable(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const issueExecutionStagePrincipalSchema = issueExecutionStagePrincipalBaseSchema
|
|
|
|
|
.superRefine((value, ctx) => {
|
|
|
|
|
if (value.type === "agent") {
|
|
|
|
|
if (!value.agentId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Agent participants require agentId", path: ["agentId"] });
|
|
|
|
|
}
|
|
|
|
|
if (value.userId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Agent participants cannot set userId", path: ["userId"] });
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!value.userId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "User participants require userId", path: ["userId"] });
|
|
|
|
|
}
|
|
|
|
|
if (value.agentId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "User participants cannot set agentId", path: ["agentId"] });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const issueExecutionStageParticipantSchema = issueExecutionStagePrincipalBaseSchema.extend({
|
|
|
|
|
id: z.string().uuid().optional(),
|
|
|
|
|
}).superRefine((value, ctx) => {
|
|
|
|
|
if (value.type === "agent") {
|
|
|
|
|
if (!value.agentId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Agent participants require agentId", path: ["agentId"] });
|
|
|
|
|
}
|
|
|
|
|
if (value.userId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Agent participants cannot set userId", path: ["userId"] });
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!value.userId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "User participants require userId", path: ["userId"] });
|
|
|
|
|
}
|
|
|
|
|
if (value.agentId) {
|
|
|
|
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "User participants cannot set agentId", path: ["agentId"] });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const issueExecutionStageSchema = z.object({
|
|
|
|
|
id: z.string().uuid().optional(),
|
|
|
|
|
type: z.enum(ISSUE_EXECUTION_STAGE_TYPES),
|
|
|
|
|
approvalsNeeded: z.number().int().positive().optional().default(1),
|
|
|
|
|
participants: z.array(issueExecutionStageParticipantSchema).default([]),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const issueExecutionPolicySchema = z.object({
|
|
|
|
|
mode: z.enum(ISSUE_EXECUTION_POLICY_MODES).optional().default("normal"),
|
|
|
|
|
commentRequired: z.boolean().optional().default(true),
|
|
|
|
|
stages: z.array(issueExecutionStageSchema).default([]),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const issueExecutionStateSchema = z.object({
|
|
|
|
|
status: z.enum(ISSUE_EXECUTION_STATE_STATUSES),
|
|
|
|
|
currentStageId: z.string().uuid().nullable(),
|
|
|
|
|
currentStageIndex: z.number().int().nonnegative().nullable(),
|
|
|
|
|
currentStageType: z.enum(ISSUE_EXECUTION_STAGE_TYPES).nullable(),
|
|
|
|
|
currentParticipant: issueExecutionStagePrincipalSchema.nullable(),
|
|
|
|
|
returnAssignee: issueExecutionStagePrincipalSchema.nullable(),
|
|
|
|
|
completedStageIds: z.array(z.string().uuid()).default([]),
|
|
|
|
|
lastDecisionId: z.string().uuid().nullable(),
|
|
|
|
|
lastDecisionOutcome: z.enum(ISSUE_EXECUTION_DECISION_OUTCOMES).nullable(),
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-16 13:31:47 -06:00
|
|
|
export const createIssueSchema = z.object({
|
Expand data model with companies, approvals, costs, and heartbeats
Add new DB schemas: companies, agent_api_keys, approvals, cost_events,
heartbeat_runs, issue_comments. Add corresponding shared types and
validators. Update existing schemas (agents, goals, issues, projects)
with new fields for company association, budgets, and richer metadata.
Generate initial Drizzle migration. Update seed data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:07:22 -06:00
|
|
|
projectId: z.string().uuid().optional().nullable(),
|
2026-03-13 17:12:25 -05:00
|
|
|
projectWorkspaceId: z.string().uuid().optional().nullable(),
|
Expand data model with companies, approvals, costs, and heartbeats
Add new DB schemas: companies, agent_api_keys, approvals, cost_events,
heartbeat_runs, issue_comments. Add corresponding shared types and
validators. Update existing schemas (agents, goals, issues, projects)
with new fields for company association, budgets, and richer metadata.
Generate initial Drizzle migration. Update seed data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:07:22 -06:00
|
|
|
goalId: z.string().uuid().optional().nullable(),
|
|
|
|
|
parentId: z.string().uuid().optional().nullable(),
|
2026-04-04 13:56:04 -05:00
|
|
|
blockedByIssueIds: z.array(z.string().uuid()).optional(),
|
2026-03-30 14:08:44 -05:00
|
|
|
inheritExecutionWorkspaceFromIssueId: z.string().uuid().optional().nullable(),
|
2026-02-16 13:31:47 -06:00
|
|
|
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"),
|
Expand data model with companies, approvals, costs, and heartbeats
Add new DB schemas: companies, agent_api_keys, approvals, cost_events,
heartbeat_runs, issue_comments. Add corresponding shared types and
validators. Update existing schemas (agents, goals, issues, projects)
with new fields for company association, budgets, and richer metadata.
Generate initial Drizzle migration. Update seed data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:07:22 -06:00
|
|
|
assigneeAgentId: z.string().uuid().optional().nullable(),
|
feat: add auth/access foundation - deps, DB schema, shared types, and config
Add Better Auth, drizzle-orm, @dnd-kit, and remark-gfm dependencies.
Introduce DB schema for auth tables (user, session, account, verification),
company memberships, instance user roles, permission grants, invites, and
join requests. Add assigneeUserId to issues. Extend shared config schema
with deployment mode/exposure/auth settings, add access types and validators,
and wire up new API path constants.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:40:16 -06:00
|
|
|
assigneeUserId: z.string().optional().nullable(),
|
Expand data model with companies, approvals, costs, and heartbeats
Add new DB schemas: companies, agent_api_keys, approvals, cost_events,
heartbeat_runs, issue_comments. Add corresponding shared types and
validators. Update existing schemas (agents, goals, issues, projects)
with new fields for company association, budgets, and richer metadata.
Generate initial Drizzle migration. Update seed data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:07:22 -06:00
|
|
|
requestDepth: z.number().int().nonnegative().optional().default(0),
|
|
|
|
|
billingCode: z.string().optional().nullable(),
|
2026-02-26 10:32:44 -06:00
|
|
|
assigneeAdapterOverrides: issueAssigneeAdapterOverridesSchema.optional().nullable(),
|
2026-04-06 08:40:38 -05:00
|
|
|
executionPolicy: issueExecutionPolicySchema.optional().nullable(),
|
2026-03-13 17:12:25 -05:00
|
|
|
executionWorkspaceId: z.string().uuid().optional().nullable(),
|
2026-04-02 12:09:02 -05:00
|
|
|
executionWorkspacePreference: z.enum(ISSUE_EXECUTION_WORKSPACE_PREFERENCES).optional().nullable(),
|
2026-03-10 09:03:31 -05:00
|
|
|
executionWorkspaceSettings: issueExecutionWorkspaceSettingsSchema.optional().nullable(),
|
2026-02-25 08:38:37 -06:00
|
|
|
labelIds: z.array(z.string().uuid()).optional(),
|
2026-02-16 13:31:47 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export type CreateIssue = z.infer<typeof createIssueSchema>;
|
2026-02-25 08:38:37 -06:00
|
|
|
|
|
|
|
|
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>;
|
2026-02-16 13:31:47 -06:00
|
|
|
|
2026-02-17 20:46:12 -06:00
|
|
|
export const updateIssueSchema = createIssueSchema.partial().extend({
|
|
|
|
|
comment: z.string().min(1).optional(),
|
2026-03-20 15:46:01 -05:00
|
|
|
reopen: z.boolean().optional(),
|
2026-03-28 10:34:36 -05:00
|
|
|
interrupt: z.boolean().optional(),
|
2026-02-19 15:43:43 -06:00
|
|
|
hiddenAt: z.string().datetime().nullable().optional(),
|
2026-02-17 20:46:12 -06:00
|
|
|
});
|
2026-02-16 13:31:47 -06:00
|
|
|
|
|
|
|
|
export type UpdateIssue = z.infer<typeof updateIssueSchema>;
|
2026-03-10 09:03:31 -05:00
|
|
|
export type IssueExecutionWorkspaceSettings = z.infer<typeof issueExecutionWorkspaceSettingsSchema>;
|
Expand data model with companies, approvals, costs, and heartbeats
Add new DB schemas: companies, agent_api_keys, approvals, cost_events,
heartbeat_runs, issue_comments. Add corresponding shared types and
validators. Update existing schemas (agents, goals, issues, projects)
with new fields for company association, budgets, and richer metadata.
Generate initial Drizzle migration. Update seed data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:07:22 -06:00
|
|
|
|
|
|
|
|
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),
|
2026-02-19 09:09:26 -06:00
|
|
|
reopen: z.boolean().optional(),
|
2026-03-02 16:43:59 -06:00
|
|
|
interrupt: z.boolean().optional(),
|
Expand data model with companies, approvals, costs, and heartbeats
Add new DB schemas: companies, agent_api_keys, approvals, cost_events,
heartbeat_runs, issue_comments. Add corresponding shared types and
validators. Update existing schemas (agents, goals, issues, projects)
with new fields for company association, budgets, and richer metadata.
Generate initial Drizzle migration. Update seed data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 09:07:22 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export type AddIssueComment = z.infer<typeof addIssueCommentSchema>;
|
2026-02-19 13:02:25 -06:00
|
|
|
|
|
|
|
|
export const linkIssueApprovalSchema = z.object({
|
|
|
|
|
approvalId: z.string().uuid(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export type LinkIssueApproval = z.infer<typeof linkIssueApprovalSchema>;
|
2026-02-20 10:31:56 -06:00
|
|
|
|
|
|
|
|
export const createIssueAttachmentMetadataSchema = z.object({
|
|
|
|
|
issueCommentId: z.string().uuid().optional().nullable(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export type CreateIssueAttachmentMetadata = z.infer<typeof createIssueAttachmentMetadataSchema>;
|
2026-03-13 21:30:48 -05:00
|
|
|
|
|
|
|
|
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,
|
2026-03-14 09:09:21 -05:00
|
|
|
body: z.string().max(524288),
|
2026-03-13 21:30:48 -05:00
|
|
|
changeSummary: z.string().trim().max(500).nullable().optional(),
|
|
|
|
|
baseRevisionId: z.string().uuid().nullable().optional(),
|
|
|
|
|
});
|
|
|
|
|
|
2026-03-26 08:24:57 -05:00
|
|
|
export const restoreIssueDocumentRevisionSchema = z.object({});
|
|
|
|
|
|
2026-03-13 21:30:48 -05:00
|
|
|
export type IssueDocumentFormat = z.infer<typeof issueDocumentFormatSchema>;
|
|
|
|
|
export type UpsertIssueDocument = z.infer<typeof upsertIssueDocumentSchema>;
|
2026-03-26 08:24:57 -05:00
|
|
|
export type RestoreIssueDocumentRevision = z.infer<typeof restoreIssueDocumentRevisionSchema>;
|