Skip to content

feat(cursor): add Marketplace plugin packaging#489

Merged
mksglu merged 6 commits into
mksglu:nextfrom
maxwell-orange:feat/cursor-plugin
May 9, 2026
Merged

feat(cursor): add Marketplace plugin packaging#489
mksglu merged 6 commits into
mksglu:nextfrom
maxwell-orange:feat/cursor-plugin

Conversation

@maxwell-orange

@maxwell-orange maxwell-orange commented May 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Cursor Marketplace plugin packaging for context-mode, mirroring the
existing Claude Code plugin layout. Refs #485.

Full research, decision tree, and grill-me self-questioning are in
.github/drafts/cursor-plugin-proposal.md
(kept on a separate docs/cursor-plugin-proposal branch on the fork to
avoid drafts in the main tree). It walks through:

  • 14-platform distribution map and why only Claude / OpenClaw / Cursor
    have a first-party plugin format we can target.
  • Why "ship a Cursor plugin" hides three distinct problems (discovery,
    routing strength, runtime distribution) and why only the first is
    packaging-fixable.
  • Cursor's additional_context not-surfaced bug (forum #155689, #156157)
    and why the .mdc rule file remains the routing primary.
  • Plugin/native duplicate-hook risk and the doctor check that mitigates it.

What this PR ships (scope = PR-B from the proposal + 2 zero-cost PR-A items)

Area Change
Plugin manifest .cursor-plugin/plugin.json at repo root, single-plugin layout per Cursor template guidance. Points at ./configs/cursor/context-mode.mdc, ./skills/, ./hooks/cursor/hooks.json, and registers an MCP server via npx -y context-mode.
Plugin hook config hooks/cursor/hooks.json (separate from the existing hooks/hooks.json Claude file to avoid collision). Registers 5 events: preToolUse, postToolUse, sessionStart, afterAgentResponse, stop.
Doctor src/adapters/cursor/index.ts now scans ~/.cursor/plugins/{local,cache} for name === "context-mode" and reports Plugin install: pass. When both the plugin and a native .cursor/hooks.json register context-mode hooks, doctor emits a warn so users can de-duplicate.
Version sync scripts/version-sync.mjs keeps .cursor-plugin/plugin.json in lockstep with package.json (alongside the 6 existing manifests).
Docs README.md Cursor section now has "Option A — Marketplace plugin" + "Option B — Manual install" (existing path preserved). docs/platform-support.md documents the Marketplace install path and the duplicate-hook warning.

Two items from PR-A in the proposal landed here because they are pure
config registrations (the hook scripts already exist in
hooks/cursor/sessionstart.mjs
and hooks/cursor/afteragentresponse.mjs
but the existing configs/cursor/hooks.json never wired them up):

  • sessionStart — proposal Q5 flagged validator acceptance as
    NEEDS VERIFICATION; manual smoke test on Cursor v3.3.27 (custom
    variant) accepted the registration and fired the hook.
  • afterAgentResponse — proposal Q4: the script existed but was dead
    code; this PR wires it up.

What this PR does NOT ship (kept for follow-up PRs)

The remaining PR-A coverage expansion (6 events) is not included:

  • beforeShellExecution, afterShellExecution
  • beforeReadFile, afterFileEdit
  • beforeSubmitPrompt
  • preCompact
  • postToolUseFailure

Each requires a new hook script under hooks/cursor/ and corresponding
adapter routing logic, plus tests. Sized as a separate PR so this one
stays narrowly focused on Marketplace packaging.

The runtime-distribution gap (proposal §2c — Cursor manifest has no
${PLUGIN_ROOT} equivalent, so the plugin still requires npm i -g context-mode or npx -y) is not addressed. That needs upstream
Cursor work.

Backward compatibility

Pure addition. Existing users with .cursor/{mcp,hooks}.json from the
manual install are untouched. If they later install the plugin too,
doctor surfaces the duplication as a warn with remediation text.

Local validation

Tested end-to-end on Cursor v3.3.27 (Windows 11) by mirroring this branch
into ~/.cursor/plugins/local/context-mode/ via robocopy (Cursor does
not follow Windows symlinks/junctions, so mklink does not work for
local plugin testing — documented for reviewers reproducing locally).

Confirmed in the IDE:

  • Plugins panel: "Context Mode (Local) — 12 skills, 1 MCP server"
  • Tools & MCPs: context-mode green dot, 11 tools enabled
  • Rules / Skills: 7 skills loaded (context-mode, context-mode-ops,
    ctx-doctor, ctx-insight, ctx-purge, +2)
  • Hooks panel: all 5 events configured; Execution Log shows each
    firing on the corresponding agent action (4–5s each due to
    npx -y cold start, acceptable trade-off for distribution)

Cursor adapter test suite: 50/50 pass (tests/adapters/cursor.test.ts + tests/hooks/cursor-hooks.test.ts).

Try it locally before merge (for reviewers)

Cursor does not follow Windows symlinks or junctions for plugin
folders, so the standard ln -s / mklink approach fails on Windows.
Use a mirror copy instead.

Windows (PowerShell):

git clone -b feat/cursor-plugin https://github.com/maxwell-orange/context-mode.git
cd context-mode
robocopy . "$env:USERPROFILE\.cursor\plugins\local\context-mode" /MIR `
  /XD node_modules .git build insight web tests scripts .vscode `
  /XF *.log .gitignore *.bundle.mjs.map

