instrlint 0.1.3 → 0.1.5
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.cjs +150 -25
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +150 -25
- package/dist/cli.js.map +1 -1
- package/package.json +5 -2
- package/skills/claude-code/SKILL.md +6 -6
package/dist/cli.cjs
CHANGED
|
@@ -815,8 +815,12 @@ function analyzeBudget(instructions) {
|
|
|
815
815
|
autoFixable: false
|
|
816
816
|
});
|
|
817
817
|
}
|
|
818
|
-
const { tokens: rulesTokens, method: rulesMethod } = sumTokens(
|
|
819
|
-
|
|
818
|
+
const { tokens: rulesTokens, method: rulesMethod } = sumTokens(
|
|
819
|
+
instructions.rules
|
|
820
|
+
);
|
|
821
|
+
const { tokens: skillsTokens, method: skillsMethod } = sumTokens(
|
|
822
|
+
instructions.skills
|
|
823
|
+
);
|
|
820
824
|
const { tokens: subFilesTokens, method: subFilesMethod } = sumTokens(
|
|
821
825
|
instructions.subFiles
|
|
822
826
|
);
|
|
@@ -854,11 +858,18 @@ function analyzeBudget(instructions) {
|
|
|
854
858
|
autoFixable: false
|
|
855
859
|
});
|
|
856
860
|
}
|
|
857
|
-
const tokenMethod = [
|
|
858
|
-
|
|
859
|
-
|
|
861
|
+
const tokenMethod = [
|
|
862
|
+
rootFileMethod,
|
|
863
|
+
rulesMethod,
|
|
864
|
+
skillsMethod,
|
|
865
|
+
subFilesMethod
|
|
866
|
+
].every((m) => m === "measured") ? "measured" : "estimated";
|
|
860
867
|
const fileBreakdown = [
|
|
861
|
-
{
|
|
868
|
+
{
|
|
869
|
+
path: instructions.rootFile.path,
|
|
870
|
+
tokenCount: rootFileTokens,
|
|
871
|
+
tokenMethod: rootFileMethod
|
|
872
|
+
},
|
|
862
873
|
...instructions.rules.map((r) => ({
|
|
863
874
|
path: r.path,
|
|
864
875
|
tokenCount: r.tokenCount,
|
|
@@ -878,6 +889,7 @@ function analyzeBudget(instructions) {
|
|
|
878
889
|
const summary = {
|
|
879
890
|
systemPromptTokens: SYSTEM_PROMPT_TOKENS,
|
|
880
891
|
rootFileTokens,
|
|
892
|
+
rootFileLines: rootLines,
|
|
881
893
|
rootFileMethod,
|
|
882
894
|
rulesTokens,
|
|
883
895
|
rulesMethod,
|
|
@@ -1454,6 +1466,8 @@ var INFO_DEDUCTION = 1;
|
|
|
1454
1466
|
var MAX_CRITICAL_DEDUCTION = 40;
|
|
1455
1467
|
var MAX_WARNING_DEDUCTION = 30;
|
|
1456
1468
|
var MAX_INFO_DEDUCTION = 10;
|
|
1469
|
+
var MAX_ROOT_FILE_PENALTY = 30;
|
|
1470
|
+
var MAX_BUDGET_DEDUCTION = 30;
|
|
1457
1471
|
function gradeFromScore(score) {
|
|
1458
1472
|
if (score >= 90) return "A";
|
|
1459
1473
|
if (score >= 80) return "B";
|
|
@@ -1465,16 +1479,32 @@ function calculateScore(findings, budget) {
|
|
|
1465
1479
|
const criticals = findings.filter((f) => f.severity === "critical").length;
|
|
1466
1480
|
const warnings = findings.filter((f) => f.severity === "warning").length;
|
|
1467
1481
|
const infos = findings.filter((f) => f.severity === "info").length;
|
|
1468
|
-
const criticalDeduction = Math.min(
|
|
1469
|
-
|
|
1482
|
+
const criticalDeduction = Math.min(
|
|
1483
|
+
criticals * CRITICAL_DEDUCTION,
|
|
1484
|
+
MAX_CRITICAL_DEDUCTION
|
|
1485
|
+
);
|
|
1486
|
+
const warningDeduction = Math.min(
|
|
1487
|
+
warnings * WARNING_DEDUCTION,
|
|
1488
|
+
MAX_WARNING_DEDUCTION
|
|
1489
|
+
);
|
|
1470
1490
|
const infoDeduction = Math.min(infos * INFO_DEDUCTION, MAX_INFO_DEDUCTION);
|
|
1491
|
+
const rootLines = budget.rootFileLines;
|
|
1492
|
+
let rootFilePenalty = 0;
|
|
1493
|
+
if (rootLines > 400) {
|
|
1494
|
+
rootFilePenalty = 10 + Math.floor((rootLines - 400) / 100) * 5;
|
|
1495
|
+
} else if (rootLines > 200) {
|
|
1496
|
+
rootFilePenalty = 5 + Math.floor((rootLines - 200) / 100) * 3;
|
|
1497
|
+
}
|
|
1498
|
+
rootFilePenalty = Math.min(rootFilePenalty, MAX_ROOT_FILE_PENALTY);
|
|
1471
1499
|
const baselinePct = budget.totalBaseline / CONTEXT_WINDOW2;
|
|
1472
1500
|
let budgetDeduction = 0;
|
|
1473
|
-
if (baselinePct > 0.
|
|
1474
|
-
|
|
1501
|
+
if (baselinePct > 0.25) {
|
|
1502
|
+
budgetDeduction = 5 + Math.floor((baselinePct - 0.25) * 40);
|
|
1503
|
+
}
|
|
1504
|
+
budgetDeduction = Math.min(budgetDeduction, MAX_BUDGET_DEDUCTION);
|
|
1475
1505
|
const score = Math.max(
|
|
1476
1506
|
0,
|
|
1477
|
-
100 - criticalDeduction - warningDeduction - infoDeduction - budgetDeduction
|
|
1507
|
+
100 - criticalDeduction - warningDeduction - infoDeduction - rootFilePenalty - budgetDeduction
|
|
1478
1508
|
);
|
|
1479
1509
|
return { score, grade: gradeFromScore(score) };
|
|
1480
1510
|
}
|
|
@@ -1586,6 +1616,8 @@ var en_default = {
|
|
|
1586
1616
|
"markdown.budgetIssues": "Budget Issues",
|
|
1587
1617
|
"markdown.refactoringOpportunities": "Refactoring Opportunities",
|
|
1588
1618
|
"markdown.lineRef": "(line {{line}})",
|
|
1619
|
+
"markdown.budgetCategory": "Category",
|
|
1620
|
+
"markdown.budgetTokens": "Tokens",
|
|
1589
1621
|
"markdown.actionPlan": "## Action Plan",
|
|
1590
1622
|
"markdown.attribution": "*Generated by [instrlint](https://github.com/jed1978/instrlint)*",
|
|
1591
1623
|
"ci.passed": "\u2713 instrlint passed score={{score}} grade={{grade}}",
|
|
@@ -1691,6 +1723,8 @@ var zh_TW_default = {
|
|
|
1691
1723
|
"markdown.budgetIssues": "Token \u9810\u7B97\u554F\u984C",
|
|
1692
1724
|
"markdown.refactoringOpportunities": "\u91CD\u69CB\u5EFA\u8B70",
|
|
1693
1725
|
"markdown.lineRef": "\uFF08\u7B2C {{line}} \u884C\uFF09",
|
|
1726
|
+
"markdown.budgetCategory": "\u985E\u5225",
|
|
1727
|
+
"markdown.budgetTokens": "Token \u6578",
|
|
1694
1728
|
"markdown.actionPlan": "## \u884C\u52D5\u8A08\u756B",
|
|
1695
1729
|
"markdown.attribution": "*\u7531 [instrlint](https://github.com/jed1978/instrlint) \u751F\u6210*",
|
|
1696
1730
|
"ci.passed": "\u2713 instrlint \u901A\u904E \u5206\u6578={{score}} \u7B49\u7D1A={{grade}}",
|
|
@@ -2034,15 +2068,25 @@ function mdSeverityIcon(f) {
|
|
|
2034
2068
|
if (f.severity === "warning") return "\u{1F7E1}";
|
|
2035
2069
|
return "\u2139\uFE0F";
|
|
2036
2070
|
}
|
|
2071
|
+
function mdBar(fraction, width = 20) {
|
|
2072
|
+
const filled = Math.round(Math.min(1, Math.max(0, fraction)) * width);
|
|
2073
|
+
const empty = width - filled;
|
|
2074
|
+
return "`" + "\u2588".repeat(filled) + "\u2591".repeat(empty) + "`";
|
|
2075
|
+
}
|
|
2076
|
+
function mdFormatTokens(count, method) {
|
|
2077
|
+
const fmt = new Intl.NumberFormat(getLocale());
|
|
2078
|
+
return method === "estimated" ? `~${fmt.format(count)}` : fmt.format(count);
|
|
2079
|
+
}
|
|
2037
2080
|
function reportMarkdown(report, extraSections = []) {
|
|
2038
|
-
const { project, tool, score, grade, findings } = report;
|
|
2081
|
+
const { project, tool, score, grade, findings, budget } = report;
|
|
2039
2082
|
const criticals = findings.filter((f) => f.severity === "critical").length;
|
|
2040
2083
|
const warnings = findings.filter((f) => f.severity === "warning").length;
|
|
2041
2084
|
const infos = findings.filter((f) => f.severity === "info").length;
|
|
2085
|
+
const gradeEmoji = grade === "A" ? "\u{1F7E2}" : grade === "B" ? "\u{1F535}" : grade === "C" ? "\u{1F7E1}" : grade === "D" ? "\u{1F7E0}" : "\u{1F534}";
|
|
2042
2086
|
const lines = [
|
|
2043
2087
|
`# ${t("markdown.title", { project })}`,
|
|
2044
2088
|
"",
|
|
2045
|
-
|
|
2089
|
+
`${gradeEmoji} **${score}/100 (${grade})** ${mdBar(score / 100, 25)} \xB7 \`${tool}\``,
|
|
2046
2090
|
"",
|
|
2047
2091
|
t("markdown.summary"),
|
|
2048
2092
|
"",
|
|
@@ -2053,6 +2097,58 @@ function reportMarkdown(report, extraSections = []) {
|
|
|
2053
2097
|
`| ${t("markdown.info")} | ${infos} |`,
|
|
2054
2098
|
""
|
|
2055
2099
|
];
|
|
2100
|
+
const window = budget.totalBaseline + budget.availableTokens;
|
|
2101
|
+
const budgetRows = [
|
|
2102
|
+
{
|
|
2103
|
+
labelKey: "label.systemPrompt",
|
|
2104
|
+
tokens: budget.systemPromptTokens,
|
|
2105
|
+
method: "estimated"
|
|
2106
|
+
},
|
|
2107
|
+
{
|
|
2108
|
+
labelKey: "label.rootFile",
|
|
2109
|
+
tokens: budget.rootFileTokens,
|
|
2110
|
+
method: budget.rootFileMethod
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
labelKey: "label.ruleFiles",
|
|
2114
|
+
tokens: budget.rulesTokens,
|
|
2115
|
+
method: budget.rulesMethod
|
|
2116
|
+
},
|
|
2117
|
+
{
|
|
2118
|
+
labelKey: "label.skillFiles",
|
|
2119
|
+
tokens: budget.skillsTokens,
|
|
2120
|
+
method: budget.skillsMethod
|
|
2121
|
+
},
|
|
2122
|
+
{
|
|
2123
|
+
labelKey: "label.subDirFiles",
|
|
2124
|
+
tokens: budget.subFilesTokens,
|
|
2125
|
+
method: budget.subFilesMethod
|
|
2126
|
+
},
|
|
2127
|
+
{
|
|
2128
|
+
labelKey: "label.mcpServers",
|
|
2129
|
+
tokens: budget.mcpTokens,
|
|
2130
|
+
method: "estimated"
|
|
2131
|
+
}
|
|
2132
|
+
].filter((r) => r.tokens > 0);
|
|
2133
|
+
lines.push(`## ${t("label.tokenBudget")}`, "");
|
|
2134
|
+
lines.push(
|
|
2135
|
+
`| ${t("markdown.budgetCategory")} | ${t("markdown.budgetTokens")} | % | |`,
|
|
2136
|
+
"|------|--------|---|---|"
|
|
2137
|
+
);
|
|
2138
|
+
for (const row of budgetRows) {
|
|
2139
|
+
const pctVal = Math.round(row.tokens / window * 100);
|
|
2140
|
+
lines.push(
|
|
2141
|
+
`| ${t(row.labelKey)} | ${mdFormatTokens(row.tokens, row.method)} | ${pctVal}% | ${mdBar(row.tokens / window, 12)} |`
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
const baselinePct = Math.round(budget.totalBaseline / window * 100);
|
|
2145
|
+
lines.push(
|
|
2146
|
+
`| **${t("label.baselineTotal")}** | **${mdFormatTokens(budget.totalBaseline, budget.tokenMethod)}** | **${baselinePct}%** | ${mdBar(budget.totalBaseline / window, 12)} |`
|
|
2147
|
+
);
|
|
2148
|
+
lines.push(
|
|
2149
|
+
`| ${t("label.available")} | ${mdFormatTokens(budget.availableTokens, "estimated")} | ${100 - baselinePct}% | |`
|
|
2150
|
+
);
|
|
2151
|
+
lines.push("");
|
|
2056
2152
|
const categories = [
|
|
2057
2153
|
{
|
|
2058
2154
|
labelKey: "markdown.contradictions",
|
|
@@ -2303,7 +2399,21 @@ function markdownStructureSuggestions(suggestions, projectRoot) {
|
|
|
2303
2399
|
var import_fs10 = require("fs");
|
|
2304
2400
|
var import_path8 = require("path");
|
|
2305
2401
|
var import_os = require("os");
|
|
2306
|
-
var
|
|
2402
|
+
var import_url = require("url");
|
|
2403
|
+
function readPackageVersion() {
|
|
2404
|
+
const thisFile = (0, import_url.fileURLToPath)(importMetaUrl);
|
|
2405
|
+
for (const levels of [2, 3]) {
|
|
2406
|
+
const pkgPath = (0, import_path8.join)(thisFile, ...Array(levels).fill(".."), "package.json");
|
|
2407
|
+
if ((0, import_fs10.existsSync)(pkgPath)) {
|
|
2408
|
+
const raw = JSON.parse((0, import_fs10.readFileSync)(pkgPath, "utf8"));
|
|
2409
|
+
if (typeof raw === "object" && raw !== null && "version" in raw && typeof raw.version === "string") {
|
|
2410
|
+
return raw.version;
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
return "0.0.0";
|
|
2415
|
+
}
|
|
2416
|
+
var CURRENT_VERSION = readPackageVersion();
|
|
2307
2417
|
var VERSION_RE = /^instrlint-version:\s*(.+)$/m;
|
|
2308
2418
|
function extractVersion(content) {
|
|
2309
2419
|
const m = VERSION_RE.exec(content);
|
|
@@ -2342,17 +2452,30 @@ function checkSkillUpdate(projectRoot) {
|
|
|
2342
2452
|
return null;
|
|
2343
2453
|
}
|
|
2344
2454
|
function injectVersion(content, version) {
|
|
2345
|
-
|
|
2346
|
-
|
|
2455
|
+
if (/^instrlint-version:/m.test(content)) {
|
|
2456
|
+
return content.replace(
|
|
2457
|
+
/^instrlint-version:.*$/m,
|
|
2458
|
+
`instrlint-version: ${version}`
|
|
2459
|
+
);
|
|
2460
|
+
}
|
|
2461
|
+
const updated = content.replace(
|
|
2462
|
+
/^(---\n[\s\S]*?)(---)$/m,
|
|
2463
|
+
`$1instrlint-version: ${version}
|
|
2464
|
+
$2`
|
|
2465
|
+
);
|
|
2466
|
+
if (updated === content) {
|
|
2467
|
+
throw new Error("injectVersion: no YAML frontmatter found in skill file");
|
|
2468
|
+
}
|
|
2469
|
+
return updated;
|
|
2347
2470
|
}
|
|
2348
2471
|
|
|
2349
2472
|
// src/commands/install-command.ts
|
|
2350
2473
|
var import_fs11 = require("fs");
|
|
2351
2474
|
var import_path9 = require("path");
|
|
2352
2475
|
var import_os2 = require("os");
|
|
2353
|
-
var
|
|
2476
|
+
var import_url2 = require("url");
|
|
2354
2477
|
function resolveSkillFile(target) {
|
|
2355
|
-
const thisFile = (0,
|
|
2478
|
+
const thisFile = (0, import_url2.fileURLToPath)(importMetaUrl);
|
|
2356
2479
|
const subDir = target === "claude-code" ? "claude-code" : "codex";
|
|
2357
2480
|
for (const levels of [2, 3]) {
|
|
2358
2481
|
const parts = Array(levels).fill("..");
|
|
@@ -2540,12 +2663,9 @@ async function runAll(opts, output = console) {
|
|
|
2540
2663
|
output.log(
|
|
2541
2664
|
` ${import_chalk4.default.yellow("\u26A0")} ${import_chalk4.default.bold(t("install.outdatedTitle"))} (${t("install.outdatedVersions", { installed: skillUpdate.installedVersion, current: skillUpdate.currentVersion })})`
|
|
2542
2665
|
);
|
|
2543
|
-
const confirmed = await promptYesNo(
|
|
2544
|
-
` ${t("install.updatePrompt")}`,
|
|
2545
|
-
output
|
|
2546
|
-
);
|
|
2666
|
+
const confirmed = await promptYesNo(` ${t("install.updatePrompt")}`);
|
|
2547
2667
|
if (confirmed) {
|
|
2548
|
-
runInstall(
|
|
2668
|
+
const installResult = runInstall(
|
|
2549
2669
|
{
|
|
2550
2670
|
claudeCode: true,
|
|
2551
2671
|
project: skillUpdate.isProject,
|
|
@@ -2554,12 +2674,17 @@ async function runAll(opts, output = console) {
|
|
|
2554
2674
|
},
|
|
2555
2675
|
output
|
|
2556
2676
|
);
|
|
2677
|
+
if (installResult.exitCode !== 0) {
|
|
2678
|
+
output.error?.(
|
|
2679
|
+
`Update failed: ${installResult.errorMessage ?? "unknown error"}`
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2557
2682
|
}
|
|
2558
2683
|
output.log("");
|
|
2559
2684
|
}
|
|
2560
2685
|
return { exitCode: 0 };
|
|
2561
2686
|
}
|
|
2562
|
-
function promptYesNo(question
|
|
2687
|
+
function promptYesNo(question) {
|
|
2563
2688
|
return new Promise((resolve) => {
|
|
2564
2689
|
const rl = (0, import_readline.createInterface)({
|
|
2565
2690
|
input: process.stdin,
|
|
@@ -2967,7 +3092,7 @@ function runInitCi(opts, output = console) {
|
|
|
2967
3092
|
var program = new import_commander.Command();
|
|
2968
3093
|
program.enablePositionalOptions().name("instrlint").description(
|
|
2969
3094
|
"Lint and optimize your CLAUDE.md / AGENTS.md \u2014 find dead rules, token waste, and structural issues"
|
|
2970
|
-
).version(
|
|
3095
|
+
).version(CURRENT_VERSION).option(
|
|
2971
3096
|
"--format <type>",
|
|
2972
3097
|
"output format (terminal|json|markdown)",
|
|
2973
3098
|
"terminal"
|