vibe-cokit 1.6.0 → 1.6.2

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.
Files changed (2) hide show
  1. package/dist/cli.js +195 -53
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -938,8 +938,8 @@ var stubFalse_default = stubFalse;
938
938
  var freeExports = typeof exports_isBuffer == "object" && exports_isBuffer && !exports_isBuffer.nodeType && exports_isBuffer;
939
939
  var freeModule = freeExports && typeof module_isBuffer == "object" && module_isBuffer && !module_isBuffer.nodeType && module_isBuffer;
940
940
  var moduleExports = freeModule && freeModule.exports === freeExports;
941
- var Buffer = moduleExports ? _root_default.Buffer : undefined;
942
- var nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;
941
+ var Buffer2 = moduleExports ? _root_default.Buffer : undefined;
942
+ var nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : undefined;
943
943
  var isBuffer = nativeIsBuffer || stubFalse_default;
944
944
  var isBuffer_default = isBuffer;
945
945
 
@@ -2669,12 +2669,35 @@ import { join as join6 } from "path";
2669
2669
  // src/utils/keyboard.ts
2670
2670
  import { homedir as homedir2, platform } from "os";
2671
2671
  import { join as join5, dirname, basename } from "path";
2672
- import { readdir as readdir2, stat as stat2, cp as cp2 } from "fs/promises";
2672
+ import { readdir as readdir2, stat as stat2, cp as cp2, readFile, writeFile } from "fs/promises";
2673
2673
  var PATCH_MARKER = "/* Vietnamese IME fix */";
