refactor: deepen GSDTools query execution seams (#3085)

* refactor: deepen gsdtools query execution seams

* docs: add changeset for query seam deepening

* docs: fix changeset summary text

* fix: address coderabbit query seam findings

* test: address remaining coderabbit findings and notes

* refactor: use internal gsdtools error type import
This commit is contained in:
Tom Boucher
2026-05-03 18:56:41 -04:00
committed by GitHub
parent 5e21bf7567
commit 42ed7cee8d
24 changed files with 871 additions and 445 deletions

View File

@@ -285,12 +285,12 @@ export const initExecutePhase: QueryHandler = async (args, projectDir, workstrea
const phase_req_ids = extractReqIds(roadmapPhase);
const configExists = existsSync(join(planningDir, 'config.json'));
const [executorModelRaw, verifierModelRaw] = await Promise.all([
getModelAlias('gsd-executor', projectDir),
getModelAlias('gsd-verifier', projectDir),
]);
const executorModel = configExists ? executorModelRaw : '';
const verifierModel = configExists ? verifierModelRaw : '';
const [executorModel, verifierModel] = configExists
? await Promise.all([
getModelAlias('gsd-executor', projectDir),
getModelAlias('gsd-verifier', projectDir),
])
: ['', ''];
const milestone = await getMilestoneInfo(projectDir, workstream);
@@ -367,14 +367,13 @@ export const initPlanPhase: QueryHandler = async (args, projectDir, workstream)
const phase_req_ids = extractReqIds(roadmapPhase);
const configExists = existsSync(join(planningDir, 'config.json'));
const [researcherModelRaw, plannerModelRaw, checkerModelRaw] = await Promise.all([
getModelAlias('gsd-phase-researcher', projectDir),
getModelAlias('gsd-planner', projectDir),
getModelAlias('gsd-plan-checker', projectDir),
]);
const researcherModel = configExists ? researcherModelRaw : '';
const plannerModel = configExists ? plannerModelRaw : '';
const checkerModel = configExists ? checkerModelRaw : '';
const [researcherModel, plannerModel, checkerModel] = configExists
? await Promise.all([
getModelAlias('gsd-phase-researcher', projectDir),
getModelAlias('gsd-planner', projectDir),
getModelAlias('gsd-plan-checker', projectDir),
])
: ['', '', ''];
const phaseNumber = (phaseInfo?.phase_number as string) || null;
const plans = (phaseInfo?.plans || []) as string[];
@@ -520,16 +519,14 @@ export const initQuick: QueryHandler = async (args, projectDir) => {
: null;
const configExists = existsSync(join(planningDir, 'config.json'));
const [plannerModelRaw, executorModelRaw, checkerModelRaw, verifierModelRaw] = await Promise.all([
getModelAlias('gsd-planner', projectDir),
getModelAlias('gsd-executor', projectDir),
getModelAlias('gsd-plan-checker', projectDir),
getModelAlias('gsd-verifier', projectDir),
]);
const plannerModel = configExists ? plannerModelRaw : '';
const executorModel = configExists ? executorModelRaw : '';
const checkerModel = configExists ? checkerModelRaw : '';
const verifierModel = configExists ? verifierModelRaw : '';
const [plannerModel, executorModel, checkerModel, verifierModel] = configExists
? await Promise.all([
getModelAlias('gsd-planner', projectDir),
getModelAlias('gsd-executor', projectDir),
getModelAlias('gsd-plan-checker', projectDir),
getModelAlias('gsd-verifier', projectDir),
])
: ['', '', '', ''];
const result: Record<string, unknown> = {
planner_model: plannerModel,
@@ -599,12 +596,12 @@ export const initVerifyWork: QueryHandler = async (args, projectDir) => {
const { phaseInfo } = await getPhaseInfoForVerifyWork(phase, projectDir);
const configExists = existsSync(join(projectDir, '.planning', 'config.json'));
const [plannerModelRaw, checkerModelRaw] = await Promise.all([
getModelAlias('gsd-planner', projectDir),
getModelAlias('gsd-plan-checker', projectDir),
]);
const plannerModel = configExists ? plannerModelRaw : '';
const checkerModel = configExists ? checkerModelRaw : '';
const [plannerModel, checkerModel] = configExists
? await Promise.all([
getModelAlias('gsd-planner', projectDir),
getModelAlias('gsd-plan-checker', projectDir),
])
: ['', ''];
const result: Record<string, unknown> = {
planner_model: plannerModel,

View File

@@ -349,6 +349,14 @@ describe('stateBeginPhase', () => {
).rejects.toThrow('missing value for --phase');
});
it('bug-2420: flag parser throws when a flag is last token with no value', async () => {
const { stateBeginPhase } = await import('./state-mutation.js');
await expect(
stateBeginPhase(['--name', 'Title', '--plans', '1', '--phase'], tmpDir)
).rejects.toThrow('missing value for --phase');
});
it('does not treat argv after named flags as positional name/plans', async () => {
const { stateBeginPhase } = await import('./state-mutation.js');

View File

@@ -321,7 +321,7 @@ export async function readModifyWriteStateMdFull(
*
* @param args - args[0]: field name, args[1]: new value
* @param projectDir - Project root directory
* @returns QueryResult with { updated: true/false, field, value }
* @returns QueryResult with { updated: true/false }
*/
export const stateUpdate: QueryHandler = async (args, projectDir, workstream) => {
const field = args[0];