fix: derive plan path from feature.json in update-agent-context#3069
fix: derive plan path from feature.json in update-agent-context#3069amirreza225 wants to merge 20 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the agent-context extension’s context refresh scripts so that, when no explicit plan_path argument is provided, they derive the active plan.md from .specify/feature.json (written by /speckit-specify) and only fall back to the “most recently modified specs/*/plan.md” heuristic when that source is unavailable or not yet present. It also adds tests to validate the new feature.json-first behavior.
Changes:
- Bash: Prefer
.specify/feature.jsonto resolve the activeplan.md, with mtime fallback retained. - PowerShell: Implement the same “feature.json-first, mtime-second” selection logic and normalize feature paths.
- Tests: Add coverage ensuring feature.json overrides the mtime heuristic (bash + PowerShell where available).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
extensions/agent-context/scripts/bash/update-agent-context.sh |
Uses .specify/feature.json to select the active plan when plan_path isn’t provided; retains mtime fallback. |
extensions/agent-context/scripts/powershell/update-agent-context.ps1 |
Mirrors bash behavior in PowerShell, including absolute-path normalization and mtime fallback. |
tests/extensions/test_update_agent_context_feature_json.py |
Adds tests validating feature.json-first selection and stale-plan avoidance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback
|
All three Copilot comments have been addressed in commit 80600a2:
All 70 tests pass locally. |
Done |
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback
|
Please address Copilot feedback |
bc239d4 to
1786def
Compare
| result = subprocess.run( | ||
| ["bash", str(UPDATE_AGENT_CTX_SH)], | ||
| cwd=tmp_path, | ||
| capture_output=True, | ||
| text=True, | ||
| check=False, | ||
| ) |
| @@ -217,8 +250,9 @@ plans = sorted( | |||
| print(plans[0] if plans else "") | |||
| PY | |||
| )" | |||
| if [[ -n "$_plan_abs" ]]; then | |||
| PLAN_PATH="${_plan_abs#"$PROJECT_ROOT/"}" | |||
| if [[ -n "$_plan_abs" ]]; then | |||
| PLAN_PATH="${_plan_abs#"$PROJECT_ROOT/"}" | |||
| fi | |||
| from tests.extensions.test_extension_agent_context import ( | ||
| BASH, | ||
| POWERSHELL, | ||
| _bash_posix_path, | ||
| _install_agent_context_config, | ||
| _run_bash_agent_context_script, | ||
| _run_powershell_agent_context_script, | ||
| ) | ||
|
|
||
|
|
||
| def _setup_project(root: Path, context_file: str = "CLAUDE.md") -> None: | ||
| """Write agent-context extension config as JSON. | ||
|
|
||
| JSON is valid YAML so bash+PyYAML can parse it, and PowerShell's built-in | ||
| ConvertFrom-Json can parse it without needing powershell-yaml or Python. | ||
| """ | ||
| _install_agent_context_config( | ||
| root, | ||
| context_file=context_file, | ||
| context_markers={ | ||
| "start": "<!-- SPECKIT START -->", | ||
| "end": "<!-- SPECKIT END -->", | ||
| }, | ||
| ) |
|
@mnriem Hi can you run the checks? |
| # feature_directory may be relative or absolute (absolute paths outside PROJECT_ROOT | ||
| # are preserved as-is by _persist_feature_json in common.sh). | ||
| if [[ "$_feature_dir" == /* ]]; then | ||
| _candidate="$_feature_dir/plan.md" | ||
| else | ||
| _candidate="$PROJECT_ROOT/$_feature_dir/plan.md" | ||
| fi |
mnriem
left a comment
There was a problem hiding this comment.
Please address Copilot feedback and fix test & lint errors
Summary
update-agent-context.shandupdate-agent-context.ps1now prefer.specify/feature.json(written by/speckit-specify) over the mtime heuristic when no explicitplan_pathargument is givenspecs/*/plan.mdonly whenfeature.jsonis absent or the derivedplan.mddoes not exist yet (e.g./speckit-planhasn't run yet)feature_directoryvalues in both scripts, normalizing to project-relative paths for the context file outputJoin-Path,IsPathRootedguard (UnixJoin-Pathdoes not treat absolute ChildPaths as "wins"), and manual prefix-strip instead ofGetRelativePathFixes #3067
AI disclosure
This PR was written with AI assistance (Claude Code). All changes were reviewed, tested, and understood by me before submission.
Manual test results
Agent: Claude Code | OS/Shell: macOS/zsh
/speckit.specify→/speckit.planCLAUDE.mdreferences the correct active feature'splan.mdCLAUDE.mdstill points to active feature, not the stale oneTest plan
uv run pytest tests/extensions/test_update_agent_context_feature_json.py— 4 new bash tests pass (2 PS skipped, nopwshon CI)uv run pytest tests/test_agent_config_consistency.py tests/extensions/test_extension_agent_context.py— all 62 existing tests pass