@su-record/vibe 0.1.3 → 0.1.7

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 (73) hide show
  1. package/.claude/commands/vibe.analyze.md +123 -0
  2. package/.claude/commands/vibe.diagram.md +174 -0
  3. package/.claude/commands/vibe.plan.md +75 -0
  4. package/.claude/commands/vibe.run.md +151 -0
  5. package/.claude/commands/vibe.spec.md +273 -0
  6. package/.claude/commands/vibe.tasks.md +77 -0
  7. package/.claude/commands/vibe.ui.md +133 -0
  8. package/.claude/commands/vibe.verify.md +128 -0
  9. package/.claude/settings.local.json +14 -0
  10. package/README.md +170 -108
  11. package/bin/vibe +113 -226
  12. package/package.json +7 -7
  13. package/scripts/install-mcp.js +16 -6
  14. package/skills/quality/bdd-contract-testing.md +388 -0
  15. package/templates/contract-backend-template.md +517 -0
  16. package/templates/contract-frontend-template.md +594 -0
  17. package/templates/feature-template.md +259 -0
  18. package/templates/spec-template.md +60 -3
  19. package/mcp/dist/__tests__/complexity.test.js +0 -126
  20. package/mcp/dist/__tests__/memory.test.js +0 -120
  21. package/mcp/dist/__tests__/python-dart-complexity.test.js +0 -146
  22. package/mcp/dist/index.js +0 -230
  23. package/mcp/dist/lib/ContextCompressor.js +0 -305
  24. package/mcp/dist/lib/MemoryManager.js +0 -334
  25. package/mcp/dist/lib/ProjectCache.js +0 -126
  26. package/mcp/dist/lib/PythonParser.js +0 -241
  27. package/mcp/dist/tools/browser/browserPool.js +0 -76
  28. package/mcp/dist/tools/browser/browserUtils.js +0 -135
  29. package/mcp/dist/tools/browser/inspectNetworkRequests.js +0 -140
  30. package/mcp/dist/tools/browser/monitorConsoleLogs.js +0 -97
  31. package/mcp/dist/tools/convention/analyzeComplexity.js +0 -248
  32. package/mcp/dist/tools/convention/applyQualityRules.js +0 -102
  33. package/mcp/dist/tools/convention/checkCouplingCohesion.js +0 -233
  34. package/mcp/dist/tools/convention/complexityMetrics.js +0 -133
  35. package/mcp/dist/tools/convention/dartComplexity.js +0 -117
  36. package/mcp/dist/tools/convention/getCodingGuide.js +0 -64
  37. package/mcp/dist/tools/convention/languageDetector.js +0 -50
  38. package/mcp/dist/tools/convention/pythonComplexity.js +0 -109
  39. package/mcp/dist/tools/convention/suggestImprovements.js +0 -257
  40. package/mcp/dist/tools/convention/validateCodeQuality.js +0 -177
  41. package/mcp/dist/tools/memory/autoSaveContext.js +0 -79
  42. package/mcp/dist/tools/memory/database.js +0 -123
  43. package/mcp/dist/tools/memory/deleteMemory.js +0 -39
  44. package/mcp/dist/tools/memory/listMemories.js +0 -38
  45. package/mcp/dist/tools/memory/memoryConfig.js +0 -27
  46. package/mcp/dist/tools/memory/memorySQLite.js +0 -138
  47. package/mcp/dist/tools/memory/memoryUtils.js +0 -34
  48. package/mcp/dist/tools/memory/migrate.js +0 -113
  49. package/mcp/dist/tools/memory/prioritizeMemory.js +0 -109
  50. package/mcp/dist/tools/memory/recallMemory.js +0 -40
  51. package/mcp/dist/tools/memory/restoreSessionContext.js +0 -69
  52. package/mcp/dist/tools/memory/saveMemory.js +0 -34
  53. package/mcp/dist/tools/memory/searchMemories.js +0 -37
  54. package/mcp/dist/tools/memory/startSession.js +0 -100
  55. package/mcp/dist/tools/memory/updateMemory.js +0 -46
  56. package/mcp/dist/tools/planning/analyzeRequirements.js +0 -166
  57. package/mcp/dist/tools/planning/createUserStories.js +0 -119
  58. package/mcp/dist/tools/planning/featureRoadmap.js +0 -202
  59. package/mcp/dist/tools/planning/generatePrd.js +0 -156
  60. package/mcp/dist/tools/prompt/analyzePrompt.js +0 -145
  61. package/mcp/dist/tools/prompt/enhancePrompt.js +0 -105
  62. package/mcp/dist/tools/semantic/findReferences.js +0 -195
  63. package/mcp/dist/tools/semantic/findSymbol.js +0 -200
  64. package/mcp/dist/tools/thinking/analyzeProblem.js +0 -50
  65. package/mcp/dist/tools/thinking/breakDownProblem.js +0 -140
  66. package/mcp/dist/tools/thinking/createThinkingChain.js +0 -39
  67. package/mcp/dist/tools/thinking/formatAsPlan.js +0 -73
  68. package/mcp/dist/tools/thinking/stepByStepAnalysis.js +0 -58
  69. package/mcp/dist/tools/thinking/thinkAloudProcess.js +0 -75
  70. package/mcp/dist/tools/time/getCurrentTime.js +0 -61
  71. package/mcp/dist/tools/ui/previewUiAscii.js +0 -232
  72. package/mcp/dist/types/tool.js +0 -2
  73. package/mcp/package.json +0 -53
