kasy-cli 1.6.0 → 1.7.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.
package/bin/kasy.js CHANGED
@@ -277,7 +277,7 @@ function buildProgram(language) {
277
277
  applyLocalizedHelp(
278
278
  program
279
279
  .command('add')
280
- .argument('[module]', 'Module to add (e.g. sentry, analytics, revenuecat, onboarding, camera, ci...)')
280
+ .argument('[module]', 'Module to add (e.g. sentry, analytics, revenuecat, onboarding, llm_chat, ci...)')
281
281
  .option('--list', 'List all available modules and their current status')
282
282
  .option('--yes', 'Skip interactive prompts (use placeholder values)')
283
283
  .option('-d, --directory <path>', 'Project folder (default: current directory)', '.')
@@ -291,7 +291,7 @@ function buildProgram(language) {
291
291
  applyLocalizedHelp(
292
292
  program
293
293
  .command('remove')
294
- .argument('[module]', 'Module to remove (e.g. sentry, analytics, camera, ci...)')
294
+ .argument('[module]', 'Module to remove (e.g. sentry, analytics, llm_chat, ci...)')
295
295
  .option('--yes', 'Skip confirmation prompt')
296
296
  .option('-d, --directory <path>', 'Project folder (default: current directory)', '.')
297
297
  .description(t('cli.command.remove.description'))
@@ -17,7 +17,7 @@ kasy new # interativo — pergunta tudo
17
17
  kasy new meu-app # cria na pasta meu-app
18
18
  kasy new --yes # modo rápido, preset Starter
19
19
  kasy new --backend supabase # define backend sem perguntar
20
- kasy new --with camera,sentry # pré-seleciona features
20
+ kasy new --with llm_chat,sentry # pré-seleciona features
21
21
  ```
22
22
 
23
23
  **Opções:**
@@ -36,12 +36,12 @@ kasy new --with camera,sentry # pré-seleciona features
36
36
  Adiciona uma feature a um projeto Kasy existente.
37
37
 
38
38
  ```bash
39
- kasy add camera
39
+ kasy add llm_chat
40
40
  kasy add sentry
41
41
  kasy add revenuecat
42
42
  kasy add --list # lista features disponíveis e status
43
- kasy add --yes camera # sem perguntas interativas
44
- kasy add -d ./outro-app camera
43
+ kasy add --yes llm_chat # sem perguntas interativas
44
+ kasy add -d ./outro-app llm_chat
45
45
  ```
46
46
 
47
47
  **Features disponíveis:**
@@ -54,7 +54,6 @@ kasy add -d ./outro-app camera
54
54
  | `onboarding` | Fluxo de onboarding customizável |
55
55
  | `web` | Suporte a Flutter Web |
56
56
  | `widget` | Home widgets para iOS e Android |
57
- | `camera` | Câmera com CameraAwesome |
58
57
  | `llm_chat` | Chat com IA via Cloud/Edge Functions |
59
58
  | `feedback` | Sistema de feedback e feature requests |
60
59
  | `ci` | CI/CD com GitHub Actions / Codemagic |
@@ -202,7 +201,6 @@ lib/
202
201
  home/ # tela principal
203
202
  notifications/ # notificações locais e push
204
203
  settings/ # configurações do app
205
- camera/ # [feature] câmera
206
204
  llm_chat/ # [feature] chat com IA
207
205
  feedbacks/ # [feature] feedback e feature requests
208
206
  onboarding/ # [feature] onboarding
@@ -13,8 +13,15 @@ const {
13
13
  FEATURES_PATCH_DIR,
14
14
  normalizeFeature,
15
15
  getVisibleFeatures,
16
+ getBaseFeatures,
17
+ BASE_FEATURES,
16
18
  } = require('../scaffold/catalog');
17
19
 
20
+ function findBaseDisplayName(id) {
21
+ const base = BASE_FEATURES.find((f) => f.id === id);
22
+ return base ? base.displayName : id;
23
+ }
24
+
18
25
  const KASY_AUDIENCE = process.env.KASY_INTERNAL === '1' ? 'internal' : 'public';
19
26
  const { applyPatch } = require('../scaffold/engine');
20
27
  const { writeRouter, writeNoOpAnalyticsApi, writeNoOpTrackingApi, writeNoOpAdminHomeWidgets, writeNoOpFeatureRequestRepository, writeMainDart, addPubspecDep, localizeReleaseDocs } = require('../scaffold/shared/generator-utils');
@@ -489,12 +496,30 @@ async function listModules(projectDir, t) {
489
496
  }
490
497
 
491
498
  const lines = [];
499
+
500
+ lines.push(kleur.bold(t('modules.featuresBase')));
501
+ for (const feature of getBaseFeatures()) {
502
+ lines.push(`${kleur.green('✓')} ${kleur.green(feature.displayName)}`);
503
+ }
504
+
505
+ // Subscriptions is base, but inactive until RevenueCat is added.
506
+ if (!activeModules.includes('revenuecat')) {
507
+ lines.push('');
508
+ lines.push(kleur.dim(t('modules.hint.subscriptionNoRc')));
509
+ }
510
+
511
+ lines.push('');
512
+ lines.push(kleur.bold(t('modules.features')));
492
513
  for (const feature of getVisibleFeatures({ audience: KASY_AUDIENCE })) {
493
514
  const active = activeModules.includes(feature.id);
494
- const badge = feature.status === 'internal' ? kleur.yellow(' [beta]') : '';
515
+ const betaBadge = feature.status === 'internal' ? kleur.yellow(' [beta]') : '';
516
+ const tagBadge = feature.tag ? kleur.yellow(` [${t(`modules.tag.${feature.tag}`)}]`) : '';
517
+ const enhancesBadge = feature.enhances
518
+ ? kleur.magenta(` [${t('modules.tag.enhances', { target: findBaseDisplayName(feature.enhances) })}]`)
519
+ : '';
495
520
  const icon = active ? kleur.green('✓') : kleur.dim('○');
496
- const label = active ? kleur.green(feature.id) : kleur.white(feature.id);
497
- lines.push(`${icon} ${label}${badge}`);
521
+ const label = active ? kleur.green(feature.displayName) : kleur.white(feature.displayName);
522
+ lines.push(`${icon} ${label}${tagBadge}${enhancesBadge}${betaBadge}`);
498
523
  }
499
524
  ui.note(lines.join('\n'), t('add.list.title'));
500
525
  }
@@ -4,9 +4,16 @@ const { printCompactHeader } = require('../utils/brand');
4
4
  const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
5
5
  const {
6
6
  AVAILABLE_BACKENDS,
7
- getVisibleFeatures
7
+ getVisibleFeatures,
8
+ getBaseFeatures,
9
+ BASE_FEATURES
8
10
  } = require('../scaffold/catalog');
9
11
 
12
+ function findBaseDisplayName(id) {
13
+ const base = BASE_FEATURES.find((f) => f.id === id);
14
+ return base ? base.displayName : id;
15
+ }
16
+
10
17
  const KASY_AUDIENCE = process.env.KASY_INTERNAL === '1' ? 'internal' : 'public';
11
18
 
12
19
  function runFeatures(options = {}) {
@@ -21,10 +28,22 @@ function runFeatures(options = {}) {
21
28
  );
22
29
  ui.log.message(backendLines.join('\n'));
23
30
 
31
+ ui.log.step(kleur.bold(t('modules.featuresBase')));
32
+ const baseLines = getBaseFeatures().map((feature) =>
33
+ `${kleur.green('✓')} ${kleur.white(feature.displayName)} - ${kleur.gray(
34
+ t(`modules.feature.base.${feature.id}.description`)
35
+ )}`
36
+ );
37
+ ui.log.message(baseLines.join('\n'));
38
+
24
39
  ui.log.step(kleur.bold(t('modules.features')));
25
40
  const featureLines = getVisibleFeatures({ audience: KASY_AUDIENCE }).map((feature) => {
26
- const badge = feature.status === 'internal' ? kleur.yellow(' [beta]') : '';
27
- return `${kleur.cyan('•')} ${kleur.white(feature.id)}${badge} - ${kleur.gray(
41
+ const betaBadge = feature.status === 'internal' ? kleur.yellow(' [beta]') : '';
42
+ const tagBadge = feature.tag ? kleur.yellow(` [${t(`modules.tag.${feature.tag}`)}]`) : '';
43
+ const enhancesBadge = feature.enhances
44
+ ? kleur.magenta(` [${t('modules.tag.enhances', { target: findBaseDisplayName(feature.enhances) })}]`)
45
+ : '';
46
+ return `${kleur.cyan('○')} ${kleur.white(feature.displayName)}${tagBadge}${enhancesBadge}${betaBadge} - ${kleur.gray(
28
47
  t(`modules.feature.${feature.id}.description`)
29
48
  )}`;
30
49
  });
@@ -25,26 +25,58 @@ const AVAILABLE_BACKENDS = [
25
25
  *
26
26
  * availableIn: backends that support this feature
27
27
  * defaultInPresets: which named presets include this feature by default
28
+ * displayName: user-facing label shown in CLI listings (Title Case, English)
29
+ * tag: optional restriction tag — `firebaseOnly` or `requiresDb` —
30
+ * rendered as a colored badge in CLI listings
31
+ * enhances: id of a base feature this optional feature activates real
32
+ * functionality for. Example: `revenuecat` enhances
33
+ * `subscription` — the Subscriptions screen exists in the base
34
+ * project but only sells real plans once RevenueCat is added.
35
+ *
36
+ * Note on id vs folder name (intentional, not a bug):
37
+ * - id `local_notifications` → folder `lib/features/local_reminder/`
38
+ * - id `feedback` → folder `lib/features/feedbacks/`
39
+ * The id describes the user-facing capability; the folder describes the
40
+ * Dart component. The generator (see generator-utils.js writeRouter and
41
+ * the cleanup step around feature dirs) removes these folders when the
42
+ * feature is not selected.
28
43
  */
29
44
  const FEATURE_CATALOG = [
30
45
  // integrations
31
- { id: 'sentry', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
32
- { id: 'analytics', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
33
- { id: 'facebook', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
46
+ { id: 'sentry', displayName: 'Crash Reports (Sentry)', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
47
+ { id: 'analytics', displayName: 'Analytics', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
48
+ { id: 'facebook', displayName: 'Facebook (Login + Ads)', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
34
49
  // monetization
35
- { id: 'revenuecat', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['saas', 'full'] },
50
+ { id: 'revenuecat', displayName: 'RevenueCat', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['saas', 'full'], enhances: 'subscription' },
36
51
  // features
37
- { id: 'onboarding', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
38
- { id: 'web', status: 'public', availableIn: ['firebase'], defaultInPresets: [] },
39
- { id: 'widget', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
40
- { id: 'llm_chat', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['content', 'full'] },
41
- { id: 'local_notifications', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: [] },
52
+ { id: 'onboarding', displayName: 'Onboarding', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['starter', 'saas', 'content', 'full'] },
53
+ { id: 'web', displayName: 'Web Support (PWA)', status: 'public', availableIn: ['firebase'], defaultInPresets: [], tag: 'firebaseOnly' },
54
+ { id: 'widget', displayName: 'Home Widget', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
55
+ { id: 'llm_chat', displayName: 'AI Chat', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['content', 'full'] },
56
+ { id: 'local_notifications', displayName: 'Local Reminders', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: [] },
42
57
  // feedback (Firebase/Supabase only)
43
- { id: 'feedback', status: 'public', availableIn: ['firebase', 'supabase'], defaultInPresets: ['saas', 'full'] },
58
+ { id: 'feedback', displayName: 'Feature Requests', status: 'public', availableIn: ['firebase', 'supabase'], defaultInPresets: ['saas', 'full'], tag: 'requiresDb' },
44
59
  // ci/cd
45
- { id: 'ci', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
60
+ { id: 'ci', displayName: 'CI/CD', status: 'public', availableIn: ['firebase', 'supabase', 'api'], defaultInPresets: ['full'] },
46
61
  ];
47
62
 
63
+ /**
64
+ * Base features — always present in every generated project.
65
+ * These cannot be added or removed via `kasy add` / `kasy remove`.
66
+ * Listed in the CLI so users understand what ships with every project.
67
+ */
68
+ const BASE_FEATURES = [
69
+ { id: 'authentication', displayName: 'Auth' },
70
+ { id: 'home', displayName: 'Home Screen' },
71
+ { id: 'settings', displayName: 'Settings Screen' },
72
+ { id: 'notifications', displayName: 'Push Notifications' },
73
+ { id: 'subscription', displayName: 'Subscriptions' },
74
+ ];
75
+
76
+ function getBaseFeatures() {
77
+ return BASE_FEATURES;
78
+ }
79
+
48
80
  /**
49
81
  * Returns features visible to the given audience, optionally filtered by backend.
50
82
  *
@@ -215,6 +247,7 @@ module.exports = {
215
247
  FEATURES_PATCH_DIR,
216
248
  AVAILABLE_BACKENDS,
217
249
  FEATURE_CATALOG,
250
+ BASE_FEATURES,
218
251
  AVAILABLE_FEATURES,
219
252
  DEFAULT_FEATURES,
220
253
  BASE_COMPONENT_FILES,
@@ -223,4 +256,5 @@ module.exports = {
223
256
  normalizeFeature,
224
257
  parseFeatureList,
225
258
  getVisibleFeatures,
259
+ getBaseFeatures,
226
260
  };
@@ -21,7 +21,7 @@ features/
21
21
  ...
22
22
  ```
23
23
 
24
- Cada subdiretório tem o **mesmo nome** que o valor do módulo em `new.js` (`sentry`, `analytics`, `facebook`, `revenuecat`, `onboarding`, `web`, `widget`, `camera`, `llm_chat`, `feedback`, `ci`).
24
+ Cada subdiretório tem o **mesmo nome** que o valor do módulo em `new.js` (`sentry`, `analytics`, `facebook`, `revenuecat`, `onboarding`, `web`, `widget`, `llm_chat`, `local_notifications`, `feedback`, `ci`).
25
25
 
26
26
  Ao gerar um projeto, o engine copia recursivamente o conteúdo de `features/{modulo}/` para a raiz do projeto, sobrescrevendo ou acrescentando arquivos.
27
27
 
@@ -32,7 +32,6 @@ Ao gerar um projeto, o engine copia recursivamente o conteúdo de `features/{mod
32
32
  | `ci` | ✅ Sim | Adiciona `.github/`, `.gitlab-ci.yml`, etc. |
33
33
  | `web` | ✅ Sim | Adiciona pasta `web/` e configurações de plataforma |
34
34
  | `widget` | ✅ Sim | Adiciona configurações Android para home widgets |
35
- | `camera` | Opcional | Permissões extras no AndroidManifest / Info.plist |
36
35
  | `llm_chat` | Não | Apenas `LLM_CHAT_ENDPOINT` via dart-define. A chave da API LLM fica no servidor (Firebase Secret / Supabase Secret) — nunca no app. |
37
36
  | `sentry` | Não | Apenas dart-define (`SENTRY_DSN`) |
38
37
  | `analytics` | Não | Apenas dart-define |
@@ -985,7 +985,7 @@ async function writeMainDart(projectDir, backend, modules, packageName, options
985
985
  * directories for modules the user did not select to avoid dead code.
986
986
  *
987
987
  * @param {string} projectDir
988
- * @param {string[]} modules - Selected modules (e.g. ['camera', 'analytics'])
988
+ * @param {string[]} modules - Selected modules (e.g. ['analytics', 'sentry'])
989
989
  */
990
990
  async function removeModuleDirs(projectDir, modules) {
991
991
  const removable = [
package/lib/utils/i18n.js CHANGED
@@ -34,7 +34,7 @@ const MESSAGES = {
34
34
  'cli.command.setup.langName': 'lang',
35
35
  'cli.command.setup.langOption': 'Prompt language (en, pt, es)',
36
36
  'cli.command.setup.backendOption': 'Backend adapter (firebase, supabase, api)',
37
- 'cli.command.setup.featuresOption': 'Comma separated optional features (web,widget,camera,llm_chat,revenuecat,ci)',
37
+ 'cli.command.setup.featuresOption': 'Comma separated optional features (web,widget,llm_chat,revenuecat,ci)',
38
38
  'cli.command.help.paramName': 'command',
39
39
  'cli.command.doctor.description': '🩺 Check environment and dependencies',
40
40
  'cli.command.modules.description': '🧩 List available backend and features',
@@ -73,22 +73,31 @@ const MESSAGES = {
73
73
  'doctor.requiredMissing': 'Missing required dependencies. Fix the errors above and rerun doctor.',
74
74
  'doctor.requiredPassed': '✓ Required environment checks passed.',
75
75
  'modules.backends': 'Available backends:',
76
- 'modules.features': 'Available optional features:',
76
+ 'modules.featuresBase': 'Always included:',
77
+ 'modules.features': 'Optional features:',
78
+ 'modules.tag.firebaseOnly': 'Firebase only',
79
+ 'modules.tag.requiresDb': 'requires Firebase or Supabase',
80
+ 'modules.tag.enhances': 'enables {target}',
81
+ 'modules.hint.subscriptionNoRc': 'Tip: Subscriptions screen is included but inactive. Run `kasy add revenuecat` to enable real payments.',
82
+ 'modules.feature.base.authentication.description': 'Sign up, login and account management',
83
+ 'modules.feature.base.home.description': 'Main app screen after login',
84
+ 'modules.feature.base.settings.description': 'Theme, language, account and preferences',
85
+ 'modules.feature.base.notifications.description': 'Push notifications via Firebase Cloud Messaging (works with any backend)',
86
+ 'modules.feature.base.subscription.description': 'Premium subscription screen and data model (add RevenueCat to enable real payments)',
77
87
  'modules.backend.firebase.description': 'Firebase backend adapter',
78
88
  'modules.backend.supabase.description': 'Supabase backend adapter',
79
89
  'modules.backend.api.description': 'REST/GraphQL API backend adapter',
80
90
  'modules.feature.sentry.description': 'Sentry error tracking and crash reporting',
81
91
  'modules.feature.analytics.description': 'Analytics event tracking (Firebase Analytics)',
82
- 'modules.feature.facebook.description': 'Facebook Login integration',
83
- 'modules.feature.revenuecat.description': 'RevenueCat subscriptions integration',
84
- 'modules.feature.onboarding.description': 'Onboarding flow feature',
85
- 'modules.feature.web.description': 'Web compatibility layer',
86
- 'modules.feature.widget.description': 'iOS/Android home widget integration',
87
- 'modules.feature.camera.description': 'Camera feature template',
88
- 'modules.feature.llm_chat.description': 'LLM chat feature template',
89
- 'modules.feature.feedback.description': 'User feedback and feature requests feature',
90
- 'modules.feature.local_notifications.description': 'Local reminders user-scheduled notifications (iOS & Android only)',
91
- 'modules.feature.ci.description': 'CI: GitHub/GitLab (tests + build) + Codemagic (publish to stores)',
92
+ 'modules.feature.facebook.description': 'Facebook Login and Meta Ads event tracking (always bundled together)',
93
+ 'modules.feature.revenuecat.description': 'Enables real in-app payments on the Subscriptions screen',
94
+ 'modules.feature.onboarding.description': 'Welcome flow shown on first launch',
95
+ 'modules.feature.web.description': 'Web/PWA support',
96
+ 'modules.feature.widget.description': 'iOS/Android home screen widget integration',
97
+ 'modules.feature.llm_chat.description': 'AI chat screen with OpenAI or Gemini',
98
+ 'modules.feature.feedback.description': 'In-app feature requests and voting',
99
+ 'modules.feature.local_notifications.description': 'Local reminders scheduled by the user (no server required)',
100
+ 'modules.feature.ci.description': 'CI/CD: GitHub/GitLab (tests + build) + Codemagic (publish to stores)',
92
101
  'checks.checking': 'Checking {name}...',
93
102
  'checks.found': '{name} found',
94
103
  'checks.foundWithVersion': '{name} ready ({version})',
@@ -248,7 +257,7 @@ const MESSAGES = {
248
257
  'new.q.preset': 'Which features to include?',
249
258
  'new.q.preset.starter': '⚡ Starter — analytics + crash reports + onboarding',
250
259
  'new.q.preset.saas': '💰 SaaS — subscriptions + analytics + onboarding + feedback',
251
- 'new.q.preset.content': '📱 Content — analytics + onboarding + camera + LLM chat',
260
+ 'new.q.preset.content': '📱 Content — crash reports + analytics + onboarding + AI chat',
252
261
  'new.q.preset.full': '🚀 Full — all features',
253
262
  'new.q.preset.custom': '⚙️ Custom — choose features one by one',
254
263
  'new.q.preset.none': '○ None — just the core',
@@ -411,18 +420,17 @@ const MESSAGES = {
411
420
  'new.modules.header.feedback': '── Feedback (Firebase + Supabase) ──',
412
421
  'new.modules.header.ci': '── CI/CD ──',
413
422
  'new.modules.header.monetization': '── Monetization ──',
414
- 'new.firebase.module.revenuecat': '💰 In-app subscriptions (RevenueCat)',
415
- 'new.firebase.module.sentry': '🚨 Crash reporting (Sentry)',
423
+ 'new.firebase.module.revenuecat': '💰 RevenueCat (enables Subscriptions)',
424
+ 'new.firebase.module.sentry': '🚨 Crash Reports (Sentry)',
416
425
  'new.firebase.module.analytics': '📊 Analytics (Mixpanel)',
417
- 'new.firebase.module.facebook': '👤 Facebook login (requires App ID + Token)',
418
- 'new.firebase.module.web': '🌐 Web (add browser support — iOS/Android always included)',
419
- 'new.firebase.module.widget': '📱 Home widget (iOS/Android)',
420
- 'new.firebase.module.camera': '📷 Camera feature',
421
- 'new.firebase.module.llm_chat': '🤖 LLM chat feature',
422
- 'new.firebase.module.local_notifications': '🔔 Local reminders — user-scheduled notifications (iOS & Android only)',
423
- 'new.firebase.module.feedback': '💬 Feedback / feature requests',
424
- 'new.firebase.module.ci': '⚙️ CI: GitHub/GitLab (tests + build) + Codemagic (publish to stores)',
425
- 'new.firebase.module.onboarding': '👋 Onboarding (welcome screens, profile questions)',
426
+ 'new.firebase.module.facebook': '👤 Facebook (Login + Ads)',
427
+ 'new.firebase.module.web': '🌐 Web Support (PWA, Firebase only)',
428
+ 'new.firebase.module.widget': '📱 Home Widget (iOS/Android)',
429
+ 'new.firebase.module.llm_chat': '🤖 AI Chat (OpenAI/Gemini)',
430
+ 'new.firebase.module.local_notifications': '🔔 Local Reminders (no server)',
431
+ 'new.firebase.module.feedback': '💬 Feature Requests (requires Firebase or Supabase)',
432
+ 'new.firebase.module.ci': '⚙️ CI/CD (GitHub + Codemagic)',
433
+ 'new.firebase.module.onboarding': '👋 Onboarding (welcome flow)',
426
434
 
427
435
  'new.firebase.q.secrets.configureNow': 'Configure server secrets now? (RevenueCat webhook, Meta Ads)',
428
436
  'new.firebase.q.secrets.configureNow.hint': 'If not now, see the README for commands to add them later',
@@ -633,7 +641,7 @@ const MESSAGES = {
633
641
  'notifications.summary.demo': 'Home → Features (demo):',
634
642
  'notifications.summary.reminder': 'Settings → Reminders (scheduled):',
635
643
 
636
- 'add.list.title': 'Available features (✓ = already active)',
644
+ 'add.list.title': 'Project features',
637
645
  'add.error.noModule': 'Provide a feature name or use --list to see available features.',
638
646
  'add.error.notKasyProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
639
647
  'add.error.unknownModule': 'Unknown feature: {module}\nAvailable: {list}',
@@ -692,7 +700,7 @@ const MESSAGES = {
692
700
  'remove.warn.ci': 'CI files removed. If you had custom workflow files, restore them from git.',
693
701
  'remove.warn.sentry.shared': 'sentry_flutter kept — still required by active features (revenuecat/facebook).',
694
702
  'cli.command.update.description': '⬆️ Update features/components in an existing project',
695
- 'cli.command.update.targetArg': 'Target to update (e.g. camera, revenuecat, sentry, components)',
703
+ 'cli.command.update.targetArg': 'Target to update (e.g. revenuecat, sentry, components)',
696
704
  'update.error.noProject': 'No kit_setup.json found. Run this command from inside a Kasy project.',
697
705
  'update.error.unknownModule': 'Unknown feature: {module}\nAvailable: {list}',
698
706
  'update.error.unknownTarget': 'Unknown update target: {module}\nAvailable: {list}',
@@ -759,7 +767,7 @@ const MESSAGES = {
759
767
  'cli.command.setup.langName': 'idioma',
760
768
  'cli.command.setup.langOption': 'Idioma dos prompts (en, pt, es)',
761
769
  'cli.command.setup.backendOption': 'Adapter de backend (firebase, supabase, api)',
762
- 'cli.command.setup.featuresOption': 'Features opcionais separadas por virgula (web,widget,camera,llm_chat,revenuecat,ci)',
770
+ 'cli.command.setup.featuresOption': 'Features opcionais separadas por virgula (web,widget,llm_chat,revenuecat,ci)',
763
771
  'cli.command.help.paramName': 'comando',
764
772
  'cli.command.doctor.description': '🩺 Verifica ambiente e dependencias',
765
773
  'cli.command.modules.description': '🧩 Lista backends e features disponiveis',
@@ -798,22 +806,31 @@ const MESSAGES = {
798
806
  'doctor.requiredMissing': 'Dependencias obrigatorias ausentes. Corrija os erros acima e execute o doctor novamente.',
799
807
  'doctor.requiredPassed': '✓ Verificacoes obrigatorias de ambiente aprovadas.',
800
808
  'modules.backends': 'Backends disponiveis:',
801
- 'modules.features': 'Features opcionais disponiveis:',
809
+ 'modules.featuresBase': 'Sempre incluido:',
810
+ 'modules.features': 'Features opcionais:',
811
+ 'modules.tag.firebaseOnly': 'somente Firebase',
812
+ 'modules.tag.requiresDb': 'requer Firebase ou Supabase',
813
+ 'modules.tag.enhances': 'ativa {target}',
814
+ 'modules.hint.subscriptionNoRc': 'Dica: a tela de Subscriptions esta inclusa mas inativa. Rode `kasy add revenuecat` para habilitar pagamentos reais.',
815
+ 'modules.feature.base.authentication.description': 'Cadastro, login e gerenciamento de conta',
816
+ 'modules.feature.base.home.description': 'Tela principal do app apos o login',
817
+ 'modules.feature.base.settings.description': 'Tema, idioma, conta e preferencias',
818
+ 'modules.feature.base.notifications.description': 'Notificacoes push via Firebase Cloud Messaging (funciona com qualquer backend)',
819
+ 'modules.feature.base.subscription.description': 'Tela e modelo de assinatura premium (adicione RevenueCat para habilitar pagamentos reais)',
802
820
  'modules.backend.firebase.description': 'Adapter de backend Firebase',
803
821
  'modules.backend.supabase.description': 'Adapter de backend Supabase',
804
822
  'modules.backend.api.description': 'Adapter de backend API REST/GraphQL',
805
823
  'modules.feature.sentry.description': 'Rastreamento de erros e crashes com Sentry',
806
824
  'modules.feature.analytics.description': 'Rastreamento de eventos de analytics (Firebase Analytics)',
807
- 'modules.feature.facebook.description': 'Integracao de Login com Facebook',
808
- 'modules.feature.revenuecat.description': 'Integracao de assinaturas com RevenueCat',
809
- 'modules.feature.onboarding.description': 'Feature de fluxo de onboarding',
810
- 'modules.feature.web.description': 'Camada de compatibilidade Web',
811
- 'modules.feature.widget.description': 'Integracao de widget iOS/Android',
812
- 'modules.feature.camera.description': 'Template da feature de camera',
813
- 'modules.feature.llm_chat.description': 'Template da feature de chat com LLM',
814
- 'modules.feature.feedback.description': 'Feature de feedback e sugestoes de funcionalidades',
815
- 'modules.feature.local_notifications.description': 'Lembretes locais agendados pelo usuario (apenas iOS e Android)',
816
- 'modules.feature.ci.description': 'CI: GitHub/GitLab (testes + build) + Codemagic (publicacao nas lojas)',
825
+ 'modules.feature.facebook.description': 'Login do Facebook e rastreamento de eventos Meta Ads (vem sempre junto)',
826
+ 'modules.feature.revenuecat.description': 'Habilita pagamentos reais na tela de Subscriptions',
827
+ 'modules.feature.onboarding.description': 'Fluxo de boas-vindas mostrado no primeiro acesso',
828
+ 'modules.feature.web.description': 'Suporte Web/PWA',
829
+ 'modules.feature.widget.description': 'Widget de tela inicial iOS/Android',
830
+ 'modules.feature.llm_chat.description': 'Tela de chat com IA usando OpenAI ou Gemini',
831
+ 'modules.feature.feedback.description': 'Pedidos e votacao de features dentro do app',
832
+ 'modules.feature.local_notifications.description': 'Lembretes locais agendados pelo usuario (sem servidor)',
833
+ 'modules.feature.ci.description': 'CI/CD: GitHub/GitLab (testes + build) + Codemagic (publicacao nas lojas)',
817
834
  'checks.checking': 'Verificando {name}...',
818
835
  'checks.found': '{name} encontrado',
819
836
  'checks.foundWithVersion': '{name} pronto ({version})',
@@ -973,7 +990,7 @@ const MESSAGES = {
973
990
  'new.q.preset': 'Quais features incluir?',
974
991
  'new.q.preset.starter': '⚡ Starter — analytics + erros + onboarding',
975
992
  'new.q.preset.saas': '💰 SaaS — assinaturas + analytics + onboarding + feedback',
976
- 'new.q.preset.content': '📱 Conteudo — analytics + onboarding + camera + chat LLM',
993
+ 'new.q.preset.content': '📱 Conteudo — crash reports + analytics + onboarding + AI chat',
977
994
  'new.q.preset.full': '🚀 Completo — todas as features',
978
995
  'new.q.preset.custom': '⚙️ Personalizar — escolha feature a feature',
979
996
  'new.q.preset.none': '○ Nenhum — so o core',
@@ -1136,18 +1153,17 @@ const MESSAGES = {
1136
1153
  'new.modules.header.feedback': '── Feedback (Firebase + Supabase) ──',
1137
1154
  'new.modules.header.ci': '── CI/CD ──',
1138
1155
  'new.modules.header.monetization': '── Monetizacao ──',
1139
- 'new.firebase.module.revenuecat': '💰 Assinaturas no app (RevenueCat)',
1140
- 'new.firebase.module.sentry': '🚨 Relatorio de erros (Sentry)',
1156
+ 'new.firebase.module.revenuecat': '💰 RevenueCat (ativa Subscriptions)',
1157
+ 'new.firebase.module.sentry': '🚨 Crash Reports (Sentry)',
1141
1158
  'new.firebase.module.analytics': '📊 Analytics (Mixpanel)',
1142
- 'new.firebase.module.facebook': '👤 Login com Facebook (requer App ID + Token)',
1143
- 'new.firebase.module.web': '🌐 Web (adicional ao nativo — iOS/Android sempre incluidos)',
1144
- 'new.firebase.module.widget': '📱 Widget na tela inicial (iOS/Android)',
1145
- 'new.firebase.module.camera': '📷 Feature de camera',
1146
- 'new.firebase.module.llm_chat': '🤖 Feature de chat com LLM',
1147
- 'new.firebase.module.local_notifications': '🔔 Lembretes locais — agendados pelo usuario (apenas iOS e Android)',
1148
- 'new.firebase.module.feedback': '💬 Feedback / sugestoes de features',
1149
- 'new.firebase.module.ci': '⚙️ CI: GitHub/GitLab (testes + build) + Codemagic (publicacao nas lojas)',
1150
- 'new.firebase.module.onboarding': '👋 Onboarding (telas de boas-vindas, perguntas de perfil)',
1159
+ 'new.firebase.module.facebook': '👤 Facebook (Login + Ads)',
1160
+ 'new.firebase.module.web': '🌐 Web Support (PWA, somente Firebase)',
1161
+ 'new.firebase.module.widget': '📱 Home Widget (iOS/Android)',
1162
+ 'new.firebase.module.llm_chat': '🤖 AI Chat (OpenAI/Gemini)',
1163
+ 'new.firebase.module.local_notifications': '🔔 Local Reminders (sem servidor)',
1164
+ 'new.firebase.module.feedback': '💬 Feature Requests (requer Firebase ou Supabase)',
1165
+ 'new.firebase.module.ci': '⚙️ CI/CD (GitHub + Codemagic)',
1166
+ 'new.firebase.module.onboarding': '👋 Onboarding (fluxo de boas-vindas)',
1151
1167
 
1152
1168
  'new.firebase.q.secrets.configureNow': 'Configurar as secrets do servidor agora? (webhook RevenueCat, Meta Ads)',
1153
1169
  'new.firebase.q.secrets.configureNow.hint': 'Se nao agora, veja o README para os comandos de configuracao depois',
@@ -1358,7 +1374,7 @@ const MESSAGES = {
1358
1374
  'notifications.summary.demo': 'Home → Features (demo):',
1359
1375
  'notifications.summary.reminder': 'Configuracoes → Lembretes (agendado):',
1360
1376
 
1361
- 'add.list.title': 'Features disponiveis (✓ = ja ativa)',
1377
+ 'add.list.title': 'Features do projeto',
1362
1378
  'add.error.noModule': 'Informe o nome da feature ou use --list para ver as disponiveis.',
1363
1379
  'add.error.notKasyProject': 'kit_setup.json nao encontrado. Execute este comando dentro de um projeto Kasy.',
1364
1380
  'add.error.unknownModule': 'Feature desconhecida: {module}\nDisponiveis: {list}',
@@ -1417,7 +1433,7 @@ const MESSAGES = {
1417
1433
  'remove.warn.ci': 'Arquivos de CI removidos. Se tinha workflows customizados, restaure-os pelo git.',
1418
1434
  'remove.warn.sentry.shared': 'sentry_flutter mantido — ainda necessario para features ativas (revenuecat/facebook).',
1419
1435
  'cli.command.update.description': '⬆️ Atualiza features/componentes em um projeto existente',
1420
- 'cli.command.update.targetArg': 'Alvo para atualizar (ex.: camera, revenuecat, sentry, components)',
1436
+ 'cli.command.update.targetArg': 'Alvo para atualizar (ex.: revenuecat, sentry, components)',
1421
1437
  'update.error.noProject': 'kit_setup.json nao encontrado. Execute dentro de um projeto Kasy.',
1422
1438
  'update.error.unknownModule': 'Modulo desconhecido: {module}\nDisponiveis: {list}',
1423
1439
  'update.error.unknownTarget': 'Alvo de atualizacao desconhecido: {module}\nDisponiveis: {list}',
@@ -1484,7 +1500,7 @@ const MESSAGES = {
1484
1500
  'cli.command.setup.langName': 'idioma',
1485
1501
  'cli.command.setup.langOption': 'Idioma de prompts (en, pt, es)',
1486
1502
  'cli.command.setup.backendOption': 'Adapter de backend (firebase, supabase, api)',
1487
- 'cli.command.setup.featuresOption': 'Features opcionales separadas por coma (web,widget,camera,llm_chat,revenuecat,ci)',
1503
+ 'cli.command.setup.featuresOption': 'Features opcionales separadas por coma (web,widget,llm_chat,revenuecat,ci)',
1488
1504
  'cli.command.help.paramName': 'comando',
1489
1505
  'cli.command.doctor.description': '🩺 Verifica entorno y dependencias',
1490
1506
  'cli.command.modules.description': '🧩 Lista backends y features disponibles',
@@ -1523,22 +1539,31 @@ const MESSAGES = {
1523
1539
  'doctor.requiredMissing': 'Faltan dependencias obligatorias. Corrige los errores anteriores y ejecuta doctor nuevamente.',
1524
1540
  'doctor.requiredPassed': '✓ Verificaciones obligatorias de entorno aprobadas.',
1525
1541
  'modules.backends': 'Backends disponibles:',
1526
- 'modules.features': 'Features opcionales disponibles:',
1542
+ 'modules.featuresBase': 'Siempre incluido:',
1543
+ 'modules.features': 'Features opcionales:',
1544
+ 'modules.tag.firebaseOnly': 'solo Firebase',
1545
+ 'modules.tag.requiresDb': 'requiere Firebase o Supabase',
1546
+ 'modules.tag.enhances': 'activa {target}',
1547
+ 'modules.hint.subscriptionNoRc': 'Tip: la pantalla de Subscriptions esta incluida pero inactiva. Ejecuta `kasy add revenuecat` para habilitar pagos reales.',
1548
+ 'modules.feature.base.authentication.description': 'Registro, inicio de sesion y gestion de cuenta',
1549
+ 'modules.feature.base.home.description': 'Pantalla principal de la app despues del login',
1550
+ 'modules.feature.base.settings.description': 'Tema, idioma, cuenta y preferencias',
1551
+ 'modules.feature.base.notifications.description': 'Notificaciones push via Firebase Cloud Messaging (funciona con cualquier backend)',
1552
+ 'modules.feature.base.subscription.description': 'Pantalla y modelo de suscripcion premium (anade RevenueCat para habilitar pagos reales)',
1527
1553
  'modules.backend.firebase.description': 'Adapter de backend Firebase',
1528
1554
  'modules.backend.supabase.description': 'Adapter de backend Supabase',
1529
1555
  'modules.backend.api.description': 'Adapter de backend API REST/GraphQL',
1530
1556
  'modules.feature.sentry.description': 'Seguimiento de errores y crashes con Sentry',
1531
1557
  'modules.feature.analytics.description': 'Seguimiento de eventos de analytics (Firebase Analytics)',
1532
- 'modules.feature.facebook.description': 'Integracion de inicio de sesion con Facebook',
1533
- 'modules.feature.revenuecat.description': 'Integracion de suscripciones con RevenueCat',
1534
- 'modules.feature.onboarding.description': 'Feature de flujo de onboarding',
1535
- 'modules.feature.web.description': 'Capa de compatibilidad Web',
1536
- 'modules.feature.widget.description': 'Integracion de widget iOS/Android',
1537
- 'modules.feature.camera.description': 'Plantilla de la feature de camara',
1538
- 'modules.feature.llm_chat.description': 'Plantilla de la feature de chat con LLM',
1539
- 'modules.feature.feedback.description': 'Feature de feedback y sugerencias de funcionalidades',
1540
- 'modules.feature.local_notifications.description': 'Recordatorios locales programados por el usuario (solo iOS y Android)',
1541
- 'modules.feature.ci.description': 'CI: GitHub/GitLab (tests + build) + Codemagic (publicacion en tiendas)',
1558
+ 'modules.feature.facebook.description': 'Login de Facebook y seguimiento de eventos Meta Ads (siempre juntos)',
1559
+ 'modules.feature.revenuecat.description': 'Habilita pagos reales en la pantalla de Subscriptions',
1560
+ 'modules.feature.onboarding.description': 'Flujo de bienvenida mostrado en el primer acceso',
1561
+ 'modules.feature.web.description': 'Soporte Web/PWA',
1562
+ 'modules.feature.widget.description': 'Widget de pantalla inicial iOS/Android',
1563
+ 'modules.feature.llm_chat.description': 'Pantalla de chat con IA usando OpenAI o Gemini',
1564
+ 'modules.feature.feedback.description': 'Solicitudes y votacion de features dentro de la app',
1565
+ 'modules.feature.local_notifications.description': 'Recordatorios locales programados por el usuario (sin servidor)',
1566
+ 'modules.feature.ci.description': 'CI/CD: GitHub/GitLab (tests + build) + Codemagic (publicacion en tiendas)',
1542
1567
  'checks.checking': 'Verificando {name}...',
1543
1568
  'checks.found': '{name} encontrado',
1544
1569
  'checks.foundWithVersion': '{name} listo ({version})',
@@ -1700,7 +1725,7 @@ const MESSAGES = {
1700
1725
  'new.q.preset': '¿Qué features incluir?',
1701
1726
  'new.q.preset.starter': '⚡ Starter — analytics + errores + onboarding',
1702
1727
  'new.q.preset.saas': '💰 SaaS — suscripciones + analytics + onboarding + feedback',
1703
- 'new.q.preset.content': '📱 Contenido — analytics + onboarding + camara + chat LLM',
1728
+ 'new.q.preset.content': '📱 Contenido — crash reports + analytics + onboarding + AI chat',
1704
1729
  'new.q.preset.full': '🚀 Completo — todas las features',
1705
1730
  'new.q.preset.custom': '⚙️ Personalizar — elige feature a feature',
1706
1731
  'new.q.preset.none': '○ Ninguno — solo el core',
@@ -1861,18 +1886,17 @@ const MESSAGES = {
1861
1886
  'new.modules.header.feedback': '── Feedback (Firebase + Supabase) ──',
1862
1887
  'new.modules.header.ci': '── CI/CD ──',
1863
1888
  'new.modules.header.monetization': '── Monetizacion ──',
1864
- 'new.firebase.module.revenuecat': '💰 Suscripciones en app (RevenueCat)',
1865
- 'new.firebase.module.sentry': '🚨 Reporte de errores (Sentry)',
1889
+ 'new.firebase.module.revenuecat': '💰 RevenueCat (activa Subscriptions)',
1890
+ 'new.firebase.module.sentry': '🚨 Crash Reports (Sentry)',
1866
1891
  'new.firebase.module.analytics': '📊 Analytics (Mixpanel)',
1867
- 'new.firebase.module.facebook': '👤 Login con Facebook (requiere App ID + Token)',
1868
- 'new.firebase.module.web': '🌐 Web (adicional al nativo — iOS/Android siempre incluidos)',
1869
- 'new.firebase.module.widget': '📱 Widget de inicio (iOS/Android)',
1870
- 'new.firebase.module.camera': '📷 Feature de camara',
1871
- 'new.firebase.module.llm_chat': '🤖 Feature de chat con LLM',
1872
- 'new.firebase.module.local_notifications': '🔔 Recordatorios locales — programados por el usuario (solo iOS y Android)',
1873
- 'new.firebase.module.feedback': '💬 Feedback / sugerencias de features',
1874
- 'new.firebase.module.ci': '⚙️ CI: GitHub/GitLab (tests + build) + Codemagic (publicacion en tiendas)',
1875
- 'new.firebase.module.onboarding': '👋 Onboarding (pantallas de bienvenida, preguntas de perfil)',
1892
+ 'new.firebase.module.facebook': '👤 Facebook (Login + Ads)',
1893
+ 'new.firebase.module.web': '🌐 Web Support (PWA, solo Firebase)',
1894
+ 'new.firebase.module.widget': '📱 Home Widget (iOS/Android)',
1895
+ 'new.firebase.module.llm_chat': '🤖 AI Chat (OpenAI/Gemini)',
1896
+ 'new.firebase.module.local_notifications': '🔔 Local Reminders (sin servidor)',
1897
+ 'new.firebase.module.feedback': '💬 Feature Requests (requiere Firebase o Supabase)',
1898
+ 'new.firebase.module.ci': '⚙️ CI/CD (GitHub + Codemagic)',
1899
+ 'new.firebase.module.onboarding': '👋 Onboarding (flujo de bienvenida)',
1876
1900
 
1877
1901
  'new.firebase.q.secrets.configureNow': '¿Configurar los secrets del servidor ahora? (webhook RevenueCat, Meta Ads)',
1878
1902
  'new.firebase.q.secrets.configureNow.hint': 'Si no ahora, vea el README para los comandos de configuración después',
@@ -2083,7 +2107,7 @@ const MESSAGES = {
2083
2107
  'notifications.summary.demo': 'Home → Features (demo):',
2084
2108
  'notifications.summary.reminder': 'Ajustes → Recordatorios (programado):',
2085
2109
 
2086
- 'add.list.title': 'Features disponibles (✓ = ya activa)',
2110
+ 'add.list.title': 'Features del proyecto',
2087
2111
  'add.error.noModule': 'Indica el nombre de la feature o usa --list para ver las disponibles.',
2088
2112
  'add.error.notKasyProject': 'kit_setup.json no encontrado. Ejecuta este comando dentro de un proyecto Kasy.',
2089
2113
  'add.error.unknownModule': 'Feature desconocida: {module}\nDisponibles: {list}',
@@ -2142,7 +2166,7 @@ const MESSAGES = {
2142
2166
  'remove.warn.ci': 'Archivos de CI eliminados. Si tenias workflows personalizados, restauralos desde git.',
2143
2167
  'remove.warn.sentry.shared': 'sentry_flutter conservado — todavia requerido por features activas (revenuecat/facebook).',
2144
2168
  'cli.command.update.description': '⬆️ Actualiza features/componentes en un proyecto existente',
2145
- 'cli.command.update.targetArg': 'Objetivo a actualizar (ej.: camera, revenuecat, sentry, components)',
2169
+ 'cli.command.update.targetArg': 'Objetivo a actualizar (ej.: revenuecat, sentry, components)',
2146
2170
  'update.error.noProject': 'kit_setup.json no encontrado. Ejecuta dentro de un proyecto Kasy.',
2147
2171
  'update.error.unknownModule': 'Modulo desconocido: {module}\nDisponibles: {list}',
2148
2172
  'update.error.unknownTarget': 'Objetivo de actualizacion desconocido: {module}\nDisponibles: {list}',
@@ -6,14 +6,6 @@ const {
6
6
  detectDefaultLanguage,
7
7
  normalizeLanguage
8
8
  } = require('./i18n');
9
- const {
10
- AVAILABLE_BACKENDS,
11
- getVisibleFeatures,
12
- normalizeBackend,
13
- parseFeatureList
14
- } = require('../scaffold/catalog');
15
-
16
- const KASY_AUDIENCE = process.env.KASY_INTERNAL === '1' ? 'internal' : 'public';
17
9
 
18
10
  function makeCancel(t) {
19
11
  return () => {
@@ -65,89 +57,9 @@ async function promptProjectName(options = {}) {
65
57
  return String(value).trim();
66
58
  }
67
59
 
68
- async function runSetupWizard(options = {}) {
69
- const t = options.t || createTranslator(options.language);
70
- const cancel = makeCancel(t);
71
- const defaultAppName = options.defaultAppName || 'MyApp';
72
- const selectedFeaturesFromArgv = parseFeatureList(options.selectedFeatures);
73
-
74
- const appName = await ui.text({
75
- message: t('prompt.appName.enter'),
76
- initialValue: defaultAppName,
77
- validate: (v) => (v && v.trim() ? undefined : t('prompt.appName.required')),
78
- onCancel: cancel,
79
- });
80
- const bundleId = await ui.text({
81
- message: t('prompt.bundleId.enter'),
82
- initialValue: 'com.example.app',
83
- validate: (v) => {
84
- if (!v || !v.trim()) return t('prompt.bundleId.required');
85
- const valid = /^[a-zA-Z][\w]*(\.[a-zA-Z][\w]*)+$/.test(v.trim());
86
- return valid ? undefined : t('prompt.bundleId.invalid');
87
- },
88
- onCancel: cancel,
89
- });
90
-
91
- const core = { appName, bundleId };
92
-
93
- const backendFromArgv = normalizeBackend(options.selectedBackend);
94
- let backend = backendFromArgv;
95
- if (!backend) {
96
- backend = await ui.select({
97
- message: t('prompt.backend.select'),
98
- initialValue: AVAILABLE_BACKENDS[0]?.id,
99
- options: AVAILABLE_BACKENDS.map((b) => ({ value: b.id, label: b.id })),
100
- onCancel: cancel,
101
- });
102
- }
103
-
104
- let features;
105
- if (selectedFeaturesFromArgv.length > 0) {
106
- features = selectedFeaturesFromArgv;
107
- } else {
108
- const selected = await ui.multiselect({
109
- message: t('prompt.features.select'),
110
- options: getVisibleFeatures({ audience: KASY_AUDIENCE }).map((feature) => ({
111
- value: feature.id,
112
- label: feature.status === 'internal' ? `${feature.id} [beta]` : feature.id,
113
- })),
114
- initialValues: [],
115
- required: false,
116
- onCancel: cancel,
117
- });
118
- features = parseFeatureList(selected);
119
- }
120
-
121
- if (backend === 'firebase') {
122
- const firebaseProjectId = await ui.text({
123
- message: t('prompt.firebase.projectId.enter'),
124
- validate: (v) => (v && v.trim() ? undefined : t('prompt.firebase.projectId.required')),
125
- onCancel: cancel,
126
- });
127
- return { ...core, backend, features, firebaseProjectId };
128
- }
129
-
130
- if (backend === 'supabase') {
131
- const supabaseUrl = await ui.text({
132
- message: t('prompt.supabase.url.enter'),
133
- validate: (v) => (v && v.trim() ? undefined : t('prompt.supabase.url.required')),
134
- onCancel: cancel,
135
- });
136
- const supabaseAnonKey = await ui.text({
137
- message: t('prompt.supabase.anonKey.enter'),
138
- validate: (v) => (v && v.trim() ? undefined : t('prompt.supabase.anonKey.required')),
139
- onCancel: cancel,
140
- });
141
- return { ...core, backend, features, supabaseUrl, supabaseAnonKey };
142
- }
143
-
144
- return { ...core, backend, features };
145
- }
146
-
147
60
  module.exports = {
148
61
  createTranslator,
149
62
  promptLicenseKey,
150
63
  promptLanguage,
151
64
  promptProjectName,
152
- runSetupWizard
153
65
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kasy-cli",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "CLI for scaffolding production-ready Flutter SaaS apps with Firebase, Supabase, or API REST backends.",
5
5
  "bin": {
6
6
  "kasy": "./bin/kasy.js"
@@ -1,7 +1,5 @@
1
- import 'package:flutter/foundation.dart' show kDebugMode;
2
1
  import 'package:flutter/material.dart';
3
2
  import 'package:flutter_riverpod/flutter_riverpod.dart';
4
- import 'package:go_router/go_router.dart';
5
3
  import 'package:kasy_kit/components/kasy_app_bar.dart';
6
4
  import 'package:kasy_kit/core/bottom_menu/bart_inner_paths.dart';
7
5
  import 'package:kasy_kit/core/bottom_menu/kasy_bart_navigation.dart';
@@ -15,7 +13,6 @@ import 'package:kasy_kit/features/home/home_components_page.dart';
15
13
  import 'package:kasy_kit/features/home/home_features_page.dart';
16
14
  import 'package:kasy_kit/features/notifications/shared/att_permission.dart';
17
15
  import 'package:kasy_kit/features/notifications/shared/notification_permission_bottom_sheet.dart';
18
- import 'package:kasy_kit/features/settings/ui/components/admin/admin_routes.dart';
19
16
  import 'package:kasy_kit/features/subscription/shared/maybeshow_premium.dart';
20
17
  import 'package:kasy_kit/i18n/translations.g.dart';
21
18
 
@@ -118,22 +115,6 @@ class HomePage extends ConsumerWidget {
118
115
  );
119
116
  },
120
117
  ),
121
- if (kDebugMode) ...[
122
- const SizedBox(height: KasySpacing.md),
123
- FilledButton.icon(
124
- onPressed: () =>
125
- context.push(adminRouteKeyboardTest),
126
- icon: const Icon(Icons.keyboard, size: 18),
127
- label: const Text('Keyboard Test'),
128
- style: FilledButton.styleFrom(
129
- backgroundColor: Colors.deepOrange,
130
- minimumSize: const Size(double.infinity, 48),
131
- shape: RoundedRectangleBorder(
132
- borderRadius: BorderRadius.circular(12),
133
- ),
134
- ),
135
- ),
136
- ],
137
118
  const SizedBox(height: KasySpacing.xl),
138
119
  ]),
139
120
  ),
@@ -7,7 +7,6 @@ import 'package:kasy_kit/features/subscription/ui/component/premium_page_factory
7
7
  const String adminRoutePaywalls = '/admin/paywalls';
8
8
  const String adminRouteHomeWidgets = '/admin/home-widgets';
9
9
  const String adminRouteSendPush = '/admin/send-push';
10
- const String adminRouteKeyboardTest = '/admin/keyboard-test';
11
10
 
12
11
  String adminRoutePremiumPreview(String variant) => '/admin/premium/$variant';
13
12
 
@@ -14,7 +14,6 @@ import 'package:kasy_kit/features/authentication/ui/phone_auth_page.dart';
14
14
  import 'package:kasy_kit/features/authentication/ui/recover_password_page.dart';
15
15
  import 'package:kasy_kit/features/authentication/ui/signin_page.dart';
16
16
  import 'package:kasy_kit/features/authentication/ui/signup_page.dart';
17
- import 'package:kasy_kit/features/dev/keyboard_test_page.dart';
18
17
  import 'package:kasy_kit/features/feedbacks/ui/feedback_page.dart';
19
18
  import 'package:kasy_kit/features/llm_chat/llm_chat_page.dart';
20
19
  import 'package:kasy_kit/features/local_reminder/ui/reminder_page.dart';
@@ -205,14 +204,6 @@ GoRouter generateRouter({
205
204
  child: const SendPushNotificationPage(),
206
205
  ),
207
206
  ),
208
- GoRoute(
209
- name: 'keyboard_test',
210
- path: adminRouteKeyboardTest,
211
- pageBuilder: (context, state) => kasyTransitionPage(
212
- key: state.pageKey,
213
- child: const KeyboardTestPage(),
214
- ),
215
- ),
216
207
  GoRoute(
217
208
  name: '404',
218
209
  path: '/404',
@@ -1,93 +0,0 @@
1
- import 'package:flutter/material.dart';
2
- import 'package:kasy_kit/components/kasy_text_field.dart';
3
- import 'package:kasy_kit/core/theme/theme.dart';
4
-
5
- class KeyboardTestPage extends StatefulWidget {
6
- const KeyboardTestPage({super.key});
7
-
8
- @override
9
- State<KeyboardTestPage> createState() => _KeyboardTestPageState();
10
- }
11
-
12
- class _KeyboardTestPageState extends State<KeyboardTestPage> {
13
- final _name = TextEditingController();
14
- final _email = TextEditingController();
15
- final _phone = TextEditingController();
16
- final _password = TextEditingController();
17
- final _bio = TextEditingController();
18
-
19
- @override
20
- void dispose() {
21
- _name.dispose();
22
- _email.dispose();
23
- _phone.dispose();
24
- _password.dispose();
25
- _bio.dispose();
26
- super.dispose();
27
- }
28
-
29
- @override
30
- Widget build(BuildContext context) {
31
- return Scaffold(
32
- appBar: AppBar(title: const Text('Keyboard Test')),
33
- body: ListView(
34
- padding: EdgeInsets.fromLTRB(
35
- KasySpacing.pageHorizontalGutter,
36
- KasySpacing.md,
37
- KasySpacing.pageHorizontalGutter,
38
- MediaQuery.paddingOf(context).bottom + 40,
39
- ),
40
- children: [
41
- const Text(
42
- 'Tap between the fields — the keyboard should stay open without closing and reopening.',
43
- style: TextStyle(fontSize: 13, color: Colors.grey),
44
- ),
45
- const SizedBox(height: KasySpacing.lg),
46
- KasyTextField(
47
- controller: _name,
48
- label: 'Name',
49
- hint: 'Your full name',
50
- textInputAction: TextInputAction.next,
51
- textCapitalization: TextCapitalization.words,
52
- ),
53
- const SizedBox(height: KasyTextField.adjacentFieldSpacing),
54
- KasyTextField(
55
- controller: _email,
56
- label: 'Email',
57
- hint: 'you@example.com',
58
- contentType: KasyTextFieldContentType.email,
59
- keyboardType: TextInputType.emailAddress,
60
- textInputAction: TextInputAction.next,
61
- ),
62
- const SizedBox(height: KasyTextField.adjacentFieldSpacing),
63
- KasyTextField(
64
- controller: _phone,
65
- label: 'Phone',
66
- hint: '+55 11 99999-9999',
67
- contentType: KasyTextFieldContentType.phone,
68
- keyboardType: TextInputType.phone,
69
- textInputAction: TextInputAction.next,
70
- ),
71
- const SizedBox(height: KasyTextField.adjacentFieldSpacing),
72
- KasyTextField(
73
- controller: _password,
74
- label: 'Password',
75
- hint: 'Min 8 characters',
76
- contentType: KasyTextFieldContentType.password,
77
- textInputAction: TextInputAction.next,
78
- ),
79
- const SizedBox(height: KasyTextField.adjacentFieldSpacing),
80
- KasyTextField(
81
- controller: _bio,
82
- label: 'Bio',
83
- hint: 'Tell us about yourself',
84
- textInputAction: TextInputAction.done,
85
- minLines: 3,
86
- maxLines: 5,
87
- textCapitalization: TextCapitalization.sentences,
88
- ),
89
- ],
90
- ),
91
- );
92
- }
93
- }