create-factory 0.3.1-alpha.4 → 0.4.0-alpha.6

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
@@ -33,7 +33,7 @@ pnpm create factory@latest
33
33
 
34
34
  The interactive setup asks where to create the project and helps configure your Mastra Factory project.
35
35
 
36
- By default, the setup wizard provisions Mastra platform resources during setup, enabling you to fully run Mastra Factory on platform or locally with cloud-backed capabilities. If you prefer to [self-host](https://factory.mastra.ai/deployment#self-host) Mastra Factory, run the setup with the `--no-platform` flag.
36
+ By default, the setup wizard scaffolds the [platform template](https://github.com/mastra-ai/template-factory) and provisions Mastra platform resources during setup, enabling you to fully run Mastra Factory on platform or locally with cloud-backed capabilities. If you prefer to [self-host](https://factory.mastra.ai/deployment#self-host) Mastra Factory, run the setup with the `--no-platform` flag. It scaffolds the [self-hosted template](https://github.com/mastra-ai/template-factory-self-hosted) instead, which uses PostgreSQL, WorkOS, a GitHub App, and local sandboxes. Either way, the setup writes a freshly generated `FACTORY_CREDENTIAL_ENCRYPTION_KEY` to `.env` when the template uses one, so stored credentials are encrypted from the first start.
37
37
 
38
38
  ```bash
39
39
  npx create-factory@latest -- --no-platform
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { Command } from "commander";
6
6
  import { PosthogAnalytics, setAnalytics } from "mastra/dist/analytics/index.js";
7
+ import { randomBytes } from "node:crypto";
7
8
  import * as p from "@clack/prompts";
8
9
  import { LoginCancelledError, MASTRA_PLATFORM_API_URL, authHeaders, extractApiErrorDetail, fetchOrgs, getToken, loadCredentials, platformFetch, resolveCurrentOrg } from "mastra/internal/auth";
9
10
  import color from "picocolors";
@@ -317,7 +318,6 @@ function getInstallArgs(packageManager) {
317
318
  default: return ["install"];
318
319
  }
319
320
  }
320
- // src/create.ts
321
321
  const PROJECT_REGION_OPTIONS = [{
322
322
  value: "eu",
323
323
  label: "🇪🇺 eu"
@@ -357,13 +357,14 @@ async function create(args) {
357
357
  const spinner = p.spinner();
358
358
  spinner.start("Downloading the Mastra Factory template...");
359
359
  try {
360
- await cloneTemplate(args.template, projectPath);
360
+ await cloneTemplate(args.template ?? (args.noPlatform ? "https://github.com/mastra-ai/template-factory-self-hosted" : "https://github.com/mastra-ai/template-factory"), projectPath);
361
361
  await renameProject(projectPath, projectName);
362
362
  const envPath = path.join(projectPath, ".env");
363
363
  fs.copyFileSync(path.join(projectPath, ".env.example"), envPath);
364
364
  try {
365
365
  fs.chmodSync(envPath, 384);
366
366
  } catch {}
367
+ seedCredentialEncryptionKey(envPath);
367
368
  spinner.stop("Template downloaded.");
368
369
  } catch (err) {
369
370
  spinner.stop("Template download failed.");
@@ -599,6 +600,17 @@ function sanitizeDatabaseName(projectName) {
599
600
  return (projectName.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/^-+|-+$/g, "") || "factory").slice(0, 64);
600
601
  }
601
602
  /**
603
+ * Fill the template's empty `FACTORY_CREDENTIAL_ENCRYPTION_KEY` placeholder
604
+ * with a fresh AES-256 key so stored credentials are encrypted from the first
605
+ * boot. Templates that don't declare the key, or that already set one, are
606
+ * left alone.
607
+ */
608
+ function seedCredentialEncryptionKey(envPath) {
609
+ const env = fs.readFileSync(envPath, "utf8");
610
+ if (!/^\s*(#\s*)?FACTORY_CREDENTIAL_ENCRYPTION_KEY\s*=\s*$/m.test(env)) return;
611
+ upsertEnvFile(envPath, { FACTORY_CREDENTIAL_ENCRYPTION_KEY: randomBytes(32).toString("base64") });
612
+ }
613
+ /**
602
614
  * Append `.env` to the scaffolded project's `.gitignore` if it isn't already
603
615
  * ignored. Runs before the initial `git add -A` so freshly-provisioned platform
604
616
  * credentials (MASTRA_PLATFORM_SECRET_KEY, DATABASE_URL) never reach the
@@ -673,12 +685,11 @@ const analytics = new PosthogAnalytics({
673
685
  });
674
686
  setAnalytics(analytics);
675
687
  const program = new Command();
676
- const DEFAULT_TEMPLATE_REPO = "https://github.com/mastra-ai/softwarefactory-template";
677
- program.name("create-factory").description("Create a new Mastra Factory project").argument("[project-name]", "Directory name of the project").option("--template <template-name>", "Create a project from a template (public GitHub URL)", DEFAULT_TEMPLATE_REPO).option("--no-platform", "Skip Mastra platform sign-in, project, and Neon provisioning").option("--org <org>", "Mastra organization id or name — skips the interactive org picker").option("--region <region>", "Platform project region (eu or us); prompts when omitted").version(pkg.version, "-v, --version").action(async (projectNameArg, args) => {
688
+ program.name("create-factory").description("Create a new Mastra Factory project").argument("[project-name]", "Directory name of the project").option("--template <template-name>", "Create a project from a template (public GitHub URL). Defaults to the platform template, or the self-hosted template with --no-platform").option("--no-platform", "Skip Mastra platform provisioning and scaffold the self-hosted template").option("--org <org>", "Mastra organization id or name — skips the interactive org picker").option("--region <region>", "Platform project region (eu or us); prompts when omitted").version(pkg.version, "-v, --version").action(async (projectNameArg, args) => {
678
689
  const region = args.region ? String(args.region) : void 0;
679
690
  const validRegion = region === "eu" || region === "us" ? region : void 0;
680
691
  const sensitiveValues = [
681
- args.template === DEFAULT_TEMPLATE_REPO ? void 0 : args.template,
692
+ args.template,
682
693
  args.org ? String(args.org) : void 0,
683
694
  validRegion ? void 0 : region,
684
695
  projectNameArg
@@ -688,7 +699,7 @@ program.name("create-factory").description("Create a new Mastra Factory project"
688
699
  await analytics.trackCommandExecution({
689
700
  command: "create-factory",
690
701
  args: {
691
- default_template: args.template === DEFAULT_TEMPLATE_REPO,
702
+ default_template: args.template === void 0,
692
703
  no_platform: args.platform === false,
693
704
  has_org: Boolean(args.org),
694
705
  region: validRegion ?? (region ? "invalid" : void 0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-factory",
3
- "version": "0.3.1-alpha.4",
3
+ "version": "0.4.0-alpha.6",
4
4
  "description": "Create a Mastra Factory project: an agent-powered software delivery environment built on Mastra. Run `npm create factory` to scaffold and get started.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -36,7 +36,7 @@
36
36
  "commander": "^14.0.3",
37
37
  "picocolors": "^1.1.1",
38
38
  "tinyexec": "^1.3.1",
39
- "mastra": "1.36.0-alpha.4"
39
+ "mastra": "1.36.0-alpha.6"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "22.19.15",