mirror of
https://github.com/anthropics/claude-plugins-official.git
synced 2026-06-17 14:53:28 +00:00
Compare commits
16 Commits
security-g
...
fix-2071-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a67587c816 | ||
|
|
502de97746 | ||
|
|
679f52da9e | ||
|
|
13a0208f38 | ||
|
|
e9b54375b8 | ||
|
|
fc49e6815f | ||
|
|
06b6d5b96f | ||
|
|
2a3dd81146 | ||
|
|
c11244778d | ||
|
|
4decd2e3b2 | ||
|
|
e77ff913ad | ||
|
|
390c2fe785 | ||
|
|
1109c43a9d | ||
|
|
4c4b3009e0 | ||
|
|
fd06e9957e | ||
|
|
a8f5f1b3c9 |
@@ -19,7 +19,7 @@
|
||||
"url": "https://github.com/42Crunch-AI/claude-plugins.git",
|
||||
"path": "plugins/api-security-testing",
|
||||
"ref": "v1.5.5",
|
||||
"sha": "a175b24f7b34852b70c78c21545cce8037eb3112"
|
||||
"sha": "5c8074d846b852c21da23bbf6effbfdabb18ba2d"
|
||||
},
|
||||
"homepage": "https://42crunch.com"
|
||||
},
|
||||
@@ -35,7 +35,7 @@
|
||||
"url": "https://github.com/adobe/skills.git",
|
||||
"path": "plugins/creative-cloud/adobe-for-creativity",
|
||||
"ref": "main",
|
||||
"sha": "dedb9597f878072ec2f6b1fd051900ccb913d653"
|
||||
"sha": "ecd1e2b2c493ba0627774f36a897bd44d47fef1d"
|
||||
},
|
||||
"homepage": "https://github.com/adobe/skills/tree/main/plugins/creative-cloud/adobe-for-creativity"
|
||||
},
|
||||
@@ -93,7 +93,7 @@
|
||||
"url": "https://github.com/Airtable/skills.git",
|
||||
"path": "plugins/airtable",
|
||||
"ref": "main",
|
||||
"sha": "1a8db588c72d31550ef6ee39b716598111840583"
|
||||
"sha": "21d2fe52774d861e2f2f997eeac2bf965e8590b8"
|
||||
},
|
||||
"homepage": "https://www.airtable.com"
|
||||
},
|
||||
@@ -120,7 +120,7 @@
|
||||
"url": "https://github.com/awslabs/agent-plugins.git",
|
||||
"path": "plugins/amazon-location-service",
|
||||
"ref": "main",
|
||||
"sha": "95381e8bcb92f58a28edb4f83eb7e163c7461a0a"
|
||||
"sha": "5d982e8a5f1e0b06545adac69ff0348141587725"
|
||||
},
|
||||
"homepage": "https://github.com/awslabs/agent-plugins"
|
||||
},
|
||||
@@ -161,7 +161,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/apollographql/skills.git",
|
||||
"sha": "64d4087d629e413da1bac780abeaefd653847440"
|
||||
"sha": "e1d07720e9bcfbf867fa2907192c94ec2ed421e1"
|
||||
},
|
||||
"homepage": "https://www.apollographql.com"
|
||||
},
|
||||
@@ -226,7 +226,7 @@
|
||||
"source": "url",
|
||||
"url": "https://github.com/BrainBlend-AI/atomic-agents.git",
|
||||
"path": "claude-plugin/atomic-agents",
|
||||
"sha": "f849087b26bbb6fb5e63acb60f2b566ce874aaa7"
|
||||
"sha": "c4e905c49884747be65e7ed42ccfb118c67f57ac"
|
||||
},
|
||||
"homepage": "https://github.com/BrainBlend-AI/atomic-agents",
|
||||
"tags": [
|
||||
@@ -274,7 +274,7 @@
|
||||
"url": "https://github.com/awslabs/agent-plugins.git",
|
||||
"path": "plugins/aws-amplify",
|
||||
"ref": "main",
|
||||
"sha": "95381e8bcb92f58a28edb4f83eb7e163c7461a0a"
|
||||
"sha": "5d982e8a5f1e0b06545adac69ff0348141587725"
|
||||
},
|
||||
"homepage": "https://github.com/awslabs/agent-plugins"
|
||||
},
|
||||
@@ -335,7 +335,7 @@
|
||||
"url": "https://github.com/awslabs/agent-plugins.git",
|
||||
"path": "plugins/aws-serverless",
|
||||
"ref": "main",
|
||||
"sha": "95381e8bcb92f58a28edb4f83eb7e163c7461a0a"
|
||||
"sha": "5d982e8a5f1e0b06545adac69ff0348141587725"
|
||||
},
|
||||
"homepage": "https://github.com/awslabs/agent-plugins"
|
||||
},
|
||||
@@ -346,7 +346,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/microsoft/azure-skills.git",
|
||||
"sha": "350e050ca30fe3464483f66193a8ff3a973b1d77"
|
||||
"sha": "d02fd24f151f5133650eaa78e7da3cac2cedd72f"
|
||||
},
|
||||
"homepage": "https://github.com/microsoft/azure-skills"
|
||||
},
|
||||
@@ -412,7 +412,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/brightdata/skills.git",
|
||||
"sha": "37145178dfc9b52e28dd224afeccc7184f7711fc"
|
||||
"sha": "071e9d4db77c8561e333799f25ea85f11f7b667d"
|
||||
},
|
||||
"homepage": "https://docs.brightdata.com"
|
||||
},
|
||||
@@ -426,7 +426,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/buildkite/skills.git",
|
||||
"sha": "252476999d4813b8f7412215e47328e1b60ae51c"
|
||||
"sha": "a43e944f2017146d0a6b7d8ea2bf21b02484e1d3"
|
||||
},
|
||||
"homepage": "https://buildkite.com"
|
||||
},
|
||||
@@ -442,7 +442,7 @@
|
||||
"url": "https://github.com/carta/plugins.git",
|
||||
"path": "plugins/carta-cap-table",
|
||||
"ref": "main",
|
||||
"sha": "b17fbfb0331e3903e5235b2fe21eb7a65c1bc394"
|
||||
"sha": "5e6c9d1cfa3bff9b91138e7906c6eb088fd9a66a"
|
||||
},
|
||||
"homepage": "https://carta.com"
|
||||
},
|
||||
@@ -458,7 +458,7 @@
|
||||
"url": "https://github.com/carta/plugins.git",
|
||||
"path": "plugins/carta-crm",
|
||||
"ref": "main",
|
||||
"sha": "b17fbfb0331e3903e5235b2fe21eb7a65c1bc394"
|
||||
"sha": "5e6c9d1cfa3bff9b91138e7906c6eb088fd9a66a"
|
||||
},
|
||||
"homepage": "https://carta.com"
|
||||
},
|
||||
@@ -474,7 +474,7 @@
|
||||
"url": "https://github.com/carta/plugins.git",
|
||||
"path": "plugins/carta-investors",
|
||||
"ref": "main",
|
||||
"sha": "b17fbfb0331e3903e5235b2fe21eb7a65c1bc394"
|
||||
"sha": "5e6c9d1cfa3bff9b91138e7906c6eb088fd9a66a"
|
||||
},
|
||||
"homepage": "https://carta.com"
|
||||
},
|
||||
@@ -490,7 +490,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/cap-js/mcp-server.git",
|
||||
"sha": "7d477ed55bbf3dd302a45d2adbd9072bcb512e87"
|
||||
"sha": "92dc99f5ba0c56957ed5d390484693a69ebd1206"
|
||||
},
|
||||
"homepage": "https://cap.cloud.sap/"
|
||||
},
|
||||
@@ -501,7 +501,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/ChromeDevTools/chrome-devtools-mcp.git",
|
||||
"sha": "8e8e83e3f8d150689ffb58c3b977eb72016c7b3f"
|
||||
"sha": "60be3e6bc157bd1121ea1d4b6ad59e37a73cac3e"
|
||||
},
|
||||
"homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp"
|
||||
},
|
||||
@@ -517,7 +517,7 @@
|
||||
"url": "https://github.com/circlefin/skills.git",
|
||||
"path": "plugins/circle",
|
||||
"ref": "master",
|
||||
"sha": "d076fe3ff992a1a9c30e2770031970b31429e905"
|
||||
"sha": "8ee9281f6e5ab737236ce969348adc463e6c2f79"
|
||||
},
|
||||
"homepage": "https://www.circle.com"
|
||||
},
|
||||
@@ -595,7 +595,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/ClickHouse/clickhouse-claude-code-plugin.git",
|
||||
"sha": "13a2df004af0df46661c9de2d4ef4e85eba2f040"
|
||||
"sha": "36889764f504cb92ab71ffe54b4c55488290ed7f"
|
||||
},
|
||||
"homepage": "https://github.com/ClickHouse/clickhouse-claude-code-plugin"
|
||||
},
|
||||
@@ -609,7 +609,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/ClickHouse/agent-skills.git",
|
||||
"sha": "67b45c5666b6999677ab3bbba4a27a7f532853af"
|
||||
"sha": "46ef08ccf32fa28587b64e0c79106ff437dc8fcb"
|
||||
},
|
||||
"homepage": "https://clickhouse.com"
|
||||
},
|
||||
@@ -623,7 +623,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/gemini-cli-extensions/cloud-sql-postgresql.git",
|
||||
"sha": "966f7b883998692d05389e4c3d3793412ca0659f"
|
||||
"sha": "5b9bc21c13324282e50183326709c533b49a97f3"
|
||||
},
|
||||
"homepage": "https://cloud.google.com/sql"
|
||||
},
|
||||
@@ -716,7 +716,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/CodSpeedHQ/codspeed.git",
|
||||
"sha": "4eac647797a5b836ef780d498e494c34f001ede2"
|
||||
"sha": "ecf3c2ebf959479126d631ad39d317738d559388"
|
||||
},
|
||||
"homepage": "https://codspeed.io"
|
||||
},
|
||||
@@ -742,18 +742,37 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "convex-backend",
|
||||
"description": "Convex backend skill for building reactive, type-safe, production-grade backends. Helps Claude design schemas, server functions, auth, file storage, scheduled jobs, and real-time multiplayer features on Convex.",
|
||||
"name": "convex",
|
||||
"displayName": "Convex",
|
||||
"description": "Official Convex plugin for Claude Code with bundled Convex skills, the convex-expert subagent for code-writing, a runtime-error monitor, and MCP access for backend development, schema design, real-time features, auth, file storage, scheduled jobs, and AI agents.",
|
||||
"author": {
|
||||
"name": "Convex"
|
||||
"name": "Convex",
|
||||
"url": "https://convex.dev"
|
||||
},
|
||||
"category": "development",
|
||||
"category": "database",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/get-convex/convex-backend-skill.git",
|
||||
"sha": "9acbc5495dd26749a5e6341dc2438146c4caa03b"
|
||||
"sha": "5e59870cda2a5892e18a7164d1a46fcf57b70bea"
|
||||
},
|
||||
"homepage": "https://convex.dev"
|
||||
"homepage": "https://github.com/get-convex/convex-backend-skill",
|
||||
"keywords": [
|
||||
"convex",
|
||||
"backend",
|
||||
"database",
|
||||
"realtime",
|
||||
"reactive",
|
||||
"websocket",
|
||||
"auth",
|
||||
"storage",
|
||||
"scheduler",
|
||||
"cron",
|
||||
"agent",
|
||||
"rag",
|
||||
"mobile",
|
||||
"typescript",
|
||||
"mcp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "crowdstrike-falcon-foundry",
|
||||
@@ -765,7 +784,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/CrowdStrike/foundry-skills.git",
|
||||
"sha": "4b517aa5729d5bb5e397ff779f98eb05c91d1b21"
|
||||
"sha": "99edea095f4e32ed008706b55257d0893fb93387"
|
||||
},
|
||||
"homepage": "https://github.com/CrowdStrike/foundry-skills"
|
||||
},
|
||||
@@ -811,7 +830,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/dash0hq/dash0-agent-plugin.git",
|
||||
"sha": "025a02ba35a7ecc72a8010aaae2e6152308224f4"
|
||||
"sha": "2909be7ebc2804af464e0d7f660ccc2b62d94623"
|
||||
},
|
||||
"homepage": "https://dash0.com/"
|
||||
},
|
||||
@@ -859,7 +878,7 @@
|
||||
"url": "https://github.com/awslabs/agent-plugins.git",
|
||||
"path": "plugins/databases-on-aws",
|
||||
"ref": "main",
|
||||
"sha": "95381e8bcb92f58a28edb4f83eb7e163c7461a0a"
|
||||
"sha": "5d982e8a5f1e0b06545adac69ff0348141587725"
|
||||
},
|
||||
"homepage": "https://github.com/awslabs/agent-plugins"
|
||||
},
|
||||
@@ -887,7 +906,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/datahub-project/datahub-skills.git",
|
||||
"sha": "f7c7c53648b71dc0841742781e108051d46fa360"
|
||||
"sha": "68585b1710601c8195eda1e7690218cc0a31d81d"
|
||||
},
|
||||
"homepage": "https://datahub.com"
|
||||
},
|
||||
@@ -901,7 +920,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/datarobot-oss/datarobot-agent-skills.git",
|
||||
"sha": "79bccc455df03d880a90d6076e4e5683b1f3288c"
|
||||
"sha": "8124faae2154117382b1046aa74d8901a3ffe930"
|
||||
},
|
||||
"homepage": "https://datarobot.com"
|
||||
},
|
||||
@@ -914,7 +933,7 @@
|
||||
"url": "https://github.com/microsoft/Dataverse-skills.git",
|
||||
"path": ".github/plugins/dataverse",
|
||||
"ref": "main",
|
||||
"sha": "5f186bf8ab1a3d6e242492d982276bbd7443ee0f"
|
||||
"sha": "ab906c960db0f2da83c2cb92a3fd162ccaba9cb9"
|
||||
},
|
||||
"homepage": "https://github.com/microsoft/Dataverse-skills"
|
||||
},
|
||||
@@ -927,7 +946,7 @@
|
||||
"url": "https://github.com/awslabs/agent-plugins.git",
|
||||
"path": "plugins/deploy-on-aws",
|
||||
"ref": "main",
|
||||
"sha": "95381e8bcb92f58a28edb4f83eb7e163c7461a0a"
|
||||
"sha": "5d982e8a5f1e0b06545adac69ff0348141587725"
|
||||
},
|
||||
"homepage": "https://github.com/awslabs/agent-plugins"
|
||||
},
|
||||
@@ -963,7 +982,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/dominodatalab/domino-claude-plugin.git",
|
||||
"sha": "3cc932f7a5a29ad6fab2a514df71513b1b0e0557"
|
||||
"sha": "47c6e0a7daa11b21eb6e12779c9d679569e8ffe2"
|
||||
},
|
||||
"homepage": "https://www.domino.ai"
|
||||
},
|
||||
@@ -1029,7 +1048,7 @@
|
||||
"url": "https://github.com/expo/skills.git",
|
||||
"path": "plugins/expo",
|
||||
"ref": "main",
|
||||
"sha": "434c935cfdce54e02b6164148e52cd151b2bc0c0"
|
||||
"sha": "510373b50956ef4dc84c20bb4c9cce70b618aa06"
|
||||
},
|
||||
"homepage": "https://github.com/expo/skills/blob/main/plugins/expo/README.md"
|
||||
},
|
||||
@@ -1045,7 +1064,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/fastly/fastly-agent-toolkit.git",
|
||||
"sha": "e0f4205723b843de0b07da4a2aea6c84a3bcb579"
|
||||
"sha": "6bd17d685a1b361a2b368bf0236f39efb1be62d6"
|
||||
},
|
||||
"homepage": "https://github.com/fastly/fastly-agent-toolkit/blob/main/README.md"
|
||||
},
|
||||
@@ -1066,7 +1085,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/voxel51/fiftyone-skills.git",
|
||||
"sha": "8b987ade2d04b85ea82c109f48d7234838b28b82"
|
||||
"sha": "6c002d680529e35a2e04adc34c03b564a3991728"
|
||||
},
|
||||
"homepage": "https://docs.voxel51.com/"
|
||||
},
|
||||
@@ -1095,7 +1114,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/firecrawl/firecrawl-claude-plugin.git",
|
||||
"sha": "48edd7943009eb4442a6f0102bbd0c251eecef3e"
|
||||
"sha": "01d11b30ace699a27f9ea7decf6ce6c9857f71ff"
|
||||
},
|
||||
"homepage": "https://github.com/firecrawl/firecrawl-claude-plugin.git"
|
||||
},
|
||||
@@ -1198,7 +1217,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/huggingface/skills.git",
|
||||
"sha": "5e3b4d2226d1beaa6a8a4df3739b6f68bd36521b"
|
||||
"sha": "7a493b09c81aae09a41bd2e1fa33dfc0f68acd75"
|
||||
},
|
||||
"homepage": "https://github.com/huggingface/skills.git"
|
||||
},
|
||||
@@ -1212,7 +1231,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/hunter-io/claude-plugin.git",
|
||||
"sha": "592cd27476935013d3652c2e2810f5267bd65a02"
|
||||
"sha": "c67942395cde155e9ad4ed8e3a137926f9992fb8"
|
||||
},
|
||||
"homepage": "https://hunter.io"
|
||||
},
|
||||
@@ -1226,7 +1245,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/heygen-com/hyperframes.git",
|
||||
"sha": "114b83bbf6bfece44480828acd14118d2854af8e"
|
||||
"sha": "7ea4d1c1314bd60d5273efa92626bd1d0f9c621d"
|
||||
},
|
||||
"homepage": "https://hyperframes.heygen.com"
|
||||
},
|
||||
@@ -1280,7 +1299,7 @@
|
||||
"source": "github",
|
||||
"repo": "jfrog/claude-plugin",
|
||||
"commit": "259c8e718266c16e99b4f30ae9b1ed0f9f00d98d",
|
||||
"sha": "2387bffa924a3cb8fd99f67b3bf09976d5f0c6b5"
|
||||
"sha": "8324c7fc9a5561398fe57b8a56db53bdbf1e2cda"
|
||||
},
|
||||
"homepage": "https://jfrog.com"
|
||||
},
|
||||
@@ -1391,7 +1410,7 @@
|
||||
"url": "https://github.com/pydantic/skills.git",
|
||||
"path": "plugins/logfire",
|
||||
"ref": "main",
|
||||
"sha": "a332dc8bd9215d2ee6deb2304af78cd71fba3bb2"
|
||||
"sha": "0c38c5bb5679f6cc41956bbbf811396a0d108ac9"
|
||||
},
|
||||
"homepage": "https://github.com/pydantic/skills/tree/main/plugins/logfire"
|
||||
},
|
||||
@@ -1504,7 +1523,7 @@
|
||||
"url": "https://github.com/mercadopago/mercadopago-claude-marketplace.git",
|
||||
"path": "plugins/mercadopago",
|
||||
"ref": "main",
|
||||
"sha": "63ff263c40e1eda642ae2038e87adaa5781f4939"
|
||||
"sha": "f52c138924d8035b39e8fe02d41c6712fc41ceb4"
|
||||
},
|
||||
"homepage": "https://github.com/mercadopago/mercadopago-claude-marketplace/tree/main/plugins/mercadopago"
|
||||
},
|
||||
@@ -1566,7 +1585,7 @@
|
||||
"url": "https://github.com/neondatabase/agent-skills.git",
|
||||
"path": "plugins/neon-postgres",
|
||||
"ref": "main",
|
||||
"sha": "f8281c1dbe55914b223ef15c7131d334435ed298"
|
||||
"sha": "bd9ec7ff273ce54bdd3ebe581d5b0802a3479618"
|
||||
},
|
||||
"homepage": "https://github.com/neondatabase/agent-skills/tree/main/plugins/neon-postgres"
|
||||
},
|
||||
@@ -1619,7 +1638,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/Nimbleway/agent-skills.git",
|
||||
"sha": "b3ab05d3c7c88857940c575e0f46752297b2249b"
|
||||
"sha": "95ed06468957ddc9de609b25c390b30c3864eac8"
|
||||
},
|
||||
"homepage": "https://docs.nimbleway.com/integrations/agent-skills/plugin-installation"
|
||||
},
|
||||
@@ -1662,7 +1681,7 @@
|
||||
"url": "https://github.com/growthxai/output.git",
|
||||
"path": "coding_assistants/claude/plugins/outputai",
|
||||
"ref": "main",
|
||||
"sha": "a45094aac1badfa9a3dba0b2cdccdd7a14cfdc45"
|
||||
"sha": "93dd22ee568a97911a332b5aa0d9cebb2b6f7da1"
|
||||
},
|
||||
"homepage": "https://output.ai"
|
||||
},
|
||||
@@ -1710,7 +1729,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/gopigment/ai-plugins.git",
|
||||
"sha": "ea85aea2ecf9ce761d32b8f6d32ffe0be503f7e1"
|
||||
"sha": "4bf16c80558416b9d69fa6531af8588fb2fcbe27"
|
||||
},
|
||||
"homepage": "https://www.pigment.com"
|
||||
},
|
||||
@@ -1721,7 +1740,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/pinecone-io/pinecone-claude-code-plugin.git",
|
||||
"sha": "53f52059f9ff9bb064f3dc9f299934e8773a642f"
|
||||
"sha": "9af99dc1dc10ce291ec67dc51d46199544a0cd4f"
|
||||
},
|
||||
"homepage": "https://github.com/pinecone-io/pinecone-claude-code-plugin"
|
||||
},
|
||||
@@ -1772,7 +1791,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/PostHog/ai-plugin.git",
|
||||
"sha": "ecc5244bb70e30532da9559b93740527e08761ca"
|
||||
"sha": "1b743cdbc568de81da5f41503e5c7caa35a4b270"
|
||||
},
|
||||
"homepage": "https://posthog.com/docs/model-context-protocol"
|
||||
},
|
||||
@@ -1827,7 +1846,7 @@
|
||||
"url": "https://github.com/pydantic/skills.git",
|
||||
"path": "plugins/ai",
|
||||
"ref": "main",
|
||||
"sha": "a332dc8bd9215d2ee6deb2304af78cd71fba3bb2"
|
||||
"sha": "0c38c5bb5679f6cc41956bbbf811396a0d108ac9"
|
||||
},
|
||||
"homepage": "https://github.com/pydantic/skills/tree/main/plugins/ai"
|
||||
},
|
||||
@@ -1865,7 +1884,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/qdrant/skills.git",
|
||||
"sha": "f108892268ea7518b528889f4604d5689f731747"
|
||||
"sha": "1390c811e03922b822dc9e12b832ba4dc82e0bf0"
|
||||
},
|
||||
"homepage": "https://skills.qdrant.tech"
|
||||
},
|
||||
@@ -1904,7 +1923,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/quarkusio/quarkus-agent-mcp.git",
|
||||
"sha": "d0925a0b761773f55fabdaf27d5dc9cf9232cfd2"
|
||||
"sha": "77fd36284a80b3ed1bde3d2fe48a0b2f99e4941e"
|
||||
},
|
||||
"homepage": "https://quarkus.io"
|
||||
},
|
||||
@@ -1917,7 +1936,7 @@
|
||||
"url": "https://github.com/railwayapp/railway-skills.git",
|
||||
"path": "plugins/railway",
|
||||
"ref": "main",
|
||||
"sha": "6ef46dde395e7e6f64179bbaa41bac420adca346"
|
||||
"sha": "7718b39037adb6fb33948ff751be7f7086f2da83"
|
||||
},
|
||||
"homepage": "https://docs.railway.com/ai/claude-code-plugin"
|
||||
},
|
||||
@@ -1940,7 +1959,7 @@
|
||||
"source": "url",
|
||||
"url": "https://github.com/RevenueCat/rc-claude-code-plugin.git",
|
||||
"path": "revenuecat",
|
||||
"sha": "407e4651ff74dbaf47c457948ab540e620403c2a"
|
||||
"sha": "81262a339601c4b64b909c370225cbd7917ade1f"
|
||||
},
|
||||
"homepage": "https://www.revenuecat.com"
|
||||
},
|
||||
@@ -1956,7 +1975,7 @@
|
||||
"url": "https://github.com/redis/agent-skills.git",
|
||||
"path": "plugins/redis-development",
|
||||
"ref": "main",
|
||||
"sha": "6edba11904bec94b0e2a35b220476ac53ad6df50"
|
||||
"sha": "18da4e42371f7eee0dcfafd8461effd41de351e9"
|
||||
},
|
||||
"homepage": "https://redis.io"
|
||||
},
|
||||
@@ -1966,7 +1985,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/Digital-Process-Tools/claude-remember.git",
|
||||
"sha": "aa55ba3f553e23f4d84387f5d7ece1ba0ce68d93"
|
||||
"sha": "c9b34417a8132f0416411a0ca51d009a256a3acc"
|
||||
},
|
||||
"homepage": "https://github.com/Digital-Process-Tools/claude-remember"
|
||||
},
|
||||
@@ -1992,7 +2011,7 @@
|
||||
"source": "url",
|
||||
"url": "https://github.com/RevenueCat/rc-claude-code-plugin.git",
|
||||
"path": "revenuecat",
|
||||
"sha": "407e4651ff74dbaf47c457948ab540e620403c2a"
|
||||
"sha": "81262a339601c4b64b909c370225cbd7917ade1f"
|
||||
},
|
||||
"homepage": "https://www.revenuecat.com"
|
||||
},
|
||||
@@ -2094,7 +2113,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/cap-js/mcp-server.git",
|
||||
"sha": "7d477ed55bbf3dd302a45d2adbd9072bcb512e87"
|
||||
"sha": "92dc99f5ba0c56957ed5d390484693a69ebd1206"
|
||||
},
|
||||
"homepage": "https://cap.cloud.sap/"
|
||||
},
|
||||
@@ -2112,7 +2131,7 @@
|
||||
"url": "https://github.com/SAP/open-ux-tools.git",
|
||||
"path": "packages/fiori-mcp-server",
|
||||
"ref": "main",
|
||||
"sha": "cb5a5b2cd1572828229f510ec11ba6ac4e631960"
|
||||
"sha": "d2a6fce818f3c046c5bbb041507be4632f926602"
|
||||
},
|
||||
"homepage": "https://github.com/SAP/open-ux-tools/tree/main/packages/fiori-mcp-server"
|
||||
},
|
||||
@@ -2144,7 +2163,7 @@
|
||||
"url": "https://github.com/spotify/save-to-spotify.git",
|
||||
"path": "plugin",
|
||||
"ref": "main",
|
||||
"sha": "af2f6faeb4139fd33a97aefcbadae17f792216e8"
|
||||
"sha": "35527660378c769bcbcfba89d8086d8b9fc4fccb"
|
||||
},
|
||||
"homepage": "https://github.com/spotify/save-to-spotify"
|
||||
},
|
||||
@@ -2179,7 +2198,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/getsentry/sentry-for-claude.git",
|
||||
"sha": "cf7efd373069d6fb073413324fe313319fb54ad9"
|
||||
"sha": "ed0875684192bb8a050297a896657ff9db1ffdf5"
|
||||
},
|
||||
"homepage": "https://github.com/getsentry/sentry-for-claude/tree/main"
|
||||
},
|
||||
@@ -2195,7 +2214,7 @@
|
||||
"url": "https://github.com/getsentry/cli.git",
|
||||
"path": "plugins/sentry-cli",
|
||||
"ref": "main",
|
||||
"sha": "1c97cbf6d8fb2ad2f76b22cfdb687b4d504abfd0"
|
||||
"sha": "d9bcd70eaa467fb3ddf591bfbfb0686fd1e9c016"
|
||||
},
|
||||
"homepage": "https://sentry.io"
|
||||
},
|
||||
@@ -2370,7 +2389,7 @@
|
||||
"source": "url",
|
||||
"url": "https://github.com/sumup/sumup-skills.git",
|
||||
"path": "providers/claude/plugin",
|
||||
"sha": "a4b5a9789e10e27fb375b68279bb0916074b8dd4"
|
||||
"sha": "715464b459def2d16e930e9ec8008f60e18a8b4d"
|
||||
},
|
||||
"homepage": "https://www.sumup.com/"
|
||||
},
|
||||
@@ -2381,7 +2400,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/supabase-community/supabase-plugin.git",
|
||||
"sha": "693a17a9970ba96e01afb9bef060d1dca48463ba"
|
||||
"sha": "1b910c021aee8c9c054196f0e840b3a65e1a7c63"
|
||||
},
|
||||
"homepage": "https://github.com/supabase-community/supabase-plugin"
|
||||
},
|
||||
@@ -2426,7 +2445,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/JetBrains/teamcity-cli.git",
|
||||
"sha": "af537a9f4db0f3b7367522a9e00e4af284c94941"
|
||||
"sha": "7f8419738b452108ff181365be30c1fab0a6905e"
|
||||
},
|
||||
"homepage": "https://www.jetbrains.com/teamcity/"
|
||||
},
|
||||
@@ -2457,7 +2476,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/togethercomputer/skills.git",
|
||||
"sha": "67a7e91ccd71b2989ed9921a03f79a86056d018c"
|
||||
"sha": "a1277729f7914d886df213de922865d30a214a9d"
|
||||
},
|
||||
"homepage": "https://www.together.ai"
|
||||
},
|
||||
@@ -2519,7 +2538,7 @@
|
||||
"url": "https://github.com/UI5/plugins-coding-agents.git",
|
||||
"path": "plugins/ui5",
|
||||
"ref": "main",
|
||||
"sha": "5eca5d066dc7d936e1bc978cc43438dca18b3013"
|
||||
"sha": "78f657e6a5004b5cdd1b998aabea616023eeabbb"
|
||||
},
|
||||
"homepage": "https://github.com/UI5/plugins-coding-agents"
|
||||
},
|
||||
@@ -2537,7 +2556,7 @@
|
||||
"url": "https://github.com/UI5/plugins-coding-agents.git",
|
||||
"path": "plugins/ui5-typescript-conversion",
|
||||
"ref": "main",
|
||||
"sha": "5eca5d066dc7d936e1bc978cc43438dca18b3013"
|
||||
"sha": "78f657e6a5004b5cdd1b998aabea616023eeabbb"
|
||||
},
|
||||
"homepage": "https://github.com/UI5/plugins-coding-agents"
|
||||
},
|
||||
@@ -2566,6 +2585,20 @@
|
||||
},
|
||||
"homepage": "https://github.com/vercel/vercel-plugin"
|
||||
},
|
||||
{
|
||||
"name": "vibe-prospecting",
|
||||
"description": "Vibe Prospecting connects Claude to live B2B company and contact data so users can search, match, enrich, filter, and export prospects at scale. It turns natural-language requests into structured GTM workflows for lead generation, CRM enrichment, company research, executive discovery, and multi-step prospecting automation inside Claude Cowork and Claude Code.",
|
||||
"author": {
|
||||
"name": "vibeprospecting.ai"
|
||||
},
|
||||
"category": "productivity",
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/explorium-ai/vibeprospecting-plugin.git",
|
||||
"sha": "ada4d569dbf70194fe18750ecbc5170e9a3f120a"
|
||||
},
|
||||
"homepage": "https://www.vibeprospecting.ai/product/claude-plugin"
|
||||
},
|
||||
{
|
||||
"name": "windsor-ai",
|
||||
"description": "Connect Claude Code to 325+ business data sources via Windsor.ai. Query marketing, sales, CRM, ecommerce, finance, and analytics data from Google Ads, Meta, HubSpot, Salesforce, Shopify, Stripe, and hundreds more — directly from your terminal.",
|
||||
@@ -2587,7 +2620,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/wix/skills.git",
|
||||
"sha": "5d22db3370c198db8db959b52d1e66cabbb5f202"
|
||||
"sha": "5da7e749a466ef9ddcdb2822099b940b9a1bc151"
|
||||
},
|
||||
"homepage": "https://dev.wix.com/docs/wix-cli/guides/development/about-wix-skills"
|
||||
},
|
||||
@@ -2666,7 +2699,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/zoom/zoom-plugin.git",
|
||||
"sha": "88f6ca3529c2dca7a38db24359ecf6fd15a23379"
|
||||
"sha": "1f86a61604c39f853df901767059256250191c43"
|
||||
},
|
||||
"homepage": "https://developers.zoom.us/"
|
||||
},
|
||||
@@ -2694,7 +2727,7 @@
|
||||
"source": {
|
||||
"source": "url",
|
||||
"url": "https://github.com/zscaler/zscaler-mcp-server.git",
|
||||
"sha": "bc56b110199294de58e6a9abf0569c49bd948670"
|
||||
"sha": "8409e1661b7f7171bfbb9297e1ecfc61c28b6d92"
|
||||
},
|
||||
"homepage": "https://github.com/zscaler/zscaler-mcp-server"
|
||||
}
|
||||
|
||||
163
.github/workflows/scan-plugins.yml
vendored
163
.github/workflows/scan-plugins.yml
vendored
@@ -381,3 +381,166 @@ jobs:
|
||||
echo "::error::Scan step failed without a parseable policy verdict (likely an infra error)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# emit-verdict: post a sticky comment per entry to the bump PR with the
|
||||
# structured verdict, so downstream tooling (label automation, delist
|
||||
# authoring) can read verdicts directly instead of scraping job logs.
|
||||
# Sticky comment marker: `<!-- bump-pr-verdict:<name> -->`.
|
||||
#
|
||||
# Mirrors the schema_v1 contract from
|
||||
# anthropics/claude-plugins-community-internal#3908 so the triage scripts
|
||||
# in mcp-local-directory/scripts/triage/ work uniformly across both repos.
|
||||
# -official doesn't run per-entry static checks (zombie, schema, binaries,
|
||||
# etc.) so the `scan.*` axes are emitted as "skipped". The granular policy
|
||||
# booleans (`has_broad_scope_hooks`, `has_undisclosed_telemetry`,
|
||||
# `description_matches_behavior`) aren't surfaced by this workflow's
|
||||
# per-entry artifact yet, so they're emitted as null; the triage
|
||||
# `triage_bool_to_str` helper maps null → "?" so display is graceful.
|
||||
# Status describes the execution state, not the outcome — `ran` when the
|
||||
# scan action evaluated this SHA fresh, `cached` when a prior verdict was
|
||||
# reused (cf. run-verdicts.json's `source` field). Outcome lives in
|
||||
# `policy.passes`. policy-sweep.sh dispatches on this exact vocabulary.
|
||||
#
|
||||
# PR resolution: pull_request events carry the PR number directly. The
|
||||
# bump workflow creates bump PRs via GITHUB_TOKEN (which doesn't fire
|
||||
# pull_request triggers — recursion guard) and dispatches this scan via
|
||||
# workflow_dispatch on the bump branch. In that case we look up the
|
||||
# open PR by head ref. No PR (scan_all dispatch on main, etc.) → no-op.
|
||||
#
|
||||
# continue-on-error at the job level: emit failure must NOT block the
|
||||
# `scan` required check. Consumers fall back to log-scraping if the
|
||||
# comment is absent (gradual migration; no flag day).
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
emit-verdict:
|
||||
needs: [scan]
|
||||
if: always() && needs.scan.result != 'skipped' && needs.scan.result != 'cancelled'
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Download scan verdicts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: scan-verdicts
|
||||
path: /tmp/scan-verdicts
|
||||
continue-on-error: true
|
||||
|
||||
- name: Resolve PR number for this ref
|
||||
id: pr
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_FROM_EVENT: ${{ github.event.pull_request.number }}
|
||||
REF: ${{ github.ref_name }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "$EVENT_NAME" == "pull_request" && -n "$PR_FROM_EVENT" ]]; then
|
||||
echo "number=$PR_FROM_EVENT" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
# workflow_dispatch on the bump branch: find the open PR for it.
|
||||
# head filter takes the form owner:branch.
|
||||
owner="${REPO%%/*}"
|
||||
pr=$(gh api "/repos/${REPO}/pulls?state=open&head=${owner}:${REF}&per_page=1" \
|
||||
--jq '.[0].number // ""')
|
||||
if [[ -z "$pr" ]]; then
|
||||
echo "::notice::No open PR for ref ${REF} — sticky comments skipped (verdicts still in scan-verdicts artifact)"
|
||||
fi
|
||||
echo "number=$pr" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build and post sticky comments
|
||||
if: steps.pr.outputs.number != ''
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR: ${{ steps.pr.outputs.number }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
verdicts_path=/tmp/scan-verdicts/run-verdicts.json
|
||||
# Missing/empty artifact: scan job ran but didn't produce verdicts
|
||||
# (e.g. the relevance gate said "no changes"). Nothing to comment;
|
||||
# exit clean.
|
||||
if [[ ! -s "$verdicts_path" ]]; then
|
||||
echo "::notice::No run-verdicts.json artifact — nothing to emit"
|
||||
exit 0
|
||||
fi
|
||||
count=$(jq 'length' "$verdicts_path")
|
||||
if [[ "$count" == "0" ]]; then
|
||||
echo "::notice::run-verdicts.json is empty — nothing to emit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
ran_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||
|
||||
# scan.* axes: -official doesn't run per-entry static checks; emit
|
||||
# "skipped" for each so the schema is shape-compatible with -internal.
|
||||
scan_stub='{"clone":"skipped","subpath_missing":"skipped","schema":"skipped","zombie":"skipped","tool_allowlist":"skipped","binaries":"skipped","unique":"skipped","mcp":"skipped"}'
|
||||
|
||||
# Pre-fetch all PR comments once (paginated) for the marker lookup.
|
||||
gh api --paginate "/repos/$REPO/issues/$PR/comments" \
|
||||
--jq '.[] | {id, body}' > /tmp/comments.ndjson
|
||||
|
||||
jq -c '.[]' "$verdicts_path" | while read -r entry; do
|
||||
name=$(jq -r '.name' <<< "$entry")
|
||||
passes=$(jq -r '.passes' <<< "$entry")
|
||||
summary=$(jq -r '.summary // ""' <<< "$entry")
|
||||
violations=$(jq -r '.violations // ""' <<< "$entry")
|
||||
source=$(jq -r '.source // "scan"' <<< "$entry")
|
||||
|
||||
# status = execution state (cf. -internal#3908 vocabulary).
|
||||
# Outcome is in `passes`. Map source → status: scan-action-run
|
||||
# → "ran"; cache-served → "cached". Anything else falls through
|
||||
# as "ran" (only those two values appear in run-verdicts.json).
|
||||
case "$source" in
|
||||
cache) status="cached" ;;
|
||||
scan) status="ran" ;;
|
||||
*) status="ran" ;;
|
||||
esac
|
||||
|
||||
policy=$(jq -n \
|
||||
--argjson passes "$passes" \
|
||||
--arg summary "$summary" \
|
||||
--arg violations "$violations" \
|
||||
--arg source "$source" \
|
||||
--arg status "$status" \
|
||||
'{passes: $passes,
|
||||
has_broad_scope_hooks: null,
|
||||
has_undisclosed_telemetry: null,
|
||||
description_matches_behavior: null,
|
||||
summary: $summary,
|
||||
violations: $violations,
|
||||
source: $source,
|
||||
status: $status}')
|
||||
|
||||
verdict=$(jq -n \
|
||||
--argjson scan "$scan_stub" \
|
||||
--argjson policy "$policy" \
|
||||
--arg ran_at "$ran_at" \
|
||||
--arg run_id "$RUN_ID" \
|
||||
'{schema_version: 1, ran_at: $ran_at, run_id: $run_id, scan: $scan, policy: $policy}')
|
||||
|
||||
marker="<!-- bump-pr-verdict:$name -->"
|
||||
body=$(printf '%s\n```json\n%s\n```' "$marker" "$verdict")
|
||||
|
||||
# jq's first() short-circuits and avoids SIGPIPE under pipefail if
|
||||
# duplicate markers exist (shouldn't, but a prior buggy run could
|
||||
# double-post). -s slurps NDJSON; `// empty` yields no output when
|
||||
# no match.
|
||||
existing=$(jq -rs --arg m "$marker" \
|
||||
'first(.[] | select(.body | startswith($m)) | .id) // empty' \
|
||||
/tmp/comments.ndjson)
|
||||
|
||||
if [[ -n "$existing" ]]; then
|
||||
gh api -X PATCH "/repos/$REPO/issues/comments/$existing" -f body="$body" >/dev/null
|
||||
echo "Updated comment $existing for $name"
|
||||
else
|
||||
gh api -X POST "/repos/$REPO/issues/$PR/comments" -f body="$body" >/dev/null
|
||||
echo "Created comment for $name"
|
||||
fi
|
||||
done
|
||||
|
||||
38
.github/workflows/validate-licenses.yml
vendored
Normal file
38
.github/workflows/validate-licenses.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Validate Plugin Licenses
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'plugins/**'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
validate-licenses:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check every plugin has an Apache 2.0 LICENSE file
|
||||
run: |
|
||||
set -euo pipefail
|
||||
missing=()
|
||||
for plugin_dir in plugins/*/; do
|
||||
plugin="${plugin_dir%/}"
|
||||
if [[ ! -f "$plugin/LICENSE" ]]; then
|
||||
missing+=("$plugin")
|
||||
fi
|
||||
done
|
||||
if [[ "${#missing[@]}" -gt 0 ]]; then
|
||||
echo "::error::The following plugins are missing a LICENSE file:"
|
||||
for p in "${missing[@]}"; do
|
||||
echo " - $p"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
echo "All $(ls -d plugins/*/ | wc -l) plugins have a LICENSE file."
|
||||
202
LICENSE
Normal file
202
LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
31
README.md
31
README.md
@@ -42,6 +42,37 @@ plugin-name/
|
||||
└── README.md # Documentation
|
||||
```
|
||||
|
||||
## Skill-bundle plugins
|
||||
|
||||
When a plugin's source repository ships skills (`SKILL.md` files) without a `.claude-plugin/plugin.json` manifest, the marketplace entry can declare the skills directly using `strict: false` and an explicit `skills` array.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "example-bundle",
|
||||
"description": "Brief description of the bundled skills.",
|
||||
"author": { "name": "Author Name" },
|
||||
"category": "development",
|
||||
"source": {
|
||||
"source": "git-subdir",
|
||||
"url": "https://github.com/example-org/sdk.git",
|
||||
"path": "packages/agent-skills",
|
||||
"ref": "main",
|
||||
"sha": "<commit sha>"
|
||||
},
|
||||
"strict": false,
|
||||
"skills": [
|
||||
"./skill-a",
|
||||
"./skill-b",
|
||||
"./skill-c"
|
||||
],
|
||||
"homepage": "https://github.com/example-org/sdk"
|
||||
}
|
||||
```
|
||||
|
||||
Each path in `skills` is relative to `source.path` and points at a directory containing a `SKILL.md`. Paths can reach deeper than a single level — for example, `["./libA/skill-1", "./libB/skill-2"]` exposes a curated subset across multiple library subdirectories. Each skill is registered as `<plugin-name>:<skill-name>` in Claude Code.
|
||||
|
||||
For the underlying schema, see [Strict mode](https://code.claude.com/docs/en/plugin-marketplaces) in the marketplace documentation.
|
||||
|
||||
## License
|
||||
|
||||
Please see each linked plugin for the relevant LICENSE file.
|
||||
|
||||
@@ -39,7 +39,7 @@ ls -la package.json pyproject.toml Cargo.toml go.mod pom.xml 2>/dev/null
|
||||
cat package.json 2>/dev/null | head -50
|
||||
|
||||
# Check dependencies for MCP server recommendations
|
||||
cat package.json 2>/dev/null | grep -E '"(react|vue|angular|next|express|fastapi|django|prisma|supabase|stripe)"'
|
||||
cat package.json 2>/dev/null | grep -E '"(react|vue|angular|next|express|fastapi|django|prisma|supabase|convex|stripe)"'
|
||||
|
||||
# Check for existing Claude Code config
|
||||
ls -la .claude/ CLAUDE.md 2>/dev/null
|
||||
@@ -55,7 +55,7 @@ ls -la src/ app/ lib/ tests/ components/ pages/ api/ 2>/dev/null
|
||||
| Language/Framework | package.json, pyproject.toml, import patterns | Hooks, MCP servers |
|
||||
| Frontend stack | React, Vue, Angular, Next.js | Playwright MCP, frontend skills |
|
||||
| Backend stack | Express, FastAPI, Django | API documentation tools |
|
||||
| Database | Prisma, Supabase, raw SQL | Database MCP servers |
|
||||
| Database | Prisma, Supabase, Convex, raw SQL | Database / backend MCP servers |
|
||||
| External APIs | Stripe, OpenAI, AWS SDKs | context7 MCP for docs |
|
||||
| Testing | Jest, pytest, Playwright configs | Testing hooks, subagents |
|
||||
| CI/CD | GitHub Actions, CircleCI | GitHub MCP server |
|
||||
@@ -75,6 +75,7 @@ See [references/mcp-servers.md](references/mcp-servers.md) for detailed patterns
|
||||
| Uses popular libraries (React, Express, etc.) | **context7** - Live documentation lookup |
|
||||
| Frontend with UI testing needs | **Playwright** - Browser automation/testing |
|
||||
| Uses Supabase | **Supabase MCP** - Direct database operations |
|
||||
| Uses Convex | **Convex MCP** - Live deployment introspection, run queries/mutations, manage env vars and logs |
|
||||
| PostgreSQL/MySQL database | **Database MCP** - Query and schema tools |
|
||||
| GitHub repository | **GitHub MCP** - Issues, PRs, actions |
|
||||
| Uses Linear for issues | **Linear MCP** - Issue management |
|
||||
|
||||
@@ -72,6 +72,18 @@ MCP (Model Context Protocol) servers extend Claude's capabilities by connecting
|
||||
|
||||
**Value**: Claude can query tables, manage auth, and interact with Supabase storage directly.
|
||||
|
||||
### Convex MCP
|
||||
**Best for**: Projects using Convex as the backend (reactive database + server functions + auth + storage + scheduling, all on one platform)
|
||||
|
||||
| Recommend When | Examples |
|
||||
|----------------|----------|
|
||||
| Convex project detected | `convex` in deps, `convex/` directory present, `convex.json` at repo root |
|
||||
| Real-time / reactive UI | `useQuery` / `useMutation` / `useAction` from `convex/react` |
|
||||
| Mobile + Convex | `convex/react-native` in deps |
|
||||
| AI / chat / agent features on Convex | `@convex-dev/agent` in deps |
|
||||
|
||||
**Value**: Claude can introspect the live deployment (tables, function specs, env vars, logs) and execute queries/mutations against it via tools like `tables`, `function-spec`, `data`, `run-once-query`, `logs`, `env list/set/get`. Run via `npx convex mcp start`.
|
||||
|
||||
### PostgreSQL MCP
|
||||
**Best for**: Direct PostgreSQL database access
|
||||
|
||||
@@ -253,6 +265,7 @@ MCP (Model Context Protocol) servers extend Claude's capabilities by connecting
|
||||
| Popular npm packages | context7 |
|
||||
| React/Vue/Next.js | Playwright MCP |
|
||||
| `@supabase/supabase-js` | Supabase MCP |
|
||||
| `convex` in deps, `convex/` directory, or `convex.json` | Convex MCP |
|
||||
| `pg` or `postgres` | PostgreSQL MCP |
|
||||
| GitHub remote | GitHub MCP |
|
||||
| `.linear` or Linear refs | Linear MCP |
|
||||
|
||||
@@ -28,8 +28,12 @@ NOOP_SYSTEM = 0 # claude_agent_sdk already importable in system python
|
||||
NOOP_VENV = 1 # venv already built and SDK imports from it
|
||||
BUILT = 2 # venv created + SDK pip-installed this run
|
||||
BUILD_FAILED = 3 # venv create or pip install raised/timed out
|
||||
SKIP_WIN32 = 4 # Windows; consumer glob doesn't handle Lib/ layout
|
||||
# Outcome 4 was previously SKIP_WIN32; retired now that the consumer glob in
|
||||
# llm.py also matches Windows venv layout (Lib/site-packages). Don't reuse the
|
||||
# value — telemetry rows from older plugin builds still emit 4.
|
||||
SKIP_SENTINEL = 5 # another SessionStart is currently building
|
||||
HOOK_PY_INCOMPATIBLE = 6 # hook interpreter is <3.10 — SDK syntax can't load
|
||||
# here no matter how the venv was built. See #2071.
|
||||
|
||||
|
||||
def _sdk_on_syspath() -> bool:
|
||||
@@ -60,12 +64,28 @@ def main() -> tuple[int, str, str]:
|
||||
err_phase / err_kind are non-empty only on BUILD_FAILED — they let
|
||||
telemetry split bootstrap failures by root cause.
|
||||
"""
|
||||
# Windows venv layout (Lib/site-packages, no python* subdir) isn't
|
||||
# handled by the consumer's glob in security_reminder_hook.py; skip the
|
||||
# bootstrap entirely rather than build a venv that's never read.
|
||||
if sys.platform == "win32":
|
||||
return SKIP_WIN32, "", ""
|
||||
|
||||
# Honesty check (fixes the misleading NOOP_VENV in #2071): the SDK
|
||||
# requires Python >=3.10 and uses 3.10+ syntax (match statements,
|
||||
# PEP 604 unions). On a 3.9 hook interpreter we CANNOT import it no
|
||||
# matter how the venv was built — llm.py runs in this same interpreter
|
||||
# and the syntax-level import will SyntaxError. macOS ships 3.9.6 as
|
||||
# the default `python3` and `/usr/bin` precedes Homebrew in PATH, so
|
||||
# this case is the default state for a large share of macOS users.
|
||||
#
|
||||
# sg-python.sh now prefers python3.10+ binaries so most users won't
|
||||
# reach this branch; the fallback to 3.9 is preserved for the
|
||||
# pattern-warning hooks that don't need the SDK. Reporting
|
||||
# HOOK_PY_INCOMPATIBLE here:
|
||||
# (a) avoids 30-60s of wasted pip install,
|
||||
# (b) avoids the lie where the venv_py probe says NOOP_VENV but the
|
||||
# consumer import fails, and
|
||||
# (c) gives telemetry a clean bucket to size the affected fleet.
|
||||
if sys.version_info < (3, 10):
|
||||
return (
|
||||
HOOK_PY_INCOMPATIBLE,
|
||||
"hook_py",
|
||||
f"py_{sys.version_info[0]}.{sys.version_info[1]}",
|
||||
)
|
||||
|
||||
if _sdk_on_syspath():
|
||||
return NOOP_SYSTEM, "", ""
|
||||
@@ -75,7 +95,11 @@ def main() -> tuple[int, str, str]:
|
||||
or os.path.expanduser("~/.claude/security")
|
||||
)
|
||||
venv = state_dir / "agent-sdk-venv"
|
||||
venv_py = venv / "bin" / "python"
|
||||
# Windows venvs put the interpreter at Scripts\python.exe; POSIX uses bin/python.
|
||||
if sys.platform == "win32":
|
||||
venv_py = venv / "Scripts" / "python.exe"
|
||||
else:
|
||||
venv_py = venv / "bin" / "python"
|
||||
|
||||
# Another SessionStart (concurrent CC instance, same plugin) may already
|
||||
# be building. The sentinel lives NEXT TO the venv, not inside it —
|
||||
@@ -125,10 +149,20 @@ def main() -> tuple[int, str, str]:
|
||||
# the user's machine, pip's own default registry applies — that's the same
|
||||
# exposure the user would have running `pip install` themselves, so
|
||||
# we're not widening the supply-chain surface.
|
||||
#
|
||||
# --prefer-binary: on ARM64 Windows, pip's default resolver picks a
|
||||
# `cryptography` version with no published binary wheel and tries to
|
||||
# build from source, which needs Rust/Cargo (almost never present
|
||||
# on user machines). The build fails and the whole bootstrap returns
|
||||
# BUILD_FAILED. A binary wheel exists on PyPI for an adjacent
|
||||
# version (`cryptography-46.0.3-cp311-abi3-win_arm64.whl`);
|
||||
# --prefer-binary tells pip to pick it. Cross-platform safe: no-op
|
||||
# on platforms where the latest version already has a wheel.
|
||||
err_phase = "pip"
|
||||
subprocess.run(
|
||||
[str(venv_py), "-m", "pip", "install", "--quiet",
|
||||
"--disable-pip-version-check", "claude-agent-sdk"],
|
||||
"--disable-pip-version-check", "--prefer-binary",
|
||||
"claude-agent-sdk"],
|
||||
capture_output=True, timeout=120, check=True,
|
||||
)
|
||||
return BUILT, "", ""
|
||||
@@ -186,6 +220,56 @@ def main() -> tuple[int, str, str]:
|
||||
sentinel.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def _maybe_emit_user_notice(outcome: int, pv: int) -> str | None:
|
||||
"""Return a one-time user-visible notice when the agentic reviewer is
|
||||
in a persistent broken state on this machine, or None if we've already
|
||||
shown the notice for this plugin version (or shouldn't show one).
|
||||
|
||||
The marker file is plugin-version-keyed: a future plugin update can
|
||||
re-notify if behavior changes (e.g. we ship out-of-process SDK in v3
|
||||
and want to tell affected users it's fixed). Failures to write the
|
||||
marker degrade to "skip the notice this session" so we don't spam
|
||||
every SessionStart on a read-only home dir.
|
||||
|
||||
Currently only HOOK_PY_INCOMPATIBLE qualifies. BUILD_FAILED is
|
||||
intentionally excluded — it covers transient causes (network failure,
|
||||
pip registry hiccup, in-flight rebuild) where the next session may
|
||||
succeed and a permanent notice would mislead.
|
||||
"""
|
||||
if outcome != HOOK_PY_INCOMPATIBLE:
|
||||
return None
|
||||
try:
|
||||
state_dir = Path(
|
||||
os.environ.get("SECURITY_WARNINGS_STATE_DIR")
|
||||
or os.path.expanduser("~/.claude/security")
|
||||
)
|
||||
marker = state_dir / f".agentic_unavailable_notice_v{pv or 0}"
|
||||
if marker.exists():
|
||||
return None
|
||||
state_dir.mkdir(parents=True, exist_ok=True)
|
||||
# Write timestamp + Python version so the marker is self-documenting
|
||||
# if a user goes looking. O_EXCL would be racier with no real win
|
||||
# (two concurrent SessionStarts both showing the notice once is fine).
|
||||
marker.write_text(
|
||||
f"{time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())} "
|
||||
f"py={sys.version_info[0]}.{sys.version_info[1]}\n"
|
||||
)
|
||||
except OSError:
|
||||
return None
|
||||
return (
|
||||
f"⚠ security-guidance plugin: the cross-file commit reviewer "
|
||||
f"(layer 3 of 3 — catches IDOR, auth-bypass, cross-file SSRF) "
|
||||
f"is unavailable in this environment. It requires Python ≥3.10, "
|
||||
f"but the hook is running on "
|
||||
f"{sys.version_info[0]}.{sys.version_info[1]}.\n\n"
|
||||
f"Pattern checks and the single-shot LLM diff review are still "
|
||||
f"active. To enable the deeper reviewer, install Python 3.10+ "
|
||||
f"(e.g. `brew install python` on macOS) and restart Claude Code.\n\n"
|
||||
f"This notice is shown once per plugin version. "
|
||||
f"See: github.com/anthropics/claude-plugins-official/issues/2071"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Tell the harness this is async — venv create + pip install can take
|
||||
# 30-60s on a cold cache, well past the default sync hook timeout.
|
||||
@@ -222,4 +306,18 @@ if __name__ == "__main__":
|
||||
pv = _plugin_version_int()
|
||||
if pv:
|
||||
metrics["pv"] = pv
|
||||
print(json.dumps({"metrics": metrics}), flush=True)
|
||||
response: dict[str, object] = {"metrics": metrics}
|
||||
# One-time user-visible notice when the agentic reviewer is dead on
|
||||
# arrival. Uses hookSpecificOutput.additionalContext (SessionStart's
|
||||
# supported channel for surfacing text to both the model and the user)
|
||||
# plus systemMessage as a belt-and-suspenders. Marker-file-gated so
|
||||
# this fires exactly once per plugin version per install — see
|
||||
# _maybe_emit_user_notice.
|
||||
notice = _maybe_emit_user_notice(outcome, pv)
|
||||
if notice:
|
||||
response["hookSpecificOutput"] = {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": notice,
|
||||
}
|
||||
response["systemMessage"] = notice
|
||||
print(json.dumps(response), flush=True)
|
||||
|
||||
@@ -31,6 +31,67 @@ from _base import debug_log, _record_usage, _PV, PROVENANCE_TAG # noqa: F401
|
||||
from session_state import with_locked_state
|
||||
|
||||
|
||||
def _inject_agent_sdk_venv_into_syspath(state_dir):
|
||||
"""Prepend the agent-SDK venv's site-packages to sys.path so the SDK
|
||||
import below picks it up when the user's system Python doesn't have it.
|
||||
|
||||
Called from two fallback sites (3P SDK + agentic_review); shared here so
|
||||
Windows pywin32 handling stays in one place.
|
||||
|
||||
Returns True if any path was added.
|
||||
|
||||
POSIX venv layout: `agent-sdk-venv/lib/pythonX.Y/site-packages`
|
||||
Windows venv layout: `agent-sdk-venv/Lib/site-packages` (capital L, no
|
||||
pythonX.Y subdir). The SDK transitively imports pywin32 on Windows, and
|
||||
pywin32's `.pth` files (which add `win32/`, `win32/lib/` to sys.path and
|
||||
register the DLL search dir via `pywin32_bootstrap.py`) are processed
|
||||
ONLY by Python's `site.py` at interpreter startup — not when we manually
|
||||
insert a path here. Without the bootstrap, the SDK's
|
||||
`mcp.client.stdio → mcp.os.win32.utilities → pywintypes` import chain
|
||||
fails with `ModuleNotFoundError: pywintypes` and the agentic reviewer
|
||||
falls back to single-shot silently. Replicate what site.py would do.
|
||||
"""
|
||||
venv_root = os.path.join(state_dir, "agent-sdk-venv")
|
||||
candidates = (
|
||||
glob.glob(os.path.join(venv_root, "lib", "python*", "site-packages"))
|
||||
+ glob.glob(os.path.join(venv_root, "Lib", "site-packages"))
|
||||
)
|
||||
added = False
|
||||
for sp in candidates:
|
||||
if not os.path.isdir(sp) or sp in sys.path:
|
||||
continue
|
||||
sys.path.insert(0, sp)
|
||||
added = True
|
||||
if sys.platform == "win32":
|
||||
_bootstrap_pywin32(sp)
|
||||
return added
|
||||
|
||||
|
||||
def _bootstrap_pywin32(site_packages_dir):
|
||||
"""Manually replicate the pywin32 `.pth` bootstrap so a venv added via
|
||||
`sys.path.insert()` (not site.py) can still import `pywintypes`. No-op
|
||||
when the venv doesn't include pywin32. Failures are swallowed — the
|
||||
SDK import below will raise its own ImportError and the caller's
|
||||
fallback path handles it cleanly."""
|
||||
try:
|
||||
win32 = os.path.join(site_packages_dir, "win32")
|
||||
win32_lib = os.path.join(win32, "lib")
|
||||
for d in (win32, win32_lib):
|
||||
if os.path.isdir(d) and d not in sys.path:
|
||||
sys.path.insert(0, d)
|
||||
bootstrap = os.path.join(win32_lib, "pywin32_bootstrap.py")
|
||||
if os.path.isfile(bootstrap):
|
||||
import importlib.util
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"pywin32_bootstrap", bootstrap,
|
||||
)
|
||||
if spec and spec.loader:
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
except Exception as e:
|
||||
debug_log(f"pywin32 bootstrap failed (may break SDK import on Windows): {e}")
|
||||
|
||||
|
||||
# Plan Security Check Configuration
|
||||
ANTHROPIC_API_KEY = os.environ.get("ANTHROPIC_API_KEY", "")
|
||||
# OAuth access token — Claude Code passes this for /login users.
|
||||
@@ -298,12 +359,7 @@ def _call_claude_via_sdk(prompt, output_schema, *, max_tokens=16000, model=None)
|
||||
"SECURITY_WARNINGS_STATE_DIR",
|
||||
os.path.expanduser("~/.claude/security"),
|
||||
)
|
||||
for _sp in glob.glob(
|
||||
os.path.join(_state_dir, "agent-sdk-venv", "lib",
|
||||
"python*", "site-packages")
|
||||
):
|
||||
if os.path.isdir(_sp) and _sp not in sys.path:
|
||||
sys.path.insert(0, _sp)
|
||||
_inject_agent_sdk_venv_into_syspath(_state_dir)
|
||||
try:
|
||||
import asyncio as _asyncio # noqa: F811
|
||||
from claude_agent_sdk import ( # noqa: F401,F811
|
||||
@@ -1089,18 +1145,11 @@ def agentic_review(
|
||||
# ~/.claude/security/ with the SDK installed; try that as a fallback
|
||||
# before giving up. The system import is attempted first so users
|
||||
# who DO have it never touch the venv.
|
||||
_venv_tried = False
|
||||
_state_dir = os.environ.get(
|
||||
"SECURITY_WARNINGS_STATE_DIR",
|
||||
os.path.expanduser("~/.claude/security"),
|
||||
)
|
||||
for _sp in glob.glob(
|
||||
os.path.join(_state_dir, "agent-sdk-venv", "lib",
|
||||
"python*", "site-packages")
|
||||
):
|
||||
if os.path.isdir(_sp) and _sp not in sys.path:
|
||||
sys.path.insert(0, _sp)
|
||||
_venv_tried = True
|
||||
_venv_tried = _inject_agent_sdk_venv_into_syspath(_state_dir)
|
||||
try:
|
||||
import asyncio as _asyncio # noqa: F811
|
||||
|
||||
|
||||
@@ -22,23 +22,90 @@
|
||||
# "${CLAUDE_PLUGIN_ROOT}/hooks/security_reminder_hook.py"
|
||||
set -e
|
||||
|
||||
# Git Bash / MSYS on Windows hands script paths to this shim in POSIX form
|
||||
# (`/c/Users/...`). When we exec a Windows `python.exe` (which we do on
|
||||
# Windows since `python3` is the Microsoft Store stub), python interprets the
|
||||
# leading `/` as the root of the current drive — e.g. `/c/Users/...` becomes
|
||||
# `C:\c\Users\...` or `D:\c\Users\...` (whichever drive the shell is on),
|
||||
# fails with ENOENT, and every Edit/Write/MultiEdit tool use blocks until the
|
||||
# session restarts. See anthropics/claude-plugins-official#2043.
|
||||
#
|
||||
# Fix: convert absolute path args to native Windows form via `cygpath -w`
|
||||
# before exec. `cygpath` is a Git Bash builtin; it's absent on macOS/Linux,
|
||||
# where the `command -v` guard makes this a no-op. `cygpath -w` is idempotent
|
||||
# for already-Windows paths so the rare mixed-form case is safe.
|
||||
if command -v cygpath >/dev/null 2>&1; then
|
||||
converted=()
|
||||
for a in "$@"; do
|
||||
case "$a" in
|
||||
/*) converted+=("$(cygpath -w "$a")") ;;
|
||||
*) converted+=("$a") ;;
|
||||
esac
|
||||
done
|
||||
set -- "${converted[@]}"
|
||||
fi
|
||||
|
||||
probe() {
|
||||
# $1..N: the interpreter command (may be multi-word like `py -3`)
|
||||
# Probe writes the major version to stdout and exits 0 iff it's >=3.
|
||||
"$@" -c 'import sys; print(sys.version_info[0])' 2>/dev/null
|
||||
# Writes "<major>.<minor>" to stdout and exits 0 iff at least Python 3.
|
||||
"$@" -c 'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")' 2>/dev/null
|
||||
}
|
||||
|
||||
# True iff arg is a "M.m" version string >= 3.10. claude_agent_sdk requires
|
||||
# Python >= 3.10; below that, pip install fails ("No matching distribution")
|
||||
# and the LLM-powered review (Stop / commit / push) silently no-ops while
|
||||
# pattern checks (PostToolUse regex) keep working. macOS ships 3.9.6 as the
|
||||
# default `python3` on current versions, so this guard matters in practice.
|
||||
# See anthropics/claude-plugins-official#2071.
|
||||
is_sdk_compatible() {
|
||||
case "$1" in
|
||||
3.1[0-9]|3.[2-9][0-9]|[4-9].*|[1-9][0-9].*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Pass 1 — try minor-versioned binaries in descending order. These are only
|
||||
# present if the user explicitly installed them (Homebrew / python.org / pyenv),
|
||||
# so picking one here always upgrades over the system `python3`. Highest
|
||||
# available wins; the user doesn't have to PATH-prefer it.
|
||||
for cmd in "python3.13" "python3.12" "python3.11" "python3.10"; do
|
||||
v=$(probe "$cmd") || continue
|
||||
if is_sdk_compatible "$v"; then
|
||||
exec "$cmd" "$@"
|
||||
fi
|
||||
done
|
||||
|
||||
# Pass 2 — bare interpreters, but only if SDK-compatible. Covers Linux distros
|
||||
# that ship 3.10+ as the default `python3`, and Windows where `python` /
|
||||
# `py -3` resolves to the user's python.org install.
|
||||
for cmd in "python3" "python" "py -3"; do
|
||||
# Word-split intentionally so `py -3` works
|
||||
# shellcheck disable=SC2086
|
||||
v=$(probe $cmd) || continue
|
||||
if [ "$v" = "3" ]; then
|
||||
if is_sdk_compatible "$v"; then
|
||||
# shellcheck disable=SC2086
|
||||
exec $cmd "$@"
|
||||
fi
|
||||
done
|
||||
|
||||
# Pass 3 — fallback to any Python 3, even <3.10. Pattern-based checks
|
||||
# (PostToolUse regex on Edit/Write) only need 3.6+ and are useful on their
|
||||
# own; the SDK-dependent paths will detect the version mismatch and degrade
|
||||
# inside the Python code. Without this fallback, the entire plugin would
|
||||
# stop working on default macOS, which is a regression vs today.
|
||||
for cmd in "python3" "python" "py -3"; do
|
||||
# shellcheck disable=SC2086
|
||||
v=$(probe $cmd) || continue
|
||||
# Accept anything that successfully reported a "M.m" string.
|
||||
case "$v" in
|
||||
[0-9]*.[0-9]*)
|
||||
# shellcheck disable=SC2086
|
||||
exec $cmd "$@"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "security-guidance: no working Python 3 interpreter found." >&2
|
||||
echo " tried: python3, python, py -3" >&2
|
||||
echo " tried: python3.13, python3.12, python3.11, python3.10, python3, python, py -3" >&2
|
||||
echo " on Windows, install Python from https://python.org (NOT the Microsoft Store)" >&2
|
||||
echo " on macOS, install Python 3.10+ via Homebrew (\`brew install python\`)" >&2
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user