optikit 1.2.5 → 1.4.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 +31 -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 +72 -95
- 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 +356 -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 +414 -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
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
4
|
+
import { validateFlutterProject } from "../../utils/validators/validation.js";
|
|
5
|
+
import { handleCommandError } from "../../utils/helpers/error.js";
|
|
6
|
+
import { VSCODE_SETTINGS_TEMPLATE, PROJECT_PATHS } from "../../constants.js";
|
|
4
7
|
|
|
5
8
|
export {
|
|
6
9
|
createVscodeSettings,
|
|
7
10
|
};
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
async function createVscodeSettings() {
|
|
13
|
+
if (!validateFlutterProject()) {
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
14
17
|
try {
|
|
15
|
-
const vscodeDir = path.join(process.cwd(),
|
|
16
|
-
const settingsPath = path.join(
|
|
18
|
+
const vscodeDir = path.join(process.cwd(), PROJECT_PATHS.VSCODE_DIR);
|
|
19
|
+
const settingsPath = path.join(process.cwd(), PROJECT_PATHS.VSCODE_SETTINGS);
|
|
17
20
|
|
|
18
|
-
// Create the .vscode folder using Node.js fs (cross-platform)
|
|
19
21
|
if (!fs.existsSync(vscodeDir)) {
|
|
20
22
|
fs.mkdirSync(vscodeDir, { recursive: true });
|
|
21
23
|
LoggerHelpers.success("Created .vscode directory.");
|
|
@@ -23,28 +25,9 @@ async function createVscodeSettings(){
|
|
|
23
25
|
LoggerHelpers.info(".vscode directory already exists.");
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
const settings = {
|
|
28
|
-
"dart.flutterSdkPath": ".fvm/flutter_sdk",
|
|
29
|
-
"editor.formatOnSave": true,
|
|
30
|
-
"dart.previewFlutterUiGuides": true,
|
|
31
|
-
"files.exclude": {
|
|
32
|
-
"**/.git": true,
|
|
33
|
-
"**/.DS_Store": true,
|
|
34
|
-
"**/node_modules": true,
|
|
35
|
-
"**/build": true
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Write settings.json using Node.js fs
|
|
40
|
-
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), "utf8");
|
|
28
|
+
fs.writeFileSync(settingsPath, JSON.stringify(VSCODE_SETTINGS_TEMPLATE, null, 2), "utf8");
|
|
41
29
|
LoggerHelpers.success("Created .vscode/settings.json with Flutter configuration.");
|
|
42
30
|
} catch (error) {
|
|
43
|
-
|
|
44
|
-
LoggerHelpers.error(`Error while creating VSCode settings: ${error.message}`);
|
|
45
|
-
} else {
|
|
46
|
-
LoggerHelpers.error(`Error while creating VSCode settings: ${error}`);
|
|
47
|
-
}
|
|
48
|
-
process.exit(1);
|
|
31
|
+
handleCommandError(error, "Error creating VSCode settings");
|
|
49
32
|
}
|
|
50
|
-
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { getCurrentVersion, formatVersion, getCurrentIosBuildNumber } from "../../utils/helpers/version.js";
|
|
5
|
+
import { getConfigPath } from "../../utils/services/config.js";
|
|
6
|
+
import { validateFlutterProject } from "../../utils/validators/validation.js";
|
|
7
|
+
import { PROJECT_PATHS, BACKUP_CONFIG } from "../../constants.js";
|
|
8
|
+
|
|
9
|
+
export { showStatus };
|
|
10
|
+
|
|
11
|
+
async function showStatus(): Promise<void> {
|
|
12
|
+
console.log(chalk.bold("\nOptiKit Status"));
|
|
13
|
+
console.log(chalk.gray("─".repeat(45)));
|
|
14
|
+
|
|
15
|
+
// Version info
|
|
16
|
+
if (validateFlutterProject(true)) {
|
|
17
|
+
try {
|
|
18
|
+
const current = getCurrentVersion();
|
|
19
|
+
const iosBuild = getCurrentIosBuildNumber();
|
|
20
|
+
console.log(chalk.cyan("\n Version:"), chalk.white.bold(formatVersion(current)));
|
|
21
|
+
console.log(chalk.gray(" Android Build:"), chalk.white(current.buildNumber));
|
|
22
|
+
console.log(chalk.gray(" iOS Build:"), chalk.white(iosBuild));
|
|
23
|
+
} catch {
|
|
24
|
+
console.log(chalk.yellow("\n Version:"), chalk.gray("Unable to read"));
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
console.log(chalk.yellow("\n Version:"), chalk.gray("Not a Flutter project"));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// FVM status
|
|
31
|
+
const fvmPath = path.join(process.cwd(), PROJECT_PATHS.FVM_FLUTTER_SDK);
|
|
32
|
+
const useFvm = fs.existsSync(fvmPath);
|
|
33
|
+
console.log(chalk.cyan(" Flutter:"), chalk.white(useFvm ? "FVM" : "Global SDK"));
|
|
34
|
+
|
|
35
|
+
// Backup count
|
|
36
|
+
const backupCount = countBackups(process.cwd());
|
|
37
|
+
console.log(chalk.cyan(" Backups:"), chalk.white(backupCount > 0 ? `${backupCount} file(s)` : "None"));
|
|
38
|
+
|
|
39
|
+
// Config
|
|
40
|
+
const configPath = getConfigPath();
|
|
41
|
+
console.log(chalk.cyan(" Config:"), chalk.white(configPath ?? "Not initialized (run: optikit init)"));
|
|
42
|
+
|
|
43
|
+
// Project structure
|
|
44
|
+
const hasIos = fs.existsSync(path.join(process.cwd(), PROJECT_PATHS.IOS_DIR));
|
|
45
|
+
const hasAndroid = fs.existsSync(path.join(process.cwd(), PROJECT_PATHS.ANDROID_DIR));
|
|
46
|
+
const platforms = [hasIos ? "iOS" : null, hasAndroid ? "Android" : null].filter(Boolean).join(", ");
|
|
47
|
+
console.log(chalk.cyan(" Platforms:"), chalk.white(platforms || "None detected"));
|
|
48
|
+
|
|
49
|
+
console.log(chalk.gray("\n" + "─".repeat(45) + "\n"));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function countBackups(dir: string): number {
|
|
53
|
+
let count = 0;
|
|
54
|
+
|
|
55
|
+
function search(currentDir: string): void {
|
|
56
|
+
try {
|
|
57
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
if (entry.isDirectory()) {
|
|
60
|
+
if (entry.name === BACKUP_CONFIG.DIR_NAME) {
|
|
61
|
+
count += fs.readdirSync(path.join(currentDir, entry.name)).length;
|
|
62
|
+
} else if (!entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
63
|
+
search(path.join(currentDir, entry.name));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch { /* skip inaccessible dirs */ }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
search(dir);
|
|
71
|
+
return count;
|
|
72
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createInterface } from "readline";
|
|
1
2
|
import { validateFlutterProject } from "../../utils/validators/validation.js";
|
|
2
3
|
import { LoggerHelpers } from "../../utils/services/logger.js";
|
|
3
4
|
import {
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
getNextBuildNumber,
|
|
8
9
|
getCurrentIosBuildNumber
|
|
9
10
|
} from "../../utils/helpers/version.js";
|
|
11
|
+
import { handleCommandError } from "../../utils/helpers/error.js";
|
|
10
12
|
import { updateFlutterVersion } from "./update.js";
|
|
11
13
|
import chalk from "chalk";
|
|
12
14
|
|
|
@@ -19,23 +21,65 @@ export {
|
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* iOS build number resets to 1 on version change
|
|
25
|
-
*
|
|
26
|
-
* @param type - Type of version bump (major, minor, patch)
|
|
24
|
+
* Prompts user for confirmation. Returns true if confirmed.
|
|
25
|
+
* Skips prompt and returns true if skipConfirm is true (--yes flag).
|
|
27
26
|
*/
|
|
27
|
+
function confirmAction(message: string, skipConfirm: boolean): Promise<boolean> {
|
|
28
|
+
if (skipConfirm) return Promise.resolve(true);
|
|
29
|
+
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
32
|
+
rl.question(chalk.yellow(`${message} (y/n): `), (answer) => {
|
|
33
|
+
rl.close();
|
|
34
|
+
resolve(answer.toLowerCase() === "y");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Shows a colored diff preview of what will change.
|
|
41
|
+
*/
|
|
42
|
+
function showDiffPreview(
|
|
43
|
+
oldVersion: string,
|
|
44
|
+
newVersion: string,
|
|
45
|
+
oldAndroidBuild: number,
|
|
46
|
+
newAndroidBuild: number | string,
|
|
47
|
+
oldIosBuild: number,
|
|
48
|
+
newIosBuild: number | string
|
|
49
|
+
) {
|
|
50
|
+
console.log(chalk.cyan("\nFile changes preview:"));
|
|
51
|
+
|
|
52
|
+
if (newAndroidBuild !== "") {
|
|
53
|
+
console.log(chalk.gray("\n pubspec.yaml:"));
|
|
54
|
+
console.log(chalk.red(` - version: ${oldVersion}+${oldAndroidBuild}`));
|
|
55
|
+
console.log(chalk.green(` + version: ${newVersion}+${newAndroidBuild}`));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (newIosBuild !== "") {
|
|
59
|
+
console.log(chalk.gray("\n project.pbxproj:"));
|
|
60
|
+
console.log(chalk.red(` - MARKETING_VERSION = ${oldVersion};`));
|
|
61
|
+
console.log(chalk.green(` + MARKETING_VERSION = ${newVersion};`));
|
|
62
|
+
console.log(chalk.red(` - CURRENT_PROJECT_VERSION = ${oldIosBuild};`));
|
|
63
|
+
console.log(chalk.green(` + CURRENT_PROJECT_VERSION = ${newIosBuild};`));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
|
|
28
69
|
async function bumpVersion(
|
|
29
|
-
type: 'major' | 'minor' | 'patch'
|
|
70
|
+
type: 'major' | 'minor' | 'patch',
|
|
71
|
+
skipConfirm: boolean = false
|
|
30
72
|
): Promise<void> {
|
|
31
|
-
// Pre-flight validation
|
|
32
73
|
if (!validateFlutterProject()) {
|
|
33
74
|
process.exit(1);
|
|
34
75
|
}
|
|
35
76
|
|
|
36
77
|
try {
|
|
37
78
|
const current = getCurrentVersion();
|
|
79
|
+
const currentIosBuild = getCurrentIosBuildNumber();
|
|
38
80
|
const newVersion = incrementVersion(current, type);
|
|
81
|
+
const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
|
|
82
|
+
const newVersionString = `${newVersion.major}.${newVersion.minor}.${newVersion.patch}`;
|
|
39
83
|
|
|
40
84
|
LoggerHelpers.info(`Current version: ${formatVersion(current)}`);
|
|
41
85
|
LoggerHelpers.info(`Bumping ${type} version...`);
|
|
@@ -46,16 +90,20 @@ async function bumpVersion(
|
|
|
46
90
|
|
|
47
91
|
console.log(chalk.cyan("\nBuild number strategy:"));
|
|
48
92
|
console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} → ${newVersion.buildNumber} (incremented)`));
|
|
49
|
-
console.log(chalk.gray(" iOS:"), chalk.white(`${
|
|
50
|
-
|
|
93
|
+
console.log(chalk.gray(" iOS:"), chalk.white(`${currentIosBuild} → 1 (reset for new version)`));
|
|
94
|
+
|
|
95
|
+
showDiffPreview(currentVersionString, newVersionString, current.buildNumber, newVersion.buildNumber, currentIosBuild, 1);
|
|
96
|
+
|
|
97
|
+
const confirmed = await confirmAction("Proceed with version bump?", skipConfirm);
|
|
98
|
+
if (!confirmed) {
|
|
99
|
+
LoggerHelpers.info("Bump cancelled.");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
51
102
|
|
|
52
|
-
// Update with new version
|
|
53
|
-
// Android uses the incremented build number from version
|
|
54
|
-
// iOS gets reset to 1 for new version releases
|
|
55
103
|
await updateFlutterVersion(
|
|
56
|
-
|
|
104
|
+
newVersionString,
|
|
57
105
|
newVersion.buildNumber.toString(),
|
|
58
|
-
"1"
|
|
106
|
+
"1"
|
|
59
107
|
);
|
|
60
108
|
|
|
61
109
|
LoggerHelpers.success(`Version bumped to ${formatVersion(newVersion)}`);
|
|
@@ -63,24 +111,11 @@ async function bumpVersion(
|
|
|
63
111
|
console.log(chalk.gray("iOS build:"), chalk.white("1"));
|
|
64
112
|
|
|
65
113
|
} catch (error) {
|
|
66
|
-
|
|
67
|
-
LoggerHelpers.error(`Error bumping version: ${error.message}`);
|
|
68
|
-
} else {
|
|
69
|
-
LoggerHelpers.error(`Error bumping version: ${error}`);
|
|
70
|
-
}
|
|
71
|
-
process.exit(1);
|
|
114
|
+
handleCommandError(error, "Error bumping version");
|
|
72
115
|
}
|
|
73
116
|
}
|
|
74
117
|
|
|
75
|
-
|
|
76
|
-
* Increments ONLY iOS build number (for TestFlight builds)
|
|
77
|
-
* Keeps version and Android build number unchanged
|
|
78
|
-
* Perfect for uploading new iOS builds without changing app version
|
|
79
|
-
*
|
|
80
|
-
* Example: 1.0.2+45 (iOS: 45) → 1.0.2+45 (iOS: 46)
|
|
81
|
-
*/
|
|
82
|
-
async function bumpIosBuildOnly(): Promise<void> {
|
|
83
|
-
// Pre-flight validation
|
|
118
|
+
async function bumpIosBuildOnly(skipConfirm: boolean = false): Promise<void> {
|
|
84
119
|
if (!validateFlutterProject()) {
|
|
85
120
|
process.exit(1);
|
|
86
121
|
}
|
|
@@ -88,8 +123,6 @@ async function bumpIosBuildOnly(): Promise<void> {
|
|
|
88
123
|
try {
|
|
89
124
|
const current = getCurrentVersion();
|
|
90
125
|
const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
|
|
91
|
-
|
|
92
|
-
// Read actual iOS build number from project.pbxproj
|
|
93
126
|
const currentIosBuild = getCurrentIosBuildNumber();
|
|
94
127
|
const nextIosBuild = currentIosBuild + 1;
|
|
95
128
|
|
|
@@ -100,35 +133,25 @@ async function bumpIosBuildOnly(): Promise<void> {
|
|
|
100
133
|
console.log(chalk.gray(" Version:"), chalk.white(`${currentVersionString} (unchanged)`));
|
|
101
134
|
console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} (unchanged)`));
|
|
102
135
|
console.log(chalk.gray(" iOS:"), chalk.white(`${currentIosBuild} → ${nextIosBuild}`), chalk.green("(incremented)"));
|
|
103
|
-
console.log();
|
|
104
136
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
137
|
+
showDiffPreview(currentVersionString, currentVersionString, current.buildNumber, "", currentIosBuild, nextIosBuild);
|
|
138
|
+
|
|
139
|
+
const confirmed = await confirmAction("Proceed?", skipConfirm);
|
|
140
|
+
if (!confirmed) {
|
|
141
|
+
LoggerHelpers.info("Bump cancelled.");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
await updateFlutterVersion(currentVersionString, "", nextIosBuild.toString());
|
|
111
146
|
|
|
112
147
|
LoggerHelpers.success(`iOS build number incremented to ${nextIosBuild}`);
|
|
113
|
-
console.log(chalk.gray("\nResult:"), chalk.white(`${currentVersionString}+${current.buildNumber} (iOS: ${nextIosBuild})`));
|
|
114
|
-
console.log(chalk.gray("Use this for:"), chalk.white("TestFlight uploads without version changes"));
|
|
115
148
|
|
|
116
149
|
} catch (error) {
|
|
117
|
-
|
|
118
|
-
LoggerHelpers.error(`Error incrementing iOS build: ${error.message}`);
|
|
119
|
-
} else {
|
|
120
|
-
LoggerHelpers.error(`Error incrementing iOS build: ${error}`);
|
|
121
|
-
}
|
|
122
|
-
process.exit(1);
|
|
150
|
+
handleCommandError(error, "Error incrementing iOS build");
|
|
123
151
|
}
|
|
124
152
|
}
|
|
125
153
|
|
|
126
|
-
|
|
127
|
-
* Increments ONLY Android build number
|
|
128
|
-
* Keeps version and iOS build number unchanged
|
|
129
|
-
*/
|
|
130
|
-
async function bumpAndroidBuildOnly(): Promise<void> {
|
|
131
|
-
// Pre-flight validation
|
|
154
|
+
async function bumpAndroidBuildOnly(skipConfirm: boolean = false): Promise<void> {
|
|
132
155
|
if (!validateFlutterProject()) {
|
|
133
156
|
process.exit(1);
|
|
134
157
|
}
|
|
@@ -136,6 +159,7 @@ async function bumpAndroidBuildOnly(): Promise<void> {
|
|
|
136
159
|
try {
|
|
137
160
|
const current = getCurrentVersion();
|
|
138
161
|
const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
|
|
162
|
+
const currentIosBuild = getCurrentIosBuildNumber();
|
|
139
163
|
const nextAndroidBuild = current.buildNumber + 1;
|
|
140
164
|
|
|
141
165
|
LoggerHelpers.info(`Current version: ${formatVersion(current)}`);
|
|
@@ -145,34 +169,25 @@ async function bumpAndroidBuildOnly(): Promise<void> {
|
|
|
145
169
|
console.log(chalk.gray(" Version:"), chalk.white(`${currentVersionString} (unchanged)`));
|
|
146
170
|
console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} → ${nextAndroidBuild}`), chalk.green("(incremented)"));
|
|
147
171
|
console.log(chalk.gray(" iOS:"), chalk.white("(unchanged)"));
|
|
148
|
-
console.log();
|
|
149
172
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
""
|
|
155
|
-
|
|
173
|
+
showDiffPreview(currentVersionString, currentVersionString, current.buildNumber, nextAndroidBuild, currentIosBuild, "");
|
|
174
|
+
|
|
175
|
+
const confirmed = await confirmAction("Proceed?", skipConfirm);
|
|
176
|
+
if (!confirmed) {
|
|
177
|
+
LoggerHelpers.info("Bump cancelled.");
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
await updateFlutterVersion(currentVersionString, nextAndroidBuild.toString(), "");
|
|
156
182
|
|
|
157
183
|
LoggerHelpers.success(`Android build number incremented to ${nextAndroidBuild}`);
|
|
158
184
|
|
|
159
185
|
} catch (error) {
|
|
160
|
-
|
|
161
|
-
LoggerHelpers.error(`Error incrementing Android build: ${error.message}`);
|
|
162
|
-
} else {
|
|
163
|
-
LoggerHelpers.error(`Error incrementing Android build: ${error}`);
|
|
164
|
-
}
|
|
165
|
-
process.exit(1);
|
|
186
|
+
handleCommandError(error, "Error incrementing Android build");
|
|
166
187
|
}
|
|
167
188
|
}
|
|
168
189
|
|
|
169
|
-
|
|
170
|
-
* Increments BOTH Android and iOS build numbers
|
|
171
|
-
* Keeps version unchanged
|
|
172
|
-
* Perfect for updating both platforms simultaneously
|
|
173
|
-
*/
|
|
174
|
-
async function bumpBothBuilds(): Promise<void> {
|
|
175
|
-
// Pre-flight validation
|
|
190
|
+
async function bumpBothBuilds(skipConfirm: boolean = false): Promise<void> {
|
|
176
191
|
if (!validateFlutterProject()) {
|
|
177
192
|
process.exit(1);
|
|
178
193
|
}
|
|
@@ -180,8 +195,6 @@ async function bumpBothBuilds(): Promise<void> {
|
|
|
180
195
|
try {
|
|
181
196
|
const current = getCurrentVersion();
|
|
182
197
|
const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
|
|
183
|
-
|
|
184
|
-
// Read actual iOS build number from project.pbxproj
|
|
185
198
|
const currentIosBuild = getCurrentIosBuildNumber();
|
|
186
199
|
const nextAndroidBuild = current.buildNumber + 1;
|
|
187
200
|
const nextIosBuild = currentIosBuild + 1;
|
|
@@ -193,32 +206,24 @@ async function bumpBothBuilds(): Promise<void> {
|
|
|
193
206
|
console.log(chalk.gray(" Version:"), chalk.white(`${currentVersionString} (unchanged)`));
|
|
194
207
|
console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} → ${nextAndroidBuild}`), chalk.green("(incremented)"));
|
|
195
208
|
console.log(chalk.gray(" iOS:"), chalk.white(`${currentIosBuild} → ${nextIosBuild}`), chalk.green("(incremented)"));
|
|
196
|
-
console.log();
|
|
197
209
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
210
|
+
showDiffPreview(currentVersionString, currentVersionString, current.buildNumber, nextAndroidBuild, currentIosBuild, nextIosBuild);
|
|
211
|
+
|
|
212
|
+
const confirmed = await confirmAction("Proceed?", skipConfirm);
|
|
213
|
+
if (!confirmed) {
|
|
214
|
+
LoggerHelpers.info("Bump cancelled.");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await updateFlutterVersion(currentVersionString, nextAndroidBuild.toString(), nextIosBuild.toString());
|
|
204
219
|
|
|
205
220
|
LoggerHelpers.success(`Both build numbers incremented successfully`);
|
|
206
|
-
console.log(chalk.gray("\nResult:"), chalk.white(`${currentVersionString}+${nextAndroidBuild} (iOS: ${nextIosBuild})`));
|
|
207
|
-
console.log(chalk.gray("Use this for:"), chalk.white("Simultaneous Android and iOS releases"));
|
|
208
221
|
|
|
209
222
|
} catch (error) {
|
|
210
|
-
|
|
211
|
-
LoggerHelpers.error(`Error incrementing build numbers: ${error.message}`);
|
|
212
|
-
} else {
|
|
213
|
-
LoggerHelpers.error(`Error incrementing build numbers: ${error}`);
|
|
214
|
-
}
|
|
215
|
-
process.exit(1);
|
|
223
|
+
handleCommandError(error, "Error incrementing build numbers");
|
|
216
224
|
}
|
|
217
225
|
}
|
|
218
226
|
|
|
219
|
-
/**
|
|
220
|
-
* Shows current version information
|
|
221
|
-
*/
|
|
222
227
|
async function showCurrentVersion(): Promise<void> {
|
|
223
228
|
try {
|
|
224
229
|
const current = getCurrentVersion();
|
|
@@ -235,23 +240,6 @@ async function showCurrentVersion(): Promise<void> {
|
|
|
235
240
|
console.log();
|
|
236
241
|
|
|
237
242
|
} catch (error) {
|
|
238
|
-
|
|
239
|
-
LoggerHelpers.error(`Error reading version: ${error.message}`);
|
|
240
|
-
} else {
|
|
241
|
-
LoggerHelpers.error(`Error reading version: ${error}`);
|
|
242
|
-
}
|
|
243
|
-
process.exit(1);
|
|
243
|
+
handleCommandError(error, "Error reading version");
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Helper to get next iOS build number
|
|
249
|
-
* In the future, this could read from Info.plist or project.pbxproj
|
|
250
|
-
* For now, we'll use a simple increment
|
|
251
|
-
*/
|
|
252
|
-
async function getNextIosBuildNumber(): Promise<number> {
|
|
253
|
-
// TODO: Read actual iOS build number from Info.plist or project.pbxproj
|
|
254
|
-
// For now, we'll just increment based on timestamp or simple counter
|
|
255
|
-
const current = getCurrentVersion();
|
|
256
|
-
return current.buildNumber + 1;
|
|
257
|
-
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { CommandModule } from "yargs";
|
|
2
|
+
import {
|
|
3
|
+
bumpVersion,
|
|
4
|
+
bumpIosBuildOnly,
|
|
5
|
+
bumpAndroidBuildOnly,
|
|
6
|
+
bumpBothBuilds,
|
|
7
|
+
showCurrentVersion,
|
|
8
|
+
} from "./bump.js";
|
|
9
|
+
import { updateFlutterVersion } from "./update.js";
|
|
10
|
+
|
|
11
|
+
const yesOption = {
|
|
12
|
+
yes: { alias: "y", type: "boolean" as const, default: false, description: "Skip confirmation prompt" },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const versionCommands: CommandModule[] = [
|
|
16
|
+
{
|
|
17
|
+
command: "bump <type>",
|
|
18
|
+
describe: "Bump version (major, minor, or patch)",
|
|
19
|
+
builder: (yargs) => {
|
|
20
|
+
return yargs
|
|
21
|
+
.positional("type", {
|
|
22
|
+
describe: "Version bump type (major, minor, patch)",
|
|
23
|
+
type: "string" as const,
|
|
24
|
+
choices: ["major", "minor", "patch"] as const,
|
|
25
|
+
})
|
|
26
|
+
.option("yes", yesOption.yes);
|
|
27
|
+
},
|
|
28
|
+
handler: async (argv) => {
|
|
29
|
+
await bumpVersion(argv.type as "major" | "minor" | "patch", argv.yes as boolean);
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
command: "bump-ios",
|
|
34
|
+
aliases: ["bi"],
|
|
35
|
+
describe: "Increment iOS build number only (for TestFlight)",
|
|
36
|
+
builder: yesOption,
|
|
37
|
+
handler: async (argv) => { await bumpIosBuildOnly(argv.yes as boolean); },
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
command: "bump-android",
|
|
41
|
+
aliases: ["ba"],
|
|
42
|
+
describe: "Increment Android build number only",
|
|
43
|
+
builder: yesOption,
|
|
44
|
+
handler: async (argv) => { await bumpAndroidBuildOnly(argv.yes as boolean); },
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
command: "bump-build",
|
|
48
|
+
aliases: ["bb"],
|
|
49
|
+
describe: "Increment both Android and iOS build numbers",
|
|
50
|
+
builder: yesOption,
|
|
51
|
+
handler: async (argv) => { await bumpBothBuilds(argv.yes as boolean); },
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
command: "version",
|
|
55
|
+
aliases: ["v"],
|
|
56
|
+
describe: "Show current version information",
|
|
57
|
+
handler: async () => { await showCurrentVersion(); },
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
command: "flutter-update-version",
|
|
61
|
+
aliases: ["vset"],
|
|
62
|
+
describe: "Update version and build numbers for both Android and iOS",
|
|
63
|
+
builder: {
|
|
64
|
+
"app-version": { type: "string", description: "The version number to set", default: "" },
|
|
65
|
+
"android-build": { type: "string", description: "The Android build number", default: "" },
|
|
66
|
+
"ios-build": { type: "string", description: "The iOS build number", default: "" },
|
|
67
|
+
},
|
|
68
|
+
handler: async (argv) => {
|
|
69
|
+
await updateFlutterVersion(
|
|
70
|
+
argv["app-version"] as string,
|
|
71
|
+
argv["android-build"] as string,
|
|
72
|
+
argv["ios-build"] as string
|
|
73
|
+
);
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
];
|