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.
- package/bin/vk.cjs +0 -0
- package/dist/cli.js +267 -74
- 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
|
|
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 =
|
|
2382
|
-
var CLAUDE_SKILLS_DIR =
|
|
2383
|
-
var ANTIGRAVITY_SKILLS_DIR =
|
|
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 =
|
|
2386
|
-
var SETTINGS_PATH =
|
|
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
|
|
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
|
|
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
|
|
2519
|
+
await mkdir2(CLAUDE_DIR, { recursive: true });
|
|
2422
2520
|
for (const folder of CONFIG_FOLDERS) {
|
|
2423
|
-
const src =
|
|
2521
|
+
const src = join2(srcDir, folder);
|
|
2424
2522
|
if (await dirExists(src)) {
|
|
2425
|
-
const dest =
|
|
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 =
|
|
2433
|
-
const dest =
|
|
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
|
-
|
|
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
|
|
2484
|
-
const entries = await
|
|
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 =
|
|
2488
|
-
const dest =
|
|
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
|
|
2517
|
-
|
|
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 =
|
|
2526
|
-
await
|
|
2527
|
-
const entries = await
|
|
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 =
|
|
2532
|
-
const target =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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,
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
3037
|
+
import { join as join7 } from "path";
|
|
2928
3038
|
|
|
2929
3039
|
// src/utils/keyboard.ts
|
|
2930
|
-
import { homedir as
|
|
2931
|
-
import { join as
|
|
2932
|
-
import { readdir as
|
|
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 =
|
|
3052
|
+
const home = homedir3();
|
|
2943
3053
|
const isWin = platform() === "win32";
|
|
2944
|
-
const nativePath =
|
|
3054
|
+
const nativePath = join6(home, ".local", "share", "claude", "versions");
|
|
2945
3055
|
try {
|
|
2946
|
-
const s = await
|
|
3056
|
+
const s = await stat3(nativePath);
|
|
2947
3057
|
if (s.isDirectory()) {
|
|
2948
|
-
const entries = await
|
|
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 =
|
|
3062
|
+
const binPath = join6(nativePath, ver);
|
|
2953
3063
|
try {
|
|
2954
|
-
const bs = await
|
|
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
|
-
|
|
2963
|
-
|
|
3072
|
+
join6(process.env.LOCALAPPDATA ?? "", "npm-cache", "_npx"),
|
|
3073
|
+
join6(process.env.APPDATA ?? "", "npm", "node_modules")
|
|
2964
3074
|
] : [
|
|
2965
|
-
|
|
2966
|
-
|
|
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
|
|
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
|
|
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 =
|
|
3103
|
+
const fullPath = join6(dir, entry.name);
|
|
2994
3104
|
if (entry.name === "@anthropic-ai") {
|
|
2995
|
-
const cliJs =
|
|
3105
|
+
const cliJs = join6(fullPath, "claude-code", "cli.js");
|
|
2996
3106
|
try {
|
|
2997
|
-
const s = await
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
3451
|
+
const claudeMdPath = join8(process.cwd(), "CLAUDE.md");
|
|
3341
3452
|
const claudeMdMissing = !await fileExists(claudeMdPath);
|
|
3342
3453
|
if (configMissing || claudeMdMissing) {
|
|
3343
|
-
const tmpDir =
|
|
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 =
|
|
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();
|