@tomako/tools-runtime 0.1.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 (531) hide show
  1. package/README.md +12 -0
  2. package/package.json +629 -0
  3. package/src/assets/icons/brands/social/bluesky-icon.tsx +9 -0
  4. package/src/assets/icons/brands/social/facebook-icon.tsx +9 -0
  5. package/src/assets/icons/brands/social/index.ts +8 -0
  6. package/src/assets/icons/brands/social/instagram-icon.tsx +9 -0
  7. package/src/assets/icons/brands/social/linkedin-icon.tsx +9 -0
  8. package/src/assets/icons/brands/social/threads-icon.tsx +9 -0
  9. package/src/assets/icons/brands/social/tiktok-icon.tsx +10 -0
  10. package/src/assets/icons/brands/social/x-icon.tsx +9 -0
  11. package/src/assets/icons/brands/social/youtube-icon.tsx +9 -0
  12. package/src/assets/icons/social-profile/facebook-icon.tsx +12 -0
  13. package/src/assets/icons/social-profile/index.ts +29 -0
  14. package/src/assets/icons/social-profile/instagram-icon.tsx +18 -0
  15. package/src/assets/icons/social-profile/linkedin-icon.tsx +12 -0
  16. package/src/assets/icons/social-profile/tiktok-icon.tsx +12 -0
  17. package/src/assets/icons/social-profile/x-icon.tsx +13 -0
  18. package/src/assets/icons/social-profile/youtube-icon.tsx +12 -0
  19. package/src/components/tools/engine/form-builder.tsx +219 -0
  20. package/src/components/tools/engine/package-widget-loader.tsx +38 -0
  21. package/src/components/tools/engine/package-widget-runtime.tsx +409 -0
  22. package/src/components/tools/engine/package-widget.tsx +77 -0
  23. package/src/components/tools/engine/result-view.tsx +596 -0
  24. package/src/components/tools/engine/use-legacy-llm-task.ts +64 -0
  25. package/src/components/tools/engine/use-tool-task.ts +195 -0
  26. package/src/components/tools/market-forecast-report.tsx +1150 -0
  27. package/src/components/tools/registry.ts +13 -0
  28. package/src/components/tools/workspace/index.ts +39 -0
  29. package/src/components/tools/workspace/tool-action-bar.tsx +99 -0
  30. package/src/components/tools/workspace/tool-empty-panel.tsx +32 -0
  31. package/src/components/tools/workspace/tool-error-panel.tsx +40 -0
  32. package/src/components/tools/workspace/tool-field.tsx +124 -0
  33. package/src/components/tools/workspace/tool-file-upload.tsx +112 -0
  34. package/src/components/tools/workspace/tool-form-section.tsx +21 -0
  35. package/src/components/tools/workspace/tool-form-shell.tsx +36 -0
  36. package/src/components/tools/workspace/tool-loading-panel.tsx +269 -0
  37. package/src/components/tools/workspace/tool-option-row.tsx +97 -0
  38. package/src/components/tools/workspace/tool-preview-panel.tsx +31 -0
  39. package/src/components/tools/workspace/tool-result-actions.tsx +67 -0
  40. package/src/components/tools/workspace/tool-result-file-actions.ts +31 -0
  41. package/src/components/tools/workspace/tool-result-header.tsx +39 -0
  42. package/src/components/tools/workspace/tool-status.tsx +13 -0
  43. package/src/components/tools/workspace/tool-workspace-layout.tsx +226 -0
  44. package/src/constants/LKS.ts +29 -0
  45. package/src/constants/related-tools.ts +18 -0
  46. package/src/constants/social-profile-kit.ts +284 -0
  47. package/src/constants/tool-assets.ts +7 -0
  48. package/src/env.d.ts +3 -0
  49. package/src/features/tools/_templates/standard-tool.container.tsx +90 -0
  50. package/src/features/tools/app-icon-resizer/app-icon-resizer.container.tsx +11 -0
  51. package/src/features/tools/app-icon-resizer/app-icon-resizer.spec.ts +15 -0
  52. package/src/features/tools/app-icon-resizer/widget/app-icon-resizer.tsx +444 -0
  53. package/src/features/tools/app-icon-resizer/widget/constants.ts +19 -0
  54. package/src/features/tools/app-icon-resizer/widget/helpers.ts +314 -0
  55. package/src/features/tools/app-icon-resizer/widget/index.ts +7 -0
  56. package/src/features/tools/app-icon-resizer/widget/platform-icons.tsx +59 -0
  57. package/src/features/tools/app-icon-resizer/widget/preview-dialogs.tsx +139 -0
  58. package/src/features/tools/app-icon-resizer/widget/result-shell.tsx +165 -0
  59. package/src/features/tools/app-icon-resizer/widget/types.ts +36 -0
  60. package/src/features/tools/app-store-screenshot-generator/app-store-screenshot-generator.container.tsx +108 -0
  61. package/src/features/tools/app-store-screenshot-generator/app-store-screenshot-generator.spec.ts +14 -0
  62. package/src/features/tools/app-store-screenshot-generator/config.ts +3 -0
  63. package/src/features/tools/app-store-screenshot-generator/widget/app-store-screenshot-generator.tsx +1250 -0
  64. package/src/features/tools/app-store-screenshot-generator/widget/asset-slots.ts +76 -0
  65. package/src/features/tools/app-store-screenshot-generator/widget/constants.ts +43 -0
  66. package/src/features/tools/app-store-screenshot-generator/widget/form-controls.tsx +214 -0
  67. package/src/features/tools/app-store-screenshot-generator/widget/generation.ts +528 -0
  68. package/src/features/tools/app-store-screenshot-generator/widget/index.ts +7 -0
  69. package/src/features/tools/app-store-screenshot-generator/widget/input-media.ts +175 -0
  70. package/src/features/tools/app-store-screenshot-generator/widget/types.ts +60 -0
  71. package/src/features/tools/app-store-screenshot-generator/widget/zip.ts +119 -0
  72. package/src/features/tools/build-in-public-story-generator/build-in-public-story-generator.container.tsx +135 -0
  73. package/src/features/tools/build-in-public-story-generator/build-in-public-story-generator.spec.ts +15 -0
  74. package/src/features/tools/build-in-public-story-generator/widget/build-in-public-story-generator.tsx +314 -0
  75. package/src/features/tools/build-in-public-story-generator/widget/constants.ts +3 -0
  76. package/src/features/tools/build-in-public-story-generator/widget/helpers.ts +25 -0
  77. package/src/features/tools/build-in-public-story-generator/widget/index.ts +7 -0
  78. package/src/features/tools/build-in-public-story-generator/widget/preview-panels.tsx +58 -0
  79. package/src/features/tools/build-in-public-story-generator/widget/result-shell.tsx +164 -0
  80. package/src/features/tools/build-in-public-story-generator/widget/types.ts +6 -0
  81. package/src/features/tools/cold-start-channel-selector/cold-start-channel-selector.container.tsx +30 -0
  82. package/src/features/tools/cold-start-channel-selector/cold-start-channel-selector.spec.ts +15 -0
  83. package/src/features/tools/cold-start-channel-selector/widget/cold-start-channel-selector.tsx +417 -0
  84. package/src/features/tools/cold-start-channel-selector/widget/constants.ts +46 -0
  85. package/src/features/tools/cold-start-channel-selector/widget/form-controls.tsx +41 -0
  86. package/src/features/tools/cold-start-channel-selector/widget/helpers.ts +75 -0
  87. package/src/features/tools/cold-start-channel-selector/widget/index.ts +7 -0
  88. package/src/features/tools/cold-start-channel-selector/widget/preview-panels.tsx +250 -0
  89. package/src/features/tools/cold-start-channel-selector/widget/result-shell.tsx +199 -0
  90. package/src/features/tools/cold-start-channel-selector/widget/types.ts +21 -0
  91. package/src/features/tools/commercial-bp-generator/commercial-bp-generator.container.tsx +102 -0
  92. package/src/features/tools/commercial-bp-generator/commercial-bp-generator.spec.ts +14 -0
  93. package/src/features/tools/commercial-bp-generator/widget/commercial-bp-generator.tsx +676 -0
  94. package/src/features/tools/commercial-bp-generator/widget/constants.ts +32 -0
  95. package/src/features/tools/commercial-bp-generator/widget/helpers.ts +147 -0
  96. package/src/features/tools/commercial-bp-generator/widget/index.ts +7 -0
  97. package/src/features/tools/commercial-bp-generator/widget/result-shell.tsx +271 -0
  98. package/src/features/tools/commercial-bp-generator/widget/style-option.tsx +54 -0
  99. package/src/features/tools/commercial-bp-generator/widget/types.ts +33 -0
  100. package/src/features/tools/community-feedback-inbox/community-feedback-inbox.container.tsx +126 -0
  101. package/src/features/tools/community-feedback-inbox/community-feedback-inbox.spec.ts +15 -0
  102. package/src/features/tools/community-feedback-inbox/widget/community-feedback-inbox.tsx +271 -0
  103. package/src/features/tools/community-feedback-inbox/widget/constants.ts +3 -0
  104. package/src/features/tools/community-feedback-inbox/widget/helpers.ts +28 -0
  105. package/src/features/tools/community-feedback-inbox/widget/index.ts +7 -0
  106. package/src/features/tools/community-feedback-inbox/widget/preview-panels.tsx +92 -0
  107. package/src/features/tools/community-feedback-inbox/widget/result-shell.tsx +266 -0
  108. package/src/features/tools/community-feedback-inbox/widget/types.ts +6 -0
  109. package/src/features/tools/community-pain-point-extractor/community-pain-point-extractor.container.tsx +124 -0
  110. package/src/features/tools/community-pain-point-extractor/community-pain-point-extractor.spec.ts +15 -0
  111. package/src/features/tools/community-pain-point-extractor/widget/community-pain-point-extractor.tsx +404 -0
  112. package/src/features/tools/community-pain-point-extractor/widget/constants.ts +41 -0
  113. package/src/features/tools/community-pain-point-extractor/widget/helpers.ts +76 -0
  114. package/src/features/tools/community-pain-point-extractor/widget/index.ts +8 -0
  115. package/src/features/tools/community-pain-point-extractor/widget/progress-panels.tsx +251 -0
  116. package/src/features/tools/community-pain-point-extractor/widget/result-shell.tsx +478 -0
  117. package/src/features/tools/community-pain-point-extractor/widget/types.ts +33 -0
  118. package/src/features/tools/community-post-risk-checker/community-post-risk-checker.package.ts +792 -0
  119. package/src/features/tools/competitor-analysis/competitor-analysis.container.tsx +136 -0
  120. package/src/features/tools/competitor-analysis/competitor-analysis.spec.ts +15 -0
  121. package/src/features/tools/competitor-analysis/widget/competitor-analysis.tsx +241 -0
  122. package/src/features/tools/competitor-analysis/widget/constants.ts +9 -0
  123. package/src/features/tools/competitor-analysis/widget/index.ts +7 -0
  124. package/src/features/tools/competitor-analysis/widget/preview-panels.tsx +60 -0
  125. package/src/features/tools/competitor-analysis/widget/result-shell.tsx +418 -0
  126. package/src/features/tools/competitor-analysis/widget/types.ts +13 -0
  127. package/src/features/tools/disclaimer-generator/disclaimer-generator.package.ts +339 -0
  128. package/src/features/tools/email-template-generator/email-template-generator.container.tsx +224 -0
  129. package/src/features/tools/email-template-generator/email-template-generator.spec.ts +14 -0
  130. package/src/features/tools/email-template-generator/widget/email-template-generator.tsx +358 -0
  131. package/src/features/tools/email-template-generator/widget/helpers.ts +39 -0
  132. package/src/features/tools/email-template-generator/widget/index.ts +7 -0
  133. package/src/features/tools/email-template-generator/widget/preview-panel.tsx +311 -0
  134. package/src/features/tools/email-template-generator/widget/result-text-block.tsx +7 -0
  135. package/src/features/tools/email-template-generator/widget/types.ts +24 -0
  136. package/src/features/tools/gtm-readiness-checklist/gtm-readiness-checklist.container.tsx +75 -0
  137. package/src/features/tools/gtm-readiness-checklist/gtm-readiness-checklist.spec.ts +15 -0
  138. package/src/features/tools/gtm-readiness-checklist/widget/gtm-readiness-checklist.tsx +122 -0
  139. package/src/features/tools/gtm-readiness-checklist/widget/index.ts +7 -0
  140. package/src/features/tools/investor-matching-planner/investor-matching-planner.package.ts +869 -0
  141. package/src/features/tools/koko-codex-assistant/koko-codex-assistant.container.tsx +151 -0
  142. package/src/features/tools/koko-codex-assistant/koko-codex-assistant.spec.ts +14 -0
  143. package/src/features/tools/koko-codex-assistant/widget/index.ts +7 -0
  144. package/src/features/tools/koko-codex-assistant/widget/koko-codex-assistant-download.tsx +192 -0
  145. package/src/features/tools/logo-generator/logo-generator.container.tsx +112 -0
  146. package/src/features/tools/logo-generator/logo-generator.spec.ts +15 -0
  147. package/src/features/tools/logo-generator/widget/index.ts +7 -0
  148. package/src/features/tools/logo-generator/widget/logo-generator.tsx +1244 -0
  149. package/src/features/tools/market-forecast-report/market-forecast-report.container.tsx +73 -0
  150. package/src/features/tools/market-forecast-report/market-forecast-report.spec.ts +15 -0
  151. package/src/features/tools/million-user-growth-test/million-user-growth-test.container.tsx +123 -0
  152. package/src/features/tools/million-user-growth-test/million-user-growth-test.spec.ts +14 -0
  153. package/src/features/tools/million-user-growth-test/widget/index.ts +7 -0
  154. package/src/features/tools/million-user-growth-test/widget/million-user-growth-test.tsx +433 -0
  155. package/src/features/tools/module-loader.ts +107 -0
  156. package/src/features/tools/og-image-generator/og-image-generator.container.tsx +86 -0
  157. package/src/features/tools/og-image-generator/og-image-generator.spec.ts +14 -0
  158. package/src/features/tools/og-image-generator/widget/constants.ts +38 -0
  159. package/src/features/tools/og-image-generator/widget/form-fields.tsx +240 -0
  160. package/src/features/tools/og-image-generator/widget/index.ts +7 -0
  161. package/src/features/tools/og-image-generator/widget/og-image-generator.tsx +742 -0
  162. package/src/features/tools/og-image-generator/widget/preview-panel.tsx +305 -0
  163. package/src/features/tools/og-image-generator/widget/types.ts +1 -0
  164. package/src/features/tools/package/direct-models.ts +20 -0
  165. package/src/features/tools/package/form.ts +38 -0
  166. package/src/features/tools/package/l10n.ts +22 -0
  167. package/src/features/tools/package/package-container.tsx +285 -0
  168. package/src/features/tools/package/package-loaders.ts +22 -0
  169. package/src/features/tools/package/package-registry.ts +36 -0
  170. package/src/features/tools/package/result-markdown.ts +142 -0
  171. package/src/features/tools/package/schema.ts +379 -0
  172. package/src/features/tools/package/to-tool-module.ts +20 -0
  173. package/src/features/tools/package/to-tool-spec.ts +52 -0
  174. package/src/features/tools/package/types.ts +381 -0
  175. package/src/features/tools/pitch-deck-generator/pitch-deck-generator.container.tsx +175 -0
  176. package/src/features/tools/pitch-deck-generator/pitch-deck-generator.spec.ts +14 -0
  177. package/src/features/tools/pitch-deck-generator/pitch-deck-library-data.ts +476 -0
  178. package/src/features/tools/pitch-deck-generator/pitch-deck-library.tsx +159 -0
  179. package/src/features/tools/pitch-deck-generator/widget/ceremony-line.tsx +27 -0
  180. package/src/features/tools/pitch-deck-generator/widget/constants.ts +27 -0
  181. package/src/features/tools/pitch-deck-generator/widget/index.ts +7 -0
  182. package/src/features/tools/pitch-deck-generator/widget/pitch-deck-generator.tsx +763 -0
  183. package/src/features/tools/pitch-deck-generator/widget/result-helpers.ts +102 -0
  184. package/src/features/tools/pitch-deck-generator/widget/result-shell.tsx +263 -0
  185. package/src/features/tools/pitch-deck-generator/widget/slide-frame.tsx +106 -0
  186. package/src/features/tools/pitch-deck-generator/widget/slide-lightbox.tsx +149 -0
  187. package/src/features/tools/pitch-deck-generator/widget/style-option.tsx +54 -0
  188. package/src/features/tools/pitch-deck-generator/widget/types.ts +44 -0
  189. package/src/features/tools/product-agreement-generator/product-agreement-generator.container.tsx +137 -0
  190. package/src/features/tools/product-agreement-generator/product-agreement-generator.spec.ts +14 -0
  191. package/src/features/tools/product-agreement-generator/widget/constants.ts +27 -0
  192. package/src/features/tools/product-agreement-generator/widget/form-controls.tsx +218 -0
  193. package/src/features/tools/product-agreement-generator/widget/helpers.ts +68 -0
  194. package/src/features/tools/product-agreement-generator/widget/index.ts +7 -0
  195. package/src/features/tools/product-agreement-generator/widget/product-agreement-generator.tsx +671 -0
  196. package/src/features/tools/product-agreement-generator/widget/result-shell.tsx +473 -0
  197. package/src/features/tools/product-agreement-generator/widget/types.ts +89 -0
  198. package/src/features/tools/product-hunt-launch-planner/product-hunt-launch-planner.container.tsx +122 -0
  199. package/src/features/tools/product-hunt-launch-planner/product-hunt-launch-planner.spec.ts +15 -0
  200. package/src/features/tools/product-hunt-launch-planner/widget/constants.ts +5 -0
  201. package/src/features/tools/product-hunt-launch-planner/widget/helpers.ts +44 -0
  202. package/src/features/tools/product-hunt-launch-planner/widget/index.ts +7 -0
  203. package/src/features/tools/product-hunt-launch-planner/widget/preview-panel.tsx +143 -0
  204. package/src/features/tools/product-hunt-launch-planner/widget/product-hunt-launch-planner.tsx +504 -0
  205. package/src/features/tools/product-hunt-launch-planner/widget/result-shell.tsx +176 -0
  206. package/src/features/tools/product-hunt-launch-planner/widget/types.ts +20 -0
  207. package/src/features/tools/product-name-generator/product-name-generator.container.tsx +14 -0
  208. package/src/features/tools/product-name-generator/product-name-generator.spec.ts +15 -0
  209. package/src/features/tools/product-name-generator/widget/candidate-card.tsx +273 -0
  210. package/src/features/tools/product-name-generator/widget/constants.ts +21 -0
  211. package/src/features/tools/product-name-generator/widget/form-controls.tsx +136 -0
  212. package/src/features/tools/product-name-generator/widget/helpers.ts +41 -0
  213. package/src/features/tools/product-name-generator/widget/index.ts +7 -0
  214. package/src/features/tools/product-name-generator/widget/product-name-generator.tsx +776 -0
  215. package/src/features/tools/product-name-generator/widget/types.ts +36 -0
  216. package/src/features/tools/product-positioning-analyzer/product-positioning-analyzer.package.ts +801 -0
  217. package/src/features/tools/product-poster-generator/product-poster-generator.container.tsx +14 -0
  218. package/src/features/tools/product-poster-generator/product-poster-generator.spec.ts +15 -0
  219. package/src/features/tools/product-poster-generator/widget/constants.ts +125 -0
  220. package/src/features/tools/product-poster-generator/widget/form-controls.tsx +204 -0
  221. package/src/features/tools/product-poster-generator/widget/helpers.ts +155 -0
  222. package/src/features/tools/product-poster-generator/widget/index.ts +7 -0
  223. package/src/features/tools/product-poster-generator/widget/product-poster-generator.tsx +663 -0
  224. package/src/features/tools/product-poster-generator/widget/result-shell.tsx +12 -0
  225. package/src/features/tools/product-poster-generator/widget/types.ts +83 -0
  226. package/src/features/tools/product-ui-generator/product-ui-generator.container.tsx +116 -0
  227. package/src/features/tools/product-ui-generator/product-ui-generator.spec.ts +14 -0
  228. package/src/features/tools/product-ui-generator/widget/constants.ts +18 -0
  229. package/src/features/tools/product-ui-generator/widget/helpers.ts +11 -0
  230. package/src/features/tools/product-ui-generator/widget/index.ts +7 -0
  231. package/src/features/tools/product-ui-generator/widget/preview-panels.tsx +73 -0
  232. package/src/features/tools/product-ui-generator/widget/product-ui-generator.tsx +304 -0
  233. package/src/features/tools/product-ui-generator/widget/result-shell.tsx +118 -0
  234. package/src/features/tools/product-ui-generator/widget/types.ts +9 -0
  235. package/src/features/tools/reddit-pain-point-finder/reddit-pain-point-finder.container.tsx +113 -0
  236. package/src/features/tools/reddit-pain-point-finder/reddit-pain-point-finder.spec.ts +15 -0
  237. package/src/features/tools/reddit-pain-point-finder/widget/constants.ts +5 -0
  238. package/src/features/tools/reddit-pain-point-finder/widget/index.ts +7 -0
  239. package/src/features/tools/reddit-pain-point-finder/widget/preview-panels.tsx +73 -0
  240. package/src/features/tools/reddit-pain-point-finder/widget/reddit-pain-point-finder.tsx +281 -0
  241. package/src/features/tools/reddit-pain-point-finder/widget/result-shell.tsx +203 -0
  242. package/src/features/tools/reddit-pain-point-finder/widget/types.ts +15 -0
  243. package/src/features/tools/registry.ts +288 -0
  244. package/src/features/tools/runtime-registry.ts +186 -0
  245. package/src/features/tools/shared/create-guide-stack-container.tsx +176 -0
  246. package/src/features/tools/shared/create-standard-landing-container.tsx +163 -0
  247. package/src/features/tools/shared/tool-content-sections.tsx +659 -0
  248. package/src/features/tools/shared/tool-cta.tsx +66 -0
  249. package/src/features/tools/shared/tool-draft-view.tsx +53 -0
  250. package/src/features/tools/shared/tool-guide-section.tsx +191 -0
  251. package/src/features/tools/shared/tool-handoff.tsx +38 -0
  252. package/src/features/tools/shared/tool-mcp-badge.tsx +23 -0
  253. package/src/features/tools/shared/tool-message-translator.ts +37 -0
  254. package/src/features/tools/shared/tool-page-shell.tsx +348 -0
  255. package/src/features/tools/shared/tool-standard-generation-steps.tsx +52 -0
  256. package/src/features/tools/shared/tool-standard-landing-sections.tsx +447 -0
  257. package/src/features/tools/shared/tool-ui-registry.ts +237 -0
  258. package/src/features/tools/shared/tool-widget-slot.tsx +29 -0
  259. package/src/features/tools/slogan-generator/slogan-generator.package.ts +641 -0
  260. package/src/features/tools/social-listening-research-report/social-listening-research-report.container.tsx +124 -0
  261. package/src/features/tools/social-listening-research-report/social-listening-research-report.spec.ts +15 -0
  262. package/src/features/tools/social-listening-research-report/widget/constants.ts +4 -0
  263. package/src/features/tools/social-listening-research-report/widget/index.ts +7 -0
  264. package/src/features/tools/social-listening-research-report/widget/preview-panels.tsx +73 -0
  265. package/src/features/tools/social-listening-research-report/widget/result-shell.tsx +216 -0
  266. package/src/features/tools/social-listening-research-report/widget/social-listening-research-report.tsx +303 -0
  267. package/src/features/tools/social-listening-research-report/widget/types.ts +15 -0
  268. package/src/features/tools/social-platform-asset-adapter/social-platform-asset-adapter.container.tsx +123 -0
  269. package/src/features/tools/social-platform-asset-adapter/social-platform-asset-adapter.spec.ts +15 -0
  270. package/src/features/tools/social-platform-asset-adapter/widget/constants.ts +43 -0
  271. package/src/features/tools/social-platform-asset-adapter/widget/helpers.ts +249 -0
  272. package/src/features/tools/social-platform-asset-adapter/widget/index.ts +7 -0
  273. package/src/features/tools/social-platform-asset-adapter/widget/result-shell.tsx +350 -0
  274. package/src/features/tools/social-platform-asset-adapter/widget/section-heading.tsx +18 -0
  275. package/src/features/tools/social-platform-asset-adapter/widget/social-platform-asset-adapter.tsx +641 -0
  276. package/src/features/tools/social-platform-asset-adapter/widget/types.ts +40 -0
  277. package/src/features/tools/social-profile-kit/social-profile-kit.container.tsx +177 -0
  278. package/src/features/tools/social-profile-kit/social-profile-kit.spec.ts +15 -0
  279. package/src/features/tools/social-profile-kit/widget/context-editor.tsx +171 -0
  280. package/src/features/tools/social-profile-kit/widget/generation-runtime.ts +281 -0
  281. package/src/features/tools/social-profile-kit/widget/index.ts +7 -0
  282. package/src/features/tools/social-profile-kit/widget/input-panel.tsx +294 -0
  283. package/src/features/tools/social-profile-kit/widget/platform-dock.tsx +115 -0
  284. package/src/features/tools/social-profile-kit/widget/profile-canvas.tsx +318 -0
  285. package/src/features/tools/social-profile-kit/widget/profile-preview/bluesky-preview.tsx +188 -0
  286. package/src/features/tools/social-profile-kit/widget/profile-preview/facebook-preview.tsx +168 -0
  287. package/src/features/tools/social-profile-kit/widget/profile-preview/index.ts +1 -0
  288. package/src/features/tools/social-profile-kit/widget/profile-preview/instagram-preview.tsx +278 -0
  289. package/src/features/tools/social-profile-kit/widget/profile-preview/linkedin-preview.tsx +358 -0
  290. package/src/features/tools/social-profile-kit/widget/profile-preview/profile-preview.tsx +348 -0
  291. package/src/features/tools/social-profile-kit/widget/profile-preview/shared.tsx +391 -0
  292. package/src/features/tools/social-profile-kit/widget/profile-preview/threads-preview.tsx +148 -0
  293. package/src/features/tools/social-profile-kit/widget/profile-preview/tiktok-preview.tsx +319 -0
  294. package/src/features/tools/social-profile-kit/widget/profile-preview/x-preview.tsx +341 -0
  295. package/src/features/tools/social-profile-kit/widget/profile-preview/youtube-preview.tsx +297 -0
  296. package/src/features/tools/social-profile-kit/widget/social-profile-kit-generator.tsx +1059 -0
  297. package/src/features/tools/social-profile-kit/widget/types.ts +104 -0
  298. package/src/features/tools/spec-registry.ts +158 -0
  299. package/src/features/tools/startup-idea-research/startup-idea-research.container.tsx +111 -0
  300. package/src/features/tools/startup-idea-research/startup-idea-research.spec.ts +15 -0
  301. package/src/features/tools/startup-idea-research/widget/constants.ts +11 -0
  302. package/src/features/tools/startup-idea-research/widget/index.ts +7 -0
  303. package/src/features/tools/startup-idea-research/widget/preview-panels.tsx +67 -0
  304. package/src/features/tools/startup-idea-research/widget/result-shell.tsx +323 -0
  305. package/src/features/tools/startup-idea-research/widget/startup-idea-research.tsx +272 -0
  306. package/src/features/tools/startup-idea-research/widget/types.ts +21 -0
  307. package/src/features/tools/tarot-reading/tarot-reading.container.tsx +412 -0
  308. package/src/features/tools/tarot-reading/tarot-reading.spec.ts +15 -0
  309. package/src/features/tools/tarot-reading/widget/cards.tsx +152 -0
  310. package/src/features/tools/tarot-reading/widget/constants.ts +69 -0
  311. package/src/features/tools/tarot-reading/widget/deck-view.tsx +86 -0
  312. package/src/features/tools/tarot-reading/widget/deck.ts +86 -0
  313. package/src/features/tools/tarot-reading/widget/index.ts +7 -0
  314. package/src/features/tools/tarot-reading/widget/landing-view.tsx +209 -0
  315. package/src/features/tools/tarot-reading/widget/reading-copy.tsx +138 -0
  316. package/src/features/tools/tarot-reading/widget/reading-view.tsx +189 -0
  317. package/src/features/tools/tarot-reading/widget/reveal-view.tsx +50 -0
  318. package/src/features/tools/tarot-reading/widget/ritual-view.tsx +276 -0
  319. package/src/features/tools/tarot-reading/widget/tarot-reading.tsx +262 -0
  320. package/src/features/tools/tarot-reading/widget/types.ts +22 -0
  321. package/src/features/tools/twitter-gif-downloader/twitter-gif-downloader.container.tsx +114 -0
  322. package/src/features/tools/twitter-gif-downloader/twitter-gif-downloader.spec.ts +14 -0
  323. package/src/features/tools/twitter-gif-downloader/widget/index.ts +7 -0
  324. package/src/features/tools/twitter-gif-downloader/widget/twitter-gif-downloader.tsx +351 -0
  325. package/src/features/tools/types.ts +68 -0
  326. package/src/features/tools/user-interview-guide-generator/user-interview-guide-generator.package.ts +774 -0
  327. package/src/features/tools/user-interview-insight-report-generator/user-interview-insight-report-generator.container.tsx +23 -0
  328. package/src/features/tools/user-interview-insight-report-generator/user-interview-insight-report-generator.spec.ts +14 -0
  329. package/src/features/tools/user-interview-insight-report-generator/widget/constants.ts +8 -0
  330. package/src/features/tools/user-interview-insight-report-generator/widget/helpers.ts +4 -0
  331. package/src/features/tools/user-interview-insight-report-generator/widget/index.ts +7 -0
  332. package/src/features/tools/user-interview-insight-report-generator/widget/preview-panels.tsx +55 -0
  333. package/src/features/tools/user-interview-insight-report-generator/widget/result-shell.tsx +122 -0
  334. package/src/features/tools/user-interview-insight-report-generator/widget/types.ts +16 -0
  335. package/src/features/tools/user-interview-insight-report-generator/widget/user-interview-insight-report-generator.tsx +293 -0
  336. package/src/features/tools/user-interview-record-generator/user-interview-record-generator.container.tsx +18 -0
  337. package/src/features/tools/user-interview-record-generator/user-interview-record-generator.spec.ts +14 -0
  338. package/src/features/tools/user-interview-record-generator/widget/constants.ts +9 -0
  339. package/src/features/tools/user-interview-record-generator/widget/helpers.ts +4 -0
  340. package/src/features/tools/user-interview-record-generator/widget/index.ts +7 -0
  341. package/src/features/tools/user-interview-record-generator/widget/preview-panels.tsx +48 -0
  342. package/src/features/tools/user-interview-record-generator/widget/result-shell.tsx +128 -0
  343. package/src/features/tools/user-interview-record-generator/widget/types.ts +16 -0
  344. package/src/features/tools/user-interview-record-generator/widget/user-interview-record-generator.tsx +305 -0
  345. package/src/features/tools/utm-builder/utm-builder.package.ts +846 -0
  346. package/src/features/tools/widget-registry.ts +73 -0
  347. package/src/generated/mcp-tools-registry.json +17 -0
  348. package/src/host/client-proxy.test.ts +33 -0
  349. package/src/host/client.ts +678 -0
  350. package/src/host/server.ts +119 -0
  351. package/src/i18n/client.ts +11 -0
  352. package/src/i18n/locale-fallback.ts +38 -0
  353. package/src/i18n/locale.ts +18 -0
  354. package/src/i18n/messages/en/page/tools.ts +124 -0
  355. package/src/i18n/messages/en/tools/app-icon-resizer.ts +244 -0
  356. package/src/i18n/messages/en/tools/app-store-screenshot-generator.ts +145 -0
  357. package/src/i18n/messages/en/tools/build-in-public-story-generator.ts +229 -0
  358. package/src/i18n/messages/en/tools/cold-start-channel-selector.ts +423 -0
  359. package/src/i18n/messages/en/tools/commercial-bp-generator.ts +304 -0
  360. package/src/i18n/messages/en/tools/community-feedback-inbox.ts +218 -0
  361. package/src/i18n/messages/en/tools/community-pain-point-extractor.ts +230 -0
  362. package/src/i18n/messages/en/tools/community-post-risk-checker.ts +209 -0
  363. package/src/i18n/messages/en/tools/competitor-analysis.ts +197 -0
  364. package/src/i18n/messages/en/tools/email-template-generator.ts +302 -0
  365. package/src/i18n/messages/en/tools/engine.ts +69 -0
  366. package/src/i18n/messages/en/tools/gtm-readiness-checklist.ts +166 -0
  367. package/src/i18n/messages/en/tools/index.ts +73 -0
  368. package/src/i18n/messages/en/tools/koko-codex-assistant.ts +171 -0
  369. package/src/i18n/messages/en/tools/logo-generator.ts +173 -0
  370. package/src/i18n/messages/en/tools/market-forecast-report.ts +228 -0
  371. package/src/i18n/messages/en/tools/million-user-growth-test.ts +386 -0
  372. package/src/i18n/messages/en/tools/og-image-generator.ts +172 -0
  373. package/src/i18n/messages/en/tools/pitch-deck-generator.ts +358 -0
  374. package/src/i18n/messages/en/tools/product-agreement-generator.ts +411 -0
  375. package/src/i18n/messages/en/tools/product-hunt-launch-planner.ts +272 -0
  376. package/src/i18n/messages/en/tools/product-name-generator.ts +383 -0
  377. package/src/i18n/messages/en/tools/product-poster-generator.ts +294 -0
  378. package/src/i18n/messages/en/tools/product-ui-generator.ts +234 -0
  379. package/src/i18n/messages/en/tools/reddit-pain-point-finder.ts +163 -0
  380. package/src/i18n/messages/en/tools/shared.ts +24 -0
  381. package/src/i18n/messages/en/tools/social-listening-research-report.ts +185 -0
  382. package/src/i18n/messages/en/tools/social-media-profile-generator.ts +22 -0
  383. package/src/i18n/messages/en/tools/social-platform-asset-adapter.ts +287 -0
  384. package/src/i18n/messages/en/tools/social-profile-kit.ts +150 -0
  385. package/src/i18n/messages/en/tools/startup-idea-research.ts +170 -0
  386. package/src/i18n/messages/en/tools/tarot-reading.ts +230 -0
  387. package/src/i18n/messages/en/tools/twitter-gif-downloader.ts +145 -0
  388. package/src/i18n/messages/en/tools/user-interview-insight-report-generator.ts +242 -0
  389. package/src/i18n/messages/en/tools/user-interview-record-generator.ts +244 -0
  390. package/src/i18n/messages/en/tools-ui.ts +704 -0
  391. package/src/i18n/messages/zh/page/tools.ts +124 -0
  392. package/src/i18n/messages/zh/tools/app-icon-resizer.ts +242 -0
  393. package/src/i18n/messages/zh/tools/app-store-screenshot-generator.ts +145 -0
  394. package/src/i18n/messages/zh/tools/build-in-public-story-generator.ts +230 -0
  395. package/src/i18n/messages/zh/tools/cold-start-channel-selector.ts +422 -0
  396. package/src/i18n/messages/zh/tools/commercial-bp-generator.ts +302 -0
  397. package/src/i18n/messages/zh/tools/community-feedback-inbox.ts +217 -0
  398. package/src/i18n/messages/zh/tools/community-pain-point-extractor.ts +230 -0
  399. package/src/i18n/messages/zh/tools/community-post-risk-checker.ts +200 -0
  400. package/src/i18n/messages/zh/tools/competitor-analysis.ts +192 -0
  401. package/src/i18n/messages/zh/tools/email-template-generator.ts +302 -0
  402. package/src/i18n/messages/zh/tools/engine.ts +68 -0
  403. package/src/i18n/messages/zh/tools/gtm-readiness-checklist.ts +166 -0
  404. package/src/i18n/messages/zh/tools/index.ts +73 -0
  405. package/src/i18n/messages/zh/tools/koko-codex-assistant.ts +170 -0
  406. package/src/i18n/messages/zh/tools/logo-generator.ts +172 -0
  407. package/src/i18n/messages/zh/tools/market-forecast-report.ts +228 -0
  408. package/src/i18n/messages/zh/tools/million-user-growth-test.ts +385 -0
  409. package/src/i18n/messages/zh/tools/og-image-generator.ts +173 -0
  410. package/src/i18n/messages/zh/tools/pitch-deck-generator.ts +358 -0
  411. package/src/i18n/messages/zh/tools/product-agreement-generator.ts +401 -0
  412. package/src/i18n/messages/zh/tools/product-hunt-launch-planner.ts +267 -0
  413. package/src/i18n/messages/zh/tools/product-name-generator.ts +383 -0
  414. package/src/i18n/messages/zh/tools/product-poster-generator.ts +282 -0
  415. package/src/i18n/messages/zh/tools/product-ui-generator.ts +234 -0
  416. package/src/i18n/messages/zh/tools/reddit-pain-point-finder.ts +162 -0
  417. package/src/i18n/messages/zh/tools/shared.ts +24 -0
  418. package/src/i18n/messages/zh/tools/social-listening-research-report.ts +181 -0
  419. package/src/i18n/messages/zh/tools/social-media-profile-generator.ts +22 -0
  420. package/src/i18n/messages/zh/tools/social-platform-asset-adapter.ts +284 -0
  421. package/src/i18n/messages/zh/tools/social-profile-kit.ts +150 -0
  422. package/src/i18n/messages/zh/tools/startup-idea-research.ts +165 -0
  423. package/src/i18n/messages/zh/tools/tarot-reading.ts +228 -0
  424. package/src/i18n/messages/zh/tools/twitter-gif-downloader.ts +138 -0
  425. package/src/i18n/messages/zh/tools/user-interview-insight-report-generator.ts +224 -0
  426. package/src/i18n/messages/zh/tools/user-interview-record-generator.ts +226 -0
  427. package/src/i18n/messages/zh/tools-ui.ts +684 -0
  428. package/src/i18n/messages/zh-tw/page/tools.ts +115 -0
  429. package/src/i18n/messages/zh-tw/tools/app-icon-resizer.ts +242 -0
  430. package/src/i18n/messages/zh-tw/tools/app-store-screenshot-generator.ts +145 -0
  431. package/src/i18n/messages/zh-tw/tools/build-in-public-story-generator.ts +230 -0
  432. package/src/i18n/messages/zh-tw/tools/cold-start-channel-selector.ts +440 -0
  433. package/src/i18n/messages/zh-tw/tools/commercial-bp-generator.ts +302 -0
  434. package/src/i18n/messages/zh-tw/tools/community-feedback-inbox.ts +217 -0
  435. package/src/i18n/messages/zh-tw/tools/community-pain-point-extractor.ts +230 -0
  436. package/src/i18n/messages/zh-tw/tools/community-post-risk-checker.ts +200 -0
  437. package/src/i18n/messages/zh-tw/tools/competitor-analysis.ts +192 -0
  438. package/src/i18n/messages/zh-tw/tools/email-template-generator.ts +302 -0
  439. package/src/i18n/messages/zh-tw/tools/engine.ts +68 -0
  440. package/src/i18n/messages/zh-tw/tools/gtm-readiness-checklist.ts +166 -0
  441. package/src/i18n/messages/zh-tw/tools/index.ts +73 -0
  442. package/src/i18n/messages/zh-tw/tools/koko-codex-assistant.ts +170 -0
  443. package/src/i18n/messages/zh-tw/tools/logo-generator.ts +71 -0
  444. package/src/i18n/messages/zh-tw/tools/market-forecast-report.ts +228 -0
  445. package/src/i18n/messages/zh-tw/tools/million-user-growth-test.ts +385 -0
  446. package/src/i18n/messages/zh-tw/tools/og-image-generator.ts +173 -0
  447. package/src/i18n/messages/zh-tw/tools/pitch-deck-generator.ts +358 -0
  448. package/src/i18n/messages/zh-tw/tools/product-agreement-generator.ts +401 -0
  449. package/src/i18n/messages/zh-tw/tools/product-hunt-launch-planner.ts +267 -0
  450. package/src/i18n/messages/zh-tw/tools/product-name-generator.ts +383 -0
  451. package/src/i18n/messages/zh-tw/tools/product-poster-generator.ts +282 -0
  452. package/src/i18n/messages/zh-tw/tools/product-ui-generator.ts +234 -0
  453. package/src/i18n/messages/zh-tw/tools/reddit-pain-point-finder.ts +162 -0
  454. package/src/i18n/messages/zh-tw/tools/shared.ts +24 -0
  455. package/src/i18n/messages/zh-tw/tools/social-listening-research-report.ts +181 -0
  456. package/src/i18n/messages/zh-tw/tools/social-media-profile-generator.ts +22 -0
  457. package/src/i18n/messages/zh-tw/tools/social-platform-asset-adapter.ts +284 -0
  458. package/src/i18n/messages/zh-tw/tools/social-profile-kit.ts +150 -0
  459. package/src/i18n/messages/zh-tw/tools/startup-idea-research.ts +165 -0
  460. package/src/i18n/messages/zh-tw/tools/tarot-reading.ts +228 -0
  461. package/src/i18n/messages/zh-tw/tools/twitter-gif-downloader.ts +138 -0
  462. package/src/i18n/messages/zh-tw/tools/user-interview-insight-report-generator.ts +224 -0
  463. package/src/i18n/messages/zh-tw/tools/user-interview-record-generator.ts +226 -0
  464. package/src/i18n/messages/zh-tw/tools-ui.ts +525 -0
  465. package/src/index.ts +15 -0
  466. package/src/lib/activity-task-handoff.ts +404 -0
  467. package/src/lib/api/errors.ts +39 -0
  468. package/src/lib/app-origin.ts +30 -0
  469. package/src/lib/fact-claim-contract.ts +68 -0
  470. package/src/lib/fake-delay.ts +3 -0
  471. package/src/lib/file/download.ts +10 -0
  472. package/src/lib/routing/locale-paths.ts +27 -0
  473. package/src/lib/seo-meta.ts +3 -0
  474. package/src/lib/tools/app-icon-resizer-schema.ts +191 -0
  475. package/src/lib/tools/app-store-screenshot-generator-schema.ts +185 -0
  476. package/src/lib/tools/build-in-public-story-generator-schema.ts +67 -0
  477. package/src/lib/tools/build-in-public-story-generator.format.ts +507 -0
  478. package/src/lib/tools/cold-start-channel-selector-schema.ts +147 -0
  479. package/src/lib/tools/commercial-bp-generator-schema.ts +222 -0
  480. package/src/lib/tools/community-feedback-inbox-schema.ts +125 -0
  481. package/src/lib/tools/community-feedback-inbox.format.ts +764 -0
  482. package/src/lib/tools/community-pain-point-extractor-schema.ts +166 -0
  483. package/src/lib/tools/community-post-risk-checker-schema.ts +99 -0
  484. package/src/lib/tools/community-post-risk-checker.format.ts +557 -0
  485. package/src/lib/tools/competitor-analysis-schema.ts +144 -0
  486. package/src/lib/tools/draft-preview-access.ts +3 -0
  487. package/src/lib/tools/draft-store.ts +69 -0
  488. package/src/lib/tools/email-template-generator-schema.ts +124 -0
  489. package/src/lib/tools/gtm-checklist-copy.ts +57 -0
  490. package/src/lib/tools/gtm-checklist-structure.ts +37 -0
  491. package/src/lib/tools/image-download.ts +68 -0
  492. package/src/lib/tools/input-quality.ts +97 -0
  493. package/src/lib/tools/logo-generator-schema.ts +224 -0
  494. package/src/lib/tools/market-forecast-report-schema.ts +299 -0
  495. package/src/lib/tools/mcp-registry.ts +16 -0
  496. package/src/lib/tools/mcp-types.ts +18 -0
  497. package/src/lib/tools/million-user-growth-test-schema.ts +49 -0
  498. package/src/lib/tools/million-user-growth-test.ts +181 -0
  499. package/src/lib/tools/og-image-generator-render.ts +448 -0
  500. package/src/lib/tools/og-image-generator-schema.ts +140 -0
  501. package/src/lib/tools/ops-catalog.ts +102 -0
  502. package/src/lib/tools/pitch-deck-generator-schema.ts +182 -0
  503. package/src/lib/tools/pitch-deck-package.ts +0 -0
  504. package/src/lib/tools/product-agreement-generator-schema.ts +168 -0
  505. package/src/lib/tools/product-hunt-launch-planner-schema.ts +136 -0
  506. package/src/lib/tools/product-hunt-launch-planner.format.ts +72 -0
  507. package/src/lib/tools/product-name-generator-schema.ts +563 -0
  508. package/src/lib/tools/product-poster-generator-schema.ts +215 -0
  509. package/src/lib/tools/product-ui-generator-schema.ts +157 -0
  510. package/src/lib/tools/reddit-pain-point-finder-schema.ts +88 -0
  511. package/src/lib/tools/resolve-tool-locale-copy.ts +75 -0
  512. package/src/lib/tools/slug.ts +60 -0
  513. package/src/lib/tools/social-listening-research-report-schema.ts +105 -0
  514. package/src/lib/tools/social-platform-asset-adapter-schema.ts +152 -0
  515. package/src/lib/tools/social-profile-kit.constants.ts +12 -0
  516. package/src/lib/tools/social-profile-kit.generation.ts +257 -0
  517. package/src/lib/tools/social-profile-kit.input.ts +290 -0
  518. package/src/lib/tools/social-profile-kit.manual.ts +481 -0
  519. package/src/lib/tools/social-profile-kit.package.ts +220 -0
  520. package/src/lib/tools/social-profile-kit.schema.ts +328 -0
  521. package/src/lib/tools/startup-idea-research-schema.ts +107 -0
  522. package/src/lib/tools/tarot-imagery.ts +89 -0
  523. package/src/lib/tools/tarot-reading.ts +1044 -0
  524. package/src/lib/tools/tool-message-keys.ts +18 -0
  525. package/src/lib/tools/types.ts +32 -0
  526. package/src/lib/tools/user-interview.format.ts +147 -0
  527. package/src/lib/tools/user-interview.generation.ts +670 -0
  528. package/src/lib/tools/user-interview.schema.ts +192 -0
  529. package/src/lib/zip.ts +106 -0
  530. package/src/services/tools/handlers/gtm-readiness-checklist.ts +71 -0
  531. package/src/services/tools/handlers/types.ts +7 -0
