Skip to content

Commit f76c6f8

Browse files
committed
Address review: fix init ordering, test coverage, and hermes inventory
- Move agent-context extension install after init-options.json is saved so skill registration can read ai_skills + integration key - Write extension config after install (avoids template overwriting context_file) - Fix test_defaults_when_markers_field_missing to truly test missing markers key - Update hermes tests to allow extension-installed agent-context skill
1 parent 2c55eab commit f76c6f8

4 files changed

Lines changed: 58 additions & 34 deletions

File tree

src/specify_cli/commands/init.py

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -394,8 +394,8 @@ def init(
394394
("chmod", "Ensure scripts executable"),
395395
("constitution", "Constitution setup"),
396396
("git", "Install git extension"),
397-
("agent-context", "Install agent-context extension"),
398397
("workflow", "Install bundled workflow"),
398+
("agent-context", "Install agent-context extension"),
399399
("final", "Finalize"),
400400
]:
401401
tracker.add(key, label)
@@ -507,28 +507,6 @@ def init(
507507
else:
508508
tracker.skip("git", "--no-git flag")
509509

510-
# --- agent-context extension (bundled, auto-installed) ---
511-
try:
512-
from ..extensions import ExtensionManager as _ExtMgr
513-
bundled_ac = _locate_bundled_extension("agent-context")
514-
if bundled_ac:
515-
ac_mgr = _ExtMgr(project_path)
516-
if ac_mgr.registry.is_installed("agent-context"):
517-
tracker.complete("agent-context", "already installed")
518-
else:
519-
ac_mgr.install_from_directory(
520-
bundled_ac, get_speckit_version()
521-
)
522-
tracker.complete("agent-context", "extension installed")
523-
else:
524-
tracker.skip("agent-context", "bundled extension not found")
525-
except Exception as ac_err:
526-
sanitized_ac = str(ac_err).replace('\n', ' ').strip()
527-
tracker.error(
528-
"agent-context",
529-
f"extension install failed: {sanitized_ac[:120]}",
530-
)
531-
532510
try:
533511
bundled_wf = _locate_bundled_workflow("speckit")
534512
if bundled_wf:
@@ -574,8 +552,33 @@ def init(
574552
init_opts["ai_skills"] = True
575553
save_init_options(project_path, init_opts)
576554

555+
# --- agent-context extension (bundled, auto-installed) ---
556+
# Installed after init-options.json is written so that skill
557+
# registration can read ai_skills + integration key.
558+
try:
559+
from ..extensions import ExtensionManager as _ExtMgr
560+
bundled_ac = _locate_bundled_extension("agent-context")
561+
if bundled_ac:
562+
ac_mgr = _ExtMgr(project_path)
563+
if ac_mgr.registry.is_installed("agent-context"):
564+
tracker.complete("agent-context", "already installed")
565+
else:
566+
ac_mgr.install_from_directory(
567+
bundled_ac, get_speckit_version()
568+
)
569+
tracker.complete("agent-context", "extension installed")
570+
else:
571+
tracker.skip("agent-context", "bundled extension not found")
572+
except Exception as ac_err:
573+
sanitized_ac = str(ac_err).replace('\n', ' ').strip()
574+
tracker.error(
575+
"agent-context",
576+
f"extension install failed: {sanitized_ac[:120]}",
577+
)
578+
577579
# Write context_file to the agent-context extension config
578-
# (not init-options.json — that is the legacy location).
580+
# AFTER the extension install (which copies the template config
581+
# with an empty context_file).
579582
if resolved_integration.context_file:
580583
_update_agent_context_config_file(
581584
project_path,

tests/extensions/test_extension_agent_context.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,13 @@ def test_defaults_when_ext_config_missing(self, tmp_path):
115115
assert end == IntegrationBase.CONTEXT_MARKER_END
116116

117117
def test_defaults_when_markers_field_missing(self, tmp_path):
118-
_write_ext_config(tmp_path, context_file="CLAUDE.md")
118+
"""Config file exists with context_file but no context_markers key."""
119+
cfg_path = (
120+
tmp_path / ".specify" / "extensions" / "agent-context"
121+
/ "agent-context-config.yml"
122+
)
123+
cfg_path.parent.mkdir(parents=True, exist_ok=True)
124+
cfg_path.write_text("context_file: CLAUDE.md\n", encoding="utf-8")
119125
i = _CtxIntegration()
120126
start, end = i._resolve_context_markers(tmp_path)
121127
assert start == IntegrationBase.CONTEXT_MARKER_START

tests/integrations/test_integration_copilot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,9 +644,9 @@ def test_complete_file_inventory_skills_sh(self, tmp_path):
644644
assert result.exit_code == 0, f"init failed: {result.output}"
645645
actual = sorted(p.relative_to(project).as_posix() for p in project.rglob("*") if p.is_file())
646646
expected = sorted([
647-
# Skill files (core commands only — extension commands are not
648-
# rendered as skills, they live in .specify/extensions/)
647+
# Skill files (core + extension-installed agent-context command)
649648
*[f".github/skills/speckit-{cmd}/SKILL.md" for cmd in self._SKILL_COMMANDS],
649+
".github/skills/speckit-agent-context-update/SKILL.md",
650650
# Context file
651651
".github/copilot-instructions.md",
652652
# Bundled agent-context extension

tests/integrations/test_integration_hermes.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,15 @@ def test_complete_file_inventory_sh(self, tmp_path, monkeypatch):
241241
p.relative_to(project).as_posix()
242242
for p in project.rglob("*") if p.is_file()
243243
)
244-
# Ensure no .hermes/skills/speckit-*/SKILL.md in project dir
245-
hermes_skill_files = [f for f in actual if f.startswith(".hermes/skills/speckit-")]
244+
# Ensure no core .hermes/skills/speckit-*/SKILL.md in project dir
245+
# (extension-installed skills like agent-context-update may appear)
246+
hermes_skill_files = [
247+
f for f in actual
248+
if f.startswith(".hermes/skills/speckit-")
249+
and "agent-context" not in f
250+
]
246251
assert hermes_skill_files == [], (
247-
f"Expected no local SKILL.md files, found: {hermes_skill_files}"
252+
f"Expected no local core SKILL.md files, found: {hermes_skill_files}"
248253
)
249254
# Ensure the marker exists (empty dir won't appear in file listing)
250255
assert (project / ".hermes" / "skills").is_dir()
@@ -274,9 +279,15 @@ def test_complete_file_inventory_ps(self, tmp_path, monkeypatch):
274279
p.relative_to(project).as_posix()
275280
for p in project.rglob("*") if p.is_file()
276281
)
277-
hermes_skill_files = [f for f in actual if f.startswith(".hermes/skills/speckit-")]
282+
# Ensure no core .hermes/skills/speckit-*/SKILL.md in project dir
283+
# (extension-installed skills like agent-context-update may appear)
284+
hermes_skill_files = [
285+
f for f in actual
286+
if f.startswith(".hermes/skills/speckit-")
287+
and "agent-context" not in f
288+
]
278289
assert hermes_skill_files == [], (
279-
f"Expected no local SKILL.md files, found: {hermes_skill_files}"
290+
f"Expected no local core SKILL.md files, found: {hermes_skill_files}"
280291
)
281292
assert (project / ".hermes" / "skills").is_dir()
282293

@@ -342,6 +353,10 @@ def test_ai_hermes_without_ai_skills_auto_promotes(self, tmp_path, monkeypatch):
342353
assert (home / ".hermes" / "skills" / "speckit-plan" / "SKILL.md").exists()
343354
# Local marker should exist
344355
assert (target / ".hermes" / "skills").is_dir()
345-
# No SKILL.md files in project-local dir
346-
local_skills = list((target / ".hermes" / "skills").iterdir())
356+
# No core SKILL.md files in project-local dir
357+
# (extension-installed skills like agent-context-update may appear)
358+
local_skills = [
359+
d for d in (target / ".hermes" / "skills").iterdir()
360+
if "agent-context" not in d.name
361+
]
347362
assert local_skills == [], f"Local skills dir should be empty, got: {local_skills}"

0 commit comments

Comments
 (0)