optikit 1.2.2 → 1.2.4

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/USAGE.md CHANGED
@@ -40,7 +40,7 @@ optikit init
40
40
  ```json
41
41
  {
42
42
  "backupRetentionCount": 5,
43
- "useFvmByDefault": false,
43
+ "useFvmByDefault": true,
44
44
  "autoBackup": true,
45
45
  "verbose": false
46
46
  }
@@ -20,7 +20,7 @@ async function initializeProject() {
20
20
  // Create default configuration
21
21
  const defaultConfig = {
22
22
  backupRetentionCount: 5,
23
- useFvmByDefault: false,
23
+ useFvmByDefault: true,
24
24
  autoBackup: true,
25
25
  verbose: false,
26
26
  };
@@ -1,6 +1,6 @@
1
1
  import { validateFlutterProject } from "../../utils/validators/validation.js";
2
2
  import { LoggerHelpers } from "../../utils/services/logger.js";
3
- import { getCurrentVersion, incrementVersion, formatVersion } from "../../utils/helpers/version.js";
3
+ import { getCurrentVersion, incrementVersion, formatVersion, getCurrentIosBuildNumber } from "../../utils/helpers/version.js";
4
4
  import { updateFlutterVersion } from "./update.js";
5
5
  import chalk from "chalk";
6
6
  export { bumpVersion, bumpIosBuildOnly, bumpAndroidBuildOnly, showCurrentVersion };
@@ -62,14 +62,15 @@ async function bumpIosBuildOnly() {
62
62
  try {
63
63
  const current = getCurrentVersion();
64
64
  const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
65
- // iOS build number increments from current Android build number
66
- const nextIosBuild = current.buildNumber + 1;
65
+ // Read actual iOS build number from project.pbxproj
66
+ const currentIosBuild = getCurrentIosBuildNumber();
67
+ const nextIosBuild = currentIosBuild + 1;
67
68
  LoggerHelpers.info(`Current version: ${formatVersion(current)}`);
68
69
  LoggerHelpers.info("Incrementing iOS build number only (for TestFlight)...");
69
70
  console.log(chalk.cyan("\nBuild number changes:"));
70
71
  console.log(chalk.gray(" Version:"), chalk.white(`${currentVersionString} (unchanged)`));
71
72
  console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} (unchanged)`));
72
- console.log(chalk.gray(" iOS:"), chalk.white(`${current.buildNumber} → ${nextIosBuild}`), chalk.green("(incremented)"));
73
+ console.log(chalk.gray(" iOS:"), chalk.white(`${currentIosBuild} → ${nextIosBuild}`), chalk.green("(incremented)"));
73
74
  console.log();
74
75
  // Update only iOS build number
75
76
  await updateFlutterVersion(currentVersionString, "", // Empty string means don't update Android
@@ -130,12 +131,14 @@ async function showCurrentVersion() {
130
131
  try {
131
132
  const current = getCurrentVersion();
132
133
  const versionString = formatVersion(current);
134
+ const currentIosBuild = getCurrentIosBuildNumber();
133
135
  console.log(chalk.bold("\n📱 Current Version Information\n"));
134
136
  console.log(chalk.cyan("Version:"), chalk.white.bold(versionString));
135
137
  console.log(chalk.gray(" Major:"), chalk.white(current.major));
136
138
  console.log(chalk.gray(" Minor:"), chalk.white(current.minor));
137
139
  console.log(chalk.gray(" Patch:"), chalk.white(current.patch));
138
- console.log(chalk.gray(" Build:"), chalk.white(current.buildNumber));
140
+ console.log(chalk.gray(" Android Build:"), chalk.white(current.buildNumber));
141
+ console.log(chalk.gray(" iOS Build:"), chalk.white(currentIosBuild));
139
142
  console.log();
140
143
  }
141
144
  catch (error) {
@@ -1,6 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- export { parseVersion, incrementVersion, getCurrentVersion };
3
+ import { LoggerHelpers } from "../services/logger.js";
4
+ export { parseVersion, incrementVersion, getCurrentVersion, getCurrentIosBuildNumber };
4
5
  /**
5
6
  * Parses a version string in format "X.Y.Z+B"
6
7
  * @param versionString - Version string (e.g., "1.2.3+45")
@@ -78,3 +79,28 @@ export function getNextBuildNumber() {
78
79
  const current = getCurrentVersion();
79
80
  return current.buildNumber + 1;
80
81
  }
82
+ /**
83
+ * Gets the current iOS build number from project.pbxproj
84
+ * @returns Current iOS build number, or 1 if not found
85
+ */
86
+ function getCurrentIosBuildNumber() {
87
+ try {
88
+ const projectPbxProjPath = path.join(process.cwd(), "ios/Runner.xcodeproj/project.pbxproj");
89
+ if (!fs.existsSync(projectPbxProjPath)) {
90
+ LoggerHelpers.warning("iOS project.pbxproj not found. Defaulting to build number 1.");
91
+ return 1;
92
+ }
93
+ const projectContent = fs.readFileSync(projectPbxProjPath, 'utf8');
94
+ // Match CURRENT_PROJECT_VERSION = <number>;
95
+ const buildMatch = projectContent.match(/CURRENT_PROJECT_VERSION\s*=\s*(\d+);/);
96
+ if (!buildMatch) {
97
+ LoggerHelpers.warning("CURRENT_PROJECT_VERSION not found in project.pbxproj. Defaulting to build number 1.");
98
+ return 1;
99
+ }
100
+ return parseInt(buildMatch[1], 10);
101
+ }
102
+ catch (error) {
103
+ LoggerHelpers.warning(`Error reading iOS build number: ${error instanceof Error ? error.message : error}. Defaulting to 1.`);
104
+ return 1;
105
+ }
106
+ }
@@ -57,6 +57,30 @@ export async function execCommand(command) {
57
57
  });
58
58
  });
