* fix(#2376): emit absolute subagent-facing init/state paths Make init.* and state.* path fields absolute rather than cwd-relative so subagent prompts resolve correctly regardless of working directory. Adds intel_dir/conflicts_path/requirements_path/roadmap_path/state_path to cmdInitIngestDocs, an absolute debug_dir to cmdStateLoad, and replaces bare .planning/... literals in 12 workflow Agent() prompt blocks with the absolute init-JSON path fields. Includes decoy-cwd regression tests and realpath'd tmpdir fixtures for macOS. Squashed rebase of the #2376 commit series onto a fresh origin/next (previous merge ee25543a1 was against a now-stale next). * chore(#2376): add changeset * chore(#2376): regenerate golden fixtures + workflow size baseline Regenerated after rebasing the absolute-path fix onto current next (picks up #2351's run-with-timeout content in execute-phase.md too). * fix(#2376): trim execute-phase.md redundancy to stay under the size margin * chore(#2376): regenerate golden/size baseline after rebase onto next
This commit is contained in:
223
src/init.cts
223
src/init.cts
@@ -398,7 +398,11 @@ function cmdInitExecutePhase(
|
||||
verifier_enabled: config.verifier,
|
||||
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseInfo?.['directory'] || null,
|
||||
// #2376: absolute (anchored on cwd/project_root), not orchestrator-cwd-relative —
|
||||
// a spawned subagent's own cwd may differ from the orchestrator's.
|
||||
phase_dir: phaseInfo?.['directory']
|
||||
? toPosixPath(path.join(cwd, phaseInfo['directory'] as string))
|
||||
: null,
|
||||
phase_number: phaseInfo?.['phase_number'] || null,
|
||||
phase_name: phaseInfo?.['phase_name'] || null,
|
||||
phase_slug: phaseInfo?.['phase_slug'] || null,
|
||||
@@ -432,15 +436,13 @@ function cmdInitExecutePhase(
|
||||
state_exists: fs.existsSync(path.join(planningDir(cwd), 'STATE.md')),
|
||||
roadmap_exists: fs.existsSync(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
config_exists: fs.existsSync(path.join(planningDir(cwd), 'config.json')),
|
||||
state_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'STATE.md')),
|
||||
),
|
||||
roadmap_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
),
|
||||
config_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'config.json')),
|
||||
),
|
||||
// #2376: emit absolute paths — see comment above on phase_dir.
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
config_path: toPosixPath(path.join(planningDir(cwd), 'config.json')),
|
||||
// #2376: execute-phase.md's verify_phase_goal step reads this instead of
|
||||
// hardcoding '.planning/REQUIREMENTS.md' into the gsd-verifier spawn prompt.
|
||||
requirements_path: toPosixPath(path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
};
|
||||
|
||||
if (options['validate']) {
|
||||
@@ -525,9 +527,8 @@ function cmdInitPlanPhase(
|
||||
if (slug) {
|
||||
const prefix = rawProjectCodePlan ? `${rawProjectCodePlan}-` : '';
|
||||
const dirName = `${prefix}${paddedNum}-${slug}`;
|
||||
expectedPhaseDirPlan = toPosixPath(
|
||||
path.relative(cwd, path.join(planningPaths(cwd).phases, dirName)),
|
||||
);
|
||||
// #2376: absolute — see comment on phase_dir below.
|
||||
expectedPhaseDirPlan = toPosixPath(path.join(planningPaths(cwd).phases, dirName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +555,10 @@ function cmdInitPlanPhase(
|
||||
mode: config.mode || 'interactive',
|
||||
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseDirPlan,
|
||||
// #2376: absolute (anchored on cwd/project_root) — path.join(cwd, phaseDirPlan)
|
||||
// handed to a spawned subagent must resolve regardless of that subagent's own cwd.
|
||||
// phaseDirPlan itself stays relative — phase_status below still joins it against cwd.
|
||||
phase_dir: phaseDirPlan ? toPosixPath(path.join(cwd, phaseDirPlan)) : null,
|
||||
expected_phase_dir: expectedPhaseDirPlan,
|
||||
phase_number: phaseNumberPlan,
|
||||
phase_name: phaseNamePlan,
|
||||
@@ -580,15 +584,10 @@ function cmdInitPlanPhase(
|
||||
planning_exists: fs.existsSync(planningDir(cwd)),
|
||||
roadmap_exists: fs.existsSync(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
|
||||
state_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'STATE.md')),
|
||||
),
|
||||
roadmap_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
),
|
||||
requirements_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
),
|
||||
// #2376: absolute — see comment on phase_dir above.
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
requirements_path: toPosixPath(path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
|
||||
patterns_path: null,
|
||||
};
|
||||
@@ -599,45 +598,35 @@ function cmdInitPlanPhase(
|
||||
const files = fs.readdirSync(phaseDirFull);
|
||||
const contextFile = findContextMdIn(phaseDirFull);
|
||||
if (contextFile) {
|
||||
result['context_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, contextFile),
|
||||
);
|
||||
result['context_path'] = toPosixPath(path.join(phaseDirFull, contextFile));
|
||||
}
|
||||
const researchFile = files.find(
|
||||
(f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md',
|
||||
);
|
||||
if (researchFile) {
|
||||
result['research_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, researchFile),
|
||||
);
|
||||
result['research_path'] = toPosixPath(path.join(phaseDirFull, researchFile));
|
||||
}
|
||||
const verificationFile = files.find(
|
||||
(f) => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md',
|
||||
);
|
||||
if (verificationFile) {
|
||||
result['verification_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, verificationFile),
|
||||
);
|
||||
result['verification_path'] = toPosixPath(path.join(phaseDirFull, verificationFile));
|
||||
}
|
||||
const uatFile = files.find((f) => f.endsWith('-UAT.md') || f === 'UAT.md');
|
||||
if (uatFile) {
|
||||
result['uat_path'] = toPosixPath(path.join(phaseInfo['directory'] as string, uatFile));
|
||||
result['uat_path'] = toPosixPath(path.join(phaseDirFull, uatFile));
|
||||
}
|
||||
const reviewsFile = files.find(
|
||||
(f) => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md',
|
||||
);
|
||||
if (reviewsFile) {
|
||||
result['reviews_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, reviewsFile),
|
||||
);
|
||||
result['reviews_path'] = toPosixPath(path.join(phaseDirFull, reviewsFile));
|
||||
}
|
||||
const patternsFile = files.find(
|
||||
(f) => f.endsWith('-PATTERNS.md') || f === 'PATTERNS.md',
|
||||
);
|
||||
if (patternsFile) {
|
||||
result['patterns_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, patternsFile),
|
||||
);
|
||||
result['patterns_path'] = toPosixPath(path.join(phaseDirFull, patternsFile));
|
||||
}
|
||||
} catch {
|
||||
/* intentionally empty */
|
||||
@@ -714,7 +703,14 @@ function cmdInitNewProject(cwd: string, raw: boolean): void {
|
||||
firecrawl_available: hasFirecrawl,
|
||||
exa_search_available: hasExaSearch,
|
||||
|
||||
project_path: '.planning/PROJECT.md',
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
project_path: toPosixPath(path.join(planningDir(cwd), 'PROJECT.md')),
|
||||
// #2376: new-project.md's research-synthesizer/roadmapper spawn prompts
|
||||
// read these instead of hardcoding '.planning/...' literals.
|
||||
requirements_path: toPosixPath(path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
config_path: toPosixPath(path.join(planningDir(cwd), 'config.json')),
|
||||
research_dir: toPosixPath(path.join(planningRoot(cwd), 'research')),
|
||||
};
|
||||
|
||||
output(withProjectRoot(cwd, result), raw);
|
||||
@@ -754,16 +750,10 @@ function cmdInitNewMilestone(cwd: string, raw: boolean): void {
|
||||
latest_completed_milestone: latestCompleted?.version || null,
|
||||
latest_completed_milestone_name: latestCompleted?.name || null,
|
||||
phase_dir_count: phaseDirCount,
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
phase_archive_path: latestCompleted
|
||||
? toPosixPath(
|
||||
path.relative(
|
||||
cwd,
|
||||
path.join(
|
||||
planningRoot(cwd),
|
||||
'milestones',
|
||||
`${latestCompleted.version}-phases`,
|
||||
),
|
||||
),
|
||||
path.join(planningRoot(cwd), 'milestones', `${latestCompleted.version}-phases`),
|
||||
)
|
||||
: null,
|
||||
|
||||
@@ -771,13 +761,15 @@ function cmdInitNewMilestone(cwd: string, raw: boolean): void {
|
||||
roadmap_exists: fs.existsSync(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
state_exists: fs.existsSync(path.join(planningDir(cwd), 'STATE.md')),
|
||||
|
||||
project_path: '.planning/PROJECT.md',
|
||||
roadmap_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
),
|
||||
state_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'STATE.md')),
|
||||
),
|
||||
project_path: toPosixPath(path.join(planningDir(cwd), 'PROJECT.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
// #2376: new-milestone.md's research-synthesizer/roadmapper spawn prompts
|
||||
// read these instead of hardcoding '.planning/...' literals.
|
||||
requirements_path: toPosixPath(path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
config_path: toPosixPath(path.join(planningDir(cwd), 'config.json')),
|
||||
research_dir: toPosixPath(path.join(planningRoot(cwd), 'research')),
|
||||
milestones_path: toPosixPath(path.join(planningDir(cwd), 'MILESTONES.md')),
|
||||
};
|
||||
|
||||
output(withProjectRoot(cwd, result), raw);
|
||||
@@ -824,8 +816,11 @@ function cmdInitQuick(cwd: string, description: string | undefined, raw: boolean
|
||||
date: realClock.localToday(),
|
||||
timestamp: realClock.nowIso(),
|
||||
|
||||
quick_dir: '.planning/quick',
|
||||
task_dir: slug ? `.planning/quick/${quickId}-${slug}` : null,
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
quick_dir: toPosixPath(path.join(planningDir(cwd), 'quick')),
|
||||
task_dir: slug
|
||||
? toPosixPath(path.join(planningDir(cwd), 'quick', `${quickId}-${slug}`))
|
||||
: null,
|
||||
|
||||
roadmap_exists: fs.existsSync(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
planning_exists: fs.existsSync(planningRoot(cwd)),
|
||||
@@ -840,7 +835,18 @@ function cmdInitIngestDocs(cwd: string, raw: boolean): void {
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
planning_exists: fs.existsSync(planningRoot(cwd)),
|
||||
...getInitGitState(cwd),
|
||||
project_path: '.planning/PROJECT.md',
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase. The
|
||||
// classify_parallel/synthesize/route_new_mode spawns in ingest-docs.md
|
||||
// (gsd-doc-classifier, gsd-doc-synthesizer, gsd-roadmapper) previously
|
||||
// hardcoded bare '.planning/intel/...', '.planning/PROJECT.md', etc.
|
||||
// literals into their Agent(prompt=...) blocks; those now interpolate
|
||||
// these fields instead.
|
||||
project_path: toPosixPath(path.join(planningDir(cwd), 'PROJECT.md')),
|
||||
requirements_path: toPosixPath(path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
intel_dir: toPosixPath(path.join(planningDir(cwd), 'intel')),
|
||||
conflicts_path: toPosixPath(path.join(planningDir(cwd), 'INGEST-CONFLICTS.md')),
|
||||
commit_docs: config.commit_docs,
|
||||
};
|
||||
output(withProjectRoot(cwd, result), raw);
|
||||
@@ -880,13 +886,10 @@ function cmdInitResume(cwd: string, raw: boolean): void {
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
planning_exists: fs.existsSync(planningRoot(cwd)),
|
||||
|
||||
state_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'STATE.md')),
|
||||
),
|
||||
roadmap_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
),
|
||||
project_path: '.planning/PROJECT.md',
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
project_path: toPosixPath(path.join(planningDir(cwd), 'PROJECT.md')),
|
||||
|
||||
has_interrupted_agent: !!interruptedAgentId,
|
||||
interrupted_agent_id: interruptedAgentId,
|
||||
@@ -959,10 +962,17 @@ function cmdInitVerifyWork(cwd: string, phase: string, raw: boolean): void {
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseDir,
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase. phaseDir
|
||||
// itself stays relative — evaluateUatPassed above still joins it against cwd.
|
||||
phase_dir: phaseDir ? toPosixPath(path.join(cwd, phaseDir)) : null,
|
||||
phase_number: phaseInfo?.['phase_number'] || null,
|
||||
phase_name: phaseInfo?.['phase_name'] || null,
|
||||
|
||||
// #2376: verify-work.md's plan_gap_closure step reads these instead of
|
||||
// hardcoding '.planning/STATE.md' / '.planning/ROADMAP.md' literals.
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
|
||||
has_verification: phaseInfo?.['has_verification'] || false,
|
||||
phase_completion: {
|
||||
...completion,
|
||||
@@ -1050,9 +1060,8 @@ function cmdInitPhaseOp(cwd: string, phase: string, raw: boolean): void {
|
||||
if (slug) {
|
||||
const prefix = rawProjectCode ? `${rawProjectCode}-` : '';
|
||||
const dirName = `${prefix}${paddedNum}-${slug}`;
|
||||
expectedPhaseDir = toPosixPath(
|
||||
path.relative(cwd, path.join(planningPaths(cwd).phases, dirName)),
|
||||
);
|
||||
// #2376: absolute — see comment on phase_dir below.
|
||||
expectedPhaseDir = toPosixPath(path.join(planningPaths(cwd).phases, dirName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1072,7 +1081,8 @@ function cmdInitPhaseOp(cwd: string, phase: string, raw: boolean): void {
|
||||
: config.exa_search,
|
||||
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseDir,
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
phase_dir: phaseDir ? toPosixPath(path.join(cwd, phaseDir)) : null,
|
||||
expected_phase_dir: expectedPhaseDir,
|
||||
phase_number: phaseNumber,
|
||||
phase_name: phaseName,
|
||||
@@ -1089,15 +1099,10 @@ function cmdInitPhaseOp(cwd: string, phase: string, raw: boolean): void {
|
||||
roadmap_exists: fs.existsSync(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
planning_exists: fs.existsSync(planningDir(cwd)),
|
||||
|
||||
state_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'STATE.md')),
|
||||
),
|
||||
roadmap_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
),
|
||||
requirements_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
),
|
||||
// #2376: absolute — see comment on phase_dir above.
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
requirements_path: toPosixPath(path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
};
|
||||
|
||||
if (phaseInfo?.['directory']) {
|
||||
@@ -1106,39 +1111,29 @@ function cmdInitPhaseOp(cwd: string, phase: string, raw: boolean): void {
|
||||
const files = fs.readdirSync(phaseDirFull);
|
||||
const contextFile = findContextMdIn(phaseDirFull);
|
||||
if (contextFile) {
|
||||
result['context_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, contextFile),
|
||||
);
|
||||
result['context_path'] = toPosixPath(path.join(phaseDirFull, contextFile));
|
||||
}
|
||||
const researchFile = files.find(
|
||||
(f) => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md',
|
||||
);
|
||||
if (researchFile) {
|
||||
result['research_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, researchFile),
|
||||
);
|
||||
result['research_path'] = toPosixPath(path.join(phaseDirFull, researchFile));
|
||||
}
|
||||
const verificationFile = files.find(
|
||||
(f) => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md',
|
||||
);
|
||||
if (verificationFile) {
|
||||
result['verification_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, verificationFile),
|
||||
);
|
||||
result['verification_path'] = toPosixPath(path.join(phaseDirFull, verificationFile));
|
||||
}
|
||||
const uatFile = files.find((f) => f.endsWith('-UAT.md') || f === 'UAT.md');
|
||||
if (uatFile) {
|
||||
result['uat_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, uatFile),
|
||||
);
|
||||
result['uat_path'] = toPosixPath(path.join(phaseDirFull, uatFile));
|
||||
}
|
||||
const reviewsFile = files.find(
|
||||
(f) => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md',
|
||||
);
|
||||
if (reviewsFile) {
|
||||
result['reviews_path'] = toPosixPath(
|
||||
path.join(phaseInfo['directory'] as string, reviewsFile),
|
||||
);
|
||||
result['reviews_path'] = toPosixPath(path.join(phaseDirFull, reviewsFile));
|
||||
}
|
||||
} catch {
|
||||
/* intentionally empty */
|
||||
@@ -1177,12 +1172,8 @@ function cmdInitTodos(cwd: string, area: string | undefined, raw: boolean): void
|
||||
created: createdMatch ? createdMatch[1].trim() : 'unknown',
|
||||
title: titleMatch ? titleMatch[1].trim() : 'Untitled',
|
||||
area: todoArea,
|
||||
path: toPosixPath(
|
||||
path.relative(
|
||||
cwd,
|
||||
path.join(planningDir(cwd), 'todos', 'pending', file),
|
||||
),
|
||||
),
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
path: toPosixPath(path.join(planningDir(cwd), 'todos', 'pending', file)),
|
||||
...(severityMatch ? { severity: severityMatch[1].trim() } : {}),
|
||||
});
|
||||
} catch {
|
||||
@@ -1203,12 +1194,9 @@ function cmdInitTodos(cwd: string, area: string | undefined, raw: boolean): void
|
||||
todos,
|
||||
area_filter: area || null,
|
||||
|
||||
pending_dir: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'todos', 'pending')),
|
||||
),
|
||||
completed_dir: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'todos', 'completed')),
|
||||
),
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
pending_dir: toPosixPath(path.join(planningDir(cwd), 'todos', 'pending')),
|
||||
completed_dir: toPosixPath(path.join(planningDir(cwd), 'todos', 'completed')),
|
||||
|
||||
planning_exists: fs.existsSync(planningDir(cwd)),
|
||||
todos_dir_exists: fs.existsSync(path.join(planningDir(cwd), 'todos')),
|
||||
@@ -1346,7 +1334,8 @@ function cmdInitMapCodebase(cwd: string, raw: boolean): void {
|
||||
date: realClock.localToday(),
|
||||
timestamp: realClock.nowIso(),
|
||||
|
||||
codebase_dir: '.planning/codebase',
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
codebase_dir: toPosixPath(path.join(planningRoot(cwd), 'codebase')),
|
||||
|
||||
existing_maps: existingMaps,
|
||||
has_maps: existingMaps.length > 0,
|
||||
@@ -1829,7 +1818,10 @@ function cmdInitProgress(cwd: string, raw: boolean): void {
|
||||
const phaseInfo: Record<string, unknown> = {
|
||||
number: phaseNumber,
|
||||
name: phaseName,
|
||||
directory: phaseDirRel,
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
// phaseDirRel itself stays relative — buildPhaseCompletionProjection
|
||||
// above still joins it against cwd.
|
||||
directory: toPosixPath(path.join(cwd, phaseDirRel)),
|
||||
status,
|
||||
plan_count: plans.length,
|
||||
summary_count: summaries.length,
|
||||
@@ -1918,16 +1910,11 @@ function cmdInitProgress(cwd: string, raw: boolean): void {
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
roadmap_exists: fs.existsSync(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
state_exists: fs.existsSync(path.join(planningDir(cwd), 'STATE.md')),
|
||||
state_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'STATE.md')),
|
||||
),
|
||||
roadmap_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
),
|
||||
project_path: '.planning/PROJECT.md',
|
||||
config_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'config.json')),
|
||||
),
|
||||
// #2376: absolute — see comment on phase_dir in cmdInitExecutePhase.
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
project_path: toPosixPath(path.join(planningDir(cwd), 'PROJECT.md')),
|
||||
config_path: toPosixPath(path.join(planningDir(cwd), 'config.json')),
|
||||
};
|
||||
|
||||
output(withProjectRoot(cwd, result), raw);
|
||||
|
||||
@@ -388,7 +388,9 @@ function buildOnboardProjection(cwd: string, options: BuildOnboardProjectionOpti
|
||||
projectExists,
|
||||
mapReadiness: mapReadinessValue,
|
||||
onboardingSummaryExists,
|
||||
onboardingSummaryPath: toPosixPath(path.relative(cwd, onboardingSummaryPath)),
|
||||
// #2376: absolute (anchored on cwd/project_root), not orchestrator-cwd-relative —
|
||||
// a spawned subagent's own cwd may differ from the orchestrator's.
|
||||
onboardingSummaryPath: toPosixPath(onboardingSummaryPath),
|
||||
hasPlanningArtifacts,
|
||||
missingPlanningFiles,
|
||||
handoffCommands,
|
||||
@@ -410,19 +412,15 @@ function buildOnboardProjection(cwd: string, options: BuildOnboardProjectionOpti
|
||||
doc_candidates: docCandidates,
|
||||
|
||||
onboarding_summary_exists: onboardingSummaryExists,
|
||||
onboarding_summary_path: toPosixPath(path.relative(cwd, onboardingSummaryPath)),
|
||||
// #2376: absolute — see comment on onboardingSummaryPath above.
|
||||
onboarding_summary_path: toPosixPath(onboardingSummaryPath),
|
||||
|
||||
project_path: toPosixPath(path.relative(
|
||||
cwd,
|
||||
fs.existsSync(projectRootPath) ? projectRootPath : projectScopedPath,
|
||||
)),
|
||||
requirements_path: toPosixPath(
|
||||
path.relative(cwd, path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
),
|
||||
roadmap_path: toPosixPath(path.relative(cwd, path.join(planningDir(cwd), 'ROADMAP.md'))),
|
||||
state_path: toPosixPath(path.relative(cwd, path.join(planningDir(cwd), 'STATE.md'))),
|
||||
codebase_dir: toPosixPath(path.relative(cwd, path.join(planningRoot(cwd), 'codebase'))),
|
||||
onboarding_dir: toPosixPath(path.relative(cwd, path.join(planningRoot(cwd), 'onboarding'))),
|
||||
project_path: toPosixPath(fs.existsSync(projectRootPath) ? projectRootPath : projectScopedPath),
|
||||
requirements_path: toPosixPath(path.join(planningDir(cwd), 'REQUIREMENTS.md')),
|
||||
roadmap_path: toPosixPath(path.join(planningDir(cwd), 'ROADMAP.md')),
|
||||
state_path: toPosixPath(path.join(planningDir(cwd), 'STATE.md')),
|
||||
codebase_dir: toPosixPath(path.join(planningRoot(cwd), 'codebase')),
|
||||
onboarding_dir: toPosixPath(path.join(planningRoot(cwd), 'onboarding')),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ const { escapeRegex, normalizePhaseName, extractPhaseToken, parsePhaseFromProse,
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import roadmapParserMod = require('./roadmap-parser.cjs');
|
||||
const { getMilestoneInfo, getMilestonePhaseFilter, extractCurrentMilestone } = roadmapParserMod;
|
||||
import { platformWriteSync, platformReadSync, platformEnsureDir, retryRenameSync } from './shell-command-projection.cjs';
|
||||
import { platformWriteSync, platformReadSync, platformEnsureDir, retryRenameSync, toPosixPath } from './shell-command-projection.cjs';
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import planningWorkspace = require('./planning-workspace.cjs');
|
||||
const { planningDir, planningPaths } = planningWorkspace;
|
||||
@@ -308,6 +308,12 @@ function cmdStateLoad(cwd: string, raw: boolean): void {
|
||||
state_exists: stateExists,
|
||||
roadmap_exists: roadmapExists,
|
||||
config_exists: configExists,
|
||||
// #2376: absolute (anchored on cwd), not orchestrator-cwd-relative — a
|
||||
// spawned subagent's own cwd may differ from the orchestrator's.
|
||||
// debug.md has no init.* call of its own; it reads this field from
|
||||
// `state load` to build debug_file_path for its gsd-debug-session-manager
|
||||
// spawns instead of hardcoding '.planning/debug/{slug}.md'.
|
||||
debug_dir: toPosixPath(path.join(planDir, 'debug')),
|
||||
};
|
||||
|
||||
// For --raw, output a condensed key=value format
|
||||
|
||||
Reference in New Issue
Block a user