instrlint 0.1.1 → 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/README.md
CHANGED
|
@@ -149,7 +149,7 @@ npx instrlint install --claude-code --project
|
|
|
149
149
|
npx instrlint install --codex
|
|
150
150
|
```
|
|
151
151
|
|
|
152
|
-
Then in your editor:
|
|
152
|
+
Then **restart Claude Code** to activate the command. Then in your editor:
|
|
153
153
|
|
|
154
154
|
```
|
|
155
155
|
/instrlint
|
|
@@ -157,6 +157,8 @@ Then in your editor:
|
|
|
157
157
|
/instrlint ci --fail-on warning
|
|
158
158
|
```
|
|
159
159
|
|
|
160
|
+
> **Note:** Claude Code only loads custom commands at startup. `/reload-plugins` does not pick up newly installed commands.
|
|
161
|
+
|
|
160
162
|
## Score and grade
|
|
161
163
|
|
|
162
164
|
| Grade | Score | Meaning |
|
package/README.zh-TW.md
CHANGED
|
@@ -155,7 +155,7 @@ npx instrlint install --claude-code --project
|
|
|
155
155
|
npx instrlint install --codex
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
安裝後**重新啟動 Claude Code** 以啟用指令,然後在編輯器中使用:
|
|
159
159
|
|
|
160
160
|
```
|
|
161
161
|
/instrlint
|
|
@@ -163,6 +163,8 @@ npx instrlint install --codex
|
|
|
163
163
|
/instrlint ci --fail-on warning
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
+
> **注意:** Claude Code 只在啟動時載入 custom commands。`/reload-plugins` 無法載入新安裝的指令。
|
|
167
|
+
|
|
166
168
|
## 分數與等級
|
|
167
169
|
|
|
168
170
|
| 等級 | 分數 | 說明 |
|
package/dist/cli.cjs
CHANGED
|
@@ -32,7 +32,8 @@ var import_commander = require("commander");
|
|
|
32
32
|
|
|
33
33
|
// src/commands/run-command.ts
|
|
34
34
|
var import_child_process = require("child_process");
|
|
35
|
-
var
|
|
35
|
+
var import_readline = require("readline");
|
|
36
|
+
var import_path10 = require("path");
|
|
36
37
|
var import_chalk4 = __toESM(require("chalk"), 1);
|
|
37
38
|
|
|
38
39
|
// src/core/scanner.ts
|
|
@@ -1592,9 +1593,13 @@ var en_default = {
|
|
|
1592
1593
|
"ci.writtenTo": "\u2192 written to {{file}}",
|
|
1593
1594
|
"initCi.created": "\u2713 Created {{path}}",
|
|
1594
1595
|
"initCi.alreadyExists": "{{path}} already exists. Use --force to overwrite.",
|
|
1595
|
-
"install.installed": "\u2713 Installed to {{path}}",
|
|
1596
|
+
"install.installed": "\u2713 Installed to {{path}}\n \u2192 Restart Claude Code to activate /instrlint",
|
|
1596
1597
|
"install.alreadyExists": "{{path}} already exists. Use --force to overwrite.",
|
|
1597
1598
|
"install.unknownTarget": "Specify --claude-code or --codex",
|
|
1599
|
+
"install.outdatedTitle": "instrlint skill is outdated",
|
|
1600
|
+
"install.outdatedVersions": "installed: {{installed}} \u2192 current: {{current}}",
|
|
1601
|
+
"install.updateCmd": "npx instrlint install {{flag}} --force",
|
|
1602
|
+
"install.updatePrompt": "Update skill now?",
|
|
1598
1603
|
"fix.manualActions": "MANUAL ACTIONS NEEDED",
|
|
1599
1604
|
"fix.hookCreate": "Add to .claude/settings.json:",
|
|
1600
1605
|
"fix.hookWarning": "\u26A0 Hook executes shell commands \u2014 review carefully before adding",
|
|
@@ -1693,9 +1698,13 @@ var zh_TW_default = {
|
|
|
1693
1698
|
"ci.writtenTo": "\u2192 \u5DF2\u5BEB\u5165 {{file}}",
|
|
1694
1699
|
"initCi.created": "\u2713 \u5DF2\u5EFA\u7ACB {{path}}",
|
|
1695
1700
|
"initCi.alreadyExists": "{{path}} \u5DF2\u5B58\u5728\u3002\u4F7F\u7528 --force \u8986\u84CB\u3002",
|
|
1696
|
-
"install.installed": "\u2713 \u5DF2\u5B89\u88DD\u81F3 {{path}}",
|
|
1701
|
+
"install.installed": "\u2713 \u5DF2\u5B89\u88DD\u81F3 {{path}}\n \u2192 \u91CD\u65B0\u555F\u52D5 Claude Code \u5F8C\u5373\u53EF\u4F7F\u7528 /instrlint",
|
|
1697
1702
|
"install.alreadyExists": "{{path}} \u5DF2\u5B58\u5728\u3002\u4F7F\u7528 --force \u8986\u84CB\u3002",
|
|
1698
1703
|
"install.unknownTarget": "\u8ACB\u6307\u5B9A --claude-code \u6216 --codex",
|
|
1704
|
+
"install.outdatedTitle": "instrlint skill \u7248\u672C\u904E\u820A",
|
|
1705
|
+
"install.outdatedVersions": "\u5DF2\u5B89\u88DD\uFF1A{{installed}} \u2192 \u6700\u65B0\uFF1A{{current}}",
|
|
1706
|
+
"install.updateCmd": "npx instrlint install {{flag}} --force",
|
|
1707
|
+
"install.updatePrompt": "\u662F\u5426\u7ACB\u5373\u66F4\u65B0\uFF1F",
|
|
1699
1708
|
"fix.manualActions": "\u9700\u8981\u624B\u52D5\u64CD\u4F5C",
|
|
1700
1709
|
"fix.hookCreate": "\u52A0\u5165 .claude/settings.json\uFF1A",
|
|
1701
1710
|
"fix.hookWarning": "\u26A0 Hook \u6703\u57F7\u884C shell command\uFF0C\u8ACB\u4ED4\u7D30\u78BA\u8A8D\u5F8C\u518D\u52A0\u5165",
|
|
@@ -2290,6 +2299,136 @@ function markdownStructureSuggestions(suggestions, projectRoot) {
|
|
|
2290
2299
|
return lines;
|
|
2291
2300
|
}
|
|
2292
2301
|
|
|
2302
|
+
// src/utils/skill-version.ts
|
|
2303
|
+
var import_fs10 = require("fs");
|
|
2304
|
+
var import_path8 = require("path");
|
|
2305
|
+
var import_os = require("os");
|
|
2306
|
+
var CURRENT_VERSION = "0.1.3";
|
|
2307
|
+
var VERSION_RE = /^instrlint-version:\s*(.+)$/m;
|
|
2308
|
+
function extractVersion(content) {
|
|
2309
|
+
const m = VERSION_RE.exec(content);
|
|
2310
|
+
return m ? m[1].trim() : null;
|
|
2311
|
+
}
|
|
2312
|
+
function readInstalledVersion(path) {
|
|
2313
|
+
if (!(0, import_fs10.existsSync)(path)) return null;
|
|
2314
|
+
try {
|
|
2315
|
+
return extractVersion((0, import_fs10.readFileSync)(path, "utf8"));
|
|
2316
|
+
} catch {
|
|
2317
|
+
return null;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
function checkSkillUpdate(projectRoot) {
|
|
2321
|
+
const candidates = [
|
|
2322
|
+
{
|
|
2323
|
+
path: (0, import_path8.join)(projectRoot, ".claude", "commands", "instrlint.md"),
|
|
2324
|
+
isProject: true
|
|
2325
|
+
},
|
|
2326
|
+
{
|
|
2327
|
+
path: (0, import_path8.join)((0, import_os.homedir)(), ".claude", "commands", "instrlint.md"),
|
|
2328
|
+
isProject: false
|
|
2329
|
+
}
|
|
2330
|
+
];
|
|
2331
|
+
for (const { path, isProject } of candidates) {
|
|
2332
|
+
const installed = readInstalledVersion(path);
|
|
2333
|
+
if (installed !== null && installed !== CURRENT_VERSION) {
|
|
2334
|
+
return {
|
|
2335
|
+
installedVersion: installed,
|
|
2336
|
+
currentVersion: CURRENT_VERSION,
|
|
2337
|
+
installPath: path,
|
|
2338
|
+
isProject
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
return null;
|
|
2343
|
+
}
|
|
2344
|
+
function injectVersion(content, version) {
|
|
2345
|
+
return content.replace(/^(---\n[\s\S]*?)(---)$/m, `$1instrlint-version: ${version}
|
|
2346
|
+
$2`);
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
// src/commands/install-command.ts
|
|
2350
|
+
var import_fs11 = require("fs");
|
|
2351
|
+
var import_path9 = require("path");
|
|
2352
|
+
var import_os2 = require("os");
|
|
2353
|
+
var import_url = require("url");
|
|
2354
|
+
function resolveSkillFile(target) {
|
|
2355
|
+
const thisFile = (0, import_url.fileURLToPath)(importMetaUrl);
|
|
2356
|
+
const subDir = target === "claude-code" ? "claude-code" : "codex";
|
|
2357
|
+
for (const levels of [2, 3]) {
|
|
2358
|
+
const parts = Array(levels).fill("..");
|
|
2359
|
+
const candidate = (0, import_path9.join)(thisFile, ...parts, "skills", subDir, "SKILL.md");
|
|
2360
|
+
if ((0, import_fs11.existsSync)(candidate)) return candidate;
|
|
2361
|
+
}
|
|
2362
|
+
return (0, import_path9.join)(thisFile, "..", "..", "skills", subDir, "SKILL.md");
|
|
2363
|
+
}
|
|
2364
|
+
function readSkillContent(target) {
|
|
2365
|
+
const skillPath = resolveSkillFile(target);
|
|
2366
|
+
try {
|
|
2367
|
+
const raw = (0, import_fs11.readFileSync)(skillPath, "utf8");
|
|
2368
|
+
return injectVersion(raw, CURRENT_VERSION);
|
|
2369
|
+
} catch {
|
|
2370
|
+
throw new Error(
|
|
2371
|
+
`Could not read skill file at ${skillPath}. Make sure the package is properly installed.`
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
function installClaudeCode(content, projectRoot, isProject, force, output) {
|
|
2376
|
+
const targetDir = isProject ? (0, import_path9.join)(projectRoot, ".claude", "commands") : (0, import_path9.join)((0, import_os2.homedir)(), ".claude", "commands");
|
|
2377
|
+
const targetPath = (0, import_path9.join)(targetDir, "instrlint.md");
|
|
2378
|
+
if ((0, import_fs11.existsSync)(targetPath) && !force) {
|
|
2379
|
+
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2380
|
+
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2381
|
+
}
|
|
2382
|
+
(0, import_fs11.mkdirSync)(targetDir, { recursive: true });
|
|
2383
|
+
(0, import_fs11.writeFileSync)(targetPath, content, "utf8");
|
|
2384
|
+
output.log(t("install.installed", { path: targetPath }));
|
|
2385
|
+
return { exitCode: 0 };
|
|
2386
|
+
}
|
|
2387
|
+
function installCodex(content, projectRoot, force, output) {
|
|
2388
|
+
const targetDir = (0, import_path9.join)(projectRoot, ".agents", "skills", "instrlint");
|
|
2389
|
+
const targetPath = (0, import_path9.join)(targetDir, "SKILL.md");
|
|
2390
|
+
if ((0, import_fs11.existsSync)(targetPath) && !force) {
|
|
2391
|
+
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2392
|
+
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2393
|
+
}
|
|
2394
|
+
(0, import_fs11.mkdirSync)(targetDir, { recursive: true });
|
|
2395
|
+
(0, import_fs11.writeFileSync)(targetPath, content, "utf8");
|
|
2396
|
+
output.log(t("install.installed", { path: targetPath }));
|
|
2397
|
+
return { exitCode: 0 };
|
|
2398
|
+
}
|
|
2399
|
+
function runInstall(opts, output = console) {
|
|
2400
|
+
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
2401
|
+
const force = opts.force ?? false;
|
|
2402
|
+
if (opts.claudeCode) {
|
|
2403
|
+
let content;
|
|
2404
|
+
try {
|
|
2405
|
+
content = readSkillContent("claude-code");
|
|
2406
|
+
} catch (err) {
|
|
2407
|
+
output.error(String(err));
|
|
2408
|
+
return { exitCode: 1, errorMessage: String(err) };
|
|
2409
|
+
}
|
|
2410
|
+
return installClaudeCode(
|
|
2411
|
+
content,
|
|
2412
|
+
projectRoot,
|
|
2413
|
+
opts.project ?? false,
|
|
2414
|
+
force,
|
|
2415
|
+
output
|
|
2416
|
+
);
|
|
2417
|
+
}
|
|
2418
|
+
if (opts.codex) {
|
|
2419
|
+
let content;
|
|
2420
|
+
try {
|
|
2421
|
+
content = readSkillContent("codex");
|
|
2422
|
+
} catch (err) {
|
|
2423
|
+
output.error(String(err));
|
|
2424
|
+
return { exitCode: 1, errorMessage: String(err) };
|
|
2425
|
+
}
|
|
2426
|
+
return installCodex(content, projectRoot, force, output);
|
|
2427
|
+
}
|
|
2428
|
+
output.error(t("install.unknownTarget"));
|
|
2429
|
+
return { exitCode: 1, errorMessage: "no target specified" };
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2293
2432
|
// src/commands/run-command.ts
|
|
2294
2433
|
function isGitClean(cwd) {
|
|
2295
2434
|
try {
|
|
@@ -2334,7 +2473,7 @@ async function runAll(opts, output = console) {
|
|
|
2334
2473
|
const { score, grade } = calculateScore(allFindings, summary);
|
|
2335
2474
|
const actionPlan = buildActionPlan(allFindings);
|
|
2336
2475
|
const report = {
|
|
2337
|
-
project: (0,
|
|
2476
|
+
project: (0, import_path10.basename)(projectRoot),
|
|
2338
2477
|
tool: instructions.tool,
|
|
2339
2478
|
score,
|
|
2340
2479
|
grade,
|
|
@@ -2379,6 +2518,7 @@ async function runAll(opts, output = console) {
|
|
|
2379
2518
|
printStructureSuggestions(suggestions, projectRoot, output);
|
|
2380
2519
|
return { exitCode: 0 };
|
|
2381
2520
|
}
|
|
2521
|
+
const skillUpdate = checkSkillUpdate(projectRoot);
|
|
2382
2522
|
if (opts.format === "json") {
|
|
2383
2523
|
output.log(reportJson(report));
|
|
2384
2524
|
return { exitCode: 0 };
|
|
@@ -2386,12 +2526,52 @@ async function runAll(opts, output = console) {
|
|
|
2386
2526
|
if (opts.format === "markdown") {
|
|
2387
2527
|
const mdSuggestions = buildStructureSuggestions(allFindings);
|
|
2388
2528
|
const mdExtra = markdownStructureSuggestions(mdSuggestions, projectRoot);
|
|
2389
|
-
|
|
2529
|
+
const updateSection = skillUpdate ? [
|
|
2530
|
+
"",
|
|
2531
|
+
`> \u26A0\uFE0F **${t("install.outdatedTitle")}** (${t("install.outdatedVersions", { installed: skillUpdate.installedVersion, current: skillUpdate.currentVersion })})`,
|
|
2532
|
+
`> \`${t("install.updateCmd", { flag: skillUpdate.isProject ? "--claude-code --project" : "--claude-code" })}\``
|
|
2533
|
+
] : [];
|
|
2534
|
+
output.log(reportMarkdown(report, [...mdExtra, ...updateSection]));
|
|
2390
2535
|
return { exitCode: 0 };
|
|
2391
2536
|
}
|
|
2392
2537
|
printCombinedTerminal(report, output);
|
|
2538
|
+
if (skillUpdate && process.stdout.isTTY) {
|
|
2539
|
+
output.log("");
|
|
2540
|
+
output.log(
|
|
2541
|
+
` ${import_chalk4.default.yellow("\u26A0")} ${import_chalk4.default.bold(t("install.outdatedTitle"))} (${t("install.outdatedVersions", { installed: skillUpdate.installedVersion, current: skillUpdate.currentVersion })})`
|
|
2542
|
+
);
|
|
2543
|
+
const confirmed = await promptYesNo(
|
|
2544
|
+
` ${t("install.updatePrompt")}`,
|
|
2545
|
+
output
|
|
2546
|
+
);
|
|
2547
|
+
if (confirmed) {
|
|
2548
|
+
runInstall(
|
|
2549
|
+
{
|
|
2550
|
+
claudeCode: true,
|
|
2551
|
+
project: skillUpdate.isProject,
|
|
2552
|
+
force: true,
|
|
2553
|
+
projectRoot
|
|
2554
|
+
},
|
|
2555
|
+
output
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
output.log("");
|
|
2559
|
+
}
|
|
2393
2560
|
return { exitCode: 0 };
|
|
2394
2561
|
}
|
|
2562
|
+
function promptYesNo(question, output) {
|
|
2563
|
+
return new Promise((resolve) => {
|
|
2564
|
+
const rl = (0, import_readline.createInterface)({
|
|
2565
|
+
input: process.stdin,
|
|
2566
|
+
output: process.stdout
|
|
2567
|
+
});
|
|
2568
|
+
rl.question(`${question} ${import_chalk4.default.gray("[Y/n]")} `, (answer) => {
|
|
2569
|
+
rl.close();
|
|
2570
|
+
const trimmed = answer.trim().toLowerCase();
|
|
2571
|
+
resolve(trimmed === "" || trimmed === "y");
|
|
2572
|
+
});
|
|
2573
|
+
});
|
|
2574
|
+
}
|
|
2395
2575
|
|
|
2396
2576
|
// src/commands/deadrules-command.ts
|
|
2397
2577
|
var import_chalk5 = __toESM(require("chalk"), 1);
|
|
@@ -2552,8 +2732,8 @@ async function runStructure(opts, output = console) {
|
|
|
2552
2732
|
}
|
|
2553
2733
|
|
|
2554
2734
|
// src/commands/ci-command.ts
|
|
2555
|
-
var
|
|
2556
|
-
var
|
|
2735
|
+
var import_fs12 = require("fs");
|
|
2736
|
+
var import_path11 = require("path");
|
|
2557
2737
|
|
|
2558
2738
|
// src/reporters/sarif.ts
|
|
2559
2739
|
function severityToLevel(severity) {
|
|
@@ -2659,7 +2839,7 @@ async function runCi(opts, output = console) {
|
|
|
2659
2839
|
const { score, grade } = calculateScore(allFindings, summary);
|
|
2660
2840
|
const actionPlan = buildActionPlan(allFindings);
|
|
2661
2841
|
const report = {
|
|
2662
|
-
project: (0,
|
|
2842
|
+
project: (0, import_path11.basename)(projectRoot),
|
|
2663
2843
|
tool: instructions.tool,
|
|
2664
2844
|
score,
|
|
2665
2845
|
grade,
|
|
@@ -2680,7 +2860,7 @@ async function runCi(opts, output = console) {
|
|
|
2680
2860
|
formatted = reportJson(report);
|
|
2681
2861
|
}
|
|
2682
2862
|
if (opts.output != null) {
|
|
2683
|
-
(0,
|
|
2863
|
+
(0, import_fs12.writeFileSync)(opts.output, formatted, "utf8");
|
|
2684
2864
|
const pass = !shouldFail(allFindings, failOn);
|
|
2685
2865
|
const statusKey = pass ? "ci.passed" : "ci.failed";
|
|
2686
2866
|
output.error(
|
|
@@ -2694,8 +2874,8 @@ async function runCi(opts, output = console) {
|
|
|
2694
2874
|
}
|
|
2695
2875
|
|
|
2696
2876
|
// src/commands/init-ci-command.ts
|
|
2697
|
-
var
|
|
2698
|
-
var
|
|
2877
|
+
var import_fs13 = require("fs");
|
|
2878
|
+
var import_path12 = require("path");
|
|
2699
2879
|
function githubWorkflow() {
|
|
2700
2880
|
return `name: instrlint
|
|
2701
2881
|
|
|
@@ -2764,14 +2944,14 @@ instrlint:
|
|
|
2764
2944
|
function runInitCi(opts, output = console) {
|
|
2765
2945
|
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
2766
2946
|
if (opts.github) {
|
|
2767
|
-
const workflowDir = (0,
|
|
2768
|
-
const workflowPath = (0,
|
|
2769
|
-
if ((0,
|
|
2947
|
+
const workflowDir = (0, import_path12.join)(projectRoot, ".github", "workflows");
|
|
2948
|
+
const workflowPath = (0, import_path12.join)(workflowDir, "instrlint.yml");
|
|
2949
|
+
if ((0, import_fs13.existsSync)(workflowPath) && !opts.force) {
|
|
2770
2950
|
output.error(t("initCi.alreadyExists", { path: workflowPath }));
|
|
2771
2951
|
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2772
2952
|
}
|
|
2773
|
-
(0,
|
|
2774
|
-
(0,
|
|
2953
|
+
(0, import_fs13.mkdirSync)(workflowDir, { recursive: true });
|
|
2954
|
+
(0, import_fs13.writeFileSync)(workflowPath, githubWorkflow(), "utf8");
|
|
2775
2955
|
output.log(t("initCi.created", { path: workflowPath }));
|
|
2776
2956
|
return { exitCode: 0 };
|
|
2777
2957
|
}
|
|
@@ -2783,88 +2963,6 @@ function runInitCi(opts, output = console) {
|
|
|
2783
2963
|
return { exitCode: 1, errorMessage: "no target specified" };
|
|
2784
2964
|
}
|
|
2785
2965
|
|
|
2786
|
-
// src/commands/install-command.ts
|
|
2787
|
-
var import_fs12 = require("fs");
|
|
2788
|
-
var import_path11 = require("path");
|
|
2789
|
-
var import_os = require("os");
|
|
2790
|
-
var import_url = require("url");
|
|
2791
|
-
function resolveSkillFile(target) {
|
|
2792
|
-
const thisFile = (0, import_url.fileURLToPath)(importMetaUrl);
|
|
2793
|
-
const subDir = target === "claude-code" ? "claude-code" : "codex";
|
|
2794
|
-
for (const levels of [2, 3]) {
|
|
2795
|
-
const parts = Array(levels).fill("..");
|
|
2796
|
-
const candidate = (0, import_path11.join)(thisFile, ...parts, "skills", subDir, "SKILL.md");
|
|
2797
|
-
if ((0, import_fs12.existsSync)(candidate)) return candidate;
|
|
2798
|
-
}
|
|
2799
|
-
return (0, import_path11.join)(thisFile, "..", "..", "skills", subDir, "SKILL.md");
|
|
2800
|
-
}
|
|
2801
|
-
function readSkillContent(target) {
|
|
2802
|
-
const skillPath = resolveSkillFile(target);
|
|
2803
|
-
try {
|
|
2804
|
-
return (0, import_fs12.readFileSync)(skillPath, "utf8");
|
|
2805
|
-
} catch {
|
|
2806
|
-
throw new Error(
|
|
2807
|
-
`Could not read skill file at ${skillPath}. Make sure the package is properly installed.`
|
|
2808
|
-
);
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
function installClaudeCode(content, projectRoot, isProject, force, output) {
|
|
2812
|
-
const targetDir = isProject ? (0, import_path11.join)(projectRoot, ".claude", "skills", "instrlint") : (0, import_path11.join)((0, import_os.homedir)(), ".claude", "skills", "instrlint");
|
|
2813
|
-
const targetPath = (0, import_path11.join)(targetDir, "SKILL.md");
|
|
2814
|
-
if ((0, import_fs12.existsSync)(targetPath) && !force) {
|
|
2815
|
-
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2816
|
-
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2817
|
-
}
|
|
2818
|
-
(0, import_fs12.mkdirSync)(targetDir, { recursive: true });
|
|
2819
|
-
(0, import_fs12.writeFileSync)(targetPath, content, "utf8");
|
|
2820
|
-
output.log(t("install.installed", { path: targetPath }));
|
|
2821
|
-
return { exitCode: 0 };
|
|
2822
|
-
}
|
|
2823
|
-
function installCodex(content, projectRoot, force, output) {
|
|
2824
|
-
const targetDir = (0, import_path11.join)(projectRoot, ".agents", "skills", "instrlint");
|
|
2825
|
-
const targetPath = (0, import_path11.join)(targetDir, "SKILL.md");
|
|
2826
|
-
if ((0, import_fs12.existsSync)(targetPath) && !force) {
|
|
2827
|
-
output.error(t("install.alreadyExists", { path: targetPath }));
|
|
2828
|
-
return { exitCode: 1, errorMessage: "file already exists" };
|
|
2829
|
-
}
|
|
2830
|
-
(0, import_fs12.mkdirSync)(targetDir, { recursive: true });
|
|
2831
|
-
(0, import_fs12.writeFileSync)(targetPath, content, "utf8");
|
|
2832
|
-
output.log(t("install.installed", { path: targetPath }));
|
|
2833
|
-
return { exitCode: 0 };
|
|
2834
|
-
}
|
|
2835
|
-
function runInstall(opts, output = console) {
|
|
2836
|
-
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
2837
|
-
const force = opts.force ?? false;
|
|
2838
|
-
if (opts.claudeCode) {
|
|
2839
|
-
let content;
|
|
2840
|
-
try {
|
|
2841
|
-
content = readSkillContent("claude-code");
|
|
2842
|
-
} catch (err) {
|
|
2843
|
-
output.error(String(err));
|
|
2844
|
-
return { exitCode: 1, errorMessage: String(err) };
|
|
2845
|
-
}
|
|
2846
|
-
return installClaudeCode(
|
|
2847
|
-
content,
|
|
2848
|
-
projectRoot,
|
|
2849
|
-
opts.project ?? false,
|
|
2850
|
-
force,
|
|
2851
|
-
output
|
|
2852
|
-
);
|
|
2853
|
-
}
|
|
2854
|
-
if (opts.codex) {
|
|
2855
|
-
let content;
|
|
2856
|
-
try {
|
|
2857
|
-
content = readSkillContent("codex");
|
|
2858
|
-
} catch (err) {
|
|
2859
|
-
output.error(String(err));
|
|
2860
|
-
return { exitCode: 1, errorMessage: String(err) };
|
|
2861
|
-
}
|
|
2862
|
-
return installCodex(content, projectRoot, force, output);
|
|
2863
|
-
}
|
|
2864
|
-
output.error(t("install.unknownTarget"));
|
|
2865
|
-
return { exitCode: 1, errorMessage: "no target specified" };
|
|
2866
|
-
}
|
|
2867
|
-
|
|
2868
2966
|
// src/cli.ts
|
|
2869
2967
|
var program = new import_commander.Command();
|
|
2870
2968
|
program.enablePositionalOptions().name("instrlint").description(
|
|
@@ -2882,27 +2980,27 @@ program.command("budget").description("Token budget analysis only").option(
|
|
|
2882
2980
|
"--format <type>",
|
|
2883
2981
|
"output format (terminal|json|markdown)",
|
|
2884
2982
|
"terminal"
|
|
2885
|
-
).option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2983
|
+
).option("--lang <locale>", "output language (en|zh-TW)").option("--tool <name>", "force tool detection (claude-code|codex|cursor)").action(async function() {
|
|
2886
2984
|
const opts = this.opts();
|
|
2887
|
-
const lang = this.parent?.opts()?.lang;
|
|
2985
|
+
const lang = opts.lang ?? this.parent?.opts()?.lang;
|
|
2888
2986
|
const result = await runBudget({
|
|
2889
2987
|
...opts,
|
|
2890
2988
|
...lang !== void 0 && { lang }
|
|
2891
2989
|
});
|
|
2892
2990
|
if (result.exitCode !== 0) process.exit(result.exitCode);
|
|
2893
2991
|
});
|
|
2894
|
-
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() {
|
|
2992
|
+
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() {
|
|
2895
2993
|
const opts = this.opts();
|
|
2896
|
-
const lang = this.parent?.opts()?.lang;
|
|
2994
|
+
const lang = opts.lang ?? this.parent?.opts()?.lang;
|
|
2897
2995
|
const result = await runDeadRules({
|
|
2898
2996
|
...opts,
|
|
2899
2997
|
...lang !== void 0 && { lang }
|
|
2900
2998
|
});
|
|
2901
2999
|
if (result.exitCode !== 0) process.exit(result.exitCode);
|
|
2902
3000
|
});
|
|
2903
|
-
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() {
|
|
3001
|
+
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() {
|
|
2904
3002
|
const opts = this.opts();
|
|
2905
|
-
const lang = this.parent?.opts()?.lang;
|
|
3003
|
+
const lang = opts.lang ?? this.parent?.opts()?.lang;
|
|
2906
3004
|
const result = await runStructure({
|
|
2907
3005
|
...opts,
|
|
2908
3006
|
...lang !== void 0 && { lang }
|