ship-em 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,7 +7,7 @@ Deploy apps built with AI coding tools (Claude, Cursor, Bolt, Lovable) in 60 sec
7
7
  ## Quick Start
8
8
 
9
9
  ```bash
10
- npx shipem
10
+ npx ship-em
11
11
  ```
12
12
 
13
13
  That's it. Shipem detects your framework, builds your app, and deploys it to a live URL.
@@ -19,17 +19,17 @@ Next.js, Vite, React, Astro, SvelteKit, Nuxt, Remix, Gatsby, Express, FastAPI, F
19
19
  ## Commands
20
20
 
21
21
  ```bash
22
- npx shipem # Deploy your app
23
- npx shipem login # Authenticate with GitHub
24
- npx shipem logout # Log out
25
- npx shipem status # Check deployment status
26
- npx shipem logs # View build logs
27
- npx shipem down # Take your app offline
22
+ npx ship-em # Deploy your app
23
+ npx ship-em login # Authenticate with GitHub
24
+ npx ship-em logout # Log out
25
+ npx ship-em status # Check deployment status
26
+ npx ship-em logs # View build logs
27
+ npx ship-em down # Take your app offline
28
28
  ```
29
29
 
30
30
  ## How it works
31
31
 
32
- 1. **Run `npx shipem`** in your project directory
32
+ 1. **Run `npx ship-em`** in your project directory
33
33
  2. **AI detects your stack** — framework, build command, env vars
34
34
  3. **Your app is live** — deployed to Cloudflare's global network
35
35
 
package/dist/index.js CHANGED
@@ -268,9 +268,9 @@ ${url}`);
268
268
  console.log("");
269
269
  }
270
270
  console.log(` ${brand.bold("Next steps:")}`);
271
- console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx shipem")}`);
272
- console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx shipem status")}`);
273
- console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx shipem down")}`);
271
+ console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx ship-em")}`);
272
+ console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx ship-em status")}`);
273
+ console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx ship-em down")}`);
274
274
  console.log("");
275
275
  },
276
276
  // Format bytes
@@ -348,9 +348,9 @@ ${url}`);
348
348
  console.log("");
349
349
  }
350
350
  console.log(` ${brand.bold("Next steps:")}`);
351
- console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx shipem")}`);
352
- console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx shipem status")}`);
353
- console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx shipem down")}`);
351
+ console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx ship-em")}`);
352
+ console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx ship-em status")}`);
353
+ console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx ship-em down")}`);
354
354
  console.log("");
355
355
  },
356
356
  // Rich status display for deploy history
@@ -1439,7 +1439,7 @@ async function fixCommand(options = {}) {
1439
1439
  ui.dim("Suggestions:");
1440
1440
  ui.dim(" 1. Paste the error into your AI coding tool for a fix");
1441
1441
  ui.dim(" 2. Check the error output above for clues");
1442
- ui.dim(" 3. Run `npx shipem --verbose` for detailed output");
1442
+ ui.dim(" 3. Run `npx ship-em --verbose` for detailed output");
1443
1443
  ui.br();
1444
1444
  return;
1445
1445
  }
