From 8f763a48141e115c8d5ecc60b6accf02e3f4cd91 Mon Sep 17 00:00:00 2001 From: Yoni Melki Date: Tue, 25 Aug 2026 13:25:31 +0300 Subject: [PATCH 1/6] AX-2162 - Align VS Code README with shared install verify recovery flow Co-authored-by: Cursor --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index fa8f097..64b7817 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ The official JFrog plugin for [Visual Studio Code](https://code.visualstudio.com/) and **GitHub Copilot Chat**. The plugin connects your Copilot agent to the JFrog Platform with policy-governed MCP access, auto-installed governance instructions, and Agent Guard. +> **Install flow:** [Shared install, verify, and recovery guide](https://github.com/jfrog/claude-plugin/blob/main/docs/shared-install-and-verify.md) — canonical cross-harness rules. This README covers **VS Code-only** steps. + Paste this into your browser: ``` @@ -101,6 +103,22 @@ If you have never configured the JFrog CLI on this machine: ``` 3. Follow the interactive prompts to enter the same JFrog platform URL and access token. +Run **`/jfrog-init`** in Copilot Chat after install. **Reload the VS Code window** after MCP config changes (a new chat alone is not enough). See [shared env-var rules](https://github.com/jfrog/claude-plugin/blob/main/docs/shared-install-and-verify.md#environment-variables--what-actually-helps) — env vars do not repair a failed init walk. + +--- + +## Verify + +Verification is a required install step, not a troubleshooting fallback: + +1. The plugin appears in Copilot's installed plugins list. +2. **`/jfrog-init`** completes without blocking errors. +3. **Reload the VS Code window**, open a **new** Copilot chat, and enable the JFrog MCP tools in the tool picker. +4. `jf rt ping` — succeeds against your configured server. + +If a check fails, fix the step `/jfrog-init` reports, re-run it, and reload the window — +see the [shared recovery playbook](https://github.com/jfrog/claude-plugin/blob/main/docs/shared-install-and-verify.md#recovery-playbook). + --- ## Usage From fd71644881518aa5928ff59f5b20b5aea13802ad Mon Sep 17 00:00:00 2001 From: Yoni Melki Date: Tue, 25 Aug 2026 18:33:53 +0300 Subject: [PATCH 2/6] AX-2162 - Keep VS Code install docs self-contained Inline verify and recovery in this README instead of sending readers to the Claude plugin repository. Co-authored-by: Cursor --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 64b7817..f4fb8ed 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ The official JFrog plugin for [Visual Studio Code](https://code.visualstudio.com/) and **GitHub Copilot Chat**. The plugin connects your Copilot agent to the JFrog Platform with policy-governed MCP access, auto-installed governance instructions, and Agent Guard. -> **Install flow:** [Shared install, verify, and recovery guide](https://github.com/jfrog/claude-plugin/blob/main/docs/shared-install-and-verify.md) — canonical cross-harness rules. This README covers **VS Code-only** steps. - Paste this into your browser: ``` @@ -103,7 +101,7 @@ If you have never configured the JFrog CLI on this machine: ``` 3. Follow the interactive prompts to enter the same JFrog platform URL and access token. -Run **`/jfrog-init`** in Copilot Chat after install. **Reload the VS Code window** after MCP config changes (a new chat alone is not enough). See [shared env-var rules](https://github.com/jfrog/claude-plugin/blob/main/docs/shared-install-and-verify.md#environment-variables--what-actually-helps) — env vars do not repair a failed init walk. +Run **`/jfrog-init`** in Copilot Chat after install. **Reload the VS Code window** after MCP config changes (a new chat alone is not enough). Setting `JFROG_URL` / `JFROG_PLATFORM_URL` / `JFROG_ACCESS_TOKEN` does not repair a failed init walk — fix the reported step and re-run `/jfrog-init`. --- @@ -116,8 +114,13 @@ Verification is a required install step, not a troubleshooting fallback: 3. **Reload the VS Code window**, open a **new** Copilot chat, and enable the JFrog MCP tools in the tool picker. 4. `jf rt ping` — succeeds against your configured server. -If a check fails, fix the step `/jfrog-init` reports, re-run it, and reload the window — -see the [shared recovery playbook](https://github.com/jfrog/claude-plugin/blob/main/docs/shared-install-and-verify.md#recovery-playbook). +If a check fails, fix the step `/jfrog-init` reports, re-run it, and reload the window. + +| Symptom | Do this | Do **not** do this | +| --- | --- | --- | +| MCP missing after install | Run `/jfrog-init`, **reload the VS Code window**, open a **new** Copilot chat, enable JFrog MCP tools. | Assume a new chat without a window reload will pick up MCP changes. | +| `/jfrog-init` stopped at CLI/auth | Follow the skill prompt (`jf config add`, web login, or token path), then **re-run `/jfrog-init`**. | Skip init and only export env vars. | +| Env vars set after a failed init | Fix the reported step, re-run `/jfrog-init`, reload the window. | Expect `JFROG_PLATFORM_URL` alone to substitute the MCP host. | --- From a77e6184e559202522cf857365df11a15458cb8d Mon Sep 17 00:00:00 2001 From: Yoni Melki Date: Tue, 25 Aug 2026 19:01:41 +0300 Subject: [PATCH 3/6] AX-2162 - Document JFROG_PLATFORM_URL instead of JFROG_URL Remove the legacy JFROG_URL row from the auth table. The documented host variable is JFROG_PLATFORM_URL. Co-authored-by: Cursor --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index f4fb8ed..9f7b34a 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,6 @@ VS Code opens, prompts you to install the plugin, and asks you to **Trust** the | Variable | Description | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| `JFROG_URL` | Your JFrog platform URL, e.g. `https://mycompany.jfrog.io` (no trailing `/`). | | `JFROG_PLATFORM_URL` | Your JFrog platform host, **without** the scheme, e.g. `mycompany.jfrog.io`. Resolves the JFrog MCP server URL (`https://${env:JFROG_PLATFORM_URL}/mcp`). | | `JFROG_ACCESS_TOKEN` | Your JFrog access token | @@ -101,7 +100,7 @@ If you have never configured the JFrog CLI on this machine: ``` 3. Follow the interactive prompts to enter the same JFrog platform URL and access token. -Run **`/jfrog-init`** in Copilot Chat after install. **Reload the VS Code window** after MCP config changes (a new chat alone is not enough). Setting `JFROG_URL` / `JFROG_PLATFORM_URL` / `JFROG_ACCESS_TOKEN` does not repair a failed init walk — fix the reported step and re-run `/jfrog-init`. +Run **`/jfrog-init`** in Copilot Chat after install. **Reload the VS Code window** after MCP config changes (a new chat alone is not enough). Setting `JFROG_PLATFORM_URL` / `JFROG_ACCESS_TOKEN` does not repair a failed init walk — fix the reported step and re-run `/jfrog-init`. --- From d3c7467af308a3caf8a23ef977343c3420d204cf Mon Sep 17 00:00:00 2001 From: Yoni Melki Date: Thu, 27 Aug 2026 15:40:32 +0300 Subject: [PATCH 4/6] Add a Recovery heading and the install-docs CI guard. --- .github/workflows/validate-install-docs.yml | 26 ++++++ README.md | 4 +- scripts/validate-install-docs.mjs | 97 +++++++++++++++++++++ scripts/validate-install-docs.test.mjs | 68 +++++++++++++++ 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/validate-install-docs.yml create mode 100644 scripts/validate-install-docs.mjs create mode 100644 scripts/validate-install-docs.test.mjs diff --git a/.github/workflows/validate-install-docs.yml b/.github/workflows/validate-install-docs.yml new file mode 100644 index 0000000..e422afd --- /dev/null +++ b/.github/workflows/validate-install-docs.yml @@ -0,0 +1,26 @@ +# Copyright (c) JFrog Ltd. 2026 +# Licensed under the Apache License, Version 2.0 +# https://www.apache.org/licenses/LICENSE-2.0 + +name: Validate install docs + +on: + push: + branches: [main] + pull_request: + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Set up Node.js + uses: actions/setup-node@v5 + with: + node-version: "20" + + - name: Validate install/recovery docs + run: | + node --test scripts/validate-install-docs.test.mjs + JFROG_PLUGIN_HARNESS=vscode node scripts/validate-install-docs.mjs diff --git a/README.md b/README.md index 9f7b34a..0c46117 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,9 @@ Verification is a required install step, not a troubleshooting fallback: 3. **Reload the VS Code window**, open a **new** Copilot chat, and enable the JFrog MCP tools in the tool picker. 4. `jf rt ping` — succeeds against your configured server. -If a check fails, fix the step `/jfrog-init` reports, re-run it, and reload the window. +If a check fails, see [Recovery](#recovery). Fix the step `/jfrog-init` reports, re-run it, and reload the window. + +## Recovery | Symptom | Do this | Do **not** do this | | --- | --- | --- | diff --git a/scripts/validate-install-docs.mjs b/scripts/validate-install-docs.mjs new file mode 100644 index 0000000..33f5268 --- /dev/null +++ b/scripts/validate-install-docs.mjs @@ -0,0 +1,97 @@ +#!/usr/bin/env node +// Copyright (c) JFrog Ltd. 2026 +// Licensed under the Apache License, Version 2.0 +// Validates install/recovery documentation invariants. + +import { readFileSync, existsSync } from 'node:fs'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const repoRoot = process.cwd(); + +const HARNESS_OWN_REPO = { + claude: 'claude-plugin', + codex: 'codex-plugin', + cursor: 'cursor-plugin', + devin: 'devin-plugin', + opencode: 'opencode-jfrog-plugin', + vscode: 'vscode-plugin', +}; + +const ALL_PLUGIN_REPOS = Object.values(HARNESS_OWN_REPO); + +const REQUIRED_README_MARKERS = ['## Verify', '## Recovery']; + +const FORBIDDEN_PATTERNS = [ + { + re: /setting\s+(?:the\s+)?environment\s+variables?\s+after\s+a\s+failed\s+init\s+may\s+repair/i, + message: 'must not claim env vars repair failed init', + }, + { + re: /JFROG_URL/, + message: 'must not document the legacy JFROG_URL env var; use JFROG_PLATFORM_URL', + }, + { + re: /atlassian\.net/i, + message: 'must not reference JFrog Jira (atlassian.net) in repo files', + }, + { + re: /\b(?:AX|MLD)-\d+\b/, + message: 'must not include Jira ticket keys in repo files', + }, +]; + +export function validateInstallDocs({ repoRoot: root, harness }) { + const errors = []; + const readmePath = join(root, 'README.md'); + if (!existsSync(readmePath)) { + return [`${harness}: missing README.md`]; + } + const files = [{ label: 'README.md', text: readFileSync(readmePath, 'utf8') }]; + + const readme = files[0].text; + for (const marker of REQUIRED_README_MARKERS) { + if (!readme.includes(marker)) { + errors.push(`${harness}: README.md missing required marker: ${marker}`); + } + } + + const ownRepo = HARNESS_OWN_REPO[harness]; + const otherRepos = ALL_PLUGIN_REPOS.filter((name) => name !== ownRepo); + + for (const { label, text } of files) { + for (const { re, message } of FORBIDDEN_PATTERNS) { + if (re.test(text)) errors.push(`${harness}: ${label} ${message}`); + } + for (const other of otherRepos) { + if (text.includes(`github.com/jfrog/${other}`)) { + errors.push(`${harness}: ${label} must not link to github.com/jfrog/${other}`); + } + } + } + + return errors; +} + +function main() { + const harness = process.env.JFROG_PLUGIN_HARNESS ?? inferHarness(repoRoot); + const errors = validateInstallDocs({ repoRoot, harness }); + if (errors.length) { + console.error('install-docs validation failed:'); + for (const e of errors) console.error(` - ${e}`); + process.exit(1); + } + console.log('install-docs validation passed'); +} + +function inferHarness(root) { + if (existsSync(join(root, '.codex-plugin'))) return 'codex'; + if (existsSync(join(root, '.devin-plugin'))) return 'devin'; + if (existsSync(join(root, '.claude-plugin'))) return 'claude'; + if (existsSync(join(root, 'plugins', 'jfrog', '.cursor-plugin'))) return 'cursor'; + if (existsSync(join(root, 'plugin', '.claude-plugin'))) return 'vscode'; + if (existsSync(join(root, 'package.json')) && root.endsWith('opencode-jfrog-plugin')) return 'opencode'; + return 'unknown'; +} + +if (process.argv[1] === fileURLToPath(import.meta.url)) main(); diff --git a/scripts/validate-install-docs.test.mjs b/scripts/validate-install-docs.test.mjs new file mode 100644 index 0000000..31e102a --- /dev/null +++ b/scripts/validate-install-docs.test.mjs @@ -0,0 +1,68 @@ +// Copyright (c) JFrog Ltd. 2026 +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { mkdtempSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { validateInstallDocs } from './validate-install-docs.mjs'; + +function writeReadme(root, body) { + writeFileSync(join(root, 'README.md'), body); +} + +test('validateInstallDocs passes when README has Verify, Recovery, and no other-plugin links', () => { + const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); + writeReadme(root, '# VS Code\n\n## Verify\n\n1. list plugins\n\n## Recovery\n\n'); + assert.deepEqual(validateInstallDocs({ repoRoot: root, harness: 'vscode' }), []); +}); + +test('validateInstallDocs flags missing Verify section', () => { + const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); + writeReadme(root, '# VS Code\n\nInstall the plugin.\n'); + const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); + assert.ok(errors.some((e) => e.includes('## Verify'))); +}); + +test('validateInstallDocs flags missing Recovery section', () => { + const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); + writeReadme(root, '# VS Code\n\n## Verify\n\n1. list plugins\n'); + const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); + assert.ok(errors.some((e) => e.includes('## Recovery'))); +}); + +test('validateInstallDocs rejects contradictory failed-init env-var recovery claims', () => { + const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); + writeReadme( + root, + '# x\n## Verify\n## Recovery\nSetting environment variables after a failed init may repair MCP registration.' + ); + const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); + assert.ok(errors.some((e) => e.includes('env vars repair failed init'))); +}); + +test('validateInstallDocs rejects the legacy JFROG_URL env var', () => { + const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); + writeReadme(root, '# VS Code\n## Verify\n## Recovery\nSet `JFROG_URL` to your platform.\n'); + const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); + assert.ok(errors.some((e) => e.includes('JFROG_URL'))); +}); + +test('validateInstallDocs rejects links to other plugin GitHub repos', () => { + const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); + writeReadme( + root, + '# VS Code\n## Verify\n## Recovery\nSee https://github.com/jfrog/claude-plugin/blob/main/README.md\n' + ); + const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); + assert.ok(errors.some((e) => e.includes('claude-plugin'))); +}); + +test('validateInstallDocs rejects Jira URLs and ticket keys', () => { + const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); + const host = ['jfrog-int', 'atlassian', 'net'].join('.'); + const key = ['AX', '1780'].join('-'); + writeReadme(root, `# VS Code\n## Verify\n## Recovery\nSee [${key}](https://${host}/browse/${key}).\n`); + const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); + assert.ok(errors.some((e) => e.includes('atlassian.net'))); + assert.ok(errors.some((e) => e.includes('Jira ticket keys'))); +}); From ea81f379687a740412eca5d5965148898a839b5e Mon Sep 17 00:00:00 2001 From: Yoni Melki Date: Thu, 27 Aug 2026 16:22:35 +0300 Subject: [PATCH 5/6] Drop the install-docs README checker and keep this repo self-contained. --- .github/workflows/validate-install-docs.yml | 26 ----- docs/package-resolution-user-guide.md | 7 +- .../package-resolution/scripts/onboarding.mjs | 16 +-- scripts/validate-install-docs.mjs | 97 ------------------- scripts/validate-install-docs.test.mjs | 68 ------------- 5 files changed, 5 insertions(+), 209 deletions(-) delete mode 100644 .github/workflows/validate-install-docs.yml delete mode 100644 scripts/validate-install-docs.mjs delete mode 100644 scripts/validate-install-docs.test.mjs diff --git a/.github/workflows/validate-install-docs.yml b/.github/workflows/validate-install-docs.yml deleted file mode 100644 index e422afd..0000000 --- a/.github/workflows/validate-install-docs.yml +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright (c) JFrog Ltd. 2026 -# Licensed under the Apache License, Version 2.0 -# https://www.apache.org/licenses/LICENSE-2.0 - -name: Validate install docs - -on: - push: - branches: [main] - pull_request: - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - - name: Set up Node.js - uses: actions/setup-node@v5 - with: - node-version: "20" - - - name: Validate install/recovery docs - run: | - node --test scripts/validate-install-docs.test.mjs - JFROG_PLUGIN_HARNESS=vscode node scripts/validate-install-docs.mjs diff --git a/docs/package-resolution-user-guide.md b/docs/package-resolution-user-guide.md index 297800d..04ea939 100644 --- a/docs/package-resolution-user-guide.md +++ b/docs/package-resolution-user-guide.md @@ -101,12 +101,9 @@ To turn it off in the config file itself, set `"enabled": false`. If your file i This is a preview, and your feedback directly shapes what ships next. Please tell us about anything that felt confusing, broken, or surprising, good or bad. -File an issue on GitHub, in whichever plugin repo you use: +File an issue on GitHub: [github.com/jfrog/vscode-plugin/issues](https://github.com/jfrog/vscode-plugin/issues) -- Cursor: [github.com/jfrog/cursor-plugin/issues](https://github.com/jfrog/cursor-plugin/issues) -- Claude Code: [github.com/jfrog/claude-plugin/issues](https://github.com/jfrog/claude-plugin/issues) -- VS Code: [github.com/jfrog/vscode-plugin/issues](https://github.com/jfrog/vscode-plugin/issues) -- Email: plugins-feedback@jfrog.com +Email: plugins-feedback@jfrog.com --- diff --git a/plugin/modules/package-resolution/scripts/onboarding.mjs b/plugin/modules/package-resolution/scripts/onboarding.mjs index 8c5ce6a..ef3569b 100644 --- a/plugin/modules/package-resolution/scripts/onboarding.mjs +++ b/plugin/modules/package-resolution/scripts/onboarding.mjs @@ -34,26 +34,16 @@ const log = createLogger("onboarding"); const here = path.dirname(fileURLToPath(import.meta.url)); const NUDGE_TEMPLATE = path.join(here, "../onboarding/session-start-nudge.md"); -export const CURSOR_ADMIN_GUIDE_URL = - "https://github.com/jfrog/cursor-plugin/blob/main/docs/package-resolution-admin-guide.md"; -export const CLAUDE_ADMIN_GUIDE_URL = - "https://github.com/jfrog/claude-plugin/blob/main/docs/package-resolution-admin-guide.md"; -export const COPILOT_ADMIN_GUIDE_URL = +export const ADMIN_GUIDE_URL = "https://github.com/jfrog/vscode-plugin/blob/main/docs/package-resolution-admin-guide.md"; -const ADMIN_GUIDE_URL_BY_IDE = { - claude_code: CLAUDE_ADMIN_GUIDE_URL, - cursor: CURSOR_ADMIN_GUIDE_URL, - copilot: COPILOT_ADMIN_GUIDE_URL, -}; - /** Human-readable list of APR package types (keeps nudge copy in sync with code). */ export function supportedTypesPhrase() { return PACKAGE_TYPES.join(", "); } -function adminGuideUrlForIde(ide) { - return ADMIN_GUIDE_URL_BY_IDE[ide] ?? CLAUDE_ADMIN_GUIDE_URL; +function adminGuideUrlForIde(_ide) { + return ADMIN_GUIDE_URL; } function configureCommandPath() { diff --git a/scripts/validate-install-docs.mjs b/scripts/validate-install-docs.mjs deleted file mode 100644 index 33f5268..0000000 --- a/scripts/validate-install-docs.mjs +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env node -// Copyright (c) JFrog Ltd. 2026 -// Licensed under the Apache License, Version 2.0 -// Validates install/recovery documentation invariants. - -import { readFileSync, existsSync } from 'node:fs'; -import { join } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const repoRoot = process.cwd(); - -const HARNESS_OWN_REPO = { - claude: 'claude-plugin', - codex: 'codex-plugin', - cursor: 'cursor-plugin', - devin: 'devin-plugin', - opencode: 'opencode-jfrog-plugin', - vscode: 'vscode-plugin', -}; - -const ALL_PLUGIN_REPOS = Object.values(HARNESS_OWN_REPO); - -const REQUIRED_README_MARKERS = ['## Verify', '## Recovery']; - -const FORBIDDEN_PATTERNS = [ - { - re: /setting\s+(?:the\s+)?environment\s+variables?\s+after\s+a\s+failed\s+init\s+may\s+repair/i, - message: 'must not claim env vars repair failed init', - }, - { - re: /JFROG_URL/, - message: 'must not document the legacy JFROG_URL env var; use JFROG_PLATFORM_URL', - }, - { - re: /atlassian\.net/i, - message: 'must not reference JFrog Jira (atlassian.net) in repo files', - }, - { - re: /\b(?:AX|MLD)-\d+\b/, - message: 'must not include Jira ticket keys in repo files', - }, -]; - -export function validateInstallDocs({ repoRoot: root, harness }) { - const errors = []; - const readmePath = join(root, 'README.md'); - if (!existsSync(readmePath)) { - return [`${harness}: missing README.md`]; - } - const files = [{ label: 'README.md', text: readFileSync(readmePath, 'utf8') }]; - - const readme = files[0].text; - for (const marker of REQUIRED_README_MARKERS) { - if (!readme.includes(marker)) { - errors.push(`${harness}: README.md missing required marker: ${marker}`); - } - } - - const ownRepo = HARNESS_OWN_REPO[harness]; - const otherRepos = ALL_PLUGIN_REPOS.filter((name) => name !== ownRepo); - - for (const { label, text } of files) { - for (const { re, message } of FORBIDDEN_PATTERNS) { - if (re.test(text)) errors.push(`${harness}: ${label} ${message}`); - } - for (const other of otherRepos) { - if (text.includes(`github.com/jfrog/${other}`)) { - errors.push(`${harness}: ${label} must not link to github.com/jfrog/${other}`); - } - } - } - - return errors; -} - -function main() { - const harness = process.env.JFROG_PLUGIN_HARNESS ?? inferHarness(repoRoot); - const errors = validateInstallDocs({ repoRoot, harness }); - if (errors.length) { - console.error('install-docs validation failed:'); - for (const e of errors) console.error(` - ${e}`); - process.exit(1); - } - console.log('install-docs validation passed'); -} - -function inferHarness(root) { - if (existsSync(join(root, '.codex-plugin'))) return 'codex'; - if (existsSync(join(root, '.devin-plugin'))) return 'devin'; - if (existsSync(join(root, '.claude-plugin'))) return 'claude'; - if (existsSync(join(root, 'plugins', 'jfrog', '.cursor-plugin'))) return 'cursor'; - if (existsSync(join(root, 'plugin', '.claude-plugin'))) return 'vscode'; - if (existsSync(join(root, 'package.json')) && root.endsWith('opencode-jfrog-plugin')) return 'opencode'; - return 'unknown'; -} - -if (process.argv[1] === fileURLToPath(import.meta.url)) main(); diff --git a/scripts/validate-install-docs.test.mjs b/scripts/validate-install-docs.test.mjs deleted file mode 100644 index 31e102a..0000000 --- a/scripts/validate-install-docs.test.mjs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) JFrog Ltd. 2026 -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import { mkdtempSync, writeFileSync } from 'node:fs'; -import { tmpdir } from 'node:os'; -import { join } from 'node:path'; -import { validateInstallDocs } from './validate-install-docs.mjs'; - -function writeReadme(root, body) { - writeFileSync(join(root, 'README.md'), body); -} - -test('validateInstallDocs passes when README has Verify, Recovery, and no other-plugin links', () => { - const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); - writeReadme(root, '# VS Code\n\n## Verify\n\n1. list plugins\n\n## Recovery\n\n'); - assert.deepEqual(validateInstallDocs({ repoRoot: root, harness: 'vscode' }), []); -}); - -test('validateInstallDocs flags missing Verify section', () => { - const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); - writeReadme(root, '# VS Code\n\nInstall the plugin.\n'); - const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); - assert.ok(errors.some((e) => e.includes('## Verify'))); -}); - -test('validateInstallDocs flags missing Recovery section', () => { - const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); - writeReadme(root, '# VS Code\n\n## Verify\n\n1. list plugins\n'); - const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); - assert.ok(errors.some((e) => e.includes('## Recovery'))); -}); - -test('validateInstallDocs rejects contradictory failed-init env-var recovery claims', () => { - const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); - writeReadme( - root, - '# x\n## Verify\n## Recovery\nSetting environment variables after a failed init may repair MCP registration.' - ); - const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); - assert.ok(errors.some((e) => e.includes('env vars repair failed init'))); -}); - -test('validateInstallDocs rejects the legacy JFROG_URL env var', () => { - const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); - writeReadme(root, '# VS Code\n## Verify\n## Recovery\nSet `JFROG_URL` to your platform.\n'); - const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); - assert.ok(errors.some((e) => e.includes('JFROG_URL'))); -}); - -test('validateInstallDocs rejects links to other plugin GitHub repos', () => { - const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); - writeReadme( - root, - '# VS Code\n## Verify\n## Recovery\nSee https://github.com/jfrog/claude-plugin/blob/main/README.md\n' - ); - const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); - assert.ok(errors.some((e) => e.includes('claude-plugin'))); -}); - -test('validateInstallDocs rejects Jira URLs and ticket keys', () => { - const root = mkdtempSync(join(tmpdir(), 'vscode-docs-')); - const host = ['jfrog-int', 'atlassian', 'net'].join('.'); - const key = ['AX', '1780'].join('-'); - writeReadme(root, `# VS Code\n## Verify\n## Recovery\nSee [${key}](https://${host}/browse/${key}).\n`); - const errors = validateInstallDocs({ repoRoot: root, harness: 'vscode' }); - assert.ok(errors.some((e) => e.includes('atlassian.net'))); - assert.ok(errors.some((e) => e.includes('Jira ticket keys'))); -}); From bedc29b9d0743f8afba74474a696f38b934d4dcc Mon Sep 17 00:00:00 2001 From: Yoni Melki Date: Thu, 27 Aug 2026 16:40:01 +0300 Subject: [PATCH 6/6] Restore vendored modules to the jfrog-agent-hooks copy. --- .../package-resolution/scripts/onboarding.mjs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/plugin/modules/package-resolution/scripts/onboarding.mjs b/plugin/modules/package-resolution/scripts/onboarding.mjs index ef3569b..8c5ce6a 100644 --- a/plugin/modules/package-resolution/scripts/onboarding.mjs +++ b/plugin/modules/package-resolution/scripts/onboarding.mjs @@ -34,16 +34,26 @@ const log = createLogger("onboarding"); const here = path.dirname(fileURLToPath(import.meta.url)); const NUDGE_TEMPLATE = path.join(here, "../onboarding/session-start-nudge.md"); -export const ADMIN_GUIDE_URL = +export const CURSOR_ADMIN_GUIDE_URL = + "https://github.com/jfrog/cursor-plugin/blob/main/docs/package-resolution-admin-guide.md"; +export const CLAUDE_ADMIN_GUIDE_URL = + "https://github.com/jfrog/claude-plugin/blob/main/docs/package-resolution-admin-guide.md"; +export const COPILOT_ADMIN_GUIDE_URL = "https://github.com/jfrog/vscode-plugin/blob/main/docs/package-resolution-admin-guide.md"; +const ADMIN_GUIDE_URL_BY_IDE = { + claude_code: CLAUDE_ADMIN_GUIDE_URL, + cursor: CURSOR_ADMIN_GUIDE_URL, + copilot: COPILOT_ADMIN_GUIDE_URL, +}; + /** Human-readable list of APR package types (keeps nudge copy in sync with code). */ export function supportedTypesPhrase() { return PACKAGE_TYPES.join(", "); } -function adminGuideUrlForIde(_ide) { - return ADMIN_GUIDE_URL; +function adminGuideUrlForIde(ide) { + return ADMIN_GUIDE_URL_BY_IDE[ide] ?? CLAUDE_ADMIN_GUIDE_URL; } function configureCommandPath() {