@pleaseai/agent 0.1.17 → 0.1.19

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.
Files changed (37) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/builds/latest.json +1 -1
  3. package/.output/public/_nuxt/builds/meta/b9184376-213c-4350-b5c2-fff46a3d287b.json +1 -0
  4. package/.output/server/chunks/build/Badge-BnQthhyg.mjs +1 -1
  5. package/.output/server/chunks/build/_id_-B-peNi7y.mjs +2 -0
  6. package/.output/server/chunks/build/_identifier_-u8aQI-B5.mjs +2 -0
  7. package/.output/server/chunks/build/dashboard-DRFqbhzu.mjs +2 -0
  8. package/.output/server/chunks/build/error-404-Boq1zV4r.mjs +2 -0
  9. package/.output/server/chunks/build/error-500-BAbnx-7I.mjs +2 -0
  10. package/.output/server/chunks/build/index-BAy5ojFe.mjs +2 -0
  11. package/.output/server/chunks/build/login-DPXKXUwG.mjs +2 -0
  12. package/.output/server/chunks/build/server.mjs +2 -0
  13. package/.output/server/chunks/routes/api/auth/_...all_.mjs +2 -0
  14. package/.output/server/chunks/routes/api/auth/_...all_.mjs.map +1 -1
  15. package/.output/server/chunks/routes/api/v1/_identifier_.get.mjs +2 -0
  16. package/.output/server/chunks/routes/api/v1/_identifier_.get.mjs.map +1 -1
  17. package/.output/server/chunks/routes/api/v1/refresh.post.mjs +2 -0
  18. package/.output/server/chunks/routes/api/v1/refresh.post.mjs.map +1 -1
  19. package/.output/server/chunks/routes/api/v1/sessions/_sessionId/messages.get.mjs +2 -0
  20. package/.output/server/chunks/routes/api/v1/sessions/_sessionId/messages.get.mjs.map +1 -1
  21. package/.output/server/chunks/routes/api/v1/state.get.mjs +2 -0
  22. package/.output/server/chunks/routes/api/v1/state.get.mjs.map +1 -1
  23. package/.output/server/chunks/routes/api/webhooks/asana.post.mjs +72 -0
  24. package/.output/server/chunks/routes/api/webhooks/asana.post.mjs.map +1 -0
  25. package/.output/server/chunks/routes/api/webhooks/github.post.mjs +3 -1
  26. package/.output/server/chunks/routes/api/webhooks/github.post.mjs.map +1 -1
  27. package/.output/server/chunks/routes/api/webhooks/slack.post.mjs +3 -1
  28. package/.output/server/chunks/routes/api/webhooks/slack.post.mjs.map +1 -1
  29. package/.output/server/chunks/routes/renderer.mjs +1 -1
  30. package/.output/server/index.mjs +126 -65
  31. package/.output/server/index.mjs.map +1 -1
  32. package/.output/server/node_modules/chat-adapter-asana/dist/index.js +312 -0
  33. package/.output/server/node_modules/chat-adapter-asana/package.json +66 -0
  34. package/.output/server/package.json +2 -1
  35. package/dist/index.js +2 -1
  36. package/package.json +3 -2
  37. package/.output/public/_nuxt/builds/meta/748a2baa-57b8-4080-8fea-335bbddd248e.json +0 -1
