@taloswork/ose-shared 0.1.1 → 0.1.3

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 (160) hide show
  1. package/package.json +3 -3
  2. package/skills/document/SKILL.md +29 -33
  3. package/skills/document/assets/fonts/Archivo-Regular.woff2 +0 -0
  4. package/skills/document/assets/fonts/Archivo-SemiBold.woff2 +0 -0
  5. package/skills/document/assets/fonts/BigShouldersDisplay-Bold.woff2 +0 -0
  6. package/skills/document/assets/fonts/BodoniModa-SemiBold.woff2 +0 -0
  7. package/skills/document/assets/fonts/CormorantGaramond-SemiBold.woff2 +0 -0
  8. package/skills/document/assets/fonts/Fraunces-SemiBold.woff2 +0 -0
  9. package/skills/document/assets/fonts/GochiHand-Regular.woff2 +0 -0
  10. package/skills/document/assets/fonts/IBMPlexSans-Regular.woff2 +0 -0
  11. package/skills/document/assets/fonts/IBMPlexSans-SemiBold.woff2 +0 -0
  12. package/skills/document/assets/fonts/Inter-Regular.woff2 +0 -0
  13. package/skills/document/assets/fonts/Jost-Regular.woff2 +0 -0
  14. package/skills/document/assets/fonts/Jost-SemiBold.woff2 +0 -0
  15. package/skills/document/assets/fonts/Karla-Regular.woff2 +0 -0
  16. package/skills/document/assets/fonts/Lora-Regular.woff2 +0 -0
  17. package/skills/document/assets/fonts/Manrope-Bold.woff2 +0 -0
  18. package/skills/document/assets/fonts/Manrope-Regular.woff2 +0 -0
  19. package/skills/document/assets/fonts/Marcellus-Regular.woff2 +0 -0
  20. package/skills/document/assets/fonts/PublicSans-Regular.woff2 +0 -0
  21. package/skills/document/assets/fonts/Sora-Regular.woff2 +0 -0
  22. package/skills/document/assets/fonts/Sora-SemiBold.woff2 +0 -0
  23. package/skills/document/assets/fonts/fonts.json +218 -0
  24. package/skills/document/bin/deck-build.cjs +275 -7
  25. package/skills/document/bin/deck-qa.cjs +1 -1
  26. package/skills/document/bin/doc-convert.cjs +11 -11
  27. package/skills/document/bin/doc-fill.cjs +1 -1
  28. package/skills/document/bin/doc-gen.cjs +119 -34
  29. package/skills/document/bin/doc-scan.cjs +8 -10
  30. package/skills/document/bin/doc-text.cjs +1 -1
  31. package/skills/document/bin/doc-validate.cjs +3 -3
  32. package/skills/document/bin/doc-xml.cjs +3 -3
  33. package/skills/document/bin/docx-annotate.cjs +3 -3
  34. package/skills/document/bin/html2pptx.cjs +290 -59
  35. package/skills/document/bin/ocr.cjs +1 -1
  36. package/skills/document/bin/pdf-form.cjs +1 -1
  37. package/skills/document/bin/pdf-images.cjs +1 -1
  38. package/skills/document/bin/pdf-ops.cjs +2 -2
  39. package/skills/document/bin/pdf-render.cjs +1 -1
  40. package/skills/document/bin/pdf-tables.cjs +1 -1
  41. package/skills/document/bin/pptx-clone.cjs +3 -3
  42. package/skills/document/bin/pptx-embed-fonts.cjs +1 -1
  43. package/skills/document/bin/pptx-set-image.cjs +3 -3
  44. package/skills/document/bin/pptx-slide.cjs +4 -4
  45. package/skills/document/bin/pptx-theme.cjs +1 -1
  46. package/skills/document/bin/pptx-tokenize.cjs +3 -3
  47. package/skills/document/bin/xlsx-query.cjs +1 -1
  48. package/skills/document/bin/xlsx-recalc.cjs +2 -2
  49. package/skills/document/catalog.json +25 -0
  50. package/skills/document/deck-design.md +191 -0
  51. package/skills/document/layouts/README.md +32 -0
  52. package/skills/document/layouts/banner-columns.tpl +9 -9
  53. package/skills/document/layouts/bento.tpl +3 -3
  54. package/skills/document/layouts/big-stat.tpl +3 -3
  55. package/skills/document/layouts/blocks-2x2.tpl +12 -12
  56. package/skills/document/layouts/brand-values.tpl +5 -5
  57. package/skills/document/layouts/cards-3.tpl +3 -3
  58. package/skills/document/layouts/cards-grid.tpl +3 -3
  59. package/skills/document/layouts/chart-full.tpl +3 -3
  60. package/skills/document/layouts/chart-kpi.tpl +3 -3
  61. package/skills/document/layouts/color-palette.tpl +5 -5
  62. package/skills/document/layouts/comparison.tpl +3 -3
  63. package/skills/document/layouts/concept-hub.tpl +3 -3
  64. package/skills/document/layouts/cover-centered.tpl +1 -1
  65. package/skills/document/layouts/cover-image.tpl +1 -1
  66. package/skills/document/layouts/cover-minimal.tpl +3 -3
  67. package/skills/document/layouts/cover-statement.tpl +3 -3
  68. package/skills/document/layouts/cover.tpl +1 -1
  69. package/skills/document/layouts/data-table.tpl +3 -3
  70. package/skills/document/layouts/dos-donts.tpl +14 -14
  71. package/skills/document/layouts/editorial-panel.tpl +11 -11
  72. package/skills/document/layouts/ending-contact.tpl +1 -1
  73. package/skills/document/layouts/ending.tpl +1 -1
  74. package/skills/document/layouts/funnel.tpl +3 -3
  75. package/skills/document/layouts/gantt.tpl +3 -3
  76. package/skills/document/layouts/hero.tpl +3 -3
  77. package/skills/document/layouts/icon-row.tpl +3 -3
  78. package/skills/document/layouts/image-full.tpl +5 -5
  79. package/skills/document/layouts/image-grid.tpl +3 -3
  80. package/skills/document/layouts/image-left.tpl +3 -3
  81. package/skills/document/layouts/list.tpl +3 -3
  82. package/skills/document/layouts/logo-guidelines.tpl +8 -8
  83. package/skills/document/layouts/map-distribution.tpl +3 -3
  84. package/skills/document/layouts/map-quad.tpl +6 -6
  85. package/skills/document/layouts/matrix-2x2.tpl +3 -3
  86. package/skills/document/layouts/numbered-brief.tpl +12 -12
  87. package/skills/document/layouts/org-tree.tpl +3 -3
  88. package/skills/document/layouts/problem-solution-banner.tpl +7 -7
  89. package/skills/document/layouts/problem-solution.tpl +3 -3
  90. package/skills/document/layouts/pyramid.tpl +3 -3
  91. package/skills/document/layouts/quote.tpl +1 -1
  92. package/skills/document/layouts/radar.tpl +3 -3
  93. package/skills/document/layouts/ring-progress.tpl +3 -3
  94. package/skills/document/layouts/section-fullbleed.tpl +3 -3
  95. package/skills/document/layouts/section-image.tpl +1 -1
  96. package/skills/document/layouts/section-stat.tpl +1 -1
  97. package/skills/document/layouts/section.tpl +1 -1
  98. package/skills/document/layouts/slots.json +1 -1
  99. package/skills/document/layouts/split-two-col.tpl +3 -3
  100. package/skills/document/layouts/stats-chart.tpl +3 -3
  101. package/skills/document/layouts/steps-serpentine.tpl +11 -11
  102. package/skills/document/layouts/steps-vertical.tpl +3 -3
  103. package/skills/document/layouts/steps.tpl +3 -3
  104. package/skills/document/layouts/team-row.tpl +4 -4
  105. package/skills/document/layouts/three-kpi.tpl +3 -3
  106. package/skills/document/layouts/timeline.tpl +3 -3
  107. package/skills/document/layouts/title-meta.tpl +5 -5
  108. package/skills/document/layouts/title.tpl +2 -2
  109. package/skills/document/layouts/toc-agenda.tpl +3 -3
  110. package/skills/document/layouts/toc-editorial.tpl +15 -0
  111. package/skills/document/layouts/toc-panel.tpl +4 -4
  112. package/skills/document/layouts/toc.tpl +3 -3
  113. package/skills/document/layouts/transition.tpl +1 -1
  114. package/skills/document/layouts/two-kpi.tpl +3 -3
  115. package/skills/document/layouts/type-specimen.tpl +10 -10
  116. package/skills/document/layouts/versus.tpl +3 -3
  117. package/skills/document/motion/README.md +11 -0
  118. package/skills/document/packs/README.md +9 -0
  119. package/skills/document/styles/README.md +36 -15
  120. package/skills/document/styles/_contract-defaults.css +55 -0
  121. package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
  122. package/skills/document/styles/_samples/_groups/creative.webp +0 -0
  123. package/skills/document/styles/_samples/_groups/editorial.webp +0 -0
  124. package/skills/document/styles/_samples/_groups/minimal.webp +0 -0
  125. package/skills/document/styles/_samples/_groups/natural.webp +0 -0
  126. package/skills/document/styles/_samples/_groups/tech-future.webp +0 -0
  127. package/skills/document/styles/_samples/anthropic.webp +0 -0
  128. package/skills/document/styles/_samples/apple.webp +0 -0
  129. package/skills/document/styles/_samples/black-gold.webp +0 -0
  130. package/skills/document/styles/_samples/branding.webp +0 -0
  131. package/skills/document/styles/_samples/cinereel.webp +0 -0
  132. package/skills/document/styles/_samples/cool.webp +0 -0
  133. package/skills/document/styles/_samples/hand-drawn.webp +0 -0
  134. package/skills/document/styles/_samples/ivory-gold.webp +0 -0
  135. package/skills/document/styles/_samples/magazine-ink.webp +0 -0
  136. package/skills/document/styles/_samples/mckinsey.webp +0 -0
  137. package/skills/document/styles/_samples/mono.webp +0 -0
  138. package/skills/document/styles/_samples/olive-gold.webp +0 -0
  139. package/skills/document/styles/_samples/swiss-grid.webp +0 -0
  140. package/skills/document/styles/anthropic/backdrop.html +4 -0
  141. package/skills/document/styles/anthropic/skin.css +15 -8
  142. package/skills/document/styles/apple/backdrop.html +4 -1
  143. package/skills/document/styles/apple/skin.css +5 -2
  144. package/skills/document/styles/black-gold/backdrop.html +3 -0
  145. package/skills/document/styles/black-gold/skin.css +15 -8
  146. package/skills/document/styles/branding/backdrop.html +4 -0
  147. package/skills/document/styles/branding/skin.css +14 -7
  148. package/skills/document/styles/cinereel/skin.css +28 -10
  149. package/skills/document/styles/cool/backdrop.html +3 -0
  150. package/skills/document/styles/cool/skin.css +5 -2
  151. package/skills/document/styles/hand-drawn/skin.css +14 -6
  152. package/skills/document/styles/ivory-gold/skin.css +19 -6
  153. package/skills/document/styles/magazine-ink/skin.css +6 -1
  154. package/skills/document/styles/mckinsey/backdrop.html +5 -0
  155. package/skills/document/styles/mckinsey/skin.css +5 -2
  156. package/skills/document/styles/mono/backdrop.html +6 -0
  157. package/skills/document/styles/mono/skin.css +5 -2
  158. package/skills/document/styles/olive-gold/backdrop.html +5 -0
  159. package/skills/document/styles/olive-gold/skin.css +15 -8
  160. package/skills/document/styles/swiss-grid/skin.css +6 -1
