vibe-cokit 1.9.0 → 1.11.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.
Files changed (3) hide show
  1. package/bin/vk.cjs +0 -0
  2. package/dist/cli.js +267 -74
  3. package/package.json +1 -1
package/bin/vk.cjs CHANGED
File without changes
package/dist/cli.js CHANGED
@@ -728,12 +728,12 @@ var dist_default = cac;
728
728
  var version = "0.1.0";
729
729
 
730
730
  // src/commands/init.ts
731
- import { join as join2 } from "path";
731
+ import { join as join3 } from "path";
732
732
 
733
733
  // src/utils/config.ts
734
- import { homedir } from "os";
735
- import { join } from "path";
736
- import { mkdir, cp, rm, stat, readdir, readFile, writeFile, appendFile } from "fs/promises";
734
+ import { homedir as homedir2 } from "os";
735
+ import { join as join2 } from "path";
736
+ import { mkdir as mkdir2, cp, rm, stat as stat2, readdir as readdir2, readFile, writeFile, appendFile as appendFile2 } from "fs/promises";
737
737
  import { execFile as execFile2 } from "child_process";
738
738
  import { promisify as promisify2 } from "util";
739
739
  // node_modules/lodash-es/_arrayFilter.js
@@ -2301,10 +2301,108 @@ var some_default = some;
2301
2301
  // src/utils/helpers.ts
2302
2302
  import { execFile } from "child_process";
2303
2303
  import { promisify } from "util";
2304
+
2305
+ // src/utils/logger.ts
2306
+ import { homedir } from "os";
2307
+ import { join } from "path";
2308
+ import { mkdir, readdir, stat, unlink, appendFile } from "fs/promises";
2309
+ var DEFAULT_LOG_DIR = join(homedir(), ".vk", "logs");
2310
+ var RETENTION_DAYS = 7;
2311
+ var LOG_FILE_PATTERN = /^vk-\d{4}-\d{2}-\d{2}\.log$/;
2312
+ function formatDate(date) {
2313
+ return date.toISOString().split("T")[0];
2314
+ }
2315
+ function padLevel(level) {
2316
+ return level.toUpperCase().padEnd(5);
2317
+ }
2318
+ function formatEntry(level, command, msg, err) {
2319
+ const ts = new Date().toISOString();
2320
+ let entry = `[${ts}] ${padLevel(level)} [${command}] ${msg}
2321
+ `;
2322
+ if (err instanceof Error && err.stack) {
2323
+ const stackLines = err.stack.split(`
2324
+ `).slice(1).map((l) => ` ${l.trim()}`).join(`
2325
+ `);
2326
+ entry += ` Stack: ${err.message}
2327
+ ${stackLines}
2328
+ `;
2329
+ }
2330
+ return entry;
2331
+ }
2332
+
2333
+ class Logger {
2334
+ logDir;
2335
+ logFilePath = null;
2336
+ debugMode = false;
2337
+ ready = false;
2338
+ constructor(logDir) {
2339
+ this.logDir = logDir ?? DEFAULT_LOG_DIR;
2340
+ }
2341
+ async init(debugMode = false) {
2342
+ this.debugMode = debugMode;
2343
+ try {
2344
+ await mkdir(this.logDir, { recursive: true });
2345
+ this.logFilePath = join(this.logDir, `vk-${formatDate(new Date)}.log`);
2346
+ await this.runRotation();
2347
+ this.ready = true;
2348
+ } catch {}
2349
+ }
2350
+ async runRotation() {
2351
+ try {
2352
+ const files = await readdir(this.logDir);
2353
+ const cutoff = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1000;
2354
+ for (const file of files) {
2355
+ if (!LOG_FILE_PATTERN.test(file))
2356
+ continue;
2357
+ const filePath = join(this.logDir, file);
2358
+ try {
2359
+ const s = await stat(filePath);
2360
+ if (s.mtimeMs < cutoff) {
2361
+ await unlink(filePath);
2362
+ }
2363
+ } catch {}
2364
+ }
2365
+ } catch {}
2366
+ }
2367
+ async write(level, command, msg, err) {
2368
+ if (!this.ready || !this.logFilePath)
2369
+ return;
2370
+ if (!this.debugMode && level === "debug")
2371
+ return;
2372
+ try {
2373
+ const entry = formatEntry(level, command, msg, err);
2374
+ await appendFile(this.logFilePath, entry, "utf-8");
2375
+ } catch {}
2376
+ }
2377
+ async debug(command, msg) {
2378
+ return this.write("debug", command, msg);
2379
+ }
2380
+ async info(command, msg) {
2381
+ return this.write("info", command, msg);
2382
+ }
2383
+ async warn(command, msg) {
2384
+ return this.write("warn", command, msg);
2385
+ }
2386
+ async error(command, msg, err) {
2387
+ return this.write("error", command, msg, err);
2388
+ }
2389
+ getLogDir() {
2390
+ return this.logDir;
2391
+ }
2392
+ getLogFilePath() {
2393
+ return this.logFilePath;
2394
+ }
2395
+ }
2396
+ var logger = new Logger;
2397
+
2398
+ // src/utils/helpers.ts
2304
2399
  var exec = promisify(execFile);
