[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7181P9DX9ZS6F3SEVRFMD32":3,"skill-same:01M7181P9DX9ZS6F3SEVRFMD32":60},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":34,"linkOnly":35,"markdownContent":36,"markdownBody":37,"frontMatter":38,"refName":40,"commitSha":41,"skillDirectory":42,"forksCount":14,"repositoryHtmlUrl":43,"repositoryHomepageUrl":6,"ownerHtmlUrl":44,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":45,"install":46,"resources":59},"01M7181P9DX9ZS6F3SEVRFMD32","azure-web-pubsub-ts",null,"Real-time messaging with WebSocket connections and pub\u002Fsub patterns.","sapsapshen\u002Fai-memory-router","sapsapshen","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F20347959?v=4","01M6XDQEF1DP50DKF37H81J3J5","shenmian","01M6XDQEJPE41Y3DT2763X8ZJN",0,"MIT","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fglobal\u002Fazure-web-pubsub-ts\u002FSKILL.md",[],[19,20,21,22,23,24,25,26,27,28,29,30,31,32,33],"azure","azure web pubsub ts","web","pubsub","azure web pubsub","community","messaging","websocket","real-time","time","connections","unknown","with","2026","patterns","2026-11-10 10:12:30",false,"---\nname: azure-web-pubsub-ts\ndescription: \"Real-time messaging with WebSocket connections and pub\u002Fsub patterns.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# Azure Web PubSub SDKs for TypeScript\n\nReal-time messaging with WebSocket connections and pub\u002Fsub patterns.\n\n## Installation\n\n```bash\n# Server-side management\nnpm install @azure\u002Fweb-pubsub @azure\u002Fidentity\n\n# Client-side real-time messaging\nnpm install @azure\u002Fweb-pubsub-client\n\n# Express middleware for event handlers\nnpm install @azure\u002Fweb-pubsub-express\n```\n\n## Environment Variables\n\n```bash\nWEBPUBSUB_CONNECTION_STRING=Endpoint=https:\u002F\u002F\u003Cresource>.webpubsub.azure.com;AccessKey=\u003Ckey>;Version=1.0;\nWEBPUBSUB_ENDPOINT=https:\u002F\u002F\u003Cresource>.webpubsub.azure.com\n```\n\n## Server-Side: WebPubSubServiceClient\n\n### Authentication\n\n```typescript\nimport { WebPubSubServiceClient, AzureKeyCredential } from \"@azure\u002Fweb-pubsub\";\nimport { DefaultAzureCredential } from \"@azure\u002Fidentity\";\n\n\u002F\u002F Connection string\nconst client = new WebPubSubServiceClient(\n  process.env.WEBPUBSUB_CONNECTION_STRING!,\n  \"chat\"  \u002F\u002F hub name\n);\n\n\u002F\u002F DefaultAzureCredential (recommended)\nconst client2 = new WebPubSubServiceClient(\n  process.env.WEBPUBSUB_ENDPOINT!,\n  new DefaultAzureCredential(),\n  \"chat\"\n);\n\n\u002F\u002F AzureKeyCredential\nconst client3 = new WebPubSubServiceClient(\n  process.env.WEBPUBSUB_ENDPOINT!,\n  new AzureKeyCredential(\"\u003Caccess-key>\"),\n  \"chat\"\n);\n```\n\n### Generate Client Access Token\n\n```typescript\n\u002F\u002F Basic token\nconst token = await client.getClientAccessToken();\nconsole.log(token.url);  \u002F\u002F wss:\u002F\u002F...?access_token=...\n\n\u002F\u002F Token with user ID\nconst userToken = await client.getClientAccessToken({\n  userId: \"user123\",\n});\n\n\u002F\u002F Token with permissions\nconst permToken = await client.getClientAccessToken({\n  userId: \"user123\",\n  roles: [\n    \"webpubsub.joinLeaveGroup\",\n    \"webpubsub.sendToGroup\",\n    \"webpubsub.sendToGroup.chat-room\",  \u002F\u002F specific group\n  ],\n  groups: [\"chat-room\"],  \u002F\u002F auto-join on connect\n  expirationTimeInMinutes: 60,\n});\n```\n\n### Send Messages\n\n```typescript\n\u002F\u002F Broadcast to all connections in hub\nawait client.sendToAll({ message: \"Hello everyone!\" });\nawait client.sendToAll(\"Plain text\", { contentType: \"text\u002Fplain\" });\n\n\u002F\u002F Send to specific user (all their connections)\nawait client.sendToUser(\"user123\", { message: \"Hello!\" });\n\n\u002F\u002F Send to specific connection\nawait client.sendToConnection(\"connectionId\", { data: \"Direct message\" });\n\n\u002F\u002F Send with filter (OData syntax)\nawait client.sendToAll({ message: \"Filtered\" }, {\n  filter: \"userId ne 'admin'\",\n});\n```\n\n### Group Management\n\n```typescript\nconst group = client.group(\"chat-room\");\n\n\u002F\u002F Add user\u002Fconnection to group\nawait group.addUser(\"user123\");\nawait group.addConnection(\"connectionId\");\n\n\u002F\u002F Remove from group\nawait group.removeUser(\"user123\");\n\n\u002F\u002F Send to group\nawait group.sendToAll({ message: \"Group message\" });\n\n\u002F\u002F Close all connections in group\nawait group.closeAllConnections({ reason: \"Maintenance\" });\n```\n\n### Connection Management\n\n```typescript\n\u002F\u002F Check existence\nconst userExists = await client.userExists(\"user123\");\nconst connExists = await client.connectionExists(\"connectionId\");\n\n\u002F\u002F Close connections\nawait client.closeConnection(\"connectionId\", { reason: \"Kicked\" });\nawait client.closeUserConnections(\"user123\");\nawait client.closeAllConnections();\n\n\u002F\u002F Permissions\nawait client.grantPermission(\"connectionId\", \"sendToGroup\", { targetName: \"chat\" });\nawait client.revokePermission(\"connectionId\", \"sendToGroup\", { targetName: \"chat\" });\n```\n\n## Client-Side: WebPubSubClient\n\n### Connect\n\n```typescript\nimport { WebPubSubClient } from \"@azure\u002Fweb-pubsub-client\";\n\n\u002F\u002F Direct URL\nconst client = new WebPubSubClient(\"\u003Cclient-access-url>\");\n\n\u002F\u002F Dynamic URL from negotiate endpoint\nconst client2 = new WebPubSubClient({\n  getClientAccessUrl: async () => {\n    const response = await fetch(\"\u002Fnegotiate\");\n    const { url } = await response.json();\n    return url;\n  },\n});\n\n\u002F\u002F Register handlers BEFORE starting\nclient.on(\"connected\", (e) => {\n  console.log(`Connected: ${e.connectionId}`);\n});\n\nclient.on(\"group-message\", (e) => {\n  console.log(`${e.message.group}: ${e.message.data}`);\n});\n\nawait client.start();\n```\n\n### Send Messages\n\n```typescript\n\u002F\u002F Join group first\nawait client.joinGroup(\"chat-room\");\n\n\u002F\u002F Send to group\nawait client.sendToGroup(\"chat-room\", \"Hello!\", \"text\");\nawait client.sendToGroup(\"chat-room\", { type: \"message\", content: \"Hi\" }, \"json\");\n\n\u002F\u002F Send options\nawait client.sendToGroup(\"chat-room\", \"Hello\", \"text\", {\n  noEcho: true,        \u002F\u002F Don't echo back to sender\n  fireAndForget: true, \u002F\u002F Don't wait for ack\n});\n\n\u002F\u002F Send event to server\nawait client.sendEvent(\"userAction\", { action: \"typing\" }, \"json\");\n```\n\n### Event Handlers\n\n```typescript\n\u002F\u002F Connection lifecycle\nclient.on(\"connected\", (e) => {\n  console.log(`Connected: ${e.connectionId}, User: ${e.userId}`);\n});\n\nclient.on(\"disconnected\", (e) => {\n  console.log(`Disconnected: ${e.message}`);\n});\n\nclient.on(\"stopped\", () => {\n  console.log(\"Client stopped\");\n});\n\n\u002F\u002F Messages\nclient.on(\"group-message\", (e) => {\n  console.log(`[${e.message.group}] ${e.message.fromUserId}: ${e.message.data}`);\n});\n\nclient.on(\"server-message\", (e) => {\n  console.log(`Server: ${e.message.data}`);\n});\n\n\u002F\u002F Rejoin failure\nclient.on(\"rejoin-group-failed\", (e) => {\n  console.log(`Failed to rejoin ${e.group}: ${e.error}`);\n});\n```\n\n## Express Event Handler\n\n```typescript\nimport express from \"express\";\nimport { WebPubSubEventHandler } from \"@azure\u002Fweb-pubsub-express\";\n\nconst app = express();\n\nconst handler = new WebPubSubEventHandler(\"chat\", {\n  path: \"\u002Fapi\u002Fwebpubsub\u002Fhubs\u002Fchat\u002F\",\n  \n  \u002F\u002F Blocking: approve\u002Freject connection\n  handleConnect: (req, res) => {\n    if (!req.claims?.sub) {\n      res.fail(401, \"Authentication required\");\n      return;\n    }\n    res.success({\n      userId: req.claims.sub[0],\n      groups: [\"general\"],\n      roles: [\"webpubsub.sendToGroup\"],\n    });\n  },\n  \n  \u002F\u002F Blocking: handle custom events\n  handleUserEvent: (req, res) => {\n    console.log(`Event from ${req.context.userId}:`, req.data);\n    res.success(`Received: ${req.data}`, \"text\");\n  },\n  \n  \u002F\u002F Non-blocking\n  onConnected: (req) => {\n    console.log(`Client connected: ${req.context.connectionId}`);\n  },\n  \n  onDisconnected: (req) => {\n    console.log(`Client disconnected: ${req.context.connectionId}`);\n  },\n});\n\napp.use(handler.getMiddleware());\n\n\u002F\u002F Negotiate endpoint\napp.get(\"\u002Fnegotiate\", async (req, res) => {\n  const token = await serviceClient.getClientAccessToken({\n    userId: req.user?.id,\n  });\n  res.json({ url: token.url });\n});\n\napp.listen(8080);\n```\n\n## Key Types\n\n```typescript\n\u002F\u002F Server\nimport {\n  WebPubSubServiceClient,\n  WebPubSubGroup,\n  GenerateClientTokenOptions,\n  HubSendToAllOptions,\n} from \"@azure\u002Fweb-pubsub\";\n\n\u002F\u002F Client\nimport {\n  WebPubSubClient,\n  WebPubSubClientOptions,\n  OnConnectedArgs,\n  OnGroupDataMessageArgs,\n} from \"@azure\u002Fweb-pubsub-client\";\n\n\u002F\u002F Express\nimport {\n  WebPubSubEventHandler,\n  ConnectRequest,\n  UserEventRequest,\n  ConnectResponseHandler,\n} from \"@azure\u002Fweb-pubsub-express\";\n```\n\n## Best Practices\n\n1. **Use Entra ID auth** - `DefaultAzureCredential` for production\n2. **Register handlers before start** - Don't miss initial events\n3. **Use groups for channels** - Organize messages by topic\u002Froom\n4. **Handle reconnection** - Client auto-reconnects by default\n5. **Validate in handleConnect** - Reject unauthorized connections early\n6. **Use noEcho** - Prevent message echo back to sender when needed\n\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n","# Azure Web PubSub SDKs for TypeScript\n\nReal-time messaging with WebSocket connections and pub\u002Fsub patterns.\n\n## Installation\n\n```bash\n# Server-side management\nnpm install @azure\u002Fweb-pubsub @azure\u002Fidentity\n\n# Client-side real-time messaging\nnpm install @azure\u002Fweb-pubsub-client\n\n# Express middleware for event handlers\nnpm install @azure\u002Fweb-pubsub-express\n```\n\n## Environment Variables\n\n```bash\nWEBPUBSUB_CONNECTION_STRING=Endpoint=https:\u002F\u002F\u003Cresource>.webpubsub.azure.com;AccessKey=\u003Ckey>;Version=1.0;\nWEBPUBSUB_ENDPOINT=https:\u002F\u002F\u003Cresource>.webpubsub.azure.com\n```\n\n## Server-Side: WebPubSubServiceClient\n\n### Authentication\n\n```typescript\nimport { WebPubSubServiceClient, AzureKeyCredential } from \"@azure\u002Fweb-pubsub\";\nimport { DefaultAzureCredential } from \"@azure\u002Fidentity\";\n\n\u002F\u002F Connection string\nconst client = new WebPubSubServiceClient(\n  process.env.WEBPUBSUB_CONNECTION_STRING!,\n  \"chat\"  \u002F\u002F hub name\n);\n\n\u002F\u002F DefaultAzureCredential (recommended)\nconst client2 = new WebPubSubServiceClient(\n  process.env.WEBPUBSUB_ENDPOINT!,\n  new DefaultAzureCredential(),\n  \"chat\"\n);\n\n\u002F\u002F AzureKeyCredential\nconst client3 = new WebPubSubServiceClient(\n  process.env.WEBPUBSUB_ENDPOINT!,\n  new AzureKeyCredential(\"\u003Caccess-key>\"),\n  \"chat\"\n);\n```\n\n### Generate Client Access Token\n\n```typescript\n\u002F\u002F Basic token\nconst token = await client.getClientAccessToken();\nconsole.log(token.url);  \u002F\u002F wss:\u002F\u002F...?access_token=...\n\n\u002F\u002F Token with user ID\nconst userToken = await client.getClientAccessToken({\n  userId: \"user123\",\n});\n\n\u002F\u002F Token with permissions\nconst permToken = await client.getClientAccessToken({\n  userId: \"user123\",\n  roles: [\n    \"webpubsub.joinLeaveGroup\",\n    \"webpubsub.sendToGroup\",\n    \"webpubsub.sendToGroup.chat-room\",  \u002F\u002F specific group\n  ],\n  groups: [\"chat-room\"],  \u002F\u002F auto-join on connect\n  expirationTimeInMinutes: 60,\n});\n```\n\n### Send Messages\n\n```typescript\n\u002F\u002F Broadcast to all connections in hub\nawait client.sendToAll({ message: \"Hello everyone!\" });\nawait client.sendToAll(\"Plain text\", { contentType: \"text\u002Fplain\" });\n\n\u002F\u002F Send to specific user (all their connections)\nawait client.sendToUser(\"user123\", { message: \"Hello!\" });\n\n\u002F\u002F Send to specific connection\nawait client.sendToConnection(\"connectionId\", { data: \"Direct message\" });\n\n\u002F\u002F Send with filter (OData syntax)\nawait client.sendToAll({ message: \"Filtered\" }, {\n  filter: \"userId ne 'admin'\",\n});\n```\n\n### Group Management\n\n```typescript\nconst group = client.group(\"chat-room\");\n\n\u002F\u002F Add user\u002Fconnection to group\nawait group.addUser(\"user123\");\nawait group.addConnection(\"connectionId\");\n\n\u002F\u002F Remove from group\nawait group.removeUser(\"user123\");\n\n\u002F\u002F Send to group\nawait group.sendToAll({ message: \"Group message\" });\n\n\u002F\u002F Close all connections in group\nawait group.closeAllConnections({ reason: \"Maintenance\" });\n```\n\n### Connection Management\n\n```typescript\n\u002F\u002F Check existence\nconst userExists = await client.userExists(\"user123\");\nconst connExists = await client.connectionExists(\"connectionId\");\n\n\u002F\u002F Close connections\nawait client.closeConnection(\"connectionId\", { reason: \"Kicked\" });\nawait client.closeUserConnections(\"user123\");\nawait client.closeAllConnections();\n\n\u002F\u002F Permissions\nawait client.grantPermission(\"connectionId\", \"sendToGroup\", { targetName: \"chat\" });\nawait client.revokePermission(\"connectionId\", \"sendToGroup\", { targetName: \"chat\" });\n```\n\n## Client-Side: WebPubSubClient\n\n### Connect\n\n```typescript\nimport { WebPubSubClient } from \"@azure\u002Fweb-pubsub-client\";\n\n\u002F\u002F Direct URL\nconst client = new WebPubSubClient(\"\u003Cclient-access-url>\");\n\n\u002F\u002F Dynamic URL from negotiate endpoint\nconst client2 = new WebPubSubClient({\n  getClientAccessUrl: async () => {\n    const response = await fetch(\"\u002Fnegotiate\");\n    const { url } = await response.json();\n    return url;\n  },\n});\n\n\u002F\u002F Register handlers BEFORE starting\nclient.on(\"connected\", (e) => {\n  console.log(`Connected: ${e.connectionId}`);\n});\n\nclient.on(\"group-message\", (e) => {\n  console.log(`${e.message.group}: ${e.message.data}`);\n});\n\nawait client.start();\n```\n\n### Send Messages\n\n```typescript\n\u002F\u002F Join group first\nawait client.joinGroup(\"chat-room\");\n\n\u002F\u002F Send to group\nawait client.sendToGroup(\"chat-room\", \"Hello!\", \"text\");\nawait client.sendToGroup(\"chat-room\", { type: \"message\", content: \"Hi\" }, \"json\");\n\n\u002F\u002F Send options\nawait client.sendToGroup(\"chat-room\", \"Hello\", \"text\", {\n  noEcho: true,        \u002F\u002F Don't echo back to sender\n  fireAndForget: true, \u002F\u002F Don't wait for ack\n});\n\n\u002F\u002F Send event to server\nawait client.sendEvent(\"userAction\", { action: \"typing\" }, \"json\");\n```\n\n### Event Handlers\n\n```typescript\n\u002F\u002F Connection lifecycle\nclient.on(\"connected\", (e) => {\n  console.log(`Connected: ${e.connectionId}, User: ${e.userId}`);\n});\n\nclient.on(\"disconnected\", (e) => {\n  console.log(`Disconnected: ${e.message}`);\n});\n\nclient.on(\"stopped\", () => {\n  console.log(\"Client stopped\");\n});\n\n\u002F\u002F Messages\nclient.on(\"group-message\", (e) => {\n  console.log(`[${e.message.group}] ${e.message.fromUserId}: ${e.message.data}`);\n});\n\nclient.on(\"server-message\", (e) => {\n  console.log(`Server: ${e.message.data}`);\n});\n\n\u002F\u002F Rejoin failure\nclient.on(\"rejoin-group-failed\", (e) => {\n  console.log(`Failed to rejoin ${e.group}: ${e.error}`);\n});\n```\n\n## Express Event Handler\n\n```typescript\nimport express from \"express\";\nimport { WebPubSubEventHandler } from \"@azure\u002Fweb-pubsub-express\";\n\nconst app = express();\n\nconst handler = new WebPubSubEventHandler(\"chat\", {\n  path: \"\u002Fapi\u002Fwebpubsub\u002Fhubs\u002Fchat\u002F\",\n  \n  \u002F\u002F Blocking: approve\u002Freject connection\n  handleConnect: (req, res) => {\n    if (!req.claims?.sub) {\n      res.fail(401, \"Authentication required\");\n      return;\n    }\n    res.success({\n      userId: req.claims.sub[0],\n      groups: [\"general\"],\n      roles: [\"webpubsub.sendToGroup\"],\n    });\n  },\n  \n  \u002F\u002F Blocking: handle custom events\n  handleUserEvent: (req, res) => {\n    console.log(`Event from ${req.context.userId}:`, req.data);\n    res.success(`Received: ${req.data}`, \"text\");\n  },\n  \n  \u002F\u002F Non-blocking\n  onConnected: (req) => {\n    console.log(`Client connected: ${req.context.connectionId}`);\n  },\n  \n  onDisconnected: (req) => {\n    console.log(`Client disconnected: ${req.context.connectionId}`);\n  },\n});\n\napp.use(handler.getMiddleware());\n\n\u002F\u002F Negotiate endpoint\napp.get(\"\u002Fnegotiate\", async (req, res) => {\n  const token = await serviceClient.getClientAccessToken({\n    userId: req.user?.id,\n  });\n  res.json({ url: token.url });\n});\n\napp.listen(8080);\n```\n\n## Key Types\n\n```typescript\n\u002F\u002F Server\nimport {\n  WebPubSubServiceClient,\n  WebPubSubGroup,\n  GenerateClientTokenOptions,\n  HubSendToAllOptions,\n} from \"@azure\u002Fweb-pubsub\";\n\n\u002F\u002F Client\nimport {\n  WebPubSubClient,\n  WebPubSubClientOptions,\n  OnConnectedArgs,\n  OnGroupDataMessageArgs,\n} from \"@azure\u002Fweb-pubsub-client\";\n\n\u002F\u002F Express\nimport {\n  WebPubSubEventHandler,\n  ConnectRequest,\n  UserEventRequest,\n  ConnectResponseHandler,\n} from \"@azure\u002Fweb-pubsub-express\";\n```\n\n## Best Practices\n\n1. **Use Entra ID auth** - `DefaultAzureCredential` for production\n2. **Register handlers before start** - Don't miss initial events\n3. **Use groups for channels** - Organize messages by topic\u002Froom\n4. **Handle reconnection** - Client auto-reconnects by default\n5. **Validate in handleConnect** - Reject unauthorized connections early\n6. **Use noEcho** - Prevent message echo back to sender when needed\n\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n",{"name":5,"risk":30,"source":24,"date_added":39,"description":7},"2026-02-27","main","7a38d8e7073e61c16eda85681cb32fb68a8657a5","skills-store\u002Fglobal\u002Fazure-web-pubsub-ts","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router","https:\u002F\u002Fgithub.com\u002Fsapsapshen","2026-04-14 21:12:12",{"source":8,"skillName":5,"commands":47,"prompt":57,"zipAvailable":58},[48,51,54],{"tool":49,"command":50},"npx","npx skills add sapsapshen\u002Fai-memory-router --skill azure-web-pubsub-ts",{"tool":52,"command":53},"bunx","bunx skills add sapsapshen\u002Fai-memory-router --skill azure-web-pubsub-ts",{"tool":55,"command":56},"pnpm","pnpm dlx skills add sapsapshen\u002Fai-memory-router --skill azure-web-pubsub-ts","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fglobal\u002Fazure-web-pubsub-ts\u002FSKILL.md",true,[],[61,83,108,118,131,150],{"skillNo":62,"name":63,"nameZh":6,"description":64,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":65,"categories":66,"keywords":72,"publishedAt":34},"01M71ATQRKG48SH06FQ697T5G9","wechat-search","Search WeChat Official Account articles using OpenClaw's web search and fetch capabilities with compliance-focused design.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fwechat-search-release\u002FSKILL.md",[67],{"categoryNo":68,"categoryName":69,"taxonomyType":70,"taxonomyTypeDesc":71},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[73,74,75,76,77,78,79,80,21,81,82,31],"wechat search","wechat","search","capabilities","openclaw","design","web search","compliance","official","fetch",{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":89,"publishedAt":34},"01M71ATNAVGZB35PFYM2GC5N00","trend-tap","Real-time trending topics aggregator across 7 platforms (X\u002FTwitter, Reddit, Google Trends, Hacker News, Zhihu, Bilibili, Weibo). Trigger: when user says 'trend', 'trends', 'trend tap', '热点', '热搜', or asks what is trending\u002Fhot. Do NOT use web_search — this skill already fetches live data from all platforms with zero API keys.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftrend-tap\u002FSKILL.md",[],[90,91,92,93,94,28,75,95,96,97,98,99,100,101,102,103,104,105,106,107],"trend","trend tap","tap","api keys","Bash","trending","hacker","aggregator","do","when","brew","live","data","google","install","read","across","api",{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":34},"01M71ATJ9AM5KM15AA8PS302EB","trend-radar","Real-time trending topics aggregator across 7 platforms (X\u002FTwitter, Reddit, Google Trends, Hacker News, Zhihu, Bilibili, Weibo). Trigger: when user says 'trend', 'trends', 'trend pulse', '热点', '热搜', or asks what is trending\u002Fhot. Do NOT use web_search — this skill already fetches live data from all platforms with zero API keys.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftrend-radar\u002FSKILL.md",[],[115,116,90,100,101,102,103,94,75,105,117,106,107,99,97,96,95,104,28,93],"trend radar","radar","pulse",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":34},"01M71ATGF095N3EJM9G8SD0BB5","tech-news-daily","每日科技新闻汇——从全球多个 RSS 源抓取最新科技新闻，翻译（英→中）、去重、排版成每日简报。当用户询问科技新闻、科技新鲜事、每日科技、技术动态、Daily Tech News 或类似表达时触发此技能。","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftech-news-daily\u002FSKILL.md",[],[125,126,127,128,129,130],"news","tech","tech news daily","daily","rss","翻译",{"skillNo":132,"name":133,"nameZh":6,"description":134,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":135,"categories":136,"keywords":142,"publishedAt":34},"01M71ATFAEAMQ17M70NQNY7SR8","summarize","Summarize URLs or files with the summarize CLI (web, PDFs, images, audio, YouTube).","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fsummarize\u002FSKILL.md",[137],{"categoryNo":138,"categoryName":139,"taxonomyType":140,"taxonomyTypeDesc":141},"01JBSEEDCAT000000000000021","资料检索与研究","SCENARIO","使用场景",[133,21,143,144,145,31,100,146,147,148,92,149,104],"Audio","cli","youtube","images","https","files","pdfs",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":156,"publishedAt":34},"01M71ATDNS3R0M4H936PACQAWZ","sonoscli","Control Sonos speakers (discover\u002Fstatus\u002Fplay\u002Fvolume\u002Fgroup).","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fsonoscli\u002FSKILL.md",[],[152,157,158,159,104,160,147,161,162,163,164,165],"status","play","go","latest","github","discover","control","cmd","volume"]