@su-record/vibe 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +448 -0
  3. package/agents/backend-python-expert.md +453 -0
  4. package/agents/database-postgres-expert.md +538 -0
  5. package/agents/frontend-flutter-expert.md +487 -0
  6. package/agents/frontend-react-expert.md +424 -0
  7. package/agents/quality-reviewer.md +542 -0
  8. package/agents/specification-agent.md +505 -0
  9. package/bin/sutory +332 -0
  10. package/bin/vibe +338 -0
  11. package/mcp/dist/__tests__/complexity.test.js +126 -0
  12. package/mcp/dist/__tests__/memory.test.js +120 -0
  13. package/mcp/dist/__tests__/python-dart-complexity.test.js +146 -0
  14. package/mcp/dist/index.js +230 -0
  15. package/mcp/dist/lib/ContextCompressor.js +305 -0
  16. package/mcp/dist/lib/MemoryManager.js +334 -0
  17. package/mcp/dist/lib/ProjectCache.js +126 -0
  18. package/mcp/dist/lib/PythonParser.js +241 -0
  19. package/mcp/dist/tools/browser/browserPool.js +76 -0
  20. package/mcp/dist/tools/browser/browserUtils.js +135 -0
  21. package/mcp/dist/tools/browser/inspectNetworkRequests.js +140 -0
  22. package/mcp/dist/tools/browser/monitorConsoleLogs.js +97 -0
  23. package/mcp/dist/tools/convention/analyzeComplexity.js +248 -0
  24. package/mcp/dist/tools/convention/applyQualityRules.js +102 -0
  25. package/mcp/dist/tools/convention/checkCouplingCohesion.js +233 -0
  26. package/mcp/dist/tools/convention/complexityMetrics.js +133 -0
  27. package/mcp/dist/tools/convention/dartComplexity.js +117 -0
  28. package/mcp/dist/tools/convention/getCodingGuide.js +64 -0
  29. package/mcp/dist/tools/convention/languageDetector.js +50 -0
  30. package/mcp/dist/tools/convention/pythonComplexity.js +109 -0
  31. package/mcp/dist/tools/convention/suggestImprovements.js +257 -0
  32. package/mcp/dist/tools/convention/validateCodeQuality.js +177 -0
  33. package/mcp/dist/tools/memory/autoSaveContext.js +79 -0
  34. package/mcp/dist/tools/memory/database.js +123 -0
  35. package/mcp/dist/tools/memory/deleteMemory.js +39 -0
  36. package/mcp/dist/tools/memory/listMemories.js +38 -0
  37. package/mcp/dist/tools/memory/memoryConfig.js +27 -0
  38. package/mcp/dist/tools/memory/memorySQLite.js +138 -0
  39. package/mcp/dist/tools/memory/memoryUtils.js +34 -0
  40. package/mcp/dist/tools/memory/migrate.js +113 -0
  41. package/mcp/dist/tools/memory/prioritizeMemory.js +109 -0
  42. package/mcp/dist/tools/memory/recallMemory.js +40 -0
  43. package/mcp/dist/tools/memory/restoreSessionContext.js +69 -0
  44. package/mcp/dist/tools/memory/saveMemory.js +34 -0
  45. package/mcp/dist/tools/memory/searchMemories.js +37 -0
  46. package/mcp/dist/tools/memory/startSession.js +100 -0
  47. package/mcp/dist/tools/memory/updateMemory.js +46 -0
  48. package/mcp/dist/tools/planning/analyzeRequirements.js +166 -0
  49. package/mcp/dist/tools/planning/createUserStories.js +119 -0
  50. package/mcp/dist/tools/planning/featureRoadmap.js +202 -0
  51. package/mcp/dist/tools/planning/generatePrd.js +156 -0
  52. package/mcp/dist/tools/prompt/analyzePrompt.js +145 -0
  53. package/mcp/dist/tools/prompt/enhancePrompt.js +105 -0
  54. package/mcp/dist/tools/semantic/findReferences.js +195 -0
  55. package/mcp/dist/tools/semantic/findSymbol.js +200 -0
  56. package/mcp/dist/tools/thinking/analyzeProblem.js +50 -0
  57. package/mcp/dist/tools/thinking/breakDownProblem.js +140 -0
  58. package/mcp/dist/tools/thinking/createThinkingChain.js +39 -0
  59. package/mcp/dist/tools/thinking/formatAsPlan.js +73 -0
  60. package/mcp/dist/tools/thinking/stepByStepAnalysis.js +58 -0
  61. package/mcp/dist/tools/thinking/thinkAloudProcess.js +75 -0
  62. package/mcp/dist/tools/time/getCurrentTime.js +61 -0
  63. package/mcp/dist/tools/ui/previewUiAscii.js +232 -0
  64. package/mcp/dist/types/tool.js +2 -0
  65. package/mcp/package.json +53 -0
  66. package/package.json +49 -0
  67. package/scripts/install-mcp.js +48 -0
  68. package/scripts/install.sh +70 -0
  69. package/skills/core/communication-guide.md +104 -0
  70. package/skills/core/development-philosophy.md +53 -0
  71. package/skills/core/quick-start.md +121 -0
  72. package/skills/languages/dart-flutter.md +509 -0
  73. package/skills/languages/python-fastapi.md +386 -0
  74. package/skills/languages/typescript-nextjs.md +441 -0
  75. package/skills/languages/typescript-react-native.md +446 -0
  76. package/skills/languages/typescript-react.md +525 -0
  77. package/skills/quality/checklist.md +276 -0
  78. package/skills/quality/testing-strategy.md +437 -0
  79. package/skills/standards/anti-patterns.md +369 -0
  80. package/skills/standards/code-structure.md +291 -0
  81. package/skills/standards/complexity-metrics.md +312 -0
  82. package/skills/standards/naming-conventions.md +198 -0
  83. package/skills/tools/mcp-hi-ai-guide.md +665 -0
  84. package/skills/tools/mcp-workflow.md +51 -0
  85. package/templates/constitution-template.md +193 -0
  86. package/templates/plan-template.md +237 -0
  87. package/templates/spec-template.md +142 -0
  88. package/templates/tasks-template.md +132 -0
