@bovinphang/craft-common 0.0.0-stage → 1.0.0
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/LICENSE +21 -0
- package/README.md +12 -2
- package/dist/content/catalog.d.ts +4 -0
- package/dist/content/resources.d.ts +2 -0
- package/dist/content/types.d.ts +21 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +668 -0
- package/dist/install/identity.d.ts +5 -0
- package/dist/install/planner.d.ts +6 -0
- package/dist/install/transaction.d.ts +7 -0
- package/dist/install/types.d.ts +44 -0
- package/docs/consuming-common.md +33 -0
- package/localized/zh-CN/methods/debug.md +13 -0
- package/localized/zh-CN/methods/doc-sync.md +12 -0
- package/localized/zh-CN/methods/refactoring.md +16 -0
- package/localized/zh-CN/methods/source-driven-development.md +19 -0
- package/localized/zh-CN/methods/tdd.md +13 -0
- package/localized/zh-CN/skills/cc-debug-methodology/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-debug-methodology/references/method.md +13 -0
- package/localized/zh-CN/skills/cc-doc-sync-core/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-doc-sync-core/references/method.md +12 -0
- package/localized/zh-CN/skills/cc-drawio-studio/SKILL.md +73 -0
- package/localized/zh-CN/skills/cc-drawio-studio/data/THIRD_PARTY_NOTICES.md +10 -0
- package/localized/zh-CN/skills/cc-drawio-studio/data/brand-icons.json +878 -0
- package/localized/zh-CN/skills/cc-drawio-studio/data/shape-index.json +83570 -0
- package/localized/zh-CN/skills/cc-drawio-studio/references/data-residency.md +27 -0
- package/localized/zh-CN/skills/cc-drawio-studio/references/diagram-patterns.md +60 -0
- package/localized/zh-CN/skills/cc-drawio-studio/references/flowchart-quality.md +49 -0
- package/localized/zh-CN/skills/cc-drawio-studio/references/layout-and-export.md +72 -0
- package/localized/zh-CN/skills/cc-drawio-studio/references/troubleshooting.md +29 -0
- package/localized/zh-CN/skills/cc-drawio-studio/references/xml-and-mermaid.md +58 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/brand-symbols.mjs +99 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/diagram-lint.mjs +205 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/diagram-url.mjs +102 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/drawio-export.mjs +134 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/layout-graph.mjs +107 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/png-embed-fix.mjs +26 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/scan-go-packages.mjs +36 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/scan-js-modules.mjs +52 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/scan-python-classes.mjs +30 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/scan-python-modules.mjs +55 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/scan-rust-modules.mjs +35 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/scan-ts-modules.mjs +7 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/shape-query.mjs +121 -0
- package/localized/zh-CN/skills/cc-drawio-studio/scripts/studio-core.mjs +139 -0
- package/localized/zh-CN/skills/cc-drawio-studio/styles/built-in/corporate.json +49 -0
- package/localized/zh-CN/skills/cc-drawio-studio/styles/built-in/default.json +49 -0
- package/localized/zh-CN/skills/cc-drawio-studio/styles/built-in/handdrawn.json +49 -0
- package/localized/zh-CN/skills/cc-drawio-studio/styles/schema.json +112 -0
- package/localized/zh-CN/skills/cc-refactoring-core/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-refactoring-core/references/method.md +16 -0
- package/localized/zh-CN/skills/cc-source-driven-development/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-source-driven-development/references/method.md +19 -0
- package/localized/zh-CN/skills/cc-tdd-methodology/SKILL.md +8 -0
- package/localized/zh-CN/skills/cc-tdd-methodology/references/method.md +13 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/SKILL.md +34 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/interactive-diagram.html +371 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/README.md +14 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/architecture.json +121 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/invalid-explicit.json +41 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/sequence.json +53 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/sequence.mmd +21 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/workflow.json +98 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/assets/quality-examples/workflow.mmd +7 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/references/diagram-workflows.md +81 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/references/html-technical-diagrams.md +243 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/references/png-qa-autofix.md +37 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/diagram-browser.mjs +153 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/diagram-layout.mjs +176 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/export-diagram.mjs +332 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/interactive-diagram-server.mjs +654 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/mermaid-render.mjs +64 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/png-qa.mjs +462 -0
- package/localized/zh-CN/skills/cc-technical-diagrams/scripts/tech-diagram-render.mjs +1537 -0
- package/localized/zh-CN/skills/eval_queries.json +160 -0
- package/localized/zh-CN/skills/metadata.json +223 -0
- package/localized/zh-CN/skills/relations.json +53 -0
- package/methods/debug.md +13 -0
- package/methods/doc-sync.md +12 -0
- package/methods/refactoring.md +16 -0
- package/methods/source-driven-development.md +19 -0
- package/methods/tdd.md +13 -0
- package/package.json +51 -4
- package/skills/cc-debug-methodology/SKILL.md +8 -0
- package/skills/cc-debug-methodology/references/method.md +13 -0
- package/skills/cc-doc-sync-core/SKILL.md +8 -0
- package/skills/cc-doc-sync-core/references/method.md +12 -0
- package/skills/cc-drawio-studio/SKILL.md +73 -0
- package/skills/cc-drawio-studio/data/THIRD_PARTY_NOTICES.md +10 -0
- package/skills/cc-drawio-studio/data/brand-icons.json +878 -0
- package/skills/cc-drawio-studio/data/shape-index.json +83570 -0
- package/skills/cc-drawio-studio/references/data-residency.md +27 -0
- package/skills/cc-drawio-studio/references/diagram-patterns.md +60 -0
- package/skills/cc-drawio-studio/references/flowchart-quality.md +49 -0
- package/skills/cc-drawio-studio/references/layout-and-export.md +72 -0
- package/skills/cc-drawio-studio/references/troubleshooting.md +29 -0
- package/skills/cc-drawio-studio/references/xml-and-mermaid.md +58 -0
- package/skills/cc-drawio-studio/scripts/brand-symbols.mjs +99 -0
- package/skills/cc-drawio-studio/scripts/diagram-lint.mjs +205 -0
- package/skills/cc-drawio-studio/scripts/diagram-url.mjs +102 -0
- package/skills/cc-drawio-studio/scripts/drawio-export.mjs +134 -0
- package/skills/cc-drawio-studio/scripts/layout-graph.mjs +107 -0
- package/skills/cc-drawio-studio/scripts/png-embed-fix.mjs +26 -0
- package/skills/cc-drawio-studio/scripts/scan-go-packages.mjs +36 -0
- package/skills/cc-drawio-studio/scripts/scan-js-modules.mjs +52 -0
- package/skills/cc-drawio-studio/scripts/scan-python-classes.mjs +30 -0
- package/skills/cc-drawio-studio/scripts/scan-python-modules.mjs +55 -0
- package/skills/cc-drawio-studio/scripts/scan-rust-modules.mjs +35 -0
- package/skills/cc-drawio-studio/scripts/scan-ts-modules.mjs +7 -0
- package/skills/cc-drawio-studio/scripts/shape-query.mjs +121 -0
- package/skills/cc-drawio-studio/scripts/studio-core.mjs +139 -0
- package/skills/cc-drawio-studio/styles/built-in/corporate.json +49 -0
- package/skills/cc-drawio-studio/styles/built-in/default.json +49 -0
- package/skills/cc-drawio-studio/styles/built-in/handdrawn.json +49 -0
- package/skills/cc-drawio-studio/styles/schema.json +112 -0
- package/skills/cc-refactoring-core/SKILL.md +8 -0
- package/skills/cc-refactoring-core/references/method.md +16 -0
- package/skills/cc-source-driven-development/SKILL.md +8 -0
- package/skills/cc-source-driven-development/references/method.md +19 -0
- package/skills/cc-tdd-methodology/SKILL.md +8 -0
- package/skills/cc-tdd-methodology/references/method.md +13 -0
- package/skills/cc-technical-diagrams/SKILL.md +34 -0
- package/skills/cc-technical-diagrams/assets/interactive-diagram.html +371 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/README.md +14 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/architecture.json +121 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/invalid-explicit.json +41 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/sequence.json +53 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/sequence.mmd +21 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/workflow.json +98 -0
- package/skills/cc-technical-diagrams/assets/quality-examples/workflow.mmd +7 -0
- package/skills/cc-technical-diagrams/references/diagram-workflows.md +81 -0
- package/skills/cc-technical-diagrams/references/html-technical-diagrams.md +243 -0
- package/skills/cc-technical-diagrams/references/png-qa-autofix.md +37 -0
- package/skills/cc-technical-diagrams/scripts/diagram-browser.mjs +153 -0
- package/skills/cc-technical-diagrams/scripts/diagram-layout.mjs +176 -0
- package/skills/cc-technical-diagrams/scripts/export-diagram.mjs +332 -0
- package/skills/cc-technical-diagrams/scripts/interactive-diagram-server.mjs +654 -0
- package/skills/cc-technical-diagrams/scripts/mermaid-render.mjs +64 -0
- package/skills/cc-technical-diagrams/scripts/png-qa.mjs +462 -0
- package/skills/cc-technical-diagrams/scripts/tech-diagram-render.mjs +1537 -0
- package/skills/eval_queries.json +160 -0
- package/skills/metadata.json +223 -0
- package/skills/relations.json +53 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { formatResult, parseArgs, skillDir } from "./studio-core.mjs";
|
|
5
|
+
|
|
6
|
+
const INDEX = path.join(skillDir, "data", "shape-index.json");
|
|
7
|
+
const ALIASES = new Map([
|
|
8
|
+
["亚马逊", "aws"],
|
|
9
|
+
["阿里云", "alibaba cloud"],
|
|
10
|
+
["微软云", "azure"],
|
|
11
|
+
["谷歌云", "gcp"],
|
|
12
|
+
["云", "cloud"],
|
|
13
|
+
["数据库", "database"],
|
|
14
|
+
["队列", "queue"],
|
|
15
|
+
["网关", "gateway"],
|
|
16
|
+
["服务", "service"],
|
|
17
|
+
["用户", "user"],
|
|
18
|
+
["角色", "actor"],
|
|
19
|
+
["流程", "flowchart"],
|
|
20
|
+
["容器", "container"],
|
|
21
|
+
["网络", "network"],
|
|
22
|
+
["交换机", "switch"],
|
|
23
|
+
["路由器", "router"],
|
|
24
|
+
["函数", "lambda"],
|
|
25
|
+
["对象存储", "storage"],
|
|
26
|
+
["消息", "message"],
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
export function loadShapes() {
|
|
30
|
+
return JSON.parse(fs.readFileSync(INDEX).toString("utf8"));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function queryShapes(shapes, query, options = {}) {
|
|
34
|
+
const terms = expandTerms(query);
|
|
35
|
+
const category = options.category
|
|
36
|
+
? String(options.category).toLowerCase()
|
|
37
|
+
: "";
|
|
38
|
+
const scored = [];
|
|
39
|
+
for (const [index, shape] of shapes.entries()) {
|
|
40
|
+
const haystack =
|
|
41
|
+
`${shape.title ?? ""} ${shape.tags ?? ""} ${shape.style ?? ""}`.toLowerCase();
|
|
42
|
+
if (category && !haystack.includes(category)) continue;
|
|
43
|
+
let score = 0;
|
|
44
|
+
const title = String(shape.title ?? "").toLowerCase();
|
|
45
|
+
const tags = String(shape.tags ?? "").toLowerCase();
|
|
46
|
+
for (const term of terms) {
|
|
47
|
+
if (title === term) score += 80;
|
|
48
|
+
else if (title.includes(term)) score += 45;
|
|
49
|
+
if (tags.split(/\s+/).includes(term)) score += 30;
|
|
50
|
+
else if (tags.includes(term)) score += 12;
|
|
51
|
+
if (fuzzyContains(haystack, term)) score += 4;
|
|
52
|
+
}
|
|
53
|
+
if (score > 0)
|
|
54
|
+
scored.push({
|
|
55
|
+
index,
|
|
56
|
+
score,
|
|
57
|
+
titleHits: terms.filter((term) => title.includes(term)).length,
|
|
58
|
+
shape,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return scored
|
|
62
|
+
.sort(
|
|
63
|
+
(a, b) =>
|
|
64
|
+
b.score - a.score ||
|
|
65
|
+
b.titleHits - a.titleHits ||
|
|
66
|
+
String(a.shape.title).localeCompare(String(b.shape.title)) ||
|
|
67
|
+
a.index - b.index,
|
|
68
|
+
)
|
|
69
|
+
.slice(0, Number(options.limit ?? 10))
|
|
70
|
+
.map(({ shape, score }) => ({
|
|
71
|
+
title: shape.title,
|
|
72
|
+
w: shape.w,
|
|
73
|
+
h: shape.h,
|
|
74
|
+
style: shape.style,
|
|
75
|
+
score,
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function expandTerms(query) {
|
|
80
|
+
const normalized = String(query ?? "").toLowerCase();
|
|
81
|
+
const raw = normalized.match(/[\p{L}\p{N}._-]+/gu) ?? [];
|
|
82
|
+
const expanded = [];
|
|
83
|
+
for (const term of raw) {
|
|
84
|
+
expanded.push(ALIASES.get(term) ?? term);
|
|
85
|
+
if (term.includes("-")) expanded.push(...term.split("-"));
|
|
86
|
+
}
|
|
87
|
+
return [
|
|
88
|
+
...new Set(
|
|
89
|
+
expanded.join(" ").match(/[a-z0-9._-]+|[\u4e00-\u9fff]+/g) ?? [],
|
|
90
|
+
),
|
|
91
|
+
].filter((term) => term.length >= 2);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function fuzzyContains(text, term) {
|
|
95
|
+
if (term.length < 4) return false;
|
|
96
|
+
let cursor = 0;
|
|
97
|
+
for (const ch of text) {
|
|
98
|
+
if (ch === term[cursor]) cursor += 1;
|
|
99
|
+
if (cursor === term.length) return true;
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const args = parseArgs(process.argv.slice(2));
|
|
105
|
+
const query = args._.join(" ");
|
|
106
|
+
if (!query) {
|
|
107
|
+
console.error(
|
|
108
|
+
"usage: node shape-query.mjs <keywords> [--limit 10] [--category aws] [--format markdown|json]",
|
|
109
|
+
);
|
|
110
|
+
process.exit(2);
|
|
111
|
+
}
|
|
112
|
+
const results = queryShapes(loadShapes(), query, args);
|
|
113
|
+
if (results.length === 0) {
|
|
114
|
+
console.error(`no shapes matched ${JSON.stringify(query)}`);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
if ((args.format ?? (args.json ? "json" : "markdown")) === "json") {
|
|
118
|
+
process.stdout.write(`${JSON.stringify(results, null, 2)}\n`);
|
|
119
|
+
} else {
|
|
120
|
+
process.stdout.write(formatResult({ title: "Shape Query", query, results }));
|
|
121
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
export const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
export const skillDir = path.resolve(scriptDir, "..");
|
|
8
|
+
|
|
9
|
+
export function readText(filePath) {
|
|
10
|
+
return fs.readFileSync(filePath, "utf8");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function writeText(filePath, body) {
|
|
14
|
+
fs.mkdirSync(path.dirname(path.resolve(filePath)), { recursive: true });
|
|
15
|
+
fs.writeFileSync(filePath, body, "utf8");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function parseArgs(argv) {
|
|
19
|
+
const args = { _: [] };
|
|
20
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
21
|
+
const token = argv[i];
|
|
22
|
+
if (!token.startsWith("--")) {
|
|
23
|
+
args._.push(token);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const [rawKey, inline] = token.slice(2).split("=", 2);
|
|
27
|
+
const key = rawKey.replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
|
|
28
|
+
if (inline !== undefined) {
|
|
29
|
+
args[key] = inline;
|
|
30
|
+
} else if (argv[i + 1] && !argv[i + 1].startsWith("--")) {
|
|
31
|
+
args[key] = argv[i + 1];
|
|
32
|
+
i += 1;
|
|
33
|
+
} else {
|
|
34
|
+
args[key] = true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return args;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function formatResult(result, format = "markdown") {
|
|
41
|
+
if (format === "json") return `${JSON.stringify(result, null, 2)}\n`;
|
|
42
|
+
const lines = [`# ${result.title ?? "Drawio Studio Result"}`, ""];
|
|
43
|
+
for (const [key, value] of Object.entries(result)) {
|
|
44
|
+
if (key === "title") continue;
|
|
45
|
+
if (Array.isArray(value)) {
|
|
46
|
+
lines.push(`## ${label(key)}`, "");
|
|
47
|
+
if (value.length === 0) lines.push("- None");
|
|
48
|
+
else for (const item of value) lines.push(`- ${typeof item === "string" ? item : JSON.stringify(item)}`);
|
|
49
|
+
lines.push("");
|
|
50
|
+
} else if (value && typeof value === "object") {
|
|
51
|
+
lines.push(`## ${label(key)}`, "", "```json", JSON.stringify(value, null, 2), "```", "");
|
|
52
|
+
} else {
|
|
53
|
+
lines.push(`- ${label(key)}: ${String(value)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function label(value) {
|
|
60
|
+
return value.replace(/([A-Z])/g, " $1").replace(/^./, (ch) => ch.toUpperCase());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function xmlEscape(value) {
|
|
64
|
+
return String(value)
|
|
65
|
+
.replaceAll("&", "&")
|
|
66
|
+
.replaceAll("<", "<")
|
|
67
|
+
.replaceAll(">", ">")
|
|
68
|
+
.replaceAll('"', """);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function snap(value, grid = 10) {
|
|
72
|
+
return Math.round(value / grid) * grid;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function walkFiles(root, predicate) {
|
|
76
|
+
const out = [];
|
|
77
|
+
const skip = new Set([".git", "node_modules", "dist", "target", "vendor", ".next", ".nuxt", "coverage"]);
|
|
78
|
+
function visit(dir) {
|
|
79
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
80
|
+
if (skip.has(entry.name)) continue;
|
|
81
|
+
const full = path.join(dir, entry.name);
|
|
82
|
+
if (entry.isDirectory()) visit(full);
|
|
83
|
+
else if (!predicate || predicate(full)) out.push(full);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
visit(path.resolve(root));
|
|
87
|
+
return out.sort();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function toPosix(value) {
|
|
91
|
+
return value.split(path.sep).join("/");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function commonPrefix(values) {
|
|
95
|
+
if (values.length === 0) return "";
|
|
96
|
+
let prefix = values[0];
|
|
97
|
+
for (const value of values.slice(1)) {
|
|
98
|
+
while (prefix && !value.startsWith(prefix)) prefix = prefix.slice(0, -1);
|
|
99
|
+
}
|
|
100
|
+
return prefix.replace(/[^/]*$/, "");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function reduceTransitive(nodes, edges) {
|
|
104
|
+
const ids = new Set(nodes.map((node) => node.id));
|
|
105
|
+
const unique = [];
|
|
106
|
+
const seen = new Set();
|
|
107
|
+
for (const edge of edges) {
|
|
108
|
+
if (!ids.has(edge.source) || !ids.has(edge.target) || edge.source === edge.target) continue;
|
|
109
|
+
const key = `${edge.source}\0${edge.target}`;
|
|
110
|
+
if (!seen.has(key)) {
|
|
111
|
+
seen.add(key);
|
|
112
|
+
unique.push({ source: edge.source, target: edge.target });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const adjacency = new Map();
|
|
116
|
+
for (const edge of unique) {
|
|
117
|
+
if (!adjacency.has(edge.source)) adjacency.set(edge.source, new Set());
|
|
118
|
+
adjacency.get(edge.source).add(edge.target);
|
|
119
|
+
}
|
|
120
|
+
return unique.filter((edge) => !hasAlternatePath(edge.source, edge.target, adjacency, edge));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function hasAlternatePath(source, target, adjacency, skipped) {
|
|
124
|
+
const stack = [...(adjacency.get(source) ?? [])].filter((next) => !(source === skipped.source && next === skipped.target));
|
|
125
|
+
const seen = new Set();
|
|
126
|
+
while (stack.length) {
|
|
127
|
+
const next = stack.pop();
|
|
128
|
+
if (next === target) return true;
|
|
129
|
+
if (!next || seen.has(next)) continue;
|
|
130
|
+
seen.add(next);
|
|
131
|
+
for (const child of adjacency.get(next) ?? []) stack.push(child);
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function printOrWrite(body, output) {
|
|
137
|
+
if (output) writeText(output, body);
|
|
138
|
+
else process.stdout.write(body);
|
|
139
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../schema.json",
|
|
3
|
+
"name": "corporate",
|
|
4
|
+
"version": 1,
|
|
5
|
+
"default": false,
|
|
6
|
+
"source": { "type": "built-in" },
|
|
7
|
+
"confidence": "high",
|
|
8
|
+
"palette": {
|
|
9
|
+
"primary": { "fillColor": "#e3f2fd", "strokeColor": "#1565c0" },
|
|
10
|
+
"success": { "fillColor": "#e8f5e9", "strokeColor": "#2e7d32" },
|
|
11
|
+
"warning": { "fillColor": "#fff9c4", "strokeColor": "#f57c00" },
|
|
12
|
+
"accent": { "fillColor": "#fff3e0", "strokeColor": "#e65100" },
|
|
13
|
+
"danger": { "fillColor": "#ffebee", "strokeColor": "#c62828" },
|
|
14
|
+
"neutral": { "fillColor": "#eceff1", "strokeColor": "#455a64" },
|
|
15
|
+
"secondary": { "fillColor": "#f3e5f5", "strokeColor": "#6a1b9a" }
|
|
16
|
+
},
|
|
17
|
+
"roles": {
|
|
18
|
+
"service": "primary",
|
|
19
|
+
"database": "success",
|
|
20
|
+
"queue": "warning",
|
|
21
|
+
"gateway": "accent",
|
|
22
|
+
"error": "danger",
|
|
23
|
+
"external": "neutral",
|
|
24
|
+
"security": "secondary"
|
|
25
|
+
},
|
|
26
|
+
"shapes": {
|
|
27
|
+
"service": "rounded=0",
|
|
28
|
+
"database": "shape=cylinder3",
|
|
29
|
+
"queue": "rounded=0",
|
|
30
|
+
"decision": "rhombus",
|
|
31
|
+
"external": "rounded=0;dashed=1",
|
|
32
|
+
"container": "swimlane;startSize=30"
|
|
33
|
+
},
|
|
34
|
+
"font": {
|
|
35
|
+
"fontFamily": "Arial",
|
|
36
|
+
"fontSize": 11,
|
|
37
|
+
"titleFontSize": 13,
|
|
38
|
+
"titleBold": true
|
|
39
|
+
},
|
|
40
|
+
"edges": {
|
|
41
|
+
"style": "edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1",
|
|
42
|
+
"arrow": "endArrow=classic;endFill=1",
|
|
43
|
+
"dashedFor": ["optional", "async"]
|
|
44
|
+
},
|
|
45
|
+
"extras": {
|
|
46
|
+
"sketch": false,
|
|
47
|
+
"globalStrokeWidth": 1
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../schema.json",
|
|
3
|
+
"name": "default",
|
|
4
|
+
"version": 1,
|
|
5
|
+
"default": false,
|
|
6
|
+
"source": { "type": "built-in" },
|
|
7
|
+
"confidence": "high",
|
|
8
|
+
"palette": {
|
|
9
|
+
"primary": { "fillColor": "#dae8fc", "strokeColor": "#6c8ebf" },
|
|
10
|
+
"success": { "fillColor": "#d5e8d4", "strokeColor": "#82b366" },
|
|
11
|
+
"warning": { "fillColor": "#fff2cc", "strokeColor": "#d6b656" },
|
|
12
|
+
"accent": { "fillColor": "#ffe6cc", "strokeColor": "#d79b00" },
|
|
13
|
+
"danger": { "fillColor": "#f8cecc", "strokeColor": "#b85450" },
|
|
14
|
+
"neutral": { "fillColor": "#f5f5f5", "strokeColor": "#666666" },
|
|
15
|
+
"secondary": { "fillColor": "#e1d5e7", "strokeColor": "#9673a6" }
|
|
16
|
+
},
|
|
17
|
+
"roles": {
|
|
18
|
+
"service": "primary",
|
|
19
|
+
"database": "success",
|
|
20
|
+
"queue": "warning",
|
|
21
|
+
"gateway": "accent",
|
|
22
|
+
"error": "danger",
|
|
23
|
+
"external": "neutral",
|
|
24
|
+
"security": "secondary"
|
|
25
|
+
},
|
|
26
|
+
"shapes": {
|
|
27
|
+
"service": "rounded=1",
|
|
28
|
+
"database": "shape=cylinder3",
|
|
29
|
+
"queue": "rounded=1",
|
|
30
|
+
"decision": "rhombus",
|
|
31
|
+
"external": "rounded=1;dashed=1",
|
|
32
|
+
"container": "swimlane;startSize=30"
|
|
33
|
+
},
|
|
34
|
+
"font": {
|
|
35
|
+
"fontFamily": "Helvetica",
|
|
36
|
+
"fontSize": 12,
|
|
37
|
+
"titleFontSize": 14,
|
|
38
|
+
"titleBold": true
|
|
39
|
+
},
|
|
40
|
+
"edges": {
|
|
41
|
+
"style": "edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1",
|
|
42
|
+
"arrow": "endArrow=classic;endFill=1",
|
|
43
|
+
"dashedFor": []
|
|
44
|
+
},
|
|
45
|
+
"extras": {
|
|
46
|
+
"sketch": false,
|
|
47
|
+
"globalStrokeWidth": 1
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../schema.json",
|
|
3
|
+
"name": "handdrawn",
|
|
4
|
+
"version": 1,
|
|
5
|
+
"default": false,
|
|
6
|
+
"source": { "type": "built-in" },
|
|
7
|
+
"confidence": "high",
|
|
8
|
+
"palette": {
|
|
9
|
+
"primary": { "fillColor": "#ffe4b5", "strokeColor": "#b8651e" },
|
|
10
|
+
"success": { "fillColor": "#def0dc", "strokeColor": "#5c8a49" },
|
|
11
|
+
"warning": { "fillColor": "#fff4cc", "strokeColor": "#b8901a" },
|
|
12
|
+
"accent": { "fillColor": "#ffd9b3", "strokeColor": "#c25100" },
|
|
13
|
+
"danger": { "fillColor": "#ffcdbf", "strokeColor": "#a53d3d" },
|
|
14
|
+
"neutral": { "fillColor": "#f5e6d3", "strokeColor": "#8b7355" },
|
|
15
|
+
"secondary": { "fillColor": "#e6d7e8", "strokeColor": "#7b4397" }
|
|
16
|
+
},
|
|
17
|
+
"roles": {
|
|
18
|
+
"service": "primary",
|
|
19
|
+
"database": "success",
|
|
20
|
+
"queue": "warning",
|
|
21
|
+
"gateway": "accent",
|
|
22
|
+
"error": "danger",
|
|
23
|
+
"external": "neutral",
|
|
24
|
+
"security": "secondary"
|
|
25
|
+
},
|
|
26
|
+
"shapes": {
|
|
27
|
+
"service": "rounded=1",
|
|
28
|
+
"database": "shape=cylinder3",
|
|
29
|
+
"queue": "rounded=1",
|
|
30
|
+
"decision": "rhombus",
|
|
31
|
+
"external": "rounded=1;dashed=1",
|
|
32
|
+
"container": "swimlane;startSize=30"
|
|
33
|
+
},
|
|
34
|
+
"font": {
|
|
35
|
+
"fontFamily": "Helvetica",
|
|
36
|
+
"fontSize": 12,
|
|
37
|
+
"titleFontSize": 14,
|
|
38
|
+
"titleBold": true
|
|
39
|
+
},
|
|
40
|
+
"edges": {
|
|
41
|
+
"style": "edgeStyle=orthogonalEdgeStyle;curved=1;rounded=1;orthogonalLoop=1;jettySize=auto;html=1",
|
|
42
|
+
"arrow": "endArrow=classic;endFill=1",
|
|
43
|
+
"dashedFor": ["optional"]
|
|
44
|
+
},
|
|
45
|
+
"extras": {
|
|
46
|
+
"sketch": true,
|
|
47
|
+
"globalStrokeWidth": 2
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://github.com/Agents365-ai/drawio-skill/styles/schema.json",
|
|
4
|
+
"title": "drawio-skill preset",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["name", "version", "palette", "roles", "shapes", "font", "edges"],
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"$schema": { "type": "string" },
|
|
10
|
+
"name": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$" },
|
|
11
|
+
"version": { "type": "integer", "const": 1 },
|
|
12
|
+
"default": { "type": "boolean" },
|
|
13
|
+
"confidence": { "type": "string", "enum": ["low", "medium", "high"] },
|
|
14
|
+
"source": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"properties": {
|
|
18
|
+
"type": { "type": "string", "enum": ["xml", "image", "built-in", "hand-authored"] },
|
|
19
|
+
"path": { "type": "string" },
|
|
20
|
+
"extracted_at": { "type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$" }
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"palette": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"required": ["primary", "success", "warning", "accent", "danger", "neutral", "secondary"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"primary": { "$ref": "#/$defs/colorPair" },
|
|
29
|
+
"success": { "$ref": "#/$defs/colorPair" },
|
|
30
|
+
"warning": { "$ref": "#/$defs/colorPair" },
|
|
31
|
+
"accent": { "$ref": "#/$defs/colorPair" },
|
|
32
|
+
"danger": { "$ref": "#/$defs/colorPair" },
|
|
33
|
+
"neutral": { "$ref": "#/$defs/colorPair" },
|
|
34
|
+
"secondary": { "$ref": "#/$defs/colorPair" }
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"roles": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"additionalProperties": false,
|
|
40
|
+
"properties": {
|
|
41
|
+
"service": { "$ref": "#/$defs/slotName" },
|
|
42
|
+
"database": { "$ref": "#/$defs/slotName" },
|
|
43
|
+
"queue": { "$ref": "#/$defs/slotName" },
|
|
44
|
+
"gateway": { "$ref": "#/$defs/slotName" },
|
|
45
|
+
"error": { "$ref": "#/$defs/slotName" },
|
|
46
|
+
"external": { "$ref": "#/$defs/slotName" },
|
|
47
|
+
"security": { "$ref": "#/$defs/slotName" }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"shapes": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"additionalProperties": { "type": "string" },
|
|
53
|
+
"properties": {
|
|
54
|
+
"service": { "type": "string" },
|
|
55
|
+
"database": { "type": "string" },
|
|
56
|
+
"queue": { "type": "string" },
|
|
57
|
+
"decision": { "type": "string" },
|
|
58
|
+
"external": { "type": "string" },
|
|
59
|
+
"container": { "type": "string" }
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"font": {
|
|
63
|
+
"type": "object",
|
|
64
|
+
"additionalProperties": false,
|
|
65
|
+
"required": ["fontFamily", "fontSize"],
|
|
66
|
+
"properties": {
|
|
67
|
+
"fontFamily": { "type": "string" },
|
|
68
|
+
"fontSize": { "type": "integer", "minimum": 8, "maximum": 36 },
|
|
69
|
+
"titleFontSize": { "type": "integer", "minimum": 8, "maximum": 48 },
|
|
70
|
+
"titleBold": { "type": "boolean" }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"edges": {
|
|
74
|
+
"type": "object",
|
|
75
|
+
"additionalProperties": false,
|
|
76
|
+
"required": ["style", "arrow"],
|
|
77
|
+
"properties": {
|
|
78
|
+
"style": { "type": "string" },
|
|
79
|
+
"arrow": { "type": "string" },
|
|
80
|
+
"dashedFor": { "type": "array", "items": { "type": "string" } }
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"extras": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"additionalProperties": false,
|
|
86
|
+
"properties": {
|
|
87
|
+
"sketch": { "type": "boolean" },
|
|
88
|
+
"globalStrokeWidth": { "type": "number", "minimum": 0.5, "maximum": 6 }
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"$defs": {
|
|
93
|
+
"colorPair": {
|
|
94
|
+
"oneOf": [
|
|
95
|
+
{ "type": "null" },
|
|
96
|
+
{
|
|
97
|
+
"type": "object",
|
|
98
|
+
"additionalProperties": false,
|
|
99
|
+
"required": ["fillColor", "strokeColor"],
|
|
100
|
+
"properties": {
|
|
101
|
+
"fillColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" },
|
|
102
|
+
"strokeColor": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" }
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"slotName": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"enum": ["primary", "success", "warning", "accent", "danger", "neutral", "secondary"]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# 保持行为的重构
|
|
2
|
+
|
|
3
|
+
重构改变内部组织并保持可观察契约,使用 GREEN → REFACTOR → GREEN,不为结构变换制造失败的行为需求。
|
|
4
|
+
|
|
5
|
+
1. 区分结构调整、新行为、缺陷修复和依赖迁移;行为变化进入独立流程。
|
|
6
|
+
2. 阅读实现、调用方、导出、注册、持久化与测试;改动前定义结果、错误、副作用及顺序、状态变换、公共名称和协议。
|
|
7
|
+
3. 建立绿色基线,或记录已有失败。关键行为缺少覆盖时补充描述当前行为的特征测试,可以从绿色开始。
|
|
8
|
+
4. 诊断结构证据并排除误判。行数或复杂度指标本身不足以证明应当重写;优先选择最小安全、可回退的变换。
|
|
9
|
+
5. 规划前置步骤;每步记录目标、结构意图、手法、风险、预计文件/函数、公共 API/行为变化(纯重构为零)、验证和回退边界。
|
|
10
|
+
6. 一次只改一个主要结构问题,立即运行最近的有效校验并检查差异;实际范围超出预算时停止并重新评估。
|
|
11
|
+
7. 新回归使当前步骤失效:只撤回当前结构步骤,验证前一基线,再缩小或调整顺序;不撤销无关用户改动,不跨无关模块扩散修复。
|
|
12
|
+
8. 按受影响契约扩展验证:本地/静态、单元/集成、完整 lint/类型/测试、构建和相关专项。使用现有工具,不强制引入框架。
|
|
13
|
+
|
|
14
|
+
风险依上下文判断:SAFE 为证据充分的局部私有变换,CAUTION 为跨模块/共享状态/生命周期变换,DANGER 为公共 API、schema、持久化、鉴权、权限、协议或架构级变化。手法名称不自动决定安全等级。
|
|
15
|
+
|
|
16
|
+
给出证明结论:PASS 表示相关行为充分覆盖且校验通过;PARTIAL 表示已执行检查通过但仍有重要覆盖缺口;NOT PROVEN 表示证据或环境不足以证明行为保持。附实际命令、回退决定和剩余风险。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# 以事实来源驱动开发
|
|
2
|
+
|
|
3
|
+
使用项目事实、权威资料和对应版本的证据做工程决策。
|
|
4
|
+
|
|
5
|
+
1. 明确问题、版本和本地契约。先读项目清单、配置、实现、调用方和测试;稳定的本地变换可依赖这些事实,运行时、依赖和公共 API 的变化假设需要权威核验。
|
|
6
|
+
2. 收集实际版本的官方文档、源码、类型定义、发布记录、规范和迁移指南。第三方讨论只作线索。记录路径或链接、版本、日期和相关结论。
|
|
7
|
+
3. 对照运行中的项目说明兼容性、维护成本、迁移范围和回退。通过小的适配边界隔离易变化的外部假设,不为追新直接推翻稳定约定。
|
|
8
|
+
4. 使用项目现有校验或最小复现证明关键假设,按实际技术栈选择工具。记录命令和结果;无法验证时明确不确定性,不宣称支持。
|
|
9
|
+
5. 公共接口、依赖或团队约定改变时同步轻量 ADR、迁移记录或事实文档,不复制大段外部资料。
|
|
10
|
+
|
|
11
|
+
## 本地知识请求
|
|
12
|
+
|
|
13
|
+
用户将来源限制在本地仓库或知识目录时,先检索指定来源,不用网络猜测补齐。使用明确路径,否则检查 `knowledge/` 是否存在;不存在则说明缺失来源,不虚构目录。
|
|
14
|
+
|
|
15
|
+
有 `data_structure.md` 时先读导航并选择相关分支,渐进搜索而不加载全库。默认最多五轮关键词调整;记录文件、章节/页码/工作表、版本范围与证据缺口。PDF 和表格先选择合适提取工具。只有用户范围允许时才使用外部来源。
|
|
16
|
+
|
|
17
|
+
## 证据优先级与交付
|
|
18
|
+
|
|
19
|
+
实现、配置和测试确定本地契约;官方版本化文档与源码确定外部行为;规范确定平台约束;Issue 和文章仅作辅助。交付决策、来源、实现影响、验证结果及剩余不确定性,不能只说“已查文档”。
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# 测试驱动开发
|
|
2
|
+
|
|
3
|
+
新增行为和改变行为的缺陷修复使用 RED → GREEN → REFACTOR,测试描述可观察契约,不锁死内部实现结构。
|
|
4
|
+
|
|
5
|
+
1. 确定一个行为:输入、输出/错误、状态变换或外部可观察副作用。沿用项目现有工具,选择最接近风险且有效的测试层。
|
|
6
|
+
2. 先写能区分缺失或错误行为的最小测试并运行,观察预期行为导致的失败,不将语法、导入或环境错误当成红灯。缺陷测试必须在原缺陷存在时失败。
|
|
7
|
+
3. 只实现足以通过测试的最少代码。红灯阶段不重构,不增加无关功能。
|
|
8
|
+
4. 重跑测试及相关周边测试,再在保持绿色的前提下整理命名和结构;新需求进入下一轮。
|
|
9
|
+
5. 报告实际红绿命令、覆盖行为和未测边界,不根据差异或未执行的测试推断成功。
|
|
10
|
+
|
|
11
|
+
纯结构重构使用另一条契约:以已有测试或特征覆盖建立当前行为,保持 GREEN → REFACTOR → GREEN,不为流程形式制造失败。
|
|
12
|
+
|
|
13
|
+
逻辑就近测试;真实边界用集成测试,需要完整旅程时才用端到端测试。不默认上 E2E,不断言脆弱私有状态,不仅为 TDD 引入新框架。项目缺少测试设施时先说明最小搭建方案,并在获得决定后引入;按实际技术栈选择工具,不要求前端测试工具。
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cc-technical-diagrams
|
|
3
|
+
description: 用于创建或导出结构化技术图表,包括架构图、流程图、序列图、数据流、生命周期、Agent 与记忆流、局部交互预览和 PNG 质检。需要长期手工编辑或厂商图形时使用可编辑 draw.io 源。不要用于 UI 样机、产品视觉、海报或位图编辑。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 技术图表
|
|
7
|
+
|
|
8
|
+
从可编辑的结构化源创建完整、清晰的技术图表,适用于前端、后端、基础设施和 Agent 系统。
|
|
9
|
+
|
|
10
|
+
## 选择源格式
|
|
11
|
+
|
|
12
|
+
读取[图表工作流](references/diagram-workflows.md)。标准序列图和流程图优先使用本地已有 Mermaid;自包含浏览器交付、语义架构图及 Agent/记忆流使用 HTML 技术图,读取 [HTML 技术图说明](references/html-technical-diagrams.md)。需要官方厂商形状或长期手工编辑时选择可编辑 draw.io。
|
|
13
|
+
|
|
14
|
+
增量讲解可使用本地交互预览;交付时保留 JSON/SVG/PNG 导出。服务使用 [interactive-diagram-server.mjs](scripts/interactive-diagram-server.mjs),页面使用 [interactive-diagram.html](assets/interactive-diagram.html)。
|
|
15
|
+
|
|
16
|
+
## 渲染和导出
|
|
17
|
+
|
|
18
|
+
保留所有节点、关系、完整标签和显式几何。渲染器支持 workflow、sequence、dataflow、lifecycle、architecture。不得静默简化高级序列语义;激活与 alt/loop/par 片段优先使用 Mermaid。
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
node skills/cc-technical-diagrams/scripts/tech-diagram-render.mjs --input diagram.json --type architecture --output diagram.html --manifest diagram.layout.json
|
|
22
|
+
node skills/cc-technical-diagrams/scripts/export-diagram.mjs --input diagram.html --format png --output diagram.png --theme light --scale 2 --manifest diagram.layout.json --output-manifest diagram.actual.json
|
|
23
|
+
node skills/cc-technical-diagrams/scripts/png-qa.mjs --png diagram.png --manifest diagram.actual.json --format json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
标准 Mermaid 使用 [mermaid-render.mjs](scripts/mermaid-render.mjs)。复用 [diagram-layout.mjs](scripts/diagram-layout.mjs) 和 [diagram-browser.mjs](scripts/diagram-browser.mjs),不另造渲染器,不增加必需的浏览器库、远程脚本或下载图标包。
|
|
27
|
+
|
|
28
|
+
## 验证与交付
|
|
29
|
+
|
|
30
|
+
检查实际导出图像中的裁切、文字截断、标签穿线、重叠和内容遗漏。PNG QA 使用实际缩放后的导出清单,不使用源文件的估算坐标。导出成功不代表视觉验收通过。读取 [PNG 修复指导](references/png-qa-autofix.md),修复源文件或布局,不直接修改输出像素;默认最多两轮修复,并报告未解决问题。
|
|
31
|
+
|
|
32
|
+
交付 JSON/Mermaid 源、适用的 HTML、导出文件和 QA 证据。记录工具版本、主题、比例、修复轮次和部分验收状态。可选 Mermaid/Graphviz/浏览器工具缺失时明确报错或采用现有降级,不自动安装,也不宣称缺失的导出成功。保留完整标签,不用更高分辨率掩盖溢出。
|
|
33
|
+
|
|
34
|
+
示例:[质量样例](assets/quality-examples/README.md)、[序列 JSON](assets/quality-examples/sequence.json)、[流程 JSON](assets/quality-examples/workflow.json)、[架构 JSON](assets/quality-examples/architecture.json)、[无效显式几何](assets/quality-examples/invalid-explicit.json)。
|