From 07c55f18ff601b66c099d1d19d528e4423625b2e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Aug 2026 08:31:16 +0000 Subject: [PATCH 1/2] chore: sync skills to v0.21.0 --- skills/jfrog-setup-package-managers/SKILL.md | 109 +++++++++++------- .../references/global-cache-file.md | 19 +-- .../references/jf-setup-command.md | 35 +++++- .../references/workspace-binding.md | 27 +++-- skills/jfrog/SKILL.md | 2 +- .../references/jfrog-cli-install-upgrade.md | 8 ++ .../scripts/jfrog-login-register-session.sh | 11 ++ 7 files changed, 142 insertions(+), 69 deletions(-) diff --git a/skills/jfrog-setup-package-managers/SKILL.md b/skills/jfrog-setup-package-managers/SKILL.md index e7eeaec..bcd511e 100644 --- a/skills/jfrog-setup-package-managers/SKILL.md +++ b/skills/jfrog-setup-package-managers/SKILL.md @@ -2,14 +2,18 @@ name: jfrog-setup-package-managers description: >- Use this skill when the user asks to set up, configure, bind, or connect a - package manager (npm, pip, maven, gradle, go, docker, helm, …) to JFrog - Artifactory via `jf setup` and `.jfrog/local/package-resolution.json`; when a - workspace manifest exists with no matching binding entry; or when a session - hook reports PM config missing. Skip when the binding already has the same - repo key — the session hook reapplies each start. Never pick a repo by - discovery; use resolver output only (unless the user explicitly names or - asks to browse repos). On unresolved or failed setup, ask for a repo key - with the failure verbatim — never switch servers. + package manager (npm, pip, uv, pipenv, maven, gradle, go, docker, helm, ...) + to JFrog Artifactory via `jf setup` and + `.jfrog/local/package-resolution.json`; when a workspace manifest exists with + no matching binding entry; or when a session hook reports package-manager + config missing. Prefer uv for `uv.lock` / `[tool.uv]` — do not substitute pip + for uv when those signals exist; still bind pip when its own manifest (e.g. + `requirements.txt`) selects it. Yarn and Poetry are not part of Agent Package + Resolution zero-touch — bind only on explicit user request. Skip when the + binding already has the same repo key. Never pick a repo by discovery; use + resolver output only (unless the user names or asks to browse repos). On + unresolved or failed setup, ask with the failure verbatim — never switch + servers. metadata: role: workflow --- @@ -18,7 +22,7 @@ metadata: Apply the session hook's repo pick via [`jf setup`](references/jf-setup-command.md), then record it in [`.jfrog/local/package-resolution.json`](references/workspace-binding.md). -`jf setup` writes PM-native config (`.npmrc`, `pip.conf`, …); the binding +`jf setup` writes package-manager-native config (`.npmrc`, `pip.conf`, `uv.toml`, …); the binding lets the hook re-apply on later sessions. ## Scope (this skill vs session hook) @@ -29,14 +33,14 @@ renderer is available on demand via `modules/package-resolution/scripts/print-po notice embeds the exact command), so the policy can be loaded after setup. **This skill:** reads that output, runs `jf setup`, and persists the workspace -binding at `.jfrog/local/package-resolution.json` when PM config is still missing. +binding at `.jfrog/local/package-resolution.json` when package-manager config is still missing. **Honor the injected policy's governed scope.** The session policy lists the -package managers it governs. Do **not** *proactively* onboard a PM the policy +package managers it governs. Do **not** *proactively* onboard a package manager the policy doesn't govern (e.g. a stray `Dockerfile` when only `pypi`/`npm` are governed) — those are intentionally out of scope. An **explicit user request** to set up any -PM still works (Step 1's user-mention signal and Step 2's AskQuestion for an -unlisted PM apply as usual). +package manager still works (Step 1's user-mention signal and Step 2's AskQuestion for an +unlisted package manager apply as usual). ## Prerequisites @@ -51,21 +55,23 @@ unlisted PM apply as usual). - **Always pass `--repo` and `--server-id`** — omitting `--repo` fails when multiple repos match. See [`jf-setup-command.md`](references/jf-setup-command.md). -- **`jf setup` overwrites PM config** without backup — skip PMs whose binding +- **`jf setup` overwrites package-manager config** without backup — skip package managers whose binding already matches (Step 1, signal 2). - **Docker / Podman — prefix or stop.** `jf setup docker` writes creds only; bare `docker pull ` hits Docker Hub. Complete setup, then pull via `//`. - **Binding holds decisions, not credentials** — never write tokens into `.jfrog/local/package-resolution.json`. +- **`gradle` ≠ `maven`.** Bind under `repositories.gradle`, never `repositories.maven`. +- **Yarn / Poetry** — not APR zero-touch; bind only on explicit user ask (Step 1). ## References | File | When to read | |------|--------------| -| [`references/jf-setup-command.md`](references/jf-setup-command.md) | CLI flags, supported PMs, exit-code contract, `jf setup --help` | +| [`references/jf-setup-command.md`](references/jf-setup-command.md) | CLI flags, supported package managers, exit-code contract, `jf setup --help` | | [`references/global-cache-file.md`](references/global-cache-file.md) | Global cache shape, resolution classes, jq one-liners | -| [`references/workspace-binding.md`](references/workspace-binding.md) | Workspace binding schema, PM → type map, merge semantics | +| [`references/workspace-binding.md`](references/workspace-binding.md) | Workspace binding schema, package-manager → type map, merge semantics | ## Step 0 — Read the base skill, then ensure `jf` is ready @@ -87,37 +93,49 @@ unlisted PM apply as usual). Combine four signals, in order; intersect with `jf setup --help` supported list: -1. **Explicit user mention.** Map aliases: python → `pip`/`poetry`; java → - `maven`/`gradle`; node → `npm`/`yarn`/`pnpm` by lockfile. -2. **Workspace binding** — read `.jfrog/local/package-resolution.json`. Drop PMs - already bound to the same key unless recovering from 401/403 (re-run same - key). PM → type table: [`workspace-binding.md`](references/workspace-binding.md). -3. **Workspace manifests** when still ambiguous: - - | Manifest file | Package manager | +1. **Explicit user mention.** Map aliases: python → `pip`/`uv`/`pipenv` (and + `poetry` only if the user named Poetry); java → `maven`/`gradle`; node → + `npm`/`pnpm` by lockfile (`yarn` only if the user named Yarn). +2. **Workspace binding** — read `.jfrog/local/package-resolution.json`. Drop + package managers already bound to the same key unless recovering from 401/403 + (re-run same key). Package-manager → type table: + [`workspace-binding.md`](references/workspace-binding.md). +3. **Workspace manifests** when still ambiguous (several package managers of one + type may apply — e.g. `requirements.txt` **and** `uv.lock`): + + | Manifest / signal | Package manager | |---|---| - | `package.json`, `pnpm-lock.yaml`, `yarn.lock` | `npm` (+ `yarn`/`pnpm` if lockfiles present) | - | `requirements.txt`, `Pipfile` | `pip` (`pipenv` for `Pipfile`) | - | `pyproject.toml` | `poetry` if `[tool.poetry]`; else `pip` | + | `package.json`, `pnpm-lock.yaml` | `npm` (+ `pnpm` if `pnpm-lock.yaml` present) | + | `yarn.lock` (alone) | `npm` — do **not** auto-select `yarn` | + | `requirements.txt` | `pip` | + | `Pipfile` | `pipenv` | + | `uv.lock` | `uv` — suppresses bare `pyproject.toml` → `pip`; keep `requirements.txt` + `uv.lock` as multi-PM | + | `pyproject.toml` | `[tool.uv]` → `uv`; `[tool.poetry]` → `poetry` only on explicit user ask, else **not applicable** (do not select `pip`); bare PEP 621 with **no** `uv.lock` → `pip` | | `pom.xml` | `maven` | - | `build.gradle`, `build.gradle.kts` | `gradle` | + | `build.gradle`, `build.gradle.kts` | `gradle` (bind under type **`gradle`**) | | `go.mod` | `go` | | `Dockerfile`, `compose.yaml`, `docker-compose.yml` | `docker` / `podman` | | `*.csproj`, `NuGet.Config` | `nuget` / `dotnet` | | `Chart.yaml` | `helm` | -4. **`jf setup --help`** — filter candidates; never hardcode the PM list. See - [`jf-setup-command.md`](references/jf-setup-command.md). Unsupported PM → - report gap, skip. + **Binary gate (client tools only):** missing client on `PATH` → skip as not + applicable; do **not** substitute another package manager or report setup + success. **Exempt `maven` / `gradle`** (config-only). Details: + [`jf-setup-command.md`](references/jf-setup-command.md). + +4. **`jf setup --help`** — filter candidates; never hardcode the list. See + [`jf-setup-command.md`](references/jf-setup-command.md). Unsupported → report + gap, skip. ## Step 2 — Get the resolved repo -For each ``, recover `` and `` from the first source +For each ``, recover `` and `` from the first source available: 1. **"Resolved URLs for this session"** table (default). Parse `` from URL; `` from host. -2. **Workspace binding** — if table was trimmed. `repositories.`. +2. **Workspace binding** — if table was trimmed. `repositories.` + (`gradle` → `repositories.gradle`, not `maven`). 3. **Global cache** — last resort only; never overrides (1) or (2). See [`global-cache-file.md`](references/global-cache-file.md). @@ -126,26 +144,28 @@ Cache disagreeing with (1)/(2) is not a reason to change the repo. **Don't choose a repo yourself:** no listing, enumerating, probing, or iterating `--server-id` to pick one, and don't second-guess the resolver — use resolver output only. If the user explicitly asks to browse repos, list them via -`jf api "/artifactory/api/repositories?type=virtual&packageType="` (filter by -repo type — prefer `virtual` — and package type), then let the user choose; the +`jf api "/artifactory/api/repositories?type=virtual&packageType="` +(Artifactory **package type** from the binding map — `gradle` not `maven`; +`uv` / `pip` / `pipenv` / `poetry` → `pypi`), then let the user choose; the agent still never makes the choice on its own. ### Unresolved repo key -Ask via AskQuestion: +Ask via AskQuestion (include the resolver/setup failure text verbatim): -> No default repo for `` on ``. +> No default repo for `` on ``. +> Failure: `` > Which Artifactory repository should I use? (repo key, or `abort`.) -Cap at **2 answers per PM**, then abort. User may override repo only, never server. +Cap at **2 answers per package manager**, then abort. User may override repo only, never server. ## Step 3 — Confirm, run `jf setup`, persist binding -1. Present the plan, one row per PM: +1. Present the plan, one row per package manager: ```text - on (source: resolver) - on (source: user-supplied) + on (source: resolver) + on (source: user-supplied) ``` 2. Show binding diffs when the repo key changes. @@ -153,10 +173,10 @@ Cap at **2 answers per PM**, then abort. User may override repo only, never serv 3. **Confirm** via AskQuestion (`apply` / `change repos` / `abort`) unless the user explicitly requested silent/non-interactive setup — then run directly. -4. Sequentially, one PM at a time: +4. Sequentially, one package manager at a time: ```bash - jf setup --server-id --repo [--project ] + jf setup --server-id --repo [--project ] ``` 5. **Exit code `0` = success** — merge binding (step 6). On non-zero, **stop**, @@ -169,7 +189,8 @@ Cap at **2 answers per PM**, then abort. User may override repo only, never serv { "repositories": { "": "" } } ``` - Map PM → type via the reference table. Merge atomically. + Map package manager → type via the reference table (`gradle` → `gradle`). + Merge atomically. ## Step 4 — Load the routing policy diff --git a/skills/jfrog-setup-package-managers/references/global-cache-file.md b/skills/jfrog-setup-package-managers/references/global-cache-file.md index 1287964..7cb7869 100644 --- a/skills/jfrog-setup-package-managers/references/global-cache-file.md +++ b/skills/jfrog-setup-package-managers/references/global-cache-file.md @@ -31,6 +31,7 @@ pruning, the file cannot. "npm": "npm-virtual", "pypi": "pypi-virtual", "maven": "libs-release", + "gradle":"gradle-virtual", "go": "go-virtual", "docker":"docker-virtual", "helm": "helm-virtual", @@ -53,20 +54,22 @@ only `repositories`. The map key **is** the `serverId`. | Field | Meaning | |---|---| | `schemaVersion` | Always `1` for this schema. | -| `servers..repositories.` | Resolver's chosen repo key for this package type, on this server. **Missing key = `unresolved`** for that PM. | +| `servers..repositories.` | Resolver's chosen repo key for this package type, on this server. **Missing key = `unresolved`** for that package manager. | | `servers..cached_at` | ISO-8601 timestamp of the last refresh. TTL from `packageResolution.cacheTtlDays` in agents-conf.json (default 7). | | `servers..agentsConfigMtimeMs` | Invalidates cache when `~/.jfrog/agents-conf.json` changes. | | `servers..source` | `verified` = keys from agents-conf.json checked via `GET /api/repositories/{key}`; `agents-config` = trusted without HTTP (`verifyRepos: false`). | -Package type keys used in the file are `npm`, `pypi`, `maven`, `go`, +Package type keys used in the file are `npm`, `pypi`, `maven`, `gradle`, `go`, `docker`, `helm`, `nuget`. Note `pypi` (not `pip`) — same convention the -JFrog API uses. The PM names accepted by `jf setup` (`pip`, `poetry`, -`gradle`, `pnpm`, `yarn`, `podman`, `dotnet`, `pipenv`, `twine`) collapse -onto these package-type keys. +JFrog API uses. The package-manager names accepted by `jf setup` (`pip`, `uv`, +`pnpm`, `podman`, `dotnet`, `pipenv`, `twine`, and optionally `yarn` / `poetry` +when the user asks) collapse onto these package-type keys — **`gradle` maps to +`gradle`**, not `maven`. -## Three result classes per PM -When you look up a PM in this file, you get one of: +## Three result classes per package manager + +When you look up a package manager in this file, you get one of: | Class | Detect | What the resolver did | HTTP-verified? | |---|---|---|---| @@ -100,7 +103,7 @@ If `$CACHE` does not exist, or the SID branch is missing, the hook has not yet resolved on this machine for this server — fall back to reading the injected "Resolved URLs for this session" table in agent context (parse the URL to recover `repoKey`), and if that is also absent, treat -every PM as `unresolved` and prompt the user (Step 2). +every package manager as `unresolved` and prompt the user (Step 2). The resolver refreshes stale entries on session start (TTL + agents-conf.json mtime). This skill never invalidates the cache — if `jf setup` fails on a repo key, ask the user. diff --git a/skills/jfrog-setup-package-managers/references/jf-setup-command.md b/skills/jfrog-setup-package-managers/references/jf-setup-command.md index 12eeaf1..da87292 100644 --- a/skills/jfrog-setup-package-managers/references/jf-setup-command.md +++ b/skills/jfrog-setup-package-managers/references/jf-setup-command.md @@ -1,12 +1,12 @@ # `jf setup` Command Reference -Configures a local PM to resolve from / publish to Artifactory. CLI install -and server config: [`../../jfrog/SKILL.md`](../../jfrog/SKILL.md). +Configures a local package manager to resolve from / publish to Artifactory. CLI +install and server config: [`../../jfrog/SKILL.md`](../../jfrog/SKILL.md). ## Invocation ```bash -jf setup --server-id --repo [--project ] +jf setup --server-id --repo [--project ] ``` Always pass `--server-id` and `--repo`. Without `--repo`, multiple matching @@ -17,7 +17,7 @@ name using '--repo' flag`). `GET /artifactory/api/repositories/` before configuring. Record `repositories.docker` in the workspace marker for pull URL composition. -## Supported PM list +## Supported package-manager list Drifts across CLI versions — always parse from the installed binary: @@ -37,9 +37,32 @@ Look for the "Supported package managers are:" line. Never hardcode. | `401` / `403` | Token issue | Re-login same server — [`jfrog-login-flow.md`](../../jfrog/references/jfrog-login-flow.md) | | Wrong server `404` | Bad `` | Stop — never iterate servers | -Do not continue to the next PM after a failure. +Do not continue to the next package manager after a failure. ## Agent notes -- `pyproject.toml` with `[tool.poetry]` → `poetry`; plain PEP 621 → `pip`. +### Python / Node detection (composition) + +- `uv.lock` → `uv` (writes `uv.toml`, not `pip.conf`). Takes precedence over a + bare `pyproject.toml` pip fallback — common layout is `uv.lock` + PEP 621 + **without** `[tool.uv]`; select `uv` only, never also `pip`. +- `requirements.txt` + `uv.lock` → bind **both** `pip` and `uv` (independent + manifests). Missing `uv` binary → skip `uv` as not applicable; do **not** + substitute `pip` for the uv candidate (pip still binds from its own file). +- `pyproject.toml`: + 1. `[tool.uv]` → `uv` + 2. `[tool.poetry]` → `poetry` **only** on explicit user ask; otherwise **not + applicable** (do not fall through to `pip`) + 3. Bare PEP 621 with **neither** uv signal and **no** `uv.lock` → `pip` +- Prefer `npm` / `pnpm` for Node; `yarn.lock` alone → `npm`. Do not proactively + run `jf setup yarn` / `jf setup poetry` (APR zero-touch omits both). + +### Binary gate / types + +- Missing package-manager binary → skip that candidate; do not substitute another. + Exception: `maven` / `gradle` need no client binary (`jf setup` writes config + only; wrappers/`pom.xml`/Gradle files are enough). Bind `gradle` under the + **`gradle`** package type (not `maven`). +- Browse repos with Artifactory `packageType` from the binding map (`uv` → + `pypi`, not `uv`). - `jf setup --help` is the authoritative flag reference. diff --git a/skills/jfrog-setup-package-managers/references/workspace-binding.md b/skills/jfrog-setup-package-managers/references/workspace-binding.md index 2b97767..24f135c 100644 --- a/skills/jfrog-setup-package-managers/references/workspace-binding.md +++ b/skills/jfrog-setup-package-managers/references/workspace-binding.md @@ -4,7 +4,7 @@ This skill records workspace repo bindings in a file the session-start hook reads to override org defaults from `~/.jfrog/skills-cache/package-resolution.json`. The file is the **decisions** record, not a credential store. Tokens live -in `jf config` and in PM-native files written by `jf setup` itself. +in `jf config` and in package-manager-native files written by `jf setup` itself. ## Location @@ -24,6 +24,7 @@ different Artifactory repos. "npm": "", "pypi": "", "maven": "", + "gradle": "", "go": "", "docker": "", "helm": "", @@ -36,13 +37,19 @@ different Artifactory repos. |---|---|---| | `repositories` | yes | Map keyed by **package type** — same keys as `servers..repositories` in the global resolver cache. Omit package types you do not override. | -### PM name → package type (when merging after `jf setup`) +### Package-manager name → package type (when merging after `jf setup`) -| `jf setup` PM | `repositories` key | +Aligned with Agent Package Resolution (`PACKAGE_TYPES` / eager families). +`gradle` is its **own** Artifactory package type — never fold it under `maven`. + +| `jf setup` package manager | `repositories` key | |---|---| -| `npm`, `yarn`, `pnpm` | `npm` | -| `pip`, `pipenv`, `poetry`, `twine` | `pypi` | -| `maven`, `gradle` | `maven` | +| `npm`, `pnpm` | `npm` | +| `yarn` | `npm` (CLI may still accept `jf setup yarn`; APR zero-touch does **not** auto-setup yarn — only bind on explicit user request) | +| `pip`, `pipenv`, `uv`, `twine` | `pypi` | +| `poetry` | `pypi` (CLI may accept it; APR zero-touch does **not** auto-setup poetry — bind only on explicit user request) | +| `maven` | `maven` | +| `gradle` | `gradle` | | `go` | `go` | | `docker`, `podman` | `docker` | | `helm` | `helm` | @@ -52,8 +59,8 @@ different Artifactory repos. ### 1. Load -Before setup, **read** the file (if it exists). For each PM in the -to-bind set, map the PM to a package type and compare +Before setup, **read** the file (if it exists). For each package manager in the +to-bind set, map it to a package type and compare `repositories.` against what the resolver chose in Step 2: | Case | Action | @@ -67,7 +74,7 @@ to-bind set, map the PM to a package type and compare After each successful `jf setup`: 1. Read the current file (treat ENOENT as `{ "repositories": {} }`). -2. Set `repositories[] = ` using the PM → type table above. +2. Set `repositories[] = ` using the package-manager → type table above. 3. Atomically write `{ "repositories": { ... } }` — preserve other package types already in the map. @@ -76,7 +83,7 @@ JSON must use 2-space indent. ### 3. Never write - Credentials (`accessToken`, passwords, …). -- PM-native config paths — those are owned by `jf setup`. +- Package-manager-native config paths — those are owned by `jf setup`. ## Integration contract diff --git a/skills/jfrog/SKILL.md b/skills/jfrog/SKILL.md index 68c0dae..bde4918 100644 --- a/skills/jfrog/SKILL.md +++ b/skills/jfrog/SKILL.md @@ -18,7 +18,7 @@ compatibility: >- Requires jq on PATH. metadata: role: base - version: "0.20.0" + version: "0.21.0" --- # JFrog Skill diff --git a/skills/jfrog/references/jfrog-cli-install-upgrade.md b/skills/jfrog/references/jfrog-cli-install-upgrade.md index 071a19f..ba87338 100644 --- a/skills/jfrog/references/jfrog-cli-install-upgrade.md +++ b/skills/jfrog/references/jfrog-cli-install-upgrade.md @@ -1,5 +1,13 @@ # JFrog CLI Install & Upgrade +## Minimum version for skills + +Skills that call `jf api` require JFrog CLI **2.100.0** or later. On an older CLI +`jf api` is an unknown command, so the login flow stops as a prerequisite failure +rather than reaching the platform. Web login itself needs **2.86.0** or later. + +Check with `jf --version`, and upgrade below that floor using the steps below. + ## Installing the JFrog CLI If `jf` is not installed (environment check exits with code 2), guide the user: diff --git a/skills/jfrog/scripts/jfrog-login-register-session.sh b/skills/jfrog/scripts/jfrog-login-register-session.sh index 7e91bf0..d02e4cf 100755 --- a/skills/jfrog/scripts/jfrog-login-register-session.sh +++ b/skills/jfrog/scripts/jfrog-login-register-session.sh @@ -49,6 +49,17 @@ if ! command -v jf &>/dev/null; then exit 1 fi +# `jf api` was added in JFrog CLI 2.100.0 and every request below depends on it. +# Check it explicitly: on an older CLI the ping fails with an unknown-command +# error that carries no HTTP status, which would otherwise be reported as an +# unreachable server and send the user looking at the network instead of the CLI. +if ! jf api --help >/dev/null 2>&1; then + echo "ERROR: this jf ($(jf --version 2>/dev/null || echo 'version unknown')) does not support 'jf api'," >&2 + echo "which this login flow requires (JFrog CLI 2.100.0 or later)." >&2 + echo "Upgrade the JFrog CLI, then retry. See references/jfrog-cli-install-upgrade.md." >&2 + exit 1 +fi + if ! command -v uuidgen &>/dev/null; then echo "ERROR: uuidgen is not installed" >&2 exit 1 From ec6585652181d2c142415d1b3b6dc94a8f75eb24 Mon Sep 17 00:00:00 2001 From: Roee Sanker Date: Sun, 2 Aug 2026 16:04:59 +0300 Subject: [PATCH 2/2] chore: bump plugin version to 0.2.18 The 0.2.17 bump already landed on main via #43, so the skills sync needs its own version. Co-authored-by: Cursor --- .claude-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 730fdef..bc44b45 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "jfrog", "displayName": "JFrog", "description": "Official JFrog plugin. Connect Claude Code to JFrog to manage, secure, and govern your software supply chain. Give agents the context to build secure, compliant software.", - "version": "0.2.17", + "version": "0.2.18", "author": { "name": "JFrog Ltd.", "email": "devrel@jfrog.com",