59
59
  }
60
+ export async function execCommandSilent(command) {
61
+ return new Promise((resolve, reject) => {
62
+ const fullCommand = `${command}`;
63
+ const process = spawn(fullCommand, { shell: true });
64
+ let output = "";
65
+ process.stdout.on("data", (data) => {
66
+ output += data.toString();
67
+ });
68
+ process.stderr.on("data", (data) => {
69
+ output += data.toString();
70
+ });
71
+ process.on("close", (code) => {
72
+ if (code !== 0) {
73
+ reject(new Error(`Command failed with exit code ${code}`));
74
+ }
75
+ else {
76
+ resolve(output);
77
+ }
78
+ });
79
+ process.on("error", (err) => {
80
+ reject(new Error(`Failed to start subprocess: ${err.message}`));
81
+ });
82
+ });
83
+ }
60
84
  export async function execInIos(command) {
61
85
  return new Promise((resolve, reject) => {
62
86
  const fullCommand = `cd "${iosDirectory}" && ${command}`;
@@ -1,6 +1,6 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { execCommand } from "../services/exec.js";
3
+ import { execCommandSilent } from "../services/exec.js";
4
4
  import { LoggerHelpers } from "../services/logger.js";
5
5
  export { validateFlutterProject, validateFlutterSdk, validateIosProject, validateAndroidProject, checkFileExists, };
6
6
  /**
@@ -36,12 +36,12 @@ async function validateFlutterSdk(useFvm = false) {
36
36
  return false;
37
37
  }
38
38
  // Check if fvm command is available
39
- await execCommand("fvm --version");
39
+ await execCommandSilent("fvm --version");
40
40
  return true;
41
41
  }
42
42
  else {
43
43
  // Check if global Flutter is available
44
- await execCommand("flutter --version");
44
+ await execCommandSilent("flutter --version");
45
45
  return true;
46
46
  }
47
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "optikit",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "OptiKit CLI",
5
5
  "main": "src/cli.ts",
6
6
  "type": "module",
@@ -25,7 +25,7 @@ async function initializeProject(): Promise<void> {
25
25
  // Create default configuration
26
26
  const defaultConfig = {
27
27
  backupRetentionCount: 5,
28
- useFvmByDefault: false,
28
+ useFvmByDefault: true,
29
29
  autoBackup: true,
30
30
  verbose: false,
31
31
  };
@@ -4,7 +4,8 @@ import {
4
4
  getCurrentVersion,
5
5
  incrementVersion,
6
6
  formatVersion,
7
- getNextBuildNumber
7
+ getNextBuildNumber,
8
+ getCurrentIosBuildNumber
8
9
  } from "../../utils/helpers/version.js";
9
10
  import { updateFlutterVersion } from "./update.js";
10
11
  import chalk from "chalk";
@@ -87,8 +88,9 @@ async function bumpIosBuildOnly(): Promise<void> {
87
88
  const current = getCurrentVersion();
88
89
  const currentVersionString = `${current.major}.${current.minor}.${current.patch}`;
89
90
 
90
- // iOS build number increments from current Android build number
91
- const nextIosBuild = current.buildNumber + 1;
91
+ // Read actual iOS build number from project.pbxproj
92
+ const currentIosBuild = getCurrentIosBuildNumber();
93
+ const nextIosBuild = currentIosBuild + 1;
92
94
 
93
95
  LoggerHelpers.info(`Current version: ${formatVersion(current)}`);
94
96
  LoggerHelpers.info("Incrementing iOS build number only (for TestFlight)...");
@@ -96,7 +98,7 @@ async function bumpIosBuildOnly(): Promise<void> {
96
98
  console.log(chalk.cyan("\nBuild number changes:"));
97
99
  console.log(chalk.gray(" Version:"), chalk.white(`${currentVersionString} (unchanged)`));
98
100
  console.log(chalk.gray(" Android:"), chalk.white(`${current.buildNumber} (unchanged)`));
99
- console.log(chalk.gray(" iOS:"), chalk.white(`${current.buildNumber} → ${nextIosBuild}`), chalk.green("(incremented)"));
101
+ console.log(chalk.gray(" iOS:"), chalk.white(`${currentIosBuild} → ${nextIosBuild}`), chalk.green("(incremented)"));
100
102
  console.log();
101
103
 
102
104
  // Update only iOS build number
@@ -170,13 +172,15 @@ async function showCurrentVersion(): Promise<void> {
170
172
  try {
171
173
  const current = getCurrentVersion();
172
174
  const versionString = formatVersion(current);
175
+ const currentIosBuild = getCurrentIosBuildNumber();
173
176
 
174
177
  console.log(chalk.bold("\n📱 Current Version Information\n"));
175
178
  console.log(chalk.cyan("Version:"), chalk.white.bold(versionString));
176
179
  console.log(chalk.gray(" Major:"), chalk.white(current.major));
177
180
  console.log(chalk.gray(" Minor:"), chalk.white(current.minor));
178
181
  console.log(chalk.gray(" Patch:"), chalk.white(current.patch));
179
- console.log(chalk.gray(" Build:"), chalk.white(current.buildNumber));
182
+ console.log(chalk.gray(" Android Build:"), chalk.white(current.buildNumber));
183
+ console.log(chalk.gray(" iOS Build:"), chalk.white(currentIosBuild));
180
184
  console.log();
181
185
 
182
186
  } catch (error) {
@@ -2,7 +2,7 @@ import fs from "fs";
2
2
  import path from "path";
3
3
  import { LoggerHelpers } from "../services/logger.js";
4
4
 
5
- export { parseVersion, incrementVersion, getCurrentVersion, VersionInfo };
5
+ export { parseVersion, incrementVersion, getCurrentVersion, getCurrentIosBuildNumber, VersionInfo };
6
6
 
7
7
  /**
8
8
  * Version information structure
@@ -107,3 +107,33 @@ export function getNextBuildNumber(): number {
107
107
  const current = getCurrentVersion();
108
108
  return current.buildNumber + 1;
109
109
  }
110
+
111
+ /**
112
+ * Gets the current iOS build number from project.pbxproj
113
+ * @returns Current iOS build number, or 1 if not found
114
+ */
115
+ function getCurrentIosBuildNumber(): number {
116
+ try {
117
+ const projectPbxProjPath = path.join(process.cwd(), "ios/Runner.xcodeproj/project.pbxproj");
118
+
119
+ if (!fs.existsSync(projectPbxProjPath)) {
120
+ LoggerHelpers.warning("iOS project.pbxproj not found. Defaulting to build number 1.");
121
+ return 1;
122
+ }
123
+
124
+ const projectContent = fs.readFileSync(projectPbxProjPath, 'utf8');
125
+
126
+ // Match CURRENT_PROJECT_VERSION = <number>;
127
+ const buildMatch = projectContent.match(/CURRENT_PROJECT_VERSION\s*=\s*(\d+);/);
128
+
129
+ if (!buildMatch) {
130
+ LoggerHelpers.warning("CURRENT_PROJECT_VERSION not found in project.pbxproj. Defaulting to build number 1.");
131
+ return 1;
132
+ }
133
+
134
+ return parseInt(buildMatch[1], 10);
135
+ } catch (error) {
136
+ LoggerHelpers.warning(`Error reading iOS build number: ${error instanceof Error ? error.message : error}. Defaulting to 1.`);
137
+ return 1;
138
+ }
139
+ }
@@ -73,6 +73,35 @@ export async function execCommand(command: string): Promise<string> {
73
73
  });
74
74
  }
75
75
 
76
+ export async function execCommandSilent(command: string): Promise<string> {
77
+ return new Promise((resolve, reject) => {
78
+ const fullCommand = `${command}`;
79
+ const process = spawn(fullCommand, { shell: true });
80
+
81
+ let output = "";
82
+
83
+ process.stdout.on("data", (data) => {
84
+ output += data.toString();
85
+ });
86
+
87
+ process.stderr.on("data", (data) => {
88
+ output += data.toString();
89
+ });
90
+
91
+ process.on("close", (code) => {
92
+ if (code !== 0) {
93
+ reject(new Error(`Command failed with exit code ${code}`));
94
+ } else {
95
+ resolve(output);
96
+ }
97
+ });
98
+
99
+ process.on("error", (err) => {
100
+ reject(new Error(`Failed to start subprocess: ${err.message}`));
101
+ });
102
+ });
103
+ }
104
+
76
105
  export async function execInIos(command: string): Promise<string> {
77
106
  return new Promise((resolve, reject) => {
78
107
  const fullCommand = `cd "${iosDirectory}" && ${command}`;
@@ -1,6 +1,6 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { execCommand } from "../services/exec.js";
3
+ import { execCommandSilent } from "../services/exec.js";
4
4
  import { LoggerHelpers } from "../services/logger.js";
5
5
 
6
6
  export {
@@ -49,11 +49,11 @@ async function validateFlutterSdk(useFvm: boolean = false): Promise<boolean> {
49
49
  }
50
50
 
51
51
  // Check if fvm command is available
52
- await execCommand("fvm --version");
52
+ await execCommandSilent("fvm --version");
53
53
  return true;
54
54
  } else {
55
55
  // Check if global Flutter is available
56
- await execCommand("flutter --version");
56
+ await execCommandSilent("flutter --version");
57
57
  return true;
58
58
  }
59
59
  } catch (error) {