@jini-ai/agent-plugins 0.6.16 → 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.
- package/CHANGELOG.md +35 -1
- package/NOTICE +14 -0
- package/README.md +35 -14
- package/charts-echarts/plugin.json +39 -0
- package/charts-echarts/skills/charts-echarts/SKILL.md +110 -0
- package/charts-recharts/plugin.json +32 -0
- package/charts-recharts/skills/charts-recharts/SKILL.md +108 -0
- package/cloudflare/NOTES.md +16 -0
- package/cloudflare/form-destinations/cloudflare-d1.mjs +9 -0
- package/cloudflare/lib/api.mjs +96 -0
- package/cloudflare/lib/assets.mjs +65 -0
- package/cloudflare/lib/dns.mjs +32 -0
- package/cloudflare/lib/domain-inventory.mjs +61 -0
- package/cloudflare/lib/domain-status.mjs +48 -0
- package/cloudflare/lib/domains.mjs +95 -0
- package/cloudflare/lib/forms.mjs +254 -0
- package/cloudflare/lib/pages-upload.mjs +51 -0
- package/cloudflare/lib/target.mjs +165 -0
- package/cloudflare/lib/workers-upload.mjs +48 -0
- package/cloudflare/lib/zones.mjs +25 -0
- package/cloudflare/mcp.json +4 -0
- package/cloudflare/plugin.json +96 -0
- package/cloudflare/skills/cloudflare/SKILL.md +57 -0
- package/cloudflare/skills/cloudflare/references/domains.md +31 -0
- package/cloudflare/skills/cloudflare/references/pages.md +18 -0
- package/cloudflare/skills/cloudflare/references/permissions.md +29 -0
- package/cloudflare/skills/cloudflare/references/troubleshooting.md +20 -0
- package/cloudflare/skills/cloudflare/references/workers.md +42 -0
- package/cloudflare/targets/cloudflare-pages.mjs +12 -0
- package/cloudflare/targets/cloudflare-workers.mjs +17 -0
- package/cloudflare/tovu-consent.json +6 -0
- package/cloudflare/tovu-deploy-targets.json +630 -0
- package/cloudflare/tovu-form-destinations.json +12 -0
- package/cloudflare/worker/forms-receiver.mjs +249 -0
- package/composio/mcp.json +10 -0
- package/composio/plugin.json +68 -0
- package/composio/skills/composio/SKILL.md +85 -0
- package/dist/core/identity-namespace.d.ts +12 -0
- package/dist/core/identity-namespace.js +20 -0
- package/dist/folder-zip-node.js +29 -7
- package/dist/lifecycle/bundled-digests.js +4 -3
- package/dist/lifecycle/install.d.ts +7 -0
- package/dist/lifecycle/install.js +45 -3
- package/dist/lifecycle/manifest.d.ts +2 -2
- package/dist/lifecycle/manifest.js +5 -3
- package/dist/lifecycle/node.js +2 -0
- package/dist/lifecycle/persistent-state.js +1 -1
- package/dist/lifecycle/ports.d.ts +8 -0
- package/dist/lifecycle/seed-bundled.js +4 -1
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +3 -2
- package/fly/deploy-configs/fly.mjs +115 -0
- package/fly/deploy-ops/fly.mjs +102 -0
- package/fly/mcp.json +4 -0
- package/fly/plugin.json +81 -0
- package/fly/scripts/render-deploy-workflow.mjs +150 -0
- package/fly/skills/fly/SKILL.md +43 -0
- package/fly/skills/fly/references/fly-deploy.template.yml +117 -0
- package/fly/skills/fly/references/fly.template.toml +81 -0
- package/fly/tovu-credential-schemes.json +11 -0
- package/fly/tovu-deploy-configs.json +21 -0
- package/fly/tovu-deploy-ops.json +14 -0
- package/github/deploy-ops/github-actions.mjs +164 -0
- package/github/deployments/github.mjs +415 -0
- package/github/mcp.json +4 -0
- package/github/plugin.json +105 -0
- package/github/skills/github/SKILL.md +249 -0
- package/github/skills/github/references/actions.md +224 -0
- package/github/skills/github/references/auth-and-tokens.md +140 -0
- package/github/skills/github/references/repo-files.md +135 -0
- package/github/skills/github/references/site-backup.md +159 -0
- package/github/skills/github/references/source-control.md +123 -0
- package/github/source-control/backup-push.mjs +242 -0
- package/github/source-control/commit-site.mjs +459 -0
- package/github/source-control/github.mjs +93 -0
- package/github/source-control/write-files.mjs +468 -0
- package/github/tovu-deploy-ops.json +13 -0
- package/github/tovu-source-control.json +117 -0
- package/github-pages/NOTES.md +19 -0
- package/github-pages/mcp.json +4 -0
- package/github-pages/plugin.json +48 -0
- package/github-pages/skills/github-pages/SKILL.md +44 -0
- package/github-pages/targets/github-pages.mjs +543 -0
- package/github-pages/tovu-deploy-targets.json +327 -0
- package/google-login/exports/google-g.svg +1 -0
- package/google-login/exports/sign-in-button.css +68 -0
- package/google-login/exports/sign-in-button.html +4 -0
- package/google-login/mcp.json +4 -0
- package/google-login/plugin.json +59 -0
- package/google-login/skills/google-login/SKILL.md +96 -0
- package/google-login/tovu-login-providers.json +21 -0
- package/google-workspace/README.md +132 -0
- package/google-workspace/form-destinations/README.md +87 -0
- package/google-workspace/form-destinations/dedupe.mjs +43 -0
- package/google-workspace/form-destinations/delivery-result.mjs +69 -0
- package/google-workspace/form-destinations/mapping.mjs +152 -0
- package/google-workspace/form-destinations/sheets.mjs +202 -0
- package/google-workspace/lib/auth.mjs +81 -0
- package/google-workspace/lib/drive-files.mjs +54 -0
- package/google-workspace/lib/form-destination-settings.mjs +72 -0
- package/google-workspace/lib/http.mjs +168 -0
- package/google-workspace/lib/picker-flow.mjs +171 -0
- package/google-workspace/lib/picker-selection.mjs +107 -0
- package/google-workspace/lib/product-state.mjs +93 -0
- package/google-workspace/lib/request-policy.mjs +163 -0
- package/google-workspace/lib/sheets-a1.mjs +79 -0
- package/google-workspace/lib/sheets-admin-csv.mjs +82 -0
- package/google-workspace/lib/sheets-admin-request-kinds.mjs +183 -0
- package/google-workspace/lib/sheets-client.mjs +286 -0
- package/google-workspace/lib/surface-actions.mjs +107 -0
- package/google-workspace/mcp.json +4 -0
- package/google-workspace/plugin.json +77 -0
- package/google-workspace/products.json +12 -0
- package/google-workspace/skills/google-workspace/SKILL.md +82 -0
- package/google-workspace/skills/google-workspace/references/connection.md +102 -0
- package/google-workspace/skills/google-workspace/references/form-delivery.md +50 -0
- package/google-workspace/skills/google-workspace/references/sheets.md +149 -0
- package/google-workspace/skills/google-workspace/references/troubleshooting.md +31 -0
- package/google-workspace/tools/account-info.mjs +18 -0
- package/google-workspace/tools/sheets/README.md +54 -0
- package/google-workspace/tools/sheets/copy-tab.mjs +23 -0
- package/google-workspace/tools/sheets/copy.mjs +23 -0
- package/google-workspace/tools/sheets/create.mjs +35 -0
- package/google-workspace/tools/sheets/find-replace.mjs +38 -0
- package/google-workspace/tools/sheets/find.mjs +52 -0
- package/google-workspace/tools/sheets/get-by-data-filter.mjs +23 -0
- package/google-workspace/tools/sheets/get.mjs +22 -0
- package/google-workspace/tools/sheets/values-append.mjs +27 -0
- package/google-workspace/tools/sheets/values-batch-clear.mjs +20 -0
- package/google-workspace/tools/sheets/values-batch-get.mjs +20 -0
- package/google-workspace/tools/sheets/values-batch-update.mjs +29 -0
- package/google-workspace/tools/sheets/values-by-data-filter.mjs +62 -0
- package/google-workspace/tools/sheets/values-clear.mjs +20 -0
- package/google-workspace/tools/sheets/values-get.mjs +21 -0
- package/google-workspace/tools/sheets/values-update.mjs +26 -0
- package/google-workspace/tools/sheets-admin/README.md +45 -0
- package/google-workspace/tools/sheets-admin/basic-filter.mjs +32 -0
- package/google-workspace/tools/sheets-admin/batch-update.mjs +25 -0
- package/google-workspace/tools/sheets-admin/developer-metadata.mjs +28 -0
- package/google-workspace/tools/sheets-admin/export-csv.mjs +67 -0
- package/google-workspace/tools/sheets-admin/filter-views.mjs +38 -0
- package/google-workspace/tools/sheets-admin/format.mjs +70 -0
- package/google-workspace/tools/sheets-admin/named-ranges.mjs +42 -0
- package/google-workspace/tools/sheets-admin/open-existing.mjs +34 -0
- package/google-workspace/tools/sheets-admin/protected-ranges-get.mjs +18 -0
- package/google-workspace/tools/sheets-admin/sort.mjs +18 -0
- package/google-workspace/tools/sheets-admin/tab-modify.mjs +36 -0
- package/google-workspace/tovu-admin-surfaces.json +63 -0
- package/google-workspace/tovu-agent-tools.json +1178 -0
- package/google-workspace/tovu-connections.json +35 -0
- package/google-workspace/tovu-form-destinations.json +10 -0
- package/google-workspace/ui/README.md +73 -0
- package/google-workspace/ui/connection-panel.handler.mjs +167 -0
- package/google-workspace/ui/connection-panel.html +17 -0
- package/google-workspace/ui/connection-panel.mjs +189 -0
- package/google-workspace/ui/connection-view.mjs +120 -0
- package/google-workspace/ui/destination-panel.handler.mjs +106 -0
- package/google-workspace/ui/destination-panel.html +17 -0
- package/google-workspace/ui/destination-panel.mjs +150 -0
- package/google-workspace/ui/dom.mjs +140 -0
- package/google-workspace/ui/panel.css +170 -0
- package/google-workspace/ui/picker-flow.mjs +87 -0
- package/google-workspace/ui/picker-view.mjs +44 -0
- package/google-workspace/ui/picker.handler.mjs +56 -0
- package/google-workspace/ui/picker.html +17 -0
- package/google-workspace/ui/picker.mjs +88 -0
- package/google-workspace/ui/surface-client.mjs +227 -0
- package/higgsfield-media/mcp.json +9 -0
- package/higgsfield-media/plugin.json +109 -0
- package/higgsfield-media/skills/higgsfield-media/SKILL.md +325 -0
- package/higgsfield-media/skills/higgsfield-media/references/failure-modes.md +116 -0
- package/higgsfield-media/skills/higgsfield-media/references/models-and-plan-gates.md +142 -0
- package/jev/mcp.json +4 -0
- package/jev/plugin.json +44 -0
- package/jev/skills/jev/SKILL.md +308 -0
- package/jev/skills/jev/references/cookbooks.md +197 -0
- package/jev/skills/jev/references/jaggedness.md +135 -0
- package/jev/skills/jev/references/javascript-sdk.md +146 -0
- package/jev/skills/jev/references/patterns.md +123 -0
- package/jev/skills/jev/references/primitives-reference.md +187 -0
- package/langfuse/plugin.json +22 -0
- package/meilisearch/mcp.json +4 -0
- package/meilisearch/plugin.json +54 -0
- package/meilisearch/providers/meilisearch.mjs +651 -0
- package/meilisearch/skills/meilisearch/SKILL.md +43 -0
- package/meilisearch/tovu-search-providers.json +10 -0
- package/netlify/NOTES.md +13 -0
- package/netlify/mcp.json +4 -0
- package/netlify/plugin.json +47 -0
- package/netlify/skills/netlify/SKILL.md +39 -0
- package/netlify/targets/netlify.mjs +384 -0
- package/netlify/tovu-consent.json +6 -0
- package/netlify/tovu-deploy-targets.json +163 -0
- package/opentelemetry/mcp.json +4 -0
- package/opentelemetry/plugin.json +52 -0
- package/opentelemetry/skills/opentelemetry/SKILL.md +39 -0
- package/package.json +161 -6
- package/posthog/mcp.json +4 -0
- package/posthog/plugin.json +46 -0
- package/posthog/skills/posthog/SKILL.md +36 -0
- package/railway/deploy-configs/railway.mjs +135 -0
- package/railway/deploy-ops/railway.mjs +167 -0
- package/railway/mcp.json +4 -0
- package/railway/plugin.json +45 -0
- package/railway/skills/railway/SKILL.md +66 -0
- package/railway/tovu-deploy-configs.json +16 -0
- package/railway/tovu-deploy-ops.json +11 -0
- package/render/deploy-configs/render.mjs +141 -0
- package/render/deploy-ops/render.mjs +152 -0
- package/render/mcp.json +4 -0
- package/render/plugin.json +47 -0
- package/render/skills/render/SKILL.md +63 -0
- package/render/tovu-deploy-configs.json +16 -0
- package/render/tovu-deploy-ops.json +11 -0
- package/resend/NOTES.md +52 -0
- package/resend/adapters/resend.mjs +161 -0
- package/resend/lib/domains.mjs +137 -0
- package/resend/lib/errors.mjs +25 -0
- package/resend/lib/feedback.mjs +118 -0
- package/resend/mcp.json +13 -0
- package/resend/plugin.json +192 -0
- package/resend/skills/resend/SKILL.md +107 -0
- package/resend/tovu-mail-adapters.json +22 -0
- package/s3-compatible/NOTES.md +11 -0
- package/s3-compatible/mcp.json +4 -0
- package/s3-compatible/object-stores/s3-compatible.mjs +287 -0
- package/s3-compatible/plugin.json +56 -0
- package/s3-compatible/skills/s3-compatible/SKILL.md +39 -0
- package/s3-compatible/targets/s3-compatible.mjs +1054 -0
- package/s3-compatible/tovu-deploy-targets.json +432 -0
- package/s3-compatible/tovu-object-stores.json +29 -0
- package/sentry/mcp.json +4 -0
- package/sentry/plugin.json +49 -0
- package/sentry/skills/sentry/SKILL.md +34 -0
- package/shopify/mcp.json +4 -0
- package/shopify/plugin.json +22 -0
- package/shopify/skills/shopify/SKILL.md +103 -0
- package/shopify/skills/shopify/references/catalog-sync.md +74 -0
- package/shopify/skills/shopify/references/domains.md +26 -0
- package/shopify/skills/shopify/references/live-storefront.md +34 -0
- package/shopify/skills/shopify/references/storefront-snippets.md +21 -0
- package/site-compliance/mcp.json +4 -0
- package/site-compliance/plugin.json +34 -0
- package/site-compliance/skills/site-compliance/SKILL.md +220 -0
- package/site-compliance/skills/site-compliance/references/ccpa-cpra.md +115 -0
- package/site-compliance/skills/site-compliance/references/gdpr-eu-uk.md +143 -0
- package/site-compliance/skills/site-compliance/references/wcag-2-2.md +129 -0
- package/site-import/mcp.json +4 -0
- package/site-import/plugin.json +41 -0
- package/site-import/skills/site-import/SKILL.md +232 -0
- package/site-import/skills/site-import/references/content-mapping.md +166 -0
- package/site-import/skills/site-import/references/discovery-and-classification.md +117 -0
- package/site-import/skills/site-import/references/theme-extraction.md +34 -0
- package/slide-design/com.anthropic.claude-code/hooks/hooks.json +4 -0
- package/slide-design/mcp.json +4 -0
- package/slide-design/plugin.json +26 -0
- package/slide-design/skills/slide-design/SKILL.md +103 -0
- package/slide-design/skills/slide-design/references/charts-and-exhibits.md +100 -0
- package/slide-design/skills/slide-design/references/html-deck.md +175 -0
- package/slide-design/skills/slide-design/references/layout-and-style.md +131 -0
- package/slide-design/skills/slide-design/references/review.md +93 -0
- package/slide-design/skills/slide-design/references/storyline.md +118 -0
- package/stripe/plugin.json +22 -0
- package/supabase/mcp.json +26 -0
- package/supabase/plugin.json +78 -0
- package/supabase/skills/supabase/SKILL.md +169 -0
- package/supabase/skills/supabase/references/failure-modes.md +101 -0
- package/ui-ux-design/CHANGELOG.md +28 -0
- package/ui-ux-design/LICENSE +201 -0
- package/ui-ux-design/NOTICE +14 -0
- package/ui-ux-design/README.md +62 -0
- package/ui-ux-design/com.anthropic.claude-code/hooks/hooks.json +4 -0
- package/ui-ux-design/mcp.json +4 -0
- package/ui-ux-design/plugin.json +26 -0
- package/ui-ux-design/skills/frontend-accessibility/SKILL.md +60 -0
- package/ui-ux-design/skills/gstack-design/SKILL.md +53 -0
- package/ui-ux-design/skills/gstack-design/references/consultation.md +30 -0
- package/ui-ux-design/skills/gstack-design/references/html.md +29 -0
- package/ui-ux-design/skills/gstack-design/references/review.md +28 -0
- package/ui-ux-design/skills/gstack-design/references/shotgun.md +33 -0
- package/ui-ux-design/skills/gstack-design/references/upstream-notes.md +23 -0
- package/ui-ux-design/skills/interface-design/ORIGINAL.md +16 -0
- package/ui-ux-design/skills/interface-design/SKILL.md +41 -0
- package/ui-ux-design/skills/interface-design/references/commands/audit.md +40 -0
- package/ui-ux-design/skills/interface-design/references/commands/critique.md +21 -0
- package/ui-ux-design/skills/interface-design/references/commands/extract.md +34 -0
- package/ui-ux-design/skills/interface-design/references/commands/init.md +31 -0
- package/ui-ux-design/skills/interface-design/references/commands/status.md +22 -0
- package/ui-ux-design/skills/interface-design/references/examples/system-precision.md +29 -0
- package/ui-ux-design/skills/interface-design/references/examples/system-warmth.md +29 -0
- package/ui-ux-design/skills/interface-design/references/system-template.md +57 -0
- package/ui-ux-design/skills/shadcn-ui/README.md +244 -0
- package/ui-ux-design/skills/shadcn-ui/SKILL.md +333 -0
- package/ui-ux-design/skills/shadcn-ui/examples/auth-layout.tsx +177 -0
- package/ui-ux-design/skills/shadcn-ui/examples/data-table.tsx +313 -0
- package/ui-ux-design/skills/shadcn-ui/examples/form-pattern.tsx +177 -0
- package/ui-ux-design/skills/shadcn-ui/resources/component-catalog.md +481 -0
- package/ui-ux-design/skills/shadcn-ui/resources/customization-guide.md +516 -0
- package/ui-ux-design/skills/shadcn-ui/resources/migration-guide.md +463 -0
- package/ui-ux-design/skills/shadcn-ui/resources/setup-guide.md +412 -0
- package/ui-ux-design/skills/shadcn-ui/scripts/verify-setup.sh +134 -0
- package/ui-ux-design/skills/ui-ux-design/SKILL.md +171 -0
- package/ui-ux-design/skills/ui-ux-design/references/brand-and-voice.md +78 -0
- package/ui-ux-design/skills/ui-ux-design/references/chrome-mobile-test-matrix.md +137 -0
- package/ui-ux-design/skills/ui-ux-design/references/components-and-states.md +112 -0
- package/ui-ux-design/skills/ui-ux-design/references/delight-and-motion.md +54 -0
- package/ui-ux-design/skills/ui-ux-design/references/foundations.md +145 -0
- package/ui-ux-design/skills/ui-ux-design/references/inclusive-ai-imagery.md +57 -0
- package/ui-ux-design/skills/ui-ux-design/references/kole-jain-uiux-concepts.md +104 -0
- package/ui-ux-design/skills/ui-ux-design/references/kuinetic-reference.md +184 -0
- package/ui-ux-design/skills/ui-ux-design/references/openai-frontend-skill.md +139 -0
- package/ui-ux-design/skills/ui-ux-design/references/premium-ui.md +55 -0
- package/ui-ux-design/skills/ui-ux-design/references/research-and-validation.md +88 -0
- package/ui-ux-design/skills/ui-ux-design/references/sam-crawford-premium-websites.md +103 -0
- package/ui-ux-design/skills/ui-ux-design/references/self-made-web-designer-core-skills.md +119 -0
- package/ui-ux-design/skills/ui-ux-design/references/ui-animation.md +173 -0
- package/ui-ux-design/skills/ui-ux-design/references/ui-loop.md +234 -0
- package/ui-ux-design/skills/ui-ux-design/references/visual-storytelling.md +54 -0
- package/ui-ux-design/skills/vercel-web-design-guidelines/SKILL.md +39 -0
- package/ui-ux-design/skills/web-compliance/SKILL.md +134 -0
- package/ui-ux-design/skills/web-compliance/references/audit-evidence.md +59 -0
- package/vercel/NOTES.md +23 -0
- package/vercel/mcp.json +4 -0
- package/vercel/object-stores/vercel-blob.mjs +147 -0
- package/vercel/plugin.json +47 -0
- package/vercel/skills/vercel/SKILL.md +48 -0
- package/vercel/targets/vercel.mjs +586 -0
- package/vercel/tovu-consent.json +6 -0
- package/vercel/tovu-deploy-targets.json +219 -0
- package/vercel/tovu-object-stores.json +10 -0
- package/wordpress/NOTES.md +33 -0
- package/wordpress/plugin.json +30 -0
- package/wordpress/skills/wordpress/SKILL.md +43 -0
- package/wordpress/skills/wordpress/references/free-site-redirect.md +46 -0
- package/wordpress/skills/wordpress/references/subdomain.md +66 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: github
|
|
3
|
+
description: Work against a GitHub repository through this workspace's own saved credentials — write and update files in one atomic commit, dispatch and follow a GitHub Actions run, read a failed run's logs, commit the site's rendered static export, back up the site itself to a private repository, deploy the host's server through its GitHub Actions deploy workflow — with no git, no gh CLI, and no token ever passing through the assistant. Encodes the rules 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 always the human's step, 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.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GitHub, through the site's saved credentials
|
|
7
|
+
|
|
8
|
+
## Connection card
|
|
9
|
+
|
|
10
|
+
Choose the card yourself from its `usedFor` list. Reuse a saved key or working sign-in for that
|
|
11
|
+
task. Never offer a replacement unless the person asks.
|
|
12
|
+
|
|
13
|
+
Open **Connect GitHub** with `credential_save {kind:"plugin-provider",target:"github"}`; it saves the API credential labelled `github`. For `github-source-control`, use `credential_save {kind:"plugin-provider",target:"github-source-control"}`; it saves through the source-control owner. For Pages hosting use the `github-pages` plugin’s card. These remain distinct save contracts. Each card names the repository permissions and links to fine-grained token creation. Never collect a token in chat.
|
|
14
|
+
|
|
15
|
+
## Scope
|
|
16
|
+
|
|
17
|
+
This plugin owns **GitHub**: repositories, commits, branches, Actions, and the token and permission
|
|
18
|
+
semantics behind all of them. It owns nothing else.
|
|
19
|
+
|
|
20
|
+
It knows nothing about where a build is *deployed to*. Fly, Render, Railway, a container registry,
|
|
21
|
+
a VPS — none of that is here, and a rule that only makes sense for one host does not belong here.
|
|
22
|
+
A host-specific procedure (the bundled `fly` plugin's server deploy is the one that ships
|
|
23
|
+
today) is expected to describe its own hosting rules and then hand the GitHub half to this
|
|
24
|
+
document. That split is deliberate: every
|
|
25
|
+
skill of every enabled plugin reaches the assistant's prompt at the same time, so the same rule
|
|
26
|
+
written twice, slightly differently, becomes a contradiction rather than emphasis.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Which job is this? Source control or a deploy
|
|
31
|
+
|
|
32
|
+
Decide this first; the two jobs use different tools.
|
|
33
|
+
|
|
34
|
+
- **Source control and backup** — write files into a repository, commit the site's rendered export,
|
|
35
|
+
back up the site, or start and follow any other workflow: the tools in the rest of this document.
|
|
36
|
+
- **Deploying the host's server with GitHub Actions** — use the deployment tools with platform
|
|
37
|
+
`github-actions`, never a hand-built dispatch. Call `deployment_ops_deploy` with target
|
|
38
|
+
`owner/repo` and the branch or tag. It resolves the ref to a full SHA and dispatches the host's
|
|
39
|
+
deploy workflow pinned to that commit; the host guidance describes that workflow's own inputs and
|
|
40
|
+
refusals. Say which commit will build. A started deploy is queued, never deployed: follow it with
|
|
41
|
+
`deployment_ops_wait` (pass the returned runId) until `finished`, then check the live site. Use
|
|
42
|
+
`deployment_ops_status` and `deployment_ops_logs` to find a failed job and step. Never retry a
|
|
43
|
+
deploy whose connection dropped before checking `deployment_ops_status`. The saved
|
|
44
|
+
`api.github.com` credential needs Actions write. Setting up the server host itself (its config,
|
|
45
|
+
volume and secrets) is the host plugin's job, not this one's.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## What you are allowed to use, and what does not exist here
|
|
50
|
+
|
|
51
|
+
Two native host tools do everything below. **This plugin ships no MCP server and adds no tool.**
|
|
52
|
+
Its deploy half is only the `github-actions` platform behind the core `deployment_ops_*` tools.
|
|
53
|
+
|
|
54
|
+
| Tool | What it is |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `custom_credential_make_request` | One authenticated `GET`/`POST`/`PUT`/`PATCH`/`DELETE` to GitHub's REST API through a saved credential. You pass a `label` and a **full absolute URL**; the server injects the real `Authorization` header. |
|
|
57
|
+
| `custom_credential_write_files` | A human-confirmed, atomic write of 1–25 named files onto an **existing** branch (blob → tree → commit → non-force ref update). |
|
|
58
|
+
|
|
59
|
+
Two more exist for a narrower job — `source_control_get_capabilities` and
|
|
60
|
+
`source_control_execute_commit` — and they are **not** general-purpose repo writes. See
|
|
61
|
+
`references/source-control.md` before you reach for either; the distinction between them and
|
|
62
|
+
`custom_credential_write_files` is the single easiest thing to get wrong in this document.
|
|
63
|
+
|
|
64
|
+
And two back up the site itself — `site_backup_plan`, then `site_backup_push` — into a private
|
|
65
|
+
repository. See `references/site-backup.md`.
|
|
66
|
+
|
|
67
|
+
There is no `git`, no `gh`, and no shell path. **Never shell out to `curl`, `wget`, or `git` to
|
|
68
|
+
talk to GitHub.** A raw shell request bypasses the saved-credential store entirely and either
|
|
69
|
+
fails outright or forces a token into your context to make it work — which is exactly the thing
|
|
70
|
+
the store exists to prevent.
|
|
71
|
+
|
|
72
|
+
### You do not choose the host
|
|
73
|
+
|
|
74
|
+
`custom_credential_make_request` refuses any URL whose host is not on that credential's own saved
|
|
75
|
+
allowlist (its base URL plus any saved additional hosts), **before any request is sent**. This is
|
|
76
|
+
not a limitation to route around. It is the property that makes an agent-held credential safe at
|
|
77
|
+
all: the human decided, once, at save time, which origins this token may ever reach.
|
|
78
|
+
|
|
79
|
+
So: build every URL from `https://api.github.com` (or whatever base the credential actually
|
|
80
|
+
saved — GitHub Enterprise has its own). If a call is refused, the error names the hosts that
|
|
81
|
+
*are* allowed. Read it and use one; do not try a different host to see what sticks.
|
|
82
|
+
|
|
83
|
+
To find the label, call `content_read.custom_credential` with `{}`. It returns each saved
|
|
84
|
+
credential's label, category, base URL and additional hosts — never a token. A workspace with a
|
|
85
|
+
credential labelled `github` is the expected case, but do not assume the label: read it.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## The rules
|
|
90
|
+
|
|
91
|
+
These are the reason this plugin exists. Each one has cost a real debugging session.
|
|
92
|
+
|
|
93
|
+
### Rule 1 — A repository secret is ALWAYS the human's step. This is not negotiable.
|
|
94
|
+
|
|
95
|
+
Creating or updating a GitHub Actions secret through the API requires encrypting the value against
|
|
96
|
+
the repository's own public key. To do that, **the secret value would have to pass through your
|
|
97
|
+
context** — you would have to hold the plaintext token in order to encrypt it.
|
|
98
|
+
|
|
99
|
+
That is not an inconvenience on the way to a shortcut. **It is the failure mode.** The entire
|
|
100
|
+
saved-credential design exists so a secret never reaches the assistant, and a step that requires
|
|
101
|
+
holding one is a step the assistant does not perform, no matter how much friction it saves.
|
|
102
|
+
|
|
103
|
+
So you never call `PUT /repos/{owner}/{repo}/actions/secrets/{name}`, you never fetch
|
|
104
|
+
`.../actions/secrets/public-key` in order to encrypt something, and you never ask a human to paste
|
|
105
|
+
a token into the chat so you can do it for them. You hand them the exact instruction instead:
|
|
106
|
+
|
|
107
|
+
> Go to **Settings → Secrets and variables → Actions → New repository secret** in
|
|
108
|
+
> `<owner>/<repo>`. Name it exactly `<SECRET_NAME>`. Paste only the value — do not commit it
|
|
109
|
+
> anywhere, and do not paste it into this chat.
|
|
110
|
+
|
|
111
|
+
Then **wait for them to confirm.** Do not dispatch a workflow that needs a secret before they have
|
|
112
|
+
said it is set: the run fails on the runner in a way that reads like a config problem rather than a
|
|
113
|
+
missing secret, and you will debug the wrong thing.
|
|
114
|
+
|
|
115
|
+
The same rule covers environment secrets, organization secrets, and Dependabot secrets. Reading
|
|
116
|
+
which secret *names* exist (`GET .../actions/secrets`) is fine — GitHub never returns a value — and
|
|
117
|
+
is a genuinely useful way to confirm a human's "I set it" without asking twice.
|
|
118
|
+
|
|
119
|
+
### Rule 2 — A 204 from a workflow dispatch means QUEUED. It does not mean anything ran.
|
|
120
|
+
|
|
121
|
+
`POST /repos/{owner}/{repo}/actions/workflows/{file}/dispatches` returns **204 with an empty body**
|
|
122
|
+
on success. All that 204 asserts is that GitHub accepted the request.
|
|
123
|
+
|
|
124
|
+
Nothing has built. Nothing has deployed. Nothing has even started — the run may not appear in the
|
|
125
|
+
runs list for a second or two, and it may sit `queued` behind another run after that.
|
|
126
|
+
|
|
127
|
+
**Never report success at the dispatch.** Report "queued", then follow the run
|
|
128
|
+
(`references/actions.md` has the poll loop and how to read a failure). Say what you actually
|
|
129
|
+
observed, at the stage you observed it.
|
|
130
|
+
|
|
131
|
+
### Rule 3 — A workflow only fires on the branch its own trigger names.
|
|
132
|
+
|
|
133
|
+
A workflow's `on: push:` names branches. A push to any other branch does **nothing** — no run, no
|
|
134
|
+
error, no warning. The same is true of `workflow_dispatch`: the `ref` you dispatch against must be
|
|
135
|
+
a branch the workflow file exists on, and GitHub reads the workflow definition *from that ref*.
|
|
136
|
+
|
|
137
|
+
Two failure shapes follow, and both look like "the workflow is broken":
|
|
138
|
+
|
|
139
|
+
- You wrote the workflow onto a branch its own `push:` trigger does not list, pushed, and nothing
|
|
140
|
+
happened. Nothing is broken; the trigger simply did not match.
|
|
141
|
+
- You dispatched against a `ref` where the workflow file does not exist yet. GitHub returns
|
|
142
|
+
**422**, not 404, and the message is about the workflow rather than the ref.
|
|
143
|
+
|
|
144
|
+
So before you push or dispatch: read the workflow's own trigger, and name the branch explicitly.
|
|
145
|
+
Never assume `main`; a repository's default branch is a fact to look up
|
|
146
|
+
(`GET /repos/{owner}/{repo}` → `default_branch`), not a convention to rely on.
|
|
147
|
+
|
|
148
|
+
### Rule 4 — When you EDIT an existing file, diff the MODIFIED files. Not just added and deleted.
|
|
149
|
+
|
|
150
|
+
This one has already cost two silent production failures.
|
|
151
|
+
|
|
152
|
+
A history force-push once rewrote a workflow file and dropped two `--build-arg` flags from it. A
|
|
153
|
+
review that looked at which files were **added** and which were **deleted** saw nothing wrong —
|
|
154
|
+
the file was neither. It was modified, and the modification quietly removed two load-bearing lines.
|
|
155
|
+
Two deploys failed before anyone connected the two facts.
|
|
156
|
+
|
|
157
|
+
`custom_credential_write_files` replaces a file's **entire content**; it does not patch. So when
|
|
158
|
+
you are updating a file that already exists:
|
|
159
|
+
|
|
160
|
+
1. Read the current content first (`GET /repos/{owner}/{repo}/contents/{path}?ref={branch}`,
|
|
161
|
+
which returns base64, or the raw blob via the Git Data API).
|
|
162
|
+
2. Produce the new content from what is actually there — never from memory, and never from a
|
|
163
|
+
template you assume matches.
|
|
164
|
+
3. Before writing, state what changed, **line by line, including every line you removed.**
|
|
165
|
+
|
|
166
|
+
The confirmation dialog names each path as a create or an update, resolved against the branch's
|
|
167
|
+
real current state. An "update" label is your cue that a full-content replacement is about to
|
|
168
|
+
happen and that everything you did not carry forward is about to be gone.
|
|
169
|
+
|
|
170
|
+
### Rule 5 — A 403 on an org-wide or account-wide listing is a permission BOUNDARY, not a broken credential.
|
|
171
|
+
|
|
172
|
+
Many real tokens are scoped to a single repository or a single app. Such a token can fully manage
|
|
173
|
+
its own resource and still **403 on any call that enumerates an organization or an account** — the
|
|
174
|
+
org's repositories, the account's installations, every-app-in-the-org listings.
|
|
175
|
+
|
|
176
|
+
That 403 looks *exactly* like an expired, revoked, or wrong-scoped credential. It is neither.
|
|
177
|
+
Misreading it once cost a full debugging session and nearly caused a working credential to be
|
|
178
|
+
replaced.
|
|
179
|
+
|
|
180
|
+
The rule: **prefer per-resource endpoints over listings.** If you know the `owner/repo`, ask about
|
|
181
|
+
that repository directly. Resolve the identifier from the human, from a file already in the repo,
|
|
182
|
+
or from the conversation — never by listing the org and searching it. If you genuinely have no
|
|
183
|
+
identifier, ask; a question costs one turn, a wrong diagnosis costs a session.
|
|
184
|
+
|
|
185
|
+
If a call does come back 401 or 403, **read the `authDiagnostic` field on the result before
|
|
186
|
+
reporting a bare failure**, follow the remedy it names, and retry at most **once**. There is
|
|
187
|
+
deliberately no diagnostic hint on a 403 at all — 403 covers scopes, policy, and missing headers,
|
|
188
|
+
so any guess would be a false lead. Report the failure and GitHub's own message plainly.
|
|
189
|
+
|
|
190
|
+
### Rule 6 — Never print, echo, or reconstruct a secret.
|
|
191
|
+
|
|
192
|
+
Not in a file you write, not in a commit message, not in a summary of what the human just did, not
|
|
193
|
+
"redacted" with the first four characters showing. If a secret value must exist, the human types
|
|
194
|
+
it — into GitHub's own secret form, or into the host's credential form's masked field.
|
|
195
|
+
|
|
196
|
+
Nothing in this plugin's procedures requires you to see one, which is what makes this rule cheap to
|
|
197
|
+
keep.
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Choosing the right tool
|
|
202
|
+
|
|
203
|
+
Answer one question first: **is this app source, or is it the site's rendered output?**
|
|
204
|
+
|
|
205
|
+
| You want to… | Use |
|
|
206
|
+
|---|---|
|
|
207
|
+
| Add or update named files — a config file, a workflow, a script, a Dockerfile | `custom_credential_write_files` |
|
|
208
|
+
| Read anything at all from GitHub | `custom_credential_make_request` (`GET`) |
|
|
209
|
+
| Deploy the host's server through its deploy workflow | `deployment_ops_deploy` with platform `github-actions` — see "Which job is this?" above |
|
|
210
|
+
| Start any other workflow, or follow a run | `custom_credential_make_request` — see `references/actions.md` |
|
|
211
|
+
| Back up the **site itself** (database, media, themes, plugins, settings) into a private repo | `site_backup_plan`, then `site_backup_push` — see `references/site-backup.md` |
|
|
212
|
+
| Publish the **site's rendered static export** into a repo | `source_control_execute_commit` — see `references/source-control.md` |
|
|
213
|
+
|
|
214
|
+
Conflating the last row with the rest wastes real work. `source_control_execute_commit` runs a
|
|
215
|
+
fresh static export of the site and commits the resulting HTML and assets, and it **deletes** paths
|
|
216
|
+
it previously wrote that the export no longer produces. It is a publishing target, not a way to put
|
|
217
|
+
a file in a repository. A container build needs app source, and a rendered export is not app
|
|
218
|
+
source — a build fed the wrong one either fails or, worse, succeeds and ships a site with no
|
|
219
|
+
server. `references/source-control.md` states the difference in full; read it before you use
|
|
220
|
+
either tool for the first time in a task.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Reporting rules
|
|
225
|
+
|
|
226
|
+
- **Report the stage you actually reached.** Queued is queued. Confirmed-but-unrun is not written.
|
|
227
|
+
- **Name the branch, the repository, and the commit** in your result. A commit SHA and URL come
|
|
228
|
+
back from a successful write; use them rather than describing what you believe happened.
|
|
229
|
+
- **A declined confirmation is a real outcome, not an error.** Say the human declined and stop.
|
|
230
|
+
Do not re-raise the dialog to see if they change their mind.
|
|
231
|
+
- **Never re-dispatch on a hunch.** A second run queued behind a broken one wastes the human's
|
|
232
|
+
time and tells you nothing new.
|
|
233
|
+
- **Say what you left unverified.** A value you guessed, a branch you assumed, a placeholder you
|
|
234
|
+
did not replace — each is a thing the human needs to know, not a detail.
|
|
235
|
+
|
|
236
|
+
## References
|
|
237
|
+
|
|
238
|
+
- `references/repo-files.md` — writing and updating files: the confirmation dialog, the limits,
|
|
239
|
+
every refusal reason, the workflow-path warning, and the read-then-replace procedure for edits.
|
|
240
|
+
- `references/actions.md` — dispatching a workflow, polling a run, reading a failed run's logs,
|
|
241
|
+
and telling the distinct failure signatures apart.
|
|
242
|
+
- `references/auth-and-tokens.md` — what a saved GitHub credential can and cannot do, scopes,
|
|
243
|
+
`authDiagnostic`, rate limits, and why repository secrets are the human's step.
|
|
244
|
+
- `references/source-control.md` — `source_control_execute_commit` versus
|
|
245
|
+
`custom_credential_write_files`: two different credential stores, two different jobs, and the
|
|
246
|
+
app-source-versus-rendered-export distinction.
|
|
247
|
+
- `references/site-backup.md` — backing up the site itself: plan then push, private repositories
|
|
248
|
+
only, what the dialog shows, the limits, every code and what to tell the human, and why a refused
|
|
249
|
+
push is planned again rather than forced.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# GitHub Actions: dispatch, follow, diagnose
|
|
2
|
+
|
|
3
|
+
Everything here goes through `custom_credential_make_request` against the saved GitHub credential.
|
|
4
|
+
Nothing here needs a new tool, and nothing here needs a shell.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Before you dispatch anything
|
|
9
|
+
|
|
10
|
+
Three facts, none of which you may guess:
|
|
11
|
+
|
|
12
|
+
1. **The repository** — `owner/repo`, exactly.
|
|
13
|
+
2. **The workflow** — its filename (`deploy.yml`) or its numeric id. The filename is what a human
|
|
14
|
+
recognizes, so prefer it.
|
|
15
|
+
3. **The ref** — the branch to run on. GitHub reads the workflow definition *from that ref*, so the
|
|
16
|
+
workflow file must already exist there. `GET /repos/{owner}/{repo}` returns `default_branch` if
|
|
17
|
+
you need it; do not assume `main`. And naming the ref is not knowing it — resolve it to a commit
|
|
18
|
+
before you dispatch, per the section below.
|
|
19
|
+
|
|
20
|
+
And one check worth its single call: confirm the workflow is actually registered.
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
custom_credential_make_request({
|
|
24
|
+
label: "github",
|
|
25
|
+
method: "GET",
|
|
26
|
+
url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows"
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Each entry carries `id`, `name`, `path`, and `state`. A workflow whose `state` is
|
|
31
|
+
`disabled_manually` or `disabled_inactivity` accepts a dispatch and then never runs — worth
|
|
32
|
+
catching here rather than in a confused poll loop ten minutes later.
|
|
33
|
+
|
|
34
|
+
If a file you just wrote is not in that list, GitHub has not picked it up yet, or it is not on the
|
|
35
|
+
ref you are looking at. Do not dispatch into that gap.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Resolve the ref to a commit, and say which commit, before you dispatch
|
|
40
|
+
|
|
41
|
+
**A branch name is not a commit.** `main` reads as the same string on the day your work lands on it
|
|
42
|
+
and on a day it is a month behind — the name cannot tell those two apart, and neither can the human,
|
|
43
|
+
unless you tell them. One GET turns the name into a fact:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
custom_credential_make_request({
|
|
47
|
+
label: "github",
|
|
48
|
+
method: "GET",
|
|
49
|
+
url: "https://api.github.com/repos/<owner>/<repo>/branches/<ref>"
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Three fields off that response:
|
|
54
|
+
|
|
55
|
+
| Field | What it gives you |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `name` | The ref, confirmed to exist. A 404 here is the same missing ref the dispatch would have returned as a **422**, caught one call earlier and in a message that names it plainly. |
|
|
58
|
+
| `commit.sha` | The exact commit this run will build. |
|
|
59
|
+
| `commit.commit.committer.date` | When that commit landed on the ref. |
|
|
60
|
+
|
|
61
|
+
**State all three before you POST the dispatch**, with the age in plain words:
|
|
62
|
+
|
|
63
|
+
> Deploying `main` @ `f2997c6e` — committed 2026-09-11, 7 days ago.
|
|
64
|
+
|
|
65
|
+
The date is the half that does the work. A tip a week old, told to someone who has been working all
|
|
66
|
+
week, is the visible shape of *"this is about to ship something other than what you just wrote"* —
|
|
67
|
+
and it is one line, at the only moment it is still cheap.
|
|
68
|
+
|
|
69
|
+
**This step reports. It never blocks.** Say what the ref resolves to, then dispatch. Do not ask for
|
|
70
|
+
confirmation, do not refuse, and do not wait to be told to continue. Whether this deploy should go
|
|
71
|
+
out is the human's call, and they can only make it if you have said what it is.
|
|
72
|
+
|
|
73
|
+
### One more comparison, already paid for
|
|
74
|
+
|
|
75
|
+
The runs list you will poll *after* the dispatch also answers a question worth asking *before* it:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
custom_credential_make_request({
|
|
79
|
+
label: "github",
|
|
80
|
+
method: "GET",
|
|
81
|
+
url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows/<file.yml>/runs?per_page=1"
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If `workflow_runs[0].head_sha` equals the `commit.sha` you just resolved, this run will build
|
|
86
|
+
**byte-identical source to the last one**. Say so, in those words, before you dispatch. A green run
|
|
87
|
+
that changes nothing is the most confusing outcome anything in this document can produce, and it is
|
|
88
|
+
fully predictable one call ahead of it happening.
|
|
89
|
+
|
|
90
|
+
### What you cannot compare against
|
|
91
|
+
|
|
92
|
+
The human's own working copy. There is no `git` and no shell here — their local branch, their
|
|
93
|
+
uncommitted work, and whether they have pushed any of it are all invisible to you. Do not guess at
|
|
94
|
+
them, and do not imply you checked. Give them the ref, the SHA and its date; if that tip reads older
|
|
95
|
+
than the conversation you are having, say the date out loud and let them draw the conclusion.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Dispatch
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
custom_credential_make_request({
|
|
103
|
+
label: "github",
|
|
104
|
+
method: "POST",
|
|
105
|
+
url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows/<file.yml>/dispatches",
|
|
106
|
+
headers: { "Accept": "application/vnd.github+json", "Content-Type": "application/json" },
|
|
107
|
+
body: "{\"ref\":\"<branch>\"}"
|
|
108
|
+
})
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Success is 204 with an empty body, and 204 means QUEUED.** Not built, not deployed, not started.
|
|
112
|
+
This is the single most reported-wrong result in this whole document. Say "queued", then follow it.
|
|
113
|
+
|
|
114
|
+
The failures you will actually see, and what each one means:
|
|
115
|
+
|
|
116
|
+
| Status | What it actually is |
|
|
117
|
+
|---|---|
|
|
118
|
+
| **404** | The workflow file does not exist at that path — *or* the token cannot see this repository at all. Both look identical here. Confirm the repo with `GET /repos/{owner}/{repo}` before you assume the path is wrong. |
|
|
119
|
+
| **422** | The workflow exists but has no `workflow_dispatch` trigger, or the `ref` you named does not exist. GitHub's message names which; read it rather than retrying. |
|
|
120
|
+
| **403** | Usually the token lacks Actions write. Occasionally an org policy. See `auth-and-tokens.md`. |
|
|
121
|
+
|
|
122
|
+
Never retry a 422 with a different guess. Fix the actual cause.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Follow the run
|
|
127
|
+
|
|
128
|
+
There is no callback and no webhook here. You poll.
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
custom_credential_make_request({
|
|
132
|
+
label: "github",
|
|
133
|
+
method: "GET",
|
|
134
|
+
url: "https://api.github.com/repos/<owner>/<repo>/actions/workflows/<file.yml>/runs?per_page=1"
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Read `workflow_runs[0]`: `id`, `status`, `conclusion`, `html_url`, `head_branch`, `head_sha`,
|
|
139
|
+
`created_at`. `head_sha` is the commit that actually built: check it against the SHA you resolved
|
|
140
|
+
before dispatching, and report it next to the conclusion. The two differ when someone pushed
|
|
141
|
+
between your read and your dispatch — a fact to state, not a problem to solve.
|
|
142
|
+
|
|
143
|
+
**Two things to get right before you interpret it:**
|
|
144
|
+
|
|
145
|
+
- The newest run may not be yours. Check `created_at` against when you dispatched, and check
|
|
146
|
+
`head_branch`. Reporting on someone else's run is worse than reporting nothing.
|
|
147
|
+
- `status` and `conclusion` are different fields. `status` is `queued` / `in_progress` /
|
|
148
|
+
`completed`. `conclusion` is `null` until `status` is `completed`, and only then is it
|
|
149
|
+
`success` / `failure` / `cancelled` / `timed_out` / `skipped` / `action_required`.
|
|
150
|
+
|
|
151
|
+
**A run sitting in `queued` is not stuck.** A concurrency group that queues rather than cancels
|
|
152
|
+
will hold a run behind another one for as long as that one takes. Say "queued behind an earlier
|
|
153
|
+
run" — do not diagnose a hang, and do not dispatch a second run to "get things moving": that
|
|
154
|
+
lengthens the queue you are complaining about.
|
|
155
|
+
|
|
156
|
+
Poll a handful of times with a real gap between calls, and report what you actually see each time.
|
|
157
|
+
If it is still running when you run out of patience, say so and give the human `html_url`. An
|
|
158
|
+
honest "still in progress after N checks, here is the link" is a better answer than a guess.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## When a run fails
|
|
163
|
+
|
|
164
|
+
Do not report "the workflow failed" and stop. Find the step.
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
custom_credential_make_request({
|
|
168
|
+
label: "github",
|
|
169
|
+
method: "GET",
|
|
170
|
+
url: "https://api.github.com/repos/<owner>/<repo>/actions/runs/<run_id>/jobs"
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Each job carries `name`, `status`, `conclusion`, and a `steps` array where every step has its own
|
|
175
|
+
`name`, `number`, and `conclusion`. **The first step whose `conclusion` is `failure` is the
|
|
176
|
+
answer** — everything after it is `skipped`, and reporting a skipped step as the failure sends the
|
|
177
|
+
human to the wrong place.
|
|
178
|
+
|
|
179
|
+
Report: the job name, the step name and number, and the run's `html_url`.
|
|
180
|
+
|
|
181
|
+
### The raw-logs endpoint does not work from here, and that is by design
|
|
182
|
+
|
|
183
|
+
`GET /repos/{owner}/{repo}/actions/jobs/{job_id}/logs` does not return logs. It returns a **302**
|
|
184
|
+
whose `Location` points at an object-store host.
|
|
185
|
+
|
|
186
|
+
`custom_credential_make_request` follows **zero** redirects, and that object-store host is not on
|
|
187
|
+
the credential's saved allowlist, so you cannot follow it either. You will see the 302 and its
|
|
188
|
+
`Location` header, and that is where it ends. This is not a bug to work around — following an
|
|
189
|
+
arbitrary redirect target with a credential attached is exactly the egress hazard the single-hop
|
|
190
|
+
policy exists to close.
|
|
191
|
+
|
|
192
|
+
So the honest procedure is:
|
|
193
|
+
|
|
194
|
+
1. Get the failing job and step from the `/jobs` response above. That is genuinely most of what a
|
|
195
|
+
log would tell you.
|
|
196
|
+
2. Give the human the run's `html_url` and name the failing step, so one click lands them on it.
|
|
197
|
+
3. If the actual log text matters, **ask them to paste the relevant lines.** Do not claim you read
|
|
198
|
+
logs you did not read.
|
|
199
|
+
|
|
200
|
+
### Telling failure signatures apart
|
|
201
|
+
|
|
202
|
+
These four are the ones that get confused with each other, and each needs a different next move:
|
|
203
|
+
|
|
204
|
+
| Signature | What it means | What to do |
|
|
205
|
+
|---|---|---|
|
|
206
|
+
| The run never appears | The trigger did not match, or the file is not on that ref | Re-read the workflow's own `on:` block and the ref you pushed to. Do not re-dispatch. |
|
|
207
|
+
| Fails immediately, in the first seconds, on a setup or auth step | A missing or wrong repository secret | Confirm with the human that the secret is set, by exact name. `GET .../actions/secrets` lists names (never values). |
|
|
208
|
+
| Fails mid-run in a build or deploy step | A real error in the thing being built or shipped | Name the step and hand over the run URL. This is not a GitHub problem. |
|
|
209
|
+
| `conclusion: "action_required"` | Waiting on a human — an approval, or a first-time contributor gate | Tell the human it is waiting on them, and where. Nothing you can do moves it. |
|
|
210
|
+
|
|
211
|
+
A cancelled run and a timed-out run are also distinct from a failure, and both are commonly a
|
|
212
|
+
human's or a queue's doing rather than a defect. Read `conclusion` before you write the word
|
|
213
|
+
"failed".
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Rate limits
|
|
218
|
+
|
|
219
|
+
Every response carries `x-ratelimit-remaining` and `x-ratelimit-reset`. A **403 with
|
|
220
|
+
`x-ratelimit-remaining: 0`** is a rate limit, not a permission problem — and telling a human their
|
|
221
|
+
token is broken when they are merely throttled is a real, avoidable mistake.
|
|
222
|
+
|
|
223
|
+
Polling is the only thing here that makes a meaningful number of calls, which is the practical
|
|
224
|
+
argument for a real gap between polls rather than a tight loop.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Tokens, scopes, and permission boundaries
|
|
2
|
+
|
|
3
|
+
## Where the token lives, and why you never see it
|
|
4
|
+
|
|
5
|
+
Open `credential_save {kind:"plugin-provider",target:"github"}` for the plugin’s own GitHub card. It saves label `github` and base URL `https://api.github.com`, with the token sealed server-side. Existing rows can still be rotated by their exact saved label.
|
|
6
|
+
|
|
7
|
+
You name the **label**. The server resolves the credential and injects the real `Authorization`
|
|
8
|
+
header itself. The token never appears in a tool's input, in a tool's output, or anywhere in your
|
|
9
|
+
context.
|
|
10
|
+
|
|
11
|
+
To discover what is saved, call `content_read.custom_credential` with `{}`. It returns
|
|
12
|
+
each credential's label, category, base URL, and additional hosts — never a token, and never a
|
|
13
|
+
saved username. An empty list is the signal to ask a human to save one, not to look for another
|
|
14
|
+
way in.
|
|
15
|
+
|
|
16
|
+
Two headers you must never set on `custom_credential_make_request`: `Authorization` and `Cookie`
|
|
17
|
+
(also `Host` and `Proxy-Authorization`). The server injects the real one, and a call trying to set
|
|
18
|
+
any of these is refused.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## The host allowlist is a feature
|
|
23
|
+
|
|
24
|
+
Every URL you pass must have a host on that credential's own saved list — its base URL plus any
|
|
25
|
+
saved additional hosts. Anything else is refused **before any request is sent**, and the error
|
|
26
|
+
names which hosts *are* allowed.
|
|
27
|
+
|
|
28
|
+
This is the property that makes an agent-held credential safe: the human decided once, at save
|
|
29
|
+
time, which origins this token may ever reach. Do not try alternate hosts to find one that works.
|
|
30
|
+
Read the error, use a named host, or ask.
|
|
31
|
+
|
|
32
|
+
The same policy follows **zero redirects**. A GitHub endpoint that answers with a 302 to an
|
|
33
|
+
object-store host (the Actions job-logs endpoint is the one you will actually hit) simply ends
|
|
34
|
+
there. See `actions.md`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Repository secrets are the human's step. Always.
|
|
39
|
+
|
|
40
|
+
Writing a GitHub Actions secret through the API requires encrypting the value against the
|
|
41
|
+
repository's public key — which requires **holding the plaintext value**, in your context, to
|
|
42
|
+
encrypt it.
|
|
43
|
+
|
|
44
|
+
That is the failure mode the entire credential design exists to prevent. It is not a shortcut you
|
|
45
|
+
are being denied; it is the thing that must not happen.
|
|
46
|
+
|
|
47
|
+
So you never:
|
|
48
|
+
|
|
49
|
+
- call `PUT /repos/{owner}/{repo}/actions/secrets/{name}`,
|
|
50
|
+
- fetch `GET /repos/{owner}/{repo}/actions/secrets/public-key` in order to encrypt something,
|
|
51
|
+
- ask a human to paste a token into chat so you can set it for them,
|
|
52
|
+
- or accept one they volunteer. If a secret appears in the conversation anyway, do not use it, do
|
|
53
|
+
not repeat it, and tell them to rotate it.
|
|
54
|
+
|
|
55
|
+
You hand them this instead:
|
|
56
|
+
|
|
57
|
+
> **Settings → Secrets and variables → Actions → New repository secret** in `<owner>/<repo>`.
|
|
58
|
+
> Name it exactly `<SECRET_NAME>`. Paste only the value — do not commit it anywhere, and do not
|
|
59
|
+
> paste it into this chat.
|
|
60
|
+
|
|
61
|
+
Then **wait for confirmation before dispatching anything that needs it.** A run that starts without
|
|
62
|
+
its secret fails on the runner in a way that reads like a config problem, and you will spend the
|
|
63
|
+
next twenty minutes debugging the wrong thing.
|
|
64
|
+
|
|
65
|
+
What you *may* do: **list secret names.** `GET /repos/{owner}/{repo}/actions/secrets` returns names
|
|
66
|
+
and timestamps and never a value. It is the honest way to verify a human's "I set it" without
|
|
67
|
+
asking them twice, and it catches the common typo of a name that does not match the workflow's
|
|
68
|
+
`${{ secrets.… }}` reference.
|
|
69
|
+
|
|
70
|
+
Organization secrets, environment secrets, and Dependabot secrets are all covered by the same rule.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Scopes, and what a 403 actually means
|
|
75
|
+
|
|
76
|
+
**A 403 on an org-wide or account-wide listing endpoint is a normal permission boundary for an
|
|
77
|
+
app-scoped or repo-scoped token. It is not a broken credential.**
|
|
78
|
+
|
|
79
|
+
Misreading this cost a full debugging session once already, and nearly got a perfectly good
|
|
80
|
+
credential replaced. A token scoped to one repository can fully manage that repository and still
|
|
81
|
+
403 on any call that enumerates an organization or an account.
|
|
82
|
+
|
|
83
|
+
The rule that follows: **prefer per-resource endpoints over listings.** Resolve `owner/repo` from
|
|
84
|
+
the human, from the conversation, or from a file already in the repository — never by listing an
|
|
85
|
+
org and searching it. If you have no identifier, ask. One question beats one wrong diagnosis.
|
|
86
|
+
|
|
87
|
+
Roughly what each capability needs, so you can say something useful when a 403 does appear:
|
|
88
|
+
|
|
89
|
+
| To do this | The token needs |
|
|
90
|
+
|---|---|
|
|
91
|
+
| Read a repository, its contents, its branches | read access to that repository |
|
|
92
|
+
| Write files, create commits, update a ref | **write** access to repository contents |
|
|
93
|
+
| Write anything under `.github/workflows/` | contents write **plus** workflow permission — a token without it is refused specifically on workflow paths and nowhere else, which is confusing if you do not know to look for it |
|
|
94
|
+
| Dispatch a workflow, read runs and jobs | Actions permission (read for following, write for dispatching) |
|
|
95
|
+
| Read secret **names** | Actions/secrets read |
|
|
96
|
+
|
|
97
|
+
The workflow-permission row is the one that surprises people: a write that succeeds for every other
|
|
98
|
+
path and fails only for `.github/workflows/…` is a scope problem, not a path problem.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Reading `authDiagnostic`
|
|
103
|
+
|
|
104
|
+
A 401 or 403 response from `custom_credential_make_request` carries an `authDiagnostic` object
|
|
105
|
+
alongside GitHub's untouched `bodyText`. **Read it before reporting a bare failure.**
|
|
106
|
+
|
|
107
|
+
- On a **401** where the scheme sent was `Bearer` and no username is stored, `hint` names the one
|
|
108
|
+
narrow guess the system is willing to make: this provider may need HTTP Basic with a saved
|
|
109
|
+
username. Treat it as a hypothesis. Ask the human for the username, save it with
|
|
110
|
+
`custom_credential_set_username`, retry **once**. Never invent a username, and never loop past
|
|
111
|
+
one retry.
|
|
112
|
+
- When a username is already stored, there is no hint — the cause is something else and unguessable.
|
|
113
|
+
- On a **403 there is no hint at all**, deliberately. 403 covers scopes, org policy, rate limits,
|
|
114
|
+
and missing headers; a Basic-auth guess there would be a false lead rather than a hedge. Report
|
|
115
|
+
the failure and GitHub's own message plainly.
|
|
116
|
+
|
|
117
|
+
If you suspect the credential itself, `custom_credential_verify` checks one saved credential
|
|
118
|
+
against its own API, live, and reports `valid` / `invalid` / `unreachable`. **`unreachable` does
|
|
119
|
+
not mean the credential is bad** — it is a network failure. Do not tell a human to replace a token
|
|
120
|
+
over a DNS error.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Rate limits
|
|
125
|
+
|
|
126
|
+
Every response carries `x-ratelimit-remaining` and `x-ratelimit-reset`. **A 403 with
|
|
127
|
+
`x-ratelimit-remaining: 0` is a rate limit**, and saying "your token is broken" when a human is
|
|
128
|
+
merely throttled is an avoidable, expensive mistake. Read the header before you diagnose.
|
|
129
|
+
|
|
130
|
+
Polling an Actions run is the only thing here that makes a meaningful number of calls — which is
|
|
131
|
+
the practical reason to leave a real gap between polls.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## The rule under all of the above
|
|
136
|
+
|
|
137
|
+
**Never print, echo, or reconstruct a secret.** Not in a file you write, not in a commit message,
|
|
138
|
+
not in a summary of what the human just did, not partially masked. Nothing in this plugin's
|
|
139
|
+
procedures requires you to hold one, which is what makes that rule cheap to keep and inexcusable to
|
|
140
|
+
break.
|