howone 0.1.51 → 0.1.52

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.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/templates/vite/.howone/skills/howone/03-ai-capabilities/01-ai-capability-architecture.md +16 -2
  3. package/templates/vite/.howone/skills/howone/03-ai-capabilities/02-workflow-contract-rules.md +107 -0
  4. package/templates/vite/.howone/skills/howone/03-ai-capabilities/03-service-capability-catalog.md +98 -22
  5. package/templates/vite/.howone/skills/howone/03-ai-capabilities/04-workflow-operations.md +8 -0
  6. package/templates/vite/.howone/skills/howone/03-ai-capabilities/05-ai-feature-playbooks.md +66 -1
  7. package/templates/vite/.howone/skills/web-clone/LICENSE +0 -21
  8. package/templates/vite/.howone/skills/web-clone/README.md +0 -179
  9. package/templates/vite/.howone/skills/web-clone/SKILL.md +0 -243
  10. package/templates/vite/.howone/skills/web-clone/follow-wechat-qrcode.jpg +0 -0
  11. package/templates/vite/.howone/skills/web-clone/references/assessment.md +0 -77
  12. package/templates/vite/.howone/skills/web-clone/references/complex-playbooks.md +0 -46
  13. package/templates/vite/.howone/skills/web-clone/references/deliverables.md +0 -144
  14. package/templates/vite/.howone/skills/web-clone/references/design-dna.md +0 -125
  15. package/templates/vite/.howone/skills/web-clone/references/effect-extraction.md +0 -73
  16. package/templates/vite/.howone/skills/web-clone/references/marbles-case.md +0 -31
  17. package/templates/vite/.howone/skills/web-clone/references/reverse-engineering.md +0 -34
  18. package/templates/vite/.howone/skills/web-clone/references/static-mirror.md +0 -72
  19. package/templates/vite/.howone/skills/web-clone/scripts/asset-harvest.mjs +0 -101
  20. package/templates/vite/.howone/skills/web-clone/scripts/audit-clone.mjs +0 -151
  21. package/templates/vite/.howone/skills/web-clone/scripts/compare-recon.mjs +0 -265
  22. package/templates/vite/.howone/skills/web-clone/scripts/dna-scaffold.mjs +0 -214
  23. package/templates/vite/.howone/skills/web-clone/scripts/init-clone.mjs +0 -136
  24. package/templates/vite/.howone/skills/web-clone/scripts/interaction-probe.mjs +0 -314
  25. package/templates/vite/.howone/skills/web-clone/scripts/lib/playwright-loader.mjs +0 -32
  26. package/templates/vite/.howone/skills/web-clone/scripts/mirror-site.mjs +0 -121
  27. package/templates/vite/.howone/skills/web-clone/scripts/network-capture.mjs +0 -127
  28. package/templates/vite/.howone/skills/web-clone/scripts/recon-site.mjs +0 -235
  29. package/templates/vite/.howone/skills/web-clone/scripts/route-crawl.mjs +0 -228
  30. package/templates/vite/.howone/skills/web-clone/scripts/sourcemap-hunt.mjs +0 -112
  31. package/templates/vite/.howone/skills/web-clone/scripts/visual-diff.mjs +0 -161
