create-twinbloc-app 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.
Files changed (151) hide show
  1. package/README.md +123 -5
  2. package/bin/cli.js +155 -2
  3. package/package.json +1 -1
  4. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/AGENTS.md +946 -0
  5. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/SKILL.md +89 -0
  6. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  7. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
  8. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  9. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
  10. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
  11. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
  12. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
  13. package/template/react-native-starter/.agents/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
  14. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/AGENTS.md +2897 -0
  15. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/SKILL.md +121 -0
  16. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/animation-derived-value.md +53 -0
  17. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/animation-gesture-detector-press.md +95 -0
  18. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/animation-gpu-properties.md +65 -0
  19. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/design-system-compound-components.md +66 -0
  20. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/fonts-config-plugin.md +71 -0
  21. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/imports-design-system-folder.md +68 -0
  22. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/js-hoist-intl.md +61 -0
  23. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-callbacks.md +44 -0
  24. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-function-references.md +132 -0
  25. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-images.md +53 -0
  26. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-inline-objects.md +97 -0
  27. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-item-expensive.md +94 -0
  28. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-item-memo.md +82 -0
  29. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-item-types.md +104 -0
  30. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/list-performance-virtualize.md +67 -0
  31. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
  32. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
  33. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/navigation-native-navigators.md +188 -0
  34. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
  35. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
  36. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/react-state-dispatcher.md +91 -0
  37. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/react-state-fallback.md +56 -0
  38. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/react-state-minimize.md +65 -0
  39. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/rendering-no-falsy-and.md +74 -0
  40. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/rendering-text-in-text-component.md +36 -0
  41. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/scroll-position-no-state.md +82 -0
  42. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/state-ground-truth.md +80 -0
  43. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-expo-image.md +66 -0
  44. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-image-gallery.md +104 -0
  45. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-measure-views.md +78 -0
  46. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-menus.md +174 -0
  47. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-native-modals.md +77 -0
  48. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-pressable.md +61 -0
  49. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-safe-area-scroll.md +65 -0
  50. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
  51. package/template/react-native-starter/.agents/skills/vercel-react-native-skills/rules/ui-styling.md +87 -0
  52. package/template/react-native-starter/.env.development +2 -0
  53. package/template/react-native-starter/.env.production +2 -0
  54. package/template/react-native-starter/.env.staging +2 -0
  55. package/template/react-native-starter/README.md +1 -2
  56. package/template/react-native-starter/app.config.ts +57 -0
  57. package/template/react-native-starter/babel.config.js +21 -0
  58. package/template/react-native-starter/eslint.config.js +35 -3
  59. package/template/react-native-starter/global.css +3 -0
  60. package/template/react-native-starter/jest.config.js +13 -0
  61. package/template/react-native-starter/jest.setup.js +184 -0
  62. package/template/react-native-starter/metro.config.js +8 -0
  63. package/template/react-native-starter/nativewind-env.d.ts +3 -0
  64. package/template/react-native-starter/package-lock.json +5913 -1647
  65. package/template/react-native-starter/package.json +53 -2
  66. package/template/react-native-starter/root-env.js +122 -0
  67. package/template/react-native-starter/src/api/common/__tests__/api-provider.test.tsx +83 -0
  68. package/template/react-native-starter/src/api/common/__tests__/api-utils.test.ts +117 -0
  69. package/template/react-native-starter/src/api/common/__tests__/execute-client.test.ts +118 -0
  70. package/template/react-native-starter/src/api/common/api-provider.tsx +57 -0
  71. package/template/react-native-starter/src/api/common/api-utils.ts +159 -0
  72. package/template/react-native-starter/src/api/common/execute-client.ts +89 -0
  73. package/template/react-native-starter/src/api/common/index.ts +4 -0
  74. package/template/react-native-starter/src/api/common/types.ts +10 -0
  75. package/template/react-native-starter/src/api/index.ts +1 -0
  76. package/template/react-native-starter/src/app/(main)/_layout.tsx +15 -0
  77. package/template/react-native-starter/src/app/(main)/index.tsx +223 -0
  78. package/template/react-native-starter/src/app/+html.tsx +46 -0
  79. package/template/react-native-starter/src/app/[...messing].tsx +25 -0
  80. package/template/react-native-starter/src/app/_layout.tsx +56 -0
  81. package/template/react-native-starter/src/app/onboarding.tsx +23 -0
  82. package/template/react-native-starter/src/components/index.ts +1 -0
  83. package/template/react-native-starter/src/components/providers/index.tsx +62 -0
  84. package/template/react-native-starter/src/components/ui/__tests__/ui-basic.test.tsx +212 -0
  85. package/template/react-native-starter/src/components/ui/__tests__/ui-forms.test.tsx +116 -0
  86. package/template/react-native-starter/src/components/ui/accordion.tsx +142 -0
  87. package/template/react-native-starter/src/components/ui/avatar.tsx +141 -0
  88. package/template/react-native-starter/src/components/ui/bottom-sheet.tsx +120 -0
  89. package/template/react-native-starter/src/components/ui/button.tsx +139 -0
  90. package/template/react-native-starter/src/components/ui/check-box.tsx +74 -0
  91. package/template/react-native-starter/src/components/ui/container.tsx +52 -0
  92. package/template/react-native-starter/src/components/ui/icon.tsx +30 -0
  93. package/template/react-native-starter/src/components/ui/image.tsx +18 -0
  94. package/template/react-native-starter/src/components/ui/index.ts +15 -0
  95. package/template/react-native-starter/src/components/ui/input-view.tsx +22 -0
  96. package/template/react-native-starter/src/components/ui/input.tsx +132 -0
  97. package/template/react-native-starter/src/components/ui/progress-bar.tsx +136 -0
  98. package/template/react-native-starter/src/components/ui/radio.tsx +67 -0
  99. package/template/react-native-starter/src/components/ui/safe-fast-image.tsx +50 -0
  100. package/template/react-native-starter/src/components/ui/select.tsx +247 -0
  101. package/template/react-native-starter/src/components/ui/stacks.tsx +49 -0
  102. package/template/react-native-starter/src/components/ui/switch.tsx +134 -0
  103. package/template/react-native-starter/src/components/ui/text.tsx +115 -0
  104. package/template/react-native-starter/src/components/ui/toggle-shared.tsx +49 -0
  105. package/template/react-native-starter/src/components/utilities/colors.js +147 -0
  106. package/template/react-native-starter/src/components/utilities/confirm-dialog.tsx +112 -0
  107. package/template/react-native-starter/src/components/utilities/index.ts +4 -0
  108. package/template/react-native-starter/src/components/utilities/show-toast.ts +75 -0
  109. package/template/react-native-starter/src/components/utilities/ui-utils.tsx +7 -0
  110. package/template/react-native-starter/src/hooks/general/index.ts +0 -0
  111. package/template/react-native-starter/src/hooks/general/use-countdown.ts +61 -0
  112. package/template/react-native-starter/src/hooks/general/use-debounce.ts +22 -0
  113. package/template/react-native-starter/src/hooks/general/use-is-first-time.tsx +17 -0
  114. package/template/react-native-starter/src/hooks/general/use-select-theme.ts +34 -0
  115. package/template/react-native-starter/src/hooks/general/use-theme.tsx +47 -0
  116. package/template/react-native-starter/src/hooks/index.ts +1 -0
  117. package/template/react-native-starter/src/lib/app-initializer.ts +31 -0
  118. package/template/react-native-starter/src/lib/env.ts +12 -0
  119. package/template/react-native-starter/src/lib/i18n/__tests__/index.test.ts +108 -0
  120. package/template/react-native-starter/src/lib/i18n/__tests__/utils.test.ts +123 -0
  121. package/template/react-native-starter/src/lib/i18n/index.tsx +51 -0
  122. package/template/react-native-starter/src/lib/i18n/react-i18next.d.ts +12 -0
  123. package/template/react-native-starter/src/lib/i18n/resources.ts +28 -0
  124. package/template/react-native-starter/src/lib/i18n/types.ts +23 -0
  125. package/template/react-native-starter/src/lib/i18n/utils.tsx +65 -0
  126. package/template/react-native-starter/src/lib/index.ts +1 -0
  127. package/template/react-native-starter/src/lib/utils/__tests__/secure-store.test.ts +75 -0
  128. package/template/react-native-starter/src/lib/utils/__tests__/storage.test.ts +168 -0
  129. package/template/react-native-starter/src/lib/utils/blurhash.ts +29 -0
  130. package/template/react-native-starter/src/lib/utils/extract-error.ts +23 -0
  131. package/template/react-native-starter/src/lib/utils/format-currency.ts +13 -0
  132. package/template/react-native-starter/src/lib/utils/index.ts +2 -0
  133. package/template/react-native-starter/src/lib/utils/rate-app.ts +37 -0
  134. package/template/react-native-starter/src/lib/utils/secure-store.ts +83 -0
  135. package/template/react-native-starter/src/lib/utils/storage.ts +126 -0
  136. package/template/react-native-starter/src/lib/utils/toast-config.ts +33 -0
  137. package/template/react-native-starter/src/store/auth/index.ts +69 -0
  138. package/template/react-native-starter/src/store/auth/utils.ts +26 -0
  139. package/template/react-native-starter/src/store/store-utils.ts +13 -0
  140. package/template/react-native-starter/src/store/utility/index.tsx +39 -0
  141. package/template/react-native-starter/src/translations/ar.json +13 -0
  142. package/template/react-native-starter/src/translations/en.json +13 -0
  143. package/template/react-native-starter/src/translations/es.json +13 -0
  144. package/template/react-native-starter/src/translations/fr.json +13 -0
  145. package/template/react-native-starter/src/types/expo-asset.d.ts +9 -0
  146. package/template/react-native-starter/tailwind.config.js +18 -0
  147. package/template/react-native-starter/tsconfig.json +7 -9
  148. package/template/react-native-starter/app/_layout.tsx +0 -5
  149. package/template/react-native-starter/app/index.tsx +0 -86
  150. package/template/react-native-starter/app.json +0 -50
  151. /package/template/react-native-starter/src/{state → store}/useCounterStore.ts +0 -0
