Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
a2b40cc
chore(cli): scaffold branch for install command (issue #8)
maiconfz Jul 22, 2026
9c171de
feat: implement single-package install command (issue #8)
maiconfz Jul 22, 2026
455fedc
fix(install): harden rollback, scope resolution, and error handling
maiconfz Jul 22, 2026
2998909
fix(install): satisfy CodeQL zipslip guard on archive extract paths
maiconfz Jul 22, 2026
cac10a3
fix(install): inline CodeQL zipslip checks on archive entry names
maiconfz Jul 22, 2026
1fc7c06
fix: address Copilot review on path checks and CLI exit
maiconfz Jul 22, 2026
08cd712
fix(install): add disallowed payload scan and symlink extract guard
maiconfz Jul 23, 2026
0f6c8ef
fix(install): align extract path checks and JSON install docs
maiconfz Jul 23, 2026
a0200c1
fix(install): tighten zip scan rules and persistence test ranges
maiconfz Jul 23, 2026
ea83e70
fix(install): align persistence test and CodeQL traversal guard
maiconfz Jul 23, 2026
91faaac
fix(install): use Claude-specific frontmatter error labels
maiconfz Jul 23, 2026
ff91391
fix(install): refuse overwrite on extract and tidy imports
maiconfz Jul 23, 2026
3812428
fix(install): align missing compatibility default with schema
maiconfz Jul 23, 2026
b598ab1
fix(install): validate lock before writing agents.json
maiconfz Jul 23, 2026
ba2e5fe
fix(cli): add stable registry error codes for JSON output
maiconfz Jul 23, 2026
a103ee8
fix(cli): keep install JSON output machine-readable
maiconfz Jul 23, 2026
667fdb0
fix(install): inline CodeQL zipslip guards before extract writes
maiconfz Jul 23, 2026
68c1f2e
fix(install): require explicit metadata compatibility for install
maiconfz Jul 23, 2026
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
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ npm run build
node dist/bin/agents-repo.js <command>
```

Commands (`install`, `search`, and more) land in later milestones. The `init`
command is available to bootstrap `agents.json`. See
[docs/commands/init.md](docs/commands/init.md).
Commands (`search`, `list`, and more) land in later milestones. The `init` and
`install` commands are available today. See
[docs/commands/init.md](docs/commands/init.md) and
[docs/commands/install.md](docs/commands/install.md).

## Stack

Expand Down Expand Up @@ -52,6 +53,7 @@ npm run env:check && npm run lint:all && npm run typecheck && npm test && npm ru
| Command | Documentation |
| --- | --- |
| `init` | [docs/commands/init.md](docs/commands/init.md) |
| `install` / `i` | [docs/commands/install.md](docs/commands/install.md) |

## IDE Agent Instructions

Expand Down
49 changes: 35 additions & 14 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ application and infrastructure APIs consumed by commands.
The config module implements schema-gated `agents.json` resolution, merge
semantics, conflict detection, environment overrides, and `agents-lock.json`
I/O per [`specs/config-schema.md`](../specs/config-schema.md) and
[`specs/lock-schema.md`](../specs/lock-schema.md). The `init` command (#7)
consumes these APIs; `install` follows in issue #8.
[`specs/lock-schema.md`](../specs/lock-schema.md). The `init` command (#7) and
`install` command (#8) consume these APIs.

### Delivered in issue #5

Expand All @@ -77,8 +77,25 @@ consumes these APIs; `install` follows in issue #8.

Product documentation: [commands/init.md](commands/init.md).

Install commands (#8) pass `ResolvedAgentsConfig.registry` to
`getRegistrySourceConfig()` from the registry module (replacing the deferred
### Delivered in issue #8 (`install`)

| Area | CLI path | Notes |
| --- | --- | --- |
| Install orchestration | `install/application/installService.ts` | Full pipeline per protocol |
| Version pick | `install/application/resolveInstallVersion.ts` | Semver range + ad-hoc pick |
| Target validation | `install/application/validateInstallTarget.ts` | Index, metadata, manifest |
| Lock ref resolution | `install/application/resolveLockRef.ts` | Concrete ref for lock writes |
| Extract scope | `install/application/installScope.ts` | Project vs global paths |
| Persistence | `install/application/installPersistence.ts` | Config + lock updates |
| Download / verify / scan / extract | `install/infrastructure/` | ZIP pipeline + path remap |
| Version metadata fetch | `registry/infrastructure/registryRepository.ts` | `loadPackageMetadata` |
| `install` command | `cli/presentation/installCommand.ts` | Commander wiring |
| Global `--dry-run` / `--no-save` | `cli/presentation/createCliProgram.ts` | Root install flags |

Product documentation: [commands/install.md](commands/install.md).

Install commands pass `ResolvedAgentsConfig.registry` to
`resolveRegistryFetchSourceConfig()` from the registry module (replacing the deferred
`registrySourceSettings.ts` webapp port).

## Registry module — webapp parity (issue #4)
Expand Down Expand Up @@ -142,23 +159,26 @@ for `init` suggestions per [`specs/target-detection.md`](../specs/target-detecti
are skipped silently; a `none` result may therefore hide present-but-inaccessible
markers—`init` adds marker detail in verbose mode when detection is ambiguous.

## Install module — webapp URL logic + CLI extensions
## Install module — download, verify, extract (issue #8)

The webapp does not HTTP-download ZIP artifacts. It builds download URLs via
`getPackageDownloadTargets` in `homePageCatalogState.ts` and
`buildRegistryArtifactUrl` in `registrySourceUrl.ts`. The CLI reuses those
registry helpers (see `application/resolveArtifact.ts`) and will add download,
registry helpers (see `application/resolveArtifact.ts`) and adds download,
verification, and extraction per [`specs/cli-protocol.md`](../specs/cli-protocol.md).

| Concern | Webapp reference | CLI responsibility |
| --- | --- | --- |
| Artifact URL resolution | `homePageCatalogState.ts` | `registry/application/resolveArtifact.ts` |
| Manifest fetch + validation | — | `registry/infrastructure/registryRepository.ts` (issue #4) |
| Semver version pick | — | `install/application/` (issue #8) |
| SHA-256 verify | — | `install/infrastructure/` (protocol step 9) |
| ZIP security scan | — | `install/infrastructure/` (protocol step 10) |
| Extract to target paths | — | `install/infrastructure/` per [registry install-targets](https://github.com/agents-repo/registry/blob/main/specs/install-targets.md) |
| Config and lock writes | — | Delegates to `config/` (protocol step 12) |
| Manifest + metadata fetch | — | `registry/infrastructure/registryRepository.ts` |
| Semver version pick | — | `install/application/resolveInstallVersion.ts` |
| SHA-256 verify | — | `install/infrastructure/sha256Verifier.ts` |
| ZIP security scan | — | `install/infrastructure/zipSecurityScanner.ts` |
| Extract to target paths | — | `install/infrastructure/packageExtractor.ts` |
| Config and lock writes | — | `install/application/installPersistence.ts` |

**Dependencies:** `adm-zip` (extract), `gray-matter` (agent frontmatter scan), `semver`
(version pick and registry ref resolution).

### Install pipeline overview

Expand All @@ -168,13 +188,13 @@ verification, and extraction per [`specs/cli-protocol.md`](../specs/cli-protocol
3. Fetch packages/index.json -> registry/
4. Resolve package id -> registry/
5. Fetch versions/manifest.json -> registry/ (issue #4)
6. Pick version (semver) -> install/application/ (issue #8)
6. Pick version (semver) -> install/application/
7. Pick artifact for install target -> registry/application/ + install/
8. Download ZIP -> install/infrastructure/
9. Verify SHA-256 -> install/infrastructure/
10. ZIP security scan -> install/infrastructure/
11. Extract package -> install/infrastructure/
12. Update agents.json + lock -> config/
12. Update agents.json + lock -> config/ + install/application/
```

See [`specs/cli-protocol.md`](../specs/cli-protocol.md) for normative step
Expand All @@ -191,5 +211,6 @@ details.
## Related docs

- [commands/init.md](commands/init.md) — `init` command usage
- [commands/install.md](commands/install.md) — `install` command usage
- [architecture/ddd-decision.md](architecture/ddd-decision.md)
- [development.md](development.md)
18 changes: 8 additions & 10 deletions docs/architecture/ddd-decision.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ registration, and global option hooks.
- `src/modules/registry/` — Registry index, manifest, and artifact URL
resolution; copy-adapted from the webapp registry module (implemented in
issue #4).
- `src/modules/install/` — Planned download, SHA-256 verification, ZIP security
scan, and extract packages per install target.
- `src/modules/install/` — Download, SHA-256 verification, ZIP security scan, and
extract packages per install target (implemented in issue #8).
- `src/modules/target/` — Detection of IDE/project install targets from filesystem
markers (implemented in issue #6; consumed by `init` in issue #7).

Expand Down Expand Up @@ -70,12 +70,9 @@ See [ARCHITECTURE.md](../ARCHITECTURE.md) for the webapp-to-CLI file mapping.
## Global Flags (M0)

Issue #3 registers root-level `--json` and `--verbose`. Issue #7 adds `--yes` /
`-y` for non-interactive conflict handling on `init` (and future `install`).

Deferred to later command issues:

- `--dry-run` — install resolve-only mode
- `--no-save` — skip config and lock writes
`-y` for non-interactive conflict handling on `init` and `install`. Issue #8
adds `--dry-run` and `--no-save` for install resolve-only mode and skipped
config/lock writes.

`DEBUG` env override for verbose logging is documented in
`specs/command-contracts.md` and will be wired when logging is implemented.
Expand All @@ -85,8 +82,9 @@ Deferred to later command issues:
Module directories and the Commander root program are scaffolded in issue #3.
The registry module (issue #4) and config module (issue #5) are implemented.
Install target detection (issue #6) is implemented in `target/`. The `init`
command (issue #7) wires config and target modules through `InitService`.
Install pipeline and remaining command wiring are tracked in downstream issues.
command (issue #7) wires config and target modules through `InitService`. The
`install` command (issue #8) wires config, registry, and install modules through
`InstallService`. Remaining command wiring is tracked in downstream issues.

## Why This Decision Exists

Expand Down
151 changes: 151 additions & 0 deletions docs/commands/install.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# `install` command

Install a single package from the registry: resolve version and artifact for the
active install target, download the ZIP, verify integrity, scan for unsafe paths,
extract into the project (or global directory), and update `agents.json` and
`agents-lock.json` unless disabled.

Bulk `install` (sync all `packages` entries) is tracked in issue #9.

## Usage

```bash
agents-repo install <package-id> [options]
agents-repo i <package-id> [options]
```

`<package-id>` is a qualified id (for example `agents-repo/sample-agent`) or an
index alias defined in `packages/index.json`.

## Flags

| Flag | Scope | Description |
| --- | --- | --- |
| `--target <id>` | install | Override install target for this invocation |
| `--global` / `-g` | install | Global extract; single-package skips config/lock writes |
| `--yes` / `-y` | install / global | Waive dual-definition mismatches with warnings |
| `--dry-run` | global | Resolve through artifact selection; no download, extract, or save |
| `--no-save` | global | Skip `agents.json` and lock writes after a successful extract |
| `--json` | global | Machine-readable success and error output |
| `--verbose` | global | Detailed logging |

`--dry-run` and `--no-save` are root-level flags (`agents-repo --dry-run install …`).

## Behavior

### Prerequisites

- An install target must be available from `agents.json` or `--target`. Without
either, the command exits `3`.
- Run `agents-repo init --target <id>` first when starting from an empty project.

### Version selection

| Condition | Version pick |
| --- | --- |
| Existing `packages[<id>]` range in config | Highest matching manifest version (no prereleases) |
| Ad-hoc install (no `packages` entry) | Highest stable manifest version (no prereleases) |

### Registry resolution

Install loads the catalog, package manifest, and version-scoped `metadata.json`.
Target support is validated against index `installTargets` (when present),
metadata `compatibility.targets`, and manifest artifacts.

### Extract scope

| Scope | Extract root | Config / lock writes |
| --- | --- | --- |
| Project (default) | Project cwd | Updates config/lock unless `--no-save` / `--dry-run` |
| Global (`-g`) | Global config dir | Skips project config on single-package install |

Ad-hoc project installs add `packages[<id>] = ^<resolved-version>` unless
`--no-save` or `--dry-run`.

### Install pipeline

The command follows [`specs/cli-protocol.md`](../../specs/cli-protocol.md):

1. Load config (with env overrides)
2. Resolve registry ref (including major-line aliases such as `v2.x`)
3. Fetch catalog, manifest, and metadata
4. Pick version and artifact for the install target
5. Download ZIP, verify SHA-256, run ZIP security scan
6. Extract using registry install-target path rules
7. Persist config and lock when allowed

`--dry-run` stops after step 4 and prints the resolved install plan.

### Environment overrides

| Variable | Effect |
| --- | --- |
| `AGENTS_REPO_CONFIG` | Absolute path to `agents.json` |
| `AGENTS_REPO_REGISTRY_URL` | Overrides `registry.url` after file resolution |

## Exit codes

| Code | Meaning |
| --- | --- |
| `0` | Success (or successful `--dry-run`) |
| `1` | Runtime failure (network, I/O, ZIP security, checksum mismatch) |
| `2` | Usage error |
| `3` | Validation failure (missing target, unsupported target, package not found, schema errors) |
| `4` | Dual-definition conflict in config (without `--yes`) |

## Examples

Install into a configured project:

```bash
agents-repo init --target cursor
agents-repo install agents-repo/sample-agent
# Installed agents-repo/sample-agent@1.0.0 for target cursor into /path/to/project
```

Resolve only:

```bash
agents-repo --dry-run install agents-repo/sample-agent
# Would install agents-repo/sample-agent@1.0.0 for target cursor into /path/to/project
```

Override target for one invocation:

```bash
agents-repo install agents-repo/sample-agent --target github-copilot
```

Extract globally without updating project config:

```bash
agents-repo install -g agents-repo/sample-agent --target cursor
```

### JSON output

With `--json`, successful installs print one JSON object on stdout:

```json
{
"packageId": "agents-repo/sample-agent",
"version": "1.0.0",
"target": "cursor",
"extractRoot": "/path/to/project",
"artifactUrl": "https://registry.example/.../1.0.0-cursor.zip",
"saved": true,
"dryRun": false,
"global": false,
"noSave": false,
"warnings": []
}
Comment thread
maiconfz marked this conversation as resolved.
Comment thread
maiconfz marked this conversation as resolved.
```

Errors use a single JSON object on stderr: `{"error":{"code":"...","message":"..."}}`.

## Related specs

- [cli-protocol.md](../../specs/cli-protocol.md) — install pipeline steps
- [command-contracts.md](../../specs/command-contracts.md) — flags and exit codes
- [config-schema.md](../../specs/config-schema.md) — `agents.json` merge rules
- [lock-schema.md](../../specs/lock-schema.md) — lockfile integrity fields
6 changes: 5 additions & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ npm install-scripts approve <name>@<version>

Commit the resulting `allowScripts` update with your dependency change.

Install support adds runtime dependencies `adm-zip` and `gray-matter` (plus
`@types/adm-zip` for development). Neither package requires install-script
approval in the current npm 12 lockfile (`allowScripts` remains empty).

## Local Validation

Run these checks before marking the pull request ready for review:
Expand Down Expand Up @@ -69,7 +73,7 @@ src/
modules/ # DDD modules (cli, config, registry, install, target)
specs/ # Normative CLI contracts
test/ # node:test tooling script tests
tests/ # Vitest application tests
tests/ # Vitest tests (async spawn when subprocess tests use local HTTP)
scripts/ # Validation and sync scripts
docs/ # Contributor and architecture docs
```
Expand Down
Loading
Loading