diff --git a/create-agentic-app/README.md b/create-agentic-app/README.md index 11e9037..3630146 100644 --- a/create-agentic-app/README.md +++ b/create-agentic-app/README.md @@ -43,41 +43,62 @@ Visit `http://localhost:3000` to see your app! To publish this package to npm: -1. **Update package.json**: Set your author, repository URL, and version -2. **Build the template**: Run the setup script to populate the template directory: - ```bash - # On Unix/Mac: - bash setup-template.sh - - # On Windows: - powershell -ExecutionPolicy Bypass -File setup-template.ps1 - ``` -3. **Test locally**: Test the package locally before publishing: +1. **Update package.json**: Set your author, repository URL, and version in `create-agentic-app/package.json` +2. **Test locally** (optional): Test the package before publishing: ```bash + cd create-agentic-app npm link cd /path/to/test/directory create-agentic-app my-test-app ``` -4. **Publish**: Publish to npm: +3. **Publish**: The sync happens automatically! ```bash + cd create-agentic-app npm publish ``` + The `prepublishOnly` hook will automatically sync the template from the main project before publishing. ## Template Updates -When you update the boilerplate in the main project: +### Automatic Sync (Recommended) -1. Navigate to the project root -2. Run the setup script to sync changes to the template: +When publishing, the template syncs automatically via the `prepublishOnly` hook. Just run: +```bash +cd create-agentic-app +npm publish +``` + +### Manual Sync + +If you want to sync without publishing: + +**From the project root:** +```bash +npm run sync-template +``` + +**Or from the create-agentic-app directory:** +```bash +npm run sync +``` + +The sync script automatically: +- Copies all files from the main project to `template/` +- Excludes build artifacts (node_modules, .next, lock files, etc.) +- Removes `"private": true` from template's package.json +- Removes the `sync-template` script (users don't need it) + +### Publishing Workflow + +1. **Make changes** to the main boilerplate project +2. **Test your changes** +3. **Bump version** in `create-agentic-app/package.json` +4. **Publish**: ```bash - # Unix/Mac - bash create-agentic-app/setup-template.sh - - # Windows - powershell -ExecutionPolicy Bypass -File create-agentic-app/setup-template.ps1 + cd create-agentic-app + npm publish ``` -3. Bump the version in `package.json` -4. Publish the updated package + (Template syncs automatically before publishing) ## License diff --git a/create-agentic-app/package-lock.json b/create-agentic-app/package-lock.json new file mode 100644 index 0000000..78dc277 --- /dev/null +++ b/create-agentic-app/package-lock.json @@ -0,0 +1,344 @@ +{ + "name": "create-agentic-app", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "create-agentic-app", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0", + "fs-extra": "^11.2.0", + "ora": "^8.1.1", + "prompts": "^2.4.2" + }, + "bin": { + "create-agentic-app": "index.js" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + } + } +} diff --git a/create-agentic-app/package.json b/create-agentic-app/package.json index bac0f59..4317783 100644 --- a/create-agentic-app/package.json +++ b/create-agentic-app/package.json @@ -10,6 +10,10 @@ "index.js", "template" ], + "scripts": { + "sync": "node scripts/sync-templates.js", + "prepublishOnly": "npm run sync" + }, "keywords": [ "ai", "agents", diff --git a/create-agentic-app/scripts/sync-templates.js b/create-agentic-app/scripts/sync-templates.js new file mode 100644 index 0000000..27247ac --- /dev/null +++ b/create-agentic-app/scripts/sync-templates.js @@ -0,0 +1,111 @@ +#!/usr/bin/env node + +import fs from 'fs-extra'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// Colors for output +const colors = { + reset: '\x1b[0m', + green: '\x1b[32m', + blue: '\x1b[34m', + yellow: '\x1b[33m', + cyan: '\x1b[36m' +}; + +console.log(`${colors.blue}📋 Syncing template from main project...${colors.reset}\n`); + +// Paths +const scriptDir = __dirname; +const packageDir = path.dirname(scriptDir); // create-agentic-app +const projectRoot = path.dirname(packageDir); // main project root +const templateDir = path.join(packageDir, 'template'); + +// Files and directories to exclude +const excludePatterns = [ + 'node_modules', + '.next', + '.git', + 'pnpm-lock.yaml', + 'package-lock.json', + 'yarn.lock', + 'tsconfig.tsbuildinfo', + '.env', + 'create-agentic-app' +]; + +// Check if a path should be excluded +function shouldExclude(filePath) { + const relativePath = path.relative(projectRoot, filePath); + return excludePatterns.some(pattern => relativePath.includes(pattern)); +} + +// Recursively copy directory with exclusions +async function copyWithExclusions(src, dest) { + const entries = await fs.readdir(src, { withFileTypes: true }); + + await fs.ensureDir(dest); + + for (const entry of entries) { + const srcPath = path.join(src, entry.name); + const destPath = path.join(dest, entry.name); + + if (shouldExclude(srcPath)) { + continue; + } + + if (entry.isDirectory()) { + await copyWithExclusions(srcPath, destPath); + } else { + await fs.copy(srcPath, destPath, { overwrite: true }); + } + } +} + +// Main sync function +async function sync() { + try { + // Remove existing template directory + console.log(`${colors.yellow}🗑️ Cleaning template directory...${colors.reset}`); + await fs.remove(templateDir); + await fs.ensureDir(templateDir); + + // Copy files + console.log(`${colors.cyan}📦 Copying project files...${colors.reset}`); + await copyWithExclusions(projectRoot, templateDir); + + // Process template package.json + console.log(`${colors.cyan}⚙️ Updating template package.json...${colors.reset}`); + const templatePackageJsonPath = path.join(templateDir, 'package.json'); + + if (await fs.pathExists(templatePackageJsonPath)) { + const packageJson = await fs.readJson(templatePackageJsonPath); + + // Remove private field + delete packageJson.private; + + // Remove sync-template script if it exists + if (packageJson.scripts && packageJson.scripts['sync-template']) { + delete packageJson.scripts['sync-template']; + } + + // Write back the cleaned package.json + await fs.writeJson(templatePackageJsonPath, packageJson, { spaces: 2 }); + console.log(`${colors.green}✓${colors.reset} Removed "private" field and sync script`); + } + + console.log(`\n${colors.green}✨ Template sync complete!${colors.reset}`); + console.log(`${colors.cyan}📁 Template directory: ${templateDir}${colors.reset}\n`); + + } catch (error) { + console.error(`${colors.yellow}❌ Error syncing template:${colors.reset}`, error); + process.exit(1); + } +} + +// Run sync +sync(); diff --git a/create-agentic-app/template/README.md b/create-agentic-app/template/README.md index c30dc18..6804274 100644 --- a/create-agentic-app/template/README.md +++ b/create-agentic-app/template/README.md @@ -35,7 +35,38 @@ Before you begin, ensure you have the following installed on your machine: ## 🛠️ Quick Setup -### 1. Clone or Download the Repository +### Automated Setup (Recommended) + +Get started with a single command: + +```bash +npx create-agentic-app@latest my-app +cd my-app +``` + +Or create in the current directory: + +```bash +npx create-agentic-app@latest . +``` + +The CLI will: +- Copy all boilerplate files +- Install dependencies with your preferred package manager (pnpm/npm/yarn) +- Set up your environment file + +**Next steps after running the command:** + +1. Update `.env` with your API keys and database credentials +2. Start the database: `docker compose up -d` +3. Run migrations: `npm run db:migrate` +4. Start dev server: `npm run dev` + +### Manual Setup (Alternative) + +If you prefer to set up manually: + +**1. Clone or Download the Repository** **Option A: Clone with Git** @@ -47,13 +78,13 @@ cd agentic-coding-starter-kit **Option B: Download ZIP** Download the repository as a ZIP file and extract it to your desired location. -### 2. Install Dependencies +**2. Install Dependencies** ```bash npm install ``` -### 3. Environment Setup +**3. Environment Setup** Copy the example environment file: @@ -82,7 +113,7 @@ OPENAI_MODEL="gpt-5-mini" NEXT_PUBLIC_APP_URL="http://localhost:3000" ``` -### 4. Database Setup +**4. Database Setup** Generate and run database migrations: @@ -91,7 +122,7 @@ npm run db:generate npm run db:migrate ``` -### 5. Start the Development Server +**5. Start the Development Server** ```bash npm run dev diff --git a/create-agentic-app/template/package.json b/create-agentic-app/template/package.json index 68b96d9..142bbdc 100644 --- a/create-agentic-app/template/package.json +++ b/create-agentic-app/template/package.json @@ -1,7 +1,6 @@ { "name": "agentic-coding-starter-kit", "version": "0.1.0", - "private": true, "scripts": { "dev": "next dev --turbopack", "build": "pnpm run db:migrate && next build", diff --git a/create-agentic-app/template/src/app/api/auth/[...all]/route.ts b/create-agentic-app/template/src/app/api/auth/[...all]/route.ts new file mode 100644 index 0000000..81724a0 --- /dev/null +++ b/create-agentic-app/template/src/app/api/auth/[...all]/route.ts @@ -0,0 +1,4 @@ +import { auth } from "@/lib/auth" +import { toNextJsHandler } from "better-auth/next-js" + +export const { GET, POST } = toNextJsHandler(auth) \ No newline at end of file diff --git a/package.json b/package.json index 68b96d9..856f37b 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "db:push": "drizzle-kit push", "db:studio": "drizzle-kit studio", "db:dev": "drizzle-kit push", - "db:reset": "drizzle-kit drop && drizzle-kit push" + "db:reset": "drizzle-kit drop && drizzle-kit push", + "sync-template": "node create-agentic-app/scripts/sync-templates.js" }, "dependencies": { "@ai-sdk/openai": "^2.0.53",