@@ -6,7 +6,7 @@ var import_promises = require("node:fs/promises");
6
6
  var import_node_fs = require("node:fs");
7
7
  var import_node_path = require("node:path");
8
8
 
9
- // packages/core/dist/fs/deck-figures.js
9
+ // packages/core/dist/document/deck-figures.js
10
10
  var FIGURE_SPECS = {
11
11
  radar: {
12
12
  metrics: { required: ["name", "score"], derived: [] }
@@ -159,7 +159,7 @@ function derivePins(rows, warnings) {
159
159
  });
160
160
  }
161
161
 
162
- // packages/core/dist/fs/deck-build.js
162
+ // packages/core/dist/document/deck-build.js
163
163
  var SLOT_RE = /\{\{(?![#/])([^{}]*)\}\}/g;
164
164
  var BLOCK_RE = /\{\{#([A-Za-z_][\w-]*)\}\}([\s\S]*?)\{\{\/\1\}\}/g;
165
165
  function escapeHtml(s) {
@@ -287,6 +287,214 @@ function assembleDeck(spec, readLayout) {
287
287
  return { html: sections.join("\n"), warnings: problems.warnings, errors: problems.errors };
288
288
  }
289
289
 
290
+ // packages/core/dist/document/deck-catalog.js
291
+ var KINDS = ["skin", "pack"];
292
+ var MODES = ["light", "dark"];
293
+ var ID_RE = /^[a-z0-9][a-z0-9-]*$/;
294
+ function isStr(v) {
295
+ return typeof v === "string" && v.length > 0;
296
+ }
297
+ function isStrArr(v) {
298
+ return Array.isArray(v) && v.every((x) => typeof x === "string");
299
+ }
300
+ function parseCatalog(raw) {
301
+ const errors = [];
302
+ const o = raw;
303
+ if (!o || typeof o !== "object")
304
+ return { catalog: null, errors: ["catalog is not an object"] };
305
+ const groups = [];
306
+ const rawGroups = Array.isArray(o.groups) ? o.groups : [];
307
+ if (!Array.isArray(o.groups))
308
+ errors.push("catalog.groups must be an array");
309
+ rawGroups.forEach((g, i) => {
310
+ const at = `group[${i}]`;
311
+ if (!isStr(g?.id) || !ID_RE.test(g.id))
312
+ errors.push(`${at}: bad id`);
313
+ if (!isStr(g?.name_cn))
314
+ errors.push(`${at}: missing name_cn`);
315
+ if (!isStr(g?.sample))
316
+ errors.push(`${at}: missing sample`);
317
+ if (!isStrArr(g?.scenarios))
318
+ errors.push(`${at}: scenarios must be a string array`);
319
+ if (isStr(g?.id) && isStr(g?.name_cn) && isStr(g?.sample) && isStrArr(g?.scenarios)) {
320
+ groups.push({ id: g.id, name_cn: g.name_cn, sample: g.sample, scenarios: g.scenarios });
321
+ }
322
+ });
323
+ const entries = [];
324
+ const rawEntries = Array.isArray(o.entries) ? o.entries : [];
325
+ if (!Array.isArray(o.entries))
326
+ errors.push("catalog.entries must be an array");
327
+ rawEntries.forEach((e, i) => {
328
+ const at = `entry[${i}]${isStr(e?.id) ? ` (${e.id})` : ""}`;
329
+ const before = errors.length;
330
+ if (!isStr(e?.id) || !ID_RE.test(e.id))
331
+ errors.push(`${at}: bad id`);
332
+ if (!isStr(e?.kind) || !KINDS.includes(e.kind))
333
+ errors.push(`${at}: kind must be "skin" or "pack"`);
334
+ if (!isStr(e?.group))
335
+ errors.push(`${at}: missing group`);
336
+ if (!isStr(e?.name_cn))
337
+ errors.push(`${at}: missing name_cn`);
338
+ if (!isStr(e?.oneliner))
339
+ errors.push(`${at}: missing oneliner`);
340
+ if (!isStrArr(e?.scenarios))
341
+ errors.push(`${at}: scenarios must be a string array`);
342
+ if (!isStr(e?.mode) || !MODES.includes(e.mode))
343
+ errors.push(`${at}: mode must be "light" or "dark"`);
344
+ if (!isStr(e?.sample))
345
+ errors.push(`${at}: missing sample`);
346
+ if (e?.motion !== void 0 && !isStr(e.motion))
347
+ errors.push(`${at}: motion must be a string when present`);
348
+ if (errors.length === before) {
349
+ entries.push({
350
+ id: e.id,
351
+ kind: e.kind,
352
+ group: e.group,
353
+ name_cn: e.name_cn,
354
+ oneliner: e.oneliner,
355
+ scenarios: e.scenarios,
356
+ mode: e.mode,
357
+ sample: e.sample,
358
+ ...e.motion !== void 0 ? { motion: e.motion } : {}
359
+ });
360
+ }
361
+ });
362
+ return { catalog: errors.length ? null : { groups, entries }, errors };
363
+ }
364
+ function resolveEntry(catalog, id) {
365
+ return catalog.entries.find((e) => e.id === id) ?? null;
366
+ }
367
+
368
+ // packages/core/dist/document/deck-motion.js
369
+ var ANIM_EFFECTS = [
370
+ "fade",
371
+ "fade-up",
372
+ "float",
373
+ "appear",
374
+ "fly-up",
375
+ "fly-down",
376
+ "fly-left",
377
+ "fly-right"
378
+ ];
379
+ var START_MODES = ["after", "with", "onclick"];
380
+ var SEL_RE = /^\.[a-z][a-z0-9-]*$/;
381
+ function validateMotionPreset(raw) {
382
+ const errors = [];
383
+ const p = raw;
384
+ if (!p || typeof p !== "object")
385
+ return ["motion preset is not an object"];
386
+ if (p.transition !== void 0) {
387
+ const t = p.transition;
388
+ if (!t || typeof t.effect !== "string" || !t.effect)
389
+ errors.push("transition.effect must be a non-empty string");
390
+ if (t?.durMs !== void 0 && typeof t.durMs !== "number")
391
+ errors.push("transition.durMs must be a number");
392
+ if (t?.dir !== void 0 && typeof t.dir !== "string")
393
+ errors.push("transition.dir must be a string");
394
+ }
395
+ if (p.entrance !== void 0) {
396
+ if (typeof p.entrance !== "object" || p.entrance === null) {
397
+ errors.push("entrance must be an object keyed by role");
398
+ } else {
399
+ for (const [role, steps] of Object.entries(p.entrance)) {
400
+ if (!Array.isArray(steps)) {
401
+ errors.push(`entrance.${role} must be an array`);
402
+ continue;
403
+ }
404
+ steps.forEach((s, i) => {
405
+ const at = `entrance.${role}[${i}]`;
406
+ if (typeof s?.sel !== "string" || !SEL_RE.test(s.sel))
407
+ errors.push(`${at}: sel must be a single class selector like ".card"`);
408
+ if (typeof s?.anim !== "string" || !ANIM_EFFECTS.includes(s.anim)) {
409
+ errors.push(`${at}: anim "${String(s?.anim)}" is not implemented by pptx-anim.ts`);
410
+ }
411
+ for (const k of ["delay", "dur", "stagger"]) {
412
+ if (s?.[k] !== void 0 && typeof s[k] !== "number")
413
+ errors.push(`${at}: ${k} must be a number`);
414
+ }
415
+ if (s?.start !== void 0 && !START_MODES.includes(s.start))
416
+ errors.push(`${at}: start must be one of ${START_MODES.join("/")}`);
417
+ });
418
+ }
419
+ }
420
+ }
421
+ return errors;
422
+ }
423
+ var ROLE_OVERRIDES = {
424
+ transition: "section",
425
+ hero: "cover",
426
+ title: "cover",
427
+ "title-meta": "cover",
428
+ quote: "content",
429
+ bento: "cards",
430
+ list: "cards",
431
+ "icon-row": "cards",
432
+ "cards-grid": "cards",
433
+ "blocks-2x2": "cards",
434
+ "chart-kpi": "stat",
435
+ "two-kpi": "stat",
436
+ "three-kpi": "stat",
437
+ "big-stat": "stat",
438
+ "stats-chart": "stat"
439
+ };
440
+ function roleOfLayout(layoutId) {
441
+ if (ROLE_OVERRIDES[layoutId])
442
+ return ROLE_OVERRIDES[layoutId];
443
+ if (layoutId.startsWith("cover"))
444
+ return "cover";
445
+ if (layoutId.startsWith("toc"))
446
+ return "toc";
447
+ if (layoutId.startsWith("section"))
448
+ return "section";
449
+ if (layoutId.startsWith("ending"))
450
+ return "ending";
451
+ if (layoutId.startsWith("cards"))
452
+ return "cards";
453
+ return "content";
454
+ }
455
+ var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? String(Math.round(v)) : null;
456
+ function addAttrs(tag, attrs) {
457
+ if (/\bdata-anim=/.test(tag))
458
+ return tag;
459
+ const extra = Object.entries(attrs).filter(([, v]) => v !== null).map(([k, v]) => ` ${k}="${v}"`).join("");
460
+ return tag.replace(/\s*\/?>$/, (end) => extra + end);
461
+ }
462
+ function applyMotion(html, layoutId, preset) {
463
+ let out = html;
464
+ const role = roleOfLayout(layoutId);
465
+ const steps = preset.entrance?.[role];
466
+ if (steps?.length) {
467
+ let seq = 0;
468
+ for (const step of steps) {
469
+ const cls = step.sel.slice(1);
470
+ const re = new RegExp(`<([a-z][a-z0-9]*)\\b([^>]*\\bclass="[^"]*(?<![\\w-])${cls}(?![\\w-])[^"]*"[^>]*)>`, "gi");
471
+ let nth = 0;
472
+ out = out.replace(re, (tag) => {
473
+ nth += 1;
474
+ seq += 1;
475
+ const delay = nth === 1 ? num2(step.delay) : num2(step.stagger ?? step.delay);
476
+ return addAttrs(tag, {
477
+ "data-anim": step.anim,
478
+ "data-anim-seq": String(seq),
479
+ "data-anim-delay": delay,
480
+ "data-anim-dur": num2(step.dur),
481
+ "data-anim-start": step.start ?? null
482
+ });
483
+ });
484
+ }
485
+ }
486
+ const t = preset.transition;
487
+ if (t?.effect) {
488
+ out = out.replace(/<section\b([^>]*\bclass="[^"]*(?<![\w-])slide(?![\w-])[^"]*"[^>]*)>/i, (tag) => {
489
+ if (/\bdata-transition=/.test(tag))
490
+ return tag;
491
+ const extra = ` data-transition="${t.effect}"` + (t.dir ? ` data-transition-dir="${t.dir}"` : "") + (num2(t.durMs) ? ` data-transition-dur="${num2(t.durMs)}"` : "");
492
+ return tag.replace(/\s*>$/, extra + ">");
493
+ });
494
+ }
495
+ return out;
496
+ }
497
+
290
498
  // apps/admin/data/skills.lib/document/bin-src/deck-build.mjs
291
499
  function die(msg, code = 1) {
292
500
  process.stderr.write(`deck-build: ${msg}
@@ -303,11 +511,36 @@ async function main() {
303
511
  } catch (e) {
304
512
  die(`cannot read spec ${specPath}: ${e.message}`, 66);
305
513
  }
306
- const layoutsDir = (0, import_node_path.join)((0, import_node_path.dirname)((0, import_node_path.dirname)(process.argv[1] || "")), "layouts");
514
+ const skillDir = (0, import_node_path.dirname)((0, import_node_path.dirname)(process.argv[1] || ""));
515
+ const layoutsDir = (0, import_node_path.join)(skillDir, "layouts");
516
+ let catalogEntry = null;
517
+ let packLayoutsDir = null;
518
+ const styleId = typeof spec?.style === "string" ? spec.style : null;
519
+ if (styleId) {
520
+ const catalogPath = (0, import_node_path.join)(skillDir, "catalog.json");
521
+ if ((0, import_node_fs.existsSync)(catalogPath)) {
522
+ try {
523
+ const { catalog } = parseCatalog(JSON.parse((0, import_node_fs.readFileSync)(catalogPath, "utf8")));
524
+ catalogEntry = catalog ? resolveEntry(catalog, styleId) : null;
525
+ if (catalogEntry?.kind === "pack") packLayoutsDir = (0, import_node_path.join)(skillDir, "packs", catalogEntry.id, "layouts");
526
+ } catch {
527
+ }
528
+ }
529
+ }
530
+ let fromPack = 0, fromShared = 0;
307
531
  const readLayout = (id) => {
308
532
  if (!/^[a-z0-9-]+$/i.test(id)) return null;
533
+ if (packLayoutsDir) {
534
+ const pp = (0, import_node_path.join)(packLayoutsDir, `${id}.tpl`);
535
+ if ((0, import_node_fs.existsSync)(pp)) {
536
+ fromPack++;
537
+ return (0, import_node_fs.readFileSync)(pp, "utf8");
538
+ }
539
+ }
309
540
  const p = (0, import_node_path.join)(layoutsDir, `${id}.tpl`);
310
- return (0, import_node_fs.existsSync)(p) ? (0, import_node_fs.readFileSync)(p, "utf8") : null;
541
+ if (!(0, import_node_fs.existsSync)(p)) return null;
542
+ if (packLayoutsDir) fromShared++;
543
+ return (0, import_node_fs.readFileSync)(p, "utf8");
311
544
  };
312
545
  const { html, warnings, errors } = assembleDeck(spec, readLayout);
313
546
  for (const w of warnings) process.stderr.write(`deck-build: ${w}
@@ -317,14 +550,49 @@ async function main() {
317
550
  `);
318
551
  die(`${errors.length} spec error(s) \u2014 nothing written (see layouts/slots.json for each layout's slots + rows)`, 1);
319
552
  }
320
- await (0, import_promises.writeFile)(outPath, html, "utf8");
321
- const style = typeof spec?.style === "string" ? spec.style : null;
553
+ const resolved = fromPack + fromShared;
554
+ if (packLayoutsDir && resolved > 0) {
555
+ const ratio = fromShared / resolved;
556
+ if (ratio > 0.4) {
557
+ process.stderr.write(
558
+ `deck-build: pack-dilution \u2014 ${fromShared}/${resolved} \u9875\uFF08${Math.round(ratio * 100)}%\uFF09\u56DE\u843D\u5230\u5171\u4EAB\u7248\u5F0F\uFF0C\u8D85\u8FC7 40% \u9608\u503C\u3002\u5305 "${styleId}" \u7684\u9875\u9762\u6E05\u5355\u76F8\u5BF9\u672C\u6B21\u5185\u5BB9\u91CF\u504F\u8584\uFF0C\u8003\u8651\u6269\u5305\u6216\u6539\u7528 skin\u3002
559
+ `
560
+ );
561
+ }
562
+ }
563
+ let motionPreset = null;
564
+ if (catalogEntry?.motion) {
565
+ const mp = (0, import_node_path.join)(skillDir, catalogEntry.motion);
566
+ if (!(0, import_node_fs.existsSync)(mp)) die(`motion preset not found: ${catalogEntry.motion}`, 66);
567
+ let raw;
568
+ try {
569
+ raw = JSON.parse((0, import_node_fs.readFileSync)(mp, "utf8"));
570
+ } catch (e) {
571
+ die(`cannot parse motion preset ${catalogEntry.motion}: ${e.message}`, 66);
572
+ }
573
+ const mErrors = validateMotionPreset(raw);
574
+ if (mErrors.length) {
575
+ for (const m of mErrors) process.stderr.write(`deck-build: ERROR motion ${m}
576
+ `);
577
+ die(`${mErrors.length} motion preset error(s) \u2014 nothing written`, 1);
578
+ }
579
+ motionPreset = raw;
580
+ }
581
+ let finalHtml = html;
582
+ if (motionPreset) {
583
+ const perSlide = html.split(/(?=<section\b[^>]*\bclass="[^"]*(?<![\w-])slide(?![\w-]))/).filter(Boolean);
584
+ finalHtml = perSlide.map((sec) => {
585
+ const id = sec.match(/data-layout="([a-z0-9-]+)"/i)?.[1];
586
+ return id ? applyMotion(sec, id, motionPreset) : sec;
587
+ }).join("");
588
+ }
589
+ await (0, import_promises.writeFile)(outPath, finalHtml, "utf8");
322
590
  process.stdout.write(JSON.stringify({
323
591
  ok: true,
324
592
  out: outPath,
325
593
  slides: Array.isArray(spec?.slides) ? spec.slides.length : 0,
326
594
  warnings,
327
- next: `html2pptx ${outPath} out.pptx${style ? ` --style ${style}` : " --style <skin>"}`
595
+ next: `html2pptx ${outPath} out.pptx${styleId ? ` --style ${styleId}` : " --style <skin>"}`
328
596
  }, null, 1) + "\n");
329
597
  }
330
598
  main().catch((e) => die(e.message, 1));
@@ -9818,7 +9818,7 @@ var require_lib3 = __commonJS({
9818
9818
  // apps/admin/data/skills.lib/document/bin-src/deck-qa.mjs
9819
9819
  var import_promises = require("node:fs/promises");
9820
9820
 
9821
- // packages/core/dist/fs/doc-design-lint.js
9821
+ // packages/core/dist/document/doc-design-lint.js
9822
9822
  var import_jszip = __toESM(require_lib3(), 1);
9823
9823
  var PLACEHOLDER_RE = /替换为|在这里写|占位|示例文本|Lorem ipsum/i;
9824
9824
  var CJK_TEXT_RE = /[぀-ヿ㐀-䶿一-鿿가-힯豈-﫿]/;
@@ -148976,11 +148976,11 @@ var require_fontkit_umd = __commonJS({
148976
148976
  var import_node_path2 = require("node:path");
148977
148977
  var import_promises2 = require("node:fs/promises");
148978
148978
 
148979
- // packages/core/dist/fs/doc-convert.js
148979
+ // packages/core/dist/document/doc-convert.js
148980
148980
  var import_jszip3 = __toESM(require_lib3(), 1);
148981
148981
  var import_mammoth2 = __toESM(require_lib6(), 1);
148982
148982
 
148983
- // packages/core/dist/fs/office-converter.js
148983
+ // packages/core/dist/document/office-converter.js
148984
148984
  var import_jszip = __toESM(require_lib3(), 1);
148985
148985
  var import_mammoth = __toESM(require_lib6(), 1);
148986
148986
  function isZipMagic(buffer) {
@@ -168101,7 +168101,7 @@ var findPatchKeys = (text) => {
168101
168101
  return (_text$match = text.match(pattern)) !== null && _text$match !== void 0 ? _text$match : [];
168102
168102
  };
168103
168103
 
168104
- // packages/core/dist/fs/doc-gen.js
168104
+ // packages/core/dist/document/doc-gen.js
168105
168105
  var import_exceljs = __toESM(require_excel(), 1);
168106
168106
  var import_jszip2 = __toESM(require_lib3(), 1);
168107
168107
  var import_pptxgenjs = __toESM(require_pptxgen_cjs(), 1);
@@ -168109,7 +168109,7 @@ var import_pdf_lib = __toESM(require_cjs(), 1);
168109
168109
  var import_fontkit = __toESM(require_fontkit_umd(), 1);
168110
168110
  var import_node_fs = require("node:fs");
168111
168111
 
168112
- // packages/core/dist/fs/doc-theme.js
168112
+ // packages/core/dist/document/doc-theme.js
168113
168113
  var DEFAULT_THEME = {
168114
168114
  bestFor: "",
168115
168115
  fonts: { heading: "", body: "" },
@@ -168301,7 +168301,7 @@ function asTheme(themeInput) {
168301
168301
  return themeInput && typeof themeInput === "object" && "warnings" in themeInput ? themeInput : resolveTheme(themeInput);
168302
168302
  }
168303
168303
 
168304
- // packages/core/dist/fs/doc-palette.js
168304
+ // packages/core/dist/document/doc-palette.js
168305
168305
  var PALETTE_LIBRARY = [
168306
168306
  {
168307
168307
  name: "corporate-navy",
@@ -168536,7 +168536,7 @@ function themeSpecFromTopic(topic) {
168536
168536
  return paletteToThemeSpec(resolvePalette(topic));
168537
168537
  }
168538
168538
 
168539
- // packages/core/dist/fs/lucide-icons.js
168539
+ // packages/core/dist/document/lucide-icons.js
168540
168540
  var LUCIDE_ICONS = {
168541
168541
  check: '<path d="M20 6 9 17l-5-5"/>',
168542
168542
  "check-circle": '<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',
@@ -168593,7 +168593,7 @@ function iconSvgDataUri(name, colorHex) {
168593
168593
  return "data:image/svg+xml;base64," + Buffer.from(svg).toString("base64");
168594
168594
  }
168595
168595
 
168596
- // packages/core/dist/fs/doc-gen.js
168596
+ // packages/core/dist/document/doc-gen.js
168597
168597
  function bareHex(c) {
168598
168598
  return c.replace("#", "").toUpperCase();
168599
168599
  }
@@ -170152,10 +170152,10 @@ async function generateDocument(kind, spec, theme) {
170152
170152
  }
170153
170153
  }
170154
170154
 
170155
- // packages/core/dist/fs/doc-html.js
170155
+ // packages/core/dist/document/doc-html.js
170156
170156
  var FONT_STACK = 'TalosCJK, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", "WenQuanYi Zen Hei", sans-serif';
170157
170157
 
170158
- // packages/core/dist/fs/doc-convert.js
170158
+ // packages/core/dist/document/doc-convert.js
170159
170159
  var PRINT_STYLE = `
170160
170160
  @page { size: A4; margin: 20mm 18mm; }
170161
170161
  * { box-sizing: border-box; }
@@ -170266,7 +170266,7 @@ async function convertOfficeToPrintable(buffer, filename) {
170266
170266
  return { error: `\u4E0D\u652F\u6301 ${filename} \u7684\u6587\u4EF6\u683C\u5F0F\uFF08doc-convert \u53EA\u652F\u6301 .docx/.pptx\uFF09` };
170267
170267
  }
170268
170268
 
170269
- // packages/core/dist/fs/soffice.js
170269
+ // packages/core/dist/document/soffice.js
170270
170270
  var import_node_child_process = require("node:child_process");
170271
170271
  var import_node_fs2 = require("node:fs");
170272
170272
  var import_promises = require("node:fs/promises");
@@ -170412,7 +170412,7 @@ function runSoffice(bin, args, timeoutMs) {
170412
170412
  });
170413
170413
  }
170414
170414
 
170415
- // packages/core/dist/fs/office-service.js
170415
+ // packages/core/dist/document/office-service.js
170416
170416
  async function convertViaOfficeService(bytes, filename, url, options = {}) {
170417
170417
  const doFetch = options.fetchImpl ?? fetch;
170418
170418
  const view = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
@@ -16068,7 +16068,7 @@ var require_js = __commonJS({
16068
16068
  var import_promises = require("node:fs/promises");
16069
16069
  var import_node_path = require("node:path");
16070
16070
 
16071
- // packages/core/dist/fs/doc-template.js
16071
+ // packages/core/dist/document/doc-template.js
16072
16072
  var import_docxtemplater = __toESM(require_docxtemplater(), 1);
16073
16073
  var import_pizzip = __toESM(require_js(), 1);
16074
16074
  var DEFAULT_DELIMITERS = { start: "{{", end: "}}" };