@opentabs-dev/opentabs-plugin-discord 0.0.75 → 0.0.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,138 +1,91 @@
1
- # opentabs-plugin-discord
1
+ # Discord
2
2
 
3
- OpenTabs plugin for Discord
3
+ OpenTabs plugin for Discord — gives AI agents access to Discord through your authenticated browser session.
4
4
 
5
- ## Project Structure
5
+ ## Install
6
6
 
7
- ```
8
- discord/
9
- ├── package.json # Plugin metadata (name, opentabs field, dependencies)
10
- ├── icon.svg # Optional custom icon (square SVG, max 8KB)
11
- ├── icon-inactive.svg # Optional manual inactive icon override
12
- ├── src/
13
- │ ├── index.ts # Plugin class (extends OpenTabsPlugin)
14
- │ └── tools/ # One file per tool (using defineTool)
15
- │ └── example.ts
16
- └── dist/ # Build output (generated)
17
- ├── adapter.iife.js # Bundled adapter injected into matching tabs
18
- └── tools.json # Tool schemas for MCP registration
7
+ ```bash
8
+ opentabs plugin install discord
19
9
  ```
20
10
 
21
- ## Configuration
11
+ Or install globally via npm:
22
12
 
23
- Plugin metadata is defined in `package.json` under the `opentabs` field:
24
-
25
- ```json
26
- {
27
- "name": "opentabs-plugin-discord",
28
- "main": "dist/adapter.iife.js",
29
- "opentabs": {
30
- "displayName": "Discord",
31
- "description": "OpenTabs plugin for Discord",
32
- "urlPatterns": ["*://discord.com/*"]
33
- }
34
- }
13
+ ```bash
14
+ npm install -g @opentabs-dev/opentabs-plugin-discord
35
15
  ```
36
16
 
37
- - **`main`** — entry point for the bundled adapter IIFE
38
- - **`opentabs.displayName`** — human-readable name shown in the side panel
39
- - **`opentabs.description`** — short description of what the plugin does
40
- - **`opentabs.urlPatterns`** — Chrome match patterns for tabs where the adapter is injected
17
+ ## Setup
41
18
 
