hoomanjs 1.47.0 → 1.55.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.
Files changed (246) hide show
  1. package/README.md +42 -18
  2. package/dist/acp/acp-agent.d.ts +3 -3
  3. package/dist/acp/acp-agent.js +16 -11
  4. package/dist/acp/acp-agent.js.map +1 -1
  5. package/dist/acp/approvals.js +11 -10
  6. package/dist/acp/approvals.js.map +1 -1
  7. package/dist/acp/browser.d.ts +9 -0
  8. package/dist/acp/browser.js +23 -0
  9. package/dist/acp/browser.js.map +1 -0
  10. package/dist/acp/meta/vscode.d.ts +8 -7
  11. package/dist/acp/meta/vscode.js +10 -11
  12. package/dist/acp/meta/vscode.js.map +1 -1
  13. package/dist/acp/sessions/store.d.ts +3 -3
  14. package/dist/acp/utils/tool-kind.js +6 -6
  15. package/dist/acp/utils/tool-kind.js.map +1 -1
  16. package/dist/chat/app.js +16 -9
  17. package/dist/chat/app.js.map +1 -1
  18. package/dist/chat/approvals.js +3 -0
  19. package/dist/chat/approvals.js.map +1 -1
  20. package/dist/chat/components/ApprovalPrompt.js +11 -22
  21. package/dist/chat/components/ApprovalPrompt.js.map +1 -1
  22. package/dist/chat/components/StatusBar.js +3 -0
  23. package/dist/chat/components/StatusBar.js.map +1 -1
  24. package/dist/chat/types.d.ts +3 -0
  25. package/dist/cli.js +162 -44
  26. package/dist/cli.js.map +1 -1
  27. package/dist/configure/app.js +46 -29
  28. package/dist/configure/app.js.map +1 -1
  29. package/dist/core/agent/default-retry-strategy.js +46 -12
  30. package/dist/core/agent/default-retry-strategy.js.map +1 -1
  31. package/dist/core/agent/gitignore-guard-plugin.js +17 -2
  32. package/dist/core/agent/gitignore-guard-plugin.js.map +1 -1
  33. package/dist/core/agent/index.js +37 -7
  34. package/dist/core/agent/index.js.map +1 -1
  35. package/dist/core/approvals/allowlist.js +1 -0
  36. package/dist/core/approvals/allowlist.js.map +1 -1
  37. package/dist/core/approvals/intervention.d.ts +10 -2
  38. package/dist/core/approvals/intervention.js +46 -8
  39. package/dist/core/approvals/intervention.js.map +1 -1
  40. package/dist/core/config.d.ts +9 -2
  41. package/dist/core/config.js +8 -4
  42. package/dist/core/config.js.map +1 -1
  43. package/dist/core/index.d.ts +2 -2
  44. package/dist/core/mcp/oauth/service.js +2 -2
  45. package/dist/core/mcp/oauth/service.js.map +1 -1
  46. package/dist/core/models/bedrock.js +6 -0
  47. package/dist/core/models/bedrock.js.map +1 -1
  48. package/dist/core/models/groq.js +34 -14
  49. package/dist/core/models/groq.js.map +1 -1
  50. package/dist/core/models/minimax.js +1 -1
  51. package/dist/core/models/minimax.js.map +1 -1
  52. package/dist/core/models/types.d.ts +10 -2
  53. package/dist/core/models/types.js +1 -0
  54. package/dist/core/models/types.js.map +1 -1
  55. package/dist/core/modes/definitions.d.ts +4 -2
  56. package/dist/core/modes/definitions.js +73 -9
  57. package/dist/core/modes/definitions.js.map +1 -1
  58. package/dist/core/modes/index.d.ts +1 -1
  59. package/dist/core/modes/index.js +1 -1
  60. package/dist/core/modes/index.js.map +1 -1
  61. package/dist/core/modes/registry.js +4 -9
  62. package/dist/core/modes/registry.js.map +1 -1
  63. package/dist/core/modes/schema.d.ts +1 -1
  64. package/dist/core/modes/schema.js +1 -1
  65. package/dist/core/modes/schema.js.map +1 -1
  66. package/dist/core/prompts/agents/{review.md → code-review.md} +2 -2
  67. package/dist/core/prompts/agents/design-review.md +35 -0
  68. package/dist/core/prompts/agents/{test-investigator.md → quality-analyst.md} +2 -2
  69. package/dist/core/prompts/modes/agent.md +2 -0
  70. package/dist/core/prompts/modes/ask.md +2 -2
  71. package/dist/core/prompts/modes/design.md +37 -0
  72. package/dist/core/prompts/modes/plan.md +5 -5
  73. package/dist/core/prompts/{runtime.js → runtime/agents.js} +2 -2
  74. package/dist/core/prompts/runtime/agents.js.map +1 -0
  75. package/dist/core/prompts/runtime/design.d.ts +11 -0
  76. package/dist/core/prompts/runtime/design.js +78 -0
  77. package/dist/core/prompts/runtime/design.js.map +1 -0
  78. package/dist/core/prompts/{session-mode-appendix.js → session-mode.js} +1 -1
  79. package/dist/core/prompts/session-mode.js.map +1 -0
  80. package/dist/core/prompts/static/ask-user.md +3 -2
  81. package/dist/core/prompts/static/fetch.md +2 -1
  82. package/dist/core/prompts/static/filesystem.md +2 -1
  83. package/dist/core/prompts/static/subagents.md +2 -1
  84. package/dist/core/prompts/static/switch-mode.md +10 -0
  85. package/dist/core/prompts/system.d.ts +1 -0
  86. package/dist/core/prompts/system.js +11 -3
  87. package/dist/core/prompts/system.js.map +1 -1
  88. package/dist/core/shell/index.d.ts +1 -1
  89. package/dist/core/shell/index.js +1 -1
  90. package/dist/core/shell/{shell.js → tools.js} +1 -1
  91. package/dist/core/shell/{shell.js.map → tools.js.map} +1 -1
  92. package/dist/core/skills/built-in/hooman-config/SKILL.md +30 -35
  93. package/dist/core/skills/built-in/hooman-config/search.md +5 -3
  94. package/dist/core/skills/built-in/hooman-design/SKILL.md +97 -0
  95. package/dist/core/skills/built-in/hooman-design/assets/article-shell.html +87 -0
  96. package/dist/core/skills/built-in/hooman-design/assets/auth-shell.html +143 -0
  97. package/dist/core/skills/built-in/hooman-design/assets/business-card-shell.html +112 -0
  98. package/dist/core/skills/built-in/hooman-design/assets/contact-shell.html +181 -0
  99. package/dist/core/skills/built-in/hooman-design/assets/dashboard-shell.html +90 -0
  100. package/dist/core/skills/built-in/hooman-design/assets/data-table-shell.html +114 -0
  101. package/dist/core/skills/built-in/hooman-design/assets/deck-shell.html +187 -0
  102. package/dist/core/skills/built-in/hooman-design/assets/dialog-shell.html +98 -0
  103. package/dist/core/skills/built-in/hooman-design/assets/email-shell.html +101 -0
  104. package/dist/core/skills/built-in/hooman-design/assets/empty-state-shell.html +92 -0
  105. package/dist/core/skills/built-in/hooman-design/assets/flyer-shell.html +168 -0
  106. package/dist/core/skills/built-in/hooman-design/assets/invite-shell.html +167 -0
  107. package/dist/core/skills/built-in/hooman-design/assets/landing-shell.html +184 -0
  108. package/dist/core/skills/built-in/hooman-design/assets/mobile-frame-shell.html +109 -0
  109. package/dist/core/skills/built-in/hooman-design/assets/newsletter-shell.html +141 -0
  110. package/dist/core/skills/built-in/hooman-design/assets/onboarding-shell.html +131 -0
  111. package/dist/core/skills/built-in/hooman-design/assets/pricing-shell.html +160 -0
  112. package/dist/core/skills/built-in/hooman-design/assets/prototype-shell.html +83 -0
  113. package/dist/core/skills/built-in/hooman-design/assets/resume-shell.html +228 -0
  114. package/dist/core/skills/built-in/hooman-design/assets/settings-shell.html +196 -0
  115. package/dist/core/skills/built-in/hooman-design/assets/tokens/botanical-calm.css +34 -0
  116. package/dist/core/skills/built-in/hooman-design/assets/tokens/copper-ledger.css +34 -0
  117. package/dist/core/skills/built-in/hooman-design/assets/tokens/editorial-ink.css +34 -0
  118. package/dist/core/skills/built-in/hooman-design/assets/tokens/fintech-clear.css +34 -0
  119. package/dist/core/skills/built-in/hooman-design/assets/tokens/harbor-navy.css +35 -0
  120. package/dist/core/skills/built-in/hooman-design/assets/tokens/midnight-editorial.css +34 -0
  121. package/dist/core/skills/built-in/hooman-design/assets/tokens/night-console.css +34 -0
  122. package/dist/core/skills/built-in/hooman-design/assets/tokens/paper-mono.css +35 -0
  123. package/dist/core/skills/built-in/hooman-design/assets/tokens/signal-mono.css +34 -0
  124. package/dist/core/skills/built-in/hooman-design/assets/tokens/soft-product.css +34 -0
  125. package/dist/core/skills/built-in/hooman-design/assets/tokens/swiss-grid.css +34 -0
  126. package/dist/core/skills/built-in/hooman-design/assets/tokens/warm-atelier.css +34 -0
  127. package/dist/core/skills/built-in/hooman-design/assets/waitlist-shell.html +139 -0
  128. package/dist/core/skills/built-in/hooman-design/craft/accessibility-baseline.md +32 -0
  129. package/dist/core/skills/built-in/hooman-design/craft/anti-ai-slop.md +27 -0
  130. package/dist/core/skills/built-in/hooman-design/craft/color-surfaces.md +45 -0
  131. package/dist/core/skills/built-in/hooman-design/craft/data-viz.md +24 -0
  132. package/dist/core/skills/built-in/hooman-design/craft/deck-slides.md +46 -0
  133. package/dist/core/skills/built-in/hooman-design/craft/forms-validation.md +35 -0
  134. package/dist/core/skills/built-in/hooman-design/craft/iconography.md +19 -0
  135. package/dist/core/skills/built-in/hooman-design/craft/layout-overflow.md +31 -0
  136. package/dist/core/skills/built-in/hooman-design/craft/motion.md +41 -0
  137. package/dist/core/skills/built-in/hooman-design/craft/print.md +37 -0
  138. package/dist/core/skills/built-in/hooman-design/craft/responsive.md +30 -0
  139. package/dist/core/skills/built-in/hooman-design/craft/spacing-density.md +46 -0
  140. package/dist/core/skills/built-in/hooman-design/craft/state-coverage.md +21 -0
  141. package/dist/core/skills/built-in/hooman-design/craft/typography.md +73 -0
  142. package/dist/core/skills/built-in/hooman-design/directions.md +115 -0
  143. package/dist/core/skills/built-in/hooman-design/references/artifact-layout.md +15 -0
  144. package/dist/core/skills/built-in/hooman-design/references/export.md +47 -0
  145. package/dist/core/skills/built-in/hooman-design/references/workflow.md +80 -0
  146. package/dist/core/skills/built-in/hooman-mcp/SKILL.md +2 -2
  147. package/dist/core/state/llm-modality.d.ts +13 -0
  148. package/dist/core/state/llm-modality.js +19 -0
  149. package/dist/core/state/llm-modality.js.map +1 -0
  150. package/dist/core/state/plan.d.ts +1 -1
  151. package/dist/core/state/plan.js +1 -1
  152. package/dist/core/state/tool-approvals.d.ts +12 -9
  153. package/dist/core/state/tool-approvals.js +91 -52
  154. package/dist/core/state/tool-approvals.js.map +1 -1
  155. package/dist/core/state/turn-boundaries.d.ts +1 -1
  156. package/dist/core/state/turn-boundaries.js +1 -1
  157. package/dist/core/subagents/index.d.ts +1 -1
  158. package/dist/core/subagents/index.js +1 -1
  159. package/dist/core/subagents/registry.js +15 -6
  160. package/dist/core/subagents/registry.js.map +1 -1
  161. package/dist/core/subagents/tool.d.ts +8 -2
  162. package/dist/core/subagents/tool.js +93 -44
  163. package/dist/core/subagents/tool.js.map +1 -1
  164. package/dist/core/tools/ask-user.d.ts +1 -1
  165. package/dist/core/tools/ask-user.js +1 -1
  166. package/dist/core/tools/export.d.ts +8 -0
  167. package/dist/core/tools/export.js +202 -0
  168. package/dist/core/tools/export.js.map +1 -0
  169. package/dist/core/tools/fetch.d.ts +2 -0
  170. package/dist/core/tools/fetch.js +92 -55
  171. package/dist/core/tools/fetch.js.map +1 -1
  172. package/dist/core/tools/filesystem.d.ts +2 -1
  173. package/dist/core/tools/filesystem.js +38 -4
  174. package/dist/core/tools/filesystem.js.map +1 -1
  175. package/dist/core/tools/index.d.ts +3 -1
  176. package/dist/core/tools/index.js +3 -1
  177. package/dist/core/tools/index.js.map +1 -1
  178. package/dist/core/tools/preview.d.ts +10 -0
  179. package/dist/core/tools/preview.js +147 -0
  180. package/dist/core/tools/preview.js.map +1 -0
  181. package/dist/core/tools/switch-mode.d.ts +6 -0
  182. package/dist/core/tools/switch-mode.js +188 -0
  183. package/dist/core/tools/switch-mode.js.map +1 -0
  184. package/dist/core/tools/web-search.js +176 -0
  185. package/dist/core/tools/web-search.js.map +1 -1
  186. package/dist/core/utils/browser.d.ts +8 -1
  187. package/dist/core/utils/browser.js +17 -1
  188. package/dist/core/utils/browser.js.map +1 -1
  189. package/dist/core/utils/export-design.d.ts +40 -0
  190. package/dist/core/utils/export-design.js +188 -0
  191. package/dist/core/utils/export-design.js.map +1 -0
  192. package/dist/core/utils/export-figma.d.ts +17 -0
  193. package/dist/core/utils/export-figma.js +189 -0
  194. package/dist/core/utils/export-figma.js.map +1 -0
  195. package/dist/core/utils/export-sketch.d.ts +11 -0
  196. package/dist/core/utils/export-sketch.js +456 -0
  197. package/dist/core/utils/export-sketch.js.map +1 -0
  198. package/dist/core/utils/fig-archive.d.ts +47 -0
  199. package/dist/core/utils/fig-archive.js +181 -0
  200. package/dist/core/utils/fig-archive.js.map +1 -0
  201. package/dist/core/utils/metadata.d.ts +30 -0
  202. package/dist/core/utils/metadata.js +122 -0
  203. package/dist/core/utils/metadata.js.map +1 -1
  204. package/dist/core/utils/models-prefetch.d.ts +53 -0
  205. package/dist/core/utils/models-prefetch.js +469 -0
  206. package/dist/core/utils/models-prefetch.js.map +1 -0
  207. package/dist/core/utils/onboarding-config.d.ts +48 -0
  208. package/dist/core/utils/onboarding-config.js +373 -0
  209. package/dist/core/utils/onboarding-config.js.map +1 -0
  210. package/dist/core/utils/paths.d.ts +9 -7
  211. package/dist/core/utils/paths.js +12 -10
  212. package/dist/core/utils/paths.js.map +1 -1
  213. package/dist/core/utils/preview-server.d.ts +20 -0
  214. package/dist/core/utils/preview-server.js +212 -0
  215. package/dist/core/utils/preview-server.js.map +1 -0
  216. package/dist/core/utils/search-probe.d.ts +19 -0
  217. package/dist/core/utils/search-probe.js +165 -0
  218. package/dist/core/utils/search-probe.js.map +1 -0
  219. package/dist/core/utils/seeds/empty-slides.deck +0 -0
  220. package/dist/core/utils/url-safety.d.ts +2 -0
  221. package/dist/core/utils/url-safety.js +47 -0
  222. package/dist/core/utils/url-safety.js.map +1 -0
  223. package/dist/core/utils/zstd.d.ts +6 -0
  224. package/dist/core/utils/zstd.js +39 -0
  225. package/dist/core/utils/zstd.js.map +1 -0
  226. package/dist/exec/approvals.js +5 -5
  227. package/dist/exec/approvals.js.map +1 -1
  228. package/dist/index.d.ts +9 -3
  229. package/dist/index.js +6 -3
  230. package/dist/index.js.map +1 -1
  231. package/dist/onboarding/app.d.ts +5 -0
  232. package/dist/onboarding/app.js +255 -0
  233. package/dist/onboarding/app.js.map +1 -0
  234. package/dist/onboarding/index.d.ts +5 -0
  235. package/dist/onboarding/index.js +27 -0
  236. package/dist/onboarding/index.js.map +1 -0
  237. package/package.json +16 -3
  238. package/dist/core/prompts/runtime.js.map +0 -1
  239. package/dist/core/prompts/session-mode-appendix.js.map +0 -1
  240. package/dist/core/prompts/static/planning.md +0 -3
  241. package/dist/core/tools/plan.d.ts +0 -5
  242. package/dist/core/tools/plan.js +0 -150
  243. package/dist/core/tools/plan.js.map +0 -1
  244. /package/dist/core/prompts/{runtime.d.ts → runtime/agents.d.ts} +0 -0
  245. /package/dist/core/prompts/{session-mode-appendix.d.ts → session-mode.d.ts} +0 -0
  246. /package/dist/core/shell/{shell.d.ts → tools.d.ts} +0 -0
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Screenshot-backed Figma Design (.fig) and Slides (.deck) writers.
3
+ * Same idea as PPTX: one full-bleed image per frame / slide.
4
+ */
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { dirname, join } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { createEmptyFigDoc, parseFig, } from "openfig-core";
9
+ import { createPlaceholderThumbnail, encodeFigArchive, FIG_BASE, figImagePaint, IDENTITY, maxLocalId, rebuildFigMaps, siblingPosition, } from "./fig-archive.js";
10
+ const FIGMA_SLIDES_WIDTH = 1920;
11
+ const FIGMA_SLIDES_HEIGHT = 1080;
12
+ const FRAME_GAP = 80;
13
+ function seedDeckPath() {
14
+ return join(dirname(fileURLToPath(import.meta.url)), "seeds", "empty-slides.deck");
15
+ }
16
+ function ensureMessageEnvelope(doc) {
17
+ const msg = doc.message;
18
+ msg.sessionID = msg.sessionID ?? 0;
19
+ msg.ackID = msg.ackID ?? 0;
20
+ msg.blobs = msg.blobs ?? [];
21
+ }
22
+ async function loadEmptyDeckDoc(title) {
23
+ const path = seedDeckPath();
24
+ if (!existsSync(path)) {
25
+ throw new Error(`Missing Figma Slides seed at ${path}. Rebuild with copy-bundled-assets.`);
26
+ }
27
+ const doc = await parseFig(readFileSync(path));
28
+ doc.header = { ...doc.header, prelude: "fig-deck" };
29
+ ensureMessageEnvelope(doc);
30
+ doc.meta = {
31
+ ...(doc.meta ?? {}),
32
+ file_name: title,
33
+ };
34
+ doc.thumbnail = createPlaceholderThumbnail();
35
+ if (!doc.images) {
36
+ doc.images = new Map();
37
+ }
38
+ rebuildFigMaps(doc);
39
+ return doc;
40
+ }
41
+ /**
42
+ * Screenshot pages → simple Design `.fig` (one frame per page, image fill).
43
+ */
44
+ export async function buildScreenshotFig(images, opts = {}) {
45
+ if (images.length === 0) {
46
+ throw new Error("no pages to export");
47
+ }
48
+ const title = opts.title ?? "Untitled";
49
+ const doc = createEmptyFigDoc();
50
+ ensureMessageEnvelope(doc);
51
+ doc.meta = { file_name: title, version: 0 };
52
+ doc.thumbnail = createPlaceholderThumbnail();
53
+ doc.images = new Map();
54
+ const pageGuid = { sessionID: 0, localID: 1 };
55
+ let nextLocal = maxLocalId(doc) + 1;
56
+ let offsetX = 0;
57
+ for (let i = 0; i < images.length; i++) {
58
+ const img = images[i];
59
+ const paint = figImagePaint(doc, new Uint8Array(img.buffer), img.width, img.height);
60
+ doc.message.nodeChanges.push({
61
+ ...FIG_BASE,
62
+ guid: { sessionID: 1, localID: nextLocal++ },
63
+ type: "FRAME",
64
+ name: images.length === 1 ? title : `Page ${i + 1}`,
65
+ parentIndex: { guid: pageGuid, position: siblingPosition(i) },
66
+ size: { x: img.width, y: img.height },
67
+ transform: { ...IDENTITY, m02: offsetX, m12: 0 },
68
+ fillPaints: [paint],
69
+ frameMaskDisabled: false,
70
+ proportionsConstrained: true,
71
+ });
72
+ offsetX += img.width + FRAME_GAP;
73
+ }
74
+ rebuildFigMaps(doc);
75
+ const bytes = await encodeFigArchive(doc, {
76
+ prelude: "fig-kiwi",
77
+ fileName: title,
78
+ thumbnail: doc.thumbnail,
79
+ });
80
+ return Buffer.from(bytes);
81
+ }
82
+ /**
83
+ * Screenshot pages → simple Slides `.deck` (one slide per page, full-bleed image).
84
+ */
85
+ export async function buildScreenshotDeck(images, opts = {}) {
86
+ if (images.length === 0) {
87
+ throw new Error("no slides to export");
88
+ }
89
+ const title = opts.title ?? "Untitled";
90
+ const doc = await loadEmptyDeckDoc(title);
91
+ const slideW = FIGMA_SLIDES_WIDTH;
92
+ const slideH = FIGMA_SLIDES_HEIGHT;
93
+ const gridPadding = 240;
94
+ const rowGap = slideW + 240;
95
+ let nodes = doc.message.nodeChanges;
96
+ const row = nodes.find((n) => n.type === "SLIDE_ROW");
97
+ if (!row) {
98
+ throw new Error("buildScreenshotDeck: seed missing SLIDE_ROW");
99
+ }
100
+ const rowGuid = { ...row.guid };
101
+ const placeholder = nodes.find((n) => n.type === "SLIDE");
102
+ const themeID = placeholder?.themeID;
103
+ const sourceLibraryKey = placeholder?.sourceLibraryKey;
104
+ const placeholderKey = placeholder
105
+ ? `${placeholder.guid.sessionID}:${placeholder.guid.localID}`
106
+ : null;
107
+ if (placeholderKey) {
108
+ const [ps, pl] = placeholderKey.split(":").map(Number);
109
+ nodes = nodes.filter((n) => !(n.guid.sessionID === ps && n.guid.localID === pl) &&
110
+ !(n.parentIndex?.guid?.sessionID === ps &&
111
+ n.parentIndex?.guid?.localID === pl));
112
+ doc.message.nodeChanges = nodes;
113
+ }
114
+ const slideCount = images.length;
115
+ const gridW = slideCount * slideW + (slideCount - 1) * 240 + gridPadding * 2;
116
+ const gridH = slideH + gridPadding * 2;
117
+ const grid = nodes.find((n) => n.type === "SLIDE_GRID");
118
+ if (grid) {
119
+ grid.size = { x: gridW, y: gridH };
120
+ }
121
+ row.size = {
122
+ x: slideCount * slideW + (slideCount - 1) * 240,
123
+ y: slideH,
124
+ };
125
+ if (doc.meta && typeof doc.meta === "object") {
126
+ const meta = doc.meta;
127
+ const clientMeta = meta.client_meta;
128
+ if (clientMeta?.render_coordinates) {
129
+ clientMeta.render_coordinates = {
130
+ x: 0,
131
+ y: 0,
132
+ width: gridW,
133
+ height: gridH,
134
+ };
135
+ }
136
+ meta.file_name = title;
137
+ }
138
+ let nextLocal = maxLocalId(doc) + 1;
139
+ for (let i = 0; i < images.length; i++) {
140
+ const img = images[i];
141
+ const slideGuid = { sessionID: 1, localID: nextLocal++ };
142
+ const imageGuid = { sessionID: 1, localID: nextLocal++ };
143
+ const paint = figImagePaint(doc, new Uint8Array(img.buffer), img.width, img.height);
144
+ nodes.push({
145
+ ...FIG_BASE,
146
+ guid: slideGuid,
147
+ type: "SLIDE",
148
+ name: String(i + 1),
149
+ parentIndex: { guid: rowGuid, position: siblingPosition(i) },
150
+ size: { x: slideW, y: slideH },
151
+ transform: { ...IDENTITY, m02: i * rowGap },
152
+ strokeWeight: 1,
153
+ strokeAlign: "INSIDE",
154
+ strokeJoin: "MITER",
155
+ fillPaints: [
156
+ {
157
+ type: "SOLID",
158
+ color: { r: 1, g: 1, b: 1, a: 1 },
159
+ opacity: 1,
160
+ visible: true,
161
+ blendMode: "NORMAL",
162
+ },
163
+ ],
164
+ frameMaskDisabled: false,
165
+ themeID,
166
+ sourceLibraryKey,
167
+ });
168
+ nodes.push({
169
+ ...FIG_BASE,
170
+ guid: imageGuid,
171
+ type: "ROUNDED_RECTANGLE",
172
+ name: "Screenshot",
173
+ parentIndex: { guid: slideGuid, position: "!" },
174
+ size: { x: slideW, y: slideH },
175
+ transform: { ...IDENTITY },
176
+ proportionsConstrained: true,
177
+ fillPaints: [{ ...paint, imageScaleMode: "FILL" }],
178
+ });
179
+ }
180
+ rebuildFigMaps(doc);
181
+ const bytes = await encodeFigArchive(doc, {
182
+ prelude: "fig-deck",
183
+ fileName: title,
184
+ thumbnail: doc.thumbnail ?? createPlaceholderThumbnail(),
185
+ includeImagesDir: true,
186
+ });
187
+ return Buffer.from(bytes);
188
+ }
189
+ //# sourceMappingURL=export-figma.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export-figma.js","sourceRoot":"","sources":["../../../src/core/utils/export-figma.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Screenshot-backed Sketch (.sketch) writer.
3
+ * Same idea as PPTX: one full-bleed artboard per page with a pattern image fill.
4
+ */
5
+ import type { RenderedPage } from "./export-design.js";
6
+ /**
7
+ * Screenshot pages → simple `.sketch` (one artboard per page, image pattern fill).
8
+ */
9
+ export declare function buildScreenshotSketch(images: RenderedPage[], opts?: {
10
+ title?: string;
11
+ }): Buffer;
@@ -0,0 +1,456 @@
1
+ /**
2
+ * Screenshot-backed Sketch (.sketch) writer.
3
+ * Same idea as PPTX: one full-bleed artboard per page with a pattern image fill.
4
+ */
5
+ import { createHash, randomUUID } from "node:crypto";
6
+ import { zipSync } from "fflate";
7
+ import * as FileFormat from "@sketch-hq/sketch-file-format-ts/dist/esm/types.js";
8
+ import { deflateSync } from "node:zlib";
9
+ function sketchId() {
10
+ return randomUUID().toUpperCase();
11
+ }
12
+ function createPlaceholderPng(width = 400, height = 260, rgb = [0xf5, 0xf7, 0xfa]) {
13
+ const row = Buffer.alloc(1 + width * 3);
14
+ row[0] = 0;
15
+ for (let x = 0; x < width; x++) {
16
+ const o = 1 + x * 3;
17
+ row[o] = rgb[0];
18
+ row[o + 1] = rgb[1];
19
+ row[o + 2] = rgb[2];
20
+ }
21
+ const raw = Buffer.alloc(height * row.length);
22
+ for (let i = 0; i < height; i++) {
23
+ row.copy(raw, i * row.length);
24
+ }
25
+ const idat = deflateSync(raw);
26
+ const crcTable = new Uint32Array(256);
27
+ for (let n = 0; n < 256; n++) {
28
+ let c = n;
29
+ for (let k = 0; k < 8; k++) {
30
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
31
+ }
32
+ crcTable[n] = c >>> 0;
33
+ }
34
+ const crc32 = (buf) => {
35
+ let c = 0xffffffff;
36
+ for (const b of buf) {
37
+ c = (crcTable[(c ^ b) & 0xff] ^ (c >>> 8)) >>> 0;
38
+ }
39
+ return (c ^ 0xffffffff) >>> 0;
40
+ };
41
+ const chunk = (type, data) => {
42
+ const len = Buffer.alloc(4);
43
+ len.writeUInt32BE(data.length, 0);
44
+ const t = Buffer.from(type, "ascii");
45
+ const crc = Buffer.alloc(4);
46
+ crc.writeUInt32BE(crc32(Buffer.concat([t, data])), 0);
47
+ return Buffer.concat([len, t, data, crc]);
48
+ };
49
+ const sig = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
50
+ const ihdr = Buffer.alloc(13);
51
+ ihdr.writeUInt32BE(width, 0);
52
+ ihdr.writeUInt32BE(height, 4);
53
+ ihdr[8] = 8;
54
+ ihdr[9] = 2;
55
+ return new Uint8Array(Buffer.concat([
56
+ sig,
57
+ chunk("IHDR", ihdr),
58
+ chunk("IDAT", idat),
59
+ chunk("IEND", Buffer.alloc(0)),
60
+ ]));
61
+ }
62
+ const DEFAULT_EXPORT_OPTIONS = {
63
+ _class: "exportOptions",
64
+ includedLayerIds: [],
65
+ layerOptions: 0,
66
+ shouldTrim: false,
67
+ exportFormats: [],
68
+ };
69
+ const DEFAULT_RULER = {
70
+ _class: "rulerData",
71
+ base: 0,
72
+ guides: [],
73
+ };
74
+ function emptyStyle(opacity = 1) {
75
+ return {
76
+ _class: "style",
77
+ do_objectID: sketchId(),
78
+ endMarkerType: FileFormat.MarkerType.OpenArrow,
79
+ miterLimit: 10,
80
+ startMarkerType: FileFormat.MarkerType.OpenArrow,
81
+ windingRule: FileFormat.WindingRule.EvenOdd,
82
+ blur: {
83
+ _class: "blur",
84
+ isEnabled: false,
85
+ center: "{0.5, 0.5}",
86
+ motionAngle: 0,
87
+ radius: 10,
88
+ saturation: 1,
89
+ type: FileFormat.BlurType.Gaussian,
90
+ },
91
+ borderOptions: {
92
+ _class: "borderOptions",
93
+ isEnabled: true,
94
+ dashPattern: [],
95
+ lineCapStyle: FileFormat.LineCapStyle.Butt,
96
+ lineJoinStyle: FileFormat.LineJoinStyle.Miter,
97
+ },
98
+ borders: [],
99
+ colorControls: {
100
+ _class: "colorControls",
101
+ isEnabled: false,
102
+ brightness: 0,
103
+ contrast: 1,
104
+ hue: 0,
105
+ saturation: 1,
106
+ },
107
+ contextSettings: {
108
+ _class: "graphicsContextSettings",
109
+ blendMode: FileFormat.BlendMode.Normal,
110
+ opacity,
111
+ },
112
+ fills: [],
113
+ innerShadows: [],
114
+ shadows: [],
115
+ };
116
+ }
117
+ function emptyGradient() {
118
+ return {
119
+ _class: "gradient",
120
+ elipseLength: 0,
121
+ from: "{0.5, 0}",
122
+ gradientType: FileFormat.GradientType.Linear,
123
+ to: "{0.5, 1}",
124
+ stops: [
125
+ {
126
+ _class: "gradientStop",
127
+ position: 0,
128
+ color: {
129
+ _class: "color",
130
+ red: 0,
131
+ green: 0,
132
+ blue: 0,
133
+ alpha: 1,
134
+ },
135
+ },
136
+ {
137
+ _class: "gradientStop",
138
+ position: 1,
139
+ color: {
140
+ _class: "color",
141
+ red: 0,
142
+ green: 0,
143
+ blue: 0,
144
+ alpha: 1,
145
+ },
146
+ },
147
+ ],
148
+ };
149
+ }
150
+ function cornerPoints(_w, _h) {
151
+ return [
152
+ {
153
+ _class: "curvePoint",
154
+ cornerRadius: 0,
155
+ cornerStyle: FileFormat.CornerStyle.Rounded,
156
+ curveFrom: "{0, 0}",
157
+ curveTo: "{0, 0}",
158
+ hasCurveFrom: false,
159
+ hasCurveTo: false,
160
+ point: "{0, 0}",
161
+ },
162
+ {
163
+ _class: "curvePoint",
164
+ cornerRadius: 0,
165
+ cornerStyle: FileFormat.CornerStyle.Rounded,
166
+ curveFrom: "{1, 0}",
167
+ curveTo: "{1, 0}",
168
+ hasCurveFrom: false,
169
+ hasCurveTo: false,
170
+ point: "{1, 0}",
171
+ },
172
+ {
173
+ _class: "curvePoint",
174
+ cornerRadius: 0,
175
+ cornerStyle: FileFormat.CornerStyle.Rounded,
176
+ curveFrom: "{1, 1}",
177
+ curveTo: "{1, 1}",
178
+ hasCurveFrom: false,
179
+ hasCurveTo: false,
180
+ point: "{1, 1}",
181
+ },
182
+ {
183
+ _class: "curvePoint",
184
+ cornerRadius: 0,
185
+ cornerStyle: FileFormat.CornerStyle.Rounded,
186
+ curveFrom: "{0, 1}",
187
+ curveTo: "{0, 1}",
188
+ hasCurveFrom: false,
189
+ hasCurveTo: false,
190
+ point: "{0, 1}",
191
+ },
192
+ ];
193
+ }
194
+ /**
195
+ * Screenshot pages → simple `.sketch` (one artboard per page, image pattern fill).
196
+ */
197
+ export function buildScreenshotSketch(images, opts = {}) {
198
+ if (images.length === 0) {
199
+ throw new Error("no pages to export");
200
+ }
201
+ const title = opts.title ?? "Untitled";
202
+ const pageId = sketchId();
203
+ const documentId = sketchId();
204
+ const imagesMap = new Map();
205
+ const artboards = [];
206
+ const artboardMeta = {};
207
+ let cursorX = 0;
208
+ const gap = 80;
209
+ for (let i = 0; i < images.length; i++) {
210
+ const img = images[i];
211
+ const bytes = new Uint8Array(img.buffer);
212
+ const sha1 = createHash("sha1").update(bytes).digest("hex");
213
+ imagesMap.set(sha1, bytes);
214
+ const imageRef = {
215
+ _class: "MSJSONFileReference",
216
+ _ref_class: "MSImageData",
217
+ _ref: `images/${sha1}`,
218
+ };
219
+ const fillStyle = emptyStyle(1);
220
+ fillStyle.fills = [
221
+ {
222
+ _class: "fill",
223
+ isEnabled: true,
224
+ fillType: FileFormat.FillType.Pattern,
225
+ color: {
226
+ _class: "color",
227
+ red: 0,
228
+ green: 0,
229
+ blue: 0,
230
+ alpha: 1,
231
+ },
232
+ contextSettings: {
233
+ _class: "graphicsContextSettings",
234
+ blendMode: FileFormat.BlendMode.Normal,
235
+ opacity: 1,
236
+ },
237
+ gradient: emptyGradient(),
238
+ image: imageRef,
239
+ noiseIndex: 0,
240
+ noiseIntensity: 0,
241
+ patternFillType: FileFormat.PatternFillType.Fill,
242
+ patternTileScale: 1,
243
+ },
244
+ ];
245
+ const rect = {
246
+ _class: "rectangle",
247
+ do_objectID: sketchId(),
248
+ booleanOperation: FileFormat.BooleanOperation.None,
249
+ isFixedToViewport: false,
250
+ isFlippedHorizontal: false,
251
+ isFlippedVertical: false,
252
+ isLocked: false,
253
+ isTemplate: false,
254
+ isVisible: true,
255
+ layerListExpandedType: FileFormat.LayerListExpanded.Undecided,
256
+ name: "Screenshot",
257
+ nameIsFixed: true,
258
+ resizingConstraint: 63,
259
+ resizingType: FileFormat.ResizeType.Stretch,
260
+ rotation: 0,
261
+ shouldBreakMaskChain: false,
262
+ exportOptions: { ...DEFAULT_EXPORT_OPTIONS },
263
+ frame: {
264
+ _class: "rect",
265
+ constrainProportions: false,
266
+ height: img.height,
267
+ width: img.width,
268
+ x: 0,
269
+ y: 0,
270
+ },
271
+ clippingMaskMode: 0,
272
+ hasClippingMask: false,
273
+ style: fillStyle,
274
+ edited: false,
275
+ isClosed: true,
276
+ pointRadiusBehaviour: FileFormat.PointsRadiusBehaviour.Rounded,
277
+ points: cornerPoints(img.width, img.height),
278
+ fixedRadius: 0,
279
+ needsConvertionToNewRoundCorners: false,
280
+ hasConvertedToNewRoundCorners: true,
281
+ };
282
+ const artboardId = sketchId();
283
+ const name = images.length === 1 ? title : `Page ${i + 1}`;
284
+ artboards.push({
285
+ _class: "artboard",
286
+ do_objectID: artboardId,
287
+ booleanOperation: FileFormat.BooleanOperation.None,
288
+ isFixedToViewport: false,
289
+ isFlippedHorizontal: false,
290
+ isFlippedVertical: false,
291
+ isLocked: false,
292
+ isTemplate: false,
293
+ isVisible: true,
294
+ layerListExpandedType: FileFormat.LayerListExpanded.Expanded,
295
+ name,
296
+ nameIsFixed: true,
297
+ resizingConstraint: 63,
298
+ resizingType: FileFormat.ResizeType.Stretch,
299
+ rotation: 0,
300
+ shouldBreakMaskChain: false,
301
+ exportOptions: { ...DEFAULT_EXPORT_OPTIONS },
302
+ frame: {
303
+ _class: "rect",
304
+ constrainProportions: false,
305
+ height: img.height,
306
+ width: img.width,
307
+ x: cursorX,
308
+ y: 0,
309
+ },
310
+ clippingMaskMode: 0,
311
+ hasClippingMask: false,
312
+ style: emptyStyle(1),
313
+ hasClickThrough: true,
314
+ groupLayout: { _class: "MSImmutableFreeformGroupLayout" },
315
+ layers: [rect],
316
+ horizontalRulerData: { ...DEFAULT_RULER },
317
+ verticalRulerData: { ...DEFAULT_RULER },
318
+ isFlowHome: false,
319
+ resizesContent: false,
320
+ backgroundColor: {
321
+ _class: "color",
322
+ red: 1,
323
+ green: 1,
324
+ blue: 1,
325
+ alpha: 1,
326
+ },
327
+ hasBackgroundColor: false,
328
+ includeBackgroundColorInExport: false,
329
+ includeBackgroundColorInInstance: false,
330
+ });
331
+ artboardMeta[artboardId] = { name };
332
+ cursorX += img.width + gap;
333
+ }
334
+ const page = {
335
+ _class: "page",
336
+ do_objectID: pageId,
337
+ booleanOperation: FileFormat.BooleanOperation.None,
338
+ isFixedToViewport: false,
339
+ isFlippedHorizontal: false,
340
+ isFlippedVertical: false,
341
+ isLocked: false,
342
+ isTemplate: false,
343
+ isVisible: true,
344
+ layerListExpandedType: FileFormat.LayerListExpanded.Undecided,
345
+ name: "Page 1",
346
+ nameIsFixed: false,
347
+ resizingConstraint: 63,
348
+ resizingType: FileFormat.ResizeType.Stretch,
349
+ rotation: 0,
350
+ shouldBreakMaskChain: false,
351
+ exportOptions: { ...DEFAULT_EXPORT_OPTIONS },
352
+ frame: {
353
+ _class: "rect",
354
+ constrainProportions: false,
355
+ height: 0,
356
+ width: 0,
357
+ x: 0,
358
+ y: 0,
359
+ },
360
+ clippingMaskMode: 0,
361
+ hasClippingMask: false,
362
+ style: emptyStyle(),
363
+ hasClickThrough: true,
364
+ groupLayout: { _class: "MSImmutableFreeformGroupLayout" },
365
+ layers: artboards,
366
+ horizontalRulerData: { ...DEFAULT_RULER },
367
+ verticalRulerData: { ...DEFAULT_RULER },
368
+ };
369
+ const document = {
370
+ _class: "document",
371
+ do_objectID: documentId,
372
+ colorSpace: FileFormat.ColorSpace.Unmanaged,
373
+ currentPageIndex: 0,
374
+ assets: {
375
+ _class: "assetCollection",
376
+ do_objectID: sketchId(),
377
+ images: [],
378
+ colorAssets: [],
379
+ exportPresets: [],
380
+ gradientAssets: [],
381
+ colors: [],
382
+ gradients: [],
383
+ },
384
+ foreignLayerStyles: [],
385
+ foreignSymbols: [],
386
+ foreignTextStyles: [],
387
+ foreignSwatches: [],
388
+ layerStyles: { _class: "sharedStyleContainer", objects: [] },
389
+ layerSymbols: { _class: "symbolContainer", objects: [] },
390
+ layerTextStyles: {
391
+ _class: "sharedTextStyleContainer",
392
+ objects: [],
393
+ },
394
+ sharedSwatches: { _class: "swatchContainer", objects: [] },
395
+ perDocumentLibraries: [],
396
+ pages: [
397
+ {
398
+ _class: "MSJSONFileReference",
399
+ _ref_class: "MSImmutablePage",
400
+ _ref: `pages/${pageId}`,
401
+ },
402
+ ],
403
+ };
404
+ const meta = {
405
+ commit: "0000000000000000000000000000000000000000",
406
+ pagesAndArtboards: {
407
+ [pageId]: {
408
+ name: "Page 1",
409
+ artboards: artboardMeta,
410
+ },
411
+ },
412
+ version: 134,
413
+ fonts: [],
414
+ compatibilityVersion: 99,
415
+ app: FileFormat.BundleId.PublicRelease,
416
+ autosaved: 0,
417
+ variant: "NONAPPSTORE",
418
+ created: {
419
+ commit: "0000000000000000000000000000000000000000",
420
+ appVersion: "99",
421
+ build: 0,
422
+ app: FileFormat.BundleId.PublicRelease,
423
+ compatibilityVersion: 99,
424
+ version: 134,
425
+ variant: "NONAPPSTORE",
426
+ },
427
+ saveHistory: ["NONAPPSTORE.0"],
428
+ appVersion: "99",
429
+ build: 0,
430
+ };
431
+ const user = {
432
+ document: {
433
+ pageListHeight: 85,
434
+ pageListCollapsed: 0,
435
+ },
436
+ [pageId]: {
437
+ scrollOrigin: "{0, 0}",
438
+ zoomValue: 1,
439
+ },
440
+ };
441
+ const enc = new TextEncoder();
442
+ const files = {
443
+ [`pages/${pageId}.json`]: enc.encode(JSON.stringify(page)),
444
+ "document.json": enc.encode(JSON.stringify(document)),
445
+ "meta.json": enc.encode(JSON.stringify(meta)),
446
+ "user.json": enc.encode(JSON.stringify(user)),
447
+ "previews/preview.png": images[0] != null
448
+ ? new Uint8Array(images[0].buffer)
449
+ : createPlaceholderPng(),
450
+ };
451
+ for (const [sha1, bytes] of imagesMap) {
452
+ files[`images/${sha1}`] = bytes;
453
+ }
454
+ return Buffer.from(zipSync(files, { level: 6 }));
455
+ }
456
+ //# sourceMappingURL=export-sketch.js.map