UNPKG

@cloudkinetix/bmad-enhanced

Version:

Cloud-Kinetix enhanced fork of BMAD-METHOD - Breakthrough Method of Agile AI-driven Development with robust versioning and unified validation.

785 lines (649 loc) • 19.2 kB
--- name: JIRA Interaction Flows version: 1.0.0 role: Reusable interaction patterns for common JIRA workflows description: Provides tested conversation flows that guide users through complex operations capabilities: - Pre-built conversation templates - Adaptive flow management - Context-aware responses - Error recovery flows - Learning from interactions --- # JIRA Interaction Flows You provide reusable interaction patterns that make complex JIRA operations feel like natural conversations. ## Flow Architecture ### 1. Flow Definition Structure ```typescript interface InteractionFlow { id: string; name: string; description: string; trigger_patterns: string[]; // What activates this flow // Flow configuration config: { max_turns: number; timeout_minutes: number; allow_interruption: boolean; save_checkpoints: boolean; personality: "professional" | "friendly" | "concise"; }; // Flow stages stages: FlowStage[]; // Adaptive elements adaptations: { user_expertise: AdaptationRule[]; context_richness: AdaptationRule[]; time_pressure: AdaptationRule[]; }; // Success metrics metrics: { avg_completion_time: number; success_rate: number; user_satisfaction: number; abandonment_rate: number; }; } interface FlowStage { id: string; type: "greeting" | "gather" | "confirm" | "execute" | "summary"; // Turn templates turns: TurnTemplate[]; // Stage logic entry_conditions: Condition[]; exit_conditions: Condition[]; skip_conditions: Condition[]; // Error handling error_recovery: ErrorRecovery; } ``` ### 2. Turn Templates ```javascript const turnTemplates = { // Greeting variations greeting: { first_time: { template: `Hello! I'll help you ${action}. ${enthusiasm} ${context_summary} ${next_step_preview}`, variables: { action: (context) => describeAction(context.intent), enthusiasm: (context) => getEnthusiasm(context.user_mood), context_summary: (context) => summarizeContext(context), next_step_preview: () => "Let me start by understanding what you need.", }, }, returning: { template: `Welcome back! ${previous_context} ${continuation_option}`, variables: { previous_context: (context) => describePreviousWork(context), continuation_option: (context) => getContinuationOptions(context), }, }, }, // Information gathering gather: { missing_required: { template: `I need a bit more information to ${goal}: ${questions} ${help_text}`, variables: { goal: (context) => context.current_goal, questions: (context) => formatQuestions(context.missing_info), help_text: (context) => (context.show_help ? getHelpText(context) : ""), }, }, clarification: { template: `Just to clarify - when you said "${user_input}", did you mean: ${options} Or something else?`, variables: { user_input: (context) => context.ambiguous_input, options: (context) => formatClarificationOptions(context), }, }, }, // Confirmation patterns confirm: { before_execution: { template: `${summary_icon} Here's what I'm about to do: ${action_list} ${impact_statement} ${confirmation_prompt}`, variables: { summary_icon: () => "šŸ“‹", action_list: (context) => formatActionList(context.planned_actions), impact_statement: (context) => describeImpact(context), confirmation_prompt: (context) => context.high_risk ? "Please type 'confirm' to proceed:" : "Ready to proceed?", }, }, }, }; ``` ## Common Interaction Flows ### 1. Sprint Planning Flow ```javascript const sprintPlanningFlow = { id: "sprint_planning_flow", name: "Sprint Planning Assistant", trigger_patterns: ["plan sprint", "sprint planning", "fill sprint"], config: { max_turns: 15, timeout_minutes: 30, allow_interruption: true, save_checkpoints: true, personality: "friendly", }, stages: [ { id: "greeting", type: "greeting", turns: [ { id: "welcome", template: turnTemplates.greeting.first_time, conditions: { is_first_interaction: true }, }, ], }, { id: "capacity_analysis", type: "gather", turns: [ { id: "check_capacity", content: async (context) => { const capacity = await calculateCapacity(context); const velocity = await getVelocity(context); return `Let's check your team's capacity for ${context.sprint_name || "the upcoming sprint"}: šŸ“Š **Capacity Analysis** • Team size: ${capacity.team_size} members • Available hours: ${capacity.hours} (${capacity.story_points} points) • Historical velocity: ${velocity.average} ± ${velocity.std_dev} points • Recommended load: ${velocity.recommended} points How would you like to fill the sprint?`; }, options: [ { label: "Use recommended load", value: "recommended", description: `Target ${velocity.recommended} points`, }, { label: "Fill to capacity", value: "full_capacity", description: `Target ${capacity.story_points} points`, warning: capacity.story_points > velocity.average * 1.2 ? "āš ļø This is above your usual velocity" : null, }, { label: "Custom target", value: "custom", description: "Set your own target", }, { label: "Focus on specific epic", value: "epic_focus", description: "Prioritize one epic's stories", }, ], handlers: { recommended: (context) => { context.target_points = context.velocity.recommended; return "backlog_review"; }, custom: () => "custom_target_input", epic_focus: () => "epic_selection", }, }, ], }, { id: "story_selection", type: "gather", turns: [ { id: "review_candidates", content: async (context) => { const stories = await getCandidateStories(context); const groups = groupStoriesByEpic(stories); return `I found ${stories.length} ready stories totaling ${getTotalPoints(stories)} points: ${formatStoryGroups(groups)} How would you like to proceed?`; }, options: [ { label: "Auto-select best mix", value: "auto_select", description: "I'll optimize for value and dependencies", }, { label: "Review each story", value: "manual_review", description: "Go through stories one by one", }, { label: "Filter stories", value: "filter", description: "Narrow down the list", }, ], }, ], }, { id: "confirmation", type: "confirm", turns: [ { id: "final_confirmation", content: (context) => { const selected = context.selected_stories; return `## Sprint ${context.sprint_name} Plan **Selected Stories:** ${selected.length} **Total Points:** ${getTotalPoints(selected)} **Target:** ${context.target_points} points ### By Epic: ${formatSelectedByEpic(selected)} ### Risks & Dependencies: ${identifyRisks(selected)} Ready to create the sprint with these stories?`; }, actions: [ { label: "āœ… Create sprint", value: "create", primary: true, }, { label: "šŸ“ Adjust selection", value: "adjust", }, { label: "āŒ Cancel", value: "cancel", }, ], }, ], }, ], }; ``` ### 2. Issue Investigation Flow ```javascript const issueInvestigationFlow = { id: "issue_investigation_flow", name: "Issue Investigation Assistant", trigger_patterns: ["investigate", "debug", "why is", "check issue"], stages: [ { id: "identify_issue", type: "gather", turns: [ { id: "what_issue", content: `What issue would you like me to investigate?`, input_type: "smart_search", handlers: { found_single: (context, issue) => { context.issue = issue; return "investigation_type"; }, found_multiple: (context, issues) => { context.candidates = issues; return "disambiguate"; }, not_found: () => "manual_input", }, }, ], }, { id: "investigation", type: "execute", turns: [ { id: "deep_analysis", content: async (context) => { const analysis = await performDeepAnalysis(context.issue); return `## Investigation Results for ${context.issue.key} ### Issue Timeline ${formatTimeline(analysis.timeline)} ### State Changes ${formatStateChanges(analysis.state_changes)} ### Related Issues ${formatRelatedIssues(analysis.related)} ### Potential Causes ${formatPotentialCauses(analysis.causes)} What would you like to explore further?`; }, dynamic_options: (analysis) => { const options = []; if (analysis.has_blockers) { options.push({ label: "Analyze blockers", value: "analyze_blockers", }); } if (analysis.has_automation_errors) { options.push({ label: "Check automation logs", value: "check_automation", }); } return options; }, }, ], }, ], }; ``` ### 3. Bulk Update Flow ```javascript const bulkUpdateFlow = { id: "bulk_update_flow", name: "Bulk Update Assistant", trigger_patterns: ["bulk update", "update multiple", "mass update"], stages: [ { id: "safety_check", type: "confirm", turns: [ { id: "understand_scope", content: `I'll help you update multiple issues. First, let's understand the scope. What issues do you want to update?`, options: [ { label: "Issues from a search/filter", value: "jql_search", }, { label: "Specific issue list", value: "issue_list", }, { label: "All issues in sprint", value: "sprint_issues", }, { label: "All issues in epic", value: "epic_issues", }, ], }, ], }, { id: "preview_changes", type: "confirm", turns: [ { id: "show_preview", content: async (context) => { const preview = await generatePreview(context); return `## Bulk Update Preview **Affected Issues:** ${preview.count} **Update Type:** ${preview.update_type} ### Changes to Apply: ${formatChanges(preview.changes)} ### Sample Before/After: ${formatBeforeAfter(preview.samples)} ### āš ļø Warnings: ${formatWarnings(preview.warnings)} This operation ${preview.reversible ? "CAN" : "CANNOT"} be easily reversed. Proceed with the update?`; }, require_confirmation: (preview) => preview.count > 50, confirmation_prompt: (preview) => `This will update ${preview.count} issues. Type 'UPDATE ${preview.count}' to confirm:`, }, ], }, ], error_recovery: { partial_failure: { content: (context, error) => `The bulk update partially failed: āœ… Successfully updated: ${error.success_count} āŒ Failed: ${error.failure_count} ### Failed Issues: ${formatFailures(error.failures)} What would you like to do?`, options: [ { label: "Retry failed issues", value: "retry_failed", }, { label: "Skip and continue", value: "skip", }, { label: "Rollback all changes", value: "rollback", available: (context) => context.rollback_available, }, ], }, }, }; ``` ## Adaptive Behaviors ### 1. User Expertise Adaptation ```javascript class ExpertiseAdapter { adaptFlowForUser(flow, userProfile) { const expertise = userProfile.jira_expertise || "intermediate"; const adaptedFlow = deepClone(flow); switch (expertise) { case "beginner": // Add more explanations adaptedFlow.stages.forEach((stage) => { stage.turns.forEach((turn) => { turn.include_help = true; turn.show_examples = true; turn.confirmation_required = true; }); }); break; case "expert": // Streamline for efficiency adaptedFlow.stages.forEach((stage) => { stage.turns.forEach((turn) => { turn.compact_mode = true; turn.skip_confirmations = true; turn.batch_operations = true; }); }); break; } return adaptedFlow; } } ``` ### 2. Context-Aware Responses ```javascript class ContextAwareResponder { enhanceResponse(baseResponse, context) { let enhanced = baseResponse; // Add relevant context if (context.previous_issues) { enhanced += `\n\nšŸ’” Based on your recent work with ${context.previous_issues.join( ", ", )}, you might also want to update those.`; } // Add warnings based on context if (context.near_sprint_end) { enhanced += `\n\nā° Note: The current sprint ends in ${context.days_until_sprint_end} days.`; } // Add suggestions based on patterns if (context.user_patterns.common_next_action) { enhanced += `\n\nšŸ”® You usually ${ context.user_patterns.common_next_action } after this. Would you like to do that next?`; } return enhanced; } } ``` ### 3. Progressive Complexity ```javascript class ProgressiveComplexity { getComplexityLevel(interaction_count, success_rate) { if (interaction_count < 5) return "simple"; if (success_rate < 0.8) return "simple"; if (interaction_count < 20) return "moderate"; return "advanced"; } adjustFlowComplexity(flow, level) { switch (level) { case "simple": return { ...flow, max_options: 3, hide_advanced: true, verbose_explanations: true, }; case "moderate": return { ...flow, max_options: 5, show_shortcuts: true, moderate_explanations: true, }; case "advanced": return { ...flow, max_options: 10, show_all_features: true, minimal_explanations: true, enable_power_features: true, }; } } } ``` ## Flow Analytics ### 1. Flow Performance Tracking ```javascript class FlowAnalytics { trackFlowExecution(flowId, execution) { const metrics = { flow_id: flowId, started_at: execution.started_at, completed_at: execution.completed_at, duration_ms: execution.duration, turns: { total: execution.turn_count, user_initiated: execution.user_turn_count, system_initiated: execution.system_turn_count, }, outcome: { completed: execution.completed, abandoned: execution.abandoned, error: execution.error, satisfaction: execution.user_satisfaction, }, efficiency: { backtracking_count: execution.backtrack_count, clarification_count: execution.clarification_count, error_recovery_count: execution.error_recovery_count, }, user_behavior: { options_explored: execution.options_explored, help_requested: execution.help_request_count, shortcuts_used: execution.shortcut_count, }, }; this.saveMetrics(metrics); this.updateFlowStatistics(flowId, metrics); } } ``` ### 2. Flow Optimization ```javascript class FlowOptimizer { optimizeFlow(flowId, analytics) { const optimizations = []; // Identify bottlenecks const bottlenecks = analytics.turns .filter((t) => t.avg_duration > 30000) .map((t) => ({ turn_id: t.id, avg_duration: t.avg_duration, abandonment_rate: t.abandonment_rate, })); bottlenecks.forEach((bottleneck) => { optimizations.push({ type: "simplify_turn", turn_id: bottleneck.turn_id, reason: "High duration and abandonment", }); }); // Find unused paths const unused_paths = analytics.paths .filter((p) => p.usage_count === 0) .map((p) => p.path_id); unused_paths.forEach((path) => { optimizations.push({ type: "remove_path", path_id: path, reason: "Never used", }); }); return optimizations; } } ``` ## Error Recovery Flows ### 1. Generic Error Recovery ```javascript const errorRecoveryFlow = { connection_error: { content: `I'm having trouble connecting to JIRA. This might be temporary.`, options: [ { label: "Retry now", value: "retry", action: () => retryLastOperation(), }, { label: "Save progress and continue later", value: "save", action: () => createCheckpoint(), }, ], }, permission_error: { content: (error) => `You don't have permission to ${error.operation}. This requires: ${error.required_permission}`, options: [ { label: "Request permission", value: "request", action: () => createPermissionRequest(), }, { label: "Try alternative approach", value: "alternative", action: () => suggestAlternative(), }, ], }, }; ``` ## Best Practices 1. **Start Simple**: Begin with basic flows, add complexity based on usage 2. **Learn Continuously**: Track what works and what doesn't 3. **Respect User Time**: Make interactions efficient 4. **Provide Escape Routes**: Always allow users to change course 5. **Test with Real Users**: Flows should match natural conversation patterns Remember: The best interaction flow is one that feels so natural, users don't realize they're being guided.