├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── src ├── index.ts ├── prompts.ts ├── tools.ts ├── tools │ ├── change-directory.ts │ ├── create-flutter-project.ts │ ├── flutter-analyze.ts │ ├── flutter-pub-add.ts │ ├── flutter-pub-get.ts │ ├── flutter-refresh.ts │ ├── flutter-run.ts │ ├── get-current-directory.ts │ ├── list-directory.ts │ ├── read-file.ts │ └── write-file.ts └── utils │ ├── ask-input.ts │ └── result.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | dist 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Welcome to Prompt2Flutter 🚀

2 | 3 | > **⚠️ DISCLAIMER: This is just a proof of concept quickly hacked together. The code quality is not production-ready and was written for demonstration purposes only.** 4 | 5 | > Transform text descriptions into fully functional Flutter applications using AI 6 | 7 | ## Features 8 | 9 | - [x] Convert natural language descriptions into Flutter code 10 | - [x] Create complete Flutter projects with proper structure 11 | - [x] Manage Flutter dependencies automatically 12 | - [x] Generate UI components and app logic 13 | - [x] Support for Flutter best practices and patterns 14 | - [x] Powered by Google's Gemini AI model 15 | 16 | ## Demo 17 | 18 | Watch the demonstration video: 19 | 20 | https://github.com/user-attachments/assets/f9f9e259-8f7e-40d7-966d-4245f8830b51 21 | 22 | ## Installation 23 | 24 | ```sh 25 | # Clone the repository 26 | git clone https://github.com/filippofinke/Prompt2Flutter.git 27 | cd Prompt2Flutter 28 | 29 | # Install dependencies 30 | npm install 31 | 32 | # Set up your API key 33 | # Create a .env file with your Google Gemini API key 34 | echo "GEMINI_API_KEY=your_api_key_here" > .env 35 | ``` 36 | 37 | ## Development 38 | 39 | ```sh 40 | npm run dev 41 | ``` 42 | 43 | ## Build and Run 44 | 45 | ```sh 46 | npm run build 47 | npm start 48 | ``` 49 | 50 | ## Requirements 51 | 52 | - Node.js and npm 53 | - Flutter SDK installed and in your PATH 54 | 55 | ## Author 56 | 57 | 👤 **Filippo Finke** 58 | 59 | - Website: https://filippofinke.ch 60 | - Twitter: [@filippofinke](https://twitter.com/filippofinke) 61 | - Github: [@filippofinke](https://github.com/filippofinke) 62 | - LinkedIn: [@filippofinke](https://linkedin.com/in/filippofinke) 63 | 64 | ## 🤝 Contributing 65 | 66 | Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/filippofinke/Prompt2Flutter/issues). 67 | 68 | ## Show your support 69 | 70 | Give a ⭐️ if this project helped you! 71 | 72 | 73 | Buy Me A McFlurry 74 | 75 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prompt2flutter", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "prompt2flutter", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@google/genai": "^0.8.0" 13 | }, 14 | "devDependencies": { 15 | "ts-node-dev": "^2.0.0", 16 | "typescript": "^5.8.3" 17 | } 18 | }, 19 | "node_modules/@cspotcode/source-map-support": { 20 | "version": "0.8.1", 21 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 22 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 23 | "dev": true, 24 | "dependencies": { 25 | "@jridgewell/trace-mapping": "0.3.9" 26 | }, 27 | "engines": { 28 | "node": ">=12" 29 | } 30 | }, 31 | "node_modules/@google/genai": { 32 | "version": "0.8.0", 33 | "resolved": "https://registry.npmjs.org/@google/genai/-/genai-0.8.0.tgz", 34 | "integrity": "sha512-Zs+OGyZKyMbFofGJTR9/jTQSv8kITh735N3tEuIZj4VlMQXTC0soCFahysJ9NaeenRlD7xGb6fyqmX+FwrpU6Q==", 35 | "dependencies": { 36 | "google-auth-library": "^9.14.2", 37 | "ws": "^8.18.0" 38 | }, 39 | "engines": { 40 | "node": ">=18.0.0" 41 | } 42 | }, 43 | "node_modules/@jridgewell/resolve-uri": { 44 | "version": "3.1.2", 45 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 46 | "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 47 | "dev": true, 48 | "engines": { 49 | "node": ">=6.0.0" 50 | } 51 | }, 52 | "node_modules/@jridgewell/sourcemap-codec": { 53 | "version": "1.5.0", 54 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 55 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 56 | "dev": true 57 | }, 58 | "node_modules/@jridgewell/trace-mapping": { 59 | "version": "0.3.9", 60 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 61 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 62 | "dev": true, 63 | "dependencies": { 64 | "@jridgewell/resolve-uri": "^3.0.3", 65 | "@jridgewell/sourcemap-codec": "^1.4.10" 66 | } 67 | }, 68 | "node_modules/@tsconfig/node10": { 69 | "version": "1.0.11", 70 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", 71 | "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", 72 | "dev": true 73 | }, 74 | "node_modules/@tsconfig/node12": { 75 | "version": "1.0.11", 76 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 77 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 78 | "dev": true 79 | }, 80 | "node_modules/@tsconfig/node14": { 81 | "version": "1.0.3", 82 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 83 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 84 | "dev": true 85 | }, 86 | "node_modules/@tsconfig/node16": { 87 | "version": "1.0.4", 88 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 89 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", 90 | "dev": true 91 | }, 92 | "node_modules/@types/node": { 93 | "version": "22.14.0", 94 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", 95 | "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", 96 | "dev": true, 97 | "peer": true, 98 | "dependencies": { 99 | "undici-types": "~6.21.0" 100 | } 101 | }, 102 | "node_modules/@types/strip-bom": { 103 | "version": "3.0.0", 104 | "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", 105 | "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", 106 | "dev": true 107 | }, 108 | "node_modules/@types/strip-json-comments": { 109 | "version": "0.0.30", 110 | "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", 111 | "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", 112 | "dev": true 113 | }, 114 | "node_modules/acorn": { 115 | "version": "8.14.1", 116 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", 117 | "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", 118 | "dev": true, 119 | "bin": { 120 | "acorn": "bin/acorn" 121 | }, 122 | "engines": { 123 | "node": ">=0.4.0" 124 | } 125 | }, 126 | "node_modules/acorn-walk": { 127 | "version": "8.3.4", 128 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", 129 | "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", 130 | "dev": true, 131 | "dependencies": { 132 | "acorn": "^8.11.0" 133 | }, 134 | "engines": { 135 | "node": ">=0.4.0" 136 | } 137 | }, 138 | "node_modules/agent-base": { 139 | "version": "7.1.3", 140 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", 141 | "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", 142 | "engines": { 143 | "node": ">= 14" 144 | } 145 | }, 146 | "node_modules/anymatch": { 147 | "version": "3.1.3", 148 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 149 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 150 | "dev": true, 151 | "dependencies": { 152 | "normalize-path": "^3.0.0", 153 | "picomatch": "^2.0.4" 154 | }, 155 | "engines": { 156 | "node": ">= 8" 157 | } 158 | }, 159 | "node_modules/arg": { 160 | "version": "4.1.3", 161 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 162 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 163 | "dev": true 164 | }, 165 | "node_modules/balanced-match": { 166 | "version": "1.0.2", 167 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 168 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 169 | "dev": true 170 | }, 171 | "node_modules/base64-js": { 172 | "version": "1.5.1", 173 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 174 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 175 | "funding": [ 176 | { 177 | "type": "github", 178 | "url": "https://github.com/sponsors/feross" 179 | }, 180 | { 181 | "type": "patreon", 182 | "url": "https://www.patreon.com/feross" 183 | }, 184 | { 185 | "type": "consulting", 186 | "url": "https://feross.org/support" 187 | } 188 | ] 189 | }, 190 | "node_modules/bignumber.js": { 191 | "version": "9.2.1", 192 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.2.1.tgz", 193 | "integrity": "sha512-+NzaKgOUvInq9TIUZ1+DRspzf/HApkCwD4btfuasFTdrfnOxqx853TgDpMolp+uv4RpRp7bPcEU2zKr9+fRmyw==", 194 | "engines": { 195 | "node": "*" 196 | } 197 | }, 198 | "node_modules/binary-extensions": { 199 | "version": "2.3.0", 200 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", 201 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", 202 | "dev": true, 203 | "engines": { 204 | "node": ">=8" 205 | }, 206 | "funding": { 207 | "url": "https://github.com/sponsors/sindresorhus" 208 | } 209 | }, 210 | "node_modules/brace-expansion": { 211 | "version": "1.1.11", 212 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 213 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 214 | "dev": true, 215 | "dependencies": { 216 | "balanced-match": "^1.0.0", 217 | "concat-map": "0.0.1" 218 | } 219 | }, 220 | "node_modules/braces": { 221 | "version": "3.0.3", 222 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 223 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 224 | "dev": true, 225 | "dependencies": { 226 | "fill-range": "^7.1.1" 227 | }, 228 | "engines": { 229 | "node": ">=8" 230 | } 231 | }, 232 | "node_modules/buffer-equal-constant-time": { 233 | "version": "1.0.1", 234 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 235 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" 236 | }, 237 | "node_modules/buffer-from": { 238 | "version": "1.1.2", 239 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 240 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", 241 | "dev": true 242 | }, 243 | "node_modules/chokidar": { 244 | "version": "3.6.0", 245 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", 246 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", 247 | "dev": true, 248 | "dependencies": { 249 | "anymatch": "~3.1.2", 250 | "braces": "~3.0.2", 251 | "glob-parent": "~5.1.2", 252 | "is-binary-path": "~2.1.0", 253 | "is-glob": "~4.0.1", 254 | "normalize-path": "~3.0.0", 255 | "readdirp": "~3.6.0" 256 | }, 257 | "engines": { 258 | "node": ">= 8.10.0" 259 | }, 260 | "funding": { 261 | "url": "https://paulmillr.com/funding/" 262 | }, 263 | "optionalDependencies": { 264 | "fsevents": "~2.3.2" 265 | } 266 | }, 267 | "node_modules/concat-map": { 268 | "version": "0.0.1", 269 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 270 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 271 | "dev": true 272 | }, 273 | "node_modules/create-require": { 274 | "version": "1.1.1", 275 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 276 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 277 | "dev": true 278 | }, 279 | "node_modules/debug": { 280 | "version": "4.4.0", 281 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 282 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 283 | "dependencies": { 284 | "ms": "^2.1.3" 285 | }, 286 | "engines": { 287 | "node": ">=6.0" 288 | }, 289 | "peerDependenciesMeta": { 290 | "supports-color": { 291 | "optional": true 292 | } 293 | } 294 | }, 295 | "node_modules/diff": { 296 | "version": "4.0.2", 297 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 298 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 299 | "dev": true, 300 | "engines": { 301 | "node": ">=0.3.1" 302 | } 303 | }, 304 | "node_modules/dynamic-dedupe": { 305 | "version": "0.3.0", 306 | "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", 307 | "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", 308 | "dev": true, 309 | "dependencies": { 310 | "xtend": "^4.0.0" 311 | } 312 | }, 313 | "node_modules/ecdsa-sig-formatter": { 314 | "version": "1.0.11", 315 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 316 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 317 | "dependencies": { 318 | "safe-buffer": "^5.0.1" 319 | } 320 | }, 321 | "node_modules/extend": { 322 | "version": "3.0.2", 323 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 324 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 325 | }, 326 | "node_modules/fill-range": { 327 | "version": "7.1.1", 328 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 329 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 330 | "dev": true, 331 | "dependencies": { 332 | "to-regex-range": "^5.0.1" 333 | }, 334 | "engines": { 335 | "node": ">=8" 336 | } 337 | }, 338 | "node_modules/fs.realpath": { 339 | "version": "1.0.0", 340 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 341 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 342 | "dev": true 343 | }, 344 | "node_modules/fsevents": { 345 | "version": "2.3.3", 346 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 347 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 348 | "dev": true, 349 | "hasInstallScript": true, 350 | "optional": true, 351 | "os": [ 352 | "darwin" 353 | ], 354 | "engines": { 355 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 356 | } 357 | }, 358 | "node_modules/function-bind": { 359 | "version": "1.1.2", 360 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 361 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 362 | "dev": true, 363 | "funding": { 364 | "url": "https://github.com/sponsors/ljharb" 365 | } 366 | }, 367 | "node_modules/gaxios": { 368 | "version": "6.7.1", 369 | "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", 370 | "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", 371 | "dependencies": { 372 | "extend": "^3.0.2", 373 | "https-proxy-agent": "^7.0.1", 374 | "is-stream": "^2.0.0", 375 | "node-fetch": "^2.6.9", 376 | "uuid": "^9.0.1" 377 | }, 378 | "engines": { 379 | "node": ">=14" 380 | } 381 | }, 382 | "node_modules/gcp-metadata": { 383 | "version": "6.1.1", 384 | "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", 385 | "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", 386 | "dependencies": { 387 | "gaxios": "^6.1.1", 388 | "google-logging-utils": "^0.0.2", 389 | "json-bigint": "^1.0.0" 390 | }, 391 | "engines": { 392 | "node": ">=14" 393 | } 394 | }, 395 | "node_modules/glob": { 396 | "version": "7.2.3", 397 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 398 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 399 | "deprecated": "Glob versions prior to v9 are no longer supported", 400 | "dev": true, 401 | "dependencies": { 402 | "fs.realpath": "^1.0.0", 403 | "inflight": "^1.0.4", 404 | "inherits": "2", 405 | "minimatch": "^3.1.1", 406 | "once": "^1.3.0", 407 | "path-is-absolute": "^1.0.0" 408 | }, 409 | "engines": { 410 | "node": "*" 411 | }, 412 | "funding": { 413 | "url": "https://github.com/sponsors/isaacs" 414 | } 415 | }, 416 | "node_modules/glob-parent": { 417 | "version": "5.1.2", 418 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 419 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 420 | "dev": true, 421 | "dependencies": { 422 | "is-glob": "^4.0.1" 423 | }, 424 | "engines": { 425 | "node": ">= 6" 426 | } 427 | }, 428 | "node_modules/google-auth-library": { 429 | "version": "9.15.1", 430 | "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", 431 | "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", 432 | "dependencies": { 433 | "base64-js": "^1.3.0", 434 | "ecdsa-sig-formatter": "^1.0.11", 435 | "gaxios": "^6.1.1", 436 | "gcp-metadata": "^6.1.0", 437 | "gtoken": "^7.0.0", 438 | "jws": "^4.0.0" 439 | }, 440 | "engines": { 441 | "node": ">=14" 442 | } 443 | }, 444 | "node_modules/google-logging-utils": { 445 | "version": "0.0.2", 446 | "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", 447 | "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", 448 | "engines": { 449 | "node": ">=14" 450 | } 451 | }, 452 | "node_modules/gtoken": { 453 | "version": "7.1.0", 454 | "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", 455 | "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", 456 | "dependencies": { 457 | "gaxios": "^6.0.0", 458 | "jws": "^4.0.0" 459 | }, 460 | "engines": { 461 | "node": ">=14.0.0" 462 | } 463 | }, 464 | "node_modules/hasown": { 465 | "version": "2.0.2", 466 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", 467 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", 468 | "dev": true, 469 | "dependencies": { 470 | "function-bind": "^1.1.2" 471 | }, 472 | "engines": { 473 | "node": ">= 0.4" 474 | } 475 | }, 476 | "node_modules/https-proxy-agent": { 477 | "version": "7.0.6", 478 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", 479 | "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", 480 | "dependencies": { 481 | "agent-base": "^7.1.2", 482 | "debug": "4" 483 | }, 484 | "engines": { 485 | "node": ">= 14" 486 | } 487 | }, 488 | "node_modules/inflight": { 489 | "version": "1.0.6", 490 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 491 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 492 | "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", 493 | "dev": true, 494 | "dependencies": { 495 | "once": "^1.3.0", 496 | "wrappy": "1" 497 | } 498 | }, 499 | "node_modules/inherits": { 500 | "version": "2.0.4", 501 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 502 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 503 | "dev": true 504 | }, 505 | "node_modules/is-binary-path": { 506 | "version": "2.1.0", 507 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 508 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 509 | "dev": true, 510 | "dependencies": { 511 | "binary-extensions": "^2.0.0" 512 | }, 513 | "engines": { 514 | "node": ">=8" 515 | } 516 | }, 517 | "node_modules/is-core-module": { 518 | "version": "2.16.1", 519 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", 520 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", 521 | "dev": true, 522 | "dependencies": { 523 | "hasown": "^2.0.2" 524 | }, 525 | "engines": { 526 | "node": ">= 0.4" 527 | }, 528 | "funding": { 529 | "url": "https://github.com/sponsors/ljharb" 530 | } 531 | }, 532 | "node_modules/is-extglob": { 533 | "version": "2.1.1", 534 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 535 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 536 | "dev": true, 537 | "engines": { 538 | "node": ">=0.10.0" 539 | } 540 | }, 541 | "node_modules/is-glob": { 542 | "version": "4.0.3", 543 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 544 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 545 | "dev": true, 546 | "dependencies": { 547 | "is-extglob": "^2.1.1" 548 | }, 549 | "engines": { 550 | "node": ">=0.10.0" 551 | } 552 | }, 553 | "node_modules/is-number": { 554 | "version": "7.0.0", 555 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 556 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 557 | "dev": true, 558 | "engines": { 559 | "node": ">=0.12.0" 560 | } 561 | }, 562 | "node_modules/is-stream": { 563 | "version": "2.0.1", 564 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", 565 | "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", 566 | "engines": { 567 | "node": ">=8" 568 | }, 569 | "funding": { 570 | "url": "https://github.com/sponsors/sindresorhus" 571 | } 572 | }, 573 | "node_modules/json-bigint": { 574 | "version": "1.0.0", 575 | "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", 576 | "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", 577 | "dependencies": { 578 | "bignumber.js": "^9.0.0" 579 | } 580 | }, 581 | "node_modules/jwa": { 582 | "version": "2.0.0", 583 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", 584 | "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", 585 | "dependencies": { 586 | "buffer-equal-constant-time": "1.0.1", 587 | "ecdsa-sig-formatter": "1.0.11", 588 | "safe-buffer": "^5.0.1" 589 | } 590 | }, 591 | "node_modules/jws": { 592 | "version": "4.0.0", 593 | "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", 594 | "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", 595 | "dependencies": { 596 | "jwa": "^2.0.0", 597 | "safe-buffer": "^5.0.1" 598 | } 599 | }, 600 | "node_modules/make-error": { 601 | "version": "1.3.6", 602 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 603 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 604 | "dev": true 605 | }, 606 | "node_modules/minimatch": { 607 | "version": "3.1.2", 608 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 609 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 610 | "dev": true, 611 | "dependencies": { 612 | "brace-expansion": "^1.1.7" 613 | }, 614 | "engines": { 615 | "node": "*" 616 | } 617 | }, 618 | "node_modules/minimist": { 619 | "version": "1.2.8", 620 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 621 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 622 | "dev": true, 623 | "funding": { 624 | "url": "https://github.com/sponsors/ljharb" 625 | } 626 | }, 627 | "node_modules/mkdirp": { 628 | "version": "1.0.4", 629 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", 630 | "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", 631 | "dev": true, 632 | "bin": { 633 | "mkdirp": "bin/cmd.js" 634 | }, 635 | "engines": { 636 | "node": ">=10" 637 | } 638 | }, 639 | "node_modules/ms": { 640 | "version": "2.1.3", 641 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 642 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 643 | }, 644 | "node_modules/node-fetch": { 645 | "version": "2.7.0", 646 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", 647 | "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", 648 | "dependencies": { 649 | "whatwg-url": "^5.0.0" 650 | }, 651 | "engines": { 652 | "node": "4.x || >=6.0.0" 653 | }, 654 | "peerDependencies": { 655 | "encoding": "^0.1.0" 656 | }, 657 | "peerDependenciesMeta": { 658 | "encoding": { 659 | "optional": true 660 | } 661 | } 662 | }, 663 | "node_modules/normalize-path": { 664 | "version": "3.0.0", 665 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 666 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 667 | "dev": true, 668 | "engines": { 669 | "node": ">=0.10.0" 670 | } 671 | }, 672 | "node_modules/once": { 673 | "version": "1.4.0", 674 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 675 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 676 | "dev": true, 677 | "dependencies": { 678 | "wrappy": "1" 679 | } 680 | }, 681 | "node_modules/path-is-absolute": { 682 | "version": "1.0.1", 683 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 684 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 685 | "dev": true, 686 | "engines": { 687 | "node": ">=0.10.0" 688 | } 689 | }, 690 | "node_modules/path-parse": { 691 | "version": "1.0.7", 692 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 693 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 694 | "dev": true 695 | }, 696 | "node_modules/picomatch": { 697 | "version": "2.3.1", 698 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 699 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 700 | "dev": true, 701 | "engines": { 702 | "node": ">=8.6" 703 | }, 704 | "funding": { 705 | "url": "https://github.com/sponsors/jonschlinkert" 706 | } 707 | }, 708 | "node_modules/readdirp": { 709 | "version": "3.6.0", 710 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 711 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 712 | "dev": true, 713 | "dependencies": { 714 | "picomatch": "^2.2.1" 715 | }, 716 | "engines": { 717 | "node": ">=8.10.0" 718 | } 719 | }, 720 | "node_modules/resolve": { 721 | "version": "1.22.10", 722 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", 723 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", 724 | "dev": true, 725 | "dependencies": { 726 | "is-core-module": "^2.16.0", 727 | "path-parse": "^1.0.7", 728 | "supports-preserve-symlinks-flag": "^1.0.0" 729 | }, 730 | "bin": { 731 | "resolve": "bin/resolve" 732 | }, 733 | "engines": { 734 | "node": ">= 0.4" 735 | }, 736 | "funding": { 737 | "url": "https://github.com/sponsors/ljharb" 738 | } 739 | }, 740 | "node_modules/rimraf": { 741 | "version": "2.7.1", 742 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 743 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 744 | "deprecated": "Rimraf versions prior to v4 are no longer supported", 745 | "dev": true, 746 | "dependencies": { 747 | "glob": "^7.1.3" 748 | }, 749 | "bin": { 750 | "rimraf": "bin.js" 751 | } 752 | }, 753 | "node_modules/safe-buffer": { 754 | "version": "5.2.1", 755 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 756 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 757 | "funding": [ 758 | { 759 | "type": "github", 760 | "url": "https://github.com/sponsors/feross" 761 | }, 762 | { 763 | "type": "patreon", 764 | "url": "https://www.patreon.com/feross" 765 | }, 766 | { 767 | "type": "consulting", 768 | "url": "https://feross.org/support" 769 | } 770 | ] 771 | }, 772 | "node_modules/source-map": { 773 | "version": "0.6.1", 774 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 775 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 776 | "dev": true, 777 | "engines": { 778 | "node": ">=0.10.0" 779 | } 780 | }, 781 | "node_modules/source-map-support": { 782 | "version": "0.5.21", 783 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", 784 | "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", 785 | "dev": true, 786 | "dependencies": { 787 | "buffer-from": "^1.0.0", 788 | "source-map": "^0.6.0" 789 | } 790 | }, 791 | "node_modules/strip-bom": { 792 | "version": "3.0.0", 793 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 794 | "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", 795 | "dev": true, 796 | "engines": { 797 | "node": ">=4" 798 | } 799 | }, 800 | "node_modules/strip-json-comments": { 801 | "version": "2.0.1", 802 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 803 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 804 | "dev": true, 805 | "engines": { 806 | "node": ">=0.10.0" 807 | } 808 | }, 809 | "node_modules/supports-preserve-symlinks-flag": { 810 | "version": "1.0.0", 811 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 812 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 813 | "dev": true, 814 | "engines": { 815 | "node": ">= 0.4" 816 | }, 817 | "funding": { 818 | "url": "https://github.com/sponsors/ljharb" 819 | } 820 | }, 821 | "node_modules/to-regex-range": { 822 | "version": "5.0.1", 823 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 824 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 825 | "dev": true, 826 | "dependencies": { 827 | "is-number": "^7.0.0" 828 | }, 829 | "engines": { 830 | "node": ">=8.0" 831 | } 832 | }, 833 | "node_modules/tr46": { 834 | "version": "0.0.3", 835 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 836 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 837 | }, 838 | "node_modules/tree-kill": { 839 | "version": "1.2.2", 840 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", 841 | "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", 842 | "dev": true, 843 | "bin": { 844 | "tree-kill": "cli.js" 845 | } 846 | }, 847 | "node_modules/ts-node": { 848 | "version": "10.9.2", 849 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", 850 | "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", 851 | "dev": true, 852 | "dependencies": { 853 | "@cspotcode/source-map-support": "^0.8.0", 854 | "@tsconfig/node10": "^1.0.7", 855 | "@tsconfig/node12": "^1.0.7", 856 | "@tsconfig/node14": "^1.0.0", 857 | "@tsconfig/node16": "^1.0.2", 858 | "acorn": "^8.4.1", 859 | "acorn-walk": "^8.1.1", 860 | "arg": "^4.1.0", 861 | "create-require": "^1.1.0", 862 | "diff": "^4.0.1", 863 | "make-error": "^1.1.1", 864 | "v8-compile-cache-lib": "^3.0.1", 865 | "yn": "3.1.1" 866 | }, 867 | "bin": { 868 | "ts-node": "dist/bin.js", 869 | "ts-node-cwd": "dist/bin-cwd.js", 870 | "ts-node-esm": "dist/bin-esm.js", 871 | "ts-node-script": "dist/bin-script.js", 872 | "ts-node-transpile-only": "dist/bin-transpile.js", 873 | "ts-script": "dist/bin-script-deprecated.js" 874 | }, 875 | "peerDependencies": { 876 | "@swc/core": ">=1.2.50", 877 | "@swc/wasm": ">=1.2.50", 878 | "@types/node": "*", 879 | "typescript": ">=2.7" 880 | }, 881 | "peerDependenciesMeta": { 882 | "@swc/core": { 883 | "optional": true 884 | }, 885 | "@swc/wasm": { 886 | "optional": true 887 | } 888 | } 889 | }, 890 | "node_modules/ts-node-dev": { 891 | "version": "2.0.0", 892 | "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", 893 | "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", 894 | "dev": true, 895 | "dependencies": { 896 | "chokidar": "^3.5.1", 897 | "dynamic-dedupe": "^0.3.0", 898 | "minimist": "^1.2.6", 899 | "mkdirp": "^1.0.4", 900 | "resolve": "^1.0.0", 901 | "rimraf": "^2.6.1", 902 | "source-map-support": "^0.5.12", 903 | "tree-kill": "^1.2.2", 904 | "ts-node": "^10.4.0", 905 | "tsconfig": "^7.0.0" 906 | }, 907 | "bin": { 908 | "ts-node-dev": "lib/bin.js", 909 | "tsnd": "lib/bin.js" 910 | }, 911 | "engines": { 912 | "node": ">=0.8.0" 913 | }, 914 | "peerDependencies": { 915 | "node-notifier": "*", 916 | "typescript": "*" 917 | }, 918 | "peerDependenciesMeta": { 919 | "node-notifier": { 920 | "optional": true 921 | } 922 | } 923 | }, 924 | "node_modules/tsconfig": { 925 | "version": "7.0.0", 926 | "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", 927 | "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", 928 | "dev": true, 929 | "dependencies": { 930 | "@types/strip-bom": "^3.0.0", 931 | "@types/strip-json-comments": "0.0.30", 932 | "strip-bom": "^3.0.0", 933 | "strip-json-comments": "^2.0.0" 934 | } 935 | }, 936 | "node_modules/typescript": { 937 | "version": "5.8.3", 938 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", 939 | "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", 940 | "dev": true, 941 | "bin": { 942 | "tsc": "bin/tsc", 943 | "tsserver": "bin/tsserver" 944 | }, 945 | "engines": { 946 | "node": ">=14.17" 947 | } 948 | }, 949 | "node_modules/undici-types": { 950 | "version": "6.21.0", 951 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", 952 | "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", 953 | "dev": true, 954 | "peer": true 955 | }, 956 | "node_modules/uuid": { 957 | "version": "9.0.1", 958 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", 959 | "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", 960 | "funding": [ 961 | "https://github.com/sponsors/broofa", 962 | "https://github.com/sponsors/ctavan" 963 | ], 964 | "bin": { 965 | "uuid": "dist/bin/uuid" 966 | } 967 | }, 968 | "node_modules/v8-compile-cache-lib": { 969 | "version": "3.0.1", 970 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 971 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 972 | "dev": true 973 | }, 974 | "node_modules/webidl-conversions": { 975 | "version": "3.0.1", 976 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 977 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 978 | }, 979 | "node_modules/whatwg-url": { 980 | "version": "5.0.0", 981 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 982 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 983 | "dependencies": { 984 | "tr46": "~0.0.3", 985 | "webidl-conversions": "^3.0.0" 986 | } 987 | }, 988 | "node_modules/wrappy": { 989 | "version": "1.0.2", 990 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 991 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 992 | "dev": true 993 | }, 994 | "node_modules/ws": { 995 | "version": "8.18.1", 996 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", 997 | "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", 998 | "engines": { 999 | "node": ">=10.0.0" 1000 | }, 1001 | "peerDependencies": { 1002 | "bufferutil": "^4.0.1", 1003 | "utf-8-validate": ">=5.0.2" 1004 | }, 1005 | "peerDependenciesMeta": { 1006 | "bufferutil": { 1007 | "optional": true 1008 | }, 1009 | "utf-8-validate": { 1010 | "optional": true 1011 | } 1012 | } 1013 | }, 1014 | "node_modules/xtend": { 1015 | "version": "4.0.2", 1016 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1017 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1018 | "dev": true, 1019 | "engines": { 1020 | "node": ">=0.4" 1021 | } 1022 | }, 1023 | "node_modules/yn": { 1024 | "version": "3.1.1", 1025 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1026 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1027 | "dev": true, 1028 | "engines": { 1029 | "node": ">=6" 1030 | } 1031 | } 1032 | } 1033 | } 1034 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prompt2flutter", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "start": "node --env-file=.env dist/index.js", 8 | "build": "tsc", 9 | "dev": "ts-node-dev --env-file=.env --respawn src/index.ts" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "@google/genai": "^0.8.0" 16 | }, 17 | "devDependencies": { 18 | "ts-node-dev": "^2.0.0", 19 | "typescript": "^5.8.3" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | FunctionResponse, 3 | GenerateContentResponse, 4 | GoogleGenAI, 5 | } from "@google/genai"; 6 | 7 | import { askInput } from "./utils/ask-input"; 8 | import { flutterAgent } from "./prompts"; 9 | import { tools, functionDeclarations } from "./tools"; 10 | 11 | const model = "gemini-2.0-flash"; 12 | 13 | const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }); 14 | 15 | const chat = ai.chats.create({ 16 | model, 17 | 18 | config: { 19 | systemInstruction: flutterAgent, 20 | tools: [ 21 | { 22 | functionDeclarations, 23 | }, 24 | ], 25 | }, 26 | }); 27 | 28 | const main = async () => { 29 | while (true) { 30 | let text = await askInput("Chat > "); 31 | let response: GenerateContentResponse | undefined; 32 | try { 33 | response = await chat.sendMessage({ 34 | message: { 35 | text, 36 | }, 37 | }); 38 | 39 | while (response.functionCalls && response.functionCalls.length > 0) { 40 | if (response.functionCalls && response.functionCalls.length > 0) { 41 | const toolsResults: FunctionResponse[] = []; 42 | for (const functionCall of response.functionCalls) { 43 | const toolName = functionCall.name as string; 44 | const tool = tools[toolName]; 45 | if (tool) { 46 | console.log( 47 | `Calling tool: ${toolName} with arguments: ${JSON.stringify( 48 | functionCall.args 49 | )}` 50 | ); 51 | try { 52 | const result = await tool(functionCall.args); 53 | 54 | console.log( 55 | `Tool ${toolName} returned: ${JSON.stringify(result)}` 56 | ); 57 | 58 | const functionResponse = { 59 | name: toolName, 60 | response: { result }, 61 | }; 62 | 63 | toolsResults.push(functionResponse); 64 | } catch (error) { 65 | if (error instanceof Error) { 66 | console.error( 67 | `Error calling tool ${toolName}: ${error.message}` 68 | ); 69 | const functionResponse = { 70 | name: toolName, 71 | response: { 72 | error: error.message, 73 | }, 74 | }; 75 | toolsResults.push(functionResponse); 76 | } 77 | } 78 | } 79 | } 80 | 81 | if (toolsResults.length > 0) { 82 | response = await chat.sendMessage({ 83 | message: toolsResults.map((functionResponse) => ({ 84 | functionResponse, 85 | })), 86 | }); 87 | } 88 | } 89 | } 90 | } catch (error) { 91 | console.error("Error:", error); 92 | } 93 | 94 | // Print only the last response 95 | if (response && response.candidates && response.candidates.length > 0) { 96 | const text = response.candidates[0]?.content?.parts?.[0]?.text; 97 | if (text) { 98 | console.log(text); 99 | } else { 100 | console.log("No response from the model."); 101 | } 102 | } 103 | } 104 | }; 105 | 106 | main(); 107 | -------------------------------------------------------------------------------- /src/prompts.ts: -------------------------------------------------------------------------------- 1 | export const flutterAgent = `You are an AI LLM agent tasked with converting text-based project descriptions into fully functional Flutter applications. The descriptions will include details about UI design, component behavior, app functionality, and sometimes even backend interaction. Based on these descriptions, you will: 2 | 3 | 1. **Identify Core Components:** Break down the project into Flutter widgets, layouts, and necessary configurations. 4 | 2. **Generate Flutter Code:** Create the appropriate Flutter code for the app, including UI, logic, and data handling, ensuring the code is modular, maintainable, and optimized for performance. 5 | 3. **Ensure Compatibility:** Make sure the app works across different platforms (Android, iOS, Web, etc.), adhering to Flutter's best practices. 6 | 4. **Consider Additional Features:** If the description suggests functionality like state management, external libraries, or APIs, incorporate them into the Flutter project. 7 | 8 | ### Guidelines: 9 | - Focus on user experience and ensure a smooth, responsive UI. 10 | - If the description mentions state management, suggest a suitable solution (e.g., Provider, Riverpod, Bloc). 11 | - Handle errors and edge cases in the app's behavior, providing fallback solutions if necessary. 12 | - Be mindful of platform-specific behavior (Android vs iOS) when implementing components like navigation, camera, etc. 13 | 14 | ### Extra 15 | You will also have some tools available to you. If you encounter a task or action that requires a tool not available to you, inform the user and mention that you need the tool to complete the action. The user can then add the necessary tool for you.`; 16 | -------------------------------------------------------------------------------- /src/tools.ts: -------------------------------------------------------------------------------- 1 | import { 2 | getCurrentDirectory, 3 | getCurrentDirectoryFunctionDeclaration, 4 | } from "./tools/get-current-directory"; 5 | import { 6 | readFileContent, 7 | readFileFunctionDeclaration, 8 | } from "./tools/read-file"; 9 | import { 10 | changeDirectory, 11 | changeDirectoryFunctionDeclaration, 12 | } from "./tools/change-directory"; 13 | import { 14 | writeFileContent, 15 | writeFileContentFunctionDeclaration, 16 | } from "./tools/write-file"; 17 | import { 18 | listDirectory, 19 | listDirectoryFunctionDeclaration, 20 | } from "./tools/list-directory"; 21 | import { 22 | createFlutterProject, 23 | createFlutterProjectFunctionDeclaration, 24 | } from "./tools/create-flutter-project"; 25 | import { 26 | flutterAnalyze, 27 | flutterAnalyzeFunctionDeclaration, 28 | } from "./tools/flutter-analyze"; 29 | import { 30 | flutterPubGet, 31 | flutterPubGetFunctionDeclaration, 32 | } from "./tools/flutter-pub-get"; 33 | import { 34 | flutterPubAdd, 35 | flutterPubAddFunctionDeclaration, 36 | } from "./tools/flutter-pub-add"; 37 | import { flutterRun, flutterRunFunctionDeclaration } from "./tools/flutter-run"; 38 | import { 39 | flutterRefresh, 40 | flutterRefreshFunctionDeclaration, 41 | } from "./tools/flutter-refresh"; 42 | import { Result } from "./utils/result"; 43 | 44 | export const functionDeclarations = [ 45 | getCurrentDirectoryFunctionDeclaration, 46 | readFileFunctionDeclaration, 47 | changeDirectoryFunctionDeclaration, 48 | writeFileContentFunctionDeclaration, 49 | listDirectoryFunctionDeclaration, 50 | createFlutterProjectFunctionDeclaration, 51 | flutterAnalyzeFunctionDeclaration, 52 | flutterPubGetFunctionDeclaration, 53 | flutterPubAddFunctionDeclaration, 54 | flutterRunFunctionDeclaration, 55 | flutterRefreshFunctionDeclaration, 56 | ]; 57 | 58 | export const tools: { 59 | [key: string]: (args?: any) => Promise>; 60 | } = { 61 | getCurrentDirectory: getCurrentDirectory, 62 | readFileContent: readFileContent, 63 | changeDirectory: changeDirectory, 64 | writeFileContent: writeFileContent, 65 | listDirectory: listDirectory, 66 | createFlutterProject: createFlutterProject, 67 | flutterAnalyze: flutterAnalyze, 68 | flutterPubGet: flutterPubGet, 69 | flutterPubAdd: flutterPubAdd, 70 | flutterRun: flutterRun, 71 | flutterRefresh: flutterRefresh, 72 | }; 73 | -------------------------------------------------------------------------------- /src/tools/change-directory.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { ok, Result } from "../utils/result"; 3 | 4 | /** 5 | * Changes the current working directory to the specified path 6 | * @param path The path to change the current directory to 7 | * @returns The new current working directory path 8 | */ 9 | export async function changeDirectory({ 10 | path, 11 | }: { 12 | path: string; 13 | }): Promise> { 14 | process.chdir(path); 15 | return ok(); 16 | } 17 | 18 | /** 19 | * Function declaration schema for Google Gen AI library 20 | */ 21 | export const changeDirectoryFunctionDeclaration: FunctionDeclaration = { 22 | name: "changeDirectory", 23 | description: "Changes the current working directory to the specified path", 24 | parameters: { 25 | type: Type.OBJECT, 26 | properties: { 27 | path: { 28 | type: Type.STRING, 29 | description: "The path to change the current directory to", 30 | }, 31 | }, 32 | required: ["path"], 33 | }, 34 | }; 35 | -------------------------------------------------------------------------------- /src/tools/create-flutter-project.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { exec } from "child_process"; 3 | import { promisify } from "util"; 4 | import { ok } from "../utils/result"; 5 | 6 | const execPromise = promisify(exec); 7 | 8 | /** 9 | * Creates a new Flutter project using the flutter create command 10 | * @param name The name of the Flutter project to create 11 | * @param path Optional path where to create the project (defaults to current directory) 12 | * @returns Information about the created project 13 | */ 14 | export async function createFlutterProject({ 15 | name, 16 | path, 17 | }: { 18 | name: string; 19 | path?: string; 20 | }) { 21 | // Validate project name (Flutter requires lowercase with underscores) 22 | if (!/^[a-z][a-z0-9_]*$/.test(name)) { 23 | throw new Error( 24 | "Invalid project name. The name must be lowercase and can only contain letters, numbers, and underscores." 25 | ); 26 | } 27 | 28 | // Determine where to create the project 29 | const targetPath = path || process.cwd(); 30 | 31 | // Execute flutter create command 32 | const { stderr } = await execPromise(`flutter create ${name}`, { 33 | cwd: targetPath, 34 | }); 35 | 36 | if (stderr && stderr.toLowerCase().includes("error")) { 37 | throw new Error(`Error creating Flutter project: ${stderr}`); 38 | } 39 | 40 | return ok(); 41 | } 42 | 43 | /** 44 | * Function declaration schema for Google Gen AI library 45 | */ 46 | export const createFlutterProjectFunctionDeclaration: FunctionDeclaration = { 47 | name: "createFlutterProject", 48 | description: "Creates a new Flutter project using the flutter create command", 49 | parameters: { 50 | type: Type.OBJECT, 51 | properties: { 52 | name: { 53 | type: Type.STRING, 54 | description: 55 | "The name of the Flutter project to create (should be lowercase with underscores)", 56 | }, 57 | path: { 58 | type: Type.STRING, 59 | description: 60 | "Optional path where to create the project (defaults to current directory)", 61 | }, 62 | }, 63 | required: ["name"], 64 | }, 65 | }; 66 | -------------------------------------------------------------------------------- /src/tools/flutter-analyze.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { execSync } from "child_process"; 3 | import { ok, err, Result } from "../utils/result"; 4 | 5 | /** 6 | * Analyzes a Flutter project to check for errors, warnings, and other issues 7 | * @param path Path to the Flutter project directory (defaults to current directory) 8 | * @returns Raw output from the flutter analyze command 9 | */ 10 | export async function flutterAnalyze({ 11 | path, 12 | }: { 13 | path?: string; 14 | }): Promise> { 15 | try { 16 | // Use provided path or default to current directory 17 | const targetPath = path || process.cwd(); 18 | 19 | // Execute flutter analyze command 20 | const output = execSync("flutter analyze", { 21 | cwd: targetPath, 22 | }); 23 | 24 | return ok(output.toString()); 25 | } catch (error) { 26 | if (error instanceof Error) { 27 | return err((error as any).output?.toString() || error.message); 28 | } 29 | 30 | throw error; 31 | } 32 | } 33 | /** 34 | * Function declaration schema for Google Gen AI library 35 | */ 36 | export const flutterAnalyzeFunctionDeclaration: FunctionDeclaration = { 37 | name: "flutterAnalyze", 38 | description: 39 | "Analyzes a Flutter project to check for errors, warnings, and other issues", 40 | parameters: { 41 | type: Type.OBJECT, 42 | properties: { 43 | path: { 44 | type: Type.STRING, 45 | description: 46 | "Path to the Flutter project directory (defaults to current directory)", 47 | }, 48 | }, 49 | required: [], 50 | }, 51 | }; 52 | -------------------------------------------------------------------------------- /src/tools/flutter-pub-add.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { execSync } from "child_process"; 3 | import { err, ok } from "../utils/result"; 4 | 5 | /** 6 | * Adds packages to a Flutter project using the flutter pub add command 7 | * @param packages Array of package names to add 8 | * @param path Path to the Flutter project directory (defaults to current directory) 9 | * @param dev Whether to add the package as a dev dependency 10 | * @returns Result of the pub add operation 11 | */ 12 | export async function flutterPubAdd({ 13 | packages, 14 | path, 15 | dev, 16 | }: { 17 | packages: string[]; 18 | path?: string; 19 | dev?: boolean; 20 | }) { 21 | try { 22 | if (!packages || packages.length === 0) { 23 | return err( 24 | "No packages specified. Please provide at least one package name." 25 | ); 26 | } 27 | 28 | const targetPath = path || process.cwd(); 29 | const devFlag = dev ? "--dev" : ""; 30 | const packageList = packages.join(" "); 31 | const command = `flutter pub add ${devFlag} ${packageList}`.trim(); 32 | 33 | const output = execSync(command, { 34 | cwd: targetPath, 35 | encoding: "utf8", 36 | }); 37 | 38 | return ok(output.toString()); 39 | } catch (error) { 40 | if (error instanceof Error) { 41 | return err((error as any).output?.toString() || error.message); 42 | } 43 | 44 | throw error; 45 | } 46 | } 47 | 48 | /** 49 | * Function declaration schema for Google Gen AI library 50 | */ 51 | export const flutterPubAddFunctionDeclaration: FunctionDeclaration = { 52 | name: "flutterPubAdd", 53 | description: "Adds packages to a Flutter project using flutter pub add", 54 | parameters: { 55 | type: Type.OBJECT, 56 | properties: { 57 | packages: { 58 | type: Type.ARRAY, 59 | items: { 60 | type: Type.STRING, 61 | }, 62 | description: "Array of package names to add to the project", 63 | }, 64 | path: { 65 | type: Type.STRING, 66 | description: 67 | "Path to the Flutter project directory (defaults to current directory)", 68 | }, 69 | dev: { 70 | type: Type.BOOLEAN, 71 | description: "Whether to add the package as a dev dependency", 72 | }, 73 | }, 74 | required: ["packages"], 75 | }, 76 | }; 77 | -------------------------------------------------------------------------------- /src/tools/flutter-pub-get.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { execSync } from "child_process"; 3 | import { err, ok } from "../utils/result"; 4 | 5 | /** 6 | * Runs flutter pub get command to fetch dependencies for a Flutter project 7 | * @param path Path to the Flutter project directory (defaults to current directory) 8 | * @returns Result of the pub get operation 9 | */ 10 | export async function flutterPubGet({ path }: { path?: string }) { 11 | try { 12 | const targetPath = path || process.cwd(); 13 | 14 | const output = execSync("flutter pub get", { 15 | cwd: targetPath, 16 | encoding: "utf8", 17 | }); 18 | 19 | return ok(output.toString()); 20 | } catch (error) { 21 | if (error instanceof Error) { 22 | return err((error as any).output?.toString() || error.message); 23 | } 24 | 25 | throw error; 26 | } 27 | } 28 | 29 | /** 30 | * Function declaration schema for Google Gen AI library 31 | */ 32 | export const flutterPubGetFunctionDeclaration: FunctionDeclaration = { 33 | name: "flutterPubGet", 34 | description: "Gets dependencies for a Flutter project using flutter pub get", 35 | parameters: { 36 | type: Type.OBJECT, 37 | properties: { 38 | path: { 39 | type: Type.STRING, 40 | description: 41 | "Path to the Flutter project directory (defaults to current directory)", 42 | }, 43 | }, 44 | required: [], 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /src/tools/flutter-refresh.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { ChildProcess } from "child_process"; 3 | import { err, ok } from "../utils/result"; 4 | 5 | // Storage for running Flutter processes 6 | // In a real application, you might want to use a more persistent storage solution 7 | const runningFlutterProcesses = new Map< 8 | string, 9 | { pid: number; proc: ChildProcess } 10 | >(); 11 | 12 | /** 13 | * Registers a Flutter process for later refreshing 14 | * @param pid Process ID of the Flutter process 15 | * @param cwd Current working directory of the process 16 | */ 17 | export function registerFlutterProcess(pid: number, proc: ChildProcess) { 18 | const key = `${pid}`; 19 | runningFlutterProcesses.set(key, { pid, proc }); 20 | } 21 | 22 | /** 23 | * Triggers a hot reload for a running Flutter application 24 | * @param pid Optional process ID of the Flutter process to refresh. If not provided, tries to find a running Flutter process 25 | * @param path Optional path to the Flutter project. If not provided, uses the current directory 26 | * @returns Result of the refresh operation 27 | */ 28 | export async function flutterRefresh({ pid }: { pid?: number }) { 29 | try { 30 | let targetPid = pid; 31 | 32 | if (!targetPid) { 33 | // If no PID is provided, try to find one from the stored Flutter processes 34 | if (runningFlutterProcesses.size > 0) { 35 | // Pick the first available Flutter process 36 | const firstProcess = Array.from(runningFlutterProcesses.values())[0]; 37 | targetPid = firstProcess.pid; 38 | } else { 39 | return err("No running Flutter processes found to trigger hot reload."); 40 | } 41 | } 42 | 43 | // Find the running Flutter process using the stored information 44 | const processInfo = runningFlutterProcesses.get(`${targetPid}`); 45 | if (!processInfo) { 46 | return err("Flutter process not registered or invalid PID."); 47 | } 48 | 49 | const { proc } = processInfo; 50 | 51 | proc.stdin?.write("r"); 52 | 53 | return ok({ 54 | message: `Hot reload triggered for Flutter process ${targetPid}`, 55 | pid: targetPid, 56 | }); 57 | } catch (error) { 58 | if (error instanceof Error) { 59 | return err(`Failed to refresh Flutter app: ${error.message}`); 60 | } 61 | throw error; 62 | } 63 | } 64 | 65 | /** 66 | * Function declaration schema for Google Gen AI library 67 | */ 68 | export const flutterRefreshFunctionDeclaration: FunctionDeclaration = { 69 | name: "flutterRefresh", 70 | description: "Triggers a hot reload for a running Flutter application", 71 | parameters: { 72 | type: Type.OBJECT, 73 | properties: { 74 | pid: { 75 | type: Type.NUMBER, 76 | description: "Process ID of the Flutter process to refresh", 77 | }, 78 | }, 79 | required: ["pid"], 80 | }, 81 | }; 82 | -------------------------------------------------------------------------------- /src/tools/flutter-run.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { ChildProcess, spawn } from "child_process"; 3 | import { err, ok } from "../utils/result"; 4 | import { registerFlutterProcess } from "./flutter-refresh"; 5 | 6 | /** 7 | * Runs a Flutter application in the background using the flutter run command. 8 | * The process will be detached and its output will be ignored by default. 9 | * @param path Path to the Flutter project directory (defaults to current directory) 10 | * @param device Optional device ID or name to run the app on 11 | * @param debug Whether to run in debug mode (default: true) 12 | * @param release Whether to run in release mode (default: false) 13 | * @param profile Whether to run in profile mode (default: false) 14 | * @param flavor The flavor to use when running the app 15 | * @param target The main entry-point file of the application 16 | * @param logOutput Redirect stdout/stderr to log files instead of ignoring (default: false) 17 | * @returns Result indicating the background process has started 18 | */ 19 | export async function flutterRun({ 20 | path, 21 | device, 22 | debug = true, 23 | release = false, 24 | profile = false, 25 | flavor, 26 | target, 27 | }: { 28 | path?: string; 29 | device?: string; 30 | debug?: boolean; 31 | release?: boolean; 32 | profile?: boolean; 33 | flavor?: string; 34 | target?: string; 35 | }) { 36 | try { 37 | const targetPath = path || process.cwd(); 38 | const args = ["run"]; 39 | 40 | // Add flags based on parameters 41 | if (device) { 42 | args.push("-d", device); 43 | } 44 | 45 | if (release) { 46 | args.push("--release"); 47 | } else if (profile) { 48 | args.push("--profile"); 49 | } 50 | 51 | if (flavor) { 52 | args.push("--flavor", flavor); 53 | } 54 | 55 | if (target) { 56 | args.push("--target", target); 57 | } 58 | 59 | // Spawn the process detached 60 | const proc: ChildProcess = spawn("flutter", args, { 61 | cwd: targetPath, 62 | detached: true, 63 | }); 64 | 65 | proc.on("error", (spawnError) => { 66 | console.error(`Failed to start Flutter process: ${spawnError.message}`); 67 | }); 68 | 69 | proc.on("close", (code, signal) => { 70 | console.log( 71 | `Background Flutter process (PID: ${proc.pid}) exited with code ${code}, signal ${signal}.` 72 | ); 73 | }); 74 | 75 | if (proc.pid) { 76 | registerFlutterProcess(proc.pid, proc); 77 | } else { 78 | return err("Failed to get process ID for background Flutter process."); 79 | } 80 | 81 | let message = `Flutter app started in the background (PID: ${proc.pid}).`; 82 | 83 | return ok({ 84 | message: message, 85 | processId: proc.pid, 86 | }); 87 | } catch (error) { 88 | if (error instanceof Error) { 89 | const errMsg = (error as any).output?.toString() || error.message; 90 | return err(`Error setting up Flutter run: ${errMsg}`); 91 | } 92 | throw error; 93 | } 94 | } 95 | 96 | /** 97 | * Function declaration schema for Google Gen AI library 98 | * (Updated to include logOutput) 99 | */ 100 | export const flutterRunFunctionDeclaration: FunctionDeclaration = { 101 | name: "flutterRun", 102 | description: 103 | "Runs a Flutter application in the background using the flutter run command. Output is ignored by default.", 104 | parameters: { 105 | type: Type.OBJECT, 106 | properties: { 107 | path: { 108 | type: Type.STRING, 109 | description: 110 | "Path to the Flutter project directory (defaults to current directory)", 111 | }, 112 | device: { 113 | type: Type.STRING, 114 | description: "Optional device ID or name to run the app on", 115 | }, 116 | debug: { 117 | type: Type.BOOLEAN, 118 | description: "Whether to run in debug mode (default: true)", 119 | }, 120 | release: { 121 | type: Type.BOOLEAN, 122 | description: "Whether to run in release mode (default: false)", 123 | }, 124 | profile: { 125 | type: Type.BOOLEAN, 126 | description: "Whether to run in profile mode (default: false)", 127 | }, 128 | flavor: { 129 | type: Type.STRING, 130 | description: "The flavor to use when running the app", 131 | }, 132 | target: { 133 | type: Type.STRING, 134 | description: "The main entry-point file of the application", 135 | }, 136 | logOutput: { 137 | type: Type.BOOLEAN, 138 | description: 139 | "Redirect process stdout/stderr to log files in '.flutter_run_logs' instead of ignoring them (default: false).", 140 | }, 141 | }, 142 | required: [], 143 | }, 144 | }; 145 | -------------------------------------------------------------------------------- /src/tools/get-current-directory.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import { Result, ok } from "../utils/result"; 3 | 4 | /** 5 | * Returns the absolute path of the current working directory 6 | */ 7 | export async function getCurrentDirectory(): Promise> { 8 | return ok(process.cwd()); 9 | } 10 | 11 | /** 12 | * Function declaration for getCurrentDirectory to be used with Google GenAI 13 | */ 14 | export const getCurrentDirectoryFunctionDeclaration: FunctionDeclaration = { 15 | name: "getCurrentDirectory", 16 | description: "Gets the absolute path of the current working directory", 17 | parameters: { 18 | type: Type.OBJECT, 19 | properties: {}, 20 | required: [], 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /src/tools/list-directory.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import * as fs from "fs"; 3 | import * as path from "path"; 4 | import { err, ok } from "../utils/result"; 5 | 6 | interface DirectoryItem { 7 | name: string; 8 | path: string; 9 | isDirectory: boolean; 10 | } 11 | 12 | /** 13 | * Lists all files and directories in the specified path 14 | * @param directoryPath The path to list files from (defaults to current directory) 15 | * @returns List of files and directories with their details 16 | */ 17 | export async function listDirectory({ 18 | directoryPath, 19 | }: { 20 | directoryPath?: string; 21 | }) { 22 | // Use current directory if no path is provided 23 | const dirPath = directoryPath || process.cwd(); 24 | 25 | // Check if the directory exists 26 | if (!fs.existsSync(dirPath)) { 27 | throw new Error(`Directory does not exist: ${dirPath}`); 28 | } 29 | 30 | // Check if the path is actually a directory 31 | if (!fs.statSync(dirPath).isDirectory()) { 32 | throw new Error(`Path is not a directory: ${dirPath}`); 33 | } 34 | 35 | // Read the directory contents 36 | const files = fs.readdirSync(dirPath); 37 | 38 | // Get details for each file/directory 39 | const items: DirectoryItem[] = files.map((file) => { 40 | const filePath = path.join(dirPath, file); 41 | const isDirectory = fs.statSync(filePath).isDirectory(); 42 | 43 | return { 44 | name: file, 45 | path: filePath, 46 | isDirectory, 47 | }; 48 | }); 49 | 50 | return ok(items); 51 | } 52 | 53 | /** 54 | * Function declaration schema for Google Gen AI library 55 | */ 56 | export const listDirectoryFunctionDeclaration: FunctionDeclaration = { 57 | name: "listDirectory", 58 | description: "Lists all files and directories in the specified path", 59 | parameters: { 60 | type: Type.OBJECT, 61 | properties: { 62 | directoryPath: { 63 | type: Type.STRING, 64 | description: 65 | "The path to list files from (defaults to current directory)", 66 | }, 67 | }, 68 | required: [], // directoryPath is optional 69 | }, 70 | }; 71 | -------------------------------------------------------------------------------- /src/tools/read-file.ts: -------------------------------------------------------------------------------- 1 | import { readFile } from "fs/promises"; 2 | import { FunctionDeclaration, Type } from "@google/genai"; 3 | import { ok, Result } from "../utils/result"; 4 | 5 | /** 6 | * Reads the content of a file at the given path 7 | * @param path Path to the file 8 | * @returns The content of the file as string 9 | */ 10 | export async function readFileContent({ 11 | path, 12 | }: { 13 | path: string; 14 | }): Promise> { 15 | const content = await readFile(path, "utf-8"); 16 | return ok(content); 17 | } 18 | 19 | /** 20 | * Function declaration schema for Google Gen AI library 21 | */ 22 | export const readFileFunctionDeclaration: FunctionDeclaration = { 23 | name: "readFileContent", 24 | description: "Reads the content of a file at the specified path", 25 | parameters: { 26 | type: Type.OBJECT, 27 | properties: { 28 | path: { 29 | type: Type.STRING, 30 | description: "The path to the file to read", 31 | }, 32 | }, 33 | required: ["path"], 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /src/tools/write-file.ts: -------------------------------------------------------------------------------- 1 | import { FunctionDeclaration, Type } from "@google/genai"; 2 | import * as fs from "fs"; 3 | import * as path from "path"; 4 | import { ok } from "../utils/result"; 5 | 6 | /** 7 | * Writes content to a file, creating it if it doesn't exist or overriding it if it does 8 | * @param filePath The path to the file to write to 9 | * @param content The content to write to the file 10 | * @returns Information about the write operation 11 | */ 12 | export async function writeFileContent({ 13 | filePath, 14 | content, 15 | }: { 16 | filePath: string; 17 | content: string; 18 | }) { 19 | // Ensure the directory exists 20 | const dirPath = path.dirname(filePath); 21 | if (!fs.existsSync(dirPath)) { 22 | fs.mkdirSync(dirPath, { recursive: true }); 23 | } 24 | 25 | // Write the file 26 | fs.writeFileSync(filePath, content, "utf8"); 27 | 28 | return ok(); 29 | } 30 | 31 | /** 32 | * Function declaration schema for Google Gen AI library 33 | */ 34 | export const writeFileContentFunctionDeclaration: FunctionDeclaration = { 35 | name: "writeFileContent", 36 | description: 37 | "Writes content to a file, creating it if it doesn't exist or overriding it if it does", 38 | parameters: { 39 | type: Type.OBJECT, 40 | properties: { 41 | filePath: { 42 | type: Type.STRING, 43 | description: "The path to the file to write to", 44 | }, 45 | content: { 46 | type: Type.STRING, 47 | description: "The content to write to the file", 48 | }, 49 | }, 50 | required: ["filePath", "content"], 51 | }, 52 | }; 53 | -------------------------------------------------------------------------------- /src/utils/ask-input.ts: -------------------------------------------------------------------------------- 1 | import readline from "readline"; 2 | 3 | export function askInput(query: string): Promise { 4 | const rl = readline.createInterface({ 5 | input: process.stdin, 6 | output: process.stdout, 7 | }); 8 | 9 | return new Promise((resolve) => { 10 | rl.question(query, (answer) => { 11 | rl.close(); 12 | resolve(answer); 13 | }); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/result.ts: -------------------------------------------------------------------------------- 1 | export type Result = Ok | Err; 2 | 3 | export type Ok = { 4 | ok: true; 5 | data?: T; 6 | }; 7 | 8 | export type Err = { 9 | ok: false; 10 | error: E; 11 | }; 12 | 13 | export function ok(data?: T): Ok { 14 | return { ok: true, data }; 15 | } 16 | 17 | export function err(error: E): Err { 18 | return { ok: false, error }; 19 | } 20 | 21 | export function isOk(result: Result): result is Ok { 22 | return result.ok; 23 | } 24 | 25 | export function isErr(result: Result): result is Err { 26 | return !result.ok; 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "libReplacement": true, /* Enable lib replacement. */ 18 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 19 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 20 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 21 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 22 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 23 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 24 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 25 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 26 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 27 | 28 | /* Modules */ 29 | "module": "commonjs", /* Specify what module code is generated. */ 30 | // "rootDir": "./", /* Specify the root folder within your source files. */ 31 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 32 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 33 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 34 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 35 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 36 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 37 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 38 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 39 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 40 | // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ 41 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 42 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 43 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 44 | // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ 45 | // "resolveJsonModule": true, /* Enable importing .json files. */ 46 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 47 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 48 | 49 | /* JavaScript Support */ 50 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 51 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 52 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 53 | 54 | /* Emit */ 55 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 56 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 57 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 58 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 59 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 62 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 63 | // "removeComments": true, /* Disable emitting comments. */ 64 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 65 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 66 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 67 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 68 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 69 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 70 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 71 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 72 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 73 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 74 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 75 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 76 | 77 | /* Interop Constraints */ 78 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 79 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 80 | // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ 81 | // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ 82 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 83 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 84 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 85 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 86 | 87 | /* Type Checking */ 88 | "strict": true, /* Enable all strict type-checking options. */ 89 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 90 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 91 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 92 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 93 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 94 | // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ 95 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 96 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 97 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 98 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 99 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 100 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 101 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 102 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 103 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 104 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 105 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 106 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 107 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 108 | 109 | /* Completeness */ 110 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 111 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 112 | } 113 | } 114 | --------------------------------------------------------------------------------