kasy-cli 1.5.3 → 1.6.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 +5 -2
- package/lib/commands/add.js +101 -100
- package/lib/commands/check.js +55 -38
- package/lib/commands/codemagic.js +61 -58
- package/lib/commands/deploy.js +49 -45
- package/lib/commands/docs.js +19 -18
- package/lib/commands/doctor.js +46 -44
- package/lib/commands/features.js +20 -17
- package/lib/commands/ios.js +69 -69
- package/lib/commands/new.js +529 -771
- package/lib/commands/notifications.js +59 -59
- package/lib/commands/remove.js +28 -27
- package/lib/commands/run.js +3 -1
- package/lib/commands/update.js +104 -96
- package/lib/commands/validate.js +24 -19
- package/lib/utils/apple-release.js +23 -11
- package/lib/utils/brand.js +72 -0
- package/lib/utils/checks.js +20 -9
- package/lib/utils/prompts.js +82 -142
- package/lib/utils/ui.js +92 -0
- package/lib/utils/updates.js +9 -8
- package/package.json +2 -1
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
const kleur = require('kleur');
|
|
5
|
-
const
|
|
5
|
+
const ui = require('../utils/ui');
|
|
6
|
+
const { printCompactHeader } = require('../utils/brand');
|
|
6
7
|
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
7
8
|
const { isKasyFlutterProject, openUrl } = require('../utils/apple-release');
|
|
8
9
|
const { validateGoogleIosUrlScheme } = require('../scaffold/shared/post-build');
|
|
@@ -29,53 +30,48 @@ async function runConfigure(directory, options = {}) {
|
|
|
29
30
|
|
|
30
31
|
await assertProject(projectDir, t);
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
printCompactHeader(t);
|
|
34
|
+
ui.intro(t('codemagic.configure.title'));
|
|
35
|
+
ui.log.message(kleur.dim(`${t('codemagic.configure.doc')}: ${codemagicReleaseDocPath(lang)}`));
|
|
36
|
+
ui.log.warn(t('codemagic.configure.checklist'));
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
ui.log.info(t('codemagic.configure.openingLinks'));
|
|
37
39
|
openUrl(URL_CODEMAGIC_API);
|
|
38
40
|
openUrl(URL_CODEMAGIC_APPS);
|
|
39
41
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
message: t('codemagic.configure.q.branch'),
|
|
64
|
-
initial: 'main',
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
{ onCancel: () => { throw new Error(t('codemagic.configure.cancelled')); } }
|
|
68
|
-
);
|
|
42
|
+
const cancel = () => { ui.cancel(t('codemagic.configure.cancelled')); process.exit(0); };
|
|
43
|
+
const required = (v) => (v && String(v).trim().length > 0 ? undefined : t('codemagic.configure.q.required'));
|
|
44
|
+
|
|
45
|
+
const token = await ui.password({
|
|
46
|
+
message: t('codemagic.configure.q.token'),
|
|
47
|
+
validate: required,
|
|
48
|
+
onCancel: cancel,
|
|
49
|
+
});
|
|
50
|
+
const appId = await ui.text({
|
|
51
|
+
message: t('codemagic.configure.q.appId'),
|
|
52
|
+
validate: required,
|
|
53
|
+
onCancel: cancel,
|
|
54
|
+
});
|
|
55
|
+
const workflowId = await ui.text({
|
|
56
|
+
message: t('codemagic.configure.q.workflowId'),
|
|
57
|
+
initialValue: 'ios-workflow',
|
|
58
|
+
onCancel: cancel,
|
|
59
|
+
});
|
|
60
|
+
const branch = await ui.text({
|
|
61
|
+
message: t('codemagic.configure.q.branch'),
|
|
62
|
+
initialValue: 'main',
|
|
63
|
+
onCancel: cancel,
|
|
64
|
+
});
|
|
69
65
|
|
|
70
66
|
await writeCodemagicEnv(projectDir, {
|
|
71
|
-
token:
|
|
72
|
-
appId:
|
|
73
|
-
workflowId:
|
|
74
|
-
branch:
|
|
67
|
+
token: String(token).trim(),
|
|
68
|
+
appId: String(appId).trim(),
|
|
69
|
+
workflowId: String(workflowId).trim() || 'ios-workflow',
|
|
70
|
+
branch: String(branch).trim() || 'main',
|
|
75
71
|
});
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
ui.log.success(t('codemagic.configure.success'));
|
|
74
|
+
ui.outro(kleur.cyan(`${t('codemagic.configure.next')}: kasy codemagic release`));
|
|
79
75
|
}
|
|
80
76
|
|
|
81
77
|
async function runRelease(directory, options = {}) {
|
|
@@ -86,12 +82,13 @@ async function runRelease(directory, options = {}) {
|
|
|
86
82
|
|
|
87
83
|
const validation = await validateCodemagicSetup(projectDir);
|
|
88
84
|
if (!validation.ok) {
|
|
89
|
-
|
|
85
|
+
printCompactHeader(t);
|
|
86
|
+
ui.log.error(t('codemagic.error.notConfigured'));
|
|
90
87
|
if (validation.issues.includes('missing_yaml')) {
|
|
91
|
-
|
|
88
|
+
ui.log.message(kleur.dim(t('codemagic.error.addCi')));
|
|
92
89
|
}
|
|
93
90
|
if (validation.issues.includes('missing_env')) {
|
|
94
|
-
|
|
91
|
+
ui.log.message(kleur.dim(t('codemagic.error.runConfigure')));
|
|
95
92
|
}
|
|
96
93
|
process.exitCode = 1;
|
|
97
94
|
return;
|
|
@@ -99,27 +96,30 @@ async function runRelease(directory, options = {}) {
|
|
|
99
96
|
|
|
100
97
|
const googleScheme = await validateGoogleIosUrlScheme(projectDir);
|
|
101
98
|
if (!googleScheme.ok) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
printCompactHeader(t);
|
|
100
|
+
ui.log.error(t('codemagic.error.googleUrlScheme'));
|
|
101
|
+
ui.log.message(kleur.dim(googleScheme.error));
|
|
102
|
+
ui.log.info(t('ios.error.googleUrlSchemeHint'));
|
|
105
103
|
process.exitCode = 1;
|
|
106
104
|
return;
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
|
|
107
|
+
printCompactHeader(t);
|
|
108
|
+
ui.intro(t('codemagic.release.title'));
|
|
110
109
|
|
|
111
110
|
try {
|
|
112
111
|
const result = await triggerBuild(projectDir, validation.env);
|
|
113
112
|
const buildId = result.buildId || result._id;
|
|
114
113
|
if (buildId) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
ui.log.success(t('codemagic.release.triggered'));
|
|
115
|
+
ui.log.info(`Build ID: ${kleur.cyan(buildId)}`);
|
|
116
|
+
ui.log.message(kleur.dim(`https://codemagic.io/builds/${buildId}`));
|
|
117
|
+
ui.outro('');
|
|
118
118
|
} else {
|
|
119
|
-
|
|
119
|
+
ui.outro(t('codemagic.release.triggered'));
|
|
120
120
|
}
|
|
121
121
|
} catch (err) {
|
|
122
|
-
|
|
122
|
+
ui.log.error(err.message);
|
|
123
123
|
process.exitCode = 1;
|
|
124
124
|
}
|
|
125
125
|
}
|
|
@@ -132,24 +132,27 @@ async function runStatus(buildId, directory, options = {}) {
|
|
|
132
132
|
|
|
133
133
|
const validation = await validateCodemagicSetup(projectDir);
|
|
134
134
|
if (!validation.env?.CODEMAGIC_API_TOKEN) {
|
|
135
|
-
|
|
135
|
+
printCompactHeader(t);
|
|
136
|
+
ui.log.error(t('codemagic.error.runConfigure'));
|
|
136
137
|
process.exitCode = 1;
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
if (!buildId) {
|
|
141
|
-
|
|
142
|
+
printCompactHeader(t);
|
|
143
|
+
ui.log.warn(t('codemagic.status.usage'));
|
|
142
144
|
process.exitCode = 1;
|
|
143
145
|
return;
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
try {
|
|
147
149
|
const result = await getBuildStatus(buildId, validation.env.CODEMAGIC_API_TOKEN);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
printCompactHeader(t);
|
|
151
|
+
ui.intro(`${t('codemagic.status.title')}: ${buildId}`);
|
|
152
|
+
ui.note(JSON.stringify(result, null, 2));
|
|
153
|
+
ui.outro('');
|
|
151
154
|
} catch (err) {
|
|
152
|
-
|
|
155
|
+
ui.log.error(err.message);
|
|
153
156
|
process.exitCode = 1;
|
|
154
157
|
}
|
|
155
158
|
}
|
package/lib/commands/deploy.js
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
const path = require('node:path');
|
|
17
17
|
const fs = require('fs-extra');
|
|
18
18
|
const kleur = require('kleur');
|
|
19
|
-
const
|
|
20
|
-
const
|
|
19
|
+
const ui = require('../utils/ui');
|
|
20
|
+
const { printCompactHeader } = require('../utils/brand');
|
|
21
21
|
|
|
22
22
|
const { createTranslator } = require('../utils/i18n');
|
|
23
23
|
const { getStoredLanguage } = require('../utils/license');
|
|
@@ -25,14 +25,13 @@ const { runDeploy: runFirebaseDeploy } = require('../scaffold/backends/firebase/
|
|
|
25
25
|
const { deployFunctions, setSupabaseSecrets, linkProject } = require('../scaffold/backends/supabase/deploy');
|
|
26
26
|
const { createFcmServiceAccountKey } = require('../scaffold/shared/fcm-service-account');
|
|
27
27
|
|
|
28
|
-
const ora = oraPackage.default || oraPackage;
|
|
29
|
-
|
|
30
28
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
31
29
|
|
|
32
30
|
function printStep(ok, skipped, label, detail) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
const text = `${label}${detail ? kleur.gray(` — ${detail.split('\n')[0]}`) : ''}`;
|
|
32
|
+
if (ok) ui.log.success(text);
|
|
33
|
+
else if (skipped) ui.log.message(kleur.dim(`– ${text}`));
|
|
34
|
+
else ui.log.error(text);
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
/**
|
|
@@ -84,7 +83,7 @@ async function isServiceAccountJsonSet(projectDir) {
|
|
|
84
83
|
// ── Firebase deploy ───────────────────────────────────────────────────────────
|
|
85
84
|
|
|
86
85
|
async function deployFirebase(projectDir, options, tr) {
|
|
87
|
-
const cancel = () => {
|
|
86
|
+
const cancel = () => { ui.cancel('Cancelled'); process.exit(0); };
|
|
88
87
|
|
|
89
88
|
// Auto-detect Firebase Project ID
|
|
90
89
|
let firebaseProjectId = options.project;
|
|
@@ -96,17 +95,17 @@ async function deployFirebase(projectDir, options, tr) {
|
|
|
96
95
|
const detected = rc.projects?.default;
|
|
97
96
|
if (detected) {
|
|
98
97
|
firebaseProjectId = detected;
|
|
99
|
-
|
|
98
|
+
ui.log.message(kleur.gray(`${tr('deploy.detected.project')} ${kleur.cyan(detected)}`));
|
|
100
99
|
}
|
|
101
100
|
} catch (_) {}
|
|
102
101
|
}
|
|
103
102
|
}
|
|
104
103
|
if (!firebaseProjectId) {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
);
|
|
109
|
-
firebaseProjectId = pid
|
|
104
|
+
const pid = await ui.text({
|
|
105
|
+
message: tr('deploy.q.project'),
|
|
106
|
+
onCancel: cancel,
|
|
107
|
+
});
|
|
108
|
+
firebaseProjectId = String(pid || '').trim();
|
|
110
109
|
if (!firebaseProjectId) process.exit(0);
|
|
111
110
|
}
|
|
112
111
|
|
|
@@ -123,50 +122,48 @@ async function deployFirebase(projectDir, options, tr) {
|
|
|
123
122
|
}
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
const spinner = ui.spinner();
|
|
126
|
+
spinner.start('Deploying Firebase...');
|
|
128
127
|
let steps;
|
|
129
128
|
try {
|
|
130
129
|
steps = await runFirebaseDeploy(projectDir, null, firebaseProjectId, {
|
|
131
130
|
functionsRegion,
|
|
132
|
-
onProgress: (key) => { spinner.
|
|
131
|
+
onProgress: (key) => { spinner.message(String(key)); },
|
|
133
132
|
});
|
|
134
|
-
spinner.stop();
|
|
133
|
+
spinner.stop('Firebase deploy completed');
|
|
135
134
|
} catch (err) {
|
|
136
|
-
spinner.
|
|
135
|
+
spinner.error(err.message);
|
|
137
136
|
throw err;
|
|
138
137
|
}
|
|
139
138
|
|
|
140
139
|
if (steps?.length) {
|
|
141
|
-
console.log('');
|
|
142
140
|
for (const s of steps) {
|
|
143
141
|
printStep(s.ok, s.skipped, s.name, s.detail);
|
|
144
142
|
}
|
|
145
|
-
console.log('');
|
|
146
143
|
}
|
|
147
144
|
|
|
148
145
|
// ── APNs reminder — required for iOS push notifications ──────────────────
|
|
149
146
|
// Cannot be automated: the .p8 key only exists in Apple Developer Portal.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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'),
|
|
151
|
+
kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`),
|
|
152
|
+
].join('\n');
|
|
153
|
+
ui.note(apnsBody);
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
// ── Supabase deploy ───────────────────────────────────────────────────────────
|
|
158
157
|
|
|
159
158
|
async function deploySupabase(projectDir) {
|
|
160
|
-
console.log('');
|
|
161
|
-
|
|
162
159
|
// ── 1. Get project ref ──────────────────────────────────────────────────
|
|
163
160
|
const projectRef = await readSupabaseProjectRef(projectDir);
|
|
164
161
|
if (!projectRef) {
|
|
165
|
-
|
|
166
|
-
|
|
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'));
|
|
167
164
|
process.exit(1);
|
|
168
165
|
}
|
|
169
|
-
|
|
166
|
+
ui.log.message(kleur.gray(`Project ref: ${kleur.cyan(projectRef)}`));
|
|
170
167
|
|
|
171
168
|
// ── 2. FCM Service Account JSON ─────────────────────────────────────────
|
|
172
169
|
const alreadySet = await isServiceAccountJsonSet(projectDir);
|
|
@@ -176,12 +173,12 @@ async function deploySupabase(projectDir) {
|
|
|
176
173
|
const firebaseProjectId = await readFirebaseProjectId(projectDir);
|
|
177
174
|
|
|
178
175
|
if (firebaseProjectId) {
|
|
179
|
-
const fcmSpinner =
|
|
176
|
+
const fcmSpinner = ui.spinner();
|
|
177
|
+
fcmSpinner.start('Gerando chave FCM (Service Account)…');
|
|
180
178
|
const fcmResult = await createFcmServiceAccountKey(firebaseProjectId);
|
|
181
|
-
fcmSpinner.stop();
|
|
179
|
+
fcmSpinner.stop('Chave FCM gerada');
|
|
182
180
|
|
|
183
181
|
if (fcmResult.ok) {
|
|
184
|
-
// Set the secret via setSupabaseSecrets (reuses existing logic with JSON compaction)
|
|
185
182
|
const secretSteps = await setSupabaseSecrets(projectDir, {
|
|
186
183
|
firebaseProjectId,
|
|
187
184
|
firebaseServiceAccountJson: fcmResult.json,
|
|
@@ -189,7 +186,7 @@ async function deploySupabase(projectDir) {
|
|
|
189
186
|
for (const s of secretSteps) printStep(s.ok, false, s.name, s.error);
|
|
190
187
|
} else {
|
|
191
188
|
printStep(false, false, 'FIREBASE_SERVICE_ACCOUNT_JSON', fcmResult.error);
|
|
192
|
-
|
|
189
|
+
ui.log.warn("Configure manualmente: supabase secrets set FIREBASE_SERVICE_ACCOUNT_JSON='...'");
|
|
193
190
|
}
|
|
194
191
|
} else {
|
|
195
192
|
printStep(false, false, 'FIREBASE_SERVICE_ACCOUNT_JSON', 'google-services.json não encontrado — configure manualmente');
|
|
@@ -197,9 +194,10 @@ async function deploySupabase(projectDir) {
|
|
|
197
194
|
}
|
|
198
195
|
|
|
199
196
|
// ── 3. Deploy edge functions ────────────────────────────────────────────
|
|
200
|
-
const fnSpinner =
|
|
197
|
+
const fnSpinner = ui.spinner();
|
|
198
|
+
fnSpinner.start('Publicando edge functions…');
|
|
201
199
|
const fnResult = await deployFunctions(projectDir);
|
|
202
|
-
fnSpinner.stop();
|
|
200
|
+
fnSpinner.stop('Edge functions processadas');
|
|
203
201
|
|
|
204
202
|
if (Array.isArray(fnResult)) {
|
|
205
203
|
fnResult.forEach((s) => printStep(s.ok, s.skipped, s.name, s.error));
|
|
@@ -211,14 +209,15 @@ async function deploySupabase(projectDir) {
|
|
|
211
209
|
|
|
212
210
|
// ── 4. APNs reminder ────────────────────────────────────────────────────
|
|
213
211
|
const firebaseProjectId = await readFirebaseProjectId(projectDir);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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'),
|
|
216
|
+
];
|
|
218
217
|
if (firebaseProjectId) {
|
|
219
|
-
|
|
218
|
+
apnsLines.push(kleur.cyan(`https://console.firebase.google.com/project/${firebaseProjectId}/settings/cloudmessaging`));
|
|
220
219
|
}
|
|
221
|
-
|
|
220
|
+
ui.note(apnsLines.join('\n'));
|
|
222
221
|
}
|
|
223
222
|
|
|
224
223
|
// ── Entry point ───────────────────────────────────────────────────────────────
|
|
@@ -240,17 +239,22 @@ async function runDeployCommand(directory, options = {}, { language: langHint }
|
|
|
240
239
|
const isSupabase = await fs.pathExists(path.join(projectDir, 'supabase'));
|
|
241
240
|
|
|
242
241
|
if (isFirebase) {
|
|
242
|
+
printCompactHeader(tr);
|
|
243
|
+
ui.intro('Deploy — Firebase');
|
|
243
244
|
await deployFirebase(projectDir, options, tr);
|
|
245
|
+
ui.outro('Deploy concluído');
|
|
244
246
|
return;
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
if (isSupabase) {
|
|
248
|
-
|
|
250
|
+
printCompactHeader(tr);
|
|
251
|
+
ui.intro('Deploy — Supabase');
|
|
249
252
|
await deploySupabase(projectDir);
|
|
253
|
+
ui.outro('Deploy concluído');
|
|
250
254
|
return;
|
|
251
255
|
}
|
|
252
256
|
|
|
253
|
-
|
|
257
|
+
ui.log.error(tr('deploy.error.notProject'));
|
|
254
258
|
process.exit(1);
|
|
255
259
|
}
|
|
256
260
|
|
package/lib/commands/docs.js
CHANGED
|
@@ -2,6 +2,8 @@ const path = require('node:path');
|
|
|
2
2
|
const { exec } = require('node:child_process');
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const kleur = require('kleur');
|
|
5
|
+
const ui = require('../utils/ui');
|
|
6
|
+
const { printCompactHeader } = require('../utils/brand');
|
|
5
7
|
const { createTranslator, detectDefaultLanguage } = require('../utils/i18n');
|
|
6
8
|
|
|
7
9
|
const DOCS_FILE = path.join(__dirname, '..', '..', 'docs', 'cli-reference.md');
|
|
@@ -18,30 +20,29 @@ function openInBrowser(url) {
|
|
|
18
20
|
async function runDocs(options = {}) {
|
|
19
21
|
const t = createTranslator(options.language || detectDefaultLanguage());
|
|
20
22
|
|
|
21
|
-
|
|
23
|
+
printCompactHeader(t);
|
|
24
|
+
ui.intro('Kasy CLI — Documentação');
|
|
22
25
|
|
|
23
|
-
// Show local CLI reference
|
|
24
26
|
if (await fs.pathExists(DOCS_FILE)) {
|
|
25
27
|
const content = await fs.readFile(DOCS_FILE, 'utf8');
|
|
26
|
-
// Show the first section (commands overview)
|
|
27
28
|
const lines = content.split('\n').slice(0, 60);
|
|
28
|
-
|
|
29
|
-
console.log(kleur.dim(`\n ... (arquivo completo: ${DOCS_FILE})\n`));
|
|
29
|
+
ui.note(`${kleur.dim(lines.join('\n'))}\n\n${kleur.dim(`... (arquivo completo: ${DOCS_FILE})`)}`);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
32
|
+
const commandsBody = [
|
|
33
|
+
`${kleur.bold('kasy new')} — Criar novo projeto`,
|
|
34
|
+
`${kleur.bold('kasy add')} — Adicionar módulo`,
|
|
35
|
+
`${kleur.bold('kasy doctor')} — Verificar ambiente`,
|
|
36
|
+
`${kleur.bold('kasy run')} — Executar app`,
|
|
37
|
+
`${kleur.bold('kasy deploy')} — Deploy do projeto`,
|
|
38
|
+
`${kleur.bold('kasy ios')} — Release iOS (configure / release / build)`,
|
|
39
|
+
`${kleur.bold('kasy codemagic')} — Build iOS na nuvem`,
|
|
40
|
+
`${kleur.bold('kasy features')} — Listar features`,
|
|
41
|
+
`${kleur.bold('kasy validate')} — Validar projeto`,
|
|
42
|
+
].join('\n');
|
|
43
|
+
ui.note(commandsBody, kleur.cyan('Comandos disponíveis'));
|
|
44
|
+
|
|
45
|
+
ui.outro(kleur.dim('Para detalhes de um comando: kasy help <comando>'));
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
module.exports = { runDocs };
|