Skip to content

feat: align OpenCode plugin with Cursor model (vendored skills, thin config-hook, CI hardening)#16

Merged
michaelfrog merged 23 commits into
mainfrom
feat/AX-1704-skills-cursor-alignment
Jun 23, 2026
Merged

feat: align OpenCode plugin with Cursor model (vendored skills, thin config-hook, CI hardening)#16
michaelfrog merged 23 commits into
mainfrom
feat/AX-1704-skills-cursor-alignment

Conversation

@michaelfrog

@michaelfrog michaelfrog commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stabilizes the OpenCode JFrog plugin and aligns it with the Cursor plugin model (AX-1704). The plugin is now thin and self-contained: it ships vendored JFrog skills and registers them via the OpenCode config hook, with no runtime downloads. MCP/Agent Guard was explored on this branch and intentionally reverted — this PR is skills-only; MCP is a later phase.

What changed

Skills (core)

  • Vendor jfrog/jfrog-skills@v0.14.0 into skills/ (pinned via sync-skills-vendor.json + scripts/sync-skills.mjs); ship them in the npm package (files).
  • Replace the fragile runtime download/unzip + setupPackageManagers with a thin config hook that pushes the bundled skills/ dir into config.skills.paths (idempotent, fail-loud).
  • No legacy-skill auto-migration: pre-0.0.3 skills are obsolete; upgraders remove any stale ~/.config/opencode/skills dirs manually (documented in the README upgrade notes).
  • Fire-and-forget toasts (no headless hang); the jf setup nudge is shown once per session.

Distribution & CI

  • npm + OpenCode-ecosystem model (no marketplace); package is self-contained, no releases.jfrog.io runtime dependency; deps resolve from public npm.
  • @opencode-ai/plugin moved to devDependencies (zero runtime deps).
  • PR CI now runs: setup → sync-skills:check (drift guard) → lint → typecheck → test → build → pkgjsonlint → pack:check (tarball self-containment).

Cleanup

  • Remove templates leftover, ignore .opencode/, scrub stale refs, drop redundant publish workflow; align repo layout with the cursor/claude plugins.

Breaking changes (pre-1.0)

  • Skill catalog 7 → 2 (jfrog, jfrog-package-safety-and-download); removed skills fold into jfrog.
  • Package-manager auto-setup removed (interim jf setup <pm> nudge).
  • No more runtime artifacts/instructions injection.
  • Old skills are no longer auto-cleaned; see the README "Upgrading from < 0.0.3" notes.

Verification

  • lint / typecheck / test / build / pkgjsonlint green; sync-skills:check no drift; pack:check OK.
  • Clean-room E2E (isolated HOME, packed tarball): plugin loads, both skills registered, no-MCP/no-templates invariant upheld, zero runtime deps.

Before merge (environmental, not plugin defects — confirm on CI/normal-network machine)

  • npm-install path: ~/.cache/opencode/node_modules/@jfrog/opencode-jfrog-plugin exercised (blocked locally by a corporate 403 on @opencode-ai/plugin).
  • Live skill selection via opencode run (local headless loop stalls even with --pure).

michaelfrog and others added 18 commits June 18, 2026 11:48
Add build-time vendoring of the official skills from jfrog/jfrog-skills
(pinned v0.11.0) into a flat, committed skills/ tree so they ship with
the package. Introduces sync-skills-vendor.json (pin config) and
scripts/sync-skills.mjs (downloads + extracts + copies skills/ to repo root).

Co-authored-by: Cursor <cursoragent@cursor.com>
…-skills script)

Add skills/ and sync-skills-vendor.json to the package files allowlist so the
vendored skills tree ships at the package root next to dist/, enabling runtime
resolution via ../skills after install. Also add a sync-skills npm script and
the skills keyword.

Co-authored-by: Cursor <cursoragent@cursor.com>
src/version.ts does not exist and nothing generates or imports it: the build
task only runs bun build, the version/publish tasks only bump package.json, and
release-please-config.json defines no extra-files. Remove the phantom entry from
the package files allowlist.

Co-authored-by: Cursor <cursoragent@cursor.com>
…s.paths; drop runtime pull + setupPackageManagers

Replace the imperative plugin (runtime download/unzip/prune + session.created
package-manager setup) with a thin plugin whose only job is to register the
bundled skills/ via the config hook (object form config.skills.paths), fail loud
if the bundled dir is missing/empty, emit a one-line jf-setup nudge, and run a
conservative one-time migration that removes only legacy version-nested managed
skills (never flat/user skills). Removes pullSkills, fetchAndSaveFile, extractZip,
pruneNonManifestSkillVersions, setupPackageManagers, the registry URL constants,
the event hook, and the instructions-file injection. Tests trimmed to the thin
behavior; comprehensive matrix lands in Phase 4.

