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>
113 lines
3.3 KiB
TypeScript
113 lines
3.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { extractSummary, type SummaryData } from '../../src/extractors/summary.js';
|
|
import { readFixture } from '../setup.js';
|
|
|
|
describe('summary extractor', () => {
|
|
it('extracts decisions from frontmatter', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.decisions.length).toBeGreaterThan(0);
|
|
expect(result.decisions[0]).toHaveProperty('decision');
|
|
expect(result.decisions[0].decision).toContain('jose');
|
|
});
|
|
|
|
it('extracts tech stack additions', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.techStack.length).toBeGreaterThan(0);
|
|
expect(result.techStack).toContainEqual(
|
|
expect.objectContaining({
|
|
library: 'jose',
|
|
version: '5.2.0'
|
|
})
|
|
);
|
|
});
|
|
|
|
it('extracts patterns established', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.patterns.length).toBeGreaterThan(0);
|
|
expect(result.patterns[0]).toContain('Token rotation');
|
|
});
|
|
|
|
it('extracts requires/provides for dependency graph', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.requires).toBeDefined();
|
|
expect(result.provides).toBeDefined();
|
|
expect(result.provides.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('extracts phase and plan identifiers', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.phase).toBe('01-foundation');
|
|
expect(result.plan).toBe(1);
|
|
});
|
|
|
|
it('extracts subsystem and tags', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.subsystem).toBe('auth');
|
|
expect(result.tags).toContain('jwt');
|
|
expect(result.tags).toContain('prisma');
|
|
});
|
|
|
|
it('extracts affects list', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.affects).toBeDefined();
|
|
expect(result.affects).toContain('02-features');
|
|
});
|
|
|
|
it('extracts key files', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.keyFiles).toBeDefined();
|
|
expect(result.keyFiles.created).toContain('src/lib/auth.ts');
|
|
});
|
|
|
|
it('extracts duration and completion date', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.duration).toBe('28min');
|
|
expect(result.completed).toBe('2025-01-15');
|
|
});
|
|
|
|
it('handles summary without optional fields', () => {
|
|
const minimalSummary = `---
|
|
phase: 01-test
|
|
plan: 01
|
|
subsystem: testing
|
|
tags: [test]
|
|
---
|
|
# Phase 1 Summary
|
|
|
|
**Test phase**`;
|
|
|
|
const result = extractSummary(minimalSummary);
|
|
|
|
expect(result.phase).toBe('01-test');
|
|
expect(result.decisions).toEqual([]);
|
|
expect(result.techStack).toEqual([]);
|
|
expect(result.patterns).toEqual([]);
|
|
});
|
|
|
|
it('extracts one-liner from content', () => {
|
|
const summary = readFixture('sample-summary.md');
|
|
const result = extractSummary(summary);
|
|
|
|
expect(result.oneLiner).toBeDefined();
|
|
expect(result.oneLiner).toContain('JWT auth');
|
|
});
|
|
});
|