vibe-cokit 1.5.1 → 1.6.1
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/dist/cli.js +363 -11
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ var __export = (target, all) => {
|
|
|
10
10
|
set: (newValue) => all[name] = () => newValue
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
|
+
var __require = import.meta.require;
|
|
13
14
|
|
|
14
15
|
// node_modules/cac/dist/index.mjs
|
|
15
16
|
import { EventEmitter } from "events";
|
|
@@ -937,8 +938,8 @@ var stubFalse_default = stubFalse;
|
|
|
937
938
|
var freeExports = typeof exports_isBuffer == "object" && exports_isBuffer && !exports_isBuffer.nodeType && exports_isBuffer;
|
|
938
939
|
var freeModule = freeExports && typeof module_isBuffer == "object" && module_isBuffer && !module_isBuffer.nodeType && module_isBuffer;
|
|
939
940
|
var moduleExports = freeModule && freeModule.exports === freeExports;
|
|
940
|
-
var
|
|
941
|
-
var nativeIsBuffer =
|
|
941
|
+
var Buffer2 = moduleExports ? _root_default.Buffer : undefined;
|
|
942
|
+
var nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : undefined;
|
|
942
943
|
var isBuffer = nativeIsBuffer || stubFalse_default;
|
|
943
944
|
var isBuffer_default = isBuffer;
|
|
944
945
|
|
|
@@ -2663,7 +2664,321 @@ vibe-cokit v${version}`);
|
|
|
2663
2664
|
}
|
|
2664
2665
|
|
|
2665
2666
|
// src/commands/doctor.ts
|
|
2666
|
-
import { join as
|
|
2667
|
+
import { join as join6 } from "path";
|
|
2668
|
+
|
|
2669
|
+
// src/utils/keyboard.ts
|
|
2670
|
+
import { homedir as homedir2, platform } from "os";
|
|
2671
|
+
import { join as join5, dirname, basename } from "path";
|
|
2672
|
+
import { readdir as readdir2, stat as stat2, cp as cp2, readFile, writeFile } from "fs/promises";
|
|
2673
|
+
var PATCH_MARKER = "/* Vietnamese IME fix */";
|
|
2674
|
+
var DEL_CHAR = "\x7F";
|
|
2675
|
+
function detectFileType(filePath) {
|
|
2676
|
+
if (filePath.includes("/claude/versions/") || filePath.includes("\\claude\\versions\\")) {
|
|
2677
|
+
return "binary";
|
|
2678
|
+
}
|
|
2679
|
+
return "js";
|
|
2680
|
+
}
|
|
2681
|
+
async function findCliJs() {
|
|
2682
|
+
const home = homedir2();
|
|
2683
|
+
const isWin = platform() === "win32";
|
|
2684
|
+
const nativePath = join5(home, ".local", "share", "claude", "versions");
|
|
2685
|
+
try {
|
|
2686
|
+
const s = await stat2(nativePath);
|
|
2687
|
+
if (s.isDirectory()) {
|
|
2688
|
+
const entries = await readdir2(nativePath);
|
|
2689
|
+
const versions = entries.filter((e) => /^\d+\.\d+\.\d+$/.test(e));
|
|
2690
|
+
versions.sort((a, b) => b.localeCompare(a, undefined, { numeric: true }));
|
|
2691
|
+
for (const ver of versions) {
|
|
2692
|
+
const binPath = join5(nativePath, ver);
|
|
2693
|
+
try {
|
|
2694
|
+
const bs = await stat2(binPath);
|
|
2695
|
+
if (bs.isFile())
|
|
2696
|
+
return binPath;
|
|
2697
|
+
} catch {}
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
} catch {}
|
|
2701
|
+
const searchDirs = isWin ? [
|
|
2702
|
+
join5(process.env.LOCALAPPDATA ?? "", "npm-cache", "_npx"),
|
|
2703
|
+
join5(process.env.APPDATA ?? "", "npm", "node_modules")
|
|
2704
|
+
] : [
|
|
2705
|
+
join5(home, ".npm", "_npx"),
|
|
2706
|
+
join5(home, ".nvm", "versions", "node"),
|
|
2707
|
+
"/usr/local/lib/node_modules",
|
|
2708
|
+
"/opt/homebrew/lib/node_modules"
|
|
2709
|
+
];
|
|
2710
|
+
for (const dir of searchDirs) {
|
|
2711
|
+
try {
|
|
2712
|
+
const s = await stat2(dir);
|
|
2713
|
+
if (!s.isDirectory())
|
|
2714
|
+
continue;
|
|
2715
|
+
} catch {
|
|
2716
|
+
continue;
|
|
2717
|
+
}
|
|
2718
|
+
const found = await findCliJsRecursive(dir, 0, 5);
|
|
2719
|
+
if (found)
|
|
2720
|
+
return found;
|
|
2721
|
+
}
|
|
2722
|
+
throw new Error(`Kh\xF4ng t\xECm th\u1EA5y Claude Code.
|
|
2723
|
+
` + "C\xE0i \u0111\u1EB7t tr\u01B0\u1EDBc: npm install -g @anthropic-ai/claude-code");
|
|
2724
|
+
}
|
|
2725
|
+
async function findCliJsRecursive(dir, depth, maxDepth) {
|
|
2726
|
+
if (depth >= maxDepth)
|
|
2727
|
+
return null;
|
|
2728
|
+
try {
|
|
2729
|
+
const entries = await readdir2(dir, { withFileTypes: true });
|
|
2730
|
+
for (const entry of entries) {
|
|
2731
|
+
if (!entry.isDirectory())
|
|
2732
|
+
continue;
|
|
2733
|
+
const fullPath = join5(dir, entry.name);
|
|
2734
|
+
if (entry.name === "@anthropic-ai") {
|
|
2735
|
+
const cliJs = join5(fullPath, "claude-code", "cli.js");
|
|
2736
|
+
try {
|
|
2737
|
+
const s = await stat2(cliJs);
|
|
2738
|
+
if (s.isFile())
|
|
2739
|
+
return cliJs;
|
|
2740
|
+
} catch {}
|
|
2741
|
+
continue;
|
|
2742
|
+
}
|
|
2743
|
+
if (entry.name === "node_modules" && depth > 0)
|
|
2744
|
+
continue;
|
|
2745
|
+
const found = await findCliJsRecursive(fullPath, depth + 1, maxDepth);
|
|
2746
|
+
if (found)
|
|
2747
|
+
return found;
|
|
2748
|
+
}
|
|
2749
|
+
} catch {}
|
|
2750
|
+
return null;
|
|
2751
|
+
}
|
|
2752
|
+
async function readContent(filePath, fileType) {
|
|
2753
|
+
if (fileType === "binary") {
|
|
2754
|
+
const buf = await readFile(filePath);
|
|
2755
|
+
return buf.toString("latin1");
|
|
2756
|
+
}
|
|
2757
|
+
return Bun.file(filePath).text();
|
|
2758
|
+
}
|
|
2759
|
+
async function writeContent(filePath, content, fileType) {
|
|
2760
|
+
if (fileType === "binary") {
|
|
2761
|
+
const bytes = Buffer.from(content, "latin1");
|
|
2762
|
+
await writeFile(filePath, bytes);
|
|
2763
|
+
} else {
|
|
2764
|
+
await Bun.write(filePath, content);
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
function getBugPattern(fileType) {
|
|
2768
|
+
if (fileType === "binary") {
|
|
2769
|
+
return '.includes("\\x7F")';
|
|
2770
|
+
}
|
|
2771
|
+
return `.includes("${DEL_CHAR}")`;
|
|
2772
|
+
}
|
|
2773
|
+
function findBugBlock(content, fileType = "js") {
|
|
2774
|
+
const pattern = getBugPattern(fileType);
|
|
2775
|
+
let searchFrom = 0;
|
|
2776
|
+
while (true) {
|
|
2777
|
+
const idx = content.indexOf(pattern, searchFrom);
|
|
2778
|
+
if (idx === -1) {
|
|
2779
|
+
throw new Error(`Kh\xF4ng t\xECm th\u1EA5y bug pattern .includes("\\x7f").
|
|
2780
|
+
` + "Claude Code c\xF3 th\u1EC3 \u0111\xE3 \u0111\u01B0\u1EE3c Anthropic fix.");
|
|
2781
|
+
}
|
|
2782
|
+
const searchStart = Math.max(0, idx - 150);
|
|
2783
|
+
const blockStart = content.lastIndexOf("if(", idx);
|
|
2784
|
+
if (blockStart === -1 || blockStart < searchStart) {
|
|
2785
|
+
searchFrom = idx + 1;
|
|
2786
|
+
continue;
|
|
2787
|
+
}
|
|
2788
|
+
let depth = 0;
|
|
2789
|
+
let blockEnd = idx;
|
|
2790
|
+
const slice = content.slice(blockStart, blockStart + 800);
|
|
2791
|
+
for (let i = 0;i < slice.length; i++) {
|
|
2792
|
+
if (slice[i] === "{")
|
|
2793
|
+
depth++;
|
|
2794
|
+
else if (slice[i] === "}") {
|
|
2795
|
+
depth--;
|
|
2796
|
+
if (depth === 0) {
|
|
2797
|
+
blockEnd = blockStart + i + 1;
|
|
2798
|
+
break;
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
if (depth !== 0) {
|
|
2803
|
+
searchFrom = idx + 1;
|
|
2804
|
+
continue;
|
|
2805
|
+
}
|
|
2806
|
+
const block = content.slice(blockStart, blockEnd);
|
|
2807
|
+
if (fileType === "binary" && !block.includes("deleteTokenBefore")) {
|
|
2808
|
+
searchFrom = idx + 1;
|
|
2809
|
+
continue;
|
|
2810
|
+
}
|
|
2811
|
+
return { start: blockStart, end: blockEnd, block };
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
function extractVariables(block) {
|
|
2815
|
+
const normalized = block.replaceAll(DEL_CHAR, "\\x7f");
|
|
2816
|
+
const m1 = normalized.match(/let ([\w$]+)=\(\w+\.match\(\/\\x7f\/g\)\|\|\[\]\)\.length[,;]([\w$]+)=([\w$]+)[;,]/);
|
|
2817
|
+
if (!m1)
|
|
2818
|
+
throw new Error("Kh\xF4ng tr\xEDch xu\u1EA5t \u0111\u01B0\u1EE3c bi\u1EBFn count/state");
|
|
2819
|
+
const state = m1[2];
|
|
2820
|
+
const curState = m1[3];
|
|
2821
|
+
const stateEsc = state.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2822
|
+
const m2 = block.match(new RegExp(`([\\w$]+)\\(${stateEsc}\\.text\\);([\\w$]+)\\(${stateEsc}\\.offset\\)`));
|
|
2823
|
+
if (!m2)
|
|
2824
|
+
throw new Error("Kh\xF4ng tr\xEDch xu\u1EA5t \u0111\u01B0\u1EE3c update functions");
|
|
2825
|
+
const m3 = block.match(/([\w$]+)\.includes\("/);
|
|
2826
|
+
if (!m3)
|
|
2827
|
+
throw new Error("Kh\xF4ng tr\xEDch xu\u1EA5t \u0111\u01B0\u1EE3c input variable");
|
|
2828
|
+
return {
|
|
2829
|
+
input: m3[1],
|
|
2830
|
+
state,
|
|
2831
|
+
curState,
|
|
2832
|
+
updateText: m2[1],
|
|
2833
|
+
updateOffset: m2[2]
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
function generateFix(vars) {
|
|
2837
|
+
const v = vars;
|
|
2838
|
+
return `${PATCH_MARKER}` + `if(${v.input}.includes("\\x7f")){` + `let _n=(${v.input}.match(/\\x7f/g)||[]).length,` + `_vn=${v.input}.replace(/\\x7f/g,""),` + `${v.state}=${v.curState};` + `for(let _i=0;_i<_n;_i++)${v.state}=${v.state}.backspace();` + `for(const _c of _vn)${v.state}=${v.state}.insert(_c);` + `if(!${v.curState}.equals(${v.state})){` + `if(${v.curState}.text!==${v.state}.text)` + `${v.updateText}(${v.state}.text);` + `${v.updateOffset}(${v.state}.offset)` + `}return;}`;
|
|
2839
|
+
}
|
|
2840
|
+
function generateBinaryFix(block, vars) {
|
|
2841
|
+
const v = vars;
|
|
2842
|
+
const counterMatch = block.match(/let ([\w$]+)=\(/);
|
|
2843
|
+
const counter = counterMatch?.[1] ?? "XH";
|
|
2844
|
+
let fix = `if(!FH.backspace&&!FH.delete&&${v.input}.includes("\\x7F")){` + `let ${counter}=(${v.input}.match(/\\x7f/g)||[]).length,` + `${v.state}=${v.curState};` + `while(${counter}--)${v.state}=${v.state}.backspace();` + `for(c of ${v.input}.replace(/\\x7f/g,""))${v.state}=${v.state}.insert(c);` + `if(!${v.curState}.equals(${v.state})){` + `if(${v.curState}.text!==${v.state}.text)` + `${v.updateText}(${v.state}.text);` + `${v.updateOffset}(${v.state}.offset)` + `}return}`;
|
|
2845
|
+
const diff = block.length - fix.length;
|
|
2846
|
+
if (diff > 0) {
|
|
2847
|
+
fix = fix.slice(0, -1) + " ".repeat(diff) + "}";
|
|
2848
|
+
} else if (diff < 0) {
|
|
2849
|
+
throw new Error(`Fix code qu\xE1 d\xE0i (${-diff} bytes). Kh\xF4ng th\u1EC3 patch binary.`);
|
|
2850
|
+
}
|
|
2851
|
+
return fix;
|
|
2852
|
+
}
|
|
2853
|
+
async function patchCliJs(filePath) {
|
|
2854
|
+
const fileType = detectFileType(filePath);
|
|
2855
|
+
try {
|
|
2856
|
+
await stat2(filePath);
|
|
2857
|
+
} catch {
|
|
2858
|
+
return { success: false, message: `File kh\xF4ng t\u1ED3n t\u1EA1i: ${filePath}` };
|
|
2859
|
+
}
|
|
2860
|
+
const content = await readContent(filePath, fileType);
|
|
2861
|
+
if (content.includes(PATCH_MARKER)) {
|
|
2862
|
+
return { success: false, message: "\u0110\xE3 patch tr\u01B0\u1EDBc \u0111\xF3" };
|
|
2863
|
+
}
|
|
2864
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
2865
|
+
const backupDir = fileType === "binary" ? "/tmp" : dirname(filePath);
|
|
2866
|
+
const backupPath = join5(backupDir, `${basename(filePath)}.backup-${timestamp}`);
|
|
2867
|
+
await cp2(filePath, backupPath);
|
|
2868
|
+
try {
|
|
2869
|
+
const bugPattern = getBugPattern(fileType);
|
|
2870
|
+
let patched = content;
|
|
2871
|
+
if (fileType === "binary") {
|
|
2872
|
+
let patchCount = 0;
|
|
2873
|
+
while (patchCount < 10) {
|
|
2874
|
+
try {
|
|
2875
|
+
const { start, end, block } = findBugBlock(patched, fileType);
|
|
2876
|
+
const vars = extractBinaryVariables(block);
|
|
2877
|
+
const fix = generateBinaryFix(block, vars);
|
|
2878
|
+
patched = patched.slice(0, start) + fix + patched.slice(end);
|
|
2879
|
+
patchCount++;
|
|
2880
|
+
} catch {
|
|
2881
|
+
break;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
if (patchCount === 0) {
|
|
2885
|
+
throw new Error("Kh\xF4ng t\xECm th\u1EA5y bug block");
|
|
2886
|
+
}
|
|
2887
|
+
} else {
|
|
2888
|
+
const { start, end, block } = findBugBlock(content, fileType);
|
|
2889
|
+
const vars = extractVariables(block);
|
|
2890
|
+
const fix = generateFix(vars);
|
|
2891
|
+
patched = content.slice(0, start) + fix + content.slice(end);
|
|
2892
|
+
}
|
|
2893
|
+
if (fileType === "binary" && patched.length !== content.length) {
|
|
2894
|
+
throw new Error(`Binary patch size mismatch: ${patched.length} vs ${content.length}`);
|
|
2895
|
+
}
|
|
2896
|
+
await writeContent(filePath, patched, fileType);
|
|
2897
|
+
const verify = await readContent(filePath, fileType);
|
|
2898
|
+
if (fileType === "binary") {
|
|
2899
|
+
let searchPos = 0;
|
|
2900
|
+
while (true) {
|
|
2901
|
+
const pos = verify.indexOf(bugPattern, searchPos);
|
|
2902
|
+
if (pos === -1)
|
|
2903
|
+
break;
|
|
2904
|
+
const vicinity = verify.slice(Math.max(0, pos - 100), pos + 300);
|
|
2905
|
+
if (vicinity.includes("deleteTokenBefore")) {
|
|
2906
|
+
throw new Error("Verify failed: unpatched bug block still present after binary patch");
|
|
2907
|
+
}
|
|
2908
|
+
searchPos = pos + 1;
|
|
2909
|
+
}
|
|
2910
|
+
} else {
|
|
2911
|
+
if (!verify.includes(PATCH_MARKER)) {
|
|
2912
|
+
throw new Error("Verify failed: patch marker not found after write");
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
return { success: true, message: "Patch th\xE0nh c\xF4ng", backupPath };
|
|
2916
|
+
} catch (err) {
|
|
2917
|
+
try {
|
|
2918
|
+
await cp2(backupPath, filePath);
|
|
2919
|
+
const { unlink } = await import("fs/promises");
|
|
2920
|
+
await unlink(backupPath);
|
|
2921
|
+
} catch {}
|
|
2922
|
+
return {
|
|
2923
|
+
success: false,
|
|
2924
|
+
message: err instanceof Error ? err.message : String(err)
|
|
2925
|
+
};
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
function extractBinaryVariables(block) {
|
|
2929
|
+
const m1 = block.match(/let ([\w$]+)=\(([\w$]+)\.match\(\/\\x7f\/g\)\|\|\[\]\)\.length,([\w$]+)=([\w$]+)[;,]/);
|
|
2930
|
+
if (!m1)
|
|
2931
|
+
throw new Error("Kh\xF4ng tr\xEDch xu\u1EA5t \u0111\u01B0\u1EE3c bi\u1EBFn count/state (binary)");
|
|
2932
|
+
const input = m1[2];
|
|
2933
|
+
const state = m1[3];
|
|
2934
|
+
const curState = m1[4];
|
|
2935
|
+
const stateEsc = state.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2936
|
+
const m2 = block.match(new RegExp(`([\\w$]+)\\(${stateEsc}\\.text\\);([\\w$]+)\\(${stateEsc}\\.offset\\)`));
|
|
2937
|
+
if (!m2)
|
|
2938
|
+
throw new Error("Kh\xF4ng tr\xEDch xu\u1EA5t \u0111\u01B0\u1EE3c update functions (binary)");
|
|
2939
|
+
return {
|
|
2940
|
+
input,
|
|
2941
|
+
state,
|
|
2942
|
+
curState,
|
|
2943
|
+
updateText: m2[1],
|
|
2944
|
+
updateOffset: m2[2]
|
|
2945
|
+
};
|
|
2946
|
+
}
|
|
2947
|
+
async function checkKeyboardStatus() {
|
|
2948
|
+
try {
|
|
2949
|
+
const cliJsPath = await findCliJs();
|
|
2950
|
+
const fileType = detectFileType(cliJsPath);
|
|
2951
|
+
const content = await readContent(cliJsPath, fileType);
|
|
2952
|
+
const bugPattern = getBugPattern(fileType);
|
|
2953
|
+
let patched;
|
|
2954
|
+
let hasBug;
|
|
2955
|
+
if (fileType === "binary") {
|
|
2956
|
+
let hasUnpatchedBlock = false;
|
|
2957
|
+
let searchPos = 0;
|
|
2958
|
+
while (true) {
|
|
2959
|
+
const pos = content.indexOf(bugPattern, searchPos);
|
|
2960
|
+
if (pos === -1)
|
|
2961
|
+
break;
|
|
2962
|
+
const vicinity = content.slice(Math.max(0, pos - 100), pos + 300);
|
|
2963
|
+
if (vicinity.includes("deleteTokenBefore")) {
|
|
2964
|
+
hasUnpatchedBlock = true;
|
|
2965
|
+
break;
|
|
2966
|
+
}
|
|
2967
|
+
searchPos = pos + 1;
|
|
2968
|
+
}
|
|
2969
|
+
hasBug = hasUnpatchedBlock;
|
|
2970
|
+
patched = content.includes(bugPattern) && !hasUnpatchedBlock;
|
|
2971
|
+
} else {
|
|
2972
|
+
patched = content.includes(PATCH_MARKER);
|
|
2973
|
+
hasBug = content.includes(bugPattern) && !patched;
|
|
2974
|
+
}
|
|
2975
|
+
return { cliJsFound: true, cliJsPath, isPatched: patched, hasBug, isBinary: fileType === "binary" };
|
|
2976
|
+
} catch {
|
|
2977
|
+
return { cliJsFound: false, cliJsPath: null, isPatched: false, hasBug: false, isBinary: false };
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
// src/commands/doctor.ts
|
|
2667
2982
|
async function doctorCommand() {
|
|
2668
2983
|
console.log(`
|
|
2669
2984
|
vibe-cokit doctor
|
|
@@ -2687,7 +3002,7 @@ vibe-cokit doctor
|
|
|
2687
3002
|
issues++;
|
|
2688
3003
|
}
|
|
2689
3004
|
for (const folder of CONFIG_FOLDERS) {
|
|
2690
|
-
const path =
|
|
3005
|
+
const path = join6(CLAUDE_DIR, folder);
|
|
2691
3006
|
if (await dirExists(path)) {
|
|
2692
3007
|
console.log(` \u2713 ~/.claude/${folder}/`);
|
|
2693
3008
|
} else {
|
|
@@ -2701,7 +3016,7 @@ vibe-cokit doctor
|
|
|
2701
3016
|
console.log(` \u2717 ~/.claude/skills/ missing \u2014 run \`vk skills\``);
|
|
2702
3017
|
issues++;
|
|
2703
3018
|
}
|
|
2704
|
-
const settingsPath =
|
|
3019
|
+
const settingsPath = join6(CLAUDE_DIR, "settings.json");
|
|
2705
3020
|
if (await fileExists(settingsPath)) {
|
|
2706
3021
|
console.log(` \u2713 ~/.claude/settings.json`);
|
|
2707
3022
|
} else {
|
|
@@ -2713,7 +3028,20 @@ vibe-cokit doctor
|
|
|
2713
3028
|
const skillsVersion = await getSkillsVersion();
|
|
2714
3029
|
console.log(` Config version: ${configVersion ? configVersion.slice(0, 10) : "not installed"}`);
|
|
2715
3030
|
console.log(` Skills version: ${skillsVersion ? skillsVersion.slice(0, 10) : "not installed"}`);
|
|
2716
|
-
const
|
|
3031
|
+
const kbStatus = await checkKeyboardStatus();
|
|
3032
|
+
if (kbStatus.cliJsFound) {
|
|
3033
|
+
if (kbStatus.isPatched) {
|
|
3034
|
+
console.log(` \u2713 Vietnamese IME fix: applied`);
|
|
3035
|
+
} else if (kbStatus.hasBug) {
|
|
3036
|
+
console.log(` \u2717 Vietnamese IME fix: not applied \u2014 run \`vk doctor --fix\``);
|
|
3037
|
+
issues++;
|
|
3038
|
+
} else {
|
|
3039
|
+
console.log(` \u2713 Vietnamese IME: no bug detected`);
|
|
3040
|
+
}
|
|
3041
|
+
} else {
|
|
3042
|
+
console.log(` \u26A0 Claude Code CLI: not found`);
|
|
3043
|
+
}
|
|
3044
|
+
const claudeMdExists = await fileExists(join6(process.cwd(), "CLAUDE.md"));
|
|
2717
3045
|
console.log(` Project CLAUDE.md: ${claudeMdExists ? "found" : "not found"}`);
|
|
2718
3046
|
console.log();
|
|
2719
3047
|
if (issues === 0) {
|
|
@@ -2726,7 +3054,7 @@ vibe-cokit doctor
|
|
|
2726
3054
|
}
|
|
2727
3055
|
|
|
2728
3056
|
// src/commands/doctor-fix.ts
|
|
2729
|
-
import { join as
|
|
3057
|
+
import { join as join7 } from "path";
|
|
2730
3058
|
async function doctorFixCommand() {
|
|
2731
3059
|
console.log(`
|
|
2732
3060
|
vibe-cokit doctor fix
|
|
@@ -2741,12 +3069,12 @@ vibe-cokit doctor fix
|
|
|
2741
3069
|
process.exit(1);
|
|
2742
3070
|
}
|
|
2743
3071
|
let fixed = 0;
|
|
2744
|
-
const folderChecks = await Promise.all(CONFIG_FOLDERS.map((f) => dirExists(
|
|
3072
|
+
const folderChecks = await Promise.all(CONFIG_FOLDERS.map((f) => dirExists(join7(CLAUDE_DIR, f))));
|
|
2745
3073
|
const configMissing = !await dirExists(CLAUDE_DIR) || some_default(folderChecks, (exists) => !exists) || !await getCurrentVersion();
|
|
2746
|
-
const claudeMdPath =
|
|
3074
|
+
const claudeMdPath = join7(process.cwd(), "CLAUDE.md");
|
|
2747
3075
|
const claudeMdMissing = !await fileExists(claudeMdPath);
|
|
2748
3076
|
if (configMissing || claudeMdMissing) {
|
|
2749
|
-
const tmpDir =
|
|
3077
|
+
const tmpDir = join7(TEMP_DIR, crypto.randomUUID());
|
|
2750
3078
|
try {
|
|
2751
3079
|
await cloneRepo(tmpDir);
|
|
2752
3080
|
if (configMissing) {
|
|
@@ -2779,7 +3107,7 @@ vibe-cokit doctor fix
|
|
|
2779
3107
|
const skillsMissing = !await dirExists(SKILLS_DIR) || !await getSkillsVersion();
|
|
2780
3108
|
if (skillsMissing) {
|
|
2781
3109
|
log("Skills missing \u2014 installing...");
|
|
2782
|
-
const tmpDir =
|
|
3110
|
+
const tmpDir = join7(TEMP_DIR, crypto.randomUUID());
|
|
2783
3111
|
try {
|
|
2784
3112
|
await cloneRepo(tmpDir, SKILLS_REPO);
|
|
2785
3113
|
await copySkillFolders(tmpDir);
|
|
@@ -2795,6 +3123,30 @@ vibe-cokit doctor fix
|
|
|
2795
3123
|
} else {
|
|
2796
3124
|
log("Skills: OK");
|
|
2797
3125
|
}
|
|
3126
|
+
const kbStatus = await checkKeyboardStatus();
|
|
3127
|
+
if (kbStatus.cliJsFound && kbStatus.hasBug && !kbStatus.isPatched) {
|
|
3128
|
+
log("Vietnamese IME fix missing \u2014 patching...");
|
|
3129
|
+
try {
|
|
3130
|
+
const result = await patchCliJs(kbStatus.cliJsPath);
|
|
3131
|
+
if (result.success) {
|
|
3132
|
+
log(`Vietnamese IME fix applied`);
|
|
3133
|
+
if (result.backupPath) {
|
|
3134
|
+
log(`Backup: ${result.backupPath}`);
|
|
3135
|
+
}
|
|
3136
|
+
fixed++;
|
|
3137
|
+
} else {
|
|
3138
|
+
console.error(` \u2717 Keyboard fix failed: ${result.message}`);
|
|
3139
|
+
}
|
|
3140
|
+
} catch (err) {
|
|
3141
|
+
console.error(` \u2717 Keyboard fix failed: ${getErrorMsg(err)}`);
|
|
3142
|
+
}
|
|
3143
|
+
} else if (kbStatus.cliJsFound && kbStatus.isPatched) {
|
|
3144
|
+
log("Vietnamese IME fix: OK");
|
|
3145
|
+
} else if (kbStatus.cliJsFound && !kbStatus.hasBug) {
|
|
3146
|
+
log("Vietnamese IME: no bug detected");
|
|
3147
|
+
} else {
|
|
3148
|
+
log("Claude Code CLI: not found (skip keyboard fix)");
|
|
3149
|
+
}
|
|
2798
3150
|
console.log();
|
|
2799
3151
|
if (fixed > 0) {
|
|
2800
3152
|
console.log(` \u2713 Fixed ${plural(fixed, "issue")}!
|