42
- ## Custom Icons
19
+ 1. Open [discord.com](https://discord.com/channels/@me) in Chrome and log in
20
+ 2. Open the OpenTabs side panel — the Discord plugin should appear as **ready**
43
21
 
44
- By default, the side panel shows a colored letter avatar for your plugin. To use a custom icon, place an `icon.svg` file in the plugin root (next to `package.json`):
22
+ ## Tools (26)
45
23
 
46
- ```
47
- discord/
48
- ├── package.json
49
- ├── icon.svg ← custom icon (optional)
50
- ├── icon-inactive.svg ← manual inactive override (optional, requires icon.svg)
51
- ├── src/
52
- │ └── ...
53
- ```
24
+ ### Messages (8)
54
25
 
55
- **How it works:**
26
+ | Tool | Description | Type |
27
+ |---|---|---|
28
+ | `send_message` | Send a message to a channel | Write |
29
+ | `edit_message` | Edit an existing message | Write |
30
+ | `delete_message` | Delete a message from a channel | Write |
31
+ | `read_messages` | Read recent messages from a channel | Read |
32
+ | `read_thread` | Read messages from a thread | Read |
33
+ | `search_messages` | Search messages in a server | Read |
34
+ | `get_message` | Get a message by ID | Read |
35
+ | `list_pinned_messages` | List pinned messages in a channel | Read |
56
36
 
57
- - `opentabs-plugin build` reads `icon.svg`, validates it, auto-generates a grayscale inactive variant, and embeds both in `dist/tools.json`
58
- - To override the auto-generated inactive icon, provide `icon-inactive.svg` (must use only grayscale colors)
59
- - If no `icon.svg` is provided, the letter avatar is used automatically
37
+ ### Servers (3)
60
38
 
61
- **Icon requirements:**
39
+ | Tool | Description | Type |
40
+ |---|---|---|
41
+ | `list_guilds` | List servers the user belongs to | Read |
42
+ | `get_guild_info` | Get detailed info about a server | Read |
43
+ | `list_roles` | List roles in a server | Read |
62
44
 
63
- - Square SVG with a `viewBox` attribute (e.g., `viewBox="0 0 32 32"`)
64
- - Maximum 8 KB file size
65
- - No embedded `<image>`, `<script>`, or event handler attributes (`onclick`, etc.)
66
- - Manual `icon-inactive.svg` must use only achromatic (grayscale) colors
45
+ ### Channels (6)
67
46
 
68
- ## Development
47
+ | Tool | Description | Type |
48
+ |---|---|---|
49
+ | `list_channels` | List channels in a server | Read |
50
+ | `get_channel_info` | Get detailed information about a channel | Read |
51
+ | `create_channel` | Create a new channel in a server | Write |
52
+ | `edit_channel` | Edit a channel's name, topic, or settings | Write |
53
+ | `delete_channel` | Delete a channel permanently | Write |
54
+ | `create_thread` | Create a new thread | Write |
69
55
 
70
- ```bash
71
- npm install
72
- npm run build # tsc && opentabs-plugin build
73
- npm run dev # watch mode (tsc --watch + opentabs-plugin build --watch)
74
- npm run type-check # tsc --noEmit
75
- npm run lint # biome
76
- ```
56
+ ### Users (2)
77
57
 
78
- ## Adding Tools
79
-
80
- Create a new file in `src/tools/` using `defineTool`:
81
-
82
- ```ts
83
- import { z } from 'zod';
84
- import { defineTool } from '@opentabs-dev/plugin-sdk';
85
-
86
- export const myTool = defineTool({
87
- name: 'my_tool',
88
- displayName: 'My Tool',
89
- description: 'What this tool does',
90
- icon: 'wrench',
91
- input: z.object({ /* ... */ }),
92
- output: z.object({ /* ... */ }),
93
- handle: async (params) => {
94
- // Tool implementation runs in the browser tab context
95
- return { /* ... */ };
96
- },
97
- });
98
- ```
58
+ | Tool | Description | Type |
59
+ |---|---|---|
60
+ | `list_members` | List members in a server | Read |
61
+ | `get_user_profile` | Get a user's profile information | Read |
99
62
 
100
- Then register it in `src/index.ts` by adding it to the `tools` array.
63
+ ### DMs (2)
101
64
 
102
- ## Shared Schemas
65
+ | Tool | Description | Type |
66
+ |---|---|---|
67
+ | `list_dms` | List open direct message channels | Read |
68
+ | `open_dm` | Open a direct message conversation | Write |
103
69
 
104
- When 3 or more tools share the same input or output shape, extract common Zod schemas into a shared file to avoid duplication:
70
+ ### Reactions (4)
105
71
 
106
- ```ts
107
- // src/schemas/channel.ts
108
- import { z } from 'zod';
72
+ | Tool | Description | Type |
73
+ |---|---|---|
74
+ | `add_reaction` | Add an emoji reaction to a message | Write |
75
+ | `remove_reaction` | Remove an emoji reaction from a message | Write |
76
+ | `pin_message` | Pin a message in a channel | Write |
77
+ | `unpin_message` | Unpin a message from a channel | Write |
109
78
 
110
- export const channelSchema = z.object({
111
- id: z.string().describe('Channel ID'),
112
- name: z.string().describe('Channel name'),
113
- });
79
+ ### Files (1)
114
80
 
115
- export type Channel = z.infer<typeof channelSchema>;
116
- ```
81
+ | Tool | Description | Type |
82
+ |---|---|---|
83
+ | `upload_file` | Upload a file to a channel | Write |
117
84
 
118
- Then import and reuse in your tools:
119
-
120
- ```ts
121
- // src/tools/list-channels.ts
122
- import { channelSchema } from '../schemas/channel.js';
123
-
124
- export const listChannels = defineTool({
125
- name: 'list_channels',
126
- displayName: 'List Channels',
127
- description: 'List all available channels',
128
- icon: 'list',
129
- input: z.object({}),
130
- output: z.object({ channels: z.array(channelSchema) }),
131
- handle: async () => {
132
- // ...
133
- return { channels: [] };
134
- },
135
- });
136
- ```
85
+ ## How It Works
86
+
87
+ This plugin runs inside your Discord tab through the [OpenTabs](https://opentabs.dev) Chrome extension. It uses your existing browser session — no API tokens or OAuth apps required. All operations happen as you, with your permissions.
88
+
89
+ ## License
137
90
 
138
- This keeps your tool schemas DRY and makes it easy to evolve shared types in one place.
91
+ MIT
@@ -291,6 +291,8 @@
291
291
  * (e.g., 'https://github.com'), not a match pattern.
292
292
  */
293
293
  homepage;
294
+ /** Typed configuration schema — declares settings that users provide via config.json or the side panel. */
295
+ configSchema;
294
296
  };
295
297
 
296
298
  // src/discord-api.ts
@@ -15169,21 +15171,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15169
15171
  };
15170
15172
  var src_default = new DiscordPlugin();
15171
15173
 
