instrlint 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 +3 -1
- package/README.zh-TW.md +3 -1
- package/dist/cli.cjs +202 -104
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +198 -100
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/skills/claude-code/SKILL.md +24 -25
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// src/commands/run-command.ts
|
|
7
7
|
import { execSync } from "child_process";
|
|
8
|
+
import { createInterface } from "readline";
|
|
8
9
|
import { basename as basename2 } from "path";
|
|
9
10
|
import chalk4 from "chalk";
|
|
10
11
|
|
|
@@ -1565,9 +1566,13 @@ var en_default = {
|
|
|
1565
1566
|
"ci.writtenTo": "\u2192 written to {{file}}",
|
|
1566
1567
|
"initCi.created": "\u2713 Created {{path}}",
|
|
1567
1568
|
"initCi.alreadyExists": "{{path}} already exists. Use --force to overwrite.",
|
|
1568
|
-
"install.installed": "\u2713 Installed to {{path}}",
|
|
1569
|
+
"install.installed": "\u2713 Installed to {{path}}\n \u2192 Restart Claude Code to activate /instrlint",
|
|
1569
1570
|
"install.alreadyExists": "{{path}} already exists. Use --force to overwrite.",
|
|
1570
1571
|
"install.unknownTarget": "Specify --claude-code or --codex",
|
|
1572
|
+
"install.outdatedTitle": "instrlint skill is outdated",
|
|
1573
|
+
"install.outdatedVersions": "installed: {{installed}} \u2192 current: {{current}}",
|
|
1574
|
+
"install.updateCmd": "npx instrlint install {{flag}} --force",
|
|
1575
|
+
"install.updatePrompt": "Update skill now?",
|
|
1571
1576
|
"fix.manualActions": "MANUAL ACTIONS NEEDED",
|
|
1572
1577
|
"fix.hookCreate": "Add to .claude/settings.json:",
|
|
1573
1578
|
"fix.hookWarning": "\u26A0 Hook executes shell commands \u2014 review carefully before adding",
|
|
@@ -1666,9 +1671,13 @@ var zh_TW_default = {
|
|
|
1666
1671
|
"ci.writtenTo": "\u2192 \u5DF2\u5BEB\u5165 {{file}}",
|
|
1667
1672
|
"initCi.created": "\u2713 \u5DF2\u5EFA\u7ACB {{path}}",
|
|
1668
1673
|
"initCi.alreadyExists": "{{path}} \u5DF2\u5B58\u5728\u3002\u4F7F\u7528 --force \u8986\u84CB\u3002",
|
|
1669
|
-
"install.installed": "\u2713 \u5DF2\u5B89\u88DD\u81F3 {{path}}",
|
|
1674
|
+
"install.installed": "\u2713 \u5DF2\u5B89\u88DD\u81F3 {{path}}\n \u2192 \u91CD\u65B0\u555F\u52D5 Claude Code \u5F8C\u5373\u53EF\u4F7F\u7528 /instrlint",
|
|
1670
1675
|
"install.alreadyExists": "{{path}} \u5DF2\u5B58\u5728\u3002\u4F7F\u7528 --force \u8986\u84CB\u3002",
|
|
1671
1676
|
"install.unknownTarget": "\u8ACB\u6307\u5B9A --claude-code \u6216 --codex",
|
|
1677
|
+
"install.outdatedTitle": "instrlint skill \u7248\u672C\u904E\u820A",
|
|
1678
|
+
"install.outdatedVersions": "\u5DF2\u5B89\u88DD\uFF1A{{installed}} \u2192 \u6700\u65B0\uFF1A{{current}}",
|
|
1679
|
+
"install.updateCmd": "npx instrlint install {{flag}} --force",
|
|
1680
|
+
"install.updatePrompt": "\u662F\u5426\u7ACB\u5373\u66F4\u65B0\uFF1F",
|
|
1672
1681
|
"fix.manualActions": "\u9700\u8981\u624B\u52D5\u64CD\u4F5C",
|
|
1673
1682
|
"fix.hookCreate": "\u52A0\u5165 .claude/settings.json\uFF1A",
|
|
1674
1683
|
"fix.hookWarning": "\u26A0 Hook \u6703\u57F7\u884C shell command\uFF0C\u8ACB\u4ED4\u7D30\u78BA\u8A8D\u5F8C\u518D\u52A0\u5165",
|
|
@@ -2263,6 +2272,136 @@ function markdownStructureSuggestions(suggestions, projectRoot) {
|
|
|
2263
2272
|
return lines;
|
|
2264
2273
|
}
|
|
2265
2274
|
|
|
2275
|
+
// src/utils/skill-version.ts
|
|
2276
|
+
import { existsSync as existsSync7, readFileSync as readFileSync8 } from "fs";
|
|
2277
|
+
import { join as join7 } from "path";
|
|
2278
|
+
import { homedir } from "os";
|
|
2279
|
+
var CURRENT_VERSION = "0.1.3";
|
|
2280
|
+
var VERSION_RE = /^instrlint-version:\s*(.+)$/m;
|
|
2281
|
+
function extractVersion(content) {
|
|
2282
|
+
const m = VERSION_RE.exec(content);
|
|
2283
|
+
return m ? m[1].trim() : null;
|
|
2284
|
+
}
|
|
2285
|
+
function readInstalledVersion(path) {
|
|
2286
|
+
if (!existsSync7(path)) return null;
|
|
2287
|
+
try {
|
|
2288
|
+
return extractVersion(readFileSync8(path, "utf8"));
|
|
2289
|
+
} catch {
|
|
2290
|
+
return null;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
function checkSkillUpdate(projectRoot) {
|
|
2294
|
+
const candidates = [
|
|
2295
|
+
{
|
|
2296
|
+
path: join7(projectRoot, ".claude", "commands", "instrlint.md"),
|
|
2297
|
+
isProject: true
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
path: join7(homedir(), ".claude", "commands", "instrlint.md"),
|
|
2301
|
+
isProject: false
|
|
2302
|
+
}
|
|
2303
|
+
];
|
|
2304
|
+
for (const { path, isProject } of candidates) {
|
|
2305
|
+
const installed = readInstalledVersion(path);
|
|
2306
|
+
if (installed !== null && installed !== CURRENT_VERSION) {
|
|
2307
|
+
return {
|
|
2308
|
+
installedVersion: installed,
|
|
2309
|
+
currentVersion: CURRENT_VERSION,
|
|
2310
|
+
installPath: path,
|
|
2311
|
+
isProject
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return null;
|
|
2316
|
+
}
|
|
2317
|
+
function injectVersion(content, version) {
|
|
2318
|
+
return content.replace(/^(---\n[\s\S]*?)(---)$/m, `$1instrlint-version: ${version}
|
|
2319
|
+
$2`);
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
// src/commands/install-command.ts
|
|
2323
|
+
import { existsSync as existsSync8, mkdirSync, readFileSync as readFileSync9, writeFileSync as writeFileSync2 } from "fs";
|
|
2324
|
+
import { join as join8 } from "path";
|
|
2325
|
+
import { homedir as homedir2 } from "os";
|
|
2326
|
+
import { fileURLToPath } from "url";
|
|
2327
|
+
function resolveSkillFile(target) {
|
|
2328
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
2329
|
+
const subDir = target === "claude-code" ? "claude-code" : "codex";
|
|
2330
|
+
for (const levels of [2, 3]) {
|
|
2331
|
+
const parts = Array(levels).fill("..");
|
|
2332
|
+
const candidate = join8(thisFile, ...parts, "skills", subDir, "SKILL.md");
|
|
2333
|
+
if (existsSync8(candidate)) return candidate;
|
|
2334
|
+
}
|
|
2335
|
+
return join8(thisFile, "..", "..", "skills", subDir, "SKILL.md");
|
|
2336
|
+
}
|
|
2337
|
+
function readSkillContent(target) {
|
|
2338
|
+
const skillPath = resolveSkillFile(target);
|
|
2339
|
+
try {
|
|
2340
|
+
const raw = readFileSync9(skillPath, "utf8");
|
|
2341
|
+
return injectVersion(raw, CURRENT_VERSION);
|
|
2342
|
+
} catch {
|
|
2343
|
+
throw new Error(
|
|
2344
|
+
`Could not read skill file at ${skillPath}. Make sure the package is properly installed.`
|
|
2345
|
+
);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
function installClaudeCode(content, projectRoot, isProject, force, output) {
|
|
2349
|
+
const targetDir = isProject ? join8(projectRoot, ".claude", "commands") : join8(homedir2(), ".claude", "commands");
|
|
2350
|
+
const targetPath = join8(targetDir, "instrlint.md");
|
|
2351
|
+
if (existsSync8(targetPath) && !force) {
|
|
2352
|
+
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2353
|
+
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2354
|
+
}
|
|
2355
|
+
mkdirSync(targetDir, { recursive: true });
|
|
2356
|
+
writeFileSync2(targetPath, content, "utf8");
|
|
2357
|
+
output.log(t("install.installed", { path: targetPath }));
|
|
2358
|
+
return { exitCode: 0 };
|
|
2359
|
+
}
|
|
2360
|
+
function installCodex(content, projectRoot, force, output) {
|
|
2361
|
+
const targetDir = join8(projectRoot, ".agents", "skills", "instrlint");
|
|
2362
|
+
const targetPath = join8(targetDir, "SKILL.md");
|
|
2363
|
+
if (existsSync8(targetPath) && !force) {
|
|
2364
|
+
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2365
|
+
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2366
|
+
}
|
|
2367
|
+
mkdirSync(targetDir, { recursive: true });
|
|
2368
|
+
writeFileSync2(targetPath, content, "utf8");
|
|
2369
|
+
output.log(t("install.installed", { path: targetPath }));
|
|
2370
|
+
return { exitCode: 0 };
|
|
2371
|
+
}
|
|
2372
|
+
function runInstall(opts, output = console) {
|
|
2373
|
+
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
2374
|
+
const force = opts.force ?? false;
|
|
2375
|
+
if (opts.claudeCode) {
|
|
2376
|
+
let content;
|
|
2377
|
+
try {
|
|
2378
|
+
content = readSkillContent("claude-code");
|
|
2379
|
+
} catch (err) {
|
|
2380
|
+
output.error(String(err));
|
|
2381
|
+
return { exitCode: 1, errorMessage: String(err) };
|
|
2382
|
+
}
|
|
2383
|
+
return installClaudeCode(
|
|
2384
|
+
content,
|
|
2385
|
+
projectRoot,
|
|
2386
|
+
opts.project ?? false,
|
|
2387
|
+
force,
|
|
2388
|
+
output
|
|
2389
|
+
);
|
|
2390
|
+
}
|
|
2391
|
+
if (opts.codex) {
|
|
2392
|
+
let content;
|
|
2393
|
+
try {
|
|
2394
|
+
content = readSkillContent("codex");
|
|
2395
|
+
} catch (err) {
|
|
2396
|
+
output.error(String(err));
|
|
2397
|
+
return { exitCode: 1, errorMessage: String(err) };
|
|
2398
|
+
}
|
|
2399
|
+
return installCodex(content, projectRoot, force, output);
|
|
2400
|
+
}
|
|
2401
|
+
output.error(t("install.unknownTarget"));
|
|
2402
|
+
return { exitCode: 1, errorMessage: "no target specified" };
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2266
2405
|
// src/commands/run-command.ts
|
|
2267
2406
|
function isGitClean(cwd) {
|
|
2268
2407
|
try {
|
|
@@ -2352,6 +2491,7 @@ async function runAll(opts, output = console) {
|
|
|
2352
2491
|
printStructureSuggestions(suggestions, projectRoot, output);
|
|
2353
2492
|
return { exitCode: 0 };
|
|
2354
2493
|
}
|
|
2494
|
+
const skillUpdate = checkSkillUpdate(projectRoot);
|
|
2355
2495
|
if (opts.format === "json") {
|
|
2356
2496
|
output.log(reportJson(report));
|
|
2357
2497
|
return { exitCode: 0 };
|
|
@@ -2359,12 +2499,52 @@ async function runAll(opts, output = console) {
|
|
|
2359
2499
|
if (opts.format === "markdown") {
|
|
2360
2500
|
const mdSuggestions = buildStructureSuggestions(allFindings);
|
|
2361
2501
|
const mdExtra = markdownStructureSuggestions(mdSuggestions, projectRoot);
|
|
2362
|
-
|
|
2502
|
+
const updateSection = skillUpdate ? [
|
|
2503
|
+
"",
|
|
2504
|
+
`> \u26A0\uFE0F **${t("install.outdatedTitle")}** (${t("install.outdatedVersions", { installed: skillUpdate.installedVersion, current: skillUpdate.currentVersion })})`,
|
|
2505
|
+
`> \`${t("install.updateCmd", { flag: skillUpdate.isProject ? "--claude-code --project" : "--claude-code" })}\``
|
|
2506
|
+
] : [];
|
|
2507
|
+
output.log(reportMarkdown(report, [...mdExtra, ...updateSection]));
|
|
2363
2508
|
return { exitCode: 0 };
|
|
2364
2509
|
}
|
|
2365
2510
|
printCombinedTerminal(report, output);
|
|
2511
|
+
if (skillUpdate && process.stdout.isTTY) {
|
|
2512
|
+
output.log("");
|
|
2513
|
+
output.log(
|
|
2514
|
+
` ${chalk4.yellow("\u26A0")} ${chalk4.bold(t("install.outdatedTitle"))} (${t("install.outdatedVersions", { installed: skillUpdate.installedVersion, current: skillUpdate.currentVersion })})`
|
|
2515
|
+
);
|
|
2516
|
+
const confirmed = await promptYesNo(
|
|
2517
|
+
` ${t("install.updatePrompt")}`,
|
|
2518
|
+
output
|
|
2519
|
+
);
|
|
2520
|
+
if (confirmed) {
|
|
2521
|
+
runInstall(
|
|
2522
|
+
{
|
|
2523
|
+
claudeCode: true,
|
|
2524
|
+
project: skillUpdate.isProject,
|
|
2525
|
+
force: true,
|
|
2526
|
+
projectRoot
|
|
2527
|
+
},
|
|
2528
|
+
output
|
|
2529
|
+
);
|
|
2530
|
+
}
|
|
2531
|
+
output.log("");
|
|
2532
|
+
}
|
|
2366
2533
|
return { exitCode: 0 };
|
|
2367
2534
|
}
|
|
2535
|
+
function promptYesNo(question, output) {
|
|
2536
|
+
return new Promise((resolve) => {
|
|
2537
|
+
const rl = createInterface({
|
|
2538
|
+
input: process.stdin,
|
|
2539
|
+
output: process.stdout
|
|
2540
|
+
});
|
|
2541
|
+
rl.question(`${question} ${chalk4.gray("[Y/n]")} `, (answer) => {
|
|
2542
|
+
rl.close();
|
|
2543
|
+
const trimmed = answer.trim().toLowerCase();
|
|
2544
|
+
resolve(trimmed === "" || trimmed === "y");
|
|
2545
|
+
});
|
|
2546
|
+
});
|
|
2547
|
+
}
|
|
2368
2548
|
|
|
2369
2549
|
// src/commands/deadrules-command.ts
|
|
2370
2550
|
import chalk5 from "chalk";
|
|
@@ -2525,7 +2705,7 @@ async function runStructure(opts, output = console) {
|
|
|
2525
2705
|
}
|
|
2526
2706
|
|
|
2527
2707
|
// src/commands/ci-command.ts
|
|
2528
|
-
import { writeFileSync as
|
|
2708
|
+
import { writeFileSync as writeFileSync3 } from "fs";
|
|
2529
2709
|
import { basename as basename3 } from "path";
|
|
2530
2710
|
|
|
2531
2711
|
// src/reporters/sarif.ts
|
|
@@ -2653,7 +2833,7 @@ async function runCi(opts, output = console) {
|
|
|
2653
2833
|
formatted = reportJson(report);
|
|
2654
2834
|
}
|
|
2655
2835
|
if (opts.output != null) {
|
|
2656
|
-
|
|
2836
|
+
writeFileSync3(opts.output, formatted, "utf8");
|
|
2657
2837
|
const pass = !shouldFail(allFindings, failOn);
|
|
2658
2838
|
const statusKey = pass ? "ci.passed" : "ci.failed";
|
|
2659
2839
|
output.error(
|
|
@@ -2667,8 +2847,8 @@ async function runCi(opts, output = console) {
|
|
|
2667
2847
|
}
|
|
2668
2848
|
|
|
2669
2849
|
// src/commands/init-ci-command.ts
|
|
2670
|
-
import { existsSync as
|
|
2671
|
-
import { join as
|
|
2850
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
2851
|
+
import { join as join9 } from "path";
|
|
2672
2852
|
function githubWorkflow() {
|
|
2673
2853
|
return `name: instrlint
|
|
2674
2854
|
|
|
@@ -2737,14 +2917,14 @@ instrlint:
|
|
|
2737
2917
|
function runInitCi(opts, output = console) {
|
|
2738
2918
|
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
2739
2919
|
if (opts.github) {
|
|
2740
|
-
const workflowDir =
|
|
2741
|
-
const workflowPath =
|
|
2742
|
-
if (
|
|
2920
|
+
const workflowDir = join9(projectRoot, ".github", "workflows");
|
|
2921
|
+
const workflowPath = join9(workflowDir, "instrlint.yml");
|
|
2922
|
+
if (existsSync9(workflowPath) && !opts.force) {
|
|
2743
2923
|
output.error(t("initCi.alreadyExists", { path: workflowPath }));
|
|
2744
2924
|
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2745
2925
|
}
|
|
2746
|
-
|
|
2747
|
-
|
|
2926
|
+
mkdirSync2(workflowDir, { recursive: true });
|
|
2927
|
+
writeFileSync4(workflowPath, githubWorkflow(), "utf8");
|
|
2748
2928
|
output.log(t("initCi.created", { path: workflowPath }));
|
|
2749
2929
|
return { exitCode: 0 };
|
|
2750
2930
|
}
|
|
@@ -2756,88 +2936,6 @@ function runInitCi(opts, output = console) {
|
|
|
2756
2936
|
return { exitCode: 1, errorMessage: "no target specified" };
|
|
2757
2937
|
}
|
|
2758
2938
|
|
|
2759
|
-
// src/commands/install-command.ts
|
|
2760
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
|
|
2761
|
-
import { join as join8 } from "path";
|
|
2762
|
-
import { homedir } from "os";
|
|
2763
|
-
import { fileURLToPath } from "url";
|
|
2764
|
-
function resolveSkillFile(target) {
|
|
2765
|
-
const thisFile = fileURLToPath(import.meta.url);
|
|
2766
|
-
const subDir = target === "claude-code" ? "claude-code" : "codex";
|
|
2767
|
-
for (const levels of [2, 3]) {
|
|
2768
|
-
const parts = Array(levels).fill("..");
|
|
2769
|
-
const candidate = join8(thisFile, ...parts, "skills", subDir, "SKILL.md");
|
|
2770
|
-
if (existsSync8(candidate)) return candidate;
|
|
2771
|
-
}
|
|
2772
|
-
return join8(thisFile, "..", "..", "skills", subDir, "SKILL.md");
|
|
2773
|
-
}
|
|
2774
|
-
function readSkillContent(target) {
|
|
2775
|
-
const skillPath = resolveSkillFile(target);
|
|
2776
|
-
try {
|
|
2777
|
-
return readFileSync8(skillPath, "utf8");
|
|
2778
|
-
} catch {
|
|
2779
|
-
throw new Error(
|
|
2780
|
-
`Could not read skill file at ${skillPath}. Make sure the package is properly installed.`
|
|
2781
|
-
);
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2784
|
-
function installClaudeCode(content, projectRoot, isProject, force, output) {
|
|
2785
|
-
const targetDir = isProject ? join8(projectRoot, ".claude", "commands") : join8(homedir(), ".claude", "commands");
|
|
2786
|
-
const targetPath = join8(targetDir, "instrlint.md");
|
|
2787
|
-
if (existsSync8(targetPath) && !force) {
|
|
2788
|
-
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2789
|
-
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2790
|
-
}
|
|
2791
|
-
mkdirSync2(targetDir, { recursive: true });
|
|
2792
|
-
writeFileSync4(targetPath, content, "utf8");
|
|
2793
|
-
output.log(t("install.installed", { path: targetPath }));
|
|
2794
|
-
return { exitCode: 0 };
|
|
2795
|
-
}
|
|
2796
|
-
function installCodex(content, projectRoot, force, output) {
|
|
2797
|
-
const targetDir = join8(projectRoot, ".agents", "skills", "instrlint");
|
|
2798
|
-
const targetPath = join8(targetDir, "SKILL.md");
|
|
2799
|
-
if (existsSync8(targetPath) && !force) {
|
|
2800
|
-
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2801
|
-
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2802
|
-
}
|
|
2803
|
-
mkdirSync2(targetDir, { recursive: true });
|
|
2804
|
-
writeFileSync4(targetPath, content, "utf8");
|
|
2805
|
-
output.log(t("install.installed", { path: targetPath }));
|
|
2806
|
-
return { exitCode: 0 };
|
|
2807
|
-
}
|
|
2808
|
-
function runInstall(opts, output = console) {
|
|
2809
|
-
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
2810
|
-
const force = opts.force ?? false;
|
|
2811
|
-
if (opts.claudeCode) {
|
|
2812
|
-
let content;
|
|
2813
|
-
try {
|
|
2814
|
-
content = readSkillContent("claude-code");
|
|
2815
|
-
} catch (err) {
|
|
2816
|
-
output.error(String(err));
|
|
2817
|
-
return { exitCode: 1, errorMessage: String(err) };
|
|
2818
|
-
}
|
|
2819
|
-
return installClaudeCode(
|
|
2820
|
-
content,
|
|
2821
|
-
projectRoot,
|
|
2822
|
-
opts.project ?? false,
|
|
2823
|
-
force,
|
|
2824
|
-
output
|
|
2825
|
-
);
|
|
2826
|
-
}
|
|
2827
|
-
if (opts.codex) {
|
|
2828
|
-
let content;
|
|
2829
|
-
try {
|
|
2830
|
-
content = readSkillContent("codex");
|
|
2831
|
-
} catch (err) {
|
|
2832
|
-
output.error(String(err));
|
|
2833
|
-
return { exitCode: 1, errorMessage: String(err) };
|
|
2834
|
-
}
|
|
2835
|
-
return installCodex(content, projectRoot, force, output);
|
|
2836
|
-
}
|
|
2837
|
-
output.error(t("install.unknownTarget"));
|
|
2838
|
-
return { exitCode: 1, errorMessage: "no target specified" };
|
|
2839
|
-
}
|
|
2840
|
-
|
|
2841
2939
|
// src/cli.ts
|
|
2842
2940
|
var program = new Command();
|
|
2843
2941
|
program.enablePositionalOptions().name("instrlint").description(
|
|
@@ -2855,27 +2953,27 @@ program.command("budget").description("Token budget analysis only").option(
|
|
|
2855
2953
|
"--format <type>",
|
|
2856
2954
|
"output format (terminal|json|markdown)",
|
|
2857
2955
|
"terminal"
|
|
2858
|
-
).option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2956
|
+
).option("--lang <locale>", "output language (en|zh-TW)").option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2859
2957
|
const opts = this.opts();
|
|
2860
|
-
const lang = this.parent?.opts()?.lang;
|
|
2958
|
+
const lang = opts.lang ?? this.parent?.opts()?.lang;
|
|
2861
2959
|
const result = await runBudget({
|
|
2862
2960
|
...opts,
|
|
2863
2961
|
...lang !== void 0 && { lang }
|
|
2864
2962
|
});
|
|
2865
2963
|
if (result.exitCode !== 0) process.exit(result.exitCode);
|
|
2866
2964
|
});
|
|
2867
|
-
program.command("deadrules").description("Dead rule detection only").option("--format <type>", "output format (terminal|json)", "terminal").option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2965
|
+
program.command("deadrules").description("Dead rule detection only").option("--format <type>", "output format (terminal|json)", "terminal").option("--lang <locale>", "output language (en|zh-TW)").option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2868
2966
|
const opts = this.opts();
|
|
2869
|
-
const lang = this.parent?.opts()?.lang;
|
|
2967
|
+
const lang = opts.lang ?? this.parent?.opts()?.lang;
|
|
2870
2968
|
const result = await runDeadRules({
|
|
2871
2969
|
...opts,
|
|
2872
2970
|
...lang !== void 0 && { lang }
|
|
2873
2971
|
});
|
|
2874
2972
|
if (result.exitCode !== 0) process.exit(result.exitCode);
|
|
2875
2973
|
});
|
|
2876
|
-
program.command("structure").description("Structural analysis only").option("--format <type>", "output format (terminal|json)", "terminal").option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2974
|
+
program.command("structure").description("Structural analysis only").option("--format <type>", "output format (terminal|json)", "terminal").option("--lang <locale>", "output language (en|zh-TW)").option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2877
2975
|
const opts = this.opts();
|
|
2878
|
-
const lang = this.parent?.opts()?.lang;
|
|
2976
|
+
const lang = opts.lang ?? this.parent?.opts()?.lang;
|
|
2879
2977
|
const result = await runStructure({
|
|
2880
2978
|
...opts,
|
|
2881
2979
|
...lang !== void 0 && { lang }
|