cardbuddy 0.14.3 → 0.16.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/dist/cli.js +0 -0
- package/dist/preview-editor/assets/index-BkbBxDTT.css +1 -0
- package/dist/preview-editor/assets/index-Bro07DTa.js +313 -0
- package/dist/preview-editor/index.html +2 -2
- package/dist/standalone.js +3 -0
- package/dist/vendored/card-editor/runtime/adapter.js +2 -2
- package/dist/vendored/mcp/client.mjs +9 -2
- package/dist/vendored/server/core/ai-chat.js +1702 -134
- package/dist/vendored/server/core/browser.js +12 -3
- package/dist/vendored/server/core/cardFiles.js +3 -0
- package/dist/vendored/server/core/cardHistory.js +1 -0
- package/dist/vendored/server/core/cardImportMeta.js +7 -6
- package/dist/vendored/server/core/cardOpenFolder.js +1 -0
- package/dist/vendored/server/core/cardSave.js +1 -0
- package/dist/vendored/server/core/cardSync.js +3 -0
- package/dist/vendored/server/core/cardValidate.js +16 -5
- package/dist/vendored/server/core/codeBridge.js +5 -1
- package/dist/vendored/server/core/logStream.js +1 -0
- package/dist/vendored/server/core/sliceStatic.js +24 -4
- package/dist/vendored/server/core/sliceUpload.js +1 -0
- package/dist/vendored/server/core/turnJournal.js +6 -0
- package/dist/vendored/skills/card-skill-trainer/SKILL.md +257 -201
- package/dist/vendored/skills/card-skill-trainer/scripts/diagnose_case.mjs +14 -82
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/diagnosis.mjs +207 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/layout-correction-sim.mjs +62 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/paradigm-router.mjs +76 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/pixel-worker-runner.mjs +31 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/pixel-worker.mjs +138 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/scoring.mjs +24 -20
- package/dist/vendored/skills/card-skill-trainer/scripts/lib/telemetry.mjs +46 -0
- package/dist/vendored/skills/card-skill-trainer/scripts/plan_next_round.mjs +4 -1
- package/dist/vendored/skills/card-skill-trainer/scripts/run_round.mjs +279 -90
- package/dist/vendored/skills/card-skill-trainer/scripts/score_round.mjs +74 -2
- package/dist/vendored/skills/card-skill-trainer/scripts/sink_rules.mjs +127 -0
- package/dist/vendored/skills/dsl-card-ai/SKILL.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/SKILL.md +208 -380
- package/dist/vendored/skills/dsl-card-generator/references/dsl_structure.md +1 -15
- package/dist/vendored/skills/dsl-card-generator/references/expression_engine.md +11 -20
- package/dist/vendored/skills/dsl-card-generator/references/generation_pitfalls.md +233 -61
- package/dist/vendored/skills/dsl-card-generator/references/ir-format.md +202 -4
- package/dist/vendored/skills/dsl-card-generator/references/iteration_protocol.md +87 -0
- package/dist/vendored/skills/dsl-card-generator/references/previewer_contract.md +1 -1
- package/dist/vendored/skills/dsl-card-generator/references/quickref.md +42 -33
- package/dist/vendored/skills/dsl-card-generator/references/recipe_snippets/title-underline-overlay.json +59 -11
- package/dist/vendored/skills/dsl-card-generator/references/recipes.md +44 -8
- package/dist/vendored/skills/dsl-card-generator/references/rules.md +26 -6
- package/dist/vendored/skills/dsl-card-generator/references/scripts_reference.md +54 -0
- package/dist/vendored/skills/dsl-card-generator/references/semantic_adjudication.md +23 -0
- package/dist/vendored/skills/dsl-card-generator/references/slices_convention.md +6 -6
- package/dist/vendored/skills/dsl-card-generator/references/spec_to_schema_patterns.md +33 -4
- package/dist/vendored/skills/dsl-card-generator/references/ui_fidelity_rules.md +13 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/add_component.mjs +5 -14
- package/dist/vendored/skills/dsl-card-generator/scripts/autofix_schema.py +133 -2
- package/dist/vendored/skills/dsl-card-generator/scripts/check_fidelity.mjs +226 -19
- package/dist/vendored/skills/dsl-card-generator/scripts/check_magic_values.mjs +6 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/check_topology.py +0 -35
- package/dist/vendored/skills/dsl-card-generator/scripts/crop_slices.mjs +92 -6
- package/dist/vendored/skills/dsl-card-generator/scripts/expand_ir.mjs +277 -27
- package/dist/vendored/skills/dsl-card-generator/scripts/gate.mjs +147 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/generate_cards.mjs +12 -8
- package/dist/vendored/skills/dsl-card-generator/scripts/ir_merge.mjs +288 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/ir_restore.mjs +175 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/iterate.mjs +1015 -54
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/component_contract.mjs +315 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/geometry_audit.mjs +131 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/layout-tokens.mjs +1 -1
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/layout_rules.mjs +160 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/paths.mjs +23 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/paths.py +0 -37
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/python.mjs +99 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/adaptive-width.mjs +105 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/bindings.mjs +260 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/expr.mjs +52 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/image.mjs +96 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/registry.mjs +166 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/structure.mjs +127 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/rules/walk.mjs +61 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/scope_alias.mjs +125 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/slicePath.mjs +17 -5
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/slice_dedupe.mjs +102 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_assemble.mjs +5727 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_extract.mjs +4214 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lib/v3_shared.mjs +1110 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/lint_card.mjs +322 -71
- package/dist/vendored/skills/dsl-card-generator/scripts/preflight.mjs +87 -43
- package/dist/vendored/skills/dsl-card-generator/scripts/readiness.mjs +634 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/register_card_template.mjs +5 -8
- package/dist/vendored/skills/dsl-card-generator/scripts/render_card.mjs +91 -43
- package/dist/vendored/skills/dsl-card-generator/scripts/route_input.mjs +7 -11
- package/dist/vendored/skills/dsl-card-generator/scripts/spec_audit.mjs +272 -46
- package/dist/vendored/skills/dsl-card-generator/scripts/spec_to_schema_v3.mjs +43 -10499
- package/dist/vendored/skills/dsl-card-generator/scripts/v3_regression.mjs +188 -0
- package/dist/vendored/skills/dsl-card-generator/scripts/validate_schema.py +23 -15
- package/dist/vendored/skills/shared/exit-codes.md +79 -0
- package/dist/vendored/skills/shared/spec-contract.md +118 -0
- package/dist/vendored/skills/sketch-spec-to-card/SKILL.md +43 -20
- package/dist/vendored/skills/sketch-spec-to-card/references/spec-schema.md +4 -4
- package/dist/vendored/skills/sketch-spec-to-card/scripts/build_prompt.py +47 -9
- package/dist/vendored/skills/sketch-spec-to-card/scripts/cluster_states.py +14 -25
- package/dist/vendored/skills/sketch-spec-to-card/scripts/parse_meaxure.py +546 -91
- package/dist/vendored/skills/sketch-spec-to-card/scripts/png_utils.py +51 -5
- package/dist/vendored/skills/sketch-spec-to-card/scripts/test_text_only_artboard.py +217 -0
- package/dist/vendored/skills/sketch-spec-to-card/scripts/vision.py +64 -34
- package/package.json +1 -1
- package/dist/preview-editor/assets/index-Cm0USikc.js +0 -307
- package/dist/preview-editor/assets/index-cbTCHp8J.css +0 -1
- package/dist/vendored/skills/card-skill-trainer/scripts/test_missing_slice.py +0 -122
- package/dist/vendored/skills/dsl-card-generator/scripts/analyze_component_usage.mjs +0 -153
|
@@ -463,6 +463,75 @@ function describeRuntimeEvents(events) {
|
|
|
463
463
|
}).filter(Boolean).slice(-20).join(' | ')
|
|
464
464
|
}
|
|
465
465
|
|
|
466
|
+
/**
|
|
467
|
+
* 抓取 `.phone__screen` 内全部 `[data-cid]` 元素的几何与文本度量。
|
|
468
|
+
*
|
|
469
|
+
* 返回 `{ elements, degenerate }`:
|
|
470
|
+
* - `elements`:正常尺寸节点(≥1px),供评分 / 归因 / 设计稿配对使用;
|
|
471
|
+
* - `degenerate`:**被压成零尺寸但仍参与布局**的节点(display:none / visibility:hidden 的
|
|
472
|
+
* v-show 变体已剔除)。旧实现把它们直接丢掉,于是「被兄弟挤成 0 宽 → 文本每字一行 →
|
|
473
|
+
* 高度爆炸」这类最致命的缺陷在度量里根本不存在,模型只能靠猜。
|
|
474
|
+
*
|
|
475
|
+
* 冷路径与热路径(keep-alive 复用页面)都必须调用,否则 keep-alive 模式下 elementBoxes 恒为空。
|
|
476
|
+
*/
|
|
477
|
+
async function extractElementBoxes(cdp) {
|
|
478
|
+
const elRes = await cdp.send('Runtime.evaluate', {
|
|
479
|
+
expression: `(function(){
|
|
480
|
+
var scr = document.querySelector('.phone__screen');
|
|
481
|
+
if (!scr) return JSON.stringify({ elements: [], degenerate: [] });
|
|
482
|
+
var sr = scr.getBoundingClientRect();
|
|
483
|
+
var els = scr.querySelectorAll('[data-cid]');
|
|
484
|
+
var out = [];
|
|
485
|
+
var degenerate = [];
|
|
486
|
+
els.forEach(function(el) {
|
|
487
|
+
var r = el.getBoundingClientRect();
|
|
488
|
+
var cs = window.getComputedStyle(el);
|
|
489
|
+
var fs = parseFloat(cs.fontSize) || 0;
|
|
490
|
+
var lhRaw = cs.lineHeight;
|
|
491
|
+
// lineHeight 供几何审计判「文本被折了几行」(h / lh > 2 即 3 行以上);
|
|
492
|
+
// 'normal' 时拿不到像素值,取 0 表示未知(调用方据此跳过该判定,不猜)。
|
|
493
|
+
var lh = (lhRaw && lhRaw !== 'normal') ? (parseFloat(lhRaw) || 0) : 0;
|
|
494
|
+
var text = (el.textContent || '').trim();
|
|
495
|
+
// Input 类组件的占位文本在内部 <input placeholder> 属性上,textContent 为空;
|
|
496
|
+
// 评分/位置配对需要把它当作可见文本捕获(否则占位行被误判为文本缺失)。
|
|
497
|
+
if (!text) {
|
|
498
|
+
var innerInput = (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') ? el : el.querySelector('input,textarea');
|
|
499
|
+
if (innerInput) text = (innerInput.getAttribute('placeholder') || innerInput.value || '').trim();
|
|
500
|
+
}
|
|
501
|
+
var rec = {
|
|
502
|
+
cid: el.getAttribute('data-cid') || '',
|
|
503
|
+
cls: el.getAttribute('data-class') || '',
|
|
504
|
+
text: text.slice(0, 60),
|
|
505
|
+
x: Math.round((r.left - sr.left) * 100) / 100,
|
|
506
|
+
y: Math.round((r.top - sr.top) * 100) / 100,
|
|
507
|
+
w: Math.round(r.width * 100) / 100,
|
|
508
|
+
h: Math.round(r.height * 100) / 100,
|
|
509
|
+
fs: Math.round(fs * 100) / 100,
|
|
510
|
+
lh: Math.round(lh * 100) / 100,
|
|
511
|
+
color: cs.color || '',
|
|
512
|
+
scrollH: el.scrollHeight || 0,
|
|
513
|
+
clientH: el.clientHeight || 0,
|
|
514
|
+
};
|
|
515
|
+
if (r.width < 1 || r.height < 1) {
|
|
516
|
+
// display:none / visibility:hidden 是**有意隐藏**(v-show 变体),不算缺陷
|
|
517
|
+
if (cs.display === 'none' || cs.visibility === 'hidden') return;
|
|
518
|
+
degenerate.push(rec);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
out.push(rec);
|
|
522
|
+
});
|
|
523
|
+
return JSON.stringify({ elements: out, degenerate: degenerate });
|
|
524
|
+
})()`,
|
|
525
|
+
returnByValue: true,
|
|
526
|
+
})
|
|
527
|
+
const raw = elRes?.result?.value
|
|
528
|
+
if (!raw) return null
|
|
529
|
+
const parsed = JSON.parse(raw)
|
|
530
|
+
// 兼容旧形态(纯数组,无 degenerate)
|
|
531
|
+
if (Array.isArray(parsed)) return { elements: parsed, degenerate: [] }
|
|
532
|
+
return { elements: Array.isArray(parsed.elements) ? parsed.elements : [], degenerate: Array.isArray(parsed.degenerate) ? parsed.degenerate : [] }
|
|
533
|
+
}
|
|
534
|
+
|
|
466
535
|
/* ------------------------------------------------------------------ */
|
|
467
536
|
/* 可复用渲染会话 */
|
|
468
537
|
/* ------------------------------------------------------------------ */
|
|
@@ -507,6 +576,11 @@ export async function createRenderSession({ cardsRoot = cardsDir } = {}) {
|
|
|
507
576
|
} catch {}
|
|
508
577
|
let closed = false
|
|
509
578
|
let pageReady = false
|
|
579
|
+
// 热路径只允许「同一张卡」复用:热更新靠 history.replaceState 改 URL 再调 window.__bootCard(),
|
|
580
|
+
// 而 __bootCard 取卡片 id 的时机/来源不由本脚本控制。实测(2026-09-21):一个会话里连续
|
|
581
|
+
// 渲染 8 张不同的卡,全部返回**第一张**的度量(8 张高度全 = 341px)——静默错卡。
|
|
582
|
+
// 一旦接上几何门禁,错卡等于给出错误结论,故用 id 白名单把热路径钉死在同卡重渲染上。
|
|
583
|
+
let lastRenderedId = null
|
|
510
584
|
|
|
511
585
|
async function render({
|
|
512
586
|
id,
|
|
@@ -537,8 +611,8 @@ export async function createRenderSession({ cardsRoot = cardsDir } = {}) {
|
|
|
537
611
|
deviceScaleFactor: 1,
|
|
538
612
|
mobile: false,
|
|
539
613
|
})
|
|
540
|
-
//
|
|
541
|
-
if (hotReload && pageReady) {
|
|
614
|
+
// 热更新路径:同会话内**同一张卡**已渲染过时,通过 history.replaceState + 重新 boot 跳过整页导航
|
|
615
|
+
if (hotReload && pageReady && id === lastRenderedId) {
|
|
542
616
|
await cdp.send('Emulation.setDeviceMetricsOverride', {
|
|
543
617
|
width: Math.ceil(Number(width)) + 40,
|
|
544
618
|
height: Math.max(2000, Math.ceil(Number(captureHeight || 2000)) + 40),
|
|
@@ -571,10 +645,19 @@ export async function createRenderSession({ cardsRoot = cardsDir } = {}) {
|
|
|
571
645
|
captureBeyondViewport: true,
|
|
572
646
|
})
|
|
573
647
|
const buffer2 = Buffer.from(shot2.data, 'base64')
|
|
648
|
+
// 热路径同样要抓元素度量:keep-alive 模式下每轮 iterate 都走这里,
|
|
649
|
+
// 漏掉就等于「除了第一轮,模型永远拿不到几何归因」。
|
|
650
|
+
let hotBoxes = null
|
|
651
|
+
if (captureElements) {
|
|
652
|
+
try { hotBoxes = await extractElementBoxes(cdp) } catch { /* best-effort */ }
|
|
653
|
+
}
|
|
654
|
+
lastRenderedId = id
|
|
574
655
|
return {
|
|
575
656
|
ok: true, source: 'standalone-hot', id,
|
|
576
657
|
width: Math.round(box2.width), height: Math.round(box2.height),
|
|
577
658
|
base64: buffer2.toString('base64'),
|
|
659
|
+
elementBoxes: hotBoxes?.elements || undefined,
|
|
660
|
+
elementBoxesDegenerate: hotBoxes?.degenerate || undefined,
|
|
578
661
|
outFile: outFile ? path.resolve(outFile) : null,
|
|
579
662
|
ms: Math.round(performance.now() - startedAt),
|
|
580
663
|
}
|
|
@@ -594,6 +677,7 @@ export async function createRenderSession({ cardsRoot = cardsDir } = {}) {
|
|
|
594
677
|
}).catch(() => {})
|
|
595
678
|
await renderDone
|
|
596
679
|
pageReady = true
|
|
680
|
+
lastRenderedId = id
|
|
597
681
|
// 截图前等网络静默:冷帧根因(背景图/字体在途时截图)在此闭环
|
|
598
682
|
await waitNetworkIdle(inflight)
|
|
599
683
|
const boxRes = await cdp.send('Runtime.evaluate', {
|
|
@@ -618,49 +702,12 @@ export async function createRenderSession({ cardsRoot = cardsDir } = {}) {
|
|
|
618
702
|
})
|
|
619
703
|
const buffer = Buffer.from(shot.data, 'base64')
|
|
620
704
|
let elementBoxes = null
|
|
705
|
+
let elementBoxesDegenerate = null
|
|
621
706
|
if (captureElements) {
|
|
622
707
|
try {
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
if (!scr) return JSON.stringify([]);
|
|
627
|
-
var sr = scr.getBoundingClientRect();
|
|
628
|
-
var els = scr.querySelectorAll('[data-cid]');
|
|
629
|
-
var out = [];
|
|
630
|
-
els.forEach(function(el) {
|
|
631
|
-
var r = el.getBoundingClientRect();
|
|
632
|
-
if (r.width < 1 || r.height < 1) return;
|
|
633
|
-
var cls = el.getAttribute('data-class') || '';
|
|
634
|
-
var text = (el.textContent || '').trim();
|
|
635
|
-
// Input 类组件的占位文本在内部 <input placeholder> 属性上,textContent 为空;
|
|
636
|
-
// 评分/位置配对需要把它当作可见文本捕获(否则占位行被误判为文本缺失)。
|
|
637
|
-
if (!text) {
|
|
638
|
-
// Input.vue 根元素即 <input>:自身优先,其次向后兼容包裹式实现
|
|
639
|
-
var innerInput = (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') ? el : el.querySelector('input,textarea');
|
|
640
|
-
if (innerInput) text = (innerInput.getAttribute('placeholder') || innerInput.value || '').trim();
|
|
641
|
-
}
|
|
642
|
-
var cs = window.getComputedStyle(el);
|
|
643
|
-
var fs = parseFloat(cs.fontSize) || 0;
|
|
644
|
-
var color = cs.color || '';
|
|
645
|
-
out.push({
|
|
646
|
-
cid: el.getAttribute('data-cid') || '',
|
|
647
|
-
cls: cls,
|
|
648
|
-
text: text.slice(0, 60),
|
|
649
|
-
x: Math.round((r.left - sr.left) * 100) / 100,
|
|
650
|
-
y: Math.round((r.top - sr.top) * 100) / 100,
|
|
651
|
-
w: Math.round(r.width * 100) / 100,
|
|
652
|
-
h: Math.round(r.height * 100) / 100,
|
|
653
|
-
fs: Math.round(fs * 100) / 100,
|
|
654
|
-
color: color,
|
|
655
|
-
scrollH: el.scrollHeight || 0,
|
|
656
|
-
clientH: el.clientHeight || 0,
|
|
657
|
-
});
|
|
658
|
-
});
|
|
659
|
-
return JSON.stringify(out);
|
|
660
|
-
})()`,
|
|
661
|
-
returnByValue: true,
|
|
662
|
-
})
|
|
663
|
-
if (elRes?.result?.value) elementBoxes = JSON.parse(elRes.result.value)
|
|
708
|
+
const boxes = await extractElementBoxes(cdp)
|
|
709
|
+
elementBoxes = boxes?.elements || null
|
|
710
|
+
elementBoxesDegenerate = boxes?.degenerate || null
|
|
664
711
|
} catch (e) { /* element extraction is best-effort */ }
|
|
665
712
|
}
|
|
666
713
|
const json = {
|
|
@@ -670,6 +717,7 @@ export async function createRenderSession({ cardsRoot = cardsDir } = {}) {
|
|
|
670
717
|
height: Math.round(captureHeight ? Math.min(box.height, Number(captureHeight)) : box.height),
|
|
671
718
|
base64: buffer.toString('base64'),
|
|
672
719
|
elementBoxes: elementBoxes,
|
|
720
|
+
elementBoxesDegenerate: elementBoxesDegenerate,
|
|
673
721
|
}
|
|
674
722
|
|
|
675
723
|
if (format === 'json') return { ok: true, source: 'standalone', ...json }
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import fs from 'node:fs'
|
|
22
22
|
import path from 'node:path'
|
|
23
|
-
import { spawnSync } from 'node:child_process'
|
|
24
23
|
import { fileURLToPath } from 'node:url'
|
|
25
24
|
import { hostSkillsDir, projectRoot } from './lib/paths.mjs'
|
|
25
|
+
import { resolvePython } from './lib/python.mjs'
|
|
26
26
|
|
|
27
27
|
const IMAGE_EXT = new Set(['.png', '.jpg', '.jpeg', '.webp'])
|
|
28
28
|
/** 已知入口文件:判定交给它所在目录(index.html=MeaXure 导出;manifest/clusters/spec/prompt=要素包;schema=卡片目录)。 */
|
|
@@ -34,7 +34,7 @@ const SKETCH_SKILL = path.join(hostSkillsDir, 'sketch-spec-to-card')
|
|
|
34
34
|
* 作为提示文本随 next/note 下发,让判定器输出即带门禁,不依赖模型记住文档。
|
|
35
35
|
*/
|
|
36
36
|
const SELECTION_GATE =
|
|
37
|
-
'# 多画板门禁(rules.md §十三 + §13.4):用 spec_tree.mjs --list-cards 把全量画板按「画板序号.卡片序号」列出(一个画板含 N 张卡则展开为 K.1 ~ K.N)+ 末尾加「全部」;让用户选的方式 = 正文逐条写清单 + 一句提问后停止输出、等用户回序号再继续(**没有** request_user_input 这个工具,不要去找弹窗,也不要替用户挑);序号格式「画板序号.卡片序号」(如 1.2),单独回画板序号默认取该画板第 1 张卡;UI 产物可回「全部」全量生成,产卡默认单卡片(回「全部」才算显式批量授权);禁止自行挑画板或挑卡、禁止擅自批量产卡;清单逐行配图:每个卡片行下紧跟它自己的 card-N.png 绝对路径,同一画板的卡共享画板预览图(artboard.png
|
|
37
|
+
'# 多画板门禁(rules.md §十三 + §13.4):用 spec_tree.mjs --list-cards 把全量画板按「画板序号.卡片序号」列出(一个画板含 N 张卡则展开为 K.1 ~ K.N)+ 末尾加「全部」;让用户选的方式 = 正文逐条写清单 + 一句提问后停止输出、等用户回序号再继续(**没有** request_user_input 这个工具,不要去找弹窗,也不要替用户挑);序号格式「画板序号.卡片序号」(如 1.2),单独回画板序号默认取该画板第 1 张卡;UI 产物可回「全部」全量生成,产卡默认单卡片(回「全部」才算显式批量授权);禁止自行挑画板或挑卡、禁止擅自批量产卡;清单逐行配图:每个卡片行下紧跟它自己的 card-N.png 绝对路径,同一画板的卡共享画板预览图(artboard.png)但各有聚焦图;与序号一一对应,缺图显式标缺失,禁止把图堆在清单末尾;路径照抄完整绝对路径——禁止用 … / ... 省略前缀、禁止包进反引号或代码块(缩写的路径渲染端取不到图,用户那几行只剩一串文字)。'
|
|
38
38
|
/**
|
|
39
39
|
* 要素包根目录 UI/ —— **锚在宿主工程根,不锚在脚本自身位置**。
|
|
40
40
|
*
|
|
@@ -88,19 +88,15 @@ function readTextCapped(file, cap = 64 * 1024 * 1024) {
|
|
|
88
88
|
return head.toString('utf8') + tail.toString('utf8')
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
/** 命令里输出相对 cwd
|
|
91
|
+
/** 命令里输出相对 cwd 的短路径,跨盘/越界时退回绝对路径(分隔符按平台原生形态)。 */
|
|
92
92
|
function shortPath(abs) {
|
|
93
93
|
const rel = path.relative(process.cwd(), abs)
|
|
94
94
|
return rel && !rel.startsWith('..') && !path.isAbsolute(rel) ? rel : abs
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/** Python 解释器:解析集中在 lib/python.mjs(单一来源,含 Windows Store 假别名识别)。 */
|
|
97
98
|
function pythonBin() {
|
|
98
|
-
|
|
99
|
-
for (const bin of ['python3', 'python']) {
|
|
100
|
-
const probe = spawnSync(bin, ['--version'], { stdio: 'ignore' })
|
|
101
|
-
if (probe.status === 0) return bin
|
|
102
|
-
}
|
|
103
|
-
return 'python3'
|
|
99
|
+
return resolvePython()
|
|
104
100
|
}
|
|
105
101
|
|
|
106
102
|
/** Sketch MeaXure 标注导出判定:index.html 的 data 签名是硬证据,preview/ assets/ links/ 是佐证。 */
|
|
@@ -340,7 +336,7 @@ function route(inputAbs) {
|
|
|
340
336
|
`node ${shortPath(path.join(hostSkillsDir, 'dsl-card-generator', 'scripts', 'spec_tree.mjs'))} --list-cards ${shortPath(inputAbs)}`,
|
|
341
337
|
SELECTION_GATE,
|
|
342
338
|
]),
|
|
343
|
-
`# 再按 SKILL.md §8 Workflow A
|
|
339
|
+
`# 再按 SKILL.md §8 Workflow A 生成 schema(整树 IR 一次下发 → expand_ir → readiness → gate → iterate 视觉闭环);add_component 仅改卡用`,
|
|
344
340
|
],
|
|
345
341
|
note: bundle.artboardBundle
|
|
346
342
|
? '输入已是单画板要素包,无需前处理,直接走 Workflow A 生成本卡。'
|
|
@@ -377,7 +373,7 @@ function route(inputAbs) {
|
|
|
377
373
|
evidence: [`单张图片 ${path.basename(inputAbs)}(同目录无 spec.json)`],
|
|
378
374
|
skillChain: ['dsl-card-generator'],
|
|
379
375
|
workflow: 'Workflow 0 入口③ → Workflow A(无标注,视觉推断)',
|
|
380
|
-
next: [`# 直接多模态读图 →
|
|
376
|
+
next: [`# 直接多模态读图 → 整树 IR(AI 判定布局)→ expand_ir → readiness → gate → iterate 视觉闭环`],
|
|
381
377
|
note: '无 MeaXure 标注时全靠 AI 视觉推断,间距/圆角从图上目视估算;若这张图其实来自某份标注导出,请改传导出目录以走入口①。',
|
|
382
378
|
}
|
|
383
379
|
}
|