15172
- // dist/_adapter_entry_0afe5675-aa72-405d-8780-6d29ae4706dc.ts
15174
+ // dist/_adapter_entry_c40360e4-e85c-4449-b0d3-64f73847481a.ts
15173
15175
  if (!globalThis.__openTabs) {
15174
15176
  globalThis.__openTabs = {};
15175
15177
  } else {
15176
15178
  const desc = Object.getOwnPropertyDescriptor(globalThis.__openTabs, "adapters");
15177
15179
  if (desc && !desc.writable) {
15178
- const ot2 = globalThis.__openTabs;
15180
+ const ot3 = globalThis.__openTabs;
15179
15181
  const newAdaptersObj = {};
15180
- if (ot2.adapters) {
15181
- for (const key of Object.keys(ot2.adapters)) {
15182
- const d = Object.getOwnPropertyDescriptor(ot2.adapters, key);
15182
+ if (ot3.adapters) {
15183
+ for (const key of Object.keys(ot3.adapters)) {
15184
+ const d = Object.getOwnPropertyDescriptor(ot3.adapters, key);
15183
15185
  if (d) Object.defineProperty(newAdaptersObj, key, d);
15184
15186
  }
15185
15187
  }
15186
- globalThis.__openTabs = Object.assign({}, ot2, { adapters: newAdaptersObj });
15188
+ globalThis.__openTabs = Object.assign({}, ot3, { adapters: newAdaptersObj });
15187
15189
  }
15188
15190
  }
15189
15191
  if (!globalThis.__openTabs.adapters) {
@@ -15221,6 +15223,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15221
15223
  }
15222
15224
  };
15223
15225
  var restoreTransport = setLogTransport ? setLogTransport(logTransport) : void 0;
15226
+ var ot2 = globalThis.__openTabs;
15227
+ ot2._notifyReadinessChanged = () => {
15228
+ try {
15229
+ const nonce = globalThis.__openTabs?._readinessNonce;
15230
+ if (nonce) {
15231
+ window.postMessage({ type: "opentabs:readiness-changed", plugin: "discord", nonce }, "*");
15232
+ }
15233
+ } catch {
15234
+ }
15235
+ };
15224
15236
  var existing = adapters["discord"];
15225
15237
  if (existing) {
15226
15238
  if (typeof existing.teardown === "function") {
@@ -15232,7 +15244,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15232
15244
  }
15233
15245
  }
15234
15246
  if (!Reflect.deleteProperty(adapters, "discord")) {
15235
- const ot2 = globalThis.__openTabs;
15247
+ const ot3 = globalThis.__openTabs;
15236
15248
  const newAdapters = {};
15237
15249
  for (const key of Object.keys(adapters)) {
15238
15250
  if (key !== "discord") {
@@ -15240,7 +15252,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15240
15252
  if (desc) Object.defineProperty(newAdapters, key, desc);
15241
15253
  }
15242
15254
  }
15243
- globalThis.__openTabs = Object.assign({}, ot2, { adapters: newAdapters });
15255
+ globalThis.__openTabs = Object.assign({}, ot3, { adapters: newAdapters });
15244
15256
  }
15245
15257
  var hasLifecycleHooks = typeof src_default.onToolInvocationStart === "function" || typeof src_default.onToolInvocationEnd === "function";
15246
15258
  for (const tool of src_default.tools) {
@@ -15301,12 +15313,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15301
15313
  }
15302
15314
  }
15303
15315
  };
15304
- const ot2 = globalThis.__openTabs;
15305
- if (!ot2._navigationInterceptor) {
15316
+ const ot3 = globalThis.__openTabs;
15317
+ if (!ot3._navigationInterceptor) {
15306
15318
  const origPushState = history.pushState.bind(history);
15307
15319
  const origReplaceState = history.replaceState.bind(history);
15308
15320
  const callbacks = /* @__PURE__ */ new Map();
15309
- ot2._navigationInterceptor = { callbacks, origPushState, origReplaceState };
15321
+ ot3._navigationInterceptor = { callbacks, origPushState, origReplaceState };
15310
15322
  history.pushState = function(...args) {
15311
15323
  origPushState(...args);
15312
15324
  for (const cb of callbacks.values()) {
@@ -15320,7 +15332,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15320
15332
  }
15321
15333
  };
15322
15334
  }
15323
- const interceptor = ot2._navigationInterceptor;
15335
+ const interceptor = ot3._navigationInterceptor;
15324
15336
  interceptor.callbacks.set("discord", checkUrl);
15325
15337
  window.addEventListener("popstate", checkUrl);
15326
15338
  window.addEventListener("hashchange", checkUrl);
@@ -15375,5 +15387,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15375
15387
  };
15376
15388
  delete src_default.onDeactivate;
15377
15389
  }
15378
- })();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["discord"]){var a=o.adapters["discord"];a.__adapterHash="c15a26519999c6bdf8200ab401fb08a824ba1bf03f104d6c07ced0c65af548e4";if(a.tools&&Array.isArray(a.tools)){for(var i=0;i<a.tools.length;i++){Object.freeze(a.tools[i]);}Object.freeze(a.tools);}Object.freeze(a);Object.defineProperty(o.adapters,"discord",{value:a,writable:false,configurable:false,enumerable:true});Object.defineProperty(o,"adapters",{value:o.adapters,writable:false,configurable:false});}})();
15390
+ })();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["discord"]){var a=o.adapters["discord"];a.__adapterHash="0e11871f60b87845e656f01724f2a50eaaab6399db05c2f24363e4d84e2950c5";if(a.tools&&Array.isArray(a.tools)){for(var i=0;i<a.tools.length;i++){Object.freeze(a.tools[i]);}Object.freeze(a.tools);}Object.freeze(a);Object.defineProperty(o.adapters,"discord",{value:a,writable:false,configurable:false,enumerable:true});Object.defineProperty(o,"adapters",{value:o.adapters,writable:false,configurable:false});}})();
15379
15391
  //# sourceMappingURL=adapter.iife.js.map