@copilotkit/channels-slack 0.1.0

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 (141) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +353 -0
  3. package/dist/__tests__/assistant.test.d.ts +2 -0
  4. package/dist/__tests__/assistant.test.d.ts.map +1 -0
  5. package/dist/__tests__/assistant.test.js +153 -0
  6. package/dist/__tests__/auto-close-streaming.test.d.ts +2 -0
  7. package/dist/__tests__/auto-close-streaming.test.d.ts.map +1 -0
  8. package/dist/__tests__/auto-close-streaming.test.js +139 -0
  9. package/dist/__tests__/built-ins.test.d.ts +2 -0
  10. package/dist/__tests__/built-ins.test.d.ts.map +1 -0
  11. package/dist/__tests__/built-ins.test.js +67 -0
  12. package/dist/__tests__/chunked-message-stream.test.d.ts +2 -0
  13. package/dist/__tests__/chunked-message-stream.test.d.ts.map +1 -0
  14. package/dist/__tests__/chunked-message-stream.test.js +226 -0
  15. package/dist/__tests__/conversation-store.test.d.ts +2 -0
  16. package/dist/__tests__/conversation-store.test.d.ts.map +1 -0
  17. package/dist/__tests__/conversation-store.test.js +209 -0
  18. package/dist/__tests__/download-files.test.d.ts +2 -0
  19. package/dist/__tests__/download-files.test.d.ts.map +1 -0
  20. package/dist/__tests__/download-files.test.js +142 -0
  21. package/dist/__tests__/ephemeral.test.d.ts +2 -0
  22. package/dist/__tests__/ephemeral.test.d.ts.map +1 -0
  23. package/dist/__tests__/ephemeral.test.js +85 -0
  24. package/dist/__tests__/event-renderer.test.d.ts +2 -0
  25. package/dist/__tests__/event-renderer.test.d.ts.map +1 -0
  26. package/dist/__tests__/event-renderer.test.js +521 -0
  27. package/dist/__tests__/markdown-to-mrkdwn.test.d.ts +2 -0
  28. package/dist/__tests__/markdown-to-mrkdwn.test.d.ts.map +1 -0
  29. package/dist/__tests__/markdown-to-mrkdwn.test.js +80 -0
  30. package/dist/__tests__/message-stream.test.d.ts +2 -0
  31. package/dist/__tests__/message-stream.test.d.ts.map +1 -0
  32. package/dist/__tests__/message-stream.test.js +116 -0
  33. package/dist/__tests__/native-renderer.test.d.ts +2 -0
  34. package/dist/__tests__/native-renderer.test.d.ts.map +1 -0
  35. package/dist/__tests__/native-renderer.test.js +236 -0
  36. package/dist/__tests__/native-stream.test.d.ts +2 -0
  37. package/dist/__tests__/native-stream.test.d.ts.map +1 -0
  38. package/dist/__tests__/native-stream.test.js +235 -0
  39. package/dist/__tests__/reactions.test.d.ts +2 -0
  40. package/dist/__tests__/reactions.test.d.ts.map +1 -0
  41. package/dist/__tests__/reactions.test.js +193 -0
  42. package/dist/__tests__/slack-listener.test.d.ts +2 -0
  43. package/dist/__tests__/slack-listener.test.d.ts.map +1 -0
  44. package/dist/__tests__/slack-listener.test.js +559 -0
  45. package/dist/__tests__/views.test.d.ts +2 -0
  46. package/dist/__tests__/views.test.d.ts.map +1 -0
  47. package/dist/__tests__/views.test.js +143 -0
  48. package/dist/adapter.d.ts +188 -0
  49. package/dist/adapter.d.ts.map +1 -0
  50. package/dist/adapter.js +859 -0
  51. package/dist/adapter.test.d.ts +2 -0
  52. package/dist/adapter.test.d.ts.map +1 -0
  53. package/dist/adapter.test.js +368 -0
  54. package/dist/assistant.d.ts +19 -0
  55. package/dist/assistant.d.ts.map +1 -0
  56. package/dist/assistant.js +124 -0
  57. package/dist/auto-close-streaming.d.ts +62 -0
  58. package/dist/auto-close-streaming.d.ts.map +1 -0
  59. package/dist/auto-close-streaming.js +273 -0
  60. package/dist/built-in-context.d.ts +22 -0
  61. package/dist/built-in-context.d.ts.map +1 -0
  62. package/dist/built-in-context.js +65 -0
  63. package/dist/built-in-tools.d.ts +23 -0
  64. package/dist/built-in-tools.d.ts.map +1 -0
  65. package/dist/built-in-tools.js +45 -0
  66. package/dist/chunked-message-stream.d.ts +67 -0
  67. package/dist/chunked-message-stream.d.ts.map +1 -0
  68. package/dist/chunked-message-stream.js +134 -0
  69. package/dist/codec.d.ts +18 -0
  70. package/dist/codec.d.ts.map +1 -0
  71. package/dist/codec.js +18 -0
  72. package/dist/codec.test.d.ts +2 -0
  73. package/dist/codec.test.d.ts.map +1 -0
  74. package/dist/codec.test.js +19 -0
  75. package/dist/conversation-store.d.ts +92 -0
  76. package/dist/conversation-store.d.ts.map +1 -0
  77. package/dist/conversation-store.js +196 -0
  78. package/dist/download-files.d.ts +59 -0
  79. package/dist/download-files.d.ts.map +1 -0
  80. package/dist/download-files.js +116 -0
  81. package/dist/event-renderer.d.ts +98 -0
  82. package/dist/event-renderer.d.ts.map +1 -0
  83. package/dist/event-renderer.js +493 -0
  84. package/dist/index.d.ts +34 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +23 -0
  87. package/dist/ingress-normalize.d.ts +75 -0
  88. package/dist/ingress-normalize.d.ts.map +1 -0
  89. package/dist/ingress-normalize.js +153 -0
  90. package/dist/ingress-normalize.test.d.ts +2 -0
  91. package/dist/ingress-normalize.test.d.ts.map +1 -0
  92. package/dist/ingress-normalize.test.js +187 -0
  93. package/dist/interaction.d.ts +30 -0
  94. package/dist/interaction.d.ts.map +1 -0
  95. package/dist/interaction.js +219 -0
  96. package/dist/interaction.test.d.ts +2 -0
  97. package/dist/interaction.test.d.ts.map +1 -0
  98. package/dist/interaction.test.js +137 -0
  99. package/dist/markdown-to-mrkdwn.d.ts +21 -0
  100. package/dist/markdown-to-mrkdwn.d.ts.map +1 -0
  101. package/dist/markdown-to-mrkdwn.js +99 -0
  102. package/dist/message-stream.d.ts +44 -0
  103. package/dist/message-stream.d.ts.map +1 -0
  104. package/dist/message-stream.js +70 -0
  105. package/dist/native-stream.d.ts +131 -0
  106. package/dist/native-stream.d.ts.map +1 -0
  107. package/dist/native-stream.js +208 -0
  108. package/dist/render/block-kit.d.ts +35 -0
  109. package/dist/render/block-kit.d.ts.map +1 -0
  110. package/dist/render/block-kit.js +399 -0
  111. package/dist/render/block-kit.test.d.ts +2 -0
  112. package/dist/render/block-kit.test.d.ts.map +1 -0
  113. package/dist/render/block-kit.test.js +289 -0
  114. package/dist/render/budget.d.ts +24 -0
  115. package/dist/render/budget.d.ts.map +1 -0
  116. package/dist/render/budget.js +30 -0
  117. package/dist/render/budget.test.d.ts +2 -0
  118. package/dist/render/budget.test.d.ts.map +1 -0
  119. package/dist/render/budget.test.js +49 -0
  120. package/dist/render/modal.d.ts +13 -0
  121. package/dist/render/modal.d.ts.map +1 -0
  122. package/dist/render/modal.js +108 -0
  123. package/dist/render/transport.d.ts +42 -0
  124. package/dist/render/transport.d.ts.map +1 -0
  125. package/dist/render/transport.js +1 -0
  126. package/dist/render.d.ts +23 -0
  127. package/dist/render.d.ts.map +1 -0
  128. package/dist/render.js +20 -0
  129. package/dist/sanitizing-http-agent.d.ts +28 -0
  130. package/dist/sanitizing-http-agent.d.ts.map +1 -0
  131. package/dist/sanitizing-http-agent.js +51 -0
  132. package/dist/slack-listener.d.ts +73 -0
  133. package/dist/slack-listener.d.ts.map +1 -0
  134. package/dist/slack-listener.js +126 -0
  135. package/dist/slack-listener.test.d.ts +2 -0
  136. package/dist/slack-listener.test.d.ts.map +1 -0
  137. package/dist/slack-listener.test.js +115 -0
  138. package/dist/types.d.ts +153 -0
  139. package/dist/types.d.ts.map +1 -0
  140. package/dist/types.js +20 -0
  141. package/package.json +73 -0
