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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- `apm compile --watch` now honors `targets: [claude, cursor]` (and every other multi-target / single-target configuration) on every recompile. Previously the watch path bypassed the resolver the one-shot path uses and let `CompilationConfig.from_apm_yml` fall back to the all-families default, silently regenerating `GEMINI.md` after every file edit. The watch path now resolves the effective target via the same helper the one-shot path uses and forwards it as `target=` into both the initial compile and every debounced recompile. (#1345)
- Fixed hook commands using relative paths that break for Claude target (#1310)
- Fixed target not propagating to intermediate CompilationConfig during compilation (#765)
- Fixed direct GitHub API and ADO/GHES `git ls-remote` calls not respecting `PROXY_REGISTRY_ONLY` mode; all four validation code paths (virtual package, GitHub.com API, ADO/GHES git, and parse-failure fallback) now skip outbound network probes and return `True` when proxy-only mode is active. (#615)
Expand Down
83 changes: 81 additions & 2 deletions src/apm_cli/commands/compile/cli.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
"""APM compile command CLI."""

from __future__ import annotations

import sys
from pathlib import Path # noqa: F401
from pathlib import Path
from typing import TYPE_CHECKING

import click

if TYPE_CHECKING:
from ...core.target_detection import CompileTargetType

from ...compilation import AgentsCompiler, CompilationConfig
from ...constants import AGENTS_MD_FILENAME, APM_DIR, APM_MODULES_DIR, APM_YML_FILENAME
from ...core.command_logger import CommandLogger
Expand Down Expand Up @@ -252,6 +258,66 @@ def _family_of(name: str) -> str | None:
return target # single string pass-through


def _resolve_effective_target(
target: str | list[str] | None,
) -> tuple[CompileTargetType, str, str | list[str] | None]:
"""Resolve the CLI --target arg to the compiler-understood effective target.

Mirrors the resolution the one-shot compile path performs (load
apm.yml ``target:`` / ``targets:``, run :func:`_resolve_compile_target`
on both, fall back to :func:`detect_target` for the auto-detect case)
so the watch path can build ``CompilationConfig`` with the same
``target=`` value the one-shot path uses (#1345).

Args:
target: The raw ``--target`` CLI argument (None, str, or list).

Returns:
Tuple ``(effective_target, detection_reason, config_target)`` where
``effective_target`` is what to pass as ``target=`` to
:meth:`CompilationConfig.from_apm_yml`, ``detection_reason`` is the
provenance label, and ``config_target`` is the raw apm.yml value
(str | list | None) for user-facing label rendering.
"""
from ...core.target_detection import detect_target
from ...models.apm_package import APMPackage

config_target = None
apm_yml_path = Path(APM_YML_FILENAME)
if apm_yml_path.exists():
apm_pkg = APMPackage.from_apm_yml(apm_yml_path)
config_target = apm_pkg.target
if config_target is None:
try:
from ...core.apm_yml import parse_targets_field
from ...utils.yaml_io import load_yaml

_raw = load_yaml(apm_yml_path)
if isinstance(_raw, dict):
_yaml_targets = parse_targets_field(_raw)
if _yaml_targets:
config_target = (
_yaml_targets[0] if len(_yaml_targets) == 1 else _yaml_targets
)
except Exception:
pass

compile_target = _resolve_compile_target(target)
compile_config_target = _resolve_compile_target(config_target)

if isinstance(compile_target, frozenset):
return compile_target, "explicit --target flag", config_target
if isinstance(compile_config_target, frozenset) and compile_target is None:
return compile_config_target, "apm.yml target", config_target

detected_target, detection_reason = detect_target(
project_root=Path("."),
explicit_target=compile_target,
config_target=compile_config_target if isinstance(compile_config_target, str) else None,
)
return detected_target, detection_reason, config_target


@click.command(help="Compile APM context into distributed AGENTS.md files")
@click.option(
"--output",
Expand Down Expand Up @@ -455,7 +521,20 @@ def compile(

# Watch mode
if watch:
_watch_mode(output, chatmode, no_links, dry_run, verbose=verbose)
# Resolve the same effective target the one-shot path uses so
# `targets: [claude, cursor]` does not silently regress to the
# all-families fanout on every recompile (#1345).
effective_target, _detection_reason, config_target = _resolve_effective_target(target)
_watch_mode(
output,
chatmode,
no_links,
dry_run,
verbose=verbose,
effective_target=effective_target,
target_label_user=target,
target_label_config=config_target,
)
return

logger.start("Starting context compilation...", symbol="cogs")
Expand Down
Loading
Loading