@jini-ai/agent-plugins 0.6.17 → 0.6.19

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 (335) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/NOTICE +14 -0
  3. package/README.md +35 -14
  4. package/charts-echarts/plugin.json +39 -0
  5. package/charts-echarts/skills/charts-echarts/SKILL.md +110 -0
  6. package/charts-recharts/plugin.json +32 -0
  7. package/charts-recharts/skills/charts-recharts/SKILL.md +108 -0
  8. package/cloudflare/NOTES.md +16 -0
  9. package/cloudflare/form-destinations/cloudflare-d1.mjs +9 -0
  10. package/cloudflare/lib/api.mjs +96 -0
  11. package/cloudflare/lib/assets.mjs +65 -0
  12. package/cloudflare/lib/dns.mjs +32 -0
  13. package/cloudflare/lib/domain-inventory.mjs +61 -0
  14. package/cloudflare/lib/domain-status.mjs +48 -0
  15. package/cloudflare/lib/domains.mjs +95 -0
  16. package/cloudflare/lib/forms.mjs +254 -0
  17. package/cloudflare/lib/pages-upload.mjs +51 -0
  18. package/cloudflare/lib/target.mjs +165 -0
  19. package/cloudflare/lib/workers-upload.mjs +48 -0
  20. package/cloudflare/lib/zones.mjs +25 -0
  21. package/cloudflare/mcp.json +4 -0
  22. package/cloudflare/plugin.json +96 -0
  23. package/cloudflare/skills/cloudflare/SKILL.md +57 -0
  24. package/cloudflare/skills/cloudflare/references/domains.md +31 -0
  25. package/cloudflare/skills/cloudflare/references/pages.md +18 -0
  26. package/cloudflare/skills/cloudflare/references/permissions.md +29 -0
  27. package/cloudflare/skills/cloudflare/references/troubleshooting.md +20 -0
  28. package/cloudflare/skills/cloudflare/references/workers.md +42 -0
  29. package/cloudflare/targets/cloudflare-pages.mjs +12 -0
  30. package/cloudflare/targets/cloudflare-workers.mjs +17 -0
  31. package/cloudflare/tovu-consent.json +6 -0
  32. package/cloudflare/tovu-deploy-targets.json +630 -0
  33. package/cloudflare/tovu-form-destinations.json +12 -0
  34. package/cloudflare/worker/forms-receiver.mjs +249 -0
  35. package/composio/mcp.json +10 -0
  36. package/composio/plugin.json +68 -0
  37. package/composio/skills/composio/SKILL.md +85 -0
  38. package/dist/core/identity-namespace.d.ts +12 -0
  39. package/dist/core/identity-namespace.js +20 -0
  40. package/dist/folder-zip-node.js +29 -7
  41. package/dist/lifecycle/bundled-digests.js +4 -3
  42. package/dist/lifecycle/install.d.ts +7 -0
  43. package/dist/lifecycle/install.js +45 -3
  44. package/dist/lifecycle/manifest.d.ts +2 -2
  45. package/dist/lifecycle/manifest.js +5 -3
  46. package/dist/lifecycle/node.js +2 -0
  47. package/dist/lifecycle/persistent-state.js +1 -1
  48. package/dist/lifecycle/ports.d.ts +8 -0
  49. package/dist/lifecycle/seed-bundled.js +4 -1
  50. package/dist/manifest.d.ts +1 -1
  51. package/dist/manifest.js +3 -2
  52. package/fly/deploy-configs/fly.mjs +115 -0
  53. package/fly/deploy-ops/fly.mjs +102 -0
  54. package/fly/mcp.json +4 -0
  55. package/fly/plugin.json +81 -0
  56. package/fly/scripts/render-deploy-workflow.mjs +150 -0
  57. package/fly/skills/fly/SKILL.md +43 -0
  58. package/fly/skills/fly/references/fly-deploy.template.yml +117 -0
  59. package/fly/skills/fly/references/fly.template.toml +81 -0
  60. package/fly/tovu-credential-schemes.json +11 -0
  61. package/fly/tovu-deploy-configs.json +21 -0
  62. package/fly/tovu-deploy-ops.json +14 -0
  63. package/github/deploy-ops/github-actions.mjs +164 -0
  64. package/github/deployments/github.mjs +415 -0
  65. package/github/mcp.json +4 -0
  66. package/github/plugin.json +105 -0
  67. package/github/skills/github/SKILL.md +249 -0
  68. package/github/skills/github/references/actions.md +224 -0
  69. package/github/skills/github/references/auth-and-tokens.md +140 -0
  70. package/github/skills/github/references/repo-files.md +135 -0
  71. package/github/skills/github/references/site-backup.md +159 -0
  72. package/github/skills/github/references/source-control.md +123 -0
  73. package/github/source-control/backup-push.mjs +242 -0
  74. package/github/source-control/commit-site.mjs +459 -0
  75. package/github/source-control/github.mjs +93 -0
  76. package/github/source-control/write-files.mjs +468 -0
  77. package/github/tovu-deploy-ops.json +13 -0
  78. package/github/tovu-source-control.json +117 -0
  79. package/github-pages/NOTES.md +19 -0
  80. package/github-pages/mcp.json +4 -0
  81. package/github-pages/plugin.json +48 -0
  82. package/github-pages/skills/github-pages/SKILL.md +44 -0
  83. package/github-pages/targets/github-pages.mjs +543 -0
  84. package/github-pages/tovu-deploy-targets.json +327 -0
  85. package/google-login/exports/google-g.svg +1 -0
  86. package/google-login/exports/sign-in-button.css +68 -0
  87. package/google-login/exports/sign-in-button.html +4 -0
  88. package/google-login/mcp.json +4 -0
  89. package/google-login/plugin.json +59 -0
  90. package/google-login/skills/google-login/SKILL.md +96 -0
  91. package/google-login/tovu-login-providers.json +21 -0
  92. package/google-workspace/README.md +132 -0
  93. package/google-workspace/form-destinations/README.md +87 -0
  94. package/google-workspace/form-destinations/dedupe.mjs +43 -0
  95. package/google-workspace/form-destinations/delivery-result.mjs +69 -0
  96. package/google-workspace/form-destinations/mapping.mjs +152 -0
  97. package/google-workspace/form-destinations/sheets.mjs +202 -0
  98. package/google-workspace/lib/auth.mjs +81 -0
  99. package/google-workspace/lib/drive-files.mjs +54 -0
  100. package/google-workspace/lib/form-destination-settings.mjs +72 -0
  101. package/google-workspace/lib/http.mjs +168 -0
  102. package/google-workspace/lib/picker-flow.mjs +171 -0
  103. package/google-workspace/lib/picker-selection.mjs +107 -0
  104. package/google-workspace/lib/product-state.mjs +93 -0
  105. package/google-workspace/lib/request-policy.mjs +163 -0
  106. package/google-workspace/lib/sheets-a1.mjs +79 -0
  107. package/google-workspace/lib/sheets-admin-csv.mjs +82 -0
  108. package/google-workspace/lib/sheets-admin-request-kinds.mjs +183 -0
  109. package/google-workspace/lib/sheets-client.mjs +286 -0
  110. package/google-workspace/lib/surface-actions.mjs +107 -0
  111. package/google-workspace/mcp.json +4 -0
  112. package/google-workspace/plugin.json +77 -0
  113. package/google-workspace/products.json +12 -0
  114. package/google-workspace/skills/google-workspace/SKILL.md +82 -0
  115. package/google-workspace/skills/google-workspace/references/connection.md +102 -0
  116. package/google-workspace/skills/google-workspace/references/form-delivery.md +50 -0
  117. package/google-workspace/skills/google-workspace/references/sheets.md +149 -0
  118. package/google-workspace/skills/google-workspace/references/troubleshooting.md +31 -0
  119. package/google-workspace/tools/account-info.mjs +18 -0
  120. package/google-workspace/tools/sheets/README.md +54 -0
  121. package/google-workspace/tools/sheets/copy-tab.mjs +23 -0
  122. package/google-workspace/tools/sheets/copy.mjs +23 -0
  123. package/google-workspace/tools/sheets/create.mjs +35 -0
  124. package/google-workspace/tools/sheets/find-replace.mjs +38 -0
  125. package/google-workspace/tools/sheets/find.mjs +52 -0
  126. package/google-workspace/tools/sheets/get-by-data-filter.mjs +23 -0
  127. package/google-workspace/tools/sheets/get.mjs +22 -0
  128. package/google-workspace/tools/sheets/values-append.mjs +27 -0
  129. package/google-workspace/tools/sheets/values-batch-clear.mjs +20 -0
  130. package/google-workspace/tools/sheets/values-batch-get.mjs +20 -0
  131. package/google-workspace/tools/sheets/values-batch-update.mjs +29 -0
  132. package/google-workspace/tools/sheets/values-by-data-filter.mjs +62 -0
  133. package/google-workspace/tools/sheets/values-clear.mjs +20 -0
  134. package/google-workspace/tools/sheets/values-get.mjs +21 -0
  135. package/google-workspace/tools/sheets/values-update.mjs +26 -0
  136. package/google-workspace/tools/sheets-admin/README.md +45 -0
  137. package/google-workspace/tools/sheets-admin/basic-filter.mjs +32 -0
  138. package/google-workspace/tools/sheets-admin/batch-update.mjs +25 -0
  139. package/google-workspace/tools/sheets-admin/developer-metadata.mjs +28 -0
  140. package/google-workspace/tools/sheets-admin/export-csv.mjs +67 -0
  141. package/google-workspace/tools/sheets-admin/filter-views.mjs +38 -0
  142. package/google-workspace/tools/sheets-admin/format.mjs +70 -0
  143. package/google-workspace/tools/sheets-admin/named-ranges.mjs +42 -0
  144. package/google-workspace/tools/sheets-admin/open-existing.mjs +34 -0
  145. package/google-workspace/tools/sheets-admin/protected-ranges-get.mjs +18 -0
  146. package/google-workspace/tools/sheets-admin/sort.mjs +18 -0
  147. package/google-workspace/tools/sheets-admin/tab-modify.mjs +36 -0
  148. package/google-workspace/tovu-admin-surfaces.json +63 -0
  149. package/google-workspace/tovu-agent-tools.json +1178 -0
  150. package/google-workspace/tovu-connections.json +35 -0
  151. package/google-workspace/tovu-form-destinations.json +10 -0
  152. package/google-workspace/ui/README.md +73 -0
  153. package/google-workspace/ui/connection-panel.handler.mjs +167 -0
  154. package/google-workspace/ui/connection-panel.html +17 -0
  155. package/google-workspace/ui/connection-panel.mjs +189 -0
  156. package/google-workspace/ui/connection-view.mjs +120 -0
  157. package/google-workspace/ui/destination-panel.handler.mjs +106 -0
  158. package/google-workspace/ui/destination-panel.html +17 -0
  159. package/google-workspace/ui/destination-panel.mjs +150 -0
  160. package/google-workspace/ui/dom.mjs +140 -0
  161. package/google-workspace/ui/panel.css +170 -0
  162. package/google-workspace/ui/picker-flow.mjs +87 -0
  163. package/google-workspace/ui/picker-view.mjs +44 -0
  164. package/google-workspace/ui/picker.handler.mjs +56 -0
  165. package/google-workspace/ui/picker.html +17 -0
  166. package/google-workspace/ui/picker.mjs +88 -0
  167. package/google-workspace/ui/surface-client.mjs +227 -0
  168. package/higgsfield-media/mcp.json +9 -0
  169. package/higgsfield-media/plugin.json +109 -0
  170. package/higgsfield-media/skills/higgsfield-media/SKILL.md +325 -0
  171. package/higgsfield-media/skills/higgsfield-media/references/failure-modes.md +116 -0
  172. package/higgsfield-media/skills/higgsfield-media/references/models-and-plan-gates.md +142 -0
  173. package/jev/mcp.json +4 -0
  174. package/jev/plugin.json +44 -0
  175. package/jev/skills/jev/SKILL.md +308 -0
  176. package/jev/skills/jev/references/cookbooks.md +197 -0
  177. package/jev/skills/jev/references/jaggedness.md +135 -0
  178. package/jev/skills/jev/references/javascript-sdk.md +146 -0
  179. package/jev/skills/jev/references/patterns.md +123 -0
  180. package/jev/skills/jev/references/primitives-reference.md +187 -0
  181. package/langfuse/plugin.json +22 -0
  182. package/meilisearch/mcp.json +4 -0
  183. package/meilisearch/plugin.json +54 -0
  184. package/meilisearch/providers/meilisearch.mjs +651 -0
  185. package/meilisearch/skills/meilisearch/SKILL.md +43 -0
  186. package/meilisearch/tovu-search-providers.json +10 -0
  187. package/netlify/NOTES.md +13 -0
  188. package/netlify/mcp.json +4 -0
  189. package/netlify/plugin.json +47 -0
  190. package/netlify/skills/netlify/SKILL.md +39 -0
  191. package/netlify/targets/netlify.mjs +384 -0
  192. package/netlify/tovu-consent.json +6 -0
  193. package/netlify/tovu-deploy-targets.json +163 -0
  194. package/opentelemetry/mcp.json +4 -0
  195. package/opentelemetry/plugin.json +52 -0
  196. package/opentelemetry/skills/opentelemetry/SKILL.md +39 -0
  197. package/package.json +161 -6
  198. package/posthog/mcp.json +4 -0
  199. package/posthog/plugin.json +46 -0
  200. package/posthog/skills/posthog/SKILL.md +36 -0
  201. package/railway/deploy-configs/railway.mjs +135 -0
  202. package/railway/deploy-ops/railway.mjs +167 -0
  203. package/railway/mcp.json +4 -0
  204. package/railway/plugin.json +45 -0
  205. package/railway/skills/railway/SKILL.md +66 -0
  206. package/railway/tovu-deploy-configs.json +16 -0
  207. package/railway/tovu-deploy-ops.json +11 -0
  208. package/render/deploy-configs/render.mjs +141 -0
  209. package/render/deploy-ops/render.mjs +152 -0
  210. package/render/mcp.json +4 -0
  211. package/render/plugin.json +47 -0
  212. package/render/skills/render/SKILL.md +63 -0
  213. package/render/tovu-deploy-configs.json +16 -0
  214. package/render/tovu-deploy-ops.json +11 -0
  215. package/resend/NOTES.md +52 -0
  216. package/resend/adapters/resend.mjs +161 -0
  217. package/resend/lib/domains.mjs +137 -0
  218. package/resend/lib/errors.mjs +25 -0
  219. package/resend/lib/feedback.mjs +118 -0
  220. package/resend/mcp.json +13 -0
  221. package/resend/plugin.json +192 -0
  222. package/resend/skills/resend/SKILL.md +107 -0
  223. package/resend/tovu-mail-adapters.json +22 -0
  224. package/s3-compatible/NOTES.md +11 -0
  225. package/s3-compatible/mcp.json +4 -0
  226. package/s3-compatible/object-stores/s3-compatible.mjs +287 -0
  227. package/s3-compatible/plugin.json +56 -0
  228. package/s3-compatible/skills/s3-compatible/SKILL.md +39 -0
  229. package/s3-compatible/targets/s3-compatible.mjs +1054 -0
  230. package/s3-compatible/tovu-deploy-targets.json +432 -0
  231. package/s3-compatible/tovu-object-stores.json +29 -0
  232. package/sentry/mcp.json +4 -0
  233. package/sentry/plugin.json +49 -0
  234. package/sentry/skills/sentry/SKILL.md +34 -0
  235. package/shopify/mcp.json +4 -0
  236. package/shopify/plugin.json +22 -0
  237. package/shopify/skills/shopify/SKILL.md +103 -0
  238. package/shopify/skills/shopify/references/catalog-sync.md +74 -0
  239. package/shopify/skills/shopify/references/domains.md +26 -0
  240. package/shopify/skills/shopify/references/live-storefront.md +34 -0
  241. package/shopify/skills/shopify/references/storefront-snippets.md +21 -0
  242. package/site-compliance/mcp.json +4 -0
  243. package/site-compliance/plugin.json +34 -0
  244. package/site-compliance/skills/site-compliance/SKILL.md +220 -0
  245. package/site-compliance/skills/site-compliance/references/ccpa-cpra.md +115 -0
  246. package/site-compliance/skills/site-compliance/references/gdpr-eu-uk.md +143 -0
  247. package/site-compliance/skills/site-compliance/references/wcag-2-2.md +129 -0
  248. package/site-import/mcp.json +4 -0
  249. package/site-import/plugin.json +41 -0
  250. package/site-import/skills/site-import/SKILL.md +232 -0
  251. package/site-import/skills/site-import/references/content-mapping.md +166 -0
  252. package/site-import/skills/site-import/references/discovery-and-classification.md +117 -0
  253. package/site-import/skills/site-import/references/theme-extraction.md +34 -0
  254. package/slide-design/com.anthropic.claude-code/hooks/hooks.json +4 -0
  255. package/slide-design/mcp.json +4 -0
  256. package/slide-design/plugin.json +26 -0
  257. package/slide-design/skills/slide-design/SKILL.md +103 -0
  258. package/slide-design/skills/slide-design/references/charts-and-exhibits.md +100 -0
  259. package/slide-design/skills/slide-design/references/html-deck.md +175 -0
  260. package/slide-design/skills/slide-design/references/layout-and-style.md +131 -0
  261. package/slide-design/skills/slide-design/references/review.md +93 -0
  262. package/slide-design/skills/slide-design/references/storyline.md +118 -0
  263. package/stripe/plugin.json +22 -0
  264. package/supabase/mcp.json +26 -0
  265. package/supabase/plugin.json +78 -0
  266. package/supabase/skills/supabase/SKILL.md +169 -0
  267. package/supabase/skills/supabase/references/failure-modes.md +101 -0
  268. package/ui-ux-design/CHANGELOG.md +28 -0
  269. package/ui-ux-design/LICENSE +201 -0
  270. package/ui-ux-design/NOTICE +14 -0
  271. package/ui-ux-design/README.md +62 -0
  272. package/ui-ux-design/com.anthropic.claude-code/hooks/hooks.json +4 -0
  273. package/ui-ux-design/mcp.json +4 -0
  274. package/ui-ux-design/plugin.json +26 -0
  275. package/ui-ux-design/skills/frontend-accessibility/SKILL.md +60 -0
  276. package/ui-ux-design/skills/gstack-design/SKILL.md +53 -0
  277. package/ui-ux-design/skills/gstack-design/references/consultation.md +30 -0
  278. package/ui-ux-design/skills/gstack-design/references/html.md +29 -0
  279. package/ui-ux-design/skills/gstack-design/references/review.md +28 -0
  280. package/ui-ux-design/skills/gstack-design/references/shotgun.md +33 -0
  281. package/ui-ux-design/skills/gstack-design/references/upstream-notes.md +23 -0
  282. package/ui-ux-design/skills/interface-design/ORIGINAL.md +16 -0
  283. package/ui-ux-design/skills/interface-design/SKILL.md +41 -0
  284. package/ui-ux-design/skills/interface-design/references/commands/audit.md +40 -0
  285. package/ui-ux-design/skills/interface-design/references/commands/critique.md +21 -0
  286. package/ui-ux-design/skills/interface-design/references/commands/extract.md +34 -0
  287. package/ui-ux-design/skills/interface-design/references/commands/init.md +31 -0
  288. package/ui-ux-design/skills/interface-design/references/commands/status.md +22 -0
  289. package/ui-ux-design/skills/interface-design/references/examples/system-precision.md +29 -0
  290. package/ui-ux-design/skills/interface-design/references/examples/system-warmth.md +29 -0
  291. package/ui-ux-design/skills/interface-design/references/system-template.md +57 -0
  292. package/ui-ux-design/skills/shadcn-ui/README.md +244 -0
  293. package/ui-ux-design/skills/shadcn-ui/SKILL.md +333 -0
  294. package/ui-ux-design/skills/shadcn-ui/examples/auth-layout.tsx +177 -0
  295. package/ui-ux-design/skills/shadcn-ui/examples/data-table.tsx +313 -0
  296. package/ui-ux-design/skills/shadcn-ui/examples/form-pattern.tsx +177 -0
  297. package/ui-ux-design/skills/shadcn-ui/resources/component-catalog.md +481 -0
  298. package/ui-ux-design/skills/shadcn-ui/resources/customization-guide.md +516 -0
  299. package/ui-ux-design/skills/shadcn-ui/resources/migration-guide.md +463 -0
  300. package/ui-ux-design/skills/shadcn-ui/resources/setup-guide.md +412 -0
  301. package/ui-ux-design/skills/shadcn-ui/scripts/verify-setup.sh +134 -0
  302. package/ui-ux-design/skills/ui-ux-design/SKILL.md +171 -0
  303. package/ui-ux-design/skills/ui-ux-design/references/brand-and-voice.md +78 -0
  304. package/ui-ux-design/skills/ui-ux-design/references/chrome-mobile-test-matrix.md +137 -0
  305. package/ui-ux-design/skills/ui-ux-design/references/components-and-states.md +112 -0
  306. package/ui-ux-design/skills/ui-ux-design/references/delight-and-motion.md +54 -0
  307. package/ui-ux-design/skills/ui-ux-design/references/foundations.md +145 -0
  308. package/ui-ux-design/skills/ui-ux-design/references/inclusive-ai-imagery.md +57 -0
  309. package/ui-ux-design/skills/ui-ux-design/references/kole-jain-uiux-concepts.md +104 -0
  310. package/ui-ux-design/skills/ui-ux-design/references/kuinetic-reference.md +184 -0
  311. package/ui-ux-design/skills/ui-ux-design/references/openai-frontend-skill.md +139 -0
  312. package/ui-ux-design/skills/ui-ux-design/references/premium-ui.md +55 -0
  313. package/ui-ux-design/skills/ui-ux-design/references/research-and-validation.md +88 -0
  314. package/ui-ux-design/skills/ui-ux-design/references/sam-crawford-premium-websites.md +103 -0
  315. package/ui-ux-design/skills/ui-ux-design/references/self-made-web-designer-core-skills.md +119 -0
  316. package/ui-ux-design/skills/ui-ux-design/references/ui-animation.md +173 -0
  317. package/ui-ux-design/skills/ui-ux-design/references/ui-loop.md +234 -0
  318. package/ui-ux-design/skills/ui-ux-design/references/visual-storytelling.md +54 -0
  319. package/ui-ux-design/skills/vercel-web-design-guidelines/SKILL.md +39 -0
  320. package/ui-ux-design/skills/web-compliance/SKILL.md +134 -0
  321. package/ui-ux-design/skills/web-compliance/references/audit-evidence.md +59 -0
  322. package/vercel/NOTES.md +23 -0
  323. package/vercel/mcp.json +4 -0
  324. package/vercel/object-stores/vercel-blob.mjs +147 -0
  325. package/vercel/plugin.json +47 -0
  326. package/vercel/skills/vercel/SKILL.md +48 -0
  327. package/vercel/targets/vercel.mjs +586 -0
  328. package/vercel/tovu-consent.json +6 -0
  329. package/vercel/tovu-deploy-targets.json +219 -0
  330. package/vercel/tovu-object-stores.json +10 -0
  331. package/wordpress/NOTES.md +33 -0
  332. package/wordpress/plugin.json +30 -0
  333. package/wordpress/skills/wordpress/SKILL.md +43 -0
  334. package/wordpress/skills/wordpress/references/free-site-redirect.md +46 -0
  335. package/wordpress/skills/wordpress/references/subdomain.md +66 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.19
