import { defineTool } from '@earendil-works/pi-coding-agent'; import { Type } from 'typebox'; import { withLinearAuth, linearGraphQL } from '../client'; import { PaginationParams, paginationVariables, FilterParam, SortParam } from '../params'; import { USER_SELECTION } from '../selections'; import type { JsonObject, LinearConnection } from '../types'; import { compactObject, asObject, asObjectArray } from '../util'; import { renderLinearGetUserCall, renderLinearUserListCall, renderLinearUserListResult, renderLinearUserResult, } from '../renderers/users'; export function userTools() { return [ defineTool({ name: 'linear_list_users', label: 'Linear List Users', description: 'List users. Supports full users query args.', parameters: Type.Object({ ...PaginationParams, ...FilterParam, ...SortParam, includeDisabled: Type.Optional(Type.Boolean()), }), renderCall: renderLinearUserListCall, async execute(_toolCallId, params, signal, _onUpdate, ctx) { return withLinearAuth(ctx, signal, async (apiKey) => { const variables = compactObject({ ...paginationVariables(params, 50), filter: asObject(params.filter), includeDisabled: params.includeDisabled, sort: asObjectArray(params.sort), }); const data = await linearGraphQL<{ users: LinearConnection; }>( apiKey, `query ListUsers( $after: String $before: String $filter: UserFilter $first: Int $includeArchived: Boolean $includeDisabled: Boolean $last: Int $orderBy: PaginationOrderBy $sort: [UserSortInput!] ) { users( after: $after before: $before filter: $filter first: $first includeArchived: $includeArchived includeDisabled: $includeDisabled last: $last orderBy: $orderBy sort: $sort ) { nodes { ${USER_SELECTION} } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } } }`, variables, signal, ); const users = data.users.nodes; const pageInfo = data.users.pageInfo; return { content: [{ type: 'text', text: JSON.stringify({ users, pageInfo }, null, 2) }], details: { users, pageInfo }, }; }); }, renderResult: renderLinearUserListResult, }), defineTool({ name: 'linear_get_user', label: 'Linear Get User', description: 'Get a specific user by id.', parameters: Type.Object({ userId: Type.String(), }), renderCall: renderLinearGetUserCall, async execute(_toolCallId, params, signal, _onUpdate, ctx) { return withLinearAuth(ctx, signal, async (apiKey) => { const data = await linearGraphQL<{ user: JsonObject | null }>( apiKey, `query GetUser($id: String!) { user(id: $id) { ${USER_SELECTION} } }`, { id: params.userId }, signal, ); const user = data.user; return { content: [{ type: 'text', text: JSON.stringify({ user }, null, 2) }], details: { user }, }; }); }, renderResult: renderLinearUserResult, }), ]; }