@@ -0,0 +1,312 @@
1
+ // src/adapter.ts
2
+ import { ValidationError } from "@chat-adapter/shared";
3
+ import { ConsoleLogger, Message, stringifyMarkdown as stringifyMarkdown2 } from "chat";
4
+
5
+ // src/api.ts
6
+ import { AuthenticationError, NetworkError, ResourceNotFoundError } from "@chat-adapter/shared";
7
+ var TIMEOUT_MS = 3e4;
8
+ var ADAPTER_NAME = "asana";
9
+ function createAsanaApiClient(accessToken, baseUrl) {
10
+ function headers() {
11
+ return {
12
+ "Authorization": `Bearer ${accessToken}`,
13
+ "Accept": "application/json",
14
+ "Content-Type": "application/json"
15
+ };
16
+ }
17
+ async function request(method, path, body) {
18
+ const url = `${baseUrl}${path}`;
19
+ let response;
20
+ try {
21
+ const ctrl = new AbortController();
22
+ const timeout = setTimeout(() => ctrl.abort(), TIMEOUT_MS);
23
+ response = await fetch(url, {
24
+ method,
25
+ headers: headers(),
26
+ body: body ? JSON.stringify(body) : void 0,
27
+ signal: ctrl.signal
28
+ });
29
+ clearTimeout(timeout);
30
+ } catch (cause) {
31
+ throw new NetworkError(ADAPTER_NAME, `Request failed: ${method} ${path}`, cause instanceof Error ? cause : void 0);
32
+ }
33
+ if (response.status === 401 || response.status === 403) {
34
+ throw new AuthenticationError(ADAPTER_NAME, `${response.status} on ${method} ${path}`);
35
+ }
36
+ if (response.status === 404) {
37
+ throw new ResourceNotFoundError(ADAPTER_NAME, "resource", path);
38
+ }
39
+ if (!response.ok) {
40
+ const text = await response.text().catch(() => "");
41
+ throw new NetworkError(ADAPTER_NAME, `${response.status} on ${method} ${path}: ${text}`);
42
+ }
43
+ if (response.status === 204 || method === "DELETE") {
44
+ return void 0;
45
+ }
46
+ const json = await response.json();
47
+ return json;
48
+ }
49
+ return {
50
+ async fetchTask(taskGid) {
51
+ const result = await request("GET", `/tasks/${taskGid}?opt_fields=gid,name,notes,assignee,assignee.name,created_at,modified_at`);
52
+ return result.data;
53
+ },
54
+ async fetchStories(taskGid, options) {
55
+ const limit = options?.limit ?? 50;
56
+ let path = `/tasks/${taskGid}/stories?opt_fields=gid,text,html_text,type,created_at,created_by,created_by.name,is_edited,likes,likes.user,likes.user.name,num_likes,target&limit=${limit}`;
57
+ if (options?.offset) {
58
+ path += `&offset=${encodeURIComponent(options.offset)}`;
59
+ }
60
+ const result = await request("GET", path);
61
+ return { data: result.data, next_page: result.next_page };
62
+ },
63
+ async postStory(taskGid, text, options) {
64
+ const result = await request("POST", `/tasks/${taskGid}/stories`, {
65
+ data: { text, is_pinned: options?.isPinned ?? false }
66
+ });
67
+ return result.data;
68
+ },
69
+ async updateStory(storyGid, text) {
70
+ const result = await request("PUT", `/stories/${storyGid}`, {
71
+ data: { text }
72
+ });
73
+ return result.data;
74
+ },
75
+ async deleteStory(storyGid) {
76
+ await request("DELETE", `/stories/${storyGid}`);
77
+ },
78
+ async likeStory(storyGid) {
79
+ await request("POST", `/stories/${storyGid}/addHeart`, { data: {} });
80
+ },
81
+ async unlikeStory(storyGid) {
82
+ await request("POST", `/stories/${storyGid}/removeHeart`, { data: {} });
83
+ }
84
+ };
85
+ }
86
+
87
+ // src/format-converter.ts
88
+ import { extractCard } from "@chat-adapter/shared";
89
+ import { parseMarkdown, stringifyMarkdown } from "chat";
90
+ function toAst(text) {
91
+ return parseMarkdown(text);
92
+ }
93
+ function fromAst(ast) {
94
+ return stringifyMarkdown(ast);
95
+ }
96
+ function renderPostable(message) {
97
+ if (typeof message === "string") {
98
+ return message;
99
+ }
100
+ const card = extractCard(message);
101
+ if (card) {
102
+ const lines = [];
103
+ if (card.title)
104
+ lines.push(card.title);
105
+ return lines.join("\n");
106
+ }
107
+ if ("markdown" in message && typeof message.markdown === "string") {
108
+ return message.markdown;
109
+ }
110
+ if ("ast" in message && message.ast) {
111
+ return fromAst(message.ast);
112
+ }
113
+ if ("text" in message && typeof message.text === "string") {
114
+ return message.text;
115
+ }
116
+ return "";
117
+ }
118
+
119
+ // src/webhook.ts
120
+ import { createHmac } from "crypto";
121
+ function isHandshake(request) {
122
+ return request.headers.get("x-hook-secret");
123
+ }
124
+ function createHandshakeResponse(secret) {
125
+ return new Response("", {
126
+ status: 200,
127
+ headers: { "X-Hook-Secret": secret }
128
+ });
129
+ }
130
+ function verifySignature(body, signature, secret) {
131
+ const hmac = createHmac("sha256", secret);
132
+ hmac.update(body);
133
+ const expected = hmac.digest("hex");
134
+ return expected === signature;
135
+ }
136
+ function extractStoryEvents(payload) {
137
+ if (!Array.isArray(payload.events))
138
+ return [];
139
+ return payload.events.filter(
140
+ (e) => e.resource.resource_type === "story" && e.action === "added" && e.parent?.resource_type === "task"
141
+ );
142
+ }
143
+
144
+ // src/adapter.ts
145
+ var AsanaAdapter = class {
146
+ name = "asana";
147
+ userName;
148
+ chat = null;
149
+ logger;
150
+ api;
151
+ webhookSecret = null;
152
+ botUserId;
153
+ constructor(config) {
154
+ this.userName = config.userName ?? "asana-bot";
155
+ this.logger = config.logger ?? new ConsoleLogger();
156
+ this.api = createAsanaApiClient(
157
+ config.accessToken,
158
+ config.baseUrl ?? "https://app.asana.com/api/1.0"
159
+ );
160
+ }
161
+ async initialize(chat) {
162
+ this.chat = chat;
163
+ this.logger = chat.getLogger("asana");
164
+ }
165
+ encodeThreadId(data) {
166
+ return `asana:${data.taskGid}`;
167
+ }
168
+ decodeThreadId(threadId) {
169
+ const parts = threadId.split(":");
170
+ if (parts.length !== 2 || parts[0] !== "asana" || !parts[1]) {
171
+ throw new ValidationError("asana", `Invalid Asana thread ID: ${threadId}`);
172
+ }
173
+ return { taskGid: parts[1] };
174
+ }
175
+ channelIdFromThreadId(threadId) {
176
+ return threadId;
177
+ }
178
+ async handleWebhook(request, options) {
179
+ const hookSecret = isHandshake(request);
180
+ if (hookSecret) {
181
+ this.webhookSecret = hookSecret;
182
+ this.logger.info("webhook handshake completed");
183
+ return createHandshakeResponse(hookSecret);
184
+ }
185
+ const signature = request.headers.get("x-hook-signature");
186
+ if (!signature) {
187
+ return new Response("Missing signature", { status: 401 });
188
+ }
189
+ const body = await request.text();
190
+ if (this.webhookSecret && !verifySignature(body, signature, this.webhookSecret)) {
191
+ return new Response("Invalid signature", { status: 401 });
192
+ }
193
+ let payload;
194
+ try {
195
+ payload = JSON.parse(body);
196
+ } catch {
197
+ return new Response("Invalid JSON", { status: 400 });
198
+ }
199
+ const storyEvents = extractStoryEvents(payload);
200
+ for (const event of storyEvents) {
201
+ if (!event.parent?.gid || !this.chat)
202
+ continue;
203
+ const taskGid = event.parent.gid;
204
+ const storyGid = event.resource.gid;
205
+ const threadId = this.encodeThreadId({ taskGid });
206
+ const factory = async () => {
207
+ const stories = await this.api.fetchStories(taskGid, { limit: 1 });
208
+ const story = stories.data.find((s) => s.gid === storyGid);
209
+ if (!story) {
210
+ throw new Error(`Story ${storyGid} not found on task ${taskGid}`);
211
+ }
212
+ return this.parseMessage(story);
213
+ };
214
+ this.chat.processMessage(this, threadId, factory, options);
215
+ }
216
+ return new Response("OK", { status: 200 });
217
+ }
218
+ parseMessage(raw) {
219
+ const threadId = raw.target?.gid ? this.encodeThreadId({ taskGid: raw.target.gid }) : "asana:unknown";
220
+ const isBotMessage = raw.created_by?.gid === this.botUserId;
221
+ return new Message({
222
+ id: raw.gid,
223
+ threadId,
224
+ text: raw.text ?? "",
225
+ formatted: toAst(raw.text ?? ""),
226
+ raw,
227
+ author: {
228
+ userId: raw.created_by?.gid ?? "unknown",
229
+ userName: raw.created_by?.name ?? "unknown",
230
+ fullName: raw.created_by?.name ?? "",
231
+ isBot: isBotMessage,
232
+ isMe: isBotMessage
233
+ },
234
+ metadata: {
235
+ dateSent: new Date(raw.created_at),
236
+ edited: raw.is_edited ?? false
237
+ },
238
+ attachments: []
239
+ });
240
+ }
241
+ async postMessage(threadId, message) {
242
+ const { taskGid } = this.decodeThreadId(threadId);
243
+ const text = renderPostable(message);
244
+ const story = await this.api.postStory(taskGid, text);
245
+ return { id: story.gid, threadId, raw: story };
246
+ }
247
+ async editMessage(threadId, messageId, message) {
248
+ const text = renderPostable(message);
249
+ const story = await this.api.updateStory(messageId, text);
250
+ return { id: story.gid, threadId, raw: story };
251
+ }
252
+ async deleteMessage(_threadId, messageId) {
253
+ await this.api.deleteStory(messageId);
254
+ }
255
+ async fetchMessages(threadId, options) {
256
+ const { taskGid } = this.decodeThreadId(threadId);
257
+ const limit = options?.limit ?? 50;
258
+ const offset = options?.cursor;
259
+ const result = await this.api.fetchStories(taskGid, { limit, offset });
260
+ const comments = result.data.filter((s) => s.type === "comment");
261
+ const messages = comments.map((s) => this.parseMessage(s));
262
+ return {
263
+ messages,
264
+ nextCursor: result.next_page?.offset
265
+ };
266
+ }
267
+ async fetchThread(threadId) {
268
+ const { taskGid } = this.decodeThreadId(threadId);
269
+ const task = await this.api.fetchTask(taskGid);
270
+ return {
271
+ id: threadId,
272
+ channelId: threadId,
273
+ channelName: task.name,
274
+ metadata: {
275
+ taskGid: task.gid,
276
+ taskName: task.name
277
+ }
278
+ };
279
+ }
280
+ async addReaction(threadId, messageId, _emoji) {
281
+ await this.api.likeStory(messageId);
282
+ }
283
+ async removeReaction(threadId, messageId, _emoji) {
284
+ await this.api.unlikeStory(messageId);
285
+ }
286
+ async startTyping(_threadId) {
287
+ }
288
+ renderFormatted(content) {
289
+ return stringifyMarkdown2(content);
290
+ }
291
+ };
292
+
293
+ // src/factory.ts
294
+ import process from "process";
295
+ function createAsanaAdapter(config) {
296
+ const accessToken = config?.accessToken ?? process.env.ASANA_ACCESS_TOKEN;
297
+ if (!accessToken) {
298
+ throw new Error("Asana adapter requires an access token. Set ASANA_ACCESS_TOKEN or pass accessToken in config.");
299
+ }
300
+ return new AsanaAdapter({
301
+ accessToken,
302
+ baseUrl: config?.baseUrl,
303
+ userName: config?.userName,
304
+ logger: config?.logger
305
+ });
306
+ }
307
+ export {
308
+ AsanaAdapter,
309
+ createAsanaAdapter,
310
+ createAsanaApiClient
311
+ };
312
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "chat-adapter-asana",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "description": "Asana adapter for Chat SDK — task comment threads",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/pleaseai/chat-adapter-asana#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/pleaseai/chat-adapter-asana.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/pleaseai/chat-adapter-asana/issues"
14
+ },
15
+ "keywords": [
16
+ "chat-sdk",
17
+ "chat-adapter",
18
+ "asana",
19
+ "bot",
20
+ "task-comments"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "main": "./dist/index.js",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "scripts": {
35
+ "build": "tsup",
36
+ "dev": "tsup --watch",
37
+ "test": "vitest run",
38
+ "test:watch": "vitest",
39
+ "test:coverage": "vitest run --coverage",
40
+ "typecheck": "tsc --noEmit",
41
+ "lint": "eslint .",
42
+ "lint:fix": "eslint . --fix",
43
+ "clean": "rm -rf dist"
44
+ },
45
+ "peerDependencies": {
46
+ "chat": "^4.0.0"
47
+ },
48
+ "dependencies": {
49
+ "@chat-adapter/shared": "^4.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@antfu/eslint-config": "^7.7.3",
53
+ "@chat-adapter/state-memory": "^4.0.0",
54
+ "@types/node": "^22.0.0",
55
+ "@vitest/coverage-v8": "^4.1.0",
56
+ "chat": "^4.20.2",
57
+ "eslint": "^10.0.3",
58
+ "tsup": "^8.3.0",
59
+ "turbo": "^2.8.20",
60
+ "typescript": "^5.7.0",
61
+ "vitest": "^4.0.0"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pleaseai/agent-prod",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "dependencies": {
@@ -64,6 +64,7 @@
64
64
  "ccount": "2.0.1",
65
65
  "character-entities": "2.0.2",
66
66
  "chat": "4.20.2",
67
+ "chat-adapter-asana": "0.1.0",
67
68
  "combined-stream": "1.0.8",
68
69
  "consola": "3.4.2",
69
70
  "cross-fetch": "4.1.0",
package/dist/index.js CHANGED
@@ -27670,7 +27670,7 @@ var {
27670
27670
  var package_default = {
27671
27671
  name: "@pleaseai/agent",
27672
27672
  type: "module",
27673
- version: "0.1.17",
27673
+ version: "0.1.19",
27674
27674
  description: "Autonomous coding agent for GitHub, Linear, and Slack",
27675
27675
  license: "FSL-1.1-MIT",
27676
27676
  repository: {
@@ -27714,6 +27714,7 @@ var package_default = {
27714
27714
  "@vueuse/nuxt": "^14.2.1",
27715
27715
  "better-auth": "^1.5.5",
27716
27716
  chat: "^4.20.2",
27717
+ "chat-adapter-asana": "^0.1.0",
27717
27718
  commander: "^14.0.3",
27718
27719
  nuxt: "^4.4.2",
27719
27720
  tailwindcss: "^4.2.2"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pleaseai/agent",
3
3
  "type": "module",
4
- "version": "0.1.17",
4
+ "version": "0.1.19",
5
5
  "description": "Autonomous coding agent for GitHub, Linear, and Slack",
6
6
  "license": "FSL-1.1-MIT",
7
7
  "repository": {
@@ -41,10 +41,11 @@
41
41
  "@chat-adapter/state-redis": "^4.20.2",
42
42
  "@nuxt/ui": "^4.5.1",
43
43
  "@octokit/graphql": "^9.0.3",
44
- "@pleaseai/agent-core": "0.1.2",
44
+ "@pleaseai/agent-core": "0.1.3",
45
45
  "@vueuse/nuxt": "^14.2.1",
46
46
  "better-auth": "^1.5.5",
47
47
  "chat": "^4.20.2",
48
+ "chat-adapter-asana": "^0.1.0",
48
49
  "commander": "^14.0.3",
49
50
  "nuxt": "^4.4.2",
50
51
  "tailwindcss": "^4.2.2"
@@ -1 +0,0 @@
1
- {"id":"748a2baa-57b8-4080-8fea-335bbddd248e","timestamp":1774063177315,"prerendered":[]}