UNPKG

linear-cmd

Version:

A GitHub CLI-like tool for Linear - manage issues, accounts, and more

119 lines (118 loc) 4.93 kB
import { LinearClient } from '@linear/sdk'; import { Command } from 'commander'; import inquirer from 'inquirer'; import { ConfigManager } from '../../lib/config-manager.js'; import { LinearAPIClient } from '../../lib/linear-client.js'; import { Logger } from '../../lib/logger.js'; export function createCommentIssueCommand() { return new Command('comment') .description('Add a comment to a Linear issue') .argument('<issue>', 'issue ID or URL') .argument('[comment]', 'comment text (optional, will prompt if not provided)') .option('-a, --account <account>', 'specify account to use') .action(async (issueIdOrUrl, commentText, options) => { const configManager = new ConfigManager(); try { // Parse issue identifier first const linearClient = new LinearAPIClient(); const issueId = linearClient.parseIssueIdentifier(issueIdOrUrl); if (!issueId) { Logger.error('Invalid issue ID or URL'); return; } // For comment, we'll try to find the account that has access to this issue // if not specified let client; if (options.account) { const account = configManager.getAccount(options.account); if (!account) { Logger.error(`Account '${options.account}' not found`); Logger.dim('Run `linear account list` to see available accounts'); return; } client = new LinearClient({ apiKey: account.api_key }); } else { // Try to find which account can access this issue const accounts = configManager.getAllAccounts(); let foundAccount = null; for (const acc of accounts) { try { const testClient = new LinearClient({ apiKey: acc.api_key }); await testClient.issue(issueId); foundAccount = acc; client = testClient; break; } catch { // This account can't access the issue, try next } } if (!foundAccount || !client) { Logger.error('Could not find an account with access to this issue'); Logger.dim('Use --account flag to specify which account to use'); Logger.dim('Run `linear account list` to see available accounts'); return; } } // Fetch the issue const issue = await client.issue(issueId); if (!issue) { Logger.error(`Issue ${issueId} not found`); return; } // Get comment text let comment = commentText; if (!comment) { const answers = await inquirer.prompt([ { type: 'input', name: 'comment', message: 'Comment:', validate: (input) => input.trim().length > 0 || 'Comment cannot be empty' } ]); comment = answers.comment; } // Add the comment Logger.loading('Adding comment...'); await client.createComment({ issueId: issue.id, body: comment }); Logger.success(`Comment added to ${issue.identifier}`); Logger.link(issue.url); // Show recent comments const comments = await issue.comments({ last: 3 }); if (comments.nodes.length > 0) { Logger.dim('\nRecent comments:'); for (const c of comments.nodes.reverse()) { const author = await c.user; const createdAt = new Date(c.createdAt); const timeAgo = getRelativeTime(createdAt); Logger.info(`💬 ${author?.name || 'Unknown'}${timeAgo}`); Logger.plain(c.body); } } } catch (error) { Logger.error('Error adding comment', error); } }); } function getRelativeTime(date) { const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMins / 60); const diffDays = Math.floor(diffHours / 24); if (diffMins < 1) return 'just now'; if (diffMins < 60) return `${diffMins}m ago`; if (diffHours < 24) return `${diffHours}h ago`; if (diffDays < 7) return `${diffDays}d ago`; return date.toLocaleDateString(); }