kasy-cli 1.21.9 → 1.23.0

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 (269) hide show
  1. package/lib/commands/add.js +93 -80
  2. package/lib/commands/configure.js +100 -32
  3. package/lib/commands/doctor.js +28 -2
  4. package/lib/commands/new.js +80 -37
  5. package/lib/commands/notifications.js +1 -1
  6. package/lib/commands/remove.js +43 -15
  7. package/lib/commands/run.js +2 -2
  8. package/lib/commands/update.js +2 -2
  9. package/lib/scaffold/CHANGELOG.json +14 -0
  10. package/lib/scaffold/backends/api/generator.js +14 -14
  11. package/lib/scaffold/backends/api/patch/README.md +83 -0
  12. package/lib/scaffold/backends/api/patch/lib/core/data/api/storage_api.dart +1 -1
  13. package/lib/scaffold/backends/api/patch/lib/core/data/entities/user_entity.dart +5 -0
  14. package/lib/scaffold/backends/api/patch/lib/{environnements.dart → environments.dart} +3 -11
  15. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_api.dart +108 -0
  16. package/lib/scaffold/backends/api/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +51 -0
  17. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +5 -5
  18. package/lib/scaffold/backends/api/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +71 -38
  19. package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +2 -2
  20. package/lib/scaffold/backends/api/patch/lib/features/feedbacks/api/feature_request_api.dart +54 -0
  21. package/lib/scaffold/backends/api/patch/lib/features/onboarding/models/user_info.dart +16 -16
  22. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  23. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  24. package/lib/scaffold/backends/api/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +100 -0
  25. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  26. package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +60 -0
  27. package/lib/scaffold/backends/api/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  28. package/lib/scaffold/backends/api/pubspec.yaml.tpl +4 -5
  29. package/lib/scaffold/backends/firebase/deploy.js +87 -13
  30. package/lib/scaffold/backends/firebase/generator.js +5 -5
  31. package/lib/scaffold/backends/firebase/tokens.js +4 -4
  32. package/lib/scaffold/backends/supabase/deploy.js +63 -11
  33. package/lib/scaffold/backends/supabase/edge-functions/admin-list-users/index.ts +149 -0
  34. package/lib/scaffold/backends/supabase/edge-functions/{llm-chat → ai-chat}/index.ts +19 -19
  35. package/lib/scaffold/backends/supabase/edge-functions/revenuecat-webhook/index.ts +2 -0
  36. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +123 -0
  37. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +97 -0
  38. package/lib/scaffold/backends/supabase/edge-functions/stripe-list-prices/index.ts +83 -0
  39. package/lib/scaffold/backends/supabase/edge-functions/stripe-webhook/index.ts +138 -0
  40. package/lib/scaffold/backends/supabase/generator.js +17 -17
  41. package/lib/scaffold/backends/supabase/migrations/20240101000009_ai_messages.sql +50 -0
  42. package/lib/scaffold/backends/supabase/migrations/20240101000012_stripe_customers.sql +36 -0
  43. package/lib/scaffold/backends/supabase/migrations/20240101000013_admin_role.sql +62 -0
  44. package/lib/scaffold/backends/supabase/patch/lib/core/data/entities/user_entity.dart +4 -0
  45. package/lib/scaffold/backends/supabase/patch/lib/{environnements.dart → environments.dart} +3 -13
  46. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_api.dart +95 -0
  47. package/lib/scaffold/backends/supabase/patch/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +52 -0
  48. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  49. package/lib/scaffold/backends/supabase/patch/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +63 -35
  50. package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +1 -1
  51. package/lib/scaffold/backends/supabase/patch/lib/features/feedbacks/api/feature_request_api.dart +46 -0
  52. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/models/user_info.dart +16 -16
  53. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  54. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  55. package/lib/scaffold/backends/supabase/patch/lib/features/settings/ui/components/admin/admin_users_api.dart +93 -0
  56. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +13 -0
  57. package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +52 -0
  58. package/lib/scaffold/backends/supabase/patch/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  59. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +4 -5
  60. package/lib/scaffold/backends/supabase/tokens.js +3 -3
  61. package/lib/scaffold/catalog.js +9 -11
  62. package/lib/scaffold/generate.js +45 -31
  63. package/lib/scaffold/shared/generator-utils.js +188 -81
  64. package/lib/scaffold/shared/sort-imports.js +191 -0
  65. package/lib/scaffold/shared/template-strings.js +3 -3
  66. package/lib/utils/checks.js +22 -6
  67. package/lib/utils/env-tools.js +7 -0
  68. package/lib/utils/flutter-install.js +114 -0
  69. package/lib/utils/i18n/messages-en.js +52 -35
  70. package/lib/utils/i18n/messages-es.js +52 -35
  71. package/lib/utils/i18n/messages-pt.js +54 -37
  72. package/lib/utils/updates.js +15 -15
  73. package/package.json +1 -1
  74. package/templates/firebase/.env.example +2 -2
  75. package/templates/firebase/android/app/src/main/res/drawable/background.png +0 -0
  76. package/templates/firebase/android/app/src/main/res/drawable-night/background.png +0 -0
  77. package/templates/firebase/android/app/src/main/res/drawable-night-v21/background.png +0 -0
  78. package/templates/firebase/android/app/src/main/res/drawable-v21/background.png +0 -0
  79. package/templates/firebase/android/app/src/main/res/values-night-v31/styles.xml +1 -1
  80. package/templates/firebase/android/app/src/main/res/values-v31/styles.xml +1 -1
  81. package/templates/firebase/assets/images/logo_wordmark_dark.png +0 -0
  82. package/templates/firebase/assets/images/logo_wordmark_light.png +0 -0
  83. package/templates/firebase/docs/revenuecat-setup.es.md +1 -1
  84. package/templates/firebase/docs/revenuecat-setup.pt.md +1 -1
  85. package/templates/firebase/firestore.rules +24 -5
  86. package/templates/firebase/functions/package-lock.json +22 -1
  87. package/templates/firebase/functions/package.json +2 -1
  88. package/templates/firebase/functions/src/admin/functions.ts +113 -0
  89. package/templates/firebase/functions/src/{llm_chat → ai_chat}/index.ts +16 -16
  90. package/templates/firebase/functions/src/index.ts +8 -2
  91. package/templates/firebase/functions/src/notifications/device_triggers.ts +2 -2
  92. package/templates/firebase/functions/src/notifications/triggers.ts +3 -3
  93. package/templates/firebase/functions/src/subscriptions/models/subscription_status.ts +2 -0
  94. package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +222 -0
  95. package/templates/firebase/functions/src/subscriptions/subscriptions_functions.ts +2 -2
  96. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png +0 -0
  97. package/templates/firebase/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png +0 -0
  98. package/templates/firebase/lib/components/components.dart +4 -1
  99. package/templates/firebase/lib/components/kasy_app_bar.dart +22 -7
  100. package/templates/firebase/lib/components/kasy_avatar.dart +7 -6
  101. package/templates/firebase/lib/components/kasy_button.dart +23 -99
  102. package/templates/firebase/lib/components/kasy_dialog.dart +11 -11
  103. package/templates/firebase/lib/components/kasy_image_viewer.dart +84 -0
  104. package/templates/firebase/lib/components/{kasy_sidebar_pro.dart → kasy_sidebar.dart} +702 -425
  105. package/templates/firebase/lib/components/kasy_status_tag.dart +91 -0
  106. package/templates/firebase/lib/components/kasy_text_area.dart +1 -3
  107. package/templates/firebase/lib/components/kasy_text_field.dart +5 -6
  108. package/templates/firebase/lib/components/kasy_text_field_otp.dart +1 -3
  109. package/templates/firebase/lib/components/kasy_toast.dart +2 -2
  110. package/templates/firebase/lib/components/kasy_web_header.dart +209 -0
  111. package/templates/firebase/lib/core/ads/ads_provider.dart +1 -1
  112. package/templates/firebase/lib/core/bottom_menu/bottom_menu.dart +136 -23
  113. package/templates/firebase/lib/core/bottom_menu/bottom_router.dart +19 -91
  114. package/templates/firebase/lib/core/bottom_menu/kasy_bottom_bar_factory.dart +196 -96
  115. package/templates/firebase/lib/core/bottom_menu/web_content_wrapper.dart +54 -0
  116. package/templates/firebase/lib/core/config/app_env.dart +5 -11
  117. package/templates/firebase/lib/core/config/features.dart +5 -4
  118. package/templates/firebase/lib/core/data/api/analytics_api.dart +1 -1
  119. package/templates/firebase/lib/core/data/api/http_client.dart +1 -1
  120. package/templates/firebase/lib/core/data/entities/user_entity.dart +3 -0
  121. package/templates/firebase/lib/core/data/models/entitlement.dart +35 -0
  122. package/templates/firebase/lib/core/data/models/subscription.dart +13 -186
  123. package/templates/firebase/lib/core/data/models/user.dart +11 -0
  124. package/templates/firebase/lib/core/data/repositories/user_repository.dart +1 -1
  125. package/templates/firebase/lib/core/home_widgets/home_widget_background_task.dart +1 -1
  126. package/templates/firebase/lib/core/home_widgets/home_widget_mywidget_service.dart +1 -1
  127. package/templates/firebase/lib/core/icons/kasy_icons.dart +31 -1
  128. package/templates/firebase/lib/core/rating/api/rating_api.dart +2 -2
  129. package/templates/firebase/lib/core/states/logout_action.dart +25 -0
  130. package/templates/firebase/lib/core/states/user_state_notifier.dart +3 -3
  131. package/templates/firebase/lib/core/theme/colors.dart +488 -188
  132. package/templates/firebase/lib/core/theme/radius.dart +22 -11
  133. package/templates/firebase/lib/core/theme/shadows.dart +66 -0
  134. package/templates/firebase/lib/core/theme/texts.dart +75 -41
  135. package/templates/firebase/lib/core/theme/universal_theme.dart +9 -4
  136. package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +5 -4
  137. package/templates/firebase/lib/core/web_viewport_scale.dart +52 -0
  138. package/templates/firebase/lib/core/widgets/kasy_brand_badge.dart +118 -0
  139. package/templates/firebase/lib/core/widgets/kasy_brand_logo.dart +40 -0
  140. package/templates/firebase/lib/core/widgets/kasy_focus_ring.dart +125 -0
  141. package/templates/firebase/lib/core/widgets/kasy_hover.dart +53 -14
  142. package/templates/firebase/lib/core/widgets/kasy_pressable_depth.dart +18 -13
  143. package/templates/firebase/lib/{environnements.dart → environments.dart} +3 -14
  144. package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +159 -0
  145. package/templates/firebase/lib/features/ai_chat/api/ai_chat_api.dart +107 -0
  146. package/templates/firebase/lib/features/ai_chat/api/ai_chat_conversation_entity.dart +64 -0
  147. package/templates/firebase/lib/features/{llm_chat/api/llm_chat_message_entity.dart → ai_chat/api/ai_chat_message_entity.dart} +6 -6
  148. package/templates/firebase/lib/features/{llm_chat/providers/llm_chat_notifier.dart → ai_chat/providers/ai_chat_notifier.dart} +73 -38
  149. package/templates/firebase/lib/features/ai_chat/providers/ai_conversations_notifier.dart +103 -0
  150. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_avatars.dart → ai_chat/ui/widgets/ai_chat_avatars.dart} +13 -13
  151. package/templates/firebase/lib/features/{llm_chat/ui/widgets/llm_chat_composer.dart → ai_chat/ui/widgets/ai_chat_composer.dart} +10 -10
  152. package/templates/firebase/lib/features/{llm_chat/llm_chat_page.dart → ai_chat/ui/widgets/ai_chat_conversation_view.dart} +80 -67
  153. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +285 -0
  154. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +163 -0
  155. package/templates/firebase/lib/features/authentication/api/authentication_api.dart +52 -13
  156. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher.dart +12 -0
  157. package/templates/firebase/lib/features/authentication/api/popup_dismiss_watcher_web.dart +35 -0
  158. package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +108 -68
  159. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +38 -51
  160. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +38 -51
  161. package/templates/firebase/lib/features/authentication/ui/widgets/auth_card_scaffold.dart +128 -0
  162. package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +61 -44
  163. package/templates/firebase/lib/features/feedbacks/api/feature_request_api.dart +32 -0
  164. package/templates/firebase/lib/features/feedbacks/models/feedback_state.dart +5 -5
  165. package/templates/firebase/lib/features/feedbacks/providers/feedback_page_notifier.dart +2 -2
  166. package/templates/firebase/lib/features/home/design_system_page.dart +808 -170
  167. package/templates/firebase/lib/features/home/home_components_page.dart +6 -3
  168. package/templates/firebase/lib/features/home/home_components_preview_page.dart +6 -6
  169. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +325 -186
  170. package/templates/firebase/lib/features/home/home_feed.dart +289 -0
  171. package/templates/firebase/lib/features/home/home_image_grid.dart +355 -0
  172. package/templates/firebase/lib/features/home/home_page.dart +11 -250
  173. package/templates/firebase/lib/features/{local_reminder → local_reminders}/providers/reminder_notifier.dart +1 -1
  174. package/templates/firebase/lib/features/{local_reminder → local_reminders}/ui/reminder_page.dart +2 -2
  175. package/templates/firebase/lib/features/notifications/shared/att_permission.dart +1 -1
  176. package/templates/firebase/lib/features/notifications/ui/request_notification_permission.dart +25 -61
  177. package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +117 -0
  178. package/templates/firebase/lib/features/onboarding/models/user_info.dart +16 -16
  179. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_att_setup.dart +4 -3
  180. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_features.dart +7 -9
  181. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +71 -48
  182. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_notifications_setup.dart +3 -2
  183. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_questions.dart +5 -5
  184. package/templates/firebase/lib/features/onboarding/ui/onboarding_page.dart +4 -4
  185. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_background.dart +4 -2
  186. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_feature.dart +39 -121
  187. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +105 -70
  188. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +639 -0
  189. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_progress.dart +62 -50
  190. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +38 -28
  191. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_step_header.dart +75 -0
  192. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_sticky_footer.dart +16 -5
  193. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +26 -22
  194. package/templates/firebase/lib/features/settings/settings_page.dart +601 -90
  195. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +1193 -0
  196. package/templates/firebase/lib/features/settings/ui/components/admin/admin_paywalls.dart +1 -1
  197. package/templates/firebase/lib/features/settings/ui/components/admin/admin_routes.dart +2 -3
  198. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_api.dart +86 -0
  199. package/templates/firebase/lib/features/settings/ui/components/admin/admin_users_tab.dart +1215 -0
  200. package/templates/firebase/lib/features/settings/ui/components/admin/send_push_notification_page.dart +236 -0
  201. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +3 -3
  202. package/templates/firebase/lib/features/settings/ui/widgets/kasy_user_avatar.dart +77 -0
  203. package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +1 -0
  204. package/templates/firebase/lib/features/{subscription → subscriptions}/api/entities/subscription_entity.dart +17 -0
  205. package/templates/firebase/lib/features/{subscription → subscriptions}/api/inapp_subscription_api.dart +67 -46
  206. package/templates/firebase/lib/features/subscriptions/api/revenuecat_product.dart +189 -0
  207. package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +55 -0
  208. package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +82 -0
  209. package/templates/firebase/lib/features/subscriptions/api/stripe_product.dart +178 -0
  210. package/templates/firebase/lib/features/{subscription → subscriptions}/api/subscription_api.dart +1 -1
  211. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api.dart +53 -0
  212. package/templates/firebase/lib/features/subscriptions/api/subscription_payment_api_provider.dart +21 -0
  213. package/templates/firebase/lib/features/{subscription → subscriptions}/providers/premium_page_provider.dart +9 -6
  214. package/templates/firebase/lib/features/{subscription → subscriptions}/repositories/subscription_repository.dart +26 -30
  215. package/{lib/scaffold/backends/supabase/patch/lib/features/subscription → templates/firebase/lib/features/subscriptions}/shared/maybeshow_premium.dart +0 -2
  216. package/templates/firebase/lib/features/subscriptions/shared/subscription_management.dart +45 -0
  217. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/active_premium_content.dart +28 -4
  218. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_minimal.dart +7 -7
  219. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_row.dart +8 -8
  220. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/paywall_with_switch.dart +7 -7
  221. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_content.dart +7 -7
  222. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/component/premium_page_factory.dart +5 -5
  223. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/premium_page.dart +5 -5
  224. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/comparison_table.dart +1 -1
  225. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/paywall_empty_state.dart +4 -4
  226. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_bottom_menu.dart +3 -4
  227. package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_col.dart +1 -1
  228. package/templates/firebase/lib/i18n/en.i18n.json +171 -46
  229. package/templates/firebase/lib/i18n/es.i18n.json +175 -50
  230. package/templates/firebase/lib/i18n/pt.i18n.json +166 -41
  231. package/templates/firebase/lib/main.dart +6 -3
  232. package/templates/firebase/lib/router.dart +15 -23
  233. package/templates/firebase/pubspec.yaml +5 -6
  234. package/templates/firebase/test/core/data/repositories/user_repository_test.dart +3 -3
  235. package/templates/firebase/test/core/states/user_state_notifier_test.dart +4 -4
  236. package/templates/firebase/test/core/widgets/focus_ring_shape_test.dart +55 -0
  237. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_inapp_subscription_api.dart +11 -4
  238. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_revenuecat_product.dart +1 -0
  239. package/templates/firebase/test/features/{subscription → subscriptions}/api/fake_subscription_api.dart +2 -2
  240. package/templates/firebase/test/features/{subscription → subscriptions}/subscription_page_test.dart +4 -4
  241. package/templates/firebase/test/test_utils.dart +6 -6
  242. package/templates/firebase/web/index.html +5 -2
  243. package/lib/scaffold/backends/api/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -58
  244. package/lib/scaffold/backends/api/patch/lib/features/subscription/shared/maybeshow_premium.dart +0 -86
  245. package/lib/scaffold/backends/supabase/migrations/20240101000009_llm_messages.sql +0 -22
  246. package/lib/scaffold/backends/supabase/patch/lib/features/llm_chat/api/llm_chat_api.dart +0 -47
  247. package/templates/firebase/assets/images/onboarding/authentication-login-template.jpg +0 -0
  248. package/templates/firebase/assets/images/onboarding/img2.jpg +0 -0
  249. package/templates/firebase/assets/images/onboarding/img3.jpg +0 -0
  250. package/templates/firebase/assets/images/onboarding/notifications.png +0 -0
  251. package/templates/firebase/assets/images/onboarding/purchase.png +0 -0
  252. package/templates/firebase/lib/core/sidebar/kasy_sidebar.dart +0 -2021
  253. package/templates/firebase/lib/features/authentication/ui/widgets/auth_brand.dart +0 -35
  254. package/templates/firebase/lib/features/home/home_features_page.dart +0 -207
  255. package/templates/firebase/lib/features/llm_chat/api/llm_chat_api.dart +0 -50
  256. package/templates/firebase/lib/features/settings/ui/components/admin/admin_bottom_sheet.dart +0 -316
  257. package/templates/firebase/lib/features/subscription/shared/maybeshow_premium.dart +0 -85
  258. /package/templates/firebase/lib/features/{local_reminder → local_reminders}/repositories/reminder_preferences.dart +0 -0
  259. /package/templates/firebase/lib/features/{subscription → subscriptions}/providers/models/premium_state.dart +0 -0
  260. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/feature_line.dart +0 -0
  261. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background.dart +0 -0
  262. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_background_gradient.dart +0 -0
  263. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_banner.dart +0 -0
  264. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_card.dart +0 -0
  265. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_close_button.dart +0 -0
  266. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/premium_feature.dart +0 -0
  267. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/selectable_row.dart +0 -0
  268. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/trial_switcher.dart +0 -0
  269. /package/templates/firebase/lib/features/{subscription → subscriptions}/ui/widgets/unsubscribe_feedback_popup.dart +0 -0
