@open-dy/vibecoding-cli 0.1.13 → 0.1.15
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-dy/vibecoding-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Command orchestration, validation and packaging for Douyin vibecoding Taro and OpenCard projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"ajv": "^8.18.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@open-dy/vibecoding-sdk-taro": "0.1.
|
|
46
|
-
"@open-dy/vibecoding-sdk-opencard": "0.1.
|
|
45
|
+
"@open-dy/vibecoding-sdk-taro": "0.1.11",
|
|
46
|
+
"@open-dy/vibecoding-sdk-opencard": "0.1.12"
|
|
47
47
|
},
|
|
48
48
|
"peerDependenciesMeta": {
|
|
49
49
|
"@open-dy/vibecoding-sdk-taro": {
|
package/release-provenance.json
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"producer": "vibecoding-cli",
|
|
4
4
|
"packageName": "@open-dy/vibecoding-cli",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.15",
|
|
6
6
|
"source": {
|
|
7
|
-
"digest": "sha256-
|
|
8
|
-
"files":
|
|
7
|
+
"digest": "sha256-2e95e7446be1bd65d9968f7cdbd51e66f5d2104d1ff0925b11d303a339342d79",
|
|
8
|
+
"files": 94
|
|
9
9
|
},
|
|
10
|
-
"payload": "sha256-
|
|
10
|
+
"payload": "sha256-79fc6af85aef054cf4c1dd2470ecda0ce3b0a06c61e868ae301380dd1c6e5b92",
|
|
11
11
|
"toolchain": {
|
|
12
12
|
"node": "v22.22.3",
|
|
13
13
|
"runtime": {
|
package/src/commands/build.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { readEnvFile } from '../core/environment.mjs'
|
|
|
5
5
|
import { resolveProjectBinary, resolveSdkTaroEntry, runProcess, runTasks } from '../core/runner.mjs'
|
|
6
6
|
import { writeWebConfig } from '../core/web-config.mjs'
|
|
7
7
|
import { validateRoutes } from '../validators/routes.mjs'
|
|
8
|
+
import { validateImageInline } from '../validators/image-inline.mjs'
|
|
8
9
|
|
|
9
10
|
function taroEnvironment(root, extra = {}) {
|
|
10
11
|
const home = path.join(root, '.home')
|
|
@@ -101,6 +102,7 @@ export async function runBuild(context, options = {}) {
|
|
|
101
102
|
}
|
|
102
103
|
if (context.target === 'opencard') {
|
|
103
104
|
await buildOpenCard(context, buildOptions)
|
|
105
|
+
if (!options.watch) validateImageInline(context)
|
|
104
106
|
return
|
|
105
107
|
}
|
|
106
108
|
|
|
@@ -138,4 +140,5 @@ export async function runBuild(context, options = {}) {
|
|
|
138
140
|
}
|
|
139
141
|
await runTasks(tasks, { label: 'build' })
|
|
140
142
|
validateRoutes(context)
|
|
143
|
+
if (!options.watch) validateImageInline(context)
|
|
141
144
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readFileSync, statSync, realpathSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
const IMAGE_INLINE_LIMIT = 4096;
|
|
5
|
+
const SKILL_GUIDANCE = "请查阅 microapp-optimize-interest-card/SKILL.md 中的图片规则";
|
|
6
|
+
|
|
7
|
+
/** Validate the image inventory after compilation. Findings only warn. */
|
|
8
|
+
export function validateImageInline(context) {
|
|
9
|
+
const cardRoot =
|
|
10
|
+
context.target === "opencard" ? context.root : context.opencardRoot;
|
|
11
|
+
if (!cardRoot || (context.target !== "opencard" && !context.hasOpenCard)) {
|
|
12
|
+
return { warnings: 0, unverified: 0 };
|
|
13
|
+
}
|
|
14
|
+
const reportFile = path.join(
|
|
15
|
+
cardRoot, "node_modules/.cache/vibecoding/image-inline-tt.json",
|
|
16
|
+
);
|
|
17
|
+
try {
|
|
18
|
+
const report = JSON.parse(readFileSync(reportFile, "utf8"));
|
|
19
|
+
if (report.schemaVersion !== 3 || report.status !== "complete" ||
|
|
20
|
+
report.target !== "tt" ||
|
|
21
|
+
realpathSync(report.projectRoot) !== realpathSync(cardRoot) ||
|
|
22
|
+
!Array.isArray(report.findings) || !Array.isArray(report.issues) ||
|
|
23
|
+
!report.findings.every(item => item && typeof item.file === "string" && Number.isInteger(item.line) && item.line > 0 &&
|
|
24
|
+
Number.isInteger(item.column) && item.column > 0 &&
|
|
25
|
+
(item.kind === "import" || item.kind === "data-url") &&
|
|
26
|
+
(item.kind === "import" ? typeof item.image === "string" : typeof item.dataUrl === "string")) ||
|
|
27
|
+
!report.issues.every(issue => typeof issue === "string")) {
|
|
28
|
+
throw new Error("图片检查报告格式或工程身份不匹配");
|
|
29
|
+
}
|
|
30
|
+
const warnings = [];
|
|
31
|
+
const issues = [...report.issues];
|
|
32
|
+
for (const item of report.findings) {
|
|
33
|
+
let bytes;
|
|
34
|
+
try {
|
|
35
|
+
if (item.kind === "import") {
|
|
36
|
+
const info = statSync(path.resolve(cardRoot, item.image));
|
|
37
|
+
if (!info.isFile()) throw new Error("图片路径不是文件");
|
|
38
|
+
bytes = info.size;
|
|
39
|
+
} else {
|
|
40
|
+
const match = /^data:image\/[a-z0-9.+-]+(?:;[a-z0-9_-]+=[^;,\s]+)*;base64,([a-z0-9+/]*={0,2})$/i.exec(item.dataUrl);
|
|
41
|
+
const encoded = match?.[1];
|
|
42
|
+
if (!encoded || encoded.length % 4 === 1) throw new Error("图片 Base64 编码无效");
|
|
43
|
+
const decoded = Buffer.from(encoded, "base64");
|
|
44
|
+
if (decoded.toString("base64").replace(/=+$/, "") !== encoded.replace(/=+$/, "") ||
|
|
45
|
+
(encoded.includes("=") && encoded.length % 4 !== 0)) {
|
|
46
|
+
throw new Error("图片 Base64 编码无效");
|
|
47
|
+
}
|
|
48
|
+
bytes = decoded.length;
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
issues.push(`${item.file}:${item.line}:${item.column} 检查未完成:${error.message}。`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (bytes < IMAGE_INLINE_LIMIT) continue;
|
|
55
|
+
warnings.push(` ${item.file}:${item.line}:${item.column}\n` +
|
|
56
|
+
(item.kind === "import"
|
|
57
|
+
? ` 类型:图片 import\n 原图:${item.image}\n 大小:${bytes} bytes\n`
|
|
58
|
+
: ` 类型:固定 Base64 图片\n 解码大小:${bytes} bytes\n`));
|
|
59
|
+
}
|
|
60
|
+
if (warnings.length || issues.length) console.warn("=== 图片性能检测报告 ===\n");
|
|
61
|
+
if (warnings.length) {
|
|
62
|
+
console.warn(`检测到以下图片 import 或固定 Base64 图片大小 ≥${IMAGE_INLINE_LIMIT} 字节,存在内联图片性能风险。${SKILL_GUIDANCE}并在确认问题后上传图片以修复以下图片性能问题:\n`);
|
|
63
|
+
for (const warning of warnings) console.warn(warning);
|
|
64
|
+
console.warn(`共 ${warnings.length} 条可能的图片性能问题`);
|
|
65
|
+
}
|
|
66
|
+
if (issues.length) {
|
|
67
|
+
console.warn("图片检查未完成:");
|
|
68
|
+
for (const issue of issues) console.warn(` ${issue}`);
|
|
69
|
+
if (!warnings.length) console.warn(`${SKILL_GUIDANCE}。`);
|
|
70
|
+
}
|
|
71
|
+
return { warnings: warnings.length, unverified: issues.length };
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.warn("=== 图片性能检测报告 ===\n");
|
|
74
|
+
console.warn(
|
|
75
|
+
"图片检查未完成:未取得有效报告。" +
|
|
76
|
+
"请检查 SDK 版本及构建日志。" +
|
|
77
|
+
` (${error.message})`,
|
|
78
|
+
);
|
|
79
|
+
console.warn(`${SKILL_GUIDANCE}。`);
|
|
80
|
+
return { warnings: 0, unverified: 1 };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -53,7 +53,7 @@ export function validateOpenCardStructure(context) {
|
|
|
53
53
|
`found ${preloadCount} preload call(s). ` +
|
|
54
54
|
'Use taro.preloadMiniApp({ appList }) on the Card instance provided by useCardTaro from @tarojs/taro (opencard-taro); ' +
|
|
55
55
|
'this is not a named export of @open-dy/vibecoding-sdk-opencard. ' +
|
|
56
|
-
'See ${
|
|
56
|
+
'See ${CAPABILITY_SKILL_DIR}/references/opencard/runtime.md, section "小程序跳转预加载", for the lifecycle guards and example.',
|
|
57
57
|
)
|
|
58
58
|
}
|
|
59
59
|
}
|