kasy-cli 1.5.3 → 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.
@@ -1,13 +1,11 @@
1
1
  const path = require('node:path');
2
2
  const fs = require('fs-extra');
3
3
  const kleur = require('kleur');
4
- const prompts = require('prompts');
5
- const oraPackage = require('ora');
4
+ const ui = require('../utils/ui');
5
+ const { printCompactHeader } = require('../utils/brand');
6
6
  const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
7
7
  const { slangGenerate } = require('../scaffold/shared/post-build');
8
8
 
9
- const ora = oraPackage.default || oraPackage;
10
-
11
9
  const SUPPORTED_LANGS = ['pt', 'en', 'es'];
12
10
 
13
11
  /**
@@ -110,49 +108,43 @@ async function promptForTexts(projectDir, t, flags) {
110
108
  };
111
109
  }
112
110
 
113
- console.log(kleur.bold(`\n${t('notifications.prompt.intro')}\n`));
114
- console.log(kleur.dim(` ${t('notifications.prompt.hint')}\n`));
115
-
116
- const response = await prompts([
117
- {
118
- type: 'text',
119
- name: 'demoTitle',
120
- message: t('notifications.prompt.demoTitle'),
121
- initial: flags.demoTitle || current.demoTitle,
122
- validate: (v) => (String(v || '').trim().length > 0 ? true : t('notifications.prompt.required')),
123
- },
124
- {
125
- type: 'text',
126
- name: 'demoBody',
127
- message: t('notifications.prompt.demoBody'),
128
- initial: flags.demoBody || current.demoBody,
129
- validate: (v) => (String(v || '').trim().length > 0 ? true : t('notifications.prompt.required')),
130
- },
131
- {
132
- type: 'text',
133
- name: 'reminderTitle',
134
- message: t('notifications.prompt.reminderTitle'),
135
- initial: flags.reminderTitle || current.reminderTitle,
136
- validate: (v) => (String(v || '').trim().length > 0 ? true : t('notifications.prompt.required')),
137
- },
138
- {
139
- type: 'text',
140
- name: 'reminderBody',
141
- message: t('notifications.prompt.reminderBody'),
142
- initial: flags.reminderBody || current.reminderBody,
143
- validate: (v) => (String(v || '').trim().length > 0 ? true : t('notifications.prompt.required')),
144
- },
145
- ]);
146
-
147
- if (!response.demoTitle) {
148
- throw new Error(t('notifications.error.cancelled'));
149
- }
111
+ const cancel = () => { ui.cancel(t('notifications.error.cancelled')); process.exit(0); };
112
+
113
+ ui.log.step(kleur.bold(t('notifications.prompt.intro')));
114
+ ui.log.message(kleur.dim(t('notifications.prompt.hint')));
115
+
116
+ const required = (v) => (String(v || '').trim().length > 0 ? undefined : t('notifications.prompt.required'));
117
+
118
+ const demoTitle = await ui.text({
119
+ message: t('notifications.prompt.demoTitle'),
120
+ initialValue: flags.demoTitle || current.demoTitle,
121
+ validate: required,
122
+ onCancel: cancel,
123
+ });
124
+ const demoBody = await ui.text({
125
+ message: t('notifications.prompt.demoBody'),
126
+ initialValue: flags.demoBody || current.demoBody,
127
+ validate: required,
128
+ onCancel: cancel,
129
+ });
130
+ const reminderTitle = await ui.text({
131
+ message: t('notifications.prompt.reminderTitle'),
132
+ initialValue: flags.reminderTitle || current.reminderTitle,
133
+ validate: required,
134
+ onCancel: cancel,
135
+ });
136
+ const reminderBody = await ui.text({
137
+ message: t('notifications.prompt.reminderBody'),
138
+ initialValue: flags.reminderBody || current.reminderBody,
139
+ validate: required,
140
+ onCancel: cancel,
141
+ });
150
142
 
151
143
  return {
152
- demoTitle: response.demoTitle.trim(),
153
- demoBody: response.demoBody.trim(),
154
- reminderTitle: response.reminderTitle.trim(),
155
- reminderBody: response.reminderBody.trim(),
144
+ demoTitle: String(demoTitle).trim(),
145
+ demoBody: String(demoBody).trim(),
146
+ reminderTitle: String(reminderTitle).trim(),
147
+ reminderBody: String(reminderBody).trim(),
156
148
  };
157
149
  }
158
150
 
@@ -169,6 +161,9 @@ async function runNotificationsText(directory, options = {}) {
169
161
  await assertKasyProject(projectDir, t);
170
162
  await assertLocalNotificationsEnabled(projectDir, t);
171
163
 
164
+ printCompactHeader(t);
165
+ ui.intro(t('notifications.prompt.intro'));
166
+
172
167
  const targetLangs = resolveTargetLangs(options.lang);
173
168
  const texts = await promptForTexts(
174
169
  projectDir,
@@ -181,27 +176,32 @@ async function runNotificationsText(directory, options = {}) {
181
176
  },
182
177
  );
183
178
 
184
- const writeSpinner = ora(t('notifications.writing')).start();
179
+ const writeSpinner = ui.spinner();
180
+ writeSpinner.start(t('notifications.writing'));
185
181
  await writeNotificationTexts(projectDir, targetLangs, texts);
186
- writeSpinner.succeed(t('notifications.written', { langs: targetLangs.join(', ') }));
182
+ writeSpinner.stop(t('notifications.written', { langs: targetLangs.join(', ') }));
187
183
 
188
- const slangSpinner = ora(t('notifications.slang')).start();
184
+ const slangSpinner = ui.spinner();
185
+ slangSpinner.start(t('notifications.slang'));
189
186
  const slangResult = await slangGenerate(projectDir);
190
187
  if (slangResult.ok) {
191
- slangSpinner.succeed(t('notifications.slangDone'));
188
+ slangSpinner.stop(t('notifications.slangDone'));
192
189
  } else {
193
- slangSpinner.warn(t('notifications.slangFailed'));
194
- console.log(kleur.dim(' dart run slang'));
190
+ slangSpinner.stop(`⚠ ${t('notifications.slangFailed')}`);
191
+ ui.log.message(kleur.dim('dart run slang'));
195
192
  }
196
193
 
197
- console.log(kleur.green(`\n✓ ${t('notifications.done')}\n`));
198
- console.log(kleur.dim(` ${t('notifications.summary.demo')}`));
199
- console.log(kleur.dim(` ${kleur.white(texts.demoTitle)}`));
200
- console.log(kleur.dim(` ${kleur.white(texts.demoBody)}`));
201
- console.log(kleur.dim(` ${t('notifications.summary.reminder')}`));
202
- console.log(kleur.dim(` ${kleur.white(texts.reminderTitle)}`));
203
- console.log(kleur.dim(` ${kleur.white(texts.reminderBody)}`));
204
- console.log('');
194
+ const summary = [
195
+ `${t('notifications.summary.demo')}`,
196
+ ` ${kleur.white(texts.demoTitle)}`,
197
+ ` ${kleur.white(texts.demoBody)}`,
198
+ `${t('notifications.summary.reminder')}`,
199
+ ` ${kleur.white(texts.reminderTitle)}`,
200
+ ` ${kleur.white(texts.reminderBody)}`,
201
+ ].join('\n');
202
+ ui.note(summary);
203
+
204
+ ui.outro(t('notifications.done'));
205
205
  }
206
206
 
207
207
  module.exports = { runNotificationsText, readNotificationTexts, writeNotificationTexts };
@@ -6,8 +6,8 @@ const path = require('node:path');
6
6
  const fs = require('fs-extra');
7
7
  const pkg = require('../../package.json');
8
8
  const kleur = require('kleur');
9
- const prompts = require('prompts');
10
- const oraPackage = require('ora');
9
+ const ui = require('../utils/ui');
10
+ const { printCompactHeader } = require('../utils/brand');
11
11
  const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
12
12
  const {
13
13
  AVAILABLE_FEATURES,
@@ -29,7 +29,6 @@ const {
29
29
  const { toPackageName } = require('../scaffold/backends/firebase/tokens');
30
30
 
31
31
  const execAsync = promisify(exec);
32
- const ora = oraPackage.default || oraPackage;
33
32
 
34
33
  // ── Module metadata ──────────────────────────────────────────────────────────
35
34
 
@@ -299,7 +298,8 @@ async function runRemove(module, options = {}) {
299
298
  const projectDir = path.resolve(options.directory || '.');
300
299
 
301
300
  if (!module) {
302
- console.log(kleur.yellow(t('remove.error.noModule')));
301
+ printCompactHeader(t);
302
+ ui.log.warn(t('remove.error.noModule'));
303
303
  return;
304
304
  }
305
305
 
@@ -325,29 +325,28 @@ async function runRemove(module, options = {}) {
325
325
  // 3. Check that the module is actually active
326
326
  const activeModules = await getActiveModules(kitSetup, projectDir);
327
327
  if (!activeModules.includes(normalized)) {
328
- console.log(kleur.yellow(`\n${t('remove.error.notActive', { module: normalized })}\n`));
328
+ printCompactHeader(t);
329
+ ui.log.warn(t('remove.error.notActive', { module: normalized }));
329
330
  return;
330
331
  }
331
332
 
333
+ printCompactHeader(t);
334
+ ui.intro(t('remove.removing', { module: normalized }));
335
+ const cancel = () => { ui.cancel(t('remove.cancelled')); process.exit(0); };
336
+
332
337
  // 4. Confirm before destructive action (skip with --yes)
333
338
  if (!options.yes) {
334
- const { confirmed } = await prompts(
335
- {
336
- type: 'confirm',
337
- name: 'confirmed',
338
- message: t('remove.confirm', { module: normalized }),
339
- initial: false,
340
- },
341
- { onCancel: () => { throw new Error(t('remove.cancelled')); } }
342
- );
339
+ const confirmed = await ui.confirm({
340
+ message: t('remove.confirm', { module: normalized }),
341
+ initialValue: false,
342
+ onCancel: cancel,
343
+ });
343
344
  if (!confirmed) {
344
- console.log(kleur.dim(`\n${t('remove.cancelled')}\n`));
345
+ ui.outro(t('remove.cancelled'));
345
346
  return;
346
347
  }
347
348
  }
348
349
 
349
- console.log(kleur.bold(`\n${t('remove.removing', { module: normalized })}\n`));
350
-
351
350
  // Build the module list that will be active AFTER removal (used for stub regen)
352
351
  const modulesAfterRemoval = activeModules.filter((m) => m !== normalized);
353
352
 
@@ -391,7 +390,7 @@ async function runRemove(module, options = {}) {
391
390
  await removePubspecDep(projectDir, 'sentry_flutter');
392
391
  await writeNoOpSentryUsages(projectDir).catch(() => {});
393
392
  } else if (normalized === 'sentry' && sentryStillNeeded) {
394
- console.log(kleur.dim(`\n ${t('remove.warn.sentry.shared')}\n`));
393
+ ui.log.message(kleur.dim(t('remove.warn.sentry.shared')));
395
394
  }
396
395
 
397
396
  // 10. Remove files and directories added by the module's patch
@@ -430,12 +429,13 @@ async function runRemove(module, options = {}) {
430
429
 
431
430
  // 13. flutter pub get
432
431
  {
433
- const spinner = ora(t('remove.pubGet')).start();
432
+ const spinner = ui.spinner();
433
+ spinner.start(t('remove.pubGet'));
434
434
  try {
435
435
  await execAsync('flutter pub get', { cwd: projectDir, timeout: 300_000 });
436
- spinner.succeed(t('remove.pubGetDone'));
436
+ spinner.stop(t('remove.pubGetDone'));
437
437
  } catch {
438
- spinner.warn(t('remove.pubGetFailed'));
438
+ spinner.stop(`⚠ ${t('remove.pubGetFailed')}`);
439
439
  }
440
440
  }
441
441
 
@@ -444,23 +444,24 @@ async function runRemove(module, options = {}) {
444
444
  'revenuecat', 'analytics', 'sentry', 'onboarding', 'llm_chat', 'feedback',
445
445
  ].includes(normalized);
446
446
  if (needsBuildRunner) {
447
- const spinner = ora(t('remove.buildRunner')).start();
447
+ const spinner = ui.spinner();
448
+ spinner.start(t('remove.buildRunner'));
448
449
  try {
449
450
  await execAsync(
450
451
  'dart run build_runner build --delete-conflicting-outputs',
451
452
  { cwd: projectDir, timeout: 600_000 }
452
453
  );
453
- spinner.succeed(t('remove.buildRunnerDone'));
454
+ spinner.stop(t('remove.buildRunnerDone'));
454
455
  } catch {
455
- spinner.warn(t('remove.buildRunnerFailed'));
456
+ spinner.stop(`⚠ ${t('remove.buildRunnerFailed')}`);
456
457
  }
457
458
  }
458
459
 
459
- console.log(kleur.green(`\n✓ ${t('remove.success', { module: normalized })}\n`));
460
-
461
460
  if (normalized === 'ci') {
462
- console.log(kleur.dim(` ${t('remove.warn.ci')}\n`));
461
+ ui.log.message(kleur.dim(t('remove.warn.ci')));
463
462
  }
463
+
464
+ ui.outro(t('remove.success', { module: normalized }));
464
465
  }
465
466
 
466
467
  module.exports = { runRemove };
@@ -3,6 +3,7 @@ const path = require('node:path');
3
3
  const fs = require('fs-extra');
4
4
  const kleur = require('kleur');
5
5
  const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
6
+ const { printCompactHeader } = require('../utils/brand');
6
7
 
7
8
  /**
8
9
  * Read dart-define args from .vscode/launch.json.
@@ -53,7 +54,8 @@ async function runRun(directory, options = {}) {
53
54
 
54
55
  const args = ['run', ...deviceArgs, ...dartDefines];
55
56
 
56
- console.log(kleur.bold(`\n${t('run.launching')}`));
57
+ printCompactHeader(t);
58
+ console.log(kleur.bold(`${t('run.launching')}`));
57
59
  console.log(kleur.dim(` flutter ${args.join(' ')}`));
58
60
  console.log(kleur.dim(` ✦ ${t('run.updateHint.prefix')} `) + kleur.cyan('kasy update') + kleur.dim(` ${t('run.updateHint.suffix')}\n`));
59
61