feat(#1463): add capability outdated (per-source update check); drop phantom slash-command docs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1117,7 +1117,7 @@ Toggle which skills are surfaced — apply a profile, list, or disable a cluster
|
||||
|
||||
### `gsd capability`
|
||||
|
||||
Manage GSD capabilities — first-party (shipped) and third-party overlays. CLI form `gsd capability <subcommand>` (slash form `gsd:capability` on slash-command runtimes). See the [`gsd capability` command reference](reference/gsd-capability-command.md) for the full contract, source-spec forms, and install layout.
|
||||
Manage GSD capabilities — first-party (shipped) and third-party overlays. CLI form `gsd capability <subcommand>`. See the [`gsd capability` command reference](reference/gsd-capability-command.md) for the full contract, source-spec forms, and install layout.
|
||||
|
||||
| Subcommand | Description |
|
||||
|------------|-------------|
|
||||
@@ -1125,6 +1125,7 @@ Manage GSD capabilities — first-party (shipped) and third-party overlays. CLI
|
||||
| `update [<id> \| --all] [--scope …] [--yes]` | Re-resolve a capability's recorded source and upgrade it (atomic stage-then-swap) |
|
||||
| `remove <id> [--purge-data] [--scope …]` | Remove an installed overlay capability's files + marker-isolated shared edits (first-party cannot be removed here) |
|
||||
| `list [--json]` | List first-party + installed overlay capabilities as a JSON array |
|
||||
| `outdated [--json] [--scope …]` | Light-peek each installed overlay's recorded source and report which have a newer version available (per-source matrix; npm ranges resolve the highest matching version; `pinned` for immutable/explicit git refs or exact npm versions; `manual`/`unknown` for sources that can't be auto-checked) |
|
||||
| `disable <id>` / `enable <id>` | Toggle a capability's activation state (same as `capability set <id> --off`/`--on`) |
|
||||
| `state` / `set <id> …` | Inspect resolved capability state / set activation + per-hook gates |
|
||||
|
||||
@@ -1133,6 +1134,7 @@ gsd capability list --json # All capabilities as JSON
|
||||
gsd capability install ./my-cap --scope project # Install a local capability into the project
|
||||
gsd capability install npm:@org/gsd-cap-x@^1 --yes # Install from npm, granting executable-surface consent
|
||||
gsd capability update my-cap # Upgrade from its recorded source
|
||||
gsd capability outdated --json # Which installed overlays have a newer version?
|
||||
gsd capability disable my-cap # Turn it off without removing it
|
||||
gsd capability remove my-cap # Remove the overlay capability
|
||||
```
|
||||
|
||||
@@ -3189,15 +3189,16 @@ The load-bearing wire is the `plan-phase` lift into `must_haves.prohibitions`, s
|
||||
|
||||
### 147. Capability Management Command
|
||||
|
||||
**Command:** `gsd capability install | update | remove | list | disable | enable`
|
||||
**Command:** `gsd capability install | update | remove | list | outdated | disable | enable`
|
||||
|
||||
**Purpose:** The user-facing CLI for the ADR-1244 capability ecosystem — install, upgrade, remove, list, and toggle GSD capabilities (first-party and third-party overlays) from a registry / git / npm / tarball / local source. Wires the Phase-3/4 lifecycle library (source resolver, install ledger, trust gate) to a command users actually run.
|
||||
**Purpose:** The user-facing CLI for the ADR-1244 capability ecosystem — install, upgrade, remove, list, check for updates, and toggle GSD capabilities (first-party and third-party overlays) from a registry / git / npm / tarball / local source. Wires the Phase-3/4 lifecycle library (source resolver, install ledger, trust gate) to a command users actually run.
|
||||
|
||||
**Behavior:**
|
||||
- `install <spec> [--integrity sha512-…] [--scope global|project] [--yes] [--shared-file <rel>]…` — resolve (copy-only) → verify integrity / SHA pin → `engines.gsd` gate → disclose executable surfaces → consent (`--yes` grants; without it an executable install aborts after printing the disclosure and writes nothing) → validate → extract → record the ledger.
|
||||
- `update [<id> | --all] [--scope] [--yes]` — re-resolve the capability's recorded source and upgrade via atomic stage-then-swap; re-consent when the executable set changed; `--all` reports a per-capability outcome and exits non-zero on any partial failure.
|
||||
- `remove <id> [--purge-data] [--scope]` — strip the ledger-recorded files + marker-isolated shared edits; first-party capabilities are rejected (use the product uninstaller).
|
||||
- `list [--json]` — first-party + installed overlay capabilities (both scopes) as a JSON array.
|
||||
- `outdated [--json] [--scope]` — light remote peek of each installed overlay's recorded source (ADR-1244 D6 per-source matrix: git `ls-remote --tags`, npm `view … version` resolving the highest version matching the recorded range, local re-read; tarball → `manual`, registry → `unknown`) reporting `outdated` / `current` / `pinned` / `manual` / `unknown` per capability. A source pinned to an immutable ref (git `#sha:` or `#tag:`, or an exact npm version) is reported `pinned`. A bare git `#<ref>` is classified at the remote: if it resolves exclusively under `refs/tags/` it is an immutable tag → `pinned`; if it resolves to a mutable branch (or is ambiguous) it is `unknown`. Bounded subprocesses (git ≤30s, npm ≤60s) and a failing peek degrades that row to `unknown` without crashing the command. `--json` for machine output, default for a table.
|
||||
- `disable | enable <id>` — toggle activation state (equivalent to `gsd capability set <id> --off` / `--on`).
|
||||
|
||||
**Trust boundary:** install never executes capability code (copy-only staging); executable surfaces require explicit consent; sources are gated by the **project-scoped** `capabilities.strict_known_registries` policy (fail-closed on a malformed/unparseable value); every shared-config write/delete is realpath-confined to the scope root, and a name collision with a user's `mcpServers` entry is never clobbered.
|
||||
|
||||
@@ -40,8 +40,6 @@ gsd capability install https://example.com/releases/gsd-cap-example-1.0.0.tgz
|
||||
gsd capability install ./path/to/capability
|
||||
```
|
||||
|
||||
You can also use the slash command form inside a supported runtime (surfaced as `gsd:capability install <spec>` — without the leading `/` in the command palette).
|
||||
|
||||
---
|
||||
|
||||
## Read the pre-install summary
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
# `gsd capability` Command Reference
|
||||
|
||||
> **Slash form:** `gsd:capability` (surfaced as a slash command on slash-command runtimes)
|
||||
> **CLI form:** `gsd capability`
|
||||
> **Canonical ADR:** [ADR-1244](../adr/1244-capability-ecosystem.md)
|
||||
> **See also:** [Capability Manifest Reference](capability-manifest.md) · [How to develop a capability](../how-to/develop-a-capability.md) · [The capability trust model](../explanation/capability-trust-model.md)
|
||||
|
||||
The `capability` family manages the installation, upgrade, removal, and inspection of GSD capabilities — both first-party (shipped) and third-party overlays. A row for this command also appears in [docs/COMMANDS.md](../COMMANDS.md) (that file is not edited here).
|
||||
|
||||
**Implemented in 1.6.0:** `install`, `update`, `remove`, `list`, `trust`, `disable`, `enable` (plus the pre-existing `state` and `set` introspection/activation subcommands). **Planned (not yet implemented):** `outdated` — see [Planned subcommands](#planned-subcommands).
|
||||
**Implemented:** `install`, `update`, `remove`, `list`, `outdated`, `trust`, `disable`, `enable` (plus the pre-existing `state` and `set` introspection/activation subcommands).
|
||||
|
||||
---
|
||||
|
||||
@@ -196,6 +195,72 @@ The `reason` field is `null` for active/incompatible rows and carries a short ex
|
||||
|
||||
---
|
||||
|
||||
### `outdated`
|
||||
|
||||
**Synopsis**
|
||||
|
||||
```
|
||||
gsd capability outdated [--json] [--scope global|project]
|
||||
```
|
||||
|
||||
**Flags**
|
||||
|
||||
| Flag | Description |
|
||||
|---|---|
|
||||
| `--json` | Emit the records array as JSON (machine output). When omitted, a human-readable table is printed instead (columns: `ID`, `Source`, `Current`, `Latest`, `Status`). |
|
||||
| `--scope` | Read only the given scope's ledger (`global` or `project`). When omitted, both scopes are swept (mirroring `list`). |
|
||||
|
||||
**Behaviour**
|
||||
|
||||
For every installed overlay capability in the chosen scope(s), `outdated` performs a **light remote peek** of the capability's **recorded source** (the `source` stored in its ledger entry at install time) to learn the latest version that re-resolving that source would install, then compares it (numeric `major.minor.patch`) with the installed version. It is a metadata-only read — it never re-clones, re-packs, or re-extracts a bundle. A failing, timed-out, or unsupported peek **degrades** that row to `status: unknown`; it never crashes the command, and a single bad entry never suppresses the others.
|
||||
|
||||
A capability is reported `outdated` **only if** re-resolving its recorded source (exactly what `update` does) would fetch a **newer** version than the one installed. A source pinned to an **immutable** ref — a git `#sha:<commit>` or `#tag:<tag>` fragment, or an **exact** npm version (`npm:@org/pkg@1.2.3`) — is never `outdated`: `update` re-resolves to the same commit/tag/version, so the row is reported `status: pinned` instead.
|
||||
|
||||
A **bare** git ref fragment (`…repo.git#<ref>`) is **ambiguous** — it may name an immutable tag or a **mutable branch**. `outdated` resolves it at the remote with a bounded `git ls-remote <url> <ref>` (the same safe argv-only seam, no shell): a ref that resolves under `refs/tags/` is an immutable tag → `status: pinned`; a ref that resolves under `refs/heads/` is a **mutable branch** (`update` re-clones and checks out the branch HEAD, which can move) and is therefore **never** reported `pinned`. Because the ledger does not record the commit a git source was installed at, a moved branch HEAD cannot be compared against the installed commit, so a branch-tracked source degrades to `status: unknown`. An unresolvable / ambiguous / errored / timed-out classification also degrades to `unknown`.
|
||||
|
||||
The per-source "update available?" matrix (ADR-1244 D6):
|
||||
|
||||
| Source kind | Latest-version peek | Bound |
|
||||
|---|---|---|
|
||||
| git, **unpinned** (`https://…/repo.git`, tracks default branch) | `git ls-remote --tags` → highest **stable** semver tag (`v`-prefix and `^{}` peeled entries handled; prerelease/junk tags ignored) | ≤ 30s |
|
||||
| git, **pinned** (`…repo.git#sha:…` / `#tag:…`) | immutable ref → `status: pinned` (no peek; `update` will not move it) | — |
|
||||
| git, **bare ref** (`…repo.git#<ref>`) | `git ls-remote <url> <ref>` classifies the ref: `refs/tags/…` → `status: pinned` (immutable tag); `refs/heads/…` → **mutable branch**, never `pinned` (no installed commit recorded to compare against → `status: unknown`); unresolvable/ambiguous → `status: unknown` | ≤ 30s |
|
||||
| npm **range** (`npm:@org/pkg@^1`) | `npm view <pkg>@<range> version` → **highest version matching the recorded range** (npm prints one line per match; the numeric max satisfying the range is what `update` installs) | ≤ 60s |
|
||||
| npm **latest** (`npm:@org/pkg`, no version) | `npm view <pkg> version` → the single `latest` dist-tag version | ≤ 60s |
|
||||
| npm **exact** (`npm:@org/pkg@1.2.3`) | pinned exact version → `status: pinned` (no peek; `update` re-installs the same version) | — |
|
||||
| local (`./path` or absolute) | re-read of `capability.json` at the recorded path | — |
|
||||
| tarball (`https://…/cap-x.y.z.tgz`) | **not auto-detectable** — one immutable URL → `status: manual` | — |
|
||||
| registry (`<name>@<registry>`) | registry adapter not yet implemented → `status: unknown` | — |
|
||||
|
||||
**Output shape** (`--json`)
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "string",
|
||||
"sourceKind": "git | npm | local | tarball | registry | unknown",
|
||||
"current": "semver | null",
|
||||
"latest": "semver | null",
|
||||
"status": "outdated | current | pinned | manual | unknown",
|
||||
"scope": "global | project"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
`status` values:
|
||||
|
||||
| Value | Meaning |
|
||||
|---|---|
|
||||
| `outdated` | Re-resolving the recorded source would fetch a newer version than the installed one (for an npm range, the latest version **matching the recorded range**). Run `gsd capability update <id>` to upgrade. |
|
||||
| `current` | The installed version is the latest the recorded source would resolve to (or newer). |
|
||||
| `pinned` | The recorded source is pinned to an **immutable** ref (git `#sha:`/`#tag:`, or a bare git `#<ref>` that resolves to a tag) or an exact npm version; `update` re-resolves to the same commit/tag/version, so it can never be `outdated`. A bare git ref that resolves to a **mutable branch** is never `pinned`. |
|
||||
| `manual` | The source (a bare tarball URL) cannot be auto-checked; re-install from a new URL to upgrade. |
|
||||
| `unknown` | The peek failed (network error / timeout / non-zero exit / unparseable output), the source kind is not auto-checkable (registry), or the source tracks a mutable git branch whose installed commit was not recorded (so a moved branch HEAD cannot be compared). |
|
||||
|
||||
An empty (or missing) ledger reports nothing: `--json` emits `[]`; the table notes that there are no installed overlay capabilities.
|
||||
|
||||
---
|
||||
|
||||
### `trust`
|
||||
|
||||
Manage the **user-owned consent store** (#1459) that gates project-scope third-party capability activation. The store lives at `${GSD_HOME||homedir()}/.gsd/consent.json` — **outside any repository** — and records, per `(realpath(projectRoot), capability id)`, the bundle integrity and disclosure signature you consented to **on this machine**. A project-scope overlay is inactive until such a record exists (so a forged or cloned in-repo project ledger activates nothing on its own); installing a project-scope capability through the lifecycle writes the record, and removing it revokes the record.
|
||||
@@ -227,16 +292,6 @@ gsd capability trust revoke <id> [--project <path>]
|
||||
|
||||
---
|
||||
|
||||
## Planned subcommands
|
||||
|
||||
These appear in ADR-1244's command surface but are **not implemented in 1.6.0**. They are documented here so the surface is explicit; invoking them returns the unknown-subcommand error listing the available set.
|
||||
|
||||
| Subcommand | Intended behaviour |
|
||||
|---|---|
|
||||
| `outdated` | Query each installed overlay's source and report those with a newer version available (`--json` for machine output). Until it ships, `update --all` re-resolves every recorded source and reports what changed. |
|
||||
|
||||
---
|
||||
|
||||
## Source specifications
|
||||
|
||||
The `install` subcommand accepts the following source specification forms.
|
||||
|
||||
Reference in New Issue
Block a user