@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 +206 -0
- package/dist/index.js +28 -90
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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: "
|
|
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": "
|
|
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
|
|
604
|
-
if (
|
|
605
|
-
logger.success(`[${packId}] ${
|
|
525
|
+
for (const check4 of result.checks) {
|
|
526
|
+
if (check4.passed) {
|
|
527
|
+
logger.success(`[${packId}] ${check4.name}`);
|
|
606
528
|
} else {
|
|
607
|
-
logger.error(`[${packId}] ${
|
|
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"]}
|