@@ -0,0 +1,22 @@
1
+ import type { ToolPackage } from "./types";
2
+
3
+ const packageLoaders: Record<string, () => Promise<ToolPackage>> = {
4
+ "user-interview-guide-generator": () =>
5
+ import("../user-interview-guide-generator/user-interview-guide-generator.package").then((mod) => mod.userInterviewGuideGeneratorPackage),
6
+ "utm-builder": () =>
7
+ import("../utm-builder/utm-builder.package").then((mod) => mod.utmBuilderPackage),
8
+ "slogan-generator": () =>
9
+ import("../slogan-generator/slogan-generator.package").then((mod) => mod.sloganGeneratorPackage),
10
+ "investor-matching-planner": () =>
11
+ import("../investor-matching-planner/investor-matching-planner.package").then((mod) => mod.investorMatchingPlannerPackage),
12
+ "disclaimer-generator": () =>
13
+ import("../disclaimer-generator/disclaimer-generator.package").then((mod) => mod.disclaimerGeneratorPackage),
14
+ "product-positioning-analyzer": () =>
15
+ import("../product-positioning-analyzer/product-positioning-analyzer.package").then((mod) => mod.productPositioningAnalyzerPackage),
16
+ "community-post-risk-checker": () =>
17
+ import("../community-post-risk-checker/community-post-risk-checker.package").then((mod) => mod.communityPostRiskCheckerPackage),
18
+ };
19
+
20
+ export function loadToolPackage(slug: string): Promise<ToolPackage | undefined> {
21
+ return packageLoaders[slug]?.();
22
+ }
@@ -0,0 +1,36 @@
1
+ import { communityPostRiskCheckerPackage } from "../community-post-risk-checker/community-post-risk-checker.package";
2
+ import { disclaimerGeneratorPackage } from "../disclaimer-generator/disclaimer-generator.package";
3
+ import { investorMatchingPlannerPackage } from "../investor-matching-planner/investor-matching-planner.package";
4
+ import { productPositioningAnalyzerPackage } from "../product-positioning-analyzer/product-positioning-analyzer.package";
5
+ import { sloganGeneratorPackage } from "../slogan-generator/slogan-generator.package";
6
+ import { userInterviewGuideGeneratorPackage } from "../user-interview-guide-generator/user-interview-guide-generator.package";
7
+ import { utmBuilderPackage } from "../utm-builder/utm-builder.package";
8
+
9
+ import type { ToolPackage } from "./types";
10
+
11
+ /**
12
+ * ToolPackage 客户端注册表。
13
+ * widget 是 client component,zod resultSchema 不能跨 RSC 边界序列化,
14
+ * 因此客户端按 slug 自行解析 package(schema 随 bundle 下发)。
15
+ * 新 package 由 pnpm tool:new 脚手架自动登记。
16
+ *
17
+ * 规模化注意:包数量大后改为按 slug 动态 import 以控制客户端体积。
18
+ */
19
+ const toolPackages: Record<string, ToolPackage> = {
20
+ [userInterviewGuideGeneratorPackage.meta.slug]: userInterviewGuideGeneratorPackage,
21
+ [utmBuilderPackage.meta.slug]: utmBuilderPackage,
22
+ [sloganGeneratorPackage.meta.slug]: sloganGeneratorPackage,
23
+ [investorMatchingPlannerPackage.meta.slug]: investorMatchingPlannerPackage,
24
+ [disclaimerGeneratorPackage.meta.slug]: disclaimerGeneratorPackage,
25
+ [productPositioningAnalyzerPackage.meta.slug]: productPositioningAnalyzerPackage,
26
+ [communityPostRiskCheckerPackage.meta.slug]: communityPostRiskCheckerPackage,
27
+ // tool-factory:package-entries (pnpm tool:new 在此锚点上方插入)
28
+ };
29
+
30
+ export function getToolPackage(slug: string): ToolPackage | undefined {
31
+ return toolPackages[slug];
32
+ }
33
+
34
+ export function listToolPackages(): ToolPackage[] {
35
+ return Object.values(toolPackages);
36
+ }
@@ -0,0 +1,142 @@
1
+ import type { AppLocale } from "../../../i18n/locale";
2
+
3
+ import { pickL10n } from "./l10n";
4
+ import type { ResultViewBlock } from "./types";
5
+
6
+ export function getResultPath(result: unknown, path: string): unknown {
7
+ let current: unknown = result;
8
+ for (const key of path.split(".")) {
9
+ if (current == null || typeof current !== "object") return undefined;
10
+ current = (current as Record<string, unknown>)[key];
11
+ }
12
+ return current;
13
+ }
14
+
15
+ export function asStringList(value: unknown): string[] {
16
+ if (!Array.isArray(value)) return [];
17
+ return value.filter((item): item is string => typeof item === "string");
18
+ }
19
+
20
+ export function asRecordList(value: unknown): Array<Record<string, unknown>> {
21
+ if (!Array.isArray(value)) return [];
22
+ return value.filter(
23
+ (item): item is Record<string, unknown> =>
24
+ Boolean(item) && typeof item === "object",
25
+ );
26
+ }
27
+
28
+ /** 按结果视图积木序列化为 Markdown,供"复制"按钮与交付使用。 */
29
+ export function resultToMarkdown(
30
+ title: string,
31
+ result: unknown,
32
+ view: ResultViewBlock[],
33
+ locale: AppLocale,
34
+ ): string {
35
+ const lines: string[] = [`# ${title}`, ""];
36
+
37
+ for (const block of view) {
38
+ if (block.block === "keyValues") {
39
+ if (block.title) lines.push(`## ${pickL10n(block.title, locale)}`, "");
40
+ for (const item of block.items) {
41
+ const value = getResultPath(result, item.path);
42
+ if (typeof value === "string" && value.trim()) {
43
+ lines.push(`- **${pickL10n(item.label, locale)}**: ${value}`);
44
+ }
45
+ const list = asStringList(value);
46
+ if (list.length) {
47
+ lines.push(`- **${pickL10n(item.label, locale)}**:`);
48
+ for (const entry of list) lines.push(` - ${entry}`);
49
+ }
50
+ }
51
+ lines.push("");
52
+ } else if (block.block === "bulletList") {
53
+ const items = asStringList(getResultPath(result, block.path));
54
+ if (!items.length) continue;
55
+ lines.push(`## ${pickL10n(block.title, locale)}`, "");
56
+ for (const item of items) lines.push(`- ${item}`);
57
+ lines.push("");
58
+ } else if (block.block === "bulletGroups") {
59
+ if (block.title) lines.push(`## ${pickL10n(block.title, locale)}`, "");
60
+ for (const column of block.columns) {
61
+ const items = asStringList(getResultPath(result, column.path));
62
+ if (!items.length) continue;
63
+ lines.push(`### ${pickL10n(column.label, locale)}`, "");
64
+ for (const item of items) lines.push(`- ${item}`);
65
+ lines.push("");
66
+ }
67
+ } else if (block.block === "strategicCurve") {
68
+ const dimensions = pickL10n(block.dimensions, locale);
69
+ const rows = asRecordList(getResultPath(result, block.path))
70
+ .map((row) => {
71
+ const player = row[block.playerField];
72
+ const values = row[block.valuesField];
73
+ if (
74
+ typeof player !== "string" ||
75
+ !player.trim() ||
76
+ !Array.isArray(values) ||
77
+ values.length !== dimensions.length ||
78
+ values.some(
79
+ (value) =>
80
+ typeof value !== "number" ||
81
+ !Number.isFinite(value) ||
82
+ value < 0 ||
83
+ value > block.maxScore,
84
+ )
85
+ ) {
86
+ return null;
87
+ }
88
+ return { player, values };
89
+ })
90
+ .filter((row): row is { player: string; values: number[] } => row !== null);
91
+ if (!rows.length) continue;
92
+ lines.push(`## ${pickL10n(block.title, locale)}`, "");
93
+ lines.push(`| Player | ${dimensions.join(" | ")} |`);
94
+ lines.push(`| --- | ${dimensions.map(() => "---").join(" | ")} |`);
95
+ for (const row of rows) {
96
+ lines.push(`| ${row.player} | ${row.values.join(" | ")} |`);
97
+ }
98
+ lines.push("");
99
+ } else {
100
+ const rows = asRecordList(getResultPath(result, block.path));
101
+ if (!rows.length) continue;
102
+ lines.push(`## ${pickL10n(block.title, locale)}`, "");
103
+ for (const row of rows) {
104
+ const cardTitle = row[block.card.titleField];
105
+ const meta = block.card.metaField ? row[block.card.metaField] : undefined;
106
+ const metaSuffix = block.card.metaSuffix
107
+ ? pickL10n(block.card.metaSuffix, locale)
108
+ : "";
109
+ lines.push(
110
+ `### ${String(cardTitle ?? "")}${meta != null ? `(${String(meta)}${metaSuffix})` : ""}`,
111
+ );
112
+ if (block.card.body) {
113
+ const body = row[block.card.body.field];
114
+ if (typeof body === "string" && body.trim()) {
115
+ const label = block.card.body.label
116
+ ? `**${pickL10n(block.card.body.label, locale)}**: `
117
+ : "";
118
+ lines.push(`${label}${body}`);
119
+ }
120
+ }
121
+ for (const listSpec of block.card.lists ?? []) {
122
+ const items = asStringList(row[listSpec.field]);
123
+ if (!items.length) continue;
124
+ lines.push(`- **${pickL10n(listSpec.label, locale)}**:`);
125
+ for (const item of items) lines.push(` - ${item}`);
126
+ }
127
+ if (block.card.footer) {
128
+ const footer = row[block.card.footer.field];
129
+ if (typeof footer === "string" && footer.trim()) {
130
+ const label = block.card.footer.label
131
+ ? `**${pickL10n(block.card.footer.label, locale)}**: `
132
+ : "";
133
+ lines.push(`${label}${footer}`);
134
+ }
135
+ }
136
+ lines.push("");
137
+ }
138
+ }
139
+ }
140
+
141
+ return lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd();
142
+ }
@@ -0,0 +1,379 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * ToolPackage 的机器校验层。
5
+ * 供 scripts/tool-factory/validate-tool-packages.mjs 与单测使用;
6
+ * 运行时组件信任类型系统,不重复解析。
7
+ *
8
+ * 注意:resultSchema 字段是 zod 实例(代码),用 z.custom 校验存在性。
9
+ */
10
+
11
+ const l10nTextSchema = z.object({
12
+ en: z.string().trim().min(1),
13
+ zh: z.string().trim().min(1),
14
+ "zh-tw": z.string().trim().min(1).optional(),
15
+ });
16
+
17
+ const l10nTextListSchema = z
18
+ .object({
19
+ en: z.array(z.string().trim().min(1)).min(1),
20
+ zh: z.array(z.string().trim().min(1)).min(1),
21
+ "zh-tw": z.array(z.string().trim().min(1)).min(1).optional(),
22
+ })
23
+ .refine((value) => value.en.length === value.zh.length, {
24
+ message: "en/zh 列表长度必须一致",
25
+ });
26
+
27
+ const sectionImageSchema = z.object({
28
+ src: z.string().startsWith("/tools/"),
29
+ alt: l10nTextSchema,
30
+ side: z.enum(["left", "right"]).optional(),
31
+ wide: z.boolean().optional(),
32
+ });
33
+
34
+ const formFieldBase = {
35
+ id: z
36
+ .string()
37
+ .regex(/^[a-z][a-zA-Z0-9]*$/, "字段 id 必须是 camelCase"),
38
+ label: l10nTextSchema,
39
+ hint: l10nTextSchema.optional(),
40
+ placeholder: l10nTextSchema.optional(),
41
+ required: z.boolean().optional(),
42
+ invalidMessage: l10nTextSchema.optional(),
43
+ fullWidth: z.boolean().optional(),
44
+ };
45
+
46
+ const formFieldSchema = z.discriminatedUnion("kind", [
47
+ z.object({
48
+ ...formFieldBase,
49
+ kind: z.literal("text"),
50
+ minLength: z.number().int().positive().optional(),
51
+ maxLength: z.number().int().positive().optional(),
52
+ }),
53
+ z.object({
54
+ ...formFieldBase,
55
+ kind: z.literal("textarea"),
56
+ rows: z.number().int().positive().optional(),
57
+ minLength: z.number().int().positive().optional(),
58
+ maxLength: z.number().int().positive().optional(),
59
+ }),
60
+ z.object({
61
+ ...formFieldBase,
62
+ kind: z.literal("select"),
63
+ options: z
64
+ .array(z.object({ value: z.string().min(1), label: l10nTextSchema }))
65
+ .min(2),
66
+ defaultValue: z.string().min(1),
67
+ }),
68
+ z.object({
69
+ ...formFieldBase,
70
+ kind: z.literal("toggle"),
71
+ onLabel: l10nTextSchema,
72
+ offLabel: l10nTextSchema,
73
+ defaultValue: z.boolean(),
74
+ }),
75
+ ]);
76
+
77
+ const resultViewBlockSchema = z.discriminatedUnion("block", [
78
+ z.object({
79
+ block: z.literal("keyValues"),
80
+ title: l10nTextSchema.optional(),
81
+ items: z
82
+ .array(
83
+ z.object({
84
+ label: l10nTextSchema,
85
+ path: z.string().min(1),
86
+ copyable: z.boolean().optional(),
87
+ }),
88
+ )
89
+ .min(1),
90
+ }),
91
+ z.object({
92
+ block: z.literal("bulletList"),
93
+ title: l10nTextSchema,
94
+ path: z.string().min(1),
95
+ tone: z.enum(["neutral", "positive", "risk"]).optional(),
96
+ }),
97
+ z.object({
98
+ block: z.literal("bulletGroups"),
99
+ title: l10nTextSchema.optional(),
100
+ columns: z
101
+ .array(
102
+ z.object({
103
+ label: l10nTextSchema,
104
+ path: z.string().min(1),
105
+ tone: z.enum(["neutral", "positive", "risk"]).optional(),
106
+ }),
107
+ )
108
+ .min(1),
109
+ }),
110
+ z.object({
111
+ block: z.literal("cardList"),
112
+ title: l10nTextSchema,
113
+ path: z.string().min(1),
114
+ layout: z.enum(["stack", "grid"]).optional(),
115
+ card: z.object({
116
+ titleField: z.string().min(1),
117
+ metaField: z.string().min(1).optional(),
118
+ metaSuffix: l10nTextSchema.optional(),
119
+ body: z
120
+ .object({ field: z.string().min(1), label: l10nTextSchema.optional() })
121
+ .optional(),
122
+ lists: z
123
+ .array(z.object({ field: z.string().min(1), label: l10nTextSchema }))
124
+ .optional(),
125
+ footer: z
126
+ .object({ field: z.string().min(1), label: l10nTextSchema.optional() })
127
+ .optional(),
128
+ }),
129
+ }),
130
+ z.object({
131
+ block: z.literal("strategicCurve"),
132
+ title: l10nTextSchema,
133
+ path: z.string().min(1),
134
+ playerField: z.string().min(1),
135
+ valuesField: z.string().min(1),
136
+ dimensions: l10nTextListSchema,
137
+ maxScore: z.number().int().positive(),
138
+ }),
139
+ ]);
140
+
141
+ const pageSectionSchema = z.discriminatedUnion("kind", [
142
+ z.object({
143
+ kind: z.literal("cards"),
144
+ heading: l10nTextSchema,
145
+ intro: l10nTextSchema.optional(),
146
+ items: z.array(z.object({ title: l10nTextSchema, body: l10nTextSchema })).min(2),
147
+ image: sectionImageSchema.optional(),
148
+ }),
149
+ z.object({
150
+ kind: z.literal("bullets"),
151
+ heading: l10nTextSchema,
152
+ intro: l10nTextSchema.optional(),
153
+ groups: z
154
+ .array(z.object({ title: l10nTextSchema.optional(), items: l10nTextListSchema }))
155
+ .min(1),
156
+ image: sectionImageSchema.optional(),
157
+ }),
158
+ z.object({
159
+ kind: z.literal("paragraphs"),
160
+ heading: l10nTextSchema,
161
+ intro: l10nTextSchema.optional(),
162
+ paragraphs: l10nTextListSchema,
163
+ image: sectionImageSchema.optional(),
164
+ }),
165
+ ]);
166
+
167
+ const standardBenefitsSchema = z.object({
168
+ title: l10nTextSchema,
169
+ cards: z.tuple([
170
+ z.object({ title: l10nTextSchema, body: l10nTextSchema }),
171
+ z.object({ title: l10nTextSchema, body: l10nTextSchema }),
172
+ z.object({ title: l10nTextSchema, body: l10nTextSchema }),
173
+ ]),
174
+ });
175
+
176
+ function standardImageTextSchema(
177
+ id: "section-primary" | "section-variation" | "section-support",
178
+ ) {
179
+ return z.object({
180
+ id: z.literal(id),
181
+ title: l10nTextSchema,
182
+ body: l10nTextListSchema,
183
+ image: sectionImageSchema,
184
+ imageFirst: z.boolean().optional(),
185
+ });
186
+ }
187
+
188
+ const standardLandingSchema = z.object({
189
+ benefits: standardBenefitsSchema,
190
+ imageTextSections: z.tuple([
191
+ standardImageTextSchema("section-primary"),
192
+ standardImageTextSchema("section-variation"),
193
+ standardImageTextSchema("section-support"),
194
+ ]),
195
+ generation: z.object({
196
+ title: l10nTextSchema,
197
+ image: sectionImageSchema,
198
+ steps: z
199
+ .array(z.object({ title: l10nTextSchema, body: l10nTextSchema }))
200
+ .min(2)
201
+ .max(5),
202
+ ctaLabel: l10nTextSchema,
203
+ }),
204
+ faq: z.object({
205
+ title: l10nTextSchema,
206
+ intro: l10nTextSchema,
207
+ ctaLabel: l10nTextSchema,
208
+ }),
209
+ });
210
+
211
+ const errorCodeSchema = z.enum([
212
+ "validation",
213
+ "authRequired",
214
+ "submitFailed",
215
+ "taskFailed",
216
+ "resultTimeout",
217
+ "wrongResultType",
218
+ "invalidResultSchema",
219
+ "resultWritebackMissing",
220
+ "computeFailed",
221
+ ]);
222
+
223
+ export const toolPackageSchema = z
224
+ .object({
225
+ meta: z.object({
226
+ slug: z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
227
+ toolType: z.enum(["calculator", "generator", "analyzer", "downloader"]),
228
+ riskLevel: z.enum(["low", "medium", "high"]).optional(),
229
+ keywordEvidence: z
230
+ .string()
231
+ .min(1)
232
+ .refine(
233
+ (value) =>
234
+ value.startsWith("docs/seo-keyword-briefs/") ||
235
+ value.startsWith("strategic:") ||
236
+ value.startsWith("legacy:"),
237
+ {
238
+ message:
239
+ "keywordEvidence 必须指向 docs/seo-keyword-briefs/ 下的 brief、以 strategic: 声明不计 SEO KPI,或以 legacy: 标记待补证据的迁移工具",
240
+ },
241
+ ),
242
+ seo: z.object({
243
+ publishedAt: z.string().optional(),
244
+ updatedAt: z.string().min(1),
245
+ readingTime: z.string().min(1),
246
+ featured: z.boolean().optional(),
247
+ ogImage: z.string().startsWith("/tools/").optional(),
248
+ }),
249
+ mcp: z
250
+ .object({ enabled: z.boolean(), toolName: z.string().optional() })
251
+ .optional(),
252
+ }),
253
+ copy: z.object({
254
+ title: l10nTextSchema,
255
+ displayTitle: l10nTextSchema.optional(),
256
+ description: l10nTextSchema,
257
+ intro: l10nTextSchema,
258
+ category: l10nTextSchema,
259
+ keywords: l10nTextListSchema,
260
+ inputSignal: l10nTextSchema.optional(),
261
+ outputSignal: l10nTextSchema.optional(),
262
+ boundarySignal: l10nTextSchema.optional(),
263
+ }),
264
+ form: z.array(formFieldSchema).min(1),
265
+ runtime: z.discriminatedUnion("lane", [
266
+ z.object({
267
+ lane: z.literal("agent"),
268
+ scene: z.string().regex(/^[a-z][a-z0-9_]*$/),
269
+ resultType: z.string().regex(/^[a-z][a-z0-9_]*$/),
270
+ skillId: z.string().startsWith("$"),
271
+ writebackScript: z.string().endsWith(".mjs"),
272
+ outputContract: z.array(z.string().min(1)).min(3),
273
+ rules: z.array(z.string().min(1)).min(1),
274
+ restrictToSkill: z.boolean().optional(),
275
+ watch: z
276
+ .object({
277
+ pollIntervalMs: z.number().int().min(500).optional(),
278
+ graceWindowMs: z.number().int().min(30_000).optional(),
279
+ })
280
+ .optional(),
281
+ }),
282
+ z.object({
283
+ lane: z.literal("direct"),
284
+ scene: z.string().regex(/^[a-z][a-z0-9_]*$/),
285
+ system: z.string().max(4_000).optional(),
286
+ promptTemplate: z
287
+ .string()
288
+ .min(40)
289
+ .refine((value) => value.includes("{{briefJson}}"), {
290
+ message: "promptTemplate 必须包含 {{briefJson}} 占位符",
291
+ }),
292
+ maxTokens: z.number().int().min(256).max(16_000).optional(),
293
+ }),
294
+ z.object({
295
+ lane: z.literal("instant"),
296
+ compute: z.custom<(...args: unknown[]) => unknown>(
297
+ (value) => typeof value === "function",
298
+ { message: "instant 车道必须提供 compute 纯函数" },
299
+ ),
300
+ }),
301
+ ]),
302
+ resultSchema: z.custom<object>(
303
+ (value) =>
304
+ Boolean(value) &&
305
+ typeof (value as { safeParse?: unknown }).safeParse === "function",
306
+ { message: "resultSchema 必须是 zod schema 实例" },
307
+ ),
308
+ resultView: z.array(resultViewBlockSchema).min(1),
309
+ widget: z.object({
310
+ formTitle: l10nTextSchema,
311
+ formHint: l10nTextSchema,
312
+ submitLabel: l10nTextSchema.optional(),
313
+ resultTitle: l10nTextSchema.optional(),
314
+ pendingTitle: l10nTextSchema.optional(),
315
+ pendingHint: l10nTextSchema.optional(),
316
+ errorOverrides: z
317
+ .partialRecord(
318
+ errorCodeSchema,
319
+ z.object({ title: l10nTextSchema, body: l10nTextSchema }),
320
+ )
321
+ .optional(),
322
+ }),
323
+ page: z.object({
324
+ workspace: z.object({
325
+ heading: l10nTextSchema,
326
+ hint: l10nTextSchema,
327
+ badge: l10nTextSchema.optional(),
328
+ }),
329
+ standard: standardLandingSchema.optional(),
330
+ sections: z.array(pageSectionSchema).min(3).optional(),
331
+ faq: z
332
+ .array(z.object({ question: l10nTextSchema, answer: l10nTextSchema }))
333
+ .min(3),
334
+ cta: z
335
+ .object({
336
+ heading: l10nTextSchema.optional(),
337
+ hint: l10nTextSchema,
338
+ primary: z.object({ href: z.string().startsWith("/"), label: l10nTextSchema }),
339
+ secondary: z
340
+ .object({ href: z.string().startsWith("/"), label: l10nTextSchema })
341
+ .optional(),
342
+ })
343
+ .optional(),
344
+ }),
345
+ assets: z.object({
346
+ hero: z
347
+ .object({ src: z.string().startsWith("/tools/"), alt: l10nTextSchema })
348
+ .optional(),
349
+ }),
350
+ })
351
+ .superRefine((pkg, ctx) => {
352
+ const ids = new Set<string>();
353
+ for (const field of pkg.form) {
354
+ if (ids.has(field.id)) {
355
+ ctx.addIssue({
356
+ code: z.ZodIssueCode.custom,
357
+ message: `表单字段 id 重复:${field.id}`,
358
+ path: ["form"],
359
+ });
360
+ }
361
+ ids.add(field.id);
362
+ }
363
+ if (!pkg.meta.seo.ogImage) {
364
+ ctx.addIssue({
365
+ code: z.ZodIssueCode.custom,
366
+ message: "registry 工具必须提供 seo.ogImage",
367
+ path: ["meta", "seo", "ogImage"],
368
+ });
369
+ }
370
+ if (!pkg.page.standard && !pkg.page.sections) {
371
+ ctx.addIssue({
372
+ code: z.ZodIssueCode.custom,
373
+ message: "page 必须提供 workspace-first standard 或 legacy sections",
374
+ path: ["page"],
375
+ });
376
+ }
377
+ });
378
+
379
+ export type ToolPackageValidationInput = z.input<typeof toolPackageSchema>;
@@ -0,0 +1,20 @@
1
+ import type { ToolModule } from "../types";
2
+ import { loadToolPackage } from "./package-loaders";
3
+ import { createPackageContainer } from "./package-container";
4
+ import { createPackageToolSpec } from "./to-tool-spec";
5
+ import type { ToolPackage } from "./types";
6
+
7
+ /** package → 标准 ToolModule:registry/路由/sitemap/MCP 零改动接入。 */
8
+ export function createPackageToolModule(pkg: ToolPackage): ToolModule {
9
+ return {
10
+ spec: createPackageToolSpec(pkg),
11
+ Container: createPackageContainer(pkg),
12
+ };
13
+ }
14
+
15
+ export async function loadPackageToolModule(
16
+ slug: string,
17
+ ): Promise<ToolModule | undefined> {
18
+ const pkg = await loadToolPackage(slug);
19
+ return pkg ? createPackageToolModule(pkg) : undefined;
20
+ }
@@ -0,0 +1,52 @@
1
+ import type { ToolLocaleCopy, ToolSpec } from "../types";
2
+ import type { L10nText, L10nTextList, ToolPackage } from "./types";
3
+
4
+ function localeCopy(
5
+ pkg: ToolPackage,
6
+ locale: "en" | "zh" | "zh-tw",
7
+ ): ToolLocaleCopy | undefined {
8
+ const pick = (text: L10nText) => text[locale];
9
+ const pickList = (list: L10nTextList) => list[locale];
10
+ const title = pick(pkg.copy.title);
11
+ const description = pick(pkg.copy.description);
12
+ if (!title || !description) return undefined;
13
+
14
+ return {
15
+ title,
16
+ displayTitle: pkg.copy.displayTitle ? pick(pkg.copy.displayTitle) : undefined,
17
+ description,
18
+ intro: pick(pkg.copy.intro),
19
+ category: pick(pkg.copy.category) ?? pkg.copy.category.en,
20
+ keywords: pickList(pkg.copy.keywords) ?? pkg.copy.keywords.en,
21
+ inputSignal: pkg.copy.inputSignal ? pick(pkg.copy.inputSignal) : undefined,
22
+ outputSignal: pkg.copy.outputSignal ? pick(pkg.copy.outputSignal) : undefined,
23
+ boundarySignal: pkg.copy.boundarySignal
24
+ ? pick(pkg.copy.boundarySignal)
25
+ : undefined,
26
+ };
27
+ }
28
+
29
+ /** Serializable package metadata for lists, SEO, sitemaps, and MCP generation. */
30
+ export function createPackageToolSpec(pkg: ToolPackage): ToolSpec {
31
+ const zhTw = localeCopy(pkg, "zh-tw");
32
+
33
+ return {
34
+ slug: pkg.meta.slug,
35
+ toolType: pkg.meta.toolType,
36
+ riskLevel: pkg.meta.riskLevel,
37
+ locales: {
38
+ en: localeCopy(pkg, "en")!,
39
+ zh: localeCopy(pkg, "zh")!,
40
+ ...(zhTw ? { "zh-tw": zhTw } : {}),
41
+ },
42
+ seo: {
43
+ publishedAt: pkg.meta.seo.publishedAt,
44
+ updatedAt: pkg.meta.seo.updatedAt,
45
+ readingTime: pkg.meta.seo.readingTime,
46
+ featured: pkg.meta.seo.featured,
47
+ ogImage: pkg.meta.seo.ogImage,
48
+ },
49
+ mcp: pkg.meta.mcp,
50
+ widget: { id: pkg.meta.slug, mode: "package" },
51
+ };
52
+ }