[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FESW17CGZCMJC7J2D6BKNX":3,"skill-same:01M6FESW17CGZCMJC7J2D6BKNX":48},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":21,"linkOnly":22,"markdownContent":23,"markdownBody":23,"frontMatter":24,"refName":25,"commitSha":26,"skillDirectory":27,"forksCount":28,"repositoryHtmlUrl":29,"repositoryHomepageUrl":30,"ownerHtmlUrl":31,"ownerBlogUrl":6,"ownerDescription":32,"updatedAt":33,"install":34,"resources":47},"01M6FESW17CGZCMJC7J2D6BKNX","electron-to-electrobun",null,"ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Frecrsn\u002Fagent-skills\u002Felectron-to-electrobun\u002FSKILL.md",[],[18,19,20],"electron","electrobun","electron to electrobun","2026-11-10 10:12:30",false,"# Electron → Electrobun Migration\n\nTwo phases: compatibility check, then migration. For mechanical transformations (import rewrites, IPC channel renames, API mappings), prefer JS\u002FTS codemods using `jscodeshift` or `ts-morph` over manual edits.\n\n> Many Electrobun APIs are identical to Electron: `BrowserWindow` options (`title`, `titleBarStyle`, `transparent`), methods (`setTitle`, `close`, `focus`, `minimize`\u002F`isMinimized`, `maximize`\u002F`unmaximize`\u002F`isMaximized`, `setFullScreen`\u002F`isFullScreen`, `setAlwaysOnTop`\u002F`isAlwaysOnTop`, `setPosition`, `setSize`), events (`resize`, `focus`), menu props (`role`, `label`, `type`, `enabled`, `checked`, `submenu`), `GlobalShortcut`, `Screen`, `Session`\u002F`Cookies`. Tables below only list differences. Caveat: `getPosition()` → `{x,y}` not `[x,y]`; `getSize()` → `{width,height}` not `[w,h]`.\n\n## Quick reference\n\n| Electron | Electrobun |\n|---|---|\n| Node.js (V8) | Bun (JavaScriptCore) |\n| Bundled Chromium | System WebView (WebKit\u002FWebView2\u002FWebKitGTK) or CEF |\n| `ipcMain.handle`\u002F`ipcRenderer.invoke` | `BrowserView.defineRPC\u003CS>()`\u002F`Electroview.defineRPC\u003CS>()` |\n| `webContents.send`\u002F`ipcRenderer.on` | RPC messages (fire-and-forget) |\n| preload + contextBridge | Typed RPC (preload supported, not for IPC bridging) |\n| `dialog.showOpenDialog()` | `Utils.openFileDialog()` |\n| `dialog.showMessageBox()` | `Utils.showMessageBox()` |\n| `Menu.buildFromTemplate()` | `ApplicationMenu.setApplicationMenu([...])` |\n| `Menu.popup()` | `ContextMenu.showContextMenu([...])` |\n| `clipboard.*` | `Utils.clipboard*()` |\n| `new Notification()` | `Utils.showNotification({title,body,subtitle?,silent?})` |\n| `app.getPath(name)` | `Utils.paths.*` |\n| `shell.openExternal\u002FopenPath\u002FshowItemInFolder` | `Utils.openExternal\u002FopenPath\u002FshowItemInFolder` |\n| `shell.trashItem` | `Utils.moveToTrash` |\n| `safeStorage.encrypt\u002Fdecrypt` | `Bun.secrets.get\u002Fset\u002Fdelete` (OS keychain, key-value) |\n| `app.quit()` | `Utils.quit()` |\n| electron-builder\u002Fforge | `electrobun build` (built-in, BSDIFF patches) |\n| `file:\u002F\u002F` \u002F custom protocol | `views:\u002F\u002Fviewname\u002Fpath` |\n| CSS `-webkit-app-region: drag` | CSS class `electrobun-webkit-app-region-drag` |\n\n## RPC pattern\n\nKey difference: Electron IPC is unidirectional — `ipcMain.handle` only serves renderer→main, `webContents.send` only pushes main→renderer. Electrobun RPC is bidirectional in a single schema — both sides can define requests (async call\u002Fresponse) and messages (fire-and-forget) in one type. This eliminates the need for separate IPC channel registrations, event forwarders, and bridge layers. A single `defineRPC\u003CSchema>()` call on each side replaces `ipcMain.handle` + `webContents.send` + `contextBridge.exposeInMainWorld` + `ipcRenderer.invoke` + `ipcRenderer.on`.\n\nShared schema type:\n```typescript\nimport type { RPCSchema } from \"electrobun\u002Fbun\";\ntype MySchema = {\n  bun: RPCSchema\u003C{\n    requests: { myMethod: { params: { id: string }; response: Result } };\n    messages: Record\u003Cstring, never>;\n  }>;\n  webview: RPCSchema\u003C{\n    requests: Record\u003Cstring, never>;\n    messages: { myEvent: { data: string } };\n  }>;\n};\n```\n`bun.requests` = renderer→main (returns response). `bun.messages` = renderer→main (fire-and-forget). `webview.requests`\u002F`messages` = main→renderer.\n\nBun side:\n```typescript\nconst rpc = BrowserView.defineRPC\u003CMySchema>({ handlers: { requests: {...}, messages: {...} } });\nconst win = new BrowserWindow({ url: \"views:\u002F\u002Fmain\u002Findex.html\", rpc });\nwin.webview.rpc.myEvent({ data: \"hello\" });\n```\n\nWebview side:\n```typescript\nconst rpc = Electroview.defineRPC\u003CMySchema>({ handlers: { requests: {...}, messages: {...} } });\nconst view = new Electroview({ rpc });\nawait view.rpc.request.myMethod({ id: \"123\" });\n```\n\n---\n\n## Phase 1: Compatibility Check\n\n### 1.1 Scan Electron API usage\n\nMain: `import {...} from 'electron'` (list all), `BrowserWindow` (options\u002Fmethods\u002Fevents\u002F`webContents`), `ipcMain.handle`\u002F`.on` (channels), `webContents.send` (channels), `dialog.*`, `Menu.*`, `Tray`, `clipboard.*`, `globalShortcut.*`, `screen.*`, `session`\u002F`cookies`, `shell.*`, `Notification`, `app.getPath()`, `app.on('ready')`\u002F`whenReady()`\u002F`'window-all-closed'`\u002F`'before-quit'`, `safeStorage`, `nativeTheme`, `protocol.registerFileProtocol`, `autoUpdater`\u002F`electron-updater`\n\nPreload: `contextBridge.exposeInMainWorld` (remove), `ipcRenderer.*` (remove). Categorize each file: IPC bridge (remove) vs non-IPC (keep).\n\nRenderer: `window.electron`\u002F`window.api`\u002Fcustom bridge names, `remote` module\n\nBuild: electron-builder\u002Fforge config, Vite\u002Fwebpack electron plugins\n\nNative modules: `*.node`, `node-gyp`, `prebuild`, `ffi-napi`, `better-sqlite3`, `keytar`, `node-pty`\n\n### 1.2 Unsupported patterns\n\n`remote` → RPC requests. `webRequest` → limited. No equivalent: `desktopCapturer`, `powerMonitor`, `powerSaveBlocker`, `TouchBar`, `crashReporter`, `vibrancy`\u002F`visualEffectState` (NSVisualEffectView), `trafficLightPosition`. `systemPreferences` → limited. `nodeIntegration: true` → N\u002FA. `dialog.showSaveDialog` → none yet. `@electron\u002Frebuild` → Bun native modules.\n\n### 1.3 Report template\n\n```\n## Compatibility Report\n### Direct equivalents\n- [ ] BrowserWindow (N instances)\n- [ ] IPC: N handles, M sends → RPC\n- [ ] Dialogs, Menu, Clipboard, Shortcuts, Screen, Session\n### Requires refactoring\n- [ ] Preload IPC bridge (N files) → strip\n- [ ] Preload non-IPC (N files) → keep\n### No equivalent\n- [ ] ...\n### Effort: N schemas, N preloads, N handlers, N events\n```\n\nSTOP. Present report. Enter plan mode and draft a migration plan based on the report. Get user approval before proceeding.\n\n---\n\n## Phase 2: Migration\n\nType-check after each step.\n\n### 2.1 Install\n\n```bash\nbun add electrobun\nbun remove electron electron-builder @electron-forge\u002F* electron-devtools-installer @electron\u002Frebuild\n```\nRemove electron vite\u002Fwebpack plugins.\n\n### 2.2 `electrobun.config.ts`\n\n```typescript\nimport type { ElectrobunConfig } from \"electrobun\";\nexport default {\n  app: { name: \"AppName\", identifier: \"com.x.app\", version: \"1.0.0\" },\n  build: {\n    bun: { entrypoint: \"src\u002Fmain\u002Findex.ts\" },\n    views: { main: { entrypoint: \"src\u002Frenderer\u002Fmain.tsx\" } },\n    copy: { \"src\u002Frenderer\u002Findex.html\": \"views\u002Fmain\u002Findex.html\" },\n  },\n} satisfies ElectrobunConfig;\n```\nWith Vite: keep for dev, use `copy` for prod output.\n\n### 2.3 RPC schemas\n\nPer window type, create schema in `src\u002Fcommon\u002Frpc\u002F`.\n\n`ipcMain.handle(ch)` → `bun.requests.ch`. `webContents.send(ch)` → `webview.messages.ch`. `ipcRenderer.invoke(ch)` → `rpc.request.ch()`. `ipcRenderer.on(ch)` → message handler in `defineRPC` or `rpc.addMessageListener`.\n\nSchema keys must be valid JS identifiers — rename `:`, `.`, `\u002F` channels.\n\n### 2.4 Preload\n\nStrip: `contextBridge.exposeInMainWorld()`, all `ipcRenderer`, electron imports for these.\nKeep: polyfills, error handlers, globals, CSS injection, DOM prep.\nDelete file if only IPC bridge code. Wire kept preloads: `preload: \"views:\u002F\u002Fmain\u002Fpreload.js\"`.\nRemove `global.d.ts`\u002F`window.api` type declarations.\n\n### 2.5 Main process\n\nBrowserWindow constructor:\n\n| Electron | Electrobun |\n|---|---|\n| `width`,`height`,`x`,`y` | `frame: {width,height,x,y}` |\n| `webPreferences.preload` | `preload` (top-level, accepts `views:\u002F\u002F`, remote URL, inline JS) |\n| `webPreferences.nodeIntegration` | N\u002FA (never available) |\n| `webPreferences.contextIsolation` | N\u002FA (always isolated) |\n| `webPreferences.partition` | `partition` (`persist:` prefix for persistence) |\n| `frame: false` | `styleMask: {Borderless:true, Titled:false}` |\n| `vibrancy` \u002F `visualEffectState` | No equivalent (use CSS `backdrop-filter` + `transparent: true`) |\n| `trafficLightPosition` | No equivalent (system default only) |\n| N\u002FA | `sandbox: true` (disables RPC), `html: \"...\"`, `rpc` |\n\n`styleMask` (macOS): `Borderless`, `Titled`, `Closable`, `Miniaturizable`, `Resizable`, `UnifiedTitleAndToolbar`, `FullScreen`, `FullSizeContentView`, `UtilityWindow`, `DocModalWindow`, `NonactivatingPanel`, `HUDWindow`. `titleBarStyle` auto-sets `styleMask`.\n\nBrowserWindow methods (differences only):\n\n| Electron | Electrobun |\n|---|---|\n| `restore()` | `unminimize()` |\n| `setBounds(rect)` | `setFrame(x,y,w,h)` |\n| `getBounds()` | `getFrame()` → `{x,y,width,height}` |\n| `loadURL(url)` | `webview.loadURL(url)` |\n| `webContents` | `webview` (all `webContents.*` moves here) |\n| `webContents.openDevTools({mode})` | `webview.openDevTools()` (no args) |\n| N\u002FA | `webview.toggleDevTools()` |\n\nBrowserWindow events (differences only):\n\n| Electron | Electrobun | Data |\n|---|---|---|\n| `'closed'` | `'close'` | `{id}` |\n| `'move'`\u002F`'moved'` | `'move'` | `{id,x,y}` |\n\nEvents also on `Electrobun.events.on(name, ...)`.\n\nApp lifecycle:\n```typescript\n\u002F\u002F Electron:\napp.whenReady().then(createWindow);\napp.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });\n\u002F\u002F Electrobun — no 'ready', starts immediately:\ncreateWindow();\n\u002F\u002F exitOnLastWindowClosed in config. before-quit:\nElectrobun.events.on('before-quit', (e) => { e.response = { allow: false }; });\n```\n\n`openFileDialog` options:\n\n| Electron | Electrobun |\n|---|---|\n| `properties: ['openFile']` | `canChooseFiles: true` |\n| `properties: ['openDirectory']` | `canChooseDirectory: true` |\n| `properties: ['multiSelections']` | `allowsMultipleSelection: true` |\n| `defaultPath` | `startingFolder` |\n| `filters: [{extensions:[...]}]` | `allowedFileTypes: \"png,jpg\"` (comma-sep, `\"*\"` for all) |\n\nReturns `string[]` directly (not `{filePaths, canceled}`). `showMessageBox` options\u002Freturn identical.\n\nMenus:\n```typescript\n\u002F\u002F Electron: Menu.setApplicationMenu(Menu.buildFromTemplate(template));\n\u002F\u002F Electrobun — no buildFromTemplate:\nApplicationMenu.setApplicationMenu([\n  { submenu: [{ label: 'Quit', role: 'quit' }] },\n  { label: 'Edit', submenu: [{ role: 'undo' }, { role: 'redo' }, { type: 'separator' }, { role: 'cut' }, { role: 'copy' }, { role: 'paste' }, { role: 'selectAll' }] },\n]);\n```\n\nMenu item differences:\n\n| Electron | Electrobun |\n|---|---|\n| `click: () => {}` | `action: \"string\"` + `Electrobun.events.on('application-menu-clicked', e => e.data.action)` |\n| `accelerator: \"CmdOrCtrl+S\"` | `accelerator: \"s\"` (just key, modifier auto-applied) |\n| `visible: false` | `hidden: true` |\n| `toolTip` | `tooltip` |\n\nRoles: `quit`, `hide`, `hideOthers`, `undo`, `redo`, `cut`, `copy`, `paste`, `pasteAndMatchStyle`, `delete`, `selectAll`, `minimize`, `close`, `toggleFullScreen`, `zoom`, `bringAllToFront`, `cycleThroughWindows`. Separators: `{type:\"separator\"}` or `{type:\"divider\"}`. Linux: menus unsupported.\n\nContext menus: `ContextMenu.showContextMenu([...])` + `Electrobun.events.on('context-menu-clicked', ...)`.\n\nShell: `shell.*` → `Utils.*`. `trashItem` → `moveToTrash` (no restore metadata on macOS). `openExternal`\u002F`openPath` return `boolean`.\n\nClipboard: `clipboard.*()` → `Utils.clipboard*()`. `readImage()` → `Uint8Array` (PNG) or `null`. `availableFormats()` → `[\"text\",\"image\",\"files\",\"html\"]`.\n\nPaths: `app.getPath(name)` → `Utils.paths.{name}`. All sync. `userData` is app-scoped: `{appData}\u002F{identifier}\u002F{channel}`. Extra: `Utils.paths.config`, `.cache`, `.userCache`, `.userLogs`.\n\nCredentials:\n```typescript\n\u002F\u002F Electron: safeStorage.encryptString(value); safeStorage.decryptString(buffer);\n\u002F\u002F Electrobun (OS keychain, key-value):\nawait Bun.secrets.set({ service: \"my-app\", name: \"api-key\", value: \"secret\" });\nawait Bun.secrets.get({ service: \"my-app\", name: \"api-key\" }); \u002F\u002F string | null\nawait Bun.secrets.delete({ service: \"my-app\", name: \"api-key\" }); \u002F\u002F boolean\n```\nNot raw encrypt\u002Fdecrypt — refactor to key-value by service+name.\n\nGlobalShortcut, Screen, Session\u002FCookies: Import from `\"electrobun\u002Fbun\"`. Same APIs.\n\n### 2.6 Renderer\n\nReplace bridge calls: `window.api.call(ch, args)` → `rpc.request.ch(args)`. `window.api.on(ch, cb)` → `rpc.addMessageListener('ch', cb)`.\n\nPer-entrypoint `rpc.ts`:\n```typescript\nimport { Electroview } from \"electrobun\u002Fview\";\nimport type { MySchema } from \"..\u002Fcommon\u002Frpc\u002Fmy-schema.js\";\nexport const rpc = Electroview.defineRPC\u003CMySchema>({ handlers: { requests: {}, messages: {} } });\nconst view = new Electroview({ rpc });\n```\n\nCSS: `-webkit-app-region: drag\u002Fno-drag` → classes `electrobun-webkit-app-region-drag`\u002F`-no-drag`.\n\nRemove `window.api`\u002F`window.electron` type declarations, `global.d.ts`\u002F`preload.d.ts`.\n\n### 2.7 Build\n\nWith Vite: keep for dev, `copy` maps output in `electrobun.config.ts`. Without: `build.views` in config.\n\n### 2.8 Verify\n\n`bun run typecheck` → `electrobun build` → test windows\u002FRPC\u002Fevents\u002Fmenus\u002Fdialogs → `electrobun build --env=stable`\n\n## Pitfalls\n\n1. Preload ≠ delete — strip only `contextBridge`\u002F`ipcRenderer`; keep polyfills\u002Fglobals\n2. Channel names — RPC keys must be valid JS identifiers, rename `:.\u002F` consistently\n3. `safeStorage` → `Bun.secrets` — key-value, not encrypt\u002Fdecrypt\n4. `remote` → must become RPC requests\n5. Native modules — may need Bun-compatible alternatives\n6. Multi-window — each window type needs its own RPC schema\n7. Draggable regions — CSS property → CSS class\n",{},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Frecrsn\u002Fagent-skills\u002Felectron-to-electrobun",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":7,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill electron-to-electrobun",{"tool":40,"command":41},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill electron-to-electrobun",{"tool":43,"command":44},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill electron-to-electrobun","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Frecrsn\u002Fagent-skills\u002Felectron-to-electrobun\u002FSKILL.md",true,[],[49,63,73,82,88,95],{"skillNo":50,"name":51,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":52,"categories":53,"keywords":59,"publishedAt":21},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[54],{"categoryNo":55,"categoryName":56,"taxonomyType":57,"taxonomyTypeDesc":58},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[60,61,62],"model","model hierarchy","model hierarchy skill",{"skillNo":64,"name":65,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":69,"publishedAt":21},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[68],{"categoryNo":55,"categoryName":56,"taxonomyType":57,"taxonomyTypeDesc":58},[70,71,72],"MCP","zoom","zoom mcp",{"skillNo":74,"name":75,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":21},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[79,80,81,71],"sdk","zoom apps sdk","apps",{"skillNo":83,"name":84,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":21},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[84],{"skillNo":89,"name":90,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":91,"categories":92,"keywords":94,"publishedAt":21},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[93],{"categoryNo":55,"categoryName":56,"taxonomyType":57,"taxonomyTypeDesc":58},[90],{"skillNo":96,"name":97,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":21},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[97]]