@@ -0,0 +1,259 @@
1
+ # Feature: {기능명}
2
+
3
+ **Generated from**: `specs/{기능명}.md`
4
+ **Language**: {ko | en}
5
+ **Priority**: {HIGH | MEDIUM | LOW}
6
+
7
+ ---
8
+
9
+ ## Feature Description
10
+
11
+ **As a** {사용자 역할}
12
+ **I want** {원하는 기능}
13
+ **So that** {이유/가치}
14
+
15
+ ---
16
+
17
+ ## Background (Optional)
18
+
19
+ ```gherkin
20
+ Background:
21
+ Given {공통 전제 조건 1}
22
+ And {공통 전제 조건 2}
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Scenarios
28
+
29
+ ### Scenario 1: {시나리오 제목}
30
+
31
+ **Mapped to**: REQ-001 in SPEC
32
+
33
+ ```gherkin
34
+ Scenario: {시나리오 제목}
35
+ Given {전제 조건}
36
+ And {추가 전제 조건}
37
+ When {사용자 행동}
38
+ And {추가 행동}
39
+ Then {예상 결과}
40
+ And {추가 검증}
41
+ ```
42
+
43
+ **Acceptance Criteria**:
44
+ - [ ] {SPEC의 Acceptance Criteria 1}
45
+ - [ ] {SPEC의 Acceptance Criteria 2}
46
+
47
+ **Test Data**:
48
+ ```json
49
+ {
50
+ "input": {...},
51
+ "expected_output": {...}
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ### Scenario 2: {에러 케이스 제목}
58
+
59
+ ```gherkin
60
+ Scenario: {에러 케이스 제목}
61
+ Given {전제 조건}
62
+ When {잘못된 입력}
63
+ Then {에러 응답}
64
+ And {에러 메시지 검증}
65
+ ```
66
+
67
+ ---
68
+
69
+ ### Scenario Outline: {파라미터화된 시나리오}
70
+
71
+ ```gherkin
72
+ Scenario Outline: {시나리오 제목}
73
+ Given {전제 조건}
74
+ When I {행동} with "<parameter>"
75
+ Then I should see "<result>"
76
+
77
+ Examples:
78
+ | parameter | result |
79
+ | value1 | result1 |
80
+ | value2 | result2 |
81
+ | value3 | result3 |
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Implementation Guide
87
+
88
+ ### Backend Tests (Python + Pytest-BDD)
89
+
90
+ **File**: `tests/features/{기능명}.feature`
91
+
92
+ ```python
93
+ # tests/step_defs/test_{기능명}.py
94
+ import pytest
95
+ from pytest_bdd import scenarios, given, when, then, parsers
96
+
97
+ # Load scenarios
98
+ scenarios('features/{기능명}.feature')
99
+
100
+ @given(parsers.parse('사용자가 {role}로 로그인되어 있다'))
101
+ def user_logged_in(context, role):
102
+ context.user = create_user(role)
103
+ context.token = authenticate(context.user)
104
+
105
+ @when(parsers.parse('{action}을 실행한다'))
106
+ def execute_action(context, action):
107
+ context.response = api_call(action, context.token)
108
+
109
+ @then(parsers.parse('응답 코드는 {status_code:d}이어야 한다'))
110
+ def check_status_code(context, status_code):
111
+ assert context.response.status_code == status_code
112
+ ```
113
+
114
+ **Run**:
115
+ ```bash
116
+ pytest tests/features/{기능명}.feature --verbose
117
+ ```
118
+
119
+ ---
120
+
121
+ ### Frontend Tests (Flutter + Gherkin)
122
+
123
+ **File**: `integration_test/features/{기능명}.feature`
124
+
125
+ ```dart
126
+ // integration_test/step_definitions/{기능명}_test.dart
127
+ import 'package:flutter_gherkin/flutter_gherkin.dart';
128
+
129
+ class UserLoggedInStep extends Given1WithWorld<String, FlutterWorld> {
130
+ @override
131
+ Future<void> executeStep(String role) async {
132
+ await world.appDriver.waitForAppToSettle();
133
+ // Login logic
134
+ }
135
+
136
+ @override
137
+ RegExp get pattern => RegExp(r'사용자가 {string}로 로그인되어 있다');
138
+ }
139
+ ```
140
+
141
+ **Run**:
142
+ ```bash
143
+ flutter test integration_test/{기능명}_test.dart
144
+ ```
145
+
146
+ ---
147
+
148
+ ### Frontend Tests (React + Cucumber)
149
+
150
+ **File**: `tests/features/{기능명}.feature`
151
+
152
+ ```javascript
153
+ // tests/step_definitions/{기능명}.steps.js
154
+ const { Given, When, Then } = require('@cucumber/cucumber');
155
+ const { render, screen, fireEvent } = require('@testing-library/react');
156
+
157
+ Given('사용자가 {string}로 로그인되어 있다', async function (role) {
158
+ this.user = await createUser(role);
159
+ this.token = await authenticate(this.user);
160
+ });
161
+
162
+ When('{string}을 실행한다', async function (action) {
163
+ this.response = await apiCall(action, this.token);
164
+ });
165
+
166
+ Then('응답 코드는 {int}이어야 한다', function (statusCode) {
167
+ expect(this.response.status).toBe(statusCode);
168
+ });
169
+ ```
170
+
171
+ **Run**:
172
+ ```bash
173
+ npm test -- --features tests/features/{기능명}.feature
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Tags
179
+
180
+ ```gherkin
181
+ @priority-high
182
+ @smoke
183
+ @regression
184
+ @backend
185
+ @frontend
186
+ ```
187
+
188
+ **Run by tag**:
189
+ ```bash
190
+ # Python
191
+ pytest -m "priority-high"
192
+
193
+ # JavaScript
194
+ npm test -- --tags "@smoke"
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Coverage Mapping
200
+
201
+ | Scenario | SPEC REQ | Acceptance Criteria | Status |
202
+ |----------|----------|---------------------|--------|
203
+ | Scenario 1 | REQ-001 | AC-1, AC-2, AC-3 | ⬜ |
204
+ | Scenario 2 | REQ-002 | AC-4, AC-5 | ⬜ |
205
+ | Scenario 3 | REQ-003 | AC-6, AC-7 | ⬜ |
206
+
207
+ **Coverage**: 0 / {총 시나리오 수} (0%)
208
+
209
+ ---
210
+
211
+ ## Test Execution Report
212
+
213
+ **Last Run**: {날짜 시간}
214
+ **Environment**: {dev | staging | production}
215
+
216
+ | Scenario | Status | Duration | Error |
217
+ |----------|--------|----------|-------|
218
+ | Scenario 1 | ⬜ PENDING | - | - |
219
+ | Scenario 2 | ⬜ PENDING | - | - |
220
+
221
+ **Total**: 0 passed, 0 failed, {총 수} pending
222
+
223
+ ---
224
+
225
+ ## Next Steps
226
+
227
+ 1. **구현 전 테스트 작성** (Test-First):
228
+ ```bash
229
+ # Create feature file first
230
+ vibe feature "{기능명}"
231
+
232
+ # Then implement
233
+ vibe run "Task 1-1"
234
+ ```
235
+
236
+ 2. **구현 중 테스트 실행**:
237
+ ```bash
238
+ vibe test "{기능명}" --watch
239
+ ```
240
+
241
+ 3. **완료 후 검증**:
242
+ ```bash
243
+ vibe verify "{기능명}"
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Notes
249
+
250
+ - ✅ **Given**: 테스트 전제 조건 (상태 설정)
251
+ - ✅ **When**: 사용자 행동 (액션 실행)
252
+ - ✅ **Then**: 예상 결과 (검증)
253
+ - ✅ **And/But**: 추가 조건/검증
254
+
255
+ **Best Practices**:
256
+ - 시나리오는 비즈니스 언어로 작성
257
+ - 구현 세부사항은 Step Definitions에
258
+ - 각 시나리오는 독립적으로 실행 가능해야 함
259
+ - Background는 중복 제거용으로만 사용
@@ -117,26 +117,83 @@ Response: {...}
117
117
 
118
118
  ---
119
119
 
120
- ## 7. Out of Scope
120
+ ## 7. 테스트 전략
121
+
122
+ ### BDD 시나리오 (Gherkin)
123
+
124
+ **생성 명령어**: `vibe feature "{기능명}"`
125
+
126
+ ```gherkin
127
+ Scenario: {시나리오 제목}
128
+ Given {전제 조건}
129
+ When {사용자 행동}
130
+ Then {예상 결과}
131
+ ```
132
+
133
+ **매핑**:
134
+ - REQ-001 → Scenario 1, 2
135
+ - REQ-002 → Scenario 3
136
+
137
+ ### Contract Tests (API 스키마)
138
+
139
+ **생성 명령어**: `vibe contract "{기능명}"`
140
+
141
+ **Backend Contract**:
142
+ ```json
143
+ {
144
+ "request": {
145
+ "method": "POST",
146
+ "path": "/api/v1/{resource}",
147
+ "schema": {JSON Schema}
148
+ },
149
+ "response": {
150
+ "status": 201,
151
+ "schema": {JSON Schema}
152
+ }
153
+ }
154
+ ```
155
+
156
+ **Frontend Contract**:
157
+ - Mock 서버로 독립 테스트
158
+ - 응답 스키마 검증 (Zod, JSON Schema)
159
+
160
+ ### 테스트 커버리지 목표
161
+
162
+ - [ ] BDD: 모든 Acceptance Criteria 커버
163
+ - [ ] Contract: 모든 API 엔드포인트 커버
164
+ - [ ] Unit: 70%+ 커버리지
165
+ - [ ] Integration: 핵심 경로 커버
166
+
167
+ ---
168
+
169
+ ## 8. Out of Scope
121
170
 
122
171
  - ❌ {제외 항목 1}
123
172
  - ❌ {제외 항목 2}
124
173
 
125
174
  ---
126
175
 
127
- ## 8. 검증 체크리스트
176
+ ## 9. 검증 체크리스트
128
177
 
178
+ ### 요구사항
129
179
  - [ ] 모든 요구사항이 테스트 가능한가?
130
180
  - [ ] SHALL/SHOULD/MAY가 명확한가?
131
181
  - [ ] Acceptance Criteria가 구체적인가?
132
182
  - [ ] 성능 목표가 측정 가능한가?
133
183
 
184
+ ### 테스팅
185
+ - [ ] BDD Feature 파일 생성 완료?
186
+ - [ ] Contract 테스트 정의 완료?
187
+ - [ ] Step Definitions 작성 완료?
188
+ - [ ] 테스트 커버리지 목표 달성?
189
+
134
190
  ---
135
191
 
136
- ## 9. 승인
192
+ ## 10. 승인
137
193
 
138
194
  - [ ] 사용자 승인
139
195
  - [ ] 기술 리뷰 완료
196
+ - [ ] 테스트 계획 승인
140
197
 
141
198
  승인일: ____________
142
199
  승인자: ____________
@@ -1,126 +0,0 @@
1
- import { describe, test, expect } from 'vitest';
2
- import { analyzeComplexity, analyzeComplexityDefinition } from '../tools/convention/analyzeComplexity.js';
3
- describe('Code Complexity Analysis', () => {
4
- describe('analyzeComplexity', () => {
5
- test('should analyze simple function with low complexity', async () => {
6
- const simpleCode = `
7
- function add(a, b) {
8
- return a + b;
9
- }
10
- `;
11
- const result = await analyzeComplexity({ code: simpleCode, metrics: 'all' });
12
- const parsed = JSON.parse(result.content[0].text.replace('Complexity Analysis:\n', ''));
13
- expect(parsed.status).toBe('success');
14
- expect(parsed.results.cyclomaticComplexity).toBeDefined();
15
- expect(parsed.results.cognitiveComplexity).toBeDefined();
16
- expect(parsed.results.halsteadMetrics).toBeDefined();
17
- expect(parsed.results.cyclomaticComplexity.status).toBe('pass');
18
- });
19
- test('should detect high cyclomatic complexity', async () => {
20
- const complexCode = `
21
- function complexFunction(x) {
22
- if (x > 0) {
23
- if (x < 10) {
24
- for (let i = 0; i < x; i++) {
25
- if (i % 2 === 0) {
26
- while (i < 5) {
27
- if (i === 3) {
28
- return i;
29
- }
30
- i++;
31
- }
32
- }
33
- }
34
- }
35
- }
36
- return x;
37
- }
38
- `;
39
- const result = await analyzeComplexity({ code: complexCode, metrics: 'all' });
40
- const parsed = JSON.parse(result.content[0].text.replace('Complexity Analysis:\n', ''));
41
- expect(parsed.results.cyclomaticComplexity.value).toBeGreaterThan(5);
42
- expect(parsed.issues.length).toBeGreaterThan(0);
43
- });
44
- test('should calculate AST-based complexity', async () => {
45
- const code = `
46
- function test() {
47
- if (true) return 1;
48
- for (let i = 0; i < 10; i++) {
49
- console.log(i);
50
- }
51
- }
52
- `;
53
- const result = await analyzeComplexity({ code, metrics: 'cyclomatic' });
54
- const parsed = JSON.parse(result.content[0].text.replace('Complexity Analysis:\n', ''));
55
- expect(parsed.results.astCyclomaticComplexity).toBeDefined();
56
- expect(parsed.results.astCyclomaticComplexity.value).toBeGreaterThan(1);
57
- });
58
- test('should calculate cognitive complexity with nesting', async () => {
59
- const code = `
60
- function nested() {
61
- if (a) {
62
- if (b) {
63
- if (c) {
64
- return true;
65
- }
66
- }
67
- }
68
- }
69
- `;
70
- const result = await analyzeComplexity({ code, metrics: 'cognitive' });
71
- const parsed = JSON.parse(result.content[0].text.replace('Complexity Analysis:\n', ''));
72
- expect(parsed.results.cognitiveComplexity.value).toBeGreaterThan(0);
73
- });
74
- test('should calculate Halstead metrics', async () => {
75
- const code = `
76
- function calculate(x, y) {
77
- const sum = x + y;
78
- const product = x * y;
79
- return sum + product;
80
- }
81
- `;
82
- const result = await analyzeComplexity({ code, metrics: 'halstead' });
83
- const parsed = JSON.parse(result.content[0].text.replace('Complexity Analysis:\n', ''));
84
- expect(parsed.results.halsteadMetrics).toBeDefined();
85
- expect(parsed.results.halsteadMetrics.vocabulary).toBeGreaterThan(0);
86
- expect(parsed.results.halsteadMetrics.difficulty).toBeGreaterThan(0);
87
- });
88
- test('should provide recommendations for complex code', async () => {
89
- const veryComplexCode = `
90
- function veryComplex(a, b, c, d, e) {
91
- if (a) {
92
- if (b) {
93
- for (let i = 0; i < 10; i++) {
94
- if (c) {
95
- while (d) {
96
- if (e) {
97
- return true;
98
- }
99
- }
100
- }
101
- }
102
- }
103
- }
104
- return false;
105
- }
106
- `;
107
- const result = await analyzeComplexity({ code: veryComplexCode, metrics: 'all' });
108
- const parsed = JSON.parse(result.content[0].text.replace('Complexity Analysis:\n', ''));
109
- expect(parsed.recommendations).toBeDefined();
110
- expect(parsed.recommendations.length).toBeGreaterThan(0);
111
- expect(parsed.overallScore).toBeLessThan(100);
112
- });
113
- });
114
- describe('Tool Definition', () => {
115
- test('should have correct definition', () => {
116
- expect(analyzeComplexityDefinition.name).toBe('analyze_complexity');
117
- expect(analyzeComplexityDefinition.description).toContain('IMPORTANT');
118
- expect(analyzeComplexityDefinition.inputSchema.required).toContain('code');
119
- });
120
- test('should include keyword triggers', () => {
121
- const desc = analyzeComplexityDefinition.description;
122
- expect(desc).toContain('복잡도');
123
- expect(desc).toContain('complexity');
124
- });
125
- });
126
- });
@@ -1,120 +0,0 @@
1
- import { describe, test, expect, beforeEach, afterEach } from 'vitest';
2
- import { saveMemory, saveMemoryDefinition } from '../tools/memory/saveMemory.js';
3
- import { recallMemory } from '../tools/memory/recallMemory.js';
4
- import { listMemories } from '../tools/memory/listMemories.js';
5
- import { deleteMemory } from '../tools/memory/deleteMemory.js';
6
- import { memoryDB } from '../tools/memory/database.js';
7
- import { clearAllMemories } from '../tools/memory/memorySQLite.js';
8
- import { promises as fs } from 'fs';
9
- import path from 'path';
10
- const TEST_MEMORY_DIR = path.join(process.cwd(), 'memories');
11
- describe('Memory Management Tools', () => {
12
- beforeEach(async () => {
13
- // Ensure fresh database for each test
14
- try {
15
- // Close existing connection if any
16
- memoryDB.close();
17
- }
18
- catch (error) {
19
- // Ignore
20
- }
21
- // Clean up test files
22
- try {
23
- await fs.rm(TEST_MEMORY_DIR, { recursive: true, force: true });
24
- }
25
- catch (error) {
26
- // Ignore
27
- }
28
- // Clear all memories (this will recreate DB if needed)
29
- try {
30
- clearAllMemories();
31
- }
32
- catch (error) {
33
- // Database might not exist yet, will be created on first use
34
- }
35
- });
36
- afterEach(async () => {
37
- // Close database connection
38
- try {
39
- memoryDB.close();
40
- }
41
- catch (error) {
42
- // Ignore
43
- }
44
- });
45
- describe('saveMemory', () => {
46
- test('should save memory successfully', async () => {
47
- const result = await saveMemory({
48
- key: 'test-key',
49
- value: 'test-value',
50
- category: 'project'
51
- });
52
- expect(result.content[0].text).toContain('success');
53
- expect(result.content[0].text).toContain('test-key');
54
- });
55
- test('should create memory database if not exists', async () => {
56
- await saveMemory({ key: 'test-key', value: 'test-value' });
57
- // Check if database file exists
58
- const dbPath = path.join(TEST_MEMORY_DIR, 'memories.db');
59
- const dbExists = await fs.access(dbPath).then(() => true).catch(() => false);
60
- expect(dbExists).toBe(true);
61
- });
62
- });
63
- describe('recallMemory', () => {
64
- test('should recall saved memory', async () => {
65
- await saveMemory({ key: 'recall-test', value: 'recall-value' });
66
- const result = await recallMemory({ key: 'recall-test' });
67
- const parsedResult = JSON.parse(result.content[0].text.replace('Memory recalled:\n', ''));
68
- expect(parsedResult.value).toBe('recall-value');
69
- expect(parsedResult.key).toBe('recall-test');
70
- });
71
- test('should return not found for non-existent key', async () => {
72
- const result = await recallMemory({ key: 'non-existent' });
73
- expect(result.content[0].text).toContain('not found');
74
- });
75
- });
76
- describe('listMemories', () => {
77
- test('should list all memories', async () => {
78
- await saveMemory({ key: 'key1', value: 'value1', category: 'project' });
79
- await saveMemory({ key: 'key2', value: 'value2', category: 'code' });
80
- const result = await listMemories({ summary: false });
81
- const parsed = JSON.parse(result.content[0].text.replace('Memory list:\n', ''));
82
- expect(parsed.memories.length).toBe(2);
83
- expect(parsed.total).toBe(2);
84
- });
85
- test('should filter memories by category', async () => {
86
- await saveMemory({ key: 'project1', value: 'val1', category: 'project' });
87
- await saveMemory({ key: 'code1', value: 'val2', category: 'code' });
88
- const result = await listMemories({ category: 'project', summary: false });
89
- const parsed = JSON.parse(result.content[0].text.replace('Memory list:\n', ''));
90
- expect(parsed.total).toBe(1);
91
- expect(parsed.memories[0].key).toBe('project1');
92
- });
93
- test('should return empty array when no memories exist', async () => {
94
- const result = await listMemories({ summary: false });
95
- const parsed = JSON.parse(result.content[0].text.replace('Memory list:\n', ''));
96
- expect(parsed.memories).toEqual([]);
97
- expect(parsed.total).toBe(0);
98
- });
99
- });
100
- describe('deleteMemory', () => {
101
- test('should delete existing memory', async () => {
102
- await saveMemory({ key: 'delete-me', value: 'temporary' });
103
- const deleteResult = await deleteMemory({ key: 'delete-me' });
104
- expect(deleteResult.content[0].text).toContain('success');
105
- const recallResult = await recallMemory({ key: 'delete-me' });
106
- expect(recallResult.content[0].text).toContain('not found');
107
- });
108
- });
109
- describe('Tool Definition', () => {
110
- test('should have correct structure', () => {
111
- expect(saveMemoryDefinition.name).toBe('save_memory');
112
- expect(saveMemoryDefinition.description).toContain('IMPORTANT');
113
- expect(saveMemoryDefinition.inputSchema.required).toContain('key');
114
- });
115
- test('should include keyword triggers', () => {
116
- expect(saveMemoryDefinition.description).toContain('기억해');
117
- expect(saveMemoryDefinition.description).toContain('remember');
118
- });
119
- });
120
- });