refactor: scan filenames at resolve, parse only selected agent at preflight

Manifest.resolve() now returns an empty-dict manifest with only directory
paths recorded (home_md, cwd_md). No content is read from any .md file
until load_for_agent() is called for a specific agent at preflight.

- Manifest.from_md_dirs: scan-only, no frontmatter parsing
- Manifest.load_for_agent: parses the selected agent file and its bottle
  chain; works on eager (from_json_obj) manifests too by returning self
- Manifest.all_agent_names: scans filenames in lazy mode
- backend._validate: calls load_for_agent and propagates upgraded spec
- cli/info.py, cli/list.py, cli/start.py: use load_for_agent / all_agent_names
- manifest_extends.py: reverted to original (no partial-resolve helpers)
- manifest_loader.py: only scan_agent_names + load_bottle_chain_from_dir
- Tests updated to call load_for_agent before accessing agents/bottles;
  test_md_agent_repos_deferred renamed to test_md_agent_repos_fails_at_preflight
This commit is contained in:
2026-06-20 02:45:33 +00:00
committed by didericis
parent 996a260a98
commit 3ccd09ed0d
8 changed files with 227 additions and 319 deletions
+10 -9
View File
@@ -217,7 +217,7 @@ class TestAgentGitUserMdLoader(unittest.TestCase):
def test_md_agent_git_user_overlays_bottle(self):
self._write("bottles/dev.md", _BOTTLE_DEV)
self._write("agents/impl.md", _AGENT_WITH_GIT)
m = Manifest.resolve(str(self.home))
m = Manifest.resolve(str(self.home)).load_for_agent("impl")
u = m.bottle_for("impl").git_user
self.assertEqual("agent-name", u.name)
self.assertEqual("bottle@example.com", u.email)
@@ -226,16 +226,17 @@ class TestAgentGitUserMdLoader(unittest.TestCase):
m.git_identity_summary("impl"),
)
def test_md_agent_repos_deferred(self):
"""git-gate.repos on an agent is an error, but deferred into
broken_agents rather than raised at resolve time, so other agents
remain accessible."""
def test_md_agent_repos_fails_at_preflight(self):
"""git-gate.repos on an agent is an error; resolve() still succeeds
so other agents remain accessible, but load_for_agent raises."""
self._write("bottles/dev.md", _BOTTLE_DEV)
self._write("agents/impl.md", _AGENT_WITH_REPOS)
m = Manifest.resolve(str(self.home))
self.assertNotIn("impl", m.agents)
self.assertIn("impl", m.broken_agents)
msg = str(m.broken_agents["impl"])
from bot_bottle.manifest import ManifestError
names = Manifest.resolve(str(self.home))
self.assertIn("impl", names.all_agent_names)
with self.assertRaises(ManifestError) as ctx:
names.load_for_agent("impl")
msg = str(ctx.exception)
self.assertIn("git-gate.repos", msg)
self.assertIn("bottle-only", msg)