kerf-cli 0.1.2 → 0.1.3
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/README.md +2 -2
- package/USAGE.md +644 -0
- package/dist/index.js +73 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -314,8 +314,11 @@ function getPeriodKey(timestamp, period) {
|
|
|
314
314
|
}
|
|
315
315
|
function formatPeriodLabel(key, period) {
|
|
316
316
|
switch (period) {
|
|
317
|
-
case "hour":
|
|
318
|
-
|
|
317
|
+
case "hour": {
|
|
318
|
+
const parts = key.split("-");
|
|
319
|
+
const dateStr = `${parts[0]}-${parts[1]}-${parts[2]}T${parts[3]}:00:00`;
|
|
320
|
+
return dayjs2(dateStr).format("MMM D, h A");
|
|
321
|
+
}
|
|
319
322
|
case "day":
|
|
320
323
|
return dayjs2(key).format("ddd, MMM D");
|
|
321
324
|
case "week":
|
|
@@ -419,8 +422,25 @@ function ContextBar({ used, total, overhead }) {
|
|
|
419
422
|
|
|
420
423
|
// src/core/tokenCounter.ts
|
|
421
424
|
import { readFileSync as readFileSync2, existsSync } from "node:fs";
|
|
425
|
+
import { execSync } from "node:child_process";
|
|
422
426
|
import { join as join3 } from "node:path";
|
|
423
427
|
import { homedir as homedir2 } from "node:os";
|
|
428
|
+
function findGitRootClaudeMd() {
|
|
429
|
+
try {
|
|
430
|
+
const gitRoot = execSync("git rev-parse --show-toplevel", {
|
|
431
|
+
encoding: "utf-8",
|
|
432
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
433
|
+
}).trim();
|
|
434
|
+
if (gitRoot && gitRoot !== process.cwd()) {
|
|
435
|
+
return [
|
|
436
|
+
join3(gitRoot, "CLAUDE.md"),
|
|
437
|
+
join3(gitRoot, ".claude", "CLAUDE.md")
|
|
438
|
+
];
|
|
439
|
+
}
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
return [];
|
|
443
|
+
}
|
|
424
444
|
function estimateTokens(text) {
|
|
425
445
|
return Math.ceil(text.length / 3.5);
|
|
426
446
|
}
|
|
@@ -473,7 +493,9 @@ function parseClaudeMdSections(content) {
|
|
|
473
493
|
function analyzeClaudeMd(filePath) {
|
|
474
494
|
const paths = filePath ? [filePath] : [
|
|
475
495
|
join3(process.cwd(), "CLAUDE.md"),
|
|
476
|
-
join3(process.cwd(), ".claude", "CLAUDE.md")
|
|
496
|
+
join3(process.cwd(), ".claude", "CLAUDE.md"),
|
|
497
|
+
...findGitRootClaudeMd(),
|
|
498
|
+
join3(homedir2(), ".claude", "CLAUDE.md")
|
|
477
499
|
];
|
|
478
500
|
for (const p of paths) {
|
|
479
501
|
if (existsSync(p)) {
|
|
@@ -674,8 +696,8 @@ async function estimateTaskCost(taskDescription, options = {}) {
|
|
|
674
696
|
let fileList = options.files ?? [];
|
|
675
697
|
if (fileList.length === 0) {
|
|
676
698
|
try {
|
|
677
|
-
const { execSync } = await import("node:child_process");
|
|
678
|
-
const output =
|
|
699
|
+
const { execSync: execSync2 } = await import("node:child_process");
|
|
700
|
+
const output = execSync2("git diff --name-only HEAD 2>/dev/null || git ls-files -m 2>/dev/null", {
|
|
679
701
|
cwd,
|
|
680
702
|
encoding: "utf-8"
|
|
681
703
|
});
|
|
@@ -1415,7 +1437,7 @@ function registerAuditCommand(program2) {
|
|
|
1415
1437
|
` Context Window Health: ${gradeColor.bold(result.grade)} (${result.contextOverhead.percentUsable.toFixed(0)}% usable)
|
|
1416
1438
|
`
|
|
1417
1439
|
);
|
|
1418
|
-
if (!opts.
|
|
1440
|
+
if (!opts.claudeMdOnly) {
|
|
1419
1441
|
console.log(chalk2.bold(" Ghost Token Breakdown:"));
|
|
1420
1442
|
const oh = result.contextOverhead;
|
|
1421
1443
|
const fmt = (label, tokens) => {
|
|
@@ -1444,17 +1466,52 @@ function registerAuditCommand(program2) {
|
|
|
1444
1466
|
console.log(
|
|
1445
1467
|
` Critical rules in dead zone: ${cma.criticalRulesInDeadZone > 0 ? chalk2.red(String(cma.criticalRulesInDeadZone)) : "0"}`
|
|
1446
1468
|
);
|
|
1469
|
+
if (opts.claudeMdOnly) {
|
|
1470
|
+
console.log();
|
|
1471
|
+
console.log(chalk2.bold(" Sections:"));
|
|
1472
|
+
for (const section of cma.sections) {
|
|
1473
|
+
const zone = section.attentionZone === "low-middle" ? chalk2.red(" [dead zone]") : chalk2.green(" [high attention]");
|
|
1474
|
+
const critical = section.hasCriticalRules ? chalk2.yellow(" *critical rules*") : "";
|
|
1475
|
+
console.log(
|
|
1476
|
+
` ${section.title.padEnd(30)} ${String(section.tokens).padStart(5)} tokens L${section.lineStart}-${section.lineEnd}${zone}${critical}`
|
|
1477
|
+
);
|
|
1478
|
+
}
|
|
1479
|
+
if (cma.suggestedReorder.length > 0) {
|
|
1480
|
+
console.log();
|
|
1481
|
+
console.log(chalk2.bold(" Suggested section order:"));
|
|
1482
|
+
cma.suggestedReorder.forEach((title, i) => {
|
|
1483
|
+
console.log(` ${i + 1}. ${title}`);
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1447
1487
|
console.log();
|
|
1488
|
+
} else if (!opts.mcpOnly && !result.claudeMdAnalysis) {
|
|
1489
|
+
console.log(chalk2.yellow(" No CLAUDE.md found in current directory or git root.\n"));
|
|
1448
1490
|
}
|
|
1449
|
-
if (result.
|
|
1450
|
-
console.log(chalk2.bold("
|
|
1451
|
-
result.
|
|
1452
|
-
const
|
|
1491
|
+
if (opts.mcpOnly && result.mcpServers.length > 0) {
|
|
1492
|
+
console.log(chalk2.bold(" MCP Servers:"));
|
|
1493
|
+
for (const server of result.mcpServers) {
|
|
1494
|
+
const heavy = server.isHeavy ? chalk2.red(" [heavy]") : "";
|
|
1453
1495
|
console.log(
|
|
1454
|
-
` ${
|
|
1496
|
+
` ${server.name.padEnd(20)} ${String(server.toolCount).padStart(3)} tools ${server.estimatedTokens.toLocaleString().padStart(6)} tokens${heavy}`
|
|
1455
1497
|
);
|
|
1456
|
-
|
|
1457
|
-
|
|
1498
|
+
}
|
|
1499
|
+
console.log();
|
|
1500
|
+
} else if (opts.mcpOnly && result.mcpServers.length === 0) {
|
|
1501
|
+
console.log(chalk2.dim(" No MCP servers configured.\n"));
|
|
1502
|
+
}
|
|
1503
|
+
if (result.recommendations.length > 0) {
|
|
1504
|
+
const filteredRecs = opts.claudeMdOnly ? result.recommendations.filter((r) => r.category === "claude-md") : opts.mcpOnly ? result.recommendations.filter((r) => r.category === "mcp") : result.recommendations;
|
|
1505
|
+
if (filteredRecs.length > 0) {
|
|
1506
|
+
console.log(chalk2.bold(" Recommendations:"));
|
|
1507
|
+
filteredRecs.forEach((rec, i) => {
|
|
1508
|
+
const priorityColor = rec.priority === "high" ? chalk2.red : rec.priority === "medium" ? chalk2.yellow : chalk2.dim;
|
|
1509
|
+
console.log(
|
|
1510
|
+
` ${i + 1}. ${priorityColor(`[${rec.priority.toUpperCase()}]`)} ${rec.action}`
|
|
1511
|
+
);
|
|
1512
|
+
console.log(chalk2.dim(` Impact: ${rec.impact}`));
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1458
1515
|
}
|
|
1459
1516
|
console.log();
|
|
1460
1517
|
if (opts.fix) {
|
|
@@ -1628,14 +1685,14 @@ function registerInitCommand(program2) {
|
|
|
1628
1685
|
}
|
|
1629
1686
|
}
|
|
1630
1687
|
try {
|
|
1631
|
-
const { execSync } = await import("node:child_process");
|
|
1688
|
+
const { execSync: execSync2 } = await import("node:child_process");
|
|
1632
1689
|
try {
|
|
1633
|
-
|
|
1690
|
+
execSync2("which rtk", { stdio: "ignore" });
|
|
1634
1691
|
console.log(chalk4.green(" Detected RTK (command compression) -- compatible!"));
|
|
1635
1692
|
} catch {
|
|
1636
1693
|
}
|
|
1637
1694
|
try {
|
|
1638
|
-
|
|
1695
|
+
execSync2("which ccusage", { stdio: "ignore" });
|
|
1639
1696
|
console.log(chalk4.green(" Detected ccusage -- will import historical data"));
|
|
1640
1697
|
} catch {
|
|
1641
1698
|
}
|