* refactor(sdk): extract gsdtools transport seam with per-command policy * refactor(query): centralize registry command catalog wiring * refactor(query): unify command resolution seam across sdk callers * fix(sdk): address CodeRabbit transport policy and timeout findings * refactor(query): extract mutation event mapper seam * refactor(query): converge mutation and transport policy data * refactor(query): share fallback orchestration across cli and sdk * refactor(query): split static registry catalog by domain clusters * refactor(query): extract mutation event emission decorator seam * refactor(query): extract alias-family handler catalog module * refactor(query): extract cjs fallback execution adapter * refactor(query): deepen command semantics seam * refactor(query): extract deep dispatch seam * refactor(query): deepen cjs fallback execution seam * refactor(query): merge routing plan into dispatch seam * fix(query): address CodeRabbit review findings on PR #3060 Critical: prevent double-execution race by checking timeout errors before subprocess fallback (gsd-transport.ts). Major: fix execRaw() to respect transport policy outputMode instead of hardcoding 'raw' (gsd-tools.ts). Major: add explicit 30s timeout to subprocess fallback execution (query-fallback-executor.ts). Major: remove raw args from stderr banner to prevent secret leakage (query-fallback-executor.ts). Minor: ensure native text output has trailing newline for CLI parity (query-dispatch.ts). Update gsd-tools.test.ts to match new execRaw() behavior. * fix(tests): update CLI integration tests for catalog-based registration The refactoring moved handler registration from inline registry.register() calls to catalog-based registration (registerStaticCatalog/registerAliasCatalog). - gsd-sdk-query-registry-integration.test.cjs: collectRegisteredNames() now also scans catalog files for handler names registered via the new system. - bug-2492-context-coverage-gate.test.cjs: checks for catalog-based registration (DECISION_ROUTING_STATIC_CATALOG) instead of inline strings. - bug-2524-sdk-query-ws-flag.test.cjs: checks for dispatchNative callback pattern instead of direct registry.dispatch() call. * fix(query): address remaining CodeRabbit review findings - query-command-semantics.ts: guard stats/progress rewrite so option tokens (e.g. --pick) are not turned into subcommands, preserving the top-level handler dispatch. - query-dispatch.ts: formatOutput now skips --pick for text-format responses (matching CJS fallback behavior) and surfaces a proper error when extractField returns undefined instead of silently producing 'undefined'. - query-dispatch.ts: fix backwards error message — 'registered' is the restrictive policy that disables fallback, not enables it. - tests/bug-2492-context-coverage-gate.test.cjs: check VERIFY_DECISION_STATIC_CATALOG (the correct catalog for plan-gate handlers) instead of DECISION_ROUTING_STATIC_CATALOG. - tests/gsd-sdk-query-registry-integration.test.cjs: resolve catalog variable before loading entries so the drift guard checks each referenced catalog individually. * refactor(query): deepen registry assembly module with strict invariants - extract registry assembly into dedicated module - split build vs mutation decoration internals - add strict assembly invariants: 1) no duplicate keys 2) alias canonicals must have handlers 3) mutation commands must be registered 4) raw-output policy commands must be registered - slim query index to thin re-export seam - add focused registry assembly tests - update drift-guard tests to target new seam * test(query): add thin-seam coverage for query index re-exports * fix(query): return structured native dispatch errors + tighten decisions.parse guard - runQueryDispatch native path now catches adapter errors and returns QueryDispatchResult.error instead of throwing. - preserve legacy CLI exit contract by using code=1 for native dispatch failures. - strengthen bug-2492 guard: decisions.parse assertion now checks VERIFY_DECISION_STATIC_CATALOG OR explicit command token.
103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
import {
|
|
GSDEventType,
|
|
type GSDEvent,
|
|
type GSDStateMutationEvent,
|
|
type GSDConfigMutationEvent,
|
|
type GSDFrontmatterMutationEvent,
|
|
type GSDGitCommitEvent,
|
|
type GSDTemplateFillEvent,
|
|
} from '../types.js';
|
|
import type { QueryResult } from './utils.js';
|
|
|
|
interface EventBase {
|
|
timestamp: string;
|
|
sessionId: string;
|
|
}
|
|
|
|
type EventFamily =
|
|
| 'template'
|
|
| 'git'
|
|
| 'frontmatter'
|
|
| 'config'
|
|
| 'validate'
|
|
| 'phase'
|
|
| 'state'
|
|
| 'default';
|
|
|
|
const FAMILY_RULES: Array<{ family: EventFamily; matches: (cmd: string) => boolean }> = [
|
|
{ family: 'template', matches: (cmd) => cmd.startsWith('template.') || cmd.startsWith('template ') },
|
|
{ family: 'git', matches: (cmd) => cmd === 'commit' || cmd === 'check-commit' || cmd === 'commit-to-subrepo' },
|
|
{ family: 'frontmatter', matches: (cmd) => cmd.startsWith('frontmatter.') || cmd.startsWith('frontmatter ') },
|
|
{ family: 'config', matches: (cmd) => cmd.startsWith('config-') },
|
|
{ family: 'validate', matches: (cmd) => cmd.startsWith('validate.') || cmd.startsWith('validate ') },
|
|
{ family: 'phase', matches: (cmd) => cmd.startsWith('phase.') || cmd.startsWith('phase ') || cmd.startsWith('phases.') || cmd.startsWith('phases ') },
|
|
{ family: 'state', matches: (cmd) => cmd.startsWith('state.') || cmd.startsWith('state ') },
|
|
];
|
|
|
|
function resolveFamily(cmd: string): EventFamily {
|
|
return FAMILY_RULES.find((rule) => rule.matches(cmd))?.family ?? 'default';
|
|
}
|
|
|
|
export function buildMutationEvent(
|
|
correlationSessionId: string,
|
|
cmd: string,
|
|
args: string[],
|
|
result: QueryResult,
|
|
): GSDEvent {
|
|
const base: EventBase = {
|
|
timestamp: new Date().toISOString(),
|
|
sessionId: correlationSessionId,
|
|
};
|
|
|
|
switch (resolveFamily(cmd)) {
|
|
case 'template': {
|
|
const data = result.data as Record<string, unknown> | null;
|
|
return {
|
|
...base,
|
|
type: GSDEventType.TemplateFill,
|
|
templateType: (data?.template as string) ?? args[0] ?? '',
|
|
path: (data?.path as string) ?? args[1] ?? '',
|
|
created: (data?.created as boolean) ?? false,
|
|
} as GSDTemplateFillEvent;
|
|
}
|
|
case 'git': {
|
|
const data = result.data as Record<string, unknown> | null;
|
|
return {
|
|
...base,
|
|
type: GSDEventType.GitCommit,
|
|
hash: (data?.hash as string) ?? null,
|
|
committed: (data?.committed as boolean) ?? false,
|
|
reason: (data?.reason as string) ?? '',
|
|
} as GSDGitCommitEvent;
|
|
}
|
|
case 'frontmatter':
|
|
return {
|
|
...base,
|
|
type: GSDEventType.FrontmatterMutation,
|
|
command: cmd,
|
|
file: args[0] ?? '',
|
|
fields: args.slice(1),
|
|
success: true,
|
|
} as GSDFrontmatterMutationEvent;
|
|
case 'config':
|
|
case 'validate':
|
|
return {
|
|
...base,
|
|
type: GSDEventType.ConfigMutation,
|
|
command: cmd,
|
|
key: args[0] ?? '',
|
|
success: true,
|
|
} as GSDConfigMutationEvent;
|
|
case 'phase':
|
|
case 'state':
|
|
case 'default':
|
|
return {
|
|
...base,
|
|
type: GSDEventType.StateMutation,
|
|
command: cmd,
|
|
fields: args.slice(0, 2),
|
|
success: true,
|
|
} as GSDStateMutationEvent;
|
|
}
|
|
}
|