├── .gitignore ├── .release-it.json ├── .vscode └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUING.md ├── LICENSE ├── README.md ├── __.eslint.config.js ├── package-lock.json ├── package.json ├── packages ├── codetie │ ├── .npmrc │ ├── .prettierrc │ ├── CHANGELOG.md │ ├── bin │ │ └── codetie.mjs │ ├── build.config.ts │ ├── package.json │ ├── playground │ │ ├── .gitignore │ │ ├── .swiftlint.yml │ │ ├── codetie.yml │ │ ├── exampleProject │ │ │ ├── ContentView.swift │ │ │ ├── Info.plist │ │ │ ├── debug.xcconfig │ │ │ └── exampleProjectApp.swift │ │ └── project.yml │ ├── src │ │ ├── commands │ │ │ ├── build.ts │ │ │ ├── generate.ts │ │ │ ├── index.ts │ │ │ └── preview.ts │ │ ├── index.ts │ │ ├── main.ts │ │ ├── run.ts │ │ └── utils │ │ │ └── fs.ts │ ├── tsconfig.json │ └── types.d.ts └── create-codetie │ ├── .gitignore │ ├── __buildServer.json │ ├── build.config.ts │ ├── index.js │ ├── package.json │ ├── src │ ├── index.ts │ ├── prompts │ │ ├── index.ts │ │ ├── init.ts │ │ └── installDependencies.ts │ └── utils │ │ └── fs.ts │ ├── template │ ├── .cursorrules │ ├── .swiftlint.yml │ ├── .vscode │ │ ├── extensions.json │ │ ├── settings.json │ │ └── tasks.json │ ├── README.md │ ├── _gitignore │ ├── _project │ │ ├── ContentView.swift │ │ ├── _main.swift │ │ └── debug.xcconfig │ ├── project.yml.mustache │ ├── scripts │ │ ├── build_project.sh │ │ ├── build_project_server.sh │ │ ├── parse_build_log.py │ │ └── run_simulator.sh.mustache │ └── simulators.yml │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── scripts ├── __release.ts ├── extendCommitHash.ts ├── release.ts └── releaseUtils.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | ## User settings 5 | xcuserdata/ 6 | 7 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 8 | *.xcscmblueprint 9 | *.xccheckout 10 | 11 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 12 | build/ 13 | DerivedData/ 14 | *.moved-aside 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | 27 | ## App packaging 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | # Package.pins 41 | # Package.resolved 42 | # *.xcodeproj 43 | # 44 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 45 | # hence it is not needed unless you have added a package configuration file to your project 46 | # .swiftpm 47 | 48 | .build/ 49 | 50 | # CocoaPods 51 | # 52 | # We recommend against adding the Pods directory to your .gitignore. However 53 | # you should judge for yourself, the pros and cons are mentioned at: 54 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 55 | # 56 | # Pods/ 57 | # 58 | # Add this line if you want to avoid checking in source code from the Xcode workspace 59 | # *.xcworkspace 60 | 61 | # Carthage 62 | # 63 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 64 | # Carthage/Checkouts 65 | 66 | Carthage/Build/ 67 | 68 | # Accio dependency management 69 | Dependencies/ 70 | .accio/ 71 | 72 | # fastlane 73 | # 74 | # It is recommended to not store the screenshots in the git repo. 75 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 76 | # For more information about the recommended setup visit: 77 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 78 | 79 | fastlane/report.xml 80 | fastlane/Preview.html 81 | fastlane/screenshots/**/*.png 82 | fastlane/test_output 83 | 84 | # Code Injection 85 | # 86 | # After new code Injection tools there's a generated folder /iOSInjectionProject 87 | # https://github.com/johnno1962/injectionforxcode 88 | 89 | iOSInjectionProject/ 90 | 91 | # macOS 92 | .DS_Store 93 | 94 | # SwiftUI Preview Content 95 | **/Preview Content 96 | 97 | 98 | node_modules/ 99 | dist 100 | .DS_Store 101 | .history 102 | .vercel 103 | .idea 104 | .env 105 | .data 106 | packages/create-codetie/debug.log 107 | -------------------------------------------------------------------------------- /.release-it.json: -------------------------------------------------------------------------------- 1 | { 2 | "git": { 3 | "commitMessage": "chore: release v${version}", 4 | "tagName": "v${version}", 5 | "pushRepo": "origin main" 6 | }, 7 | "npm": { 8 | "publish": false 9 | }, 10 | "plugins": { 11 | "@release-it/conventional-changelog": { 12 | "preset": "angular", 13 | "infile": "CHANGELOG.md" 14 | }, 15 | "@release-it/bumper": { 16 | "out": [ 17 | "packages/*/package.json" 18 | ] 19 | } 20 | }, 21 | "hooks": { 22 | "after:bump": "pnpm install", 23 | "after:git:release": "echo Successfully released ${name} v${version} to ${repo.repository}.", 24 | "after:release": "echo Successfully released ${name} v${version}. Now you can publish the packages individually." 25 | } 26 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "lldb.library": "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB", 3 | "lldb.launch.expressions": "native" 4 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## [1.0.9](https://github.com/codetie-ai/codetie/compare/v1.0.8...v1.0.9) (2024-09-25) 4 | 5 | ## [1.0.8](https://github.com/codetie-ai/codetie/compare/v1.0.7...v1.0.8) (2024-09-25) 6 | 7 | ## [1.0.7](https://github.com/codetie-ai/codetie/compare/v1.0.6...v1.0.7) (2024-09-18) 8 | 9 | ## [1.0.6](https://github.com/codetie-ai/codetie/compare/v1.0.5...v1.0.6) (2024-09-16) 10 | 11 | ## [1.0.5](https://github.com/codetie-ai/codetie/compare/v1.0.4...v1.0.5) (2024-09-16) 12 | 13 | ## [1.0.4](https://github.com/codetie-ai/codetie/compare/v1.0.3...v1.0.4) (2024-09-16) 14 | 15 | ## [1.0.3](https://github.com/codetie-ai/codetie/compare/v1.0.2...v1.0.3) (2024-09-16) 16 | 17 | ## [1.0.2](https://github.com/codetie-ai/codetie/compare/v1.0.1...v1.0.2) (2024-09-16) 18 | 19 | # Changelog 20 | 21 | ## 1.0.1 (2024-09-15) 22 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | - Using welcoming and inclusive language 11 | - Being respectful of differing viewpoints and experiences 12 | - Gracefully accepting constructive criticism 13 | - Focusing on what is best for the community 14 | - Showing empathy towards other community members 15 | 16 | Examples of unacceptable behavior by participants include: 17 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 18 | - Trolling, insulting/derogatory comments, and personal or political attacks 19 | - Public or private harassment 20 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 21 | - Other conduct which could reasonably be considered inappropriate in a professional setting 22 | 23 | ## Our Responsibilities 24 | 25 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 26 | 27 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 28 | 29 | ## Scope 30 | 31 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 32 | 33 | ## Enforcement 34 | 35 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [INSERT EMAIL ADDRESS]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 36 | 37 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 38 | 39 | ## Attribution 40 | 41 | This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 42 | 43 | For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq 44 | -------------------------------------------------------------------------------- /CONTRIBUING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for considering contributing to our project! We welcome all kinds of contributions, including bug reports, feature requests, documentation improvements, and code enhancements. 4 | 5 | ## How to Contribute 6 | 7 | 1. **Fork the Repository**: Start by forking the repository to your GitHub account. 8 | 9 | 2. **Clone the Repository**: Clone your forked repository to your local machine. 10 | ```bash 11 | git clone https://github.com/your-username/repository-name.git 12 | ``` 13 | 14 | 3. **Create a Branch**: Create a new branch for your contribution. 15 | ```bash 16 | git checkout -b feature/your-feature-name 17 | ``` 18 | 19 | 4. **Make Changes**: Make your changes in the new branch. Ensure your code follows the project's coding standards and includes appropriate tests. 20 | 21 | 5. **Commit Changes**: Commit your changes with a clear and concise commit message. 22 | ```bash 23 | git commit -m "Add feature: your feature description" 24 | ``` 25 | 26 | 6. **Push Changes**: Push your changes to your forked repository. 27 | ```bash 28 | git push origin feature/your-feature-name 29 | ``` 30 | 31 | 7. **Create a Pull Request**: Open a pull request from your branch to the main repository's `main` branch. Provide a detailed description of your changes and any related issues. 32 | 33 | ## Code of Conduct 34 | 35 | Please note that this project is governed by a [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. 36 | 37 | ## License 38 | 39 | By contributing, you agree that your contributions will be licensed under the [MIT License](LICENSE). 40 | 41 | ## Contact 42 | 43 | If you have any questions or need further assistance, feel free to contact the project maintainers. 44 | 45 | Thank you for your contributions! 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Nuxt Project 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Codetie.ai - Cursor-XCode-Swift-Sync 2 | 3 | Cursor-XCode-Swift-Sync is a project boilerplate that leverages the power of [XcodeGen](https://github.com/yonaskolb/XcodeGen) to streamline the Xcode project generation process for Swift applications. 4 | 5 | Read more at [codetie.ai](https://codetie.ai) 6 | 7 | [![Watch the video](https://res.cloudinary.com/ddbi0suli/image/upload/v1726438129/codetie/todoapp_zmnfsk.png)](https://res.cloudinary.com/ddbi0suli/video/upload/v1725936511/codetie/twitter_cursor_swift2_jnarb7.mp4) 8 | 9 | 10 | ## Features 11 | 12 | - Automated Xcode project generation 13 | - Simplified project configuration using YAML or JSON 14 | - Easy management of targets, configurations, and schemes 15 | - Seamless integration with version control systems 16 | - VS Code tasks for project generation, building, and linting 17 | 18 | ## Prerequisites 19 | 20 | Before you begin, ensure you have the following installed: 21 | - Xcode (latest stable version) 22 | - [XcodeGen](https://github.com/yonaskolb/XcodeGen) 23 | - [SwiftLint](https://github.com/realm/SwiftLint) (optional, for linting) 24 | 25 | ## Installation 26 | 27 | Read docs at [codetie.ai](https://codetie.ai/docs) 28 | 29 | ## Tasks 30 | 31 | 4. Use VS Code tasks to manage your project: 32 | - Generate Xcode Project: `CMD+SHIFT+B` > "Tasks: Run Task" > "Generate Xcode Project with XcodeGen" 33 | - Build Swift Project: `CMD+SHIFT+B` > "Tasks: Run Task" > "Build Swift Project" 34 | - Run SwiftLint: `CMD+SHIFT+B` > "Tasks: Run Task" > "Run SwiftLint" 35 | 36 | ## Project Structure 37 | 38 | ``` 39 | Cursor-XCode-Swift-Sync/ 40 | ├── Sources/ 41 | │ └── (Your Swift source files) 42 | ├── Tests/ 43 | │ └── (Your test files) 44 | ├── Resources/ 45 | │ └── (Asset catalogs, storyboards, etc.) 46 | ├── project.yml 47 | └── README.md 48 | ``` 49 | 50 | ## Built with Cursor-XCode-Swift-Sync 51 | 52 | [Flappy Bird Clone in Swift](https://github.com/regenrek/flappy-bird-clone-swift) 53 | [![Watch the video](https://res.cloudinary.com/ddbi0suli/image/upload/v1726438129/codetie/game_l1ze4t.png)](https://res.cloudinary.com/ddbi0suli/video/upload/v1726393407/codetie/flappy_bird_zai8ig_5_s7kmjt.mp4) 54 | 55 | 56 | ## Customization 57 | 58 | Edit the `project.yml` file to customize your project settings, targets, and configurations. Refer to the [XcodeGen documentation](https://github.com/yonaskolb/XcodeGen/blob/master/Docs/ProjectSpec.md) for detailed information on available options. 59 | 60 | ## Benefits of Using XcodeGen 61 | 62 | - **Version Control Friendly**: Keep your Xcode project configuration in a simple, readable format. 63 | - **Reduced Merge Conflicts**: Eliminate `.xcodeproj` merge conflicts in team environments. 64 | - **Consistency**: Ensure project structure consistency across team members and CI systems. 65 | - **Automation**: Easily integrate project generation into your development and CI workflows. 66 | 67 | ## Contributing 68 | 69 | Contributions are welcome! Please feel free to submit a Pull Request. 70 | 71 | 1. Clone this repository: 72 | 73 | ``` 74 | git clone https://github.com/regenrek/Cursor-XCode-Swift-Sync 75 | ``` 76 | 77 | ## License 78 | 79 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 80 | 81 | ## Acknowledgments 82 | 83 | - [XcodeGen](https://github.com/yonaskolb/XcodeGen) for making Xcode project management a breeze. 84 | 85 | --- 86 | 87 | Feel free to customize this README further to match the specific details and requirements of your Cursor2Swift project. The structure provided gives a solid foundation for explaining your project's purpose, setup process, and the benefits of using XcodeGen in your workflow. -------------------------------------------------------------------------------- /__.eslint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { builtinModules, createRequire } from 'node:module' 3 | import eslint from '@eslint/js' 4 | import pluginN from 'eslint-plugin-n' 5 | import pluginImportX from 'eslint-plugin-import-x' 6 | import pluginRegExp from 'eslint-plugin-regexp' 7 | import tseslint from 'typescript-eslint' 8 | import globals from 'globals' 9 | 10 | const require = createRequire(import.meta.url) 11 | const pkg = require('./package.json') 12 | const pkgVite = require('./packages/codetie/package.json') 13 | 14 | // Some rules work better with typechecking enabled, but as enabling it is slow, 15 | // we only do so when linting in IDEs for now. If you want to lint with typechecking 16 | // explicitly, set this to `true` manually. 17 | const shouldTypeCheck = typeof process.env.VSCODE_PID === 'string' 18 | 19 | export default tseslint.config( 20 | { 21 | ignores: [ 22 | 'packages/create-codetie/template-*', 23 | '**/dist/**', 24 | '**/fixtures/**', 25 | '**/playground-temp/**', 26 | '**/temp/**', 27 | '**/*.snap', 28 | ], 29 | }, 30 | eslint.configs.recommended, 31 | ...tseslint.configs.recommended, 32 | ...tseslint.configs.stylistic, 33 | pluginRegExp.configs['flat/recommended'], 34 | { 35 | name: 'main', 36 | languageOptions: { 37 | parser: tseslint.parser, 38 | parserOptions: { 39 | sourceType: 'module', 40 | ecmaVersion: 2022, 41 | project: shouldTypeCheck 42 | ? [ 43 | './packages/*/tsconfig.json', 44 | './packages/codetie/src/*/tsconfig.json', 45 | ] 46 | : undefined, 47 | }, 48 | globals: { 49 | ...globals.es2021, 50 | ...globals.node, 51 | }, 52 | }, 53 | plugins: { 54 | n: pluginN, 55 | 'import-x': pluginImportX, 56 | }, 57 | rules: { 58 | 'n/no-exports-assign': 'error', 59 | 'n/no-unpublished-bin': 'error', 60 | 'n/no-unsupported-features/es-builtins': 'error', 61 | 'n/no-unsupported-features/node-builtins': 'error', 62 | 'n/process-exit-as-throw': 'error', 63 | 'n/hashbang': 'error', 64 | 65 | eqeqeq: ['warn', 'always', { null: 'never' }], 66 | 'no-debugger': ['error'], 67 | 'no-empty': ['warn', { allowEmptyCatch: true }], 68 | 'no-process-exit': 'off', 69 | 'prefer-const': [ 70 | 'warn', 71 | { 72 | destructuring: 'all', 73 | }, 74 | ], 75 | 76 | 'n/no-missing-require': [ 77 | 'error', 78 | { 79 | // for try-catching yarn pnp 80 | allowModules: ['pnpapi', 'codetie'], 81 | tryExtensions: ['.ts', '.js', '.jsx', '.tsx', '.d.ts'], 82 | }, 83 | ], 84 | 'n/no-extraneous-import': [ 85 | 'error', 86 | { 87 | allowModules: ['codetie', 'less', 'sass', 'vitest', 'unbuild'], 88 | }, 89 | ], 90 | 'n/no-extraneous-require': [ 91 | 'error', 92 | { 93 | allowModules: ['codetie'], 94 | }, 95 | ], 96 | 97 | '@typescript-eslint/ban-ts-comment': 'error', 98 | '@typescript-eslint/no-unsafe-function-type': 'off', 99 | '@typescript-eslint/explicit-module-boundary-types': [ 100 | 'error', 101 | { allowArgumentsExplicitlyTypedAsAny: true }, 102 | ], 103 | '@typescript-eslint/no-empty-function': [ 104 | 'error', 105 | { allow: ['arrowFunctions'] }, 106 | ], 107 | '@typescript-eslint/no-empty-object-type': [ 108 | 'error', 109 | { allowInterfaces: 'with-single-extends' }, 110 | ], 111 | '@typescript-eslint/no-empty-interface': 'off', 112 | '@typescript-eslint/no-explicit-any': 'off', 113 | 'no-extra-semi': 'off', 114 | '@typescript-eslint/no-extra-semi': 'off', // conflicts with prettier 115 | '@typescript-eslint/no-inferrable-types': 'off', 116 | '@typescript-eslint/no-unused-vars': [ 117 | 'error', 118 | { 119 | args: 'all', 120 | argsIgnorePattern: '^_', 121 | caughtErrors: 'all', 122 | caughtErrorsIgnorePattern: '^_', 123 | destructuredArrayIgnorePattern: '^_', 124 | varsIgnorePattern: '^_', 125 | ignoreRestSiblings: true, 126 | }, 127 | ], 128 | '@typescript-eslint/no-require-imports': 'off', 129 | '@typescript-eslint/consistent-type-imports': [ 130 | 'error', 131 | { prefer: 'type-imports', disallowTypeAnnotations: false }, 132 | ], 133 | // disable rules set in @typescript-eslint/stylistic which conflict with current code 134 | // we should discuss if we want to enable these as they encourage consistent code 135 | '@typescript-eslint/array-type': 'off', 136 | '@typescript-eslint/consistent-type-definitions': 'off', 137 | '@typescript-eslint/prefer-for-of': 'off', 138 | '@typescript-eslint/prefer-function-type': 'off', 139 | 140 | 'import-x/no-nodejs-modules': [ 141 | 'error', 142 | { allow: builtinModules.map((mod) => `node:${mod}`) }, 143 | ], 144 | 'import-x/no-duplicates': 'error', 145 | 'import-x/order': 'error', 146 | 'sort-imports': [ 147 | 'error', 148 | { 149 | ignoreCase: false, 150 | ignoreDeclarationSort: true, 151 | ignoreMemberSort: false, 152 | memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'], 153 | allowSeparatedGroups: false, 154 | }, 155 | ], 156 | 157 | 'regexp/prefer-regexp-exec': 'error', 158 | 'regexp/prefer-regexp-test': 'error', 159 | // in some cases using explicit letter-casing is more performant than the `i` flag 160 | 'regexp/use-ignore-case': 'off', 161 | }, 162 | }, 163 | { 164 | name: 'vite/globals', 165 | files: ['packages/**/*.?([cm])[jt]s?(x)'], 166 | ignores: ['**/__tests__/**'], 167 | rules: { 168 | 'no-restricted-globals': ['error', 'require', '__dirname', '__filename'], 169 | }, 170 | }, 171 | { 172 | name: 'vite/node', 173 | files: ['packages/vite/src/node/**/*.?([cm])[jt]s?(x)'], 174 | rules: { 175 | 'no-console': ['error'], 176 | 'n/no-restricted-require': [ 177 | 'error', 178 | Object.keys(pkgVite.devDependencies).map((d) => ({ 179 | name: d, 180 | message: 181 | `devDependencies can only be imported using ESM syntax so ` + 182 | `that they are included in the rollup bundle. If you are trying to ` + 183 | `lazy load a dependency, use (await import('dependency')).default instead.`, 184 | })), 185 | ], 186 | }, 187 | }, 188 | { 189 | name: 'playground/enforce-esm', 190 | files: ['playground/**/*.?([cm])[jt]s?(x)'], 191 | ignores: [ 192 | 'playground/ssr-resolve/**', 193 | 'playground/**/*{commonjs,cjs}*/**', 194 | 'playground/**/*{commonjs,cjs}*', 195 | 'playground/**/*dep*/**', 196 | 'playground/resolve/browser-module-field2/index.web.js', 197 | 'playground/resolve/browser-field/**', 198 | 'playground/tailwind/**', // blocked by https://github.com/postcss/postcss-load-config/issues/239 199 | ], 200 | rules: { 201 | 'import-x/no-commonjs': 'error', 202 | }, 203 | }, 204 | { 205 | name: 'playground/test', 206 | files: ['playground/**/__tests__/**/*.?([cm])[jt]s?(x)'], 207 | rules: { 208 | // engine field doesn't exist in playgrounds 209 | 'n/no-unsupported-features/es-builtins': [ 210 | 'error', 211 | { 212 | version: pkg.engines.node, 213 | }, 214 | ], 215 | 'n/no-unsupported-features/node-builtins': [ 216 | 'error', 217 | { 218 | version: pkg.engines.node, 219 | // ideally we would like to allow all experimental features 220 | // https://github.com/eslint-community/eslint-plugin-n/issues/199 221 | ignores: ['fetch'], 222 | }, 223 | ], 224 | }, 225 | }, 226 | 227 | { 228 | name: 'disables/vite/client', 229 | files: ['packages/vite/src/client/**/*.?([cm])[jt]s?(x)'], 230 | ignores: ['**/__tests__/**'], 231 | rules: { 232 | 'n/no-unsupported-features/node-builtins': 'off', 233 | }, 234 | }, 235 | { 236 | name: 'disables/vite/types', 237 | files: [ 238 | 'packages/vite/src/types/**/*.?([cm])[jt]s?(x)', 239 | 'packages/vite/scripts/**/*.?([cm])[jt]s?(x)', 240 | '**/*.spec.ts', 241 | ], 242 | rules: { 243 | 'n/no-extraneous-import': 'off', 244 | }, 245 | }, 246 | { 247 | name: 'disables/vite/cjs', 248 | files: ['packages/vite/index.cjs'], 249 | rules: { 250 | 'no-restricted-globals': 'off', 251 | 'n/no-missing-require': 'off', 252 | }, 253 | }, 254 | { 255 | name: 'disables/create-vite/templates', 256 | files: [ 257 | 'packages/create-vite/template-*/**/*.?([cm])[jt]s?(x)', 258 | '**/build.config.ts', 259 | ], 260 | rules: { 261 | 'no-undef': 'off', 262 | 'n/no-missing-import': 'off', 263 | 'n/no-extraneous-import': 'off', 264 | 'n/no-extraneous-require': 'off', 265 | '@typescript-eslint/explicit-module-boundary-types': 'off', 266 | }, 267 | }, 268 | { 269 | name: 'disables/playground', 270 | files: ['playground/**/*.?([cm])[jt]s?(x)', 'docs/**/*.?([cm])[jt]s?(x)'], 271 | rules: { 272 | 'n/no-extraneous-import': 'off', 273 | 'n/no-extraneous-require': 'off', 274 | 'n/no-missing-import': 'off', 275 | 'n/no-missing-require': 'off', 276 | 'n/no-unsupported-features/es-builtins': 'off', 277 | 'n/no-unsupported-features/node-builtins': 'off', 278 | '@typescript-eslint/explicit-module-boundary-types': 'off', 279 | '@typescript-eslint/no-unused-expressions': 'off', 280 | '@typescript-eslint/no-unused-vars': 'off', 281 | 'no-undef': 'off', 282 | 'no-empty': 'off', 283 | 'no-constant-condition': 'off', 284 | '@typescript-eslint/no-empty-function': 'off', 285 | }, 286 | }, 287 | { 288 | name: 'disables/playground/tsconfig-json', 289 | files: [ 290 | 'playground/tsconfig-json/**/*.?([cm])[jt]s?(x)', 291 | 'playground/tsconfig-json-load-error/**/*.?([cm])[jt]s?(x)', 292 | ], 293 | ignores: ['**/__tests__/**'], 294 | rules: { 295 | '@typescript-eslint/ban-ts-comment': 'off', 296 | }, 297 | }, 298 | { 299 | name: 'disables/js', 300 | files: ['**/*.js', '**/*.mjs', '**/*.cjs'], 301 | rules: { 302 | '@typescript-eslint/explicit-module-boundary-types': 'off', 303 | }, 304 | }, 305 | { 306 | name: 'disables/dts', 307 | files: ['**/*.d.ts'], 308 | rules: { 309 | '@typescript-eslint/consistent-indexed-object-style': 'off', 310 | '@typescript-eslint/triple-slash-reference': 'off', 311 | }, 312 | }, 313 | { 314 | name: 'disables/test', 315 | files: ['**/__tests__/**/*.?([cm])[jt]s?(x)'], 316 | rules: { 317 | 'no-console': 'off', 318 | '@typescript-eslint/ban-ts-comment': 'off', 319 | }, 320 | }, 321 | { 322 | name: 'disables/typechecking', 323 | files: [ 324 | '**/*.js', 325 | '**/*.mjs', 326 | '**/*.cjs', 327 | '**/*.d.ts', 328 | '**/*.d.cts', 329 | '**/__tests__/**', 330 | 'docs/**', 331 | 'playground/**', 332 | 'scripts/**', 333 | 'vitest.config.ts', 334 | 'vitest.config.e2e.ts', 335 | ], 336 | languageOptions: { 337 | parserOptions: { 338 | project: false, 339 | }, 340 | }, 341 | }, 342 | ) -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Cursor-XCode-Swift-Sync", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "chalk": "^5.3.0", 9 | "inquirer": "^10.2.2", 10 | "mustache": "^4.2.0", 11 | "yargs": "^17.7.2" 12 | }, 13 | "version": "1.0.9" 14 | }, 15 | "node_modules/@inquirer/checkbox": { 16 | "version": "2.5.0", 17 | "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.5.0.tgz", 18 | "integrity": "sha512-sMgdETOfi2dUHT8r7TT1BTKOwNvdDGFDXYWtQ2J69SvlYNntk9I/gJe7r5yvMwwsuKnYbuRs3pNhx4tgNck5aA==", 19 | "dependencies": { 20 | "@inquirer/core": "^9.1.0", 21 | "@inquirer/figures": "^1.0.5", 22 | "@inquirer/type": "^1.5.3", 23 | "ansi-escapes": "^4.3.2", 24 | "yoctocolors-cjs": "^2.1.2" 25 | }, 26 | "engines": { 27 | "node": ">=18" 28 | } 29 | }, 30 | "node_modules/@inquirer/confirm": { 31 | "version": "3.2.0", 32 | "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.2.0.tgz", 33 | "integrity": "sha512-oOIwPs0Dvq5220Z8lGL/6LHRTEr9TgLHmiI99Rj1PJ1p1czTys+olrgBqZk4E2qC0YTzeHprxSQmoHioVdJ7Lw==", 34 | "dependencies": { 35 | "@inquirer/core": "^9.1.0", 36 | "@inquirer/type": "^1.5.3" 37 | }, 38 | "engines": { 39 | "node": ">=18" 40 | } 41 | }, 42 | "node_modules/@inquirer/core": { 43 | "version": "9.1.0", 44 | "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.1.0.tgz", 45 | "integrity": "sha512-RZVfH//2ytTjmaBIzeKT1zefcQZzuruwkpTwwbe/i2jTl4o9M+iML5ChULzz6iw1Ok8iUBBsRCjY2IEbD8Ft4w==", 46 | "dependencies": { 47 | "@inquirer/figures": "^1.0.5", 48 | "@inquirer/type": "^1.5.3", 49 | "@types/mute-stream": "^0.0.4", 50 | "@types/node": "^22.5.2", 51 | "@types/wrap-ansi": "^3.0.0", 52 | "ansi-escapes": "^4.3.2", 53 | "cli-spinners": "^2.9.2", 54 | "cli-width": "^4.1.0", 55 | "mute-stream": "^1.0.0", 56 | "signal-exit": "^4.1.0", 57 | "strip-ansi": "^6.0.1", 58 | "wrap-ansi": "^6.2.0", 59 | "yoctocolors-cjs": "^2.1.2" 60 | }, 61 | "engines": { 62 | "node": ">=18" 63 | } 64 | }, 65 | "node_modules/@inquirer/editor": { 66 | "version": "2.2.0", 67 | "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.2.0.tgz", 68 | "integrity": "sha512-9KHOpJ+dIL5SZli8lJ6xdaYLPPzB8xB9GZItg39MBybzhxA16vxmszmQFrRwbOA918WA2rvu8xhDEg/p6LXKbw==", 69 | "dependencies": { 70 | "@inquirer/core": "^9.1.0", 71 | "@inquirer/type": "^1.5.3", 72 | "external-editor": "^3.1.0" 73 | }, 74 | "engines": { 75 | "node": ">=18" 76 | } 77 | }, 78 | "node_modules/@inquirer/expand": { 79 | "version": "2.3.0", 80 | "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.3.0.tgz", 81 | "integrity": "sha512-qnJsUcOGCSG1e5DTOErmv2BPQqrtT6uzqn1vI/aYGiPKq+FgslGZmtdnXbhuI7IlT7OByDoEEqdnhUnVR2hhLw==", 82 | "dependencies": { 83 | "@inquirer/core": "^9.1.0", 84 | "@inquirer/type": "^1.5.3", 85 | "yoctocolors-cjs": "^2.1.2" 86 | }, 87 | "engines": { 88 | "node": ">=18" 89 | } 90 | }, 91 | "node_modules/@inquirer/figures": { 92 | "version": "1.0.5", 93 | "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", 94 | "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", 95 | "engines": { 96 | "node": ">=18" 97 | } 98 | }, 99 | "node_modules/@inquirer/input": { 100 | "version": "2.3.0", 101 | "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.3.0.tgz", 102 | "integrity": "sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw==", 103 | "dependencies": { 104 | "@inquirer/core": "^9.1.0", 105 | "@inquirer/type": "^1.5.3" 106 | }, 107 | "engines": { 108 | "node": ">=18" 109 | } 110 | }, 111 | "node_modules/@inquirer/number": { 112 | "version": "1.1.0", 113 | "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-1.1.0.tgz", 114 | "integrity": "sha512-ilUnia/GZUtfSZy3YEErXLJ2Sljo/mf9fiKc08n18DdwdmDbOzRcTv65H1jjDvlsAuvdFXf4Sa/aL7iw/NanVA==", 115 | "dependencies": { 116 | "@inquirer/core": "^9.1.0", 117 | "@inquirer/type": "^1.5.3" 118 | }, 119 | "engines": { 120 | "node": ">=18" 121 | } 122 | }, 123 | "node_modules/@inquirer/password": { 124 | "version": "2.2.0", 125 | "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.2.0.tgz", 126 | "integrity": "sha512-5otqIpgsPYIshqhgtEwSspBQE40etouR8VIxzpJkv9i0dVHIpyhiivbkH9/dGiMLdyamT54YRdGJLfl8TFnLHg==", 127 | "dependencies": { 128 | "@inquirer/core": "^9.1.0", 129 | "@inquirer/type": "^1.5.3", 130 | "ansi-escapes": "^4.3.2" 131 | }, 132 | "engines": { 133 | "node": ">=18" 134 | } 135 | }, 136 | "node_modules/@inquirer/prompts": { 137 | "version": "5.5.0", 138 | "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.5.0.tgz", 139 | "integrity": "sha512-BHDeL0catgHdcHbSFFUddNzvx/imzJMft+tWDPwTm3hfu8/tApk1HrooNngB2Mb4qY+KaRWF+iZqoVUPeslEog==", 140 | "dependencies": { 141 | "@inquirer/checkbox": "^2.5.0", 142 | "@inquirer/confirm": "^3.2.0", 143 | "@inquirer/editor": "^2.2.0", 144 | "@inquirer/expand": "^2.3.0", 145 | "@inquirer/input": "^2.3.0", 146 | "@inquirer/number": "^1.1.0", 147 | "@inquirer/password": "^2.2.0", 148 | "@inquirer/rawlist": "^2.3.0", 149 | "@inquirer/search": "^1.1.0", 150 | "@inquirer/select": "^2.5.0" 151 | }, 152 | "engines": { 153 | "node": ">=18" 154 | } 155 | }, 156 | "node_modules/@inquirer/rawlist": { 157 | "version": "2.3.0", 158 | "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.3.0.tgz", 159 | "integrity": "sha512-zzfNuINhFF7OLAtGHfhwOW2TlYJyli7lOUoJUXw/uyklcwalV6WRXBXtFIicN8rTRK1XTiPWB4UY+YuW8dsnLQ==", 160 | "dependencies": { 161 | "@inquirer/core": "^9.1.0", 162 | "@inquirer/type": "^1.5.3", 163 | "yoctocolors-cjs": "^2.1.2" 164 | }, 165 | "engines": { 166 | "node": ">=18" 167 | } 168 | }, 169 | "node_modules/@inquirer/search": { 170 | "version": "1.1.0", 171 | "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-1.1.0.tgz", 172 | "integrity": "sha512-h+/5LSj51dx7hp5xOn4QFnUaKeARwUCLs6mIhtkJ0JYPBLmEYjdHSYh7I6GrLg9LwpJ3xeX0FZgAG1q0QdCpVQ==", 173 | "dependencies": { 174 | "@inquirer/core": "^9.1.0", 175 | "@inquirer/figures": "^1.0.5", 176 | "@inquirer/type": "^1.5.3", 177 | "yoctocolors-cjs": "^2.1.2" 178 | }, 179 | "engines": { 180 | "node": ">=18" 181 | } 182 | }, 183 | "node_modules/@inquirer/select": { 184 | "version": "2.5.0", 185 | "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.5.0.tgz", 186 | "integrity": "sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA==", 187 | "dependencies": { 188 | "@inquirer/core": "^9.1.0", 189 | "@inquirer/figures": "^1.0.5", 190 | "@inquirer/type": "^1.5.3", 191 | "ansi-escapes": "^4.3.2", 192 | "yoctocolors-cjs": "^2.1.2" 193 | }, 194 | "engines": { 195 | "node": ">=18" 196 | } 197 | }, 198 | "node_modules/@inquirer/type": { 199 | "version": "1.5.4", 200 | "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.4.tgz", 201 | "integrity": "sha512-E9sqh3kOGvFj+/tF0RVnclE39tUoa03kDu++WyYXjjf/X0FSI5tAfSHedRWYelix9l3xBUr2klQ92eFyl0aNzQ==", 202 | "dependencies": { 203 | "mute-stream": "^1.0.0" 204 | }, 205 | "engines": { 206 | "node": ">=18" 207 | } 208 | }, 209 | "node_modules/@types/mute-stream": { 210 | "version": "0.0.4", 211 | "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", 212 | "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", 213 | "dependencies": { 214 | "@types/node": "*" 215 | } 216 | }, 217 | "node_modules/@types/node": { 218 | "version": "22.5.5", 219 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", 220 | "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", 221 | "dependencies": { 222 | "undici-types": "~6.19.2" 223 | } 224 | }, 225 | "node_modules/@types/wrap-ansi": { 226 | "version": "3.0.0", 227 | "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", 228 | "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==" 229 | }, 230 | "node_modules/ansi-escapes": { 231 | "version": "4.3.2", 232 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", 233 | "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", 234 | "dependencies": { 235 | "type-fest": "^0.21.3" 236 | }, 237 | "engines": { 238 | "node": ">=8" 239 | }, 240 | "funding": { 241 | "url": "https://github.com/sponsors/sindresorhus" 242 | } 243 | }, 244 | "node_modules/ansi-regex": { 245 | "version": "5.0.1", 246 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 247 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 248 | "engines": { 249 | "node": ">=8" 250 | } 251 | }, 252 | "node_modules/ansi-styles": { 253 | "version": "4.3.0", 254 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 255 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 256 | "dependencies": { 257 | "color-convert": "^2.0.1" 258 | }, 259 | "engines": { 260 | "node": ">=8" 261 | }, 262 | "funding": { 263 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 264 | } 265 | }, 266 | "node_modules/chalk": { 267 | "version": "5.3.0", 268 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", 269 | "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", 270 | "engines": { 271 | "node": "^12.17.0 || ^14.13 || >=16.0.0" 272 | }, 273 | "funding": { 274 | "url": "https://github.com/chalk/chalk?sponsor=1" 275 | } 276 | }, 277 | "node_modules/chardet": { 278 | "version": "0.7.0", 279 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 280 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" 281 | }, 282 | "node_modules/cli-spinners": { 283 | "version": "2.9.2", 284 | "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", 285 | "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", 286 | "engines": { 287 | "node": ">=6" 288 | }, 289 | "funding": { 290 | "url": "https://github.com/sponsors/sindresorhus" 291 | } 292 | }, 293 | "node_modules/cli-width": { 294 | "version": "4.1.0", 295 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", 296 | "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", 297 | "engines": { 298 | "node": ">= 12" 299 | } 300 | }, 301 | "node_modules/cliui": { 302 | "version": "8.0.1", 303 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 304 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 305 | "dependencies": { 306 | "string-width": "^4.2.0", 307 | "strip-ansi": "^6.0.1", 308 | "wrap-ansi": "^7.0.0" 309 | }, 310 | "engines": { 311 | "node": ">=12" 312 | } 313 | }, 314 | "node_modules/cliui/node_modules/wrap-ansi": { 315 | "version": "7.0.0", 316 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 317 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 318 | "dependencies": { 319 | "ansi-styles": "^4.0.0", 320 | "string-width": "^4.1.0", 321 | "strip-ansi": "^6.0.0" 322 | }, 323 | "engines": { 324 | "node": ">=10" 325 | }, 326 | "funding": { 327 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 328 | } 329 | }, 330 | "node_modules/color-convert": { 331 | "version": "2.0.1", 332 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 333 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 334 | "dependencies": { 335 | "color-name": "~1.1.4" 336 | }, 337 | "engines": { 338 | "node": ">=7.0.0" 339 | } 340 | }, 341 | "node_modules/color-name": { 342 | "version": "1.1.4", 343 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 344 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 345 | }, 346 | "node_modules/emoji-regex": { 347 | "version": "8.0.0", 348 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 349 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 350 | }, 351 | "node_modules/escalade": { 352 | "version": "3.2.0", 353 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 354 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 355 | "engines": { 356 | "node": ">=6" 357 | } 358 | }, 359 | "node_modules/external-editor": { 360 | "version": "3.1.0", 361 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", 362 | "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", 363 | "dependencies": { 364 | "chardet": "^0.7.0", 365 | "iconv-lite": "^0.4.24", 366 | "tmp": "^0.0.33" 367 | }, 368 | "engines": { 369 | "node": ">=4" 370 | } 371 | }, 372 | "node_modules/get-caller-file": { 373 | "version": "2.0.5", 374 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 375 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 376 | "engines": { 377 | "node": "6.* || 8.* || >= 10.*" 378 | } 379 | }, 380 | "node_modules/iconv-lite": { 381 | "version": "0.4.24", 382 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 383 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 384 | "dependencies": { 385 | "safer-buffer": ">= 2.1.2 < 3" 386 | }, 387 | "engines": { 388 | "node": ">=0.10.0" 389 | } 390 | }, 391 | "node_modules/inquirer": { 392 | "version": "10.2.2", 393 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-10.2.2.tgz", 394 | "integrity": "sha512-tyao/4Vo36XnUItZ7DnUXX4f1jVao2mSrleV/5IPtW/XAEA26hRVsbc68nuTEKWcr5vMP/1mVoT2O7u8H4v1Vg==", 395 | "dependencies": { 396 | "@inquirer/core": "^9.1.0", 397 | "@inquirer/prompts": "^5.5.0", 398 | "@inquirer/type": "^1.5.3", 399 | "@types/mute-stream": "^0.0.4", 400 | "ansi-escapes": "^4.3.2", 401 | "mute-stream": "^1.0.0", 402 | "run-async": "^3.0.0", 403 | "rxjs": "^7.8.1" 404 | }, 405 | "engines": { 406 | "node": ">=18" 407 | } 408 | }, 409 | "node_modules/is-fullwidth-code-point": { 410 | "version": "3.0.0", 411 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 412 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 413 | "engines": { 414 | "node": ">=8" 415 | } 416 | }, 417 | "node_modules/mustache": { 418 | "version": "4.2.0", 419 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 420 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", 421 | "bin": { 422 | "mustache": "bin/mustache" 423 | } 424 | }, 425 | "node_modules/mute-stream": { 426 | "version": "1.0.0", 427 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", 428 | "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", 429 | "engines": { 430 | "node": "^14.17.0 || ^16.13.0 || >=18.0.0" 431 | } 432 | }, 433 | "node_modules/os-tmpdir": { 434 | "version": "1.0.2", 435 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 436 | "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", 437 | "engines": { 438 | "node": ">=0.10.0" 439 | } 440 | }, 441 | "node_modules/require-directory": { 442 | "version": "2.1.1", 443 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 444 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 445 | "engines": { 446 | "node": ">=0.10.0" 447 | } 448 | }, 449 | "node_modules/run-async": { 450 | "version": "3.0.0", 451 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", 452 | "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", 453 | "engines": { 454 | "node": ">=0.12.0" 455 | } 456 | }, 457 | "node_modules/rxjs": { 458 | "version": "7.8.1", 459 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", 460 | "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", 461 | "dependencies": { 462 | "tslib": "^2.1.0" 463 | } 464 | }, 465 | "node_modules/safer-buffer": { 466 | "version": "2.1.2", 467 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 468 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 469 | }, 470 | "node_modules/signal-exit": { 471 | "version": "4.1.0", 472 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", 473 | "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", 474 | "engines": { 475 | "node": ">=14" 476 | }, 477 | "funding": { 478 | "url": "https://github.com/sponsors/isaacs" 479 | } 480 | }, 481 | "node_modules/string-width": { 482 | "version": "4.2.3", 483 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 484 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 485 | "dependencies": { 486 | "emoji-regex": "^8.0.0", 487 | "is-fullwidth-code-point": "^3.0.0", 488 | "strip-ansi": "^6.0.1" 489 | }, 490 | "engines": { 491 | "node": ">=8" 492 | } 493 | }, 494 | "node_modules/strip-ansi": { 495 | "version": "6.0.1", 496 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 497 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 498 | "dependencies": { 499 | "ansi-regex": "^5.0.1" 500 | }, 501 | "engines": { 502 | "node": ">=8" 503 | } 504 | }, 505 | "node_modules/tmp": { 506 | "version": "0.0.33", 507 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 508 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 509 | "dependencies": { 510 | "os-tmpdir": "~1.0.2" 511 | }, 512 | "engines": { 513 | "node": ">=0.6.0" 514 | } 515 | }, 516 | "node_modules/tslib": { 517 | "version": "2.7.0", 518 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", 519 | "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" 520 | }, 521 | "node_modules/type-fest": { 522 | "version": "0.21.3", 523 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", 524 | "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", 525 | "engines": { 526 | "node": ">=10" 527 | }, 528 | "funding": { 529 | "url": "https://github.com/sponsors/sindresorhus" 530 | } 531 | }, 532 | "node_modules/undici-types": { 533 | "version": "6.19.8", 534 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", 535 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" 536 | }, 537 | "node_modules/wrap-ansi": { 538 | "version": "6.2.0", 539 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", 540 | "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", 541 | "dependencies": { 542 | "ansi-styles": "^4.0.0", 543 | "string-width": "^4.1.0", 544 | "strip-ansi": "^6.0.0" 545 | }, 546 | "engines": { 547 | "node": ">=8" 548 | } 549 | }, 550 | "node_modules/y18n": { 551 | "version": "5.0.8", 552 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 553 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 554 | "engines": { 555 | "node": ">=10" 556 | } 557 | }, 558 | "node_modules/yargs": { 559 | "version": "17.7.2", 560 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 561 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 562 | "dependencies": { 563 | "cliui": "^8.0.1", 564 | "escalade": "^3.1.1", 565 | "get-caller-file": "^2.0.5", 566 | "require-directory": "^2.1.1", 567 | "string-width": "^4.2.3", 568 | "y18n": "^5.0.5", 569 | "yargs-parser": "^21.1.1" 570 | }, 571 | "engines": { 572 | "node": ">=12" 573 | } 574 | }, 575 | "node_modules/yargs-parser": { 576 | "version": "21.1.1", 577 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 578 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 579 | "engines": { 580 | "node": ">=12" 581 | } 582 | }, 583 | "node_modules/yoctocolors-cjs": { 584 | "version": "2.1.2", 585 | "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", 586 | "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", 587 | "engines": { 588 | "node": ">=18" 589 | }, 590 | "funding": { 591 | "url": "https://github.com/sponsors/sindresorhus" 592 | } 593 | } 594 | }, 595 | "version": "1.0.9" 596 | } 597 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@codetie/codetie-monorepo", 3 | "private": true, 4 | "homepage": "https://codetie.ai", 5 | "engines": { 6 | "node": "^18.0.0 || >=20.0.0" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/codetie-ai/codetie.git" 11 | }, 12 | "license": "MIT", 13 | "bin": { 14 | "codetie-create": "./index.js" 15 | }, 16 | "scripts": { 17 | "lint": "eslint --cache .", 18 | "typecheck": "tsc -p scripts --noEmit && pnpm -r --parallel run typecheck", 19 | "build": "pnpm -r --filter='./packages/*' run build", 20 | "publish": "pnpm -r --filter='./packages/*' run build && npx release-it --git.pushRepo=https://github.com/codetie-ai/codetie.git && tsx scripts/release.ts", 21 | "release": "pnpm run build && npx release-it --git.pushRepo=https://github.com/codetie-ai/codetie.git", 22 | "publish-npm": "tsx scripts/release.ts", 23 | "test-create": "pnpm -F create-codetie run create --debug --cwd /Users/kevin/projects/swift/testing-codetie" 24 | }, 25 | "keywords": [ 26 | "codetie", 27 | "cli", 28 | "xcode", 29 | "swift", 30 | "project-setup", 31 | "cursor", 32 | "cursor-ai" 33 | ], 34 | "devDependencies": { 35 | "@release-it/bumper": "^6.0.1", 36 | "@release-it/conventional-changelog": "^8.0.2", 37 | "@vitejs/release-scripts": "^1.3.2", 38 | "chalk": "^5.3.0", 39 | "conventional-changelog-cli": "^5.0.0", 40 | "eslint": "^9.10.0", 41 | "execa": "^9.3.1", 42 | "globals": "^15.9.0", 43 | "inquirer": "^10.2.2", 44 | "lint-staged": "^15.2.10", 45 | "mustache": "^4.2.0", 46 | "picocolors": "^1.1.0", 47 | "prompts": "^2.4.2", 48 | "release-it": "^17.6.0", 49 | "rimraf": "^5.0.10", 50 | "semver": "^7.5.4", 51 | "tslib": "^2.7.0", 52 | "tsx": "^4.19.1", 53 | "typescript": "^5.5.3", 54 | "typescript-eslint": "^8.4.0", 55 | "yargs": "^17.7.2" 56 | }, 57 | "packageManager": "pnpm@9.9.0", 58 | "pnpm": { 59 | "overrides": { 60 | "codetie": "workspace:*" 61 | } 62 | }, 63 | "version": "1.0.9" 64 | } 65 | -------------------------------------------------------------------------------- /packages/codetie/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false -------------------------------------------------------------------------------- /packages/codetie/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "vueIndentScriptAndStyle": false 5 | } -------------------------------------------------------------------------------- /packages/codetie/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## (2024-09-15) 2 | 3 | * cleanup ([6592721](https://github.com/codetie-ai/codetie/commit/6592721)) 4 | * Remove node_modules from the repository ([3446486](https://github.com/codetie-ai/codetie/commit/3446486)) 5 | * update ([59fe5e7](https://github.com/codetie-ai/codetie/commit/59fe5e7)) 6 | * update packages ([7a60825](https://github.com/codetie-ai/codetie/commit/7a60825)) 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/codetie/bin/codetie.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { runMain } from '../dist/index.mjs' 4 | 5 | runMain() 6 | -------------------------------------------------------------------------------- /packages/codetie/build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild' 2 | import type { InputPluginOption } from 'rollup' 3 | 4 | export default defineBuildConfig({ 5 | declaration: true, 6 | hooks: { 7 | 'rollup:options'(_, options) { 8 | const plugins = (options.plugins ||= []) as InputPluginOption[] 9 | }, 10 | }, 11 | rollup: { 12 | inlineDependencies: true, 13 | resolve: { 14 | exportConditions: ['production', 'node'] as any, 15 | }, 16 | }, 17 | entries: ['src/index'], 18 | // externals: [ 19 | // '@nuxt/test-utils', 20 | // 'fsevents', 21 | // 'node:url', 22 | // 'node:buffer', 23 | // 'node:path', 24 | // 'node:child_process', 25 | // 'node:process', 26 | // 'node:path', 27 | // 'node:os', 28 | // ], 29 | }) 30 | -------------------------------------------------------------------------------- /packages/codetie/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codetie", 3 | "version": "1.0.9", 4 | "description": "Create iOS Apps and Games with Cursor AI & VSCode", 5 | "homepage": "https://codetie.ai", 6 | "author": "Kevin Regenrek", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/codetie-ai/codetie.git", 10 | "directory": "packages/codetie" 11 | }, 12 | "type": "module", 13 | "exports": { 14 | ".": "./dist/index.mjs", 15 | "./cli": "./bin/codetie.mjs" 16 | }, 17 | "license": "MIT", 18 | "types": "./dist/index.d.ts", 19 | "bin": { 20 | "codetie": "./bin/codetie.mjs" 21 | }, 22 | "files": [ 23 | "bin", 24 | "dist" 25 | ], 26 | "scripts": { 27 | "release": "release-it", 28 | "build": "unbuild", 29 | "codetie": "node ./bin/codetie.mjs", 30 | "play:generate": "node ./bin/codetie.mjs generate --cwd ./playground", 31 | "play:build": "node ./bin/codetie.mjs build --cwd ./playground", 32 | "play:preview": "node ./bin/codetie.mjs preview --cwd ./playground" 33 | }, 34 | "bugs": { 35 | "url": "https://github.com/codetie-ai/codetie/issues" 36 | }, 37 | "keywords": [ 38 | "codetie", 39 | "cli", 40 | "xcode", 41 | "swift", 42 | "project-setup", 43 | "cursor", 44 | "cursor-ai" 45 | ], 46 | "dependencies": { 47 | "@release-it/conventional-changelog": "^8.0.1", 48 | "c12": "^1.11.2", 49 | "citty": "^0.1.6", 50 | "consola": "^3.2.3", 51 | "destr": "^2.0.3", 52 | "execa": "^9.3.1", 53 | "jiti": "^1.21.6", 54 | "pathe": "^1.1.2", 55 | "release-it": "^17.6.0", 56 | "unbuild": "^2.0.0" 57 | }, 58 | "devDependencies": { 59 | "@types/node": "^22.5.5" 60 | }, 61 | "packageManager": "pnpm@9.11.0" 62 | } 63 | -------------------------------------------------------------------------------- /packages/codetie/playground/.gitignore: -------------------------------------------------------------------------------- 1 | *.xcodeproj/ -------------------------------------------------------------------------------- /packages/codetie/playground/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - line_length # Disable if long lines are frequently unavoidable 3 | - trailing_whitespace # Manage this rule based on team preferences 4 | - file_length # Disable for larger files like data models 5 | - cyclomatic_complexity # Disable if complex functions are unavoidable 6 | - force_cast # Be cautious but allow force casting where necessary 7 | - force_unwrapping # Allow force unwrapping for simplicity in some cases 8 | - large_tuple # Manage tuple size based on specific needs 9 | - function_body_length # Disable if longer functions are necessary 10 | - type_body_length # Disable if types naturally grow large 11 | 12 | opt_in_rules: 13 | - empty_count # Prefer `.isEmpty` over counting elements 14 | - closure_end_indentation # Align closing brackets for better readability 15 | - sorted_first_last # Use `.first` and `.last` instead of `.sorted()` 16 | - strict_fileprivate # Enforce using `fileprivate` when appropriate 17 | - redundant_nil_coalescing # Avoid unnecessary nil coalescing 18 | 19 | included: 20 | - Sources 21 | - Tests 22 | 23 | excluded: 24 | - Carthage 25 | - Pods 26 | - .build 27 | - Generated 28 | 29 | reporter: "xcode" -------------------------------------------------------------------------------- /packages/codetie/playground/codetie.yml: -------------------------------------------------------------------------------- 1 | project_name: "exampleProject" 2 | bundle_id_prefix: "com.example" 3 | deployment_target: "17.0" 4 | xcode_version: "15.3" 5 | swift_version: "5.10.1" 6 | app_version: "1.0.0" 7 | build_number: "1" -------------------------------------------------------------------------------- /packages/codetie/playground/exampleProject/ContentView.swift: -------------------------------------------------------------------------------- 1 | import Inject 2 | import SwiftUI 3 | 4 | struct ContentView: View { 5 | var body: some View { 6 | VStack { 7 | Image(systemName: "swift") 8 | .resizable() 9 | .aspectRatio(contentMode: .fit) 10 | .frame(width: 100, height: 100) 11 | .foregroundColor(.orange) 12 | 13 | Text("Hello, World!") 14 | .font(.largeTitle) 15 | .fontWeight(.bold) 16 | .padding() 17 | } 18 | .enableInjection() 19 | } 20 | @ObserveInjection var redraw 21 | } 22 | 23 | #Preview { 24 | ContentView() 25 | } 26 | -------------------------------------------------------------------------------- /packages/codetie/playground/exampleProject/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleVersion 20 | 1 21 | UIApplicationSceneManifest 22 | 23 | UIApplicationSupportsMultipleScenes 24 | 25 | 26 | UILaunchStoryboardName 27 | LaunchScreen 28 | 29 | 30 | -------------------------------------------------------------------------------- /packages/codetie/playground/exampleProject/debug.xcconfig: -------------------------------------------------------------------------------- 1 | OTHER_LDFLAGS = -Xlinker -interposable -------------------------------------------------------------------------------- /packages/codetie/playground/exampleProject/exampleProjectApp.swift: -------------------------------------------------------------------------------- 1 | @_exported import Inject 2 | import SwiftUI 3 | 4 | @main 5 | struct hotReload2App: App { 6 | var body: some Scene { 7 | WindowGroup { 8 | ContentView() 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/codetie/playground/project.yml: -------------------------------------------------------------------------------- 1 | name: exampleProject 2 | options: 3 | bundleIdPrefix: com.example 4 | deploymentTarget: 5 | iOS: 17.0 6 | xcodeVersion: "15.3" 7 | generateEmptyDirectories: true 8 | createIntermediateGroups: true 9 | 10 | targets: 11 | exampleProject: 12 | type: application 13 | platform: iOS 14 | sources: [exampleProject] 15 | settings: 16 | base: 17 | SWIFT_VERSION: 5.10.1 18 | ENABLE_TESTABILITY: YES 19 | dependencies: 20 | - package: Inject 21 | - package: HotReloading 22 | info: 23 | path: exampleProject/Info.plist 24 | properties: 25 | CFBundleShortVersionString: "1.0.0" 26 | CFBundleVersion: "1" 27 | UILaunchStoryboardName: LaunchScreen 28 | UIApplicationSceneManifest: 29 | UIApplicationSupportsMultipleScenes: true 30 | 31 | packages: 32 | Inject: 33 | url: https://github.com/krzysztofzablocki/Inject.git 34 | from: "1.2.0" 35 | HotReloading: 36 | url: https://github.com/johnno1962/HotReloading.git 37 | from: "5.0.7" 38 | 39 | schemes: 40 | exampleProject: 41 | build: 42 | targets: 43 | exampleProject: all 44 | run: 45 | config: Debug 46 | 47 | configFiles: 48 | Debug: exampleProject/debug.xcconfig 49 | 50 | configs: 51 | Debug: debug 52 | Release: release 53 | -------------------------------------------------------------------------------- /packages/codetie/src/commands/build.ts: -------------------------------------------------------------------------------- 1 | import { defineCommand } from "citty"; 2 | import { resolve, } from 'pathe' 3 | import { exists } from '../utils/fs' 4 | import { consola } from 'consola' 5 | import { loadConfig } from "c12"; 6 | import {$} from 'execa'; 7 | 8 | export default defineCommand({ 9 | meta: { 10 | name: "build", 11 | description: "Build the project", 12 | }, 13 | args: { 14 | cwd: { 15 | type: 'string', 16 | description: 'The directory to build the project in', 17 | } 18 | }, 19 | async run(ctx) { 20 | const argsCwd = typeof ctx.args.cwd === 'boolean' ? undefined : ctx.args.cwd 21 | const cwd = resolve(argsCwd || '.') 22 | const configName = 'codetie.yml' 23 | const projectConfigPath = resolve(cwd, configName) 24 | 25 | if (!(await exists(projectConfigPath))) { 26 | consola.error(`Project config ${configName} not found`) 27 | process.exit(1) 28 | } 29 | 30 | const { config } = await loadConfig({ cwd, configFile: configName }) 31 | 32 | if (!await exists(resolve(cwd, `${config.project_name}.xcodeproj/project.pbxproj`))) { 33 | consola.error(`${config.project_name}.xcodeproj/project.pbxproj not found. Run 'codetie generate' to generate the project first.`) 34 | process.exit(1) 35 | } 36 | 37 | consola.start(`Building ${config.project_name} for iOS Simulator...`) 38 | 39 | const simulator_name = "iPhone 15 Pro"; 40 | const simulator_os = "17.0"; 41 | const build_dir = resolve(cwd, 'build') 42 | 43 | try { 44 | await $(`xcodebuild -project ${config.project_name}.xcodeproj -scheme ${config.project_name} -configuration Debug -destination "platform=iOS Simulator,name=${ simulator_name },OS=${ simulator_os }" -derivedDataPath ${ build_dir }`, [], { cwd, shell: true }) 45 | const appPath = resolve(cwd, `build/Build/Products/Debug-iphonesimulator/${config.project_name}.app`) 46 | if (!(await exists(appPath))) { 47 | throw new Error(`App bundle not found at expected location: ${appPath}`) 48 | } 49 | consola.success(`${config.project_name} built successfully!`) 50 | } catch (error) { 51 | consola.error(error) 52 | process.exit(1) 53 | } 54 | } 55 | }) -------------------------------------------------------------------------------- /packages/codetie/src/commands/generate.ts: -------------------------------------------------------------------------------- 1 | import { defineCommand } from 'citty' 2 | import { resolve } from 'pathe' 3 | import { consola } from 'consola' 4 | import { $ } from 'execa' 5 | 6 | export default defineCommand({ 7 | meta: { 8 | name: 'generate', 9 | description: 'Generate the project', 10 | }, 11 | args: { 12 | cwd: { 13 | type: 'string', 14 | description: 'The directory to generate the project in', 15 | }, 16 | }, 17 | async run(ctx) { 18 | const argsCwd = typeof ctx.args.cwd === 'boolean' ? undefined : ctx.args.cwd 19 | const cwd = resolve(argsCwd || '.') 20 | 21 | try { 22 | const { stdout } = await $`command -v xcodegen &> /dev/null` 23 | if (!stdout) { 24 | throw new Error() 25 | } 26 | } catch (error) { 27 | consola.error( 28 | 'Error: XcodeGen is not installed. Please install XcodeGen before running this script.' 29 | ) 30 | consola.box( 31 | 'You can install XcodeGen using Homebrew:\n\nbrew install xcodegen' 32 | ) 33 | process.exit(1) 34 | } 35 | 36 | consola.start('Generating Xcode project using XcodeGen...') 37 | 38 | try { 39 | await $(`xcodegen generate`, [], { cwd, shell: true }) 40 | consola.success('Xcode project generated successfully.') 41 | } catch (error) { 42 | consola.error(error) 43 | process.exit(1) 44 | } 45 | }, 46 | }) 47 | -------------------------------------------------------------------------------- /packages/codetie/src/commands/index.ts: -------------------------------------------------------------------------------- 1 | import type { CommandDef } from 'citty' 2 | 3 | const _rDefault = (r: any) => (r.default || r) as Promise 4 | 5 | export const commands = { 6 | build: () => import('./build').then(_rDefault), 7 | generate: () => import('./generate').then(_rDefault), 8 | preview: () => import('./preview').then(_rDefault), 9 | } as const 10 | -------------------------------------------------------------------------------- /packages/codetie/src/commands/preview.ts: -------------------------------------------------------------------------------- 1 | import { defineCommand } from 'citty' 2 | import { resolve } from 'pathe' 3 | import { exists } from '../utils/fs' 4 | import { consola } from 'consola' 5 | import { loadConfig } from 'c12' 6 | import { $ } from 'execa' 7 | import { destr } from 'destr' 8 | 9 | interface ISimulator { 10 | dataPath: string 11 | dataPathSize: number 12 | logPath: string 13 | udid: string 14 | isAvailable: boolean 15 | name: string 16 | deviceTypeIdentifier: string 17 | state: string 18 | } 19 | 20 | export default defineCommand({ 21 | meta: { 22 | name: 'preview', 23 | description: 'Preview the project', 24 | }, 25 | args: { 26 | cwd: { 27 | type: 'string', 28 | description: 'The directory to preview the project from', 29 | }, 30 | }, 31 | async run(ctx) { 32 | const argsCwd = typeof ctx.args.cwd === 'boolean' ? undefined : ctx.args.cwd 33 | const cwd = resolve(argsCwd || '.') 34 | const configName = 'codetie.yml' 35 | const projectConfigPath = resolve(cwd, configName) 36 | 37 | try { 38 | if (!(await exists(projectConfigPath))) { 39 | consola.error(`Project config ${configName} not found`) 40 | process.exit(1) 41 | } 42 | 43 | const { config } = await loadConfig({ cwd, configFile: configName }) 44 | const appPath = resolve( 45 | cwd, 46 | `build/Build/Products/Debug-iphonesimulator/${config.project_name}.app` 47 | ) 48 | 49 | if (!(await exists(appPath))) { 50 | throw new Error(`App bundle not found at expected location: ${appPath}`) 51 | } 52 | 53 | // Get the list of installed iOS simulators 54 | const { stdout } = await $( 55 | `xcrun simctl list devices available --json`, 56 | [], 57 | { shell: true } 58 | ) 59 | // .pipe(`jq '.devices[] | .[]'`, [], { shell: true}) 60 | const deviceObject = destr<{ devices: { [key: string]: ISimulator[] } }>( 61 | `${stdout}` 62 | ) 63 | const simulators = Object.values(deviceObject.devices).flat() 64 | 65 | if (simulators.length === 0) { 66 | throw new Error('No iOS simulators found.') 67 | } 68 | 69 | const selectedSimulator = await consola.prompt( 70 | 'Select an iOS simulator to start:', 71 | { 72 | type: 'select', 73 | required: true, 74 | options: simulators.map((simulator) => simulator.name), 75 | } 76 | ) 77 | 78 | if (typeof selectedSimulator === 'string') { 79 | process.exit(1) 80 | } 81 | 82 | const simulatorId = ( 83 | simulators.find( 84 | (simulator) => simulator.name === selectedSimulator 85 | ) as ISimulator 86 | ).udid 87 | 88 | consola.box( 89 | [ 90 | `Using the following settings:\n`, 91 | `Simulator: ${selectedSimulator}`, 92 | `Simulator ID: ${simulatorId}`, 93 | `Project Name: ${config.project_name}`, 94 | `App Bundle ID: ${config.bundle_id_prefix}.${config.project_name}`, 95 | `App Path: ${appPath}`, 96 | ].join('\n') 97 | ) 98 | 99 | consola.start(`Starting simulator: ${selectedSimulator}`) 100 | 101 | consola.info('Booting simulator...') 102 | await $(`xcrun simctl boot "${simulatorId}"`, [], { shell: true }) 103 | 104 | consola.info('Waiting for simulator to boot...') 105 | while ( 106 | ( 107 | await $( 108 | `xcrun simctl list devices | grep "${simulatorId}" | grep -o "Booted"`, 109 | [], 110 | { shell: true } 111 | ) 112 | ).stdout.trim() !== 'Booted' 113 | ) { 114 | await new Promise((resolve) => setTimeout(resolve, 1000)) 115 | } 116 | 117 | consola.info('Opening Simulator...') 118 | await $(`open -a Simulator`, [], { shell: true }) 119 | 120 | consola.info('Installing app...') 121 | await $(`xcrun simctl install booted "${appPath}"`, [], { shell: true }) 122 | 123 | consola.info('Launching app...') 124 | await $( 125 | `xcrun simctl launch booted "${config.bundle_id_prefix}.${config.project_name}"`, 126 | [], 127 | { shell: true } 128 | ) 129 | 130 | consola.success('Done!') 131 | } catch (error) { 132 | consola.error(error) 133 | } 134 | }, 135 | }) 136 | -------------------------------------------------------------------------------- /packages/codetie/src/index.ts: -------------------------------------------------------------------------------- 1 | export { main } from './main' 2 | export { runCommand, runMain } from './run' 3 | -------------------------------------------------------------------------------- /packages/codetie/src/main.ts: -------------------------------------------------------------------------------- 1 | import { defineCommand } from 'citty' 2 | import codetiePkg from '../package.json' assert { type: 'json' } 3 | import { commands } from './commands' 4 | 5 | export const main = defineCommand({ 6 | meta: { 7 | name: codetiePkg.name, 8 | version: codetiePkg.version, 9 | description: codetiePkg.description, 10 | }, 11 | subCommands: commands, 12 | }) as any 13 | -------------------------------------------------------------------------------- /packages/codetie/src/run.ts: -------------------------------------------------------------------------------- 1 | import { runCommand as _runCommand, runMain as _runMain } from 'citty' 2 | 3 | import { commands } from './commands' 4 | import { main } from './main' 5 | 6 | export const runMain = () => _runMain(main) 7 | 8 | export async function runCommand( 9 | name: string, 10 | argv: string[] = process.argv.slice(2), 11 | data: { overrides?: Record } = {} 12 | ) { 13 | if (!(name in commands)) { 14 | throw new Error(`Invalid command ${name}`) 15 | } 16 | 17 | return await _runCommand(await commands[name as keyof typeof commands](), { 18 | rawArgs: argv, 19 | data: { 20 | overrides: data.overrides || {}, 21 | }, 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /packages/codetie/src/utils/fs.ts: -------------------------------------------------------------------------------- 1 | import { promises as fsp } from 'node:fs' 2 | 3 | // Check if a file exists 4 | export async function exists(path: string) { 5 | try { 6 | await fsp.access(path) 7 | return true 8 | } 9 | catch { 10 | return false 11 | } 12 | } -------------------------------------------------------------------------------- /packages/codetie/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": false, 4 | "allowSyntheticDefaultImports": true, 5 | "skipLibCheck": true, 6 | "target": "ESNext", 7 | "module": "ESNext", 8 | "moduleResolution": "Node", 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "allowJs": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "resolveJsonModule": true, 15 | "types": [ 16 | "node", 17 | "./types" 18 | ], 19 | }, 20 | "include": [ 21 | "src" 22 | ] 23 | } -------------------------------------------------------------------------------- /packages/codetie/types.d.ts: -------------------------------------------------------------------------------- 1 | export {} -------------------------------------------------------------------------------- /packages/create-codetie/.gitignore: -------------------------------------------------------------------------------- 1 | playground/ -------------------------------------------------------------------------------- /packages/create-codetie/__buildServer.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "xcode", 3 | "project": "fresh1.xcodeproj", 4 | "scheme": "com.fresh1", 5 | "configuration": "Debug", 6 | "sdk": "iphonesimulator", 7 | "destination": { 8 | "platform": "iOS Simulator", 9 | "name": "iPhone 15 Pro", 10 | "OS": "17.0" 11 | }, 12 | "build_root": "/Users/kevin/projects/swift/testing-codetie/build", 13 | "build_args": [ 14 | "ONLY_ACTIVE_ARCH=YES", 15 | "DEVELOPMENT_TEAM=", 16 | "CODE_SIGN_IDENTITY=", 17 | "CODE_SIGNING_REQUIRED=NO", 18 | "CODE_SIGNING_ALLOWED=NO" 19 | ], 20 | "actions": [ 21 | "clean", 22 | "build" 23 | ] 24 | } -------------------------------------------------------------------------------- /packages/create-codetie/build.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'node:path' 2 | import url from 'node:url' 3 | import { defineBuildConfig } from 'unbuild' 4 | 5 | const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) 6 | 7 | export default defineBuildConfig({ 8 | entries: ['src/index'], 9 | clean: true, 10 | rollup: { 11 | inlineDependencies: true, 12 | esbuild: { 13 | target: 'node18', 14 | minify: true, 15 | }, 16 | }, 17 | // alias: { 18 | // we can always use non-transpiled code since we support node 18+ 19 | // prompts: 'prompts/lib/index.js', 20 | // }, 21 | hooks: { 22 | 'rollup:options'(_ctx, options) { 23 | options.plugins = [ 24 | options.plugins 25 | ] 26 | }, 27 | }, 28 | }) -------------------------------------------------------------------------------- /packages/create-codetie/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import './dist/index.mjs' -------------------------------------------------------------------------------- /packages/create-codetie/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-codetie", 3 | "version": "1.0.9", 4 | "description": "Create a new codetie project", 5 | "main": "index.js", 6 | "bin": { 7 | "create-codetie": "index.js" 8 | }, 9 | "type": "module", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/codetie-ai/codetie.git", 13 | "directory": "packages/create-codetie" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/codetie-ai/codetie/issues" 17 | }, 18 | "license": "MIT", 19 | "scripts": { 20 | "create": "tsx src/index.ts", 21 | "play:clean": "rm -rf playground", 22 | "dev": "unbuild --stub", 23 | "build": "unbuild", 24 | "typecheck": "tsc --noEmit", 25 | "prepublishOnly": "npm run build" 26 | }, 27 | "keywords": [ 28 | "codetie", 29 | "cli", 30 | "xcode", 31 | "swift", 32 | "project-setup", 33 | "cursor", 34 | "cursor-ai" 35 | ], 36 | "dependencies": { 37 | "@types/fs-extra": "^11.0.4", 38 | "@types/mustache": "^4.2.5", 39 | "citty": "^0.1.6", 40 | "codetie": "^1.0.8", 41 | "consola": "^3.2.3", 42 | "fs-extra": "^11.2.0", 43 | "mustache": "^4.2.0", 44 | "pathe": "^1.1.2", 45 | "scule": "^1.3.0", 46 | "unbuild": "^2.0.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/create-codetie/src/index.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import { runMain, defineCommand } from "citty"; 3 | import { consola } from "consola"; 4 | import { resolve, dirname } from "pathe"; 5 | import { fileURLToPath } from "node:url"; 6 | import { 7 | exists, 8 | mkDir, 9 | isEmpty, 10 | readDir, 11 | writeFile, 12 | readFile, 13 | copyFile, 14 | rename, 15 | deleteFile, 16 | } from "./utils/fs"; 17 | import { initPrompts, installDependenciesPrompts } from "./prompts"; 18 | import Mustache from "mustache"; 19 | 20 | const __filename = fileURLToPath(import.meta.url); 21 | const __dirname = dirname(__filename); 22 | const templateDir = resolve(__dirname, "../template"); 23 | 24 | const renameFiles: Record = { 25 | _gitignore: ".gitignore", 26 | }; 27 | 28 | const main = defineCommand({ 29 | args: { 30 | cwd: { 31 | type: "string", 32 | description: "The directory to create the project in", 33 | }, 34 | }, 35 | async run(ctx) { 36 | consola.log(templateDir); 37 | const argsCwd = 38 | ctx.args._[0] ?? (typeof ctx.args.cwd === "string" ? ctx.args.cwd : "."); 39 | const cwd = resolve(argsCwd); 40 | 41 | try { 42 | // 1. prompts 43 | const { 44 | projectName, 45 | bundleIdPrefix, 46 | deploymentTarget, 47 | xcodeVersion, 48 | swiftVersion, 49 | appVersion, 50 | buildNumber, 51 | } = await initPrompts(); 52 | 53 | // 2. check if cwd is empty 54 | const root = resolve(cwd, projectName); 55 | if (exists(root)) { 56 | if (!isEmpty(root)) { 57 | throw new Error( 58 | `Directory ${root} is not empty. Please choose a different directory or empty it.` 59 | ); 60 | } 61 | } else { 62 | mkDir(root); 63 | } 64 | 65 | // 3. copy template 66 | const templateVariables = { 67 | PROJECT_NAME: projectName, 68 | BUNDLE_ID_PREFIX: bundleIdPrefix, 69 | DEPLOYMENT_TARGET: deploymentTarget, 70 | XCODE_VERSION: xcodeVersion, 71 | SWIFT_VERSION: swiftVersion, 72 | APP_VERSION: appVersion, 73 | BUILD_NUMBER: buildNumber, 74 | }; 75 | 76 | const files = readDir(templateDir); 77 | for (const file of files) { 78 | const srcPath = resolve(file.path, file.name); 79 | const targetParentPath = resolve( 80 | root, 81 | file.path.replace(new RegExp(`^${templateDir}\\/?`, "g"), "") 82 | ); 83 | const destPath = resolve( 84 | targetParentPath, 85 | renameFiles[file.name] ?? file.name 86 | ); 87 | const stat = fs.statSync(srcPath); 88 | if (stat.isDirectory()) { 89 | mkDir(destPath); 90 | } else if (file.name.endsWith(".mustache")) { 91 | if (exists(srcPath)) { 92 | const content = readFile(srcPath); 93 | const rendered = Mustache.render(content, templateVariables); 94 | writeFile(destPath.replace(/\.mustache$/g, ""), rendered); 95 | } 96 | } else { 97 | copyFile(srcPath, destPath); 98 | } 99 | } 100 | // 4. rename project entry file and content 101 | const oldMainSwift = resolve(root, "_project", "_main.swift"); 102 | const newMainSwift = resolve(root, "_project", `${projectName}App.swift`); 103 | if (exists(oldMainSwift)) { 104 | const content = readFile(oldMainSwift).replace( 105 | "HelloWorldApp", 106 | `${projectName}App` 107 | ); 108 | writeFile(newMainSwift, content); 109 | deleteFile(oldMainSwift); 110 | } 111 | // 5. rename _project folder 112 | rename(resolve(root, "_project"), resolve(root, projectName)); 113 | 114 | // 6. generate codetie.yml 115 | const codetieConfig = { 116 | project_name: projectName, 117 | bundle_id_prefix: bundleIdPrefix, 118 | deployment_target: deploymentTarget, 119 | xcode_version: xcodeVersion, 120 | swift_version: swiftVersion, 121 | app_version: appVersion, 122 | build_number: buildNumber, 123 | }; 124 | writeFile( 125 | resolve(root, "codetie.yml"), 126 | JSON.stringify(codetieConfig, null, 2) 127 | ); 128 | 129 | // 6. install dependencies 130 | await installDependenciesPrompts(root); 131 | 132 | consola.box("Project setup complete! Happy coding! 🎈"); 133 | } catch (error) { 134 | consola.error(error); 135 | process.exit(1); 136 | } 137 | }, 138 | }); 139 | 140 | runMain(main); 141 | -------------------------------------------------------------------------------- /packages/create-codetie/src/prompts/index.ts: -------------------------------------------------------------------------------- 1 | export { initPrompts } from "./init"; 2 | export { installDependenciesPrompts } from "./installDependencies"; 3 | -------------------------------------------------------------------------------- /packages/create-codetie/src/prompts/init.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "consola"; 2 | import { camelCase } from "scule"; 3 | 4 | async function prompt( 5 | message: string, 6 | options: any, 7 | required: boolean = true, 8 | errorMessage: string = "Field is required" 9 | ) { 10 | const result = await consola.prompt(message, options); 11 | if (typeof result === "symbol") { 12 | process.exit(1); 13 | } 14 | if (required && (result || "").trim().length === 0) { 15 | throw new Error(errorMessage); 16 | } 17 | return (result || "").trim(); 18 | } 19 | 20 | export async function initPrompts() { 21 | const projectName = camelCase( 22 | (await prompt( 23 | "Enter project name:", 24 | { type: "text", placeholder: "codetieProject" }, 25 | true, 26 | "Project name is required" 27 | )) || "codetieProject" 28 | ); 29 | const bundleIdPrefix = 30 | (await prompt( 31 | "Enter Bundle ID Prefix:", 32 | { type: "text", placeholder: "com.example" }, 33 | false, 34 | "Bundle ID Prefix is required" 35 | )) || "com.example"; 36 | const deploymentTarget = 37 | (await prompt( 38 | "Enter Deployment Target iOS Version:", 39 | { type: "text", placeholder: "17.0" }, 40 | false, 41 | "Deployment Target is required" 42 | )) || "17.0"; 43 | const xcodeVersion = 44 | (await prompt( 45 | "Enter Xcode Version:", 46 | { type: "text", placeholder: "15.3" }, 47 | false, 48 | "Xcode Version is required" 49 | )) || "15.3"; 50 | const swiftVersion = 51 | (await prompt( 52 | "Enter Swift Version:", 53 | { type: "text", placeholder: "5.10.1" }, 54 | false, 55 | "Swift Version is required" 56 | )) || "5.10.1"; 57 | const appVersion = 58 | (await prompt( 59 | "Enter App Version:", 60 | { type: "text", placeholder: "1.0.0" }, 61 | false, 62 | "App Version is required" 63 | )) || "1.0.0"; 64 | const buildNumber = 65 | (await prompt( 66 | "Enter Build Number:", 67 | { type: "text", placeholder: "1" }, 68 | false, 69 | "Build Number is required" 70 | )) || "1"; 71 | return { 72 | projectName, 73 | bundleIdPrefix, 74 | deploymentTarget, 75 | xcodeVersion, 76 | swiftVersion, 77 | appVersion, 78 | buildNumber, 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /packages/create-codetie/src/prompts/installDependencies.ts: -------------------------------------------------------------------------------- 1 | import { consola } from "consola"; 2 | import { runCommand } from "codetie"; 3 | 4 | export async function installDependenciesPrompts(cwd: string) { 5 | const generateProject = await consola.prompt( 6 | "Do you want to generate the Xcode project now?", 7 | { 8 | type: "confirm", 9 | } 10 | ); 11 | if (typeof generateProject === "symbol") { 12 | process.exit(1); 13 | } 14 | if (generateProject) { 15 | await runCommand("generate", ["", "", "--cwd", cwd]); 16 | 17 | const startSimulator = await consola.prompt( 18 | "Do you want to start the project with the simulator now?", 19 | { 20 | type: "confirm", 21 | } 22 | ); 23 | if (typeof startSimulator === "symbol") { 24 | process.exit(1); 25 | } 26 | if (startSimulator) { 27 | await runCommand("build", ["", "", "--cwd", cwd]); 28 | await runCommand("preview", ["", "", "--cwd", cwd]); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/create-codetie/src/utils/fs.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import { resolve } from "pathe"; 3 | 4 | export function exists(path: string) { 5 | return fs.existsSync(path); 6 | } 7 | 8 | export function isEmpty(path: string) { 9 | return fs.readdirSync(path).length === 0; 10 | } 11 | 12 | export function mkDir(path: string) { 13 | return fs.mkdirSync(path, { recursive: true }); 14 | } 15 | 16 | export function readDir(path: string) { 17 | return fs.readdirSync(path, { withFileTypes: true, recursive: true }); 18 | } 19 | 20 | export function copyDir(src: string, dest: string) { 21 | mkDir(dest); 22 | for (const file of fs.readdirSync(src)) { 23 | const srcFile = resolve(src, file); 24 | const destFile = resolve(dest, file); 25 | copy(srcFile, destFile); 26 | } 27 | } 28 | 29 | export function writeFile(path: string, content: string) { 30 | const destDir = resolve(path, ".."); 31 | fs.ensureDirSync(destDir); 32 | fs.writeFileSync(path, content); 33 | } 34 | 35 | export function copyFile(src: string, dest: string) { 36 | const destDir = resolve(dest, ".."); 37 | fs.ensureDirSync(destDir); 38 | fs.copyFileSync(src, dest); 39 | } 40 | 41 | export function copy(src: string, dest: string) { 42 | const stat = fs.statSync(src); 43 | if (stat.isDirectory()) { 44 | copyDir(src, dest); 45 | } else { 46 | copyFile(src, dest); 47 | } 48 | } 49 | 50 | export function readFile(path: string) { 51 | return fs.readFileSync(path, "utf-8"); 52 | } 53 | 54 | export function rename(oldPath: string, newPath: string) { 55 | return fs.renameSync(oldPath, newPath); 56 | } 57 | 58 | export function deleteFile(path: string) { 59 | return fs.unlinkSync(path); 60 | } 61 | 62 | export function deleteDir(path: string) { 63 | return fs.rmdirSync(path); 64 | } 65 | -------------------------------------------------------------------------------- /packages/create-codetie/template/.cursorrules: -------------------------------------------------------------------------------- 1 | you are an expert in coding with swift, swift ui. you always write maintainable code and clean code. 2 | focus on latest august, september 2024 version of the documentation and features. 3 | 4 | SwiftUIProject structure: 5 | All code is placed in the "MyZunderApp" folder. This folder includes all main entry files like App.swift, AppConfig.swift, the we have a "Views" group with different views, "Shared" for reusable components and modifiers. It includes "Models" for data models, "Services" with "Network" for networking and "Persistence" for data storage, and "Utils" for extensions, constants, and helpers. The "Resources" folder holds "Assets" for images and colors, "Localization" for localized strings, and "Fonts" for custom fonts. Lastly, the "Tests" folder includes "UnitTests" for unit testing and "UITests" for UI testing. 6 | 7 | GENERAL RULES: 8 | - your descriptions should be short and concise. 9 | - don't remove any comments. 10 | 11 | SWIFTUI DESIGN RULES: 12 | - Use Built-in Components: Utilize SwiftUI's native UI elements like List, NavigationView, TabView, and SF Symbols for a polished, iOS-consistent look. 13 | - Master Layout Tools: Employ VStack, HStack, ZStack, Spacer, and Padding for responsive designs; use LazyVGrid and LazyHGrid for grids; GeometryReader for dynamic layouts. 14 | - Add Visual Flair: Enhance UIs with shadows, gradients, blurs, custom shapes, and animations using the .animation() modifier for smooth transitions. 15 | Design for Interaction: Incorporate gestures (swipes, long presses), haptic feedback, clear navigation, and responsive elements to improve user engagement and satisfaction. -------------------------------------------------------------------------------- /packages/create-codetie/template/.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - line_length # Disable if long lines are frequently unavoidable 3 | - trailing_whitespace # Manage this rule based on team preferences 4 | - file_length # Disable for larger files like data models 5 | - cyclomatic_complexity # Disable if complex functions are unavoidable 6 | - force_cast # Be cautious but allow force casting where necessary 7 | - force_unwrapping # Allow force unwrapping for simplicity in some cases 8 | - large_tuple # Manage tuple size based on specific needs 9 | - function_body_length # Disable if longer functions are necessary 10 | - type_body_length # Disable if types naturally grow large 11 | 12 | opt_in_rules: 13 | - empty_count # Prefer `.isEmpty` over counting elements 14 | - closure_end_indentation # Align closing brackets for better readability 15 | - sorted_first_last # Use `.first` and `.last` instead of `.sorted()` 16 | - strict_fileprivate # Enforce using `fileprivate` when appropriate 17 | - redundant_nil_coalescing # Avoid unnecessary nil coalescing 18 | 19 | included: 20 | - Sources 21 | - Tests 22 | 23 | excluded: 24 | - Carthage 25 | - Pods 26 | - .build 27 | - Generated 28 | 29 | reporter: "xcode" -------------------------------------------------------------------------------- /packages/create-codetie/template/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "sswg.swift-lang", 4 | "vknabel.vscode-swiftlint" 5 | ] 6 | } -------------------------------------------------------------------------------- /packages/create-codetie/template/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll": "explicit" 4 | }, 5 | "[swift]": { 6 | "editor.defaultFormatter": "vknabel.vscode-swiftlint" 7 | }, 8 | "swiftlint.enable": true, 9 | "swiftlint.configSearchPaths": [ 10 | "./.swiftlint.yml" 11 | ] 12 | } -------------------------------------------------------------------------------- /packages/create-codetie/template/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Generate project", 6 | "type": "shell", 7 | "command": "npx codetie generate", 8 | "problemMatcher": [] 9 | }, 10 | { 11 | "label": "Build project", 12 | "type": "shell", 13 | "command": "npx codetie build", 14 | "problemMatcher": [] 15 | }, 16 | { 17 | "label": "Preview project", 18 | "type": "shell", 19 | "command": "npx codetie preview", 20 | "problemMatcher": [] 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /packages/create-codetie/template/README.md: -------------------------------------------------------------------------------- 1 | # Codetie Starter 2 | 3 | This is a starter template for creating iOS apps and games with Cursor AI & VSCode. 4 | -------------------------------------------------------------------------------- /packages/create-codetie/template/_gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | ## User settings 5 | xcuserdata/ 6 | 7 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 8 | *.xcscmblueprint 9 | *.xccheckout 10 | 11 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 12 | build/ 13 | DerivedData/ 14 | *.moved-aside 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | 27 | ## App packaging 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | # Package.pins 41 | # Package.resolved 42 | # *.xcodeproj 43 | # 44 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 45 | # hence it is not needed unless you have added a package configuration file to your project 46 | # .swiftpm 47 | 48 | .build/ 49 | 50 | # CocoaPods 51 | # 52 | # We recommend against adding the Pods directory to your .gitignore. However 53 | # you should judge for yourself, the pros and cons are mentioned at: 54 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 55 | # 56 | # Pods/ 57 | # 58 | # Add this line if you want to avoid checking in source code from the Xcode workspace 59 | # *.xcworkspace 60 | 61 | # Carthage 62 | # 63 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 64 | # Carthage/Checkouts 65 | 66 | Carthage/Build/ 67 | 68 | # Accio dependency management 69 | Dependencies/ 70 | .accio/ 71 | 72 | # fastlane 73 | # 74 | # It is recommended to not store the screenshots in the git repo. 75 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 76 | # For more information about the recommended setup visit: 77 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 78 | 79 | fastlane/report.xml 80 | fastlane/Preview.html 81 | fastlane/screenshots/**/*.png 82 | fastlane/test_output 83 | 84 | # Code Injection 85 | # 86 | # After new code Injection tools there's a generated folder /iOSInjectionProject 87 | # https://github.com/johnno1962/injectionforxcode 88 | 89 | iOSInjectionProject/ 90 | 91 | # macOS 92 | .DS_Store 93 | 94 | # SwiftUI Preview Content 95 | **/Preview Content 96 | 97 | 98 | node_modules 99 | dist 100 | .DS_Store 101 | .history 102 | .vercel 103 | .idea 104 | .env 105 | .data 106 | -------------------------------------------------------------------------------- /packages/create-codetie/template/_project/ContentView.swift: -------------------------------------------------------------------------------- 1 | import Inject 2 | import SwiftUI 3 | 4 | struct ContentView: View { 5 | var body: some View { 6 | VStack { 7 | Image(systemName: "swift") 8 | .resizable() 9 | .aspectRatio(contentMode: .fit) 10 | .frame(width: 100, height: 100) 11 | .foregroundColor(.orange) 12 | 13 | Text("Hello, World!") 14 | .font(.largeTitle) 15 | .fontWeight(.bold) 16 | .padding() 17 | } 18 | .enableInjection() 19 | } 20 | @ObserveInjection var redraw 21 | } 22 | 23 | #Preview { 24 | ContentView() 25 | } 26 | -------------------------------------------------------------------------------- /packages/create-codetie/template/_project/_main.swift: -------------------------------------------------------------------------------- 1 | @_exported import Inject 2 | import SwiftUI 3 | 4 | @main 5 | struct HelloWorldApp: App { 6 | var body: some Scene { 7 | WindowGroup { 8 | ContentView() 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/create-codetie/template/_project/debug.xcconfig: -------------------------------------------------------------------------------- 1 | OTHER_LDFLAGS = -Xlinker -interposable -------------------------------------------------------------------------------- /packages/create-codetie/template/project.yml.mustache: -------------------------------------------------------------------------------- 1 | name: {{PROJECT_NAME}} 2 | options: 3 | bundleIdPrefix: {{BUNDLE_ID_PREFIX}} 4 | deploymentTarget: 5 | iOS: {{DEPLOYMENT_TARGET}} 6 | xcodeVersion: "{{XCODE_VERSION}}" 7 | generateEmptyDirectories: true 8 | createIntermediateGroups: true 9 | 10 | targets: 11 | {{PROJECT_NAME}}: 12 | type: application 13 | platform: iOS 14 | sources: [{{PROJECT_NAME}}] 15 | settings: 16 | base: 17 | SWIFT_VERSION: {{SWIFT_VERSION}} 18 | ENABLE_TESTABILITY: YES 19 | dependencies: 20 | - package: Inject 21 | info: 22 | path: {{PROJECT_NAME}}/Info.plist 23 | properties: 24 | CFBundleShortVersionString: "{{APP_VERSION}}" 25 | CFBundleVersion: "{{BUILD_NUMBER}}" 26 | UILaunchStoryboardName: LaunchScreen 27 | UIApplicationSceneManifest: 28 | UIApplicationSupportsMultipleScenes: true 29 | 30 | packages: 31 | Inject: 32 | url: https://github.com/krzysztofzablocki/Inject.git 33 | from: "1.2.0" 34 | 35 | schemes: 36 | {{PROJECT_NAME}}: 37 | build: 38 | targets: 39 | {{PROJECT_NAME}}: all 40 | run: 41 | config: Debug 42 | 43 | configFiles: 44 | Debug: {{PROJECT_NAME}}/debug.xcconfig 45 | 46 | configs: 47 | Debug: debug 48 | Release: release -------------------------------------------------------------------------------- /packages/create-codetie/template/scripts/build_project.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get the project name from the first argument 4 | PROJECT_NAME=$1 5 | 6 | # Remove .xcodeproj extension if present 7 | PROJECT_NAME=${PROJECT_NAME%.xcodeproj} 8 | 9 | # Set the output directory 10 | BUILD_DIR="$(pwd)/build" 11 | 12 | # Set simulator details 13 | SIMULATOR_NAME="iPhone 15 Pro" 14 | SIMULATOR_OS="17.0" # Updated to a more likely iOS version 15 | 16 | # Get the latest iOS runtime 17 | RUNTIME=$(xcrun simctl list runtimes | grep iOS | tail -1 | awk '{print $NF}') 18 | 19 | # Get the device type 20 | DEVICE_TYPE=$(xcrun simctl list devicetypes | grep "$DEVICE" | tail -1 | awk '{print $NF}') 21 | 22 | if [ -z "$RUNTIME" ] || [ -z "$DEVICE_TYPE" ]; then 23 | echo "Could not determine runtime or device type for $DEVICE" 24 | exit 1 25 | fi 26 | 27 | # Ensure the project file exists 28 | if [ ! -f "${PROJECT_NAME}.xcodeproj/project.pbxproj" ]; then 29 | echo "Error: ${PROJECT_NAME}.xcodeproj not found in the current directory." 30 | exit 1 31 | fi 32 | 33 | 34 | # Check if the simulator already exists 35 | if ! xcrun simctl list devices | grep -q "$SIMULATOR_NAME"; then 36 | echo "Creating $SIMULATOR_NAME simulator..." 37 | xcrun simctl create "$SIMULATOR_NAME" "$SIMULATOR_NAME" "$RUNTIME" 38 | else 39 | echo "$SIMULATOR_NAME simulator already exists." 40 | fi 41 | 42 | # Build the project for iOS Simulator 43 | # echo "Building ${PROJECT_NAME} for iOS Simulator..." 44 | # xcodebuild -project "${PROJECT_NAME}.xcodeproj" -scheme "${PROJECT_NAME}" \ 45 | # -configuration Debug \ 46 | # -sdk iphonesimulator \ 47 | # -destination "platform=iOS Simulator,name=${SIMULATOR_NAME},OS=${SIMULATOR_OS}" \ 48 | # -derivedDataPath "${BUILD_DIR}" \ 49 | # -allowProvisioningUpdates \ 50 | # CODE_SIGN_STYLE=Automatic \ 51 | # DEVELOPMENT_TEAM="3G79D9D34R" \ 52 | # clean build 53 | 54 | xcodebuild -project "${PROJECT_NAME}.xcodeproj" -scheme "${PROJECT_NAME}" \ 55 | -configuration Debug \ 56 | -destination "platform=iOS Simulator,name=${SIMULATOR_NAME}" \ 57 | -derivedDataPath "${BUILD_DIR}" \ 58 | ONLY_ACTIVE_ARCH=YES \ 59 | CODE_SIGN_IDENTITY="" \ 60 | CODE_SIGNING_REQUIRED=NO \ 61 | CODE_SIGNING_ALLOWED=NO \ 62 | clean build 63 | 64 | # xcodebuild -project "${PROJECT_NAME}.xcodeproj" -scheme "${PROJECT_NAME}" \ 65 | # -configuration Debug \ 66 | # -destination "platform=iOS Simulator,name=${SIMULATOR_NAME},OS=${SIMULATOR_OS}" \ 67 | # -derivedDataPath "${BUILD_DIR}" \ 68 | # ONLY_ACTIVE_ARCH=YES \ 69 | # CODE_SIGN_IDENTITY="" \ 70 | # CODE_SIGNING_REQUIRED=NO \ 71 | # CODE_SIGNING_ALLOWED=NO \ 72 | # clean build 73 | 74 | # xcodebuild -project "${PROJECT_NAME}.xcodeproj" -scheme "${PROJECT_NAME}" \ 75 | # -configuration Debug \ 76 | # -destination "platform=iOS Simulator,name=iPhone 14,OS=latest" \ 77 | # -derivedDataPath "${BUILD_DIR}" \ 78 | # -verbose \ 79 | # ONLY_ACTIVE_ARCH=YES \ 80 | # DEVELOPMENT_TEAM="" \ 81 | # CODE_SIGN_IDENTITY="" \ 82 | # CODE_SIGNING_REQUIRED=NO \ 83 | # CODE_SIGNING_ALLOWED=NO \ 84 | # clean build 85 | 86 | # xcodebuild -project "app_w_xcode.xcodeproj" -scheme "app_w_xcode" \ 87 | # -configuration Debug \ 88 | # -destination "platform=iOS Simulator,name=iPhone 15" \ 89 | # -derivedDataPath "/Users/kevin/projects/swift/testing-codetie/app_w_xcode/build" \ 90 | # -verbose \ 91 | # ONLY_ACTIVE_ARCH=YES \ 92 | # DEVELOPMENT_TEAM="" \ 93 | # CODE_SIGN_IDENTITY="" \ 94 | # CODE_SIGNING_REQUIRED=NO \ 95 | # CODE_SIGNING_ALLOWED=NO \ 96 | # clean build 97 | 98 | # CONFIGURATION_BUILD_DIR="${BUILD_DIR}/Build/Products/Debug-iphonesimulator" \ 99 | 100 | # Check if the build was successful 101 | if [ $? -eq 0 ]; then 102 | APP_PATH="${BUILD_DIR}/Build/Products/Debug-iphonesimulator/${PROJECT_NAME}.app" 103 | if [ -d "$APP_PATH" ]; then 104 | echo "✅ Project built successfully!" 105 | echo "App bundle location: $APP_PATH" 106 | # Export the APP_PATH for use in run_simulator.sh 107 | echo "export APP_PATH=\"$APP_PATH\"" > build_output.sh 108 | else 109 | echo "❌ Build succeeded, but app bundle not found at expected location." 110 | exit 1 111 | fi 112 | else 113 | echo "❌ Project build failed." 114 | exit 1 115 | fi -------------------------------------------------------------------------------- /packages/create-codetie/template/scripts/build_project_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get the project name from the first argument 4 | PROJECT_NAME=$1 5 | 6 | # Remove .xcodeproj extension if present 7 | PROJECT_NAME=${PROJECT_NAME%.xcodeproj} 8 | 9 | # Set the output directory 10 | BUILD_DIR="$(pwd)/build" 11 | 12 | # Ensure the project file exists 13 | if [ ! -f "${PROJECT_NAME}.xcodeproj/project.pbxproj" ]; then 14 | echo "Error: ${PROJECT_NAME}.xcodeproj not found in the current directory." 15 | exit 1 16 | fi 17 | 18 | # Configure xcode-build-server 19 | xcode-build-server config -project "${PROJECT_NAME}.xcodeproj" -scheme "${PROJECT_NAME}" 20 | 21 | # Build the project for iOS Simulator and generate build log 22 | xcodebuild -project "${PROJECT_NAME}.xcodeproj" -scheme "${PROJECT_NAME}" \ 23 | -configuration Debug \ 24 | -destination "platform=iOS Simulator,name=iPhone 14,OS=latest" \ 25 | -derivedDataPath "${BUILD_DIR}" \ 26 | -resultBundlePath .bundle \ 27 | clean build | tee build.log 28 | 29 | # Parse the build log with xcode-build-server 30 | xcode-build-server parse -a build.log 31 | 32 | # Check if the build was successful 33 | if [ $? -eq 0 ]; then 34 | APP_PATH="${BUILD_DIR}/Build/Products/Debug-iphonesimulator/${PROJECT_NAME}.app" 35 | if [ -d "$APP_PATH" ]; then 36 | echo "✅ Project built successfully!" 37 | echo "App bundle location: $APP_PATH" 38 | # Export the APP_PATH for use in run_simulator.sh 39 | echo "export APP_PATH=\"$APP_PATH\"" > build_output.sh 40 | else 41 | echo "❌ Build succeeded, but app bundle not found at expected location." 42 | exit 1 43 | fi 44 | else 45 | echo "❌ Project build failed." 46 | exit 1 47 | fi -------------------------------------------------------------------------------- /packages/create-codetie/template/scripts/parse_build_log.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codetie-ai/codetie/0603d6d4cbcd4d557ed14b6bfae0846447ec6b23/packages/create-codetie/template/scripts/parse_build_log.py -------------------------------------------------------------------------------- /packages/create-codetie/template/scripts/run_simulator.sh.mustache: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get the simulator name from the argument, or use the default if not provided 4 | SIMULATOR_NAME="${1:-iPhone 14}" 5 | 6 | # Get the simulator ID 7 | SIMULATOR_ID=$(xcrun simctl list devices | grep "$SIMULATOR_NAME" | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})" | head -n 1) 8 | 9 | # Debugging: Print the retrieved SIMULATOR_ID 10 | # echo "Retrieved SIMULATOR_ID: $SIMULATOR_ID" 11 | 12 | if [ -z "$SIMULATOR_ID" ]; then 13 | echo "Error: Simulator '$SIMULATOR_NAME' not found." 14 | exit 1 15 | fi 16 | 17 | # Set variables 18 | SCHEME_NAME="{{PROJECT_NAME}}" # Use environment variable or default 19 | APP_BUNDLE_ID="{{BUNDLE_ID_PREFIX}}.$SCHEME_NAME" # Use environment variable or generate from SCHEME_NAME 20 | APP_PATH="$(pwd)/build/Build/Products/Debug-iphonesimulator/$SCHEME_NAME.app" 21 | 22 | # Print the variables for verification 23 | echo "Using the following settings:" 24 | echo "SIMULATOR_NAME: $SIMULATOR_NAME" 25 | echo "SIMULATOR_ID: $SIMULATOR_ID" 26 | echo "SCHEME_NAME: $SCHEME_NAME" 27 | echo "APP_BUNDLE_ID: $APP_BUNDLE_ID" 28 | echo "APP_PATH: $APP_PATH" 29 | 30 | # Ensure the simulator is shutdown before booting 31 | echo "Shutting down simulator if it's running..." 32 | xcrun simctl shutdown "$SIMULATOR_ID" 33 | 34 | # Boot the simulator 35 | echo "Booting simulator..." 36 | xcrun simctl boot "$SIMULATOR_ID" || { echo "Error: Failed to boot simulator with ID $SIMULATOR_ID"; exit 1; } 37 | 38 | # Wait until the simulator is fully booted 39 | echo "Waiting for simulator to boot..." 40 | while [[ "$(xcrun simctl list devices | grep "$SIMULATOR_ID" | grep -o "Booted")" != "Booted" ]]; do 41 | sleep 1 42 | done 43 | 44 | # Open Simulator 45 | echo "Opening Simulator..." 46 | open -a Simulator 47 | 48 | if [ -z "$APP_PATH" ]; then 49 | echo "Error: Built app not found." 50 | exit 1 51 | fi 52 | 53 | # Install the app 54 | echo "Installing app..." 55 | xcrun simctl install booted "$APP_PATH" 56 | 57 | # Launch the app 58 | echo "Launching app..." 59 | xcrun simctl launch booted "$APP_BUNDLE_ID" 60 | 61 | echo "Done!" -------------------------------------------------------------------------------- /packages/create-codetie/template/simulators.yml: -------------------------------------------------------------------------------- 1 | defaultAlways: false 2 | default: "iPhone 14" 3 | simulators: 4 | - "iPhone 14" 5 | - "iPhone 14 Pro" 6 | - "iPhone 14 Pro Max" 7 | - "iPhone SE (3rd generation)" 8 | - "iPad Air (5th generation)" 9 | - "iPad Pro (11-inch) (4th generation)" 10 | - "iPad Pro (12.9-inch) (6th generation)" -------------------------------------------------------------------------------- /packages/create-codetie/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "build.config.ts", 4 | "src", 5 | "__tests__" 6 | ], 7 | "compilerOptions": { 8 | "outDir": "dist", 9 | "target": "ES2022", 10 | "module": "ES2020", 11 | "moduleResolution": "bundler", 12 | "strict": true, 13 | "skipLibCheck": true, 14 | "declaration": false, 15 | "sourceMap": false, 16 | "noUnusedLocals": true, 17 | "esModuleInterop": true 18 | } 19 | } -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' -------------------------------------------------------------------------------- /scripts/__release.ts: -------------------------------------------------------------------------------- 1 | import { release } from '@vitejs/release-scripts' 2 | import colors from 'picocolors' 3 | import { logRecentCommits, run, updateTemplateVersions } from './releaseUtils' 4 | import extendCommitHash from './extendCommitHash' 5 | 6 | release({ 7 | repo: 'codetie', 8 | packages: ['codetie', 'create-codetie'], 9 | toTag: (pkg, version) => 10 | pkg === 'codetie' ? `v${version}` : `${pkg}@${version}`, 11 | logChangelog: (pkg) => logRecentCommits(pkg), 12 | generateChangelog: async (pkgName) => { 13 | if (pkgName === 'create-codetie') await updateTemplateVersions() 14 | 15 | console.log(colors.cyan('\nGenerating changelog...')) 16 | const changelogArgs = [ 17 | 'conventional-changelog', 18 | '-p', 19 | 'angular', 20 | '-i', 21 | 'CHANGELOG.md', 22 | '-s', 23 | '--commit-path', 24 | '.', 25 | ] 26 | if (pkgName !== 'codetie') changelogArgs.push('--lerna-package', pkgName) 27 | await run('npx', changelogArgs, { cwd: `packages/${pkgName}` }) 28 | // conventional-changelog generates links with short commit hashes, extend them to full hashes 29 | extendCommitHash(`packages/${pkgName}/CHANGELOG.md`) 30 | }, 31 | }) -------------------------------------------------------------------------------- /scripts/extendCommitHash.ts: -------------------------------------------------------------------------------- 1 | import fs from "node:fs"; 2 | import { execSync } from "node:child_process"; 3 | import colors from "picocolors"; 4 | 5 | export default function extendCommitHash(path: string): void { 6 | let content = fs.readFileSync(path, "utf-8"); 7 | const base = "https://github.com/codetie-ai/codetie/commit/"; 8 | const matchHashReg = new RegExp(`${base}(\\w{7})\\)`, "g"); 9 | console.log(colors.cyan(`\nextending commit hash in ${path}...`)); 10 | let match; 11 | while ((match = matchHashReg.exec(content))) { 12 | const shortHash = match[1]; 13 | try { 14 | const longHash = execSync(`git rev-parse ${shortHash}`).toString().trim(); 15 | content = content.replace(`${base}${shortHash}`, `${base}${longHash}`); 16 | } catch {} 17 | } 18 | fs.writeFileSync(path, content); 19 | console.log(colors.green(`${path} update success!`)); 20 | } 21 | -------------------------------------------------------------------------------- /scripts/release.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | 5 | const packages = ['codetie', 'create-codetie']; 6 | 7 | function run(command: string, cwd: string) { 8 | console.log(`Executing: ${command} in ${cwd}`); 9 | execSync(command, { stdio: 'inherit', cwd }); 10 | } 11 | 12 | async function publishPackages() { 13 | for (const pkg of packages) { 14 | const pkgPath = path.resolve(`packages/${pkg}`); 15 | const pkgJson = JSON.parse(fs.readFileSync(path.join(pkgPath, 'package.json'), 'utf-8')); 16 | 17 | console.log(`Publishing ${pkg}@${pkgJson.version}...`); 18 | run('pnpm publish --no-git-checks', pkgPath); 19 | } 20 | } 21 | 22 | publishPackages().catch(console.error); -------------------------------------------------------------------------------- /scripts/releaseUtils.ts: -------------------------------------------------------------------------------- 1 | import fs from 'node:fs/promises' 2 | import path from 'node:path' 3 | import colors from 'picocolors' 4 | import type { Options as ExecaOptions, ResultPromise } from 'execa' 5 | import { execa } from 'execa' 6 | 7 | export function run( 8 | bin: string, 9 | args: string[], 10 | opts?: EO, 11 | ): ResultPromise< 12 | EO & (keyof EO extends 'stdio' ? object : { stdio: 'inherit' }) 13 | > { 14 | return execa(bin, args, { stdio: 'inherit', ...opts }) as any 15 | } 16 | 17 | export async function getLatestTag(pkgName: string): Promise { 18 | const pkgJson = JSON.parse( 19 | await fs.readFile(`packages/${pkgName}/package.json`, 'utf-8'), 20 | ) 21 | const version = pkgJson.version 22 | return pkgName === 'codetie' ? `v${version}` : `${pkgName}@${version}` 23 | } 24 | 25 | export async function logRecentCommits(pkgName: string): Promise { 26 | const tag = await getLatestTag(pkgName) 27 | if (!tag) return 28 | const sha = await run('git', ['rev-list', '-n', '1', tag], { 29 | stdio: 'pipe', 30 | }).then((res) => res.stdout.trim()) 31 | console.log( 32 | colors.bold( 33 | `\n${colors.blue(`i`)} Commits of ${colors.green( 34 | pkgName, 35 | )} since ${colors.green(tag)} ${colors.gray(`(${sha.slice(0, 5)})`)}`, 36 | ), 37 | ) 38 | await run( 39 | 'git', 40 | [ 41 | '--no-pager', 42 | 'log', 43 | `${sha}..HEAD`, 44 | '--oneline', 45 | '--', 46 | `packages/${pkgName}`, 47 | ], 48 | { stdio: 'inherit' }, 49 | ) 50 | console.log() 51 | } 52 | 53 | export async function updateTemplateVersions(): Promise { 54 | const codetiePkgJson = JSON.parse( 55 | await fs.readFile('packages/codetie/package.json', 'utf-8'), 56 | ) 57 | const codetieVersion = codetiePkgJson.version 58 | if (/beta|alpha|rc/.test(codetieVersion)) return 59 | 60 | const dir = 'packages/create-codetie' 61 | const templates = (await fs.readdir(dir)).filter((dir) => 62 | dir.startsWith('template-'), 63 | ) 64 | for (const template of templates) { 65 | const pkgPath = path.join(dir, template, `package.json`) 66 | const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf-8')) 67 | pkg.devDependencies.codetie = `^` + codetieVersion 68 | await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n') 69 | } 70 | } --------------------------------------------------------------------------------