fix(query): workstream resolution in init.milestone-op and roadmap.analyze (#3196)
- initMilestoneOp now accepts and propagates the workstream parameter: relPlanningPath(workstream) replaces the hardcoded '.planning' dir, getMilestoneInfo gets workstream passed, extractCurrentMilestone gets workstream passed, archiveDir is derived from planningDir not root. - resolveQueryRuntimeContext now reads .planning/active-workstream as a third-priority fallback after --ws flag and GSD_WORKSTREAM env var, completing the documented resolution chain for all query handlers. Closes #3196 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { join } from 'node:path';
|
||||
import { readFileSync, existsSync } from 'node:fs';
|
||||
import { findProjectRoot } from './helpers.js';
|
||||
import { validateWorkstreamName } from '../workstream-utils.js';
|
||||
|
||||
@@ -11,6 +13,35 @@ export interface QueryRuntimeContext {
|
||||
ws?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the active workstream from `.planning/active-workstream` file.
|
||||
*
|
||||
* Mirrors the logic in workstream.ts:getActiveWorkstream — returns null
|
||||
* when the file is missing, empty, contains invalid characters, or names
|
||||
* a workstream directory that doesn't exist on disk.
|
||||
*/
|
||||
function readActiveWorkstreamFile(projectDir: string): string | null {
|
||||
const filePath = join(projectDir, '.planning', 'active-workstream');
|
||||
try {
|
||||
const name = readFileSync(filePath, 'utf-8').trim();
|
||||
if (!name || !validateWorkstreamName(name)) return null;
|
||||
const wsDir = join(projectDir, '.planning', 'workstreams', name);
|
||||
if (!existsSync(wsDir)) return null;
|
||||
return name;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the runtime context for a query invocation.
|
||||
*
|
||||
* Workstream resolution priority:
|
||||
* 1. `--ws <name>` flag (input.ws)
|
||||
* 2. `GSD_WORKSTREAM` environment variable
|
||||
* 3. `.planning/active-workstream` file
|
||||
* 4. Root `.planning/` (no workstream)
|
||||
*/
|
||||
export function resolveQueryRuntimeContext(input: QueryRuntimeContextInput): QueryRuntimeContext {
|
||||
const projectDir = findProjectRoot(input.projectDir);
|
||||
|
||||
@@ -22,8 +53,13 @@ export function resolveQueryRuntimeContext(input: QueryRuntimeContextInput): Que
|
||||
}
|
||||
|
||||
const envWs = process.env.GSD_WORKSTREAM;
|
||||
if (envWs && validateWorkstreamName(envWs)) {
|
||||
return { projectDir, ws: envWs };
|
||||
}
|
||||
|
||||
const fileWs = readActiveWorkstreamFile(projectDir);
|
||||
return {
|
||||
projectDir,
|
||||
ws: envWs && validateWorkstreamName(envWs) ? envWs : undefined,
|
||||
ws: fileWs ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user