diff --git a/flutter-cursor-templates/generator/CHANGELOG.md b/flutter-cursor-templates/generator/CHANGELOG.md new file mode 100644 index 0000000..be24b8a --- /dev/null +++ b/flutter-cursor-templates/generator/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +## 1.0.0 + +- Initial published release of the `cursor_gen` CLI. +- Generates `.cursor/` rules and related config from `project-brief.yaml`. +- Supports validate, generate, refresh (preserve customizations), diff preview, wizard, and update checks. diff --git a/flutter-cursor-templates/generator/LICENSE b/flutter-cursor-templates/generator/LICENSE new file mode 100644 index 0000000..251b468 --- /dev/null +++ b/flutter-cursor-templates/generator/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 cursor_gen contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/flutter-cursor-templates/generator/README.md b/flutter-cursor-templates/generator/README.md new file mode 100644 index 0000000..fdf2fd3 --- /dev/null +++ b/flutter-cursor-templates/generator/README.md @@ -0,0 +1,53 @@ +# cursor_gen + +CLI that generates project-specific [Cursor](https://cursor.com) AI configuration for Flutter projects from a `project-brief.yaml` file (stack, architecture, routing, backends, testing, and more). + +## Requirements + +- Dart SDK `>=3.3.0 <4.0.0` + +## Install + +**From path (local checkout):** + +```bash +dart pub global activate --source path . +``` + +Run from the `flutter-cursor-templates/generator` directory (where this `README` lives). + +**From Git:** use `dart pub global activate --source git ` and set the `path` option if your `pubspec.yaml` is not at the repository root (see [pub dependencies](https://dart.dev/tools/pub/dependencies#git-packages)). + +**From a private Pub registry:** configure `dart pub token add` and install with `dart pub add cursor_gen --hosted-url=`. + +## Usage + +```bash +cursor_gen --help +cursor_gen --validate --brief project-brief.yaml +cursor_gen --brief project-brief.yaml --output .cursor +cursor_gen --refresh # regenerate while preserving custom/ and CURSOR:CUSTOM blocks +cursor_gen --wizard # interactive project-brief.yaml creator +``` + +## Minimal `project-brief.yaml` + +```yaml +project: + name: MyApp + package: com.example.myapp + scale: medium +stack: + state_management: bloc + architecture: clean + routing: gorouter + platforms: [ios, android] + backend: firebase + auth: firebase_auth +``` + +Use `brief-schema.json` in this package for IDE validation and autocomplete of the full schema. + +## Repository + +For full monorepo layout, template library, and architecture notes, see the parent repository README. diff --git a/flutter-cursor-templates/generator/bin/cursor_gen.dart b/flutter-cursor-templates/generator/bin/cursor_gen.dart index 8b5252b..18f770d 100644 --- a/flutter-cursor-templates/generator/bin/cursor_gen.dart +++ b/flutter-cursor-templates/generator/bin/cursor_gen.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:args/args.dart'; +import '../src/models.dart'; import '../src/brief_loader.dart'; import '../src/resolver.dart'; import '../src/renderer.dart'; diff --git a/flutter-cursor-templates/generator/pubspec.lock b/flutter-cursor-templates/generator/pubspec.lock new file mode 100644 index 0000000..23ba998 --- /dev/null +++ b/flutter-cursor-templates/generator/pubspec.lock @@ -0,0 +1,405 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: cd6add6f846f35fb79f3c315296703c1a24f3cfd7f4739d91a74961c1c7e9f1b + url: "https://pub.dev" + source: hosted + version: "100.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "6ba98576948803398b69e3a444df24eacdbe12ed699c7014e120ea38552debbf" + url: "https://pub.dev" + source: hosted + version: "13.0.0" + ansi_styles: + dependency: "direct main" + description: + name: ansi_styles + sha256: "9c656cc12b3c27b17dd982b2cc5c0cfdfbdabd7bc8f3ae5e8542d9867b47ce8a" + url: "https://pub.dev" + source: hosted + version: "0.3.2+1" + args: + dependency: "direct main" + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" + collection: + dependency: "direct main" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + url: "https://pub.dev" + source: hosted + version: "1.15.0" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + http: + dependency: "direct main" + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + lints: + dependency: "direct dev" + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" + url: "https://pub.dev" + source: hosted + version: "0.12.20" + meta: + dependency: transitive + description: + name: meta + sha256: df0c643f44ad098eb37988027a8e2b2b5a031fd3977f06bbfd3a76637e8df739 + url: "https://pub.dev" + source: hosted + version: "1.18.2" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: "direct main" + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test: + dependency: "direct dev" + description: + name: test + sha256: ca578dc12bb8b2f40b67b7d3bd2fac4f31c01a6ff7130a14e2597b919934507f + url: "https://pub.dev" + source: hosted + version: "1.31.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11" + url: "https://pub.dev" + source: hosted + version: "0.7.12" + test_core: + dependency: transitive + description: + name: test_core + sha256: d2e98ec12998368dc59ddd47ab709f2cd55acd6b66dc7db764455a44082f4bc5 + url: "https://pub.dev" + source: hosted + version: "0.6.18" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" + url: "https://pub.dev" + source: hosted + version: "15.2.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: "direct main" + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.11.0 <4.0.0" diff --git a/flutter-cursor-templates/generator/pubspec.yaml b/flutter-cursor-templates/generator/pubspec.yaml index 3be368c..e08ba7e 100644 --- a/flutter-cursor-templates/generator/pubspec.yaml +++ b/flutter-cursor-templates/generator/pubspec.yaml @@ -9,7 +9,6 @@ environment: dependencies: args: ^2.4.2 yaml: ^3.1.2 - json_schema: ^6.0.0 path: ^1.9.0 http: ^1.2.0 crypto: ^3.0.3 diff --git a/flutter-cursor-templates/generator/test/generator_test.dart b/flutter-cursor-templates/generator/test/generator_test.dart index 2f636f6..38b69e8 100644 --- a/flutter-cursor-templates/generator/test/generator_test.dart +++ b/flutter-cursor-templates/generator/test/generator_test.dart @@ -95,6 +95,7 @@ final _getxMvcBrief = ProjectBrief( locales: ['en'], ); +void main() { // ─── Resolver tests ───────────────────────────────────────────────────────── group('Resolver', () { @@ -343,6 +344,8 @@ group('Golden file tests', () { }); }); +} + // ─── Helpers ───────────────────────────────────────────────────────────────── Future _compareGoldens(String goldenDir, Map rendered) async { @@ -364,9 +367,4 @@ String _templateDir() { return script.replaceAll(RegExp(r'test[/\\][^/\\]+$'), '../templates'); } -// Custom matcher -Matcher get containsNot => isNot(contains); - -extension on Matcher { - Matcher call(dynamic value) => isNot(contains(value)); -} +Matcher containsNot(dynamic expected) => isNot(contains(expected));