2674
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
+ }
2675
2681
  async function findCliJs() {
2676
2682
  const home = homedir2();
2677
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 {}
2678
2701
  const searchDirs = isWin ? [
2679
2702
  join5(process.env.LOCALAPPDATA ?? "", "npm-cache", "_npx"),
2680
2703
  join5(process.env.APPDATA ?? "", "npm", "node_modules")
@@ -2696,7 +2719,7 @@ async function findCliJs() {
2696
2719
  if (found)
2697
2720
  return found;
2698
2721
  }
2699
- throw new Error(`Kh\xF4ng t\xECm th\u1EA5y Claude Code npm.
2722
+ throw new Error(`Kh\xF4ng t\xECm th\u1EA5y Claude Code.
2700
2723
  ` + "C\xE0i \u0111\u1EB7t tr\u01B0\u1EDBc: npm install -g @anthropic-ai/claude-code");
2701
2724
  }
2702
2725
  async function findCliJsRecursive(dir, depth, maxDepth) {
@@ -2726,40 +2749,67 @@ async function findCliJsRecursive(dir, depth, maxDepth) {
2726
2749
  } catch {}
2727
2750
  return null;
2728
2751
  }
2729
- function findBugBlock(content) {
2730
- const pattern = `.includes("${DEL_CHAR}")`;
2731
- const idx = content.indexOf(pattern);
2732
- if (idx === -1) {
2733
- throw new Error(`Kh\xF4ng t\xECm th\u1EA5y bug pattern .includes("\\x7f").
2734
- ` + "Claude Code c\xF3 th\u1EC3 \u0111\xE3 \u0111\u01B0\u1EE3c Anthropic fix.");
2752
+ async function readContent(filePath, fileType) {
2753
+ if (fileType === "binary") {
2754
+ const buf = await readFile(filePath);
2755
+ return buf.toString("latin1");
2735
2756
  }
2736
- const searchStart = Math.max(0, idx - 150);
2737
- const blockStart = content.lastIndexOf("if(", idx);
2738
- if (blockStart === -1 || blockStart < searchStart) {
2739
- throw new Error("Kh\xF4ng t\xECm th\u1EA5y block if ch\u1EE9a pattern");
2740
- }
2741
- let depth = 0;
2742
- let blockEnd = idx;
2743
- const slice = content.slice(blockStart, blockStart + 800);
2744
- for (let i = 0;i < slice.length; i++) {
2745
- if (slice[i] === "{")
2746
- depth++;
2747
- else if (slice[i] === "}") {
2748
- depth--;
2749
- if (depth === 0) {
2750
- blockEnd = blockStart + i + 1;
2751
- break;
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
+ }
2752
2800
  }
2753
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 };
2754
2812
  }
2755
- if (depth !== 0) {
2756
- throw new Error("Kh\xF4ng t\xECm th\u1EA5y closing brace c\u1EE7a block if");
2757
- }
2758
- return {
2759
- start: blockStart,
2760
- end: blockEnd,
2761
- block: content.slice(blockStart, blockEnd)
2762
- };
2763
2813
  }
2764
2814
  function extractVariables(block) {
2765
2815
  const normalized = block.replaceAll(DEL_CHAR, "\\x7f");
@@ -2787,28 +2837,80 @@ function generateFix(vars) {
2787
2837
  const v = vars;
2788
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;}`;
2789
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(${counter} of ${v.input}.replace(/\\x7f/g,""))${v.state}=${v.state}.insert(${counter});` + `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
+ }
2790
2853
  async function patchCliJs(filePath) {
2791
- const file = Bun.file(filePath);
2792
- if (!await file.exists()) {
2854
+ const fileType = detectFileType(filePath);
2855
+ try {
2856
+ await stat2(filePath);
2857
+ } catch {
2793
2858
  return { success: false, message: `File kh\xF4ng t\u1ED3n t\u1EA1i: ${filePath}` };
2794
2859
  }
2795
- const content = await file.text();
2860
+ const content = await readContent(filePath, fileType);
2796
2861
  if (content.includes(PATCH_MARKER)) {
2797
2862
  return { success: false, message: "\u0110\xE3 patch tr\u01B0\u1EDBc \u0111\xF3" };
2798
2863
  }
2799
2864
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
2800
- const backupPath = `${filePath}.backup-${timestamp}`;
2865
+ const backupDir = fileType === "binary" ? "/tmp" : dirname(filePath);
2866
+ const backupPath = join5(backupDir, `${basename(filePath)}.backup-${timestamp}`);
2801
2867
  await cp2(filePath, backupPath);
2802
2868
  try {
2803
- const { start, end } = findBugBlock(content);
2804
- const block = content.slice(start, end);
2805
- const vars = extractVariables(block);
2806
- const fix = generateFix(vars);
2807
- const patched = content.slice(0, start) + fix + content.slice(end);
2808
- await Bun.write(filePath, patched);
2809
- const verify = await Bun.file(filePath).text();
2810
- if (!verify.includes(PATCH_MARKER)) {
2811
- throw new Error("Verify failed: patch marker not found after write");
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
+ }
2812
2914
  }
2813
2915
  return { success: true, message: "Patch th\xE0nh c\xF4ng", backupPath };
2814
2916
  } catch (err) {
@@ -2823,16 +2925,56 @@ async function patchCliJs(filePath) {
2823
2925
  };
2824
2926
  }
2825
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
+ }
2826
2947
  async function checkKeyboardStatus() {
2827
2948
  try {
2828
2949
  const cliJsPath = await findCliJs();
2829
- const file = Bun.file(cliJsPath);
2830
- const content = await file.text();
2831
- const patched = content.includes(PATCH_MARKER);
2832
- const hasBug = content.includes(`.includes("${DEL_CHAR}")`);
2833
- return { cliJsFound: true, cliJsPath, isPatched: patched, hasBug: !patched && hasBug };
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" };
2834
2976
  } catch {
2835
- return { cliJsFound: false, cliJsPath: null, isPatched: false, hasBug: false };
2977
+ return { cliJsFound: false, cliJsPath: null, isPatched: false, hasBug: false, isBinary: false };
2836
2978
  }
2837
2979
  }
2838
2980
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-cokit",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "A toolkit for interacting with Claude Code",
5
5
  "module": "index.ts",
6
6
  "type": "module",