@trailer-park-oss/create-rn-ai-starter 0.1.1 → 0.1.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.
package/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # create-rn-ai-starter
2
+
3
+ CLI to scaffold Expo React Native projects with modular feature packs — including built-in AI chat powered by OpenRouter or on-device ML Kit.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx create-rn-ai-starter my-app
9
+ ```
10
+
11
+ This launches an interactive wizard that walks you through each option. To skip prompts and accept all defaults:
12
+
13
+ ```bash
14
+ npx create-rn-ai-starter my-app --yes
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```
20
+ create-rn-ai-starter <project-path> [options]
21
+ ```
22
+
23
+ The `<project-path>` argument can be a plain name, a relative path, an absolute path, or `.` to scaffold in the current (empty) directory. The project name is derived from the last segment of the path.
24
+
25
+ ```bash
26
+ npx create-rn-ai-starter my-app # creates ./my-app
27
+ npx create-rn-ai-starter ./projects/my-app # creates ./projects/my-app
28
+ npx create-rn-ai-starter /absolute/path/my-app # creates /absolute/path/my-app
29
+ npx create-rn-ai-starter . # scaffolds in cwd (must be empty)
30
+ ```
31
+
32
+ ### Options
33
+
34
+ | Flag | Values | Default |
35
+ | --- | --- | --- |
36
+ | `--ui <provider>` | `tamagui` \| `gluestack` | `tamagui` |
37
+ | `--auth <provider>` | `clerk` \| `none` | `none` |
38
+ | `--preset <theme>` | `radix-blue` \| `radix-green` \| `radix-purple` \| `radix-orange` \| `radix-cyan` \| `radix-red` | `radix-blue` |
39
+ | `--yes` | — | Skip prompts, use defaults for unset flags |
40
+
41
+ > **Note:** AI, payments, and DX profile options are not yet exposed as CLI flags. The generated project always includes the AI pack (defaults to `online-openrouter`). Payments defaults to `none` and DX defaults to `basic`.
42
+
43
+ ### Examples
44
+
45
+ Scaffold with all defaults (no prompts):
46
+
47
+ ```bash
48
+ npx create-rn-ai-starter my-app --yes
49
+ ```
50
+
51
+ Pick specific providers:
52
+
53
+ ```bash
54
+ npx create-rn-ai-starter my-app --ui gluestack --auth clerk --preset radix-purple
55
+ ```
56
+
57
+ Mix flags with interactive prompts for the rest:
58
+
59
+ ```bash
60
+ npx create-rn-ai-starter my-app --ui tamagui
61
+ ```
62
+
63
+ Interactive prompt order is: `ui -> auth -> preset`.
64
+
65
+ Scaffold inside an existing projects folder:
66
+
67
+ ```bash
68
+ npx create-rn-ai-starter ./work/my-app --yes
69
+ ```
70
+
71
+ Scaffold in the current directory:
72
+
73
+ ```bash
74
+ mkdir my-app && cd my-app
75
+ npx create-rn-ai-starter . --yes
76
+ ```
77
+
78
+ ## What Gets Generated
79
+
80
+ The CLI creates a new Expo project with:
81
+
82
+ - **Core** — Expo Router file-based routing, onboarding flow (3 screens), tab navigation (Home, AI, Settings), login button, Zustand stores, React Query setup, provider resolvers, and a `starter.config.ts` manifest.
83
+ - **UI** — Full design system with canonical tokens (colors, spacing, radius, typography), `ThemeProvider` with animated transitions, MMKV-persisted theme store, and library-specific components (Card, PrimaryButton, StatusBanner). Screens import directly from the selected UI library via the kit pattern — `tamagui` or `@gluestack-ui/themed`.
84
+ - **AI** — AI chat screen with a shared provider interface (`ai.interface.ts`). Two back-end implementations:
85
+ - **OpenRouter** (`online-openrouter`, default) — streaming chat client, `useChat` / `useAiChat` hooks, and env config for API keys.
86
+ - **ML Kit** (`on-device-mlkit`) — on-device object detection via `@infinitered/react-native-mlkit-object-detection`, vision hook, and camera/image-picker integration.
87
+ - **Auth** — Auth provider wiring, `(auth)` route group, and login button (when not `none`).
88
+ - **DX** — Developer experience profile (linting, formatting, TypeScript strictness).
89
+
90
+ After scaffolding, the CLI installs dependencies and runs validation checks to make sure everything is wired correctly.
91
+
92
+ ### UI library selection
93
+
94
+ Screens use the selected library's components directly — no abstraction layer:
95
+
96
+ - `--ui tamagui` → screens import `YStack`, `Text` from `'tamagui'`
97
+ - `--ui gluestack` → screens import `VStack`, `Text` from `'@gluestack-ui/themed'`
98
+
99
+ This is powered by a **kit pattern** in the CLI templates: a plain object maps component names and import paths per library, so screen templates are written once with EJS variables and produce clean, idiomatic output for each library.
100
+
101
+ ### AI providers
102
+
103
+ Every generated project includes an AI tab with a chat interface. The provider is selected at scaffold time (defaults to OpenRouter):
104
+
105
+ - **OpenRouter** — calls cloud LLMs via the OpenRouter API with streaming responses. Requires an `OPENROUTER_API_KEY` environment variable at runtime.
106
+ - **ML Kit** — runs object detection on-device using React Native ML Kit. No API key needed; works fully offline.
107
+
108
+ Both providers implement a shared `AiChatProvider` interface so swapping later is straightforward.
109
+
110
+ ### Theme presets
111
+
112
+ All Radix-based presets include light and dark mode palettes:
113
+
114
+ - `--preset radix-blue` — Blue accent palette
115
+ - `--preset radix-green` — Green accent palette
116
+ - `--preset radix-purple` — Purple accent palette
117
+ - `--preset radix-orange` — Orange accent palette
118
+ - `--preset radix-cyan` — Cyan accent palette
119
+ - `--preset radix-red` — Red accent palette
120
+
121
+ Theme selection persists across app restarts via Zustand persist middleware.
122
+
123
+ ## Generated Project Structure
124
+
125
+ ```
126
+ my-app/
127
+ ├── app/
128
+ │ ├── _layout.tsx # Root layout — SafeAreaProvider, QueryClient, ThemeProvider
129
+ │ ├── index.tsx # Entry redirect (splash handling)
130
+ │ ├── (onboarding)/
131
+ │ │ ├── _layout.tsx # Stack navigator
132
+ │ │ ├── welcome.tsx # Uses YStack/VStack + design tokens
133
+ │ │ ├── features.tsx
134
+ │ │ └── get-started.tsx
135
+ │ ├── (app)/
136
+ │ │ ├── _layout.tsx # Tab navigator (Home, AI, Settings)
137
+ │ │ ├── index.tsx # Home screen with login button
138
+ │ │ ├── ai.tsx # AI chat screen
139
+ │ │ └── settings.tsx
140
+ │ └── (auth)/ # (generated when auth ≠ none)
141
+ │ └── _layout.tsx
142
+ ├── src/
143
+ │ ├── starter.config.ts # Selected providers & modes
144
+ │ ├── design-system/
145
+ │ │ ├── index.ts # Barrel export (resolveTokens, useTokens, ThemeProvider, elevation)
146
+ │ │ ├── tokens.ts # Canonical tokens — colors, spacing, radius, typography
147
+ │ │ ├── ThemeProvider.tsx # Reads store, resolves tokens, animated theme transitions
148
+ │ │ └── elevation.ts # Platform-aware card/modal/toast shadows
149
+ │ ├── components/
150
+ │ │ ├── Card.tsx # Animated card with haptics — uses tamagui or gluestack directly
151
+ │ │ ├── PrimaryButton.tsx # Animated button with haptics
152
+ │ │ └── StatusBanner.tsx # Success/warning/critical/info banners
153
+ │ ├── store/
154
+ │ │ ├── index.ts # Barrel export
155
+ │ │ ├── onboarding.ts # Zustand — onboarding state
156
+ │ │ └── theme.ts # Zustand + MMKV persist — preset & colorMode
157
+ │ ├── lib/
158
+ │ │ ├── query-client.ts # TanStack Query client
159
+ │ │ └── mmkv-storage.ts # MMKV instance + Zustand StateStorage adapter
160
+ │ └── providers/
161
+ │ ├── ui/
162
+ │ │ ├── index.ts # Resolver — tamagui or gluestack
163
+ │ │ └── tamagui/ # (or gluestack/) — library-specific config & provider
164
+ │ ├── ai/
165
+ │ │ ├── ai.interface.ts # Shared AI provider interface
166
+ │ │ ├── index.ts # Barrel export
167
+ │ │ └── openrouter/ # (or mlkit/) — provider-specific implementation
168
+ │ │ ├── client.ts # Streaming OpenRouter API client
169
+ │ │ ├── useChat.ts # Chat hook with message history
170
+ │ │ ├── useAiChat.ts # High-level chat hook
171
+ │ │ ├── env.ts # API key configuration
172
+ │ │ └── index.ts
173
+ │ ├── auth/index.ts # Resolver — clerk or no-op stub
174
+ │ └── payments/index.ts # Resolver — stripe or no-op stub
175
+ ├── tamagui.config.ts # (only when --ui tamagui)
176
+ ├── app.json
177
+ ├── tsconfig.json # strict, noUncheckedIndexedAccess, @/* alias
178
+ └── package.json
179
+ ```
180
+
181
+ ## After Scaffolding
182
+
183
+ ```bash
184
+ cd my-app
185
+ npx expo start
186
+ ```
187
+
188
+ For OpenRouter AI, set your API key before running:
189
+
190
+ ```bash
191
+ OPENROUTER_API_KEY=sk-or-... npx expo start
192
+ ```
193
+
194
+ ## Development
195
+
196
+ ```bash
197
+ npm install
198
+ npm run build # compile with tsup
199
+ npm run dev # compile in watch mode
200
+ npm test # run tests with vitest
201
+ npm run typecheck # type-check without emitting
202
+ ```
203
+
204
+ ## Requirements
205
+
206
+ - Node.js >= 18
package/dist/index.js CHANGED
@@ -8,18 +8,16 @@ import { select } from "@inquirer/prompts";
8
8
  var ALLOWED_VALUES = {
9
9
  ui: ["tamagui", "gluestack"],
10
10
  auth: ["clerk", "none"],
11
- // ai: ['on-device-mlkit', 'online-openrouter'] as readonly AiProvider[],
12
- // payments: ['stripe', 'none'] as readonly PaymentsProvider[],
13
- // dx: ['basic', 'full'] as readonly DxProfile[],
14
- preset: ["radix-blue", "radix-green", "radix-purple", "radix-orange", "radix-cyan", "radix-red"]
11
+ payments: ["stripe", "none"],
12
+ dx: ["basic", "full"],
13
+ preset: ["neutral-green", "fluent-blue"]
15
14
  };
16
15
  var DEFAULT_CONFIG = {
17
16
  ui: "tamagui",
18
17
  auth: "none",
19
- ai: "online-openrouter",
20
18
  payments: "none",
21
19
  dx: "basic",
22
- preset: "radix-blue"
20
+ preset: "neutral-green"
23
21
  };