package/README.md CHANGED
@@ -1,14 +1,51 @@
1
1
  # Create Twinbloc App
2
2
 
3
- Create a React Native app from the Twinbloc starter template.
3
+ Create a React Native app with the Twinbloc starter template. This CLI scaffolds a production-ready Expo SDK 54 project with Expo Router, TypeScript, native modules, and a curated set of defaults for state, API, UI, and localization.
4
4
 
5
- ## Usage
5
+ ## What You Get
6
+
7
+ - Expo SDK 54 project with Expo Router and typed routes
8
+ - React Native 0.81 + React 19 setup
9
+ - TypeScript-first structure with strict TS config
10
+ - NativeWind + Tailwind utilities, themed UI primitives, and tokens
11
+ - Zustand store examples with persisted auth state
12
+ - TanStack Query with MMKV persistence
13
+ - Axios API client with auth-aware helpers
14
+ - i18next localization with English, Spanish, French, and Arabic samples
15
+ - Reanimated-ready bottom sheet provider and gesture handler setup
16
+ - Toasts, haptics, blur, image, and icon tooling prewired
17
+ - Environment-driven app config for name, slug, scheme, bundle IDs
18
+
19
+ ## Requirements
20
+
21
+ - Node.js 18+
22
+ - npm, yarn, pnpm, or bun
23
+ - Xcode for iOS (macOS) and/or Android Studio for Android
24
+
25
+ ## Quick Start (npm)
6
26
 
