Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions amplifier_app_cli/lib/mention_loading/app_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from __future__ import annotations

import logging
from copy import copy
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Protocol
Expand Down Expand Up @@ -126,6 +127,12 @@ def resolve(self, mention: str) -> Path | None:
# === RELATIVE PATHS ===
return self._resolve_relative(mention)

def resolve_relative(self, mention: str, relative_to: Path) -> Path | None:
"""Scope local paths for one load without changing shortcut roots/state."""
scoped = copy(self)
scoped.relative_to = relative_to
return scoped.resolve(mention)

def _resolve_user(self, mention: str) -> Path | None:
"""Resolve @user:path → ~/.amplifier/{path}."""
path = mention[6:] # Remove "@user:"
Expand Down
36 changes: 36 additions & 0 deletions tests/lib/mention_loading/test_resolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,42 @@ def test_resolver_relative_to(temp_context_dirs):
assert path.read_text() == "relative content"


@pytest.mark.asyncio
async def test_installed_foundation_expands_nested_references_with_app_policy(tmp_path, monkeypatch):
"""Exercise the installed dependency, not only the resolver adapter method."""
from amplifier_foundation.mentions import ContentDeduplicator, load_mentions

monkeypatch.chdir(tmp_path)
(tmp_path / "rules").mkdir()
(tmp_path / "rules/AGENTS.md").write_text("Follow @./tasks.md and @workspace.md")
(tmp_path / "rules/tasks.md").write_text("NESTED TASKS")
(tmp_path / "tasks.md").write_text("WRONG WORKSPACE TASKS")
(tmp_path / "workspace.md").write_text("WORKSPACE RULE")
dedup = ContentDeduplicator()
await load_mentions("@rules/AGENTS.md", AppMentionResolver(), dedup)
contents = {entry.content for entry in dedup.get_unique_files()}
assert "NESTED TASKS" in contents
assert "WORKSPACE RULE" in contents
assert "WRONG WORKSPACE TASKS" not in contents


def test_per_call_relative_scope_preserves_shortcuts_and_policy(tmp_path, monkeypatch):
workspace, nested, user, bundle = (tmp_path / name for name in ("workspace", "nested", "user", "bundle"))
for path in (workspace / ".amplifier", nested, user, bundle):
path.mkdir(parents=True)
(path / "rules.md").write_text(str(path))
monkeypatch.chdir(workspace)
monkeypatch.setenv("AMPLIFIER_HOME", str(user))
resolver = AppMentionResolver(bundle_mappings={"bundle": bundle})
assert resolver.resolve_relative("@./rules.md", nested) == nested / "rules.md"
assert resolver.resolve_relative("@project:rules.md", nested) == workspace / ".amplifier/rules.md"
assert resolver.resolve_relative("@user:rules.md", nested) == user / "rules.md"
assert resolver.resolve_relative("@bundle:rules.md", nested) == bundle / "rules.md"
assert resolver.resolve_relative("@../rules.md", nested) is None
assert resolver.relative_to is None
assert resolver.resolve("@./rules.md") is None


def test_resolver_relative_path_syntax(temp_context_dirs, monkeypatch):
"""Test ./relative.md syntax with relative_to."""
base_dir = temp_context_dirs["bundled"]
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading