fix(#2376): emit absolute subagent-facing paths from init/state, convert workflow literals (#2428)

* 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:
Tom Boucher
2026-07-19 15:43:48 -04:00
committed by GitHub
parent d04e287fa9
commit 1a46bc068a
42 changed files with 905 additions and 510 deletions

View File

@@ -11,7 +11,7 @@ const assert = require('node:assert/strict');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const { runGsdTools, createTempDir, createTempProject, cleanup } = require('./helpers.cjs');
const { createFixture } = require('./fixtures/index.cjs');
function writePassedVerification(tmpDir, phaseDirName, paddedPhase) {
@@ -870,6 +870,44 @@ describe('cmdStateLoad (state load)', () => {
});
});
// ─────────────────────────────────────────────────────────────────────────────
// #2376: cmdStateLoad's *_dir/*_path fields must resolve regardless of the
// calling process's own cwd, not just the orchestrator's — debug.md has no
// init.* call of its own and reads debug_dir from `state load` to build
// debug_file_path for its gsd-debug-session-manager spawns instead of
// hardcoding '.planning/debug/{slug}.md'. See tests/init.test.cjs's matching
// '#2376 — init.* path fields resolve...' describe block for the established
// pattern (spawn gsd-tools with its OS-level process cwd pointed at an
// unrelated decoy directory while passing the real project root via --cwd).
// ─────────────────────────────────────────────────────────────────────────────
describe('#2376 — state load emits absolute debug_dir regardless of process cwd', () => {
let projectDir;
let decoyDir;
beforeEach(() => {
projectDir = createFixture();
decoyDir = createTempDir('gsd-2376-decoy-');
});
afterEach(() => {
cleanup(projectDir);
cleanup(decoyDir);
});
test('state load emits absolute debug_dir field that resolves from a different process cwd (previously absent)', () => {
fs.mkdirSync(path.join(projectDir, '.planning', 'debug'), { recursive: true });
const result = runGsdTools(['state', 'load', '--cwd', projectDir], decoyDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const output = JSON.parse(result.output);
assert.ok('debug_dir' in output, 'cmdStateLoad must now emit debug_dir (#2376)');
assert.ok(path.isAbsolute(output.debug_dir), `debug_dir must be absolute, got: "${output.debug_dir}"`);
assert.ok(fs.existsSync(output.debug_dir), `debug_dir must resolve to the real directory: "${output.debug_dir}"`);
});
});
describe('cmdStateGet (state get)', () => {
let tmpDir;