7
27
  ```bash
8
28
  npx create-twinbloc-app@latest MyApp
29
+ cd MyApp
30
+ npm run start
31
+ ```
32
+
33
+ Then build and open a dev client:
34
+
35
+ ```bash
36
+ npx expo run:ios
37
+ npx expo run:android
38
+ ```
39
+
40
+ ## Using Other Package Managers
41
+
42
+ ```bash
43
+ yarn create twinbloc-app MyApp
44
+ pnpm create twinbloc-app MyApp
45
+ bun create twinbloc-app MyApp
9
46
  ```
10
47
 
11
- ## Options
48
+ ## CLI Options
12
49
 
13
50
  ```bash
14
51
  npx create-twinbloc-app@latest MyApp --example base
@@ -19,6 +56,87 @@ npx create-twinbloc-app@latest MyApp --pm pnpm
19
56
  npx create-twinbloc-app@latest MyApp --pm bun
20
57
  ```
21
58
 
22
- ## Template
59
+ ### Example Variants
60
+
61
+ Only the base template ships in this repo. Use:
62
+
63
+ ```bash
64
+ npx create-twinbloc-app@latest MyApp --example base
65
+ ```
66
+
67
+ ## Running the App
68
+
69
+ This starter includes native modules, so you should use a development build instead of Expo Go.
70
+
71
+ ```bash
72
+ npm run start
73
+ ```
74
+
75
+ Then run a dev client when you need native modules:
76
+
77
+ ```bash
78
+ npx expo run:ios
79
+ npx expo run:android
80
+ ```
81
+
82
+ ## Project Structure
83
+
84
+ ```
85
+ MyApp/
86
+ app/ # Expo Router routes
87
+ assets/ # Images and icons
88
+ src/
89
+ api/ # Axios client and React Query helpers
90
+ components/ # UI components and providers
91
+ hooks/ # App hooks
92
+ lib/ # i18n, env, storage, utilities
93
+ store/ # Zustand stores
94
+ translations/ # i18n resource files
95
+ app.config.ts # Env-driven Expo config
96
+ global.css # NativeWind globals
97
+ package.json # Scripts and dependencies
98
+ tsconfig.json # TypeScript config
99
+ ```
100
+
101
+ ## Environment Configuration
102
+
103
+ The template loads environment values from `.env.{APP_ENV}` and `.env` with `APP_ENV=development|staging|production`.
104
+
105
+ Required by default:
106
+
107
+ - `EXPO_PUBLIC_API_URL` for your API base URL
108
+
109
+ Optional overrides:
110
+
111
+ - `APP_NAME`, `APP_SLUG`, `APP_SCHEME`
112
+ - `APP_BUNDLE_ID_DEVELOPMENT`, `APP_BUNDLE_ID_STAGING`, `APP_BUNDLE_ID_PRODUCTION`
113
+ - `APP_PACKAGE_DEVELOPMENT`, `APP_PACKAGE_STAGING`, `APP_PACKAGE_PRODUCTION`
114
+
115
+ Values are validated on startup. If you update `.env` files and still see errors, restart the dev server with `-c` to clear cache.
116
+
117
+ ## Scripts
118
+
119
+ ```bash
120
+ npm run start # Expo dev server
121
+ npm run ios # Build iOS dev client
122
+ npm run android # Build Android dev client
123
+ npm run web # Run web build
124
+ npm run lint # Lint project
125
+ npm run test # Jest tests
126
+ npm run reset-project # Move starter to app-example and create a fresh app
127
+ ```
128
+
129
+ ## Template Details
130
+
131
+ - Location: `template/react-native-starter`
132
+ - Framework: Expo SDK 54 + Expo Router
133
+ - Styling: NativeWind + Tailwind utilities
134
+ - State: Zustand stores in `src/store`
135
+ - Data: TanStack Query helpers in `src/api`
136
+ - i18n: `src/lib/i18n` and `src/translations`
137
+
138
+ ## Troubleshooting
23
139
 