@@ -0,0 +1,191 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Sorts Dart `import`/`export`/`part` directives to satisfy the
5
+ * `directives_ordering` lint, which otherwise fires across generated projects
6
+ * because renaming the `kasy_kit` package to the project's name breaks the
7
+ * source's alphabetical order.
8
+ *
9
+ * Order:
10
+ * 1. dart: imports
11
+ * 2. package: imports (alphabetical)
12
+ * 3. relative imports (alphabetical)
13
+ * 4. part / part of (kept after imports)
14
+ *
15
+ * Comments above the first directive (license / ignore_for_file) and the full
16
+ * directive line (with `as`/`show`/`hide`/conditional `if`) are preserved.
17
+ * Generated files (.g.dart / .freezed.dart) are skipped.
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const path = require('path');
22
+
23
+ const DIRECTIVE_RE = /^(import|export|part)\s+['"]([^'"]+)['"](.*?);?\s*$/;
24
+
25
+ // Groups, in output order:
26
+ // 0 import dart: 1 import package: 2 import relative
27
+ // 3 export dart: 4 export package: 5 export relative
28
+ // 6 part / part of
29
+ const OTHER_GROUP = 7;
30
+
31
+ function classify(line) {
32
+ const m = line.match(DIRECTIVE_RE);
33
+ if (!m) return OTHER_GROUP;
34
+ const keyword = m[1];
35
+ const uri = m[2];
36
+ if (keyword === 'part') return 6;
37
+ const base = uri.startsWith('dart:') ? 0 : uri.startsWith('package:') ? 1 : 2;
38
+ return keyword === 'export' ? base + 3 : base;
39
+ }
40
+
41
+ function sortKey(line) {
42
+ const m = line.match(DIRECTIVE_RE);
43
+ return m ? m[2] : '';
44
+ }
45
+
46
+ const DIRECTIVE_START_RE = /^(import|export|part)\b/;
47
+
48
+ function isHeaderComment(trimmed) {
49
+ return (
50
+ trimmed.startsWith('//') ||
51
+ trimmed.startsWith('/*') ||
52
+ trimmed.startsWith('*') ||
53
+ trimmed.startsWith('@')
54
+ );
55
+ }
56
+
57
+ // ASCII / code-unit ordering matches the Dart analyzer (where '/' (0x2F) sorts
58
+ // before '_' (0x5F), so 'flutter/material' < 'flutter_riverpod'). localeCompare
59
+ // gets this wrong. A directive may span multiple physical lines (e.g.
60
+ // `import '...'` then ` as foo;`, or a conditional `import '...' if (...) '...';`),
61
+ // so we accumulate lines until one ends with ';' and sort each unit by its first URI.
62
+ function processContent(original) {
63
+ const lines = original.split('\n');
64
+
65
+ // Find the first directive; bail if real code appears before any directive.
66
+ let firstDir = -1;
67
+ for (let k = 0; k < lines.length; k++) {
68
+ const t = lines[k].trim();
69
+ if (DIRECTIVE_START_RE.test(t)) {
70
+ firstDir = k;
71
+ break;
72
+ }
73
+ if (t !== '' && !isHeaderComment(t)) break;
74
+ }
75
+ if (firstDir === -1) return { changed: false, content: original };
76
+
77
+ const prefix = lines.slice(0, firstDir); // license / ignore_for_file — kept verbatim
78
+
79
+ // Parse directive units. A unit carries any comment lines directly above it
80
+ // (e.g. `// ignore: depend_on_referenced_packages`) so the comment travels
81
+ // with its import when reordered. A directive may also span multiple physical
82
+ // lines until one ends with ';'.
83
+ let i = firstDir;
84
+ const units = [];
85
+ let pending = [];
86
+ while (i < lines.length) {
87
+ const t = lines[i].trim();
88
+ if (t === '') {
89
+ i++;
90
+ continue;
91
+ }
92
+ if (isHeaderComment(t)) {
93
+ pending.push(lines[i]);
94
+ i++;
95
+ continue;
96
+ }
97
+ if (!DIRECTIVE_START_RE.test(t)) break; // first real code
98
+ const dir = [...pending, lines[i]];
99
+ pending = [];
100
+ while (!lines[i].trim().endsWith(';') && i + 1 < lines.length) {
101
+ i++;
102
+ dir.push(lines[i]);
103
+ }
104
+ i++;
105
+ const dirLine = dir.find((l) => DIRECTIVE_START_RE.test(l.trim())).trim();
106
+ units.push({ group: classify(dirLine), key: sortKey(dirLine), lines: dir });
107
+ }
108
+
109
+ // Any comment lines that weren't attached to an import belong to the body.
110
+ const bodyLines = [...pending, ...lines.slice(i)];
111
+
112
+ units.sort((a, b) =>
113
+ a.group !== b.group
114
+ ? a.group - b.group
115
+ : a.key < b.key
116
+ ? -1
117
+ : a.key > b.key
118
+ ? 1
119
+ : 0,
120
+ );
121
+
122
+ // Rebuild with a blank line between distinct groups.
123
+ const rebuilt = [];
124
+ let lastGroup = -1;
125
+ for (const u of units) {
126
+ if (lastGroup !== -1 && u.group !== lastGroup) rebuilt.push('');
127
+ rebuilt.push(...u.lines);
128
+ lastGroup = u.group;
129
+ }
130
+
131
+ const out = [...prefix, ...rebuilt];
132
+ if (bodyLines.length && bodyLines[0].trim() !== '') out.push('');
133
+ out.push(...bodyLines);
134
+
135
+ const newContent = out.join('\n');
136
+ if (newContent === original) return { changed: false, content: original };
137
+ return { changed: true, content: newContent };
138
+ }
139
+
140
+ function walkDartFiles(dir) {
141
+ const out = [];
142
+ let entries;
143
+ try {
144
+ entries = fs.readdirSync(dir, { withFileTypes: true });
145
+ } catch {
146
+ return out;
147
+ }
148
+ for (const entry of entries) {
149
+ const full = path.join(dir, entry.name);
150
+ if (entry.isDirectory()) {
151
+ if (['build', '.dart_tool', 'node_modules', '.git'].includes(entry.name)) {
152
+ continue;
153
+ }
154
+ out.push(...walkDartFiles(full));
155
+ } else if (
156
+ entry.isFile() &&
157
+ entry.name.endsWith('.dart') &&
158
+ !entry.name.endsWith('.g.dart') &&
159
+ !entry.name.endsWith('.freezed.dart')
160
+ ) {
161
+ out.push(full);
162
+ }
163
+ }
164
+ return out;
165
+ }
166
+
167
+ /**
168
+ * Sorts directives in every .dart file under the given directories (in place).
169
+ * Returns the number of files changed. Never throws on a single bad file.
170
+ */
171
+ function sortImportsInDirs(dirs) {
172
+ let changed = 0;
173
+ for (const dir of dirs) {
174
+ if (!fs.existsSync(dir)) continue;
175
+ for (const file of walkDartFiles(dir)) {
176
+ try {
177
+ const original = fs.readFileSync(file, 'utf8');
178
+ const result = processContent(original);
179
+ if (result.changed) {
180
+ fs.writeFileSync(file, result.content, 'utf8');
181
+ changed++;
182
+ }
183
+ } catch {
184
+ // skip unreadable/odd files — sorting is best-effort cosmetics
185
+ }
186
+ }
187
+ }
188
+ return changed;
189
+ }
190
+
191
+ module.exports = { sortImportsInDirs, processContent };
@@ -37,7 +37,7 @@ const TEMPLATE_STRINGS = {
37
37
  revenuecatProd: '# Production keys — auto-used on physical devices',
38
38
  sentry: '# Sentry (prod only)',
39
39
  mixpanel: '# Mixpanel',
40
- llmChat: '# LLM Chat — Cloud/Edge Function endpoint (API key stays on the server, not here)',
40
+ aiChat: '# AI Chat — Cloud/Edge Function endpoint (API key stays on the server, not here)',
41
41
  },
