Files
2026-07-13 13:34:48 +08:00

301 lines
9.8 KiB
TypeScript

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']