Thanks for looking. This is a small plugin; contributions are welcome.
Read AGENTS.md at the repo root — it spells out the hard rules (zero runtime deps, no build step, etc.). If your change would break one of them, open an issue first.
git clone https://github.com/freema/cursor-plugin-cc
cd cursor-plugin-cc/plugins/cursor
npm install # installs only dev deps: vitest, eslint, prettier, @eslint/js
npm test
npm run lintNo build, no bundler. scripts/*.mjs runs directly via node. If node_modules/ needed in the install step surprised you, that is only for running tests and the formatter; the shipped plugin itself needs zero dependencies.
feat/<slug>— new user-visible feature or command.fix/<slug>— bug fix.refactor/<slug>— internal reshape, no user impact.docs/<slug>— docs only.ci/<slug>— CI or tooling.
Keep branches focused. One feature or fix per PR.
Conventional-commits style:
feat(browser): auto-discover localhost port from vite.config
fix(delegate): quote $ARGUMENTS so zsh doesn't glob ?
refactor: drop esbuild, ship .mjs directly
docs(readme): add troubleshooting section
One short subject line, imperative mood, optional body explaining the why.
- Push your branch.
- Open a PR against
main. The PR template asks for a summary and a test plan — fill both. - CI runs the test matrix (Node 18.18 / 20 / 22 × Ubuntu / macOS). All six must pass.
- The maintainer reviews, suggests changes, or merges. Squash merge is the default.
- No direct pushes to
main— branch protection enforces PR review.
The plugin has a consistent recipe. Follow it exactly for any new command — reviewers will bounce anything that deviates without explanation.
- Pick a name. Keep it short and under the
cursor:namespace (e.g./cursor:diff,/cursor:retry). Verbs preferred. - Write
plugins/cursor/scripts/<cmd>.mjs.- Starts with
#!/usr/bin/env node. - Imports
parseArgv,collapseArgumentsfrom./lib/args.mjs. - Exports
async function main(rawArgv): Promise<number>returning the exit code. - Uses
invokedAsScript(import.meta.url)from./lib/invoked.mjsfor the "am I the entry point?" guard. - Writes structured Markdown to stdout so Claude Code renders it. Stick to bullet lists, tables, and fenced code blocks — nothing Claude has to paraphrase.
- Writes errors to stderr; return code 2 for bad input, 1 for runtime failure, 0 for success.
- Starts with
- Write
plugins/cursor/commands/<cmd>.md.- Frontmatter:
description,argument-hint,allowed-tools: Bash(node:*). - Body:
!+ a single line`node "${CLAUDE_PLUGIN_ROOT}/scripts/<cmd>.mjs" -- "$ARGUMENTS"`(quotes around$ARGUMENTSare mandatory — zsh will glob otherwise). - Add a one-paragraph note telling Claude Code how to render the output (usually "verbatim, do not paraphrase").
- Frontmatter:
- Write
plugins/cursor/tests/<cmd>.test.mjs.- Import
mainfrom../scripts/<cmd>.mjs. - Use the stub
cursor-agentbinary (tests/fixtures/cursor-agent-stub.mjs) viaCURSOR_AGENT_BINenv and a fixture NDJSON. - Spy on
process.stdout.writeandprocess.stderr.writeto assert output without polluting the test runner. - Cover: happy path, bad input (exit 2), empty env (graceful degradation).
- Import
- Update
plugins/cursor/package.json'sscriptswith a"<cmd>": "node scripts/<cmd>.mjs"alias so maintainers can run it vianpm run <cmd>. - Update the README:
- Add it to the "What you get" bullet list at the top.
- Add a
### /cursor:<cmd>subsection under Usage explaining flags + 2 example invocations.
- Update
CHANGELOG.mdunder the## Unreleased→### Addedsection.
- Don't add runtime deps. If the command needs behaviour you would normally pull a library for, write 30 lines in
lib/instead. Seelib/run.mjs(execa replacement) andlib/args.mjs(yargs-parser replacement) for the shape. - Don't introduce
dist/,build.mjs, or any TypeScript file. The source IS the ship artefact. - Don't bypass
lib/run.mjs. Every external command invocation goes through it so timeouts and exit-code handling stay consistent. - Don't hardcode
~oros.homedir()directly. Uselib/paths.mjs— it honours theCURSOR_PLUGIN_CC_HOMEenv override (test suites rely on this).
Tests use a stub binary that replays NDJSON fixtures. To smoke-test against the real CLI:
CURSOR_AGENT_BIN=/path/to/cursor-agent node plugins/cursor/scripts/setup.mjs --doctor
node plugins/cursor/scripts/delegate.mjs --no-git-check -- "write a short haiku about git"This spends real Cursor tokens, so keep it to trivial tasks during development.
Use the GitHub issue template. Include:
node --version,cursor-agent --version- Output of
/cursor:setup --doctor - For
/cursor:delegateor/cursor:browserfailures: the job id from/cursor:statusand the path of the raw log under~/.cursor-plugin-cc/jobs/<hash>/logs/<id>.ndjson.
Maintainer-only, reference:
- Ensure
CHANGELOG.mdhas a## x.y.z — …section with Added/Changed/Fixed bullets moved out of## Unreleased. - Bump
versioninplugins/cursor/package.jsonandplugins/cursor/plugin.jsonto match. - Merge a
release/x.y.zbranch tomainvia PR. git tag -a vX.Y.Z -m "vX.Y.Z — headline"+git push origin vX.Y.Z.gh release create vX.Y.Z --title "vX.Y.Z — headline" --notes-file <release-notes.md>.
No automated publish pipeline yet — by design, see roadmap.