From a60425106cc806793d533819833431383c7b03b7 Mon Sep 17 00:00:00 2001 From: "jfrog-agentic-release-bot[bot]" <276080306+jfrog-agentic-release-bot[bot]@users.noreply.github.com> Date: Sun, 27 Sep 2026 12:44:33 +0000 Subject: [PATCH] [patch] chore: sync skills to v0.40.0 --- .codex-plugin/plugin.json | 2 +- package.json | 2 +- scripts/sync-skills-vendor.json | 2 +- skills/jfrog-ai-catalog/SKILL.md | 14 +- .../references/discovering-skills.md | 103 +++++++++- .../references/installing-skills.md | 176 ++++++++++++++++-- skills/jfrog-init/scripts/lib/jf-api.mjs | 1 + skills/jfrog-mcp-management/SKILL.md | 21 ++- .../references/harness-claude.md | 16 +- .../references/harness-codex.md | 31 ++- .../references/harness-common.md | 21 ++- .../references/harness-cursor.md | 20 +- .../references/harness-devin.md | 36 ++-- .../references/harness-kiro.md | 20 +- .../references/harness-opencode.md | 35 ++-- .../references/harness-vscode.md | 24 ++- .../key-rules-and-troubleshooting.md | 76 ++++++-- skills/jfrog/SKILL.md | 72 ++++--- skills/jfrog/references/cli-gotchas.md | 5 + skills/jfrog/references/jf-api.md | 3 +- .../references/jfrog-cli-install-upgrade.md | 6 +- skills/jfrog/references/xray-entities.md | 17 +- skills/jfrog/scripts/check-environment.sh | 2 +- .../jfrog/scripts/cli-newer-version-offer.sh | 16 +- 24 files changed, 537 insertions(+), 184 deletions(-) diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index e724636..08beedb 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jfrog", - "version": "0.1.12", + "version": "0.1.13", "description": "JFrog skills and the JFrog MCP server for Codex \u2014 interact with the JFrog Platform.", "author": { "name": "JFrog", diff --git a/package.json b/package.json index 758ba89..ab3139d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codex-plugin", - "version": "0.1.12", + "version": "0.1.13", "private": true, "type": "module", "description": "JFrog skills and MCP server plugin for OpenAI Codex.", diff --git a/scripts/sync-skills-vendor.json b/scripts/sync-skills-vendor.json index 380a56c..95d2b38 100644 --- a/scripts/sync-skills-vendor.json +++ b/scripts/sync-skills-vendor.json @@ -1,6 +1,6 @@ { "repo": "jfrog/jfrog-skills", - "pin": "v0.38.0", + "pin": "v0.40.0", "paths": [ "skills" ] diff --git a/skills/jfrog-ai-catalog/SKILL.md b/skills/jfrog-ai-catalog/SKILL.md index fc94f85..44311c0 100644 --- a/skills/jfrog-ai-catalog/SKILL.md +++ b/skills/jfrog-ai-catalog/SKILL.md @@ -26,7 +26,7 @@ Pick the row matching the user's intent and read that reference file. | Intent | Read | |--------|------| | "What skills are available?" / browse the catalog / list versions / search by name | [references/discovering-skills.md](references/discovering-skills.md) | -| Install or update a skill (latest or a pinned version), or a download is blocked | [references/installing-skills.md](references/installing-skills.md) | +| Install a skill with an explicitly resolved version and repo, update a skill, or handle a blocked download | [references/installing-skills.md](references/installing-skills.md) | | "What's installed?" / remove an installed skill | [references/managing-installed-skills.md](references/managing-installed-skills.md) | | Publish / upload / release a skill to the catalog | [references/publishing-skills.md](references/publishing-skills.md) | | "What plugins are available?" / browse the plugin catalog / list plugin versions / search plugins | [references/discovering-plugins.md](references/discovering-plugins.md) | @@ -97,7 +97,7 @@ flowchart TD B -->|No| C[Ask user to install jf CLI, then continue] B -->|Yes| D{Intent} C --> D - D -->|List all skills / versions| E[npx @jfrog/agent-guard --list-skills] + D -->|List all skills / versions| E[npx @jfrog/agent-guard --list-skills --allowed-only] D -->|Install / update skill| F[Resolve slug + version, then jf skills install/update] D -->|List installed skills / remove| G[jf skills list / rm -rf install dir] D -->|Publish skill| H[Resolve/provision repo, validate bundle, jf skills publish] @@ -121,7 +121,15 @@ the reference files above. the next agent session start, so tell the user to restart. - **Don't leak the plumbing**: present skills/versions/repos to the user, never the `npx`/Agent Guard commands, `--registry`, flags, or cursors. Run follow-ups - yourself. + yourself. Discuss catalog filtering only when the user asks about missing or + blocked results; follow the refusal in `discovering-skills.md`. +- **Skill discovery is always policy-scoped**: every skill and skill-version + listing must follow `discovering-skills.md`. Never weaken that listing path, + including for audit, blocked-content, or named-repository requests. Each + `locations[]` entry from `--list-skill-versions` also carries its own + `allowStatus`, since a repo's governance status is a per-repo fact, never a + per-version one (MLAI-1309) — see `discovering-skills.md` and + `installing-skills.md`. - **Use the response templates verbatim**: where a reference file gives a "reply using this exact template" block, fill the placeholders and send exactly that, with the same wording every time and no extra preamble or commentary. diff --git a/skills/jfrog-ai-catalog/references/discovering-skills.md b/skills/jfrog-ai-catalog/references/discovering-skills.md index 60d2f82..4ee7709 100644 --- a/skills/jfrog-ai-catalog/references/discovering-skills.md +++ b/skills/jfrog-ai-catalog/references/discovering-skills.md @@ -1,22 +1,30 @@ # Discovering skills -List-all and versions go through the **Agent Guard**. +List-all and versions go through the **Agent Guard** and are always limited to +skills allowed by the project's governance policy. This has no exceptions for +those Agent Guard catalog calls (`--list-skills`, `--list-skill-versions`). + +The repo-scoped `jf skills list --repo` command below is a different, narrower +tool: it lists a repository's raw contents directly from Artifactory, not +through Agent Guard, so it is not governance-filtered. It is not a discovery +path — see *List a repo's skills* for when it's appropriate to use. ## List skills (page through the catalog) ```bash npx --yes --registry @jfrog/agent-guard \ - --list-skills --project "" [--name ] [--server ""] [--page-size ] [--cursor ] [--format json] + --list-skills --project "" --allowed-only [--name ] [--server ""] [--page-size ] [--cursor ] --format json ``` | Flag | Required | Purpose | |------|----------|---------| | `--project ` | **Yes** | AI Catalog project to list. | +| `--allowed-only` | **Yes** | Limit results to skills allowed by project policy. Never omit it. | | `--name ` | No | Find skills by name: server-side, case-insensitive substring, scoped to the project. | | `--server ` | No | jf CLI config entry to authenticate with (defaults to the resolved single server). | | `--page-size ` | No | Results per page. Pass `50` to stay bounded. The Agent Guard defaults to 500 if omitted. | | `--cursor ` | No | Continuation cursor from a previous page's JSON, to fetch the next page. | -| `--format json` | No | Raw page JSON instead of the default compact TSV (name + last-updated). | +| `--format json` | **Yes** | Raw page JSON used to render the result. | Request a bounded page with `--page-size 50 --format json`, present those skills, then read `exhausted` and `cursor` from the response. If `exhausted` is `false` @@ -37,6 +45,20 @@ For a `--name` search with no matches, reply with one line instead: To offer a follow-up (a skill's versions or repos), ask in plain language ("want the versions for one of these?") and run the command yourself. +## Requests for blocked or missing results + +Never omit `--allowed-only`, even when the user asks to see everything, blocked +skills, disallowed skills, or the contents of a repo absent from the results. +Never run another command to infer or expose what filtering removed. + +Only when the user asks about blocked or missing results, reply: + +> The listing is always governance-filtered. For access to a missing or blocked +> skill or repository, contact your project's governance policy owner. + +Otherwise, present the results simply as the list. Do not mention filtering, the +flag, or its mechanism. + ## List a repo's skills To see what is published in one specific skills repository (for example, to check @@ -50,6 +72,9 @@ jf skills list --repo "" --server-id "" --format json Never run a bare `jf skills list` (it errors): always pass `--repo ` here, or `--harness ` for installed skills (see `managing-installed-skills.md`). +Use this repo-scoped command only for a repo already returned by an allowed +catalog response or explicitly resolved/provisioned during publishing. Never use +it to inspect a missing repo or work around the governed catalog listing. **Presenting results (use this exact format).** Render the skills as this table, sorted by name, and nothing else (no commands, URLs, or flags): @@ -66,18 +91,76 @@ line instead: > No skills published in ``. -## A skill's versions and hosting repos +## A skill's versions, then its hosting repos + +This is a two-step reveal, not one combined table: show versions first, and +only surface repos once the user has picked a specific version. Both steps +read from the **same** query's result — do not start a new, separate query +for the repo step. That query itself can span multiple pages (see below); "the +same result" means the one fully-paged, merged result, not a single HTTP call. ```bash npx --yes --registry @jfrog/agent-guard \ - --list-skill-versions --project "" --skill "" [--server ""] [--page-size ] [--cursor ] [--format json] -# JSON: versions[].version, versions[].locations[].repoKey (page through with cursor like above) + --list-skill-versions --project "" --skill "" --allowed-only [--server ""] [--cursor ] --format json +# JSON: versions[].version, versions[].locations[].repoKey, versions[].locations[].allowStatus, exhausted, cursor ``` -**Presenting versions (use this exact format).** Newest version first: +**This call can be paginated — read every page before treating the result as +complete.** Unlike `--list-skills` (a browsing list, where stopping at one +page and offering more is a fine UX tradeoff), this call feeds a version/repo +*decision*: a truncated result here isn't a UX compromise, it's a wrong +answer — a real newer version, or a repo that only hosts a later version, +could be sitting on a page you never fetched. If `exhausted` is `false`, keep +calling with `--cursor ` (same `--skill`/`--allowed-only`) and merge +every page's `versions[]` into one combined list before doing anything else. +Only once `exhausted` is `true` do you have a complete result to run the +version-first / repo-second reveal on. Do this silently — do not narrate +paging to the user or ask if they want more, and never repeat the call for a +page you've already fetched. + +Skill identity is **name+version+repository-path, not just name+version** +(MLAI-1309): the same slug and version can exist as genuinely different +skills in different repos, so a name+version match alone is never proof two +entries are the same skill. Each `locations[]` entry carries its own +`allowStatus` — a repo's governance status is a per-repo fact, never a +per-version one. Because `--allowed-only` is always on, every repo that comes +back is allowed; a version whose only host repo is blocked simply won't +appear. + +**Step 1 — present versions only (use this exact format).** Newest version +first. Do **not** include a repos/"Hosted in" column here — repos are a +separate reveal in step 2: Versions of ``: -| Version | Hosted in | -|---------|-----------| -| `` | ``[, ``…] | +| Version | +|---------| +| `` | + +Then ask which version the user wants (to install, or just to see where it's +hosted) — use the agent surface's native single-choice picker when one is +available (one option per version, newest first), otherwise ask in plain +language. Do not assume the newest one. + +**Step 2 — once a version is chosen, present its repos (use this exact +format).** Filter the already-fetched `locations[]` down to that one version +— no new API call: + +Repos hosting `@`: + +| Repo | +|------| +| `` | + +Every repo listed here is governance-allowed (the filter is always on), so +do **not** annotate rows with a status suffix — an "(allowed)" tag on every +row is noise. Agent Guard's own compact TSV does print ` (allowed)`; +strip that when rendering this table. + +- **Exactly one repo.** State it plainly ("hosted in ``") — no need + to ask the user to choose. +- **More than one repo.** Never auto-pick or merge. Ask which repo they mean + before doing anything further (installing, etc.) — use the agent surface's + native single-choice picker when one is available (one option per + `repoKey`), otherwise render the table above and ask in plain language. See + `installing-skills.md`'s *Resolve the repo*. diff --git a/skills/jfrog-ai-catalog/references/installing-skills.md b/skills/jfrog-ai-catalog/references/installing-skills.md index 3f98dfc..8c3276c 100644 --- a/skills/jfrog-ai-catalog/references/installing-skills.md +++ b/skills/jfrog-ai-catalog/references/installing-skills.md @@ -6,13 +6,26 @@ verify-landed check. ## Contents +- Choice UI - When evidence verification fails - Handling a blocked download (403 / Xray-gated) - Verify the install landed - Update an installed skill -Install by **slug** (the registry `slug`/`name`, never a display name). Latest -version is used by default, and the user may pass an explicit version. +Install by **slug** (the registry `slug`/`name`, never a display name). Always +resolve and pass a concrete version and repository. Never install with +`--version "latest"` and never choose the first repository as a default — +at install time the repo is not yet resolved, and `--version "latest"` could +silently pick an ambiguous version/repo combination without the required ask. + +**Exception — `jf skills update` may use `--version "latest"`.** An update +target is already installed, so its repo is fixed — not automatically by +`jf`, but by reading it back from that install's own record (see *Update an +installed skill* below) — and `allowStatus` is a per-repo fact, not +per-version, so every version in that already-allowed repo is equally +allowed. "Latest version in this specific, already-resolved repo" carries +none of the version/repo ambiguity this rule exists to prevent. + **The `jf skills install` command takes no project.** Resolving which repo hosts the slug uses `--list-skill-versions` (below), which does require `--project`, so use `` resolved at session start (see SKILL.md Prerequisites). @@ -20,7 +33,7 @@ use `` resolved at session start (see SKILL.md Prerequisites). ```bash jf skills install "" \ --server-id "" \ - --version "latest" \ + --version "" \ --repo "" \ --harness "" \ --quiet @@ -70,28 +83,131 @@ Choose exactly one install target (these are mutually exclusive): | `--project-dir ` | Project root combined with the agent's project path. | | `--path ` | Direct: files go under `/`. | -**Always resolve and pass `--repo`.** When the platform has more than one skills -repository (the common case), `jf skills install` errors with `multiple skills -repositories found … specify --repo` if you omit it, even when the skill lives -in only one repo. So **the first install step is always** to look up where the -slug is hosted with the Agent Guard: +**Always resolve and pass a concrete `--version` and `--repo`.** When the platform +has more than one skills repository (the common case), `jf skills install` +errors with `multiple skills repositories found … specify --repo` if you omit +it, even when the skill lives in only one repo. Resolve both values from this +one Agent Guard query: ```bash npx --yes --registry @jfrog/agent-guard \ - --list-skill-versions --project "" --skill "" [--server ""] --format json -# read versions[].version and versions[].locations[].repoKey + --list-skill-versions --project "" --skill "" --allowed-only [--server ""] [--cursor ] --format json +# read versions[].version, versions[].locations[].repoKey, versions[].locations[].allowStatus, exhausted, cursor ``` +**This can be paginated — read every page before resolving anything from it.** +If `exhausted` is `false`, keep calling with `--cursor ` (same +`--skill`/`--allowed-only`) and merge every page's `versions[]` before doing +the version/repo resolution below. A skill with more versions than one page +holds must never look like it has fewer, or be missing the repo that only +hosts its true latest version. Do this silently, with no pagination commentary +to the user. Once merged and `exhausted` is `true`, that combined result is +what "Do not make another catalog call" below refers to — you still must not +re-run this query a second time to separately resolve version and then repo. + **Resolve the repo and version only via `--list-skill-versions`.** The catalog listing (`--list-skills`, even with `--name`) returns just names, not repos or versions, so use the versions call above to pick the repo, never a name listing. -- **One repo hosts the slug.** Use it as `--repo ` directly. Don't ask. -- **Multiple repos host the slug.** Do not pick silently. Naming a project is not - a repo choice, so ask even when one repo is project-scoped. List the repos (and - the version each holds), ask the user which to install from, then pass - `--repo `. The newest version may only exist in one of them, so - surface that to avoid giving the user a stale version. +Resolve choices in this order. **These are two separate questions, asked one +at a time — never combine them into a single choice.** Even when the +version-versions endpoint returns every version×repo combination in one +response, do not present that as a flattened list (e.g. "0.1.1 → +repo-a", "0.1.1 → repo-b", "0.1.0 → repo-a", "0.1.0 → repo-b") and ask the +user to pick one row. Ask which version first, stop and wait for that +answer, and only then — scoped to the chosen version alone — ask which repo, +if more than one hosts it. + +1. **Version first.** + - If the user named a version, verify that exact value exists in + `versions[].version`. If absent, stop and offer the returned versions with + the picker described below. Do not make another catalog call. + - If the user did not name a version and exactly one version exists, use that + concrete version without asking. + - If the user did not name a version and more than one exists, ask which + version to install. Present versions newest first. Never assume the newest, + `"latest"`, or the first response entry. **Stop your turn on this + question and wait for the user's reply.** Do not pick one yourself and + continue in the same response — see *Choice UI* below. + - **"Newest allowed" is still assuming the newest.** `--allowed-only` + filters out versions/locations you must never show, not a signal that + the remaining newest one is the right default. If more than one + governance-allowed version remains, the ask above still applies — do + not silently install "the newest allowed version" and only ask about + the repo. + - If no versions exist, report that the skill is unavailable for the project + and stop. + +2. **Repository second.** After settling the version, use only that version + object's `locations[]`; discard locations attached to every other version. + Do not make another catalog call. + - If the user named a repo, verify it is among the selected version's + locations. If absent, say that repo is not governance-allowed for the + project and stop. Never retry without the policy filter or inspect the repo + directly. + - If exactly one repo hosts the selected version, use its `repoKey` without + asking. + - If more than one repo hosts the selected version, ask which repo to use. + Never pick the first or the most recently updated-looking repo: equal + slug+version values in different repos can contain different skills. + **Stop your turn on this question and wait for the user's reply.** Do not + pick one yourself and continue in the same response — see *Choice UI* + below. + - **There is no "project-owned repo."** `` scopes which skills and + versions the catalog query returns — it is not a field on `locations[]` + and it never disambiguates between multiple repos that host the same + version. Do not infer a repo from the project name, a repo name that + happens to contain the project name, "the one that matches the active + project," or any other derived signal not present in `locations[]` + (`repoKey`, `allowStatus`). If you catch yourself constructing a + justification for skipping the ask, that justification is wrong — ask + instead. + - If the selected version has no returned locations, report it unavailable + for the project and stop. + + **Each repo carries its own governance status (MLAI-1309).** Skill + identity is name+version+repository-path, not just name+version, and a + repo's `allowStatus` in `locations[]` is a per-repo fact, never a + per-version one. The skill always passes `--allowed-only` to + `--list-skill-versions`, so only governance-allowed repos ever come back + and every candidate you show the user is installable. Never re-run + without the flag to surface blocked repos — if a repo the user expects is + missing, say it isn't governance-allowed for this project and stop there. + +## Choice UI + +Use the agent surface's native interactive single-choice picker (an arrow-key +selectable menu) whenever a version or repo choice is required and such a +picker is available to the skill. Do not print a table and wait for a typed +reply when a picker is available. + +**Asking is not complete until the user replies — on any surface.** Whether +you use a native picker or the Markdown table fallback, end your turn on the +question itself. Never treat rendering the question as satisfying the "ask +the user" requirement and then proceed to resolve the choice yourself and +call `jf skills install` in that same turn — that is exactly the missing +version/repo confirmation this section exists to prevent (MLAI-1309). This +applies even on chat-only surfaces with no way to block for input: the fix +for having no blocking mechanism is to stop responding, not to guess and +install. + +**Not every harness has a native picker.** Some agent surfaces (for example +GitHub Copilot Chat in the VS Code plugin) run skills as chat-turn +instructions with no programmatic access to a native single-choice picker. +Never claim or imply a picker exists where it doesn't — on those surfaces, +always use the Markdown table fallback below. + +- Version picker: label each option with only the version string, newest first. + Do not include repo keys before the version is settled. +- Repo picker: label each option with only its `repoKey`. Put + `@` in that option's description or subtitle, not its label. +- Do not append "(allowed)" to repo labels. Every returned location is already + allowed. +- Fall back to a Markdown table followed by a plain-language question whenever + no interactive picker exists in the current context. Use one **Version** + column (newest first) for versions or one **Repository** column (`repoKey` + only) for repos, and name `@` in the repo question. Never add + an "(allowed)" annotation. ## When evidence verification fails @@ -168,14 +284,34 @@ On success, reply using **this exact template**: ## Update an installed skill To upgrade an installed skill to a newer version, use the CLI (it re-downloads -and reinstalls in place): +and reinstalls in place). **`jf skills update` does not remember which repo the +skill was installed from — you must resolve and pass `--repo` yourself.** +Without it, update either fails with `multiple skills repositories found` +(listing every skills repo on the whole server, not scoped to this project or +its governance policy at all) or, if handed some other repo, silently updates +from it — even one that never hosted the originally installed skill. Never +run `jf skills update` without a resolved `--repo`. + +**Resolve `` from the existing install, never by asking the user or +guessing.** Every install writes it to `.jfrog/skill-info.json` under the +install directory: + +```bash +jq -r '.repo' "//.jfrog/skill-info.json" +``` + +If that file or its `.repo` field is missing (for example, a skill that was +manually copied in rather than installed with `jf skills install`), tell the +user you can't safely determine which repo to update from and stop. Do not +substitute a repo from a fresh catalog listing instead — a same-named repo +returned there is not proof it is the repo this specific install came from. ```bash -jf skills update "" --server-id "" --harness "" --version "latest" --quiet +jf skills update "" --server-id "" --harness "" --repo "" --version "latest" --quiet # Preview without touching Artifactory: -jf skills update "" --server-id "" --harness "" --dry-run +jf skills update "" --server-id "" --harness "" --repo "" --dry-run # Reinstall even if already at the target version: -jf skills update "" --server-id "" --harness "" --force --quiet +jf skills update "" --server-id "" --harness "" --repo "" --force --quiet ``` Use the same install-target flag (`--harness`/`--global`/`--project-dir`/ diff --git a/skills/jfrog-init/scripts/lib/jf-api.mjs b/skills/jfrog-init/scripts/lib/jf-api.mjs index ec4d436..92ba907 100644 --- a/skills/jfrog-init/scripts/lib/jf-api.mjs +++ b/skills/jfrog-init/scripts/lib/jf-api.mjs @@ -45,6 +45,7 @@ export function jfApi(args) { // Pinning stdio here keeps this silent: nothing is inherited, // everything is still captured. stdio: ["ignore", "pipe", "pipe"], + env: { ...process.env, CI: "true" }, }); return { ok: true, stdout, stderr: "" }; } catch (err) { diff --git a/skills/jfrog-mcp-management/SKILL.md b/skills/jfrog-mcp-management/SKILL.md index 5291e55..d60fb40 100644 --- a/skills/jfrog-mcp-management/SKILL.md +++ b/skills/jfrog-mcp-management/SKILL.md @@ -425,10 +425,13 @@ Then tell the user: 2. Restart per the harness's **Restart** column. 3. Accept any per-server approval / workspace-trust prompt on first launch (skipped when pre-approval succeeded). -4. Verify per the harness's **Verify** column. **The server MUST expose at least - one tool** — a "connected" label alone is NOT proof (the proxy reports - connected with 0 upstream tools). Empty tool list = Failed; see the "0 tools" - entry in [references/key-rules-and-troubleshooting.md](references/key-rules-and-troubleshooting.md). +4. Verify per the harness's **Verify**. Success = **at least one + upstream tool** you can see or call. If you already can, stop — do + not ask the user to check a tool count. If you cannot, Enable / + Restart may still be needed (tools often attach only after). An + empty tool list is not success and not a diagnosis — follow + [Connected but 0 tools](references/key-rules-and-troubleshooting.md#connected-but-0-tools). + Do not invent another debug path until that section is finished. ## Step 5: Authenticate OAuth MCPs (auto, after Step 4) @@ -442,9 +445,13 @@ Skip for local MCPs and for remote MCPs whose auth comes from a static token in `env`. `--login` opens the browser, runs OAuth, caches tokens in -`~/.jfrog/jfrogmcp.conf.json`. In the same turn, tell the user you are about -to open the browser to sign them in to `` and immediately run the -command — do not wait for confirmation or a follow-up prompt: +`~/.jfrog/jfrogmcp.conf.json`. Agent Guard may also expose +`enable__tools` until login completes; invoking it starts the same +OAuth login from the session. + +In the same turn, tell the user you are about to open the browser to sign +them in to `` and immediately run the command — do not wait for +confirmation or a follow-up prompt: ``` npx --yes \ diff --git a/skills/jfrog-mcp-management/references/harness-claude.md b/skills/jfrog-mcp-management/references/harness-claude.md index 5db2295..f99a2ea 100644 --- a/skills/jfrog-mcp-management/references/harness-claude.md +++ b/skills/jfrog-mcp-management/references/harness-claude.md @@ -86,11 +86,17 @@ metadata, read `mcpServers` from `.mcp.json` (project) and `~/.claude.json` ## Verify -`/mcp` → **drill into the server entry** (arrow into it, not just the top-level -row) → read `Capabilities:`. It MUST list at least one tool. Top-level -`✓ connected` alone is NOT proof (green whenever the proxy started, even with 0 -upstream tools). Empty `Capabilities:` = Failed → see the "0 tools" -troubleshooting in [key-rules-and-troubleshooting.md](key-rules-and-troubleshooting.md). +If you can already see or call at least one upstream tool from this +server, skip this check. Otherwise: you run `/mcp` → **drill into the +server entry** (arrow into it, not just the top-level row) → read +`Capabilities:`. Do not ask the user to report `Capabilities:`. + +Success: `Capabilities:` lists at least one upstream tool. Top-level `✓ connected` +alone is not success (green whenever the proxy started). + +Empty tool list: not success, not a diagnosis — follow +[Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. ## Approval / stuck-state precedence diff --git a/skills/jfrog-mcp-management/references/harness-codex.md b/skills/jfrog-mcp-management/references/harness-codex.md index f2c0eaa..729878a 100644 --- a/skills/jfrog-mcp-management/references/harness-codex.md +++ b/skills/jfrog-mcp-management/references/harness-codex.md @@ -184,26 +184,25 @@ match `^[a-zA-Z0-9_-]+$`), or an untrusted project config. ## Verify -Run `/mcp` in the Codex TUI (or check the IDE extension's MCP view) and confirm -the server exposes the upstream MCP's **real tools**. `codex mcp list` shows the -server and its auth status but is NOT proof of working tools - the Agent Guard -proxy can report up with 0 upstream tools. +If you can already see or call at least one upstream tool from this +server, skip this check. Otherwise: run `/mcp` in the Codex TUI (or check the IDE +extension's MCP view) for the server's tools. `codex mcp list` shows the +server and its auth status. -Codex-specific signals to read correctly: - **`Auth: Unsupported` is normal** for static-header and local MCPs - it describes Codex's own OAuth support, not the upstream MCP. Judge by the tool list. -- **An `enable__tools` tool is a normal Agent Guard gate**, not an error: - for MCPs that need sign-in or explicit enablement, the Agent Guard first - exposes this single tool; invoking it (e.g. "sign in to ``") runs the flow - and the upstream MCP's real tools then appear. Re-check `/mcp` afterward. -- If the **real tools never appear** (even after enabling / signing in), a - required input likely did not reach the server - most often an `env_vars` name - or shell export whose case does not match the catalog input `name` (see Value - reference), or a variable that was not exported in the launching shell. Fix it - and start a new session. A truly empty tool list = Failed → see the "0 tools" - troubleshooting in - [key-rules-and-troubleshooting.md](key-rules-and-troubleshooting.md). +- **`enable__tools`** starts OAuth login (Step 5) — invoke it, then + re-check `/mcp`. Not success by itself. + +Success: at least one **real** upstream tool (not only `enable__tools`). +`codex mcp list` "connected" or auth status alone is not success. + +Empty tool list: not success, not a diagnosis. Check that each `env_vars` +name matches the catalog input `name` and is exported in the launching +shell (see Value reference). Mismatch → fix it and start a new session. +Then follow [Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. ## Remove diff --git a/skills/jfrog-mcp-management/references/harness-common.md b/skills/jfrog-mcp-management/references/harness-common.md index 4cd417e..f740c92 100644 --- a/skills/jfrog-mcp-management/references/harness-common.md +++ b/skills/jfrog-mcp-management/references/harness-common.md @@ -115,10 +115,23 @@ case; harnesses whose config is not JSON differ — e.g. **Codex** uses TOML wit JFrog project key is lowercase alphanumerics/hyphens, and `spec.packageName` adds only `@ . /`. Never substitute any other value into `_JF_ARGS`. -**Success criterion (every harness):** after enable + restart, the server MUST -expose **at least one tool**. A "connected" / "running" label alone is NOT proof -— the Agent Guard proxy can report up with 0 upstream tools. An empty -tool/capability list = Failed. +**Success criterion (every harness):** success = at least one upstream tool +from that server that you can see or call, not a connected/running +indicator. Agent Guard can show connected with 0 upstream tools. +`enable__tools` starts that server's OAuth login (Step 5) — invoke +it, then re-check. It is not an upstream tool. + +1. If you can already see or call at least one upstream tool from this + server, that is success. Stop. Do not ask the user to check a tool + count for you; tools you can already use are enough. +2. If you cannot, that is not a failure. Some harnesses inject tools as + soon as the MCP is up; some only after Restart. Follow the **Verify** + section in the harness file. Ask the user only when that section + tells you to. + +Still no tools after that check: not success, not a diagnosis — follow +[Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. **OAuth cache (every harness):** OAuth `--login` caches tokens in `~/.jfrog/jfrogmcp.conf.json` regardless of harness; removal cleanup of that diff --git a/skills/jfrog-mcp-management/references/harness-cursor.md b/skills/jfrog-mcp-management/references/harness-cursor.md index 14930d1..8f4994c 100644 --- a/skills/jfrog-mcp-management/references/harness-cursor.md +++ b/skills/jfrog-mcp-management/references/harness-cursor.md @@ -45,19 +45,25 @@ never enabled — re-run Enable. ## Verify -**`cursor agent mcp list` / `cursor agent mcp enable` are NOT authoritative** for -the Cursor IDE — do not treat them as proof the MCP works. The only proof is that -tool descriptor files are actually present at: +If you can already see or call at least one upstream tool from this +server, skip this check. Otherwise: after `Developer: Reload Window`, +check that tool descriptor files exist at: ``` ~/.cursor/projects//mcps//tools/*.json ``` (`` is the JSON key of the MCP, optionally prefixed `user-`.) -NEVER ask the user to inspect these files themselves — after they enable the MCP, -**offer to check the `tools/` directory for them**. If `tools/` is empty or -missing after a `Developer: Reload Window`, treat as Failed → see the "0 tools" -troubleshooting in [key-rules-and-troubleshooting.md](key-rules-and-troubleshooting.md). +**`cursor agent mcp list` / `cursor agent mcp enable` are not the check** for +the Cursor IDE. NEVER ask the user to inspect these files — **offer to check +the `tools/` directory for them**. + +Success: at least one upstream tool from this server you can see or call, or at +least one `*.json` in that `tools/` directory. + +Empty tool list: not success, not a diagnosis — follow +[Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. ## Notes diff --git a/skills/jfrog-mcp-management/references/harness-devin.md b/skills/jfrog-mcp-management/references/harness-devin.md index d4800ca..2dbd330 100644 --- a/skills/jfrog-mcp-management/references/harness-devin.md +++ b/skills/jfrog-mcp-management/references/harness-devin.md @@ -124,24 +124,24 @@ only. ## Verify Before treating a missing server as Failed, confirm the entry is in the active -store for this harness (user `~/.config/devin/mcp_config.json` by default). - -After the user completes Restart (see Restart), run `devin mcp list` for connection status, -then **list that server's live tools** through the connected MCP (Devin CLI and -Devin Desktop Local). - -The server MUST expose **at least one tool**. A connected indicator alone is -NOT proof — the Agent Guard proxy can report connected with 0 upstream tools. -Empty tool list = Failed → see the "0 tools" troubleshooting in -[key-rules-and-troubleshooting.md](key-rules-and-troubleshooting.md). - -Do **not** treat a tool list scraped from npm / GitHub docs as verification — -only a live tool list from the connected server counts. - -On first connect without cached OAuth, Devin opens a browser to sign in; later -runs reuse stored credentials. Devin Local and Devin CLI may prompt to approve -each MCP tool call by default — grant the prompt before treating an empty list -as a failure. +store (user `~/.config/devin/mcp_config.json` by default). + +If you can already see or call at least one upstream tool from this +server, skip this check. Otherwise: after the user completes Restart, +run `devin mcp list` for connection status, then +**list that server's live tools** through the connected MCP (Devin CLI and +Devin Desktop Local). On first connect without cached OAuth, Devin opens a +browser to sign in; later runs reuse stored credentials. Devin Local and Devin +CLI may prompt to approve each MCP tool call by default — grant the prompt +before listing tools. + +Success: the live tool list from the connected server has at least one +upstream tool. A connected indicator alone is not success. Do **not** treat a +tool list scraped from npm / GitHub docs as verification. + +Empty tool list: not success, not a diagnosis — follow +[Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. ## Notes diff --git a/skills/jfrog-mcp-management/references/harness-kiro.md b/skills/jfrog-mcp-management/references/harness-kiro.md index fa802d4..72cb922 100644 --- a/skills/jfrog-mcp-management/references/harness-kiro.md +++ b/skills/jfrog-mcp-management/references/harness-kiro.md @@ -63,14 +63,18 @@ var exported after Kiro is already running won't resolve until you relaunch. ## Verify +If you can already see or call at least one upstream tool from this +server, skip this check. Otherwise: + - **`kiro-cli`:** `kiro-cli mcp status --name ` for connection status, - then confirm real tools via `/mcp` in the same chat session (lists each - active server's tools). + then confirm tools via `/mcp` in the same chat session (lists each active + server's tools). - **Kiro IDE:** tell the user to type `/mcp` in the chat — it lists each - active server's tools directly, so they can drill into the target server. - Do not invoke it as a tool yourself. + active server's tools. Do not invoke it as a tool yourself. + +Success: `/mcp` lists at least one upstream tool for the server. Connected/active +status alone is not success. -A connected/active status alone is NOT proof — the Agent Guard proxy can -report up with 0 upstream tools. Empty tool list = Failed, see the "0 tools" -troubleshooting in -[key-rules-and-troubleshooting.md](key-rules-and-troubleshooting.md). +Empty tool list: not success, not a diagnosis — follow +[Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. diff --git a/skills/jfrog-mcp-management/references/harness-opencode.md b/skills/jfrog-mcp-management/references/harness-opencode.md index 816b810..1142eaa 100644 --- a/skills/jfrog-mcp-management/references/harness-opencode.md +++ b/skills/jfrog-mcp-management/references/harness-opencode.md @@ -133,24 +133,23 @@ section - do NOT print, log, or return the whole file or unrelated config values ## Verify -Confirm the server exposes the upstream MCP's **real tools** (they appear to the -agent as `_`). `opencode mcp list` shows connection -status, but a "connected" row is NOT proof - the Agent Guard proxy can report up -with 0 upstream tools. - -- **An `enable__tools` tool is a normal Agent Guard gate**, not an error: - for MCPs that need sign-in or explicit enablement, the Agent Guard first - exposes this single tool; invoking it (e.g. "sign in to ``") runs the flow - and the upstream MCP's real tools then appear. Re-check afterward. (OpenCode's - own `opencode mcp auth` is for `type: "remote"` OAuth servers only and does NOT - apply to this local Agent Guard entry.) -- If the **real tools never appear** (even after enabling / signing in), a - required input likely did not reach the server - most often an `environment` - name or shell export whose case does not match the catalog input `name` (see - Value reference), or a variable that was not exported in the launching shell. - Fix it and start a new session. A truly empty tool list = Failed → see the - "0 tools" troubleshooting in - [key-rules-and-troubleshooting.md](key-rules-and-troubleshooting.md). +If you can already see or call at least one upstream tool from this +server, skip this check. Otherwise: confirm tools via the names the agent sees: +`_`. `opencode mcp list` shows connection status. + +`enable__tools` starts OAuth login (Step 5) — invoke it, then +re-check. Not success by itself. (OpenCode's own `opencode mcp auth` is for +`type: "remote"` OAuth servers only and does NOT apply to this local Agent +Guard entry.) + +Success: at least one **real** upstream tool (not only `enable__tools`). +`opencode mcp list` "connected" alone is not success. + +Empty tool list: not success, not a diagnosis. Check that each +`environment` name matches the catalog input `name` and is exported in +the launching shell (see Value reference). Mismatch → fix it and start +a new session. Then follow [Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. ## Remove diff --git a/skills/jfrog-mcp-management/references/harness-vscode.md b/skills/jfrog-mcp-management/references/harness-vscode.md index 2c0b61f..465c488 100644 --- a/skills/jfrog-mcp-management/references/harness-vscode.md +++ b/skills/jfrog-mcp-management/references/harness-vscode.md @@ -100,10 +100,18 @@ started — re-run Enable. ## Verify -Ask the user to confirm in `MCP: List Servers` that the server is **Running with -at least one tool**. "Discovered 0 tools" is NOT healthy — the Agent Guard -started but the upstream MCP didn't. Treat 0 tools as Failed → see the "0 tools" -troubleshooting in [key-rules-and-troubleshooting.md](key-rules-and-troubleshooting.md). +If you can already see or call at least one upstream tool from this +server, skip this check. Otherwise: Enable / Restart if that has not +happened, then check this session again. Only then ask the user to open +`MCP: List Servers` and say whether the server is up. Do not ask them +for a tool count. + +Success: at least one upstream tool from this server is available to you. +The server being up is not success. + +Empty tool list: not success, not a diagnosis — follow +[Connected but 0 tools](key-rules-and-troubleshooting.md#connected-but-0-tools). +Do not invent another debug path until that section is finished. ## Remove cleanup @@ -122,6 +130,8 @@ echo any stored value. A wrong stored secret is cleared via the **Clear** CodeLens above the matching `inputs` entry in `mcp.json`; then restart the server and VS Code re-prompts. -Several steps here (Start, entering inputs, checking `MCP: List Servers`) are -UI-only **user** actions — ask the user to do them; editing `mcp.json` and -running the agent guard commands are your steps. +Several steps here (Start, entering inputs) are UI-only **user** actions — +ask the user to do them. Editing `mcp.json`, running the agent guard +commands, and checking this session's tools are your steps. `MCP: List +Servers` only when you cannot see tools yourself, or when they ask whether +a server is running — do not ask them for a tool count. diff --git a/skills/jfrog-mcp-management/references/key-rules-and-troubleshooting.md b/skills/jfrog-mcp-management/references/key-rules-and-troubleshooting.md index 738662a..7cf492b 100644 --- a/skills/jfrog-mcp-management/references/key-rules-and-troubleshooting.md +++ b/skills/jfrog-mcp-management/references/key-rules-and-troubleshooting.md @@ -97,25 +97,71 @@ as the MCP proxy. Carve-out: `--login` `expected 401, got 200` is anonymous MCP — ignore, not this bucket. +## Connected but 0 tools + +The harness shows the server connected/running but this agent still has no +tools from that server (none you can see or call). Agent Guard (the proxy) +is up; upstream tools are not visible. Do not report success. If this +session already has an upstream tool from that server, this section does not apply. + +Run the steps in order. Do not skip a step, including because you think you +already know the answer. When a step says re-run **Verify**, +use this harness's **Verify** section. Do not invent another +check, script, or debug path until these steps are finished. + +Expected flow: when the upstream is ready, Agent Guard sends MCP +`tools/list_changed` and the harness updates the tool list. Re-check this +harness's **Verify**. If the harness does not hot-refresh, the user must +apply that harness's **Restart**. + +**Restart** means the action in this harness's **Restart** section (new +agent session / reload). It does not mean rebooting the machine or a +separate MCP-only command. + +Typical reasons: +- Upstream still starting (download, install, first launch). +- Not allowed in this JFrog project (allowlist is dynamic). +- Upstream failed to start (missing env, expired token, runtime/spawn error). +- The harness session was not running. Agent Guard and the upstream start + when the harness starts — waiting with it closed does not count. + +Steps: +1. If the config changed and this harness's **Restart** has not run since, + do that first. +2. Re-run Verify (including now). ≥1 tool → success. Stop. +3. List → Available to install (`--list-available`). Confirm this MCP is + still in the catalog for this project. A recent `--inspect` is not this + check — allowlist membership is dynamic, and a wrong project key looks + the same as one that is still starting. +4. Re-run Verify. ≥1 tool → success. Stop. +5. Still empty: **stop**. Do not gather logs in this turn. Tell the user + once that after Restart the upstream may take up to a few minutes. + They can say **check again**. Do not guess how long, and + do not send them away to wait. If they waited with the harness closed, + the MCP was not running — the wait starts after Restart. +6. After **check again**, or if they ask to debug further: re-run Verify. + ≥1 tool → success. Stop. How long it has already been is not a + diagnosis. +7. Still empty with the harness running after Restart — gather logs: + - Set `JF_AGENT_GUARD_LOG_LEVEL=debug` on the Agent Guard entry's env, + then Restart, and read Agent Guard stderr. + - If the harness has a debug mode (e.g. Claude Code `claude --debug`), + relaunching in that mode can add more log output. + From stderr: + - **OAuth (remote)** — re-run `--login`. + - **Static-token (remote)** — this harness's **Value reference** is set. + - **Local (stdio)** — spawn/runtime error. + Last resort: run the same command as the config entry in a terminal + (`npx --yes --registry @jfrog/agent-guard` plus that + entry's `--server` / `_JF_ARGS`, with `JF_AGENT_GUARD_LOG_LEVEL=debug`). + This is an MCP stdio process — it will block until you stop it. Read + stderr. Do not start by writing a wrapper script. + ## Troubleshooting Items below are harness-agnostic unless they point into the current harness's row in [harness-common.md](harness-common.md). -- **"connected" but 0 tools** (empty tool/capability list in the harness's - verify view — e.g. Claude Code's `/mcp` `Capabilities:`) — agent guard proxy - started, upstream MCP did not. A "connected" label is misleading here. NEVER - report success when there are 0 tools. - 1. Relaunch in the harness's debug mode if it has one (e.g. Claude Code: - `claude --debug`) and read the agent guard stderr; diagnose by MCP type: - - **OAuth (remote)** — re-run the OAuth login (`--login`); refresh token - likely expired. - - **Static-token (remote)** — confirm every `${VAR}` in `env` is exported - in the launching shell and the token is still valid. - - **Local (stdio)** — check that the bundled binary actually launched - (agent guard stderr will show the spawn error). - 2. Verify that the MCP server is still allowed. See the skill's "Available to - install" flow. - **An MCP was installed as a `stdio` Agent Guard entry although Gateway routing is expected** — this is the designed fallback, not a failure. `--inspect` returns anything other than @@ -131,7 +177,7 @@ row in [harness-common.md](harness-common.md). why, the reason is on stderr: re-run the Step 2 `--inspect` command with `JF_AGENT_GUARD_LOG_LEVEL=debug` exported and read the single eligibility record it prints. Never paste an access token from that output. -- **Configured server missing from the harness's list/verify view** — +- **Configured server missing from the harness's list or Verify** — rejected/pending. Re-run the enable/verify step (Install → Step 4a). - **MCP still appears as approved (or won't go away) after editing the config** — on harnesses that pre-approve via files (e.g. Claude Code), approval state diff --git a/skills/jfrog/SKILL.md b/skills/jfrog/SKILL.md index 07806a0..c62af5d 100644 --- a/skills/jfrog/SKILL.md +++ b/skills/jfrog/SKILL.md @@ -19,7 +19,7 @@ compatibility: >- (CLI) and Tier 3 (jf api) operations; without it, only MCP (Tier 1) is available. metadata: role: base - version: "0.38.0" + version: "0.40.0" --- # JFrog Skill @@ -36,25 +36,30 @@ Network-facing `jf` this session. Exempt until ``: `jf --version`, - **UA:** [Environment check](#environment-check) once → on exit 0/1, export its **exact stdout line** as `JFROG_CLI_USER_AGENT` atop every bash that runs `jf` (never invent / rebuild the UA) -- **CLI offer:** after [Environment check](#environment-check) exit 0/1 - (skip `jfrog-init` / MCP-only). `NEWER_AVAILABLE` → stop, Yes/No; SKIP/No → silent +- **CLI offer:** after Environment check exit 0/1 (skip `jfrog-init` / + MCP-only). `NEWER_AVAILABLE` → never block: `--clear` immediately (before + any other command), finish the task, end the reply with the upgrade note; + SKIP → silent - **Server:** resolve default once → `--server-id ` **after** subcommand (`jf api --server-id …`, never `jf --server-id … api`). One request → one server (unless user names servers, e.g. `compare and `) -- **Error (401/403/404/timeout):** stop — never retry another server / never - infer multi-server. Override only if user names a server +- **Error (401/403/404/timeout):** never hop servers. List a repo with AQL + (local or `-cache`). 401 → re-login **same** server, then **one** + retry (sole identical-request exception). 403/404/timeout → never re-fire + the same path+query (package-block 403 → `jfrog-package-curation`). Empty + `offset`/`page` → stop. Pager ≤20 pages. Same path 403 → stop (one hop) - **No prep mutations:** missing repo/artifact/build → stop + report; no create/copy/move/upload to fill the gap (workaround ask ≠ permission) - **Never guess** tools / `jf api` paths → tool list / `--help` / `references/`. 404 → stop (no guessed retry). `jf api` needs product prefix - (`/artifactory`, `/xray`, …) + (`/artifactory`, `/xray`, …). Never `GET /api/v1/artifacts` to list a repo - **Hard-rule signals:** [Cautious execution](#cautious-execution), [Server selection rules](#server-selection-rules-mandatory), [Gotchas](#gotchas--hard-rules-never-skip) Tier A bullets below — not tips - **Gotcha floor (Tier A):** never interactive (`jf config add`, `jf login`, template wizards, …); if a call fails **with** `--server-id`, do **not** - retry without it; 401/403/404/timeout → stop, never hop servers; `--quiet` - is not global — check `--help` before adding it + retry without it; 401 → one re-login retry; 403/404/timeout → stop, never + hop or loop; `--quiet` is not global — check `--help` before adding it **Tier B — path-gated MUST** (before `jf api` / AQL / advanced CLI I/O / MCP-result-via-shell anti-patterns): full @@ -111,8 +116,9 @@ cover the operation or fails: subcommand. Validate the path first — see rule 6 in [Cautious execution](#cautious-execution). -MCP and CLI may use different token scopes. One tier returns 403 → try the -other tier before reporting the operation blocked. +MCP and CLI may use different token scopes. One 403 → try the **other** +tier **once** (package-block → `jfrog-package-curation`). 401 → then +**one** retry of that URL. ## Prerequisites @@ -159,10 +165,15 @@ Then, on exit 0/1 only: ```bash bash /scripts/cli-newer-version-offer.sh # SKIP → continue the original task; do not mention the offer. -# NEWER_AVAILABLE (suggest_upgrade) → stop; Yes / No. After: +# NEWER_AVAILABLE (suggest_upgrade) → never block or ask +# mid-task. Immediately run (before any other command): # bash /scripts/cli-newer-version-offer.sh --clear -# Yes → references/jfrog-cli-install-upgrade.md, then check-environment.sh --force -# (Tier 2/3 only on exit 0/1). No → silent. Next offer = next new latest. +# Then finish the original task (success or failure) and end the final reply +# with this line verbatim as its very last line (no other upgrade mention): +# JFrog CLI is available (you have ). Upgrade? Yes / No +# Yes (later turn) → references/jfrog-cli-install-upgrade.md, then +# check-environment.sh --force (Tier 2/3 only on exit 0/1). No → silent. +# Next offer = next new latest. JFROG_CLI_AVOID_NEW_VERSION_WARNING=true → SKIP. ``` Exit 2/3 produces no ``; follow the exit table below and do not proceed to @@ -212,7 +223,8 @@ any workflow skill that builds on this base skill. Examples elsewhere in this skill and in `references/*.md` omit the export for readability — the rule is global. When launching a subagent, pass `` in its prompt (see [Never invent](#never-invent-jfrog_cli_user_agent)) and whether the CLI -offer already ran. Subagents do not re-ask. +offer already ran. Subagents never show the upgrade note: on `NEWER_AVAILABLE` +they `--clear` and return that line; the parent ends its reply with the note. | Exit | Meaning | |------|---------| @@ -286,6 +298,9 @@ forbidden. Before any JFrog CLI command, MCP tool call, or API call: [JFrog OpenAPI specifications](https://docs.jfrog.com/integrations/docs/openapi-specifications) if you have web access). On a 404, stop and report — never retry with a guessed alternative path. +7. **Never retry a failed call in a loop.** AQL on `-cache` (virtuals + are not `-cache`). 401 → then **one** retry. Pager **20-page cap** — + `cli-gotchas.md`. Do not invent `GET /api/v1/artifacts`. ## Server selection rules (mandatory) @@ -339,8 +354,9 @@ re-resolve. Examples elsewhere in this skill and in `references/*.md` omit ### On any error, stop — never switch -If a `jf` call returns 401/403, 404, network error, timeout, or any other -failure, **stop with no further `jf` calls** and respond: +If a `jf` call returns 403, 404, network error, timeout, or any other +non-401 failure, **stop with no further `jf` calls** and respond. 401 → +re-login same server, then **one** retry; if that fails, stop: > `` returned `` for ``: ``. Other > configured server(s): `` — I won't query them without your explicit @@ -431,8 +447,8 @@ full file on Tier B paths. default-server switch). See [Server selection rules](#server-selection-rules-mandatory) - **Non-interactive only** — avoid `jf config add`, `jf login`, `*template` wizards; use `references/jfrog-login-flow.md` / REST -- **Auth errors:** 401 → re-login **same** server; 403 → permissions; 404 → - path/prefix/version. Never switch configured servers as a workaround +- **Auth errors:** 401 → re-login **same** server, then retry **once**. + 403 → stop (package-block → `jfrog-package-curation`). 404 → path, stop **Tier B reminders (load full `cli-gotchas.md` + sibling Tier B refs before these paths):** @@ -464,19 +480,17 @@ re-run the same network call to fix parsing. [At a glance](#at-a-glance-always-read-core) **Tier A** floor; add **Tier B** only when the next action needs `jf api` / advanced CLI: -- [ ] `export JFROG_CLI_USER_AGENT=''` in this bash — `` is the exact - stdout line from `check-environment.sh` exit 0/1 (never invent / rebuild) -- [ ] CLI offer (`cli-newer-version-offer.sh`) done or N/A (`jfrog-init` / MCP-only) +- [ ] `export JFROG_CLI_USER_AGENT=''` — exact stdout line from + `check-environment.sh` exit 0/1; CLI offer done or N/A (`jfrog-init`); + `NEWER_AVAILABLE` = end-of-reply note, never a mid-task stop - [ ] network `jf`: `--server-id ` after subcommand (not `jf --version` / `jf config show` pre-SID) - [ ] one server; error → stop, don't switch (multi only if user names / - `compare`) -- [ ] no prep create/copy/move/upload to fill a gap (workaround ask ≠ permission) + `compare`); no prep create/copy/move/upload to fill a gap - [ ] never guess tools/paths → list / `--help` / `references/`; 404 → stop; - `jf api` product prefix (`/artifactory`, `/xray`, …) + `jf api` product prefix; same path 403/404 → stop (no pager); never + `GET /api/v1/artifacts` - [ ] **Tier A** hard rules: Cautious execution + Server selection + Gotchas - Tier A floor (interactive / `--server-id` retry / stop-on-error / - `--quiet`) -- [ ] **Tier B** (only if next action is `jf api` / AQL / advanced CLI I/O): - full `cli-gotchas.md`, `jf-api.md`, `preserving-command-output.md`, - `cli-command-discovery.md` + floor (interactive / `--server-id` retry / stop-on-error / `--quiet`) +- [ ] **Tier B** (`jf api` / AQL / advanced CLI I/O): full `cli-gotchas.md`, + `jf-api.md`, `preserving-command-output.md`, `cli-command-discovery.md` diff --git a/skills/jfrog/references/cli-gotchas.md b/skills/jfrog/references/cli-gotchas.md index 410b205..089bb89 100644 --- a/skills/jfrog/references/cli-gotchas.md +++ b/skills/jfrog/references/cli-gotchas.md @@ -58,6 +58,11 @@ Hard rules and known failure modes: (especially the product prefix) and target server version. On any of these errors, do not try a different configured server as a workaround — that targets a different environment. Report the error and ask the user. +- **No retry loops (HARD).** No `while true`; no empty `offset=`/`page=`. + 403/404/timeout → stop. 401 → re-login **same** server, then **one** retry of that URL (sole identical-request exception). Identical path + query a **second** time → stop. First page `offset=0` or `page_num=1`. + Pager: 2xx and `next_offset` **greater than** last offset, or increment + `page_num`. Cap **20 pages**. No `GET /api/v1/artifacts`. AQL on + `-cache` (never `-cache`). Package-block 403 → `jfrog-package-curation`. - **Xray contextual analysis:** the summary artifact response has two applicability fields — `applicability` (top-level, often null) and `applicability_details` (always present with a `result` string). **Use diff --git a/skills/jfrog/references/jf-api.md b/skills/jfrog/references/jf-api.md index b4ecaf4..65d7bf6 100644 --- a/skills/jfrog/references/jf-api.md +++ b/skills/jfrog/references/jf-api.md @@ -9,7 +9,8 @@ endpoints, auto-authenticated against the resolved server. **Do not use ## Product-prefix table `jf api` requires the **full** path including the product prefix; omitting it -returns 404. +returns 404. Never invent `GET /api/v1/artifacts`. Cursor is `offset=0` or +Xray `page_num=1`. Loops / 401 / 403 → `cli-gotchas.md`. | Product | Path prefix | |---------|-------------| diff --git a/skills/jfrog/references/jfrog-cli-install-upgrade.md b/skills/jfrog/references/jfrog-cli-install-upgrade.md index 3100bf8..84d06f9 100644 --- a/skills/jfrog/references/jfrog-cli-install-upgrade.md +++ b/skills/jfrog/references/jfrog-cli-install-upgrade.md @@ -25,8 +25,10 @@ After installation, run `jf --version` to confirm, then ## Upgrading the JFrog CLI -If the environment check reports a newer version is available, inform the user -and offer to upgrade: +On `NEWER_AVAILABLE`, run +`bash /scripts/cli-newer-version-offer.sh --clear` immediately. +Never interrupt the task: finish the user's task first, then offer the upgrade +as the last line of the reply. Upgrade only after the user says Yes: ```bash # macOS diff --git a/skills/jfrog/references/xray-entities.md b/skills/jfrog/references/xray-entities.md index f8d5caa..8c1c120 100644 --- a/skills/jfrog/references/xray-entities.md +++ b/skills/jfrog/references/xray-entities.md @@ -536,14 +536,15 @@ jf api "/xray/api/v1/services/results?repo=docker-local&path=my-service/1.0/mani ### Paginating exposure results +`page_num` starts at **1**. Non-zero exit or empty `.data` → stop. Cap **20 pages**. + ```bash PAGE=1 -while true; do - RESP=$(jf api "/xray/api/v1/secrets/results?repo=my-repo&path=my-artifact&page_num=$PAGE&num_of_rows=100") - echo "$RESP" | jq '.data[]' - TOTAL=$(echo "$RESP" | jq '.total_count') - COUNT=$(echo "$RESP" | jq '.data | length') - [ "$COUNT" -eq 0 ] && break +MAX_PAGES=20 +while [ "$PAGE" -le "$MAX_PAGES" ]; do + if ! jf api "/xray/api/v1/secrets/results?repo=my-repo&path=my-artifact&page_num=$PAGE&num_of_rows=100" \ + > /tmp/xr-$$.json; then break; fi + jq '.data[]' /tmp/xr-$$.json PAGE=$((PAGE + 1)) done ``` @@ -662,8 +663,8 @@ policy that affected the decision (blocking, bypassed, waived). ### Pagination -`offset` + `num_of_rows`. `meta.next_offset` → next page. First request: -`include_total=true` for total event count. +`offset` + `num_of_rows`. First page **`offset=0`** (never `offset=`). +Advance only when `next_offset` is an integer **greater than** last offset. Cap 20 pages. ### Common use cases diff --git a/skills/jfrog/scripts/check-environment.sh b/skills/jfrog/scripts/check-environment.sh index c2e1d7a..cc1d80c 100755 --- a/skills/jfrog/scripts/check-environment.sh +++ b/skills/jfrog/scripts/check-environment.sh @@ -137,7 +137,7 @@ check_cli() { # Offer once per new latest. suggest_upgrade is tri-state: # true — pending offer - # false — declined (or not behind); --clear writes false + # false — already offered (or not behind); --clear writes false # missing / non-semver prev latest — never evaluated → set true when behind local prev_latest="" prev_flag="" suggest_upgrade=false if [[ -f "$CACHE_FILE" ]] && command -v jq &>/dev/null; then diff --git a/skills/jfrog/scripts/cli-newer-version-offer.sh b/skills/jfrog/scripts/cli-newer-version-offer.sh index 490f9c5..36ce618 100755 --- a/skills/jfrog/scripts/cli-newer-version-offer.sh +++ b/skills/jfrog/scripts/cli-newer-version-offer.sh @@ -3,8 +3,16 @@ # # check-environment.sh is the only writer of suggest_upgrade (true when # latest is first evaluated or replaced and is strictly newer than -# cli_version). This script only reads that bool and, after Yes or No, -# --clear writes false. It does not run jf. +# cli_version). This script only reads that bool; --clear writes false as +# soon as the agent has read NEWER_AVAILABLE. It does not run jf. +# +# --clear means "mark this latest as already offered", not "clear the cache": +# it flips suggest_upgrade to false and deliberately leaves cli_version and +# latest_version_available intact, which is what makes the next offer wait for +# a genuinely new latest instead of re-offering this one. +# +# JFROG_CLI_AVOID_NEW_VERSION_WARNING=true (case-insensitive, same check as the +# jf CLI's own new-version warning) forces SKIP without touching the cache. # # Usage: # bash cli-newer-version-offer.sh @@ -42,6 +50,10 @@ if [[ "${1:-}" == "--clear" ]]; then emit_skip fi +avoid_warning="$(printf '%s' "${JFROG_CLI_AVOID_NEW_VERSION_WARNING:-}" \ + | tr '[:upper:]' '[:lower:]')" +[[ "$avoid_warning" == "true" ]] && emit_skip + if command -v jq >/dev/null 2>&1 && [[ -f "$CACHE_FILE" ]] \ && jq -e '.suggest_upgrade == true' "$CACHE_FILE" >/dev/null 2>&1; then current="$(jq -r '.cli_version // empty' "$CACHE_FILE" 2>/dev/null)" || emit_skip