Skip to content

feat(deps): resolve semver constraints on git-source dependencies against repo tags #1488

@danielmeppiel

Description

@danielmeppiel

Summary

Git-source dependencies in apm.yml accept only branch names, tag names,
and SHAs as ref: values. Marketplace dependencies (PR #1422) and
registry dependencies (PR #1471) both accept semver ranges (^1.2.0,
~2.1, >=1.0 <2.0). The git source is the odd one out, which forces
authors who depend on a tagged git repo to either pin to an exact tag
(losing patch-level updates) or track a moving branch (losing
determinism).

This issue proposes resolving semver ranges on git-source deps against
the repo's git tags, using the existing RefResolver + tag-pattern
machinery already shipped for the marketplace source.

Motivation

After PR #1471 and PR #1422 land, three of APM's resolution sources speak
semver and one does not:

Source Semver range? Lookup against
Registry Yes Registry /versions
Marketplace Yes (#1422) {name}--v{version} tags
Git No n/a
Local path n/a n/a

A consumer who depends on acme-org/some-skills@^1.2.0 directly from a
git repository (no marketplace, no registry) cannot express that intent
today. They must write ref: v1.5.3 and bump it manually.

Proposal

Accept a semver range or version expression as ref: on git-source
deps (string shorthand owner/repo#^1.2.0 and object form { git: ..., ref: ^1.2.0 }). When the value matches the registry semver grammar
(apm_cli.deps.registry.semver.is_semver_range), resolve it as
follows:

  1. List the repo's tags via the existing RefResolver.list_remote_refs.
  2. Filter tags through two default tag patterns:
  3. Drop pre-release tags by default (matching the existing marketplace
    behavior). An opt-in (e.g. an include_prerelease: true field on the
    object form) follows in a later issue if requested.
  4. Pick the highest tag satisfying the range using
    marketplace.semver.satisfies_range + SemVer ordering.
  5. Record both the constraint and the resolved tag in the lockfile so
    apm install is reproducible and apm update knows what to widen.

Existing ref: semantics are preserved unchanged: any value that
parses as a branch, a tag literal, or a SHA continues to take that
path. Semver routing is opt-in by syntax, not by flag.

Examples

String shorthand:

dependencies:
  apm:
    - acme-org/some-skills#^1.2.0     # resolved to highest v1.x.y tag
    - acme-org/other-skills#main      # unchanged: branch ref
    - acme-org/pinned#v1.5.3          # unchanged: literal tag
    - acme-org/sha-pin#abc1234        # unchanged: SHA

Object form:

dependencies:
  apm:
    - git: https://github.com/acme-org/some-skills
      ref: ~1.2.0
      alias: some-skills

Considerations

  • No new tag-pattern field on git deps in v1. Authors who use a
    non-default tag pattern can declare the dep through a marketplace
    entry (where tagPattern is already supported) or pin to a literal
    tag. We can revisit per-dep tag_pattern: if demand surfaces.
  • Pattern compatibility with Claude Code and PR feat(deps): support marketplace dependencies in plugin.json #1422. Both
    default patterns map to real ecosystems: v{version} is the
    lockstep convention; {name}--v{version} is the Claude/feat(deps): support marketplace dependencies in plugin.json #1422
    per-package convention. The patterns are disjoint regexes, so both
    can be tried in order without ambiguity.
  • Pre-release exclusion default matches marketplace behavior and
    the registry resolver. Authors who genuinely want a pre-release can
    pin it as a literal tag (ref: v2.0.0-beta.1).
  • Lockfile additivity. New fields are constraint, resolved_tag,
    resolved_at on LockedDependency. They are written only for
    git-source semver-resolved deps. The lockfile version stays at v2.

Out of scope

  • Per-dep tag_pattern: override.
  • Pre-release opt-in flag.
  • apm update behavior changes (covered by existing update flow once
    the lockfile carries the constraint).
  • Registry/marketplace changes (those already speak semver).

References

Consumed by

Related (orthogonal)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/package-authoringapm pack/unpack, plugin authoring, vendoring guidance, bundle format.status/needs-triageNew, awaiting maintainer review.theme/portabilityOne manifest, every target. Multi-target deploy, marketplace, packaging, install.type/featureNew capability, new flag, new primitive.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions