@opentabs-dev/opentabs-plugin-asana 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 +64 -129
- package/dist/adapter.iife.js +25 -13
- package/dist/adapter.iife.js.map +3 -3
- package/dist/tools.json +4 -4
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -1,159 +1,94 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Asana
|
|
2
2
|
|
|
3
|
-
OpenTabs plugin for Asana
|
|
3
|
+
OpenTabs plugin for Asana — gives AI agents access to Asana through your authenticated browser session.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
|
+
```bash
|
|
8
|
+
opentabs plugin install asana
|
|
7
9
|
```
|
|
8
|
-
asana/
|
|
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
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Configuration
|
|
22
|
-
|
|
23
|
-
Plugin metadata is defined in `package.json` under the `opentabs` field:
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"name": "opentabs-plugin-asana",
|
|
28
|
-
"main": "dist/adapter.iife.js",
|
|
29
|
-
"opentabs": {
|
|
30
|
-
"displayName": "Asana",
|
|
31
|
-
"description": "OpenTabs plugin for Asana",
|
|
32
|
-
"urlPatterns": ["*://*.app.asana.com/*"]
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
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
|
|
41
|
-
|
|
42
|
-
## Custom Icons
|
|
43
10
|
|
|
44
|
-
|
|
11
|
+
Or install globally via npm:
|
|
45
12
|
|
|
46
|
-
```
|
|
47
|
-
asana
|
|
48
|
-
├── package.json
|
|
49
|
-
├── icon.svg ← custom icon (optional)
|
|
50
|
-
├── icon-inactive.svg ← manual inactive override (optional, requires icon.svg)
|
|
51
|
-
├── src/
|
|
52
|
-
│ └── ...
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @opentabs-dev/opentabs-plugin-asana
|
|
53
15
|
```
|
|
54
16
|
|
|
55
|
-
|
|
17
|
+
## Setup
|
|
56
18
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
- If no `icon.svg` is provided, the letter avatar is used automatically
|
|
19
|
+
1. Open [app.asana.com](https://asana.com) in Chrome and log in
|
|
20
|
+
2. Open the OpenTabs side panel — the Asana plugin should appear as **ready**
|
|
60
21
|
|
|
61
|
-
|
|
22
|
+
## Tools (24)
|
|
62
23
|
|
|
63
|
-
|
|
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
|
|
24
|
+
### Tasks (9)
|
|
67
25
|
|
|
68
|
-
|
|
26
|
+
| Tool | Description | Type |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `get_task` | Get details of a specific task | Read |
|
|
29
|
+
| `create_task` | Create a new task | Write |
|
|
30
|
+
| `update_task` | Update an existing task | Write |
|
|
31
|
+
| `delete_task` | Delete a task permanently | Write |
|
|
32
|
+
| `search_tasks` | Search tasks in a workspace | Read |
|
|
33
|
+
| `get_tasks_for_project` | List tasks in a project | Read |
|
|
34
|
+
| `get_tasks_for_section` | List tasks in a section | Read |
|
|
35
|
+
| `get_subtasks` | List subtasks of a task | Read |
|
|
36
|
+
| `add_followers` | Add followers to a task | Write |
|
|
69
37
|
|
|
70
|
-
|
|
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
|
-
```
|
|
38
|
+
### Projects (4)
|
|
77
39
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
```
|
|
40
|
+
| Tool | Description | Type |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `list_projects` | List projects in a workspace | Read |
|
|
43
|
+
| `get_project` | Get details of a specific project | Read |
|
|
44
|
+
| `create_project` | Create a new project in a workspace | Write |
|
|
45
|
+
| `update_project` | Update an existing project | Write |
|
|
99
46
|
|
|
100
|
-
|
|
47
|
+
### Sections (3)
|
|
101
48
|
|
|
102
|
-
|
|
49
|
+
| Tool | Description | Type |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `list_sections` | List sections in a project | Read |
|
|
52
|
+
| `create_section` | Create a new section in a project | Write |
|
|
53
|
+
| `add_task_to_section` | Move a task into a section | Write |
|
|
103
54
|
|
|
104
|
-
|
|
55
|
+
### Stories (2)
|
|
105
56
|
|
|
106
|
-
|
|
107
|
-
|
|
57
|
+
| Tool | Description | Type |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| `get_stories_for_task` | List stories on a task | Read |
|
|
60
|
+
| `create_story` | Add a comment to a task | Write |
|
|
108
61
|
|
|
109
|
-
|
|
110
|
-
const token = getLocalStorage('token');
|
|
62
|
+
### Users (3)
|
|
111
63
|
|
|
112
|
-
|
|
113
|
-
|
|
64
|
+
| Tool | Description | Type |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `get_current_user` | Get the current user profile | Read |
|
|
67
|
+
| `get_user` | Get a user by GID | Read |
|
|
68
|
+
| `list_users_for_workspace` | List users in a workspace | Read |
|
|
114
69
|
|
|
115
|
-
|
|
116
|
-
const appState = getPageGlobal('__APP_STATE__');
|
|
117
|
-
```
|
|
70
|
+
### Workspaces (1)
|
|
118
71
|
|
|
119
|
-
|
|
72
|
+
| Tool | Description | Type |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| `list_workspaces` | List all workspaces | Read |
|
|
120
75
|
|
|
121
|
-
|
|
76
|
+
### Tags (1)
|
|
122
77
|
|
|
123
|
-
|
|
78
|
+
| Tool | Description | Type |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `list_tags` | List tags in a workspace | Read |
|
|
124
81
|
|
|
125
|
-
|
|
82
|
+
### Teams (1)
|
|
126
83
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
84
|
+
| Tool | Description | Type |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `list_teams` | List teams in a workspace | Read |
|
|
130
87
|
|
|
131
|
-
|
|
132
|
-
id: z.string().describe('Channel ID'),
|
|
133
|
-
name: z.string().describe('Channel name'),
|
|
134
|
-
});
|
|
88
|
+
## How It Works
|
|
135
89
|
|
|
136
|
-
|
|
137
|
-
```
|
|
90
|
+
This plugin runs inside your Asana 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.
|
|
138
91
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
```ts
|
|
142
|
-
// src/tools/list-channels.ts
|
|
143
|
-
import { channelSchema } from '../schemas/channel.js';
|
|
144
|
-
|
|
145
|
-
export const listChannels = defineTool({
|
|
146
|
-
name: 'list_channels',
|
|
147
|
-
displayName: 'List Channels',
|
|
148
|
-
description: 'List all available channels',
|
|
149
|
-
icon: 'list',
|
|
150
|
-
input: z.object({}),
|
|
151
|
-
output: z.object({ channels: z.array(channelSchema) }),
|
|
152
|
-
handle: async () => {
|
|
153
|
-
// ...
|
|
154
|
-
return { channels: [] };
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
```
|
|
92
|
+
## License
|
|
158
93
|
|
|
159
|
-
|
|
94
|
+
MIT
|
package/dist/adapter.iife.js
CHANGED
|
@@ -280,6 +280,8 @@
|
|
|
280
280
|
* (e.g., 'https://github.com'), not a match pattern.
|
|
281
281
|
*/
|
|
282
282
|
homepage;
|
|
283
|
+
/** Typed configuration schema — declares settings that users provide via config.json or the side panel. */
|
|
284
|
+
configSchema;
|
|
283
285
|
};
|
|
284
286
|
|
|
285
287
|
// src/asana-api.ts
|
|
@@ -15077,21 +15079,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15077
15079
|
};
|
|
15078
15080
|
var src_default = new AsanaPlugin();
|
|
15079
15081
|
|
|
15080
|
-
// dist/
|
|
15082
|
+
// dist/_adapter_entry_8d511b27-6933-49e2-8e0f-99201978a6fb.ts
|
|
15081
15083
|
if (!globalThis.__openTabs) {
|
|
15082
15084
|
globalThis.__openTabs = {};
|
|
15083
15085
|
} else {
|
|
15084
15086
|
const desc = Object.getOwnPropertyDescriptor(globalThis.__openTabs, "adapters");
|
|
15085
15087
|
if (desc && !desc.writable) {
|
|
15086
|
-
const
|
|
15088
|
+
const ot3 = globalThis.__openTabs;
|
|
15087
15089
|
const newAdaptersObj = {};
|
|
15088
|
-
if (
|
|
15089
|
-
for (const key of Object.keys(
|
|
15090
|
-
const d = Object.getOwnPropertyDescriptor(
|
|
15090
|
+
if (ot3.adapters) {
|
|
15091
|
+
for (const key of Object.keys(ot3.adapters)) {
|
|
15092
|
+
const d = Object.getOwnPropertyDescriptor(ot3.adapters, key);
|
|
15091
15093
|
if (d) Object.defineProperty(newAdaptersObj, key, d);
|
|
15092
15094
|
}
|
|
15093
15095
|
}
|
|
15094
|
-
globalThis.__openTabs = Object.assign({},
|
|
15096
|
+
globalThis.__openTabs = Object.assign({}, ot3, { adapters: newAdaptersObj });
|
|
15095
15097
|
}
|
|
15096
15098
|
}
|
|
15097
15099
|
if (!globalThis.__openTabs.adapters) {
|
|
@@ -15129,6 +15131,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15129
15131
|
}
|
|
15130
15132
|
};
|
|
15131
15133
|
var restoreTransport = setLogTransport ? setLogTransport(logTransport) : void 0;
|
|
15134
|
+
var ot2 = globalThis.__openTabs;
|
|
15135
|
+
ot2._notifyReadinessChanged = () => {
|
|
15136
|
+
try {
|
|
15137
|
+
const nonce = globalThis.__openTabs?._readinessNonce;
|
|
15138
|
+
if (nonce) {
|
|
15139
|
+
window.postMessage({ type: "opentabs:readiness-changed", plugin: "asana", nonce }, "*");
|
|
15140
|
+
}
|
|
15141
|
+
} catch {
|
|
15142
|
+
}
|
|
15143
|
+
};
|
|
15132
15144
|
var existing = adapters["asana"];
|
|
15133
15145
|
if (existing) {
|
|
15134
15146
|
if (typeof existing.teardown === "function") {
|
|
@@ -15140,7 +15152,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15140
15152
|
}
|
|
15141
15153
|
}
|
|
15142
15154
|
if (!Reflect.deleteProperty(adapters, "asana")) {
|
|
15143
|
-
const
|
|
15155
|
+
const ot3 = globalThis.__openTabs;
|
|
15144
15156
|
const newAdapters = {};
|
|
15145
15157
|
for (const key of Object.keys(adapters)) {
|
|
15146
15158
|
if (key !== "asana") {
|
|
@@ -15148,7 +15160,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15148
15160
|
if (desc) Object.defineProperty(newAdapters, key, desc);
|
|
15149
15161
|
}
|
|
15150
15162
|
}
|
|
15151
|
-
globalThis.__openTabs = Object.assign({},
|
|
15163
|
+
globalThis.__openTabs = Object.assign({}, ot3, { adapters: newAdapters });
|
|
15152
15164
|
}
|
|
15153
15165
|
var hasLifecycleHooks = typeof src_default.onToolInvocationStart === "function" || typeof src_default.onToolInvocationEnd === "function";
|
|
15154
15166
|
for (const tool of src_default.tools) {
|
|
@@ -15209,12 +15221,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15209
15221
|
}
|
|
15210
15222
|
}
|
|
15211
15223
|
};
|
|
15212
|
-
const
|
|
15213
|
-
if (!
|
|
15224
|
+
const ot3 = globalThis.__openTabs;
|
|
15225
|
+
if (!ot3._navigationInterceptor) {
|
|
15214
15226
|
const origPushState = history.pushState.bind(history);
|
|
15215
15227
|
const origReplaceState = history.replaceState.bind(history);
|
|
15216
15228
|
const callbacks = /* @__PURE__ */ new Map();
|
|
15217
|
-
|
|
15229
|
+
ot3._navigationInterceptor = { callbacks, origPushState, origReplaceState };
|
|
15218
15230
|
history.pushState = function(...args) {
|
|
15219
15231
|
origPushState(...args);
|
|
15220
15232
|
for (const cb of callbacks.values()) {
|
|
@@ -15228,7 +15240,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15228
15240
|
}
|
|
15229
15241
|
};
|
|
15230
15242
|
}
|
|
15231
|
-
const interceptor =
|
|
15243
|
+
const interceptor = ot3._navigationInterceptor;
|
|
15232
15244
|
interceptor.callbacks.set("asana", checkUrl);
|
|
15233
15245
|
window.addEventListener("popstate", checkUrl);
|
|
15234
15246
|
window.addEventListener("hashchange", checkUrl);
|
|
@@ -15283,5 +15295,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
15283
15295
|
};
|
|
15284
15296
|
delete src_default.onDeactivate;
|
|
15285
15297
|
}
|
|
15286
|
-
})();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["asana"]){var a=o.adapters["asana"];a.__adapterHash="
|
|
15298
|
+
})();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["asana"]){var a=o.adapters["asana"];a.__adapterHash="8406a882ee2345931bbe7c5ea295f5ba41951db6d69359341cb8d2854d9a659c";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,"asana",{value:a,writable:false,configurable:false,enumerable:true});Object.defineProperty(o,"adapters",{value:o.adapters,writable:false,configurable:false});}})();
|
|
15287
15299
|
//# sourceMappingURL=adapter.iife.js.map
|