@ai-devkit/channel-connector 0.13.2 → 0.13.4

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 (69) hide show
  1. package/dist/ChannelConfigRepository.d.ts +1 -1
  2. package/dist/ChannelConfigRepository.d.ts.map +1 -1
  3. package/dist/ChannelConfigRepository.js +13 -13
  4. package/dist/ChannelConfigRepository.js.map +1 -1
  5. package/dist/ChannelManager.d.ts +1 -1
  6. package/dist/ChannelManager.d.ts.map +1 -1
  7. package/dist/ChannelManager.js +9 -9
  8. package/dist/ChannelManager.js.map +1 -1
  9. package/dist/__tests__/ChannelConfigRepository.test.js +72 -72
  10. package/dist/__tests__/ChannelConfigRepository.test.js.map +1 -1
  11. package/dist/__tests__/ChannelManager.test.js +26 -26
  12. package/dist/__tests__/ChannelManager.test.js.map +1 -1
  13. package/dist/__tests__/adapters/slack/SlackAdapter.test.js +137 -137
  14. package/dist/__tests__/adapters/slack/SlackAdapter.test.js.map +1 -1
  15. package/dist/__tests__/adapters/slack/SlackMessageDelivery.test.js +36 -36
  16. package/dist/__tests__/adapters/slack/SlackMessageDelivery.test.js.map +1 -1
  17. package/dist/__tests__/adapters/slack/slackMarkdown.test.js +25 -25
  18. package/dist/__tests__/adapters/slack/slackMarkdown.test.js.map +1 -1
  19. package/dist/__tests__/adapters/slack/slackQuestion.test.js +41 -41
  20. package/dist/__tests__/adapters/slack/slackQuestion.test.js.map +1 -1
  21. package/dist/__tests__/adapters/telegram/TelegramAdapter.test.js +154 -154
  22. package/dist/__tests__/adapters/telegram/TelegramAdapter.test.js.map +1 -1
  23. package/dist/__tests__/adapters/telegram/telegramHtml.test.js +109 -109
  24. package/dist/__tests__/adapters/telegram/telegramHtml.test.js.map +1 -1
  25. package/dist/adapters/ChannelAdapter.d.ts +1 -1
  26. package/dist/adapters/ChannelAdapter.d.ts.map +1 -1
  27. package/dist/adapters/ChannelAdapter.js +1 -1
  28. package/dist/adapters/ChannelAdapter.js.map +1 -1
  29. package/dist/adapters/slack/SlackAdapter.d.ts +2 -2
  30. package/dist/adapters/slack/SlackAdapter.d.ts.map +1 -1
  31. package/dist/adapters/slack/SlackAdapter.js +17 -17
  32. package/dist/adapters/slack/SlackAdapter.js.map +1 -1
  33. package/dist/adapters/slack/SlackMessageDelivery.d.ts +1 -1
  34. package/dist/adapters/slack/SlackMessageDelivery.d.ts.map +1 -1
  35. package/dist/adapters/slack/SlackMessageDelivery.js +6 -6
  36. package/dist/adapters/slack/SlackMessageDelivery.js.map +1 -1
  37. package/dist/adapters/slack/slackMarkdown.d.ts.map +1 -1
  38. package/dist/adapters/slack/slackMarkdown.js +36 -36
  39. package/dist/adapters/slack/slackMarkdown.js.map +1 -1
  40. package/dist/adapters/slack/slackQuestion.d.ts +7 -7
  41. package/dist/adapters/slack/slackQuestion.d.ts.map +1 -1
  42. package/dist/adapters/slack/slackQuestion.js +13 -13
  43. package/dist/adapters/slack/slackQuestion.js.map +1 -1
  44. package/dist/adapters/telegram/TelegramAdapter.d.ts +2 -2
  45. package/dist/adapters/telegram/TelegramAdapter.d.ts.map +1 -1
  46. package/dist/adapters/telegram/TelegramAdapter.js +30 -27
  47. package/dist/adapters/telegram/TelegramAdapter.js.map +1 -1
  48. package/dist/adapters/telegram/TelegramMessageDelivery.d.ts.map +1 -1
  49. package/dist/adapters/telegram/TelegramMessageDelivery.js +2 -2
  50. package/dist/adapters/telegram/TelegramMessageDelivery.js.map +1 -1
  51. package/dist/adapters/telegram/telegramHtml.d.ts.map +1 -1
  52. package/dist/adapters/telegram/telegramHtml.js +16 -16
  53. package/dist/adapters/telegram/telegramHtml.js.map +1 -1
  54. package/dist/adapters/telegram/telegramKeyboard.d.ts +1 -1
  55. package/dist/adapters/telegram/telegramKeyboard.d.ts.map +1 -1
  56. package/dist/adapters/telegram/telegramKeyboard.js.map +1 -1
  57. package/dist/adapters/telegram/telegramMarkdown.d.ts.map +1 -1
  58. package/dist/adapters/telegram/telegramMarkdown.js +28 -28
  59. package/dist/adapters/telegram/telegramMarkdown.js.map +1 -1
  60. package/dist/index.d.ts +9 -9
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +5 -5
  63. package/dist/index.js.map +1 -1
  64. package/dist/types.d.ts +6 -6
  65. package/dist/types.d.ts.map +1 -1
  66. package/dist/types.js +1 -1
  67. package/dist/types.js.map +1 -1
  68. package/package.json +21 -22
  69. package/vitest.config.ts +16 -16
