{"id":28924083,"url":"https://github.com/gmickel/cursor-windsurf-convert","last_synced_at":"2026-02-27T21:34:53.211Z","repository":{"id":292052545,"uuid":"979668215","full_name":"gmickel/cursor-windsurf-convert","owner":"gmickel","description":"Node CLI + TypeScript API that losslessly converts Cursor AI rule files to Windsurf rules - and back - in a single stream-first command.","archived":false,"fork":false,"pushed_at":"2025-12-01T01:39:49.000Z","size":79,"stargazers_count":5,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-13T22:33:11.728Z","etag":null,"topics":["ci","cli","converter","cursor-ai","cursor-ai-project-rules","devtool","markdown","nodejs","rules","typescript","windsurf","windsurf-ai","yaml"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/cursor-windsurf-convert","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gmickel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["gmickel"]}},"created_at":"2025-05-07T22:03:55.000Z","updated_at":"2025-10-08T00:56:08.000Z","dependencies_parsed_at":"2025-05-07T23:21:47.042Z","dependency_job_id":"8fcc9d1e-4d64-4e9e-be2d-d92ec9560d09","html_url":"https://github.com/gmickel/cursor-windsurf-convert","commit_stats":null,"previous_names":["gmickel/cursor-windsurf-convert"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gmickel/cursor-windsurf-convert","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fcursor-windsurf-convert","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fcursor-windsurf-convert/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fcursor-windsurf-convert/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fcursor-windsurf-convert/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gmickel","download_url":"https://codeload.github.com/gmickel/cursor-windsurf-convert/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gmickel%2Fcursor-windsurf-convert/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29915345,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T19:37:42.220Z","status":"ssl_error","status_checked_at":"2026-02-27T19:37:41.463Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci","cli","converter","cursor-ai","cursor-ai-project-rules","devtool","markdown","nodejs","rules","typescript","windsurf","windsurf-ai","yaml"],"created_at":"2025-06-22T10:03:52.253Z","updated_at":"2026-02-27T21:34:53.206Z","avatar_url":"https://github.com/gmickel.png","language":"TypeScript","readme":"# cursor-windsurf-convert (\"cuws\")\n\n*Surf your AI rules from **Cursor** to **Windsurf** (and back) faster than you can say `cat | cuws`.* 🏄‍♂️⛵\n\n[![CI](https://github.com/gmickel/cursor-windsurf-convert/actions/workflows/ci.yml/badge.svg)](https://github.com/YOUR_ORG/cursor-windsurf-convert/actions/workflows/ci.yml)\n[![License](https://img.shields.io/github/license/gmickel/cursor-windsurf-convert)](LICENSE)\n[![NPM Version](https://img.shields.io/npm/v/cursor-windsurf-convert)](https://www.npmjs.com/package/cursor-windsurf-convert)\n[![NPM Downloads](https://img.shields.io/npm/dw/cursor-windsurf-convert)](https://www.npmjs.com/package/cursor-windsurf-convert)\n\n[About](#-about) •\n[Why cuws?](#-why-cuws) •\n[Key Features](#-key-features) •\n[Quick Start](#-quick-start) •\n[Installation](#-installation) •\n[Usage](#-usage) •\n[API](#-api) •\n[Developing](#-developing) •\n[Contributing](#-contributing) •\n[Roadmap](#-roadmap) •\n[FAQ](#-faq)\n\n---\n\n## 📖 About\n\n`cuws` is a tiny but mighty Node.js CLI + library that losslessly converts rule files between **Cursor** (`.cursor/rules/*.mdc`) and **Windsurf** (`.windsurf/rules/*.md`) formats.  Pipe it, script it, or call it from TypeScript—either way your rules arrive on the right shore untouched.\n\n\u003e *Windsurf shipped file‑based rules on **7 May 2025**. This project exists so you can ride that wave **today**.*\n\n---\n\n## 🤔 Why cuws?\n\n* **Zero friction** – stream via `stdin`/`stdout` or give it paths.\n* **Bidirectional** – Cursor ➜ Windsurf **and** Windsurf ➜ Cursor.\n* **Fast** – converts a 1 kB rule in \u003c 50 ms. Blink and you’ll miss it.\n* **Lossless metadata mapping** – front‑matter stays intact, content unchanged.\n* **CI‑ready** – deterministic, non‑interactive, exit codes you can trust.\n* **Tiny footprint** – minimal runtime dependencies (`gray-matter`, `commander`, `fast-glob` for CLI).\n\n---\n\n## ✨ Key Features\n\n| Feature                         | Description                                                                         |\n| ------------------------------- | ----------------------------------------------------------------------------------- |\n| 🔄 **Bidirectional conversion** | `cuws` detects the source format or let you force it.                               |\n| 📂 **Directory mode**           | Convert whole trees while mirroring structure (requires output directory specified). |\n| 🏗️ **TypeScript API**          | Import `convertString()`, `convertFile()`, or `convertDirectory()` in your scripts. |\n| 🪝 **Streaming first**          | Works perfectly in Unix pipes \u0026 GitHub Actions.                                     |\n| 🐚 **Single‑file binary**       | ES module with hashbang—no compilation required.                                    |\n\n---\n\n## 🚀 Quick Start\n\nThe easiest way to use `cuws` without a global installation is with `npx`:\n\n```bash\n# Convert a single file (Cursor ➜ Windsurf) using npx\nnpx cursor-windsurf-convert -i .cursor/rules/auth.mdc -o .windsurf/rules/auth.md\n\n# Pipe via stdin/stdout using npx\ngit show HEAD:my-rule.mdc | npx cursor-windsurf-convert --reverse \u003e my-rule-cursor.mdc\n\n# Convert all Cursor rules from '.cursor/rules' to Windsurf rules in '.windsurf/rules'\nnpx cursor-windsurf-convert -d .cursor/rules -o .windsurf/rules\n\n# Convert all Windsurf rules from '.windsurf/rules' back to Cursor in '.cursor/rules-backup'\nnpx cursor-windsurf-convert -d .windsurf/rules -o .cursor/rules-backup --reverse\n```\n\nAlternatively, if you prefer a global installation for frequent use:\n```bash\n# Global install (optional)\nnpm install -g cursor-windsurf-convert\n# Then use 'cuws' directly:\n# cuws -i .cursor/rules/another.mdc -o .windsurf/rules/another.md\n```\n\n---\n\n## 📦 Installation\n\nWhile `npx cursor-windsurf-convert ...` is recommended for quick, one-off uses (see [Quick Start](#-quick-start)), you can also install `cuws`:\n\n**As a project dependency:**\n```bash\n# Using pnpm\npnpm add -D cursor-windsurf-convert\n\n# Using yarn\nyarn add -D cursor-windsurf-convert\n\n# Using npm\nnpm install -D cursor-windsurf-convert\n```\nThen you can run it via `pnpm cuws ...` (if using pnpm) or add it to your `package.json` scripts.\n\n**Globally (for frequent use):**\n```bash\nnpm install -g cursor-windsurf-convert\n# Now you can use 'cuws' directly anywhere:\n# cuws --help\n```\n\n\u003e **Node ≥ 18** required (tested on 18 \u0026 20).\n\n---\n\n## 💻 Usage\n\n### CLI\n\n```bash\ncuws [options]\n```\n\n| Flag                  | Default     | Description                                                                 |\n| --------------------- | ----------- | --------------------------------------------------------------------------- |\n| `-i, --input \u003cpath\u003e`  | `-`         | Path to source file or `-` for stdin. Conflicts with `-d`.                  |\n| `-o, --output \u003cpath\u003e` | `-`         | Path to dest file (with `-i`) or output directory (required with `-d`).     |\n| `-r, --reverse`       | `false`     | Convert from Windsurf (.md) to Cursor (.mdc).                               |\n| `--force \u003cformat\u003e`    |             | Override auto-detection (`cursor` or `windsurf`).                           |\n| `-d, --dir \u003cpath\u003e`    |             | Recursively convert directory. Requires `-o` for output. Conflicts with `-i`. |\n| `--dry-run`           | `false`     | Print planned actions, don’t write files.                                   |\n| `--verbose`           | `false`     | Extra logging.                                                              |\n\n### Programmatic API\n\n```typescript\nimport {\n  convertString,\n  convertFile,\n  convertDirectory,\n} from 'cursor-windsurf-convert';\n\n// Convert a string\nconst cursorRuleContent = '...'; // content of a .mdc file\nconst windsurfRuleContent = convertString(cursorRuleContent, 'cw');\n\n// Convert a single file\nasync function exampleConvertFile() {\n  const outputPath = await convertFile('path/to/source.mdc', 'path/to/output.md');\n  console.log(`Converted file written to: ${outputPath}`);\n}\n\n// Convert a directory\nasync function exampleConvertDirectory() {\n  const results = await convertDirectory('path/to/source-dir', 'path/to/output-dir');\n  results.forEach(result =\u003e {\n    console.log(`${result.sourcePath} -\u003e ${result.destinationPath} (${result.status})`);\n  });\n}\n```\n\nSee [API docs](docs/API.md) for full typings.\n\n---\n\n## 🛠️ Developing\n\n1. Clone \u0026 install deps:\n\n   ```bash\n   git clone https://github.com/YOUR_ORG/cursor-windsurf-convert.git\n   cd cursor-windsurf-convert \u0026\u0026 pnpm install\n   ```\n2. Link the CLI for local testing:\n\n   ```bash\n   pnpm run build # if you transpile\n   pnpm link --global   # exposes `cuws` in PATH\n   ```\n3. Run tests:\n\n   ```bash\n   pnpm test\n   ```\n\n### `package.json` bin field\n\n```jsonc\n{\n  \"name\": \"cursor-windsurf-convert\",\n  \"version\": \"1.0.0\",\n  \"bin\": {\n    \"cuws\": \"dist/cli.mjs\"\n  },\n  ...\n}\n```\n\nThe CLI file **must** start with `#!/usr/bin/env node` and be `chmod +x`.\n\n---\n\n## 🤝 Contributing\n\nPRs welcome! Check the [open issues](https://github.com/gmickel/cursor-windsurf-convert/issues) or open a new one. Also see [CONTRIBUTING.md](CONTRIBUTING.md) for details.\n\n---\n\n## 🏄 Roadmap\n\n* [x] One‑file conversion\n* [x] Directory batch mode\n\n---\n\n## ❓ FAQ\n\n| Q                                  | A                                              |\n| ---------------------------------- | ---------------------------------------------- |\n| *Does it change my markdown body?* | Nope. Only the YAML/MD header is mapped.       |\n| *Can I embed this in my own tool?* | Absolutely—import the TS API.                  |\n| *What if I get YAML errors?*       | `cuws` uses a strict YAML parser. See [YAML Parsing Strictness](#yaml-parsing-strictness) below. |\n\n---\n\n## YAML Parsing Strictness\n\n`cuws` uses a strict YAML parser for the front-matter in rule files. This ensures that conversions are accurate and that your rule files adhere to valid YAML syntax. If you encounter errors related to YAML parsing (often error code `E03`), please check the following common pitfalls:\n\n*   **Missing Colons**: Ensure every key-value pair has a colon separating the key and the value.\n    *   Incorrect: `alwaysApply true`\n    *   Correct: `alwaysApply: true`\n*   **Missing Values**: Ensure that if a key has a colon, it also has a value following it.\n    *   Incorrect: `description:` (with nothing after the colon)\n    *   Correct: `description: My rule description` or remove the line if `description` is not needed.\n*   **Indentation**: YAML is sensitive to indentation. Ensure that your indentation is consistent and correctly represents the structure of your metadata.\n*   **Special Characters in Unquoted Strings**: If your string values contain special characters (e.g., `:`, `{`, `}`, `[`, `]`, `,`, `\u0026`, `*`, `#`, `?`, `|`, `-`, `\u003c`, `\u003e`, `=`, `!`, `%`, `@`, `` ` ``), they might need to be quoted.\n    *   Example: `title: My Rule: A Detailed Look` should be `title: 'My Rule: A Detailed Look'` or `title: \"My Rule: A Detailed Look\"`.\n    *   `cuws` attempts to auto-quote problematic `globs` values during parsing, but other fields might require manual quoting if they contain special characters that could be misinterpreted by the YAML parser.\n\nThe error messages provided by `cuws` for YAML parsing issues will typically include the line number and a snippet from the original parser to help you locate the problem.\n\n---\n\n## 📄 License\n\n[MIT](LICENSE) © 2025 Gordon Mickel\n\n---\n\n⭐ **If this saves you time, drop a star!** ⭐\n","funding_links":["https://github.com/sponsors/gmickel"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmickel%2Fcursor-windsurf-convert","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgmickel%2Fcursor-windsurf-convert","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgmickel%2Fcursor-windsurf-convert/lists"}