2305
2400
  function getErrorMsg(err) {
2306
2401
  return err instanceof Error ? err.message : String(err);
2307
2402
  }
2403
+ function logError(command, err) {
2404
+ logger.error(command, getErrorMsg(err), err).catch(() => {});
2405
+ }
2308
2406
  async function checkBin(name) {
2309
2407
  try {
2310
2408
  await exec(name, ["--version"]);
@@ -2378,12 +2476,12 @@ var exec2 = promisify2(execFile2);
2378
2476
  var REPO = "vibe-cokit/claude-code";
2379
2477
  var ANTIGRAVITY_REPO = "vibe-cokit/antigravity";
2380
2478
  var SKILLS_REPO = "vibe-cokit/skills";
2381
- var CLAUDE_DIR = join(homedir(), ".claude");
2382
- var CLAUDE_SKILLS_DIR = join(CLAUDE_DIR, "skills");
2383
- var ANTIGRAVITY_SKILLS_DIR = join(homedir(), ".gemini", "antigravity", "skills");
2479
+ var CLAUDE_DIR = join2(homedir2(), ".claude");
2480
+ var CLAUDE_SKILLS_DIR = join2(CLAUDE_DIR, "skills");
2481
+ var ANTIGRAVITY_SKILLS_DIR = join2(homedir2(), ".gemini", "antigravity", "skills");
2384
2482
  var CONFIG_FOLDERS = ["agents", "commands", "hooks", "prompts", "workflows"];
2385
- var TEMP_DIR = join(homedir(), ".vibe-cokit-tmp");
2386
- var SETTINGS_PATH = join(CLAUDE_DIR, "settings.json");
2483
+ var TEMP_DIR = join2(homedir2(), ".vibe-cokit-tmp");
2484
+ var SETTINGS_PATH = join2(CLAUDE_DIR, "settings.json");
2387
2485
  function log(step) {
2388
2486
  console.log(` \u2192 ${step}`);
2389
2487
  }
@@ -2403,7 +2501,7 @@ async function cloneRepo(tmpDir, repo = REPO) {
2403
2501
  }
2404
2502
  async function dirExists(path) {
2405
2503
  try {
2406
- const s = await stat(path);
2504
+ const s = await stat2(path);
2407
2505
  return s.isDirectory();
2408
2506
  } catch {
2409
2507
  return false;
@@ -2411,26 +2509,26 @@ async function dirExists(path) {
2411
2509
  }
2412
2510
  async function fileExists(path) {
2413
2511
  try {
2414
- const s = await stat(path);
2512
+ const s = await stat2(path);
2415
2513
  return s.isFile();
2416
2514
  } catch {
2417
2515
  return false;
2418
2516
  }
2419
2517
  }
2420
2518
  async function copyConfigFolders(srcDir) {
2421
- await mkdir(CLAUDE_DIR, { recursive: true });
2519
+ await mkdir2(CLAUDE_DIR, { recursive: true });
2422
2520
  for (const folder of CONFIG_FOLDERS) {
2423
- const src = join(srcDir, folder);
2521
+ const src = join2(srcDir, folder);
2424
2522
  if (await dirExists(src)) {
2425
- const dest = join(CLAUDE_DIR, folder);
2523
+ const dest = join2(CLAUDE_DIR, folder);
2426
2524
  await cp(src, dest, { recursive: true, force: true });
2427
2525
  log(`Copied ${folder}/`);
2428
2526
  }
2429
2527
  }
2430
2528
  }
2431
2529
  async function copyClaudeMd(srcDir) {
2432
- const src = join(srcDir, "CLAUDE.md");
2433
- const dest = join(process.cwd(), "CLAUDE.md");
2530
+ const src = join2(srcDir, "CLAUDE.md");
2531
+ const dest = join2(process.cwd(), "CLAUDE.md");
2434
2532
  if (await fileExists(src)) {
2435
2533
  await cp(src, dest, { force: true });
2436
2534
  }
@@ -2450,8 +2548,11 @@ async function getCommitSha(tmpDir) {
2450
2548
  }
2451
2549
  async function readSettings() {
2452
2550
  const file = Bun.file(SETTINGS_PATH);
2453
- if (await file.exists())
2454
- return file.json();
2551
+ if (await file.exists()) {
2552
+ const text = await file.text();
2553
+ const stripped = text.replace(/^\s*\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
2554
+ return JSON.parse(stripped);
2555
+ }
2455
2556
  return {};
2456
2557
  }
2457
2558
  async function writeSettings(settings) {
@@ -2480,12 +2581,12 @@ async function getRemoteSha(ref, repo = REPO) {
2480
2581
  return sha;
2481
2582
  }
2482
2583
  async function copySkillFolders(srcDir, destDir = CLAUDE_SKILLS_DIR) {
2483
- await mkdir(destDir, { recursive: true });
2484
- const entries = await readdir(srcDir, { withFileTypes: true });
2584
+ await mkdir2(destDir, { recursive: true });
2585
+ const entries = await readdir2(srcDir, { withFileTypes: true });
2485
2586
  for (const entry of entries) {
2486
2587
  if (entry.isDirectory() && !entry.name.startsWith(".")) {
2487
- const src = join(srcDir, entry.name);
2488
- const dest = join(destDir, entry.name);
2588
+ const src = join2(srcDir, entry.name);
2589
+ const dest = join2(destDir, entry.name);
2489
2590
  await cp(src, dest, { recursive: true, force: true });
2490
2591
  log(`Copied skill: ${entry.name}/`);
2491
2592
  }
@@ -2513,8 +2614,11 @@ async function upgradeCli() {
2513
2614
  const { stdout: installedRaw } = await exec2("bun", ["pm", "ls", "-g"]);
2514
2615
  const match = installedRaw.match(/vibe-cokit@(\S+)/);
2515
2616
  const currentVersion = match?.[1] ?? "0.0.0";
2516
- const { stdout: latestRaw } = await exec2("npm", ["view", "vibe-cokit", "version"]);
2517
- const latestVersion = latestRaw.trim();
2617
+ const res = await fetch("https://registry.npmjs.org/vibe-cokit/latest");
2618
+ if (!res.ok)
2619
+ throw new Error(`npm registry returned ${res.status}`);
2620
+ const data = await res.json();
2621
+ const latestVersion = data.version;
2518
2622
  if (currentVersion === latestVersion) {
2519
2623
  return { upgraded: false, from: currentVersion, to: latestVersion };
2520
2624
  }
@@ -2522,19 +2626,19 @@ async function upgradeCli() {
2522
2626
  return { upgraded: true, from: currentVersion, to: latestVersion };
2523
2627
  }
2524
2628
  async function copyAgentFolder(srcDir) {
2525
- const dest = join(process.cwd(), ".agents");
2526
- await mkdir(dest, { recursive: true });
2527
- const entries = await readdir(srcDir, { withFileTypes: true });
2629
+ const dest = join2(process.cwd(), ".agents");
2630
+ await mkdir2(dest, { recursive: true });
2631
+ const entries = await readdir2(srcDir, { withFileTypes: true });
2528
2632
  for (const entry of entries) {
2529
2633
  if (entry.name.startsWith(".git"))
2530
2634
  continue;
2531
- const src = join(srcDir, entry.name);
2532
- const target = join(dest, entry.name);
2635
+ const src = join2(srcDir, entry.name);
2636
+ const target = join2(dest, entry.name);
2533
2637
  await cp(src, target, { recursive: true, force: true });
2534
2638
  }
2535
2639
  }
2536
2640
  async function ensureGitignore(entry) {
2537
- const gitignorePath = join(process.cwd(), ".gitignore");
2641
+ const gitignorePath = join2(process.cwd(), ".gitignore");
2538
2642
  try {
2539
2643
  const content = await readFile(gitignorePath, "utf-8");
2540
2644
  const lines = content.split(/\r?\n/);
@@ -2543,7 +2647,7 @@ async function ensureGitignore(entry) {
2543
2647
  const separator = content.endsWith(`
2544
2648
  `) ? "" : `
2545
2649
  `;
2546
- await appendFile(gitignorePath, `${separator}${entry}
2650
+ await appendFile2(gitignorePath, `${separator}${entry}
2547
2651
  `);
2548
2652
  } catch {
2549
2653
  await writeFile(gitignorePath, `${entry}
@@ -2570,7 +2674,7 @@ async function initCommand(agent) {
2570
2674
  }
2571
2675
  }
2572
2676
  async function initClaudeCode() {
2573
- const tmpDir = join2(TEMP_DIR, crypto.randomUUID());
2677
+ const tmpDir = join3(TEMP_DIR, crypto.randomUUID());
2574
2678
  try {
2575
2679
  console.log(`
2576
2680
  vibe-cokit init (claude-code)
@@ -2595,6 +2699,7 @@ vibe-cokit init (claude-code)
2595
2699
  console.log(` Claude: ./CLAUDE.md
2596
2700
  `);
2597
2701
  } catch (err) {
2702
+ logError("init", err);
2598
2703
  console.error(`
2599
2704
  \u2717 Init failed: ${getErrorMsg(err)}
2600
2705
  `);
@@ -2604,7 +2709,7 @@ vibe-cokit init (claude-code)
2604
2709
  }
2605
2710
  }
2606
2711
  async function initAntigravity() {
2607
- const tmpDir = join2(TEMP_DIR, crypto.randomUUID());
2712
+ const tmpDir = join3(TEMP_DIR, crypto.randomUUID());
2608
2713
  try {
2609
2714
  console.log(`
2610
2715
  vibe-cokit init (antigravity)
@@ -2615,12 +2720,12 @@ vibe-cokit init (antigravity)
2615
2720
  await cloneRepo(tmpDir, ANTIGRAVITY_REPO);
2616
2721
  log("Copying agent config to .agents/...");
2617
2722
  await copyAgentFolder(tmpDir);
2618
- const skillsTmpDir = join2(TEMP_DIR, crypto.randomUUID());
2723
+ const skillsTmpDir = join3(TEMP_DIR, crypto.randomUUID());
2619
2724
  try {
2620
2725
  log("Cloning skills repository...");
2621
2726
  await cloneRepo(skillsTmpDir, SKILLS_REPO);
2622
2727
  log("Installing skills to .agent/skills/...");
2623
- await copySkillFolders(skillsTmpDir, join2(process.cwd(), ".agent", "skills"));
2728
+ await copySkillFolders(skillsTmpDir, join3(process.cwd(), ".agent", "skills"));
2624
2729
  } finally {
2625
2730
  await cleanup(skillsTmpDir);
2626
2731
  }
@@ -2636,6 +2741,7 @@ vibe-cokit init (antigravity)
2636
2741
  console.log(` Agent: ./.agents/
2637
2742
  `);
2638
2743
  } catch (err) {
2744
+ logError("init", err);
2639
2745
  console.error(`
2640
2746
  \u2717 Init failed: ${getErrorMsg(err)}
2641
2747
  `);
@@ -2646,7 +2752,7 @@ vibe-cokit init (antigravity)
2646
2752
  }
2647
2753
 
2648
2754
  // src/commands/update.ts
2649
- import { join as join3 } from "path";
2755
+ import { join as join4 } from "path";
2650
2756
  import { execFile as execFile3 } from "child_process";
2651
2757
  import { promisify as promisify3 } from "util";
2652
2758
  var exec3 = promisify3(execFile3);
@@ -2672,8 +2778,10 @@ vibe-cokit update${agentType ? ` (${agentType})` : ""}
2672
2778
  } else {
2673
2779
  log(`CLI: v${from} (latest)`);
2674
2780
  }
2675
- } catch {
2676
- log("CLI upgrade skipped (npm registry unavailable)");
2781
+ } catch (err) {
2782
+ const reason = getErrorMsg(err);
2783
+ logError("update:cli", err);
2784
+ log(`CLI upgrade skipped: ${reason}`);
2677
2785
  }
2678
2786
  if (agentType) {
2679
2787
  log("Verifying prerequisites...");
@@ -2692,6 +2800,7 @@ vibe-cokit update${agentType ? ` (${agentType})` : ""}
2692
2800
  \u2713 vibe-cokit update complete!
2693
2801
  `);
2694
2802
  } catch (err) {
2803
+ logError("update", err);
2695
2804
  const msg = getErrorMsg(err);
2696
2805
  console.error(`
2697
2806
  \u2717 Update failed: ${msg}
@@ -2704,7 +2813,7 @@ async function updateClaudeCode(ref) {
2704
2813
  await updateSkills(ref);
2705
2814
  }
2706
2815
  async function updateConfig(ref) {
2707
- const tmpDir = join3(TEMP_DIR, crypto.randomUUID());
2816
+ const tmpDir = join4(TEMP_DIR, crypto.randomUUID());
2708
2817
  try {
2709
2818
  log("Checking config version...");
2710
2819
  const currentSha = await getCurrentVersion();
@@ -2731,7 +2840,7 @@ async function updateConfig(ref) {
2731
2840
  }
2732
2841
  }
2733
2842
  async function updateSkills(ref, destDir) {
2734
- const tmpDir = join3(TEMP_DIR, crypto.randomUUID());
2843
+ const tmpDir = join4(TEMP_DIR, crypto.randomUUID());
2735
2844
  try {
2736
2845
  log("Checking skills version...");
2737
2846
  const currentSha = await getSkillsVersion();
@@ -2760,7 +2869,7 @@ async function updateSkills(ref, destDir) {
2760
2869
  }
2761
2870
  }
2762
2871
  async function updateAntigravity(ref) {
2763
- const tmpDir = join3(TEMP_DIR, crypto.randomUUID());
2872
+ const tmpDir = join4(TEMP_DIR, crypto.randomUUID());
2764
2873
  try {
2765
2874
  log("Checking antigravity version...");
2766
2875
  const currentSha = await getAntigravityVersion();
@@ -2788,12 +2897,12 @@ async function updateAntigravity(ref) {
2788
2897
  }
2789
2898
 
2790
2899
  // src/commands/skills.ts
2791
- import { join as join4 } from "path";
2900
+ import { join as join5 } from "path";
2792
2901
  import { execFile as execFile4 } from "child_process";
2793
2902
  import { promisify as promisify4 } from "util";
2794
2903
  var exec4 = promisify4(execFile4);
2795
2904
  async function skillsCommand(ref) {
2796
- const tmpDir = join4(TEMP_DIR, crypto.randomUUID());
2905
+ const tmpDir = join5(TEMP_DIR, crypto.randomUUID());
2797
2906
  try {
2798
2907
  console.log(`
2799
2908
  vibe-cokit skills
@@ -2829,6 +2938,7 @@ vibe-cokit skills
2829
2938
  console.log(` Skills: ~/.claude/skills/
2830
2939
  `);
2831
2940
  } catch (err) {
2941
+ logError("skills", err);
2832
2942
  console.error(`
2833
2943
  \u2717 Skills setup failed: ${getErrorMsg(err)}
2834
2944
  `);
@@ -2924,12 +3034,12 @@ vibe-cokit v${version}`);
2924
3034
  }
2925
3035
 
2926
3036
  // src/commands/doctor.ts
2927
- import { join as join6 } from "path";
3037
+ import { join as join7 } from "path";
2928
3038
 
2929
3039
  // src/utils/keyboard.ts
2930
- import { homedir as homedir2, platform } from "os";
2931
- import { join as join5, dirname, basename } from "path";
2932
- import { readdir as readdir2, stat as stat2, cp as cp2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
3040
+ import { homedir as homedir3, platform } from "os";
3041
+ import { join as join6, dirname, basename } from "path";
3042
+ import { readdir as readdir3, stat as stat3, cp as cp2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
2933
3043
  var PATCH_MARKER = "/* Vietnamese IME fix */";
2934
3044
  var DEL_CHAR = "\x7F";
2935
3045
  function detectFileType(filePath) {
@@ -2939,19 +3049,19 @@ function detectFileType(filePath) {
2939
3049
  return "js";
2940
3050
  }
2941
3051
  async function findCliJs() {
2942
- const home = homedir2();
3052
+ const home = homedir3();
2943
3053
  const isWin = platform() === "win32";
2944
- const nativePath = join5(home, ".local", "share", "claude", "versions");
3054
+ const nativePath = join6(home, ".local", "share", "claude", "versions");
2945
3055
  try {
2946
- const s = await stat2(nativePath);
3056
+ const s = await stat3(nativePath);
2947
3057
  if (s.isDirectory()) {
2948
- const entries = await readdir2(nativePath);
3058
+ const entries = await readdir3(nativePath);
2949
3059
  const versions = entries.filter((e) => /^\d+\.\d+\.\d+$/.test(e));
2950
3060
  versions.sort((a, b) => b.localeCompare(a, undefined, { numeric: true }));
2951
3061
  for (const ver of versions) {
2952
- const binPath = join5(nativePath, ver);
3062
+ const binPath = join6(nativePath, ver);
2953
3063
  try {
2954
- const bs = await stat2(binPath);
3064
+ const bs = await stat3(binPath);
2955
3065
  if (bs.isFile())
2956
3066
  return binPath;
2957
3067
  } catch {}
@@ -2959,17 +3069,17 @@ async function findCliJs() {
2959
3069
  }
2960
3070
  } catch {}
2961
3071
  const searchDirs = isWin ? [
2962
- join5(process.env.LOCALAPPDATA ?? "", "npm-cache", "_npx"),
2963
- join5(process.env.APPDATA ?? "", "npm", "node_modules")
3072
+ join6(process.env.LOCALAPPDATA ?? "", "npm-cache", "_npx"),
3073
+ join6(process.env.APPDATA ?? "", "npm", "node_modules")
2964
3074
  ] : [
2965
- join5(home, ".npm", "_npx"),
2966
- join5(home, ".nvm", "versions", "node"),
3075
+ join6(home, ".npm", "_npx"),
3076
+ join6(home, ".nvm", "versions", "node"),
2967
3077
  "/usr/local/lib/node_modules",
2968
3078
  "/opt/homebrew/lib/node_modules"
2969
3079
  ];
2970
3080
  for (const dir of searchDirs) {
2971
3081
  try {
2972
- const s = await stat2(dir);
3082
+ const s = await stat3(dir);
2973
3083
  if (!s.isDirectory())
2974
3084
  continue;
2975
3085
  } catch {
@@ -2986,15 +3096,15 @@ async function findCliJsRecursive(dir, depth, maxDepth) {
2986
3096
  if (depth >= maxDepth)
2987
3097
  return null;
2988
3098
  try {
2989
- const entries = await readdir2(dir, { withFileTypes: true });
3099
+ const entries = await readdir3(dir, { withFileTypes: true });
2990
3100
  for (const entry of entries) {
2991
3101
  if (!entry.isDirectory())
2992
3102
  continue;
2993
- const fullPath = join5(dir, entry.name);
3103
+ const fullPath = join6(dir, entry.name);
2994
3104
  if (entry.name === "@anthropic-ai") {
2995
- const cliJs = join5(fullPath, "claude-code", "cli.js");
3105
+ const cliJs = join6(fullPath, "claude-code", "cli.js");
2996
3106
  try {
2997
- const s = await stat2(cliJs);
3107
+ const s = await stat3(cliJs);
2998
3108
  if (s.isFile())
2999
3109
  return cliJs;
3000
3110
  } catch {}
@@ -3114,7 +3224,7 @@ function generateBinaryFix(block, vars) {
3114
3224
  async function patchCliJs(filePath) {
3115
3225
  const fileType = detectFileType(filePath);
3116
3226
  try {
3117
- await stat2(filePath);
3227
+ await stat3(filePath);
3118
3228
  } catch {
3119
3229
  return { success: false, message: `File kh\xF4ng t\u1ED3n t\u1EA1i: ${filePath}` };
3120
3230
  }
@@ -3124,7 +3234,7 @@ async function patchCliJs(filePath) {
3124
3234
  }
3125
3235
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
3126
3236
  const backupDir = fileType === "binary" ? "/tmp" : dirname(filePath);
3127
- const backupPath = join5(backupDir, `${basename(filePath)}.backup-${timestamp}`);
3237
+ const backupPath = join6(backupDir, `${basename(filePath)}.backup-${timestamp}`);
3128
3238
  await cp2(filePath, backupPath);
3129
3239
  try {
3130
3240
  const bugPattern = getBugPattern(fileType);
@@ -3177,8 +3287,8 @@ async function patchCliJs(filePath) {
3177
3287
  } catch (err) {
3178
3288
  try {
3179
3289
  await cp2(backupPath, filePath);
3180
- const { unlink } = await import("fs/promises");
3181
- await unlink(backupPath);
3290
+ const { unlink: unlink2 } = await import("fs/promises");
3291
+ await unlink2(backupPath);
3182
3292
  } catch {}
3183
3293
  return {
3184
3294
  success: false,
@@ -3268,7 +3378,7 @@ vibe-cokit doctor
3268
3378
  issues++;
3269
3379
  }
3270
3380
  for (const folder of CONFIG_FOLDERS) {
3271
- const path = join6(CLAUDE_DIR, folder);
3381
+ const path = join7(CLAUDE_DIR, folder);
3272
3382
  if (await dirExists(path)) {
3273
3383
  console.log(` \u2713 ~/.claude/${folder}/`);
3274
3384
  } else {
@@ -3282,7 +3392,7 @@ vibe-cokit doctor
3282
3392
  console.log(` \u2717 ~/.claude/skills/ missing \u2014 run \`vk skills\``);
3283
3393
  issues++;
3284
3394
  }
3285
- const settingsPath = join6(CLAUDE_DIR, "settings.json");
3395
+ const settingsPath = join7(CLAUDE_DIR, "settings.json");
3286
3396
  if (await fileExists(settingsPath)) {
3287
3397
  console.log(` \u2713 ~/.claude/settings.json`);
3288
3398
  } else {
@@ -3307,7 +3417,7 @@ vibe-cokit doctor
3307
3417
  } else {
3308
3418
  console.log(` \u26A0 Claude Code CLI: not found`);
3309
3419
  }
3310
- const claudeMdExists = await fileExists(join6(process.cwd(), "CLAUDE.md"));
3420
+ const claudeMdExists = await fileExists(join7(process.cwd(), "CLAUDE.md"));
3311
3421
  console.log(` Project CLAUDE.md: ${claudeMdExists ? "found" : "not found"}`);
3312
3422
  console.log();
3313
3423
  if (issues === 0) {
@@ -3320,7 +3430,7 @@ vibe-cokit doctor
3320
3430
  }
3321
3431
 
3322
3432
  // src/commands/doctor-fix.ts
3323
- import { join as join7 } from "path";
3433
+ import { join as join8 } from "path";
3324
3434
  async function doctorFixCommand() {
3325
3435
  console.log(`
3326
3436
  vibe-cokit doctor fix
@@ -3329,18 +3439,19 @@ vibe-cokit doctor fix
3329
3439
  log("Verifying prerequisites...");
3330
3440
  await verifyPrerequisites();
3331
3441
  } catch (err) {
3442
+ logError("doctor-fix", err);
3332
3443
  console.error(`
3333
3444
  \u2717 Cannot fix: ${getErrorMsg(err)}
3334
3445
  `);
3335
3446
  process.exit(1);
3336
3447
  }
3337
3448
  let fixed = 0;
3338
- const folderChecks = await Promise.all(CONFIG_FOLDERS.map((f) => dirExists(join7(CLAUDE_DIR, f))));
3449
+ const folderChecks = await Promise.all(CONFIG_FOLDERS.map((f) => dirExists(join8(CLAUDE_DIR, f))));
3339
3450
  const configMissing = !await dirExists(CLAUDE_DIR) || some_default(folderChecks, (exists) => !exists) || !await getCurrentVersion();
3340
- const claudeMdPath = join7(process.cwd(), "CLAUDE.md");
3451
+ const claudeMdPath = join8(process.cwd(), "CLAUDE.md");
3341
3452
  const claudeMdMissing = !await fileExists(claudeMdPath);
3342
3453
  if (configMissing || claudeMdMissing) {
3343
- const tmpDir = join7(TEMP_DIR, crypto.randomUUID());
3454
+ const tmpDir = join8(TEMP_DIR, crypto.randomUUID());
3344
3455
  try {
3345
3456
  await cloneRepo(tmpDir);
3346
3457
  if (configMissing) {
@@ -3362,6 +3473,7 @@ vibe-cokit doctor fix
3362
3473
  log("CLAUDE.md: OK");
3363
3474
  }
3364
3475
  } catch (err) {
3476
+ logError("doctor-fix", err);
3365
3477
  console.error(` \u2717 Config/CLAUDE.md fix failed: ${getErrorMsg(err)}`);
3366
3478
  } finally {
3367
3479
  await cleanup(tmpDir);
@@ -3373,7 +3485,7 @@ vibe-cokit doctor fix
3373
3485
  const skillsMissing = !await dirExists(CLAUDE_SKILLS_DIR) || !await getSkillsVersion();
3374
3486
  if (skillsMissing) {
3375
3487
  log("Skills missing \u2014 installing...");
3376
- const tmpDir = join7(TEMP_DIR, crypto.randomUUID());
3488
+ const tmpDir = join8(TEMP_DIR, crypto.randomUUID());
3377
3489
  try {
3378
3490
  await cloneRepo(tmpDir, SKILLS_REPO);
3379
3491
  await copySkillFolders(tmpDir);
@@ -3382,6 +3494,7 @@ vibe-cokit doctor fix
3382
3494
  log(`Skills installed (${sha.slice(0, 8)})`);
3383
3495
  fixed++;
3384
3496
  } catch (err) {
3497
+ logError("doctor-fix", err);
3385
3498
  console.error(` \u2717 Skills fix failed: ${getErrorMsg(err)}`);
3386
3499
  } finally {
3387
3500
  await cleanup(tmpDir);
@@ -3404,6 +3517,7 @@ vibe-cokit doctor fix
3404
3517
  console.error(` \u2717 Keyboard fix failed: ${result.message}`);
3405
3518
  }
3406
3519
  } catch (err) {
3520
+ logError("doctor-fix", err);
3407
3521
  console.error(` \u2717 Keyboard fix failed: ${getErrorMsg(err)}`);
3408
3522
  }
3409
3523
  } else if (kbStatus.cliJsFound && kbStatus.isPatched) {
@@ -3491,6 +3605,7 @@ async function addModule(mod) {
3491
3605
  await exec5("claude", ["mcp", "add-json", mod.name, JSON.stringify(config)]);
3492
3606
  return true;
3493
3607
  } catch (err) {
3608
+ logError("mcp", err);
3494
3609
  console.error(` \u2717 Failed to add ${mod.name}: ${getErrorMsg(err)}`);
3495
3610
  return false;
3496
3611
  }
@@ -3505,6 +3620,7 @@ async function removeModule(name) {
3505
3620
  console.log(` \u26A0 ${name} not configured, skipping`);
3506
3621
  return true;
3507
3622
  }
3623
+ logError("mcp", err);
3508
3624
  console.error(` \u2717 Failed to remove ${name}: ${msg}`);
3509
3625
  return false;
3510
3626
  }
@@ -3677,6 +3793,7 @@ async function addPlugin(plugin) {
3677
3793
  } catch (err) {
3678
3794
  const msg = getErrorMsg(err);
3679
3795
  if (!msg.includes("already installed")) {
3796
+ logError("plugin", err);
3680
3797
  console.error(` \u2717 Failed to install ${plugin.name}: ${msg}`);
3681
3798
  return false;
3682
3799
  }
@@ -3686,6 +3803,7 @@ async function addPlugin(plugin) {
3686
3803
  } catch (err) {
3687
3804
  const msg = getErrorMsg(err);
3688
3805
  if (!msg.includes("already enabled")) {
3806
+ logError("plugin", err);
3689
3807
  console.error(` \u2717 Failed to enable ${plugin.name}: ${msg}`);
3690
3808
  return false;
3691
3809
  }
@@ -3704,6 +3822,7 @@ async function removePlugin(name) {
3704
3822
  console.log(` \u26A0 ${name} not installed, skipping`);
3705
3823
  return true;
3706
3824
  }
3825
+ logError("plugin", err);
3707
3826
  console.error(` \u2717 Failed to uninstall ${name}: ${msg}`);
3708
3827
  return false;
3709
3828
  }
@@ -3790,6 +3909,7 @@ Killing process on port ${port}...`);
3790
3909
  \u2713 No process running on port ${port}
3791
3910
  `);
3792
3911
  } else {
3912
+ logError("tools", err);
3793
3913
  console.error(`
3794
3914
  \u2717 Failed to kill port ${port}: ${msg}
3795
3915
  `);
@@ -3837,7 +3957,78 @@ vibe-cokit tools
3837
3957
  }
3838
3958
  }
3839
3959
 
3960
+ // src/commands/logs.ts
3961
+ import { readdir as readdir4, unlink as unlink2 } from "fs/promises";
3962
+ import { join as join9 } from "path";
3963
+ var LOG_FILE_PATTERN2 = /^vk-\d{4}-\d{2}-\d{2}\.log$/;
3964
+ async function showLogs(lines) {
3965
+ const logDir = logger.getLogDir();
3966
+ let targetPath = logger.getLogFilePath();
3967
+ if (targetPath && !await Bun.file(targetPath).exists()) {
3968
+ targetPath = null;
3969
+ }
3970
+ if (!targetPath) {
3971
+ try {
3972
+ const files = (await readdir4(logDir)).filter((f) => LOG_FILE_PATTERN2.test(f)).sort().reverse();
3973
+ if (files.length > 0) {
3974
+ targetPath = join9(logDir, files[0]);
3975
+ }
3976
+ } catch {}
3977
+ }
3978
+ if (!targetPath) {
3979
+ console.log(`
3980
+ No log files found. Logs are created when errors occur.`);
3981
+ console.log(`Run 'vk init' or any other command that fails to generate a log.
3982
+ `);
3983
+ return;
3984
+ }
3985
+ const content = await Bun.file(targetPath).text();
3986
+ const allLines = content.split(`
3987
+ `);
3988
+ const tail = allLines.slice(-lines).join(`
3989
+ `);
3990
+ const fileName = targetPath.split("/").pop();
3991
+ console.log(`
3992
+ --- ${fileName} (last ${lines} lines) ---`);
3993
+ console.log(tail);
3994
+ }
3995
+ async function clearLogs() {
3996
+ const logDir = logger.getLogDir();
3997
+ let count = 0;
3998
+ try {
3999
+ const files = await readdir4(logDir);
4000
+ for (const file of files) {
4001
+ if (LOG_FILE_PATTERN2.test(file)) {
4002
+ await unlink2(join9(logDir, file));
4003
+ count++;
4004
+ }
4005
+ }
4006
+ } catch {}
4007
+ if (count > 0) {
4008
+ console.log(`
4009
+ \u2713 Cleared ${count} log file${count > 1 ? "s" : ""} from ${logDir}
4010
+ `);
4011
+ } else {
4012
+ console.log(`
4013
+ No log files to clear.
4014
+ `);
4015
+ }
4016
+ }
4017
+ async function logsCommand(options) {
4018
+ if (options.path) {
4019
+ console.log(logger.getLogDir());
4020
+ return;
4021
+ }
4022
+ if (options.clear) {
4023
+ return clearLogs();
4024
+ }
4025
+ const lines = Number(options.tail) || 50;
4026
+ return showLogs(lines);
4027
+ }
4028
+
3840
4029
  // src/cli.ts
4030
+ var debugMode = process.argv.includes("--debug") || process.env["VK_DEBUG"] === "1";
4031
+ await logger.init(debugMode);
3841
4032
  var cli = dist_default("vibe-cokit");
3842
4033
  cli.command("", "A toolkit for interacting with Claude Code").action(() => {
3843
4034
  cli.outputHelp();
@@ -3861,6 +4052,8 @@ cli.command("plugin [action] [...plugins]", "Manage plugins (install/uninstall)"
3861
4052
  cli.command("tools [action] [...args]", "Developer utilities (kill-port, etc.)").action((action, args) => {
3862
4053
  return toolsCommand(action, args);
3863
4054
  });
4055
+ cli.command("logs", "View or manage diagnostic log files (~/.vk/logs/)").option("--tail <n>", "Number of lines to show (default: 50)").option("--clear", "Delete all log files").option("--path", "Print log directory path").action((options) => logsCommand(options));
4056
+ cli.option("--debug", "Enable debug logging to ~/.vk/logs/");
3864
4057
  cli.help();
3865
4058
  cli.version(version);
3866
4059
  cli.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-cokit",
3
- "version": "1.9.0",
3
+ "version": "1.11.0",
4
4
  "description": "A toolkit for interacting with Claude Code",
5
5
  "module": "index.ts",
6
6
  "type": "module",