@symbiote-native/cli 0.0.1
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/LICENSE +21 -0
- package/README.md +492 -0
- package/bundle.js +2833 -0
- package/package.json +49 -0
- package/src/index.ts +70 -0
- package/templates/README.md +93 -0
- package/templates/js/angular/.prettierrc.js +5 -0
- package/templates/js/angular/.watchmanconfig +1 -0
- package/templates/js/angular/README.md +117 -0
- package/templates/js/angular/app.json +4 -0
- package/templates/js/angular/babel.config.js +34 -0
- package/templates/js/angular/index.js +12 -0
- package/templates/js/angular/metro.config.js +38 -0
- package/templates/js/angular/package.json.fragment.json +29 -0
- package/templates/js/angular/src/App.css +89 -0
- package/templates/js/angular/src/App.ts +40 -0
- package/templates/js/angular/src/assets/angular-logo.png +0 -0
- package/templates/js/angular/src/assets/angular-logo@2x.png +0 -0
- package/templates/js/angular/src/assets/angular-logo@3x.png +0 -0
- package/templates/js/angular/src/assets/plus-icon.png +0 -0
- package/templates/js/angular/src/assets/plus-icon@2x.png +0 -0
- package/templates/js/angular/src/assets/plus-icon@3x.png +0 -0
- package/templates/js/angular/src/assets/react-native-logo.png +0 -0
- package/templates/js/angular/src/assets/react-native-logo@2x.png +0 -0
- package/templates/js/angular/src/assets/react-native-logo@3x.png +0 -0
- package/templates/js/angular/src/css.d.ts +23 -0
- package/templates/js/angular/tsconfig.angular.json +42 -0
- package/templates/js/angular/tsconfig.json +17 -0
- package/templates/js/react/.prettierrc.js +5 -0
- package/templates/js/react/.watchmanconfig +1 -0
- package/templates/js/react/App.css +69 -0
- package/templates/js/react/App.jsx +27 -0
- package/templates/js/react/App.tsx +27 -0
- package/templates/js/react/README.md +116 -0
- package/templates/js/react/app.json +4 -0
- package/templates/js/react/assets/react-native-logo.png +0 -0
- package/templates/js/react/assets/react-native-logo@2x.png +0 -0
- package/templates/js/react/assets/react-native-logo@3x.png +0 -0
- package/templates/js/react/babel.config.js +24 -0
- package/templates/js/react/css.d.ts +24 -0
- package/templates/js/react/index.js +14 -0
- package/templates/js/react/metro.config.js +29 -0
- package/templates/js/react/package.json.fragment.json +22 -0
- package/templates/js/react/package.json.fragment.typescript.json +11 -0
- package/templates/js/react/tsconfig.json +18 -0
- package/templates/js/solid/.prettierrc.js +5 -0
- package/templates/js/solid/.watchmanconfig +1 -0
- package/templates/js/solid/App.css +89 -0
- package/templates/js/solid/App.jsx +35 -0
- package/templates/js/solid/App.tsx +35 -0
- package/templates/js/solid/README.md +18 -0
- package/templates/js/solid/app.json +4 -0
- package/templates/js/solid/assets/plus-icon.png +0 -0
- package/templates/js/solid/assets/plus-icon@2x.png +0 -0
- package/templates/js/solid/assets/plus-icon@3x.png +0 -0
- package/templates/js/solid/assets/react-native-logo.png +0 -0
- package/templates/js/solid/assets/react-native-logo@2x.png +0 -0
- package/templates/js/solid/assets/react-native-logo@3x.png +0 -0
- package/templates/js/solid/assets/solid-logo.png +0 -0
- package/templates/js/solid/assets/solid-logo@2x.png +0 -0
- package/templates/js/solid/assets/solid-logo@3x.png +0 -0
- package/templates/js/solid/babel.config.js +29 -0
- package/templates/js/solid/css.d.ts +20 -0
- package/templates/js/solid/eslint.config.js +3 -0
- package/templates/js/solid/index.js +13 -0
- package/templates/js/solid/metro.config.js +50 -0
- package/templates/js/solid/package.json.fragment.json +23 -0
- package/templates/js/solid/package.json.fragment.typescript.json +11 -0
- package/templates/js/solid/tsconfig.json +11 -0
- package/templates/js/svelte/.prettierrc.js +15 -0
- package/templates/js/svelte/.watchmanconfig +1 -0
- package/templates/js/svelte/App.svelte +123 -0
- package/templates/js/svelte/App.typescript.svelte +123 -0
- package/templates/js/svelte/README.md +18 -0
- package/templates/js/svelte/app.json +4 -0
- package/templates/js/svelte/babel.config.js +22 -0
- package/templates/js/svelte/css.d.ts +21 -0
- package/templates/js/svelte/eslint.config.js +37 -0
- package/templates/js/svelte/image-uris.js +8 -0
- package/templates/js/svelte/index.js +13 -0
- package/templates/js/svelte/metro.config.js +83 -0
- package/templates/js/svelte/package.json.fragment.json +26 -0
- package/templates/js/svelte/package.json.fragment.typescript.json +12 -0
- package/templates/js/svelte/svelte.config.js +47 -0
- package/templates/js/svelte/tsconfig.json +9 -0
- package/templates/js/svelte/tsconfig.typecheck.json +4 -0
- package/templates/js/vue-sfc/.prettierrc.js +5 -0
- package/templates/js/vue-sfc/.watchmanconfig +1 -0
- package/templates/js/vue-sfc/App.typescript.vue +128 -0
- package/templates/js/vue-sfc/App.vue +128 -0
- package/templates/js/vue-sfc/README.md +124 -0
- package/templates/js/vue-sfc/app.json +4 -0
- package/templates/js/vue-sfc/assets/plus-icon.png +0 -0
- package/templates/js/vue-sfc/assets/plus-icon@2x.png +0 -0
- package/templates/js/vue-sfc/assets/plus-icon@3x.png +0 -0
- package/templates/js/vue-sfc/assets/react-native-logo.png +0 -0
- package/templates/js/vue-sfc/assets/react-native-logo@2x.png +0 -0
- package/templates/js/vue-sfc/assets/react-native-logo@3x.png +0 -0
- package/templates/js/vue-sfc/assets/vue-logo.png +0 -0
- package/templates/js/vue-sfc/assets/vue-logo@2x.png +0 -0
- package/templates/js/vue-sfc/assets/vue-logo@3x.png +0 -0
- package/templates/js/vue-sfc/babel.config.js +24 -0
- package/templates/js/vue-sfc/css.d.ts +24 -0
- package/templates/js/vue-sfc/eslint.config.js +48 -0
- package/templates/js/vue-sfc/index.js +13 -0
- package/templates/js/vue-sfc/metro.config.js +30 -0
- package/templates/js/vue-sfc/package.json.fragment.json +26 -0
- package/templates/js/vue-sfc/package.json.fragment.typescript.json +11 -0
- package/templates/js/vue-sfc/tsconfig.json +18 -0
- package/templates/js/vue-sfc/tsconfig.typecheck.json +8 -0
- package/templates/js/vue-sfc/vue-runtime-core.d.ts +3 -0
- package/templates/js/vue-tsx/.prettierrc.js +5 -0
- package/templates/js/vue-tsx/.watchmanconfig +1 -0
- package/templates/js/vue-tsx/App.css +89 -0
- package/templates/js/vue-tsx/App.jsx +40 -0
- package/templates/js/vue-tsx/App.tsx +40 -0
- package/templates/js/vue-tsx/README.md +110 -0
- package/templates/js/vue-tsx/app.json +4 -0
- package/templates/js/vue-tsx/assets/plus-icon.png +0 -0
- package/templates/js/vue-tsx/assets/plus-icon@2x.png +0 -0
- package/templates/js/vue-tsx/assets/plus-icon@3x.png +0 -0
- package/templates/js/vue-tsx/assets/react-native-logo.png +0 -0
- package/templates/js/vue-tsx/assets/react-native-logo@2x.png +0 -0
- package/templates/js/vue-tsx/assets/react-native-logo@3x.png +0 -0
- package/templates/js/vue-tsx/assets/vue-logo.png +0 -0
- package/templates/js/vue-tsx/assets/vue-logo@2x.png +0 -0
- package/templates/js/vue-tsx/assets/vue-logo@3x.png +0 -0
- package/templates/js/vue-tsx/babel.config.js +67 -0
- package/templates/js/vue-tsx/css.d.ts +24 -0
- package/templates/js/vue-tsx/index.js +14 -0
- package/templates/js/vue-tsx/metro.config.js +42 -0
- package/templates/js/vue-tsx/package.json.fragment.json +26 -0
- package/templates/js/vue-tsx/package.json.fragment.typescript.json +11 -0
- package/templates/js/vue-tsx/tsconfig.json +15 -0
- package/templates/js/vue-tsx/tsconfig.typecheck.json +10 -0
- package/templates/js/vue-tsx/vue-jsx.d.ts +43 -0
- package/templates/js/vue-tsx/vue-runtime-core.d.ts +3 -0
- package/templates/layers/README.md +90 -0
- package/templates/layers/application/package.json.fragment.json +5 -0
- package/templates/layers/battery/package.json.fragment.json +5 -0
- package/templates/layers/brightness/package.json.fragment.json +5 -0
- package/templates/layers/cellular/package.json.fragment.json +5 -0
- package/templates/layers/clipboard/package.json.fragment.json +5 -0
- package/templates/layers/crypto/package.json.fragment.json +5 -0
- package/templates/layers/device/package.json.fragment.json +5 -0
- package/templates/layers/expo-modules/ios/Canary/Info.plist +66 -0
- package/templates/layers/expo-modules/package.json.fragment.json +9 -0
- package/templates/layers/haptics/package.json.fragment.json +5 -0
- package/templates/layers/keep-awake/package.json.fragment.json +5 -0
- package/templates/layers/local-auth/package.json.fragment.json +5 -0
- package/templates/layers/localization/package.json.fragment.json +5 -0
- package/templates/layers/navigation/app/angular/assets/angular-logo.png +0 -0
- package/templates/layers/navigation/app/angular/assets/angular-logo@2x.png +0 -0
- package/templates/layers/navigation/app/angular/assets/angular-logo@3x.png +0 -0
- package/templates/layers/navigation/app/angular/assets/plus-icon.png +0 -0
- package/templates/layers/navigation/app/angular/assets/plus-icon@2x.png +0 -0
- package/templates/layers/navigation/app/angular/assets/plus-icon@3x.png +0 -0
- package/templates/layers/navigation/app/angular/assets/react-native-logo.png +0 -0
- package/templates/layers/navigation/app/angular/assets/react-native-logo@2x.png +0 -0
- package/templates/layers/navigation/app/angular/assets/react-native-logo@3x.png +0 -0
- package/templates/layers/navigation/app/angular/src/App.css +129 -0
- package/templates/layers/navigation/app/angular/src/App.ts +31 -0
- package/templates/layers/navigation/app/angular/src/DetailsScreen.ts +24 -0
- package/templates/layers/navigation/app/angular/src/MenuScreen.ts +43 -0
- package/templates/layers/navigation/app/react/App.css +109 -0
- package/templates/layers/navigation/app/react/App.jsx +77 -0
- package/templates/layers/navigation/app/react/App.tsx +77 -0
- package/templates/layers/navigation/app/react/assets/react-native-logo.png +0 -0
- package/templates/layers/navigation/app/react/assets/react-native-logo@2x.png +0 -0
- package/templates/layers/navigation/app/react/assets/react-native-logo@3x.png +0 -0
- package/templates/layers/navigation/app/solid/App.css +129 -0
- package/templates/layers/navigation/app/solid/App.jsx +85 -0
- package/templates/layers/navigation/app/solid/App.tsx +85 -0
- package/templates/layers/navigation/app/solid/assets/plus-icon.png +0 -0
- package/templates/layers/navigation/app/solid/assets/plus-icon@2x.png +0 -0
- package/templates/layers/navigation/app/solid/assets/plus-icon@3x.png +0 -0
- package/templates/layers/navigation/app/solid/assets/react-native-logo.png +0 -0
- package/templates/layers/navigation/app/solid/assets/react-native-logo@2x.png +0 -0
- package/templates/layers/navigation/app/solid/assets/react-native-logo@3x.png +0 -0
- package/templates/layers/navigation/app/solid/assets/solid-logo.png +0 -0
- package/templates/layers/navigation/app/solid/assets/solid-logo@2x.png +0 -0
- package/templates/layers/navigation/app/solid/assets/solid-logo@3x.png +0 -0
- package/templates/layers/navigation/app/svelte/App.css +129 -0
- package/templates/layers/navigation/app/svelte/App.svelte +19 -0
- package/templates/layers/navigation/app/svelte/App.typescript.svelte +19 -0
- package/templates/layers/navigation/app/svelte/DetailsScreen.svelte +17 -0
- package/templates/layers/navigation/app/svelte/DetailsScreen.typescript.svelte +17 -0
- package/templates/layers/navigation/app/svelte/MenuScreen.svelte +40 -0
- package/templates/layers/navigation/app/svelte/MenuScreen.typescript.svelte +40 -0
- package/templates/layers/navigation/app/svelte/image-uris.js +8 -0
- package/templates/layers/navigation/app/vue-sfc/App.css +129 -0
- package/templates/layers/navigation/app/vue-sfc/App.typescript.vue +36 -0
- package/templates/layers/navigation/app/vue-sfc/App.vue +36 -0
- package/templates/layers/navigation/app/vue-sfc/DetailsScreen.typescript.vue +20 -0
- package/templates/layers/navigation/app/vue-sfc/DetailsScreen.vue +20 -0
- package/templates/layers/navigation/app/vue-sfc/MenuScreen.typescript.vue +52 -0
- package/templates/layers/navigation/app/vue-sfc/MenuScreen.vue +52 -0
- package/templates/layers/navigation/app/vue-sfc/assets/plus-icon.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/plus-icon@2x.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/plus-icon@3x.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/react-native-logo.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/react-native-logo@2x.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/react-native-logo@3x.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/vue-logo.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/vue-logo@2x.png +0 -0
- package/templates/layers/navigation/app/vue-sfc/assets/vue-logo@3x.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/App.css +129 -0
- package/templates/layers/navigation/app/vue-tsx/App.jsx +91 -0
- package/templates/layers/navigation/app/vue-tsx/App.tsx +91 -0
- package/templates/layers/navigation/app/vue-tsx/assets/plus-icon.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/plus-icon@2x.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/plus-icon@3x.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/react-native-logo.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/react-native-logo@2x.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/react-native-logo@3x.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/vue-logo.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/vue-logo@2x.png +0 -0
- package/templates/layers/navigation/app/vue-tsx/assets/vue-logo@3x.png +0 -0
- package/templates/layers/navigation/package.json.fragment.json +5 -0
- package/templates/layers/network/package.json.fragment.json +5 -0
- package/templates/layers/screen-orientation/package.json.fragment.json +5 -0
- package/templates/layers/secure-store/package.json.fragment.json +5 -0
- package/templates/layers/sensors/package.json.fragment.json +5 -0
- package/templates/layers/sharing/package.json.fragment.json +5 -0
- package/templates/layers/slider/package.json.fragment.json +5 -0
- package/templates/layers/sms/package.json.fragment.json +5 -0
- package/templates/layers/splash-screen/native/android/app/src/main/AndroidManifest.xml +28 -0
- package/templates/layers/splash-screen/native/android/app/src/main/java/com/canary/MainActivity.kt +29 -0
- package/templates/layers/splash-screen/native/android/app/src/main/res/values/styles.xml +12 -0
- package/templates/layers/splash-screen/native/ios/Canary/AppDelegate.swift +54 -0
- package/templates/layers/splash-screen/package.json.fragment.json +5 -0
- package/templates/layers/standard-web-crypto/package.json.fragment.json +5 -0
- package/templates/layers/store-review/package.json.fragment.json +5 -0
- package/templates/layers/system-ui/package.json.fragment.json +5 -0
- package/templates/layers/testing/detox.config.js +42 -0
- package/templates/layers/testing/e2e/jest.config.js +21 -0
- package/templates/layers/testing/e2e/setup.ts +3 -0
- package/templates/layers/testing/e2e/smoke.test.ts +17 -0
- package/templates/layers/testing/e2e/tsconfig.json +7 -0
- package/templates/layers/testing/fragment/angular/package.json.fragment.json +18 -0
- package/templates/layers/testing/fragment/base/package.json.fragment.json +18 -0
- package/templates/layers/tracking-transparency/package.json.fragment.json +5 -0
- package/templates/layers/web-browser/package.json.fragment.json +5 -0
- package/templates/native/Gemfile +17 -0
- package/templates/native/README.md +48 -0
- package/templates/native/android/app/build.gradle +130 -0
- package/templates/native/android/app/debug.keystore +0 -0
- package/templates/native/android/app/proguard-rules.pro +10 -0
- package/templates/native/android/app/src/androidTest/java/com/canary/DetoxTest.java +29 -0
- package/templates/native/android/app/src/main/AndroidManifest.xml +28 -0
- package/templates/native/android/app/src/main/java/com/canary/MainActivity.kt +22 -0
- package/templates/native/android/app/src/main/java/com/canary/MainApplication.kt +27 -0
- package/templates/native/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/templates/native/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png +0 -0
- package/templates/native/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png +0 -0
- package/templates/native/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png +0 -0
- package/templates/native/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/templates/native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/templates/native/android/app/src/main/res/values/colors.xml +3 -0
- package/templates/native/android/app/src/main/res/values/strings.xml +3 -0
- package/templates/native/android/app/src/main/res/values/styles.xml +6 -0
- package/templates/native/android/build.gradle +33 -0
- package/templates/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/templates/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/templates/native/android/gradle.properties +44 -0
- package/templates/native/android/gradlew +248 -0
- package/templates/native/android/gradlew.bat +98 -0
- package/templates/native/android/settings.gradle +10 -0
- package/templates/native/bootsplash-logo/angular/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/angular/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/angular/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/angular/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/angular/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/angular/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55.png +0 -0
- package/templates/native/bootsplash-logo/angular/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@2x.png +0 -0
- package/templates/native/bootsplash-logo/angular/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@3x.png +0 -0
- package/templates/native/bootsplash-logo/solid/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/solid/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/solid/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/solid/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/solid/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/solid/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55.png +0 -0
- package/templates/native/bootsplash-logo/solid/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@2x.png +0 -0
- package/templates/native/bootsplash-logo/solid/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@3x.png +0 -0
- package/templates/native/bootsplash-logo/svelte/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/svelte/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/svelte/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/svelte/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/svelte/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/svelte/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55.png +0 -0
- package/templates/native/bootsplash-logo/svelte/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@2x.png +0 -0
- package/templates/native/bootsplash-logo/svelte/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@3x.png +0 -0
- package/templates/native/bootsplash-logo/vue/android/app/src/main/res/drawable-hdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/vue/android/app/src/main/res/drawable-mdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/vue/android/app/src/main/res/drawable-xhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/vue/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/vue/android/app/src/main/res/drawable-xxxhdpi/bootsplash_logo.png +0 -0
- package/templates/native/bootsplash-logo/vue/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55.png +0 -0
- package/templates/native/bootsplash-logo/vue/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@2x.png +0 -0
- package/templates/native/bootsplash-logo/vue/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@3x.png +0 -0
- package/templates/native/eslint.config.js +3 -0
- package/templates/native/ios/.xcode.env +11 -0
- package/templates/native/ios/Canary/AppDelegate.swift +48 -0
- package/templates/native/ios/Canary/BootSplash.storyboard +46 -0
- package/templates/native/ios/Canary/Colors.xcassets/BootSplashBackground-498e55.colorset/Contents.json +20 -0
- package/templates/native/ios/Canary/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/templates/native/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/Contents.json +23 -0
- package/templates/native/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55.png +0 -0
- package/templates/native/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@2x.png +0 -0
- package/templates/native/ios/Canary/Images.xcassets/BootSplashLogo-498e55.imageset/logo-498e55@3x.png +0 -0
- package/templates/native/ios/Canary/Images.xcassets/Contents.json +6 -0
- package/templates/native/ios/Canary/Info.plist +60 -0
- package/templates/native/ios/Canary/LaunchScreen.storyboard +47 -0
- package/templates/native/ios/Canary/PrivacyInfo.xcprivacy +37 -0
- package/templates/native/ios/Canary.xcodeproj/project.pbxproj +504 -0
- package/templates/native/ios/Canary.xcodeproj/xcshareddata/xcschemes/Canary.xcscheme +88 -0
- package/templates/native/ios/Canary.xcworkspace/contents.xcworkspacedata +10 -0
- package/templates/native/ios/Podfile +34 -0
- package/templates/native/package.json.fragment.json +22 -0
- package/templates/native/package.json.fragment.typescript.json +8 -0
- package/templates/styling/js/angular/css-modules/src/App.ts +25 -0
- package/templates/styling/js/angular/stylesheet/src/App.ts +26 -0
- package/templates/styling/js/react/css-modules/App.jsx +15 -0
- package/templates/styling/js/react/css-modules/App.tsx +15 -0
- package/templates/styling/js/react/stylesheet/App.jsx +19 -0
- package/templates/styling/js/react/stylesheet/App.tsx +19 -0
- package/templates/styling/js/solid/css-modules/App.jsx +15 -0
- package/templates/styling/js/solid/css-modules/App.tsx +15 -0
- package/templates/styling/js/solid/stylesheet/App.jsx +19 -0
- package/templates/styling/js/solid/stylesheet/App.tsx +19 -0
- package/templates/styling/js/svelte/css-modules/App.svelte +12 -0
- package/templates/styling/js/svelte/css-modules/App.typescript.svelte +12 -0
- package/templates/styling/js/svelte/stylesheet/App.svelte +15 -0
- package/templates/styling/js/svelte/stylesheet/App.typescript.svelte +15 -0
- package/templates/styling/js/vue-sfc/css-modules/App.typescript.vue +15 -0
- package/templates/styling/js/vue-sfc/css-modules/App.vue +15 -0
- package/templates/styling/js/vue-sfc/stylesheet/App.typescript.vue +18 -0
- package/templates/styling/js/vue-sfc/stylesheet/App.vue +18 -0
- package/templates/styling/js/vue-tsx/css-modules/App.jsx +16 -0
- package/templates/styling/js/vue-tsx/css-modules/App.tsx +16 -0
- package/templates/styling/js/vue-tsx/stylesheet/App.jsx +20 -0
- package/templates/styling/js/vue-tsx/stylesheet/App.tsx +20 -0
- package/templates/styling/navigation/angular/css-modules/src/DetailsScreen.ts +17 -0
- package/templates/styling/navigation/angular/css-modules/src/MenuScreen.ts +22 -0
- package/templates/styling/navigation/angular/stylesheet/src/DetailsScreen.ts +18 -0
- package/templates/styling/navigation/angular/stylesheet/src/MenuScreen.ts +23 -0
- package/templates/styling/navigation/react/css-modules/App.jsx +32 -0
- package/templates/styling/navigation/react/css-modules/App.tsx +32 -0
- package/templates/styling/navigation/react/stylesheet/App.jsx +36 -0
- package/templates/styling/navigation/react/stylesheet/App.tsx +36 -0
- package/templates/styling/navigation/solid/css-modules/App.jsx +32 -0
- package/templates/styling/navigation/solid/css-modules/App.tsx +32 -0
- package/templates/styling/navigation/solid/stylesheet/App.jsx +36 -0
- package/templates/styling/navigation/solid/stylesheet/App.tsx +36 -0
- package/templates/styling/navigation/svelte/css-modules/DetailsScreen.svelte +7 -0
- package/templates/styling/navigation/svelte/css-modules/DetailsScreen.typescript.svelte +7 -0
- package/templates/styling/navigation/svelte/css-modules/MenuScreen.svelte +13 -0
- package/templates/styling/navigation/svelte/css-modules/MenuScreen.typescript.svelte +13 -0
- package/templates/styling/navigation/svelte/stylesheet/DetailsScreen.svelte +11 -0
- package/templates/styling/navigation/svelte/stylesheet/DetailsScreen.typescript.svelte +11 -0
- package/templates/styling/navigation/svelte/stylesheet/MenuScreen.svelte +16 -0
- package/templates/styling/navigation/svelte/stylesheet/MenuScreen.typescript.svelte +16 -0
- package/templates/styling/navigation/vue-sfc/css-modules/DetailsScreen.typescript.vue +9 -0
- package/templates/styling/navigation/vue-sfc/css-modules/DetailsScreen.vue +9 -0
- package/templates/styling/navigation/vue-sfc/css-modules/MenuScreen.typescript.vue +15 -0
- package/templates/styling/navigation/vue-sfc/css-modules/MenuScreen.vue +15 -0
- package/templates/styling/navigation/vue-sfc/stylesheet/DetailsScreen.typescript.vue +13 -0
- package/templates/styling/navigation/vue-sfc/stylesheet/DetailsScreen.vue +13 -0
- package/templates/styling/navigation/vue-sfc/stylesheet/MenuScreen.typescript.vue +18 -0
- package/templates/styling/navigation/vue-sfc/stylesheet/MenuScreen.vue +18 -0
- package/templates/styling/navigation/vue-tsx/css-modules/App.jsx +34 -0
- package/templates/styling/navigation/vue-tsx/css-modules/App.tsx +34 -0
- package/templates/styling/navigation/vue-tsx/stylesheet/App.jsx +38 -0
- package/templates/styling/navigation/vue-tsx/stylesheet/App.tsx +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 A. Prokopenko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
# @symbiote-native/cli
|
|
2
|
+
|
|
3
|
+
**Status: `new` scaffolds a real app; `add` extends an existing one with all of `new`'s optional
|
|
4
|
+
layers** (5 hand-named + one per `EXPO_PACKAGE_LAYERS` entry, 26 total as of 2026-09-18). `new`
|
|
5
|
+
copies `templates/native` + `templates/js/<framework>` + any selected optional
|
|
6
|
+
layers onto a fresh directory and merges `package.json` — closing the gap the root README's
|
|
7
|
+
["Try It In Your Own App"](../../README.md#try-it-in-your-own-app) section currently documents as
|
|
8
|
+
a manual process and the `DX` row of the [Milestones table](../../README.md#milestones).
|
|
9
|
+
|
|
10
|
+
`add` is a DIFFERENT command from what an earlier draft of this package planned (see "Design
|
|
11
|
+
decisions" below, 2026-09-17): it does not bootstrap symbiote into a plain RN project. It only
|
|
12
|
+
extends an app that already has a `@symbiote-native/<adapter>` dependency with more of `new`'s
|
|
13
|
+
optional layers (`--navigation`, `--expo-modules`, `--testing`, `--splash-screen`, `--slider`, or
|
|
14
|
+
one `--<id>` flag per Expo-backed package — `--battery`, `--sensors`, … — see `src/expo-package-
|
|
15
|
+
layers.ts`), never touching App/user source — native files get idempotent text-splices, not
|
|
16
|
+
overlays (see below).
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx @symbiote-native/cli new my-app --framework react
|
|
22
|
+
npx @symbiote-native/cli new my-app --framework vue --vue-flavor sfc --navigation --expo-modules --pm pnpm
|
|
23
|
+
npx @symbiote-native/cli new my-app --framework solid
|
|
24
|
+
npx @symbiote-native/cli new my-app --framework svelte
|
|
25
|
+
|
|
26
|
+
# inside an existing @symbiote-native/* app:
|
|
27
|
+
npx @symbiote-native/cli add --navigation --testing --splash-screen
|
|
28
|
+
npx @symbiote-native/cli add # interactive: offers only layers not already present
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`npx @symbiote-native/cli <args>` works with no install step: npx fetches the package and, since
|
|
32
|
+
it ships exactly one `bin` entry, runs that bin with `<args>` — the same resolution
|
|
33
|
+
`npx @angular/cli new` relies on. No `-p`/`--package` flag needed. There is no separate short
|
|
34
|
+
command to remember: `@symbiote-native/cli` is the one name for the package and every
|
|
35
|
+
invocation, whether or not the package happens to be installed locally.
|
|
36
|
+
|
|
37
|
+
Any flag left out is asked for interactively via `@clack/prompts`. `--pm` defaults to
|
|
38
|
+
whichever package manager launched the process (npm/pnpm/yarn, however it was invoked),
|
|
39
|
+
detected from `npm_config_user_agent` — see `src/detect-package-manager.ts`. `--framework` is
|
|
40
|
+
one of `react | vue | angular | solid | svelte`; `--vue-flavor tsx|sfc` only applies to Vue
|
|
41
|
+
(defaults to `sfc`).
|
|
42
|
+
|
|
43
|
+
`--javascript` opts out of TypeScript (default on): `render-template.ts` drops every
|
|
44
|
+
`tsconfig*.json`/`*.d.ts` file and the framework's `package.json.fragment.typescript.json`
|
|
45
|
+
sibling fragment (`typescript`, `@react-native/typescript-config`, `@types/react`, `vue-tsc`).
|
|
46
|
+
Angular is the one exception — its AOT pipeline (`ngtsc`) compiles templates as a TypeScript-
|
|
47
|
+
compiler extension, so `--javascript` is ignored for it (`resolveTypescript` forces `true`):
|
|
48
|
+
|
|
49
|
+
| framework | JS | TS |
|
|
50
|
+
| ---------------- | --- | --- |
|
|
51
|
+
| react | ✅ | ✅ |
|
|
52
|
+
| vue (sfc \| tsx) | ✅ | ✅ |
|
|
53
|
+
| solid | ✅ | ✅ |
|
|
54
|
+
| svelte | ✅ | ✅ |
|
|
55
|
+
| angular | ❌ | ✅ |
|
|
56
|
+
|
|
57
|
+
`add` detects the framework from a `@symbiote-native/<adapter>` dependency in the current
|
|
58
|
+
directory's `package.json` (a DIFFERENT check from `new`'s plain `@angular/core`/`vue`/`svelte`/
|
|
59
|
+
`solid-js`/`react` match — see `src/detect-framework.ts`'s `detectSymbioteFrameworkFromDependencies`).
|
|
60
|
+
No dependency found → refuses immediately with no interactive fallback, since there is no existing
|
|
61
|
+
symbiote app to extend in any terminal. No layer flag given, interactively → offers a multiselect
|
|
62
|
+
of only the layers not already present (`src/detect-added-layers.ts`). `--force` skips the confirm
|
|
63
|
+
before overwriting an already-generated `--testing` layer's files; without it, a non-interactive
|
|
64
|
+
run leaves them untouched rather than clobbering or hanging.
|
|
65
|
+
|
|
66
|
+
`--navigation` and `--expo-modules` are additive layers, not competing base profiles: every
|
|
67
|
+
SymbioteNative app is bare React Native (never managed Expo/EAS). `--expo-modules` layers in
|
|
68
|
+
`@symbiote-native/expo-modules-link` autolinking alone (`expo` + `expo-modules-link` — no specific
|
|
69
|
+
Expo-backed package, since 2026-09-18); `--navigation` adds
|
|
70
|
+
`@symbiote-native/navigation` alone. Every individual Expo-backed package `examples/expo-react`
|
|
71
|
+
carries (`application`, `battery`, `sensors`, …) is its own flag now — `--battery`, `--sensors`,
|
|
72
|
+
etc. — and picking any one of them implies `--expo-modules`'s wiring without asking for it twice.
|
|
73
|
+
See `templates/layers/README.md`.
|
|
74
|
+
|
|
75
|
+
## Package shape
|
|
76
|
+
|
|
77
|
+
Mirrors [`create-vue`](https://www.npmjs.com/package/create-vue)'s own toolchain choice: zero
|
|
78
|
+
runtime dependencies, bundled to a single dependency-free `bundle.js` at publish time (see
|
|
79
|
+
`build.config.ts`). Published **scoped** as `@symbiote-native/cli` (not `create-symbiote`).
|
|
80
|
+
`npm create symbiote`'s unscoped-`create-*` shorthand doesn't apply to a scoped package, so the
|
|
81
|
+
invocation is always `npx @symbiote-native/cli new ...` (npx resolves the package's one `bin`
|
|
82
|
+
entry automatically, same as `npx @angular/cli new` — see `build.config.ts`'s comment on why the
|
|
83
|
+
`bin` key itself isn't `@symbiote-native/cli` verbatim). Deliberately **not** documented as a
|
|
84
|
+
separate short command: one name (the package's) covers both identity and invocation, nothing
|
|
85
|
+
else to remember. Argv parsing is hand-rolled (`src/cli.ts`) rather than a `commander`/`yargs`
|
|
86
|
+
dependency, for the same fast-`npx`-cold-start reason create-vue avoids one. It still supports the
|
|
87
|
+
conventions those libraries give you for free — `--framework=react` alongside `--framework react`
|
|
88
|
+
(git/npm's own `--flag=value` form), "did you mean" suggestions for a typo'd command/flag, and
|
|
89
|
+
`--flag=value` on a boolean flag (`--force=false`) rejected loudly rather than silently ignored.
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
src/
|
|
93
|
+
index.ts # entry point — argv → subcommand routing, error reporting
|
|
94
|
+
cli.ts # hand-rolled argv parser (no dependency)
|
|
95
|
+
prompts.ts # @clack/prompts wrappers for every option this CLI resolves
|
|
96
|
+
detect-package-manager.ts # npm_config_user_agent → npm | pnpm | yarn
|
|
97
|
+
detect-framework.ts # cwd package.json deps → react | vue | angular | solid | svelte
|
|
98
|
+
template-dir.ts # (framework, vueFlavor) → templates/js/<dir> name
|
|
99
|
+
get-command.ts # (pm, 'install'|'dev') → printable shell command
|
|
100
|
+
generate.ts # scaffoldApp() — the actual copy/merge orchestration
|
|
101
|
+
add-layers.ts # addLayersToApp() — extends an EXISTING app with optional layers
|
|
102
|
+
detect-added-layers.ts # cwd package.json deps -> which optional layers are already present
|
|
103
|
+
errors.ts # CliUsageError, NotSymbioteAppError
|
|
104
|
+
utils/
|
|
105
|
+
render-template.ts # ported from create-vue: recursive copy, package.json merge, .gitignore append
|
|
106
|
+
deep-merge.ts # ported from create-vue
|
|
107
|
+
sort-dependencies.ts # ported from create-vue
|
|
108
|
+
json.ts # IJsonValue/IJsonObject + isJsonObject guard
|
|
109
|
+
commands/
|
|
110
|
+
new.ts # resolves options, calls scaffoldApp(), prints install/dev commands
|
|
111
|
+
add.ts # eligibility guard + resolveAddLayers, calls addLayersToApp()
|
|
112
|
+
templates/ # see templates/README.md
|
|
113
|
+
build.config.ts # rolldown config for the bundle.js publish artifact
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## What's real vs. stubbed
|
|
117
|
+
|
|
118
|
+
Real: argv parsing, all interactive prompts, package-manager/framework autodetection, the full
|
|
119
|
+
`templates/` content (`native/`, `js/{react,vue-tsx,vue-sfc,angular,solid,svelte}`,
|
|
120
|
+
`layers/{navigation,expo-modules,testing,splash-screen,slider,<one per EXPO_PACKAGE_LAYERS entry>}`),
|
|
121
|
+
`new`'s copy/merge mechanism end-to-end, and `add`'s full extend-an-existing-app path — all 26
|
|
122
|
+
layers (`--navigation`/`--expo-modules`/`--testing`/`--splash-screen`/`--slider` + one `--<id>`
|
|
123
|
+
flag per Expo-backed package, `src/add-layers.ts`), including `--splash-screen`'s 4 idempotent
|
|
124
|
+
native-file text-splices (`MainActivity.kt`/`AppDelegate.swift`/`styles.xml`/`AndroidManifest.xml`)
|
|
125
|
+
— verified against real scaffolded-app fixtures.
|
|
126
|
+
|
|
127
|
+
Not wired in yet either: the root `pnpm run build`/`prepublish-build` pipeline doesn't invoke
|
|
128
|
+
this package's `rolldown` build (every other publishable package goes through `tsc --build` +
|
|
129
|
+
`fix-esm-extensions`, which this package deliberately does not — see `build.config.ts`).
|
|
130
|
+
|
|
131
|
+
- **`--styling css|css-modules|scss|less|stylus|stylesheet` (2026-09-17).** The App stub's own
|
|
132
|
+
`style={{...}}` was flagged as a real gap: it never demonstrated the project's actual styling
|
|
133
|
+
story (CSS classes work in RN — see the root README's "Styling" section) and tripped
|
|
134
|
+
`react-native/no-inline-styles` on every fresh react/vue-tsx/solid scaffold. Fixed by making
|
|
135
|
+
`css` (plain class + external stylesheet) the default across all six frameworks, with five more
|
|
136
|
+
selectable code shapes:
|
|
137
|
+
- vue-sfc/svelte's `css` default uses an inline `<style scoped>`/`<style>` block — the idiomatic
|
|
138
|
+
web convention for those two — while react/vue-tsx/solid/angular (no template block to put one
|
|
139
|
+
in) use an external `App.css` + `className`/`class="container"`.
|
|
140
|
+
- `scss`/`less`/`stylus` produce byte-identical output to `css` for the trivial flat rule this
|
|
141
|
+
stub carries, so they are NOT separate template content — `applyStyling`
|
|
142
|
+
(`src/utils/apply-styling.ts`) just renames `App.css` → `App.<ext>` and rewrites the one import
|
|
143
|
+
string. **vue-sfc/svelte take a different path (2026-09-17, no file swap at all):** both
|
|
144
|
+
compilers already dispatch a `<style lang="scss|less|stylus">` block through the same
|
|
145
|
+
preprocessor pipeline a standalone file gets
|
|
146
|
+
(`adapters/vue/metro-vue-transformer.cjs`'s `SFC_STYLE_LANG_TO_PREPROCESSOR`,
|
|
147
|
+
`adapters/svelte/src/preprocessor/scoped-styles.ts`'s `STYLE_LANG_TO_PREPROCESSOR`), confirmed
|
|
148
|
+
live by `core/css-parser/src/svelte-less-style-block.test.ts` — so a preprocessor choice for
|
|
149
|
+
these two is just inserting `lang="<option>"` into the existing inline `<style>` tag in place.
|
|
150
|
+
An earlier version of this feature instead swapped in a whole second `external-css` override
|
|
151
|
+
(external file + class) before renaming, because it assumed inline preprocessor syntax wasn't
|
|
152
|
+
supported — checking first (an `Explore` sub-agent read both compiler sources) deleted 4
|
|
153
|
+
template folders and the swap-then-rename two-step, and is MORE idiomatic besides (an SFC/
|
|
154
|
+
Svelte author reaches for `lang="scss"` on the block they already have, not a second file).
|
|
155
|
+
- `css-modules` and `stylesheet` (StyleSheet.create) are genuinely different code and get their
|
|
156
|
+
own `styling/js/<framework>/<option>/` (+ the navigation layer's own
|
|
157
|
+
`styling/navigation/<framework>/<option>/`) override, applied AFTER the navigation
|
|
158
|
+
layer so it overwrites the final nav-shaped files, not the pre-nav base ones.
|
|
159
|
+
- Angular's `StyleSheet.create({...})` call needs no `as const` on its argument (unlike the bare
|
|
160
|
+
`readonly rootStyle = {...}` shape this project used before) — a value passed through a typed
|
|
161
|
+
function PARAMETER gets that parameter's type as its contextual type, so `alignItems: 'center'`
|
|
162
|
+
checks against the union directly instead of widening to `string`. Verified with a real `ngc`
|
|
163
|
+
build, not assumed.
|
|
164
|
+
- A `renderTemplate` layer picks its destination filename from the SOURCE file's own basename,
|
|
165
|
+
not from the `dest` path passed to it (see the `templates/layers/README.md` note on the
|
|
166
|
+
testing layer for the same gotcha) — every per-framework override folder here is named exactly
|
|
167
|
+
`<option>/`, never a differently-named file merged into a differently-named dest.
|
|
168
|
+
- **These overrides originally lived at `templates/js/<framework>/styling/` and
|
|
169
|
+
`templates/layers/navigation/app/<framework>/styling/` — a real bug (2026-09-17), found
|
|
170
|
+
while auditing the feature for unnecessary code, not by any test.** `renderTemplate` recursively
|
|
171
|
+
copies a source directory verbatim; nesting the override folders *inside* the tree the base
|
|
172
|
+
`js/<framework>` and navigation-layer renders already copy meant every single scaffolded app —
|
|
173
|
+
for every styling choice, `css` included — shipped a leaked `styling/` folder at its root
|
|
174
|
+
containing all six frameworks' unused override variants. None of the matrix/install/lint/`ngc`
|
|
175
|
+
verification below caught it, because none of those checks assert on the generated file *tree*,
|
|
176
|
+
only on whether known files build and lint clean — an orphaned, never-imported file passes all
|
|
177
|
+
of them silently. Moved to a sibling `templates/styling/{js,navigation}/<framework>/<option>/`
|
|
178
|
+
tree that the base copies never touch; re-verified across the full 72-combination matrix with
|
|
179
|
+
an explicit "no `styling/` dir at the scaffolded root" assertion.
|
|
180
|
+
- **`App.module.css` was 12 byte-identical copies of the same 5-line rule** — one per
|
|
181
|
+
framework × {base, navigation}. Deleted the template files; `applyStyling` now writes the one
|
|
182
|
+
shared constant directly next to wherever the App component landed, found by walking the
|
|
183
|
+
scaffolded tree for an `App.{tsx,jsx,ts,vue,svelte}` file. CSS content carries no per-framework
|
|
184
|
+
idiom the way component code does, so unlike the JS/TS-pair duplication noted elsewhere in this
|
|
185
|
+
file, this one was pure copy-paste with nothing to keep independent. (The `external-css`
|
|
186
|
+
override this bullet used to also cite for vue-sfc/svelte no longer exists at all — see the
|
|
187
|
+
`lang` attribute note above.)
|
|
188
|
+
- Verified: the full 6-framework × 6-styling × {base, navigation} = 72-combination matrix
|
|
189
|
+
scaffolds without error and leaves no leaked `styling/` directory in any combination; a
|
|
190
|
+
representative sample (react × css/css-modules/stylesheet/scss, vue-sfc × scss/css-modules
|
|
191
|
+
with navigation, svelte × stylus with navigation, solid × css-modules with navigation, angular
|
|
192
|
+
× stylesheet/css-modules with navigation) passes a REAL `npm install` + `npm run lint`, and the
|
|
193
|
+
two angular and one vue-sfc-scss-with-navigation combinations additionally pass a real
|
|
194
|
+
type-check (`ngc`/`vue-tsc`).
|
|
195
|
+
|
|
196
|
+
## Design decisions (2026-09-15)
|
|
197
|
+
|
|
198
|
+
- **templates/ vs examples/\*: independent fork, not a sync target.** `examples/*` is the dev
|
|
199
|
+
canary; `templates/` starts as a copy but diverges and gets patched directly as needed. No
|
|
200
|
+
CI drift check — deliberate, not an oversight. (One apparent drift turned out to be correct
|
|
201
|
+
as-is: `templates/js/react/babel.config.js` lacks the `allowDeclareFields` override that
|
|
202
|
+
`examples/react/babel.config.js` has, but that override exists solely for
|
|
203
|
+
`ContextProviderDemo.tsx`'s `declare context` field — a demo file the template deliberately
|
|
204
|
+
doesn't ship. No demo, no need for the override. Worth the reminder that a config diff against
|
|
205
|
+
`examples/*` isn't automatically a bug — check what the diff is actually *for* first.)
|
|
206
|
+
- **Layering, not one verbatim copy per framework.** A "layer" is a named patch that can touch
|
|
207
|
+
`native/{ios,android}`, `js/<framework>`, and `package.json.fragment.json` together — not
|
|
208
|
+
just the JS side. `renderTemplate` (ported from create-vue) copies `base` first, then each
|
|
209
|
+
selected layer on top; `package.json`/`.gitignore` merge instead of overwrite.
|
|
210
|
+
- **v1 layers: `base` + `expo-modules` + `navigation` + `testing` + `splash-screen` + `slider`.**
|
|
211
|
+
All JS/package.json-only except `splash-screen` (native changes, see below).
|
|
212
|
+
- **`--slider` (2026-09-17, real gap): the one package outside the `expo-modules` bundle with zero
|
|
213
|
+
scaffolder wiring, despite being a real dependency of every example** (`examples/react`,
|
|
214
|
+
`vue-sfc`, `vue-tsx`, `angular`, `svelte`, `solid`). Unlike `--splash-screen` it needs no
|
|
215
|
+
`native/` overlay at all: `@symbiote-native/slider` autolinks itself via its own
|
|
216
|
+
`react-native.config.cjs` + `symbiote-slider.podspec` (see `packages/slider/README.md`), so the
|
|
217
|
+
"necessary native side" the scaffolder owns is just the dependency declaration —
|
|
218
|
+
`layers/slider/package.json.fragment.json`. `npm install` + the developer's own `pod install`
|
|
219
|
+
do the rest.
|
|
220
|
+
- **`@symbiote-native/android` (2026-09-17, real bug, unconditional).** Every framework's real
|
|
221
|
+
example pins this Android host-shim (re-provides RN host signals — keyboard events, … — that
|
|
222
|
+
SymbioteNative's Fabric surface bypasses; `packages/android/package.json`'s own description) as
|
|
223
|
+
a plain dependency, no feature flag involved. None of the six `js/<framework>/
|
|
224
|
+
package.json.fragment.json` base fragments declared it — every scaffolded app was missing a
|
|
225
|
+
base runtime dependency its Android build needs. Fixed directly in all six base fragments, not
|
|
226
|
+
behind an option: unlike `--slider`/`--splash-screen` this isn't optional in any example.
|
|
227
|
+
- **`--expo-modules` was also missing its Info.plist half (2026-09-17, real bug).** The layer
|
|
228
|
+
wired the package.json fragment + postinstall linker (see above) but never touched
|
|
229
|
+
`ios/Canary/Info.plist` — three of its bundled modules need an iOS usage-description string or
|
|
230
|
+
the OS rejects the call outright (`NSFaceIDUsageDescription` for local-auth,
|
|
231
|
+
`NSMotionUsageDescription` for sensors, `NSUserTrackingUsageDescription` for
|
|
232
|
+
tracking-transparency), App Store review included. Fixed by overlaying
|
|
233
|
+
`layers/expo-modules/ios/Canary/Info.plist` — copied from `examples/expo-react`'s real one, the
|
|
234
|
+
only checked-in expo-* example with a native iOS project.
|
|
235
|
+
- **`--expo-modules`'s Android half had the same gap (2026-09-17, real bug).** 4 missing
|
|
236
|
+
`<uses-permission>` (local-auth's biometric prompt, brightness's `setSystemBrightnessAsync`,
|
|
237
|
+
cellular's carrier lookups all fail on Android without them) plus 2 `<application>` backup-
|
|
238
|
+
control attributes expo-secure-store's own Android config-plugin writes unconditionally
|
|
239
|
+
(verified via `/vendor`-ing `expo-secure-store` and reading `plugin/src/withSecureStore.ts` —
|
|
240
|
+
also confirmed the `@xml/secure_store_*` resources it points at ship inside expo-secure-store's
|
|
241
|
+
OWN Android library module and resolve through Gradle's cross-module resource merge, so the
|
|
242
|
+
reference example's manifest reference isn't broken despite no local `res/xml/` copy). Fixed as
|
|
243
|
+
a text-splice POST-process (`utils/apply-expo-modules-manifest.ts`), not a third
|
|
244
|
+
`AndroidManifest.xml` overlay: `--expo-modules` renders before `--splash-screen`, and
|
|
245
|
+
`renderTemplate` overwrites rather than merges — a competing overlay would silently lose
|
|
246
|
+
whichever layer wrote last (BootTheme vs. the permissions). The splice runs after both layers,
|
|
247
|
+
so it works regardless of which manifest variant ended up on disk.
|
|
248
|
+
- **`@symbiote-native/engine` was missing from react's fragment specifically (2026-09-17, real
|
|
249
|
+
bug).** It's a `peerDependency` of every adapter identically (npm never auto-installs a peer —
|
|
250
|
+
the app must declare it directly, same convention as `react-native` itself per CLAUDE.md's
|
|
251
|
+
`<react_native_is_an_explicit_top_level_peer>`); `vue-sfc`/`vue-tsx`/`angular`/`solid`/`svelte`
|
|
252
|
+
already had it, only `js/react/package.json.fragment.json` didn't. Found by diffing a full
|
|
253
|
+
scaffold's dependency set against `examples/react`'s real `package.json` — the same audit that
|
|
254
|
+
found `--slider` and `@symbiote-native/android`.
|
|
255
|
+
- **`--splash-screen` (2026-09-17) is the first layer with native changes, and a real bug it
|
|
256
|
+
fixed: every scaffolded app's `native/` template already wired `react-native-bootsplash`
|
|
257
|
+
unconditionally (`MainActivity.kt`/`AppDelegate.swift` call its init API, `styles.xml` extends
|
|
258
|
+
its `Theme.BootSplash`) but never added `@symbiote-native/splash-screen` as a dependency — so
|
|
259
|
+
every fresh scaffold failed to compile natively on both platforms. Fixed by making it optional
|
|
260
|
+
instead of mandatory: the base template ships WITHOUT the plugin wired (compiles clean with
|
|
261
|
+
nothing installed), and `--splash-screen` overlays the 4 files that actually need the
|
|
262
|
+
dependency to compile. Everything else that references bootsplash-looking assets
|
|
263
|
+
(`colors.xml`, the drawables, `BootSplash.storyboard`, the `.xcassets`, `Info.plist`'s
|
|
264
|
+
`UILaunchStoryboardName`, the `.xcodeproj`) stays in the base template unconditionally, because
|
|
265
|
+
none of it actually depends on the plugin being installed — see `templates/layers/README.md`
|
|
266
|
+
for the exact file-by-file split and why.
|
|
267
|
+
- **`--splash-screen` never wired the JS side, and the native side alone means the app never
|
|
268
|
+
starts (2026-09-17, real bug, found by cross-checking every real example's App entry).** All 6
|
|
269
|
+
real examples call `hide()` once, at mount, from the framework's own lifecycle hook
|
|
270
|
+
(`examples/react`'s `useEffect`, `.../vue-sfc`'s `onMounted`, `.../angular`'s `ngOnInit`,
|
|
271
|
+
`.../solid`'s `onMount`, `.../svelte`'s bare top-level call — svelte needs no wrapper, its
|
|
272
|
+
script body already runs once at component init) — react-native-bootsplash's native splash
|
|
273
|
+
screen never hides itself. Without this, a scaffolded `--splash-screen` app compiles and installs
|
|
274
|
+
fine but the user never sees anything past the launch screen: the app is frozen there forever.
|
|
275
|
+
Fixed as a text-splice post-process (`utils/apply-splash-screen-hide.ts`), same shape as the
|
|
276
|
+
`AndroidManifest.xml` splice above and for the same reason: `--navigation`'s own `app/<framework>`
|
|
277
|
+
overlay and `--styling`'s `css-modules`/`stylesheet` overlay BOTH already overwrite the whole App
|
|
278
|
+
file, so this has to run last, against whatever's actually on disk, not as a `js/` layer overlay.
|
|
279
|
+
Verified against all 6 frameworks × with/without `--navigation` × `css-modules`/`stylesheet`
|
|
280
|
+
styling — the splice never depends on the CSS import line (it differs per styling option), only
|
|
281
|
+
on anchors proven stable across every variant (`export default function App() {`, `setup() {`,
|
|
282
|
+
`</script>`), and a merge-or-insert helper for each framework's own lifecycle import so it never
|
|
283
|
+
emits a duplicate `import { useState } from 'react'`-shaped line.
|
|
284
|
+
- **Investigated (not fixed) — `RNScreensFragmentFactory` wiring, found via `/vendor`-ing
|
|
285
|
+
`react-native-bootsplash@7.3.2` itself.** Its own README documents THREE Android `MainActivity`
|
|
286
|
+
variants gated on the installed `react-native-screens` version; ours matches the "without
|
|
287
|
+
react-native-screens" one, but `react-native-screens` is pinned to `4.26.0` (`pnpm-workspace.
|
|
288
|
+
yaml`) and IS present the moment `--navigation` is selected (`@symbiote-native/navigation` is
|
|
289
|
+
built on its `RNSScreen`/`RNSScreenStack` primitives) — past the documented `>= v4.16.0`
|
|
290
|
+
threshold, where upstream says `MainActivity.onCreate` must also set
|
|
291
|
+
`supportFragmentManager.fragmentFactory = RNScreensFragmentFactory()` before calling
|
|
292
|
+
`RNBootSplash.init(...)`, or Android can crash reconstructing a screens `Fragment` after
|
|
293
|
+
process death. Web-search (2026-09-17) confirmed the version threshold is current, not stale
|
|
294
|
+
advice. **Not wired into the scaffolder**, because it isn't wired into any of the 11 real
|
|
295
|
+
examples that combine `--navigation` + bootsplash either (`grep -rl RNScreensFragmentFactory
|
|
296
|
+
examples --include='*.kt'` — zero hits) — adding it here would make a fresh scaffold diverge
|
|
297
|
+
from every real reference app, the opposite of this whole audit's method. If this is a real gap,
|
|
298
|
+
it belongs in the examples first; the scaffolder mirrors them, it doesn't correct them.
|
|
299
|
+
- **`native/` was missing its own `package.json.fragment.json` entirely (2026-09-17, real bug).**
|
|
300
|
+
Every scaffolded app inherited zero baseline RN devDependencies — no
|
|
301
|
+
`@react-native-community/cli` (so `npm run ios`/`android` couldn't even resolve the CLI),
|
|
302
|
+
no `@symbiote-native/css-parser`, no `sass`/`less`/`stylus`, no `eslint`/`prettier`, no
|
|
303
|
+
`engines`. Fixed with `native/package.json.fragment.json` (JS+TS universal) +
|
|
304
|
+
`native/package.json.fragment.typescript.json` (the `typescript`/`@types/*`/
|
|
305
|
+
`@react-native/typescript-config` floor, via the same `.typescript.` infix every other
|
|
306
|
+
TS/JS split in this project uses). Verified against `examples/*`'s real `package.json`s —
|
|
307
|
+
a scaffolded app's merged devDependencies now match byte-for-byte (module names/versions).
|
|
308
|
+
- **`--testing` adds Detox e2e, not unit tests.** `vitest`/`@symbiote-native/test-utils` unit-test
|
|
309
|
+
setup is only genuinely real in `examples/vue-tsx` (one real test, `vue-fragment.test.ts`) —
|
|
310
|
+
`examples/react` has the `vitest` devDependency and `"test"` script but no actual unit test file
|
|
311
|
+
yet, and `examples/vue-sfc`, `examples/svelte`, `examples/angular` have neither. Inconsistent
|
|
312
|
+
and, in react's case, incomplete upstream, so none of it is cloned into the scaffolder yet
|
|
313
|
+
(would need per-framework unit-test authoring, not just config copying). Both examples were also
|
|
314
|
+
missing a local `vitest.config.ts`: with no `exclude`, a standalone `npm test` picks up
|
|
315
|
+
`e2e/*.test.ts` under vitest's own default include glob and crashes on Detox's `device`/
|
|
316
|
+
`element`/`by` (only wired up by Detox's own on-device runner) — fixed directly in both
|
|
317
|
+
examples, independent of the scaffolder question.
|
|
318
|
+
`detox` + a generic smoke test IS consistent across every non-Solid example and is dependency +
|
|
319
|
+
config only, so it shipped first. Tracked as a follow-up, not silently dropped.
|
|
320
|
+
- **SUPERSEDED — the entry above (`--splash-screen` "is deferred, not in v1") described a plan
|
|
321
|
+
that was abandoned before it shipped, and shipping made the whole concern moot.** The original
|
|
322
|
+
worry was that `.pbxproj`/`Info.plist`/`AndroidManifest.xml`/`colors.xml`/`styles.xml` would all
|
|
323
|
+
need a real with/without-BootSplash variant generated via `@expo/config-plugins` + `xcode`
|
|
324
|
+
AST surgery. It turned out none of that needs two variants: `.pbxproj`, `Info.plist`,
|
|
325
|
+
`BootSplash.storyboard`, `colors.xml` and the drawables reference only OUR OWN asset catalog,
|
|
326
|
+
never the plugin, so they stay in the base template unconditionally and are harmless when the
|
|
327
|
+
option is off. Only 4 files actually reference the plugin's API/resources
|
|
328
|
+
(`MainActivity.kt`, `AppDelegate.swift`, `styles.xml`'s `BootTheme`, `AndroidManifest.xml`'s
|
|
329
|
+
activity theme attribute) — those are exactly what `--splash-screen` overlays. No `.pbxproj`
|
|
330
|
+
mutation, no `@expo/config-plugins` dependency, ever needed. Verified end-to-end (2026-09-17):
|
|
331
|
+
every native file the layer produces is byte-identical to `examples/react`'s real one, and
|
|
332
|
+
cross-framework coverage confirms the overlay is genuinely framework-agnostic.
|
|
333
|
+
- **`eslint.config.js` was missing from every template entirely (2026-09-17) — this IS the
|
|
334
|
+
"File ignored because of a matching ignore pattern" bug flagged earlier and left unresolved.**
|
|
335
|
+
Every scaffold shipped `"lint": "eslint ."` + `eslint` as a devDependency but no config file at
|
|
336
|
+
all, so ESLint fell back to its flat-config default (only recognized JS-like extensions) and
|
|
337
|
+
reported every source file ignored. Fixed with `native/eslint.config.js` (the trivial
|
|
338
|
+
`@react-native/eslint-config/flat` default react/vue-tsx/angular/solid all use verbatim) plus
|
|
339
|
+
framework-specific overrides in `js/vue-sfc` and `js/svelte` (they need `eslint-plugin-vue` /
|
|
340
|
+
`eslint-plugin-svelte` + `@typescript-eslint/parser` wired in for `.vue`/`.svelte` files) — same
|
|
341
|
+
native-default-plus-per-framework-override shape as the earlier `.typescript.` infix split, just
|
|
342
|
+
at the layer level. Verified with a REAL `npm install` + `npm run lint`, both frameworks, zero
|
|
343
|
+
errors, zero "ignored" warnings.
|
|
344
|
+
- **Investigated unit-test (vitest) scaffolding and found nothing real to clone.**
|
|
345
|
+
`examples/react`/`examples/vue-tsx` carry `vitest` + `@symbiote-native/test-utils` as
|
|
346
|
+
dependencies and a `"test": "vitest run"` script, but zero `*.test.ts` files outside `e2e/` and
|
|
347
|
+
no `vitest.config.*` — the unit-test setup is vestigial in the reference examples themselves,
|
|
348
|
+
and `@symbiote-native/test-utils` isn't even a package that exists in this monorepo
|
|
349
|
+
(`packages/test-utils` doesn't exist). Nothing to scaffold from; not cloning dead config.
|
|
350
|
+
- **Confirmed (not adopted) — Angular CLI's `ng new` auto-runs `git init` AND `npm install` by
|
|
351
|
+
default** (`--skip-git`/`--skip-install` opt out), the opposite of create-vue's suggest-only
|
|
352
|
+
convention this project already follows. Deliberately NOT adopted — stays consistent with the
|
|
353
|
+
project's own "nothing happens without the user typing it" stance for git/install, which was
|
|
354
|
+
chosen before this comparison and this only confirms it was the right call.
|
|
355
|
+
- **Three more real gaps found by a systematic `comm` diff of every example's root files against
|
|
356
|
+
the merged template output (2026-09-17), same method that found the eslint bug above.**
|
|
357
|
+
`js/angular` was missing `.prettierrc.js` entirely (the same trivial default react/vue-tsx/
|
|
358
|
+
vue-sfc/solid already ship) AND its own `"lint": "eslint ."` script — `npm run lint` errored
|
|
359
|
+
"Missing script" on every angular scaffold. `js/svelte` was missing `svelte.config.js` (its own
|
|
360
|
+
header calls `fragments: 'tree'` "mandatory, not a preference" — read by svelte-check, the
|
|
361
|
+
editor's language server, and Metro) and the `prettier-plugin-svelte` devDependency its own
|
|
362
|
+
`.prettierrc.js` already referenced (`plugins: ['prettier-plugin-svelte']` with the package never
|
|
363
|
+
installed). All three fixed and verified with real `npm install` + `npm run lint`/`prettier
|
|
364
|
+
--check`. Files intentionally NOT cloned in this same sweep: `App.css`/`fabric-call-counter.ts`/
|
|
365
|
+
`navigation-lines.ts`/`navigation-linking.ts`/`routes.ts`/`tunnel-demo.ts`/`*.test.ts` (canary
|
|
366
|
+
benchmark/demo-specific, not starter concerns) and `.cdp-console-probe.mjs` (a manual Chrome
|
|
367
|
+
DevTools Protocol debugging script, not app config).
|
|
368
|
+
- **Deep recursive audit (2026-09-17, not just root files) against `examples/{vue-tsx,angular}`
|
|
369
|
+
found one more real cleanup and confirmed no further real gaps.** `js/{react,vue-sfc,vue-tsx}`
|
|
370
|
+
each carried a stale legacy `.eslintrc.js` (`extends: '@react-native'` — a package that isn't
|
|
371
|
+
even a declared dependency anymore) left over from before the project's flat-config migration;
|
|
372
|
+
deleted as dead/misleading now that `eslint.config.js` is real. Confirmed working: ESLint 8.57
|
|
373
|
+
picks flat config over a stray `.eslintrc.js` automatically, so this was never a functional bug,
|
|
374
|
+
just confusing cruft. Everything else the recursive diff surfaced (`assets/bootsplash/*`,
|
|
375
|
+
`components/*`, `screens/*` beyond Menu/Details, `*.test.ts`) is canary-demo content, already
|
|
376
|
+
out of scope by the same reasoning as the root-file audit above.
|
|
377
|
+
- **The App stub's inline `style={{ ... }}` (flagged above as trip-hazard for
|
|
378
|
+
`react-native/no-inline-styles`) is fixed, not just noted — see `--styling` below**, which
|
|
379
|
+
replaced every inline style object with the framework's real styling convention.
|
|
380
|
+
- **Git-init suggestion, borrowed from create-vue (2026-09-17).** create-vue never runs `git init`
|
|
381
|
+
itself — it only prints `git init && git add -A && git commit -m "initial commit"` in the outro,
|
|
382
|
+
and only when the target directory had no `.git` before scaffolding
|
|
383
|
+
(`dotGitDirectoryState.hasDotGitDirectory`, set by its `canSkipEmptying`). Ported the same two
|
|
384
|
+
pieces: `isEmptyDir` now treats a directory holding only `.git` as empty (so scaffolding into an
|
|
385
|
+
already-`git init`'d empty folder no longer triggers the "empty it?" prompt and can't `rm -rf`
|
|
386
|
+
the user's git history), and `runNew`'s outro prints the same suggested command when
|
|
387
|
+
`<root>/.git` doesn't exist after scaffolding — never runs it automatically, matching this
|
|
388
|
+
project's own "nothing happens without the user typing it" convention for git operations.
|
|
389
|
+
- **Solid and Svelte added as `js/` templates**, alongside the original four
|
|
390
|
+
(react/vue-tsx/vue-sfc/angular) — both are full milestone-complete adapters and had no
|
|
391
|
+
reason to be missing.
|
|
392
|
+
- **`package.json` merge ports create-vue's `deepMerge` + `sortDependencies` verbatim** (see
|
|
393
|
+
`src/utils/`) rather than a from-scratch merge — proven code, and layering (base + navigation
|
|
394
|
+
+ expo-modules stacking) needs the same array-dedupe/object-merge semantics.
|
|
395
|
+
- **Post-scaffold install is printed, not spawned** — matches create-vue's `outro` behavior.
|
|
396
|
+
No child_process install call; the CLI prints `cd`/install/dev commands and stops.
|
|
397
|
+
- **Priority: `new` before `add`.** `new` has no existing `package.json` to merge into;
|
|
398
|
+
`add`'s retrofit-into-existing-project path comes after the copy/merge mechanism is proven.
|
|
399
|
+
- **`add`'s purpose changed from "bootstrap symbiote into any RN app" to "extend an existing
|
|
400
|
+
@symbiote-native/* app" (2026-09-17).** The earlier plan (see the now-superseded `TODO(symbiote)`
|
|
401
|
+
this replaced in `src/commands/add.ts`'s git history) was to install `@symbiote-native/<framework>`
|
|
402
|
+
+ `react-native` into an arbitrary existing RN project. Dropped: a plain RN app has no reason to
|
|
403
|
+
expect SymbioteNative's renderer swap, and `new`'s own native templates are hand-authored — there
|
|
404
|
+
is no safe, generic way to retrofit them onto a real project's already-customized native files
|
|
405
|
+
without a real risk of breaking it. The new, narrower job: an app `new` already scaffolded (or an
|
|
406
|
+
equivalent hand-built one) picks up more of `new`'s OWN optional layers later, the same way
|
|
407
|
+
`vue add <plugin>` extends a `vue create` project rather than converting a random app to Vue.
|
|
408
|
+
- **Eligibility guard, not framework detection.** `add` requires a `@symbiote-native/<adapter>`
|
|
409
|
+
dependency (`detectSymbioteFrameworkFromDependencies`, `src/detect-framework.ts`) — a
|
|
410
|
+
different, narrower check than `new`'s plain `react`/`vue`/etc. match, which any RN app would
|
|
411
|
+
pass. Missing → `NotSymbioteAppError`, no interactive fallback (unlike every other resolver in
|
|
412
|
+
`prompts.ts`): there is no existing symbiote app to extend in ANY terminal, so nothing is
|
|
413
|
+
gained by asking.
|
|
414
|
+
- **Never touches user/App source.** `--navigation` in `new` overwrites the App entry with a
|
|
415
|
+
Stack demo; in `add` it only merges the `@symbiote-native/navigation` dependency and prints the
|
|
416
|
+
import snippet in the outro — wiring the `<Stack>` into a real, already-written App is the
|
|
417
|
+
developer's own call, `add` doesn't know what else lives in that file.
|
|
418
|
+
- **Native touches are idempotent text-splices, never whole-file overlays.** `--expo-modules` is
|
|
419
|
+
the one v1 layer with native files: `apply-expo-modules-manifest.ts` was made idempotent (a
|
|
420
|
+
second pass used to duplicate the permissions block — it matched its own previously-inserted
|
|
421
|
+
anchor line) and reused as-is; a new `apply-expo-modules-plist.ts` does the iOS half, since
|
|
422
|
+
`new`'s whole-file `Info.plist` overlay would silently discard whatever a real app's Info.plist
|
|
423
|
+
already had. Both check "is this key already there" before writing, so a repeat `add
|
|
424
|
+
--expo-modules` (or one running against an app that got the same permissions another way)
|
|
425
|
+
is a no-op, not a duplicate.
|
|
426
|
+
- **`--splash-screen` landed as a follow-up pass the same day, once `--expo-modules` proved the
|
|
427
|
+
idempotent-splice shape.** Same treatment, 4 native files instead of 2:
|
|
428
|
+
`apply-splash-screen-manifest.ts` swaps only `<activity android:name=".MainActivity">`'s theme
|
|
429
|
+
to `BootTheme` (never the `<application>` theme), `apply-splash-screen-styles.ts` inserts the
|
|
430
|
+
`BootTheme` style block, and `apply-splash-screen-main-activity.ts`/
|
|
431
|
+
`apply-splash-screen-app-delegate.ts` insert the plugin's init call into an EXISTING
|
|
432
|
+
`onCreate`/`customize()` override when the real app already has one, or add a whole new one
|
|
433
|
+
when it doesn't — Kotlin/Swift don't allow declaring the same override twice, so which shape
|
|
434
|
+
the real file is in has to be detected, not assumed. `findIosAppDir`/the Kotlin package walk
|
|
435
|
+
locate the real (never `Canary`-named) app dir and MainActivity package path, factored into
|
|
436
|
+
`find-ios-app-dir.ts` once `apply-expo-modules-plist.ts` needed the same iOS lookup. Same as
|
|
437
|
+
`--navigation`, the JS-side `hide()` call is never spliced into App source — `add`'s outro
|
|
438
|
+
prints the exact per-framework snippet instead
|
|
439
|
+
(`SPLASH_SCREEN_HIDE_SNIPPET`, `src/commands/add.ts`).
|
|
440
|
+
- **`--testing` asks before overwriting.** `detox.config.js`/`e2e/*` are new files, not user
|
|
441
|
+
App source, but a re-run of `add --testing` could clobber customizations made since the first
|
|
442
|
+
run — `resolveAddOverwrite` (`prompts.ts`) confirms interactively, defaults to SKIP (not
|
|
443
|
+
overwrite) when there's no terminal to ask in, and `--force` bypasses the ask either way.
|
|
444
|
+
- **No-flags UX mirrors `new`'s `resolveFeatures` multiselect**, but offers only layers
|
|
445
|
+
`detect-added-layers.ts` doesn't already find a dependency marker for — re-offering an
|
|
446
|
+
installed layer would either no-op confusingly or, for `--testing`, trigger the overwrite
|
|
447
|
+
confirm for no reason.
|
|
448
|
+
- **Removed the checked-in `templates/native/ios/Podfile.lock` (2026-09-18, real device bug).** A
|
|
449
|
+
lockfile is dependency-installer OUTPUT, never scaffolder input — shipping one anyway caused a
|
|
450
|
+
real `dyld: Library not loaded: @rpath/ReactNativeDependencies.framework` crash at app launch,
|
|
451
|
+
no red-box, no build error. Mechanism: `applyAppIdentity` text-renames `Canary` -> the real app
|
|
452
|
+
name INSIDE `Podfile` itself (extension-less files are in its rewrite set); RN's own
|
|
453
|
+
`react_native_pods.rb` gates BOTH `React-Core-prebuilt` and the separate `ReactNativeDependencies`
|
|
454
|
+
pod behind independent Maven-artifact-availability checks, and `pod install` trusts an existing
|
|
455
|
+
`Podfile.lock` only while its `PODFILE CHECKSUM` (a SHA1 of `Podfile`'s own text) still matches —
|
|
456
|
+
the rename breaks that match, forcing a fresh resolve. The shipped lock had frozen an
|
|
457
|
+
INCONSISTENT split from whatever environment originally produced it (Core resolved prebuilt,
|
|
458
|
+
Dependencies resolved from-source) — React's prebuilt binary hard-links
|
|
459
|
+
`@rpath/ReactNativeDependencies.framework` unconditionally, so the moment a real fresh install
|
|
460
|
+
reused half of that frozen split, the framework it needed was never fetched. Fix verified
|
|
461
|
+
on-device: with the lock removed, a genuinely fresh `pod install` resolves BOTH sides
|
|
462
|
+
consistently (this device: both from-source, logged as `[ReactNativeCore] Building from source:
|
|
463
|
+
true` / `[ReactNativeDependencies] Building from source: true`) — no `React-Core-prebuilt` in
|
|
464
|
+
the mix at all, so no split to be inconsistent. No Podfile env-var workaround needed; the lock
|
|
465
|
+
was the whole bug.
|
|
466
|
+
- **Every Expo-backed package split into its own selectable layer (2026-09-18, real gap).**
|
|
467
|
+
`--expo-modules` used to bundle all 21 `@symbiote-native/<expo-wrapper>` packages
|
|
468
|
+
unconditionally (`application`, `battery`, `brightness`, …) — picking it, or picking any ONE of
|
|
469
|
+
our packages from `packages/*`, always installed every other one too, with no way to scaffold
|
|
470
|
+
e.g. a battery-only app. Fixed by giving each package its OWN dependency-only layer (same shape
|
|
471
|
+
as `--slider`), registered ONCE in `src/expo-package-layers.ts` (`EXPO_PACKAGE_LAYERS`) rather
|
|
472
|
+
than 21 hand-written near-duplicates — that one table drives cli.ts's `--<id>` flag, prompts.ts's
|
|
473
|
+
multiselect option, and `detect-added-layers.ts`'s marker generically. `expo-modules` itself
|
|
474
|
+
shrank to just the core autolinking bits (`expo` + `expo-modules-link`): it doesn't make sense to
|
|
475
|
+
ask a developer to opt into autolinking a second time once they've picked a real Expo-backed
|
|
476
|
+
package, so it rides along automatically — `resolveFeatures` (`new`) folds `hasExpoModules` to
|
|
477
|
+
`true`, and `resolveAddLayers` (`add`) appends the `expo-modules` layer, in both cases without a
|
|
478
|
+
second explicit tick. (A same-day follow-up also added the raw npm `expo-linking` package
|
|
479
|
+
unconditionally, on the unverified assumption that Expo's wrapper modules need it for autolinking
|
|
480
|
+
— reverted once checking the real installed `expo-battery`/`expo-web-browser`/`expo-sharing`/
|
|
481
|
+
`expo-store-review`/`expo-local-authentication`/`expo`/`expo-modules-autolinking` `package.json`s
|
|
482
|
+
showed none of them depend on it.)
|
|
483
|
+
|
|
484
|
+
## References
|
|
485
|
+
|
|
486
|
+
- Root [`README.md`](../../README.md) — the `DX` milestone row and the "Try It In Your Own App"
|
|
487
|
+
section this package replaces.
|
|
488
|
+
- `symbiote-release-publishing` skill — how every other package's publish pipeline works;
|
|
489
|
+
this package's `rolldown`-bundled `bin` is a deliberate divergence from it, not yet
|
|
490
|
+
reconciled with the shared CI gate.
|
|
491
|
+
- `symbiote-new-package-skeleton` skill — the tiered scope-triage convention this package's
|
|
492
|
+
own design conversation borrowed from, adapted for a CLI tool rather than a runtime library.
|