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,28 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { promisify } from "util";
|
|
1
|
+
import { spawn } from "child_process";
|
|
3
2
|
import path from "path";
|
|
4
3
|
import { LoggerHelpers } from "./logger.js";
|
|
4
|
+
import { RETRY_CONFIG } from "../../constants.js";
|
|
5
|
+
import { isDryRunMode, DryRunManager } from "../helpers/dryRun.js";
|
|
5
6
|
export const iosDirectory = path.join(process.cwd(), "ios");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Shared base executor with proper timeout support via setTimeout + kill.
|
|
9
|
+
* Both execCommand and execInIos delegate to this.
|
|
10
|
+
*/
|
|
11
|
+
function execBase(fullCommand, options = {}) {
|
|
12
|
+
const { silent = false, timeoutMs } = options;
|
|
13
|
+
// Dry-run: log the command instead of executing
|
|
14
|
+
if (isDryRunMode()) {
|
|
15
|
+
const dryRun = new DryRunManager();
|
|
16
|
+
dryRun.logCommand("Execute command", fullCommand);
|
|
17
|
+
return Promise.resolve("");
|
|
11
18
|
}
|
|
12
|
-
if (stderr) {
|
|
13
|
-
LoggerHelpers.warning(`stderr: ${stderr}`);
|
|
14
|
-
}
|
|
15
|
-
if (stdout) {
|
|
16
|
-
LoggerHelpers.success(`stdout: ${stdout}`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export async function execCommand(command) {
|
|
20
19
|
return new Promise((resolve, reject) => {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
20
|
+
const childProcess = spawn(fullCommand, { shell: true });
|
|
21
|
+
const startTime = Date.now();
|
|
23
22
|
let output = "";
|
|
24
23
|
let lastLogLine = "";
|
|
25
|
-
|
|
24
|
+
let killed = false;
|
|
25
|
+
// Enforce timeout via setTimeout + kill (spawn doesn't support timeout)
|
|
26
|
+
let timer;
|
|
27
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
28
|
+
timer = setTimeout(() => {
|
|
29
|
+
killed = true;
|
|
30
|
+
childProcess.kill("SIGTERM");
|
|
31
|
+
reject(new Error(`Command timed out after ${timeoutMs / 1000}s: ${fullCommand}`));
|
|
32
|
+
}, timeoutMs);
|
|
33
|
+
}
|
|
34
|
+
childProcess.stdout.on("data", (data) => {
|
|
35
|
+
if (silent) {
|
|
36
|
+
output += data.toString();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
26
39
|
const dataString = data.toString().trim();
|
|
27
40
|
output += dataString;
|
|
28
41
|
if (dataString) {
|
|
@@ -38,78 +51,29 @@ export async function execCommand(command) {
|
|
|
38
51
|
}
|
|
39
52
|
}
|
|
40
53
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
process.on("close", (code) => {
|
|
45
|
-
if (lastLogLine) {
|
|
46
|
-
LoggerHelpers.success(lastLogLine);
|
|
47
|
-
}
|
|
48
|
-
if (code !== 0) {
|
|
49
|
-
reject(new Error(`Command failed with exit code ${code}`));
|
|
54
|
+
childProcess.stderr.on("data", (data) => {
|
|
55
|
+
if (silent) {
|
|
56
|
+
output += data.toString();
|
|
50
57
|
}
|
|
51
58
|
else {
|
|
52
|
-
|
|
59
|
+
LoggerHelpers.error(data.toString());
|
|
53
60
|
}
|
|
54
61
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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);
|
|
62
|
+
childProcess.on("close", (code) => {
|
|
63
|
+
if (timer)
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
if (killed)
|
|
66
|
+
return;
|
|
67
|
+
if (!silent && lastLogLine) {
|
|
68
|
+
LoggerHelpers.success(lastLogLine);
|
|
77
69
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
export async function execInIos(command) {
|
|
85
|
-
return new Promise((resolve, reject) => {
|
|
86
|
-
const fullCommand = `cd "${iosDirectory}" && ${command}`;
|
|
87
|
-
const process = spawn(fullCommand, { shell: true, timeout: 600000 });
|
|
88
|
-
let output = "";
|
|
89
|
-
let lastLogLine = "";
|
|
90
|
-
process.stdout.on("data", (data) => {
|
|
91
|
-
const dataString = data.toString().trim();
|
|
92
|
-
output += dataString;
|
|
93
|
-
if (dataString) {
|
|
94
|
-
if ((dataString.endsWith("ms") || dataString.endsWith("s")) &&
|
|
95
|
-
lastLogLine) {
|
|
96
|
-
lastLogLine += ` ${dataString}`;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
if (lastLogLine) {
|
|
100
|
-
LoggerHelpers.success(lastLogLine);
|
|
101
|
-
}
|
|
102
|
-
lastLogLine = dataString;
|
|
70
|
+
// Show elapsed time for non-silent commands over 1 second
|
|
71
|
+
if (!silent) {
|
|
72
|
+
const elapsed = Date.now() - startTime;
|
|
73
|
+
if (elapsed > 1000) {
|
|
74
|
+
LoggerHelpers.info(`Completed in ${formatElapsed(elapsed)}`);
|
|
103
75
|
}
|
|
104
76
|
}
|
|
105
|
-
});
|
|
106
|
-
process.stderr.on("data", (data) => {
|
|
107
|
-
LoggerHelpers.error(data.toString());
|
|
108
|
-
});
|
|
109
|
-
process.on("close", (code) => {
|
|
110
|
-
if (lastLogLine) {
|
|
111
|
-
LoggerHelpers.success(lastLogLine);
|
|
112
|
-
}
|
|
113
77
|
if (code !== 0) {
|
|
114
78
|
reject(new Error(`Command failed with exit code ${code}`));
|
|
115
79
|
}
|
|
@@ -117,40 +81,51 @@ export async function execInIos(command) {
|
|
|
117
81
|
resolve(output);
|
|
118
82
|
}
|
|
119
83
|
});
|
|
120
|
-
|
|
84
|
+
childProcess.on("error", (err) => {
|
|
85
|
+
if (timer)
|
|
86
|
+
clearTimeout(timer);
|
|
121
87
|
reject(new Error(`Failed to start subprocess: ${err.message}`));
|
|
122
88
|
});
|
|
123
89
|
});
|
|
124
90
|
}
|
|
125
|
-
export async function
|
|
91
|
+
export async function execCommand(command) {
|
|
92
|
+
return execBase(command);
|
|
93
|
+
}
|
|
94
|
+
export async function execCommandSilent(command) {
|
|
95
|
+
return execBase(command, { silent: true });
|
|
96
|
+
}
|
|
97
|
+
export async function execInIos(command, timeoutMs = RETRY_CONFIG.IOS_TIMEOUT_MS) {
|
|
98
|
+
const fullCommand = `cd "${iosDirectory}" && ${command}`;
|
|
99
|
+
return execBase(fullCommand, { timeoutMs });
|
|
100
|
+
}
|
|
101
|
+
export async function execInIosWithRetry(command, retries = RETRY_CONFIG.DEFAULT_ATTEMPTS, delay = RETRY_CONFIG.DEFAULT_DELAY_MS) {
|
|
126
102
|
let attempts = 0;
|
|
127
103
|
let lastError;
|
|
128
104
|
while (attempts < retries) {
|
|
129
105
|
try {
|
|
130
|
-
|
|
131
|
-
return result;
|
|
106
|
+
return await execInIos(command);
|
|
132
107
|
}
|
|
133
108
|
catch (error) {
|
|
134
109
|
attempts++;
|
|
135
110
|
lastError = error;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
LoggerHelpers.error(`Attempt ${attempts} failed. Unknown error: ${JSON.stringify(error)}`);
|
|
141
|
-
}
|
|
111
|
+
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
|
112
|
+
LoggerHelpers.error(`Attempt ${attempts} failed. Error: ${message}`);
|
|
142
113
|
if (attempts >= retries) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
LoggerHelpers.error(`Command failed after ${retries} attempts: Unknown error`);
|
|
148
|
-
}
|
|
149
|
-
throw new Error(`Command failed after ${retries} attempts: ${lastError instanceof Error ? lastError.message : "Unknown error"}`);
|
|
114
|
+
const finalMessage = lastError instanceof Error ? lastError.message : "Unknown error";
|
|
115
|
+
LoggerHelpers.error(`Command failed after ${retries} attempts: ${finalMessage}`);
|
|
116
|
+
throw new Error(`Command failed after ${retries} attempts: ${finalMessage}`);
|
|
150
117
|
}
|
|
151
118
|
LoggerHelpers.error(`Retrying in ${delay / 1000} seconds...`);
|
|
152
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
119
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
153
120
|
}
|
|
154
121
|
}
|
|
155
122
|
throw lastError;
|
|
156
123
|
}
|
|
124
|
+
function formatElapsed(ms) {
|
|
125
|
+
const seconds = Math.floor(ms / 1000);
|
|
126
|
+
if (seconds < 60)
|
|
127
|
+
return `${seconds}s`;
|
|
128
|
+
const minutes = Math.floor(seconds / 60);
|
|
129
|
+
const remainingSeconds = seconds % 60;
|
|
130
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
131
|
+
}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
export class LoggerHelpers {
|
|
3
3
|
static success(message) {
|
|
4
|
-
console.log(chalk.green(message));
|
|
4
|
+
console.log(chalk.green(` ✔ ${message}`));
|
|
5
5
|
}
|
|
6
6
|
static error(message) {
|
|
7
|
-
console.log(chalk.red(message));
|
|
7
|
+
console.log(chalk.red(` ✖ ${message}`));
|
|
8
8
|
}
|
|
9
9
|
static warning(message) {
|
|
10
|
-
console.log(chalk.yellow(message));
|
|
10
|
+
console.log(chalk.yellow(` ⚠ ${message}`));
|
|
11
11
|
}
|
|
12
12
|
static info(message) {
|
|
13
|
-
console.log(chalk.
|
|
13
|
+
console.log(chalk.cyan(` ℹ ${message}`));
|
|
14
|
+
}
|
|
15
|
+
static step(message) {
|
|
16
|
+
console.log(chalk.white(` → ${message}`));
|
|
17
|
+
}
|
|
18
|
+
static dim(message) {
|
|
19
|
+
console.log(chalk.gray(` ${message}`));
|
|
14
20
|
}
|
|
15
21
|
}
|
|
@@ -7,17 +7,21 @@ export { validateFlutterProject, validateFlutterSdk, validateIosProject, validat
|
|
|
7
7
|
* Validates that the current directory is a Flutter project
|
|
8
8
|
* by checking for pubspec.yaml
|
|
9
9
|
*/
|
|
10
|
-
function validateFlutterProject() {
|
|
10
|
+
function validateFlutterProject(silent = false) {
|
|
11
11
|
const pubspecPath = path.join(process.cwd(), "pubspec.yaml");
|
|
12
12
|
if (!fs.existsSync(pubspecPath)) {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
if (!silent) {
|
|
14
|
+
LoggerHelpers.error("Not a Flutter project: pubspec.yaml not found.");
|
|
15
|
+
LoggerHelpers.info("Please run this command from the root of a Flutter project.");
|
|
16
|
+
}
|
|
15
17
|
return false;
|
|
16
18
|
}
|
|
17
19
|
// Check if pubspec.yaml contains Flutter SDK
|
|
18
20
|
const pubspecContent = fs.readFileSync(pubspecPath, "utf8");
|
|
19
21
|
if (!pubspecContent.includes("flutter:")) {
|
|
20
|
-
|
|
22
|
+
if (!silent) {
|
|
23
|
+
LoggerHelpers.error("Not a Flutter project: pubspec.yaml does not reference Flutter SDK.");
|
|
24
|
+
}
|
|
21
25
|
return false;
|
|
22
26
|
}
|
|
23
27
|
return true;
|
|
@@ -60,17 +64,21 @@ async function validateFlutterSdk(useFvm = false) {
|
|
|
60
64
|
/**
|
|
61
65
|
* Validates that the iOS project exists
|
|
62
66
|
*/
|
|
63
|
-
function validateIosProject() {
|
|
67
|
+
function validateIosProject(silent = false) {
|
|
64
68
|
const iosPath = path.join(process.cwd(), "ios");
|
|
65
69
|
if (!fs.existsSync(iosPath)) {
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
if (!silent) {
|
|
71
|
+
LoggerHelpers.error("iOS project directory not found.");
|
|
72
|
+
LoggerHelpers.info("Run 'flutter create .' to add iOS support.");
|
|
73
|
+
}
|
|
68
74
|
return false;
|
|
69
75
|
}
|
|
70
76
|
const xcodeProjPath = path.join(iosPath, "Runner.xcodeproj");
|
|
71
77
|
const xcworkspacePath = path.join(iosPath, "Runner.xcworkspace");
|
|
72
78
|
if (!fs.existsSync(xcodeProjPath) && !fs.existsSync(xcworkspacePath)) {
|
|
73
|
-
|
|
79
|
+
if (!silent) {
|
|
80
|
+
LoggerHelpers.error("No Xcode project or workspace found in ios/ directory.");
|
|
81
|
+
}
|
|
74
82
|
return false;
|
|
75
83
|
}
|
|
76
84
|
return true;
|
|
@@ -78,17 +86,21 @@ function validateIosProject() {
|
|
|
78
86
|
/**
|
|
79
87
|
* Validates that the Android project exists
|
|
80
88
|
*/
|
|
81
|
-
function validateAndroidProject() {
|
|
89
|
+
function validateAndroidProject(silent = false) {
|
|
82
90
|
const androidPath = path.join(process.cwd(), "android");
|
|
83
91
|
if (!fs.existsSync(androidPath)) {
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
if (!silent) {
|
|
93
|
+
LoggerHelpers.error("Android project directory not found.");
|
|
94
|
+
LoggerHelpers.info("Run 'flutter create .' to add Android support.");
|
|
95
|
+
}
|
|
86
96
|
return false;
|
|
87
97
|
}
|
|
88
98
|
const buildGradlePath = path.join(androidPath, "build.gradle");
|
|
89
99
|
const buildGradleKtsPath = path.join(androidPath, "build.gradle.kts");
|
|
90
100
|
if (!fs.existsSync(buildGradlePath) && !fs.existsSync(buildGradleKtsPath)) {
|
|
91
|
-
|
|
101
|
+
if (!silent) {
|
|
102
|
+
LoggerHelpers.error("No build.gradle found in android/ directory.");
|
|
103
|
+
}
|
|
92
104
|
return false;
|
|
93
105
|
}
|
|
94
106
|
return true;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# 🔧 Installation Guide
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## ⚡ NPM (Recommended)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g optikit
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Verify:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
optikit --version
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
You get two commands — `optikit` and `ok` — both work identically.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 📦 Homebrew
|
|
22
|
+
|
|
23
|
+
### Via HTTPS
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
brew tap dev-mahmoud-elshenawy/optikit
|
|
27
|
+
brew install optikit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Via SSH (Recommended)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
brew tap dev-mahmoud-elshenawy/optikit git@github.com:dev-mahmoud-elshenawy/optikit.git
|
|
34
|
+
brew install optikit
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🛠️ From Source
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/dev-mahmoud-elshenawy/optikit.git
|
|
43
|
+
cd optikit
|
|
44
|
+
npm install && npm run build
|
|
45
|
+
npm link
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Verify:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
optikit --version
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## ✅ Shell Autocomplete (Optional)
|
|
57
|
+
|
|
58
|
+
Enable tab completion for all commands and flags:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
optikit completion >> ~/.zshrc && source ~/.zshrc
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚀 Next Steps
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
optikit init # Setup OptiKit in your Flutter project
|
|
70
|
+
optikit aliases # See all commands & shortcuts
|
|
71
|
+
optikit --help # Full help
|
|
72
|
+
```
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# 🔍 Troubleshooting
|
|
2
|
+
|
|
3
|
+
Quick fixes for common OptiKit issues.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ❌ `optikit` or `ok` command not found
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Reinstall globally
|
|
11
|
+
npm install -g optikit
|
|
12
|
+
|
|
13
|
+
# Verify
|
|
14
|
+
optikit --version
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
If still not found, check your npm global bin is in PATH:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm bin -g
|
|
21
|
+
# Add the output path to your shell config if missing
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ❌ FVM not found
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
✖ FVM Flutter SDK not found at .fvm/flutter_sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Fix:** Install FVM and set up the project:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
fvm install
|
|
36
|
+
fvm use <version>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Or skip FVM for this command:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
optikit apk -f # -f = --disable-fvm
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or disable FVM globally in `.optikitrc.json`:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"useFvmByDefault": false
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## ❌ Not a Flutter project
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
✖ Not a Flutter project: pubspec.yaml not found.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Fix:** Run OptiKit from the **root** of your Flutter project (where `pubspec.yaml` is).
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## ❌ iOS / Android project not found
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
✖ iOS project directory not found.
|
|
69
|
+
✖ Android project directory not found.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Fix:** Add platform support:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
flutter create . # Adds missing ios/ and android/ directories
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## ❌ Build fails
|
|
81
|
+
|
|
82
|
+
1. **Check environment first:**
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
optikit dr # Doctor checks Flutter, FVM, platforms
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
2. **Try a clean build:**
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
optikit apk --clean # Clean before building
|
|
92
|
+
optikit ipa --clean # Clean before building (iOS)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
3. **For iOS CocoaPods issues:**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
optikit ci -cu # Clean iOS + clear cache + update repo
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## ❌ Wrong version after bump
|
|
104
|
+
|
|
105
|
+
**Check current state:**
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
optikit v # Show current version info
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Restore from backup:**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
optikit undo # List all backups
|
|
115
|
+
optikit undo --restore 1 # Restore the most recent backup
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## ❌ Module generation overwrites existing files
|
|
121
|
+
|
|
122
|
+
OptiKit warns before overwriting. If you accidentally overwrote:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Check git for the original
|
|
126
|
+
git diff lib/module/<module_name>/
|
|
127
|
+
git checkout -- lib/module/<module_name>/
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 💡 General Tips
|
|
133
|
+
|
|
134
|
+
| Tip | Command |
|
|
135
|
+
|-----|---------|
|
|
136
|
+
| Check environment health | `optikit dr` |
|
|
137
|
+
| Preview without executing | `optikit apk --dry-run` |
|
|
138
|
+
| See all available commands | `optikit aliases` |
|
|
139
|
+
| Get help for any command | `optikit <command> --help` |
|
|
140
|
+
| Check for CLI updates | `optikit up` |
|