@@ -0,0 +1,193 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { decodeReaction } from "../interaction.js";
3
+ describe("decodeReaction", () => {
4
+ it("maps a reaction_added event to an IncomingReaction", () => {
5
+ const evt = decodeReaction({
6
+ user: "U1",
7
+ reaction: "thumbsup",
8
+ item: { type: "message", channel: "C9", ts: "171.1" },
9
+ }, true);
10
+ expect(evt).toMatchObject({
11
+ rawEmoji: "thumbsup",
12
+ added: true,
13
+ user: { id: "U1" },
14
+ messageId: "171.1",
15
+ replyTarget: { channel: "C9" },
16
+ });
17
+ expect(evt.conversationKey).toBe("C9::171.1");
18
+ });
19
+ it("uses DM_SCOPE for direct-message channels", () => {
20
+ const evt = decodeReaction({
21
+ user: "U1",
22
+ reaction: "x",
23
+ item: { type: "message", channel: "D2", ts: "9.9" },
24
+ }, false);
25
+ expect(evt.added).toBe(false);
26
+ expect(evt.conversationKey).toBe("D2::dm");
27
+ });
28
+ it("threads the reply target under the reacted message in a channel", () => {
29
+ const evt = decodeReaction({
30
+ user: "U1",
31
+ reaction: "thumbsup",
32
+ item: { type: "message", channel: "C9", ts: "171.1" },
33
+ }, true);
34
+ expect(evt.replyTarget.threadTs).toBe("171.1");
35
+ });
36
+ it("carries the reactor id as recipientUserId on a channel reply target", () => {
37
+ // chat.startStream requires recipient_user_id when streaming to a channel.
38
+ // The reaction reply target must carry it (parity with onTurn) so a native
39
+ // channel stream started from a reaction does not fail and process-wide
40
+ // downgrade nativeStreamingOk.
41
+ const evt = decodeReaction({
42
+ user: "U1",
43
+ reaction: "thumbsup",
44
+ item: { type: "message", channel: "C9", ts: "171.1" },
45
+ }, true);
46
+ expect(evt.replyTarget.recipientUserId).toBe("U1");
47
+ });
48
+ it("keeps the reply target flat (no threadTs) for a DM reaction", () => {
49
+ const evt = decodeReaction({
50
+ user: "U1",
51
+ reaction: "x",
52
+ item: { type: "message", channel: "D2", ts: "9.9" },
53
+ }, false);
54
+ expect(evt.replyTarget.threadTs).toBeUndefined();
55
+ });
56
+ it("ignores non-message reaction items", () => {
57
+ expect(decodeReaction({ user: "U1", reaction: "x", item: { type: "file", file: "F1" } }, true)).toBeUndefined();
58
+ });
59
+ });
60
+ const BOT_USER_ID = "UBOT0001";
61
+ /**
62
+ * A permissive fake Bolt app that records the `reaction_added`/`reaction_removed`
63
+ * handlers registered during `start()` and no-ops every other registration
64
+ * (message/event/action/view/command) the adapter and its sub-listeners attach.
65
+ */
66
+ function makeFakeApp() {
67
+ const handlers = {};
68
+ const app = {
69
+ init: vi.fn().mockResolvedValue(undefined),
70
+ start: vi.fn().mockResolvedValue(undefined),
71
+ stop: vi.fn().mockResolvedValue(undefined),
72
+ event(name, handler) {
73
+ handlers[name] = handler;
74
+ },
75
+ message() { },
76
+ action() { },
77
+ view() { },
78
+ command() { },
79
+ assistant() { },
80
+ use() { },
81
+ };
82
+ return {
83
+ app,
84
+ fireReaction: (name, event) => handlers[name]?.({ event }),
85
+ };
86
+ }
87
+ function makeSink() {
88
+ return {
89
+ onTurn: vi.fn().mockResolvedValue(undefined),
90
+ onCommand: vi.fn().mockResolvedValue(undefined),
91
+ onInteraction: vi.fn().mockResolvedValue(undefined),
92
+ onReaction: vi.fn().mockResolvedValue(undefined),
93
+ onModalSubmit: vi.fn().mockResolvedValue(undefined),
94
+ onModalClose: vi.fn().mockResolvedValue(undefined),
95
+ };
96
+ }
97
+ describe("adapter reaction ingress loop guard", () => {
98
+ async function startWithFakes() {
99
+ const { SlackAdapter } = await import("../adapter.js");
100
+ // Disable the assistant middleware so start() takes the simplest listener path.
101
+ const adapter = new SlackAdapter({
102
+ botToken: "xoxb",
103
+ appToken: "xapp",
104
+ signingSecret: "s",
105
+ assistant: false,
106
+ });
107
+ const { app, fireReaction } = makeFakeApp();
108
+ adapter.app = app;
109
+ const usersInfo = vi.fn().mockResolvedValue({
110
+ user: {
111
+ id: "UHUMAN",
112
+ name: "humanuser",
113
+ real_name: "Human User",
114
+ profile: { email: "human@example.com" },
115
+ },
116
+ });
117
+ adapter.client = {
118
+ auth: {
119
+ test: vi
120
+ .fn()
121
+ .mockResolvedValue({ user_id: BOT_USER_ID, team_id: "T1" }),
122
+ },
123
+ users: { info: usersInfo },
124
+ };
125
+ const sink = makeSink();
126
+ await adapter.start(sink);
127
+ return { fireReaction, sink, usersInfo };
128
+ }
129
+ it("does NOT dispatch the bot's OWN reaction to sink.onReaction", async () => {
130
+ const { fireReaction, sink } = await startWithFakes();
131
+ await fireReaction("reaction_added", {
132
+ user: BOT_USER_ID,
133
+ reaction: "thumbsup",
134
+ item: { type: "message", channel: "C9", ts: "171.1" },
135
+ });
136
+ expect(sink.onReaction).not.toHaveBeenCalled();
137
+ });
138
+ it("DOES dispatch a normal user's reaction to sink.onReaction", async () => {
139
+ const { fireReaction, sink } = await startWithFakes();
140
+ await fireReaction("reaction_added", {
141
+ user: "UHUMAN",
142
+ reaction: "thumbsup",
143
+ item: { type: "message", channel: "C9", ts: "171.1" },
144
+ });
145
+ expect(sink.onReaction).toHaveBeenCalledTimes(1);
146
+ });
147
+ it("enriches the reaction user via resolveUser (name + email), not a bare {id}", async () => {
148
+ const { fireReaction, sink, usersInfo } = await startWithFakes();
149
+ await fireReaction("reaction_added", {
150
+ user: "UHUMAN",
151
+ reaction: "thumbsup",
152
+ item: { type: "message", channel: "C9", ts: "171.1" },
153
+ });
154
+ expect(usersInfo).toHaveBeenCalledWith({ user: "UHUMAN" });
155
+ const evt = sink.onReaction.mock.calls[0]?.[0];
156
+ expect(evt.user).toEqual({
157
+ id: "UHUMAN",
158
+ name: "Human User",
159
+ email: "human@example.com",
160
+ });
161
+ });
162
+ it("enriches the reaction user on reaction_removed too", async () => {
163
+ const { fireReaction, sink } = await startWithFakes();
164
+ await fireReaction("reaction_removed", {
165
+ user: "UHUMAN",
166
+ reaction: "thumbsup",
167
+ item: { type: "message", channel: "C9", ts: "171.1" },
168
+ });
169
+ const evt = sink.onReaction.mock.calls[0]?.[0];
170
+ expect(evt.user).toMatchObject({ name: "Human User" });
171
+ });
172
+ });
173
+ describe("adapter reaction egress", () => {
174
+ it("calls reactions.add with the resolved Slack shortcode", async () => {
175
+ const { SlackAdapter } = await import("../adapter.js");
176
+ const adapter = new SlackAdapter({
177
+ botToken: "xoxb",
178
+ appToken: "xapp",
179
+ signingSecret: "s",
180
+ });
181
+ const add = vi.fn().mockResolvedValue({ ok: true });
182
+ adapter.client = {
183
+ reactions: { add, remove: vi.fn().mockResolvedValue({ ok: true }) },
184
+ };
185
+ const res = await adapter.addReaction({ channel: "C1" }, { id: "1.2", channel: "C1" }, "thumbs_up");
186
+ expect(res).toEqual({ ok: true });
187
+ expect(add).toHaveBeenCalledWith({
188
+ channel: "C1",
189
+ timestamp: "1.2",
190
+ name: "+1",
191
+ });
192
+ });
193
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=slack-listener.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-listener.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/slack-listener.test.ts"],"names":[],"mappings":""}