diff --git a/.changeset/create-emdash-ux.md b/.changeset/create-emdash-ux.md new file mode 100644 index 0000000..4b11e92 --- /dev/null +++ b/.changeset/create-emdash-ux.md @@ -0,0 +1,5 @@ +--- +"create-emdash": patch +--- + +Improve create-emdash CLI experience: add the EmDash branded banner, let users pick their package manager (auto-detects the one that invoked it), and ask whether to install dependencies with a spinner showing progress. diff --git a/packages/create-emdash/src/index.ts b/packages/create-emdash/src/index.ts index cb479ef..51e27dc 100644 --- a/packages/create-emdash/src/index.ts +++ b/packages/create-emdash/src/index.ts @@ -18,6 +18,17 @@ const PROJECT_NAME_PATTERN = /^[a-z0-9-]+$/; const GITHUB_REPO = "emdash-cms/templates"; +type PackageManager = "pnpm" | "npm" | "yarn" | "bun"; + +/** Detect which package manager invoked us, or fall back to npm */ +function detectPackageManager(): PackageManager { + const agent = process.env.npm_config_user_agent ?? ""; + if (agent.startsWith("pnpm")) return "pnpm"; + if (agent.startsWith("yarn")) return "yarn"; + if (agent.startsWith("bun")) return "bun"; + return "npm"; +} + type Platform = "node" | "cloudflare"; interface TemplateConfig { @@ -95,7 +106,8 @@ function selectOptions( async function main() { console.clear(); - p.intro(`${pc.bgCyan(pc.black(" create-emdash "))}`); + console.log(`\n ${pc.bold(pc.cyan("— E M D A S H —"))}\n`); + p.intro("Create a new EmDash project"); const projectName = await p.text({ message: "Project name?", @@ -132,16 +144,16 @@ async function main() { const platform = await p.select({ message: "Where will you deploy?", options: [ - { - value: "node", - label: "Node.js", - hint: "SQLite + local file storage", - }, { value: "cloudflare", label: "Cloudflare Workers", hint: "D1 + R2", }, + { + value: "node", + label: "Node.js", + hint: "SQLite + local file storage", + }, ], initialValue: "node", }); @@ -175,6 +187,38 @@ async function main() { ? NODE_TEMPLATES[templateKey as NodeTemplate] : CLOUDFLARE_TEMPLATES[templateKey as CloudflareTemplate]; + // Step 3: pick package manager + const detectedPm = detectPackageManager(); + const pm = await p.select({ + message: "Which package manager?", + options: [ + { value: "pnpm", label: "pnpm" }, + { value: "npm", label: "npm" }, + { value: "yarn", label: "yarn" }, + { value: "bun", label: "bun" }, + ], + initialValue: detectedPm, + }); + + if (p.isCancel(pm)) { + p.cancel("Operation cancelled."); + process.exit(0); + } + + // Step 4: install dependencies? + const shouldInstall = await p.confirm({ + message: "Install dependencies?", + initialValue: true, + }); + + if (p.isCancel(shouldInstall)) { + p.cancel("Operation cancelled."); + process.exit(0); + } + + const installCmd = `${pm} install`; + const runCmd = (script: string) => (pm === "npm" ? `npm run ${script}` : `${pm} ${script}`); + const s = p.spinner(); s.start("Creating project..."); @@ -204,19 +248,25 @@ async function main() { s.stop("Project created!"); - s.start("Installing dependencies..."); - try { - execSync("pnpm install", { - cwd: projectDir, - stdio: "ignore", - }); - s.stop("Dependencies installed!"); - } catch { - s.stop("Failed to install dependencies"); - p.log.warn(`Run ${pc.cyan(`cd ${projectName} && pnpm install`)} manually`); + if (shouldInstall) { + s.start(`Installing dependencies with ${pc.cyan(pm)}...`); + try { + execSync(installCmd, { + cwd: projectDir, + stdio: "ignore", + }); + s.stop("Dependencies installed!"); + } catch { + s.stop("Failed to install dependencies"); + p.log.warn(`Run ${pc.cyan(`cd ${projectName} && ${installCmd}`)} manually`); + } } - p.note(`cd ${projectName}\npnpm run bootstrap\npnpm run dev`, "Next steps"); + const steps = [`cd ${projectName}`]; + if (!shouldInstall) steps.push(installCmd); + steps.push(runCmd("bootstrap"), runCmd("dev")); + + p.note(steps.join("\n"), "Next steps"); p.outro(`${pc.green("Done!")} Your EmDash project is ready at ${pc.cyan(projectName)}`); } catch (error) { diff --git a/packages/plugins/ai-moderation/package.json b/packages/plugins/ai-moderation/package.json index 69f35bb..e71ddd1 100644 --- a/packages/plugins/ai-moderation/package.json +++ b/packages/plugins/ai-moderation/package.json @@ -1,43 +1,48 @@ { - "name": "@emdash-cms/plugin-ai-moderation", - "version": "0.0.2", - "description": "AI-powered comment moderation plugin for EmDash CMS using Cloudflare Workers AI (Llama Guard)", - "type": "module", - "main": "src/descriptor.ts", - "exports": { - ".": "./src/descriptor.ts", - "./plugin": "./src/index.ts", - "./admin": "./src/admin.tsx" - }, - "files": [ - "src" - ], - "keywords": [ - "emdash", - "cms", - "plugin", - "ai", - "moderation", - "comments", - "llama-guard" - ], - "author": "Matt Kane", - "license": "MIT", - "peerDependencies": { - "emdash": "workspace:*", - "react": "^18.0.0 || ^19.0.0", - "@phosphor-icons/react": "^2.1.10", - "@cloudflare/kumo": "^1.0.0" - }, - "devDependencies": { - "@cloudflare/workers-types": "^4.20250224.0", - "@types/react": "catalog:", - "vitest": "catalog:" - }, - "scripts": { - "test": "vitest run", - "typecheck": "tsgo --noEmit" - }, - "dependencies": {}, - "optionalDependencies": {} + "name": "@emdash-cms/plugin-ai-moderation", + "version": "0.0.2", + "description": "AI-powered comment moderation plugin for EmDash CMS using Cloudflare Workers AI (Llama Guard)", + "type": "module", + "main": "src/descriptor.ts", + "exports": { + ".": "./src/descriptor.ts", + "./plugin": "./src/index.ts", + "./admin": "./src/admin.tsx" + }, + "files": [ + "src" + ], + "keywords": [ + "emdash", + "cms", + "plugin", + "ai", + "moderation", + "comments", + "llama-guard" + ], + "author": "Matt Kane", + "license": "MIT", + "peerDependencies": { + "emdash": "workspace:*", + "react": "^18.0.0 || ^19.0.0", + "@phosphor-icons/react": "^2.1.10", + "@cloudflare/kumo": "^1.0.0" + }, + "devDependencies": { + "@cloudflare/workers-types": "^4.20250224.0", + "@types/react": "catalog:", + "vitest": "catalog:" + }, + "scripts": { + "test": "vitest run", + "typecheck": "tsgo --noEmit" + }, + "dependencies": {}, + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/ai-moderation" + } } diff --git a/packages/plugins/api-test/package.json b/packages/plugins/api-test/package.json index 88817f5..2a3712f 100644 --- a/packages/plugins/api-test/package.json +++ b/packages/plugins/api-test/package.json @@ -1,32 +1,37 @@ { - "name": "@emdash-cms/plugin-api-test", - "private": true, - "version": "0.0.2", - "description": "Test plugin that exercises all EmDash plugin APIs", - "type": "module", - "main": "src/index.ts", - "exports": { - ".": "./src/index.ts", - "./admin": "./src/admin.tsx" - }, - "files": [ - "src" - ], - "keywords": [ - "emdash", - "cms", - "plugin", - "test", - "api" - ], - "author": "Matt Kane", - "license": "MIT", - "peerDependencies": { - "emdash": "workspace:*", - "react": "^18.0.0 || ^19.0.0", - "@phosphor-icons/react": "^2.1.10" - }, - "dependencies": {}, - "devDependencies": {}, - "optionalDependencies": {} -} \ No newline at end of file + "name": "@emdash-cms/plugin-api-test", + "private": true, + "version": "0.0.2", + "description": "Test plugin that exercises all EmDash plugin APIs", + "type": "module", + "main": "src/index.ts", + "exports": { + ".": "./src/index.ts", + "./admin": "./src/admin.tsx" + }, + "files": [ + "src" + ], + "keywords": [ + "emdash", + "cms", + "plugin", + "test", + "api" + ], + "author": "Matt Kane", + "license": "MIT", + "peerDependencies": { + "emdash": "workspace:*", + "react": "^18.0.0 || ^19.0.0", + "@phosphor-icons/react": "^2.1.10" + }, + "dependencies": {}, + "devDependencies": {}, + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/api-test" + } +} diff --git a/packages/plugins/atproto/package.json b/packages/plugins/atproto/package.json index a826779..68dbb7d 100644 --- a/packages/plugins/atproto/package.json +++ b/packages/plugins/atproto/package.json @@ -32,5 +32,10 @@ "scripts": { "test": "vitest run", "typecheck": "tsgo --noEmit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/atproto" } } diff --git a/packages/plugins/audit-log/package.json b/packages/plugins/audit-log/package.json index 6e8f31d..ce29e2b 100644 --- a/packages/plugins/audit-log/package.json +++ b/packages/plugins/audit-log/package.json @@ -1,33 +1,38 @@ { - "name": "@emdash-cms/plugin-audit-log", - "version": "0.0.2", - "description": "Audit logging plugin for EmDash CMS - tracks content changes", - "type": "module", - "main": "src/index.ts", - "exports": { - ".": "./src/index.ts", - "./sandbox": "./src/sandbox-entry.ts" - }, - "files": [ - "src" - ], - "keywords": [ - "emdash", - "cms", - "plugin", - "audit", - "logging", - "history" - ], - "author": "Matt Kane", - "license": "MIT", - "dependencies": {}, - "peerDependencies": { - "emdash": "workspace:*" - }, - "devDependencies": {}, - "scripts": { - "typecheck": "tsgo --noEmit" - }, - "optionalDependencies": {} -} \ No newline at end of file + "name": "@emdash-cms/plugin-audit-log", + "version": "0.0.2", + "description": "Audit logging plugin for EmDash CMS - tracks content changes", + "type": "module", + "main": "src/index.ts", + "exports": { + ".": "./src/index.ts", + "./sandbox": "./src/sandbox-entry.ts" + }, + "files": [ + "src" + ], + "keywords": [ + "emdash", + "cms", + "plugin", + "audit", + "logging", + "history" + ], + "author": "Matt Kane", + "license": "MIT", + "dependencies": {}, + "peerDependencies": { + "emdash": "workspace:*" + }, + "devDependencies": {}, + "scripts": { + "typecheck": "tsgo --noEmit" + }, + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/audit-log" + } +} diff --git a/packages/plugins/color/package.json b/packages/plugins/color/package.json index ce4f444..b467bc9 100644 --- a/packages/plugins/color/package.json +++ b/packages/plugins/color/package.json @@ -30,5 +30,10 @@ }, "scripts": { "typecheck": "tsgo --noEmit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/color" } } diff --git a/packages/plugins/embeds/package.json b/packages/plugins/embeds/package.json index 84beab6..47676a0 100644 --- a/packages/plugins/embeds/package.json +++ b/packages/plugins/embeds/package.json @@ -1,37 +1,42 @@ { - "name": "@emdash-cms/plugin-embeds", - "version": "0.0.2", - "description": "Embed blocks for EmDash CMS - YouTube, Vimeo, Twitter, Bluesky, Mastodon, and more", - "type": "module", - "main": "src/index.ts", - "exports": { - ".": "./src/index.ts", - "./astro": "./src/astro/index.ts" - }, - "files": [ - "src" - ], - "keywords": [ - "emdash", - "cms", - "plugin", - "embed", - "youtube", - "vimeo", - "twitter", - "bluesky" - ], - "author": "Matt Kane", - "license": "MIT", - "peerDependencies": { - "astro": ">=6.0.0-beta.0", - "emdash": "workspace:*" - }, - "dependencies": { - "@emdash-cms/blocks": "workspace:*", - "astro-embed": "^0.12.0" - }, - "scripts": { - "typecheck": "tsgo --noEmit" - } -} \ No newline at end of file + "name": "@emdash-cms/plugin-embeds", + "version": "0.0.2", + "description": "Embed blocks for EmDash CMS - YouTube, Vimeo, Twitter, Bluesky, Mastodon, and more", + "type": "module", + "main": "src/index.ts", + "exports": { + ".": "./src/index.ts", + "./astro": "./src/astro/index.ts" + }, + "files": [ + "src" + ], + "keywords": [ + "emdash", + "cms", + "plugin", + "embed", + "youtube", + "vimeo", + "twitter", + "bluesky" + ], + "author": "Matt Kane", + "license": "MIT", + "peerDependencies": { + "astro": ">=6.0.0-beta.0", + "emdash": "workspace:*" + }, + "dependencies": { + "@emdash-cms/blocks": "workspace:*", + "astro-embed": "^0.12.0" + }, + "scripts": { + "typecheck": "tsgo --noEmit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/embeds" + } +} diff --git a/packages/plugins/forms/package.json b/packages/plugins/forms/package.json index 6e2dd53..8409d45 100644 --- a/packages/plugins/forms/package.json +++ b/packages/plugins/forms/package.json @@ -36,5 +36,10 @@ }, "scripts": { "typecheck": "tsgo --noEmit" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/forms" } } diff --git a/packages/plugins/marketplace-test/package.json b/packages/plugins/marketplace-test/package.json index 357db00..0c5fd84 100644 --- a/packages/plugins/marketplace-test/package.json +++ b/packages/plugins/marketplace-test/package.json @@ -35,5 +35,10 @@ "devDependencies": { "tsdown": "catalog:", "typescript": "catalog:" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/marketplace-test" } } diff --git a/packages/plugins/sandboxed-test/package.json b/packages/plugins/sandboxed-test/package.json index 9c1d9ce..51f0792 100644 --- a/packages/plugins/sandboxed-test/package.json +++ b/packages/plugins/sandboxed-test/package.json @@ -1,41 +1,46 @@ { - "name": "@emdash-cms/plugin-sandboxed-test", - "private": true, - "version": "0.0.2", - "description": "Test plugin for sandboxed plugin system", - "type": "module", - "main": "dist/index.mjs", - "exports": { - ".": { - "import": "./dist/index.mjs", - "types": "./dist/index.d.mts" - }, - "./sandbox": "./dist/sandbox-entry.mjs" - }, - "files": [ - "dist" - ], - "scripts": { - "build": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --clean", - "dev": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --watch", - "typecheck": "tsgo --noEmit" - }, - "keywords": [ - "emdash", - "cms", - "plugin", - "test", - "sandbox" - ], - "author": "Matt Kane", - "license": "MIT", - "dependencies": { - "emdash": "workspace:*" - }, - "devDependencies": { - "tsdown": "catalog:", - "typescript": "catalog:" - }, - "peerDependencies": {}, - "optionalDependencies": {} -} \ No newline at end of file + "name": "@emdash-cms/plugin-sandboxed-test", + "private": true, + "version": "0.0.2", + "description": "Test plugin for sandboxed plugin system", + "type": "module", + "main": "dist/index.mjs", + "exports": { + ".": { + "import": "./dist/index.mjs", + "types": "./dist/index.d.mts" + }, + "./sandbox": "./dist/sandbox-entry.mjs" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --clean", + "dev": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --watch", + "typecheck": "tsgo --noEmit" + }, + "keywords": [ + "emdash", + "cms", + "plugin", + "test", + "sandbox" + ], + "author": "Matt Kane", + "license": "MIT", + "dependencies": { + "emdash": "workspace:*" + }, + "devDependencies": { + "tsdown": "catalog:", + "typescript": "catalog:" + }, + "peerDependencies": {}, + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/sandboxed-test" + } +} diff --git a/packages/plugins/webhook-notifier/package.json b/packages/plugins/webhook-notifier/package.json index 7a5d074..f47dfdb 100644 --- a/packages/plugins/webhook-notifier/package.json +++ b/packages/plugins/webhook-notifier/package.json @@ -1,33 +1,38 @@ { - "name": "@emdash-cms/plugin-webhook-notifier", - "version": "0.0.2", - "description": "Webhook notification plugin for EmDash CMS - posts to external URLs on content changes", - "type": "module", - "main": "src/index.ts", - "exports": { - ".": "./src/index.ts", - "./sandbox": "./src/sandbox-entry.ts" - }, - "files": [ - "src" - ], - "keywords": [ - "emdash", - "cms", - "plugin", - "webhook", - "notifications", - "integration" - ], - "author": "Matt Kane", - "license": "MIT", - "peerDependencies": { - "emdash": "workspace:*" - }, - "devDependencies": {}, - "scripts": { - "typecheck": "tsgo --noEmit" - }, - "dependencies": {}, - "optionalDependencies": {} -} \ No newline at end of file + "name": "@emdash-cms/plugin-webhook-notifier", + "version": "0.0.2", + "description": "Webhook notification plugin for EmDash CMS - posts to external URLs on content changes", + "type": "module", + "main": "src/index.ts", + "exports": { + ".": "./src/index.ts", + "./sandbox": "./src/sandbox-entry.ts" + }, + "files": [ + "src" + ], + "keywords": [ + "emdash", + "cms", + "plugin", + "webhook", + "notifications", + "integration" + ], + "author": "Matt Kane", + "license": "MIT", + "peerDependencies": { + "emdash": "workspace:*" + }, + "devDependencies": {}, + "scripts": { + "typecheck": "tsgo --noEmit" + }, + "dependencies": {}, + "optionalDependencies": {}, + "repository": { + "type": "git", + "url": "git+https://github.com/emdash-cms/emdash.git", + "directory": "packages/plugins/webhook-notifier" + } +}