Co-authored-by: Cursor <cursoragent@cursor.com>
The repo forbids a scripts property in package.json (.mise/tasks/pkgjsonlint).
Move the sync-skills entrypoint to a .mise task instead, matching repo conventions.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ic npm

This is a public repo and must not embed internal JFrog infrastructure.
- bun.lock: repoint all 281 tarball URLs from the private ctoa/carmit virtual
  registry to https://registry.npmjs.org (integrity hashes unchanged; the virtual
  repo mirrors npmjs byte-for-byte, so the lock stays reproducible).
- pr.yml / publish-as-is.yml: drop the "Setup JFrog CLI" + "setup jfrog npm repo"
  steps, JF_URL/JF_PROJECT env, and the ctoa bunfig; resolve deps from public npm.
  Publish continues to target public npmjs.

Note: dependency resolution now uses public npm (no JFrog curation/security gating),
and npmjs publish requires an npm auth method configured by the maintainer.

Co-authored-by: Cursor <cursoragent@cursor.com>
await client.tui.showToast never resolves in headless sessions (no TUI to
ack), which hung the config hook on every opencode run/debug skill/CI load.
Surface toasts fire-and-forget via a helper; durable signals still go through
log(). Headless debug skill now returns and registers skills as expected.

Co-authored-by: Cursor <cursoragent@cursor.com>
V5: drive migrateLegacyManagedSkills via a temp HOME and assert it removes only
version-nested managed skills while keeping flat (possibly user-owned), unrelated,
and unknown-shape dirs; plus a no-throw case when the skills root is absent.
V9: assert the vendored skills/ tree is exactly {jfrog, jfrog-package-safety-and-download},
flat, each SKILL.md having frontmatter name/description with name == dir.
Tests only; no behavior change.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ocument breaking changes

Rewrite README to describe the thin plugin that ships two vendored, pinned skills
(jfrog, jfrog-package-safety-and-download) and registers them via config.skills.paths
at load. Remove stale runtime-download/package-managers.json/instructions-injection
content. Add VENDOR.md documenting sync-skills-vendor.json and the pin-bump workflow
(mise run sync-skills) that requires a plugin release. Fix AGENTS.md test framework
(bun:test, not vitest). Surface open questions (min OpenCode version, publish auth).

BREAKING CHANGE: skill catalog reduced from 7 Artifactory skills (skill-install,
skill-publish, jfrog-cli, opencode-jfrog-mcp, jfrog-setup-package-managers,
jfrog-curation, jfrog-packages) to 2 canonical skills (jfrog,
jfrog-package-safety-and-download); the removed skill names no longer exist and fold
into the jfrog skill. Package-manager auto-setup on session start is removed (interim
jf setup nudge; durable recovery upstream). Old version-nested skills under
~/.config/opencode/skills are auto-cleaned by a one-time migration. The instructions
file and package-managers.json are no longer written, and there is no runtime skills
download. Dependencies/CI now resolve from public npm.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
It's a type-only import (erased at build); dist/index.js needs only
fs/path/url. Declaring it as a runtime dependency made OpenCode's
post-install bun install try to fetch it, which 403s on the Artifactory-
pinned npm registries common to this plugin's customer base
(NpmInstallFailedError). The published package now has no runtime
dependencies.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
In the same config hook that registers the vendored skills, also register the
JFrog Platform remote MCP server into config.mcp. Resolve the platform URL from
JFROG_URL (fallback JFROG_PLATFORM_URL), normalize to https://<host>/mcp, and set
cfg.mcp.jfrog only when absent (non-destructive). Skip with a log line when no URL
is set. OpenCode handles OAuth lazily, so no auth config and no network on load.

Co-authored-by: Cursor <cursoragent@cursor.com>
Pivot the MCP step from Cursor's OAuth direct-MCP model to the Claude Code
plugin's token-based, headless Agent Guard model.

- Revert the OAuth direct config.mcp.jfrog injection (commit 23cac6c). Platform
  ops stay on the jfrog skill (token-based CLI). The plugin no longer writes any
  config.mcp entry.
- Gate on the account setting mcp_gateway_plugin_enabled via a Bearer-token GET
  (JFROG_URL/JF_URL + JFROG_ACCESS_TOKEN/JF_ACCESS_TOKEN), bounded by a 5s
  AbortController and FAIL-CLOSED so load never hangs. Honor
  _JF_AGENT_GUARD_FORCE_DISABLE / JF_AGENT_GUARD_FORCE_ENABLE.
