diff --git a/.github/scripts/sync-modules-vendor.json b/.github/scripts/sync-modules-vendor.json new file mode 100644 index 0000000..2ab0ddb --- /dev/null +++ b/.github/scripts/sync-modules-vendor.json @@ -0,0 +1,8 @@ +{ + "repo": "github.jfrog.info/JFROG/jfrog-agent-hooks", + "pin": "master", + "dest_prefix": "plugins/jfrog", + "paths": [ + "modules" + ] +} diff --git a/.github/scripts/sync-modules.mjs b/.github/scripts/sync-modules.mjs new file mode 100644 index 0000000..99a5d29 --- /dev/null +++ b/.github/scripts/sync-modules.mjs @@ -0,0 +1,66 @@ +#!/usr/bin/env node +// Vendors modules bundle from jfrog-agent-hooks into plugins/jfrog/. +// +// Usage: +// JFROG_AGENT_HOOKS_PATH=/path/to/jfrog-agent-hooks node .github/scripts/sync-modules.mjs +// +// Defaults JFROG_AGENT_HOOKS_PATH to ../jfrog-agent-hooks (sibling clone). +// Reads paths from sync-modules-vendor.json. + +import { promises as fs } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(scriptDir, "..", ".."); +const vendorPath = path.join(scriptDir, "sync-modules-vendor.json"); + +async function fileExists(p) { + try { + await fs.access(p); + return true; + } catch { + return false; + } +} + +async function copyPath(fromDir, toDir, relativePath) { + const from = path.join(fromDir, relativePath); + const to = path.join(toDir, relativePath); + if (!(await fileExists(from))) { + throw new Error(`path missing in upstream: ${relativePath}`); + } + await fs.rm(to, { recursive: true, force: true }); + await fs.mkdir(path.dirname(to), { recursive: true }); + await fs.cp(from, to, { recursive: true }); + console.log(` ${relativePath} -> ${path.relative(process.cwd(), to)}`); +} + +async function main() { + const vendor = JSON.parse(await fs.readFile(vendorPath, "utf8")); + const paths = vendor.paths; + if (!Array.isArray(paths) || paths.length === 0) { + throw new Error(`${vendorPath} must define a non-empty paths array`); + } + + const hooksRoot = + process.env.JFROG_AGENT_HOOKS_PATH?.trim() || + path.resolve(repoRoot, "..", "jfrog-agent-hooks"); + + if (!(await fileExists(hooksRoot))) { + throw new Error( + `jfrog-agent-hooks not found at ${hooksRoot}. Set JFROG_AGENT_HOOKS_PATH.`, + ); + } + + const destPrefix = (vendor.dest_prefix ?? "").replace(/^\/+|\/+$/g, ""); + const destRoot = destPrefix ? path.join(repoRoot, destPrefix) : repoRoot; + + console.log(`--- sync from ${hooksRoot} (pin: ${vendor.pin ?? "local"}) ---`); + for (const rel of paths) { + await copyPath(hooksRoot, destRoot, rel); + } + console.log("done."); +} + +await main(); diff --git a/VENDOR.md b/VENDOR.md index 96f2c48..d02a64a 100644 --- a/VENDOR.md +++ b/VENDOR.md @@ -24,3 +24,24 @@ node .github/scripts/sync-skills.mjs ``` The script reads its sibling `sync-skills-vendor.json`, downloads the pinned upstream tarball from `codeload.github.com`, and replaces the directories listed in `paths` (today: `skills/`) under `plugins/jfrog/`. + +--- + +# Vendored modules + +The `plugins/jfrog/modules/` bundle is vendored from **jfrog-agent-hooks** (GHE) and committed to `main`. + +| | | +| --- | --- | +| **Repository** | `github.jfrog.info/JFROG/jfrog-agent-hooks` | +| **Pinned release** | see `pin` in [`.github/scripts/sync-modules-vendor.json`](.github/scripts/sync-modules-vendor.json) | + +The bundle contains harness runners (`core/`, `cursor-session-start.mjs`), the `package-resolution/` capability, and `assets/agents-default-conf.json`. Automated sync PRs (`chore/sync-modules-v*`) update this tree on each `jfrog-agent-hooks` release. + +## Refreshing modules + +```bash +JFROG_AGENT_HOOKS_PATH=/path/to/jfrog-agent-hooks node .github/scripts/sync-modules.mjs +``` + +The script reads `paths` from `sync-modules-vendor.json` (today: `["modules"]`) and replaces the whole `plugins/jfrog/modules/` tree. diff --git a/plugins/jfrog/.cursor-plugin/plugin.json b/plugins/jfrog/.cursor-plugin/plugin.json index e24c846..76816b5 100644 --- a/plugins/jfrog/.cursor-plugin/plugin.json +++ b/plugins/jfrog/.cursor-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "jfrog", "displayName": "JFrog Platform", "version": "0.5.4", - "description": "JFrog Platform integration with MCP, security skills, supply-chain best practices, and JFrog Agent Guard governance for adding, removing, and listing MCP servers.", + "description": "JFrog Platform integration with MCP, security skills, Agent Package Resolution, supply-chain best practices, and JFrog Agent Guard governance for adding, removing, and listing MCP servers.", "author": { "name": "JFrog", "email": "devrel@jfrog.com" @@ -15,6 +15,7 @@ "security", "mcp", "agent-guard", + "package-resolution", "supply-chain", "devops", "artifacts", diff --git a/plugins/jfrog/hooks/hooks.json b/plugins/jfrog/hooks/hooks.json index 36ff5ae..8f02956 100644 --- a/plugins/jfrog/hooks/hooks.json +++ b/plugins/jfrog/hooks/hooks.json @@ -2,6 +2,10 @@ "version": 1, "hooks": { "sessionStart": [ + { + "command": "node \"./modules/cursor-session-start.mjs\" package-resolution", + "timeout": 7 + }, { "command": "node \"./scripts/inject-instructions.mjs\"", "timeout": 7