Implements MCP server for semantic search across GSD projects: MCP Tools: - gsd_memory_search: Search across all registered projects - gsd_memory_decisions: Find decisions from SUMMARY/PROJECT.md - gsd_memory_patterns: Find patterns from SUMMARY.md - gsd_memory_pitfalls: Find pitfalls from RESEARCH.md - gsd_memory_stack: Find tech stack entries - gsd_memory_register: Register project with memory - gsd_memory_index: Trigger indexing/update - gsd_memory_status: Show system status Architecture: - QMD wrapper with grep fallback when QMD unavailable - YAML frontmatter extractors for GSD document types - Project registry at ~/.gsd/projects.json - Auto-install via bin/install.js for Claude Code Workflow integrations: - new-project: Registers project with memory - plan-phase: Indexes after planning - execute-phase: Indexes after execution - complete-milestone: Indexes milestone completion - Researcher agents query memory before Context7 Tests: 117 passing (66 unit + 51 integration) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
90 lines
2.8 KiB
TypeScript
90 lines
2.8 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { extractResearch, type ResearchData } from '../../src/extractors/research.js';
|
|
import { readFixture } from '../setup.js';
|
|
|
|
describe('research extractor', () => {
|
|
it('extracts metadata from frontmatter', () => {
|
|
const research = readFixture('sample-research.md');
|
|
const result = extractResearch(research);
|
|
|
|
expect(result.domain).toBe('WebSocket and Server-Sent Events for real-time updates');
|
|
expect(result.confidence).toBe('HIGH');
|
|
expect(result.researched).toBe('2025-01-20');
|
|
});
|
|
|
|
it('extracts pitfalls section', () => {
|
|
const research = readFixture('sample-research.md');
|
|
const result = extractResearch(research);
|
|
|
|
expect(result.pitfalls.length).toBeGreaterThan(0);
|
|
expect(result.pitfalls[0]).toHaveProperty('name');
|
|
expect(result.pitfalls[0]).toHaveProperty('description');
|
|
expect(result.pitfalls[0]).toHaveProperty('prevention');
|
|
});
|
|
|
|
it('extracts standard stack table', () => {
|
|
const research = readFixture('sample-research.md');
|
|
const result = extractResearch(research);
|
|
|
|
expect(result.standardStack.length).toBeGreaterThan(0);
|
|
expect(result.standardStack[0]).toHaveProperty('library');
|
|
expect(result.standardStack[0]).toHaveProperty('purpose');
|
|
});
|
|
|
|
it('extracts dont-hand-roll items', () => {
|
|
const research = readFixture('sample-research.md');
|
|
const result = extractResearch(research);
|
|
|
|
expect(result.dontHandRoll.length).toBeGreaterThan(0);
|
|
expect(result.dontHandRoll[0]).toHaveProperty('problem');
|
|
expect(result.dontHandRoll[0]).toHaveProperty('useInstead');
|
|
});
|
|
|
|
it('extracts anti-patterns', () => {
|
|
const research = readFixture('sample-research.md');
|
|
const result = extractResearch(research);
|
|
|
|
expect(result.antiPatterns.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('extracts user constraints if present', () => {
|
|
const research = readFixture('sample-research.md');
|
|
const result = extractResearch(research);
|
|
|
|
expect(result.userConstraints).toBeDefined();
|
|
expect(result.userConstraints.locked.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('extracts primary recommendation', () => {
|
|
const research = readFixture('sample-research.md');
|
|
const result = extractResearch(research);
|
|
|
|
expect(result.primaryRecommendation).toBeDefined();
|
|
expect(result.primaryRecommendation).toContain('SSE');
|
|
});
|
|
|
|
it('handles research without optional sections', () => {
|
|
const minimalResearch = `---
|
|
domain: testing
|
|
confidence: LOW
|
|
researched: 2025-01-20
|
|
---
|
|
|
|
# Research
|
|
|
|
## Summary
|
|
|
|
Basic research document.
|
|
|
|
**Primary recommendation:** Use standard tools.
|
|
`;
|
|
|
|
const result = extractResearch(minimalResearch);
|
|
|
|
expect(result.domain).toBe('testing');
|
|
expect(result.pitfalls).toEqual([]);
|
|
expect(result.standardStack).toEqual([]);
|
|
expect(result.dontHandRoll).toEqual([]);
|
|
});
|
|
});
|