42
42
  },
43
43
  pt: {
@@ -71,7 +71,7 @@ const TEMPLATE_STRINGS = {
71
71
  revenuecatProd: '# Chaves de produção — usadas automaticamente em dispositivo físico',
72
72
  sentry: '# Sentry (apenas prod)',
73
73
  mixpanel: '# Mixpanel',
74
- llmChat: '# LLM Chat — endpoint da Cloud/Edge Function (a chave de API fica no servidor, não aqui)',
74
+ aiChat: '# AI Chat — endpoint da Cloud/Edge Function (a chave de API fica no servidor, não aqui)',
75
75
  },
76
76
  },
77
77
  es: {
@@ -105,7 +105,7 @@ const TEMPLATE_STRINGS = {
105
105
  revenuecatProd: '# Claves de producción — se usan automáticamente en dispositivo físico',
106
106
  sentry: '# Sentry (solo prod)',
107
107
  mixpanel: '# Mixpanel',
108
- llmChat: '# LLM Chat — endpoint de Cloud/Edge Function (la clave de API queda en el servidor, no aquí)',
108
+ aiChat: '# AI Chat — endpoint de Cloud/Edge Function (la clave de API queda en el servidor, no aquí)',
109
109
  },
110
110
  },
111
111
  };
@@ -5,12 +5,13 @@ const ui = require('./ui');
5
5
  const { createTranslator, detectDefaultLanguage } = require('./i18n');