- When enabled, inject the bundled templates/jfrog-mcp-management.md into
  config.instructions (absolute path, deduped). The agent then installs catalog
  MCPs via npx @jfrog/agent-guard as OpenCode local MCP entries.
- Add the OpenCode-adapted template (opencode.json mcp, type "local" command
  array, environment {env:VAR}, opencode mcp auth/list, JFROG_AGENT_GUARD_REPO).
- Ship templates/ via package.json files; add AbortController/setTimeout/
  clearTimeout to eslint globals.

Co-authored-by: Cursor <cursoragent@cursor.com>
…plugin

Reverts the token-based Agent Guard template injection (632025f) and the
direct MCP injection (23cac6c). The plugin again only registers the vendored
skills via the config hook. MCP support is deferred to a later phase.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ll-contents check

Add two mise.toml tasks: 'sync-skills:check' re-runs the vendoring and fails on
any skills/ drift from the pin; 'pack:check' asserts the npm tarball includes
dist/index.js + both vendored SKILL.md files and excludes *-TEST-PLAN.md /
*-TEST-RESULTS.md / .opencode scratch files. Wire the full gate sequence into
pr.yml: setup -> sync-skills:check -> lint -> typecheck -> test -> build ->
pkgjsonlint -> pack:check.

Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve the "assumes published / open questions" hedges: the package is published
to public npm and listed on the OpenCode ecosystem page. Give a concrete install
snippet, note org-wide rollout via remote config, and state the plugin is
self-contained (skills shipped in the tarball; no runtime downloads, no
releases.jfrog.io dependency). Point VENDOR.md at the sync-skills:check drift guard.

Co-authored-by: Cursor <cursoragent@cursor.com>
…plates leftover

Move the planning/test scratch docs (E2E-TEST-PLAN.md, SKILLS-AGENTIC-TEST-PLAN.md,
SKILLS-AGENTIC-TEST-RESULTS.md) out of the public plugin repo into the external
planning workspace, and gitignore the runtime .opencode/ debug-log directory. The
templates/ leftover from the reverted MCP work is already gone.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

michaelfrog and others added 4 commits June 22, 2026 17:36
….github/

Declutters the project root to the conventional essentials (README, LICENSE,
NOTICE, CHANGELOG, AGENTS). Updates all internal links accordingly. No code or
package contents change (docs/ and .github/ are not in the npm `files` set).

Co-authored-by: Cursor <cursoragent@cursor.com>
The cursor and claude JFrog plugins don't carry an AGENTS.md, and ours was
generic template content (referenced a nonexistent test, .memory/, etc.).
Code-style guidance is already covered by ESLint/Prettier + CONTRIBUTING.md.

Co-authored-by: Cursor <cursoragent@cursor.com>
Flatten CONTRIBUTING.md and VENDOR.md back to the root (matching the cursor and
claude JFrog plugins), drop the docs/ folder, and remove NOTICE (neither peer
ships one and the MIT devDeps are not redistributed). CHANGELOG.md and
RELEASE.md stay, as they are required by this repo's npm/release-please flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drops the one-time cleanup of old version-nested managed skills (and its
helpers/tests). The pre-0.0.3 skills are obsolete and no longer auto-removed;
the plugin now only registers the bundled skills. Upgrade note updated to point
users to remove any stale ~/.config/opencode/skills dirs manually.

Co-authored-by: Cursor <cursoragent@cursor.com>
@michaelfrog

Copy link
Copy Markdown
Collaborator Author

I have read the CLA Document and I hereby sign the CLA

@YoniMelki YoniMelki left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall: solid simplification. Replacing the runtime download/unzip pipeline with a vendored, committed skills/ tree is the right call — it makes the plugin reproducible, offline-capable, and much easier to reason about. CI hardening (drift guard, tarball self-containment check) is a nice addition.

Three things worth addressing before merge:

Comment thread src/index.ts
Comment thread scripts/sync-skills.mjs Outdated
Comment thread src/index.ts
Addresses PR review:
- config hook can run multiple times per session -> show the `jf setup` nudge
  once via a closure flag (adds a regression test).
- sync-skills: select the extracted tarball's top-level dir deterministically
  (filter to directories + sort) instead of relying on readdir order.

Co-authored-by: Cursor <cursoragent@cursor.com>
@michaelfrog michaelfrog merged commit de03bef into main Jun 23, 2026
4 checks passed
@michaelfrog michaelfrog deleted the feat/AX-1704-skills-cursor-alignment branch June 23, 2026 12:54
@michaelfrog michaelfrog mentioned this pull request Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants