import { z, IntegrationDefinitionProps, ActionDefinition } from '@botpress/sdk' import { linearIdsSchema, userProfileSchema, issueSchema } from './schemas' const _channels = ['issue'] as const export type Target = { displayName: string tags: { [key: string]: string } channel: (typeof _channels)[number] } const findTarget = { title: 'Find Target', description: 'Find a target on Linear', input: { schema: z.object({ query: z.string().min(2).title('Search query').describe('Issue title, description, or number'), channel: z.enum(['issue']).title('Channel').describe('The channel to search in'), }), }, output: { schema: z.object({ targets: z .array( z.object({ displayName: z.string().title('Display Name').describe('The name of the issue'), tags: z.record(z.string()).title('Tags').describe('The tags applied to the issue'), channel: z.enum(['issue']).title('Channel').describe('The channel of the search result'), }) ) .title('Results') .describe('The list of issues found'), }), }, } as const satisfies ActionDefinition const getIssue = { title: 'Get Issue', description: 'Get an issue by its ID', input: { schema: z.object({ issueId: z.string().title('Issue ID').describe('The issue ID on Linear. Ex: {{event.payload.linearIds.issueId}}'), }), }, output: { schema: issueSchema.title('Issue').describe('The issue found'), }, } as const satisfies ActionDefinition const listIssues = { title: 'List Issues', description: 'List issues from Linear', input: { schema: z.object({ count: z.number().optional().default(10).title('Fetch Amount').describe('The number of issues to return'), startCursor: z.string().optional().title('Start Cursor').describe('The cursor to start from'), teamId: z.string().optional().title('Team ID').describe('The team ID to filter by'), startDate: z.string().optional().title('Start Date').describe('Ignore issues created before this date'), }), }, output: { schema: z.object({ issues: z .array(issueSchema.extend({ linearIds: linearIdsSchema })) .title('Issues') .describe('The list of matching issues'), nextCursor: z.string().optional().title('Next Cursor').describe('The cursor to fetch the next page'), }), }, } as const satisfies ActionDefinition const userSchema = z.object({ id: z.string().title('ID').describe('The user ID on Linear'), email: z.string().title('Email').describe("The user's email address"), name: z.string().title('Name').describe("The user's nickname"), displayName: z.string().title('Display Name').describe("The user's display name"), avatarUrl: z.string().optional().title('Avatar URL').describe('The URL of the user avatar'), description: z .string() .optional() .title('Description') .describe("The user's description, such as their title or bio"), lastSeen: z.string().optional().title('Last Seen').describe('The last time the user was seen'), updatedAt: z.string().datetime().title('Updated At').describe('The last time the user was updated'), }) const listUsers = { title: 'List Users', description: 'List users from Linear', input: { schema: z.object({ count: z.number().optional().default(10).title('Fetch Amount').describe('The number of users to return'), startCursor: z.string().optional().title('Start Cursor').describe('The cursor to start from'), }), }, output: { schema: z.object({ users: z.array(userSchema).title('Users').describe('The list of matching users'), nextCursor: z.string().optional().title('Next Cursor').describe('The cursor to fetch the next page'), }), }, } as const satisfies ActionDefinition const listTeams = { title: 'List Teams', description: 'List teams from Linear', input: { schema: z.object({}), }, output: { schema: z.object({ teams: z .array( z.object({ id: z.string().title('ID').describe('The unique identifier of the entity'), key: z.string().title('Key').describe("The team's key"), name: z.string().title('Name').describe("The team's name"), description: z.string().optional().title('Description').describe("The team's description"), icon: z.string().optional().title('Icon').describe('The icon of the team'), }) ) .title('Teams') .describe('The list of teams'), }), }, } as const satisfies ActionDefinition const listStates = { title: 'List States', description: 'List states from Linear', input: { schema: z.object({ count: z.number().optional().default(10).title('Fetch Amount').describe('The number of states to return'), startCursor: z.string().optional().title('Start Cursor').describe('The cursor to start from'), }), }, output: { schema: z.object({ states: z .array( z.object({ id: z.string().title('ID').describe('The unique identifier of the entity'), name: z.string().title('Name').describe("The state's name"), }) ) .title('States') .describe('The list of states'), nextCursor: z.string().optional().title('Next Cursor').describe('The cursor to fetch the next page'), }), }, } as const satisfies ActionDefinition const markAsDuplicate = { title: 'Mark Issue as Duplicate', description: 'Mark an issue as a duplicate of another', input: { schema: z.object({ issueId: z.string().title('Issue ID').describe('The issue ID on Linear. Ex: {{event.payload.linearIds.issueId}}'), relatedIssueId: z.string().title('Related Issue ID').describe('The ID of the existing issue on Linear'), }), }, output: { schema: z.object({}), }, } as const satisfies ActionDefinition const getUser = { title: 'Get User Profile', description: 'Get a user profile from Linear', input: { schema: z.object({ linearUserId: z .string() .optional() .title('User ID') .describe( "The user's ID on Linear. Ex: {{event.payload.linearIds.creatorId}}. If omitted, returns the current user." ), }), }, output: { schema: userProfileSchema.title('User').describe('The user profile'), }, } as const satisfies ActionDefinition const updateIssue = { title: 'Update Issue', description: 'Update an issue on Linear', input: { schema: z.object({ issueId: z.string().title('Issue ID').describe('The issue ID on Linear. Example: {{event.payload.id}}'), priority: z.number().optional().title('Priority').describe('0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low'), teamName: z .string() .optional() .title('Move to team...') .describe('Type a name to change the assigned team of the issue'), labels: z .array(z.string()) .optional() .title('Set labels') .describe('One or multiple labels to assign to this issue'), project: z.string().optional().title('Associate to project...').describe('A project to associate to this issue'), }), }, output: { schema: z.object({ issue: issueSchema.optional().title('Issue').describe('The updated issue'), }), }, } as const satisfies ActionDefinition const createIssue = { title: 'Create Issue', description: 'Create an issue on Linear', input: { schema: z.object({ title: z.string().min(1).title('Title').describe("The issue's title"), description: z.string().title('Description').describe('The content of the issue'), priority: z.number().optional().title('Priority').describe('0 = none, 1 = urgent, 2 = high, 3 = medium, 4 = low'), teamName: z.string().title('Team Name').describe('Name of the team to assign the issue to'), labels: z.array(z.string()).optional().title('Labels').describe('One or multiple labels to assign to this issue'), project: z.string().optional().title('Project').describe('A project to associate to this issue'), }), }, output: { schema: z.object({ issue: issueSchema.title('Issue').describe('The created issue'), }), }, } as const satisfies ActionDefinition const deleteIssue = { title: 'Delete Issue', description: 'Delete an issue on Linear', input: { schema: z.object({ id: z.string().title('Issue ID').describe('The issue ID on Linear. Ex: {{event.payload.linearIds.issueId}}'), }), }, output: { schema: z.object({}), }, } as const satisfies ActionDefinition const sendRawGraphqlQuery = { title: 'Send Raw GraphQL Query', description: 'Send a raw GraphQL query to the linear API', input: { schema: z.object({ query: z.string().title('Query').describe('The GraphQL query'), parameters: z .array( z.object({ name: z.string().title('Name').describe('The parameter name'), value: z.any().title('Value').describe('The parameter value'), }) ) .optional() .title('Parameters') .describe('The query parameters'), }), }, output: { schema: z.object({ result: z.unknown().title('Result').describe('The query result'), }), }, } as const satisfies ActionDefinition const resolveComment = { title: 'Resolve Comment', description: 'Resolve a comment by id', input: { schema: z.object({ id: z.string().title('ID').describe('The comment ID'), }), }, output: { schema: z.object({ success: z.boolean().title('Success').describe('Whether the operation was successful'), }), }, } as const satisfies ActionDefinition export const actions = { findTarget, listIssues, listTeams, listUsers, listStates, markAsDuplicate, getIssue, getUser, updateIssue, createIssue, deleteIssue, sendRawGraphqlQuery, resolveComment, } as const satisfies IntegrationDefinitionProps['actions']