6
6
  const { augmentedEnv, pubCacheBin } = require('./env-tools');
7
7
  const { promptOpenBrowser } = require('./browser');
8
+ const { installFlutterWindows } = require('./flutter-install');
8
9
 
9
10
  const execAsync = promisify(exec);
10
11
 
11
- // Timeout para verificar se uma ferramenta está instalada (15 s é mais que suficiente)
12
+ // Timeout to check whether a tool is installed (15 s is more than enough)
12
13
  const TOOL_CHECK_TIMEOUT = 15_000;
13
- // Timeout para instalação automática de ferramentas (5 min)
14
+ // Timeout for automatic tool installation (5 min)
14
15
  const INSTALL_TIMEOUT = 300_000;
15
16
  const MAX_BUFFER = 50 * 1024 * 1024;
16
17
 
@@ -66,6 +67,12 @@ const BASE_CHECKS = [
66
67
  minVersion: MIN_FLUTTER_VERSION,
67
68
  installGuide: () => getInstallGuide('flutter'),
68
69
  confirmInstall: true,
70
+ // Windows has no clean winget path for Flutter, so we run a custom installer
71
+ // (download SDK zip + Git) instead of a package-manager command. macOS/Linux
72
+ // keep using installGuide().cmd (brew). See flutter-install.js.
73
+ installFn: process.platform === 'win32' ? installFlutterWindows : null,
74
+ installFnDescKey: 'checks.install.flutterWinDesc',
75
+ installFnNoteKey: 'checks.install.flutterWinNote',
69
76
  },
