@docker-doctor/cli 0.4.2 → 0.4.4
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 +7 -0
- package/dist/cli.cjs +21 -13
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +21 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +12 -5
- package/dist/index.d.mts +12 -5
- package/dist/index.mjs +1 -1
- package/dist/{src-BuUGk4ND.mjs → src-CvOv-hL3.mjs} +280 -167
- package/dist/src-CvOv-hL3.mjs.map +1 -0
- package/dist/{src-909bBBPN.cjs → src-DwuAaQcq.cjs} +284 -165
- package/dist/src-DwuAaQcq.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/src-909bBBPN.cjs.map +0 -1
- package/dist/src-BuUGk4ND.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -73,6 +73,13 @@ npx @docker-doctor/cli@latest install
|
|
|
73
73
|
|
|
74
74
|
Works with Claude Code, Cursor, Codex, OpenCode, and many more. After an interactive scan finds issues, Docker Doctor also offers to hand them straight to an agent detected on your machine. Add `--global` to install the skill once for your whole machine instead of the current project.
|
|
75
75
|
|
|
76
|
+
Prefer plugins? This repository is also a Claude Code plugin marketplace and ships a Cursor plugin — both bundle all three skills (`docker-doctor`, `docker-author`, `improve-docker`) and update with the repo:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
/plugin marketplace add PunGrumpy/docker-doctor
|
|
80
|
+
/plugin install docker-doctor@docker-doctor
|
|
81
|
+
```
|
|
82
|
+
|
|
76
83
|
[Rules reference →](https://docker-doctor.vercel.app/docs/reference/rules)
|
|
77
84
|
|
|
78
85
|
### 3. Run in Docker Sandboxes
|
package/dist/cli.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_src = require('./src-
|
|
2
|
+
const require_src = require('./src-DwuAaQcq.cjs');
|
|
3
3
|
let node_fs_promises = require("node:fs/promises");
|
|
4
4
|
node_fs_promises = require_src.__toESM(node_fs_promises, 1);
|
|
5
5
|
let node_path = require("node:path");
|
|
@@ -545,6 +545,18 @@ const tryCommands = async (commands, text) => {
|
|
|
545
545
|
};
|
|
546
546
|
const copyToClipboard = (text) => tryCommands(getClipboardCommands(), text);
|
|
547
547
|
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/agents/sanitize.ts
|
|
550
|
+
const CONTROL_CHARS_RE = /[\u0000-\u001F\u007F]+/gu;
|
|
551
|
+
const MAX_MESSAGE_LENGTH = 300;
|
|
552
|
+
const MAX_PATH_LENGTH = 200;
|
|
553
|
+
const flatten = (value, maxLength) => {
|
|
554
|
+
const flat = value.replaceAll(CONTROL_CHARS_RE, " ").trim();
|
|
555
|
+
return flat.length > maxLength ? `${flat.slice(0, maxLength)}…` : flat;
|
|
556
|
+
};
|
|
557
|
+
const sanitizeMessage = (message) => flatten(message, MAX_MESSAGE_LENGTH);
|
|
558
|
+
const sanitizePath = (filePath) => flatten(filePath, MAX_PATH_LENGTH);
|
|
559
|
+
|
|
548
560
|
//#endregion
|
|
549
561
|
//#region src/agents/diagnostics-dir.ts
|
|
550
562
|
const DIAGNOSTICS_DIR_NAME = ".docker-doctor";
|
|
@@ -579,10 +591,10 @@ const writeDiagnosticsDirectory = async (diagnostics, report, rootDir) => {
|
|
|
579
591
|
const lines = [
|
|
580
592
|
TRUST_BOUNDARY_NOTE,
|
|
581
593
|
`${rule} (${first.severity})`,
|
|
582
|
-
first.message,
|
|
594
|
+
sanitizeMessage(first.message),
|
|
583
595
|
`Fix: ${first.help}`,
|
|
584
596
|
"",
|
|
585
|
-
...ruleDiagnostics.map((d) => `${d.file}${d.line === void 0 ? "" : `:${d.line}`}`),
|
|
597
|
+
...ruleDiagnostics.map((d) => `${sanitizePath(d.file)}${d.line === void 0 ? "" : `:${d.line}`}`),
|
|
586
598
|
""
|
|
587
599
|
];
|
|
588
600
|
writes.push(node_fs_promises.default.writeFile(node_path.default.join(dir, ruleFileName(rule)), lines.join("\n"), "utf-8"));
|
|
@@ -629,12 +641,6 @@ const SEVERITY_LABEL = {
|
|
|
629
641
|
info: "INFO",
|
|
630
642
|
warning: "WARN"
|
|
631
643
|
};
|
|
632
|
-
const MAX_MESSAGE_LENGTH = 300;
|
|
633
|
-
const CONTROL_CHARS_RE = /[\u0000-\u001F\u007F]+/gu;
|
|
634
|
-
const sanitizeMessage = (message) => {
|
|
635
|
-
const flat = message.replaceAll(CONTROL_CHARS_RE, " ").trim();
|
|
636
|
-
return flat.length > MAX_MESSAGE_LENGTH ? `${flat.slice(0, MAX_MESSAGE_LENGTH)}…` : flat;
|
|
637
|
-
};
|
|
638
644
|
const buildHandoffPayload = (input) => {
|
|
639
645
|
const groups = [...groupDiagnosticsByRule(input.diagnostics).entries()].toSorted(([, a], [, b]) => {
|
|
640
646
|
const rankDelta = SEVERITY_RANK[a[0].severity] - SEVERITY_RANK[b[0].severity];
|
|
@@ -644,7 +650,7 @@ const buildHandoffPayload = (input) => {
|
|
|
644
650
|
const issueWord = issueCount === 1 ? "issue" : "issues";
|
|
645
651
|
const ruleWord = groups.length === 1 ? "rule" : "rules";
|
|
646
652
|
const lines = [
|
|
647
|
-
`Fix the ${issueCount} Docker Doctor ${issueWord} (${groups.length} ${ruleWord}) in ${input.projectName}.`,
|
|
653
|
+
`Fix the ${issueCount} Docker Doctor ${issueWord} (${groups.length} ${ruleWord}) in ${sanitizePath(input.projectName)}.`,
|
|
648
654
|
TRUST_BOUNDARY_NOTE,
|
|
649
655
|
""
|
|
650
656
|
];
|
|
@@ -656,7 +662,7 @@ const buildHandoffPayload = (input) => {
|
|
|
656
662
|
const files = [...new Set(ruleDiagnostics.map((d) => d.file))];
|
|
657
663
|
for (const file of files.slice(0, MAX_FILES_PER_RULE)) {
|
|
658
664
|
const firstSite = ruleDiagnostics.find((d) => d.file === file && d.line !== void 0);
|
|
659
|
-
lines.push(` - ${file}${firstSite ? `:${firstSite.line}` : ""}`);
|
|
665
|
+
lines.push(` - ${sanitizePath(file)}${firstSite ? `:${firstSite.line}` : ""}`);
|
|
660
666
|
}
|
|
661
667
|
const remaining = files.length - MAX_FILES_PER_RULE;
|
|
662
668
|
if (remaining > 0) lines.push(` - +${remaining} more files`);
|
|
@@ -1217,7 +1223,7 @@ const runRulesEngine = async (rootDir, project, rulesConfig, categoriesConfig, p
|
|
|
1217
1223
|
const content = await node_fs_promises.default.readFile(fullPath, "utf-8");
|
|
1218
1224
|
fileContents[cf] = content;
|
|
1219
1225
|
const composeObj = require_src.parseCompose(content, cf);
|
|
1220
|
-
return require_src.runComposeRules(composeObj, cf, rulesConfig, categoriesConfig);
|
|
1226
|
+
return require_src.runComposeRules(composeObj, cf, rulesConfig, categoriesConfig, require_src.createComposeLocator(content));
|
|
1221
1227
|
} catch (error) {
|
|
1222
1228
|
const msg = error instanceof Error ? error.message : String(error);
|
|
1223
1229
|
console.error(`Failed to analyze Compose file ${cf}: ${msg}`);
|
|
@@ -1295,7 +1301,9 @@ program.argument("[dir]", "directory to scan", ".").option("-v, --verbose", "sho
|
|
|
1295
1301
|
try {
|
|
1296
1302
|
if (process.stdout.isTTY && !isSilent) await (0, node_timers_promises.setTimeout)(150);
|
|
1297
1303
|
setStatus("Loading configuration...");
|
|
1298
|
-
const config = await require_src.loadConfig(rootDir, options.config)
|
|
1304
|
+
const config = await require_src.loadConfig(rootDir, options.config, (message) => {
|
|
1305
|
+
console.error(`Warning: ${message}`);
|
|
1306
|
+
});
|
|
1299
1307
|
setStatus("Scanning workspace files...");
|
|
1300
1308
|
const project = await require_src.discoverProject(rootDir);
|
|
1301
1309
|
const fileContents = {};
|