optikit 1.2.5 → 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 +67 -98
- package/CLAUDE.md +57 -206
- package/OPTIKIT_AGENT.md +398 -0
- package/README.md +293 -60
- package/dist/cli.js +75 -244
- 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 +75 -101
- 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 -371
- 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 +98 -110
- 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 -412
- package/VERSION_MANAGEMENT.md +0 -438
package/src/cli.ts
CHANGED
|
@@ -1,387 +1,98 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// MCP mode: redirect all console output to stderr before any imports
|
|
4
|
+
const isMcpMode = process.argv.includes("mcp");
|
|
5
|
+
if (isMcpMode) {
|
|
6
|
+
const origLog = console.log;
|
|
7
|
+
console.log = (...args: unknown[]) => console.error(...args);
|
|
8
|
+
// Restore for JSON-RPC (SDK uses process.stdout directly)
|
|
9
|
+
void origLog;
|
|
10
|
+
}
|
|
11
|
+
|
|
3
12
|
import chalk from "chalk";
|
|
4
13
|
import boxen from "boxen";
|
|
5
14
|
import yargs from "yargs/yargs";
|
|
6
15
|
import { hideBin } from "yargs/helpers";
|
|
7
|
-
import {
|
|
8
|
-
import { cleanProject } from "./commands/clean/flutter.js";
|
|
9
|
-
import { cleanIosProject } from "./commands/clean/ios.js";
|
|
10
|
-
import { updateFlutterVersion } from "./commands/version/update.js";
|
|
11
|
-
import {
|
|
12
|
-
buildFlutterApk,
|
|
13
|
-
buildFlutterBundle,
|
|
14
|
-
buildFlutterIos,
|
|
15
|
-
buildFlutterIpa,
|
|
16
|
-
} from "./commands/build/releases.js";
|
|
17
|
-
import { boxenOptions } from "./styles.js";
|
|
18
|
-
import { openIos, openAndroid, openIpaOutput, openBundleOutput, openApkOutput } from "./commands/project/open.js";
|
|
16
|
+
import type { CommandModule } from "yargs";
|
|
19
17
|
import { createRequire } from "module";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from "./commands/
|
|
30
|
-
import {
|
|
18
|
+
import { bannerBoxOptions, createBanner } from "./styles.js";
|
|
19
|
+
import { loadConfig } from "./utils/services/config.js";
|
|
20
|
+
import { setDryRunMode } from "./utils/helpers/dryRun.js";
|
|
21
|
+
|
|
22
|
+
// Command modules
|
|
23
|
+
import { buildCommands } from "./commands/build/commands.js";
|
|
24
|
+
import { cleanCommands } from "./commands/clean/commands.js";
|
|
25
|
+
import { versionCommands } from "./commands/version/commands.js";
|
|
26
|
+
import { projectCommands } from "./commands/project/commands.js";
|
|
27
|
+
import { configCommands } from "./commands/config/commands.js";
|
|
28
|
+
import { mcpCommands } from "./commands/mcp/commands.js";
|
|
29
|
+
|
|
31
30
|
const require = createRequire(import.meta.url);
|
|
32
31
|
const packageInfo: { version: string } = require("../package.json");
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
// Greeting banner (skip in MCP mode — stdout is reserved for JSON-RPC)
|
|
34
|
+
if (!isMcpMode) {
|
|
35
|
+
console.log(boxen(createBanner(packageInfo.version), bannerBoxOptions));
|
|
36
|
+
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
// Load config once
|
|
39
|
+
const config = loadConfig();
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
},
|
|
49
|
-
(argv) => {
|
|
50
|
-
const moduleName = argv.moduleName as string;
|
|
51
|
-
generateModule(moduleName);
|
|
52
|
-
}
|
|
53
|
-
)
|
|
54
|
-
.command(
|
|
55
|
-
"clean-flutter",
|
|
56
|
-
"Clean the Flutter project",
|
|
57
|
-
(yargs) => {
|
|
58
|
-
return yargs.option("disable-fvm", {
|
|
59
|
-
type: "boolean",
|
|
60
|
-
default: false,
|
|
61
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
62
|
-
});
|
|
63
|
-
},
|
|
64
|
-
(argv) => {
|
|
65
|
-
const noFvm = argv.disableFvm as boolean;
|
|
66
|
-
cleanProject(noFvm);
|
|
67
|
-
}
|
|
68
|
-
)
|
|
69
|
-
.command(
|
|
70
|
-
"clean-ios",
|
|
71
|
-
"Clean the iOS project",
|
|
72
|
-
(yargs) => {
|
|
73
|
-
return yargs
|
|
74
|
-
.option("clean-cache", {
|
|
75
|
-
type: "boolean",
|
|
76
|
-
default: false,
|
|
77
|
-
description:
|
|
78
|
-
"Run with CocoaPods cache cleaning (use --clean-cache to enable)",
|
|
79
|
-
})
|
|
80
|
-
.option("repo-update", {
|
|
81
|
-
type: "boolean",
|
|
82
|
-
default: false,
|
|
83
|
-
description:
|
|
84
|
-
"Run pod install with repository update (use --repo-update to enable)",
|
|
85
|
-
});
|
|
86
|
-
},
|
|
87
|
-
(argv) => {
|
|
88
|
-
const cleanCache = argv.cleanCache as boolean;
|
|
89
|
-
const repoUpdate = argv.repoUpdate as boolean;
|
|
90
|
-
cleanIosProject(cleanCache, repoUpdate);
|
|
91
|
-
}
|
|
92
|
-
)
|
|
93
|
-
.command(
|
|
94
|
-
"flutter-build-apk",
|
|
95
|
-
"Build the Flutter APK with release configuration, obfuscation, and split debug info",
|
|
96
|
-
(yargs) => {
|
|
97
|
-
return yargs.option("disable-fvm", {
|
|
98
|
-
type: "boolean",
|
|
99
|
-
default: false,
|
|
100
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
101
|
-
});
|
|
102
|
-
},
|
|
103
|
-
async (argv) => {
|
|
104
|
-
const noFvm = argv.disableFvm as boolean;
|
|
105
|
-
await buildFlutterApk(noFvm);
|
|
106
|
-
}
|
|
107
|
-
)
|
|
108
|
-
.command(
|
|
109
|
-
"flutter-build-bundle",
|
|
110
|
-
"Build the Flutter Bundle with release configuration, obfuscation, and split debug info",
|
|
111
|
-
(yargs) => {
|
|
112
|
-
return yargs.option("disable-fvm", {
|
|
113
|
-
type: "boolean",
|
|
114
|
-
default: false,
|
|
115
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
116
|
-
});
|
|
117
|
-
},
|
|
118
|
-
async (argv) => {
|
|
119
|
-
const noFvm = argv.disableFvm as boolean;
|
|
120
|
-
await buildFlutterBundle(noFvm);
|
|
121
|
-
}
|
|
122
|
-
)
|
|
123
|
-
.command(
|
|
124
|
-
"flutter-build-ios",
|
|
125
|
-
"Build the Flutter iOS app with release configuration and increment the build version",
|
|
126
|
-
(yargs) => {
|
|
127
|
-
return yargs.option("disable-fvm", {
|
|
128
|
-
type: "boolean",
|
|
129
|
-
default: false,
|
|
130
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
131
|
-
});
|
|
132
|
-
},
|
|
133
|
-
async (argv) => {
|
|
134
|
-
const noFvm = argv.disableFvm as boolean;
|
|
135
|
-
await buildFlutterIos(noFvm);
|
|
136
|
-
}
|
|
137
|
-
)
|
|
138
|
-
.command(
|
|
139
|
-
"flutter-build-ipa",
|
|
140
|
-
"Create a release IPA with an updated build version number",
|
|
141
|
-
(yargs) => {
|
|
142
|
-
return yargs.option("disable-fvm", {
|
|
143
|
-
type: "boolean",
|
|
144
|
-
default: false,
|
|
145
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
146
|
-
});
|
|
147
|
-
},
|
|
148
|
-
async (argv) => {
|
|
149
|
-
const noFvm = argv.disableFvm as boolean;
|
|
150
|
-
await buildFlutterIpa(noFvm);
|
|
151
|
-
}
|
|
152
|
-
)
|
|
153
|
-
.command(
|
|
154
|
-
"flutter-update-version",
|
|
155
|
-
"Update version and build numbers for both Android and iOS",
|
|
156
|
-
(yargs) => {
|
|
157
|
-
return yargs
|
|
158
|
-
.option("app-version", {
|
|
159
|
-
type: "string",
|
|
160
|
-
description: "The version number to set for both Android and iOS",
|
|
161
|
-
demandOption: false,
|
|
162
|
-
default: "",
|
|
163
|
-
})
|
|
164
|
-
.option("android-build", {
|
|
165
|
-
type: "string",
|
|
166
|
-
description: "The Android build number to set in pubspec.yaml",
|
|
167
|
-
demandOption: false,
|
|
168
|
-
default: "",
|
|
169
|
-
})
|
|
170
|
-
.option("ios-build", {
|
|
171
|
-
type: "string",
|
|
172
|
-
description:
|
|
173
|
-
"The iOS build number to set using agv-tool and Info.plist",
|
|
174
|
-
demandOption: false,
|
|
175
|
-
default: "",
|
|
176
|
-
});
|
|
177
|
-
},
|
|
178
|
-
async (argv) => {
|
|
179
|
-
const version = argv["app-version"];
|
|
180
|
-
const androidBuildNumber = argv["android-build"];
|
|
181
|
-
const iosBuildNumber = argv["ios-build"];
|
|
41
|
+
// Collect all commands
|
|
42
|
+
const allCommands: CommandModule[] = [
|
|
43
|
+
...buildCommands,
|
|
44
|
+
...cleanCommands,
|
|
45
|
+
...versionCommands,
|
|
46
|
+
...projectCommands,
|
|
47
|
+
...configCommands,
|
|
48
|
+
...mcpCommands,
|
|
49
|
+
];
|
|
182
50
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
)
|
|
186
|
-
.
|
|
187
|
-
|
|
51
|
+
// Build CLI
|
|
52
|
+
const cli = yargs(hideBin(process.argv))
|
|
53
|
+
.scriptName("optikit")
|
|
54
|
+
.option("dry-run", {
|
|
55
|
+
type: "boolean",
|
|
56
|
+
default: false,
|
|
57
|
+
description: "Preview operations without executing them",
|
|
58
|
+
global: true,
|
|
188
59
|
})
|
|
189
|
-
.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
{},
|
|
193
|
-
async () => {
|
|
194
|
-
await openAndroid();
|
|
60
|
+
.middleware((argv) => {
|
|
61
|
+
if (argv.dryRun) {
|
|
62
|
+
setDryRunMode(true);
|
|
195
63
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
"open-ipa",
|
|
199
|
-
"Open the IPA build output directory",
|
|
200
|
-
{},
|
|
201
|
-
async () => {
|
|
202
|
-
await openIpaOutput();
|
|
203
|
-
}
|
|
204
|
-
)
|
|
205
|
-
.command(
|
|
206
|
-
"open-apk",
|
|
207
|
-
"Open the APK build output directory",
|
|
208
|
-
{},
|
|
209
|
-
async () => {
|
|
210
|
-
await openApkOutput();
|
|
64
|
+
if (config.useFvmByDefault === false && !process.argv.includes("--disable-fvm")) {
|
|
65
|
+
argv.disableFvm = true;
|
|
211
66
|
}
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
)
|
|
221
|
-
.command
|
|
222
|
-
|
|
223
|
-
"
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
)
|
|
229
|
-
.
|
|
230
|
-
"
|
|
231
|
-
"
|
|
232
|
-
()
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
)
|
|
237
|
-
|
|
238
|
-
"
|
|
239
|
-
"
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
demandOption: false,
|
|
245
|
-
});
|
|
246
|
-
},
|
|
247
|
-
async (argv) => {
|
|
248
|
-
const restoreIndex = argv.restore as number | undefined;
|
|
249
|
-
if (restoreIndex !== undefined) {
|
|
250
|
-
await rollbackRestore(restoreIndex);
|
|
251
|
-
} else {
|
|
252
|
-
await rollbackFiles();
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
)
|
|
256
|
-
.command(
|
|
257
|
-
"bump <type>",
|
|
258
|
-
"Bump version (major, minor, or patch)",
|
|
259
|
-
(yargs) => {
|
|
260
|
-
return yargs.positional("type", {
|
|
261
|
-
describe: "Version bump type (major, minor, patch)",
|
|
262
|
-
type: "string",
|
|
263
|
-
choices: ["major", "minor", "patch"],
|
|
264
|
-
});
|
|
265
|
-
},
|
|
266
|
-
async (argv) => {
|
|
267
|
-
const type = argv.type as 'major' | 'minor' | 'patch';
|
|
268
|
-
await bumpVersion(type);
|
|
269
|
-
}
|
|
270
|
-
)
|
|
271
|
-
.command(
|
|
272
|
-
"bump-ios",
|
|
273
|
-
"Increment iOS build number only (for TestFlight)",
|
|
274
|
-
() => {},
|
|
275
|
-
async () => {
|
|
276
|
-
await bumpIosBuildOnly();
|
|
277
|
-
}
|
|
278
|
-
)
|
|
279
|
-
.command(
|
|
280
|
-
"bump-android",
|
|
281
|
-
"Increment Android build number only",
|
|
282
|
-
() => {},
|
|
283
|
-
async () => {
|
|
284
|
-
await bumpAndroidBuildOnly();
|
|
285
|
-
}
|
|
286
|
-
)
|
|
287
|
-
.command(
|
|
288
|
-
"bump-build",
|
|
289
|
-
"Increment both Android and iOS build numbers",
|
|
290
|
-
() => {},
|
|
291
|
-
async () => {
|
|
292
|
-
await bumpBothBuilds();
|
|
293
|
-
}
|
|
294
|
-
)
|
|
295
|
-
.command(
|
|
296
|
-
"version",
|
|
297
|
-
"Show current version information",
|
|
298
|
-
() => {},
|
|
299
|
-
async () => {
|
|
300
|
-
await showCurrentVersion();
|
|
301
|
-
}
|
|
302
|
-
)
|
|
303
|
-
.command(
|
|
304
|
-
"devices",
|
|
305
|
-
"List all connected devices",
|
|
306
|
-
(yargs) => {
|
|
307
|
-
return yargs.option("disable-fvm", {
|
|
308
|
-
type: "boolean",
|
|
309
|
-
default: false,
|
|
310
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
311
|
-
});
|
|
312
|
-
},
|
|
313
|
-
async (argv) => {
|
|
314
|
-
const useFvm = !argv.disableFvm;
|
|
315
|
-
await listDevices(useFvm);
|
|
316
|
-
}
|
|
317
|
-
)
|
|
318
|
-
.command(
|
|
319
|
-
"run",
|
|
320
|
-
"Run Flutter app on connected device",
|
|
321
|
-
(yargs) => {
|
|
322
|
-
return yargs
|
|
323
|
-
.option("device", {
|
|
324
|
-
alias: "d",
|
|
325
|
-
type: "string",
|
|
326
|
-
description: "Specific device ID to run on",
|
|
327
|
-
})
|
|
328
|
-
.option("release", {
|
|
329
|
-
alias: "r",
|
|
330
|
-
type: "boolean",
|
|
331
|
-
default: false,
|
|
332
|
-
description: "Run in release mode",
|
|
333
|
-
})
|
|
334
|
-
.option("flavor", {
|
|
335
|
-
alias: "f",
|
|
336
|
-
type: "string",
|
|
337
|
-
description: "Build flavor to use",
|
|
338
|
-
})
|
|
339
|
-
.option("disable-fvm", {
|
|
340
|
-
type: "boolean",
|
|
341
|
-
default: false,
|
|
342
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
343
|
-
});
|
|
344
|
-
},
|
|
345
|
-
async (argv) => {
|
|
346
|
-
const useFvm = !argv.disableFvm;
|
|
347
|
-
await runApp({
|
|
348
|
-
device: argv.device as string | undefined,
|
|
349
|
-
release: argv.release as boolean,
|
|
350
|
-
flavor: argv.flavor as string | undefined,
|
|
351
|
-
useFvm,
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
)
|
|
355
|
-
.command(
|
|
356
|
-
"run-select",
|
|
357
|
-
"Interactive device selection and run",
|
|
358
|
-
(yargs) => {
|
|
359
|
-
return yargs
|
|
360
|
-
.option("release", {
|
|
361
|
-
alias: "r",
|
|
362
|
-
type: "boolean",
|
|
363
|
-
default: false,
|
|
364
|
-
description: "Run in release mode",
|
|
365
|
-
})
|
|
366
|
-
.option("flavor", {
|
|
367
|
-
alias: "f",
|
|
368
|
-
type: "string",
|
|
369
|
-
description: "Build flavor to use",
|
|
370
|
-
})
|
|
371
|
-
.option("disable-fvm", {
|
|
372
|
-
type: "boolean",
|
|
373
|
-
default: false,
|
|
374
|
-
description: "Run without FVM (use --disable-fvm to enable)",
|
|
375
|
-
});
|
|
376
|
-
},
|
|
377
|
-
async (argv) => {
|
|
378
|
-
const useFvm = !argv.disableFvm;
|
|
379
|
-
await runAppInteractive({
|
|
380
|
-
release: argv.release as boolean,
|
|
381
|
-
flavor: argv.flavor as string | undefined,
|
|
382
|
-
useFvm,
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
)
|
|
386
|
-
.version(version)
|
|
387
|
-
.help(true).argv;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Register all commands
|
|
70
|
+
for (const command of allCommands) {
|
|
71
|
+
cli.command(command);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
cli
|
|
75
|
+
.completion("completion", "Generate shell completion script")
|
|
76
|
+
.usage(chalk.white.bold("\nUsage:") + chalk.gray(" optikit <command> [options]"))
|
|
77
|
+
.epilogue(
|
|
78
|
+
chalk.cyan.bold("\nQuick Reference") + chalk.gray(" (use ok or optikit — both work)\n") +
|
|
79
|
+
"\n" +
|
|
80
|
+
chalk.cyan(" Build ") + chalk.white.bold("apk aab ios ipa tf") + chalk.gray(" (testflight)\n") +
|
|
81
|
+
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") +
|
|
82
|
+
chalk.cyan(" Bump ") + chalk.white.bold("bump <type> bi ba bb\n") +
|
|
83
|
+
chalk.cyan(" Version ") + chalk.white.bold("v") + chalk.gray(" (show) ") + chalk.white.bold("vset") + chalk.gray(" (set manually)\n") +
|
|
84
|
+
chalk.cyan(" Generate ") + chalk.white.bold("gen module <name> gen repo <name> route <name>\n") +
|
|
85
|
+
chalk.cyan(" Run ") + chalk.white.bold("run rs") + chalk.gray(" (interactive) ") + chalk.white.bold("devs") + chalk.gray(" (list devices)\n") +
|
|
86
|
+
chalk.cyan(" Open ") + chalk.white.bold("xcode studio\n") +
|
|
87
|
+
chalk.cyan(" Config ") + chalk.white.bold("init vscode undo up\n") +
|
|
88
|
+
chalk.cyan(" Info ") + chalk.white.bold("info dr aliases\n") +
|
|
89
|
+
chalk.cyan(" MCP ") + chalk.white.bold("mcp setup-claude\n") +
|
|
90
|
+
"\n" +
|
|
91
|
+
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") +
|
|
92
|
+
"\n\n" +
|
|
93
|
+
chalk.gray(" Run ") + chalk.white("optikit <command> --help") + chalk.gray(" for details | ") +
|
|
94
|
+
chalk.white("optikit aliases") + chalk.gray(" for full reference")
|
|
95
|
+
)
|
|
96
|
+
.version(packageInfo.version)
|
|
97
|
+
.help(true)
|
|
98
|
+
.argv;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
import {
|
|
3
|
+
buildFlutterApk,
|
|
4
|
+
buildFlutterBundle,
|
|
5
|
+
buildFlutterIos,
|
|
6
|
+
buildFlutterIpa,
|
|
7
|
+
} from "./releases.js";
|
|
8
|
+
import { cleanProject } from "../clean/flutter.js";
|
|
9
|
+
import { cleanIosProject } from "../clean/ios.js";
|
|
10
|
+
import { bumpVersion, bumpIosBuildOnly } from "../version/bump.js";
|
|
11
|
+
import { openApkOutput, openBundleOutput, openIpaOutput } from "../project/open.js";
|
|
12
|
+
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
13
|
+
import { runTestflight } from "./testflight.js";
|
|
14
|
+
|
|
15
|
+
const buildOptions = {
|
|
16
|
+
"disable-fvm": {
|
|
17
|
+
alias: "f",
|
|
18
|
+
type: "boolean" as const,
|
|
19
|
+
default: false,
|
|
20
|
+
description: "Run without FVM",
|
|
21
|
+
},
|
|
22
|
+
clean: {
|
|
23
|
+
type: "boolean" as const,
|
|
24
|
+
default: false,
|
|
25
|
+
description: "Clean before building",
|
|
26
|
+
},
|
|
27
|
+
open: {
|
|
28
|
+
alias: "o",
|
|
29
|
+
type: "boolean" as const,
|
|
30
|
+
default: false,
|
|
31
|
+
description: "Open output directory after build",
|
|
32
|
+
},
|
|
33
|
+
bump: {
|
|
34
|
+
alias: "b",
|
|
35
|
+
type: "string" as const,
|
|
36
|
+
choices: ["major", "minor", "patch"] as const,
|
|
37
|
+
description: "Bump version before building",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const ipaOptions = {
|
|
42
|
+
...buildOptions,
|
|
43
|
+
"bump-ios": {
|
|
44
|
+
alias: "i",
|
|
45
|
+
type: "boolean" as const,
|
|
46
|
+
default: false,
|
|
47
|
+
description: "Bump iOS build number before building",
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type BumpType = "major" | "minor" | "patch";
|
|
52
|
+
|
|
53
|
+
interface BuildFlags {
|
|
54
|
+
disableFvm: boolean;
|
|
55
|
+
clean: boolean;
|
|
56
|
+
open: boolean;
|
|
57
|
+
bump?: BumpType;
|
|
58
|
+
bumpIos?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function runPreBuild(flags: BuildFlags, isIosBuild: boolean): Promise<void> {
|
|
62
|
+
// 1. Bump version
|
|
63
|
+
if (flags.bump) {
|
|
64
|
+
LoggerHelpers.step(`Bumping ${flags.bump} version...`);
|
|
65
|
+
await bumpVersion(flags.bump, true);
|
|
66
|
+
}
|
|
67
|
+
if (flags.bumpIos) {
|
|
68
|
+
LoggerHelpers.step("Bumping iOS build number...");
|
|
69
|
+
await bumpIosBuildOnly(true);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 2. Clean
|
|
73
|
+
if (flags.clean) {
|
|
74
|
+
LoggerHelpers.step("Cleaning project...");
|
|
75
|
+
await cleanProject(flags.disableFvm);
|
|
76
|
+
if (isIosBuild) {
|
|
77
|
+
await cleanIosProject(false, false);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function runPostBuild(flags: BuildFlags, openFn: () => Promise<void>): Promise<void> {
|
|
83
|
+
// 4. Open output
|
|
84
|
+
if (flags.open) {
|
|
85
|
+
await openFn();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function parseFlags(argv: Record<string, unknown>): BuildFlags {
|
|
90
|
+
return {
|
|
91
|
+
disableFvm: argv.disableFvm as boolean,
|
|
92
|
+
clean: argv.clean as boolean,
|
|
93
|
+
open: argv.open as boolean,
|
|
94
|
+
bump: argv.bump as BumpType | undefined,
|
|
95
|
+
bumpIos: argv.bumpIos as boolean | undefined,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const buildCommands: CommandModule[] = [
|
|
100
|
+
{
|
|
101
|
+
command: "flutter-build-apk",
|
|
102
|
+
aliases: ["apk"],
|
|
103
|
+
describe: "Build the Flutter APK with release configuration, obfuscation, and split debug info",
|
|
104
|
+
builder: buildOptions,
|
|
105
|
+
handler: async (argv) => {
|
|
106
|
+
const flags = parseFlags(argv);
|
|
107
|
+
await runPreBuild(flags, false);
|
|
108
|
+
await buildFlutterApk(flags.disableFvm);
|
|
109
|
+
await runPostBuild(flags, openApkOutput);
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
command: "flutter-build-bundle",
|
|
114
|
+
aliases: ["aab"],
|
|
115
|
+
describe: "Build the Flutter Bundle with release configuration, obfuscation, and split debug info",
|
|
116
|
+
builder: buildOptions,
|
|
117
|
+
handler: async (argv) => {
|
|
118
|
+
const flags = parseFlags(argv);
|
|
119
|
+
await runPreBuild(flags, false);
|
|
120
|
+
await buildFlutterBundle(flags.disableFvm);
|
|
121
|
+
await runPostBuild(flags, openBundleOutput);
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
command: "flutter-build-ios",
|
|
126
|
+
aliases: ["ios"],
|
|
127
|
+
describe: "Build the Flutter iOS app with release configuration and increment the build version",
|
|
128
|
+
builder: buildOptions,
|
|
129
|
+
handler: async (argv) => {
|
|
130
|
+
const flags = parseFlags(argv);
|
|
131
|
+
await runPreBuild(flags, true);
|
|
132
|
+
await buildFlutterIos(flags.disableFvm);
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
command: "flutter-build-ipa",
|
|
137
|
+
aliases: ["ipa"],
|
|
138
|
+
describe: "Create a release IPA with an updated build version number",
|
|
139
|
+
builder: ipaOptions,
|
|
140
|
+
handler: async (argv) => {
|
|
141
|
+
const flags = parseFlags(argv);
|
|
142
|
+
await runPreBuild(flags, true);
|
|
143
|
+
await buildFlutterIpa(flags.disableFvm);
|
|
144
|
+
await runPostBuild(flags, openIpaOutput);
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
command: "testflight",
|
|
149
|
+
aliases: ["tf"],
|
|
150
|
+
describe: "Bump iOS build number and build IPA (TestFlight workflow)",
|
|
151
|
+
builder: {
|
|
152
|
+
"disable-fvm": {
|
|
153
|
+
alias: "f",
|
|
154
|
+
type: "boolean" as const,
|
|
155
|
+
default: false,
|
|
156
|
+
description: "Run without FVM",
|
|
157
|
+
},
|
|
158
|
+
open: {
|
|
159
|
+
alias: "o",
|
|
160
|
+
type: "boolean" as const,
|
|
161
|
+
default: false,
|
|
162
|
+
description: "Open IPA output directory after build",
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
handler: async (argv) => {
|
|
166
|
+
await runTestflight(argv.disableFvm as boolean, argv.open as boolean);
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
];
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
|
|
6
|
+
export { runTestflight };
|
|
7
|
+
|
|
8
|
+
async function runTestflight(disableFvm: boolean, open: boolean): Promise<void> {
|
|
9
|
+
LoggerHelpers.step("Bumping iOS build number...");
|
|
10
|
+
await bumpIosBuildOnly(true);
|
|
11
|
+
|
|
12
|
+
LoggerHelpers.step("Building IPA...");
|
|
13
|
+
await buildFlutterIpa(disableFvm);
|
|
14
|
+
|
|
15
|
+
if (open) {
|
|
16
|
+
await openIpaOutput();
|
|
17
|
+
}
|
|
18
|
+
}
|