Compare commits

...

5 Commits

Author SHA1 Message Date
tobin
242a3d0175 Refresh AWS plugins: add amplify/databases/sagemaker, remove migration
Adds three plugins from awslabs/agent-plugins:
- aws-amplify (development)
- databases-on-aws (database)
- sagemaker-ai (development)

Removes migration-to-aws (deprecated by the AWS team).
2026-04-16 23:21:03 +00:00
Dickson Tsai
de39da5ba2 Point supabase plugin to supabase-community/supabase-plugin (#1442)
Remove the in-repo supabase stub; source from the external repo.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-16 21:01:47 +01:00
Bryan Thompson
cb8c857a5e Normalize git-subdir source URLs to full HTTPS format (#1422)
Standardize 12 git-subdir plugin entries from owner/repo shorthand to
full https://github.com/owner/repo.git URLs for consistency with the
existing HTTPS entries.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:01:08 +01:00
Daisy S. Hollman
48aa435178 fix(discord): use cached author.id when DMChannel.recipientId is null (#1365)
DMChannel.recipientId can be null when client.channels.fetch() returns
a DM channel with a cold cache. The inbound gate correctly uses
msg.author.id, but fetchAllowedChannel relied on recipientId, so
replies to allowlisted DMs intermittently failed with "channel not
allowlisted" after session restart.

Maintain a channelId→userId map populated during inbound handling and
fall back to it when recipientId is null.

Fixes anthropics/claude-code#40576
Fixes anthropics/claude-code#41647

🏠 Remote-Dev: homespace
2026-04-14 14:46:42 -07:00
Noah Zweben
7e401edac7 fix(telegram): retry polling on all transient errors, not just 409 (#1397)
A single ETIMEDOUT/ECONNRESET/DNS failure during long-polling rejected
bot.start(); the catch block returned and polling stopped permanently.
The MCP server process stayed alive (stdin keeps it running), so outbound
reply/react tools kept working — but the bot was deaf to inbound messages
until a full restart. Users see 'typing...' then nothing, indistinguishable
from the harness-side gate bug.

Now all errors retry with the same capped backoff (max 15s). attempt resets
to 0 in onStart so backoff doesn't accumulate across a long-running session.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-14 12:47:13 -07:00
6 changed files with 82 additions and 64 deletions

View File

@@ -44,7 +44,7 @@
"description": "AI-first project auditor and re-engineer based on the 9 design principles and 7 design patterns from the TechWolf AI-First Bootcamp", "description": "AI-first project auditor and re-engineer based on the 9 design principles and 7 design patterns from the TechWolf AI-First Bootcamp",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "techwolf-ai/ai-first-toolkit", "url": "https://github.com/techwolf-ai/ai-first-toolkit.git",
"path": "plugins/ai-firstify", "path": "plugins/ai-firstify",
"ref": "main", "ref": "main",
"sha": "7f18e11d694b9ae62ea3009fbbc175f08ae913df" "sha": "7f18e11d694b9ae62ea3009fbbc175f08ae913df"
@@ -156,6 +156,18 @@
"source": "./external_plugins/autofix-bot", "source": "./external_plugins/autofix-bot",
"homepage": "https://github.com/anthropics/claude-plugins-public/tree/main/external_plugins/autofix-bot" "homepage": "https://github.com/anthropics/claude-plugins-public/tree/main/external_plugins/autofix-bot"
}, },
{
"name": "aws-amplify",
"description": "Build full-stack apps with AWS Amplify Gen 2 using guided workflows for authentication, data models, storage, GraphQL APIs, and Lambda functions.",
"category": "development",
"source": {
"source": "git-subdir",
"url": "https://github.com/awslabs/agent-plugins.git",
"path": "plugins/aws-amplify",
"ref": "main"
},
"homepage": "https://github.com/awslabs/agent-plugins"
},
{ {
"name": "aws-serverless", "name": "aws-serverless",
"description": "Design, build, deploy, test, and debug serverless applications with AWS Serverless services.", "description": "Design, build, deploy, test, and debug serverless applications with AWS Serverless services.",
@@ -209,7 +221,7 @@
"category": "database", "category": "database",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "Bigdata-com/bigdata-plugins-marketplace", "url": "https://github.com/Bigdata-com/bigdata-plugins-marketplace.git",
"path": "plugins/bigdata-com", "path": "plugins/bigdata-com",
"ref": "main" "ref": "main"
}, },
@@ -446,6 +458,18 @@
}, },
"homepage": "https://github.com/astronomer/agents" "homepage": "https://github.com/astronomer/agents"
}, },
{
"name": "databases-on-aws",
"description": "Expert database guidance for the AWS database portfolio. Design schemas, execute queries, handle migrations, and choose the right database for your workload.",
"category": "database",
"source": {
"source": "git-subdir",
"url": "https://github.com/awslabs/agent-plugins.git",
"path": "plugins/databases-on-aws",
"ref": "main"
},
"homepage": "https://github.com/awslabs/agent-plugins"
},
{ {
"name": "dataverse", "name": "dataverse",
"description": "Agent skills for building on, analyzing, and managing Microsoft Dataverse — with Dataverse MCP, PAC CLI, and Python SDK.", "description": "Agent skills for building on, analyzing, and managing Microsoft Dataverse — with Dataverse MCP, PAC CLI, and Python SDK.",
@@ -503,7 +527,7 @@
"category": "development", "category": "development",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "expo/skills", "url": "https://github.com/expo/skills.git",
"path": "plugins/expo", "path": "plugins/expo",
"ref": "main" "ref": "main"
}, },
@@ -670,7 +694,7 @@
"description": "Build on Solana with Helius — live blockchain tools, expert coding patterns, and autonomous account signup", "description": "Build on Solana with Helius — live blockchain tools, expert coding patterns, and autonomous account signup",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "helius-labs/core-ai", "url": "https://github.com/helius-labs/core-ai.git",
"path": "helius-plugin", "path": "helius-plugin",
"ref": "main", "ref": "main",
"sha": "05ea4d1128d46618266bbcc23a5e7019c57be0d6" "sha": "05ea4d1128d46618266bbcc23a5e7019c57be0d6"
@@ -785,7 +809,7 @@
"category": "productivity", "category": "productivity",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "legalzoom/claude-plugins", "url": "https://github.com/legalzoom/claude-plugins.git",
"path": "plugins/legalzoom", "path": "plugins/legalzoom",
"ref": "main", "ref": "main",
"sha": "f9fd8a0ca6e1421bc1aacb113a109663a7a6f6d8" "sha": "f9fd8a0ca6e1421bc1aacb113a109663a7a6f6d8"
@@ -851,18 +875,6 @@
}, },
"homepage": "https://github.com/microsoftdocs/mcp" "homepage": "https://github.com/microsoftdocs/mcp"
}, },
{
"name": "migration-to-aws",
"description": "Assess current cloud provider usage and billing to estimate and compare AWS services and pricing, with recommendations for migration or continued use of current provider.",
"category": "migration",
"source": {
"source": "git-subdir",
"url": "https://github.com/awslabs/agent-plugins.git",
"path": "plugins/migration-to-aws",
"ref": "main"
},
"homepage": "https://github.com/awslabs/agent-plugins"
},
{ {
"name": "mintlify", "name": "mintlify",
"description": "Build beautiful documentation sites with Mintlify. Convert non-markdown files into properly formatted MDX pages, add and modify content with correct component use, and automate documentation updates.", "description": "Build beautiful documentation sites with Mintlify. Convert non-markdown files into properly formatted MDX pages, add and modify content with correct component use, and automate documentation updates.",
@@ -891,7 +903,7 @@
"category": "database", "category": "database",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "neondatabase/agent-skills", "url": "https://github.com/neondatabase/agent-skills.git",
"path": "plugins/neon-postgres", "path": "plugins/neon-postgres",
"ref": "main", "ref": "main",
"sha": "54d7a9db2ddd476f84d5d1fd7bac323907858a8b" "sha": "54d7a9db2ddd476f84d5d1fd7bac323907858a8b"
@@ -1109,7 +1121,7 @@
"category": "development", "category": "development",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "pydantic/skills", "url": "https://github.com/pydantic/skills.git",
"path": "plugins/ai", "path": "plugins/ai",
"ref": "main" "ref": "main"
}, },
@@ -1155,7 +1167,7 @@
"category": "deployment", "category": "deployment",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "railwayapp/railway-skills", "url": "https://github.com/railwayapp/railway-skills.git",
"path": "plugins/railway", "path": "plugins/railway",
"ref": "main", "ref": "main",
"sha": "d52f3741a6a33a3191d6138eb3d6c3355cb970d1" "sha": "d52f3741a6a33a3191d6138eb3d6c3355cb970d1"
@@ -1249,6 +1261,18 @@
} }
} }
}, },
{
"name": "sagemaker-ai",
"description": "Build, train, and deploy AI models with deep AWS AI/ML expertise brought directly into your coding assistants, covering the surface area of Amazon SageMaker AI.",
"category": "development",
"source": {
"source": "git-subdir",
"url": "https://github.com/awslabs/agent-plugins.git",
"path": "plugins/sagemaker-ai",
"ref": "main"
},
"homepage": "https://github.com/awslabs/agent-plugins"
},
{ {
"name": "sanity", "name": "sanity",
"description": "Sanity content platform integration with MCP server, agent skills, and slash commands. Query and author content, build and optimize GROQ queries, design schemas, and set up Visual Editing.", "description": "Sanity content platform integration with MCP server, agent skills, and slash commands. Query and author content, build and optimize GROQ queries, design schemas, and set up Visual Editing.",
@@ -1448,7 +1472,7 @@
"category": "development", "category": "development",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "stripe/ai", "url": "https://github.com/stripe/ai.git",
"path": "providers/claude/plugin", "path": "providers/claude/plugin",
"ref": "main" "ref": "main"
}, },
@@ -1469,8 +1493,11 @@
"name": "supabase", "name": "supabase",
"description": "Supabase MCP integration for database operations, authentication, storage, and real-time subscriptions. Manage your Supabase projects, run SQL queries, and interact with your backend directly.", "description": "Supabase MCP integration for database operations, authentication, storage, and real-time subscriptions. Manage your Supabase projects, run SQL queries, and interact with your backend directly.",
"category": "database", "category": "database",
"source": "./external_plugins/supabase", "source": {
"homepage": "https://github.com/anthropics/claude-plugins-public/tree/main/external_plugins/supabase" "source": "url",
"url": "https://github.com/supabase-community/supabase-plugin.git"
},
"homepage": "https://github.com/supabase-community/supabase-plugin"
}, },
{ {
"name": "superpowers", "name": "superpowers",
@@ -1555,7 +1582,7 @@
"category": "development", "category": "development",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "UI5/plugins-claude", "url": "https://github.com/UI5/plugins-claude.git",
"path": "plugins/ui5", "path": "plugins/ui5",
"ref": "main", "ref": "main",
"sha": "5070dfc1cef711d6efad40beb43750027039d71f" "sha": "5070dfc1cef711d6efad40beb43750027039d71f"
@@ -1568,7 +1595,7 @@
"category": "development", "category": "development",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "UI5/plugins-claude", "url": "https://github.com/UI5/plugins-claude.git",
"path": "plugins/ui5-typescript-conversion", "path": "plugins/ui5-typescript-conversion",
"ref": "main", "ref": "main",
"sha": "5070dfc1cef711d6efad40beb43750027039d71f" "sha": "5070dfc1cef711d6efad40beb43750027039d71f"
@@ -1622,7 +1649,7 @@
"category": "productivity", "category": "productivity",
"source": { "source": {
"source": "git-subdir", "source": "git-subdir",
"url": "zapier/zapier-mcp", "url": "https://github.com/zapier/zapier-mcp.git",
"path": "plugins/zapier", "path": "plugins/zapier",
"ref": "main", "ref": "main",
"sha": "b93007e9a726c6ee93c57a949e732744ef5acbfd" "sha": "b93007e9a726c6ee93c57a949e732744ef5acbfd"

View File

@@ -222,6 +222,8 @@ type GateResult =
const recentSentIds = new Set<string>() const recentSentIds = new Set<string>()
const RECENT_SENT_CAP = 200 const RECENT_SENT_CAP = 200
const dmChannelUsers = new Map<string, string>()
function noteSent(id: string): void { function noteSent(id: string): void {
recentSentIds.add(id) recentSentIds.add(id)
if (recentSentIds.size > RECENT_SENT_CAP) { if (recentSentIds.size > RECENT_SENT_CAP) {
@@ -404,7 +406,8 @@ async function fetchAllowedChannel(id: string) {
const ch = await fetchTextChannel(id) const ch = await fetchTextChannel(id)
const access = loadAccess() const access = loadAccess()
if (ch.type === ChannelType.DM) { if (ch.type === ChannelType.DM) {
if (access.allowFrom.includes(ch.recipientId)) return ch const userId = ch.recipientId ?? dmChannelUsers.get(id)
if (userId && access.allowFrom.includes(userId)) return ch
} else { } else {
const key = ch.isThread() ? ch.parentId ?? ch.id : ch.id const key = ch.isThread() ? ch.parentId ?? ch.id : ch.id
if (key in access.groups) return ch if (key in access.groups) return ch
@@ -823,6 +826,10 @@ async function handleInbound(msg: Message): Promise<void> {
const chat_id = msg.channelId const chat_id = msg.channelId
if (msg.channel.type === ChannelType.DM) {
dmChannelUsers.set(chat_id, msg.author.id)
}
// Permission-reply intercept: if this looks like "yes xxxxx" for a // Permission-reply intercept: if this looks like "yes xxxxx" for a
// pending permission request, emit the structured event instead of // pending permission request, emit the structured event instead of
// relaying as chat. The sender is already gate()-approved at this point // relaying as chat. The sender is already gate()-approved at this point

View File

@@ -1,7 +0,0 @@
{
"name": "supabase",
"description": "Supabase MCP integration for database operations, authentication, storage, and real-time subscriptions. Manage your Supabase projects, run SQL queries, and interact with your backend directly.",
"author": {
"name": "Supabase"
}
}

View File

@@ -1,6 +0,0 @@
{
"supabase": {
"type": "http",
"url": "https://mcp.supabase.com/mcp"
}
}

View File

@@ -1,7 +1,7 @@
{ {
"name": "telegram", "name": "telegram",
"description": "Telegram channel for Claude Code \u2014 messaging bridge with built-in access control. Manage pairing, allowlists, and policy via /telegram:access.", "description": "Telegram channel for Claude Code \u2014 messaging bridge with built-in access control. Manage pairing, allowlists, and policy via /telegram:access.",
"version": "0.0.5", "version": "0.0.6",
"keywords": [ "keywords": [
"telegram", "telegram",
"messaging", "messaging",

View File

@@ -985,14 +985,17 @@ bot.catch(err => {
process.stderr.write(`telegram channel: handler error (polling continues): ${err.error}\n`) process.stderr.write(`telegram channel: handler error (polling continues): ${err.error}\n`)
}) })
// 409 Conflict = another getUpdates consumer is still active (zombie from a // Retry polling with backoff on any error. Previously only 409 was retried —
// previous session, or a second Claude Code instance). Retry with backoff // a single ETIMEDOUT/ECONNRESET/DNS failure rejected bot.start(), the catch
// until the slot frees up instead of crashing on the first rejection. // returned, and polling stopped permanently while the process stayed alive
// (MCP stdin keeps it running). Outbound tools kept working but the bot was
// deaf to inbound messages until a full restart.
void (async () => { void (async () => {
for (let attempt = 1; ; attempt++) { for (let attempt = 1; ; attempt++) {
try { try {
await bot.start({ await bot.start({
onStart: info => { onStart: info => {
attempt = 0
botUsername = info.username botUsername = info.username
process.stderr.write(`telegram channel: polling as @${info.username}\n`) process.stderr.write(`telegram channel: polling as @${info.username}\n`)
void bot.api.setMyCommands( void bot.api.setMyCommands(
@@ -1008,8 +1011,10 @@ void (async () => {
return // bot.stop() was called — clean exit from the loop return // bot.stop() was called — clean exit from the loop
} catch (err) { } catch (err) {
if (shuttingDown) return if (shuttingDown) return
if (err instanceof GrammyError && err.error_code === 409) { // bot.stop() mid-setup rejects with grammy's "Aborted delay" — expected, not an error.
if (attempt >= 8) { if (err instanceof Error && err.message === 'Aborted delay') return
const is409 = err instanceof GrammyError && err.error_code === 409
if (is409 && attempt >= 8) {
process.stderr.write( process.stderr.write(
`telegram channel: 409 Conflict persists after ${attempt} attempts — ` + `telegram channel: 409 Conflict persists after ${attempt} attempts — ` +
`another poller is holding the bot token (stray 'bun server.ts' process or a second session). Exiting.\n`, `another poller is holding the bot token (stray 'bun server.ts' process or a second session). Exiting.\n`,
@@ -1017,19 +1022,11 @@ void (async () => {
return return
} }
const delay = Math.min(1000 * attempt, 15000) const delay = Math.min(1000 * attempt, 15000)
const detail = attempt === 1 const detail = is409
? ' — another instance is polling (zombie session, or a second Claude Code running?)' ? `409 Conflict${attempt === 1 ? ' — another instance is polling (zombie session, or a second Claude Code running?)' : ''}`
: '' : `polling error: ${err}`
process.stderr.write( process.stderr.write(`telegram channel: ${detail}, retrying in ${delay / 1000}s\n`)
`telegram channel: 409 Conflict${detail}, retrying in ${delay / 1000}s\n`,
)
await new Promise(r => setTimeout(r, delay)) await new Promise(r => setTimeout(r, delay))
continue
}
// bot.stop() mid-setup rejects with grammy's "Aborted delay" — expected, not an error.
if (err instanceof Error && err.message === 'Aborted delay') return
process.stderr.write(`telegram channel: polling failed: ${err}\n`)
return
} }
} }
})() })()