Skip to content
Open
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
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Artifactory archive entry download for virtual file packages (#525)

### Added

- `apm info <package> [field]` command for inspecting package metadata and remote refs
- `apm info <package> versions` field selector lists remote tags and branches via `git ls-remote`
- `apm outdated` command compares locked dependencies against remote refs
- `--parallel-checks` (`-j`) option on `apm outdated` for concurrent remote checks (default: 4)
- Rich progress feedback during `apm outdated` dependency checking
- `--global` flag on `apm info` for inspecting user-scope packages

### Changed

- Scope resolution now happens once via `TargetProfile.for_scope()` and `resolve_targets()` -- integrators no longer need scope-aware parameters (#562)
- Unified integration dispatch table in `dispatch.py` -- both install and uninstall import from one source of truth (#562)
- Hook merge logic deduplicated: three copy-pasted JSON-merge methods replaced with `_integrate_merged_hooks()` + config dict (#562)
- `apm outdated` uses SHA comparison for branch-pinned deps instead of reporting them as `unknown`

### Fixed

Expand Down Expand Up @@ -46,6 +56,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- `apm install` now deploys `.instructions.md` files to `.claude/rules/*.md` for Claude Code, converting `applyTo:` frontmatter to Claude's `paths:` format (#516)
- `apm info <package> [field]` as a top-level command, promoted from `apm deps info`
- `apm info <package> versions` to list available remote tags and branches without cloning
- `apm outdated` to check installed dependencies for available updates

### Changed

Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/guides/dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ apm deps list
apm deps tree

# Get package details
apm deps info apm-sample-package
apm info apm-sample-package
```

### 4. Use Dependencies in Compilation
Expand Down Expand Up @@ -801,7 +801,7 @@ curl -H "Authorization: token $GITHUB_CLI_PAT" https://api.github.com/user

```bash
# Show detailed package information
apm deps info package-name
apm info package-name

# Show full dependency tree
apm deps tree
Expand Down Expand Up @@ -856,4 +856,4 @@ apm compile
- **[Context Guide](../../introduction/how-it-works/)** - Understanding the AI-Native Development framework
- **[Creating Packages](../../introduction/key-concepts/)** - Build your own APM packages

Ready to create your own APM packages? See the [Context Guide](../../introduction/key-concepts/) for detailed instructions on building reusable context collections and agent workflows.
Ready to create your own APM packages? See the [Context Guide](../../introduction/key-concepts/) for detailed instructions on building reusable context collections and agent workflows.
94 changes: 81 additions & 13 deletions docs/src/content/docs/reference/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,79 @@ curl -sSL https://aka.ms/apm-unix | sh
powershell -ExecutionPolicy Bypass -c "irm https://aka.ms/apm-windows | iex"
```

### `apm info` - Show package metadata or remote versions

Show local metadata for an installed package, or query remote refs with a field selector.

```bash
apm info PACKAGE [FIELD] [OPTIONS]
```

**Arguments:**
- `PACKAGE` - Package name, usually `owner/repo` or a short repo name
- `FIELD` - Optional field selector. Supported value: `versions`

**Options:**
- `-g, --global` - Inspect package from user scope (`~/.apm/`)

**Examples:**
```bash
# Show installed package metadata
apm info microsoft/apm-sample-package

# Short-name lookup for an installed package
apm info apm-sample-package

# List remote tags and branches without cloning
apm info microsoft/apm-sample-package versions

# Inspect a package from user scope
apm info microsoft/apm-sample-package -g
```

**Behavior:**
- Without `FIELD`, reads installed package metadata from `apm_modules/`
- Shows package name, version, description, source, install path, context files, workflows, and hooks
- `versions` lists remote tags and branches without cloning the repository
- `versions` does not require the package to be installed locally

### `apm outdated` - Check locked dependencies for updates

Compare locked dependencies against remote refs to detect staleness.

```bash
apm outdated [OPTIONS]
```

**Options:**
- `-g, --global` - Check user-scope dependencies from `~/.apm/`
- `-v, --verbose` - Show extra detail for outdated packages, including available tags
- `-j, --parallel-checks N` - Max concurrent remote checks (default: 4, 0 = sequential)

**Examples:**
```bash
# Check project dependencies
apm outdated

# Check user-scope dependencies
apm outdated --global

# Show available tags for outdated packages
apm outdated --verbose

# Use 8 parallel checks for large dependency sets
apm outdated -j 8
```

**Behavior:**
- Reads the current lockfile (`apm.lock.yaml`; legacy `apm.lock` is migrated automatically)
- For tag-pinned deps: compares the locked semver tag against the latest available remote tag
- For branch-pinned deps: compares the locked commit SHA against the remote branch tip SHA
- For deps with no ref: compares against the default branch (main/master) tip SHA
- Displays `Package`, `Current`, `Latest`, and `Status` columns
- Status values are `up-to-date`, `outdated`, and `unknown`
- Local dependencies and Artifactory dependencies are skipped

### `apm deps` - Manage APM package dependencies

Manage APM package dependencies with installation status, tree visualization, and package information.
Expand Down Expand Up @@ -680,32 +753,27 @@ company-website (local)
- Version numbers from dependency package metadata
- Version information for each dependency

#### `apm deps info` - Show detailed package information
#### `apm deps info` - Alias for `apm info`

Display comprehensive information about a specific installed package.
Backward-compatible alias for `apm info PACKAGE_NAME`.

```bash
apm deps info PACKAGE_NAME
```

**Arguments:**
- `PACKAGE_NAME` - Name of the package to show information about
- `PACKAGE_NAME` - Installed package name to inspect

**Examples:**
```bash
# Show details for compliance rules package
# Show installed package metadata
apm deps info compliance-rules

# Show info for design guidelines package
apm deps info design-guidelines
```

**Output includes:**
- Complete package metadata (name, version, description, author)
- Source repository and installation details
- Detailed context file counts by type
- Agent workflow descriptions and counts
- Installation path and status
**Notes:**
- Produces the same local metadata output as `apm info PACKAGE_NAME`
- Use `apm info` in new docs and scripts
- For remote refs, use `apm info PACKAGE_NAME versions`

#### `apm deps clean` - Remove all APM dependencies

Expand Down
4 changes: 3 additions & 1 deletion packages/apm-guide/.apm/skills/apm-usage/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
| `apm prune` | Remove orphaned packages | `--dry-run` |
| `apm deps list` | List installed packages | `-g` global, `--all` both scopes |
| `apm deps tree` | Show dependency tree | -- |
| `apm deps info PKG` | Show package details | -- |
| `apm info PKG [FIELD]` | Show package details or remote refs | `-g` global, `FIELD=versions` |
| `apm outdated` | Check locked deps via SHA/semver comparison | `-g` global, `-v` verbose, `-j N` parallel checks |
| `apm deps info PKG` | Alias for `apm info PKG` local metadata | -- |
| `apm deps clean` | Clean dependency cache | `--dry-run`, `-y` skip confirm |
| `apm deps update [PKGS...]` | Update specific packages | `--verbose`, `--force`, `--target`, `--parallel-downloads N` |

Expand Down
4 changes: 4 additions & 0 deletions src/apm_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
from apm_cli.commands.compile import compile as compile_cmd
from apm_cli.commands.config import config
from apm_cli.commands.deps import deps
from apm_cli.commands.info import info as info_cmd
from apm_cli.commands.init import init
from apm_cli.commands.install import install
from apm_cli.commands.list_cmd import list as list_cmd
from apm_cli.commands.marketplace import marketplace, search as marketplace_search
from apm_cli.commands.mcp import mcp
from apm_cli.commands.outdated import outdated as outdated_cmd
from apm_cli.commands.pack import pack_cmd, unpack_cmd
from apm_cli.commands.prune import prune
from apm_cli.commands.run import preview, run
Expand Down Expand Up @@ -57,6 +59,7 @@ def cli(ctx):
# Register command groups
cli.add_command(audit)
cli.add_command(deps)
cli.add_command(info_cmd, name="info")
cli.add_command(pack_cmd, name="pack")
cli.add_command(unpack_cmd, name="unpack")
cli.add_command(init)
Expand All @@ -71,6 +74,7 @@ def cli(ctx):
cli.add_command(config)
cli.add_command(runtime)
cli.add_command(mcp)
cli.add_command(outdated_cmd, name="outdated")
cli.add_command(marketplace)
cli.add_command(marketplace_search, name="search")

Expand Down
114 changes: 4 additions & 110 deletions src/apm_cli/commands/deps/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,8 @@ def update(packages, verbose, force, target, parallel_downloads, global_):
@click.argument('package', required=True)
def info(package: str):
"""Show detailed information about a specific package including context files and workflows."""
from ..info import resolve_package_path, display_package_info

logger = CommandLogger("deps-info")

project_root = Path(".")
Expand All @@ -672,113 +674,5 @@ def info(package: str):
logger.progress("Run 'apm install' to install dependencies first")
sys.exit(1)

# Find the package directory - handle org/repo and deep sub-path structures
package_path = None
# First try direct path match (handles any depth: org/repo, org/repo/subdir/pkg)
direct_match = apm_modules_path / package
if direct_match.is_dir() and (
(direct_match / APM_YML_FILENAME).exists() or (direct_match / SKILL_MD_FILENAME).exists()
):
package_path = direct_match
else:
# Fallback: scan org/repo structure (2-level) for short package names
for org_dir in apm_modules_path.iterdir():
if org_dir.is_dir() and not org_dir.name.startswith('.'):
for package_dir in org_dir.iterdir():
if package_dir.is_dir() and not package_dir.name.startswith('.'):
if package_dir.name == package or f"{org_dir.name}/{package_dir.name}" == package:
package_path = package_dir
break
if package_path:
break

if not package_path:
logger.error(f"Package '{package}' not found in apm_modules/")
logger.progress("Available packages:")

for org_dir in apm_modules_path.iterdir():
if org_dir.is_dir() and not org_dir.name.startswith('.'):
for package_dir in org_dir.iterdir():
if package_dir.is_dir() and not package_dir.name.startswith('.'):
click.echo(f" - {org_dir.name}/{package_dir.name}")
sys.exit(1)

try:
# Load package information
package_info = _get_detailed_package_info(package_path)

# Display with Rich panel if available
try:
from rich.panel import Panel
from rich.console import Console
from rich.text import Text
console = Console()

content_lines = []
content_lines.append(f"[bold]Name:[/bold] {package_info['name']}")
content_lines.append(f"[bold]Version:[/bold] {package_info['version']}")
content_lines.append(f"[bold]Description:[/bold] {package_info['description']}")
content_lines.append(f"[bold]Author:[/bold] {package_info['author']}")
content_lines.append(f"[bold]Source:[/bold] {package_info['source']}")
content_lines.append(f"[bold]Install Path:[/bold] {package_info['install_path']}")
content_lines.append("")
content_lines.append("[bold]Context Files:[/bold]")

for context_type, count in package_info['context_files'].items():
if count > 0:
content_lines.append(f" * {count} {context_type}")

if not any(count > 0 for count in package_info['context_files'].values()):
content_lines.append(" * No context files found")

content_lines.append("")
content_lines.append("[bold]Agent Workflows:[/bold]")
if package_info['workflows'] > 0:
content_lines.append(f" * {package_info['workflows']} executable workflows")
else:
content_lines.append(" * No agent workflows found")

if package_info.get('hooks', 0) > 0:
content_lines.append("")
content_lines.append("[bold]Hooks:[/bold]")
content_lines.append(f" * {package_info['hooks']} hook file(s)")

content = "\n".join(content_lines)
panel = Panel(content, title=f"[i] Package Info: {package}", border_style="cyan")
console.print(panel)

except ImportError:
# Fallback text display
click.echo(f"[i] Package Info: {package}")
click.echo("=" * 40)
click.echo(f"Name: {package_info['name']}")
click.echo(f"Version: {package_info['version']}")
click.echo(f"Description: {package_info['description']}")
click.echo(f"Author: {package_info['author']}")
click.echo(f"Source: {package_info['source']}")
click.echo(f"Install Path: {package_info['install_path']}")
click.echo("")
click.echo("Context Files:")

for context_type, count in package_info['context_files'].items():
if count > 0:
click.echo(f" * {count} {context_type}")

if not any(count > 0 for count in package_info['context_files'].values()):
click.echo(" * No context files found")

click.echo("")
click.echo("Agent Workflows:")
if package_info['workflows'] > 0:
click.echo(f" * {package_info['workflows']} executable workflows")
else:
click.echo(" * No agent workflows found")

if package_info.get('hooks', 0) > 0:
click.echo("")
click.echo("Hooks:")
click.echo(f" * {package_info['hooks']} hook file(s)")

except Exception as e:
logger.error(f"Error reading package information: {e}")
sys.exit(1)
package_path = resolve_package_path(package, apm_modules_path, logger)
display_package_info(package, package_path, logger)
Loading
Loading