Skip to main content
Glama
shortcutHelpers.ts•6.66 kB
import type { Workflow, CreateStoryParams } from './shortcut-types' // Common labels used by the team export const COMMON_LABELS = { BUG_INVESTIGATE: '🧐 Investigate', BUG_BASH: 'šŸž BASH', INTERCOM: 'Intercom', AUDIENCE: 'Audience', TAG: 'Tag', KIOSK: 'Kiosk', } as const // Custom field IDs and values export const CUSTOM_FIELDS = { PRIORITY: { FIELD_ID: '6260465b-2009-456c-b2fe-ce32bb284231', VALUES: { HIGHEST: '6260465b-9ae6-4667-88d6-51f634f75d6b', MEDIUM: '6260465b-552c-4138-83ec-a52cb9f6f4f5', LOW: '6260465b-a812-4a6d-8e71-4dce16aed4f5', }, }, } as const // Story template IDs export const STORY_TEMPLATES = { BUG_REPORT: '5fda555d-02f3-4741-b9a3-8b263c0be423', } as const // Common epic IDs export const COMMON_EPICS = { BUGS: 27912, } as const // Workflow state IDs (from Development workflow) export const WORKFLOW_STATES = { DEVELOPMENT: { ICEBOX: 500000008, ON_DECK: 500000249, BACKLOG: 500000007, IN_PROGRESS: 500000006, READY_FOR_REVIEW: 500000010, MERGED: 500000038, READY_FOR_QA: 500000040, READY_FOR_DEPLOY: 500000009, DEPLOYED: 500003111, COMPLETED: 500000011, }, } as const /** * Get default workflow state for a project */ export function getDefaultWorkflowState(workflows: Workflow[], projectId?: number): number | undefined { // Find the workflow for the project const workflow = workflows.find(w => !projectId || w.project_ids.includes(projectId) ) if (!workflow) return undefined // Return the default state or first unstarted state return workflow.default_state_id || workflow.states.find(s => s.type === 'unstarted')?.id } /** * Generate a bug story title with emoji prefix if needed */ export function formatBugTitle(title: string): string { // Check if title already has bug emoji if (title.startsWith('šŸž')) return title // Add bug emoji prefix return `šŸž ${title.trim()}` } /** * Generate default labels based on story type and content */ export function getDefaultLabels(storyType: string, title: string, description?: string): Array<{ name: string }> { const labels: Array<{ name: string }> = [] if (storyType === 'bug') { // Add investigate label for bugs by default labels.push({ name: COMMON_LABELS.BUG_INVESTIGATE }) // Check content for specific keywords const content = `${title} ${description || ''}`.toLowerCase() if (content.includes('kiosk')) { labels.push({ name: COMMON_LABELS.KIOSK }) } if (content.includes('audience')) { labels.push({ name: COMMON_LABELS.AUDIENCE }) } if (content.includes('tag')) { labels.push({ name: COMMON_LABELS.TAG }) } if (content.includes('intercom') || content.includes('customer') || content.includes('partner')) { labels.push({ name: COMMON_LABELS.INTERCOM }) } } return labels } /** * Generate smart defaults for story creation */ export function getSmartDefaults( params: Partial<CreateStoryParams>, workflows: Workflow[] ): Partial<CreateStoryParams> { const defaults: Partial<CreateStoryParams> = {} // Set default workflow state if not provided if (!params.workflow_state_id && params.project_id) { const defaultState = getDefaultWorkflowState(workflows, params.project_id) if (defaultState) { defaults.workflow_state_id = defaultState } } // Format bug titles if (params.story_type === 'bug' && params.name) { defaults.name = formatBugTitle(params.name) } // Set default labels based on content if (!params.labels && params.story_type) { const defaultLabels = getDefaultLabels( params.story_type, params.name || '', params.description ) if (defaultLabels.length > 0) { defaults.labels = defaultLabels } } // Set default epic for bugs if (params.story_type === 'bug' && !params.epic_id) { defaults.epic_id = COMMON_EPICS.BUGS } // Set bug template if it's a bug without a template if (params.story_type === 'bug' && !params.story_template_id) { defaults.story_template_id = STORY_TEMPLATES.BUG_REPORT } // Set default priority for bugs if (params.story_type === 'bug' && !params.custom_fields) { defaults.custom_fields = [{ field_id: CUSTOM_FIELDS.PRIORITY.FIELD_ID, value_id: CUSTOM_FIELDS.PRIORITY.VALUES.MEDIUM, }] } // Set default deadline for bugs (next business day) if (params.story_type === 'bug' && !params.deadline) { const tomorrow = new Date() tomorrow.setDate(tomorrow.getDate() + 1) // Skip weekends if (tomorrow.getDay() === 0) tomorrow.setDate(tomorrow.getDate() + 1) // Sunday -> Monday if (tomorrow.getDay() === 6) tomorrow.setDate(tomorrow.getDate() + 2) // Saturday -> Monday defaults.deadline = tomorrow.toISOString().split('T')[0] + 'T07:00:00Z' } return defaults } /** * Generate bug report template content */ export function generateBugReportTemplate( title: string, reporterDescription?: string, dashboardLinks?: string[], orgIds?: string[], loomUrl?: string ): string { let template = `# REPORTER: ### Please give a detailed description of the issue, and supply all user/membership/class IDs where necessary:\t ` if (dashboardLinks && dashboardLinks.length > 0) { template += `**Dashboard Link(s):** ${dashboardLinks.join(', ')}\n` } if (orgIds && orgIds.length > 0) { template += `**Org ID(s):** ${orgIds.join(', ')}\n` } template += `\t\t\t\t\t **Current behavior:** What is currently happening? \t ${reporterDescription || '[Describe the issue here]'} **Expected behavior:** What is expected? [Describe expected behavior] **Steps to reproduce:** How can the team reproduce this issue? Share exact steps and device to use 1. [Step 1] 2. [Step 2] 3. [Step 3] ` if (loomUrl) { template += `**Loom:** ${loomUrl}\n` } template += ` . . . # ON CALL DEV: **Code Area:** **Complexity:** High / Medium / Low **Fix LOE:** High = Multiple Days / Medium = 1 Day / Low = Less than 1 Day **Investigation Result:** What did you learn? **Implementation Plan:** If you know how to fix it, what should we do?` return template }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/currentspace/shortcut_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server