4
+
5
+ - A plugin's state lock left by a killed boot no longer keeps that plugin off on every later boot after the machine's hostname spelling changed (macOS `.lan`/`.local`): the node process port records the kernel boot (`bootIdentity`), so the platform lock can prove the holder was this machine's and reclaim it once its pid is dead.
6
+ - Tests: the hosting plugins' identical `vitest-compat.mjs` (3 copies) and `fake-deploy-host-kit.mjs` (4 copies) are one shared test-only copy each under `packages/agent-plugins/__tests__/` (never published). Cloudflare's doubled DNS-marker and Pages-config comments are merged.
7
+ - Google Workspace: a Sheets `batchUpdate` with more than one request is never replayed after an unknown outcome. Each request was judged replay-safe alone, but Google applies them in order, so a retry of "copy A1 to B1, then set A1" changed B1.
8
+ - Security: reinstalling a plugin whose digest directory already exists compares that directory's bytes with the verified archive before reusing it. A same-build reseed used to keep an operator-edited bundled revision selected as shipped code; a modified copy is now kept aside under a `.modified-*` name (never indexed or selected) and the verified bytes are reinstalled.
9
+ - Railway's deploy-config generator refuses an `env` value containing a newline or control character (C0, DEL, C1) with an error naming the variable. Before, it printed the raw LF or NUL into the copy-paste `railway variables set` command. The error never echoes the value.
10
+ - Add the portable Shopify catalog and checkout skill under `@jini-ai/agent-plugins/shopify`; host collection tools, markup and domain routing stay in the host overlay.
11
+ - Pin Fly's portable template safety settings: operator placeholders, secret-free app configuration, single-machine defaults, serialized deploys and repository-secret token wiring.
12
+ - `charts-recharts` and `charts-echarts` declare `provides: ["chart"]` (the kind their provider draws), so capability lookup and automatic-use ranking find the chart faces.
13
+ - Plugin-folder suites (`<id>/**/__tests__/*.test.mjs`) are node:test files: the root `test:agent-plugins:content` script runs them and this package's vitest config no longer collects them. Shipped plugin `.mjs` modules are under the root `complexity:strict` gate.
14
+ - Every Jini agent plugin now ships in this package as a subpath: `@jini-ai/agent-plugins/<id>`
15
+ resolves to `<id>/plugin.json` and `@jini-ai/agent-plugins/<id>/*` to its files (ui-ux-design,
16
+ slide-design, the hosting, mail, search, login, workspace, media and chart faces, and the
17
+ posthog/sentry/opentelemetry setup faces). There are no per-plugin `@jini-ai/plugin-*` packages
18
+ for agent plugins; `__tests__/` folders are not published.
19
+ - Bundled seeding no longer prunes other revisions of a plugin. Reseeding kept deleting an
20
+ operator-edited, uploaded or older bundled same-name copy; every copy now survives and the
21
+ bundled-digests ledger selects the build's revision. `installAgentPlugin` takes
22
+ `{ pruneSupersededRevisions: false }`; explicit install, update and replace keep pruning.
23
+ - `zipCustomizedAgentPluginFolder` gives the fork `local/<name>` under every host key that
24
+ declared an id (and under the requesting host's key even when none existed), and removes
25
+ `renamedFrom` and `supersedes` from every key, not only the requesting host's.
26
+ - README documents the extension-namespace policy: one `extensions` key per host.
27
+ - slide-design review checklist matches the chart guide: a compact legend is fine when direct
28
+ labels would collide, and only magnitude bars and columns must start at zero (waterfall change
29
+ bars float).
30
+
3
31
  ## 0.6.17
4
32
 
5
33
  ### Patch Changes
@@ -18,7 +46,7 @@
18
46
 
19
47
  - Breaking package-surface change for the fixed 0.6.15 release: remove the bundled
20
48
  ui-ux-design files and wildcard export from @jini-ai/agent-plugins. Hosts must
21
- explicitly install @jini-ai/plugin-ui-ux-design and resolve its ./plugin.json
49
+ use @jini-ai/agent-plugins/ui-ux-design to resolve its plugin.json
22
50
  export, stage that payload and seed through the existing Agent Plugin lifecycle.
23
51
  The lifecycle implementation remains in @jini-ai/agent-plugins. Inner plugin
24
52
  version 0.4.6, deterministic packing, digest selection and operator activation
package/NOTICE ADDED
@@ -0,0 +1,14 @@
1
+ Jini UI/UX Design Agent Plugin
2
+ Copyright 2026 Leona Burime
3
+
4
+ Portable skill sources remain at packages/agent-plugins/ui-ux-design.
5
+ Originally assembled from AI-Dev-Shop's Web Design skill trees; the ADS-specific
6
+ agent persona and routing implementation are not included.
7
+
8
+ Source notes and attribution are retained in the generated skills tree, including
9
+ skills/interface-design/ORIGINAL.md (Dammyjay93/interface-design) and
10
+ skills/gstack-design/references/upstream-notes.md (garrytan/gstack).
11
+ The skill references retain their original source links and attribution.
12
+
13
+ This distribution does not include the provider-plugin aggregate or its Open SaaS
14
+ Stripe adaptations. See LICENSE for the Apache License, Version 2.0.
package/README.md CHANGED
@@ -29,7 +29,7 @@ decides its own install mechanism, permission model, and sandboxing.
29
29
 
30
30
  ## What a plugin looks like on disk
31
31
 
32
- A plugin is a directory. Example (`@jini-ai/plugin-ui-ux-design` publishes this payload):
32
+ A plugin is a directory. Example (this package publishes it as `@jini-ai/agent-plugins/ui-ux-design`):
33
33
 
34
34
  ```
35
35
  ui-ux-design/
@@ -150,19 +150,22 @@ package supports. Do not confuse the two — "agent plugins" (this package, a
150
150
  public spec) and "Jini plugins" (`@jini-ai/plugins`'s `./host`, Jini's own unbuilt format) share
151
151
  the word "plugin" and nothing else.
152
152
 
153
- ## Independently packaged plugins
153
+ ## Plugins as subpaths
154
154
 
155
- Starting with the breaking 0.6.17 release, this library ships manifest and lifecycle code only.
156
- Install `@jini-ai/plugin-ui-ux-design` explicitly for the design payload. Resolve
157
- `@jini-ai/plugin-ui-ux-design/plugin.json`; its containing directory holds the portable assets.
158
- Stage that directory beneath the host's bundled-source root, then call the existing
155
+ Every Jini agent plugin ships inside this package as its own folder and subpath:
156
+ `@jini-ai/agent-plugins/<id>` resolves to `<id>/plugin.json`, and `@jini-ai/agent-plugins/<id>/*`
157
+ reaches any file in that folder. Resolve the manifest (`require.resolve` or
158
+ `import.meta.resolve('@jini-ai/agent-plugins/vercel')`); its containing directory holds the
159
+ portable assets. Stage that directory beneath the host's bundled-source root, then call the existing
159
160
  `seedBundledAgentPlugins({ layout, workspaceId, sourceRoot })`. Read contributions through trusted
160
161
  installed-package readers. Seeding preserves digest selection and operator activation decisions.
161
162
 
162
- The editable design source remains at `ui-ux-design/` here, outside `src/`: its `.tsx` examples
163
- are illustrative skill content and must not enter the TypeScript compile root. Assembly generates
164
- only the standalone package's payload. The old `@jini-ai/agent-plugins/ui-ux-design/*` export is
165
- removed; product-specific assets remain owned by their product.
163
+ A plugin folder imports nothing from a sibling plugin folder (`scripts/check-agent-plugin-content.ts`
164
+ and the packed-isolation gate refuse it), so resolving one subpath never loads another plugin's
165
+ files. Plugin folders sit outside `src/`: their `.tsx` examples are illustrative skill content and
166
+ must not enter the TypeScript compile root. `__tests__/` folders are not published. Provider
167
+ runtime code (charts, analytics, observability, payments) is not here; it ships as provider
168
+ plugins (`@jini-ai/provider-plugins/<provider>/*`).
166
169
 
167
170
  ## Scripts
168
171
 
@@ -177,10 +180,11 @@ translated to Vitest registration, preserving per-test timeouts and platform ski
177
180
 
178
181
  ## Adding another plugin
179
182
 
180
- Create a separate `@jini-ai/plugin-<id>` workspace package with its own reviewed manifest,
181
- README, LICENSE and NOTICE. Generate only that plugin's payload; do not add plugin assets or
182
- plugin dependencies to this lifecycle library. Keep skill trees outside TypeScript compile roots,
183
- validate the plugin manifest and test installation through this package's existing lifecycle.
183
+ Create `packages/agent-plugins/<id>/` with its `plugin.json` (name `<id>`), add its row to
184
+ `scripts/lib/agent-plugin-packages.ts`, and add `./<id>`, `./<id>/*` (exports and `jini.entries`)
185
+ and `<id>` (`files`) here. Shipped `.mjs` may import only `node:*`, same-folder files and
186
+ `@jini-ai/*` contracts; tests live in `<id>/**/__tests__/*.test.mjs` (node:test). Validate the
187
+ manifest and test installation through this package's existing lifecycle.
184
188
 
185
189
  ## Lifecycle API and ports
186
190
 
@@ -262,6 +266,23 @@ For a host that needs only activation, use `createAgentPluginActivations` with
262
266
  ports. Retain one returned object for the process lifetime. See `API.md` for the
263
267
  object-shaped reads, filters and optional legacy metadata reader.
264
268
 
269
+ ### Extension namespaces
270
+
271
+ `extensions` keys in `plugin.json` are **host keys**. A plugin declares one entry per host it
272
+ supports, for example `"tovu": { "id": "tovu/stock" }` beside `"open-marketing": { "id": "tovu/stock" }`.
273
+
274
+ - A host reads only its own key, the `extensionNamespace` it passes to the lifecycle.
275
+ - Without a host namespace, exported parsers and validators read `jini`, falling back to the legacy
276
+ `tovu` key only when `jini` is absent. A present malformed `jini` entry is refused, never bypassed.
277
+ Passing a namespace explicitly reads only that key, with no fallback to another host.
278
+ - Publisher ids stay as declared. There is no alias between keys and no content rewrite.
279
+ - A customized fork (`zipCustomizedAgentPluginFolder`) gets `local/<name>` under every host key
280
+ that declared an id, and loses every `renamedFrom` and `supersedes` claim, so no host sees the
281
+ fork answer for, or retire, the package it was copied from.
282
+ - Bundled seeding never prunes other revisions of a plugin, so an operator-edited or uploaded
283
+ same-name copy survives every boot. The bundled-digests ledger selects the build's revision; the
284
+ other copies stay installed and unselected. Explicit install, update and replace still prune.
285
+
265
286
  ### Persistent plugin state (Layout B)
266
287
 
267
288
  `@jini-ai/agent-plugins/persistent-state` is a build-free Node entry with declarations.
@@ -0,0 +1,39 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "charts-echarts",
4
+ "version": "0.1.0",
5
+ "description": "Teaches the assistant to draw bar, stacked bar, line, area, pie, donut and scatter charts in chat with the Apache ECharts chart provider: finding the chart components with search_components, the data shape each one takes, several series in one chart through the generic chart.spec entry, axis names and number formats, and what falls back to a table. Know-how only: no code, no MCP server; the ECharts provider plugin (charts-echarts) draws the charts and switches this plugin on and off.",
6
+ "license": "Apache-2.0",
7
+ "extensions": {
8
+ "tovu": {
9
+ "id": "jini/charts-echarts-agent",
10
+ "displayName": "ECharts",
11
+ "summary": "Lets the assistant draw bar, stacked bar, line, area, pie, donut and scatter charts in chat, with several series. Ask for a chart of your data.",
12
+ "providerPlugin": "charts-echarts",
13
+ "provides": ["chart"]
14
+ }
15
+ },
16
+ "keywords": [
17
+ "chart",
18
+ "charts",
19
+ "graph",
20
+ "plot",
21
+ "bar-chart",
22
+ "stacked-bar-chart",
23
+ "line-chart",
24
+ "area-chart",
25
+ "pie-chart",
26
+ "donut-chart",
27
+ "scatter-plot",
28
+ "data-visualization",
29
+ "visualization",
30
+ "trend",
31
+ "breakdown",
32
+ "comparison",
33
+ "correlation",
34
+ "multi-series",
35
+ "chart-spec",
36
+ "echarts",
37
+ "charts-echarts"
38
+ ]
39
+ }
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: charts-echarts
3
+ version: 0.1.0
4
+ last_updated: 2026-11-02
5
+ description: Use when the user asks for a chart, graph or plot of data (comparisons, trends, shares of a whole, stacked totals, correlations) and the ECharts chart provider is enabled. Covers finding the chart components, the data each takes, several series in one chart, axis names and number formats, and what falls back to a table.
6
+ ---
7
+
8
+ # Skill: Charts with ECharts
9
+
10
+ The ECharts provider draws charts the host shows in chat or on a canvas. You never write chart
11
+ code. You pick a chart component from the host's component catalog and hand it data as props.
12
+
13
+ ## Find the components first
14
+
15
+ 1. Call `search_components` with `"chart"` (or the shape you need, such as "stacked bar of revenue
16
+ and cost by month" or "scatter of height against weight").
17
+ 2. Call `describe_component` on the one or two ids that fit, to read the exact props schema.
18
+ 3. Render through the host's UI-rendering tool (the one that takes a component tree). Put the chart
19
+ inside a layout component if the tool needs a root.
20
+
21
+ The catalog is the source of truth. Ids and schemas below are what it lists today; if the catalog
22
+ differs, follow the catalog.
23
+
24
+ ## Which kind
25
+
26
+ | Question the chart answers | Kind |
27
+ |---|---|
28
+ | How do categories compare (posts by status, sales by region)? | `bar` |
29
+ | How do parts add up per category (revenue split by product, per month)? | `stacked-bar` |
30
+ | How did a value change over time (sign-ups per month)? | `line` |
31
+ | How did a volume change over time, filled to the axis? | `area` |
32
+ | What share of a whole does each part take (pages vs posts)? | `pie` or `donut` |
33
+ | Do two measures move together (price against rating)? | `scatter` |
34
+
35
+ ECharts draws `bar`, `line`, `area`, `pie`, `donut`, `scatter` and `stacked-bar` only.
36
+
37
+ ## The components and their data
38
+
39
+ **One series, simplest props** (`bar`, `line` and `pie` keep the shared single-series shapes):
40
+
41
+ - `plugin.echarts.bar-chart`, `plugin.echarts.line-chart`:
42
+ `{ data: [rows], categoryKey, valueKey, valueLabel?, color? }`.
43
+ - `plugin.echarts.pie-chart`: `{ data: [{ name, value }], color? }`. One row per slice.
44
+
45
+ **Every other kind, and any chart with several series: `{ spec }`**
46
+
47
+ `plugin.echarts.area-chart`, `.donut-chart`, `.scatter-chart` and `.stacked-bar-chart` take
48
+ `{ spec }` with that `spec.kind`. `chart.spec` takes the same `{ spec }` for any kind:
49
+
50
+ ```json
51
+ { "spec": {
52
+ "kind": "stacked-bar",
53
+ "categoryKey": "month",
54
+ "series": [{ "key": "revenue", "label": "Revenue" }, { "key": "cost", "label": "Cost" }],
55
+ "data": [{ "month": "Jan", "revenue": 120, "cost": 80 }, { "month": "Feb", "revenue": 150, "cost": null }],
56
+ "title": "Revenue and cost by month",
57
+ "axes": { "y": { "label": "USD", "format": { "notation": "compact" } } },
58
+ "provider": "plugin.echarts"
59
+ } }
60
+ ```
61
+
62
+ - Every row carries the category and a number (or `null` for a gap) for every series key.
63
+ - Series keys are unique. There is at least one row and one series.
64
+ - `spec.provider: "plugin.echarts"` asks for ECharts when several chart providers are enabled.
65
+ - `axes.x.label` / `axes.y.label` name the axes. `format` (or `axes.x.format` / `axes.y.format`,
66
+ which win) takes `{ locale?, notation? }`, with `notation` `"standard"` or `"compact"` (1.5K).
67
+
68
+ ## Kind rules
69
+
70
+ - `pie` and `donut`: exactly **one** series of numbers that are zero or more, with a total above
71
+ zero. `categoryKey` names the slices. No gaps.
72
+ - `scatter`: `categoryKey` is the numeric **x** of every point; each series is a **y**. Points with
73
+ a `null` y are left out.
74
+ - `bar`, `stacked-bar`, `line`, `area`: any number of series; `null` leaves a gap.
75
+
76
+ ## What falls back
77
+
78
+ ECharts draws a spec only when the kind is one of its seven, there is a `categoryKey`, at least
79
+ one row and series, every value is a finite number or `null` (at least one is a number), the kind
80
+ rules above hold and any `locale` is a valid language tag. Anything else goes to another enabled
81
+ provider that accepts it, or shows as a table. Nothing is lost, but tell the user when you know
82
+ the result will be a table.
83
+
84
+ ## Making it read well
85
+
86
+ - Aggregate first. Send the counts or totals to plot, not raw records.
87
+ - Bars: about 12 categories or fewer. Sort by value unless the order means something (months,
88
+ stages). In narrow spaces some category labels are skipped; the tooltip keeps every value.
89
+ - Stacked bars: 2 to 5 series, in a fixed order the user would read top to bottom.
90
+ - Lines and areas: time in order, oldest first; up to about 5 series.
91
+ - Pies and donuts: 6 slices or fewer, values that add up to a meaningful whole. Merge the small
92
+ ones into "Other". Use a bar chart when the user needs to compare similar values.
93
+ - Whole-number data (counts) gets whole-number axis ticks automatically.
94
+ - Leave `color` out unless the user asks. The host theme colours the chart.
95
+ - Give a short title that states what is shown, and a description when the chart makes a point
96
+ the title doesn't. Keep labels short and human: "Published", not `post_status_published`.
97
+
98
+ ## Never
99
+
100
+ - Never paste ECharts, SVG or HTML chart code into the chat, a page or a file to draw a chart.
101
+ The provider owns the drawing; your job is the data and the component choice.
102
+ - Never invent data. If you can't get the numbers, say so and ask.
103
+ - Never claim a chart rendered when the host reported a refusal. Read the error, fix the props
104
+ (usually a missing key or a string where a number belongs), and try once more.
105
+
106
+ ## When charts are off
107
+
108
+ If the chart entries `search_components` returns all report provider `core.table`, no chart
109
+ provider is enabled. The data will show as a table; say so, and tell the user an administrator can
110
+ turn the ECharts chart provider on.
@@ -0,0 +1,32 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "charts-recharts",
4
+ "version": "0.1.0",
5
+ "description": "Teaches the assistant to draw bar, line and pie charts in chat with the Recharts chart provider: finding the chart components with search_components, the data shape each one takes, what Recharts draws and what falls back to a table, and the generic chart.spec entry for several series. Know-how only: no code, no MCP server; the Recharts provider plugin (charts-recharts) draws the charts and switches this plugin on and off.",
6
+ "license": "Apache-2.0",
7
+ "extensions": {
8
+ "tovu": {
9
+ "id": "jini/charts-recharts-agent",
10
+ "displayName": "Recharts",
11
+ "summary": "Lets the assistant draw bar, line and pie charts in chat. Ask for a chart of your data.",
12
+ "providerPlugin": "charts-recharts",
13
+ "provides": ["chart"]
14
+ }
15
+ },
16
+ "keywords": [
17
+ "chart",
18
+ "charts",
19
+ "graph",
20
+ "plot",
21
+ "bar-chart",
22
+ "line-chart",
23
+ "pie-chart",
24
+ "data-visualization",
25
+ "visualization",
26
+ "trend",
27
+ "breakdown",
28
+ "chart-spec",
29
+ "recharts",
30
+ "charts-recharts"
31
+ ]
32
+ }
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: charts-recharts
3
+ version: 0.1.0
4
+ last_updated: 2026-11-02
5
+ description: Use when the user asks for a chart, graph or plot of data (counts, totals, trends over time, shares of a whole) and the Recharts chart provider is enabled. Covers finding the chart components, the data each takes, what Recharts draws, and when to use the generic chart.spec entry.
6
+ ---
7
+
8
+ # Skill: Charts with Recharts
9
+
10
+ The Recharts provider draws charts the host shows in chat or on a canvas. You never write chart
11
+ code. You pick a chart component from the host's component catalog and hand it data as props.
12
+
13
+ ## Find the components first
14
+
15
+ 1. Call `search_components` with `"chart"` (or the shape you need, such as "bar chart of counts by
16
+ category" or "trend over months").
17
+ 2. Call `describe_component` on the one or two ids that fit, to read the exact props schema.
18
+ 3. Render through the host's UI-rendering tool (the one that takes a component tree). Put the chart
19
+ inside a layout component if the tool needs a root.
20
+
21
+ The catalog is the source of truth. Ids and schemas below are what it lists today; if the catalog
22
+ differs, follow the catalog.
23
+
24
+ ## Which kind
25
+
26
+ | Question the chart answers | Kind |
27
+ |---|---|
28
+ | How do categories compare (posts by status, sales by region)? | `bar` |
29
+ | How did a value change over time (sign-ups per month)? | `line` |
30
+ | What share of a whole does each part take (pages vs posts)? | `pie` |
31
+
32
+ Recharts draws `bar`, `line` and `pie` only. For any other kind (area, scatter, stacked bars), check
33
+ `search_components "chart"` for another provider; if none draws it, the data shows as a table.
34
+
35
+ ## The components and their data
36
+
37
+ **One series, simplest props** (bar and line share one schema):
38
+
39
+ - `recharts.bar-chart`, `recharts.line-chart`:
40
+ `{ data: [rows], categoryKey, valueKey, valueLabel?, color? }`.
41
+ Every row has the category (`categoryKey`) and a number (`valueKey`).
42
+ `valueLabel` is the human name shown in the legend and tooltip ("Sign-ups"). Set it whenever
43
+ the key is not already readable.
44
+ - `recharts.pie-chart`: `{ data: [{ name, value }], color? }`. One row per slice.
45
+
46
+ The catalog may also list `plugin.recharts.bar-chart` and similar ids. They take the same props and
47
+ always ask Recharts by name.
48
+
49
+ **Any kind, one or more series: `chart.spec`**
50
+
51
+ ```json
52
+ { "spec": {
53
+ "kind": "bar",
54
+ "categoryKey": "month",
55
+ "series": [{ "key": "signups", "label": "Sign-ups" }],
56
+ "data": [{ "month": "Jan", "signups": 12 }, { "month": "Feb", "signups": 19 }],
57
+ "title": "Sign-ups by month"
58
+ } }
59
+ ```
60
+
61
+ - Every row carries the category and a number (or `null` for a gap) for every series key.
62
+ - Series keys are unique. There is at least one row and one series.
63
+ - For a pie, `categoryKey` names the slices and the single series holds the values.
64
+ - `spec.provider: "plugin.recharts"` asks for Recharts when several providers are enabled.
65
+ - `chart.spec` is always in the catalog. With no provider enabled, it shows the data as a table.
66
+
67
+ ## What Recharts draws, and what falls back
68
+
69
+ Recharts draws a spec only when all of these hold:
70
+
71
+ - the kind is `bar`, `line` or `pie`;
72
+ - there is exactly **one** series and a `categoryKey`;
73
+ - every value is a finite number (no `null` gaps);
74
+ - the spec sets no `axes` or `format`.
75
+
76
+ Anything else goes to another enabled provider that accepts it, or shows as a table. Nothing is
77
+ lost, but tell the user when you know the result will be a table (for example two series with only
78
+ Recharts enabled). Offer one chart per series instead.
79
+
80
+ ## Making it read well
81
+
82
+ - Aggregate first. Send the counts or totals to plot, not raw records.
83
+ - Bars: about 12 categories or fewer. Sort by value unless the order means something (months,
84
+ stages). Long labels wrap onto up to three lines; in narrow spaces some labels are skipped, and
85
+ the full label stays in the tooltip.
86
+ - Lines: time in order, oldest first. Long series are fine; the axis thins its own labels.
87
+ - Pies: 6 slices or fewer, values that add up to a meaningful whole. Merge the small ones into
88
+ "Other". Use a bar chart when the user needs to compare similar values.
89
+ - Whole-number data (counts) gets whole-number axis ticks automatically. Do not round other data
90
+ to force it.
91
+ - Leave `color` out unless the user asks. The host theme colours the chart.
92
+ - Give a short title that states what is shown ("Posts by status"), and a description when the
93
+ chart makes a point the title doesn't.
94
+ - Keep labels short and human: "Published", not `post_status_published`.
95
+
96
+ ## Never
97
+
98
+ - Never paste Recharts, React, SVG or HTML chart code into the chat, a page or a file to draw a
99
+ chart. The provider owns the drawing; your job is the data and the component choice.
100
+ - Never invent data. If you can't get the numbers, say so and ask.
101
+ - Never claim a chart rendered when the host reported a refusal. Read the error, fix the props
102
+ (usually a missing key or a string where a number belongs), and try once more.
103
+
104
+ ## When charts are off
105
+
106
+ If the chart entries `search_components` returns all report provider `core.table`, no chart
107
+ provider is enabled. The data will show as a table; say so, and tell the user an administrator can
108
+ turn the Recharts chart provider on.
@@ -0,0 +1,16 @@
1
+ # Cloudflare — implementation notes
2
+
3
+ Host-specific notes moved out of the host's core comments (2026-10-22, vendor-to-plugins). The host describes these
4
+ behaviours generically; the vendor detail lives here.
5
+
6
+ - **Credentials.** `accountId` is HARD required for Pages publishes; a credential missing it fails with a
7
+ `DeployError` naming the field. The optional Zone ID may be submitted blank, meaning "not provided".
8
+ - **Stored `projectName`.** Accepted and stored although, when written, the Pages target derived its project
9
+ name from the publish call's label, not from stored config.
10
+ - **Account label.** No reviewed account field is read from the verify response; the account-label heal
11
+ skips these credentials.
12
+ - **Security headers.** Root `_headers` is applied only when sent as its own upload field, never as an asset
13
+ (see `lib/pages-upload.mjs`, `skills/cloudflare/references/pages.md`).
14
+ - **Forms receiver hides the sent form.** On 2026-10-19 a theme's `.oh-form form{display:grid}` kept a sent
15
+ form on screen after the Cloudflare Worker's script set `hidden` on it; the host's form CSS now forces
16
+ `[hidden]{display:none!important}`.
@@ -0,0 +1,9 @@
1
+ import { acknowledgeFormSubmissions, pullFormSubmissions } from '../lib/forms.mjs';
2
+
3
+ /** Form destination `cloudflare-d1`, co-hosted on Cloudflare Workers: publishing to Workers installs
4
+ * the receiver and its D1 database in the site's own Worker (`lib/target.mjs`); this module only
5
+ * reads and acknowledges what that receiver stored. */
6
+ export default {
7
+ pull: pullFormSubmissions,
8
+ ack: acknowledgeFormSubmissions,
9
+ };
@@ -0,0 +1,96 @@
1
+ /** Cloudflare-only HTTP owner. All network effects use the injected, traced host transport. */
2
+ export const API_ROOT = 'https://api.cloudflare.com/client/v4';
3
+ export const segment = ({ value }, _options = {}) => encodeURIComponent(value);
4
+ /** Cloudflare rejects `per_page` above 10 on the Pages projects list (error 8000024, HTTP 400). */
5
+ export const PAGES_PROJECTS_PAGING = { perPage: 10, maxPages: 11 };
6
+ /** Cloudflare caps `per_page` at 50 on the zones list (the default 100 is refused). */
7
+ export const ZONES_PAGING = { perPage: 50, maxPages: 20 };
8
+
9
+ /** Safe, stable refusal; upstream bodies can contain credentials and never cross this boundary. */
10
+ export function refusal({ kit, code, message, status = 400 }, _options = {}) {
11
+ const error = new kit.DeployError(`${code}: ${message}`, status, { errorCode: code });
12
+ error.code = code;
13
+ return error;
14
+ }
15
+
16
+ function nextStep({ status }, _options = {}) {
17
+ if (status === 401 || status === 403) return 'Check the token permissions and account/zone scope in the Cloudflare skill, then preview again.';
18
+ if (status === 429) return 'Cloudflare is rate limiting this account. Wait, then preview again.';
19
+ return 'Check the named resource in Cloudflare, then preview again.';
20
+ }
21
+
22
+ /** Bind credential and HTTP once. Requests never follow redirects with a bearer token. */
23
+ export function createApi({ credential, kit }, _options = {}) {
24
+ if (!credential.token || !credential.accountId) throw refusal({ kit, code: 'CLOUDFLARE_CREDENTIAL_REQUIRED', message: 'Save a Cloudflare API token and Account ID in the secure connection form.' });
25
+ const accountPath = `/accounts/${segment({ value: credential.accountId })}`;
26
+ async function response({ path, method = 'GET', body, jwt }, options = {}) {
27
+ const init = requestInit({ method, body, token: jwt ?? credential.token });
28
+ let resp;
29
+ try { resp = await kit.fetch(`${API_ROOT}${path}`, init, { timeoutMs: options.timeoutMs ?? kit.timeouts.QUICK }); }
30
+ catch { throw refusal({ kit, code: 'CLOUDFLARE_UNREACHABLE', message: `${method} ${path} could not reach Cloudflare. Check your connection and retry.`, status: 502 }); }
31
+ if (options.allowMissing && resp.status === 404) return { missing: true };
32
+ return decodeResponse({ resp, method, path, kit });
33
+ }
34
+ async function request(input, options = {}) {
35
+ const json = await response(input, options);
36
+ if (json.missing) return null;
37
+ return json.result ?? json;
38
+ }
39
+ async function list({ path }, { maxPages = 100, perPage = 100 } = {}) {
40
+ const items = [];
41
+ let pagination = { count: 0, pages: 0 };
42
+ for (let page = 1; page <= maxPages; page += 1) {
43
+ const separator = path.includes('?') ? '&' : '?';
44
+ const json = await response({ path: `${path}${separator}page=${page}&per_page=${perPage}` });
45
+ if (!Array.isArray(json.result)) throw refusal({ kit, code: 'CLOUDFLARE_INVENTORY_UNKNOWN', message: `${path} did not return a complete list. Check read permissions and preview again.`, status: 502 });
46
+ items.push(...json.result);
47
+ pagination = paginationState({ previous: pagination, info: json.result_info });
48
+ if (items.length > maxPages * perPage) throw refusal({ kit, code: 'CLOUDFLARE_INVENTORY_UNKNOWN', message: `${path} exceeded the inventory item limit. Narrow the account and preview again.`, status: 409 });
49
+ const more = hasNextPage({ info: json.result_info, page, perPage, count: json.result.length });
50
+ assertCompletePage({ kit, path, pagination, itemCount: items.length, lastCount: json.result.length, more });
51
+ if (!more) return items;
52
+ }
53
+ throw refusal({ kit, code: 'CLOUDFLARE_INVENTORY_UNKNOWN', message: `${path} exceeded the ${maxPages}-page inventory limit. Narrow the account scope or contact support; no domain changes are safe.`, status: 409 });
54
+ }
55
+ return { request, list, accountPath, accountId: credential.accountId, zoneId: credential.zoneId, kit };
56
+ }
57
+
58
+ function paginationState({ previous, info }, _options = {}) {
59
+ return { count: Math.max(previous.count, Number(info?.total_count) || 0), pages: Math.max(previous.pages, Number(info?.total_pages) || 0) };
60
+ }
61
+ function assertCompletePage({ kit, path, pagination, itemCount, lastCount, more }, _options = {}) {
62
+ if ((!more && itemCount < pagination.count) || (lastCount === 0 && pagination.pages > 1)) throw refusal({ kit, code: 'CLOUDFLARE_INVENTORY_UNKNOWN', message: `${path} returned an incomplete inventory page. Refresh read permissions and preview again; no domain changes are safe.`, status: 409 });
63
+ }
64
+
65
+ async function decodeResponse({ resp, method, path, kit }, _options = {}) {
66
+ let json;
67
+ try { json = await resp.json(); }
68
+ catch { throw refusal({ kit, code: 'CLOUDFLARE_INVALID_RESPONSE', message: `${method} ${path} returned unreadable data. Retry; if it persists check Cloudflare status.`, status: 502 }); }
69
+ if (json === null || typeof json !== 'object') throw refusal({ kit, code: 'CLOUDFLARE_INVALID_RESPONSE', message: `${method} ${path} returned no usable response object. Retry the request and check Cloudflare status.`, status: 502 });
70
+ if (!resp.ok || json?.success === false) throw apiFailure({ kit, json, method, path, status: resp.status });
71
+ return json;
72
+ }
73
+
74
+ function apiFailure({ kit, json, method, path, status }, _options = {}) {
75
+ const error = refusal({ kit, code: 'CLOUDFLARE_API_ERROR', message: `${method} ${path} failed (HTTP ${status}). ${nextStep({ status })}`, status });
76
+ // Classify duplicate creation races without returning Cloudflare's potentially secret-bearing text.
77
+ const errors = Array.isArray(json.errors) ? json.errors : [];
78
+ error.details.alreadyExists = errors.some(item => /already exist|already bound|already been taken|already in use|duplicate/i.test(String(item?.message)));
79
+ return error;
80
+ }
81
+
82
+ function requestInit({ method, body, token }, _options = {}) {
83
+ const headers = { Authorization: `Bearer ${token}` };
84
+ const init = { method, headers, redirect: 'error' };
85
+ if (body === undefined) return init;
86
+ if (body instanceof FormData) init.body = body;
87
+ else { headers['Content-Type'] = 'application/json'; init.body = JSON.stringify(body); }
88
+ return init;
89
+ }
90
+
91
+ /** Empty pages before a reported end are incomplete, not evidence of absence. */
92
+ function hasNextPage({ info, page, perPage, count }, _options = {}) {
93
+ if (Number.isFinite(info?.total_pages)) return page < info.total_pages;
94
+ if (Number.isFinite(info?.total_count)) return page * (info.per_page ?? perPage) < info.total_count;
95
+ return count >= perPage;
96
+ }
@@ -0,0 +1,65 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { refusal } from './api.mjs';
3
+
4
+ /** Stable Pages/Workers dedup key; native crypto avoids a native/WASM dependency.
5
+ * Retains Pages' historical data+extension hash so existing uploads stay deduplicated. */
6
+ /**
7
+ * Deterministic content hash used purely as Cloudflare Pages' per-asset
8
+ * dedup key (the direct-upload protocol needs a stable 32-hex-char key per
9
+ * file, not a specific algorithm). Swapped from the OD origin's
10
+ * `blake3-wasm` to Node's built-in `crypto` so this package carries no
11
+ * native/WASM dependency — see `source-map.md`.
12
+ */
13
+ export function assetHash({ file, data }, _options = {}) {
14
+ const extension = file.includes('.') ? file.slice(file.lastIndexOf('.') + 1) : '';
15
+ return createHash('sha256').update(`${Buffer.from(data).toString('base64')}${extension}`).digest('hex').slice(0, 32);
16
+ }
17
+
18
+ /** Root _headers/_redirects are configuration, never public assets. A nested copy remains an asset.
19
+ * Host security headers replace the site's root _headers because they are host policy.
20
+ * @complexity O(n + bytes) time and space; n is capped by the selected hosting plan. */
21
+ export function prepareAssets({ files, responseHeaders, kit }, { maxFiles = 20_000 } = {}) {
22
+ const normalized = files.map(file => ({ ...file, file: file.file.replaceAll('\\', '/').replace(/^\.\//, '') }));
23
+ const headers = responseHeaders && Object.keys(responseHeaders).length > 0;
24
+ const supplied = headers ? [...normalized.filter(file => file.file !== '_headers'), { file: '_headers', data: renderHeaders({ headers: responseHeaders }) }] : normalized;
25
+ if (supplied.length > maxFiles) throw refusal({ kit, code: 'CLOUDFLARE_ASSET_COUNT_LIMIT', message: `${supplied.length} files exceed this destination's ${maxFiles}-file limit (including generated files). Reduce the export or explicitly select a supported paid Workers plan.` });
26
+ const manifest = {};
27
+ const byHash = new Map();
28
+ const config = {};
29
+ for (const file of supplied) addAsset({ file, manifest, byHash, config, kit });
30
+ return { manifest, byHash, config };
31
+ }
32
+
33
+ function addAsset({ file, manifest, byHash, config, kit }, _options = {}) {
34
+ if (!file.file || file.file.startsWith('/') || file.file.split('/').includes('..')) throw refusal({ kit, code: 'CLOUDFLARE_ASSET_PATH', message: `Export path ${file.file} must be relative without '..'. Fix the export and retry.` });
35
+ const data = Buffer.from(file.data);
36
+ if (data.length > 25 * 1024 * 1024) throw refusal({ kit, code: 'CLOUDFLARE_ASSET_SIZE_LIMIT', message: `${file.file} exceeds 25 MiB. Resize the file and export again.` });
37
+ if (file.file === '_headers' || file.file === '_redirects') { config[file.file] = data.toString('utf8'); return; }
38
+ const path = `/${file.file}`;
39
+ if (Object.hasOwn(manifest, path)) throw refusal({ kit, code: 'CLOUDFLARE_ASSET_PATH', message: `Duplicate export path ${path}. Fix the export and retry.` });
40
+ const hash = assetHash({ file: file.file, data });
41
+ manifest[path] = { hash, size: data.length };
42
+ byHash.set(hash, { hash, data, contentType: file.contentType ?? 'application/octet-stream' });
43
+ }
44
+
45
+ export function renderHeaders({ headers }, _options = {}) {
46
+ const lines = Object.entries(headers).map(([name, value]) => ` ${name}: ${value}`).join('\n');
47
+ return `/*\n${lines}\n`;
48
+ }
49
+
50
+ /** Respect both Pages limits. A single oversize request is refused before any upload.
51
+ * @complexity O(n) over unique missing assets; at most 100 per request. */
52
+ export function chunkUploads({ files }, { maxFiles = 100, maxBytes = 75 * 1024 * 1024 } = {}) {
53
+ const chunks = [];
54
+ let chunk = [];
55
+ let bytes = 2; // JSON array brackets.
56
+ for (const file of files) {
57
+ const size = Math.ceil(file.data.length / 3) * 4 + Buffer.byteLength(file.contentType) + file.hash.length + 128;
58
+ if (size + 2 > maxBytes) throw new Error('CLOUDFLARE_UPLOAD_LIMIT: One asset cannot fit in the upload request. Reduce its size.');
59
+ if (chunk.length >= maxFiles || bytes + size > maxBytes) { chunks.push(chunk); chunk = []; bytes = 2; }
60
+ chunk.push(file);
61
+ bytes += size;
62
+ }
63
+ if (chunk.length) chunks.push(chunk);
64
+ return chunks;
65
+ }