24
22
 
25
23
  // src/generator.ts
@@ -115,7 +113,6 @@ function buildTemplateData(ctx) {
115
113
  projectName: ctx.projectName,
116
114
  ui: ctx.config.ui,
117
115
  auth: ctx.config.auth,
118
- ai: ctx.config.ai,
119
116
  payments: ctx.config.payments,
120
117
  dx: ctx.config.dx,
121
118
  preset: ctx.config.preset,
@@ -210,7 +207,6 @@ function buildTemplateData2(ctx) {
210
207
  projectName: ctx.projectName,
211
208
  ui: ctx.config.ui,
212
209
  auth: ctx.config.auth,
213
- ai: ctx.config.ai,
214
210
  payments: ctx.config.payments,
215
211
  dx: ctx.config.dx,
216
212
  preset: ctx.config.preset,
@@ -301,7 +297,6 @@ function buildTemplateData3(ctx) {
301
297
  projectName: ctx.projectName,
302
298
  ui: ctx.config.ui,
303
299
  auth: ctx.config.auth,
304
- ai: ctx.config.ai,
305
300
  payments: ctx.config.payments,
306
301
  dx: ctx.config.dx,
307
302
  preset: ctx.config.preset,
@@ -318,7 +313,7 @@ async function check3(name, fn) {
318
313
  var authPack = {
319
314
  id: "auth",
320
315
  dependencies: {
321
- "@clerk/expo": "npm:@clerk/clerk-expo@^2.19.30",
316
+ "@clerk/expo": "^2.2.0",
322
317
  "@hookform/resolvers": "^3.9.0"
323
318
  },
324
319
  devDependencies: {},
@@ -376,78 +371,6 @@ var authPack = {
376
371
  }
377
372
  };
378
373
 
379
- // src/packs/ai/index.ts
380
- function buildTemplateData4(ctx) {
381
- return {
382
- projectName: ctx.projectName,
383
- ui: ctx.config.ui,
384
- auth: ctx.config.auth,
385
- ai: ctx.config.ai,
386
- payments: ctx.config.payments,
387
- dx: ctx.config.dx,
388
- preset: ctx.config.preset,
389
- hasAuth: ctx.config.auth !== "none",
390
- hasPayments: ctx.config.payments !== "none",
391
- isFullDx: ctx.config.dx === "full",
392
- uiKit: getUIKit(ctx.config.ui)
393
- };
394
- }
395
- async function check4(name, fn) {
396
- const passed = await fn();
397
- return { name, passed, message: passed ? void 0 : "File not found" };
398
- }
399
- function createAiPack(config) {
400
- const isOpenRouter = config.ai === "online-openrouter";
401
- const expoInstallPackages = isOpenRouter ? ["expo-image-picker"] : [
402
- "@infinitered/react-native-mlkit-object-detection",
403
- "expo-image-picker"
404
- ];
405
- return {
406
- id: "ai",
407
- dependencies: {},
408
- devDependencies: {},
409
- expoInstallPackages,
410
- ownedPaths: [
411
- "src/providers/ai/",
412
- "app/(app)/ai.tsx"
413
- ],
414
- async generate(ctx) {
415
- const data = buildTemplateData4(ctx);
416
- ctx.logger.info("Generating shared AI provider templates");
417
- await renderTemplates("ai", ctx.projectDir, data);
418
- if (isOpenRouter) {
419
- ctx.logger.info("Generating OpenRouter AI templates");
420
- await renderTemplates("ai-openrouter", ctx.projectDir, data);
421
- } else {
422
- ctx.logger.info("Generating ML Kit AI templates");
423
- await renderTemplates("ai-mlkit", ctx.projectDir, data);
424
- }
425
- },
426
- async postApplyValidation(ctx) {
427
- const sharedChecks = [
428
- check4("AI interface exists", () => fileExists(ctx.projectDir, "src/providers/ai/ai.interface.ts")),
429
- check4("AI barrel export exists", () => fileExists(ctx.projectDir, "src/providers/ai/index.ts")),
430
- check4("AI screen exists", () => fileExists(ctx.projectDir, "app/(app)/ai.tsx"))
431
- ];
432
- const providerChecks = isOpenRouter ? [
433
- check4("OpenRouter client exists", () => fileExists(ctx.projectDir, "src/providers/ai/openrouter/client.ts")),
434
- check4("OpenRouter useChat hook exists", () => fileExists(ctx.projectDir, "src/providers/ai/openrouter/useChat.ts")),
435
- check4("OpenRouter env config exists", () => fileExists(ctx.projectDir, "src/providers/ai/openrouter/env.ts")),
436
- check4("OpenRouter barrel export exists", () => fileExists(ctx.projectDir, "src/providers/ai/openrouter/index.ts"))
437
- ] : [
438
- check4("MLKit provider exists", () => fileExists(ctx.projectDir, "src/providers/ai/mlkit/MLKitProvider.tsx")),
439
- check4("MLKit vision hook exists", () => fileExists(ctx.projectDir, "src/providers/ai/mlkit/useVision.ts")),
440
- check4("MLKit barrel export exists", () => fileExists(ctx.projectDir, "src/providers/ai/mlkit/index.ts"))
441
- ];
442
- const checks = await Promise.all([...sharedChecks, ...providerChecks]);
443
- return {
444
- passed: checks.every((c) => c.passed),
445
- checks
446
- };
447
- }
448
- };
449
- }
450
-
451
374
  // src/packs/payments/index.ts
452
375
  var STRIPE_STUB = `// TODO: Prompt 4 \u2014 replace with real Stripe integration
453
376
  export function usePayments() {
@@ -500,7 +423,6 @@ function getActivePacks(config) {
500
423
  corePack,
501
424
  createUiPack(config),
502
425
  authPack,
503
- createAiPack(config),
504
426
  paymentsPack,
505
427
  dxPack
506
428
  ];
@@ -514,8 +436,6 @@ function isPackEnabled(id, config) {
514
436
  return true;
515
437
  case "auth":
516
438
  return config.auth !== "none";
517
- case "ai":
518
- return true;
519
439
  case "payments":
520
440
  return config.payments !== "none";
521
441
  case "dx":
@@ -596,15 +516,17 @@ function printSummary(logger, config, results, projectDir) {
596
516
  logger.info("Configuration:");
597
517
  logger.info(` UI: ${config.ui}`);
598
518
  logger.info(` Auth: ${config.auth}`);
519
+ logger.info(` Payments: ${config.payments}`);
520
+ logger.info(` DX: ${config.dx}`);
599
521
  logger.info(` Preset: ${config.preset}`);
600
522
  logger.info("");
601
523
  let allPassed = true;
602
524
  for (const { packId, result } of results) {
603
- for (const check5 of result.checks) {
604
- if (check5.passed) {
605
- logger.success(`[${packId}] ${check5.name}`);
525
+ for (const check4 of result.checks) {
526
+ if (check4.passed) {
527
+ logger.success(`[${packId}] ${check4.name}`);
606
528
  } else {
607
- logger.error(`[${packId}] ${check5.name}${check5.message ? ` \u2014 ${check5.message}` : ""}`);
529
+ logger.error(`[${packId}] ${check4.name}${check4.message ? ` \u2014 ${check4.message}` : ""}`);
608
530
  allPassed = false;
609
531
  }
610
532
  }
@@ -695,12 +617,14 @@ function createLogger() {
695
617
 
696
618
  // src/cli.ts
697
619
  async function run() {
698
- const program = new Command().name("create-rn-ai-starter").description("Scaffold an Expo React Native project with modular feature packs").argument("<project-path>", "Name or path for the new project (e.g. my-app, ./projects/my-app, .)").option("--ui <provider>", `UI library: ${ALLOWED_VALUES.ui.join(" | ")}`).option("--auth <provider>", `Auth provider: ${ALLOWED_VALUES.auth.join(" | ")}`).option("--preset <theme>", `Theme preset: ${ALLOWED_VALUES.preset.join(" | ")}`).option("--yes", "Skip interactive prompts, use defaults for unset flags").action(async (projectPath, opts) => {
620
+ const program = new Command().name("create-rn-ai-starter").description("Scaffold an Expo React Native project with modular feature packs").argument("<project-path>", "Name or path for the new project (e.g. my-app, ./projects/my-app, .)").option("--ui <provider>", `UI library: ${ALLOWED_VALUES.ui.join(" | ")}`).option("--auth <provider>", `Auth provider: ${ALLOWED_VALUES.auth.join(" | ")}`).option("--payments <provider>", `Payments provider: ${ALLOWED_VALUES.payments.join(" | ")}`).option("--dx <profile>", `DX profile: ${ALLOWED_VALUES.dx.join(" | ")}`).option("--preset <theme>", `Theme preset: ${ALLOWED_VALUES.preset.join(" | ")}`).option("--yes", "Skip interactive prompts, use defaults for unset flags").action(async (projectPath, opts) => {
699
621
  const logger = createLogger();
700
622
  const { projectName, projectDir } = await resolveProjectPath(projectPath);
701
623
  const partial = {};
702
624
  if (opts["ui"]) partial.ui = opts["ui"];
703
625
  if (opts["auth"]) partial.auth = opts["auth"];
626
+ if (opts["payments"]) partial.payments = opts["payments"];
627
+ if (opts["dx"]) partial.dx = opts["dx"];
704
628
  if (opts["preset"]) partial.preset = opts["preset"];
705
629
  const config = opts["yes"] ? { ...DEFAULT_CONFIG, ...partial } : await promptForMissing(partial);
706
630
  validateConfig(config);
@@ -724,6 +648,20 @@ async function promptForMissing(partial) {
724
648
  default: DEFAULT_CONFIG.auth
725
649
  });
726
650
  }
651
+ if (!partial.payments) {
652
+ config.payments = await select({
653
+ message: "Which payments provider?",
654
+ choices: ALLOWED_VALUES.payments.map((v) => ({ value: v, name: v })),
655
+ default: DEFAULT_CONFIG.payments
656
+ });
657
+ }
658
+ if (!partial.dx) {
659
+ config.dx = await select({
660
+ message: "Which DX profile?",
661
+ choices: ALLOWED_VALUES.dx.map((v) => ({ value: v, name: v })),
662
+ default: DEFAULT_CONFIG.dx
663
+ });
664
+ }
727
665
  if (!partial.preset) {
728
666
  config.preset = await select({
729
667
  message: "Which theme preset?",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/config.ts","../src/generator.ts","../src/utils/template.ts","../src/utils/fs.ts","../src/packs/ui/kits.ts","../src/packs/core/index.ts","../src/packs/ui/index.ts","../src/packs/auth/index.ts","../src/packs/ai/index.ts","../src/packs/payments/index.ts","../src/packs/dx/index.ts","../src/pack-registry.ts","../src/utils/package-json.ts","../src/utils/validation.ts","../src/utils/logger.ts","../src/index.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { select } from '@inquirer/prompts'\nimport { DEFAULT_CONFIG, ALLOWED_VALUES } from '@/config.js'\nimport { runGenerator } from '@/generator.js'\nimport { resolveProjectPath, validateConfig } from '@/utils/validation.js'\nimport { createLogger } from '@/utils/logger.js'\nimport type { StarterConfig } from '@/types.js'\n\nexport async function run(): Promise<void> {\n const program = new Command()\n .name('create-rn-ai-starter')\n .description('Scaffold an Expo React Native project with modular feature packs')\n .argument('<project-path>', 'Name or path for the new project (e.g. my-app, ./projects/my-app, .)')\n .option('--ui <provider>', `UI library: ${ALLOWED_VALUES.ui.join(' | ')}`)\n .option('--auth <provider>', `Auth provider: ${ALLOWED_VALUES.auth.join(' | ')}`)\n // .option('--ai <provider>', `AI implementation: ${ALLOWED_VALUES.ai.join(' | ')}`)\n // .option('--payments <provider>', `Payments provider: ${ALLOWED_VALUES.payments.join(' | ')}`)\n // .option('--dx <profile>', `DX profile: ${ALLOWED_VALUES.dx.join(' | ')}`)\n .option('--preset <theme>', `Theme preset: ${ALLOWED_VALUES.preset.join(' | ')}`)\n .option('--yes', 'Skip interactive prompts, use defaults for unset flags')\n .action(async (projectPath: string, opts: Record<string, string | boolean | undefined>) => {\n const logger = createLogger()\n\n const { projectName, projectDir } = await resolveProjectPath(projectPath)\n\n const partial: Partial<StarterConfig> = {}\n if (opts['ui']) partial.ui = opts['ui'] as StarterConfig['ui']\n if (opts['auth']) partial.auth = opts['auth'] as StarterConfig['auth']\n // if (opts['ai']) partial.ai = opts['ai'] as StarterConfig['ai']\n // if (opts['payments']) partial.payments = opts['payments'] as StarterConfig['payments']\n // if (opts['dx']) partial.dx = opts['dx'] as StarterConfig['dx']\n if (opts['preset']) partial.preset = opts['preset'] as StarterConfig['preset']\n\n const config = opts['yes']\n ? { ...DEFAULT_CONFIG, ...partial }\n : await promptForMissing(partial)\n\n validateConfig(config)\n\n await runGenerator(projectName, projectDir, config, logger)\n })\n\n await program.parseAsync(process.argv)\n}\n\nasync function promptForMissing(partial: Partial<StarterConfig>): Promise<StarterConfig> {\n const config = { ...DEFAULT_CONFIG, ...partial }\n\n if (!partial.ui) {\n config.ui = await select({\n message: 'Which UI library?',\n choices: ALLOWED_VALUES.ui.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.ui,\n })\n }\n\n if (!partial.auth) {\n config.auth = await select({\n message: 'Which auth provider?',\n choices: ALLOWED_VALUES.auth.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.auth,\n })\n }\n\n // if (!partial.ai) {\n // config.ai = await select({\n // message: 'Which AI implementation?',\n // choices: ALLOWED_VALUES.ai.map((v) => ({ value: v, name: v })),\n // default: DEFAULT_CONFIG.ai,\n // })\n // }\n\n // if (!partial.payments) {\n // config.payments = await select({\n // message: 'Which payments provider?',\n // choices: ALLOWED_VALUES.payments.map((v) => ({ value: v, name: v })),\n // default: DEFAULT_CONFIG.payments,\n // })\n // }\n\n // if (!partial.dx) {\n // config.dx = await select({\n // message: 'Which DX profile?',\n // choices: ALLOWED_VALUES.dx.map((v) => ({ value: v, name: v })),\n // default: DEFAULT_CONFIG.dx,\n // })\n // }\n\n if (!partial.preset) {\n config.preset = await select({\n message: 'Which theme preset?',\n choices: ALLOWED_VALUES.preset.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.preset,\n })\n }\n\n return config\n}\n","import type {\n StarterConfig,\n UiProvider,\n AuthProvider,\n AiProvider,\n PaymentsProvider,\n DxProfile,\n ThemePreset,\n} from '@/types.js'\n\nexport const ALLOWED_VALUES = {\n ui: ['tamagui', 'gluestack'] as readonly UiProvider[],\n auth: ['clerk', 'none'] as readonly AuthProvider[],\n // ai: ['on-device-mlkit', 'online-openrouter'] as readonly AiProvider[],\n // payments: ['stripe', 'none'] as readonly PaymentsProvider[],\n // dx: ['basic', 'full'] as readonly DxProfile[],\n preset: ['radix-blue', 'radix-green', 'radix-purple', 'radix-orange', 'radix-cyan', 'radix-red'] as readonly ThemePreset[],\n} as const\n\nexport const DEFAULT_CONFIG: StarterConfig = {\n ui: 'tamagui',\n auth: 'none',\n ai: 'online-openrouter',\n payments: 'none',\n dx: 'basic',\n preset: 'radix-blue',\n}\n","import { mkdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { execa } from 'execa'\nimport type { StarterConfig, Logger, PackContext } from '@/types.js'\nimport type { ValidationResult } from '@/packs/pack.interface.js'\nimport { getActivePacks } from '@/pack-registry.js'\nimport { buildBasePackageJson, mergePackDependencies } from '@/utils/package-json.js'\nimport { writeProjectFile } from '@/utils/fs.js'\n\nexport async function runGenerator(\n projectName: string,\n projectDir: string,\n config: StarterConfig,\n logger: Logger,\n): Promise<void> {\n const packs = getActivePacks(config)\n const totalSteps = 4 + packs.length\n\n let step = 1\n\n // Step 1: Create project directory\n logger.step(step++, totalSteps, 'Creating project directory')\n await mkdir(projectDir, { recursive: true })\n\n // Step 2..N: Apply packs in order\n const context: PackContext = { projectName, projectDir, config, logger }\n\n for (const pack of packs) {\n logger.step(step++, totalSteps, `Applying ${pack.id} pack`)\n await pack.generate(context)\n }\n\n // Step N+1: Write merged package.json\n logger.step(step++, totalSteps, 'Writing package.json')\n const packageJson = mergePackDependencies(buildBasePackageJson(projectName), packs)\n await writeProjectFile(projectDir, 'package.json', JSON.stringify(packageJson, null, 2) + '\\n')\n\n // Step N+2: Install base deps, then use expo install for SDK-compatible packages\n logger.step(step++, totalSteps, 'Installing dependencies')\n await execa('npm', ['install'], { cwd: projectDir, stdio: 'inherit' })\n\n const expoPackages = packs.flatMap((p) => p.expoInstallPackages ?? [])\n if (expoPackages.length > 0) {\n await execa('npx', ['expo', 'install', ...expoPackages], { cwd: projectDir, stdio: 'inherit' })\n }\n\n // Step N+3: Run post-apply validations\n logger.step(step++, totalSteps, 'Running validations')\n const results: { packId: string; result: ValidationResult }[] = []\n\n for (const pack of packs) {\n const result = await pack.postApplyValidation(context)\n results.push({ packId: pack.id, result })\n }\n\n // Print summary\n printSummary(logger, config, results, projectDir)\n}\n\nfunction printSummary(\n logger: Logger,\n config: StarterConfig,\n results: { packId: string; result: ValidationResult }[],\n projectDir: string,\n): void {\n logger.info('')\n logger.info('Configuration:')\n logger.info(` UI: ${config.ui}`)\n logger.info(` Auth: ${config.auth}`)\n // logger.info(` AI: ${config.ai}`)\n // logger.info(` Payments: ${config.payments}`)\n // logger.info(` DX: ${config.dx}`)\n logger.info(` Preset: ${config.preset}`)\n logger.info('')\n\n let allPassed = true\n for (const { packId, result } of results) {\n for (const check of result.checks) {\n if (check.passed) {\n logger.success(`[${packId}] ${check.name}`)\n } else {\n logger.error(`[${packId}] ${check.name}${check.message ? ` — ${check.message}` : ''}`)\n allPassed = false\n }\n }\n }\n\n logger.info('')\n if (allPassed) {\n logger.success('All validations passed!')\n } else {\n logger.warn('Some validations failed. Check the output above.')\n }\n\n const cdPath = path.relative(process.cwd(), projectDir) || '.'\n logger.info('')\n logger.info('Next steps:')\n logger.info(` cd ${cdPath}`)\n logger.info(' npx expo start')\n}\n","import { readFile, readdir, stat } from 'node:fs/promises'\nimport path from 'node:path'\nimport ejs from 'ejs'\nimport { writeProjectFile } from '@/utils/fs.js'\n\nexport interface TemplateData {\n projectName: string\n ui: string\n auth: string\n ai: string\n payments: string\n dx: string\n preset: string\n hasAuth: boolean\n hasPayments: boolean\n isFullDx: boolean\n uiKit: {\n lib: string\n VStack: string\n HStack: string\n }\n}\n\n// In dev: import.meta.url is src/utils/template.ts → go up 3 levels\n// In built bundle: import.meta.url is dist/index.js → go up 2 levels\n// We detect by checking which path actually contains the templates/ dir\nimport { accessSync } from 'node:fs'\n\nfunction resolveTemplatesRoot(): string {\n const fileDir = path.dirname(new URL(import.meta.url).pathname)\n // Try progressively fewer parent levels until we find templates/\n for (let levels = 1; levels <= 4; levels++) {\n const candidate = path.resolve(fileDir, ...Array(levels).fill('..'), 'templates')\n try {\n accessSync(candidate)\n return candidate\n } catch {\n continue\n }\n }\n throw new Error('Could not locate templates/ directory')\n}\n\nconst TEMPLATES_ROOT = resolveTemplatesRoot()\n\nexport async function renderTemplates(\n templateDir: string,\n projectDir: string,\n data: TemplateData,\n): Promise<void> {\n const srcDir = path.join(TEMPLATES_ROOT, templateDir)\n await walkAndRender(srcDir, srcDir, projectDir, data)\n}\n\nasync function walkAndRender(\n baseDir: string,\n currentDir: string,\n projectDir: string,\n data: TemplateData,\n): Promise<void> {\n const entries = await readdir(currentDir, { withFileTypes: true })\n\n for (const entry of entries) {\n const srcPath = path.join(currentDir, entry.name)\n const relativePath = path.relative(baseDir, srcPath)\n\n if (entry.isDirectory()) {\n await walkAndRender(baseDir, srcPath, projectDir, data)\n continue\n }\n\n if (entry.name.endsWith('.ejs')) {\n const raw = await readFile(srcPath, 'utf-8')\n const rendered = ejs.render(raw, data, { filename: srcPath })\n const outPath = relativePath.replace(/\\.ejs$/, '')\n await writeProjectFile(projectDir, outPath, rendered)\n } else {\n const content = await readFile(srcPath, 'utf-8')\n await writeProjectFile(projectDir, relativePath, content)\n }\n }\n}\n","import { mkdir, writeFile as fsWriteFile, access } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport async function writeProjectFile(\n projectDir: string,\n relativePath: string,\n content: string,\n): Promise<void> {\n const fullPath = path.join(projectDir, relativePath)\n await mkdir(path.dirname(fullPath), { recursive: true })\n await fsWriteFile(fullPath, content, 'utf-8')\n}\n\nexport async function fileExists(\n projectDir: string,\n relativePath: string,\n): Promise<boolean> {\n try {\n await access(path.join(projectDir, relativePath))\n return true\n } catch {\n return false\n }\n}\n","import type { UiProvider } from '@/types.js'\n\nexport interface UIKit {\n lib: string\n VStack: string\n HStack: string\n}\n\nconst tamaguiKit: UIKit = {\n lib: 'tamagui',\n VStack: 'YStack',\n HStack: 'XStack',\n}\n\nconst gluestackKit: UIKit = {\n lib: '@gluestack-ui/themed',\n VStack: 'VStack',\n HStack: 'HStack',\n}\n\nconst kits: Record<UiProvider, UIKit> = {\n tamagui: tamaguiKit,\n gluestack: gluestackKit,\n}\n\nexport function getUIKit(provider: UiProvider): UIKit {\n return kits[provider]\n}\n","import type { FeaturePack, ValidationResult } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\nimport { renderTemplates, type TemplateData } from '@/utils/template.js'\nimport { fileExists } from '@/utils/fs.js'\nimport { getUIKit } from '@/packs/ui/kits.js'\n\nfunction buildTemplateData(ctx: PackContext): TemplateData {\n return {\n projectName: ctx.projectName,\n ui: ctx.config.ui,\n auth: ctx.config.auth,\n ai: ctx.config.ai,\n payments: ctx.config.payments,\n dx: ctx.config.dx,\n preset: ctx.config.preset,\n hasAuth: ctx.config.auth !== 'none',\n hasPayments: ctx.config.payments !== 'none',\n isFullDx: ctx.config.dx === 'full',\n uiKit: getUIKit(ctx.config.ui),\n }\n}\n\nasync function generateCore(ctx: PackContext): Promise<void> {\n const data = buildTemplateData(ctx)\n await renderTemplates('core', ctx.projectDir, data)\n}\n\nasync function validateCore(ctx: PackContext): Promise<ValidationResult> {\n const checks = await Promise.all([\n check('starter.config.ts exists', () => fileExists(ctx.projectDir, 'src/starter.config.ts')),\n check('tsconfig.json exists', () => fileExists(ctx.projectDir, 'tsconfig.json')),\n check('babel.config.js exists', () => fileExists(ctx.projectDir, 'babel.config.js')),\n check('app.json exists', () => fileExists(ctx.projectDir, 'app.json')),\n check('Root layout exists', () => fileExists(ctx.projectDir, 'app/_layout.tsx')),\n check('Entry screen exists', () => fileExists(ctx.projectDir, 'app/index.tsx')),\n check('Onboarding layout exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/_layout.tsx')),\n check('Onboarding welcome screen exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/welcome.tsx')),\n check('Onboarding features screen exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/features.tsx')),\n check('Onboarding get-started screen exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/get-started.tsx')),\n check('App tab layout exists', () => fileExists(ctx.projectDir, 'app/(app)/_layout.tsx')),\n check('Home screen exists', () => fileExists(ctx.projectDir, 'app/(app)/index.tsx')),\n check('Profile screen exists', () => fileExists(ctx.projectDir, 'app/(app)/profile.tsx')),\n check('Settings screen exists', () => fileExists(ctx.projectDir, 'app/(app)/settings.tsx')),\n check('Onboarding store exists', () => fileExists(ctx.projectDir, 'src/store/onboarding.ts')),\n check('Theme store exists', () => fileExists(ctx.projectDir, 'src/store/theme.ts')),\n check('Store barrel export exists', () => fileExists(ctx.projectDir, 'src/store/index.ts')),\n check('Query client exists', () => fileExists(ctx.projectDir, 'src/lib/query-client.ts')),\n check('UI provider resolver exists', () => fileExists(ctx.projectDir, 'src/providers/ui/index.ts')),\n check('Auth provider resolver exists', () => fileExists(ctx.projectDir, 'src/providers/auth/index.ts')),\n check('Payments provider resolver exists', () => fileExists(ctx.projectDir, 'src/providers/payments/index.ts')),\n ])\n\n return {\n passed: checks.every((c) => c.passed),\n checks,\n }\n}\n\nasync function check(name: string, fn: () => Promise<boolean>) {\n const passed = await fn()\n return { name, passed, message: passed ? undefined : 'File not found' }\n}\n\nexport const corePack: FeaturePack = {\n id: 'core',\n dependencies: {\n 'expo': '~55.0.5',\n 'react': '19.2.0',\n 'react-native': '0.83.2',\n },\n devDependencies: {},\n // Packages to install via `npx expo install` (resolves SDK-compatible versions)\n expoInstallPackages: [\n 'expo-router',\n 'expo-status-bar',\n 'expo-linking',\n 'expo-constants',\n 'expo-font',\n 'expo-splash-screen',\n 'react-native-safe-area-context',\n 'react-native-screens',\n 'react-native-gesture-handler',\n 'zustand',\n '@tanstack/react-query',\n 'typescript',\n '@types/react',\n ],\n ownedPaths: [\n 'src/starter.config.ts',\n 'tsconfig.json',\n 'babel.config.js',\n 'app.json',\n 'app/_layout.tsx',\n 'app/index.tsx',\n 'app/(onboarding)/',\n 'app/(app)/',\n 'src/store/',\n 'src/lib/',\n 'src/providers/ui/index.ts',\n 'src/providers/payments/index.ts',\n ],\n generate: generateCore,\n postApplyValidation: validateCore,\n}\n","import type { FeaturePack, ValidationCheck } from '@/packs/pack.interface.js'\nimport type { PackContext, StarterConfig } from '@/types.js'\nimport { renderTemplates, type TemplateData } from '@/utils/template.js'\nimport { fileExists } from '@/utils/fs.js'\nimport { getUIKit } from '@/packs/ui/kits.js'\n\nfunction buildTemplateData(ctx: PackContext): TemplateData {\n return {\n projectName: ctx.projectName,\n ui: ctx.config.ui,\n auth: ctx.config.auth,\n ai: ctx.config.ai,\n payments: ctx.config.payments,\n dx: ctx.config.dx,\n preset: ctx.config.preset,\n hasAuth: ctx.config.auth !== 'none',\n hasPayments: ctx.config.payments !== 'none',\n isFullDx: ctx.config.dx === 'full',\n uiKit: getUIKit(ctx.config.ui),\n }\n}\n\nasync function check(name: string, fn: () => Promise<boolean>): Promise<ValidationCheck> {\n const passed = await fn()\n return { name, passed, message: passed ? undefined : 'File not found' }\n}\n\nexport function createUiPack(config: StarterConfig): FeaturePack {\n const isTamagui = config.ui === 'tamagui'\n\n const dependencies: Record<string, string> = isTamagui\n ? {\n 'tamagui': '^1.116.0',\n '@tamagui/config': '^1.116.0',\n '@tamagui/font-inter': '^1.116.0',\n '@tamagui/animations-react-native': '^1.116.0',\n }\n : {\n '@gluestack-ui/themed': '^1.1.0',\n '@gluestack-style/react': '^1.0.0',\n '@gluestack-ui/config': '^1.1.0',\n }\n\n const devDependencies: Record<string, string> = isTamagui\n ? { '@tamagui/babel-plugin': '^1.116.0' }\n : {}\n\n return {\n id: 'ui',\n dependencies,\n devDependencies,\n expoInstallPackages: [\n 'react-native-reanimated',\n '@react-native-async-storage/async-storage',\n 'expo-haptics',\n 'expo-linear-gradient',\n ],\n ownedPaths: [\n 'src/design-system/',\n 'src/components/',\n ...(isTamagui\n ? ['src/providers/ui/tamagui/', 'tamagui.config.ts']\n : ['src/providers/ui/gluestack/']),\n ],\n async generate(ctx: PackContext) {\n const data = buildTemplateData(ctx)\n\n ctx.logger.info('Generating shared design system templates')\n await renderTemplates('ui', ctx.projectDir, data)\n\n if (isTamagui) {\n ctx.logger.info('Generating Tamagui adapter templates')\n await renderTemplates('ui-tamagui', ctx.projectDir, data)\n } else {\n ctx.logger.info('Generating Gluestack adapter templates')\n await renderTemplates('ui-gluestack', ctx.projectDir, data)\n }\n },\n async postApplyValidation(ctx: PackContext) {\n const sharedChecks = [\n check('Design system tokens exist', () =>\n fileExists(ctx.projectDir, 'src/design-system/tokens.ts')),\n check('ThemeProvider exists', () =>\n fileExists(ctx.projectDir, 'src/design-system/ThemeProvider.tsx')),\n check('Elevation styles exist', () =>\n fileExists(ctx.projectDir, 'src/design-system/elevation.ts')),\n check('Design system barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/design-system/index.ts')),\n check('Storage adapter exists', () =>\n fileExists(ctx.projectDir, 'src/lib/storage.ts')),\n check('Persisted theme store exists', () =>\n fileExists(ctx.projectDir, 'src/store/theme.ts')),\n ]\n\n const libraryChecks = isTamagui\n ? [\n check('Tamagui config exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/tamagui/tamagui.config.ts')),\n check('TamaguiProvider exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/tamagui/TamaguiProvider.tsx')),\n check('Root tamagui.config.ts exists', () =>\n fileExists(ctx.projectDir, 'tamagui.config.ts')),\n ]\n : [\n check('Gluestack config exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/gluestack/gluestack.config.ts')),\n check('GluestackProvider exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/gluestack/GluestackProvider.tsx')),\n ]\n\n const componentChecks = [\n check('Card component exists', () =>\n fileExists(ctx.projectDir, 'src/components/Card.tsx')),\n check('StatusBanner component exists', () =>\n fileExists(ctx.projectDir, 'src/components/StatusBanner.tsx')),\n check('PrimaryButton component exists', () =>\n fileExists(ctx.projectDir, 'src/components/PrimaryButton.tsx')),\n ]\n\n const checks = await Promise.all([...sharedChecks, ...libraryChecks, ...componentChecks])\n\n return {\n passed: checks.every((c) => c.passed),\n checks,\n }\n },\n }\n}\n","import type { FeaturePack, ValidationCheck } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\nimport { renderTemplates, type TemplateData } from '@/utils/template.js'\nimport { fileExists } from '@/utils/fs.js'\nimport { getUIKit } from '@/packs/ui/kits.js'\n\nfunction buildTemplateData(ctx: PackContext): TemplateData {\n return {\n projectName: ctx.projectName,\n ui: ctx.config.ui,\n auth: ctx.config.auth,\n ai: ctx.config.ai,\n payments: ctx.config.payments,\n dx: ctx.config.dx,\n preset: ctx.config.preset,\n hasAuth: ctx.config.auth !== 'none',\n hasPayments: ctx.config.payments !== 'none',\n isFullDx: ctx.config.dx === 'full',\n uiKit: getUIKit(ctx.config.ui),\n }\n}\n\nasync function check(name: string, fn: () => Promise<boolean>): Promise<ValidationCheck> {\n const passed = await fn()\n return { name, passed, message: passed ? undefined : 'File not found' }\n}\n\nexport const authPack: FeaturePack = {\n id: 'auth',\n dependencies: {\n '@clerk/expo': 'npm:@clerk/clerk-expo@^2.19.30',\n '@hookform/resolvers': '^3.9.0',\n },\n devDependencies: {},\n expoInstallPackages: [\n 'react-hook-form',\n 'zod',\n 'expo-secure-store',\n 'expo-web-browser',\n 'expo-auth-session',\n ],\n ownedPaths: [\n 'src/providers/auth/auth.interface.ts',\n 'src/providers/auth/auth.schemas.ts',\n 'src/providers/auth/useAuth.ts',\n 'src/providers/auth/AuthGate.tsx',\n 'src/providers/auth/AuthProviderWrapper.tsx',\n 'src/providers/auth/index.ts',\n 'src/providers/auth/clerk/',\n 'app/(auth)/',\n ],\n async generate(ctx: PackContext) {\n const data = buildTemplateData(ctx)\n ctx.logger.info('Generating auth provider templates')\n await renderTemplates('auth', ctx.projectDir, data)\n },\n async postApplyValidation(ctx: PackContext) {\n const providerChecks = [\n check('Auth interface exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/auth.interface.ts')),\n check('Auth schemas exist', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/auth.schemas.ts')),\n check('useAuth hook exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/useAuth.ts')),\n check('AuthGate exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/AuthGate.tsx')),\n check('AuthProviderWrapper exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/AuthProviderWrapper.tsx')),\n check('Auth barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/index.ts')),\n ]\n\n const clerkChecks = [\n check('Clerk adapter exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/clerk-adapter.ts')),\n check('Clerk provider exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/clerk-provider.tsx')),\n check('Clerk token cache exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/token-cache.ts')),\n check('Clerk env validation exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/env.ts')),\n check('Clerk warm-up browser hook exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/use-warm-up-browser.ts')),\n check('Clerk barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/index.ts')),\n ]\n\n const screenChecks = [\n check('Auth layout exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/_layout.tsx')),\n check('Sign-in screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/sign-in.tsx')),\n check('Sign-up screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/sign-up.tsx')),\n check('Forgot-password screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/forgot-password.tsx')),\n check('Verify-email screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/verify-email.tsx')),\n ]\n\n const checks = await Promise.all([...providerChecks, ...clerkChecks, ...screenChecks])\n\n return {\n passed: checks.every((c) => c.passed),\n checks,\n }\n },\n}\n","import type { FeaturePack, ValidationCheck } from '@/packs/pack.interface.js'\nimport type { PackContext, StarterConfig } from '@/types.js'\nimport { renderTemplates, type TemplateData } from '@/utils/template.js'\nimport { fileExists } from '@/utils/fs.js'\nimport { getUIKit } from '@/packs/ui/kits.js'\n\nfunction buildTemplateData(ctx: PackContext): TemplateData {\n return {\n projectName: ctx.projectName,\n ui: ctx.config.ui,\n auth: ctx.config.auth,\n ai: ctx.config.ai,\n payments: ctx.config.payments,\n dx: ctx.config.dx,\n preset: ctx.config.preset,\n hasAuth: ctx.config.auth !== 'none',\n hasPayments: ctx.config.payments !== 'none',\n isFullDx: ctx.config.dx === 'full',\n uiKit: getUIKit(ctx.config.ui),\n }\n}\n\nasync function check(name: string, fn: () => Promise<boolean>): Promise<ValidationCheck> {\n const passed = await fn()\n return { name, passed, message: passed ? undefined : 'File not found' }\n}\n\nexport function createAiPack(config: StarterConfig): FeaturePack {\n const isOpenRouter = config.ai === 'online-openrouter'\n\n const expoInstallPackages: string[] = isOpenRouter\n ? ['expo-image-picker']\n : [\n '@infinitered/react-native-mlkit-object-detection',\n 'expo-image-picker',\n ]\n\n return {\n id: 'ai',\n dependencies: {},\n devDependencies: {},\n expoInstallPackages,\n ownedPaths: [\n 'src/providers/ai/',\n 'app/(app)/ai.tsx',\n ],\n async generate(ctx: PackContext) {\n const data = buildTemplateData(ctx)\n\n ctx.logger.info('Generating shared AI provider templates')\n await renderTemplates('ai', ctx.projectDir, data)\n\n if (isOpenRouter) {\n ctx.logger.info('Generating OpenRouter AI templates')\n await renderTemplates('ai-openrouter', ctx.projectDir, data)\n } else {\n ctx.logger.info('Generating ML Kit AI templates')\n await renderTemplates('ai-mlkit', ctx.projectDir, data)\n }\n },\n async postApplyValidation(ctx: PackContext) {\n const sharedChecks = [\n check('AI interface exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/ai.interface.ts')),\n check('AI barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/index.ts')),\n check('AI screen exists', () =>\n fileExists(ctx.projectDir, 'app/(app)/ai.tsx')),\n ]\n\n const providerChecks = isOpenRouter\n ? [\n check('OpenRouter client exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/openrouter/client.ts')),\n check('OpenRouter useChat hook exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/openrouter/useChat.ts')),\n check('OpenRouter env config exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/openrouter/env.ts')),\n check('OpenRouter barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/openrouter/index.ts')),\n ]\n : [\n check('MLKit provider exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/mlkit/MLKitProvider.tsx')),\n check('MLKit vision hook exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/mlkit/useVision.ts')),\n check('MLKit barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ai/mlkit/index.ts')),\n ]\n\n const checks = await Promise.all([...sharedChecks, ...providerChecks])\n\n return {\n passed: checks.every((c) => c.passed),\n checks,\n }\n },\n }\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\nimport { writeProjectFile } from '@/utils/fs.js'\n\nconst STRIPE_STUB = `// TODO: Prompt 4 — replace with real Stripe integration\nexport function usePayments() {\n return { isReady: false }\n}\n`\n\nexport const paymentsPack: FeaturePack = {\n id: 'payments',\n // TODO: Phase 4 — populate Stripe deps when payments === 'stripe'\n dependencies: {},\n devDependencies: {},\n ownedPaths: [\n 'src/providers/payments/stripe/',\n 'src/features/payments/',\n 'app/(app)/paywall.tsx',\n ],\n async generate(ctx: PackContext) {\n ctx.logger.info('Payments pack: generating placeholder (Phase 4 — payments provider & screens)')\n await writeProjectFile(ctx.projectDir, 'src/providers/payments/stripe/index.ts', STRIPE_STUB)\n },\n async postApplyValidation() {\n return { passed: true, checks: [] }\n },\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\n\nexport const dxPack: FeaturePack = {\n id: 'dx',\n // TODO: Phase 5 — populate based on ctx.config.dx (basic or full)\n dependencies: {},\n devDependencies: {},\n ownedPaths: [\n 'eslint.config.mjs',\n '.prettierrc',\n 'jest.config.ts',\n '.github/',\n '.husky/',\n ],\n async generate(ctx: PackContext) {\n ctx.logger.info(`DX pack: stub (Phase 5 — ${ctx.config.dx} profile)`)\n },\n async postApplyValidation() {\n return { passed: true, checks: [] }\n },\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\nimport type { StarterConfig } from '@/types.js'\nimport { corePack } from '@/packs/core/index.js'\nimport { createUiPack } from '@/packs/ui/index.js'\nimport { authPack } from '@/packs/auth/index.js'\nimport { createAiPack } from '@/packs/ai/index.js'\nimport { paymentsPack } from '@/packs/payments/index.js'\nimport { dxPack } from '@/packs/dx/index.js'\n\nexport function getActivePacks(config: StarterConfig): FeaturePack[] {\n const allPacks: FeaturePack[] = [\n corePack,\n createUiPack(config),\n authPack,\n createAiPack(config),\n paymentsPack,\n dxPack,\n ]\n return allPacks.filter((pack) => isPackEnabled(pack.id, config))\n}\n\nfunction isPackEnabled(id: string, config: StarterConfig): boolean {\n switch (id) {\n case 'core':\n return true\n case 'ui':\n return true\n case 'auth':\n return config.auth !== 'none'\n case 'ai':\n return true\n case 'payments':\n return config.payments !== 'none'\n case 'dx':\n return true\n default:\n return false\n }\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\n\ninterface PackageJson {\n name: string\n version: string\n private: boolean\n main: string\n scripts: Record<string, string>\n dependencies: Record<string, string>\n devDependencies: Record<string, string>\n overrides: Record<string, string>\n}\n\nexport function buildBasePackageJson(projectName: string): PackageJson {\n return {\n name: projectName,\n version: '0.1.0',\n private: true,\n main: 'expo-router/entry',\n scripts: {\n dev: 'expo start',\n 'dev:ios': 'expo start --ios',\n 'dev:android': 'expo start --android',\n 'dev:web': 'expo start --web',\n },\n dependencies: {},\n devDependencies: {},\n overrides: {},\n }\n}\n\nexport function mergePackDependencies(\n base: PackageJson,\n packs: FeaturePack[],\n): PackageJson {\n const merged = { ...base }\n const deps = { ...merged.dependencies }\n const devDeps = { ...merged.devDependencies }\n\n for (const pack of packs) {\n Object.assign(deps, pack.dependencies)\n Object.assign(devDeps, pack.devDependencies)\n }\n\n merged.dependencies = sortObject(deps)\n merged.devDependencies = sortObject(devDeps)\n\n // Pin react to match react-native's bundled renderer\n if (deps['react']) {\n merged.overrides = { react: deps['react'] }\n }\n\n return merged\n}\n\nfunction sortObject(obj: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)))\n}\n","import { access, readdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { StarterConfig } from '@/types.js'\nimport { ALLOWED_VALUES } from '@/config.js'\n\nconst PROJECT_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_-]*$/\n\nexport interface ResolvedProject {\n projectName: string\n projectDir: string\n}\n\nexport async function resolveProjectPath(argument: string): Promise<ResolvedProject> {\n const projectDir = path.resolve(argument)\n const projectName = path.basename(projectDir)\n\n if (!PROJECT_NAME_RE.test(projectName)) {\n throw new Error(\n `Invalid project name \"${projectName}\". Must start with a letter and contain only letters, numbers, hyphens, and underscores.`,\n )\n }\n\n const isDot = argument === '.'\n\n if (isDot) {\n const entries = await readdir(projectDir)\n if (entries.length > 0) {\n throw new Error(\n `Current directory is not empty. Use \".\" only in an empty folder.`,\n )\n }\n return { projectName, projectDir }\n }\n\n const parentDir = path.dirname(projectDir)\n try {\n await access(parentDir)\n } catch {\n throw new Error(\n `Parent directory \"${parentDir}\" does not exist.`,\n )\n }\n\n try {\n await access(projectDir)\n throw new Error(`Directory \"${projectDir}\" already exists.`)\n } catch (err) {\n if (err instanceof Error && err.message.startsWith('Directory')) throw err\n }\n\n return { projectName, projectDir }\n}\n\nexport function validateConfig(config: StarterConfig): void {\n const entries = Object.entries(ALLOWED_VALUES) as [keyof StarterConfig, readonly string[]][]\n for (const [key, allowed] of entries) {\n if (!allowed.includes(config[key])) {\n throw new Error(\n `Invalid value \"${config[key]}\" for --${key}. Allowed: ${allowed.join(', ')}`,\n )\n }\n }\n}\n","import chalk from 'chalk'\nimport type { Logger } from '@/types.js'\n\nexport function createLogger(): Logger {\n return {\n info(msg) {\n console.log(chalk.blue('info'), msg)\n },\n success(msg) {\n console.log(chalk.green('✓'), msg)\n },\n warn(msg) {\n console.log(chalk.yellow('warn'), msg)\n },\n error(msg) {\n console.error(chalk.red('error'), msg)\n },\n step(current, total, msg) {\n console.log(chalk.cyan(`[${current}/${total}]`), msg)\n },\n }\n}\n","import { run } from '@/cli.js'\n\nrun().catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : err)\n process.exit(1)\n})\n"],"mappings":"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","names":["mkdir","path","path","path","buildTemplateData","check","buildTemplateData","check","buildTemplateData","check","mkdir","check","path","access","readdir","path","path","readdir","access"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/config.ts","../src/generator.ts","../src/utils/template.ts","../src/utils/fs.ts","../src/packs/ui/kits.ts","../src/packs/core/index.ts","../src/packs/ui/index.ts","../src/packs/auth/index.ts","../src/packs/payments/index.ts","../src/packs/dx/index.ts","../src/pack-registry.ts","../src/utils/package-json.ts","../src/utils/validation.ts","../src/utils/logger.ts","../src/index.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { select } from '@inquirer/prompts'\nimport { DEFAULT_CONFIG, ALLOWED_VALUES } from '@/config.js'\nimport { runGenerator } from '@/generator.js'\nimport { resolveProjectPath, validateConfig } from '@/utils/validation.js'\nimport { createLogger } from '@/utils/logger.js'\nimport type { StarterConfig } from '@/types.js'\n\nexport async function run(): Promise<void> {\n const program = new Command()\n .name('create-rn-ai-starter')\n .description('Scaffold an Expo React Native project with modular feature packs')\n .argument('<project-path>', 'Name or path for the new project (e.g. my-app, ./projects/my-app, .)')\n .option('--ui <provider>', `UI library: ${ALLOWED_VALUES.ui.join(' | ')}`)\n .option('--auth <provider>', `Auth provider: ${ALLOWED_VALUES.auth.join(' | ')}`)\n .option('--payments <provider>', `Payments provider: ${ALLOWED_VALUES.payments.join(' | ')}`)\n .option('--dx <profile>', `DX profile: ${ALLOWED_VALUES.dx.join(' | ')}`)\n .option('--preset <theme>', `Theme preset: ${ALLOWED_VALUES.preset.join(' | ')}`)\n .option('--yes', 'Skip interactive prompts, use defaults for unset flags')\n .action(async (projectPath: string, opts: Record<string, string | boolean | undefined>) => {\n const logger = createLogger()\n\n const { projectName, projectDir } = await resolveProjectPath(projectPath)\n\n const partial: Partial<StarterConfig> = {}\n if (opts['ui']) partial.ui = opts['ui'] as StarterConfig['ui']\n if (opts['auth']) partial.auth = opts['auth'] as StarterConfig['auth']\n if (opts['payments']) partial.payments = opts['payments'] as StarterConfig['payments']\n if (opts['dx']) partial.dx = opts['dx'] as StarterConfig['dx']\n if (opts['preset']) partial.preset = opts['preset'] as StarterConfig['preset']\n\n const config = opts['yes']\n ? { ...DEFAULT_CONFIG, ...partial }\n : await promptForMissing(partial)\n\n validateConfig(config)\n\n await runGenerator(projectName, projectDir, config, logger)\n })\n\n await program.parseAsync(process.argv)\n}\n\nasync function promptForMissing(partial: Partial<StarterConfig>): Promise<StarterConfig> {\n const config = { ...DEFAULT_CONFIG, ...partial }\n\n if (!partial.ui) {\n config.ui = await select({\n message: 'Which UI library?',\n choices: ALLOWED_VALUES.ui.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.ui,\n })\n }\n\n if (!partial.auth) {\n config.auth = await select({\n message: 'Which auth provider?',\n choices: ALLOWED_VALUES.auth.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.auth,\n })\n }\n\n if (!partial.payments) {\n config.payments = await select({\n message: 'Which payments provider?',\n choices: ALLOWED_VALUES.payments.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.payments,\n })\n }\n\n if (!partial.dx) {\n config.dx = await select({\n message: 'Which DX profile?',\n choices: ALLOWED_VALUES.dx.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.dx,\n })\n }\n\n if (!partial.preset) {\n config.preset = await select({\n message: 'Which theme preset?',\n choices: ALLOWED_VALUES.preset.map((v) => ({ value: v, name: v })),\n default: DEFAULT_CONFIG.preset,\n })\n }\n\n return config\n}\n","import type {\n StarterConfig,\n UiProvider,\n AuthProvider,\n PaymentsProvider,\n DxProfile,\n ThemePreset,\n} from '@/types.js'\n\nexport const ALLOWED_VALUES = {\n ui: ['tamagui', 'gluestack'] as readonly UiProvider[],\n auth: ['clerk', 'none'] as readonly AuthProvider[],\n payments: ['stripe', 'none'] as readonly PaymentsProvider[],\n dx: ['basic', 'full'] as readonly DxProfile[],\n preset: ['neutral-green', 'fluent-blue'] as readonly ThemePreset[],\n} as const\n\nexport const DEFAULT_CONFIG: StarterConfig = {\n ui: 'tamagui',\n auth: 'none',\n payments: 'none',\n dx: 'basic',\n preset: 'neutral-green',\n}\n","import { mkdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport { execa } from 'execa'\nimport type { StarterConfig, Logger, PackContext } from '@/types.js'\nimport type { ValidationResult } from '@/packs/pack.interface.js'\nimport { getActivePacks } from '@/pack-registry.js'\nimport { buildBasePackageJson, mergePackDependencies } from '@/utils/package-json.js'\nimport { writeProjectFile } from '@/utils/fs.js'\n\nexport async function runGenerator(\n projectName: string,\n projectDir: string,\n config: StarterConfig,\n logger: Logger,\n): Promise<void> {\n const packs = getActivePacks(config)\n const totalSteps = 4 + packs.length\n\n let step = 1\n\n // Step 1: Create project directory\n logger.step(step++, totalSteps, 'Creating project directory')\n await mkdir(projectDir, { recursive: true })\n\n // Step 2..N: Apply packs in order\n const context: PackContext = { projectName, projectDir, config, logger }\n\n for (const pack of packs) {\n logger.step(step++, totalSteps, `Applying ${pack.id} pack`)\n await pack.generate(context)\n }\n\n // Step N+1: Write merged package.json\n logger.step(step++, totalSteps, 'Writing package.json')\n const packageJson = mergePackDependencies(buildBasePackageJson(projectName), packs)\n await writeProjectFile(projectDir, 'package.json', JSON.stringify(packageJson, null, 2) + '\\n')\n\n // Step N+2: Install base deps, then use expo install for SDK-compatible packages\n logger.step(step++, totalSteps, 'Installing dependencies')\n await execa('npm', ['install'], { cwd: projectDir, stdio: 'inherit' })\n\n const expoPackages = packs.flatMap((p) => p.expoInstallPackages ?? [])\n if (expoPackages.length > 0) {\n await execa('npx', ['expo', 'install', ...expoPackages], { cwd: projectDir, stdio: 'inherit' })\n }\n\n // Step N+3: Run post-apply validations\n logger.step(step++, totalSteps, 'Running validations')\n const results: { packId: string; result: ValidationResult }[] = []\n\n for (const pack of packs) {\n const result = await pack.postApplyValidation(context)\n results.push({ packId: pack.id, result })\n }\n\n // Print summary\n printSummary(logger, config, results, projectDir)\n}\n\nfunction printSummary(\n logger: Logger,\n config: StarterConfig,\n results: { packId: string; result: ValidationResult }[],\n projectDir: string,\n): void {\n logger.info('')\n logger.info('Configuration:')\n logger.info(` UI: ${config.ui}`)\n logger.info(` Auth: ${config.auth}`)\n logger.info(` Payments: ${config.payments}`)\n logger.info(` DX: ${config.dx}`)\n logger.info(` Preset: ${config.preset}`)\n logger.info('')\n\n let allPassed = true\n for (const { packId, result } of results) {\n for (const check of result.checks) {\n if (check.passed) {\n logger.success(`[${packId}] ${check.name}`)\n } else {\n logger.error(`[${packId}] ${check.name}${check.message ? ` — ${check.message}` : ''}`)\n allPassed = false\n }\n }\n }\n\n logger.info('')\n if (allPassed) {\n logger.success('All validations passed!')\n } else {\n logger.warn('Some validations failed. Check the output above.')\n }\n\n const cdPath = path.relative(process.cwd(), projectDir) || '.'\n logger.info('')\n logger.info('Next steps:')\n logger.info(` cd ${cdPath}`)\n logger.info(' npx expo start')\n}\n","import { readFile, readdir, stat } from 'node:fs/promises'\nimport path from 'node:path'\nimport ejs from 'ejs'\nimport { writeProjectFile } from '@/utils/fs.js'\n\nexport interface TemplateData {\n projectName: string\n ui: string\n auth: string\n payments: string\n dx: string\n preset: string\n hasAuth: boolean\n hasPayments: boolean\n isFullDx: boolean\n uiKit: {\n lib: string\n VStack: string\n HStack: string\n }\n}\n\n// In dev: import.meta.url is src/utils/template.ts → go up 3 levels\n// In built bundle: import.meta.url is dist/index.js → go up 2 levels\n// We detect by checking which path actually contains the templates/ dir\nimport { accessSync } from 'node:fs'\n\nfunction resolveTemplatesRoot(): string {\n const fileDir = path.dirname(new URL(import.meta.url).pathname)\n // Try progressively fewer parent levels until we find templates/\n for (let levels = 1; levels <= 4; levels++) {\n const candidate = path.resolve(fileDir, ...Array(levels).fill('..'), 'templates')\n try {\n accessSync(candidate)\n return candidate\n } catch {\n continue\n }\n }\n throw new Error('Could not locate templates/ directory')\n}\n\nconst TEMPLATES_ROOT = resolveTemplatesRoot()\n\nexport async function renderTemplates(\n templateDir: string,\n projectDir: string,\n data: TemplateData,\n): Promise<void> {\n const srcDir = path.join(TEMPLATES_ROOT, templateDir)\n await walkAndRender(srcDir, srcDir, projectDir, data)\n}\n\nasync function walkAndRender(\n baseDir: string,\n currentDir: string,\n projectDir: string,\n data: TemplateData,\n): Promise<void> {\n const entries = await readdir(currentDir, { withFileTypes: true })\n\n for (const entry of entries) {\n const srcPath = path.join(currentDir, entry.name)\n const relativePath = path.relative(baseDir, srcPath)\n\n if (entry.isDirectory()) {\n await walkAndRender(baseDir, srcPath, projectDir, data)\n continue\n }\n\n if (entry.name.endsWith('.ejs')) {\n const raw = await readFile(srcPath, 'utf-8')\n const rendered = ejs.render(raw, data, { filename: srcPath })\n const outPath = relativePath.replace(/\\.ejs$/, '')\n await writeProjectFile(projectDir, outPath, rendered)\n } else {\n const content = await readFile(srcPath, 'utf-8')\n await writeProjectFile(projectDir, relativePath, content)\n }\n }\n}\n","import { mkdir, writeFile as fsWriteFile, access } from 'node:fs/promises'\nimport path from 'node:path'\n\nexport async function writeProjectFile(\n projectDir: string,\n relativePath: string,\n content: string,\n): Promise<void> {\n const fullPath = path.join(projectDir, relativePath)\n await mkdir(path.dirname(fullPath), { recursive: true })\n await fsWriteFile(fullPath, content, 'utf-8')\n}\n\nexport async function fileExists(\n projectDir: string,\n relativePath: string,\n): Promise<boolean> {\n try {\n await access(path.join(projectDir, relativePath))\n return true\n } catch {\n return false\n }\n}\n","import type { UiProvider } from '@/types.js'\n\nexport interface UIKit {\n lib: string\n VStack: string\n HStack: string\n}\n\nconst tamaguiKit: UIKit = {\n lib: 'tamagui',\n VStack: 'YStack',\n HStack: 'XStack',\n}\n\nconst gluestackKit: UIKit = {\n lib: '@gluestack-ui/themed',\n VStack: 'VStack',\n HStack: 'HStack',\n}\n\nconst kits: Record<UiProvider, UIKit> = {\n tamagui: tamaguiKit,\n gluestack: gluestackKit,\n}\n\nexport function getUIKit(provider: UiProvider): UIKit {\n return kits[provider]\n}\n","import type { FeaturePack, ValidationResult } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\nimport { renderTemplates, type TemplateData } from '@/utils/template.js'\nimport { fileExists } from '@/utils/fs.js'\nimport { getUIKit } from '@/packs/ui/kits.js'\n\nfunction buildTemplateData(ctx: PackContext): TemplateData {\n return {\n projectName: ctx.projectName,\n ui: ctx.config.ui,\n auth: ctx.config.auth,\n payments: ctx.config.payments,\n dx: ctx.config.dx,\n preset: ctx.config.preset,\n hasAuth: ctx.config.auth !== 'none',\n hasPayments: ctx.config.payments !== 'none',\n isFullDx: ctx.config.dx === 'full',\n uiKit: getUIKit(ctx.config.ui),\n }\n}\n\nasync function generateCore(ctx: PackContext): Promise<void> {\n const data = buildTemplateData(ctx)\n await renderTemplates('core', ctx.projectDir, data)\n}\n\nasync function validateCore(ctx: PackContext): Promise<ValidationResult> {\n const checks = await Promise.all([\n check('starter.config.ts exists', () => fileExists(ctx.projectDir, 'src/starter.config.ts')),\n check('tsconfig.json exists', () => fileExists(ctx.projectDir, 'tsconfig.json')),\n check('babel.config.js exists', () => fileExists(ctx.projectDir, 'babel.config.js')),\n check('app.json exists', () => fileExists(ctx.projectDir, 'app.json')),\n check('Root layout exists', () => fileExists(ctx.projectDir, 'app/_layout.tsx')),\n check('Entry screen exists', () => fileExists(ctx.projectDir, 'app/index.tsx')),\n check('Onboarding layout exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/_layout.tsx')),\n check('Onboarding welcome screen exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/welcome.tsx')),\n check('Onboarding features screen exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/features.tsx')),\n check('Onboarding get-started screen exists', () => fileExists(ctx.projectDir, 'app/(onboarding)/get-started.tsx')),\n check('App tab layout exists', () => fileExists(ctx.projectDir, 'app/(app)/_layout.tsx')),\n check('Home screen exists', () => fileExists(ctx.projectDir, 'app/(app)/index.tsx')),\n check('Profile screen exists', () => fileExists(ctx.projectDir, 'app/(app)/profile.tsx')),\n check('Settings screen exists', () => fileExists(ctx.projectDir, 'app/(app)/settings.tsx')),\n check('Onboarding store exists', () => fileExists(ctx.projectDir, 'src/store/onboarding.ts')),\n check('Theme store exists', () => fileExists(ctx.projectDir, 'src/store/theme.ts')),\n check('Store barrel export exists', () => fileExists(ctx.projectDir, 'src/store/index.ts')),\n check('Query client exists', () => fileExists(ctx.projectDir, 'src/lib/query-client.ts')),\n check('UI provider resolver exists', () => fileExists(ctx.projectDir, 'src/providers/ui/index.ts')),\n check('Auth provider resolver exists', () => fileExists(ctx.projectDir, 'src/providers/auth/index.ts')),\n check('Payments provider resolver exists', () => fileExists(ctx.projectDir, 'src/providers/payments/index.ts')),\n ])\n\n return {\n passed: checks.every((c) => c.passed),\n checks,\n }\n}\n\nasync function check(name: string, fn: () => Promise<boolean>) {\n const passed = await fn()\n return { name, passed, message: passed ? undefined : 'File not found' }\n}\n\nexport const corePack: FeaturePack = {\n id: 'core',\n dependencies: {\n 'expo': '~55.0.5',\n 'react': '19.2.0',\n 'react-native': '0.83.2',\n },\n devDependencies: {},\n // Packages to install via `npx expo install` (resolves SDK-compatible versions)\n expoInstallPackages: [\n 'expo-router',\n 'expo-status-bar',\n 'expo-linking',\n 'expo-constants',\n 'expo-font',\n 'expo-splash-screen',\n 'react-native-safe-area-context',\n 'react-native-screens',\n 'react-native-gesture-handler',\n 'zustand',\n '@tanstack/react-query',\n 'typescript',\n '@types/react',\n ],\n ownedPaths: [\n 'src/starter.config.ts',\n 'tsconfig.json',\n 'babel.config.js',\n 'app.json',\n 'app/_layout.tsx',\n 'app/index.tsx',\n 'app/(onboarding)/',\n 'app/(app)/',\n 'src/store/',\n 'src/lib/',\n 'src/providers/ui/index.ts',\n 'src/providers/payments/index.ts',\n ],\n generate: generateCore,\n postApplyValidation: validateCore,\n}\n","import type { FeaturePack, ValidationCheck } from '@/packs/pack.interface.js'\nimport type { PackContext, StarterConfig } from '@/types.js'\nimport { renderTemplates, type TemplateData } from '@/utils/template.js'\nimport { fileExists } from '@/utils/fs.js'\nimport { getUIKit } from '@/packs/ui/kits.js'\n\nfunction buildTemplateData(ctx: PackContext): TemplateData {\n return {\n projectName: ctx.projectName,\n ui: ctx.config.ui,\n auth: ctx.config.auth,\n payments: ctx.config.payments,\n dx: ctx.config.dx,\n preset: ctx.config.preset,\n hasAuth: ctx.config.auth !== 'none',\n hasPayments: ctx.config.payments !== 'none',\n isFullDx: ctx.config.dx === 'full',\n uiKit: getUIKit(ctx.config.ui),\n }\n}\n\nasync function check(name: string, fn: () => Promise<boolean>): Promise<ValidationCheck> {\n const passed = await fn()\n return { name, passed, message: passed ? undefined : 'File not found' }\n}\n\nexport function createUiPack(config: StarterConfig): FeaturePack {\n const isTamagui = config.ui === 'tamagui'\n\n const dependencies: Record<string, string> = isTamagui\n ? {\n 'tamagui': '^1.116.0',\n '@tamagui/config': '^1.116.0',\n '@tamagui/font-inter': '^1.116.0',\n '@tamagui/animations-react-native': '^1.116.0',\n }\n : {\n '@gluestack-ui/themed': '^1.1.0',\n '@gluestack-style/react': '^1.0.0',\n '@gluestack-ui/config': '^1.1.0',\n }\n\n const devDependencies: Record<string, string> = isTamagui\n ? { '@tamagui/babel-plugin': '^1.116.0' }\n : {}\n\n return {\n id: 'ui',\n dependencies,\n devDependencies,\n expoInstallPackages: [\n 'react-native-reanimated',\n '@react-native-async-storage/async-storage',\n 'expo-haptics',\n 'expo-linear-gradient',\n ],\n ownedPaths: [\n 'src/design-system/',\n 'src/components/',\n ...(isTamagui\n ? ['src/providers/ui/tamagui/', 'tamagui.config.ts']\n : ['src/providers/ui/gluestack/']),\n ],\n async generate(ctx: PackContext) {\n const data = buildTemplateData(ctx)\n\n ctx.logger.info('Generating shared design system templates')\n await renderTemplates('ui', ctx.projectDir, data)\n\n if (isTamagui) {\n ctx.logger.info('Generating Tamagui adapter templates')\n await renderTemplates('ui-tamagui', ctx.projectDir, data)\n } else {\n ctx.logger.info('Generating Gluestack adapter templates')\n await renderTemplates('ui-gluestack', ctx.projectDir, data)\n }\n },\n async postApplyValidation(ctx: PackContext) {\n const sharedChecks = [\n check('Design system tokens exist', () =>\n fileExists(ctx.projectDir, 'src/design-system/tokens.ts')),\n check('ThemeProvider exists', () =>\n fileExists(ctx.projectDir, 'src/design-system/ThemeProvider.tsx')),\n check('Elevation styles exist', () =>\n fileExists(ctx.projectDir, 'src/design-system/elevation.ts')),\n check('Design system barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/design-system/index.ts')),\n check('Storage adapter exists', () =>\n fileExists(ctx.projectDir, 'src/lib/storage.ts')),\n check('Persisted theme store exists', () =>\n fileExists(ctx.projectDir, 'src/store/theme.ts')),\n ]\n\n const libraryChecks = isTamagui\n ? [\n check('Tamagui config exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/tamagui/tamagui.config.ts')),\n check('TamaguiProvider exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/tamagui/TamaguiProvider.tsx')),\n check('Root tamagui.config.ts exists', () =>\n fileExists(ctx.projectDir, 'tamagui.config.ts')),\n ]\n : [\n check('Gluestack config exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/gluestack/gluestack.config.ts')),\n check('GluestackProvider exists', () =>\n fileExists(ctx.projectDir, 'src/providers/ui/gluestack/GluestackProvider.tsx')),\n ]\n\n const componentChecks = [\n check('Card component exists', () =>\n fileExists(ctx.projectDir, 'src/components/Card.tsx')),\n check('StatusBanner component exists', () =>\n fileExists(ctx.projectDir, 'src/components/StatusBanner.tsx')),\n check('PrimaryButton component exists', () =>\n fileExists(ctx.projectDir, 'src/components/PrimaryButton.tsx')),\n ]\n\n const checks = await Promise.all([...sharedChecks, ...libraryChecks, ...componentChecks])\n\n return {\n passed: checks.every((c) => c.passed),\n checks,\n }\n },\n }\n}\n","import type { FeaturePack, ValidationCheck } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\nimport { renderTemplates, type TemplateData } from '@/utils/template.js'\nimport { fileExists } from '@/utils/fs.js'\nimport { getUIKit } from '@/packs/ui/kits.js'\n\nfunction buildTemplateData(ctx: PackContext): TemplateData {\n return {\n projectName: ctx.projectName,\n ui: ctx.config.ui,\n auth: ctx.config.auth,\n payments: ctx.config.payments,\n dx: ctx.config.dx,\n preset: ctx.config.preset,\n hasAuth: ctx.config.auth !== 'none',\n hasPayments: ctx.config.payments !== 'none',\n isFullDx: ctx.config.dx === 'full',\n uiKit: getUIKit(ctx.config.ui),\n }\n}\n\nasync function check(name: string, fn: () => Promise<boolean>): Promise<ValidationCheck> {\n const passed = await fn()\n return { name, passed, message: passed ? undefined : 'File not found' }\n}\n\nexport const authPack: FeaturePack = {\n id: 'auth',\n dependencies: {\n '@clerk/expo': '^2.2.0',\n '@hookform/resolvers': '^3.9.0',\n },\n devDependencies: {},\n expoInstallPackages: [\n 'react-hook-form',\n 'zod',\n 'expo-secure-store',\n 'expo-web-browser',\n 'expo-auth-session',\n ],\n ownedPaths: [\n 'src/providers/auth/auth.interface.ts',\n 'src/providers/auth/auth.schemas.ts',\n 'src/providers/auth/useAuth.ts',\n 'src/providers/auth/AuthGate.tsx',\n 'src/providers/auth/AuthProviderWrapper.tsx',\n 'src/providers/auth/index.ts',\n 'src/providers/auth/clerk/',\n 'app/(auth)/',\n ],\n async generate(ctx: PackContext) {\n const data = buildTemplateData(ctx)\n ctx.logger.info('Generating auth provider templates')\n await renderTemplates('auth', ctx.projectDir, data)\n },\n async postApplyValidation(ctx: PackContext) {\n const providerChecks = [\n check('Auth interface exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/auth.interface.ts')),\n check('Auth schemas exist', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/auth.schemas.ts')),\n check('useAuth hook exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/useAuth.ts')),\n check('AuthGate exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/AuthGate.tsx')),\n check('AuthProviderWrapper exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/AuthProviderWrapper.tsx')),\n check('Auth barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/index.ts')),\n ]\n\n const clerkChecks = [\n check('Clerk adapter exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/clerk-adapter.ts')),\n check('Clerk provider exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/clerk-provider.tsx')),\n check('Clerk token cache exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/token-cache.ts')),\n check('Clerk env validation exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/env.ts')),\n check('Clerk warm-up browser hook exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/use-warm-up-browser.ts')),\n check('Clerk barrel export exists', () =>\n fileExists(ctx.projectDir, 'src/providers/auth/clerk/index.ts')),\n ]\n\n const screenChecks = [\n check('Auth layout exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/_layout.tsx')),\n check('Sign-in screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/sign-in.tsx')),\n check('Sign-up screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/sign-up.tsx')),\n check('Forgot-password screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/forgot-password.tsx')),\n check('Verify-email screen exists', () =>\n fileExists(ctx.projectDir, 'app/(auth)/verify-email.tsx')),\n ]\n\n const checks = await Promise.all([...providerChecks, ...clerkChecks, ...screenChecks])\n\n return {\n passed: checks.every((c) => c.passed),\n checks,\n }\n },\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\nimport { writeProjectFile } from '@/utils/fs.js'\n\nconst STRIPE_STUB = `// TODO: Prompt 4 — replace with real Stripe integration\nexport function usePayments() {\n return { isReady: false }\n}\n`\n\nexport const paymentsPack: FeaturePack = {\n id: 'payments',\n // TODO: Phase 4 — populate Stripe deps when payments === 'stripe'\n dependencies: {},\n devDependencies: {},\n ownedPaths: [\n 'src/providers/payments/stripe/',\n 'src/features/payments/',\n 'app/(app)/paywall.tsx',\n ],\n async generate(ctx: PackContext) {\n ctx.logger.info('Payments pack: generating placeholder (Phase 4 — payments provider & screens)')\n await writeProjectFile(ctx.projectDir, 'src/providers/payments/stripe/index.ts', STRIPE_STUB)\n },\n async postApplyValidation() {\n return { passed: true, checks: [] }\n },\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\nimport type { PackContext } from '@/types.js'\n\nexport const dxPack: FeaturePack = {\n id: 'dx',\n // TODO: Phase 5 — populate based on ctx.config.dx (basic or full)\n dependencies: {},\n devDependencies: {},\n ownedPaths: [\n 'eslint.config.mjs',\n '.prettierrc',\n 'jest.config.ts',\n '.github/',\n '.husky/',\n ],\n async generate(ctx: PackContext) {\n ctx.logger.info(`DX pack: stub (Phase 5 — ${ctx.config.dx} profile)`)\n },\n async postApplyValidation() {\n return { passed: true, checks: [] }\n },\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\nimport type { StarterConfig } from '@/types.js'\nimport { corePack } from '@/packs/core/index.js'\nimport { createUiPack } from '@/packs/ui/index.js'\nimport { authPack } from '@/packs/auth/index.js'\nimport { paymentsPack } from '@/packs/payments/index.js'\nimport { dxPack } from '@/packs/dx/index.js'\n\nexport function getActivePacks(config: StarterConfig): FeaturePack[] {\n const allPacks: FeaturePack[] = [\n corePack,\n createUiPack(config),\n authPack,\n paymentsPack,\n dxPack,\n ]\n return allPacks.filter((pack) => isPackEnabled(pack.id, config))\n}\n\nfunction isPackEnabled(id: string, config: StarterConfig): boolean {\n switch (id) {\n case 'core':\n return true\n case 'ui':\n return true\n case 'auth':\n return config.auth !== 'none'\n case 'payments':\n return config.payments !== 'none'\n case 'dx':\n return true\n default:\n return false\n }\n}\n","import type { FeaturePack } from '@/packs/pack.interface.js'\n\ninterface PackageJson {\n name: string\n version: string\n private: boolean\n main: string\n scripts: Record<string, string>\n dependencies: Record<string, string>\n devDependencies: Record<string, string>\n overrides: Record<string, string>\n}\n\nexport function buildBasePackageJson(projectName: string): PackageJson {\n return {\n name: projectName,\n version: '0.1.0',\n private: true,\n main: 'expo-router/entry',\n scripts: {\n dev: 'expo start',\n 'dev:ios': 'expo start --ios',\n 'dev:android': 'expo start --android',\n 'dev:web': 'expo start --web',\n },\n dependencies: {},\n devDependencies: {},\n overrides: {},\n }\n}\n\nexport function mergePackDependencies(\n base: PackageJson,\n packs: FeaturePack[],\n): PackageJson {\n const merged = { ...base }\n const deps = { ...merged.dependencies }\n const devDeps = { ...merged.devDependencies }\n\n for (const pack of packs) {\n Object.assign(deps, pack.dependencies)\n Object.assign(devDeps, pack.devDependencies)\n }\n\n merged.dependencies = sortObject(deps)\n merged.devDependencies = sortObject(devDeps)\n\n // Pin react to match react-native's bundled renderer\n if (deps['react']) {\n merged.overrides = { react: deps['react'] }\n }\n\n return merged\n}\n\nfunction sortObject(obj: Record<string, string>): Record<string, string> {\n return Object.fromEntries(Object.entries(obj).sort(([a], [b]) => a.localeCompare(b)))\n}\n","import { access, readdir } from 'node:fs/promises'\nimport path from 'node:path'\nimport type { StarterConfig } from '@/types.js'\nimport { ALLOWED_VALUES } from '@/config.js'\n\nconst PROJECT_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_-]*$/\n\nexport interface ResolvedProject {\n projectName: string\n projectDir: string\n}\n\nexport async function resolveProjectPath(argument: string): Promise<ResolvedProject> {\n const projectDir = path.resolve(argument)\n const projectName = path.basename(projectDir)\n\n if (!PROJECT_NAME_RE.test(projectName)) {\n throw new Error(\n `Invalid project name \"${projectName}\". Must start with a letter and contain only letters, numbers, hyphens, and underscores.`,\n )\n }\n\n const isDot = argument === '.'\n\n if (isDot) {\n const entries = await readdir(projectDir)\n if (entries.length > 0) {\n throw new Error(\n `Current directory is not empty. Use \".\" only in an empty folder.`,\n )\n }\n return { projectName, projectDir }\n }\n\n const parentDir = path.dirname(projectDir)\n try {\n await access(parentDir)\n } catch {\n throw new Error(\n `Parent directory \"${parentDir}\" does not exist.`,\n )\n }\n\n try {\n await access(projectDir)\n throw new Error(`Directory \"${projectDir}\" already exists.`)\n } catch (err) {\n if (err instanceof Error && err.message.startsWith('Directory')) throw err\n }\n\n return { projectName, projectDir }\n}\n\nexport function validateConfig(config: StarterConfig): void {\n const entries = Object.entries(ALLOWED_VALUES) as [keyof StarterConfig, readonly string[]][]\n for (const [key, allowed] of entries) {\n if (!allowed.includes(config[key])) {\n throw new Error(\n `Invalid value \"${config[key]}\" for --${key}. Allowed: ${allowed.join(', ')}`,\n )\n }\n }\n}\n","import chalk from 'chalk'\nimport type { Logger } from '@/types.js'\n\nexport function createLogger(): Logger {\n return {\n info(msg) {\n console.log(chalk.blue('info'), msg)\n },\n success(msg) {\n console.log(chalk.green('✓'), msg)\n },\n warn(msg) {\n console.log(chalk.yellow('warn'), msg)\n },\n error(msg) {\n console.error(chalk.red('error'), msg)\n },\n step(current, total, msg) {\n console.log(chalk.cyan(`[${current}/${total}]`), msg)\n },\n }\n}\n","import { run } from '@/cli.js'\n\nrun().catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : err)\n process.exit(1)\n})\n"],"mappings":"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","names":["mkdir","path","path","path","buildTemplateData","check","buildTemplateData","check","mkdir","check","path","access","readdir","path","path","readdir","access"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trailer-park-oss/create-rn-ai-starter",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "CLI to scaffold Expo React Native projects with modular feature packs",
5
5
  "type": "module",
6
6
  "bin": {