@@ -1,161 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from "node:fs";
3
- import path from "node:path";
4
- import { loadPlaywright, launchChromium } from "./lib/playwright-loader.mjs";
5
-
6
- function usage() {
7
- console.log(`Usage:
8
- node scripts/visual-diff.mjs --original <png> --clone <png> --out visual-diff.json [--diff visual-diff.png] [--threshold 0.08]
9
-
10
- Compares screenshots in a real browser canvas and outputs numeric visual-diff metrics.
11
- `);
12
- }
13
-
14
- function parseArgs(argv) {
15
- const out = { original: "", clone: "", out: "visual-diff.json", diff: "", threshold: 0.08 };
16
- for (let i = 0; i < argv.length; i += 1) {
17
- const arg = argv[i];
18
- if (arg === "--help" || arg === "-h") out.help = true;
19
- else if (arg === "--original") out.original = argv[++i] || "";
20
- else if (arg === "--clone") out.clone = argv[++i] || "";
21
- else if (arg === "--out") out.out = argv[++i] || "visual-diff.json";
22
- else if (arg === "--diff") out.diff = argv[++i] || "";
23
- else if (arg === "--threshold") out.threshold = Number(argv[++i] || "0.08");
24
- else throw new Error(`Unexpected argument: ${arg}`);
25
- }
26
- return out;
27
- }
28
-
29
- function imageDataUrl(file) {
30
- const ext = path.extname(file).slice(1).toLowerCase() || "png";
31
- const mime = ext === "jpg" || ext === "jpeg" ? "image/jpeg" : "image/png";
32
- return `data:${mime};base64,${fs.readFileSync(file).toString("base64")}`;
33
- }
34
-
35
- function scoreFromDiff(diffRatio, meanAbsDiff) {
36
- if (diffRatio <= 0.01 && meanAbsDiff <= 0.01) return 5;
37
- if (diffRatio <= 0.04 && meanAbsDiff <= 0.025) return 4.5;
38
- if (diffRatio <= 0.08 && meanAbsDiff <= 0.05) return 4;
39
- if (diffRatio <= 0.16 && meanAbsDiff <= 0.08) return 3;
40
- if (diffRatio <= 0.3 && meanAbsDiff <= 0.14) return 2;
41
- return 1;
42
- }
43
-
44
- async function compareInBrowser(page, original, clone, threshold) {
45
- return page.evaluate(async ({ original, clone, threshold }) => {
46
- const loadImage = (src) => new Promise((resolve, reject) => {
47
- const image = new Image();
48
- image.onload = () => resolve(image);
49
- image.onerror = () => reject(new Error(`Failed to load image: ${src.slice(0, 80)}`));
50
- image.src = src;
51
- });
52
-
53
- const [left, right] = await Promise.all([loadImage(original), loadImage(clone)]);
54
- const width = Math.max(left.naturalWidth, right.naturalWidth);
55
- const height = Math.max(left.naturalHeight, right.naturalHeight);
56
-
57
- const canvasA = document.createElement("canvas");
58
- const canvasB = document.createElement("canvas");
59
- const canvasD = document.createElement("canvas");
60
- for (const canvas of [canvasA, canvasB, canvasD]) {
61
- canvas.width = width;
62
- canvas.height = height;
63
- }
64
-
65
- const ctxA = canvasA.getContext("2d");
66
- const ctxB = canvasB.getContext("2d");
67
- const ctxD = canvasD.getContext("2d");
68
- ctxA.fillStyle = "white";
69
- ctxB.fillStyle = "white";
70
- ctxA.fillRect(0, 0, width, height);
71
- ctxB.fillRect(0, 0, width, height);
72
- ctxA.drawImage(left, 0, 0);
73
- ctxB.drawImage(right, 0, 0);
74
-
75
- const a = ctxA.getImageData(0, 0, width, height);
76
- const b = ctxB.getImageData(0, 0, width, height);
77
- const d = ctxD.createImageData(width, height);
78
- let changed = 0;
79
- let sumAbs = 0;
80
- let sumSq = 0;
81
-
82
- for (let i = 0; i < a.data.length; i += 4) {
83
- const dr = Math.abs(a.data[i] - b.data[i]);
84
- const dg = Math.abs(a.data[i + 1] - b.data[i + 1]);
85
- const db = Math.abs(a.data[i + 2] - b.data[i + 2]);
86
- const da = Math.abs(a.data[i + 3] - b.data[i + 3]);
87
- const delta = (dr + dg + db + da) / 1020;
88
- sumAbs += delta;
89
- sumSq += delta * delta;
90
- if (delta > threshold) changed += 1;
91
-
92
- if (delta > threshold) {
93
- d.data[i] = 255;
94
- d.data[i + 1] = Math.max(0, 80 - delta * 80);
95
- d.data[i + 2] = Math.max(0, 80 - delta * 80);
96
- d.data[i + 3] = 255;
97
- } else {
98
- d.data[i] = Math.round(a.data[i] * 0.25 + 245 * 0.75);
99
- d.data[i + 1] = Math.round(a.data[i + 1] * 0.25 + 245 * 0.75);
100
- d.data[i + 2] = Math.round(a.data[i + 2] * 0.25 + 245 * 0.75);
101
- d.data[i + 3] = 255;
102
- }
103
- }
104
-
105
- ctxD.putImageData(d, 0, 0);
106
- const pixels = width * height;
107
- const diffPixelRatio = changed / pixels;
108
- const meanAbsDiff = sumAbs / pixels;
109
- const rmse = Math.sqrt(sumSq / pixels);
110
-
111
- return {
112
- original: { width: left.naturalWidth, height: left.naturalHeight },
113
- clone: { width: right.naturalWidth, height: right.naturalHeight },
114
- comparedCanvas: { width, height },
115
- threshold,
116
- changedPixels: changed,
117
- totalPixels: pixels,
118
- diffPixelRatio,
119
- meanAbsDiff,
120
- rmse,
121
- diffPngDataUrl: canvasD.toDataURL("image/png"),
122
- };
123
- }, { original, clone, threshold });
124
- }
125
-
126
- try {
127
- const args = parseArgs(process.argv.slice(2));
128
- if (args.help || !args.original || !args.clone) {
129
- usage();
130
- process.exit(args.help ? 0 : 1);
131
- }
132
-
133
- const { chromium } = loadPlaywright();
134
- const browser = await launchChromium(chromium);
135
- const page = await browser.newPage();
136
- const result = await compareInBrowser(page, imageDataUrl(args.original), imageDataUrl(args.clone), args.threshold);
137
- await browser.close();
138
-
139
- const diffDataUrl = result.diffPngDataUrl;
140
- delete result.diffPngDataUrl;
141
- result.visualScore = scoreFromDiff(result.diffPixelRatio, result.meanAbsDiff);
142
- result.files = {
143
- original: path.resolve(args.original),
144
- clone: path.resolve(args.clone),
145
- diff: args.diff ? path.resolve(args.diff) : "",
146
- };
147
-
148
- fs.mkdirSync(path.dirname(path.resolve(args.out)), { recursive: true });
149
- fs.writeFileSync(args.out, `${JSON.stringify(result, null, 2)}\n`);
150
-
151
- if (args.diff) {
152
- const base64 = diffDataUrl.replace(/^data:image\/png;base64,/, "");
153
- fs.mkdirSync(path.dirname(path.resolve(args.diff)), { recursive: true });
154
- fs.writeFileSync(args.diff, Buffer.from(base64, "base64"));
155
- }
156
-
157
- console.log(path.resolve(args.out));
158
- } catch (error) {
159
- console.error(`visual-diff failed: ${error.message}`);
160
- process.exit(1);
161
- }