@@ -1,41 +1,41 @@
1
- import { SlackMessageDelivery } from '../../../adapters/slack/SlackMessageDelivery.js';
2
- describe('SlackMessageDelivery', ()=>{
3
- it('serializes long output as a parent followed by threaded continuations', async ()=>{
1
+ import { SlackMessageDelivery } from "../../../adapters/slack/SlackMessageDelivery.js";
2
+ describe("SlackMessageDelivery", ()=>{
3
+ it("serializes long output as a parent followed by threaded continuations", async ()=>{
4
4
  const postMessage = vi.fn().mockResolvedValueOnce({
5
5
  ok: true,
6
- ts: '100.1'
6
+ ts: "100.1"
7
7
  }).mockResolvedValue({
8
8
  ok: true,
9
- ts: '100.2'
9
+ ts: "100.2"
10
10
  });
11
11
  const queue = new SlackMessageDelivery({
12
12
  postMessage
13
13
  }, {
14
14
  maxMessageLength: 20
15
15
  });
16
- const result = await queue.send('D123', 'first paragraph\n\nsecond paragraph that is long');
16
+ const result = await queue.send("D123", "first paragraph\n\nsecond paragraph that is long");
17
17
  expect(result).toEqual({
18
- messageId: '100.1',
19
- threadId: '100.1'
18
+ messageId: "100.1",
19
+ threadId: "100.1"
20
20
  });
21
21
  expect(postMessage).toHaveBeenCalledTimes(3);
22
- expect(postMessage.mock.calls[0][0]).not.toHaveProperty('thread_ts');
22
+ expect(postMessage.mock.calls[0][0]).not.toHaveProperty("thread_ts");
23
23
  expect(postMessage.mock.calls[1][0]).toMatchObject({
24
- channel: 'D123',
25
- thread_ts: '100.1'
24
+ channel: "D123",
25
+ thread_ts: "100.1"
26
26
  });
27
27
  expect(postMessage.mock.calls[2][0]).toMatchObject({
28
- channel: 'D123',
29
- thread_ts: '100.1'
28
+ channel: "D123",
29
+ thread_ts: "100.1"
30
30
  });
31
31
  });
32
- it('waits for retryAfter before retrying a rate-limited API call', async ()=>{
33
- const error = Object.assign(new Error('rate limited'), {
32
+ it("waits for retryAfter before retrying a rate-limited API call", async ()=>{
33
+ const error = Object.assign(new Error("rate limited"), {
34
34
  retryAfter: 2
35
35
  });
36
36
  const postMessage = vi.fn().mockRejectedValueOnce(error).mockResolvedValue({
37
37
  ok: true,
38
- ts: '200.1'
38
+ ts: "200.1"
39
39
  });
40
40
  const sleep = vi.fn().mockResolvedValue(undefined);
41
41
  const queue = new SlackMessageDelivery({
@@ -43,20 +43,20 @@ describe('SlackMessageDelivery', ()=>{
43
43
  }, {
44
44
  sleep
45
45
  });
46
- await expect(queue.send('D123', 'hello')).resolves.toEqual({
47
- messageId: '200.1',
48
- threadId: '200.1'
46
+ await expect(queue.send("D123", "hello")).resolves.toEqual({
47
+ messageId: "200.1",
48
+ threadId: "200.1"
49
49
  });
50
50
  expect(sleep).toHaveBeenCalledWith(2000);
51
51
  expect(postMessage).toHaveBeenCalledTimes(2);
52
52
  });
53
- it('caps an excessive rate-limit delay', async ()=>{
54
- const error = Object.assign(new Error('rate limited'), {
53
+ it("caps an excessive rate-limit delay", async ()=>{
54
+ const error = Object.assign(new Error("rate limited"), {
55
55
  retryAfter: 86_400
56
56
  });
57
57
  const postMessage = vi.fn().mockRejectedValueOnce(error).mockResolvedValue({
58
58
  ok: true,
59
- ts: '200.1'
59
+ ts: "200.1"
60
60
  });
61
61
  const sleep = vi.fn().mockResolvedValue(undefined);
62
62
  const queue = new SlackMessageDelivery({
@@ -64,15 +64,15 @@ describe('SlackMessageDelivery', ()=>{
64
64
  }, {
65
65
  sleep
66
66
  });
67
- await queue.send('D123', 'hello');
67
+ await queue.send("D123", "hello");
68
68
  expect(sleep).toHaveBeenCalledWith(60_000);
69
69
  });
70
- it('rejects overflow while a conversation send is pending', async ()=>{
70
+ it("rejects overflow while a conversation send is pending", async ()=>{
71
71
  let release;
72
72
  const pending = new Promise((resolve)=>{
73
73
  release = ()=>resolve({
74
74
  ok: true,
75
- ts: '300.1'
75
+ ts: "300.1"
76
76
  });
77
77
  });
78
78
  const postMessage = vi.fn().mockReturnValue(pending);
@@ -81,34 +81,34 @@ describe('SlackMessageDelivery', ()=>{
81
81
  }, {
82
82
  maxQueueSize: 1
83
83
  });
84
- const first = queue.send('D123', 'first');
85
- await expect(queue.send('D123', 'second')).rejects.toThrow('Slack message delivery queue is full');
84
+ const first = queue.send("D123", "first");
85
+ await expect(queue.send("D123", "second")).rejects.toThrow("Slack message delivery queue is full");
86
86
  release();
87
87
  await first;
88
88
  });
89
- it('rejects empty output and responses without a timestamp', async ()=>{
89
+ it("rejects empty output and responses without a timestamp", async ()=>{
90
90
  const postMessage = vi.fn().mockResolvedValue({
91
91
  ok: true
92
92
  });
93
93
  const queue = new SlackMessageDelivery({
94
94
  postMessage
95
95
  });
96
- await expect(queue.send('D123', '')).rejects.toThrow('Cannot send an empty Slack message');
97
- await expect(queue.send('D123', 'hello')).rejects.toThrow('Slack did not return a message timestamp');
96
+ await expect(queue.send("D123", "")).rejects.toThrow("Cannot send an empty Slack message");
97
+ await expect(queue.send("D123", "hello")).rejects.toThrow("Slack did not return a message timestamp");
98
98
  });
99
- it('propagates permanent and invalid rate-limit errors without sleeping', async ()=>{
99
+ it("propagates permanent and invalid rate-limit errors without sleeping", async ()=>{
100
100
  const sleep = vi.fn();
101
- const permanent = new Error('invalid_auth');
101
+ const permanent = new Error("invalid_auth");
102
102
  const postMessage = vi.fn().mockRejectedValue(permanent);
103
103
  const queue = new SlackMessageDelivery({
104
104
  postMessage
105
105
  }, {
106
106
  sleep
107
107
  });
108
- await expect(queue.send('D123', 'hello')).rejects.toBe(permanent);
108
+ await expect(queue.send("D123", "hello")).rejects.toBe(permanent);
109
109
  expect(sleep).not.toHaveBeenCalled();
110
110
  });
111
- it('allows separate conversation queues to progress independently', async ()=>{
111
+ it("allows separate conversation queues to progress independently", async ()=>{
112
112
  const postMessage = vi.fn().mockImplementation(async ({ channel })=>({
113
113
  ok: true,
114
114
  ts: `${channel}.1`
@@ -117,8 +117,8 @@ describe('SlackMessageDelivery', ()=>{
117
117
  postMessage
118
118
  });
119
119
  await expect(Promise.all([
120
- queue.send('D1', 'one'),
121
- queue.send('D2', 'two')
120
+ queue.send("D1", "one"),
121
+ queue.send("D2", "two")
122
122
  ])).resolves.toHaveLength(2);
123
123
  expect(postMessage).toHaveBeenCalledTimes(2);
124
124
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/__tests__/adapters/slack/SlackMessageDelivery.test.ts"],"sourcesContent":["import { SlackMessageDelivery } from '../../../adapters/slack/SlackMessageDelivery.js';\n\ndescribe('SlackMessageDelivery', () => {\n it('serializes long output as a parent followed by threaded continuations', async () => {\n const postMessage = vi.fn()\n .mockResolvedValueOnce({ ok: true, ts: '100.1' })\n .mockResolvedValue({ ok: true, ts: '100.2' });\n const queue = new SlackMessageDelivery({ postMessage }, { maxMessageLength: 20 });\n const result = await queue.send('D123', 'first paragraph\\n\\nsecond paragraph that is long');\n expect(result).toEqual({ messageId: '100.1', threadId: '100.1' });\n expect(postMessage).toHaveBeenCalledTimes(3);\n expect(postMessage.mock.calls[0][0]).not.toHaveProperty('thread_ts');\n expect(postMessage.mock.calls[1][0]).toMatchObject({ channel: 'D123', thread_ts: '100.1' });\n expect(postMessage.mock.calls[2][0]).toMatchObject({ channel: 'D123', thread_ts: '100.1' });\n });\n\n it('waits for retryAfter before retrying a rate-limited API call', async () => {\n const error = Object.assign(new Error('rate limited'), { retryAfter: 2 });\n const postMessage = vi.fn().mockRejectedValueOnce(error).mockResolvedValue({ ok: true, ts: '200.1' });\n const sleep = vi.fn().mockResolvedValue(undefined);\n const queue = new SlackMessageDelivery({ postMessage }, { sleep });\n await expect(queue.send('D123', 'hello')).resolves.toEqual({ messageId: '200.1', threadId: '200.1' });\n expect(sleep).toHaveBeenCalledWith(2000);\n expect(postMessage).toHaveBeenCalledTimes(2);\n });\n\n it('caps an excessive rate-limit delay', async () => {\n const error = Object.assign(new Error('rate limited'), { retryAfter: 86_400 });\n const postMessage = vi.fn().mockRejectedValueOnce(error).mockResolvedValue({ ok: true, ts: '200.1' });\n const sleep = vi.fn().mockResolvedValue(undefined);\n const queue = new SlackMessageDelivery({ postMessage }, { sleep });\n await queue.send('D123', 'hello');\n expect(sleep).toHaveBeenCalledWith(60_000);\n });\n\n it('rejects overflow while a conversation send is pending', async () => {\n let release!: () => void;\n const pending = new Promise<{ ok: true; ts: string }>((resolve) => {\n release = () => resolve({ ok: true, ts: '300.1' });\n });\n const postMessage = vi.fn().mockReturnValue(pending);\n const queue = new SlackMessageDelivery({ postMessage }, { maxQueueSize: 1 });\n const first = queue.send('D123', 'first');\n await expect(queue.send('D123', 'second')).rejects.toThrow('Slack message delivery queue is full');\n release();\n await first;\n });\n\n it('rejects empty output and responses without a timestamp', async () => {\n const postMessage = vi.fn().mockResolvedValue({ ok: true });\n const queue = new SlackMessageDelivery({ postMessage });\n await expect(queue.send('D123', '')).rejects.toThrow('Cannot send an empty Slack message');\n await expect(queue.send('D123', 'hello')).rejects.toThrow('Slack did not return a message timestamp');\n });\n\n it('propagates permanent and invalid rate-limit errors without sleeping', async () => {\n const sleep = vi.fn();\n const permanent = new Error('invalid_auth');\n const postMessage = vi.fn().mockRejectedValue(permanent);\n const queue = new SlackMessageDelivery({ postMessage }, { sleep });\n await expect(queue.send('D123', 'hello')).rejects.toBe(permanent);\n expect(sleep).not.toHaveBeenCalled();\n });\n\n it('allows separate conversation queues to progress independently', async () => {\n const postMessage = vi.fn().mockImplementation(async ({ channel }) => ({ ok: true, ts: `${channel}.1` }));\n const queue = new SlackMessageDelivery({ postMessage });\n await expect(Promise.all([queue.send('D1', 'one'), queue.send('D2', 'two')])).resolves.toHaveLength(2);\n expect(postMessage).toHaveBeenCalledTimes(2);\n });\n});\n"],"names":["SlackMessageDelivery","describe","it","postMessage","vi","fn","mockResolvedValueOnce","ok","ts","mockResolvedValue","queue","maxMessageLength","result","send","expect","toEqual","messageId","threadId","toHaveBeenCalledTimes","mock","calls","not","toHaveProperty","toMatchObject","channel","thread_ts","error","Object","assign","Error","retryAfter","mockRejectedValueOnce","sleep","undefined","resolves","toHaveBeenCalledWith","release","pending","Promise","resolve","mockReturnValue","maxQueueSize","first","rejects","toThrow","permanent","mockRejectedValue","toBe","toHaveBeenCalled","mockImplementation","all","toHaveLength"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/__tests__/adapters/slack/SlackMessageDelivery.test.ts"],"sourcesContent":["import { SlackMessageDelivery } from \"../../../adapters/slack/SlackMessageDelivery.js\";\n\ndescribe(\"SlackMessageDelivery\", () => {\n it(\"serializes long output as a parent followed by threaded continuations\", async () => {\n const postMessage = vi\n .fn()\n .mockResolvedValueOnce({ ok: true, ts: \"100.1\" })\n .mockResolvedValue({ ok: true, ts: \"100.2\" });\n const queue = new SlackMessageDelivery({ postMessage }, { maxMessageLength: 20 });\n const result = await queue.send(\"D123\", \"first paragraph\\n\\nsecond paragraph that is long\");\n expect(result).toEqual({ messageId: \"100.1\", threadId: \"100.1\" });\n expect(postMessage).toHaveBeenCalledTimes(3);\n expect(postMessage.mock.calls[0][0]).not.toHaveProperty(\"thread_ts\");\n expect(postMessage.mock.calls[1][0]).toMatchObject({ channel: \"D123\", thread_ts: \"100.1\" });\n expect(postMessage.mock.calls[2][0]).toMatchObject({ channel: \"D123\", thread_ts: \"100.1\" });\n });\n\n it(\"waits for retryAfter before retrying a rate-limited API call\", async () => {\n const error = Object.assign(new Error(\"rate limited\"), { retryAfter: 2 });\n const postMessage = vi\n .fn()\n .mockRejectedValueOnce(error)\n .mockResolvedValue({ ok: true, ts: \"200.1\" });\n const sleep = vi.fn().mockResolvedValue(undefined);\n const queue = new SlackMessageDelivery({ postMessage }, { sleep });\n await expect(queue.send(\"D123\", \"hello\")).resolves.toEqual({\n messageId: \"200.1\",\n threadId: \"200.1\",\n });\n expect(sleep).toHaveBeenCalledWith(2000);\n expect(postMessage).toHaveBeenCalledTimes(2);\n });\n\n it(\"caps an excessive rate-limit delay\", async () => {\n const error = Object.assign(new Error(\"rate limited\"), { retryAfter: 86_400 });\n const postMessage = vi\n .fn()\n .mockRejectedValueOnce(error)\n .mockResolvedValue({ ok: true, ts: \"200.1\" });\n const sleep = vi.fn().mockResolvedValue(undefined);\n const queue = new SlackMessageDelivery({ postMessage }, { sleep });\n await queue.send(\"D123\", \"hello\");\n expect(sleep).toHaveBeenCalledWith(60_000);\n });\n\n it(\"rejects overflow while a conversation send is pending\", async () => {\n let release!: () => void;\n const pending = new Promise<{ ok: true; ts: string }>((resolve) => {\n release = () => resolve({ ok: true, ts: \"300.1\" });\n });\n const postMessage = vi.fn().mockReturnValue(pending);\n const queue = new SlackMessageDelivery({ postMessage }, { maxQueueSize: 1 });\n const first = queue.send(\"D123\", \"first\");\n await expect(queue.send(\"D123\", \"second\")).rejects.toThrow(\n \"Slack message delivery queue is full\",\n );\n release();\n await first;\n });\n\n it(\"rejects empty output and responses without a timestamp\", async () => {\n const postMessage = vi.fn().mockResolvedValue({ ok: true });\n const queue = new SlackMessageDelivery({ postMessage });\n await expect(queue.send(\"D123\", \"\")).rejects.toThrow(\"Cannot send an empty Slack message\");\n await expect(queue.send(\"D123\", \"hello\")).rejects.toThrow(\n \"Slack did not return a message timestamp\",\n );\n });\n\n it(\"propagates permanent and invalid rate-limit errors without sleeping\", async () => {\n const sleep = vi.fn();\n const permanent = new Error(\"invalid_auth\");\n const postMessage = vi.fn().mockRejectedValue(permanent);\n const queue = new SlackMessageDelivery({ postMessage }, { sleep });\n await expect(queue.send(\"D123\", \"hello\")).rejects.toBe(permanent);\n expect(sleep).not.toHaveBeenCalled();\n });\n\n it(\"allows separate conversation queues to progress independently\", async () => {\n const postMessage = vi\n .fn()\n .mockImplementation(async ({ channel }) => ({ ok: true, ts: `${channel}.1` }));\n const queue = new SlackMessageDelivery({ postMessage });\n await expect(\n Promise.all([queue.send(\"D1\", \"one\"), queue.send(\"D2\", \"two\")]),\n ).resolves.toHaveLength(2);\n expect(postMessage).toHaveBeenCalledTimes(2);\n });\n});\n"],"names":["SlackMessageDelivery","describe","it","postMessage","vi","fn","mockResolvedValueOnce","ok","ts","mockResolvedValue","queue","maxMessageLength","result","send","expect","toEqual","messageId","threadId","toHaveBeenCalledTimes","mock","calls","not","toHaveProperty","toMatchObject","channel","thread_ts","error","Object","assign","Error","retryAfter","mockRejectedValueOnce","sleep","undefined","resolves","toHaveBeenCalledWith","release","pending","Promise","resolve","mockReturnValue","maxQueueSize","first","rejects","toThrow","permanent","mockRejectedValue","toBe","toHaveBeenCalled","mockImplementation","all","toHaveLength"],"mappings":"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"}
@@ -1,41 +1,41 @@
1
- import { SLACK_MAX_MESSAGE_LENGTH, chunkMarkdownForSlack, markdownToSlackMrkdwn } from '../../../adapters/slack/slackMarkdown.js';
2
- describe('Slack Markdown', ()=>{
3
- it('renders common Markdown without activating broad mentions', ()=>{
4
- expect(markdownToSlackMrkdwn('# Result\n\n**Passed** & <safe> @channel [docs](https://example.com)')).toBe('*Result*\n\n*Passed* &amp; &lt;safe&gt; @channel <https://example.com|docs>');
1
+ import { SLACK_MAX_MESSAGE_LENGTH, chunkMarkdownForSlack, markdownToSlackMrkdwn } from "../../../adapters/slack/slackMarkdown.js";
2
+ describe("Slack Markdown", ()=>{
3
+ it("renders common Markdown without activating broad mentions", ()=>{
4
+ expect(markdownToSlackMrkdwn("# Result\n\n**Passed** & <safe> @channel [docs](https://example.com)")).toBe("*Result*\n\n*Passed* &amp; &lt;safe&gt; @channel <https://example.com|docs>");
5
5
  });
6
- it('preserves inline and fenced code while escaping Slack control characters', ()=>{
6
+ it("preserves inline and fenced code while escaping Slack control characters", ()=>{
7
7
  expect(markdownToSlackMrkdwn('Use `<tag>`\n\n```ts\nconst x = "<ok>";\n```')).toContain('`&lt;tag&gt;`\n\n```\nconst x = "&lt;ok&gt;";\n```');
8
8
  });
9
- it('chunks long fenced code into independently fenced Slack messages', ()=>{
10
- const chunks = chunkMarkdownForSlack(`\`\`\`ts\n${'const value = 1;\n'.repeat(400)}\`\`\``);
9
+ it("chunks long fenced code into independently fenced Slack messages", ()=>{
10
+ const chunks = chunkMarkdownForSlack(`\`\`\`ts\n${"const value = 1;\n".repeat(400)}\`\`\``);
11
11
  expect(chunks.length).toBeGreaterThan(1);
12
12
  expect(chunks.every((chunk)=>chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);
13
- expect(chunks.every((chunk)=>chunk.startsWith('```') && chunk.endsWith('```'))).toBe(true);
13
+ expect(chunks.every((chunk)=>chunk.startsWith("```") && chunk.endsWith("```"))).toBe(true);
14
14
  });
15
- it('accounts for escaped control-character expansion in code chunks', ()=>{
16
- const chunks = chunkMarkdownForSlack(`\`\`\`\n${'<&>'.repeat(2000)}\n\`\`\``);
15
+ it("accounts for escaped control-character expansion in code chunks", ()=>{
16
+ const chunks = chunkMarkdownForSlack(`\`\`\`\n${"<&>".repeat(2000)}\n\`\`\``);
17
17
  expect(chunks.length).toBeGreaterThan(1);
18
18
  expect(chunks.every((chunk)=>chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);
19
- expect(chunks.every((chunk)=>chunk.startsWith('```') && chunk.endsWith('```'))).toBe(true);
19
+ expect(chunks.every((chunk)=>chunk.startsWith("```") && chunk.endsWith("```"))).toBe(true);
20
20
  });
21
- it('splits Unicode text without breaking code points', ()=>{
22
- const chunks = chunkMarkdownForSlack('🎉'.repeat(5000));
23
- expect(chunks.join('')).toBe('🎉'.repeat(5000));
21
+ it("splits Unicode text without breaking code points", ()=>{
22
+ const chunks = chunkMarkdownForSlack("🎉".repeat(5000));
23
+ expect(chunks.join("")).toBe("🎉".repeat(5000));
24
24
  expect(chunks.every((chunk)=>chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);
25
25
  });
26
- it('renders lists, quotes, emphasis, strike, breaks, and rules conservatively', ()=>{
27
- const rendered = markdownToSlackMrkdwn('1. _one_\n2. ~~two~~\n\n> quoted \n> next\n\n---');
28
- expect(rendered).toContain('1. _one_');
29
- expect(rendered).toContain('2. ~two~');
30
- expect(rendered).toContain('> quoted');
31
- expect(rendered).toContain('> next');
32
- expect(rendered).toContain('—');
26
+ it("renders lists, quotes, emphasis, strike, breaks, and rules conservatively", ()=>{
27
+ const rendered = markdownToSlackMrkdwn("1. _one_\n2. ~~two~~\n\n> quoted \n> next\n\n---");
28
+ expect(rendered).toContain("1. _one_");
29
+ expect(rendered).toContain("2. ~two~");
30
+ expect(rendered).toContain("> quoted");
31
+ expect(rendered).toContain("> next");
32
+ expect(rendered).toContain("—");
33
33
  });
34
- it('packs short semantic blocks and splits oversized plain paragraphs', ()=>{
35
- expect(chunkMarkdownForSlack('one\n\ntwo', 20)).toEqual([
36
- 'one\n\ntwo'
34
+ it("packs short semantic blocks and splits oversized plain paragraphs", ()=>{
35
+ expect(chunkMarkdownForSlack("one\n\ntwo", 20)).toEqual([
36
+ "one\n\ntwo"
37
37
  ]);
38
- const chunks = chunkMarkdownForSlack('word '.repeat(30), 25);
38
+ const chunks = chunkMarkdownForSlack("word ".repeat(30), 25);
39
39
  expect(chunks.length).toBeGreaterThan(1);
40
40
  expect(chunks.every((chunk)=>chunk.length <= 25)).toBe(true);
41
41
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/__tests__/adapters/slack/slackMarkdown.test.ts"],"sourcesContent":["import {\n SLACK_MAX_MESSAGE_LENGTH,\n chunkMarkdownForSlack,\n markdownToSlackMrkdwn,\n} from '../../../adapters/slack/slackMarkdown.js';\n\ndescribe('Slack Markdown', () => {\n it('renders common Markdown without activating broad mentions', () => {\n expect(markdownToSlackMrkdwn('# Result\\n\\n**Passed** & <safe> @channel [docs](https://example.com)'))\n .toBe('*Result*\\n\\n*Passed* &amp; &lt;safe&gt; @channel <https://example.com|docs>');\n });\n\n it('preserves inline and fenced code while escaping Slack control characters', () => {\n expect(markdownToSlackMrkdwn('Use `<tag>`\\n\\n```ts\\nconst x = \"<ok>\";\\n```'))\n .toContain('`&lt;tag&gt;`\\n\\n```\\nconst x = \"&lt;ok&gt;\";\\n```');\n });\n\n it('chunks long fenced code into independently fenced Slack messages', () => {\n const chunks = chunkMarkdownForSlack(`\\`\\`\\`ts\\n${'const value = 1;\\n'.repeat(400)}\\`\\`\\``);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n expect(chunks.every((chunk) => chunk.startsWith('```') && chunk.endsWith('```'))).toBe(true);\n });\n\n it('accounts for escaped control-character expansion in code chunks', () => {\n const chunks = chunkMarkdownForSlack(`\\`\\`\\`\\n${'<&>'.repeat(2000)}\\n\\`\\`\\``);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n expect(chunks.every((chunk) => chunk.startsWith('```') && chunk.endsWith('```'))).toBe(true);\n });\n\n it('splits Unicode text without breaking code points', () => {\n const chunks = chunkMarkdownForSlack('🎉'.repeat(5000));\n expect(chunks.join('')).toBe('🎉'.repeat(5000));\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n });\n\n it('renders lists, quotes, emphasis, strike, breaks, and rules conservatively', () => {\n const rendered = markdownToSlackMrkdwn('1. _one_\\n2. ~~two~~\\n\\n> quoted \\n> next\\n\\n---');\n expect(rendered).toContain('1. _one_');\n expect(rendered).toContain('2. ~two~');\n expect(rendered).toContain('> quoted');\n expect(rendered).toContain('> next');\n expect(rendered).toContain('—');\n });\n\n it('packs short semantic blocks and splits oversized plain paragraphs', () => {\n expect(chunkMarkdownForSlack('one\\n\\ntwo', 20)).toEqual(['one\\n\\ntwo']);\n const chunks = chunkMarkdownForSlack('word '.repeat(30), 25);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= 25)).toBe(true);\n });\n});\n"],"names":["SLACK_MAX_MESSAGE_LENGTH","chunkMarkdownForSlack","markdownToSlackMrkdwn","describe","it","expect","toBe","toContain","chunks","repeat","length","toBeGreaterThan","every","chunk","startsWith","endsWith","join","rendered","toEqual"],"mappings":"AAAA,SACIA,wBAAwB,EACxBC,qBAAqB,EACrBC,qBAAqB,QAClB,2CAA2C;AAElDC,SAAS,kBAAkB;IACvBC,GAAG,6DAA6D;QAC5DC,OAAOH,sBAAsB,yEACxBI,IAAI,CAAC;IACd;IAEAF,GAAG,4EAA4E;QAC3EC,OAAOH,sBAAsB,iDACxBK,SAAS,CAAC;IACnB;IAEAH,GAAG,oEAAoE;QACnE,MAAMI,SAASP,sBAAsB,CAAC,UAAU,EAAE,qBAAqBQ,MAAM,CAAC,KAAK,MAAM,CAAC;QAC1FJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;QAC/ED,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMC,UAAU,CAAC,UAAUD,MAAME,QAAQ,CAAC,SAAST,IAAI,CAAC;IAC3F;IAEAF,GAAG,mEAAmE;QAClE,MAAMI,SAASP,sBAAsB,CAAC,QAAQ,EAAE,MAAMQ,MAAM,CAAC,MAAM,QAAQ,CAAC;QAC5EJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;QAC/ED,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMC,UAAU,CAAC,UAAUD,MAAME,QAAQ,CAAC,SAAST,IAAI,CAAC;IAC3F;IAEAF,GAAG,oDAAoD;QACnD,MAAMI,SAASP,sBAAsB,KAAKQ,MAAM,CAAC;QACjDJ,OAAOG,OAAOQ,IAAI,CAAC,KAAKV,IAAI,CAAC,KAAKG,MAAM,CAAC;QACzCJ,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;IACnF;IAEAF,GAAG,6EAA6E;QAC5E,MAAMa,WAAWf,sBAAsB;QACvCG,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;IAC/B;IAEAH,GAAG,qEAAqE;QACpEC,OAAOJ,sBAAsB,cAAc,KAAKiB,OAAO,CAAC;YAAC;SAAa;QACtE,MAAMV,SAASP,sBAAsB,QAAQQ,MAAM,CAAC,KAAK;QACzDJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAI,KAAKJ,IAAI,CAAC;IAC7D;AACJ"}
1
+ {"version":3,"sources":["../../../../src/__tests__/adapters/slack/slackMarkdown.test.ts"],"sourcesContent":["import {\n SLACK_MAX_MESSAGE_LENGTH,\n chunkMarkdownForSlack,\n markdownToSlackMrkdwn,\n} from \"../../../adapters/slack/slackMarkdown.js\";\n\ndescribe(\"Slack Markdown\", () => {\n it(\"renders common Markdown without activating broad mentions\", () => {\n expect(\n markdownToSlackMrkdwn(\"# Result\\n\\n**Passed** & <safe> @channel [docs](https://example.com)\"),\n ).toBe(\"*Result*\\n\\n*Passed* &amp; &lt;safe&gt; @channel <https://example.com|docs>\");\n });\n\n it(\"preserves inline and fenced code while escaping Slack control characters\", () => {\n expect(markdownToSlackMrkdwn('Use `<tag>`\\n\\n```ts\\nconst x = \"<ok>\";\\n```')).toContain(\n '`&lt;tag&gt;`\\n\\n```\\nconst x = \"&lt;ok&gt;\";\\n```',\n );\n });\n\n it(\"chunks long fenced code into independently fenced Slack messages\", () => {\n const chunks = chunkMarkdownForSlack(`\\`\\`\\`ts\\n${\"const value = 1;\\n\".repeat(400)}\\`\\`\\``);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n expect(chunks.every((chunk) => chunk.startsWith(\"```\") && chunk.endsWith(\"```\"))).toBe(true);\n });\n\n it(\"accounts for escaped control-character expansion in code chunks\", () => {\n const chunks = chunkMarkdownForSlack(`\\`\\`\\`\\n${\"<&>\".repeat(2000)}\\n\\`\\`\\``);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n expect(chunks.every((chunk) => chunk.startsWith(\"```\") && chunk.endsWith(\"```\"))).toBe(true);\n });\n\n it(\"splits Unicode text without breaking code points\", () => {\n const chunks = chunkMarkdownForSlack(\"🎉\".repeat(5000));\n expect(chunks.join(\"\")).toBe(\"🎉\".repeat(5000));\n expect(chunks.every((chunk) => chunk.length <= SLACK_MAX_MESSAGE_LENGTH)).toBe(true);\n });\n\n it(\"renders lists, quotes, emphasis, strike, breaks, and rules conservatively\", () => {\n const rendered = markdownToSlackMrkdwn(\"1. _one_\\n2. ~~two~~\\n\\n> quoted \\n> next\\n\\n---\");\n expect(rendered).toContain(\"1. _one_\");\n expect(rendered).toContain(\"2. ~two~\");\n expect(rendered).toContain(\"> quoted\");\n expect(rendered).toContain(\"> next\");\n expect(rendered).toContain(\"—\");\n });\n\n it(\"packs short semantic blocks and splits oversized plain paragraphs\", () => {\n expect(chunkMarkdownForSlack(\"one\\n\\ntwo\", 20)).toEqual([\"one\\n\\ntwo\"]);\n const chunks = chunkMarkdownForSlack(\"word \".repeat(30), 25);\n expect(chunks.length).toBeGreaterThan(1);\n expect(chunks.every((chunk) => chunk.length <= 25)).toBe(true);\n });\n});\n"],"names":["SLACK_MAX_MESSAGE_LENGTH","chunkMarkdownForSlack","markdownToSlackMrkdwn","describe","it","expect","toBe","toContain","chunks","repeat","length","toBeGreaterThan","every","chunk","startsWith","endsWith","join","rendered","toEqual"],"mappings":"AAAA,SACEA,wBAAwB,EACxBC,qBAAqB,EACrBC,qBAAqB,QAChB,2CAA2C;AAElDC,SAAS,kBAAkB;IACzBC,GAAG,6DAA6D;QAC9DC,OACEH,sBAAsB,yEACtBI,IAAI,CAAC;IACT;IAEAF,GAAG,4EAA4E;QAC7EC,OAAOH,sBAAsB,iDAAiDK,SAAS,CACrF;IAEJ;IAEAH,GAAG,oEAAoE;QACrE,MAAMI,SAASP,sBAAsB,CAAC,UAAU,EAAE,qBAAqBQ,MAAM,CAAC,KAAK,MAAM,CAAC;QAC1FJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;QAC/ED,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMC,UAAU,CAAC,UAAUD,MAAME,QAAQ,CAAC,SAAST,IAAI,CAAC;IACzF;IAEAF,GAAG,mEAAmE;QACpE,MAAMI,SAASP,sBAAsB,CAAC,QAAQ,EAAE,MAAMQ,MAAM,CAAC,MAAM,QAAQ,CAAC;QAC5EJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;QAC/ED,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMC,UAAU,CAAC,UAAUD,MAAME,QAAQ,CAAC,SAAST,IAAI,CAAC;IACzF;IAEAF,GAAG,oDAAoD;QACrD,MAAMI,SAASP,sBAAsB,KAAKQ,MAAM,CAAC;QACjDJ,OAAOG,OAAOQ,IAAI,CAAC,KAAKV,IAAI,CAAC,KAAKG,MAAM,CAAC;QACzCJ,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAIV,2BAA2BM,IAAI,CAAC;IACjF;IAEAF,GAAG,6EAA6E;QAC9E,MAAMa,WAAWf,sBAAsB;QACvCG,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;QAC3BF,OAAOY,UAAUV,SAAS,CAAC;IAC7B;IAEAH,GAAG,qEAAqE;QACtEC,OAAOJ,sBAAsB,cAAc,KAAKiB,OAAO,CAAC;YAAC;SAAa;QACtE,MAAMV,SAASP,sBAAsB,QAAQQ,MAAM,CAAC,KAAK;QACzDJ,OAAOG,OAAOE,MAAM,EAAEC,eAAe,CAAC;QACtCN,OAAOG,OAAOI,KAAK,CAAC,CAACC,QAAUA,MAAMH,MAAM,IAAI,KAAKJ,IAAI,CAAC;IAC3D;AACF"}
@@ -1,81 +1,81 @@
1
- import { buildSlackQuestionMessage } from '../../../adapters/slack/slackQuestion.js';
2
- describe('buildSlackQuestionMessage', ()=>{
3
- it('builds an accessible Block Kit question with optional skip action', ()=>{
4
- const message = buildSlackQuestionMessage('D123', {
5
- id: 'q1',
6
- header: 'Scope',
7
- question: 'Choose one',
1
+ import { buildSlackQuestionMessage } from "../../../adapters/slack/slackQuestion.js";
2
+ describe("buildSlackQuestionMessage", ()=>{
3
+ it("builds an accessible Block Kit question with optional skip action", ()=>{
4
+ const message = buildSlackQuestionMessage("D123", {
5
+ id: "q1",
6
+ header: "Scope",
7
+ question: "Choose one",
8
8
  allowSkip: true,
9
9
  options: [
10
10
  {
11
- label: 'Safe',
12
- description: 'Read only',
13
- value: '1'
11
+ label: "Safe",
12
+ description: "Read only",
13
+ value: "1"
14
14
  }
15
15
  ]
16
16
  });
17
17
  expect(message).toMatchObject({
18
- channel: 'D123',
19
- text: 'Scope: Choose one',
18
+ channel: "D123",
19
+ text: "Scope: Choose one",
20
20
  blocks: [
21
21
  {
22
- type: 'section',
22
+ type: "section",
23
23
  text: {
24
- type: 'mrkdwn',
25
- text: '*Scope*\nChoose one'
24
+ type: "mrkdwn",
25
+ text: "*Scope*\nChoose one"
26
26
  }
27
27
  },
28
28
  {
29
- type: 'actions',
29
+ type: "actions",
30
30
  elements: [
31
31
  {
32
- type: 'button',
33
- action_id: 'ai_devkit_question',
32
+ type: "button",
33
+ action_id: "ai_devkit_question",
34
34
  text: {
35
- type: 'plain_text',
36
- text: 'Safe'
35
+ type: "plain_text",
36
+ text: "Safe"
37
37
  },
38
- value: 'q1:1'
38
+ value: "q1:1"
39
39
  },
40
40
  {
41
- type: 'button',
42
- action_id: 'ai_devkit_question',
41
+ type: "button",
42
+ action_id: "ai_devkit_question",
43
43
  text: {
44
- type: 'plain_text',
45
- text: 'Skip'
44
+ type: "plain_text",
45
+ text: "Skip"
46
46
  },
47
- value: 'q1:skip'
47
+ value: "q1:skip"
48
48
  }
49
49
  ]
50
50
  }
51
51
  ]
52
52
  });
53
53
  });
54
- it('escapes Slack control syntax in fallback and mrkdwn text', ()=>{
55
- const message = buildSlackQuestionMessage('D123', {
56
- id: 'q1',
57
- header: '<!channel>',
58
- question: 'Choose <one> & continue',
54
+ it("escapes Slack control syntax in fallback and mrkdwn text", ()=>{
55
+ const message = buildSlackQuestionMessage("D123", {
56
+ id: "q1",
57
+ header: "<!channel>",
58
+ question: "Choose <one> & continue",
59
59
  allowSkip: false,
60
60
  options: [
61
61
  {
62
- label: 'Safe',
63
- value: '1'
62
+ label: "Safe",
63
+ value: "1"
64
64
  }
65
65
  ]
66
66
  });
67
- expect(message.text).toBe('&lt;!channel&gt;: Choose &lt;one&gt; &amp; continue');
68
- expect(message.blocks[0].text.text).toBe('*&lt;!channel&gt;*\nChoose &lt;one&gt; &amp; continue');
67
+ expect(message.text).toBe("&lt;!channel&gt;: Choose &lt;one&gt; &amp; continue");
68
+ expect(message.blocks[0].text.text).toBe("*&lt;!channel&gt;*\nChoose &lt;one&gt; &amp; continue");
69
69
  });
70
- it('limits button labels and values to Slack bounds', ()=>{
71
- const message = buildSlackQuestionMessage('D123', {
72
- id: 'q1',
73
- question: 'Choose',
70
+ it("limits button labels and values to Slack bounds", ()=>{
71
+ const message = buildSlackQuestionMessage("D123", {
72
+ id: "q1",
73
+ question: "Choose",
74
74
  allowSkip: false,
75
75
  options: [
76
76
  {
77
- label: 'A'.repeat(100),
78
- value: 'v'.repeat(3000)
77
+ label: "A".repeat(100),
78
+ value: "v".repeat(3000)
79
79
  }
80
80
  ]
81
81
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/__tests__/adapters/slack/slackQuestion.test.ts"],"sourcesContent":["import { buildSlackQuestionMessage } from '../../../adapters/slack/slackQuestion.js';\n\ndescribe('buildSlackQuestionMessage', () => {\n it('builds an accessible Block Kit question with optional skip action', () => {\n const message = buildSlackQuestionMessage('D123', {\n id: 'q1',\n header: 'Scope',\n question: 'Choose one',\n allowSkip: true,\n options: [{ label: 'Safe', description: 'Read only', value: '1' }],\n });\n\n expect(message).toMatchObject({\n channel: 'D123',\n text: 'Scope: Choose one',\n blocks: [\n {\n type: 'section',\n text: { type: 'mrkdwn', text: '*Scope*\\nChoose one' },\n },\n {\n type: 'actions',\n elements: [\n {\n type: 'button',\n action_id: 'ai_devkit_question',\n text: { type: 'plain_text', text: 'Safe' },\n value: 'q1:1',\n },\n {\n type: 'button',\n action_id: 'ai_devkit_question',\n text: { type: 'plain_text', text: 'Skip' },\n value: 'q1:skip',\n },\n ],\n },\n ],\n });\n });\n\n it('escapes Slack control syntax in fallback and mrkdwn text', () => {\n const message = buildSlackQuestionMessage('D123', {\n id: 'q1',\n header: '<!channel>',\n question: 'Choose <one> & continue',\n allowSkip: false,\n options: [{ label: 'Safe', value: '1' }],\n });\n\n expect(message.text).toBe('&lt;!channel&gt;: Choose &lt;one&gt; &amp; continue');\n expect(message.blocks[0].text.text).toBe('*&lt;!channel&gt;*\\nChoose &lt;one&gt; &amp; continue');\n });\n\n it('limits button labels and values to Slack bounds', () => {\n const message = buildSlackQuestionMessage('D123', {\n id: 'q1',\n question: 'Choose',\n allowSkip: false,\n options: [{ label: 'A'.repeat(100), value: 'v'.repeat(3000) }],\n });\n\n const button = message.blocks[1].elements[0];\n expect(button.text.text).toHaveLength(75);\n expect(button.value).toHaveLength(2000);\n });\n});\n"],"names":["buildSlackQuestionMessage","describe","it","message","id","header","question","allowSkip","options","label","description","value","expect","toMatchObject","channel","text","blocks","type","elements","action_id","toBe","repeat","button","toHaveLength"],"mappings":"AAAA,SAASA,yBAAyB,QAAQ,2CAA2C;AAErFC,SAAS,6BAA6B;IAClCC,GAAG,qEAAqE;QACpE,MAAMC,UAAUH,0BAA0B,QAAQ;YAC9CI,IAAI;YACJC,QAAQ;YACRC,UAAU;YACVC,WAAW;YACXC,SAAS;gBAAC;oBAAEC,OAAO;oBAAQC,aAAa;oBAAaC,OAAO;gBAAI;aAAE;QACtE;QAEAC,OAAOT,SAASU,aAAa,CAAC;YAC1BC,SAAS;YACTC,MAAM;YACNC,QAAQ;gBACJ;oBACIC,MAAM;oBACNF,MAAM;wBAAEE,MAAM;wBAAUF,MAAM;oBAAsB;gBACxD;gBACA;oBACIE,MAAM;oBACNC,UAAU;wBACN;4BACID,MAAM;4BACNE,WAAW;4BACXJ,MAAM;gCAAEE,MAAM;gCAAcF,MAAM;4BAAO;4BACzCJ,OAAO;wBACX;wBACA;4BACIM,MAAM;4BACNE,WAAW;4BACXJ,MAAM;gCAAEE,MAAM;gCAAcF,MAAM;4BAAO;4BACzCJ,OAAO;wBACX;qBACH;gBACL;aACH;QACL;IACJ;IAEAT,GAAG,4DAA4D;QAC3D,MAAMC,UAAUH,0BAA0B,QAAQ;YAC9CI,IAAI;YACJC,QAAQ;YACRC,UAAU;YACVC,WAAW;YACXC,SAAS;gBAAC;oBAAEC,OAAO;oBAAQE,OAAO;gBAAI;aAAE;QAC5C;QAEAC,OAAOT,QAAQY,IAAI,EAAEK,IAAI,CAAC;QAC1BR,OAAOT,QAAQa,MAAM,CAAC,EAAE,CAACD,IAAI,CAACA,IAAI,EAAEK,IAAI,CAAC;IAC7C;IAEAlB,GAAG,mDAAmD;QAClD,MAAMC,UAAUH,0BAA0B,QAAQ;YAC9CI,IAAI;YACJE,UAAU;YACVC,WAAW;YACXC,SAAS;gBAAC;oBAAEC,OAAO,IAAIY,MAAM,CAAC;oBAAMV,OAAO,IAAIU,MAAM,CAAC;gBAAM;aAAE;QAClE;QAEA,MAAMC,SAASnB,QAAQa,MAAM,CAAC,EAAE,CAACE,QAAQ,CAAC,EAAE;QAC5CN,OAAOU,OAAOP,IAAI,CAACA,IAAI,EAAEQ,YAAY,CAAC;QACtCX,OAAOU,OAAOX,KAAK,EAAEY,YAAY,CAAC;IACtC;AACJ"}
1
+ {"version":3,"sources":["../../../../src/__tests__/adapters/slack/slackQuestion.test.ts"],"sourcesContent":["import { buildSlackQuestionMessage } from \"../../../adapters/slack/slackQuestion.js\";\n\ndescribe(\"buildSlackQuestionMessage\", () => {\n it(\"builds an accessible Block Kit question with optional skip action\", () => {\n const message = buildSlackQuestionMessage(\"D123\", {\n id: \"q1\",\n header: \"Scope\",\n question: \"Choose one\",\n allowSkip: true,\n options: [{ label: \"Safe\", description: \"Read only\", value: \"1\" }],\n });\n\n expect(message).toMatchObject({\n channel: \"D123\",\n text: \"Scope: Choose one\",\n blocks: [\n {\n type: \"section\",\n text: { type: \"mrkdwn\", text: \"*Scope*\\nChoose one\" },\n },\n {\n type: \"actions\",\n elements: [\n {\n type: \"button\",\n action_id: \"ai_devkit_question\",\n text: { type: \"plain_text\", text: \"Safe\" },\n value: \"q1:1\",\n },\n {\n type: \"button\",\n action_id: \"ai_devkit_question\",\n text: { type: \"plain_text\", text: \"Skip\" },\n value: \"q1:skip\",\n },\n ],\n },\n ],\n });\n });\n\n it(\"escapes Slack control syntax in fallback and mrkdwn text\", () => {\n const message = buildSlackQuestionMessage(\"D123\", {\n id: \"q1\",\n header: \"<!channel>\",\n question: \"Choose <one> & continue\",\n allowSkip: false,\n options: [{ label: \"Safe\", value: \"1\" }],\n });\n\n expect(message.text).toBe(\"&lt;!channel&gt;: Choose &lt;one&gt; &amp; continue\");\n expect(message.blocks[0].text.text).toBe(\n \"*&lt;!channel&gt;*\\nChoose &lt;one&gt; &amp; continue\",\n );\n });\n\n it(\"limits button labels and values to Slack bounds\", () => {\n const message = buildSlackQuestionMessage(\"D123\", {\n id: \"q1\",\n question: \"Choose\",\n allowSkip: false,\n options: [{ label: \"A\".repeat(100), value: \"v\".repeat(3000) }],\n });\n\n const button = message.blocks[1].elements[0];\n expect(button.text.text).toHaveLength(75);\n expect(button.value).toHaveLength(2000);\n });\n});\n"],"names":["buildSlackQuestionMessage","describe","it","message","id","header","question","allowSkip","options","label","description","value","expect","toMatchObject","channel","text","blocks","type","elements","action_id","toBe","repeat","button","toHaveLength"],"mappings":"AAAA,SAASA,yBAAyB,QAAQ,2CAA2C;AAErFC,SAAS,6BAA6B;IACpCC,GAAG,qEAAqE;QACtE,MAAMC,UAAUH,0BAA0B,QAAQ;YAChDI,IAAI;YACJC,QAAQ;YACRC,UAAU;YACVC,WAAW;YACXC,SAAS;gBAAC;oBAAEC,OAAO;oBAAQC,aAAa;oBAAaC,OAAO;gBAAI;aAAE;QACpE;QAEAC,OAAOT,SAASU,aAAa,CAAC;YAC5BC,SAAS;YACTC,MAAM;YACNC,QAAQ;gBACN;oBACEC,MAAM;oBACNF,MAAM;wBAAEE,MAAM;wBAAUF,MAAM;oBAAsB;gBACtD;gBACA;oBACEE,MAAM;oBACNC,UAAU;wBACR;4BACED,MAAM;4BACNE,WAAW;4BACXJ,MAAM;gCAAEE,MAAM;gCAAcF,MAAM;4BAAO;4BACzCJ,OAAO;wBACT;wBACA;4BACEM,MAAM;4BACNE,WAAW;4BACXJ,MAAM;gCAAEE,MAAM;gCAAcF,MAAM;4BAAO;4BACzCJ,OAAO;wBACT;qBACD;gBACH;aACD;QACH;IACF;IAEAT,GAAG,4DAA4D;QAC7D,MAAMC,UAAUH,0BAA0B,QAAQ;YAChDI,IAAI;YACJC,QAAQ;YACRC,UAAU;YACVC,WAAW;YACXC,SAAS;gBAAC;oBAAEC,OAAO;oBAAQE,OAAO;gBAAI;aAAE;QAC1C;QAEAC,OAAOT,QAAQY,IAAI,EAAEK,IAAI,CAAC;QAC1BR,OAAOT,QAAQa,MAAM,CAAC,EAAE,CAACD,IAAI,CAACA,IAAI,EAAEK,IAAI,CACtC;IAEJ;IAEAlB,GAAG,mDAAmD;QACpD,MAAMC,UAAUH,0BAA0B,QAAQ;YAChDI,IAAI;YACJE,UAAU;YACVC,WAAW;YACXC,SAAS;gBAAC;oBAAEC,OAAO,IAAIY,MAAM,CAAC;oBAAMV,OAAO,IAAIU,MAAM,CAAC;gBAAM;aAAE;QAChE;QAEA,MAAMC,SAASnB,QAAQa,MAAM,CAAC,EAAE,CAACE,QAAQ,CAAC,EAAE;QAC5CN,OAAOU,OAAOP,IAAI,CAACA,IAAI,EAAEQ,YAAY,CAAC;QACtCX,OAAOU,OAAOX,KAAK,EAAEY,YAAY,CAAC;IACpC;AACF"}