@@ -1449,7 +1449,7 @@ async function fixCommand(options = {}) {
1449
1449
  if (buildResult.success) {
1450
1450
  ui.br();
1451
1451
  ui.success("Fixed! Build passes now.");
1452
- ui.dim("Run `npx shipem` to deploy.");
1452
+ ui.dim("Run `npx ship-em` to deploy.");
1453
1453
  ui.br();
1454
1454
  } else {
1455
1455
  ui.br();
@@ -2086,7 +2086,7 @@ function showBuildErrorHelp(errMsg) {
2086
2086
  ui.friendlyError(
2087
2087
  "Your app failed to build",
2088
2088
  errMsg.split("\n")[0] ?? errMsg,
2089
- "Fix the error above, then run `npx shipem` again",
2089
+ "Fix the error above, then run `npx ship-em` again",
2090
2090
  "Tip: If your AI tool generated this code, paste the error back to it for a fix."
2091
2091
  );
2092
2092
  }
@@ -2109,13 +2109,45 @@ async function deployCommand(options) {
2109
2109
  ui.banner();
2110
2110
  }
2111
2111
  const isAnonymous = !getSessionToken() && !getCloudflareCredentials();
2112
+ let sessionToken = getSessionToken();
2112
2113
  if (isFirstRun) {
2113
2114
  console.log(` ${chalk4.white.bold("Welcome to Shipem!")} \u2728`);
2114
2115
  console.log("");
2115
- console.log(` ${chalk4.dim("No account needed. Deploying your app now...")}`);
2116
+ }
2117
+ if (isAnonymous) {
2118
+ console.log(` ${chalk4.dim("To deploy, you need either Cloudflare credentials or a Shipem login.")}`);
2119
+ console.log("");
2120
+ console.log(` ${chalk4.cyan("Option 1:")} Set Cloudflare credentials (free account)`);
2121
+ console.log(` ${chalk4.dim("export CLOUDFLARE_API_TOKEN=your_token")}`);
2122
+ console.log(` ${chalk4.dim("export CLOUDFLARE_ACCOUNT_ID=your_account_id")}`);
2123
+ console.log(` ${chalk4.dim("Get these from: https://dash.cloudflare.com/profile/api-tokens")}`);
2124
+ console.log("");
2125
+ console.log(` ${chalk4.cyan("Option 2:")} Log in to Shipem`);
2126
+ console.log(` ${chalk4.dim("npx ship-em login")}`);
2127
+ console.log("");
2128
+ const { action } = await inquirer.prompt([
2129
+ {
2130
+ type: "list",
2131
+ name: "action",
2132
+ message: "What would you like to do?",
2133
+ choices: [
2134
+ { name: "Log in with GitHub (sets up deployment)", value: "login" },
2135
+ { name: "Quit (I'll set up Cloudflare credentials)", value: "quit" }
2136
+ ]
2137
+ }
2138
+ ]);
2139
+ if (action === "quit") {
2140
+ process.exit(0);
2141
+ }
2142
+ await loginCommand({ skipBanner: true });
2143
+ sessionToken = getSessionToken();
2144
+ if (!sessionToken) {
2145
+ throw new AuthError("Login failed. Please try again with: npx ship-em login");
2146
+ }
2147
+ console.log("");
2148
+ console.log(` ${chalk4.hex("#22C55E")("\u2713")} ${chalk4.bold("Signed in! Continuing deploy...")}`);
2116
2149
  console.log("");
2117
2150
  }
2118
- let sessionToken = getSessionToken();
2119
2151
  phaseStart = Date.now();
2120
2152
  ui.section("Scanning project...");
2121
2153
  ui.br();
@@ -2469,8 +2501,8 @@ async function deployCommand(options) {
2469
2501
  } else {
2470
2502
  uploadSpinner.succeed("Deployed successfully");
2471
2503
  }
2472
- liveUrl = response.data.url;
2473
- projectId = response.data.projectId;
2504
+ liveUrl = response.data.data.url;
2505
+ projectId = response.data.data.projectId;
2474
2506
  } catch (err) {
2475
2507
  if (err instanceof AuthError || err instanceof NetworkError || err instanceof DeployError) {
2476
2508
  throw err;
@@ -2484,99 +2516,7 @@ async function deployCommand(options) {
2484
2516
  }
2485
2517
  }
2486
2518
  } else {
2487
- ui.br();
2488
- ui.warn("No Cloudflare credentials found and not logged in.");
2489
- ui.br();
2490
- console.log(` ${chalk4.bold("To deploy, choose one option:")}`);
2491
- console.log("");
2492
- console.log(` ${chalk4.cyan("Option 1:")} Set Cloudflare credentials (free account)`);
2493
- console.log(` ${chalk4.dim("export CLOUDFLARE_API_TOKEN=your_token")}`);
2494
- console.log(` ${chalk4.dim("export CLOUDFLARE_ACCOUNT_ID=your_account_id")}`);
2495
- console.log(` ${chalk4.dim("Get these from: https://dash.cloudflare.com/profile/api-tokens")}`);
2496
- console.log("");
2497
- console.log(` ${chalk4.cyan("Option 2:")} Log in to Shipem`);
2498
- console.log(` ${chalk4.dim("npx shipem login")}`);
2499
- console.log("");
2500
- const { action } = await inquirer.prompt([
2501
- {
2502
- type: "list",
2503
- name: "action",
2504
- message: "What would you like to do?",
2505
- choices: [
2506
- { name: "Log in with GitHub (sets up deployment)", value: "login" },
2507
- { name: "Quit (I'll set up Cloudflare credentials)", value: "quit" }
2508
- ]
2509
- }
2510
- ]);
2511
- if (action === "quit") {
2512
- process.exit(0);
2513
- }
2514
- await loginCommand({ skipBanner: true });
2515
- sessionToken = getSessionToken();
2516
- if (!sessionToken) {
2517
- throw new AuthError("Login failed. Please try again with: shipem login");
2518
- }
2519
- console.log("");
2520
- console.log(` ${chalk4.hex("#22C55E")("\u2713")} ${chalk4.bold("Signed in!")}`);
2521
- console.log("");
2522
- const tarPath = join8(tmpdir(), `shipem-${Date.now()}.tar.gz`);
2523
- try {
2524
- const outputPath = join8(cwd, projectConfig.outputDirectory);
2525
- warnIfEnvFilesInOutputDir(outputPath);
2526
- const stats = countOutputFiles(outputPath);
2527
- deployFileCount = stats.fileCount;
2528
- deployTotalBytes = stats.totalBytes;
2529
- const packagingSpinner = ui.spinner("Packaging files...");
2530
- await tarCreate(
2531
- {
2532
- gzip: true,
2533
- file: tarPath,
2534
- cwd: outputPath,
2535
- filter: (filePath) => !shouldExclude(filePath, cwd)
2536
- },
2537
- ["."]
2538
- );
2539
- packagingSpinner.succeed(
2540
- `Packaged ${deployFileCount} files (${ui.formatBytes(deployTotalBytes)})`
2541
- );
2542
- const uploadSpinner = ui.spinner("Uploading to cloud...");
2543
- const form = new FormData2();
2544
- form.append("config", JSON.stringify({
2545
- name: projectConfig.name,
2546
- framework: projectConfig.framework,
2547
- deployTarget: projectConfig.deployTarget,
2548
- outputDirectory: projectConfig.outputDirectory
2549
- }));
2550
- form.append("artifacts", createReadStream(tarPath), {
2551
- filename: "artifacts.tar.gz",
2552
- contentType: "application/gzip"
2553
- });
2554
- const response = await apiRequest({
2555
- method: "post",
2556
- url: `${SHIPEM_API_URL}/projects/deploy`,
2557
- data: form,
2558
- headers: {
2559
- ...form.getHeaders(),
2560
- Authorization: `Bearer ${sessionToken}`
2561
- },
2562
- maxBodyLength: Infinity,
2563
- timeout: DEPLOY_TIMEOUT_MS2
2564
- });
2565
- uploadSpinner.succeed("Deployed successfully");
2566
- liveUrl = response.data.url;
2567
- projectId = response.data.projectId;
2568
- } catch (err) {
2569
- if (err instanceof AuthError || err instanceof NetworkError || err instanceof DeployError) {
2570
- throw err;
2571
- }
2572
- const msg = err instanceof Error ? err.message : String(err);
2573
- throw new DeployError(`Deployment failed: ${msg}`, { cause: err });
2574
- } finally {
2575
- try {
2576
- rmSync(tarPath);
2577
- } catch {
2578
- }
2579
- }
2519
+ throw new AuthError("No Cloudflare credentials found and not logged in. Run: npx ship-em login");
2580
2520
  }
2581
2521
  phases.push({ name: "Upload", durationMs: Date.now() - phaseStart });
2582
2522
  const elapsedSec = (Date.now() - startTime) / 1e3;
@@ -2803,63 +2743,50 @@ import chalk5 from "chalk";
2803
2743
  var TEMPLATES = [
2804
2744
  {
2805
2745
  name: "astro-blog",
2806
- description: "Astro blog with Markdown/MDX support and RSS feed",
2746
+ description: "Astro blog with Markdown support",
2807
2747
  framework: "astro",
2808
- createCmd: ["npm", "create", "astro@latest", "--", "--template", "blog"],
2809
- postScaffold: ["npx", "astro", "add", "mdx", "--yes"]
2748
+ createCmd: ["npm", "create", "astro@latest", "--", "--template", "blog"]
2810
2749
  },
2811
2750
  {
2812
2751
  name: "nextjs-saas",
2813
- description: "Next.js SaaS starter with App Router, Tailwind CSS, and TypeScript",
2752
+ description: "Next.js SaaS starter with App Router",
2814
2753
  framework: "nextjs",
2815
- createCmd: ["npx", "create-next-app@latest", "--", "--ts", "--app", "--tailwind", "--eslint", "--src-dir", "--no-import-alias"]
2754
+ createCmd: ["npx", "create-next-app@latest", "--", "--app", "--ts", "--tailwind", "--eslint", "--src-dir"]
2816
2755
  },
2817
2756
  {
2818
2757
  name: "vite-react",
2819
- description: "Vite + React + TypeScript \u2014 fast SPA starter",
2820
- framework: "vite-react",
2758
+ description: "Vite + React + TypeScript starter",
2759
+ framework: "vite",
2821
2760
  createCmd: ["npm", "create", "vite@latest", "--", "--template", "react-ts"]
2822
2761
  },
2823
2762
  {
2824
2763
  name: "sveltekit-app",
2825
- description: "SvelteKit full-stack app with TypeScript",
2764
+ description: "SvelteKit full-stack app",
2826
2765
  framework: "sveltekit",
2827
- createCmd: ["npm", "create", "svelte@latest"]
2766
+ createCmd: ["npx", "sv", "create", "--", "--template", "minimal", "--types", "ts"]
2828
2767
  },
2829
2768
  {
2830
2769
  name: "static-portfolio",
2831
- description: "Minimal static HTML/CSS portfolio \u2014 no build step required",
2832
- framework: "static-html",
2770
+ description: "Simple static HTML/CSS portfolio site",
2771
+ framework: "static",
2833
2772
  createCmd: []
2834
- // No create tool — we scaffold manually
2835
2773
  }
2836
2774
  ];
2837
2775
  function getTemplate(name) {
2838
- return TEMPLATES.find((t) => t.name.toLowerCase() === name.toLowerCase());
2776
+ return TEMPLATES.find((t) => t.name === name);
2839
2777
  }
2840
2778
  function getTemplateNames() {
2841
2779
  return TEMPLATES.map((t) => t.name);
2842
2780
  }
2843
2781
  async function templatesCommand() {
2844
- ui.banner();
2845
- console.log(` ${brand.bold("Available templates")}`);
2846
- console.log(` ${brand.dim("Use with: shipem init --template <name>")}`);
2847
- console.log("");
2848
- const maxNameLen = Math.max(...TEMPLATES.map((t) => t.name.length));
2782
+ ui.section("Available templates");
2783
+ ui.br();
2849
2784
  for (const tpl of TEMPLATES) {
2850
- const padding = " ".repeat(maxNameLen - tpl.name.length);
2851
- console.log(
2852
- ` ${chalk5.cyan(tpl.name)}${padding} ${brand.dim("\u2014")} ${tpl.description}`
2853
- );
2854
- console.log(
2855
- ` ${" ".repeat(maxNameLen)} ${brand.dim(`Framework: ${tpl.framework}`)}`
2856
- );
2857
- console.log("");
2785
+ console.log(` ${chalk5.cyan(tpl.name.padEnd(20))} ${tpl.description}`);
2858
2786
  }
2859
- console.log(` ${brand.bold("Quick start:")}`);
2860
- console.log(` ${chalk5.cyan("npx shipem init --template astro-blog")}`);
2861
- console.log(` ${chalk5.cyan("npx shipem init --template nextjs-saas")}`);
2862
- console.log("");
2787
+ ui.br();
2788
+ ui.dim("Usage: shipem init --template <name>");
2789
+ ui.br();
2863
2790
  }
2864
2791
 
2865
2792
  // src/commands/init.ts
@@ -3010,7 +2937,7 @@ async function initCommand(options = {}) {
3010
2937
  console.log("");
3011
2938
  console.log(` ${brand.green.bold("Ready!")} Now run:`);
3012
2939
  console.log("");
3013
- console.log(` ${chalk6.cyan(`cd ${projectName} && npx shipem`)}`);
2940
+ console.log(` ${chalk6.cyan(`cd ${projectName} && npx ship-em`)}`);
3014
2941
  console.log("");
3015
2942
  }
3016
2943
  async function scaffoldFromTemplate(tpl, options) {
@@ -3091,7 +3018,7 @@ async function scaffoldFromTemplate(tpl, options) {
3091
3018
  console.log("");
3092
3019
  console.log(` ${brand.green.bold("Ready!")} Now run:`);
3093
3020
  console.log("");
3094
- console.log(` ${chalk6.cyan(`cd ${projectName} && npx shipem`)}`);
3021
+ console.log(` ${chalk6.cyan(`cd ${projectName} && npx ship-em`)}`);
3095
3022
  console.log("");
3096
3023
  }
3097
3024
  function createMinimalProject(projectName, description) {
@@ -4122,22 +4049,22 @@ program.name("shipem").description(
4122
4049
  return "";
4123
4050
  }).addHelpText("after", `
4124
4051
  Quick start:
4125
- npx shipem Deploy your app
4126
- npx shipem preview Deploy a preview from your branch
4127
- npx shipem watch Watch for changes and auto-deploy
4128
- npx shipem init Bootstrap a new project
4129
- npx shipem init -t <t> Init from a template
4130
- npx shipem templates List available templates
4131
- npx shipem fix Auto-fix build errors
4132
- npx shipem env Check environment variables
4133
- npx shipem dev Start dev server with deploy shortcut
4134
- npx shipem status Check deployment status
4135
- npx shipem history Show deploy history across projects
4136
- npx shipem monitor Monitor site uptime
4137
- npx shipem hooks Manage git deploy hooks
4138
- npx shipem config Manage global settings
4139
- npx shipem login Authenticate with GitHub
4140
- npx shipem down Take your app offline
4052
+ npx ship-em Deploy your app
4053
+ npx ship-em preview Deploy a preview from your branch
4054
+ npx ship-em watch Watch for changes and auto-deploy
4055
+ npx ship-em init Bootstrap a new project
4056
+ npx ship-em init -t <t> Init from a template
4057
+ npx ship-em templates List available templates
4058
+ npx ship-em fix Auto-fix build errors
4059
+ npx ship-em env Check environment variables
4060
+ npx ship-em dev Start dev server with deploy shortcut
4061
+ npx ship-em status Check deployment status
4062
+ npx ship-em history Show deploy history across projects
4063
+ npx ship-em monitor Monitor site uptime
4064
+ npx ship-em hooks Manage git deploy hooks
4065
+ npx ship-em config Manage global settings
4066
+ npx ship-em login Authenticate with GitHub
4067
+ npx ship-em down Take your app offline
4141
4068
  `);
4142
4069
  program.command("deploy", { isDefault: true }).description("Detect and deploy your app (default command)").option("-y, --yes", "Skip all prompts and use defaults").option("-n, --name <name>", "Override app name").option("--skip-build", "Skip the build step (deploy existing output directory)").option("--turbo", "Skip the build step (alias for --skip-build)").option("--package <name>", "Deploy a specific package from a monorepo").option("--direct", "Deploy directly using your Cloudflare credentials (bypass Shipem API)").option("--verbose", "Show detailed debug output").option("--json", "Output machine-readable JSON instead of human-friendly text").option("--notify [url]", "Send deploy notification to webhook").option("--quiet", "Minimal output (just URL on success)").action(async (options) => {
4143
4070
  globalVerbose = options.verbose ?? false;
package/dist/lib.d.ts CHANGED
@@ -244,9 +244,7 @@ interface Template {
244
244
  postScaffold?: string[];
245
245
  }
246
246
  declare const TEMPLATES: Template[];
247
- /** Look up a template by name (case-insensitive). */
248
247
  declare function getTemplate(name: string): Template | undefined;
249
- /** List all available template names. */
250
248
  declare function getTemplateNames(): string[];
251
249
 
252
250
  export { type AuthConfig, AuthError, BuildError, type BuildResult, type CloudflareCredentials, CloudflarePages, ConfigError, DeployError, type DeployRecord, type DeployTarget, type DeploymentState, type EnvVar, FRAMEWORKS, type Framework, type FrameworkChoice, type MonorepoInfo, NetworkError, type PreviewRecord, type ProjectConfig, SHIPEM_API_URL, type ServerType, type ShipemConfig, ShipemError, TEMPLATES, type Template, buildProject, detectMonorepo, generateProjectName, getCloudflareCredentials, getCurrentBranch, getSessionToken, getTemplate, getTemplateNames, matchFramework, readEnvFile, readProjectConfig, runFixHeuristics, sanitizeBranchName, sanitizeProjectName, scanProject, scanSourceForEnvVars, writeProjectConfig };
package/dist/lib.js CHANGED
@@ -708,9 +708,9 @@ ${url}`);
708
708
  console.log("");
709
709
  }
710
710
  console.log(` ${brand.bold("Next steps:")}`);
711
- console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx shipem")}`);
712
- console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx shipem status")}`);
713
- console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx shipem down")}`);
711
+ console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx ship-em")}`);
712
+ console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx ship-em status")}`);
713
+ console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx ship-em down")}`);
714
714
  console.log("");
715
715
  },
716
716
  // Format bytes
@@ -788,9 +788,9 @@ ${url}`);
788
788
  console.log("");
789
789
  }
790
790
  console.log(` ${brand.bold("Next steps:")}`);
791
- console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx shipem")}`);
792
- console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx shipem status")}`);
793
- console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx shipem down")}`);
791
+ console.log(` ${brand.gray("Update")} \u2192 ${chalk.cyan("npx ship-em")}`);
792
+ console.log(` ${brand.gray("Status")} \u2192 ${chalk.cyan("npx ship-em status")}`);
793
+ console.log(` ${brand.gray("Remove")} \u2192 ${chalk.cyan("npx ship-em down")}`);
794
794
  console.log("");
795
795
  },
