* feat(sdk): golden parity harness and query handler CJS alignment (#2302 Track A) Golden/read-only parity tests and registry alignment, query handler fixes (check-completion, state-mutation, commit, validate, summary, etc.), and WAITING.json dual-write for .gsd/.planning readers. Refs gsd-build/get-shit-done#2341 * fix(sdk): getMilestoneInfo matches GSD ROADMAP (🟡, last bold, STATE fallback) - Recognize in-flight 🟡 milestone bullets like 🚧. - Derive from last **vX.Y Title** before ## Phases when emoji absent. - Fall back to STATE.md milestone when ROADMAP is missing; use last bare vX.Y in cleaned text instead of first (avoids v1.0 from shipped list). - Fixes init.execute-phase milestone_version and buildStateFrontmatter after state.begin-phase (syncStateFrontmatter). * feat(sdk): phase list, plan task structure, requirements extract handlers - Register phase.list-plans, phase.list-artifacts, plan.task-structure, requirements.extract-from-plans (SDK-only; golden-policy exceptions). - Add unit tests; document in QUERY-HANDLERS.md. - writeProfile: honor --output, render dimensions, return profile_path and dimensions_scored. * feat(sdk): centralize getGsdAgentsDir in query helpers Extract agent directory resolution to helpers (GSD_AGENTS_DIR, primary ~/.claude/agents, legacy path). Use from init and docs-init init bundles. docs(15): add 15-CONTEXT for autonomous phase-15 run. * feat(sdk): query CLI CJS fallback and session correlation - createRegistry(eventStream, sessionId) threads correlation into mutation events - gsd-sdk query falls back to gsd-tools.cjs when no native handler matches (disable with GSD_QUERY_FALLBACK=off); stderr bridge warnings - Export createRegistry from @gsd-build/sdk; add sdk/README.md - Update QUERY-HANDLERS.md and registry module docs for fallback + sessionId - Agents: prefer node dist/cli.js query over cat/grep for STATE and plans * fix(sdk): init phase_found parity, docs-init agents path, state field extract - Normalize findPhase not-found to null before roadmap fallback (matches findPhaseInternal) - docs-init: use detectRuntime + resolveAgentsDir for checkAgentsInstalled - state.cjs stateExtractField: horizontal whitespace only after colon (YAML progress guard) - Tests: commit_docs default true; config-get golden uses temp config; golden integration green Refs: #2302 * refactor(sdk): share SessionJsonlRecord in profile-extract-messages CodeRabbit nit: dedupe JSONL record shape for isGenuineUserMessage and streamExtractMessages. * fix(sdk): address CodeRabbit major threads (paths, gates, audit, verify) - Resolve @file: and CLI JSON indirection relative to projectDir; guard empty normalized query command - plan.task-structure + intel extract/patch-meta: resolvePathUnderProject containment - check.config-gates: safe string booleans; plan_checker alias precedence over plan_check default - state.validate/sync: phaseTokenMatches + comparePhaseNum ordering - verify.schema-drift: token match phase dirs; files_modified from parsed frontmatter - audit-open: has_scan_errors, unreadable rows, human report when scans fail - requirements PLANNED key PLAN for root PLAN.md; gsd-tools timeout note - ingest-docs: repo-root path containment; classifier output slug-hash Golden parity test strips has_scan_errors until CJS adds field. * fix: Resolve CodeRabbit security and quality findings - Secure intel.ts and cli.ts against path traversal - Catch and validate git add status in commit.ts - Expand roadmap milestone marker extraction - Fix parsing array-of-objects in frontmatter YAML - Fix unhandled config evaluations - Improve coverage test parity mapping * test: raise planner character extraction limit to 48K * fix(sdk): resolve TS build error in docs-init passing config
This commit is contained in:
@@ -17,9 +17,13 @@
|
||||
import { QueryRegistry } from './registry.js';
|
||||
import { generateSlug, currentTimestamp } from './utils.js';
|
||||
import { frontmatterGet } from './frontmatter.js';
|
||||
import { configGet, resolveModel } from './config-query.js';
|
||||
import { stateLoad, stateGet, stateSnapshot } from './state.js';
|
||||
import { configGet, configPath, resolveModel } from './config-query.js';
|
||||
import { stateJson, stateGet, stateSnapshot } from './state.js';
|
||||
import { stateProjectLoad } from './state-project-load.js';
|
||||
import { findPhase, phasePlanIndex } from './phase.js';
|
||||
import { phaseListPlans, phaseListArtifacts } from './phase-list-queries.js';
|
||||
import { planTaskStructure } from './plan-task-structure.js';
|
||||
import { requirementsExtractFromPlans } from './requirements-extract-from-plans.js';
|
||||
import { roadmapAnalyze, roadmapGetPhase } from './roadmap.js';
|
||||
import { progressJson } from './progress.js';
|
||||
import { frontmatterSet, frontmatterMerge, frontmatterValidate } from './frontmatter-mutation.js';
|
||||
@@ -27,6 +31,7 @@ import {
|
||||
stateUpdate, statePatch, stateBeginPhase, stateAdvancePlan,
|
||||
stateRecordMetric, stateUpdateProgress, stateAddDecision,
|
||||
stateAddBlocker, stateResolveBlocker, stateRecordSession,
|
||||
stateSignalWaiting, stateSignalResume, stateValidate, stateSync, statePrune,
|
||||
} from './state-mutation.js';
|
||||
import {
|
||||
configSet, configSetModelProfile, configNewProject, configEnsureSection,
|
||||
@@ -34,9 +39,9 @@ import {
|
||||
import { commit, checkCommit } from './commit.js';
|
||||
import { templateFill, templateSelect } from './template.js';
|
||||
import { verifyPlanStructure, verifyPhaseCompleteness, verifyArtifacts, verifyCommits, verifyReferences, verifySummary, verifyPathExists } from './verify.js';
|
||||
import { verifyKeyLinks, validateConsistency, validateHealth } from './validate.js';
|
||||
import { verifyKeyLinks, validateConsistency, validateHealth, validateAgents } from './validate.js';
|
||||
import {
|
||||
phaseAdd, phaseInsert, phaseRemove, phaseComplete,
|
||||
phaseAdd, phaseAddBatch, phaseInsert, phaseRemove, phaseComplete,
|
||||
phaseScaffold, phasesClear, phasesArchive,
|
||||
phasesList, phaseNextDecimal,
|
||||
} from './phase-lifecycle.js';
|
||||
@@ -48,28 +53,46 @@ import {
|
||||
} from './init.js';
|
||||
import { initNewProject, initProgress, initManager } from './init-complex.js';
|
||||
import { agentSkills } from './skills.js';
|
||||
import { roadmapUpdatePlanProgress, requirementsMarkComplete } from './roadmap.js';
|
||||
import { requirementsMarkComplete } from './roadmap.js';
|
||||
import { roadmapUpdatePlanProgress } from './roadmap-update-plan-progress.js';
|
||||
import { statePlannedPhase } from './state-mutation.js';
|
||||
import { verifySchemaDrift } from './verify.js';
|
||||
import { todoMatchPhase, statsJson, progressBar, listTodos, todoComplete } from './progress.js';
|
||||
import {
|
||||
todoMatchPhase, statsJson, statsTable, progressBar, progressTable, listTodos, todoComplete,
|
||||
} from './progress.js';
|
||||
import { milestoneComplete } from './phase-lifecycle.js';
|
||||
import { summaryExtract, historyDigest } from './summary.js';
|
||||
import { commitToSubrepo } from './commit.js';
|
||||
import {
|
||||
workstreamList, workstreamCreate, workstreamSet, workstreamStatus,
|
||||
workstreamGet, workstreamList, workstreamCreate, workstreamSet, workstreamStatus,
|
||||
workstreamComplete, workstreamProgress,
|
||||
} from './workstream.js';
|
||||
import { docsInit } from './init.js';
|
||||
import { docsInit } from './docs-init.js';
|
||||
import { uatRenderCheckpoint, auditUat } from './uat.js';
|
||||
import { websearch } from './websearch.js';
|
||||
import {
|
||||
intelStatus, intelDiff, intelSnapshot, intelValidate, intelQuery,
|
||||
intelExtractExports, intelPatchMeta,
|
||||
intelExtractExports, intelPatchMeta, intelUpdate,
|
||||
} from './intel.js';
|
||||
import {
|
||||
learningsCopy, learningsQuery, extractMessages, scanSessions, profileSample, profileQuestionnaire,
|
||||
writeProfile, generateClaudeProfile, generateDevPreferences, generateClaudeMd,
|
||||
learningsCopy, learningsQuery, learningsListHandler, learningsPrune, learningsDelete,
|
||||
extractMessages, scanSessions, profileSample, profileQuestionnaire,
|
||||
} from './profile.js';
|
||||
import {
|
||||
writeProfile, generateClaudeProfile, generateDevPreferences, generateClaudeMd,
|
||||
} from './profile-output.js';
|
||||
import { skillManifest } from './skill-manifest.js';
|
||||
import { auditOpen } from './audit-open.js';
|
||||
import { detectCustomFiles } from './detect-custom-files.js';
|
||||
import { checkConfigGates } from './config-gates.js';
|
||||
import { checkAutoMode } from './check-auto-mode.js';
|
||||
import { checkPhaseReady } from './phase-ready.js';
|
||||
import { routeNextAction } from './route-next-action.js';
|
||||
import { detectPhaseType } from './detect-phase-type.js';
|
||||
import { checkCompletion } from './check-completion.js';
|
||||
import { checkGates } from './check-gates.js';
|
||||
import { checkVerificationStatus } from './check-verification-status.js';
|
||||
import { checkShipReady } from './check-ship-ready.js';
|
||||
import { GSDEventStream } from '../event-stream.js';
|
||||
import {
|
||||
GSDEventType,
|
||||
@@ -86,6 +109,8 @@ import type { QueryHandler, QueryResult } from './utils.js';
|
||||
|
||||
export type { QueryResult, QueryHandler } from './utils.js';
|
||||
export { extractField } from './registry.js';
|
||||
/** Same argv normalization as `gsd-sdk query` — use when calling `registry.dispatch()` with CLI-style `command` + `args`. */
|
||||
export { normalizeQueryCommand } from './normalize-query-command.js';
|
||||
|
||||
// ─── Mutation commands set ────────────────────────────────────────────────
|
||||
|
||||
@@ -102,14 +127,18 @@ export const QUERY_MUTATION_COMMANDS = new Set<string>([
|
||||
'state.record-metric', 'state.update-progress', 'state.add-decision',
|
||||
'state.add-blocker', 'state.resolve-blocker', 'state.record-session',
|
||||
'state.planned-phase', 'state planned-phase',
|
||||
'state.signal-waiting', 'state signal-waiting',
|
||||
'state.signal-resume', 'state signal-resume',
|
||||
'state.sync', 'state sync',
|
||||
'state.prune', 'state prune',
|
||||
'frontmatter.set', 'frontmatter.merge', 'frontmatter.validate', 'frontmatter validate',
|
||||
'config-set', 'config-set-model-profile', 'config-new-project', 'config-ensure-section',
|
||||
'commit', 'check-commit', 'commit-to-subrepo',
|
||||
'template.fill', 'template.select', 'template select',
|
||||
'validate.health', 'validate health',
|
||||
'phase.add', 'phase.insert', 'phase.remove', 'phase.complete',
|
||||
'phase.add', 'phase.add-batch', 'phase.insert', 'phase.remove', 'phase.complete',
|
||||
'phase.scaffold', 'phases.clear', 'phases.archive',
|
||||
'phase add', 'phase insert', 'phase remove', 'phase complete',
|
||||
'phase add', 'phase add-batch', 'phase insert', 'phase remove', 'phase complete',
|
||||
'phase scaffold', 'phases clear', 'phases archive',
|
||||
'roadmap.update-plan-progress', 'roadmap update-plan-progress',
|
||||
'requirements.mark-complete', 'requirements mark-complete',
|
||||
@@ -119,6 +148,8 @@ export const QUERY_MUTATION_COMMANDS = new Set<string>([
|
||||
'workstream create', 'workstream set', 'workstream complete', 'workstream progress',
|
||||
'docs-init',
|
||||
'learnings.copy', 'learnings copy',
|
||||
'learnings.prune', 'learnings prune',
|
||||
'learnings.delete', 'learnings delete',
|
||||
'intel.snapshot', 'intel.patch-meta', 'intel snapshot', 'intel patch-meta',
|
||||
'write-profile', 'generate-claude-profile', 'generate-dev-preferences', 'generate-claude-md',
|
||||
]);
|
||||
@@ -128,13 +159,17 @@ export const QUERY_MUTATION_COMMANDS = new Set<string>([
|
||||
/**
|
||||
* Build a mutation event based on the command prefix and result.
|
||||
*
|
||||
* `sessionId` is empty until a future phase wires session correlation into
|
||||
* the query layer; see QUERY-HANDLERS.md.
|
||||
* @param correlationSessionId - Optional session correlation id (from {@link createRegistry})
|
||||
*/
|
||||
function buildMutationEvent(cmd: string, args: string[], result: QueryResult): GSDEvent {
|
||||
function buildMutationEvent(
|
||||
correlationSessionId: string,
|
||||
cmd: string,
|
||||
args: string[],
|
||||
result: QueryResult,
|
||||
): GSDEvent {
|
||||
const base = {
|
||||
timestamp: new Date().toISOString(),
|
||||
sessionId: '',
|
||||
sessionId: correlationSessionId,
|
||||
};
|
||||
|
||||
if (cmd.startsWith('template.') || cmd.startsWith('template ')) {
|
||||
@@ -226,22 +261,36 @@ function buildMutationEvent(cmd: string, args: string[], result: QueryResult): G
|
||||
* Create a fully-wired QueryRegistry with all native handlers registered.
|
||||
*
|
||||
* @param eventStream - Optional event stream for mutation event emission
|
||||
* @param correlationSessionId - Optional session id threaded into mutation-related events
|
||||
* @returns A QueryRegistry instance with all handlers registered
|
||||
*/
|
||||
export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
export function createRegistry(
|
||||
eventStream?: GSDEventStream,
|
||||
correlationSessionId?: string,
|
||||
): QueryRegistry {
|
||||
const mutationSessionId = correlationSessionId ?? '';
|
||||
const registry = new QueryRegistry();
|
||||
|
||||
registry.register('generate-slug', generateSlug);
|
||||
registry.register('current-timestamp', currentTimestamp);
|
||||
registry.register('frontmatter.get', frontmatterGet);
|
||||
registry.register('config-get', configGet);
|
||||
registry.register('config-path', configPath);
|
||||
registry.register('resolve-model', resolveModel);
|
||||
registry.register('state.load', stateLoad);
|
||||
registry.register('state.json', stateLoad);
|
||||
registry.register('state.load', stateProjectLoad);
|
||||
registry.register('state.json', stateJson);
|
||||
registry.register('state.get', stateGet);
|
||||
registry.register('state-snapshot', stateSnapshot);
|
||||
registry.register('find-phase', findPhase);
|
||||
registry.register('phase-plan-index', phasePlanIndex);
|
||||
registry.register('phase.list-plans', phaseListPlans);
|
||||
registry.register('phase list-plans', phaseListPlans);
|
||||
registry.register('phase.list-artifacts', phaseListArtifacts);
|
||||
registry.register('phase list-artifacts', phaseListArtifacts);
|
||||
registry.register('plan.task-structure', planTaskStructure);
|
||||
registry.register('plan task-structure', planTaskStructure);
|
||||
registry.register('requirements.extract-from-plans', requirementsExtractFromPlans);
|
||||
registry.register('requirements extract-from-plans', requirementsExtractFromPlans);
|
||||
registry.register('roadmap.analyze', roadmapAnalyze);
|
||||
registry.register('roadmap.get-phase', roadmapGetPhase);
|
||||
registry.register('progress', progressJson);
|
||||
@@ -264,6 +313,16 @@ export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
registry.register('state.add-blocker', stateAddBlocker);
|
||||
registry.register('state.resolve-blocker', stateResolveBlocker);
|
||||
registry.register('state.record-session', stateRecordSession);
|
||||
registry.register('state.signal-waiting', stateSignalWaiting);
|
||||
registry.register('state.signal-resume', stateSignalResume);
|
||||
registry.register('state.validate', stateValidate);
|
||||
registry.register('state.sync', stateSync);
|
||||
registry.register('state.prune', statePrune);
|
||||
registry.register('state signal-waiting', stateSignalWaiting);
|
||||
registry.register('state signal-resume', stateSignalResume);
|
||||
registry.register('state validate', stateValidate);
|
||||
registry.register('state sync', stateSync);
|
||||
registry.register('state prune', statePrune);
|
||||
|
||||
// Config mutation handlers
|
||||
registry.register('config-set', configSet);
|
||||
@@ -303,9 +362,32 @@ export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
registry.register('validate consistency', validateConsistency);
|
||||
registry.register('validate.health', validateHealth);
|
||||
registry.register('validate health', validateHealth);
|
||||
registry.register('validate.agents', validateAgents);
|
||||
registry.register('validate agents', validateAgents);
|
||||
|
||||
// Decision routing (SDK-only — no `gsd-tools.cjs` mirror yet; see QUERY-HANDLERS.md)
|
||||
registry.register('check.config-gates', checkConfigGates);
|
||||
registry.register('check config-gates', checkConfigGates);
|
||||
registry.register('check.auto-mode', checkAutoMode);
|
||||
registry.register('check auto-mode', checkAutoMode);
|
||||
registry.register('check.phase-ready', checkPhaseReady);
|
||||
registry.register('check phase-ready', checkPhaseReady);
|
||||
registry.register('route.next-action', routeNextAction);
|
||||
registry.register('route next-action', routeNextAction);
|
||||
registry.register('detect.phase-type', detectPhaseType);
|
||||
registry.register('detect phase-type', detectPhaseType);
|
||||
registry.register('check.completion', checkCompletion);
|
||||
registry.register('check completion', checkCompletion);
|
||||
registry.register('check.gates', checkGates);
|
||||
registry.register('check gates', checkGates);
|
||||
registry.register('check.verification-status', checkVerificationStatus);
|
||||
registry.register('check verification-status', checkVerificationStatus);
|
||||
registry.register('check.ship-ready', checkShipReady);
|
||||
registry.register('check ship-ready', checkShipReady);
|
||||
|
||||
// Phase lifecycle handlers
|
||||
registry.register('phase.add', phaseAdd);
|
||||
registry.register('phase.add-batch', phaseAddBatch);
|
||||
registry.register('phase.insert', phaseInsert);
|
||||
registry.register('phase.remove', phaseRemove);
|
||||
registry.register('phase.complete', phaseComplete);
|
||||
@@ -316,6 +398,7 @@ export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
registry.register('phase.next-decimal', phaseNextDecimal);
|
||||
// Space-delimited aliases for CJS compatibility
|
||||
registry.register('phase add', phaseAdd);
|
||||
registry.register('phase add-batch', phaseAddBatch);
|
||||
registry.register('phase insert', phaseInsert);
|
||||
registry.register('phase remove', phaseRemove);
|
||||
registry.register('phase complete', phaseComplete);
|
||||
@@ -388,11 +471,18 @@ export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
registry.register('history.digest', historyDigest);
|
||||
registry.register('history digest', historyDigest);
|
||||
registry.register('history-digest', historyDigest);
|
||||
registry.register('stats', statsJson);
|
||||
registry.register('stats.json', statsJson);
|
||||
registry.register('stats json', statsJson);
|
||||
registry.register('stats.table', statsTable);
|
||||
registry.register('stats table', statsTable);
|
||||
registry.register('commit-to-subrepo', commitToSubrepo);
|
||||
registry.register('progress.bar', progressBar);
|
||||
registry.register('progress bar', progressBar);
|
||||
registry.register('progress.table', progressTable);
|
||||
registry.register('progress table', progressTable);
|
||||
registry.register('workstream.get', workstreamGet);
|
||||
registry.register('workstream get', workstreamGet);
|
||||
registry.register('workstream.list', workstreamList);
|
||||
registry.register('workstream list', workstreamList);
|
||||
registry.register('workstream.create', workstreamCreate);
|
||||
@@ -411,6 +501,17 @@ export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
registry.register('learnings copy', learningsCopy);
|
||||
registry.register('learnings.query', learningsQuery);
|
||||
registry.register('learnings query', learningsQuery);
|
||||
registry.register('learnings.list', learningsListHandler);
|
||||
registry.register('learnings list', learningsListHandler);
|
||||
registry.register('learnings.prune', learningsPrune);
|
||||
registry.register('learnings prune', learningsPrune);
|
||||
registry.register('learnings.delete', learningsDelete);
|
||||
registry.register('learnings delete', learningsDelete);
|
||||
registry.register('skill-manifest', skillManifest);
|
||||
registry.register('skill manifest', skillManifest);
|
||||
registry.register('audit-open', auditOpen);
|
||||
registry.register('audit open', auditOpen);
|
||||
registry.register('detect-custom-files', detectCustomFiles);
|
||||
registry.register('extract-messages', extractMessages);
|
||||
registry.register('extract.messages', extractMessages);
|
||||
registry.register('audit-uat', auditUat);
|
||||
@@ -430,6 +531,8 @@ export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
registry.register('intel extract-exports', intelExtractExports);
|
||||
registry.register('intel.patch-meta', intelPatchMeta);
|
||||
registry.register('intel patch-meta', intelPatchMeta);
|
||||
registry.register('intel.update', intelUpdate);
|
||||
registry.register('intel update', intelUpdate);
|
||||
registry.register('generate-claude-profile', generateClaudeProfile);
|
||||
registry.register('generate-dev-preferences', generateDevPreferences);
|
||||
registry.register('write-profile', writeProfile);
|
||||
@@ -446,7 +549,7 @@ export function createRegistry(eventStream?: GSDEventStream): QueryRegistry {
|
||||
registry.register(cmd, async (args: string[], projectDir: string) => {
|
||||
const result = await original(args, projectDir);
|
||||
try {
|
||||
const event = buildMutationEvent(cmd, args, result);
|
||||
const event = buildMutationEvent(mutationSessionId, cmd, args, result);
|
||||
eventStream.emitEvent(event);
|
||||
} catch {
|
||||
// T-11-12: Event emission is fire-and-forget; never block mutation success
|
||||
|
||||
Reference in New Issue
Block a user