kasy-cli 1.5.0 → 1.5.2

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.
@@ -73,6 +73,7 @@ const fs = require('fs-extra');
73
73
  const { createTranslator } = require('../utils/i18n');
74
74
  const { getStoredLanguage, setStoredLanguage } = require('../utils/license');
75
75
  const { promptLanguage } = require('../utils/prompts');
76
+ const { warnIfOutdatedBeforeNew } = require('../utils/updates');
76
77
  const {
77
78
  getBaseChecks,
78
79
  getPlatformChecks,
@@ -517,6 +518,11 @@ async function runNew(directory, { language: langHint = null, backend: backendHi
517
518
  const tr = createTranslator(language);
518
519
  const cancel = () => onCancel(tr);
519
520
 
521
+ // ── 1b. Version check — warn if outdated, let user decide ───────────────
522
+ if (!yes) {
523
+ await warnIfOutdatedBeforeNew(tr);
524
+ }
525
+
520
526
  // ── 2. Environment checks (non-blocking — only warnings) ────────────────
521
527
  const envChecks = [...getBaseChecks(), ...getPlatformChecks()];
522
528
  await runChecks(envChecks, tr('new.checks.environment'), {
@@ -595,26 +601,7 @@ async function runNew(directory, { language: langHint = null, backend: backendHi
595
601
  }
596
602
  }
597
603
 
598
- // ── 3c. Wizard mode — Quick (few questions) or Full (all options) ──────────
599
- let isQuick = yes; // --yes implies Quick mode
600
- if (!yes) {
601
- const { wizardMode } = await prompts(
602
- {
603
- type: 'select',
604
- name: 'wizardMode',
605
- message: tr('new.q.mode'),
606
- choices: [
607
- { title: tr('new.q.mode.quick'), value: 'quick' },
608
- { title: tr('new.q.mode.advanced'), value: 'advanced' },
609
- ],
610
- initial: 0,
611
- },
612
- { onCancel: cancel }
613
- );
614
- isQuick = wizardMode === 'quick';
615
- }
616
-
617
- // ── 4b. Firebase setup mode (create vs existing) — ask first so prereqs are correct ─
604
+ // ── Firebase setup mode (create vs existing) ────────────────────────────────
618
605
  // Firebase backend: full setup. Supabase/API: Firebase only for push notifications (FCM).
619
606
  let firebaseSetupMode = 'existing';
620
607
  if (!yes) {
@@ -634,6 +621,7 @@ async function runNew(directory, { language: langHint = null, backend: backendHi
634
621
  );
635
622
  firebaseSetupMode = setupMode;
636
623
  } else if (backend === 'supabase' || backend === 'api') {
624
+ console.log(kleur.dim(`\n ℹ ${tr('new.firebase.q.setupMode.push.explain')}\n`));
637
625
  const { setupMode } = await prompts(
638
626
  {
639
627
  type: 'select',
@@ -651,7 +639,27 @@ async function runNew(directory, { language: langHint = null, backend: backendHi
651
639
  }
652
640
  }
653
641
 
654
- // ── 4c. Backend-specific prerequisites (dynamic: only show what's not yet verified)
642
+ // ── Wizard mode Quick (few questions) or Full (all options) ───────────────
643
+ // Asked after app name + setup context are clear, so the user understands what it controls.
644
+ let isQuick = yes; // --yes implies Quick mode
645
+ if (!yes) {
646
+ const { wizardMode } = await prompts(
647
+ {
648
+ type: 'select',
649
+ name: 'wizardMode',
650
+ message: tr('new.q.mode'),
651
+ choices: [
652
+ { title: tr('new.q.mode.quick'), value: 'quick' },
653
+ { title: tr('new.q.mode.advanced'), value: 'advanced' },
654
+ ],
655
+ initial: 0,
656
+ },
657
+ { onCancel: cancel }
658
+ );
659
+ isQuick = wizardMode === 'quick';
660
+ }
661
+
662
+ // ── Backend-specific prerequisites (dynamic: only show what's not yet verified) ─
655
663
  printPrerequisites(tr, backend, firebaseSetupMode, backendCheckResults);
656
664
 
657
665
  // ── Firebase region — Quick mode uses default (us-central1) ──────────
@@ -12,6 +12,7 @@ const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
12
12
  const {
13
13
  AVAILABLE_FEATURES,
14
14
  BASE_COMPONENT_FILES,
15
+ CORE_FILES,
15
16
  CORE_SOURCE_DIR,
16
17
  FEATURES_PATCH_DIR,
17
18
  normalizeFeature,
@@ -29,6 +30,7 @@ const NEEDS_BUILD_RUNNER = [
29
30
  'revenuecat', 'analytics', 'sentry', 'onboarding', 'llm_chat', 'feedback',
30
31
  ];
31
32
  const COMPONENTS_UPDATE_TARGET = 'components';
33
+ const CORE_UPDATE_TARGET = 'core';
32
34
  const IOS_RELEASE_UPDATE_TARGET = 'ios-release';
33
35
 
34
36
  // ── Helpers ──────────────────────────────────────────────────────────────────
@@ -80,6 +82,10 @@ function normalizeUpdateTarget(value) {
80
82
  if (componentAliases.has(normalized)) {
81
83
  return COMPONENTS_UPDATE_TARGET;
82
84
  }
85
+ const coreAliases = new Set(['core', 'core_files', 'corefiles']);
86
+ if (coreAliases.has(normalized)) {
87
+ return CORE_UPDATE_TARGET;
88
+ }
83
89
  const iosAliases = new Set(['ios_release', 'iosrelease']);
84
90
  if (iosAliases.has(normalized) || normalized === 'ios-release') {
85
91
  return IOS_RELEASE_UPDATE_TARGET;
@@ -87,9 +93,9 @@ function normalizeUpdateTarget(value) {
87
93
  return null;
88
94
  }
89
95
 
90
- async function applyBaseComponents(projectDir) {
96
+ async function applyFileList(fileList, projectDir) {
91
97
  let filesApplied = 0;
92
- for (const relativePath of BASE_COMPONENT_FILES) {
98
+ for (const relativePath of fileList) {
93
99
  const sourcePath = path.join(CORE_SOURCE_DIR, relativePath);
94
100
  if (!(await fs.pathExists(sourcePath))) {
95
101
  continue;
@@ -102,6 +108,14 @@ async function applyBaseComponents(projectDir) {
102
108
  return filesApplied;
103
109
  }
104
110
 
111
+ function applyBaseComponents(projectDir) {
112
+ return applyFileList(BASE_COMPONENT_FILES, projectDir);
113
+ }
114
+
115
+ function applyCoreFiles(projectDir) {
116
+ return applyFileList(CORE_FILES, projectDir);
117
+ }
118
+
105
119
  /** Same detection logic used by add.js and remove.js. */
106
120
  async function getActiveModules(kitSetup, projectDir) {
107
121
  const modules = [];
@@ -203,6 +217,49 @@ async function runUpdate(module, options = {}) {
203
217
  return;
204
218
  }
205
219
 
220
+ if (normalizedTarget === CORE_UPDATE_TARGET) {
221
+ if (!options.yes) {
222
+ console.log(kleur.yellow(`\n ⚠ ${t('update.warn.commitComponents')}\n`));
223
+ const { confirmed } = await prompts(
224
+ { type: 'confirm', name: 'confirmed', message: t('update.confirmCore'), initial: false },
225
+ { onCancel: () => { throw new Error(t('update.cancelled')); } }
226
+ );
227
+ if (!confirmed) {
228
+ console.log(kleur.dim(`\n${t('update.cancelled')}\n`));
229
+ return;
230
+ }
231
+ }
232
+
233
+ console.log('');
234
+ const spinner = ora(t('update.applyingCore')).start();
235
+ try {
236
+ const filesApplied = await applyCoreFiles(projectDir);
237
+ if (filesApplied === 0) {
238
+ spinner.warn(t('update.noComponentFiles'));
239
+ return;
240
+ }
241
+ spinner.succeed(t('update.appliedCore', { count: filesApplied }));
242
+ } catch (err) {
243
+ spinner.fail(t('update.applyComponentsFailed'));
244
+ throw err;
245
+ }
246
+
247
+ {
248
+ const spinnerPubGet = ora(t('update.pubGet')).start();
249
+ try {
250
+ await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
251
+ spinnerPubGet.succeed(t('update.pubGetDone'));
252
+ } catch {
253
+ spinnerPubGet.warn(t('update.pubGetFailed'));
254
+ }
255
+ }
256
+
257
+ kitSetup.cliVersion = currentVersion;
258
+ await fs.outputFile(kitSetupPath, JSON.stringify(kitSetup, null, 2) + '\n', 'utf8');
259
+ console.log(kleur.green(`\n✓ ${t('update.coreSuccess')}\n`));
260
+ return;
261
+ }
262
+
206
263
  if (normalizedTarget === IOS_RELEASE_UPDATE_TARGET) {
207
264
  const patchDir = path.join(FEATURES_PATCH_DIR, 'ios-release');
208
265
  if (!(await fs.pathExists(patchDir))) {
@@ -249,7 +306,7 @@ async function runUpdate(module, options = {}) {
249
306
  throw new Error(
250
307
  t('update.error.unknownTarget', {
251
308
  module,
252
- list: [...AVAILABLE_FEATURES, COMPONENTS_UPDATE_TARGET, IOS_RELEASE_UPDATE_TARGET].join(', '),
309
+ list: [...AVAILABLE_FEATURES, COMPONENTS_UPDATE_TARGET, CORE_UPDATE_TARGET, IOS_RELEASE_UPDATE_TARGET].join(', '),
253
310
  })
254
311
  );
255
312
  }
@@ -335,7 +392,7 @@ async function runUpdate(module, options = {}) {
335
392
 
336
393
  // ── Mode B: show status ──────────────────────────────────────────────────────
337
394
  const alreadyUpToDate = projectVersion && !isNewer(currentVersion, projectVersion);
338
- const modulesForChangelog = [...new Set([...activeModules, COMPONENTS_UPDATE_TARGET])];
395
+ const modulesForChangelog = [...new Set([...activeModules, COMPONENTS_UPDATE_TARGET, CORE_UPDATE_TARGET])];
339
396
  const changes = getChangesSince(changelog, projectVersion, modulesForChangelog, options.language);
340
397
 
341
398
  // Modules in this project that have patch dirs (can be re-applied)
@@ -74,6 +74,54 @@ const DEFAULT_FEATURES = [...AVAILABLE_FEATURES];
74
74
  * shared widgets); keep this list in sync with `Firebase/lib/components/` and
75
75
  * the home component catalog.
76
76
  */
77
+ const CORE_FILES = [
78
+ // Dev tools
79
+ 'lib/core/web_device_preview/web_device_preview.dart',
80
+ 'lib/core/dev_inspector/dev_inspector.dart',
81
+ 'lib/core/dev_inspector/dev_inspector_highlight.dart',
82
+ 'lib/core/dev_inspector/dev_inspector_info.dart',
83
+ 'lib/core/dev_inspector/dev_inspector_panel.dart',
84
+ 'lib/core/dev_inspector/dev_inspector_service.dart',
85
+ 'lib/core/keyboard_fix/keyboard_flicker_fix.dart',
86
+ // Animations
87
+ 'lib/core/animations/bottomfade_anim.dart',
88
+ 'lib/core/animations/movefade_anim.dart',
89
+ 'lib/core/animations/slideright_anim.dart',
90
+ // Core widgets (pure utilities, never user-modified)
91
+ 'lib/core/widgets/debouncer.dart',
92
+ 'lib/core/widgets/kasy_hover.dart',
93
+ 'lib/core/widgets/kasy_pressable.dart',
94
+ 'lib/core/widgets/kasy_scroll_behavior.dart',
95
+ 'lib/core/widgets/keyboard_visibility.dart',
96
+ 'lib/core/widgets/page_background.dart',
97
+ 'lib/core/widgets/page_not_found.dart',
98
+ 'lib/core/widgets/responsive_layout.dart',
99
+ 'lib/core/widgets/update_bottom_sheet.dart',
100
+ // Page transitions (pure utilities)
101
+ 'lib/core/navigation/kasy_fade_page_transitions_builder.dart',
102
+ 'lib/core/navigation/kasy_material_page_route.dart',
103
+ 'lib/core/navigation/kasy_page_transition.dart',
104
+ 'lib/core/navigation/kasy_route_transition.dart',
105
+ 'lib/core/navigation/kasy_transition_kind.dart',
106
+ // Utilities
107
+ 'lib/core/toast/toast_service.dart',
108
+ 'lib/core/ui/app_dialog.dart',
109
+ 'lib/core/icons/kasy_icons.dart',
110
+ 'lib/core/haptics/kasy_haptics.dart',
111
+ 'lib/core/haptics/haptic_feedback_notifier.dart',
112
+ // Theme (colors.dart and shadows.dart are in BASE_COMPONENT_FILES)
113
+ 'lib/core/theme/spacing.dart',
114
+ 'lib/core/theme/texts.dart',
115
+ 'lib/core/theme/radius.dart',
116
+ 'lib/core/theme/theme.dart',
117
+ 'lib/core/theme/theme_data/theme_data.dart',
118
+ 'lib/core/theme/theme_data/theme_data_factory.dart',
119
+ 'lib/core/theme/extensions/theme_extension.dart',
120
+ 'lib/core/theme/providers/kasy_theme.dart',
121
+ 'lib/core/theme/providers/theme_provider.dart',
122
+ 'lib/core/theme/universal_theme.dart',
123
+ ];
124
+
77
125
  const BASE_COMPONENT_FILES = [
78
126
  'lib/core/theme/colors.dart',
79
127
  'lib/core/theme/shadows.dart',
@@ -170,6 +218,7 @@ module.exports = {
170
218
  AVAILABLE_FEATURES,
171
219
  DEFAULT_FEATURES,
172
220
  BASE_COMPONENT_FILES,
221
+ CORE_FILES,
173
222
  normalizeBackend,
174
223
  normalizeFeature,
175
224
  parseFeatureList,
package/lib/utils/i18n.js CHANGED
@@ -132,6 +132,7 @@ const MESSAGES = {
132
132
  'new.supabase.q.create.existing': '📂 Use existing project',
133
133
  'new.firebase.q.setupMode': 'How do you want to set up Firebase?',
134
134
  'new.firebase.q.setupMode.push': 'Firebase project for push notifications (FCM):',
135
+ 'new.firebase.q.setupMode.push.explain': 'Push notifications (FCM) require a Firebase project, even when your main backend is Supabase or API REST.',
135
136
  'new.firebase.q.setupMode.create': '✨ Create from scratch (recommended for beginners)',
136
137
  'new.firebase.q.setupMode.existing': '📂 Use existing project',
137
138
  'new.firebase.q.region': 'Where are most of your app users located?',
@@ -510,6 +511,8 @@ const MESSAGES = {
510
511
  'new.firebase.interactive.billingWaiting': 'Checking Blaze status...',
511
512
  'new.firebase.interactive.billingTimeout': 'Blaze plan not confirmed after timeout. Deploy skipped — run manually when ready.',
512
513
  'new.firebase.interactive.authWarn': 'Could not enable Email/Password and Anonymous auth automatically. Enable manually:',
514
+ 'new.firebase.existing.apisFailed': 'Could not activate APIs:',
515
+ 'new.firebase.existing.googleSignInManual': 'Google Sign-In: enable manually in Authentication → Sign-in method → Google',
513
516
 
514
517
  'new.firebase.interactive.ready': 'Ready to deploy Push Notifications + Security Rules now?',
515
518
  'new.firebase.interactive.deploying': 'Deploying Cloud Functions + Firestore/Storage rules...',
@@ -548,6 +551,7 @@ const MESSAGES = {
548
551
  'new.api.success.fcm': '• Firebase is required for push notifications (FCM) — configure APNs key in Firebase console',
549
552
  'new.api.success.auth': '• Implement the social auth endpoints (Google, Apple) on your backend',
550
553
 
554
+ 'new.outdated.continueAnyway': 'Continue creating the project with the current version?',
551
555
  'new.success.title': 'Project created successfully!',
552
556
  'new.success.nextSteps': 'Next steps:',
553
557
  'new.success.step.cd': 'Go to your project folder:',
@@ -698,11 +702,14 @@ const MESSAGES = {
698
702
  'update.warn.commitComponents': 'This will overwrite base component files. Make sure you have committed your changes first.',
699
703
  'update.confirm': 'Overwrite feature "{module}" files with the latest version?',
700
704
  'update.confirmComponents': 'Overwrite base component files with the latest version?',
705
+ 'update.confirmCore': 'Overwrite core files (animations, widgets, theme, dev tools) with the latest version?',
701
706
  'update.cancelled': 'Cancelled.',
702
707
  'update.applying': 'Applying update for feature: {module}',
703
708
  'update.applyingComponents': 'Applying update for base components...',
709
+ 'update.applyingCore': 'Applying update for core files...',
704
710
  'update.applied': 'Feature {module} updated',
705
711
  'update.appliedComponents': '{count} base component files updated',
712
+ 'update.appliedCore': '{count} core files updated',
706
713
  'update.applyFailed': 'Failed to apply update for feature {module}',
707
714
  'update.applyComponentsFailed': 'Failed to apply update for base components',
708
715
  'update.noPatch': 'Feature "{module}" has no files to update (configuration-only feature).',
@@ -715,6 +722,7 @@ const MESSAGES = {
715
722
  'update.buildRunnerFailed': 'build_runner failed — run it manually',
716
723
  'update.success': 'Feature "{module}" updated successfully.',
717
724
  'update.componentsSuccess': 'Base components updated successfully.',
725
+ 'update.coreSuccess': 'Core files updated successfully.',
718
726
  },
719
727
  pt: {
720
728
  'cli.tagline': 'Crie apps móveis sem dor de configuração',
@@ -843,6 +851,7 @@ const MESSAGES = {
843
851
  'new.supabase.q.create.existing': '📂 Usar projeto existente',
844
852
  'new.firebase.q.setupMode': 'Como deseja configurar o Firebase?',
845
853
  'new.firebase.q.setupMode.push': 'Projeto Firebase para notificações push (FCM):',
854
+ 'new.firebase.q.setupMode.push.explain': 'Notificações push (FCM) precisam de um projeto Firebase, mesmo quando seu backend principal é Supabase ou API REST.',
846
855
  'new.firebase.q.setupMode.create': '✨ Criar do zero (recomendado para iniciantes)',
847
856
  'new.firebase.q.setupMode.existing': '📂 Usar projeto existente',
848
857
  'new.firebase.q.region': 'Onde está a maioria dos usuários do seu app?',
@@ -1221,6 +1230,8 @@ const MESSAGES = {
1221
1230
  'new.firebase.interactive.billingWaiting': 'Verificando status do Blaze...',
1222
1231
  'new.firebase.interactive.billingTimeout': 'Plano Blaze nao confirmado apos o tempo limite. Deploy ignorado — rode manualmente quando estiver pronto.',
1223
1232
  'new.firebase.interactive.authWarn': 'Nao foi possivel ativar Email/Senha e Anonimo automaticamente. Ative manualmente:',
1233
+ 'new.firebase.existing.apisFailed': 'Nao foi possivel ativar APIs:',
1234
+ 'new.firebase.existing.googleSignInManual': 'Google Sign-In: ative manualmente em Authentication → Sign-in method → Google',
1224
1235
 
1225
1236
  'new.firebase.interactive.ready': 'Pronto para publicar Push Notifications + Regras agora?',
1226
1237
  'new.firebase.interactive.deploying': 'Fazendo deploy das Cloud Functions + Regras (Storage e Firestore)...',
@@ -1259,6 +1270,7 @@ const MESSAGES = {
1259
1270
  'new.api.success.fcm': '• Firebase e necessario para notificacoes push (FCM) — configure a chave APNs no console do Firebase',
1260
1271
  'new.api.success.auth': '• Implemente os endpoints de auth social (Google, Apple) no seu backend',
1261
1272
 
1273
+ 'new.outdated.continueAnyway': 'Continuar criando o projeto com a versao atual?',
1262
1274
  'new.success.title': 'Projeto criado com sucesso!',
1263
1275
  'new.success.nextSteps': 'Proximos passos:',
1264
1276
  'new.success.step.cd': 'Entre na pasta do projeto:',
@@ -1409,11 +1421,14 @@ const MESSAGES = {
1409
1421
  'update.warn.commitComponents': 'Isso vai sobrescrever arquivos dos componentes base. Faca commit de tudo antes de continuar.',
1410
1422
  'update.confirm': 'Sobrescrever arquivos da feature "{module}" com a versao mais recente?',
1411
1423
  'update.confirmComponents': 'Sobrescrever arquivos dos componentes base com a versao mais recente?',
1424
+ 'update.confirmCore': 'Sobrescrever arquivos do core (animacoes, widgets, tema, ferramentas de dev) com a versao mais recente?',
1412
1425
  'update.cancelled': 'Cancelado.',
1413
1426
  'update.applying': 'Aplicando atualizacao da feature: {module}',
1414
1427
  'update.applyingComponents': 'Aplicando atualizacao dos componentes base...',
1428
+ 'update.applyingCore': 'Aplicando atualizacao dos arquivos de core...',
1415
1429
  'update.applied': 'Feature {module} atualizada',
1416
1430
  'update.appliedComponents': '{count} arquivos de componentes base atualizados',
1431
+ 'update.appliedCore': '{count} arquivos de core atualizados',
1417
1432
  'update.applyFailed': 'Falha ao aplicar atualizacao da feature {module}',
1418
1433
  'update.applyComponentsFailed': 'Falha ao aplicar atualizacao dos componentes base',
1419
1434
  'update.noPatch': 'Feature "{module}" nao tem arquivos para atualizar (feature so de configuracao).',
@@ -1426,6 +1441,7 @@ const MESSAGES = {
1426
1441
  'update.buildRunnerFailed': 'build_runner falhou — execute manualmente',
1427
1442
  'update.success': 'Feature "{module}" atualizada com sucesso.',
1428
1443
  'update.componentsSuccess': 'Componentes base atualizados com sucesso.',
1444
+ 'update.coreSuccess': 'Arquivos de core atualizados com sucesso.',
1429
1445
  },
1430
1446
  es: {
1431
1447
  'cli.tagline': 'Crea apps móviles sin dolor de configuración',
@@ -1554,6 +1570,7 @@ const MESSAGES = {
1554
1570
  'new.supabase.q.create.existing': '📂 Usar proyecto existente',
1555
1571
  'new.firebase.q.setupMode': '¿Cómo quieres configurar Firebase?',
1556
1572
  'new.firebase.q.setupMode.push': 'Proyecto Firebase para notificaciones push (FCM):',
1573
+ 'new.firebase.q.setupMode.push.explain': 'Las notificaciones push (FCM) requieren un proyecto Firebase, incluso cuando tu backend principal es Supabase o API REST.',
1557
1574
  'new.firebase.q.setupMode.create': '✨ Crear desde cero (recomendado para principiantes)',
1558
1575
  'new.firebase.q.setupMode.existing': '📂 Usar proyecto existente',
1559
1576
  'new.firebase.q.region': '¿Dónde están la mayoría de los usuarios de tu app?',
@@ -1932,6 +1949,8 @@ const MESSAGES = {
1932
1949
  'new.firebase.interactive.billingWaiting': 'Verificando estado del Blaze...',
1933
1950
  'new.firebase.interactive.billingTimeout': 'Plan Blaze no confirmado tras el tiempo límite. Despliegue omitido — ejecuta manualmente cuando estés listo.',
1934
1951
  'new.firebase.interactive.authWarn': 'No se pudo activar Email/Contraseña y Anónimo automáticamente. Actívalos manualmente:',
1952
+ 'new.firebase.existing.apisFailed': 'No se pudieron activar las APIs:',
1953
+ 'new.firebase.existing.googleSignInManual': 'Google Sign-In: activa manualmente en Authentication → Sign-in method → Google',
1935
1954
 
1936
1955
  'new.firebase.interactive.ready': '¿Listo para publicar Push Notifications + Reglas ahora?',
1937
1956
  'new.firebase.interactive.deploying': 'Desplegando Cloud Functions + Reglas (Storage y Firestore)...',
@@ -1970,6 +1989,7 @@ const MESSAGES = {
1970
1989
  'new.api.success.fcm': '• Firebase es necesario para notificaciones push (FCM) — configura la clave APNs en la consola de Firebase',
1971
1990
  'new.api.success.auth': '• Implementa los endpoints de auth social (Google, Apple) en tu backend',
1972
1991
 
1992
+ 'new.outdated.continueAnyway': '¿Continuar creando el proyecto con la version actual?',
1973
1993
  'new.success.title': '¡Proyecto creado con exito!',
1974
1994
  'new.success.nextSteps': 'Proximos pasos:',
1975
1995
  'new.success.step.cd': 'Ve a la carpeta del proyecto:',
@@ -2120,11 +2140,14 @@ const MESSAGES = {
2120
2140
  'update.warn.commitComponents': 'Esto sobreescribira archivos de los componentes base. Asegurate de haber hecho commit antes.',
2121
2141
  'update.confirm': 'Sobreescribir archivos de la feature "{module}" con la version mas reciente?',
2122
2142
  'update.confirmComponents': 'Sobreescribir archivos de los componentes base con la version mas reciente?',
2143
+ 'update.confirmCore': 'Sobreescribir archivos de core (animaciones, widgets, tema, herramientas dev) con la version mas reciente?',
2123
2144
  'update.cancelled': 'Cancelado.',
2124
2145
  'update.applying': 'Aplicando actualizacion de la feature: {module}',
2125
2146
  'update.applyingComponents': 'Aplicando actualizacion de componentes base...',
2147
+ 'update.applyingCore': 'Aplicando actualizacion de archivos de core...',
2126
2148
  'update.applied': 'Feature {module} actualizada',
2127
2149
  'update.appliedComponents': '{count} archivos de componentes base actualizados',
2150
+ 'update.appliedCore': '{count} archivos de core actualizados',
2128
2151
  'update.applyFailed': 'Error al aplicar actualizacion de la feature {module}',
2129
2152
  'update.applyComponentsFailed': 'Error al aplicar actualizacion de componentes base',
2130
2153
  'update.noPatch': 'La feature "{module}" no tiene archivos para actualizar (feature solo de configuracion).',
@@ -2137,6 +2160,7 @@ const MESSAGES = {
2137
2160
  'update.buildRunnerFailed': 'build_runner fallo — ejecutalo manualmente',
2138
2161
  'update.success': 'Feature "{module}" actualizada exitosamente.',
2139
2162
  'update.componentsSuccess': 'Componentes base actualizados exitosamente.',
2163
+ 'update.coreSuccess': 'Archivos de core actualizados exitosamente.',
2140
2164
  }
2141
2165
  };
2142
2166
 
@@ -4,6 +4,7 @@ const https = require('node:https');
4
4
  const path = require('node:path');
5
5
  const { existsSync, readJsonSync, writeJsonSync, ensureDirSync } = require('fs-extra');
6
6
  const kleur = require('kleur');
7
+ const prompts = require('prompts');
7
8
  const pkg = require('../../package.json');
8
9
  const { CONFIG_PATH } = require('./license');
9
10
 
@@ -94,4 +95,42 @@ async function checkForUpdates() {
94
95
  }
95
96
  }
96
97
 
97
- module.exports = { checkForUpdates };
98
+ /**
99
+ * Chamado antes de kasy new. Se houver versão mais nova no cache,
100
+ * mostra aviso e pergunta se quer continuar ou sair para atualizar.
101
+ * Nunca bloqueia — se o usuário ignorar, o fluxo segue normalmente.
102
+ */
103
+ async function warnIfOutdatedBeforeNew(t) {
104
+ try {
105
+ const cache = (readConfig().updateCheck) || {};
106
+ if (!cache.latestVersion || !isNewer(cache.latestVersion, pkg.version)) return;
107
+
108
+ console.log('');
109
+ console.log(
110
+ kleur.bgYellow().black(' VERSÃO DESATUALIZADA ') + ' ' +
111
+ kleur.bold(`v${cache.latestVersion} disponível`) +
112
+ kleur.dim(` (você tem v${pkg.version})`)
113
+ );
114
+ console.log(kleur.dim(' Projetos novos são criados com a versão que você tem instalada.'));
115
+ console.log(kleur.dim(' Para criar com a versão mais recente: ') + kleur.cyan('kasy upgrade') + kleur.dim(' (requer assinatura ativa)'));
116
+ console.log('');
117
+
118
+ const { proceed } = await prompts({
119
+ type: 'confirm',
120
+ name: 'proceed',
121
+ message: t ? t('new.outdated.continueAnyway') : 'Continuar com a versão atual?',
122
+ initial: true,
123
+ });
124
+
125
+ if (proceed === false) {
126
+ console.log('');
127
+ console.log(kleur.cyan(' kasy upgrade'));
128
+ console.log('');
129
+ process.exit(0);
130
+ }
131
+ } catch {
132
+ // Nunca travar o kasy new por causa do aviso de versão
133
+ }
134
+ }
135
+
136
+ module.exports = { checkForUpdates, warnIfOutdatedBeforeNew };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kasy-cli",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
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"