@@ -0,0 +1,69 @@
1
+ // Memory management tool - SQLite based (v1.3)
2
+ import { MemoryManager } from '../../lib/MemoryManager.js';
3
+ export const restoreSessionContextDefinition = {
4
+ name: 'restore_session_context',
5
+ description: 'restore|revert|go back|복원|되돌려 - Restore previous session context',
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {
9
+ sessionId: { type: 'string', description: 'Session ID to restore' },
10
+ restoreLevel: { type: 'string', description: 'Level of detail to restore', enum: ['essential', 'detailed', 'complete'] },
11
+ filterType: { type: 'string', description: 'Filter context by type', enum: ['all', 'progress', 'decisions', 'code-snippets', 'debugging', 'planning'] }
12
+ },
13
+ required: ['sessionId']
14
+ },
15
+ annotations: {
16
+ title: 'Restore Session',
17
+ audience: ['user', 'assistant']
18
+ }
19
+ };
20
+ export async function restoreSessionContext(args) {
21
+ const { sessionId, restoreLevel = 'detailed', filterType = 'all' } = args;
22
+ try {
23
+ const memoryManager = MemoryManager.getInstance();
24
+ // Get all context memories
25
+ let memories = memoryManager.list('context');
26
+ // Filter by session ID
27
+ memories = memories.filter(m => m.key.includes(sessionId));
28
+ // Filter by context type if not 'all'
29
+ if (filterType !== 'all') {
30
+ memories = memories.filter(m => {
31
+ try {
32
+ const contextData = JSON.parse(m.value);
33
+ return contextData.contextType === filterType;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ });
39
+ }
40
+ const maxItems = restoreLevel === 'essential' ? 3 : restoreLevel === 'detailed' ? 10 : 20;
41
+ const limitedMemories = memories.slice(0, maxItems);
42
+ if (limitedMemories.length === 0) {
43
+ return {
44
+ content: [{ type: 'text', text: `✗ No context found for session: ${sessionId}` }]
45
+ };
46
+ }
47
+ let response = `✓ Restored ${limitedMemories.length} context item(s) for session: ${sessionId}\n`;
48
+ limitedMemories.forEach(m => {
49
+ try {
50
+ const data = JSON.parse(m.value);
51
+ response += `\n• ${data.contextType || 'context'} (${data.urgency || 'medium'})`;
52
+ if (data.summary)
53
+ response += `: ${data.summary}`;
54
+ response += `\n Time: ${new Date(m.timestamp).toLocaleString()}`;
55
+ }
56
+ catch {
57
+ response += `\n• ${m.key}\n Time: ${new Date(m.timestamp).toLocaleString()}`;
58
+ }
59
+ });
60
+ return {
61
+ content: [{ type: 'text', text: response }]
62
+ };
63
+ }
64
+ catch (error) {
65
+ return {
66
+ content: [{ type: 'text', text: `✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}` }]
67
+ };
68
+ }
69
+ }
@@ -0,0 +1,34 @@
1
+ // Memory management tool - SQLite based (v1.3)
2
+ import { MemoryManager } from '../../lib/MemoryManager.js';
3
+ export const saveMemoryDefinition = {
4
+ name: 'save_memory',
5
+ description: '기억해|remember|저장해|save|memorize|keep - Save to long-term memory',
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {
9
+ key: { type: 'string', description: 'Memory key/identifier' },
10
+ value: { type: 'string', description: 'Information to save' },
11
+ category: { type: 'string', description: 'Memory category', enum: ['project', 'personal', 'code', 'notes'] }
12
+ },
13
+ required: ['key', 'value']
14
+ },
15
+ annotations: {
16
+ title: 'Save Memory',
17
+ audience: ['user', 'assistant']
18
+ }
19
+ };
20
+ export async function saveMemory(args) {
21
+ const { key: memoryKey, value: memoryValue, category = 'general' } = args;
22
+ try {
23
+ const memoryManager = MemoryManager.getInstance();
24
+ memoryManager.save(memoryKey, memoryValue, category);
25
+ return {
26
+ content: [{ type: 'text', text: `✓ Saved: ${memoryKey}\nCategory: ${category}` }]
27
+ };
28
+ }
29
+ catch (error) {
30
+ return {
31
+ content: [{ type: 'text', text: `✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}` }]
32
+ };
33
+ }
34
+ }
@@ -0,0 +1,37 @@
1
+ // Memory management tool - completely independent
2
+ import { MemoryManager } from '../../lib/MemoryManager.js';
3
+ export const searchMemoriesDefinition = {
4
+ name: 'search_memories',
5
+ description: '찾아|검색|기억 중에|search|find|look for - Search memories by content',
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {
9
+ query: { type: 'string', description: 'Search query' },
10
+ category: { type: 'string', description: 'Category to search in' }
11
+ },
12
+ required: ['query']
13
+ },
14
+ annotations: {
15
+ title: 'Search Memories',
16
+ audience: ['user', 'assistant']
17
+ }
18
+ };
19
+ export async function searchMemoriesHandler(args) {
20
+ const { query, category: searchCategory } = args;
21
+ try {
22
+ const mm = MemoryManager.getInstance();
23
+ const results = mm.search(query);
24
+ const resultList = results.map(m => `• ${m.key} (${m.category}): ${m.value.substring(0, 100)}${m.value.length > 100 ? '...' : ''}`).join('\n');
25
+ return {
26
+ content: [{
27
+ type: 'text',
28
+ text: `✓ Found ${results.length} matches for "${query}":\n${resultList || 'None'}`
29
+ }]
30
+ };
31
+ }
32
+ catch (error) {
33
+ return {
34
+ content: [{ type: 'text', text: `✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}` }]
35
+ };
36
+ }
37
+ }
@@ -0,0 +1,100 @@
1
+ // Memory management tool - SQLite based (v1.3)
2
+ import { MemoryManager } from '../../lib/MemoryManager.js';
3
+ import { promises as fs } from 'fs';
4
+ import path from 'path';
5
+ const GUIDES_DIR = path.join(process.cwd(), 'guides');
6
+ const GUIDES_FILE = path.join(GUIDES_DIR, 'coding_guides.json');
7
+ async function ensureGuidesDir() {
8
+ try {
9
+ await fs.access(GUIDES_DIR);
10
+ }
11
+ catch {
12
+ await fs.mkdir(GUIDES_DIR, { recursive: true });
13
+ }
14
+ }
15
+ async function loadGuides() {
16
+ try {
17
+ await ensureGuidesDir();
18
+ const data = await fs.readFile(GUIDES_FILE, 'utf-8');
19
+ return JSON.parse(data);
20
+ }
21
+ catch {
22
+ return [];
23
+ }
24
+ }
25
+ export const startSessionDefinition = {
26
+ name: 'start_session',
27
+ description: 'hi-ai|hello|안녕|하이아이 - Start session with context',
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {
31
+ greeting: { type: 'string', description: 'Greeting message that triggered this action (e.g., "하이아이", "hi-ai")' },
32
+ loadMemory: { type: 'boolean', description: 'Load relevant project memories (default: true)' },
33
+ loadGuides: { type: 'boolean', description: 'Load applicable coding guides (default: true)' },
34
+ restoreContext: { type: 'boolean', description: 'Restore previous session context (default: true)' }
35
+ },
36
+ required: []
37
+ },
38
+ annotations: {
39
+ title: 'Start Session',
40
+ audience: ['user', 'assistant']
41
+ }
42
+ };
43
+ export async function startSession(args) {
44
+ const { greeting = '', loadMemory = true, loadGuides: shouldLoadGuides = true, restoreContext = true } = args;
45
+ try {
46
+ const memoryManager = MemoryManager.getInstance();
47
+ let summary = `${greeting ? greeting + '! ' : ''}Session started.\n`;
48
+ // Load relevant project memories
49
+ if (loadMemory) {
50
+ const projectMemories = memoryManager.list('project');
51
+ const codeMemories = memoryManager.list('code');
52
+ const memories = [...projectMemories, ...codeMemories].slice(0, 5);
53
+ if (memories.length > 0) {
54
+ summary += `\nRecent Project Info:\n`;
55
+ memories.forEach(mem => {
56
+ const preview = mem.value.substring(0, 80);
57
+ summary += ` • ${mem.key}: ${preview}${mem.value.length > 80 ? '...' : ''}\n`;
58
+ });
59
+ }
60
+ }
61
+ // Load coding guides
62
+ if (shouldLoadGuides) {
63
+ const allGuides = await loadGuides();
64
+ const guides = allGuides
65
+ .sort((a, b) => new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime())
66
+ .slice(0, 3);
67
+ if (guides.length > 0) {
68
+ summary += `\nActive Coding Guides:\n`;
69
+ guides.forEach(guide => {
70
+ summary += ` • ${guide.name} (${guide.category}): ${guide.description}\n`;
71
+ });
72
+ }
73
+ }
74
+ // Restore context
75
+ if (restoreContext) {
76
+ const contextMemories = memoryManager.list('context').slice(0, 3);
77
+ if (contextMemories.length > 0) {
78
+ summary += `\nPrevious Context:\n`;
79
+ contextMemories.forEach(ctx => {
80
+ try {
81
+ const data = JSON.parse(ctx.value);
82
+ summary += ` • ${data.urgency?.toUpperCase() || 'MEDIUM'} priority from ${new Date(ctx.timestamp).toLocaleString()}\n`;
83
+ }
84
+ catch {
85
+ summary += ` • Context from ${new Date(ctx.timestamp).toLocaleString()}\n`;
86
+ }
87
+ });
88
+ }
89
+ }
90
+ summary += '\nReady to continue development! What would you like to work on?';
91
+ return {
92
+ content: [{ type: 'text', text: summary }]
93
+ };
94
+ }
95
+ catch (error) {
96
+ return {
97
+ content: [{ type: 'text', text: `${greeting ? greeting + '! ' : ''}Session started.\n\nReady to begin! What can I help you with?` }]
98
+ };
99
+ }
100
+ }
@@ -0,0 +1,46 @@
1
+ // Memory management tool - completely independent
2
+ import { MemoryManager } from '../../lib/MemoryManager.js';
3
+ export const updateMemoryDefinition = {
4
+ name: 'update_memory',
5
+ description: '수정해|업데이트|바꿔|update|change|modify|edit - Update existing memory',
6
+ inputSchema: {
7
+ type: 'object',
8
+ properties: {
9
+ key: { type: 'string', description: 'Memory key to update' },
10
+ value: { type: 'string', description: 'New value' },
11
+ append: { type: 'boolean', description: 'Append to existing value' }
12
+ },
13
+ required: ['key', 'value']
14
+ },
15
+ annotations: {
16
+ title: 'Update Memory',
17
+ audience: ['user', 'assistant']
18
+ }
19
+ };
20
+ export async function updateMemory(args) {
21
+ const { key: updateKey, value: updateValue, append = false } = args;
22
+ try {
23
+ const mm = MemoryManager.getInstance();
24
+ const existingMemory = mm.recall(updateKey);
25
+ if (existingMemory) {
26
+ const newValue = append ? existingMemory.value + ' ' + updateValue : updateValue;
27
+ mm.update(updateKey, newValue);
28
+ return {
29
+ content: [{
30
+ type: 'text',
31
+ text: `✓ ${append ? 'Appended to' : 'Updated'} memory: "${updateKey}"`
32
+ }]
33
+ };
34
+ }
35
+ else {
36
+ return {
37
+ content: [{ type: 'text', text: `✗ Memory not found: "${updateKey}". Use save_memory to create new memory.` }]
38
+ };
39
+ }
40
+ }
41
+ catch (error) {
42
+ return {
43
+ content: [{ type: 'text', text: `✗ Error: ${error instanceof Error ? error.message : 'Unknown error'}` }]
44
+ };
45
+ }
46
+ }
@@ -0,0 +1,166 @@
1
+ // Planning tool - completely independent
2
+ export const analyzeRequirementsDefinition = {
3
+ name: 'analyze_requirements',
4
+ description: '요구사항 분석|필요한 것들|requirements analysis|what we need|analyze requirements|필수 기능 - Analyze project requirements',
5
+ inputSchema: {
6
+ type: 'object',
7
+ properties: {
8
+ requirements: { type: 'string', description: 'List of requirements to analyze' },
9
+ stakeholders: { type: 'string', description: 'Project stakeholders (e.g., users, admins, developers)' },
10
+ constraints: { type: 'string', description: 'Project constraints (timeline, budget, technical)' },
11
+ analysisMethod: { type: 'string', description: 'Analysis method', enum: ['moscow', 'kano', 'value-effort'], default: 'moscow' }
12
+ },
13
+ required: ['requirements']
14
+ },
15
+ annotations: {
16
+ title: 'Analyze Requirements',
17
+ audience: ['user', 'assistant']
18
+ }
19
+ };
20
+ export async function analyzeRequirements(args) {
21
+ const { requirements, stakeholders = 'end users, product owner, development team', constraints = 'standard timeline and budget constraints', analysisMethod = 'moscow' } = args;
22
+ // Parse requirements
23
+ const requirementList = requirements.split(/[,\n]/).map(r => r.trim()).filter(r => r.length > 0);
24
+ const stakeholderList = stakeholders.split(',').map(s => s.trim());
25
+ const analyzedRequirements = requirementList.map((req, index) => {
26
+ const reqId = `REQ-${String(index + 1).padStart(3, '0')}`;
27
+ // Determine requirement type
28
+ let type = 'functional';
29
+ if (req.toLowerCase().includes('performance') || req.toLowerCase().includes('security') || req.toLowerCase().includes('scalability')) {
30
+ type = 'non-functional';
31
+ }
32
+ else if (req.toLowerCase().includes('business') || req.toLowerCase().includes('revenue') || req.toLowerCase().includes('cost')) {
33
+ type = 'business';
34
+ }
35
+ else if (req.toLowerCase().includes('infrastructure') || req.toLowerCase().includes('architecture') || req.toLowerCase().includes('database')) {
36
+ type = 'technical';
37
+ }
38
+ // Determine priority using MoSCoW
39
+ let priority = 'should-have';
40
+ if (req.toLowerCase().includes('critical') || req.toLowerCase().includes('essential') || req.toLowerCase().includes('required')) {
41
+ priority = 'must-have';
42
+ }
43
+ else if (req.toLowerCase().includes('important') || req.toLowerCase().includes('needed')) {
44
+ priority = 'should-have';
45
+ }
46
+ else if (req.toLowerCase().includes('nice') || req.toLowerCase().includes('optional') || req.toLowerCase().includes('enhancement')) {
47
+ priority = 'could-have';
48
+ }
49
+ else if (req.toLowerCase().includes('future') || req.toLowerCase().includes('later') || req.toLowerCase().includes('v2')) {
50
+ priority = 'wont-have';
51
+ }
52
+ // Assess complexity
53
+ let complexity = 'medium';
54
+ if (req.length > 100 || req.toLowerCase().includes('complex') || req.toLowerCase().includes('integration') || req.toLowerCase().includes('advanced')) {
55
+ complexity = 'high';
56
+ }
57
+ else if (req.length < 50 || req.toLowerCase().includes('simple') || req.toLowerCase().includes('basic')) {
58
+ complexity = 'low';
59
+ }
60
+ // Assess risk
61
+ let risk = 'low';
62
+ if (req.toLowerCase().includes('external') || req.toLowerCase().includes('third-party') || req.toLowerCase().includes('new technology')) {
63
+ risk = 'high';
64
+ }
65
+ else if (req.toLowerCase().includes('integration') || req.toLowerCase().includes('performance') || complexity === 'high') {
66
+ risk = 'medium';
67
+ }
68
+ // Estimate effort
69
+ let estimatedEffort = '3-5 days';
70
+ if (complexity === 'high') {
71
+ estimatedEffort = '1-3 weeks';
72
+ }
73
+ else if (complexity === 'low') {
74
+ estimatedEffort = '1-2 days';
75
+ }
76
+ // Determine relevant stakeholders
77
+ const relevantStakeholders = stakeholderList.filter(stakeholder => {
78
+ if (type === 'business' && stakeholder.toLowerCase().includes('owner'))
79
+ return true;
80
+ if (type === 'technical' && stakeholder.toLowerCase().includes('developer'))
81
+ return true;
82
+ if (type === 'functional' && stakeholder.toLowerCase().includes('user'))
83
+ return true;
84
+ return true; // Include all by default
85
+ });
86
+ return {
87
+ id: reqId,
88
+ title: req.length > 50 ? req.substring(0, 47) + '...' : req,
89
+ description: req,
90
+ type,
91
+ priority,
92
+ complexity,
93
+ risk,
94
+ dependencies: [],
95
+ estimatedEffort,
96
+ stakeholders: relevantStakeholders
97
+ };
98
+ });
99
+ const analysis = {
100
+ action: 'analyze_requirements',
101
+ method: analysisMethod,
102
+ totalRequirements: analyzedRequirements.length,
103
+ requirements: analyzedRequirements,
104
+ priorityBreakdown: {
105
+ mustHave: analyzedRequirements.filter(r => r.priority === 'must-have').length,
106
+ shouldHave: analyzedRequirements.filter(r => r.priority === 'should-have').length,
107
+ couldHave: analyzedRequirements.filter(r => r.priority === 'could-have').length,
108
+ wontHave: analyzedRequirements.filter(r => r.priority === 'wont-have').length
109
+ },
110
+ typeBreakdown: {
111
+ functional: analyzedRequirements.filter(r => r.type === 'functional').length,
112
+ nonFunctional: analyzedRequirements.filter(r => r.type === 'non-functional').length,
113
+ business: analyzedRequirements.filter(r => r.type === 'business').length,
114
+ technical: analyzedRequirements.filter(r => r.type === 'technical').length
115
+ },
116
+ riskAssessment: {
117
+ high: analyzedRequirements.filter(r => r.risk === 'high').length,
118
+ medium: analyzedRequirements.filter(r => r.risk === 'medium').length,
119
+ low: analyzedRequirements.filter(r => r.risk === 'low').length
120
+ },
121
+ recommendations: [
122
+ 'Focus on Must-Have requirements for MVP',
123
+ 'Validate high-risk requirements early',
124
+ 'Consider Should-Have items for post-MVP releases',
125
+ 'Review Could-Have items based on resource availability',
126
+ 'Plan technical requirements to support functional ones'
127
+ ],
128
+ constraints: constraints,
129
+ status: 'success'
130
+ };
131
+ // Format output
132
+ let formattedOutput = `# Requirements Analysis\n\n`;
133
+ formattedOutput += `**Analysis Method:** ${analysisMethod.toUpperCase()} \n`;
134
+ formattedOutput += `**Total Requirements:** ${analysis.totalRequirements} \n`;
135
+ formattedOutput += `**Constraints:** ${constraints}\n\n`;
136
+ formattedOutput += `## Priority Breakdown (MoSCoW)\n`;
137
+ formattedOutput += `- **Must Have:** ${analysis.priorityBreakdown.mustHave}\n`;
138
+ formattedOutput += `- **Should Have:** ${analysis.priorityBreakdown.shouldHave}\n`;
139
+ formattedOutput += `- **Could Have:** ${analysis.priorityBreakdown.couldHave}\n`;
140
+ formattedOutput += `- **Won't Have:** ${analysis.priorityBreakdown.wontHave}\n\n`;
141
+ formattedOutput += `## Risk Assessment\n`;
142
+ formattedOutput += `- **High Risk:** ${analysis.riskAssessment.high} requirements\n`;
143
+ formattedOutput += `- **Medium Risk:** ${analysis.riskAssessment.medium} requirements\n`;
144
+ formattedOutput += `- **Low Risk:** ${analysis.riskAssessment.low} requirements\n\n`;
145
+ formattedOutput += `## Detailed Requirements\n\n`;
146
+ // Group by priority
147
+ const priorities = ['must-have', 'should-have', 'could-have', 'wont-have'];
148
+ priorities.forEach(priority => {
149
+ const reqsForPriority = analyzedRequirements.filter(r => r.priority === priority);
150
+ if (reqsForPriority.length > 0) {
151
+ formattedOutput += `### ${priority.toUpperCase().replace('-', ' ')} (${reqsForPriority.length})\n\n`;
152
+ reqsForPriority.forEach(req => {
153
+ formattedOutput += `**${req.id}:** ${req.title} \n`;
154
+ formattedOutput += `*Type:* ${req.type} | *Complexity:* ${req.complexity} | *Risk:* ${req.risk} | *Effort:* ${req.estimatedEffort} \n`;
155
+ formattedOutput += `*Stakeholders:* ${req.stakeholders.join(', ')}\n\n`;
156
+ });
157
+ }
158
+ });
159
+ formattedOutput += `## Recommendations\n`;
160
+ analysis.recommendations.forEach(rec => {
161
+ formattedOutput += `- ${rec}\n`;
162
+ });
163
+ return {
164
+ content: [{ type: 'text', text: formattedOutput }]
165
+ };
166
+ }
@@ -0,0 +1,119 @@
1
+ // Planning tool - completely independent
2
+ export const createUserStoriesDefinition = {
3
+ name: 'create_user_stories',
4
+ description: '스토리|사용자 스토리|user story|user stories|as a user - Generate user stories from requirements',
5
+ inputSchema: {
6
+ type: 'object',
7
+ properties: {
8
+ features: { type: 'string', description: 'List of features or requirements to convert to user stories' },
9
+ userTypes: { type: 'string', description: 'Types of users (e.g., admin, customer, guest)' },
10
+ priority: { type: 'string', description: 'Default priority level', enum: ['high', 'medium', 'low'] },
11
+ includeAcceptanceCriteria: { type: 'boolean', description: 'Include acceptance criteria for each story' }
12
+ },
13
+ required: ['features']
14
+ },
15
+ annotations: {
16
+ title: 'Create User Stories',
17
+ audience: ['user', 'assistant']
18
+ }
19
+ };
20
+ export async function createUserStories(args) {
21
+ const { features, userTypes = 'user, admin, guest', priority = 'medium', includeAcceptanceCriteria = true } = args;
22
+ // Parse features into individual items
23
+ const featureList = features.split(/[,\n]/).map(f => f.trim()).filter(f => f.length > 0);
24
+ const userTypeList = userTypes.split(',').map(u => u.trim());
25
+ const userStories = featureList.map((feature, index) => {
26
+ const storyId = `US-${String(index + 1).padStart(3, '0')}`;
27
+ // Determine user type based on feature content
28
+ let selectedUserType = userTypeList[0];
29
+ if (feature.toLowerCase().includes('admin') || feature.toLowerCase().includes('manage')) {
30
+ selectedUserType = userTypeList.find(u => u.toLowerCase().includes('admin')) || selectedUserType;
31
+ }
32
+ else if (feature.toLowerCase().includes('guest') || feature.toLowerCase().includes('browse')) {
33
+ selectedUserType = userTypeList.find(u => u.toLowerCase().includes('guest')) || selectedUserType;
34
+ }
35
+ // Extract functionality and benefit
36
+ const functionality = feature;
37
+ let benefit = 'to achieve my goals efficiently';
38
+ // Try to infer benefit from common patterns
39
+ if (feature.toLowerCase().includes('search'))
40
+ benefit = 'to find relevant information quickly';
41
+ else if (feature.toLowerCase().includes('save') || feature.toLowerCase().includes('store'))
42
+ benefit = 'to preserve my data for future use';
43
+ else if (feature.toLowerCase().includes('share'))
44
+ benefit = 'to collaborate with others effectively';
45
+ else if (feature.toLowerCase().includes('track') || feature.toLowerCase().includes('monitor'))
46
+ benefit = 'to stay informed about important changes';
47
+ else if (feature.toLowerCase().includes('customize') || feature.toLowerCase().includes('configure'))
48
+ benefit = 'to tailor the experience to my needs';
49
+ // Generate acceptance criteria
50
+ const acceptanceCriteria = includeAcceptanceCriteria ? [
51
+ `Given I am a ${selectedUserType}, when I access the ${functionality.toLowerCase()} feature, then it should be available and functional`,
52
+ `When I use the ${functionality.toLowerCase()} feature, then it should provide clear feedback about the action`,
53
+ `The ${functionality.toLowerCase()} feature should handle errors gracefully and provide helpful messages`,
54
+ `The feature should be accessible and usable across different devices and browsers`
55
+ ] : [];
56
+ // Determine priority based on feature content
57
+ let storyPriority = priority;
58
+ if (feature.toLowerCase().includes('critical') || feature.toLowerCase().includes('security') || feature.toLowerCase().includes('login')) {
59
+ storyPriority = 'high';
60
+ }
61
+ else if (feature.toLowerCase().includes('nice to have') || feature.toLowerCase().includes('optional')) {
62
+ storyPriority = 'low';
63
+ }
64
+ // Estimate effort based on complexity
65
+ let estimatedEffort = '3-5 days';
66
+ if (feature.length > 100 || feature.toLowerCase().includes('complex') || feature.toLowerCase().includes('integration')) {
67
+ estimatedEffort = '1-2 weeks';
68
+ }
69
+ else if (feature.length < 30 || feature.toLowerCase().includes('simple') || feature.toLowerCase().includes('basic')) {
70
+ estimatedEffort = '1-2 days';
71
+ }
72
+ return {
73
+ id: storyId,
74
+ title: `${selectedUserType} - ${functionality}`,
75
+ story: `As a ${selectedUserType}, I want to ${functionality.toLowerCase()}, so that ${benefit}.`,
76
+ userType: selectedUserType,
77
+ functionality,
78
+ benefit,
79
+ acceptanceCriteria,
80
+ priority: storyPriority,
81
+ estimatedEffort,
82
+ dependencies: []
83
+ };
84
+ });
85
+ const result = {
86
+ action: 'create_user_stories',
87
+ totalStories: userStories.length,
88
+ userTypes: userTypeList,
89
+ stories: userStories,
90
+ summary: {
91
+ high: userStories.filter(s => s.priority === 'high').length,
92
+ medium: userStories.filter(s => s.priority === 'medium').length,
93
+ low: userStories.filter(s => s.priority === 'low').length,
94
+ estimatedTotalEffort: `${userStories.length * 3}-${userStories.length * 7} days`
95
+ },
96
+ status: 'success'
97
+ };
98
+ // Format output
99
+ let formattedOutput = `# User Stories\n\n**Total Stories:** ${result.totalStories} \n**Priority Breakdown:** ${result.summary.high} High, ${result.summary.medium} Medium, ${result.summary.low} Low \n**Estimated Effort:** ${result.summary.estimatedTotalEffort}\n\n`;
100
+ userStories.forEach((story, index) => {
101
+ formattedOutput += `## ${story.id}: ${story.title}\n\n`;
102
+ formattedOutput += `**Story:** ${story.story}\n\n`;
103
+ formattedOutput += `**Priority:** ${story.priority.toUpperCase()} \n`;
104
+ formattedOutput += `**Estimated Effort:** ${story.estimatedEffort}\n\n`;
105
+ if (story.acceptanceCriteria.length > 0) {
106
+ formattedOutput += `**Acceptance Criteria:**\n`;
107
+ story.acceptanceCriteria.forEach((criteria, i) => {
108
+ formattedOutput += `${i + 1}. ${criteria}\n`;
109
+ });
110
+ formattedOutput += '\n';
111
+ }
112
+ if (index < userStories.length - 1) {
113
+ formattedOutput += '---\n\n';
114
+ }
115
+ });
116
+ return {
117
+ content: [{ type: 'text', text: formattedOutput }]
118
+ };
119
+ }