70
77
  {
71
78
  name: 'Dart SDK',
@@ -268,16 +275,25 @@ async function recoverCheckInteractively(check, t) {
268
275
  // The step list already flagged this tool as missing; go straight to fixing it.
269
276
  const guide = typeof check.installGuide === 'function' ? check.installGuide() : null;
270
277
 
271
- // 1) Offer auto-install for heavy tools that have a package-manager command.
272
- if (guide && guide.cmd && check.confirmInstall) {
278
+ // 1) Offer auto-install for heavy tools. Most use a package-manager command
279
+ // (brew/winget); Flutter on Windows uses a custom installer (check.installFn)
280
+ // because winget ships no stable Flutter package.
281
+ if (check.confirmInstall && (check.installFn || (guide && guide.cmd))) {
282
+ const cmdLabel = check.installFn
283
+ ? (check.installFnDescKey ? t(check.installFnDescKey) : check.name)
284
+ : guide.cmd;
273
285
  const doInstall = await ui.confirm({
274
- message: t('checks.install.confirm', { name: check.name, cmd: guide.cmd }),
286
+ message: t('checks.install.confirm', { name: check.name, cmd: cmdLabel }),
275
287
  initialValue: true,
276
288
  });
277
289
  if (doInstall) {
290
+ // Heads-up for the custom installer: it's a big download and may pop a UAC.
291
+ if (check.installFn && check.installFnNoteKey) ui.log.info(t(check.installFnNoteKey));
278
292
  const spinner = ui.timedSpinner();
279
293
  spinner.start(t('checks.install.running', { name: check.name }));
280
- const installed = await execTool(guide.cmd, INSTALL_TIMEOUT);
294
+ const installed = check.installFn
295
+ ? await check.installFn({})
296
+ : await execTool(guide.cmd, INSTALL_TIMEOUT);
281
297
  spinner.stop(t('checks.install.running', { name: check.name }));
282
298
  if (installed.ok && (await revalidate(check, t))) return true;
283
299
  ui.log.warn(t('checks.install.failedManual', { name: check.name }));
@@ -105,6 +105,13 @@ function extraToolDirs() {
105
105
  process.env.LOCALAPPDATA && path.win32.join(process.env.LOCALAPPDATA, 'Google', 'Cloud SDK', 'google-cloud-sdk', 'bin'),
106
106
  process.env.ProgramFiles && path.win32.join(process.env.ProgramFiles, 'Google', 'Cloud SDK', 'google-cloud-sdk', 'bin'),
107
107
  process.env['ProgramFiles(x86)'] && path.win32.join(process.env['ProgramFiles(x86)'], 'Google', 'Cloud SDK', 'google-cloud-sdk', 'bin'),
108
+ // Flutter SDK auto-installed by `kasy new` (archive unzipped into %LOCALAPPDATA%\flutter).
109
+ // Putting its bin here lets the same run's flutter pub get / build_runner /
110
+ // flutterfire find both `flutter` and `dart` without a new terminal.
111
+ process.env.LOCALAPPDATA && path.win32.join(process.env.LOCALAPPDATA, 'flutter', 'bin'),
112
+ // Git (a Flutter prerequisite) installed via winget Git.Git — default locations.
113
+ process.env.ProgramFiles && path.win32.join(process.env.ProgramFiles, 'Git', 'cmd'),
114
+ process.env.LOCALAPPDATA && path.win32.join(process.env.LOCALAPPDATA, 'Programs', 'Git', 'cmd'),
108
115
  ].filter(Boolean);
109
116
  return candidates.filter((dir) => fs.existsSync(dir));
110
117
  }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Auto-install the Flutter SDK on Windows, the only OS where there is no clean
3
+ * package-manager path (winget ships no stable Flutter package — the official
4
+ * route is the SDK archive). We mirror what the Flutter docs tell a human to do,
5
+ * but do it for the user so `kasy new` can prepare a bare machine end to end:
6
+ *
7
+ * 1. Install Git via winget if missing (Flutter refuses to run without it).
8
+ * 2. Download the current stable Flutter SDK zip and unzip it into
9
+ * %LOCALAPPDATA%\flutter (a per-user dir that never needs admin rights).
10
+ * 3. Persist %LOCALAPPDATA%\flutter\bin on the User PATH for future terminals.
11
+ *
12
+ * The freshly-installed dirs are added to `augmentedEnv()` (see env-tools), so
13
+ * the rest of THIS `kasy new` run — flutter pub get, build_runner, flutterfire —
14
+ * finds the SDK immediately, without the user opening a new terminal.
15
+ *
16
+ * macOS/Linux don't need this: there Flutter installs via `brew install --cask
17
+ * flutter` (handled by the generic install path in checks.js).
18
+ */
19
+ const { exec } = require('node:child_process');
20
+ const path = require('node:path');
21
+
22
+ const isWindows = process.platform === 'win32';
23
+
24
+ // Where the SDK archive is unzipped. Must stay in sync with env-tools
25
+ // extraToolDirs() so the recheck and the build steps look in the same place.
26
+ function flutterWinHome() {
27
+ const base =
28
+ process.env.LOCALAPPDATA ||
29
+ path.win32.join(process.env.USERPROFILE || '', 'AppData', 'Local');
30
+ return path.win32.join(base, 'flutter');
31
+ }
32
+
33
+ // The PowerShell that does the actual work. Kept as a script (not a one-liner)
34
+ // because it has to download ~1 GB, unzip it, and edit the persistent PATH —
35
+ // none of which fits a single shell command cleanly.
36
+ const PS_SCRIPT = `
37
+ $ErrorActionPreference = 'Stop'
38
+ # Silencing the progress bar makes Invoke-WebRequest dramatically faster and
39
+ # keeps our spinner the only thing the user sees.
40
+ $ProgressPreference = 'SilentlyContinue'
41
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
42
+
43
+ $dest = Join-Path $env:LOCALAPPDATA 'flutter'
44
+ $bin = Join-Path $dest 'bin'
45
+
46
+ # 1. Git — Flutter uses it internally and won't run without it.
47
+ if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
48
+ if (Get-Command winget -ErrorAction SilentlyContinue) {
49
+ winget install --id Git.Git -e --source winget --silent --accept-source-agreements --accept-package-agreements --disable-interactivity | Out-Null
50
+ }
51
+ }
52
+
53
+ # 2. Flutter SDK — download + unzip, unless it's already there.
54
+ if (-not (Test-Path (Join-Path $bin 'flutter.bat'))) {
55
+ if (Test-Path $dest) { Remove-Item -Recurse -Force $dest }
56
+ $json = Invoke-RestMethod 'https://storage.googleapis.com/flutter_infra_release/releases/releases_windows.json'
57
+ $hash = $json.current_release.stable
58
+ $rel = $json.releases | Where-Object { $_.hash -eq $hash } | Select-Object -First 1
59
+ if (-not $rel) { throw 'Could not find the current stable Flutter release.' }
60
+ $url = $json.base_url + '/' + $rel.archive
61
+ $zip = Join-Path $env:TEMP ('flutter_sdk_' + $rel.version + '.zip')
62
+ Invoke-WebRequest -Uri $url -OutFile $zip
63
+ # ZipFile.ExtractToDirectory is much faster than Expand-Archive for a SDK-sized
64
+ # archive. The zip contains a top-level 'flutter\\' folder, so extracting into
65
+ # %LOCALAPPDATA% yields exactly %LOCALAPPDATA%\flutter.
66
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
67
+ [System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $env:LOCALAPPDATA)
68
+ Remove-Item $zip -Force -ErrorAction SilentlyContinue
69
+ }
70
+
71
+ # 3. Persist flutter\\bin on the User PATH so every future terminal finds it.
72
+ $userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
73
+ if (-not $userPath) { $userPath = '' }
74
+ if (($userPath -split ';') -notcontains $bin) {
75
+ $newPath = if ($userPath.Length -gt 0) { $userPath.TrimEnd(';') + ';' + $bin } else { $bin }
76
+ [Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
77
+ }
78
+
79
+ Write-Output ('FLUTTER_BIN=' + $bin)
80
+ `;
81
+
82
+ /**
83
+ * Run the installer. Resolves to the same shape as checks.execTool
84
+ * ({ ok, stdout, stderr, error }) so the caller can treat it uniformly.
85
+ *
86
+ * @param {{ timeout?: number }} [opts]
87
+ * @returns {Promise<{ ok: boolean, stdout: string, stderr: string, error: string|null }>}
88
+ */
89
+ function installFlutterWindows({ timeout = 1_800_000 } = {}) {
90
+ return new Promise((resolve) => {
91
+ if (!isWindows) {
92
+ resolve({ ok: false, stdout: '', stderr: '', error: 'not windows' });
93
+ return;
94
+ }
95
+ // -EncodedCommand (UTF-16LE base64) sidesteps every quoting headache of
96
+ // passing a multi-line script through a shell.
97
+ const encoded = Buffer.from(PS_SCRIPT, 'utf16le').toString('base64');
98
+ const cmd = `powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand ${encoded}`;
99
+ exec(
100
+ cmd,
101
+ { timeout, maxBuffer: 50 * 1024 * 1024, windowsHide: true },
102
+ (error, stdout, stderr) => {
103
+ resolve({
104
+ ok: !error,
105
+ stdout: stdout || '',
106
+ stderr: stderr || '',
107
+ error: error ? error.message : null,
108
+ });
109
+ }
110
+ );
111
+ });
112
+ }
113
+
114
+ module.exports = { installFlutterWindows, flutterWinHome };
@@ -43,7 +43,7 @@ module.exports = {
43
43
  'cli.command.setup.langName': 'lang',
44
44
  'cli.command.setup.langOption': 'Prompt language (en, pt, es)',
45
45
  'cli.command.setup.backendOption': 'Backend adapter (firebase, supabase, api)',
46
- 'cli.command.setup.featuresOption': 'Comma separated optional features (web,widget,llm_chat,revenuecat,ci)',
46
+ 'cli.command.setup.featuresOption': 'Comma separated optional features (web,widget,ai_chat,revenuecat,ci)',
47
47
  'cli.command.help.paramName': 'command',
48
48
  'cli.command.doctor.description': 'Check if your computer is ready to run Kasy',
49
49
  'cli.command.modules.description': 'Show what comes included and what you can add',
@@ -109,15 +109,15 @@ module.exports = {
109
109
  'modules.backend.supabase.description': 'Supabase backend adapter',
110
110
  'modules.backend.api.description': 'REST/GraphQL API backend adapter',
111
111
  'modules.feature.sentry.description': 'Sentry error tracking and crash reporting',
112
- 'modules.feature.analytics.description': 'Analytics event tracking (Firebase Analytics)',
112
+ 'modules.feature.analytics.description': 'Analytics event tracking (Mixpanel)',
113
113
  'modules.feature.facebook.description': 'Facebook Login and Meta Ads event tracking (always bundled together)',
114
114
  'modules.feature.revenuecat.description': 'Enables real in-app payments on the Subscriptions screen',
115
115
  'modules.feature.onboarding.description': 'Welcome flow shown on first launch',
116
116
  'modules.feature.web.description': 'Web/PWA support',
117
117
  'modules.feature.widget.description': 'iOS/Android home screen widget integration',
118
- 'modules.feature.llm_chat.description': 'AI chat screen with OpenAI or Gemini',
118
+ 'modules.feature.ai_chat.description': 'AI chat screen with OpenAI or Gemini',
119
119
  'modules.feature.feedback.description': 'In-app feature requests and voting',
120
- 'modules.feature.local_notifications.description': 'Local reminders scheduled by the user (no server required)',
120
+ 'modules.feature.local_reminders.description': 'Local reminders scheduled by the user (no server required)',
121
121
  'modules.feature.ci.description': 'CI/CD: GitHub/GitLab (tests + build) + Codemagic (publish to stores)',
122
122
  'checks.checking': 'Checking {name}...',
123
123
  'checks.found': '{name} found',
@@ -134,6 +134,8 @@ module.exports = {
134
134
  'checks.thenRun': 'Then run',
135
135
  'checks.recheck': 'After installing {name}, press Enter to check again',
136
136
  'checks.install.confirm': 'Install {name} now? ({cmd})',
137
+ 'checks.install.flutterWinDesc': 'downloads the official Flutter SDK + Git, ~1.8 GB',
138
+ 'checks.install.flutterWinNote': 'This can take a few minutes (large download). If a Windows approval popup appears, click Yes.',
137
139
  'checks.install.running': 'Installing {name}…',
138
140
  'checks.install.failedManual': 'Could not install {name} automatically. Do it manually:',
139
141
  'checks.install.openDocs': 'Open the install page in the browser?',
@@ -268,6 +270,9 @@ module.exports = {
268
270
  'new.supabase.created': 'Project created successfully.',
269
271
  'new.supabase.createFailed': 'Could not create project',
270
272
  'new.supabase.loginHint': 'Run: supabase login. Then enter your existing project URL and key below.',
273
+ 'new.supabase.createFailed.freeLimit': 'Your Supabase free plan reached the project limit for this organization.',
274
+ 'new.supabase.freeLimit.title': 'How to unblock',
275
+ 'new.supabase.freeLimit.options': '• Delete a project you no longer use\n• Pick another organization (if you have more than one)\n• Or upgrade your plan in the Supabase dashboard\nThen run kasy new again.',
271
276
  'new.supabase.setup': 'Linking project and deploying…',
272
277
  'new.supabase.setupManual': 'Run manually: supabase link, supabase db push, supabase functions deploy',
273
278
  'new.supabase.passwordSaved': 'Database password auto-generated and saved to .kasy/supabase.json (gitignored).',
@@ -345,8 +350,10 @@ module.exports = {
345
350
  'configure.section.sentry': 'Sentry (Crash Reports)',
346
351
  'configure.section.mixpanel': 'Mixpanel (Analytics)',
347
352
  'configure.section.revenuecat': 'RevenueCat (Subscriptions)',
353
+ 'configure.section.stripe': 'Stripe (Web Payments)',
354
+ 'configure.stripe.apiNote': 'API backend: set STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET on your own server (see Stripe-Guia.md). The CLI cannot store them for you.',
348
355
  'configure.section.facebook': 'Facebook (Login + Ads)',
349
- 'configure.section.llmChat': 'AI Chat (LLM)',
356
+ 'configure.section.aiChat': 'AI Chat',
350
357
  'configure.savedFacebook': 'Facebook credentials written to Info.plist and strings.xml.',
351
358
  'configure.facebookPlistMissing': 'ios/Runner/Info.plist not found — Facebook iOS was not updated.',
352
359
  'configure.facebookStringsMissing': 'android/.../strings.xml not found — Facebook Android was not updated.',
@@ -501,7 +508,13 @@ module.exports = {
501
508
  'doctor.revenuecat.prefixMismatch': 'Key has wrong prefix: {key} should start with {expected}',
502
509
  'doctor.revenuecat.keysTest': 'Only Test Store keys (test_) configured — store releases require appl_/goog_, otherwise the app crashes',
503
510
  'doctor.revenuecat.webhookUrlSupabase': 'Webhook URL (paste in RevenueCat → Integrations → Webhooks)',
504
- 'doctor.revenuecat.webhookUrlFirebase': 'Webhook URL: Firebase Console → Functions → subscriptionsOnRcPremiumUpdate',
511
+ 'doctor.revenuecat.webhookUrlFirebase': 'Webhook URL: Firebase Console → Functions → subscriptions-revenuecatWebhook',
512
+ 'doctor.stripe.title': 'Stripe (Web Payments)',
513
+ 'doctor.stripe.serverSide': 'Server-side only — no Stripe key ships in the app (hosted Checkout).',
514
+ 'doctor.stripe.secretsFirebase': 'Set STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET via `kasy configure stripe`, then `kasy deploy`.',
515
+ 'doctor.stripe.secretsSupabase': 'Secrets set with `supabase secrets set` (done at `kasy new` if provided).',
516
+ 'doctor.stripe.secretsApi': 'Configure STRIPE_SECRET_KEY + STRIPE_WEBHOOK_SECRET on your own server (see Stripe-Guia.md).',
517
+ 'doctor.stripe.webhookUrl': 'Stripe webhook URL (add in Stripe → Developers → Webhooks)',
505
518
 
506
519
  'update.iosRelease.success': 'iOS release files updated',
507
520
  'add.iosRelease.success': 'iOS release files added',
@@ -548,14 +561,15 @@ module.exports = {
548
561
  'new.modules.header.feedback': '── Feedback (Firebase + Supabase) ──',
549
562
  'new.modules.header.ci': '── CI/CD ──',
550
563
  'new.modules.header.monetization': '── Monetization ──',
551
- 'new.firebase.module.revenuecat': '💰 RevenueCat (enables Subscriptions)',
564
+ 'new.firebase.module.revenuecat': '💰 RevenueCat (mobile subscriptions)',
565
+ 'new.firebase.module.stripe': '🌐 Stripe (web subscriptions)',
552
566
  'new.firebase.module.sentry': '🚨 Crash Reports (Sentry)',
553
567
  'new.firebase.module.analytics': '📊 Analytics (Mixpanel)',
554
568
  'new.firebase.module.facebook': '👤 Facebook (Login + Ads)',
555
569
  'new.firebase.module.web': '🌐 Web Support (PWA)',
556
570
  'new.firebase.module.widget': '📱 Home Widget (iOS/Android)',
557
- 'new.firebase.module.llm_chat': '🤖 AI Chat (OpenAI/Gemini)',
558
- 'new.firebase.module.local_notifications': '🔔 Local Reminders (no server)',
571
+ 'new.firebase.module.ai_chat': '🤖 AI Chat (OpenAI/Gemini)',
572
+ 'new.firebase.module.local_reminders': '🔔 Local Reminders (no server)',
559
573
  'new.firebase.module.feedback': '💬 Feature Requests (requires Firebase or Supabase)',
560
574
  'new.firebase.module.ci': '⚙️ CI/CD (GitHub + Codemagic)',
561
575
  'new.firebase.module.onboarding': '👋 Onboarding (welcome flow)',
@@ -579,10 +593,12 @@ module.exports = {
579
593
  'new.firebase.q.revenuecat.ios': 'RevenueCat API key for iOS',
580
594
  'new.firebase.q.paywall': 'Which paywall style?',
581
595
  'new.firebase.q.paywall.hint': 'Layout of the subscription screen — you can change it later in RevenueCat',
582
- 'new.firebase.q.revenuecat.web': 'Enable subscriptions on web (RevenueCat Web Billing)?',
583
- 'new.firebase.q.revenuecat.web.hint': 'Requires Web Billing setup in RevenueCat dashboard + Stripe. Leave unchecked if not needed.',
584
- 'new.firebase.q.revenuecat.webKey': 'RevenueCat Web Billing API key (rcb_xxx or rcb_sb_xxx, optional — configure later)',
585
- 'new.firebase.success.revenuecatWeb': ' RevenueCat Web: add RC_WEB_API_KEY (launch.json) for web subscriptions',
596
+ 'new.firebase.q.stripe.secretKey': 'Stripe Secret Key (sk_test_… / sk_live_…) — optional, configure later',
597
+ 'new.firebase.q.stripe.webhookSecret': 'Stripe Webhook Signing Secret (whsec_…) optional, configure later',
598
+ 'new.firebase.q.stripe.webhookSecret.hint': 'From Stripe Developers Webhooks your endpoint',
599
+ 'new.firebase.q.stripe.webhookSecret.invalid': 'Webhook signing secret must start with whsec_.',
600
+ 'new.firebase.q.stripe.productId': 'Stripe Product ID (prod_…) — optional, limits the paywall to one product',
601
+ 'new.firebase.q.stripe.productId.hint': 'Leave blank to list all active recurring prices',
586
602
  'new.firebase.q.sentry.dsn': 'Sentry DSN (leave blank to configure later)',
587
603
  'new.firebase.q.sentry.dsn.invalid': 'Invalid DSN. Expected format: https://key@host/project-id',
588
604
  'new.firebase.q.mixpanel.token': 'Mixpanel Token (leave blank to configure later)',
@@ -594,7 +610,6 @@ module.exports = {
594
610
  'new.firebase.q.revenuecat.android.required': 'RevenueCat Android key is required.',
595
611
  'new.firebase.q.revenuecat.ios.required': 'RevenueCat iOS key is required.',
596
612
  'new.firebase.q.revenuecat.metaDataset.invalid': 'Pixel ID must be numeric (e.g. 1234567890).',
597
- 'new.firebase.q.revenuecat.webKey.invalid': 'Web Billing key must start with rcb_ (e.g. rcb_sb_xxx or rcb_xxx).',
598
613
 
599
614
  'new.firebase.confirm.title': 'Configuration summary:',
600
615
  'new.firebase.confirm.app': 'App',
@@ -707,6 +722,8 @@ module.exports = {
707
722
  'new.outdated.upgraded': 'kasy updated! Run kasy new again.',
708
723
  'new.success.title': 'Project created successfully!',
709
724
  'new.success.featuresInstalled': 'Features enabled:',
725
+ 'new.success.bundleId': 'App identifier (bundle ID)',
726
+ 'new.success.bundleId.hint': "Your app's unique identifier on Android, iOS and Firebase (push).",
710
727
  'new.success.nextSteps': 'Next steps:',
711
728
  'new.success.step.cd': 'Go to your project folder:',
712
729
  'new.success.step.deploy': 'Push the server to Firebase (DB + functions):',
@@ -916,7 +933,7 @@ module.exports = {
916
933
  'notifications.error.notKasyProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
917
934
  'notifications.error.noI18n': 'lib/i18n/*.i18n.json not found in this project.',
918
935
  'notifications.error.noFeatures': 'lib/core/config/features.dart not found.',
919
- 'notifications.error.notEnabled': 'Local notifications are disabled. Run: kasy add local_notifications',
936
+ 'notifications.error.notEnabled': 'Local notifications are disabled. Run: kasy add local_reminders',
920
937
  'notifications.error.cancelled': 'Cancelled.',
921
938
  'notifications.prompt.intro': 'Local notification texts',
922
939
  'notifications.prompt.hint': 'Home demo = instant test from Features. Reminder = scheduled alert from Settings.',
@@ -959,26 +976,26 @@ module.exports = {
959
976
  // Legacy keys — kept for compatibility with old scripts.
960
977
  'add.prompt.rcAndroidKey': 'RevenueCat Android API key (leave blank to configure later):',
961
978
  'add.prompt.rcIosKey': 'RevenueCat iOS API key (leave blank to configure later):',
962
- 'add.note.facebook': 'Add your Facebook App ID and token in .vscode/launch.json (FB_APP_ID, FB_TOKEN).',
963
- 'new.q.llm_chat.configureNow': 'Configure the LLM Chat agent now?',
964
- 'new.q.llm_chat.configureNow.hint': 'You can skip and run "kasy add llm_chat" later',
965
- 'add.llm_chat.reconfigure': 'Feature already active — reconfiguring credentials only.',
966
- 'add.prompt.llmProvider': 'LLM provider:',
967
- 'add.prompt.llmSystemPrompt': 'Agent system prompt (leave blank for none):\n Example: "You are a support assistant for the Fitsync app. Only answer about workouts."\n >',
968
- 'add.prompt.llmApiKey': 'API key (OpenAI or Gemini) — stored as server secret, never in the app (leave blank to set later):',
969
- 'add.prompt.llmEndpoint': 'Your LLM endpoint URL (leave blank to configure later):',
970
- 'add.llm_chat.settingSecret': 'Storing API key as server secret...',
971
- 'add.llm_chat.secretSet': 'API key stored as secret',
972
- 'add.llm_chat.secretFailed': 'Could not set secret automatically — set it manually (see instructions below)',
973
- 'add.llm_chat.skipSecret': 'API key skipped — set it later via the server CLI before deploying',
974
- 'add.llm_chat.deploying': 'Deploying LLM function to server...',
975
- 'add.llm_chat.deployed': 'LLM function deployed successfully',
976
- 'add.llm_chat.deployFailed': 'Auto-deploy failed — deploy manually (see instructions below)',
977
- 'add.llm_chat.nextSteps.firebase': '\n Next steps:\n 1. The LLM_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 2. Run the app: kasy run\n',
978
- 'add.llm_chat.nextSteps.firebase.deployFailed': '\n Next steps:\n 1. Deploy manually: firebase deploy --only functions:llmChat\n 2. The LLM_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 3. Run the app: kasy run\n',
979
- 'add.llm_chat.nextSteps.supabase': '\n Next steps:\n 1. The LLM_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 2. Run the app: kasy run\n',
980
- 'add.llm_chat.nextSteps.supabase.deployFailed': '\n Next steps:\n 1. Deploy manually: supabase functions deploy llm-chat --no-verify-jwt\n 2. The LLM_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 3. Run the app: kasy run\n',
981
- 'add.llm_chat.nextSteps.api': '\n Next steps:\n 1. Create an endpoint on your server that accepts {message, history} and calls your LLM.\n 2. Update LLM_CHAT_ENDPOINT in .vscode/launch.json with your endpoint URL.\n 3. Run the app: kasy run\n',
979
+ 'add.note.facebook': 'Add your Facebook App ID and token in .vscode/launch.json (FB_APP_ID, FB_CLIENT_TOKEN).',
980
+ 'new.q.ai_chat.configureNow': 'Configure the AI Chat agent now?',
981
+ 'new.q.ai_chat.configureNow.hint': 'You can skip and run "kasy add ai_chat" later',
982
+ 'add.ai_chat.reconfigure': 'Feature already active — reconfiguring credentials only.',
983
+ 'add.prompt.aiProvider': 'AI provider:',
984
+ 'add.prompt.aiSystemPrompt': 'Agent system prompt (leave blank for none):\n Example: "You are a support assistant for the Fitsync app. Only answer about workouts."\n >',
985
+ 'add.prompt.aiApiKey': 'API key (OpenAI or Gemini) — stored as server secret, never in the app (leave blank to set later):',
986
+ 'add.prompt.aiEndpoint': 'Your AI endpoint URL (leave blank to configure later):',
987
+ 'add.ai_chat.settingSecret': 'Storing API key as server secret...',
988
+ 'add.ai_chat.secretSet': 'API key stored as secret',
989
+ 'add.ai_chat.secretFailed': 'Could not set secret automatically — set it manually (see instructions below)',
990
+ 'add.ai_chat.skipSecret': 'API key skipped — set it later via the server CLI before deploying',
991
+ 'add.ai_chat.deploying': 'Deploying AI function to server...',
992
+ 'add.ai_chat.deployed': 'AI function deployed successfully',
993
+ 'add.ai_chat.deployFailed': 'Auto-deploy failed — deploy manually (see instructions below)',
994
+ 'add.ai_chat.nextSteps.firebase': '\n Next steps:\n 1. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 2. Run the app: kasy run\n',
995
+ 'add.ai_chat.nextSteps.firebase.deployFailed': '\n Next steps:\n 1. Deploy manually: firebase deploy --only functions:aiChat\n 2. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 3. Run the app: kasy run\n',
996
+ 'add.ai_chat.nextSteps.supabase': '\n Next steps:\n 1. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 2. Run the app: kasy run\n',
997
+ 'add.ai_chat.nextSteps.supabase.deployFailed': '\n Next steps:\n 1. Deploy manually: supabase functions deploy ai-chat --no-verify-jwt\n 2. The AI_CHAT_ENDPOINT in .vscode/launch.json has been pre-filled.\n 3. Run the app: kasy run\n',
998
+ 'add.ai_chat.nextSteps.api': '\n Next steps:\n 1. Create an endpoint on your server that accepts {message, history} and calls your AI.\n 2. Update AI_CHAT_ENDPOINT in .vscode/launch.json with your endpoint URL.\n 3. Run the app: kasy run\n',
982
999
  'cli.command.remove.description': 'Remove a feature you no longer use (e.g.: kasy remove sentry)',
983
1000
  'remove.error.noModule': 'Provide a feature name. Usage: kasy remove <feature>',
984
1001
  'remove.error.notKasyProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',