796
796
  // Rich status display for deploy history
@@ -1785,39 +1785,37 @@ import chalk4 from "chalk";
1785
1785
  var TEMPLATES = [
1786
1786
  {
1787
1787
  name: "astro-blog",
1788
- description: "Astro blog with Markdown/MDX support and RSS feed",
1788
+ description: "Astro blog with Markdown support",
1789
1789
  framework: "astro",
1790
- createCmd: ["npm", "create", "astro@latest", "--", "--template", "blog"],
1791
- postScaffold: ["npx", "astro", "add", "mdx", "--yes"]
1790
+ createCmd: ["npm", "create", "astro@latest", "--", "--template", "blog"]
1792
1791
  },
1793
1792
  {
1794
1793
  name: "nextjs-saas",
1795
- description: "Next.js SaaS starter with App Router, Tailwind CSS, and TypeScript",
1794
+ description: "Next.js SaaS starter with App Router",
1796
1795
  framework: "nextjs",
1797
- createCmd: ["npx", "create-next-app@latest", "--", "--ts", "--app", "--tailwind", "--eslint", "--src-dir", "--no-import-alias"]
1796
+ createCmd: ["npx", "create-next-app@latest", "--", "--app", "--ts", "--tailwind", "--eslint", "--src-dir"]
1798
1797
  },
1799
1798
  {
1800
1799
  name: "vite-react",
1801
- description: "Vite + React + TypeScript \u2014 fast SPA starter",
1802
- framework: "vite-react",
1800
+ description: "Vite + React + TypeScript starter",
1801
+ framework: "vite",
1803
1802
  createCmd: ["npm", "create", "vite@latest", "--", "--template", "react-ts"]
1804
1803
  },
1805
1804
  {
1806
1805
  name: "sveltekit-app",
1807
- description: "SvelteKit full-stack app with TypeScript",
1806
+ description: "SvelteKit full-stack app",
1808
1807
  framework: "sveltekit",
1809
- createCmd: ["npm", "create", "svelte@latest"]
1808
+ createCmd: ["npx", "sv", "create", "--", "--template", "minimal", "--types", "ts"]
1810
1809
  },
1811
1810
  {
1812
1811
  name: "static-portfolio",
1813
- description: "Minimal static HTML/CSS portfolio \u2014 no build step required",
1814
- framework: "static-html",
1812
+ description: "Simple static HTML/CSS portfolio site",
1813
+ framework: "static",
1815
1814
  createCmd: []
1816
- // No create tool — we scaffold manually
1817
1815
  }
1818
1816
  ];
1819
1817
  function getTemplate(name) {
1820
- return TEMPLATES.find((t) => t.name.toLowerCase() === name.toLowerCase());
1818
+ return TEMPLATES.find((t) => t.name === name);
1821
1819
  }
1822
1820
  function getTemplateNames() {
1823
1821
  return TEMPLATES.map((t) => t.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ship-em",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "One-command deployment for apps built by AI coding tools",
5
5
  "type": "module",
6
6
  "bin": {