optikit 1.2.4 → 1.3.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/.claude/commands/build.md +57 -0
- package/.claude/commands/clean.md +45 -0
- package/.claude/commands/generate.md +64 -0
- package/.claude/commands/rollback.md +67 -0
- package/.claude/commands/run.md +63 -0
- package/.claude/commands/setup.md +69 -0
- package/.claude/commands/sync-docs.md +148 -0
- package/.claude/commands/version.md +63 -0
- package/.claude/settings.local.json +28 -0
- package/.claude-plugin/marketplace.json +36 -0
- package/.claude-plugin/plugin.json +25 -0
- package/.history/README_20260325211923.md +268 -0
- package/.history/README_20260325212116.md +268 -0
- package/.history/README_20260325212234.md +266 -0
- package/.history/README_20260325221838.md +321 -0
- package/.history/README_20260325221920.md +327 -0
- package/.history/README_20260325222245.md +328 -0
- package/.history/README_20260325222247.md +328 -0
- package/.mcp.json +8 -0
- package/CHANGELOG.md +79 -46
- package/CLAUDE.md +57 -206
- package/OPTIKIT_AGENT.md +398 -0
- package/README.md +293 -60
- package/dist/cli.js +75 -241
- package/dist/commands/build/commands.js +146 -0
- package/dist/commands/build/testflight.js +14 -0
- package/dist/commands/clean/commands.js +41 -0
- package/dist/commands/clean/flutter.js +8 -14
- package/dist/commands/clean/ios.js +12 -15
- package/dist/commands/config/aliases.js +122 -0
- package/dist/commands/config/commands.js +49 -0
- package/dist/commands/config/initApp.js +191 -0
- package/dist/commands/config/rollback.js +15 -4
- package/dist/commands/config/upgrade.js +36 -0
- package/dist/commands/mcp/commands.js +21 -0
- package/dist/commands/mcp/server.js +27 -0
- package/dist/commands/mcp/setup.js +62 -0
- package/dist/commands/mcp/tools.js +359 -0
- package/dist/commands/project/commands.js +132 -0
- package/dist/commands/project/devices.js +10 -26
- package/dist/commands/project/doctor.js +58 -0
- package/dist/commands/project/generate.js +183 -30
- package/dist/commands/project/setup.js +10 -28
- package/dist/commands/project/status.js +65 -0
- package/dist/commands/version/bump.js +96 -82
- package/dist/commands/version/commands.js +63 -0
- package/dist/commands/version/update.js +36 -24
- package/dist/constants.js +6 -1
- package/dist/styles.js +42 -5
- package/dist/utils/helpers/error.js +14 -0
- package/dist/utils/helpers/file.js +1 -1
- package/dist/utils/helpers/version.js +2 -1
- package/dist/utils/services/backup.js +12 -1
- package/dist/utils/services/command.js +1 -34
- package/dist/utils/services/exec.js +76 -101
- package/dist/utils/services/logger.js +10 -4
- package/dist/utils/validators/validation.js +24 -12
- package/docs/INSTALLATION.md +72 -0
- package/docs/TROUBLESHOOT.md +140 -0
- package/docs/USAGE.md +185 -0
- package/docs/VERSION_MANAGEMENT.md +177 -0
- package/package.json +7 -11
- package/src/cli.ts +82 -362
- package/src/commands/build/commands.ts +169 -0
- package/src/commands/build/testflight.ts +18 -0
- package/src/commands/clean/commands.ts +43 -0
- package/src/commands/clean/flutter.ts +9 -13
- package/src/commands/clean/ios.ts +13 -13
- package/src/commands/config/aliases.ts +150 -0
- package/src/commands/config/commands.ts +50 -0
- package/src/commands/config/initApp.ts +213 -0
- package/src/commands/config/rollback.ts +16 -4
- package/src/commands/config/upgrade.ts +40 -0
- package/src/commands/mcp/commands.ts +23 -0
- package/src/commands/mcp/server.ts +35 -0
- package/src/commands/mcp/setup.ts +69 -0
- package/src/commands/mcp/tools.ts +365 -0
- package/src/commands/project/commands.ts +132 -0
- package/src/commands/project/devices.ts +11 -24
- package/src/commands/project/doctor.ts +81 -0
- package/src/commands/project/generate.ts +211 -32
- package/src/commands/project/setup.ts +13 -30
- package/src/commands/project/status.ts +72 -0
- package/src/commands/version/bump.ts +124 -85
- package/src/commands/version/commands.ts +76 -0
- package/src/commands/version/update.ts +86 -75
- package/src/constants.ts +7 -1
- package/src/styles.ts +49 -7
- package/src/utils/helpers/error.ts +16 -0
- package/src/utils/helpers/file.ts +1 -1
- package/src/utils/helpers/version.ts +2 -1
- package/src/utils/services/backup.ts +17 -1
- package/src/utils/services/command.ts +1 -58
- package/src/utils/services/exec.ts +92 -117
- package/src/utils/services/logger.ts +12 -4
- package/src/utils/validators/validation.ts +24 -12
- package/CODE_QUALITY.md +0 -398
- package/ENHANCEMENTS.md +0 -310
- package/FEATURE_ENHANCEMENTS.md +0 -435
- package/INSTALLATION.md +0 -118
- package/SAFETY_FEATURES.md +0 -396
- package/TROUBLESHOOT.md +0 -60
- package/USAGE.md +0 -388
- package/VERSION_MANAGEMENT.md +0 -438
package/dist/cli.js
CHANGED
|
@@ -1,251 +1,85 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
// MCP mode: redirect all console output to stderr before any imports
|
|
3
|
+
const isMcpMode = process.argv.includes("mcp");
|
|
4
|
+
if (isMcpMode) {
|
|
5
|
+
const origLog = console.log;
|
|
6
|
+
console.log = (...args) => console.error(...args);
|
|
7
|
+
// Restore for JSON-RPC (SDK uses process.stdout directly)
|
|
8
|
+
void origLog;
|
|
9
|
+
}
|
|
2
10
|
import chalk from "chalk";
|
|
3
11
|
import boxen from "boxen";
|
|
4
12
|
import yargs from "yargs/yargs";
|
|
5
13
|
import { hideBin } from "yargs/helpers";
|
|
6
|
-
import { generateModule } from "./commands/project/generate.js";
|
|
7
|
-
import { cleanProject } from "./commands/clean/flutter.js";
|
|
8
|
-
import { cleanIosProject } from "./commands/clean/ios.js";
|
|
9
|
-
import { updateFlutterVersion } from "./commands/version/update.js";
|
|
10
|
-
import { buildFlutterApk, buildFlutterBundle, buildFlutterIos, buildFlutterIpa, } from "./commands/build/releases.js";
|
|
11
|
-
import { boxenOptions } from "./styles.js";
|
|
12
|
-
import { openIos, openAndroid, openIpaOutput, openBundleOutput, openApkOutput } from "./commands/project/open.js";
|
|
13
14
|
import { createRequire } from "module";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
import {
|
|
15
|
+
import { bannerBoxOptions, createBanner } from "./styles.js";
|
|
16
|
+
import { loadConfig } from "./utils/services/config.js";
|
|
17
|
+
import { setDryRunMode } from "./utils/helpers/dryRun.js";
|
|
18
|
+
// Command modules
|
|
19
|
+
import { buildCommands } from "./commands/build/commands.js";
|
|
20
|
+
import { cleanCommands } from "./commands/clean/commands.js";
|
|
21
|
+
import { versionCommands } from "./commands/version/commands.js";
|
|
22
|
+
import { projectCommands } from "./commands/project/commands.js";
|
|
23
|
+
import { configCommands } from "./commands/config/commands.js";
|
|
24
|
+
import { mcpCommands } from "./commands/mcp/commands.js";
|
|
19
25
|
const require = createRequire(import.meta.url);
|
|
20
26
|
const packageInfo = require("../package.json");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
console.log(boxen(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
default: false,
|
|
49
|
-
description: "Run with CocoaPods cache cleaning (use --clean-cache to enable)",
|
|
50
|
-
})
|
|
51
|
-
.option("repo-update", {
|
|
52
|
-
type: "boolean",
|
|
53
|
-
default: false,
|
|
54
|
-
description: "Run pod install with repository update (use --repo-update to enable)",
|
|
55
|
-
});
|
|
56
|
-
}, (argv) => {
|
|
57
|
-
const cleanCache = argv.cleanCache;
|
|
58
|
-
const repoUpdate = argv.repoUpdate;
|
|
59
|
-
cleanIosProject(cleanCache, repoUpdate);
|
|
60
|
-
})
|
|
61
|
-
.command("flutter-build-apk", "Build the Flutter APK with release configuration, obfuscation, and split debug info", (yargs) => {
|
|
62
|
-
return yargs.option("disable-fvm", {
|
|
63
|
-
type: "boolean",
|
|
64
|
-
default: false,
|
|
65
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
66
|
-
});
|
|
67
|
-
}, async (argv) => {
|
|
68
|
-
const noFvm = argv.disableFvm;
|
|
69
|
-
await buildFlutterApk(noFvm);
|
|
70
|
-
})
|
|
71
|
-
.command("flutter-build-bundle", "Build the Flutter Bundle with release configuration, obfuscation, and split debug info", (yargs) => {
|
|
72
|
-
return yargs.option("disable-fvm", {
|
|
73
|
-
type: "boolean",
|
|
74
|
-
default: false,
|
|
75
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
76
|
-
});
|
|
77
|
-
}, async (argv) => {
|
|
78
|
-
const noFvm = argv.disableFvm;
|
|
79
|
-
await buildFlutterBundle(noFvm);
|
|
80
|
-
})
|
|
81
|
-
.command("flutter-build-ios", "Build the Flutter iOS app with release configuration and increment the build version", (yargs) => {
|
|
82
|
-
return yargs.option("disable-fvm", {
|
|
83
|
-
type: "boolean",
|
|
84
|
-
default: false,
|
|
85
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
86
|
-
});
|
|
87
|
-
}, async (argv) => {
|
|
88
|
-
const noFvm = argv.disableFvm;
|
|
89
|
-
await buildFlutterIos(noFvm);
|
|
90
|
-
})
|
|
91
|
-
.command("flutter-build-ipa", "Create a release IPA with an updated build version number", (yargs) => {
|
|
92
|
-
return yargs.option("disable-fvm", {
|
|
93
|
-
type: "boolean",
|
|
94
|
-
default: false,
|
|
95
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
96
|
-
});
|
|
97
|
-
}, async (argv) => {
|
|
98
|
-
const noFvm = argv.disableFvm;
|
|
99
|
-
await buildFlutterIpa(noFvm);
|
|
100
|
-
})
|
|
101
|
-
.command("flutter-update-version", "Update version and build numbers for both Android and iOS", (yargs) => {
|
|
102
|
-
return yargs
|
|
103
|
-
.option("app-version", {
|
|
104
|
-
type: "string",
|
|
105
|
-
description: "The version number to set for both Android and iOS",
|
|
106
|
-
demandOption: false,
|
|
107
|
-
default: "",
|
|
108
|
-
})
|
|
109
|
-
.option("android-build", {
|
|
110
|
-
type: "string",
|
|
111
|
-
description: "The Android build number to set in pubspec.yaml",
|
|
112
|
-
demandOption: false,
|
|
113
|
-
default: "",
|
|
114
|
-
})
|
|
115
|
-
.option("ios-build", {
|
|
116
|
-
type: "string",
|
|
117
|
-
description: "The iOS build number to set using agv-tool and Info.plist",
|
|
118
|
-
demandOption: false,
|
|
119
|
-
default: "",
|
|
120
|
-
});
|
|
121
|
-
}, async (argv) => {
|
|
122
|
-
const version = argv["app-version"];
|
|
123
|
-
const androidBuildNumber = argv["android-build"];
|
|
124
|
-
const iosBuildNumber = argv["ios-build"];
|
|
125
|
-
await updateFlutterVersion(version, androidBuildNumber, iosBuildNumber);
|
|
126
|
-
})
|
|
127
|
-
.command("open-ios", "Open the iOS project in Xcode", {}, async () => {
|
|
128
|
-
await openIos();
|
|
129
|
-
})
|
|
130
|
-
.command("open-android", "Open the Android project in Android Studio", {}, async () => {
|
|
131
|
-
await openAndroid();
|
|
132
|
-
})
|
|
133
|
-
.command("open-ipa", "Open the IPA build output directory", {}, async () => {
|
|
134
|
-
await openIpaOutput();
|
|
135
|
-
})
|
|
136
|
-
.command("open-apk", "Open the APK build output directory", {}, async () => {
|
|
137
|
-
await openApkOutput();
|
|
138
|
-
})
|
|
139
|
-
.command("open-bundle", "Open the Android Bundle build output directory", {}, async () => {
|
|
140
|
-
await openBundleOutput();
|
|
141
|
-
})
|
|
142
|
-
.command("setup-vscode", "Create a .vscode folder with recommended Flutter settings", () => { }, async () => {
|
|
143
|
-
await createVscodeSettings();
|
|
144
|
-
})
|
|
145
|
-
.command("init", "Initialize OptiKit configuration in the current project", () => { }, async () => {
|
|
146
|
-
await initializeProject();
|
|
147
|
-
})
|
|
148
|
-
.command("rollback", "List and restore files from OptiKit backups", (yargs) => {
|
|
149
|
-
return yargs.option("restore", {
|
|
150
|
-
type: "number",
|
|
151
|
-
description: "Restore backup by index number",
|
|
152
|
-
demandOption: false,
|
|
153
|
-
});
|
|
154
|
-
}, async (argv) => {
|
|
155
|
-
const restoreIndex = argv.restore;
|
|
156
|
-
if (restoreIndex !== undefined) {
|
|
157
|
-
await rollbackRestore(restoreIndex);
|
|
27
|
+
// Greeting banner (skip in MCP mode — stdout is reserved for JSON-RPC)
|
|
28
|
+
if (!isMcpMode) {
|
|
29
|
+
console.log(boxen(createBanner(packageInfo.version), bannerBoxOptions));
|
|
30
|
+
}
|
|
31
|
+
// Load config once
|
|
32
|
+
const config = loadConfig();
|
|
33
|
+
// Collect all commands
|
|
34
|
+
const allCommands = [
|
|
35
|
+
...buildCommands,
|
|
36
|
+
...cleanCommands,
|
|
37
|
+
...versionCommands,
|
|
38
|
+
...projectCommands,
|
|
39
|
+
...configCommands,
|
|
40
|
+
...mcpCommands,
|
|
41
|
+
];
|
|
42
|
+
// Build CLI
|
|
43
|
+
const cli = yargs(hideBin(process.argv))
|
|
44
|
+
.scriptName("optikit")
|
|
45
|
+
.option("dry-run", {
|
|
46
|
+
type: "boolean",
|
|
47
|
+
default: false,
|
|
48
|
+
description: "Preview operations without executing them",
|
|
49
|
+
global: true,
|
|
50
|
+
})
|
|
51
|
+
.middleware((argv) => {
|
|
52
|
+
if (argv.dryRun) {
|
|
53
|
+
setDryRunMode(true);
|
|
158
54
|
}
|
|
159
|
-
|
|
160
|
-
|
|
55
|
+
if (config.useFvmByDefault === false && !process.argv.includes("--disable-fvm")) {
|
|
56
|
+
argv.disableFvm = true;
|
|
161
57
|
}
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
await listDevices(useFvm);
|
|
191
|
-
})
|
|
192
|
-
.command("run", "Run Flutter app on connected device", (yargs) => {
|
|
193
|
-
return yargs
|
|
194
|
-
.option("device", {
|
|
195
|
-
alias: "d",
|
|
196
|
-
type: "string",
|
|
197
|
-
description: "Specific device ID to run on",
|
|
198
|
-
})
|
|
199
|
-
.option("release", {
|
|
200
|
-
alias: "r",
|
|
201
|
-
type: "boolean",
|
|
202
|
-
default: false,
|
|
203
|
-
description: "Run in release mode",
|
|
204
|
-
})
|
|
205
|
-
.option("flavor", {
|
|
206
|
-
alias: "f",
|
|
207
|
-
type: "string",
|
|
208
|
-
description: "Build flavor to use",
|
|
209
|
-
})
|
|
210
|
-
.option("disable-fvm", {
|
|
211
|
-
type: "boolean",
|
|
212
|
-
default: false,
|
|
213
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
214
|
-
});
|
|
215
|
-
}, async (argv) => {
|
|
216
|
-
const useFvm = !argv.disableFvm;
|
|
217
|
-
await runApp({
|
|
218
|
-
device: argv.device,
|
|
219
|
-
release: argv.release,
|
|
220
|
-
flavor: argv.flavor,
|
|
221
|
-
useFvm,
|
|
222
|
-
});
|
|
223
|
-
})
|
|
224
|
-
.command("run-select", "Interactive device selection and run", (yargs) => {
|
|
225
|
-
return yargs
|
|
226
|
-
.option("release", {
|
|
227
|
-
alias: "r",
|
|
228
|
-
type: "boolean",
|
|
229
|
-
default: false,
|
|
230
|
-
description: "Run in release mode",
|
|
231
|
-
})
|
|
232
|
-
.option("flavor", {
|
|
233
|
-
alias: "f",
|
|
234
|
-
type: "string",
|
|
235
|
-
description: "Build flavor to use",
|
|
236
|
-
})
|
|
237
|
-
.option("disable-fvm", {
|
|
238
|
-
type: "boolean",
|
|
239
|
-
default: false,
|
|
240
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
241
|
-
});
|
|
242
|
-
}, async (argv) => {
|
|
243
|
-
const useFvm = !argv.disableFvm;
|
|
244
|
-
await runAppInteractive({
|
|
245
|
-
release: argv.release,
|
|
246
|
-
flavor: argv.flavor,
|
|
247
|
-
useFvm,
|
|
248
|
-
});
|
|
249
|
-
})
|
|
250
|
-
.version(version)
|
|
251
|
-
.help(true).argv;
|
|
58
|
+
});
|
|
59
|
+
// Register all commands
|
|
60
|
+
for (const command of allCommands) {
|
|
61
|
+
cli.command(command);
|
|
62
|
+
}
|
|
63
|
+
cli
|
|
64
|
+
.completion("completion", "Generate shell completion script")
|
|
65
|
+
.usage(chalk.white.bold("\nUsage:") + chalk.gray(" optikit <command> [options]"))
|
|
66
|
+
.epilogue(chalk.cyan.bold("\nQuick Reference") + chalk.gray(" (use ok or optikit — both work)\n") +
|
|
67
|
+
"\n" +
|
|
68
|
+
chalk.cyan(" Build ") + chalk.white.bold("apk aab ios ipa tf") + chalk.gray(" (testflight)\n") +
|
|
69
|
+
chalk.cyan(" Clean ") + chalk.white.bold("c") + chalk.gray(" (flutter) ") + chalk.white.bold("ci") + chalk.gray(" (iOS) ") + chalk.white.bold("c -a") + chalk.gray(" (all)\n") +
|
|
70
|
+
chalk.cyan(" Bump ") + chalk.white.bold("bump <type> bi ba bb\n") +
|
|
71
|
+
chalk.cyan(" Version ") + chalk.white.bold("v") + chalk.gray(" (show) ") + chalk.white.bold("vset") + chalk.gray(" (set manually)\n") +
|
|
72
|
+
chalk.cyan(" Generate ") + chalk.white.bold("gen module <name> gen repo <name> route <name>\n") +
|
|
73
|
+
chalk.cyan(" Run ") + chalk.white.bold("run rs") + chalk.gray(" (interactive) ") + chalk.white.bold("devs") + chalk.gray(" (list devices)\n") +
|
|
74
|
+
chalk.cyan(" Open ") + chalk.white.bold("xcode studio\n") +
|
|
75
|
+
chalk.cyan(" Config ") + chalk.white.bold("init vscode undo up\n") +
|
|
76
|
+
chalk.cyan(" Info ") + chalk.white.bold("info dr aliases\n") +
|
|
77
|
+
chalk.cyan(" MCP ") + chalk.white.bold("mcp setup-claude\n") +
|
|
78
|
+
"\n" +
|
|
79
|
+
chalk.cyan(" Combos ") + chalk.green("ok apk --clean -o") + chalk.gray(" | ") + chalk.green("ok ipa -b patch -o") + chalk.gray(" | ") + chalk.green("ok tf -o") +
|
|
80
|
+
"\n\n" +
|
|
81
|
+
chalk.gray(" Run ") + chalk.white("optikit <command> --help") + chalk.gray(" for details | ") +
|
|
82
|
+
chalk.white("optikit aliases") + chalk.gray(" for full reference"))
|
|
83
|
+
.version(packageInfo.version)
|
|
84
|
+
.help(true)
|
|
85
|
+
.argv;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { buildFlutterApk, buildFlutterBundle, buildFlutterIos, buildFlutterIpa, } from "./releases.js";
|
|
2
|
+
import { cleanProject } from "../clean/flutter.js";
|
|
3
|
+
import { cleanIosProject } from "../clean/ios.js";
|
|
4
|
+
import { bumpVersion, bumpIosBuildOnly } from "../version/bump.js";
|
|
5
|
+
import { openApkOutput, openBundleOutput, openIpaOutput } from "../project/open.js";
|
|
6
|
+
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
7
|
+
import { runTestflight } from "./testflight.js";
|
|
8
|
+
const buildOptions = {
|
|
9
|
+
"disable-fvm": {
|
|
10
|
+
alias: "f",
|
|
11
|
+
type: "boolean",
|
|
12
|
+
default: false,
|
|
13
|
+
description: "Run without FVM",
|
|
14
|
+
},
|
|
15
|
+
clean: {
|
|
16
|
+
type: "boolean",
|
|
17
|
+
default: false,
|
|
18
|
+
description: "Clean before building",
|
|
19
|
+
},
|
|
20
|
+
open: {
|
|
21
|
+
alias: "o",
|
|
22
|
+
type: "boolean",
|
|
23
|
+
default: false,
|
|
24
|
+
description: "Open output directory after build",
|
|
25
|
+
},
|
|
26
|
+
bump: {
|
|
27
|
+
alias: "b",
|
|
28
|
+
type: "string",
|
|
29
|
+
choices: ["major", "minor", "patch"],
|
|
30
|
+
description: "Bump version before building",
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
const ipaOptions = {
|
|
34
|
+
...buildOptions,
|
|
35
|
+
"bump-ios": {
|
|
36
|
+
alias: "i",
|
|
37
|
+
type: "boolean",
|
|
38
|
+
default: false,
|
|
39
|
+
description: "Bump iOS build number before building",
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
async function runPreBuild(flags, isIosBuild) {
|
|
43
|
+
// 1. Bump version
|
|
44
|
+
if (flags.bump) {
|
|
45
|
+
LoggerHelpers.step(`Bumping ${flags.bump} version...`);
|
|
46
|
+
await bumpVersion(flags.bump, true);
|
|
47
|
+
}
|
|
48
|
+
if (flags.bumpIos) {
|
|
49
|
+
LoggerHelpers.step("Bumping iOS build number...");
|
|
50
|
+
await bumpIosBuildOnly(true);
|
|
51
|
+
}
|
|
52
|
+
// 2. Clean
|
|
53
|
+
if (flags.clean) {
|
|
54
|
+
LoggerHelpers.step("Cleaning project...");
|
|
55
|
+
await cleanProject(flags.disableFvm);
|
|
56
|
+
if (isIosBuild) {
|
|
57
|
+
await cleanIosProject(false, false);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function runPostBuild(flags, openFn) {
|
|
62
|
+
// 4. Open output
|
|
63
|
+
if (flags.open) {
|
|
64
|
+
await openFn();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function parseFlags(argv) {
|
|
68
|
+
return {
|
|
69
|
+
disableFvm: argv.disableFvm,
|
|
70
|
+
clean: argv.clean,
|
|
71
|
+
open: argv.open,
|
|
72
|
+
bump: argv.bump,
|
|
73
|
+
bumpIos: argv.bumpIos,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export const buildCommands = [
|
|
77
|
+
{
|
|
78
|
+
command: "flutter-build-apk",
|
|
79
|
+
aliases: ["apk"],
|
|
80
|
+
describe: "Build the Flutter APK with release configuration, obfuscation, and split debug info",
|
|
81
|
+
builder: buildOptions,
|
|
82
|
+
handler: async (argv) => {
|
|
83
|
+
const flags = parseFlags(argv);
|
|
84
|
+
await runPreBuild(flags, false);
|
|
85
|
+
await buildFlutterApk(flags.disableFvm);
|
|
86
|
+
await runPostBuild(flags, openApkOutput);
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
command: "flutter-build-bundle",
|
|
91
|
+
aliases: ["aab"],
|
|
92
|
+
describe: "Build the Flutter Bundle with release configuration, obfuscation, and split debug info",
|
|
93
|
+
builder: buildOptions,
|
|
94
|
+
handler: async (argv) => {
|
|
95
|
+
const flags = parseFlags(argv);
|
|
96
|
+
await runPreBuild(flags, false);
|
|
97
|
+
await buildFlutterBundle(flags.disableFvm);
|
|
98
|
+
await runPostBuild(flags, openBundleOutput);
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
command: "flutter-build-ios",
|
|
103
|
+
aliases: ["ios"],
|
|
104
|
+
describe: "Build the Flutter iOS app with release configuration and increment the build version",
|
|
105
|
+
builder: buildOptions,
|
|
106
|
+
handler: async (argv) => {
|
|
107
|
+
const flags = parseFlags(argv);
|
|
108
|
+
await runPreBuild(flags, true);
|
|
109
|
+
await buildFlutterIos(flags.disableFvm);
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
command: "flutter-build-ipa",
|
|
114
|
+
aliases: ["ipa"],
|
|
115
|
+
describe: "Create a release IPA with an updated build version number",
|
|
116
|
+
builder: ipaOptions,
|
|
117
|
+
handler: async (argv) => {
|
|
118
|
+
const flags = parseFlags(argv);
|
|
119
|
+
await runPreBuild(flags, true);
|
|
120
|
+
await buildFlutterIpa(flags.disableFvm);
|
|
121
|
+
await runPostBuild(flags, openIpaOutput);
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
command: "testflight",
|
|
126
|
+
aliases: ["tf"],
|
|
127
|
+
describe: "Bump iOS build number and build IPA (TestFlight workflow)",
|
|
128
|
+
builder: {
|
|
129
|
+
"disable-fvm": {
|
|
130
|
+
alias: "f",
|
|
131
|
+
type: "boolean",
|
|
132
|
+
default: false,
|
|
133
|
+
description: "Run without FVM",
|
|
134
|
+
},
|
|
135
|
+
open: {
|
|
136
|
+
alias: "o",
|
|
137
|
+
type: "boolean",
|
|
138
|
+
default: false,
|
|
139
|
+
description: "Open IPA output directory after build",
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
handler: async (argv) => {
|
|
143
|
+
await runTestflight(argv.disableFvm, argv.open);
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { bumpIosBuildOnly } from "../version/bump.js";
|
|
2
|
+
import { buildFlutterIpa } from "./releases.js";
|
|
3
|
+
import { openIpaOutput } from "../project/open.js";
|
|
4
|
+
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
5
|
+
export { runTestflight };
|
|
6
|
+
async function runTestflight(disableFvm, open) {
|
|
7
|
+
LoggerHelpers.step("Bumping iOS build number...");
|
|
8
|
+
await bumpIosBuildOnly(true);
|
|
9
|
+
LoggerHelpers.step("Building IPA...");
|
|
10
|
+
await buildFlutterIpa(disableFvm);
|
|
11
|
+
if (open) {
|
|
12
|
+
await openIpaOutput();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { cleanProject } from "./flutter.js";
|
|
2
|
+
import { cleanIosProject } from "./ios.js";
|
|
3
|
+
export const cleanCommands = [
|
|
4
|
+
{
|
|
5
|
+
command: "clean",
|
|
6
|
+
aliases: ["c"],
|
|
7
|
+
describe: "Clean Flutter project (add --ios or --all for iOS)",
|
|
8
|
+
builder: {
|
|
9
|
+
ios: { alias: "i", type: "boolean", default: false, description: "Also clean iOS project (pods)" },
|
|
10
|
+
all: { alias: "a", type: "boolean", default: false, description: "Clean both Flutter and iOS" },
|
|
11
|
+
"disable-fvm": { alias: "f", type: "boolean", default: false, description: "Run without FVM" },
|
|
12
|
+
"clean-cache": { alias: "c", type: "boolean", default: false, description: "Clean CocoaPods cache (iOS only)" },
|
|
13
|
+
"repo-update": { alias: "u", type: "boolean", default: false, description: "Update CocoaPods repo (iOS only)" },
|
|
14
|
+
},
|
|
15
|
+
handler: async (argv) => {
|
|
16
|
+
await cleanProject(argv.disableFvm);
|
|
17
|
+
if (argv.ios || argv.all) {
|
|
18
|
+
await cleanIosProject(argv.cleanCache, argv.repoUpdate);
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
command: "clean-flutter",
|
|
24
|
+
aliases: ["cf"],
|
|
25
|
+
describe: "Clean the Flutter project",
|
|
26
|
+
builder: {
|
|
27
|
+
"disable-fvm": { alias: "f", type: "boolean", default: false, description: "Run without FVM" },
|
|
28
|
+
},
|
|
29
|
+
handler: (argv) => { cleanProject(argv.disableFvm); },
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
command: "clean-ios",
|
|
33
|
+
aliases: ["ci"],
|
|
34
|
+
describe: "Clean the iOS project",
|
|
35
|
+
builder: {
|
|
36
|
+
"clean-cache": { alias: "c", type: "boolean", default: false, description: "Clean CocoaPods cache" },
|
|
37
|
+
"repo-update": { alias: "u", type: "boolean", default: false, description: "Update CocoaPods repo" },
|
|
38
|
+
},
|
|
39
|
+
handler: (argv) => { cleanIosProject(argv.cleanCache, argv.repoUpdate); },
|
|
40
|
+
},
|
|
41
|
+
];
|
|
@@ -3,7 +3,9 @@ import path from "path";
|
|
|
3
3
|
import { execCommand } from "../../utils/services/exec.js";
|
|
4
4
|
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
5
5
|
import { validateFlutterProject, validateFlutterSdk } from "../../utils/validators/validation.js";
|
|
6
|
-
import {
|
|
6
|
+
import { createBackupWithCleanup } from "../../utils/services/backup.js";
|
|
7
|
+
import { handleCommandError } from "../../utils/helpers/error.js";
|
|
8
|
+
import { getFlutterCommand } from "../../utils/services/command.js";
|
|
7
9
|
export { cleanProject };
|
|
8
10
|
async function cleanProject(noFvm) {
|
|
9
11
|
LoggerHelpers.info(noFvm ? "Running clean without FVM..." : "Running clean with FVM...");
|
|
@@ -15,17 +17,16 @@ async function cleanProject(noFvm) {
|
|
|
15
17
|
process.exit(1);
|
|
16
18
|
}
|
|
17
19
|
try {
|
|
20
|
+
const useFvm = !noFvm;
|
|
18
21
|
// Step 1: Run flutter clean
|
|
19
|
-
const flutterCommand = noFvm ? "flutter clean" : "fvm flutter clean";
|
|
20
22
|
LoggerHelpers.info("Running Flutter clean...");
|
|
21
|
-
await execCommand(
|
|
23
|
+
await execCommand(getFlutterCommand("flutter clean", useFvm));
|
|
22
24
|
LoggerHelpers.success("Flutter clean completed.");
|
|
23
25
|
// Step 2: Remove pubspec.lock using Node.js fs (cross-platform)
|
|
24
26
|
const pubspecLockPath = path.join(process.cwd(), "pubspec.lock");
|
|
25
27
|
if (fs.existsSync(pubspecLockPath)) {
|
|
26
28
|
LoggerHelpers.info("Removing pubspec.lock...");
|
|
27
|
-
|
|
28
|
-
createBackup(pubspecLockPath);
|
|
29
|
+
createBackupWithCleanup(pubspecLockPath);
|
|
29
30
|
fs.unlinkSync(pubspecLockPath);
|
|
30
31
|
LoggerHelpers.success("pubspec.lock removed.");
|
|
31
32
|
}
|
|
@@ -33,19 +34,12 @@ async function cleanProject(noFvm) {
|
|
|
33
34
|
LoggerHelpers.info("pubspec.lock does not exist, skipping removal.");
|
|
34
35
|
}
|
|
35
36
|
// Step 3: Run flutter pub get
|
|
36
|
-
const pubGetCommand = noFvm ? "flutter pub get" : "fvm flutter pub get";
|
|
37
37
|
LoggerHelpers.info("Running Flutter pub get...");
|
|
38
|
-
await execCommand(
|
|
38
|
+
await execCommand(getFlutterCommand("flutter pub get", useFvm));
|
|
39
39
|
LoggerHelpers.success("Flutter pub get completed.");
|
|
40
40
|
LoggerHelpers.success("Project cleaned successfully.");
|
|
41
41
|
}
|
|
42
42
|
catch (error) {
|
|
43
|
-
|
|
44
|
-
LoggerHelpers.error(`Error during clean: ${error.message}`);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
LoggerHelpers.error(`Error during clean: ${error}`);
|
|
48
|
-
}
|
|
49
|
-
process.exit(1);
|
|
43
|
+
handleCommandError(error, "Error during clean");
|
|
50
44
|
}
|
|
51
45
|
}
|
|
@@ -3,6 +3,8 @@ import * as path from "path";
|
|
|
3
3
|
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
4
4
|
import { execInIos, execCommand, iosDirectory, execInIosWithRetry } from "../../utils/services/exec.js";
|
|
5
5
|
import { validateFlutterProject, validateIosProject } from "../../utils/validators/validation.js";
|
|
6
|
+
import { FLUTTER_COMMANDS, FVM_COMMANDS, RETRY_CONFIG } from "../../constants.js";
|
|
7
|
+
import { handleCommandError } from "../../utils/helpers/error.js";
|
|
6
8
|
export { cleanIosProject };
|
|
7
9
|
async function getFlutterSdkPath() {
|
|
8
10
|
const fvmDir = path.join(process.cwd(), ".fvm", "flutter_sdk");
|
|
@@ -29,9 +31,13 @@ async function ensureFlutterArtifactsExist() {
|
|
|
29
31
|
const flutterXcframeworkPath = await getFlutterXcframeworkPath();
|
|
30
32
|
if (!fs.existsSync(flutterXcframeworkPath)) {
|
|
31
33
|
LoggerHelpers.warning("Flutter.xcframework not found.");
|
|
34
|
+
const useFvm = fs.existsSync(path.join(process.cwd(), ".fvm", "flutter_sdk"));
|
|
35
|
+
const precacheCommand = useFvm
|
|
36
|
+
? FVM_COMMANDS.PRECACHE_IOS
|
|
37
|
+
: FLUTTER_COMMANDS.PRECACHE_IOS;
|
|
32
38
|
try {
|
|
33
39
|
LoggerHelpers.info("Downloading Flutter.xcframework...");
|
|
34
|
-
await execCommand(
|
|
40
|
+
await execCommand(precacheCommand);
|
|
35
41
|
LoggerHelpers.success("Flutter.xcframework has been downloaded successfully.");
|
|
36
42
|
}
|
|
37
43
|
catch (error) {
|
|
@@ -39,7 +45,7 @@ async function ensureFlutterArtifactsExist() {
|
|
|
39
45
|
}
|
|
40
46
|
}
|
|
41
47
|
else {
|
|
42
|
-
LoggerHelpers.success("Flutter.xcframework exists. No need to run
|
|
48
|
+
LoggerHelpers.success("Flutter.xcframework exists. No need to run precache.");
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
async function cleanIosProject(cleanCache, repoUpdate) {
|
|
@@ -73,7 +79,7 @@ async function cleanIosProject(cleanCache, repoUpdate) {
|
|
|
73
79
|
if (repoUpdate) {
|
|
74
80
|
LoggerHelpers.info("Updating CocoaPods repositories...");
|
|
75
81
|
try {
|
|
76
|
-
await execInIosWithRetry("pod repo update",
|
|
82
|
+
await execInIosWithRetry("pod repo update", RETRY_CONFIG.DEFAULT_ATTEMPTS, RETRY_CONFIG.DEFAULT_DELAY_MS);
|
|
77
83
|
LoggerHelpers.success("Updated CocoaPods repositories.");
|
|
78
84
|
}
|
|
79
85
|
catch (error) {
|
|
@@ -81,7 +87,7 @@ async function cleanIosProject(cleanCache, repoUpdate) {
|
|
|
81
87
|
}
|
|
82
88
|
LoggerHelpers.info("Installing pods with repo update...");
|
|
83
89
|
try {
|
|
84
|
-
await execInIosWithRetry("pod update",
|
|
90
|
+
await execInIosWithRetry("pod update", RETRY_CONFIG.DEFAULT_ATTEMPTS, RETRY_CONFIG.DEFAULT_DELAY_MS);
|
|
85
91
|
LoggerHelpers.success("Installed pods with repo update.");
|
|
86
92
|
}
|
|
87
93
|
catch (error) {
|
|
@@ -90,20 +96,11 @@ async function cleanIosProject(cleanCache, repoUpdate) {
|
|
|
90
96
|
}
|
|
91
97
|
else {
|
|
92
98
|
LoggerHelpers.info("Installing pods without repo update...");
|
|
93
|
-
await execInIosWithRetry("pod install",
|
|
99
|
+
await execInIosWithRetry("pod install", RETRY_CONFIG.DEFAULT_ATTEMPTS, RETRY_CONFIG.DEFAULT_DELAY_MS);
|
|
94
100
|
LoggerHelpers.success("Installed pods without repo update.");
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
catch (error) {
|
|
98
|
-
|
|
99
|
-
LoggerHelpers.error(`Error: ${error.message}`);
|
|
100
|
-
}
|
|
101
|
-
else if (typeof error === "string") {
|
|
102
|
-
LoggerHelpers.error(`Error: ${error}`);
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
LoggerHelpers.error(`Unknown error: ${JSON.stringify(error)}`);
|
|
106
|
-
}
|
|
107
|
-
process.exit(1);
|
|
104
|
+
handleCommandError(error, "Error cleaning iOS project");
|
|
108
105
|
}
|
|
109
106
|
}
|