kasy-cli 1.10.0 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/kasy.js CHANGED
@@ -242,14 +242,15 @@ function buildProgram(language) {
242
242
  const langName = t('cli.command.setup.langName');
243
243
  applyLocalizedHelp(
244
244
  program
245
- .command('setup')
245
+ .command('setup', { hidden: true })
246
246
  .argument(`[${directoryName}]`, t('cli.command.setup.directoryArg'), '.')
247
247
  .option(`-l, --lang <${langName}>`, t('cli.command.setup.langOption'))
248
248
  .option('-b, --backend <backend>', t('cli.command.setup.backendOption'))
249
249
  .option('--with <features>', t('cli.command.setup.featuresOption'))
250
250
  .description(t('cli.command.setup.description'))
251
251
  .action(async (directory, options) => {
252
- // `setup` is an alias for `new` — unified flow
252
+ // `setup` is an alias for `new` — unified flow.
253
+ // Hidden from root help to reduce noise; still callable.
253
254
  await runNew(directory, {
254
255
  language: options.lang,
255
256
  backend: options.backend,
@@ -516,7 +517,6 @@ function buildProgram(language) {
516
517
  notificationsCmd
517
518
  .command('text')
518
519
  .argument('[directory]', 'Project folder (default: current directory)', '.')
519
- .option('-d, --directory <path>', 'Project folder (default: current directory)')
520
520
  .option('--locale <code>', 'i18n files to update: pt, en, es, or all (default: all)', 'all')
521
521
  .option('--demo-title <text>', 'Home → Features demo notification title')
522
522
  .option('--demo-body <text>', 'Home → Features demo card description / instant notification body')
@@ -524,7 +524,7 @@ function buildProgram(language) {
524
524
  .option('--reminder-body <text>', 'Scheduled reminder notification body')
525
525
  .description(t('cli.command.notifications.text.description'))
526
526
  .action(async (directory, options) => {
527
- const dir = options.directory || directory || '.';
527
+ const dir = directory || '.';
528
528
  await runNotificationsText(dir, {
529
529
  language,
530
530
  directory: dir,
@@ -110,67 +110,67 @@ async function runCheck(options = {}) {
110
110
  const t = createTranslator(lang);
111
111
 
112
112
  printCompactHeader(t);
113
- ui.intro('Kasy Check — Push Notifications');
113
+ ui.intro(t('check.intro'));
114
114
 
115
115
  // ── Detect backend ────────────────────────────────────────────────────────
116
116
  const isFirebase = await fs.pathExists(path.join(projectDir, 'firebase.json'));
117
117
  const isSupabase = await fs.pathExists(path.join(projectDir, 'supabase'));
118
118
 
119
119
  if (isFirebase && !isSupabase) {
120
- ok('Firebase backend');
121
- info('Firebase usa Application Default Credentials — nenhuma configuração extra necessária.');
120
+ ok(t('check.firebase.detected'));
121
+ info(t('check.firebase.adcInfo'));
122
122
  const firebaseProjectId = await readFirebaseProjectId(projectDir);
123
123
  const apnsLines = [
124
- kleur.yellow('Push iOS requer APNs Key (não verificável via CLI)'),
125
- kleur.dim('Firebase Console → Cloud Messaging → app iOS → Chave de autenticação APNs'),
124
+ kleur.yellow(t('check.apns.warn')),
125
+ kleur.dim(t('check.apns.where')),
126
126
  ];
127
127
  if (firebaseProjectId) {
128
128
  apnsLines.push(kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`));
129
129
  }
130
130
  ui.note(apnsLines.join('\n'));
131
- ui.outro('Done');
131
+ ui.outro(t('check.done'));
132
132
  return;
133
133
  }
134
134
 
135
135
  if (!isSupabase) {
136
- ui.log.error('Diretório não parece ser um projeto Kasy.');
137
- ui.cancel('Aborted');
136
+ ui.log.error(t('check.notKasy'));
137
+ ui.cancel(t('check.aborted'));
138
138
  process.exit(1);
139
139
  }
140
140
 
141
141
  // ── 1. Project linked? ────────────────────────────────────────────────────
142
142
  const projectRef = await readProjectRef(projectDir);
143
143
  if (!projectRef) {
144
- fail('Projeto Supabase não vinculado', 'execute: supabase link --project-ref SEU_REF');
145
- ui.cancel('Aborted');
144
+ fail(t('check.supabase.notLinked'), t('check.supabase.notLinkedHint'));
145
+ ui.cancel(t('check.aborted'));
146
146
  process.exit(1);
147
147
  }
148
- ok('Projeto vinculado', projectRef);
148
+ ok(t('check.supabase.linked'), projectRef);
149
149
 
150
150
  // ── Read secrets list ─────────────────────────────────────────────────────
151
151
  const spinner = ui.spinner();
152
- spinner.start('Verificando secrets');
152
+ spinner.start(t('check.spin.secrets'));
153
153
  const secrets = await listSecretNames(projectDir);
154
- spinner.stop('Secrets verificados');
154
+ spinner.stop(t('check.spin.secretsDone'));
155
155
 
156
156
  if (!secrets) {
157
- warn('Não foi possível listar secrets', 'verifique: supabase login');
157
+ warn(t('check.secrets.listFailed'), t('check.secrets.checkLogin'));
158
158
  }
159
159
 
160
160
  // ── 2. FIREBASE_PROJECT_ID ────────────────────────────────────────────────
161
161
  const firebaseProjectId = await readFirebaseProjectId(projectDir);
162
162
  if (secrets) {
163
163
  if (secrets.has('FIREBASE_PROJECT_ID')) {
164
- ok('FIREBASE_PROJECT_ID configurado');
164
+ ok(t('check.fbProjId.ok'));
165
165
  } else {
166
- fail('FIREBASE_PROJECT_ID ausente');
166
+ fail(t('check.fbProjId.missing'));
167
167
  if (firebaseProjectId) {
168
- ui.log.message(kleur.gray(`Corrija: supabase secrets set FIREBASE_PROJECT_ID="${firebaseProjectId}"`));
168
+ ui.log.message(kleur.gray(t('check.fbProjId.fixHint', { id: firebaseProjectId })));
169
169
  if (options.fix) {
170
170
  const r = await runCmd(`supabase secrets set FIREBASE_PROJECT_ID="${firebaseProjectId}"`, projectDir);
171
171
  r.ok
172
- ? ok('FIREBASE_PROJECT_ID → configurado automaticamente')
173
- : fail('FIREBASE_PROJECT_ID → falhou ao configurar', r.error);
172
+ ? ok(t('check.fbProjId.fixed'))
173
+ : fail(t('check.fbProjId.fixFailed'), r.error);
174
174
  }
175
175
  }
176
176
  }
@@ -179,15 +179,15 @@ async function runCheck(options = {}) {
179
179
  // ── 3. FIREBASE_SERVICE_ACCOUNT_JSON ─────────────────────────────────────
180
180
  if (secrets) {
181
181
  if (secrets.has('FIREBASE_SERVICE_ACCOUNT_JSON')) {
182
- ok('FIREBASE_SERVICE_ACCOUNT_JSON configurado');
182
+ ok(t('check.fbSak.ok'));
183
183
  } else {
184
- fail('FIREBASE_SERVICE_ACCOUNT_JSON ausente');
184
+ fail(t('check.fbSak.missing'));
185
185
 
186
186
  if (options.fix && firebaseProjectId) {
187
187
  const fixSpinner = ui.spinner();
188
- fixSpinner.start('Gerando e configurando chave FCM…');
188
+ fixSpinner.start(t('check.fbSak.spin'));
189
189
  const fcmResult = await createFcmServiceAccountKey(firebaseProjectId);
190
- fixSpinner.stop('Chave FCM gerada');
190
+ fixSpinner.stop(t('check.fbSak.spinDone'));
191
191
 
192
192
  if (fcmResult.ok) {
193
193
  const secretSteps = await setSupabaseSecrets(projectDir, {
@@ -196,62 +196,52 @@ async function runCheck(options = {}) {
196
196
  });
197
197
  const setStep = secretSteps.find((s) => s.name === 'secret FIREBASE_SERVICE_ACCOUNT_JSON');
198
198
  setStep?.ok
199
- ? ok('FIREBASE_SERVICE_ACCOUNT_JSON → configurado automaticamente')
200
- : fail('FIREBASE_SERVICE_ACCOUNT_JSON → falhou ao configurar', setStep?.error);
199
+ ? ok(t('check.fbSak.fixed'))
200
+ : fail(t('check.fbSak.fixFailed'), setStep?.error);
201
201
  } else {
202
- fail('FIREBASE_SERVICE_ACCOUNT_JSON → não foi possível gerar chave', fcmResult.error);
203
- ui.log.message(kleur.gray(
204
- 'Manual: Firebase Console → Configurações → Contas de serviço → Gerar chave\n' +
205
- "Depois: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat chave.json)'"
206
- ));
202
+ fail(t('check.fbSak.genFailed'), fcmResult.error);
203
+ ui.log.message(kleur.gray(t('check.fbSak.manual')));
207
204
  }
208
205
  } else {
209
- ui.log.message(kleur.gray(
210
- 'Corrija automaticamente: kasy check --fix\n' +
211
- 'Ou manualmente: Firebase Console → Configurações → Contas de serviço → Gerar chave\n' +
212
- "Depois: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat chave.json)'"
213
- ));
206
+ ui.log.message(kleur.gray(t('check.fbSak.hint')));
214
207
  }
215
208
  }
216
209
  }
217
210
 
218
211
  // ── 4. Edge function send-push-notification ────────────────────────────────
219
212
  const fnSpinner = ui.spinner();
220
- fnSpinner.start('Verificando edge functions…');
213
+ fnSpinner.start(t('check.fn.spin'));
221
214
  const functions = await listDeployedFunctions(projectDir);
222
- fnSpinner.stop('Edge functions verificadas');
215
+ fnSpinner.stop(t('check.fn.spinDone'));
223
216
 
224
217
  if (!functions) {
225
- warn('Não foi possível listar edge functions', 'verifique: supabase login');
218
+ warn(t('check.fn.listFailed'), t('check.secrets.checkLogin'));
226
219
  } else if (functions.has('send-push-notification')) {
227
- ok('Edge function send-push-notification deployada');
220
+ ok(t('check.fn.deployed'));
228
221
  } else {
229
- fail('Edge function send-push-notification não deployada');
222
+ fail(t('check.fn.missing'));
230
223
  if (options.fix) {
231
224
  const deploySpinner = ui.spinner();
232
- deploySpinner.start('Publicando send-push-notification…');
225
+ deploySpinner.start(t('check.fn.deploySpin'));
233
226
  const r = await runCmd('supabase functions deploy send-push-notification', projectDir);
234
227
  r.ok
235
- ? deploySpinner.stop('send-push-notification → deployada automaticamente')
236
- : deploySpinner.error(`send-push-notification → falhou no deploy${r.error ? ` — ${r.error}` : ''}`);
228
+ ? deploySpinner.stop(t('check.fn.deployDone'))
229
+ : deploySpinner.error(`${t('check.fn.deployFailed')}${r.error ? ` — ${r.error}` : ''}`);
237
230
  } else {
238
- ui.log.message(kleur.gray(
239
- 'Corrija automaticamente: kasy check --fix\n' +
240
- 'Ou manualmente: supabase functions deploy send-push-notification'
241
- ));
231
+ ui.log.message(kleur.gray(t('check.fn.hint')));
242
232
  }
243
233
  }
244
234
 
245
235
  // ── 5. APNs reminder ─────────────────────────────────────────────────────
246
236
  const apnsLines = [
247
- kleur.yellow('Push iOS requer APNs Key (não verificável via CLI)'),
248
- kleur.dim('Firebase Console → Cloud Messaging → app iOS → Chave de autenticação APNs'),
237
+ kleur.yellow(t('check.apns.warn')),
238
+ kleur.dim(t('check.apns.where')),
249
239
  ];
250
240
  if (firebaseProjectId) {
251
241
  apnsLines.push(kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`));
252
242
  }
253
243
  ui.note(apnsLines.join('\n'));
254
- ui.outro('Done');
244
+ ui.outro(t('check.done'));
255
245
  }
256
246
 
257
247
  module.exports = { runCheck };
@@ -123,14 +123,14 @@ async function deployFirebase(projectDir, options, tr) {
123
123
  }
124
124
 
125
125
  const spinner = ui.spinner();
126
- spinner.start('Deploying Firebase...');
126
+ spinner.start(tr('deploy.firebase.spin'));
127
127
  let steps;
128
128
  try {
129
129
  steps = await runFirebaseDeploy(projectDir, null, firebaseProjectId, {
130
130
  functionsRegion,
131
131
  onProgress: (key) => { spinner.message(String(key)); },
132
132
  });
133
- spinner.stop('Firebase deploy completed');
133
+ spinner.stop(tr('deploy.firebase.spinDone'));
134
134
  } catch (err) {
135
135
  spinner.error(err.message);
136
136
  throw err;
@@ -145,9 +145,9 @@ async function deployFirebase(projectDir, options, tr) {
145
145
  // ── APNs reminder — required for iOS push notifications ──────────────────
146
146
  // Cannot be automated: the .p8 key only exists in Apple Developer Portal.
147
147
  const apnsBody = [
148
- kleur.yellow('Push iOS: configure a APNs Key no Firebase Console'),
149
- kleur.dim('1. Apple Developer Portal → Keys → criar APNs Key (.p8)'),
150
- kleur.dim('2. Firebase Console → Cloud Messaging → app iOS → upload da APNs Key'),
148
+ kleur.yellow(tr('deploy.apns.title')),
149
+ kleur.dim(tr('deploy.apns.step1')),
150
+ kleur.dim(tr('deploy.apns.step2')),
151
151
  kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`),
152
152
  ].join('\n');
153
153
  ui.note(apnsBody);
@@ -155,28 +155,28 @@ async function deployFirebase(projectDir, options, tr) {
155
155
 
156
156
  // ── Supabase deploy ───────────────────────────────────────────────────────────
157
157
 
158
- async function deploySupabase(projectDir) {
158
+ async function deploySupabase(projectDir, tr) {
159
159
  // ── 1. Get project ref ──────────────────────────────────────────────────
160
160
  const projectRef = await readSupabaseProjectRef(projectDir);
161
161
  if (!projectRef) {
162
- ui.log.error('Projeto Supabase não está vinculado neste diretório.');
163
- ui.log.message(kleur.gray('Execute: supabase link --project-ref SEU_PROJECT_REF'));
162
+ ui.log.error(tr('deploy.supabase.notLinked'));
163
+ ui.log.message(kleur.gray(tr('deploy.supabase.linkHint')));
164
164
  process.exit(1);
165
165
  }
166
- ui.log.message(kleur.gray(`Project ref: ${kleur.cyan(projectRef)}`));
166
+ ui.log.message(kleur.gray(tr('deploy.supabase.projectRef', { ref: kleur.cyan(projectRef) })));
167
167
 
168
168
  // ── 2. FCM Service Account JSON ─────────────────────────────────────────
169
169
  const alreadySet = await isServiceAccountJsonSet(projectDir);
170
170
  if (alreadySet) {
171
- printStep(true, false, 'FIREBASE_SERVICE_ACCOUNT_JSON já configurado');
171
+ printStep(true, false, tr('deploy.supabase.sakAlready'));
172
172
  } else {
173
173
  const firebaseProjectId = await readFirebaseProjectId(projectDir);
174
174
 
175
175
  if (firebaseProjectId) {
176
176
  const fcmSpinner = ui.spinner();
177
- fcmSpinner.start('Gerando chave FCM (Service Account)…');
177
+ fcmSpinner.start(tr('deploy.supabase.sakSpin'));
178
178
  const fcmResult = await createFcmServiceAccountKey(firebaseProjectId);
179
- fcmSpinner.stop('Chave FCM gerada');
179
+ fcmSpinner.stop(tr('deploy.supabase.sakSpinDone'));
180
180
 
181
181
  if (fcmResult.ok) {
182
182
  const secretSteps = await setSupabaseSecrets(projectDir, {
@@ -186,23 +186,23 @@ async function deploySupabase(projectDir) {
186
186
  for (const s of secretSteps) printStep(s.ok, false, s.name, s.error);
187
187
  } else {
188
188
  printStep(false, false, 'FIREBASE_SERVICE_ACCOUNT_JSON', fcmResult.error);
189
- ui.log.warn("Configure manualmente: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='...'");
189
+ ui.log.warn(tr('deploy.supabase.sakManual'));
190
190
  }
191
191
  } else {
192
- printStep(false, false, 'FIREBASE_SERVICE_ACCOUNT_JSON', 'google-services.json não encontrado — configure manualmente');
192
+ printStep(false, false, 'FIREBASE_SERVICE_ACCOUNT_JSON', tr('deploy.supabase.sakNoGS'));
193
193
  }
194
194
  }
195
195
 
196
196
  // ── 3. Deploy edge functions ────────────────────────────────────────────
197
197
  const fnSpinner = ui.spinner();
198
- fnSpinner.start('Publicando edge functions…');
198
+ fnSpinner.start(tr('deploy.supabase.fnSpin'));
199
199
  const fnResult = await deployFunctions(projectDir);
200
- fnSpinner.stop('Edge functions processadas');
200
+ fnSpinner.stop(tr('deploy.supabase.fnSpinDone'));
201
201
 
202
202
  if (Array.isArray(fnResult)) {
203
203
  fnResult.forEach((s) => printStep(s.ok, s.skipped, s.name, s.error));
204
204
  } else if (fnResult.skipped) {
205
- printStep(true, true, 'edge functions (nenhuma encontrada)');
205
+ printStep(true, true, tr('deploy.supabase.fnNone'));
206
206
  } else {
207
207
  printStep(fnResult.ok, false, 'supabase functions deploy', fnResult.error);
208
208
  }
@@ -210,9 +210,9 @@ async function deploySupabase(projectDir) {
210
210
  // ── 4. APNs reminder ────────────────────────────────────────────────────
211
211
  const firebaseProjectId = await readFirebaseProjectId(projectDir);
212
212
  const apnsLines = [
213
- kleur.yellow('Push iOS: configure a APNs Key no Firebase Console'),
214
- kleur.dim('1. Apple Developer Portal → Keys → criar APNs Key (.p8)'),
215
- kleur.dim('2. Firebase Console → Cloud Messaging → app iOS → upload da APNs Key'),
213
+ kleur.yellow(tr('deploy.apns.title')),
214
+ kleur.dim(tr('deploy.apns.step1')),
215
+ kleur.dim(tr('deploy.apns.step2')),
216
216
  ];
217
217
  if (firebaseProjectId) {
218
218
  apnsLines.push(kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`));
@@ -240,17 +240,17 @@ async function runDeployCommand(directory, options = {}, { language: langHint }
240
240
 
241
241
  if (isFirebase) {
242
242
  printCompactHeader(tr);
243
- ui.intro('Deploy — Firebase');
243
+ ui.intro(tr('deploy.firebase.intro'));
244
244
  await deployFirebase(projectDir, options, tr);
245
- ui.outro('Deploy concluído');
245
+ ui.outro(tr('deploy.outro'));
246
246
  return;
247
247
  }
248
248
 
249
249
  if (isSupabase) {
250
250
  printCompactHeader(tr);
251
- ui.intro('Deploy — Supabase');
252
- await deploySupabase(projectDir);
253
- ui.outro('Deploy concluído');
251
+ ui.intro(tr('deploy.supabase.intro'));
252
+ await deploySupabase(projectDir, tr);
253
+ ui.outro(tr('deploy.outro'));
254
254
  return;
255
255
  }
256
256
 
package/lib/utils/i18n.js CHANGED
@@ -59,7 +59,7 @@ const MESSAGES = {
59
59
  'new.checks.environment.done': 'Environment ready',
60
60
  'setup.checks.backend.checking': 'Checking {backend} tools',
61
61
  'setup.checks.backend.done': '{backend} tools ready',
62
- 'new.checks.firebaseForPush': 'Note: Firebase CLI is required for push notifications (FCM) on all backends.',
62
+ 'new.checks.firebaseForPush': 'Note: Firebase CLI is required for push notifications (Firebase Cloud Messaging / FCM) on all backends.',
63
63
  'new.checks.requiredBlock': 'Required tools are missing. Install them to continue.',
64
64
  'new.checks.installFirebase': 'Firebase: npm i -g firebase-tools && firebase login. FlutterFire: dart pub global activate flutterfire_cli',
65
65
  'new.checks.installSupabase': 'Supabase: npm i -g supabase (or brew install supabase/tap/supabase) && supabase login',
@@ -578,7 +578,7 @@ const MESSAGES = {
578
578
  'new.success.step.run': 'Run your app (with your configured keys):',
579
579
  'new.success.step.run.vscode': '(or F5 in VS Code)',
580
580
  'new.success.step.console': 'Open your backend console:',
581
- 'new.fcm.generating': 'Generating FCM Service Account key…',
581
+ 'new.fcm.generating': 'Generating push notifications key (Firebase Service Account)…',
582
582
  'new.sha1.registering': 'Registering SHA-1 for Google Sign-In (Android)…',
583
583
  'new.sha1.failed': 'SHA-1 not added automatically: {error}',
584
584
  'new.sha1.manual': 'Add it manually so Google Sign-In works on Android:',
@@ -654,15 +654,15 @@ const MESSAGES = {
654
654
  'add.error.unknownModule': 'Unknown feature: {module}\nAvailable: {list}',
655
655
  'add.alreadyActive': 'Feature "{module}" is already active in this project.',
656
656
  'add.applying': 'Adding feature: {module}',
657
- 'add.applyingPatch': 'Applying patch files...',
657
+ 'add.applyingPatch': 'Applying feature changes...',
658
658
  'add.patchApplied': 'Patch applied',
659
659
  'add.patchFailed': 'Patch failed — check the output above',
660
- 'add.pubGet': 'Running flutter pub get...',
660
+ 'add.pubGet': 'Installing Flutter packages (flutter pub get)...',
661
661
  'add.pubGetDone': 'Dependencies updated',
662
- 'add.pubGetFailed': 'flutter pub get failed — run it manually',
663
- 'add.buildRunner': 'Running build_runner...',
662
+ 'add.pubGetFailed': 'Failed to install Flutter packages — run `flutter pub get` manually',
663
+ 'add.buildRunner': 'Generating code (Riverpod/Freezed)...',
664
664
  'add.buildRunnerDone': 'Code generation complete',
665
- 'add.buildRunnerFailed': 'build_runner failed — run it manually',
665
+ 'add.buildRunnerFailed': 'Code generation failed — run `dart run build_runner build` manually',
666
666
  'add.success': 'Feature "{module}" added successfully.',
667
667
  'add.cancelled': 'Cancelled.',
668
668
  'add.prompt.sentryDsn': 'Sentry DSN (leave blank to configure later):',
@@ -697,12 +697,12 @@ const MESSAGES = {
697
697
  'remove.confirm': 'Remove feature "{module}"? This will delete files and dependencies.',
698
698
  'remove.cancelled': 'Cancelled.',
699
699
  'remove.removing': 'Removing feature: {module}',
700
- 'remove.pubGet': 'Running flutter pub get...',
700
+ 'remove.pubGet': 'Installing Flutter packages (flutter pub get)...',
701
701
  'remove.pubGetDone': 'Dependencies updated',
702
- 'remove.pubGetFailed': 'flutter pub get failed — run it manually',
703
- 'remove.buildRunner': 'Running build_runner...',
702
+ 'remove.pubGetFailed': 'Failed to install Flutter packages — run `flutter pub get` manually',
703
+ 'remove.buildRunner': 'Generating code (Riverpod/Freezed)...',
704
704
  'remove.buildRunnerDone': 'Code generation complete',
705
- 'remove.buildRunnerFailed': 'build_runner failed — run it manually',
705
+ 'remove.buildRunnerFailed': 'Code generation failed — run `dart run build_runner build` manually',
706
706
  'remove.success': 'Feature "{module}" removed successfully.',
707
707
  'remove.warn.ci': 'CI files removed. If you had custom workflow files, restore them from git.',
708
708
  'remove.warn.sentry.shared': 'sentry_flutter kept — still required by active features (revenuecat/facebook).',
@@ -735,15 +735,72 @@ const MESSAGES = {
735
735
  'update.applyComponentsFailed': 'Failed to apply update for base components',
736
736
  'update.noPatch': 'Feature "{module}" has no files to update (configuration-only feature).',
737
737
  'update.noComponentFiles': 'No base component files were found to update.',
738
- 'update.pubGet': 'Running flutter pub get...',
738
+ 'update.pubGet': 'Installing Flutter packages (flutter pub get)...',
739
739
  'update.pubGetDone': 'Dependencies updated',
740
- 'update.pubGetFailed': 'flutter pub get failed — run it manually',
741
- 'update.buildRunner': 'Running build_runner...',
740
+ 'update.pubGetFailed': 'Failed to install Flutter packages — run `flutter pub get` manually',
741
+ 'update.buildRunner': 'Generating code (Riverpod/Freezed)...',
742
742
  'update.buildRunnerDone': 'Code generation complete',
743
- 'update.buildRunnerFailed': 'build_runner failed — run it manually',
743
+ 'update.buildRunnerFailed': 'Code generation failed — run `dart run build_runner build` manually',
744
744
  'update.success': 'Feature "{module}" updated successfully.',
745
745
  'update.componentsSuccess': 'Base components updated successfully.',
746
746
  'update.coreSuccess': 'Core files updated successfully.',
747
+ 'check.intro': 'Kasy Check — Push Notifications',
748
+ 'check.firebase.detected': 'Firebase backend',
749
+ 'check.firebase.adcInfo': 'Firebase uses Application Default Credentials — no extra setup needed.',
750
+ 'check.apns.warn': 'iOS push requires APNs Key (cannot be verified via CLI)',
751
+ 'check.apns.where': 'Firebase Console → Cloud Messaging → iOS app → APNs Authentication Key',
752
+ 'check.done': 'Done',
753
+ 'check.notKasy': 'This directory does not look like a Kasy project.',
754
+ 'check.aborted': 'Aborted',
755
+ 'check.supabase.notLinked': 'Supabase project not linked',
756
+ 'check.supabase.notLinkedHint': 'run: supabase link --project-ref YOUR_REF',
757
+ 'check.supabase.linked': 'Project linked',
758
+ 'check.spin.secrets': 'Checking secrets…',
759
+ 'check.spin.secretsDone': 'Secrets checked',
760
+ 'check.secrets.listFailed': 'Could not list secrets',
761
+ 'check.secrets.checkLogin': 'verify: supabase login',
762
+ 'check.fbProjId.ok': 'FIREBASE_PROJECT_ID configured',
763
+ 'check.fbProjId.missing': 'FIREBASE_PROJECT_ID missing',
764
+ 'check.fbProjId.fixHint': 'Fix: supabase secrets set FIREBASE_PROJECT_ID="{id}"',
765
+ 'check.fbProjId.fixed': 'FIREBASE_PROJECT_ID → set automatically',
766
+ 'check.fbProjId.fixFailed': 'FIREBASE_PROJECT_ID → failed to set',
767
+ 'check.fbSak.ok': 'FIREBASE_SERVICE_ACCOUNT_JSON configured',
768
+ 'check.fbSak.missing': 'FIREBASE_SERVICE_ACCOUNT_JSON missing',
769
+ 'check.fbSak.spin': 'Generating and setting FCM key…',
770
+ 'check.fbSak.spinDone': 'FCM key generated',
771
+ 'check.fbSak.fixed': 'FIREBASE_SERVICE_ACCOUNT_JSON → set automatically',
772
+ 'check.fbSak.fixFailed': 'FIREBASE_SERVICE_ACCOUNT_JSON → failed to set',
773
+ 'check.fbSak.genFailed': 'FIREBASE_SERVICE_ACCOUNT_JSON → could not generate key',
774
+ 'check.fbSak.manual': "Manual: Firebase Console → Settings → Service accounts → Generate key\nThen: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat key.json)'",
775
+ 'check.fbSak.hint': "Auto-fix: kasy check --fix\nOr manually: Firebase Console → Settings → Service accounts → Generate key\nThen: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat key.json)'",
776
+ 'check.fn.spin': 'Checking edge functions…',
777
+ 'check.fn.spinDone': 'Edge functions checked',
778
+ 'check.fn.listFailed': 'Could not list edge functions',
779
+ 'check.fn.deployed': 'Edge function send-push-notification deployed',
780
+ 'check.fn.missing': 'Edge function send-push-notification not deployed',
781
+ 'check.fn.deploySpin': 'Deploying send-push-notification…',
782
+ 'check.fn.deployDone': 'send-push-notification → deployed automatically',
783
+ 'check.fn.deployFailed': 'send-push-notification → deploy failed',
784
+ 'check.fn.hint': 'Auto-fix: kasy check --fix\nOr manually: supabase functions deploy send-push-notification',
785
+ 'deploy.firebase.intro': 'Deploy — Firebase',
786
+ 'deploy.firebase.spin': 'Deploying Firebase...',
787
+ 'deploy.firebase.spinDone': 'Firebase deploy completed',
788
+ 'deploy.apns.title': 'iOS push: configure the APNs Key in Firebase Console',
789
+ 'deploy.apns.step1': '1. Apple Developer Portal → Keys → create APNs Key (.p8)',
790
+ 'deploy.apns.step2': '2. Firebase Console → Cloud Messaging → iOS app → upload APNs Key',
791
+ 'deploy.supabase.intro': 'Deploy — Supabase',
792
+ 'deploy.supabase.notLinked': 'Supabase project not linked in this directory.',
793
+ 'deploy.supabase.linkHint': 'Run: supabase link --project-ref YOUR_PROJECT_REF',
794
+ 'deploy.supabase.projectRef': 'Project ref: {ref}',
795
+ 'deploy.supabase.sakAlready': 'FIREBASE_SERVICE_ACCOUNT_JSON already configured',
796
+ 'deploy.supabase.sakSpin': 'Generating FCM key (Service Account)…',
797
+ 'deploy.supabase.sakSpinDone': 'FCM key generated',
798
+ 'deploy.supabase.sakManual': "Configure manually: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='...'",
799
+ 'deploy.supabase.sakNoGS': 'google-services.json not found — configure manually',
800
+ 'deploy.supabase.fnSpin': 'Deploying edge functions…',
801
+ 'deploy.supabase.fnSpinDone': 'Edge functions processed',
802
+ 'deploy.supabase.fnNone': 'edge functions (none found)',
803
+ 'deploy.outro': 'Deploy completed',
747
804
  },
748
805
  pt: {
749
806
  'cli.tagline': 'Crie apps móveis sem dor de configuração',
@@ -799,7 +856,7 @@ const MESSAGES = {
799
856
  'new.checks.environment.done': 'Ambiente pronto',
800
857
  'setup.checks.backend.checking': 'Verificando ferramentas {backend}',
801
858
  'setup.checks.backend.done': 'Ferramentas {backend} prontas',
802
- 'new.checks.firebaseForPush': 'Atenção: Firebase CLI é obrigatório para notificações push (FCM) em todos os backends.',
859
+ 'new.checks.firebaseForPush': 'Atenção: Firebase CLI é obrigatório para notificações push (Firebase Cloud Messaging / FCM) em todos os backends.',
803
860
  'new.checks.requiredBlock': 'Ferramentas obrigatórias não encontradas. Instale-as para continuar.',
804
861
  'new.checks.installFirebase': 'Firebase: npm i -g firebase-tools && firebase login. FlutterFire: dart pub global activate flutterfire_cli',
805
862
  'new.checks.installSupabase': 'Supabase: npm i -g supabase (ou brew install supabase/tap/supabase) && supabase login',
@@ -1394,15 +1451,15 @@ const MESSAGES = {
1394
1451
  'add.error.unknownModule': 'Feature desconhecida: {module}\nDisponiveis: {list}',
1395
1452
  'add.alreadyActive': 'A feature "{module}" já está ativa neste projeto.',
1396
1453
  'add.applying': 'Adicionando feature: {module}',
1397
- 'add.applyingPatch': 'Aplicando arquivos de patch...',
1454
+ 'add.applyingPatch': 'Aplicando mudanças da feature...',
1398
1455
  'add.patchApplied': 'Patch aplicado',
1399
1456
  'add.patchFailed': 'Patch falhou — verifique a saída acima',
1400
- 'add.pubGet': 'Executando flutter pub get...',
1457
+ 'add.pubGet': 'Instalando pacotes do Flutter (flutter pub get)...',
1401
1458
  'add.pubGetDone': 'Dependencias atualizadas',
1402
- 'add.pubGetFailed': 'flutter pub get falhou — execute manualmente',
1403
- 'add.buildRunner': 'Executando build_runner...',
1459
+ 'add.pubGetFailed': 'Falha ao instalar pacotes do Flutter — execute `flutter pub get` manualmente',
1460
+ 'add.buildRunner': 'Gerando código (Riverpod/Freezed)...',
1404
1461
  'add.buildRunnerDone': 'Geração de código concluída',
1405
- 'add.buildRunnerFailed': 'build_runner falhou — execute manualmente',
1462
+ 'add.buildRunnerFailed': 'Geração de código falhou — execute `dart run build_runner build` manualmente',
1406
1463
  'add.success': 'Feature "{module}" adicionada com sucesso.',
1407
1464
  'add.cancelled': 'Cancelado.',
1408
1465
  'add.prompt.sentryDsn': 'Sentry DSN (deixe em branco para configurar depois):',
@@ -1437,12 +1494,12 @@ const MESSAGES = {
1437
1494
  'remove.confirm': 'Remover a feature "{module}"? Isso vai deletar arquivos e dependências.',
1438
1495
  'remove.cancelled': 'Cancelado.',
1439
1496
  'remove.removing': 'Removendo feature: {module}',
1440
- 'remove.pubGet': 'Executando flutter pub get...',
1497
+ 'remove.pubGet': 'Instalando pacotes do Flutter (flutter pub get)...',
1441
1498
  'remove.pubGetDone': 'Dependencias atualizadas',
1442
- 'remove.pubGetFailed': 'flutter pub get falhou — execute manualmente',
1443
- 'remove.buildRunner': 'Executando build_runner...',
1499
+ 'remove.pubGetFailed': 'Falha ao instalar pacotes do Flutter — execute `flutter pub get` manualmente',
1500
+ 'remove.buildRunner': 'Gerando código (Riverpod/Freezed)...',
1444
1501
  'remove.buildRunnerDone': 'Geração de código concluída',
1445
- 'remove.buildRunnerFailed': 'build_runner falhou — execute manualmente',
1502
+ 'remove.buildRunnerFailed': 'Geração de código falhou — execute `dart run build_runner build` manualmente',
1446
1503
  'remove.success': 'Feature "{module}" removida com sucesso.',
1447
1504
  'remove.warn.ci': 'Arquivos de CI removidos. Se tinha workflows customizados, restaure-os pelo git.',
1448
1505
  'remove.warn.sentry.shared': 'sentry_flutter mantido — ainda necessário para features ativas (revenuecat/facebook).',
@@ -1475,15 +1532,72 @@ const MESSAGES = {
1475
1532
  'update.applyComponentsFailed': 'Falha ao aplicar atualização dos componentes base',
1476
1533
  'update.noPatch': 'Feature "{module}" não tem arquivos para atualizar (feature so de configuração).',
1477
1534
  'update.noComponentFiles': 'Nenhum arquivo de componente base foi encontrado para atualizar.',
1478
- 'update.pubGet': 'Executando flutter pub get...',
1535
+ 'update.pubGet': 'Instalando pacotes do Flutter (flutter pub get)...',
1479
1536
  'update.pubGetDone': 'Dependencias atualizadas',
1480
- 'update.pubGetFailed': 'flutter pub get falhou — execute manualmente',
1481
- 'update.buildRunner': 'Executando build_runner...',
1537
+ 'update.pubGetFailed': 'Falha ao instalar pacotes do Flutter — execute `flutter pub get` manualmente',
1538
+ 'update.buildRunner': 'Gerando código (Riverpod/Freezed)...',
1482
1539
  'update.buildRunnerDone': 'Geração de código concluída',
1483
- 'update.buildRunnerFailed': 'build_runner falhou — execute manualmente',
1540
+ 'update.buildRunnerFailed': 'Geração de código falhou — execute `dart run build_runner build` manualmente',
1484
1541
  'update.success': 'Feature "{module}" atualizada com sucesso.',
1485
1542
  'update.componentsSuccess': 'Componentes base atualizados com sucesso.',
1486
1543
  'update.coreSuccess': 'Arquivos de core atualizados com sucesso.',
1544
+ 'check.intro': 'Kasy Check — Notificações Push',
1545
+ 'check.firebase.detected': 'Backend Firebase',
1546
+ 'check.firebase.adcInfo': 'Firebase usa Application Default Credentials — nenhuma configuração extra necessária.',
1547
+ 'check.apns.warn': 'Push iOS requer APNs Key (não verificável via CLI)',
1548
+ 'check.apns.where': 'Firebase Console → Cloud Messaging → app iOS → Chave de autenticação APNs',
1549
+ 'check.done': 'Pronto',
1550
+ 'check.notKasy': 'Esse diretório não parece ser um projeto Kasy.',
1551
+ 'check.aborted': 'Cancelado',
1552
+ 'check.supabase.notLinked': 'Projeto Supabase não vinculado',
1553
+ 'check.supabase.notLinkedHint': 'execute: supabase link --project-ref SEU_REF',
1554
+ 'check.supabase.linked': 'Projeto vinculado',
1555
+ 'check.spin.secrets': 'Verificando secrets…',
1556
+ 'check.spin.secretsDone': 'Secrets verificados',
1557
+ 'check.secrets.listFailed': 'Não foi possível listar secrets',
1558
+ 'check.secrets.checkLogin': 'verifique: supabase login',
1559
+ 'check.fbProjId.ok': 'FIREBASE_PROJECT_ID configurado',
1560
+ 'check.fbProjId.missing': 'FIREBASE_PROJECT_ID ausente',
1561
+ 'check.fbProjId.fixHint': 'Corrija: supabase secrets set FIREBASE_PROJECT_ID="{id}"',
1562
+ 'check.fbProjId.fixed': 'FIREBASE_PROJECT_ID → configurado automaticamente',
1563
+ 'check.fbProjId.fixFailed': 'FIREBASE_PROJECT_ID → falhou ao configurar',
1564
+ 'check.fbSak.ok': 'FIREBASE_SERVICE_ACCOUNT_JSON configurado',
1565
+ 'check.fbSak.missing': 'FIREBASE_SERVICE_ACCOUNT_JSON ausente',
1566
+ 'check.fbSak.spin': 'Gerando e configurando chave FCM…',
1567
+ 'check.fbSak.spinDone': 'Chave FCM gerada',
1568
+ 'check.fbSak.fixed': 'FIREBASE_SERVICE_ACCOUNT_JSON → configurado automaticamente',
1569
+ 'check.fbSak.fixFailed': 'FIREBASE_SERVICE_ACCOUNT_JSON → falhou ao configurar',
1570
+ 'check.fbSak.genFailed': 'FIREBASE_SERVICE_ACCOUNT_JSON → não foi possível gerar chave',
1571
+ 'check.fbSak.manual': "Manual: Firebase Console → Configurações → Contas de serviço → Gerar chave\nDepois: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat chave.json)'",
1572
+ 'check.fbSak.hint': "Corrija automaticamente: kasy check --fix\nOu manualmente: Firebase Console → Configurações → Contas de serviço → Gerar chave\nDepois: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat chave.json)'",
1573
+ 'check.fn.spin': 'Verificando edge functions…',
1574
+ 'check.fn.spinDone': 'Edge functions verificadas',
1575
+ 'check.fn.listFailed': 'Não foi possível listar edge functions',
1576
+ 'check.fn.deployed': 'Edge function send-push-notification deployada',
1577
+ 'check.fn.missing': 'Edge function send-push-notification não deployada',
1578
+ 'check.fn.deploySpin': 'Publicando send-push-notification…',
1579
+ 'check.fn.deployDone': 'send-push-notification → deployada automaticamente',
1580
+ 'check.fn.deployFailed': 'send-push-notification → falhou no deploy',
1581
+ 'check.fn.hint': 'Corrija automaticamente: kasy check --fix\nOu manualmente: supabase functions deploy send-push-notification',
1582
+ 'deploy.firebase.intro': 'Deploy — Firebase',
1583
+ 'deploy.firebase.spin': 'Publicando no Firebase...',
1584
+ 'deploy.firebase.spinDone': 'Deploy do Firebase concluído',
1585
+ 'deploy.apns.title': 'Push iOS: configure a APNs Key no Firebase Console',
1586
+ 'deploy.apns.step1': '1. Apple Developer Portal → Keys → criar APNs Key (.p8)',
1587
+ 'deploy.apns.step2': '2. Firebase Console → Cloud Messaging → app iOS → upload da APNs Key',
1588
+ 'deploy.supabase.intro': 'Deploy — Supabase',
1589
+ 'deploy.supabase.notLinked': 'Projeto Supabase não está vinculado neste diretório.',
1590
+ 'deploy.supabase.linkHint': 'Execute: supabase link --project-ref SEU_PROJECT_REF',
1591
+ 'deploy.supabase.projectRef': 'Project ref: {ref}',
1592
+ 'deploy.supabase.sakAlready': 'FIREBASE_SERVICE_ACCOUNT_JSON já configurado',
1593
+ 'deploy.supabase.sakSpin': 'Gerando chave FCM (Service Account)…',
1594
+ 'deploy.supabase.sakSpinDone': 'Chave FCM gerada',
1595
+ 'deploy.supabase.sakManual': "Configure manualmente: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='...'",
1596
+ 'deploy.supabase.sakNoGS': 'google-services.json não encontrado — configure manualmente',
1597
+ 'deploy.supabase.fnSpin': 'Publicando edge functions…',
1598
+ 'deploy.supabase.fnSpinDone': 'Edge functions processadas',
1599
+ 'deploy.supabase.fnNone': 'edge functions (nenhuma encontrada)',
1600
+ 'deploy.outro': 'Deploy concluído',
1487
1601
  },
1488
1602
  es: {
1489
1603
  'cli.tagline': 'Crea apps móviles sin dolor de configuración',
@@ -1539,7 +1653,7 @@ const MESSAGES = {
1539
1653
  'new.checks.environment.done': 'Entorno listo',
1540
1654
  'setup.checks.backend.checking': 'Verificando herramientas {backend}',
1541
1655
  'setup.checks.backend.done': 'Herramientas {backend} listas',
1542
- 'new.checks.firebaseForPush': 'Nota: Firebase CLI es obligatorio para notificaciones push (FCM) en todos los backends.',
1656
+ 'new.checks.firebaseForPush': 'Nota: Firebase CLI es obligatorio para notificaciones push (Firebase Cloud Messaging / FCM) en todos los backends.',
1543
1657
  'new.checks.requiredBlock': 'Faltan herramientas obligatorias. Instalalas para continuar.',
1544
1658
  'new.checks.installFirebase': 'Firebase: npm i -g firebase-tools && firebase login. FlutterFire: dart pub global activate flutterfire_cli',
1545
1659
  'new.checks.installSupabase': 'Supabase: npm i -g supabase (o brew install supabase/tap/supabase) && supabase login',
@@ -2134,15 +2248,15 @@ const MESSAGES = {
2134
2248
  'add.error.unknownModule': 'Feature desconocida: {module}\nDisponibles: {list}',
2135
2249
  'add.alreadyActive': 'La feature "{module}" ya está activa en este proyecto.',
2136
2250
  'add.applying': 'Agregando feature: {module}',
2137
- 'add.applyingPatch': 'Aplicando archivos de patch...',
2251
+ 'add.applyingPatch': 'Aplicando cambios de la feature...',
2138
2252
  'add.patchApplied': 'Patch aplicado',
2139
2253
  'add.patchFailed': 'Patch fallo — revisa la salida anterior',
2140
- 'add.pubGet': 'Ejecutando flutter pub get...',
2254
+ 'add.pubGet': 'Instalando paquetes de Flutter (flutter pub get)...',
2141
2255
  'add.pubGetDone': 'Dependencias actualizadas',
2142
- 'add.pubGetFailed': 'flutter pub get falloejecutalo manualmente',
2143
- 'add.buildRunner': 'Ejecutando build_runner...',
2256
+ 'add.pubGetFailed': 'Falló al instalar paquetes de Flutter ejecuta `flutter pub get` manualmente',
2257
+ 'add.buildRunner': 'Generando código (Riverpod/Freezed)...',
2144
2258
  'add.buildRunnerDone': 'Generación de código completada',
2145
- 'add.buildRunnerFailed': 'build_runner falloejecutalo manualmente',
2259
+ 'add.buildRunnerFailed': 'Generación de código falló ejecuta `dart run build_runner build` manualmente',
2146
2260
  'add.success': 'Feature "{module}" agregada exitosamente.',
2147
2261
  'add.cancelled': 'Cancelado.',
2148
2262
  'add.prompt.sentryDsn': 'Sentry DSN (deja en blanco para configurar después):',
@@ -2177,12 +2291,12 @@ const MESSAGES = {
2177
2291
  'remove.confirm': 'Eliminar la feature "{module}"? Esto borrara archivos y dependencias.',
2178
2292
  'remove.cancelled': 'Cancelado.',
2179
2293
  'remove.removing': 'Eliminando feature: {module}',
2180
- 'remove.pubGet': 'Ejecutando flutter pub get...',
2294
+ 'remove.pubGet': 'Instalando paquetes de Flutter (flutter pub get)...',
2181
2295
  'remove.pubGetDone': 'Dependencias actualizadas',
2182
- 'remove.pubGetFailed': 'flutter pub get falloejecutalo manualmente',
2183
- 'remove.buildRunner': 'Ejecutando build_runner...',
2296
+ 'remove.pubGetFailed': 'Falló al instalar paquetes de Flutter ejecuta `flutter pub get` manualmente',
2297
+ 'remove.buildRunner': 'Generando código (Riverpod/Freezed)...',
2184
2298
  'remove.buildRunnerDone': 'Generación de código completada',
2185
- 'remove.buildRunnerFailed': 'build_runner falloejecutalo manualmente',
2299
+ 'remove.buildRunnerFailed': 'Generación de código falló ejecuta `dart run build_runner build` manualmente',
2186
2300
  'remove.success': 'Feature "{module}" eliminada exitosamente.',
2187
2301
  'remove.warn.ci': 'Archivos de CI eliminados. Si tenias workflows personalizados, restauralos desde git.',
2188
2302
  'remove.warn.sentry.shared': 'sentry_flutter conservado — todavia requerido por features activas (revenuecat/facebook).',
@@ -2215,15 +2329,72 @@ const MESSAGES = {
2215
2329
  'update.applyComponentsFailed': 'Error al aplicar actualización de componentes base',
2216
2330
  'update.noPatch': 'La feature "{module}" no tiene archivos para actualizar (feature solo de configuración).',
2217
2331
  'update.noComponentFiles': 'No se encontraron archivos de componentes base para actualizar.',
2218
- 'update.pubGet': 'Ejecutando flutter pub get...',
2332
+ 'update.pubGet': 'Instalando paquetes de Flutter (flutter pub get)...',
2219
2333
  'update.pubGetDone': 'Dependencias actualizadas',
2220
- 'update.pubGetFailed': 'flutter pub get falloejecutalo manualmente',
2221
- 'update.buildRunner': 'Ejecutando build_runner...',
2334
+ 'update.pubGetFailed': 'Falló al instalar paquetes de Flutter ejecuta `flutter pub get` manualmente',
2335
+ 'update.buildRunner': 'Generando código (Riverpod/Freezed)...',
2222
2336
  'update.buildRunnerDone': 'Generación de código completada',
2223
- 'update.buildRunnerFailed': 'build_runner falloejecutalo manualmente',
2337
+ 'update.buildRunnerFailed': 'Generación de código falló ejecuta `dart run build_runner build` manualmente',
2224
2338
  'update.success': 'Feature "{module}" actualizada exitosamente.',
2225
2339
  'update.componentsSuccess': 'Componentes base actualizados exitosamente.',
2226
2340
  'update.coreSuccess': 'Archivos de core actualizados exitosamente.',
2341
+ 'check.intro': 'Kasy Check — Notificaciones Push',
2342
+ 'check.firebase.detected': 'Backend Firebase',
2343
+ 'check.firebase.adcInfo': 'Firebase usa Application Default Credentials — no requiere configuración extra.',
2344
+ 'check.apns.warn': 'Push iOS requiere APNs Key (no verificable via CLI)',
2345
+ 'check.apns.where': 'Firebase Console → Cloud Messaging → app iOS → Clave de autenticación APNs',
2346
+ 'check.done': 'Listo',
2347
+ 'check.notKasy': 'Este directorio no parece ser un proyecto Kasy.',
2348
+ 'check.aborted': 'Cancelado',
2349
+ 'check.supabase.notLinked': 'Proyecto Supabase no vinculado',
2350
+ 'check.supabase.notLinkedHint': 'ejecuta: supabase link --project-ref TU_REF',
2351
+ 'check.supabase.linked': 'Proyecto vinculado',
2352
+ 'check.spin.secrets': 'Verificando secrets…',
2353
+ 'check.spin.secretsDone': 'Secrets verificados',
2354
+ 'check.secrets.listFailed': 'No se pudo listar los secrets',
2355
+ 'check.secrets.checkLogin': 'verifica: supabase login',
2356
+ 'check.fbProjId.ok': 'FIREBASE_PROJECT_ID configurado',
2357
+ 'check.fbProjId.missing': 'FIREBASE_PROJECT_ID ausente',
2358
+ 'check.fbProjId.fixHint': 'Corrige: supabase secrets set FIREBASE_PROJECT_ID="{id}"',
2359
+ 'check.fbProjId.fixed': 'FIREBASE_PROJECT_ID → configurado automáticamente',
2360
+ 'check.fbProjId.fixFailed': 'FIREBASE_PROJECT_ID → falló al configurar',
2361
+ 'check.fbSak.ok': 'FIREBASE_SERVICE_ACCOUNT_JSON configurado',
2362
+ 'check.fbSak.missing': 'FIREBASE_SERVICE_ACCOUNT_JSON ausente',
2363
+ 'check.fbSak.spin': 'Generando y configurando clave FCM…',
2364
+ 'check.fbSak.spinDone': 'Clave FCM generada',
2365
+ 'check.fbSak.fixed': 'FIREBASE_SERVICE_ACCOUNT_JSON → configurado automáticamente',
2366
+ 'check.fbSak.fixFailed': 'FIREBASE_SERVICE_ACCOUNT_JSON → falló al configurar',
2367
+ 'check.fbSak.genFailed': 'FIREBASE_SERVICE_ACCOUNT_JSON → no se pudo generar la clave',
2368
+ 'check.fbSak.manual': "Manual: Firebase Console → Configuración → Cuentas de servicio → Generar clave\nLuego: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat clave.json)'",
2369
+ 'check.fbSak.hint': "Corrige automáticamente: kasy check --fix\nO manualmente: Firebase Console → Configuración → Cuentas de servicio → Generar clave\nLuego: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='$(cat clave.json)'",
2370
+ 'check.fn.spin': 'Verificando edge functions…',
2371
+ 'check.fn.spinDone': 'Edge functions verificadas',
2372
+ 'check.fn.listFailed': 'No se pudo listar edge functions',
2373
+ 'check.fn.deployed': 'Edge function send-push-notification publicada',
2374
+ 'check.fn.missing': 'Edge function send-push-notification no publicada',
2375
+ 'check.fn.deploySpin': 'Publicando send-push-notification…',
2376
+ 'check.fn.deployDone': 'send-push-notification → publicada automáticamente',
2377
+ 'check.fn.deployFailed': 'send-push-notification → falló el deploy',
2378
+ 'check.fn.hint': 'Corrige automáticamente: kasy check --fix\nO manualmente: supabase functions deploy send-push-notification',
2379
+ 'deploy.firebase.intro': 'Deploy — Firebase',
2380
+ 'deploy.firebase.spin': 'Publicando en Firebase...',
2381
+ 'deploy.firebase.spinDone': 'Deploy de Firebase completado',
2382
+ 'deploy.apns.title': 'Push iOS: configura la APNs Key en Firebase Console',
2383
+ 'deploy.apns.step1': '1. Apple Developer Portal → Keys → crear APNs Key (.p8)',
2384
+ 'deploy.apns.step2': '2. Firebase Console → Cloud Messaging → app iOS → subir APNs Key',
2385
+ 'deploy.supabase.intro': 'Deploy — Supabase',
2386
+ 'deploy.supabase.notLinked': 'Proyecto Supabase no vinculado en este directorio.',
2387
+ 'deploy.supabase.linkHint': 'Ejecuta: supabase link --project-ref TU_PROJECT_REF',
2388
+ 'deploy.supabase.projectRef': 'Project ref: {ref}',
2389
+ 'deploy.supabase.sakAlready': 'FIREBASE_SERVICE_ACCOUNT_JSON ya configurado',
2390
+ 'deploy.supabase.sakSpin': 'Generando clave FCM (Service Account)…',
2391
+ 'deploy.supabase.sakSpinDone': 'Clave FCM generada',
2392
+ 'deploy.supabase.sakManual': "Configura manualmente: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='...'",
2393
+ 'deploy.supabase.sakNoGS': 'google-services.json no encontrado — configura manualmente',
2394
+ 'deploy.supabase.fnSpin': 'Publicando edge functions…',
2395
+ 'deploy.supabase.fnSpinDone': 'Edge functions procesadas',
2396
+ 'deploy.supabase.fnNone': 'edge functions (ninguna encontrada)',
2397
+ 'deploy.outro': 'Deploy completado',
2227
2398
  }
2228
2399
  };
2229
2400
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kasy-cli",
3
- "version": "1.10.0",
3
+ "version": "1.12.1",
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"
@@ -64,7 +64,13 @@ class _InitializerState extends ConsumerState<Initializer> {
64
64
  Sentry.captureException(e, stackTrace: s);
65
65
  ref.read(onStartProvider.notifier).notifyError(e.toString());
66
66
  } finally {
67
- FlutterNativeSplash.remove();
67
+ // Defer splash removal until after the next frame is painted so the
68
+ // onReady widget renders under the splash before it disappears.
69
+ // Without this, the splash is removed before the new frame paints,
70
+ // briefly revealing the onLoading widget (visible flash).
71
+ WidgetsBinding.instance.addPostFrameCallback((_) {
72
+ FlutterNativeSplash.remove();
73
+ });
68
74
  }
69
75
  });
70
76
  }