24
- The generated app is located in the `template/react-native-starter` directory of this package and uses Expo with Expo Router.
140
+ - If install fails, retry with `--pm` to force a package manager.
141
+ - If the folder is not empty, choose a new directory name.
142
+ - If your app launches but native modules crash, rebuild the dev client.
package/bin/cli.js CHANGED
@@ -5,6 +5,8 @@ import fs from "fs-extra";
5
5
  import { spawnSync } from "child_process";
6
6
  import chalk from "chalk";
7
7
  import { fileURLToPath } from "url";
8
+ import readline from "readline";
9
+ import { stdin as input, stdout as output } from "process";
8
10
 
9
11
  const __filename = fileURLToPath(import.meta.url);
10
12
  const __dirname = path.dirname(__filename);
@@ -64,6 +66,129 @@ const runInstall = (dir, pm) => {
64
66
  if (result.status !== 0) process.exit(result.status);
65
67
  };
66
68
 
69
+ const brandPrimary = chalk.hex("#6CABDD");
70
+ const brandDeep = chalk.hex("#1C2C5B");
71
+ const rnBlue = chalk.hex("#61DAFB");
72
+ const uiMuted = chalk.gray;
73
+ const uiAccent = chalk.hex("#9FD7F2");
74
+ const uiActive = chalk.hex("#88C6FF");
75
+ const uiSelected = chalk.hex("#6EDC91");
76
+
77
+ const printBanner = () => {
78
+ const lines = [
79
+ "████████╗██╗ ██╗██╗███╗ ██╗██████╗ ██╗ ██████╗ ██████╗",
80
+ "╚══██╔══╝██║ ██║██║████╗ ██║██╔══██╗██║ ██╔═══██╗██╔════╝",
81
+ " ██║ ██║ █╗ ██║██║██╔██╗ ██║██████╔╝██║ ██║ ██║██║",
82
+ " ██║ ██║███╗██║██║██║╚██╗██║██╔══██╗██║ ██║ ██║██║",
83
+ " ██║ ╚███╔███╔╝██║██║ ╚████║██████╔╝███████╗╚██████╔╝╚██████╗",
84
+ " ╚═╝ ╚══╝╚══╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝",
85
+ ];
86
+ lines.forEach((line, index) => {
87
+ const paint = index < 3 ? brandPrimary : brandDeep;
88
+ console.log(paint(line));
89
+ });
90
+ console.log(brandPrimary("React Native Starter"));
91
+ console.log(rnBlue(" ⚛ React Native • Expo + Router • TypeScript • Zustand"));
92
+ console.log("");
93
+ };
94
+
95
+ const agentDirectories = [
96
+ { key: "Antigravity", path: ".agents", label: ".agents/skills" },
97
+ { key: "agent", path: ".agent", label: ".agent/skills" },
98
+ { key: "claude", path: ".claude", label: ".claude/skills" },
99
+ { key: "codex", path: ".codex", label: ".codex/skills" },
100
+ { key: "cursor", path: ".cursor", label: ".cursor/skills" },
101
+ { key: "github", path: ".github", label: ".github/skills" },
102
+ { key: "kilocode", path: ".kilocode", label: ".kilocode/skills" },
103
+ { key: "opencode", path: ".opencode", label: ".opencode/skills" },
104
+ { key: "trae", path: ".trae", label: ".trae" },
105
+ { key: "vscode", path: ".vscode", label: ".vscode" },
106
+ { key: "windsurf", path: ".windsurf", label: ".windsurf" },
107
+ ];
108
+
109
+ const getExistingAgentKeys = async (rootDir) => {
110
+ const existing = new Set();
111
+ for (const dir of agentDirectories) {
112
+ if (await fs.pathExists(path.join(rootDir, dir.path))) {
113
+ existing.add(dir.key);
114
+ }
115
+ }
116
+ return existing;
117
+ };
118
+
119
+ const renderAgentSelection = (choices, selectedKeys, activeIndex) => {
120
+ output.write("\x1b[2J\x1b[0;0H");
121
+ printBanner();
122
+ console.log(brandPrimary.bold("Select agent configs to include"));
123
+ console.log(uiMuted("Use ↑/↓ to move, space to toggle, enter to confirm."));
124
+ console.log(uiMuted("Press enter with nothing selected for none."));
125
+ console.log("");
126
+
127
+ choices.forEach((choice, index) => {
128
+ const isActive = index === activeIndex;
129
+ const isSelected = selectedKeys.has(choice.key);
130
+ const cursor = isActive ? ">" : " ";
131
+ const mark = isSelected ? "x" : " ";
132
+ const line = `${cursor} [${mark}] ${choice.label}`;
133
+ if (isActive) {
134
+ console.log(uiActive.bold(line));
135
+ return;
136
+ }
137
+ if (isSelected) {
138
+ console.log(uiSelected(line));
139
+ return;
140
+ }
141
+ console.log(uiAccent(line));
142
+ });
143
+ };
144
+
145
+ const promptAgentSelection = async (choices, defaultKeys) => {
146
+ readline.emitKeypressEvents(input);
147
+ if (input.isTTY) {
148
+ input.setRawMode(true);
149
+ }
150
+
151
+ const selectedKeys = new Set(defaultKeys);
152
+ let activeIndex = 0;
153
+
154
+ renderAgentSelection(choices, selectedKeys, activeIndex);
155
+
156
+ return new Promise((resolve) => {
157
+ const onKeypress = (_str, key) => {
158
+ if (key.name === "up") {
159
+ activeIndex = (activeIndex - 1 + choices.length) % choices.length;
160
+ renderAgentSelection(choices, selectedKeys, activeIndex);
161
+ return;
162
+ }
163
+ if (key.name === "down") {
164
+ activeIndex = (activeIndex + 1) % choices.length;
165
+ renderAgentSelection(choices, selectedKeys, activeIndex);
166
+ return;
167
+ }
168
+ if (key.name === "space") {
169
+ const choice = choices[activeIndex];
170
+ if (selectedKeys.has(choice.key)) {
171
+ selectedKeys.delete(choice.key);
172
+ } else {
173
+ selectedKeys.add(choice.key);
174
+ }
175
+ renderAgentSelection(choices, selectedKeys, activeIndex);
176
+ return;
177
+ }
178
+ if (key.name === "return") {
179
+ input.off("keypress", onKeypress);
180
+ if (input.isTTY) {
181
+ input.setRawMode(false);
182
+ }
183
+ output.write("\n");
184
+ resolve(selectedKeys);
185
+ }
186
+ };
187
+
188
+ input.on("keypress", onKeypress);
189
+ });
190
+ };
191
+
67
192
  const main = async () => {
68
193
  const empty = await isEmptyDir(targetDir);
69
194
  if (!empty) {
@@ -89,10 +214,20 @@ const main = async () => {
89
214
  await fs.copy(examplePath, targetDir, { overwrite: true });
90
215
  }
91
216
 
217
+ const existingAgentKeys = await getExistingAgentKeys(targetDir);
218
+ const defaultKeys = agentDirectories.filter((dir) => existingAgentKeys.has(dir.key)).map((dir) => dir.key);
219
+
220
+ const selectedKeys = await promptAgentSelection(agentDirectories, defaultKeys);
221
+ const selectedLabels = agentDirectories.filter((dir) => selectedKeys.has(dir.key)).map((dir) => dir.label);
222
+
223
+ const dirsToRemove = agentDirectories.filter((dir) => !selectedKeys.has(dir.key));
224
+ await Promise.all(dirsToRemove.map((dir) => fs.remove(path.join(targetDir, dir.path))));
225
+
226
+ const appName = path.basename(targetDir);
92
227
  const targetPackageJson = path.join(targetDir, "package.json");
93
228
  if (fs.existsSync(targetPackageJson)) {
94
229
  const pkg = await fs.readJson(targetPackageJson);
95
- pkg.name = path.basename(targetDir);
230
+ pkg.name = appName;
96
231
  await fs.writeJson(targetPackageJson, pkg, { spaces: 2 });
97
232
  }
98
233
 
@@ -104,7 +239,25 @@ const main = async () => {
104
239
  runInstall(targetDir, pm);
105
240
  }
106
241
 
107
- console.log(chalk.green("Project created successfully."));
242
+ printBanner();
243
+ console.log(
244
+ [
245
+ brandPrimary.bold("Project created successfully."),
246
+ "",
247
+ uiMuted(`Agent configs: ${selectedLabels.length > 0 ? selectedLabels.join(", ") : "none"}`),
248
+ "",
249
+ brandPrimary("Next steps"),
250
+ uiAccent(` cd ${appName}`),
251
+ options.skipInstall ? uiAccent(" npm install") : null,
252
+ uiAccent(" npm run start"),
253
+ "",
254
+ brandPrimary("Then"),
255
+ uiMuted(" - Build a dev client (if you haven’t): npx expo run:ios / npx expo run:android"),
256
+ uiMuted(" - Open the app from the dev client on your device or simulator"),
257
+ ]
258
+ .filter(Boolean)
259
+ .join("\n"),
260
+ );
108
261
  };
109
262
 
110
263
  main().catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-twinbloc-app",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "React Native starter template with optional examples",
5
5
  "type": "module",
6
6
  "bin": {