macOS / Linux:

git clone -b feat/cursor-plugin https://github.com/maxwell-orange/context-mode.git
ln -s "$PWD/context-mode" ~/.cursor/plugins/local/context-mode

Then restart Cursor and open the Plugins panel — "Context Mode
(Local)" should appear with 1 MCP server, 7 skills, and 5 hooks. To
smoke-test the routing, ask the agent to read a large file or run a
shell command; the Hooks panel's Execution Log should show
preToolUse firing.

To update after pulling new commits, re-run the same robocopy /
ln -s line (the /MIR flag handles updates and deletions).

Submission checklist (cursor.com/docs/reference/plugins)

  • Valid .cursor-plugin/plugin.json
  • Kebab-case unique name (context-mode)
  • Clear description
  • Frontmatter on rules/skills/agents/commands
  • Logo — .cursor-plugin/assets/logo.png (snowflake mark, 49 KB)
  • README usage docs
  • Relative-only paths (no .., no absolutes)
  • Tested via local plugin folder
  • Single-plugin layout (no multi-plugin marketplace.json)

Follow-up plan

After this lands, planned follow-ups in priority order:

  1. PR-A coverage expansion — register the remaining 6 hook events
    listed above, with new scripts under hooks/cursor/ and tests.
    Highest expected context-saving impact.
  2. Marketplace submission — once the plugin is on next, submit to
    Cursor's review queue. Logo asset needed first.
  3. Doctor --fix for duplicates — currently doctor warns; could
    offer to delete the matching entries in .cursor/hooks.json
    automatically.
  4. bin/context-mode-cursor-install.mjs (proposal §6 PR-C, low
    priority) — copy plugin files into ~/.cursor/plugins/local/ for
    users who want plugin behavior before Marketplace acceptance.

Marketplace submission (after merge)

Only the repo owner can submit to the public Marketplace. Once this PR
lands on next (and gets promoted to main), submission is a one-time
step at https://cursor.com/marketplace/publish:

  1. Sign in with the GitHub account that owns mksglu/context-mode.
  2. Paste the repo URL https://github.com/mksglu/context-mode.
  3. Cursor's review team validates the manifest, runs frontmatter
    checks, and renders the logo from
    raw.githubusercontent.com/mksglu/context-mode/<sha>/.cursor-plugin/assets/logo.png.
  4. After approval the plugin appears in the in-IDE Plugins search panel
    and at https://cursor.com/marketplace.

I cannot file the submission from the fork — Cursor verifies repo
ownership during the publish flow.

Open questions for maintainer

  1. Author field — Mert Koseoğlu (matching .claude-plugin/plugin.json)
    is what I used. Confirm or change?
  2. Are you happy with the single-PR scope (PR-B + 2 zero-cost PR-A
    items), or do you want me to split sessionStart/afterAgentResponse
    into a separate PR?

Refs #485

Mirror the Claude Code plugin layout for Cursor's plugin marketplace:

- .cursor-plugin/plugin.json: manifest pointing at ./configs/cursor/context-mode.mdc, ./skills/, ./hooks/cursor/hooks.json, and an MCP server entry running 'npx -y context-mode'.

- hooks/cursor/hooks.json: registers preToolUse, postToolUse, sessionStart, afterAgentResponse, and stop, all dispatched through 'npx -y context-mode hook cursor <event>' so users do not need a local clone.

- src/adapters/cursor/index.ts: doctor now detects plugin installs under ~/.cursor/plugins/{local,cache} and warns when both the plugin and a native .cursor/hooks.json register context-mode hooks.

- scripts/version-sync.mjs: keeps .cursor-plugin/plugin.json in lockstep with package.json.

- README.md, docs/platform-support.md: document the Marketplace install path alongside the existing manual install.

Refs mksglu#485
@mksglu mksglu marked this pull request as draft May 9, 2026 09:20
Maxwell_sun added 3 commits May 9, 2026 21:57
- Add .cursor-plugin/README.md so the Marketplace tile has a dedicated landing page (project root README is unchanged).

- Remove 'displayName' from .cursor-plugin/plugin.json: the field is not in Cursor's plugin manifest schema (https://cursor.com/docs/reference/plugins) and would be flagged by the validator.

Validated all manifest keys against the official schema; no other extra fields. Cursor adapter test suite: 50/50 pass.
Adds .cursor-plugin/assets/logo.png and references it via the manifest 'logo' field. Cursor resolves relative paths to raw.githubusercontent.com URLs at the commit SHA, so the Marketplace tile renders the snowflake icon directly from the repo.
Document the robocopy/symlink workflow so reviewers (and early adopters) can try the plugin from the repo before Marketplace acceptance. Calls out the Windows symlink limitation explicitly so testers do not waste time debugging mklink.
@mksglu mksglu marked this pull request as ready for review May 9, 2026 14:23
mksglu and others added 2 commits May 9, 2026 17:23
Per maintainer feedback: until Cursor's review team lists the plugin, the README needs an explicit 'work in progress' notice plus copy-pasteable local-install commands for both Windows (robocopy) and macOS/Linux (ln -s). Calls out the Windows symlink limitation directly so testers do not waste time debugging mklink.

Refs mksglu#485, mksglu#489
@mksglu mksglu merged commit 7b86ee5 into mksglu:next May 9, 2026
5 checks passed
mksglu added a commit that referenced this pull request May 10, 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