feat(sdk): Phase 1 typed query foundation (gsd-sdk query) (#2118)
* feat(sdk): add typed query foundation and gsd-sdk query (Phase 1) Add sdk/src/query registry and handlers with tests, GSDQueryError, CLI query wiring, and supporting type/tool-scoping hooks. Update CHANGELOG. Vitest 4 constructor mock fixes in milestone-runner tests. Made-with: Cursor * chore: gitignore .cursor for local-only Cursor assets Made-with: Cursor * fix(sdk): harden query layer for PR review (paths, locks, CLI, ReDoS) - resolvePathUnderProject: realpath + relative containment for frontmatter and key_links - commitToSubrepo: path checks + sanitizeCommitMessage - statePlannedPhase: readModifyWriteStateMd (lock); MUTATION_COMMANDS + events - key_links: regexForKeyLinkPattern length/ReDoS guard; phase dirs: reject .. and separators - gsd-sdk: strip --pick before parseArgs; strict parser; QueryRegistry.commands() - progress: static GSDError import; tests updated Made-with: Cursor * feat(sdk): query follow-up — tests, QUERY-HANDLERS, registry, locks, intel depth Made-with: Cursor * docs(sdk): use ASCII punctuation in QUERY-HANDLERS.md Made-with: Cursor
This commit is contained in:
55
sdk/src/query/summary.test.ts
Normal file
55
sdk/src/query/summary.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Tests for summary / history digest handlers.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { mkdtemp, writeFile, mkdir, rm } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
|
||||
import { summaryExtract, historyDigest } from './summary.js';
|
||||
|
||||
describe('summaryExtract', () => {
|
||||
let tmpDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tmpDir = await mkdtemp(join(tmpdir(), 'gsd-sum-'));
|
||||
await mkdir(join(tmpDir, '.planning', 'phases', '01-x'), { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('extracts headings from a summary file', async () => {
|
||||
const rel = '.planning/phases/01-x/01-SUMMARY.md';
|
||||
await writeFile(
|
||||
join(tmpDir, '.planning', 'phases', '01-x', '01-SUMMARY.md'),
|
||||
'# Summary\n\n## What Was Done\n\nBuilt the thing.\n\n## Tests\n\nUnit tests pass.\n',
|
||||
'utf-8',
|
||||
);
|
||||
const r = await summaryExtract([rel], tmpDir);
|
||||
const data = r.data as Record<string, Record<string, string>>;
|
||||
expect(data.sections.what_was_done).toContain('Built');
|
||||
});
|
||||
});
|
||||
|
||||
describe('historyDigest', () => {
|
||||
let tmpDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tmpDir = await mkdtemp(join(tmpdir(), 'gsd-hist-'));
|
||||
await mkdir(join(tmpDir, '.planning'), { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('returns digest object for project without phases', async () => {
|
||||
const r = await historyDigest([], tmpDir);
|
||||
const data = r.data as Record<string, unknown>;
|
||||
expect(data.phases).toBeDefined();
|
||||
expect(data.decisions).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user