create-projx 1.4.2 → 1.4.3

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.
Files changed (3) hide show
  1. package/README.md +16 -6
  2. package/dist/index.js +51 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/create-projx)](https://www.npmjs.com/package/create-projx)
4
4
  [![CI](https://github.com/ukanhaupa/projx/actions/workflows/ci.yml/badge.svg)](https://github.com/ukanhaupa/projx/actions/workflows/ci.yml)
5
+ [![GitHub stars](https://img.shields.io/github/stars/ukanhaupa/projx)](https://github.com/ukanhaupa/projx)
5
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
7
 
7
8
  Production-grade project scaffolder. Pick your stack, get a fully wired project with auth, database, CI/CD, and E2E tests — ready to deploy.
@@ -111,7 +112,7 @@ To skip root-level files (docker-compose, README), add `skip` to `.projx`:
111
112
 
112
113
  ```json
113
114
  {
114
- "version": "1.3.6",
115
+ "version": "1.4.2",
115
116
  "components": ["fastapi", "frontend"],
116
117
  "skip": ["docker-compose.yml", "README.md"]
117
118
  }
@@ -131,10 +132,12 @@ npx create-projx pin <patterns...>
131
132
  npx create-projx unpin <patterns...>
132
133
  npx create-projx pin --list
133
134
  npx create-projx doctor [--fix]
134
- npx create-projx gen entity <name>
135
+ npx create-projx gen entity <name> [--ai | --backend]
135
136
  npx create-projx sync [--url <url>]
136
137
 
137
138
  --components <list> Comma-separated: fastapi,fastify,frontend,mobile,e2e,infra
139
+ --ai Target fastapi (AI/ML) for gen entity
140
+ --backend Target fastify (API backend) for gen entity
138
141
  --no-git Skip git init
139
142
  --no-install Skip dependency installation
140
143
  -y, --yes Accept defaults (fastify + frontend + e2e)
@@ -178,19 +181,26 @@ Checks: config validity, component markers, baseline ref, stale worktrees, skip
178
181
 
179
182
  ### Generate Entities
180
183
 
181
- Scaffold a new entity across all components in your project:
184
+ Scaffold a new entity in your primary backend + typed models for frontend/mobile:
182
185
 
183
186
  ```bash
184
187
  npx create-projx gen entity invoice # interactive
185
188
  npx create-projx gen entity invoice --fields "name:string,amount:number" # non-interactive
189
+ npx create-projx gen entity embedding --ai --fields "name:string,vector:json" # target AI backend
186
190
  ```
187
191
 
188
- Generates based on what's in your `.projx`:
192
+ When both `fastapi` and `fastify` exist, the entity generates in the **primary backend** only (not both). First run prompts you to choose and saves to `.projx`:
193
+
194
+ ```json
195
+ { "primaryBackend": "fastify" }
196
+ ```
197
+
198
+ Override with `--ai` (fastapi) or `--backend` (fastify).
189
199
 
190
200
  | Component | Generated |
191
201
  | --------- | --------- |
192
- | `fastapi` | `src/entities/<name>/_model.py` — auto-discovered by registry |
193
- | `fastify` | `src/modules/<name>/schemas.ts` + `index.ts` + Prisma model + app.ts import |
202
+ | Primary backend (fastapi) | `src/entities/<name>/_model.py` — auto-discovered by registry |
203
+ | Primary backend (fastify) | `src/modules/<name>/schemas.ts` + `index.ts` + Prisma model + app.ts import |
194
204
  | `frontend` | `src/types/<name>.ts` — TypeScript interface + Create/Update variants |
195
205
  | `mobile` | `lib/entities/<name>/model.dart` — Dart class with fromJson/toJson/copyWith |
196
206
 
package/dist/index.js CHANGED
@@ -2622,7 +2622,40 @@ function generateDartModel(config) {
2622
2622
  lines.push("");
2623
2623
  return lines.join("\n");
2624
2624
  }
2625
- async function gen(cwd, entityName, fieldsFlag) {
2625
+ async function resolvePrimaryBackend(cwd, hasFastapi, hasFastify, backendFlag) {
2626
+ if (backendFlag) return backendFlag;
2627
+ if (hasFastapi && !hasFastify) return "fastapi";
2628
+ if (hasFastify && !hasFastapi) return "fastify";
2629
+ const configPath = join12(cwd, ".projx");
2630
+ if (existsSync11(configPath)) {
2631
+ try {
2632
+ const data = JSON.parse(await readFile11(configPath, "utf-8"));
2633
+ if (data.primaryBackend === "fastapi" || data.primaryBackend === "fastify") {
2634
+ return data.primaryBackend;
2635
+ }
2636
+ } catch {
2637
+ }
2638
+ }
2639
+ if (!process.stdin.isTTY) return "fastify";
2640
+ const choice = await p9.select({
2641
+ message: "Both backends detected. Which is your primary?",
2642
+ options: [
2643
+ { value: "fastify", label: "fastify (API backend)" },
2644
+ { value: "fastapi", label: "fastapi (AI/ML engine)" }
2645
+ ],
2646
+ initialValue: "fastify"
2647
+ });
2648
+ if (p9.isCancel(choice)) process.exit(0);
2649
+ try {
2650
+ const data = JSON.parse(await readFile11(configPath, "utf-8"));
2651
+ data.primaryBackend = choice;
2652
+ await writeFile5(configPath, JSON.stringify(data, null, 2) + "\n");
2653
+ p9.log.success(`Saved primaryBackend: ${choice} to .projx`);
2654
+ } catch {
2655
+ }
2656
+ return choice;
2657
+ }
2658
+ async function gen(cwd, entityName, fieldsFlag, backendFlag) {
2626
2659
  p9.intro(`projx gen entity ${entityName}`);
2627
2660
  const configPath = join12(cwd, ".projx");
2628
2661
  if (!existsSync11(configPath)) {
@@ -2638,6 +2671,9 @@ async function gen(cwd, entityName, fieldsFlag) {
2638
2671
  p9.log.error("No backend component found. Need fastapi or fastify.");
2639
2672
  process.exit(1);
2640
2673
  }
2674
+ const targetBackend = await resolvePrimaryBackend(cwd, hasFastapi, hasFastify, backendFlag);
2675
+ const genFastapi = targetBackend === "fastapi" && hasFastapi;
2676
+ const genFastify = targetBackend === "fastify" && hasFastify;
2641
2677
  let config;
2642
2678
  if (fieldsFlag) {
2643
2679
  const fields = parseFieldsFlag(fieldsFlag);
@@ -2658,7 +2694,7 @@ async function gen(cwd, entityName, fieldsFlag) {
2658
2694
  config = await promptEntityConfig(entityName);
2659
2695
  }
2660
2696
  const generated = [];
2661
- if (hasFastapi) {
2697
+ if (genFastapi) {
2662
2698
  const dir = componentPaths.fastapi;
2663
2699
  const entityDir = join12(cwd, dir, "src/entities", toSnake(config.name));
2664
2700
  if (existsSync11(entityDir)) {
@@ -2669,7 +2705,7 @@ async function gen(cwd, entityName, fieldsFlag) {
2669
2705
  generated.push(`${dir}/src/entities/${toSnake(config.name)}/_model.py`);
2670
2706
  }
2671
2707
  }
2672
- if (hasFastify) {
2708
+ if (genFastify) {
2673
2709
  const dir = componentPaths.fastify;
2674
2710
  const moduleDir = join12(cwd, dir, "src/modules", toKebab(config.name));
2675
2711
  if (existsSync11(moduleDir)) {
@@ -2754,13 +2790,13 @@ async function gen(cwd, entityName, fieldsFlag) {
2754
2790
  p9.log.info(` ${f}`);
2755
2791
  }
2756
2792
  const className = toPascal(config.name);
2757
- if (hasFastapi) {
2793
+ if (genFastapi) {
2758
2794
  p9.log.info("");
2759
2795
  p9.log.info("FastAPI next steps:");
2760
2796
  p9.log.info(` alembic revision --autogenerate -m "add ${config.tableName}"`);
2761
2797
  p9.log.info(" alembic upgrade head");
2762
2798
  }
2763
- if (hasFastify) {
2799
+ if (genFastify) {
2764
2800
  p9.log.info("");
2765
2801
  p9.log.info("Fastify next steps:");
2766
2802
  p9.log.info(` npx prisma migrate dev --name add_${toSnake(config.name)}`);
@@ -3146,6 +3182,14 @@ function parseArgs() {
3146
3182
  flags.fix = true;
3147
3183
  continue;
3148
3184
  }
3185
+ if (arg === "--ai") {
3186
+ flags.ai = true;
3187
+ continue;
3188
+ }
3189
+ if (arg === "--backend") {
3190
+ flags.backend = true;
3191
+ continue;
3192
+ }
3149
3193
  if (arg === "--url") {
3150
3194
  const val = args[++i];
3151
3195
  if (val) extraArgs.push(`--url=${val}`);
@@ -3266,7 +3310,8 @@ async function main() {
3266
3310
  const entityName = extraArgs[1];
3267
3311
  const fieldsArg = extraArgs.find((a) => a.startsWith("--fields="));
3268
3312
  const fieldsFlag = fieldsArg ? fieldsArg.split("=").slice(1).join("=") : void 0;
3269
- await gen(process.cwd(), entityName, fieldsFlag);
3313
+ const backendFlag = flags.ai ? "fastapi" : flags.backend ? "fastify" : void 0;
3314
+ await gen(process.cwd(), entityName, fieldsFlag, backendFlag);
3270
3315
  return;
3271
3316
  }
3272
3317
  let opts;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-projx",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "Scaffold production-grade fullstack projects in seconds. FastAPI, Fastify, React, Flutter, Terraform — with auth, database, CI/CD, E2E tests, and Docker. One command, ready to deploy.",
5
5
  "type": "module",
6
6
  "bin": {