@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
@@ -0,0 +1,415 @@
1
+ import { createSign } from "node:crypto";
2
+
3
+ /**
4
+ * @file The first-party `github` deployment provider — GitHub App installation auth over the
5
+ * guarded ADR-038 `HttpClientPort`.
6
+ *
7
+ * Why a GitHub App and not `gh` or a stored PAT (ADS deployments debate, all three rounds, 5/5):
8
+ * a PAT is a long-lived, human-scoped credential with no per-workspace or per-repository boundary
9
+ * in a multi-tenant process; `gh` inherits whatever credential is on the host's global config and
10
+ * bypasses the guarded HTTP client entirely. A GitHub App installation token is narrowable to one
11
+ * repository and one permission (`deployments: write`) at mint time, and expires in exactly one
12
+ * hour regardless of caller-supplied TTL — verified against
13
+ * docs.github.com/en/rest/apps/apps#create-an-installation-access-token-for-an-app. The App JWT
14
+ * used to mint it must be RS256 with `exp` no more than ten minutes past `iat` — verified against
15
+ * docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app.
16
+ *
17
+ * `EgressPolicy` cannot pin a host — see the host deployment port's file header. `sendPinned` below is this
18
+ * file's answer: the ONLY function allowed to call `http.send`, and it refuses anything whose
19
+ * resolved origin is not exactly `https://api.github.com`, so a malformed URL template (or a
20
+ * future workspace-supplied GitHub Enterprise base URL, if that is ever added) fails closed instead
21
+ * of silently reaching an arbitrary host.
22
+ */
23
+
24
+ export const GITHUB_DEPLOYMENT_PROVIDER_ID = "github";
25
+
26
+ const GITHUB_API_ORIGIN = "https://api.github.com";
27
+ const API_VERSION = "2022-11-28";
28
+ const DEFAULT_TIMEOUT_MS = 10_000;
29
+
30
+ /** GitHub App JWTs: `exp` MUST be no more than 10 minutes past `iat` (verified — see file header).
31
+ * 9 minutes leaves margin against clock drift between signing and GitHub's verification. */
32
+ const APP_JWT_TTL_SECONDS = 9 * 60;
33
+ /** GitHub's own guidance is to back-date `iat` by up to 60s to tolerate clock skew between this
34
+ * process and GitHub's clock (verified — see file header). */
35
+ const APP_JWT_CLOCK_SKEW_SECONDS = 60;
36
+
37
+ function fail(
38
+ code,
39
+ message,
40
+ optional = {}
41
+ ) {
42
+ return {
43
+ code,
44
+ message,
45
+ retryable: optional.retryable ?? false,
46
+ ...(optional.providerStatus === undefined ? {} : { providerStatus: optional.providerStatus }),
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Reads and validates `target.config`'s three required GitHub-specific fields.
52
+ *
53
+ * @complexity O(1).
54
+ */
55
+ function readGitHubTargetConfig(target) {
56
+ const { owner, repo, environmentName } = target.config;
57
+ if (typeof owner !== "string" || owner.length === 0) return null;
58
+ if (typeof repo !== "string" || repo.length === 0) return null;
59
+ if (typeof environmentName !== "string" || environmentName.length === 0) return null;
60
+ return { owner, repo, environmentName };
61
+ }
62
+
63
+ /**
64
+ * The origin pin. This is the ONLY call site for `http.send` in this file — every outbound request
65
+ * (minting a token, creating a deployment, polling statuses) is routed through it. See the file
66
+ * header for why this check cannot be delegated to `EgressPolicy`.
67
+ *
68
+ * Exported so this guard can be tested directly (see `../__tests__/deployments-provider.test.mjs`'s "sendPinned
69
+ * refuses..." case) — every current call site builds its URL through `githubApiUrl()`, which
70
+ * already can only resolve under `GITHUB_API_ORIGIN`, so an adapter-level test alone cannot prove
71
+ * this check is load-bearing (confirmed by a mutation check: disabling it did not fail any
72
+ * adapter-level test). This function is the actual safety boundary for a future call site that
73
+ * builds a URL a different way — e.g. a workspace-supplied GitHub Enterprise base URL, if that is
74
+ * ever added — so it must be proven correct on its own.
75
+ *
76
+ * @complexity O(1) beyond the underlying `http.send` call.
77
+ */
78
+ export async function sendPinned(http, request) {
79
+ const url = new URL(request.url);
80
+ if (url.origin !== GITHUB_API_ORIGIN) {
81
+ throw new Error(
82
+ `github deployment adapter refused to send to '${url.origin}' — pinned to ${GITHUB_API_ORIGIN} only`
83
+ );
84
+ }
85
+ return http.send(request);
86
+ }
87
+
88
+ /** Builds a same-origin URL from a path. Every caller-influenced path segment (owner, repo,
89
+ * installation id, provider run ref) MUST already be `encodeURIComponent`-encoded before reaching
90
+ * this function — encoding is what stops a value like `../../app/installations/1` from being
91
+ * interpreted as a literal dot-segment and resolving outside the intended endpoint: RFC 3986
92
+ * dot-segment removal only recognizes literal, unencoded `..` between `/` characters, never a
93
+ * percent-encoded `%2E%2E`. */
94
+ function githubApiUrl(path) {
95
+ return new URL(path, GITHUB_API_ORIGIN).toString();
96
+ }
97
+
98
+ function githubHeaders(token) {
99
+ return {
100
+ accept: "application/vnd.github+json",
101
+ authorization: `Bearer ${token}`,
102
+ "user-agent": "Tovu-CMS",
103
+ "x-github-api-version": API_VERSION,
104
+ };
105
+ }
106
+
107
+ function base64url(input) {
108
+ return Buffer.from(input).toString("base64url");
109
+ }
110
+
111
+ /**
112
+ * Signs a GitHub App JWT locally. The private key never leaves this process.
113
+ *
114
+ * @complexity O(1) (one RSA signature over a short, fixed-shape payload).
115
+ */
116
+ function signGitHubAppJwt(input) {
117
+ const header = base64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
118
+ const payload = base64url(JSON.stringify({ iat: input.issuedAt, exp: input.expiresAt, iss: input.appId }));
119
+ const signature = createSign("RSA-SHA256")
120
+ .update(`${header}.${payload}`)
121
+ .sign(input.privateKeyPem)
122
+ .toString("base64url");
123
+ return `${header}.${payload}.${signature}`;
124
+ }
125
+
126
+ function sanitizeMessage(value) {
127
+ if (typeof value !== "string") return null;
128
+ return value.replace(/[\r\n\0]/g, " ").slice(0, 500);
129
+ }
130
+
131
+ /**
132
+ * Mints a short-lived App JWT, exchanges it for an installation access token narrowed to exactly
133
+ * this installation's `deployments: write` permission. Minted fresh on every call rather than
134
+ * cached: simpler and correct, at the cost of one extra round trip per deploy action — acceptable
135
+ * given deploy actions are infrequent, not a hot path.
136
+ *
137
+ * @complexity One outbound HTTP request, hard-bounded by `DEFAULT_TIMEOUT_MS`.
138
+ */
139
+ async function mintInstallationToken(
140
+ http,
141
+ credentials,
142
+ nowMs
143
+ ) {
144
+ const now = Math.floor(nowMs() / 1000);
145
+ const jwt = signGitHubAppJwt({
146
+ appId: credentials.appId,
147
+ privateKeyPem: credentials.privateKeyPem,
148
+ issuedAt: now - APP_JWT_CLOCK_SKEW_SECONDS,
149
+ expiresAt: now + APP_JWT_TTL_SECONDS,
150
+ });
151
+
152
+ let response;
153
+ try {
154
+ response = await sendPinned(http, {
155
+ method: "POST",
156
+ url: githubApiUrl(`/app/installations/${encodeURIComponent(credentials.installationId)}/access_tokens`),
157
+ headers: { ...githubHeaders(jwt), "content-type": "application/json" },
158
+ body: JSON.stringify({ permissions: { deployments: "write" } }),
159
+ timeoutMs: DEFAULT_TIMEOUT_MS,
160
+ });
161
+ } catch (err) {
162
+ return { ok: false, error: fail("TRANSPORT_ERROR", err instanceof Error ? err.message : String(err), { retryable: true }) };
163
+ }
164
+
165
+ if (response.status >= 400) {
166
+ return {
167
+ ok: false,
168
+ error: fail("PROVIDER_ERROR", `GitHub installation token exchange failed: ${response.status}`, {
169
+ providerStatus: response.status,
170
+ retryable: response.status >= 500,
171
+ }),
172
+ };
173
+ }
174
+
175
+ let body;
176
+ try {
177
+ body = JSON.parse(response.bodyText);
178
+ } catch {
179
+ return { ok: false, error: fail("PROVIDER_RESPONSE_INVALID", "GitHub returned invalid JSON minting an installation token") };
180
+ }
181
+ // Token formats are opaque; do not assume a fixed prefix or length.
182
+ if (typeof body.token !== "string" || body.token.length === 0) {
183
+ return { ok: false, error: fail("PROVIDER_RESPONSE_INVALID", "GitHub returned an empty installation token") };
184
+ }
185
+ return { ok: true, token: body.token };
186
+ }
187
+
188
+ function requireCredentials(
189
+ credentials
190
+ ) {
191
+ const { appId, installationId, privateKeyPem } = credentials;
192
+ if (!appId || !installationId || !privateKeyPem) return null;
193
+ return { appId, installationId, privateKeyPem };
194
+ }
195
+
196
+ /**
197
+ * Sends the `POST .../deployments` call and validates its response — split out of `startRun` so
198
+ * the pre-checks (target config, release shape, credentials) and the HTTP round-trip each carry
199
+ * only their own branches. `release` is the two fields already narrowed out of
200
+ * `input.release` by `startRun`'s own `kind !== "git-revision"` guard.
201
+ */
202
+ async function createGitHubDeployment(
203
+ ctx,
204
+ token,
205
+ config,
206
+ release
207
+ ) {
208
+ let response;
209
+ try {
210
+ response = await sendPinned(ctx.httpClient, {
211
+ method: "POST",
212
+ url: githubApiUrl(`/repos/${encodeURIComponent(config.owner)}/${encodeURIComponent(config.repo)}/deployments`),
213
+ headers: { ...githubHeaders(token), "content-type": "application/json" },
214
+ body: JSON.stringify({
215
+ ref: release.commitSha,
216
+ environment: config.environmentName,
217
+ description: `Tovu deployment of release ${release.releaseId}`,
218
+ auto_merge: false,
219
+ required_contexts: [],
220
+ transient_environment: false,
221
+ production_environment: config.environmentName === "production",
222
+ }),
223
+ timeoutMs: DEFAULT_TIMEOUT_MS,
224
+ });
225
+ } catch (err) {
226
+ return { ok: false, error: fail("TRANSPORT_ERROR", err instanceof Error ? err.message : String(err), { retryable: true }) };
227
+ }
228
+
229
+ if (response.status >= 400) {
230
+ return {
231
+ ok: false,
232
+ error: fail("PROVIDER_ERROR", `GitHub deployment create failed: ${response.status}`, {
233
+ providerStatus: response.status,
234
+ retryable: response.status >= 500,
235
+ }),
236
+ };
237
+ }
238
+
239
+ let body;
240
+ try {
241
+ body = JSON.parse(response.bodyText);
242
+ } catch {
243
+ return { ok: false, error: fail("PROVIDER_RESPONSE_INVALID", "GitHub returned invalid JSON creating a deployment") };
244
+ }
245
+ if (!Number.isSafeInteger(body.id) || (body.id) <= 0) {
246
+ return { ok: false, error: fail("PROVIDER_RESPONSE_INVALID", "GitHub returned an invalid deployment id") };
247
+ }
248
+
249
+ return { ok: true, providerRunRef: String(body.id), reconciliation: "callback" };
250
+ }
251
+
252
+ /**
253
+ * Creates a GitHub Deployment for an existing commit. Does NOT wait for (or fabricate) evidence
254
+ * that a build or deploy has started — GitHub's own docs state it does not access or deploy to the
255
+ * target servers itself; creating a deployment only dispatches a `deployment` event to whatever is
256
+ * listening.
257
+ *
258
+ * @complexity Two outbound HTTP requests (mint token, create deployment), each hard-bounded by
259
+ * `DEFAULT_TIMEOUT_MS`.
260
+ */
261
+ async function startRun(input, ctx) {
262
+ const config = readGitHubTargetConfig(input.target);
263
+ if (!config) {
264
+ return { ok: false, error: fail("INVALID_TARGET_CONFIG", "github target is missing owner/repo/environmentName") };
265
+ }
266
+ if (input.release.source.kind !== "git-revision") {
267
+ // The honesty constraint, enforced at the one place it can be: this adapter promotes an
268
+ // EXISTING commit. It cannot manufacture one from an "external-artifact" release — the host's CLI
269
+ // has no build or export command.
270
+ return {
271
+ ok: false,
272
+ error: fail("INVALID_RELEASE", "github deployment target requires a git-revision release (commit sha), not an external artifact"),
273
+ };
274
+ }
275
+ const credentials = requireCredentials(ctx.credentials);
276
+ if (!credentials) {
277
+ return { ok: false, error: fail("NO_CREDENTIALS_CONFIGURED", "github deployment target is missing appId/installationId/privateKeyPem") };
278
+ }
279
+
280
+ const token = await mintInstallationToken(ctx.httpClient, credentials, ctx.now);
281
+ if (!token.ok) return { ok: false, error: token.error };
282
+
283
+ return createGitHubDeployment(ctx, token.token, config, {
284
+ commitSha: input.release.source.commitSha,
285
+ releaseId: input.release.id,
286
+ });
287
+ }
288
+
289
+ /**
290
+ * GitHub's real deployment-status `state` enum has SEVEN values — `error`, `failure`, `inactive`,
291
+ * `in_progress`, `queued`, `pending`, `success` — verified against
292
+ * docs.github.com/en/rest/deployments/statuses. Every value is handled explicitly here; an
293
+ * unrecognized future value falls to `"running"` (never a terminal state), so it can never be
294
+ * mistaken for success or a permanent failure.
295
+ *
296
+ * GitHub never fires a `deployment_status` WEBHOOK for `inactive` (verified against
297
+ * docs.github.com/en/webhooks/webhook-events-and-payloads#deployment_status) — so this mapping is
298
+ * the only place `inactive` is ever observed, and only via `pollRun`, never a callback.
299
+ *
300
+ * @complexity O(1).
301
+ */
302
+ export function mapGitHubDeploymentStatus(status) {
303
+ const providerStatusId = String(status.id);
304
+ const message = sanitizeMessage(status.description);
305
+ switch (status.state) {
306
+ case "success":
307
+ return { status: "succeeded", providerStatusId, message };
308
+ case "failure":
309
+ case "error":
310
+ return { status: "failed", providerStatusId, message };
311
+ case "inactive":
312
+ return { status: "cancelled", providerStatusId, message };
313
+ case "in_progress":
314
+ return { status: "running", providerStatusId, message };
315
+ case "queued":
316
+ case "pending":
317
+ return { status: "queued", providerStatusId, message };
318
+ default:
319
+ return { status: "running", providerStatusId, message };
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Sends the `GET .../statuses` call and resolves the latest status from it — split out of
325
+ * `pollRun` for the same "pre-checks vs. HTTP round-trip" reason as `createGitHubDeployment`. Does
326
+ * NOT assume the response is newest-first — GitHub's docs describe pagination for this endpoint but
327
+ * state no response order (verified against docs.github.com/en/rest/deployments/statuses). Status
328
+ * ids are assigned monotonically, so the correct status is the one with the greatest `id`,
329
+ * independent of array position.
330
+ */
331
+ async function pollGitHubDeploymentStatuses(
332
+ ctx,
333
+ token,
334
+ config,
335
+ providerRunRef
336
+ ) {
337
+ let response;
338
+ try {
339
+ response = await sendPinned(ctx.httpClient, {
340
+ method: "GET",
341
+ url: githubApiUrl(
342
+ `/repos/${encodeURIComponent(config.owner)}/${encodeURIComponent(config.repo)}/deployments/` +
343
+ `${encodeURIComponent(providerRunRef)}/statuses?per_page=100`
344
+ ),
345
+ headers: githubHeaders(token),
346
+ timeoutMs: DEFAULT_TIMEOUT_MS,
347
+ });
348
+ } catch (err) {
349
+ return { ok: false, error: fail("TRANSPORT_ERROR", err instanceof Error ? err.message : String(err), { retryable: true }) };
350
+ }
351
+
352
+ if (response.status >= 400) {
353
+ return {
354
+ ok: false,
355
+ error: fail("PROVIDER_ERROR", `GitHub deployment status poll failed: ${response.status}`, {
356
+ providerStatus: response.status,
357
+ retryable: response.status >= 500,
358
+ }),
359
+ };
360
+ }
361
+
362
+ let statuses;
363
+ try {
364
+ const parsed = JSON.parse(response.bodyText);
365
+ if (!Array.isArray(parsed)) throw new Error("not an array");
366
+ statuses = parsed;
367
+ } catch {
368
+ return { ok: false, error: fail("PROVIDER_RESPONSE_INVALID", "GitHub returned a malformed statuses response") };
369
+ }
370
+
371
+ if (statuses.length === 0) {
372
+ return { ok: true, update: { status: "queued", providerStatusId: null, message: null } };
373
+ }
374
+
375
+ const latest = statuses.reduce((best, candidate) => (candidate.id > best.id ? candidate : best));
376
+ return { ok: true, update: mapGitHubDeploymentStatus(latest) };
377
+ }
378
+
379
+ /**
380
+ * Polls the latest deployment status.
381
+ *
382
+ * @complexity One outbound HTTP request (plus the token mint) and a single linear scan over the
383
+ * returned statuses (bounded by `per_page=100`), each hard-bounded by `DEFAULT_TIMEOUT_MS`.
384
+ */
385
+ async function pollRun(input, ctx) {
386
+ const config = readGitHubTargetConfig(input.target);
387
+ if (!config) {
388
+ return { ok: false, error: fail("INVALID_TARGET_CONFIG", "github target is missing owner/repo/environmentName") };
389
+ }
390
+ if (!/^[1-9]\d*$/.test(input.providerRunRef)) {
391
+ return { ok: false, error: fail("INVALID_TARGET_CONFIG", "providerRunRef is not a github deployment id") };
392
+ }
393
+ const credentials = requireCredentials(ctx.credentials);
394
+ if (!credentials) {
395
+ return { ok: false, error: fail("NO_CREDENTIALS_CONFIGURED", "github deployment target is missing appId/installationId/privateKeyPem") };
396
+ }
397
+
398
+ const token = await mintInstallationToken(ctx.httpClient, credentials, ctx.now);
399
+ if (!token.ok) return { ok: false, error: token.error };
400
+
401
+ return pollGitHubDeploymentStatuses(ctx, token.token, config, input.providerRunRef);
402
+ }
403
+
404
+ /**
405
+ * Builds the `github` deployment provider adapter. Stateless — safe to construct once and reuse
406
+ * across requests; all per-call state lives in the `ctx` passed to each method.
407
+ */
408
+ export function createGitHubDeploymentProvider() {
409
+ return {
410
+ id: GITHUB_DEPLOYMENT_PROVIDER_ID,
411
+ credentialKeys: ["appId", "installationId", "privateKeyPem"],
412
+ startRun,
413
+ pollRun,
414
+ };
415
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json",
3
+ "mcpServers": {}
4
+ }
@@ -0,0 +1,105 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "github",
4
+ "version": "1.1.0",
5
+ "description": "Everything a host's assistant needs to work against a GitHub repository through the workspace's own saved credentials, with no git, no gh CLI, and no token ever passing through the assistant: writing and updating files in one atomic commit, dispatching and following a GitHub Actions run, reading a failed run's logs, committing the site's rendered static export, backing up the site itself (database, media, themes, plugins, settings) to a private repository, and deploying the host's server through its GitHub Actions deploy workflow (the `github-actions` deployment ops platform). Encodes the rules that generic GitHub knowledge gets wrong here — a 204 dispatch means queued and never deployed, a workflow only fires on the branch its own trigger names, a repository secret is the human's step and never the assistant's, a 403 on an org-wide listing is a normal app-scoped-token boundary rather than a broken credential, and editing an existing file means diffing the MODIFIED files and not only the added and deleted ones.",
6
+ "author": "Tovu",
7
+ "license": "Apache-2.0",
8
+ "extensions": {
9
+ "tovu": {
10
+ "vendorAliases": ["github_pat_"],
11
+ "displayName": "GitHub",
12
+ "summary": "Lets the assistant save your site's files to GitHub, run builds there, and back up your whole site.",
13
+ "id": "tovu/github",
14
+ "provides": [
15
+ "source-control",
16
+ "site-backup",
17
+ "deploy-ops:github-actions"
18
+ ],
19
+ "credentialCards": [
20
+ {
21
+ "target": "github",
22
+ "title": "Connect GitHub",
23
+ "label": "github",
24
+ "category": "source-control",
25
+ "intro": "Connect GitHub for repository files, Actions and site backups.",
26
+ "usedFor": [
27
+ "Reads and updates repository files",
28
+ "Starts workflows and checks their results and logs",
29
+ "Backs up your site to a private repository"
30
+ ],
31
+ "keyHint": "Select only the repositories you need. Contents → Read and write for commits; Workflows → Read and write for workflow files; Actions → Read for runs or Read and write for dispatch. Reading secret names needs Secrets → Read. Never grant secret-writing access for this flow.",
32
+ "saveKind": "api",
33
+ "helpUrl": "https://github.com/settings/personal-access-tokens/new",
34
+ "helpLabel": "Create a fine-grained token",
35
+ "baseUrl": "https://api.github.com",
36
+ "probeUrl": "https://api.github.com/user"
37
+ },
38
+ {
39
+ "target": "github-source-control",
40
+ "title": "Connect GitHub for source control",
41
+ "label": "default",
42
+ "category": "source-control",
43
+ "intro": "Connect GitHub to commit this site’s rendered static export to a repository.",
44
+ "usedFor": [
45
+ "Commits your site's exported website files to a repository"
46
+ ],
47
+ "keyHint": "Select only the destination repository, with Contents → Read and write. A classic token with repo scope also works but has broader access.",
48
+ "saveKind": "source-control",
49
+ "saveTarget": "github",
50
+ "helpUrl": "https://github.com/settings/personal-access-tokens/new",
51
+ "helpLabel": "Create a fine-grained token",
52
+ "baseUrl": "https://api.github.com"
53
+ }
54
+ ],
55
+ "toolKeywords": {
56
+ "credential_save": "github",
57
+ "deployment_ops_deploy": "github",
58
+ "deployment_ops_logs": "github",
59
+ "deployment_ops_status": "github",
60
+ "site_backup_plan": "github",
61
+ "site_backup_push": "github",
62
+ "skills_install": "github",
63
+ "source_control_execute_commit": "github",
64
+ "source_control_get_capabilities": "github"
65
+ }
66
+ }
67
+ },
68
+ "keywords": [
69
+ "github",
70
+ "git",
71
+ "repo",
72
+ "repository",
73
+ "commit",
74
+ "push",
75
+ "branch",
76
+ "pull-request",
77
+ "source-control",
78
+ "version-control",
79
+ "github-actions",
80
+ "actions",
81
+ "workflow",
82
+ "workflow-dispatch",
83
+ "ci",
84
+ "cd",
85
+ "pipeline",
86
+ "run",
87
+ "job",
88
+ "logs",
89
+ "secrets",
90
+ "repository-secret",
91
+ "token",
92
+ "pat",
93
+ "scopes",
94
+ "permissions",
95
+ "api",
96
+ "rest",
97
+ "git-data-api",
98
+ "blob",
99
+ "tree",
100
+ "ref",
101
+ "backup",
102
+ "site-backup",
103
+ "deploy-ops:github-actions"
104
+ ]
105
+ }