@opentag/slack 0.2.0 → 0.3.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.
package/dist/events.d.ts CHANGED
@@ -38,6 +38,43 @@ export type SlackEventEnvelope = {
38
38
  user_id?: string;
39
39
  }>;
40
40
  };
41
+ export type SlackInteractiveBlockAction = {
42
+ type?: string;
43
+ action_id?: string;
44
+ block_id?: string;
45
+ value?: string;
46
+ action_ts?: string;
47
+ };
48
+ export type SlackInteractivePayload = {
49
+ type: "block_actions";
50
+ api_app_id?: string;
51
+ team?: {
52
+ id?: string;
53
+ domain?: string;
54
+ };
55
+ user?: {
56
+ id?: string;
57
+ username?: string;
58
+ name?: string;
59
+ };
60
+ channel?: {
61
+ id?: string;
62
+ name?: string;
63
+ };
64
+ message?: {
65
+ ts?: string;
66
+ thread_ts?: string;
67
+ };
68
+ container?: {
69
+ type?: string;
70
+ channel_id?: string;
71
+ message_ts?: string;
72
+ thread_ts?: string;
73
+ };
74
+ trigger_id?: string;
75
+ actions?: SlackInteractiveBlockAction[];
76
+ };
77
+ export type SlackIngressPayload = SlackEventEnvelope | SlackInteractivePayload;
41
78
  export type SlackAppRuntimeConfig = {
42
79
  agentId: string;
43
80
  appId?: string;
@@ -65,6 +102,6 @@ export type SlackEventProcessorResult = {
65
102
  body: string;
66
103
  };
67
104
  export declare function createSlackEventProcessor(input: SlackEventProcessorInput): {
68
- process(payload: SlackEventEnvelope, slackApp: SlackAppRuntimeConfig): Promise<SlackEventProcessorResult>;
105
+ process(payload: SlackIngressPayload, slackApp: SlackAppRuntimeConfig): Promise<SlackEventProcessorResult>;
69
106
  };
70
107
  //# sourceMappingURL=events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAwE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAEhI,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE;QACL,QAAQ,EAAE,OAAO,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,QAAQ,EAAE;QACR,QAAQ,EAAE,OAAO,CAAC;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,kBAAkB,GAAG,gBAAgB,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,qBAAqB,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IACzG,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,kBAAkB,CAAC,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,GAAG,IAAI,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,GAAG,GAAG,GAAG,CAAC;AAElD,MAAM,MAAM,yBAAyB,GACjC;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,yBAAyB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,yBAAyB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAUN,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,wBAAwB;qBAE9C,kBAAkB,YAAY,qBAAqB,GAAG,OAAO,CAAC,yBAAyB,CAAC;EA0FlH"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,15 +3,22 @@ import { parseThreadActionCommand } from "@opentag/core";
3
3
 
4
4
  // src/normalize.ts
5
5
  import { commandFromRawText } from "@opentag/core";
6
+ var LEADING_MENTION_RUN = /^(?:<@[^>]+>\s*)+/;
7
+ var MENTION_TOKEN = /<@([^>]+)>/g;
6
8
  function stripSlackAppMention(text2, botUserId) {
7
- const patterns = botUserId ? [new RegExp(`^<@${botUserId}>\\s*`, "i"), /^<@[^>]+>\s*/] : [/^<@[^>]+>\s*/];
8
- for (const pattern of patterns) {
9
- const stripped = text2.replace(pattern, "").trim();
10
- if (stripped !== text2.trim()) {
11
- return stripped.length > 0 ? stripped : null;
12
- }
9
+ const run = text2.match(LEADING_MENTION_RUN);
10
+ if (!run) return null;
11
+ const leadingRun = run[0];
12
+ if (botUserId) {
13
+ const mentionedIds = leadingRun.match(MENTION_TOKEN) ?? [];
14
+ const botIsMentioned = mentionedIds.some((token) => {
15
+ const id = token.slice(2, -1).split("|")[0] ?? "";
16
+ return id.toLowerCase() === botUserId.toLowerCase();
17
+ });
18
+ if (!botIsMentioned) return null;
13
19
  }
14
- return null;
20
+ const stripped = text2.slice(leadingRun.length).trim();
21
+ return stripped.length > 0 ? stripped : null;
15
22
  }
16
23
  function encodeSlackThreadKey(input) {
17
24
  return `${input.teamId}|${input.channelId}|${input.threadTs}`;
@@ -23,18 +30,27 @@ function parseSlackThreadKey(threadKey) {
23
30
  }
24
31
  return { teamId, channelId, threadTs };
25
32
  }
26
- function permissionsForIntent(intent) {
33
+ var UNKNOWN_WRITE_VERB_PATTERN = /\b(add|append|apply|change|commit|create|delete|edit|fix|modify|open\s+a?\s*pr|pull\s+request|remove|update|write)\b/i;
34
+ var REPO_WRITE_TARGET_PATTERN = /\b(repo|repository|code|file|files|branch|commit|diff|patch|readme|pr|pull\s+request|package\.json|pnpm|npm|test|build)\b|(?:^|\s)[./\w-]+\.(?:cjs|css|gitignore|go|html|js|json|jsx|lock|md|mjs|py|rb|rs|sh|toml|ts|tsx|txt|yaml|yml)\b|(?:^|[\s`'"(])(?:[./\w-]+\/)?(?:Dockerfile|Makefile|Procfile|Rakefile|Gemfile|Brewfile|Justfile|Taskfile|\.dockerignore|\.env(?:\.[\w-]+)?|\.gitignore|\.npmrc)(?=$|[\s`'",.):])/i;
35
+ function commandLooksRepoWriteCapable(command) {
36
+ return UNKNOWN_WRITE_VERB_PATTERN.test(command.rawText) && REPO_WRITE_TARGET_PATTERN.test(command.rawText);
37
+ }
38
+ function permissionsForCommand(command) {
27
39
  const permissions = [
28
40
  {
29
41
  scope: "chat:postMessage",
30
42
  reason: "reply in the originating Slack thread"
31
43
  },
44
+ {
45
+ scope: "reactions:write",
46
+ reason: "mark the originating Slack message as received without posting a thread reply"
47
+ },
32
48
  {
33
49
  scope: "runner:local",
34
50
  reason: "execute the run on a paired local daemon"
35
51
  }
36
52
  ];
37
- if (intent === "fix" || intent === "run") {
53
+ if (command.intent === "fix" || command.intent === "run" || command.intent === "unknown" && commandLooksRepoWriteCapable(command)) {
38
54
  permissions.push(
39
55
  {
40
56
  scope: "repo:read",
@@ -129,7 +145,7 @@ function normalizeSlackAppMention(input) {
129
145
  },
130
146
  ...contextPointersForCommand(command)
131
147
  ],
132
- permissions: permissionsForIntent(command.intent),
148
+ permissions: permissionsForCommand(command),
133
149
  callback: {
134
150
  provider: "slack",
135
151
  uri: input.callbackUri ?? "https://slack.com/api/chat.postMessage",
@@ -153,6 +169,290 @@ function normalizeSlackAppMention(input) {
153
169
  };
154
170
  }
155
171
 
172
+ // src/render.ts
173
+ import { suggestedActionCandidatesFromResult } from "@opentag/core";
174
+ var MAX_SLACK_SUGGESTED_ACTION_CANDIDATES = 20;
175
+ function buildSlackSuggestedActionButtonValue(input) {
176
+ return JSON.stringify(input);
177
+ }
178
+ function parseSlackSuggestedActionButtonValue(value) {
179
+ try {
180
+ const parsed = JSON.parse(value);
181
+ if (parsed.version !== 1 || typeof parsed.command !== "string" || parsed.command.trim().length === 0 || typeof parsed.proposalId !== "string" || parsed.proposalId.length === 0 || typeof parsed.intentId !== "string" || parsed.intentId.length === 0) {
182
+ return null;
183
+ }
184
+ return {
185
+ version: 1,
186
+ command: parsed.command.trim(),
187
+ proposalId: parsed.proposalId,
188
+ intentId: parsed.intentId
189
+ };
190
+ } catch {
191
+ return null;
192
+ }
193
+ }
194
+ function escapeSlackText(text2) {
195
+ return text2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
196
+ }
197
+ function markdownToSlackMrkdwn(text2) {
198
+ const links = [];
199
+ const withoutLinks = text2.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, label, url) => {
200
+ const token = `\0SLACK_LINK_${links.length}\0`;
201
+ links.push(`<${url}|${escapeSlackText(label)}>`);
202
+ return token;
203
+ });
204
+ const converted = escapeSlackText(withoutLinks).replace(/\*\*(.+?)\*\*/g, "*$1*").replace(/__(.+?)__/g, "*$1*");
205
+ return links.reduce((output, link, index) => output.replace(`\0SLACK_LINK_${index}\0`, link), converted);
206
+ }
207
+ function renderSlackAcknowledgement(runId) {
208
+ void runId;
209
+ return "Working on it.";
210
+ }
211
+ function slackSourceReceiptReactionName(state) {
212
+ if (state === "received") return "eyes";
213
+ return "eyes";
214
+ }
215
+ function createSlackReactionPayload(input) {
216
+ return {
217
+ channel: input.channelId,
218
+ timestamp: input.messageTs,
219
+ name: input.name
220
+ };
221
+ }
222
+ function nextActionSummary(result) {
223
+ if (!result.nextAction) return void 0;
224
+ if (typeof result.nextAction === "string") return result.nextAction;
225
+ return result.nextAction.summary;
226
+ }
227
+ function stringParam(params, key) {
228
+ const value = params?.[key];
229
+ return typeof value === "string" && value.length > 0 ? value : void 0;
230
+ }
231
+ function stringArrayParam(params, key) {
232
+ const value = params?.[key];
233
+ if (!Array.isArray(value)) return [];
234
+ return value.filter((item) => typeof item === "string" && item.length > 0);
235
+ }
236
+ function renderVerificationParams(params) {
237
+ const value = params?.["verification"];
238
+ if (!Array.isArray(value)) return [];
239
+ return value.map((item) => {
240
+ if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
241
+ const command = item["command"];
242
+ const outcome = item["outcome"];
243
+ return typeof command === "string" && typeof outcome === "string" ? ` - \`${command}\`: ${outcome}` : void 0;
244
+ }).filter((line) => Boolean(line));
245
+ }
246
+ function renderSuggestedActionDetails(params, action) {
247
+ if (action !== "create_pull_request") return [];
248
+ const lines = [];
249
+ const title = stringParam(params, "title");
250
+ const head = stringParam(params, "head") ?? stringParam(params, "branch");
251
+ const base = stringParam(params, "base") ?? stringParam(params, "baseBranch");
252
+ const changedFiles = stringArrayParam(params, "changedFiles");
253
+ const risks = stringArrayParam(params, "risks");
254
+ const verification = renderVerificationParams(params);
255
+ if (title) lines.push(` Title: ${markdownToSlackMrkdwn(title)}`);
256
+ if (head || base) lines.push(` Branch: \`${head ?? "unknown"}\` -> \`${base ?? "main"}\``);
257
+ if (changedFiles.length > 0) lines.push(` Changed files: ${changedFiles.map((file) => `\`${file}\``).join(", ")}`);
258
+ if (risks.length > 0) {
259
+ lines.push(" Risks:");
260
+ for (const risk of risks) {
261
+ lines.push(` - ${markdownToSlackMrkdwn(risk)}`);
262
+ }
263
+ }
264
+ if (verification.length > 0) {
265
+ lines.push(" Verification:");
266
+ lines.push(...verification);
267
+ }
268
+ return lines;
269
+ }
270
+ function truncateSlackText(text2, maxLength) {
271
+ const normalized = text2.replace(/\s+/g, " ").trim();
272
+ if (normalized.length <= maxLength) return normalized;
273
+ return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}\u2026`;
274
+ }
275
+ function firstMarkdownSection(text2, heading) {
276
+ const pattern = new RegExp(`\\*\\*${heading}:\\*\\*\\s*([\\s\\S]*?)(?=\\n\\s*\\n\\*\\*[^*]+:\\*\\*|\\n\\s*\\n[A-Z][^\\n]{0,60}:|$)`, "i");
277
+ const match = text2.match(pattern);
278
+ return match?.[1]?.trim();
279
+ }
280
+ function compactSlackSummary(summary) {
281
+ const whatChanged = firstMarkdownSection(summary, "What changed");
282
+ const firstParagraph = summary.split(/\n\s*\n/).map((part) => part.trim()).find(Boolean);
283
+ const selected = whatChanged ?? firstParagraph ?? summary;
284
+ return truncateSlackText(selected.replace(/^\*\*[^*]+:\*\*\s*/i, ""), 360);
285
+ }
286
+ function compactNextAction(nextAction) {
287
+ return truncateSlackText(nextAction, 180);
288
+ }
289
+ function renderSuggestedActionCandidateLines(candidate) {
290
+ const lines = [`${candidate.index}. *${markdownToSlackMrkdwn(candidate.intent.summary)}*`];
291
+ const details = renderSuggestedActionDetails(candidate.intent.params, candidate.intent.action).filter((line) => line.trim().startsWith("Branch:") || line.trim().startsWith("Changed files:")).map((line) => line.replace(/^\s+/, ""));
292
+ lines.push(...details);
293
+ if (candidate.proposalPreconditions?.length) {
294
+ lines.push(`Preconditions: ${candidate.proposalPreconditions.length} check(s) in the audit log.`);
295
+ }
296
+ return lines;
297
+ }
298
+ function renderSuggestedActionsMarkdown(result) {
299
+ const candidates = suggestedActionCandidatesFromResult(result);
300
+ if (candidates.length === 0) return [];
301
+ const lines = ["*Suggested actions*"];
302
+ const visibleCandidates = candidates.slice(0, MAX_SLACK_SUGGESTED_ACTION_CANDIDATES);
303
+ for (const candidate of visibleCandidates) {
304
+ lines.push("", ...renderSuggestedActionCandidateLines(candidate));
305
+ }
306
+ const remainingCount = candidates.length - visibleCandidates.length;
307
+ if (remainingCount > 0) {
308
+ lines.push("", `Showing first ${visibleCandidates.length} of ${candidates.length} actions. Reply with an action number for the rest.`);
309
+ }
310
+ lines.push("", "Use the buttons below, or reply `apply 1`, `approve 1`, or `reject 1`.");
311
+ return lines;
312
+ }
313
+ function createSuggestedActionButtons(candidate) {
314
+ return [
315
+ {
316
+ type: "button",
317
+ text: { type: "plain_text", text: `Apply ${candidate.index}`, emoji: true },
318
+ action_id: `opentag:apply:${candidate.index}`,
319
+ value: buildSlackSuggestedActionButtonValue({
320
+ version: 1,
321
+ command: `apply ${candidate.index}`,
322
+ proposalId: candidate.proposalId,
323
+ intentId: candidate.intent.intentId
324
+ }),
325
+ style: "primary"
326
+ },
327
+ {
328
+ type: "button",
329
+ text: { type: "plain_text", text: "Approve", emoji: true },
330
+ action_id: `opentag:approve:${candidate.index}`,
331
+ value: buildSlackSuggestedActionButtonValue({
332
+ version: 1,
333
+ command: `approve ${candidate.index}`,
334
+ proposalId: candidate.proposalId,
335
+ intentId: candidate.intent.intentId
336
+ })
337
+ },
338
+ {
339
+ type: "button",
340
+ text: { type: "plain_text", text: "Reject", emoji: true },
341
+ action_id: `opentag:reject:${candidate.index}`,
342
+ value: buildSlackSuggestedActionButtonValue({
343
+ version: 1,
344
+ command: `reject ${candidate.index}`,
345
+ proposalId: candidate.proposalId,
346
+ intentId: candidate.intent.intentId
347
+ }),
348
+ style: "danger"
349
+ }
350
+ ];
351
+ }
352
+ function renderSlackFinalResult(result) {
353
+ const lines = [`*Finished: ${result.conclusion}.*`, markdownToSlackMrkdwn(compactSlackSummary(result.summary))];
354
+ if (result.verification?.length) {
355
+ lines.push(
356
+ `Verified: ${result.verification.slice(0, 3).map((check) => `\`${markdownToSlackMrkdwn(check.command)}\` ${markdownToSlackMrkdwn(check.outcome)}`).join(", ")}`
357
+ );
358
+ }
359
+ const nextAction = nextActionSummary(result);
360
+ if (nextAction && !result.suggestedChanges?.length) {
361
+ lines.push(`Next: ${markdownToSlackMrkdwn(compactNextAction(nextAction))}`);
362
+ }
363
+ const suggestedActions = renderSuggestedActionsMarkdown(result);
364
+ if (suggestedActions.length > 0) {
365
+ lines.push("", ...suggestedActions);
366
+ }
367
+ return lines.join("\n");
368
+ }
369
+ function createSlackFinalResultBlocks(result) {
370
+ const blocks = [
371
+ {
372
+ type: "section",
373
+ text: {
374
+ type: "mrkdwn",
375
+ text: `*Finished: ${result.conclusion}.*
376
+ ${markdownToSlackMrkdwn(compactSlackSummary(result.summary))}`
377
+ }
378
+ }
379
+ ];
380
+ if (result.verification?.length) {
381
+ blocks.push({
382
+ type: "section",
383
+ text: {
384
+ type: "mrkdwn",
385
+ text: `Verified: ${markdownToSlackMrkdwn(
386
+ result.verification.slice(0, 3).map((check) => `\`${check.command}\` ${check.outcome}`).join(", ")
387
+ )}`
388
+ }
389
+ });
390
+ }
391
+ const nextAction = nextActionSummary(result);
392
+ const suggestedActionCandidates = suggestedActionCandidatesFromResult(result);
393
+ if (nextAction && suggestedActionCandidates.length === 0) {
394
+ blocks.push({
395
+ type: "section",
396
+ text: {
397
+ type: "mrkdwn",
398
+ text: `Next: ${markdownToSlackMrkdwn(compactNextAction(nextAction))}`
399
+ }
400
+ });
401
+ }
402
+ if (suggestedActionCandidates.length > 0) {
403
+ blocks.push({ type: "divider" });
404
+ blocks.push({
405
+ type: "section",
406
+ text: {
407
+ type: "mrkdwn",
408
+ text: "*Suggested actions*\nChoose an action in this thread. Details stay in the OpenTag audit log."
409
+ }
410
+ });
411
+ const visibleCandidates = suggestedActionCandidates.slice(0, MAX_SLACK_SUGGESTED_ACTION_CANDIDATES);
412
+ for (const candidate of visibleCandidates) {
413
+ blocks.push({
414
+ type: "section",
415
+ text: {
416
+ type: "mrkdwn",
417
+ text: renderSuggestedActionCandidateLines(candidate).join("\n")
418
+ }
419
+ });
420
+ blocks.push({
421
+ type: "actions",
422
+ block_id: `opentag_actions_${candidate.index}`,
423
+ elements: createSuggestedActionButtons(candidate)
424
+ });
425
+ }
426
+ const remainingCount = suggestedActionCandidates.length - visibleCandidates.length;
427
+ if (remainingCount > 0) {
428
+ blocks.push({
429
+ type: "section",
430
+ text: {
431
+ type: "mrkdwn",
432
+ text: `Showing first ${visibleCandidates.length} of ${suggestedActionCandidates.length} actions. Reply with an action number for the rest.`
433
+ }
434
+ });
435
+ }
436
+ }
437
+ return blocks;
438
+ }
439
+ function createSlackPostMessagePayload(input) {
440
+ return {
441
+ channel: input.channelId,
442
+ text: markdownToSlackMrkdwn(input.text),
443
+ thread_ts: input.threadTs,
444
+ ...input.blocks?.length ? { blocks: input.blocks } : {}
445
+ };
446
+ }
447
+ function createSlackUpdateMessagePayload(input) {
448
+ return {
449
+ channel: input.channelId,
450
+ text: markdownToSlackMrkdwn(input.text),
451
+ ts: input.messageTs,
452
+ ...input.blocks?.length ? { blocks: input.blocks } : {}
453
+ };
454
+ }
455
+
156
456
  // src/events.ts
157
457
  function json(body, status = 200) {
158
458
  return { kind: "json", status, body };
@@ -161,8 +461,77 @@ function text(body, status = 200) {
161
461
  return { kind: "text", status, body };
162
462
  }
163
463
  function createSlackEventProcessor(input) {
464
+ async function processBlockActions(payload, slackApp) {
465
+ const action = payload.actions?.find((candidate) => {
466
+ if (candidate.action_id?.startsWith("opentag:")) return true;
467
+ return typeof candidate.value === "string" && parseSlackSuggestedActionButtonValue(candidate.value) !== null;
468
+ });
469
+ if (!action) {
470
+ return json({ ok: true });
471
+ }
472
+ const parsedValue = typeof action.value === "string" ? parseSlackSuggestedActionButtonValue(action.value) : null;
473
+ const rawText = parsedValue?.command ?? (typeof action.value === "string" && parseThreadActionCommand(action.value) ? action.value.trim() : void 0);
474
+ if (!rawText || !parseThreadActionCommand(rawText)) {
475
+ return json({ error: "invalid_interactive_action" }, 400);
476
+ }
477
+ if (!input.submitThreadAction) {
478
+ return json({ ok: true });
479
+ }
480
+ const teamId = payload.team?.id;
481
+ const userId = payload.user?.id;
482
+ const channelId = payload.channel?.id ?? payload.container?.channel_id;
483
+ const messageTs = payload.message?.ts ?? payload.container?.message_ts;
484
+ const threadTs = payload.message?.thread_ts ?? payload.container?.thread_ts ?? messageTs;
485
+ if (!teamId || !userId || !channelId || !messageTs || !threadTs) {
486
+ return json({ error: "invalid_interactive_payload" }, 400);
487
+ }
488
+ const binding = await input.resolveChannelBinding({
489
+ teamId,
490
+ channelId
491
+ });
492
+ if (!binding) {
493
+ return json({ ok: true, ignored: "unbound_channel" });
494
+ }
495
+ await input.submitThreadAction({
496
+ id: `approval_slack_block_${payload.trigger_id ?? `${action.action_id ?? "action"}_${action.action_ts ?? messageTs}`}`,
497
+ rawText,
498
+ actor: {
499
+ provider: "slack",
500
+ providerUserId: userId,
501
+ handle: payload.user?.username ?? payload.user?.name ?? userId,
502
+ organizationId: teamId
503
+ },
504
+ callback: {
505
+ provider: "slack",
506
+ uri: slackApp.callbackUri ?? "https://slack.com/api/chat.postMessage",
507
+ threadKey: encodeSlackThreadKey({
508
+ teamId,
509
+ channelId,
510
+ threadTs
511
+ })
512
+ },
513
+ metadata: {
514
+ source: "slack_button",
515
+ teamId,
516
+ channelId,
517
+ messageTs,
518
+ ...payload.api_app_id ? { slackAppId: payload.api_app_id } : {},
519
+ ...action.action_id ? { actionId: action.action_id } : {},
520
+ ...action.block_id ? { blockId: action.block_id } : {},
521
+ ...action.action_ts ? { actionTs: action.action_ts } : {},
522
+ ...parsedValue ? { proposalId: parsedValue.proposalId, intentId: parsedValue.intentId } : {},
523
+ repoProvider: binding.repoProvider ?? "github",
524
+ owner: binding.owner,
525
+ repo: binding.repo
526
+ }
527
+ });
528
+ return json({ ok: true });
529
+ }
164
530
  return {
165
531
  async process(payload, slackApp) {
532
+ if (payload.type === "block_actions") {
533
+ return processBlockActions(payload, slackApp);
534
+ }
166
535
  if (payload.type === "url_verification") {
167
536
  return text(payload.challenge ?? "");
168
537
  }
@@ -314,8 +683,13 @@ function verifySlackTimestamp(input) {
314
683
  function createSlackEventsApp(input) {
315
684
  const app = new Hono();
316
685
  const processor = createSlackEventProcessor(input);
317
- function parseSlackPayload(rawBody) {
686
+ function parseSlackPayload(rawBody, contentType) {
318
687
  try {
688
+ if (contentType?.includes("application/x-www-form-urlencoded") || rawBody.startsWith("payload=")) {
689
+ const interactivePayload = new URLSearchParams(rawBody).get("payload");
690
+ if (!interactivePayload) return null;
691
+ return JSON.parse(interactivePayload);
692
+ }
319
693
  return JSON.parse(rawBody);
320
694
  } catch {
321
695
  return null;
@@ -346,7 +720,7 @@ function createSlackEventsApp(input) {
346
720
  return c.json({ error: "stale_signature_timestamp" }, 401);
347
721
  }
348
722
  const rawBody = await c.req.text();
349
- const payload = parseSlackPayload(rawBody);
723
+ const payload = parseSlackPayload(rawBody, c.req.header("content-type"));
350
724
  if (!payload) {
351
725
  return c.json({ error: "invalid_json" }, 400);
352
726
  }
@@ -400,185 +774,25 @@ function startSlackIngress(config) {
400
774
  };
401
775
  }
402
776
 
403
- // src/render.ts
404
- import { suggestedActionCandidatesFromResult } from "@opentag/core";
405
- function escapeSlackText(text2) {
406
- return text2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
407
- }
408
- function markdownToSlackMrkdwn(text2) {
409
- const links = [];
410
- const withoutLinks = text2.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, label, url) => {
411
- const token = `\0SLACK_LINK_${links.length}\0`;
412
- links.push(`<${url}|${escapeSlackText(label)}>`);
413
- return token;
414
- });
415
- const converted = escapeSlackText(withoutLinks).replace(/\*\*(.+?)\*\*/g, "*$1*").replace(/__(.+?)__/g, "*$1*");
416
- return links.reduce((output, link, index) => output.replace(`\0SLACK_LINK_${index}\0`, link), converted);
417
- }
418
- function renderSlackAcknowledgement(runId) {
419
- return `I picked this up: \`${runId}\``;
420
- }
421
- function nextActionSummary(result) {
422
- if (!result.nextAction) return void 0;
423
- if (typeof result.nextAction === "string") return result.nextAction;
424
- return result.nextAction.summary;
425
- }
426
- function stringParam(params, key) {
427
- const value = params?.[key];
428
- return typeof value === "string" && value.length > 0 ? value : void 0;
429
- }
430
- function stringArrayParam(params, key) {
431
- const value = params?.[key];
432
- if (!Array.isArray(value)) return [];
433
- return value.filter((item) => typeof item === "string" && item.length > 0);
434
- }
435
- function renderVerificationParams(params) {
436
- const value = params?.["verification"];
437
- if (!Array.isArray(value)) return [];
438
- return value.map((item) => {
439
- if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
440
- const command = item["command"];
441
- const outcome = item["outcome"];
442
- return typeof command === "string" && typeof outcome === "string" ? ` - \`${command}\`: ${outcome}` : void 0;
443
- }).filter((line) => Boolean(line));
444
- }
445
- function renderSuggestedActionDetails(params, action) {
446
- if (action !== "create_pull_request") return [];
447
- const lines = [];
448
- const title = stringParam(params, "title");
449
- const head = stringParam(params, "head") ?? stringParam(params, "branch");
450
- const base = stringParam(params, "base") ?? stringParam(params, "baseBranch");
451
- const changedFiles = stringArrayParam(params, "changedFiles");
452
- const risks = stringArrayParam(params, "risks");
453
- const verification = renderVerificationParams(params);
454
- if (title) lines.push(` Title: ${markdownToSlackMrkdwn(title)}`);
455
- if (head || base) lines.push(` Branch: \`${head ?? "unknown"}\` -> \`${base ?? "main"}\``);
456
- if (changedFiles.length > 0) lines.push(` Changed files: ${changedFiles.map((file) => `\`${file}\``).join(", ")}`);
457
- if (risks.length > 0) {
458
- lines.push(" Risks:");
459
- for (const risk of risks) {
460
- lines.push(` - ${markdownToSlackMrkdwn(risk)}`);
461
- }
462
- }
463
- if (verification.length > 0) {
464
- lines.push(" Verification:");
465
- lines.push(...verification);
466
- }
467
- return lines;
468
- }
469
- function renderSuggestedActionsMarkdown(result) {
470
- const candidates = suggestedActionCandidatesFromResult(result);
471
- if (candidates.length === 0) return [];
472
- const lines = ["*Suggested actions*"];
473
- for (const candidate of candidates) {
474
- lines.push(
475
- "",
476
- `${candidate.index}. *${markdownToSlackMrkdwn(candidate.intent.summary)}*`,
477
- ` Intent: \`${candidate.intent.action}\` (\`${candidate.intent.domain}\`)`,
478
- ` Proposal: \`${candidate.proposalId}\``,
479
- ` Intent ID: \`${candidate.intent.intentId}\``
480
- );
481
- lines.push(...renderSuggestedActionDetails(candidate.intent.params, candidate.intent.action));
482
- if (candidate.proposalPreconditions?.length) {
483
- lines.push(" Preconditions:");
484
- for (const precondition of candidate.proposalPreconditions) {
485
- lines.push(` - ${markdownToSlackMrkdwn(precondition)}`);
486
- }
487
- }
488
- }
489
- lines.push(
490
- "",
491
- "Reply with:",
492
- "- `approve 1` to record approval",
493
- "- `apply 1` or `apply all` to apply supported actions",
494
- "- `continue 1` to continue with a follow-up run",
495
- "- `reject 1` to reject an action"
496
- );
497
- return lines;
498
- }
499
- function renderSlackFinalResult(result) {
500
- const lines = [`Finished with *${result.conclusion}*.`, "", markdownToSlackMrkdwn(result.summary)];
501
- if (result.verification?.length) {
502
- lines.push("", "*Verification*");
503
- for (const check of result.verification) {
504
- lines.push(`- \`${check.command}\`: ${check.outcome}`);
505
- }
506
- }
507
- const nextAction = nextActionSummary(result);
508
- if (nextAction) {
509
- lines.push("", `*Next action*: ${markdownToSlackMrkdwn(nextAction)}`);
510
- }
511
- const suggestedActions = renderSuggestedActionsMarkdown(result);
512
- if (suggestedActions.length > 0) {
513
- lines.push("", ...suggestedActions);
514
- }
515
- return lines.join("\n");
516
- }
517
- function createSlackFinalResultBlocks(result) {
518
- const blocks = [
519
- {
520
- type: "section",
521
- text: {
522
- type: "mrkdwn",
523
- text: `*Finished with ${result.conclusion}.*
524
- ${markdownToSlackMrkdwn(result.summary)}`
525
- }
526
- }
527
- ];
528
- if (result.verification?.length) {
529
- blocks.push({ type: "divider" });
530
- blocks.push({
531
- type: "section",
532
- text: {
533
- type: "mrkdwn",
534
- text: markdownToSlackMrkdwn(["*Verification*", ...result.verification.map((check) => `- \`${check.command}\`: ${check.outcome}`)].join("\n"))
535
- }
536
- });
537
- }
538
- const nextAction = nextActionSummary(result);
539
- if (nextAction) {
540
- blocks.push({
541
- type: "section",
542
- text: {
543
- type: "mrkdwn",
544
- text: `*Next action*: ${markdownToSlackMrkdwn(nextAction)}`
545
- }
546
- });
547
- }
548
- const suggestedActions = renderSuggestedActionsMarkdown(result);
549
- if (suggestedActions.length > 0) {
550
- blocks.push({ type: "divider" });
551
- blocks.push({
552
- type: "section",
553
- text: {
554
- type: "mrkdwn",
555
- text: suggestedActions.join("\n")
556
- }
557
- });
558
- }
559
- return blocks;
560
- }
561
- function createSlackPostMessagePayload(input) {
562
- return {
563
- channel: input.channelId,
564
- text: markdownToSlackMrkdwn(input.text),
565
- thread_ts: input.threadTs,
566
- ...input.blocks?.length ? { blocks: input.blocks } : {}
567
- };
568
- }
569
- function createSlackUpdateMessagePayload(input) {
570
- return {
571
- channel: input.channelId,
572
- text: markdownToSlackMrkdwn(input.text),
573
- ts: input.messageTs,
574
- ...input.blocks?.length ? { blocks: input.blocks } : {}
575
- };
576
- }
577
-
578
777
  // src/socket-mode.ts
579
778
  import WebSocket from "ws";
580
779
  var SLACK_CONNECTIONS_OPEN_URL = "https://slack.com/api/apps.connections.open";
581
780
  var DEFAULT_RECONNECT_DELAY_MS = 1e3;
781
+ var TERMINAL_SLACK_ERROR_CODES = [
782
+ "invalid_auth",
783
+ "not_authed",
784
+ "account_inactive",
785
+ "token_revoked",
786
+ "token_expired",
787
+ "not_allowed_token_type",
788
+ "no_permission",
789
+ "missing_scope",
790
+ "ekm_access_denied"
791
+ ];
792
+ function isTerminalSlackAuthError(error) {
793
+ if (!(error instanceof Error)) return false;
794
+ return TERMINAL_SLACK_ERROR_CODES.some((code) => error.message.includes(code));
795
+ }
582
796
  function rawDataToString(data) {
583
797
  if (typeof data === "string") return data;
584
798
  if (Buffer.isBuffer(data)) return data.toString("utf8");
@@ -614,12 +828,15 @@ async function handleSocketMessage(input) {
614
828
  return;
615
829
  }
616
830
  input.socket.send(JSON.stringify({ envelope_id: envelope.envelope_id }));
617
- if (envelope.type !== "events_api" || !envelope.payload) {
831
+ if (!envelope.payload) {
618
832
  return;
619
833
  }
620
834
  if (input.slackApp.appId && envelope.payload.api_app_id && envelope.payload.api_app_id !== input.slackApp.appId) {
621
835
  return;
622
836
  }
837
+ if (envelope.type !== "events_api" && envelope.payload.type !== "block_actions") {
838
+ return;
839
+ }
623
840
  await input.processor.process(envelope.payload, input.slackApp);
624
841
  }
625
842
  function wait(ms) {
@@ -671,8 +888,20 @@ function startSlackSocketModeApp(input, dependencies = {}) {
671
888
  }
672
889
  const startPromise = (async () => {
673
890
  while (!closed) {
674
- const socketUrl = await openSlackSocketUrl({ appToken: input.appToken, fetchImpl });
675
- await runOneConnection(socketUrl);
891
+ try {
892
+ const socketUrl = await openSlackSocketUrl({ appToken: input.appToken, fetchImpl });
893
+ await runOneConnection(socketUrl);
894
+ } catch (error) {
895
+ if (isTerminalSlackAuthError(error)) {
896
+ if (!closed) {
897
+ logError("[slack] terminal Socket Mode auth/config error, aborting:", error);
898
+ }
899
+ throw error;
900
+ }
901
+ if (!closed) {
902
+ logError("[slack] failed to open Socket Mode connection, retrying:", error);
903
+ }
904
+ }
676
905
  if (!closed) {
677
906
  await wait(reconnectDelayMs);
678
907
  }
@@ -702,18 +931,22 @@ function startSlackSocketModeIngress(config, dependencies = {}) {
702
931
  );
703
932
  }
704
933
  export {
934
+ buildSlackSuggestedActionButtonValue,
705
935
  computeSlackSignature,
706
936
  createSlackEventProcessor,
707
937
  createSlackEventsApp,
708
938
  createSlackFinalResultBlocks,
709
939
  createSlackPostMessagePayload,
940
+ createSlackReactionPayload,
710
941
  createSlackUpdateMessagePayload,
711
942
  encodeSlackThreadKey,
712
943
  markdownToSlackMrkdwn,
713
944
  normalizeSlackAppMention,
945
+ parseSlackSuggestedActionButtonValue,
714
946
  parseSlackThreadKey,
715
947
  renderSlackAcknowledgement,
716
948
  renderSlackFinalResult,
949
+ slackSourceReceiptReactionName,
717
950
  startSlackIngress,
718
951
  startSlackSocketModeApp,
719
952
  startSlackSocketModeIngress,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/events.ts","../src/normalize.ts","../src/ingress.ts","../src/dispatcher-events.ts","../src/render.ts","../src/socket-mode.ts"],"sourcesContent":["import { parseThreadActionCommand, type OpenTagEvent } from \"@opentag/core\";\nimport { encodeSlackThreadKey, normalizeSlackAppMention, stripSlackAppMention, type SlackChannelBinding } from \"./normalize.js\";\n\nexport type SlackThreadActionInput = {\n id: string;\n rawText: string;\n actor: {\n provider: \"slack\";\n providerUserId: string;\n handle: string;\n organizationId: string;\n };\n callback: {\n provider: \"slack\";\n uri: string;\n threadKey: string;\n };\n metadata: Record<string, unknown>;\n};\n\nexport type SlackEventEnvelope = {\n token?: string;\n type: \"url_verification\" | \"event_callback\";\n challenge?: string;\n team_id?: string;\n api_app_id?: string;\n event?: {\n type: string;\n user?: string;\n text?: string;\n ts?: string;\n thread_ts?: string;\n channel?: string;\n subtype?: string;\n bot_id?: string;\n };\n event_id?: string;\n event_time?: number;\n authorizations?: Array<{ user_id?: string }>;\n};\n\nexport type SlackAppRuntimeConfig = {\n agentId: string;\n appId?: string;\n callbackUri?: string;\n};\n\nexport type SlackEventProcessorInput = {\n resolveChannelBinding(input: { teamId: string; channelId: string }): Promise<SlackChannelBinding | null>;\n createRun(event: OpenTagEvent): Promise<{ runId: string }>;\n submitThreadAction?(action: SlackThreadActionInput): Promise<unknown>;\n now(): string;\n};\n\nexport type SlackEventProcessorStatus = 200 | 400;\n\nexport type SlackEventProcessorResult =\n | {\n kind: \"json\";\n status: SlackEventProcessorStatus;\n body: Record<string, unknown>;\n }\n | {\n kind: \"text\";\n status: SlackEventProcessorStatus;\n body: string;\n };\n\nfunction json(body: Record<string, unknown>, status: SlackEventProcessorStatus = 200): SlackEventProcessorResult {\n return { kind: \"json\", status, body };\n}\n\nfunction text(body: string, status: SlackEventProcessorStatus = 200): SlackEventProcessorResult {\n return { kind: \"text\", status, body };\n}\n\nexport function createSlackEventProcessor(input: SlackEventProcessorInput) {\n return {\n async process(payload: SlackEventEnvelope, slackApp: SlackAppRuntimeConfig): Promise<SlackEventProcessorResult> {\n if (payload.type === \"url_verification\") {\n return text(payload.challenge ?? \"\");\n }\n if (payload.type !== \"event_callback\" || !payload.event || ![\"app_mention\", \"message\"].includes(payload.event.type)) {\n return json({ ok: true });\n }\n if (payload.event.type === \"message\" && (payload.event.subtype || payload.event.bot_id)) {\n return json({ ok: true });\n }\n if (!payload.team_id || !payload.event.channel || !payload.event.user || !payload.event.text || !payload.event.ts || !payload.event_id) {\n return json({ error: \"invalid_event_payload\" }, 400);\n }\n\n const rawThreadActionText =\n payload.event.type === \"app_mention\"\n ? stripSlackAppMention(payload.event.text, payload.authorizations?.[0]?.user_id)\n : payload.event.text.trim();\n if (payload.event.type === \"message\" && (!rawThreadActionText || !parseThreadActionCommand(rawThreadActionText))) {\n return json({ ok: true });\n }\n\n const binding = await input.resolveChannelBinding({\n teamId: payload.team_id,\n channelId: payload.event.channel\n });\n if (!binding) {\n return json({ ok: true, ignored: \"unbound_channel\" });\n }\n\n if (rawThreadActionText && parseThreadActionCommand(rawThreadActionText) && input.submitThreadAction) {\n await input.submitThreadAction({\n id: `approval_slack_${payload.event_id}`,\n rawText: rawThreadActionText,\n actor: {\n provider: \"slack\",\n providerUserId: payload.event.user,\n handle: payload.event.user,\n organizationId: payload.team_id\n },\n callback: {\n provider: \"slack\",\n uri: slackApp.callbackUri ?? \"https://slack.com/api/chat.postMessage\",\n threadKey: encodeSlackThreadKey({\n teamId: payload.team_id,\n channelId: payload.event.channel,\n threadTs: payload.event.thread_ts ?? payload.event.ts\n })\n },\n metadata: {\n teamId: payload.team_id,\n channelId: payload.event.channel,\n messageTs: payload.event.ts,\n ...(payload.api_app_id ? { slackAppId: payload.api_app_id } : {}),\n ...(payload.authorizations?.[0]?.user_id ? { slackBotUserId: payload.authorizations[0].user_id } : {}),\n repoProvider: binding.repoProvider ?? \"github\",\n owner: binding.owner,\n repo: binding.repo\n }\n });\n return json({ ok: true });\n }\n\n if (payload.event.type !== \"app_mention\") {\n return json({ ok: true });\n }\n\n const event = normalizeSlackAppMention({\n teamId: payload.team_id,\n channelId: payload.event.channel,\n userId: payload.event.user,\n text: payload.event.text,\n ts: payload.event.ts,\n eventId: payload.event_id,\n eventTime: payload.event_time ?? Math.floor(Date.parse(input.now()) / 1000),\n agentId: slackApp.agentId,\n binding,\n ...(payload.api_app_id ? { appId: payload.api_app_id } : {}),\n ...(payload.event.thread_ts ? { threadTs: payload.event.thread_ts } : {}),\n ...(payload.authorizations?.[0]?.user_id ? { botUserId: payload.authorizations[0].user_id } : {}),\n ...(slackApp.callbackUri ? { callbackUri: slackApp.callbackUri } : {})\n });\n if (!event) {\n return json({ ok: true, ignored: \"empty_command\" });\n }\n\n await input.createRun(event);\n return json({ ok: true });\n }\n };\n}\n","import { commandFromRawText, type ContextPointer, type OpenTagCommand, type OpenTagEvent, type PermissionGrant } from \"@opentag/core\";\n\nexport type SlackChannelBinding = {\n teamId: string;\n channelId: string;\n repoProvider?: string;\n owner: string;\n repo: string;\n};\n\nexport type SlackAppMentionInput = {\n teamId: string;\n channelId: string;\n userId: string;\n text: string;\n ts: string;\n threadTs?: string;\n eventId: string;\n eventTime: number;\n appId?: string;\n agentId?: string;\n botUserId?: string;\n callbackUri?: string;\n binding: SlackChannelBinding;\n};\n\nexport function stripSlackAppMention(text: string, botUserId?: string): string | null {\n const patterns = botUserId\n ? [new RegExp(`^<@${botUserId}>\\\\s*`, \"i\"), /^<@[^>]+>\\s*/]\n : [/^<@[^>]+>\\s*/];\n\n for (const pattern of patterns) {\n const stripped = text.replace(pattern, \"\").trim();\n if (stripped !== text.trim()) {\n return stripped.length > 0 ? stripped : null;\n }\n }\n\n return null;\n}\n\nexport function encodeSlackThreadKey(input: { teamId: string; channelId: string; threadTs: string }): string {\n return `${input.teamId}|${input.channelId}|${input.threadTs}`;\n}\n\nexport function parseSlackThreadKey(threadKey: string): { teamId: string; channelId: string; threadTs: string } {\n const [teamId, channelId, threadTs] = threadKey.split(\"|\");\n if (!teamId || !channelId || !threadTs) {\n throw new Error(`Invalid Slack thread key: ${threadKey}`);\n }\n return { teamId, channelId, threadTs };\n}\n\nfunction permissionsForIntent(intent: OpenTagCommand[\"intent\"]): PermissionGrant[] {\n const permissions: PermissionGrant[] = [\n {\n scope: \"chat:postMessage\",\n reason: \"reply in the originating Slack thread\"\n },\n {\n scope: \"runner:local\",\n reason: \"execute the run on a paired local daemon\"\n }\n ];\n\n if (intent === \"fix\" || intent === \"run\") {\n permissions.push(\n {\n scope: \"repo:read\",\n reason: \"inspect the repository in the paired local checkout\"\n },\n {\n scope: \"repo:write\",\n reason: \"commit code changes on an isolated run branch\"\n },\n {\n scope: \"pr:create\",\n reason: \"open a pull request for completed code changes\"\n }\n );\n }\n\n return permissions;\n}\n\nfunction contextPointersForCommand(command: OpenTagCommand): ContextPointer[] {\n const context: ContextPointer[] = [];\n\n for (const reference of command.parsed?.references ?? []) {\n if (reference.kind === \"url\") {\n context.push({\n kind: \"url\",\n uri: reference.uri,\n visibility: \"organization\",\n title: reference.title ?? \"Command URL reference\"\n });\n continue;\n }\n\n if (reference.kind === \"file\" || reference.kind === \"path\") {\n context.push({\n kind: \"file\",\n uri: reference.uri,\n ...(reference.line ? { line: reference.line } : {}),\n ...(reference.startLine ? { startLine: reference.startLine } : {}),\n ...(reference.endLine ? { endLine: reference.endLine } : {}),\n visibility: \"organization\",\n title: referenceTitle(reference)\n });\n }\n }\n\n return context;\n}\n\nfunction referenceTitle(reference: NonNullable<OpenTagCommand[\"parsed\"]>[\"references\"][number]): string {\n return reference.title ?? \"Command file reference\";\n}\n\nfunction commandMetadata(command: OpenTagCommand): Record<string, unknown> {\n if (!command.parsed) return {};\n return {\n commandParser: command.parsed.version,\n commandDiagnostics: command.parsed.diagnostics,\n ...(command.parsed.approval ? { approval: command.parsed.approval } : {}),\n ...(command.parsed.network ? { network: command.parsed.network } : {})\n };\n}\n\nexport function normalizeSlackAppMention(input: SlackAppMentionInput): OpenTagEvent | null {\n const rawText = stripSlackAppMention(input.text, input.botUserId);\n if (!rawText) return null;\n\n const command = commandFromRawText(rawText);\n const replyThreadTs = input.threadTs ?? input.ts;\n const agentId = input.agentId ?? \"opentag\";\n\n return {\n id: `evt_slack_app_mention_${input.eventId}`,\n source: \"slack\",\n sourceEventId: input.eventId,\n receivedAt: new Date(input.eventTime * 1000).toISOString(),\n actor: {\n provider: \"slack\",\n providerUserId: input.userId,\n handle: input.userId,\n organizationId: input.teamId\n },\n target: {\n mention: input.botUserId ? `<@${input.botUserId}>` : \"<@app>\",\n agentId,\n ...(command.parsed?.executorHint ? { executorHint: command.parsed.executorHint } : {})\n },\n command,\n context: [\n {\n provider: \"slack\",\n kind: \"message\",\n uri: `slack://team/${input.teamId}/channel/${input.channelId}/message/${input.ts}`,\n visibility: \"organization\",\n title: \"Slack message\"\n },\n {\n kind: \"text\",\n uri: input.text,\n visibility: \"organization\",\n title: \"Slack message text\"\n },\n ...contextPointersForCommand(command)\n ],\n permissions: permissionsForIntent(command.intent),\n callback: {\n provider: \"slack\",\n uri: input.callbackUri ?? \"https://slack.com/api/chat.postMessage\",\n threadKey: encodeSlackThreadKey({\n teamId: input.teamId,\n channelId: input.channelId,\n threadTs: replyThreadTs\n })\n },\n metadata: {\n teamId: input.teamId,\n channelId: input.channelId,\n messageTs: input.ts,\n ...(input.appId ? { slackAppId: input.appId } : {}),\n ...(input.botUserId ? { slackBotUserId: input.botUserId } : {}),\n ...commandMetadata(command),\n repoProvider: input.binding.repoProvider ?? \"github\",\n owner: input.binding.owner,\n repo: input.binding.repo\n }\n };\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport { createSlackDispatcherEventProcessorInput } from \"./dispatcher-events.js\";\nimport { createSlackEventProcessor, type SlackAppRuntimeConfig, type SlackEventEnvelope, type SlackEventProcessorInput } from \"./events.js\";\n\nexport type SlackEventsAppInput = {\n slackApps: Array<\n SlackAppRuntimeConfig & {\n signingSecret: string;\n }\n >;\n clock?: () => number;\n} & SlackEventProcessorInput;\n\nexport type SlackEventsApiIngressConfig = {\n signingSecret: string;\n dispatcherUrl: string;\n dispatcherToken?: string;\n port?: number;\n agentId?: string;\n appId?: string;\n callbackUri?: string;\n};\n\nexport type SlackIngressConfig = SlackEventsApiIngressConfig;\n\nexport type SlackIngressHandle = {\n url: string;\n server: ReturnType<typeof serve>;\n close(): Promise<void>;\n};\n\nexport function computeSlackSignature(input: {\n signingSecret: string;\n timestamp: string;\n rawBody: string;\n}): string {\n const base = `v0:${input.timestamp}:${input.rawBody}`;\n const digest = createHmac(\"sha256\", input.signingSecret).update(base).digest(\"hex\");\n return `v0=${digest}`;\n}\n\nexport function verifySlackSignature(input: {\n signingSecret: string;\n timestamp: string;\n rawBody: string;\n signature: string;\n}): boolean {\n const expected = computeSlackSignature(input);\n const expectedBuffer = Buffer.from(expected);\n const actualBuffer = Buffer.from(input.signature);\n return expectedBuffer.length === actualBuffer.length && timingSafeEqual(expectedBuffer, actualBuffer);\n}\n\nexport function verifySlackTimestamp(input: { timestamp: string; nowMs: number; toleranceSeconds?: number }): boolean {\n const timestampSeconds = Number(input.timestamp);\n if (!Number.isFinite(timestampSeconds)) return false;\n const toleranceSeconds = input.toleranceSeconds ?? 300;\n const ageSeconds = Math.abs(Math.floor(input.nowMs / 1000) - timestampSeconds);\n return ageSeconds <= toleranceSeconds;\n}\n\nexport function createSlackEventsApp(input: SlackEventsAppInput) {\n const app = new Hono();\n const processor = createSlackEventProcessor(input);\n\n function parseSlackPayload(rawBody: string): SlackEventEnvelope | null {\n try {\n return JSON.parse(rawBody) as SlackEventEnvelope;\n } catch {\n return null;\n }\n }\n\n function resolveSlackApp(inputValue: {\n apiAppId?: string;\n rawBody: string;\n signature: string;\n timestamp: string;\n }) {\n const candidates = inputValue.apiAppId\n ? input.slackApps.filter((candidate) => !candidate.appId || candidate.appId === inputValue.apiAppId)\n : input.slackApps;\n if (candidates.length === 0) {\n return { error: \"unknown_slack_app\" as const };\n }\n const slackApp = candidates.find((candidate) =>\n verifySlackSignature({\n signingSecret: candidate.signingSecret,\n timestamp: inputValue.timestamp,\n rawBody: inputValue.rawBody,\n signature: inputValue.signature\n })\n );\n return slackApp ? { slackApp } : { error: \"invalid_signature\" as const };\n }\n\n app.post(\"/slack/events\", async (c) => {\n const timestamp = c.req.header(\"x-slack-request-timestamp\");\n const signature = c.req.header(\"x-slack-signature\");\n if (!timestamp || !signature) {\n return c.json({ error: \"missing_signature_headers\" }, 401);\n }\n if (!verifySlackTimestamp({ timestamp, nowMs: input.clock?.() ?? Date.now() })) {\n return c.json({ error: \"stale_signature_timestamp\" }, 401);\n }\n const rawBody = await c.req.text();\n const payload = parseSlackPayload(rawBody);\n if (!payload) {\n return c.json({ error: \"invalid_json\" }, 400);\n }\n const resolvedSlackApp = resolveSlackApp({\n rawBody,\n signature,\n timestamp,\n ...(payload.api_app_id ? { apiAppId: payload.api_app_id } : {})\n });\n if (\"error\" in resolvedSlackApp) {\n return c.json({ error: resolvedSlackApp.error }, 401);\n }\n const result = await processor.process(payload, resolvedSlackApp.slackApp);\n if (result.kind === \"text\") {\n return c.text(result.body, result.status);\n }\n return c.json(result.body, result.status);\n });\n\n return app;\n}\n\nexport function startSlackIngress(config: SlackEventsApiIngressConfig): SlackIngressHandle {\n const port = config.port ?? 3040;\n const server = serve({\n fetch: createSlackEventsApp({\n slackApps: [\n {\n signingSecret: config.signingSecret,\n agentId: config.agentId ?? \"opentag\",\n ...(config.appId ? { appId: config.appId } : {}),\n ...(config.callbackUri ? { callbackUri: config.callbackUri } : {})\n }\n ],\n ...createSlackDispatcherEventProcessorInput(config)\n }).fetch,\n port\n });\n\n return {\n url: `http://localhost:${port}`,\n server,\n close() {\n return new Promise((resolve, reject) => {\n server.close((error?: Error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n }\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { createOpenTagClient } from \"@opentag/client\";\nimport type { SlackEventProcessorInput } from \"./events.js\";\n\nexport type SlackDispatcherEventConfig = {\n dispatcherUrl: string;\n dispatcherToken?: string;\n};\n\nexport function createSlackDispatcherEventProcessorInput(config: SlackDispatcherEventConfig): SlackEventProcessorInput {\n const dispatcherClient = createOpenTagClient({\n dispatcherUrl: config.dispatcherUrl,\n ...(config.dispatcherToken ? { pairingToken: config.dispatcherToken } : {})\n });\n\n return {\n async resolveChannelBinding(input) {\n try {\n const { binding } = await dispatcherClient.getChannelBinding({\n provider: \"slack\",\n accountId: input.teamId,\n conversationId: input.channelId\n });\n return {\n teamId: binding.accountId,\n channelId: binding.conversationId,\n repoProvider: binding.repoProvider,\n owner: binding.owner,\n repo: binding.repo\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"channel_binding_not_found\")) {\n return null;\n }\n throw error;\n }\n },\n async createRun(event) {\n const runId = `run_${randomUUID()}`;\n const created = await dispatcherClient.createRun({ runId, event });\n return created.outcome === \"run_created\" ? { runId: created.run.id } : { runId };\n },\n async submitThreadAction(action) {\n await dispatcherClient.submitThreadAction(action);\n },\n now: () => new Date().toISOString()\n };\n}\n","import { suggestedActionCandidatesFromResult, type OpenTagRunResult } from \"@opentag/core\";\n\nexport type SlackTextBlock = {\n type: \"section\";\n text: {\n type: \"mrkdwn\";\n text: string;\n };\n};\n\nexport type SlackDividerBlock = {\n type: \"divider\";\n};\n\nexport type SlackBlock = SlackTextBlock | SlackDividerBlock;\n\nexport type SlackMessagePayload = {\n channel: string;\n text: string;\n thread_ts?: string;\n ts?: string;\n blocks?: SlackBlock[];\n};\n\nfunction escapeSlackText(text: string): string {\n return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\nexport function markdownToSlackMrkdwn(text: string): string {\n const links: string[] = [];\n const withoutLinks = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label: string, url: string) => {\n const token = `\\u0000SLACK_LINK_${links.length}\\u0000`;\n links.push(`<${url}|${escapeSlackText(label)}>`);\n return token;\n });\n const converted = escapeSlackText(withoutLinks)\n .replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\")\n .replace(/__(.+?)__/g, \"*$1*\");\n return links.reduce((output, link, index) => output.replace(`\\u0000SLACK_LINK_${index}\\u0000`, link), converted);\n}\n\nexport function renderSlackAcknowledgement(runId: string): string {\n return `I picked this up: \\`${runId}\\``;\n}\n\nfunction nextActionSummary(result: OpenTagRunResult): string | undefined {\n if (!result.nextAction) return undefined;\n if (typeof result.nextAction === \"string\") return result.nextAction;\n return result.nextAction.summary;\n}\n\nfunction stringParam(params: Record<string, unknown> | undefined, key: string): string | undefined {\n const value = params?.[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction stringArrayParam(params: Record<string, unknown> | undefined, key: string): string[] {\n const value = params?.[key];\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n}\n\nfunction renderVerificationParams(params: Record<string, unknown> | undefined): string[] {\n const value = params?.[\"verification\"];\n if (!Array.isArray(value)) return [];\n return value\n .map((item) => {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return undefined;\n const command = (item as Record<string, unknown>)[\"command\"];\n const outcome = (item as Record<string, unknown>)[\"outcome\"];\n return typeof command === \"string\" && typeof outcome === \"string\" ? ` - \\`${command}\\`: ${outcome}` : undefined;\n })\n .filter((line): line is string => Boolean(line));\n}\n\nfunction renderSuggestedActionDetails(params: Record<string, unknown> | undefined, action: string): string[] {\n if (action !== \"create_pull_request\") return [];\n const lines: string[] = [];\n const title = stringParam(params, \"title\");\n const head = stringParam(params, \"head\") ?? stringParam(params, \"branch\");\n const base = stringParam(params, \"base\") ?? stringParam(params, \"baseBranch\");\n const changedFiles = stringArrayParam(params, \"changedFiles\");\n const risks = stringArrayParam(params, \"risks\");\n const verification = renderVerificationParams(params);\n if (title) lines.push(` Title: ${markdownToSlackMrkdwn(title)}`);\n if (head || base) lines.push(` Branch: \\`${head ?? \"unknown\"}\\` -> \\`${base ?? \"main\"}\\``);\n if (changedFiles.length > 0) lines.push(` Changed files: ${changedFiles.map((file) => `\\`${file}\\``).join(\", \")}`);\n if (risks.length > 0) {\n lines.push(\" Risks:\");\n for (const risk of risks) {\n lines.push(` - ${markdownToSlackMrkdwn(risk)}`);\n }\n }\n if (verification.length > 0) {\n lines.push(\" Verification:\");\n lines.push(...verification);\n }\n return lines;\n}\n\nfunction renderSuggestedActionsMarkdown(result: OpenTagRunResult): string[] {\n const candidates = suggestedActionCandidatesFromResult(result);\n if (candidates.length === 0) return [];\n\n const lines = [\"*Suggested actions*\"];\n for (const candidate of candidates) {\n lines.push(\n \"\",\n `${candidate.index}. *${markdownToSlackMrkdwn(candidate.intent.summary)}*`,\n ` Intent: \\`${candidate.intent.action}\\` (\\`${candidate.intent.domain}\\`)`,\n ` Proposal: \\`${candidate.proposalId}\\``,\n ` Intent ID: \\`${candidate.intent.intentId}\\``\n );\n lines.push(...renderSuggestedActionDetails(candidate.intent.params, candidate.intent.action));\n if (candidate.proposalPreconditions?.length) {\n lines.push(\" Preconditions:\");\n for (const precondition of candidate.proposalPreconditions) {\n lines.push(` - ${markdownToSlackMrkdwn(precondition)}`);\n }\n }\n }\n\n lines.push(\n \"\",\n \"Reply with:\",\n \"- `approve 1` to record approval\",\n \"- `apply 1` or `apply all` to apply supported actions\",\n \"- `continue 1` to continue with a follow-up run\",\n \"- `reject 1` to reject an action\"\n );\n return lines;\n}\n\nexport function renderSlackFinalResult(result: OpenTagRunResult): string {\n const lines = [`Finished with *${result.conclusion}*.`, \"\", markdownToSlackMrkdwn(result.summary)];\n\n if (result.verification?.length) {\n lines.push(\"\", \"*Verification*\");\n for (const check of result.verification) {\n lines.push(`- \\`${check.command}\\`: ${check.outcome}`);\n }\n }\n\n const nextAction = nextActionSummary(result);\n if (nextAction) {\n lines.push(\"\", `*Next action*: ${markdownToSlackMrkdwn(nextAction)}`);\n }\n\n const suggestedActions = renderSuggestedActionsMarkdown(result);\n if (suggestedActions.length > 0) {\n lines.push(\"\", ...suggestedActions);\n }\n\n return lines.join(\"\\n\");\n}\n\nexport function createSlackFinalResultBlocks(result: OpenTagRunResult): SlackBlock[] {\n const blocks: SlackBlock[] = [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `*Finished with ${result.conclusion}.*\\n${markdownToSlackMrkdwn(result.summary)}`\n }\n }\n ];\n\n if (result.verification?.length) {\n blocks.push({ type: \"divider\" });\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: markdownToSlackMrkdwn([\"*Verification*\", ...result.verification.map((check) => `- \\`${check.command}\\`: ${check.outcome}`)].join(\"\\n\"))\n }\n });\n }\n\n const nextAction = nextActionSummary(result);\n if (nextAction) {\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `*Next action*: ${markdownToSlackMrkdwn(nextAction)}`\n }\n });\n }\n\n const suggestedActions = renderSuggestedActionsMarkdown(result);\n if (suggestedActions.length > 0) {\n blocks.push({ type: \"divider\" });\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: suggestedActions.join(\"\\n\")\n }\n });\n }\n\n return blocks;\n}\n\nexport function createSlackPostMessagePayload(input: { channelId: string; text: string; threadTs: string; blocks?: SlackBlock[] }): SlackMessagePayload {\n return {\n channel: input.channelId,\n text: markdownToSlackMrkdwn(input.text),\n thread_ts: input.threadTs,\n ...(input.blocks?.length ? { blocks: input.blocks } : {})\n };\n}\n\nexport function createSlackUpdateMessagePayload(input: { channelId: string; text: string; messageTs: string; blocks?: SlackBlock[] }): SlackMessagePayload {\n return {\n channel: input.channelId,\n text: markdownToSlackMrkdwn(input.text),\n ts: input.messageTs,\n ...(input.blocks?.length ? { blocks: input.blocks } : {})\n };\n}\n","import WebSocket, { type RawData } from \"ws\";\nimport { createSlackDispatcherEventProcessorInput, type SlackDispatcherEventConfig } from \"./dispatcher-events.js\";\nimport { createSlackEventProcessor, type SlackAppRuntimeConfig, type SlackEventEnvelope, type SlackEventProcessorInput } from \"./events.js\";\n\nconst SLACK_CONNECTIONS_OPEN_URL = \"https://slack.com/api/apps.connections.open\";\nconst DEFAULT_RECONNECT_DELAY_MS = 1_000;\n\nexport type SlackSocketModeEnvelope = {\n type?: string;\n envelope_id?: string;\n payload?: SlackEventEnvelope;\n accepts_response_payload?: boolean;\n};\n\nexport type SlackSocketModeAppInput = {\n appToken: string;\n slackApp: SlackAppRuntimeConfig;\n} & SlackEventProcessorInput;\n\nexport type SlackSocketModeIngressConfig = SlackDispatcherEventConfig & {\n appToken: string;\n agentId?: string;\n appId?: string;\n callbackUri?: string;\n};\n\nexport type SlackSocketModeIngressHandle = {\n startPromise: Promise<void>;\n close(): Promise<void>;\n};\n\nexport type SlackSocketModeDependencies = {\n fetchImpl?: typeof fetch;\n createWebSocket?(url: string): WebSocket;\n reconnectDelayMs?: number;\n log?(message: string): void;\n logError?(message: string, error?: unknown): void;\n};\n\ntype SlackConnectionsOpenResponse = {\n ok?: boolean;\n url?: string;\n error?: string;\n needed?: string;\n provided?: string;\n};\n\nfunction rawDataToString(data: RawData): string {\n if (typeof data === \"string\") return data;\n if (Buffer.isBuffer(data)) return data.toString(\"utf8\");\n if (Array.isArray(data)) return Buffer.concat(data).toString(\"utf8\");\n if (data instanceof ArrayBuffer) return Buffer.from(data).toString(\"utf8\");\n return Buffer.from(data).toString(\"utf8\");\n}\n\nasync function openSlackSocketUrl(input: { appToken: string; fetchImpl: typeof fetch }): Promise<string> {\n const response = await input.fetchImpl(SLACK_CONNECTIONS_OPEN_URL, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${input.appToken}`\n }\n });\n const body = (await response.json().catch(() => ({}))) as SlackConnectionsOpenResponse;\n if (!response.ok || !body.ok || !body.url) {\n const reason = body.error ?? `http_${response.status}`;\n throw new Error(`Slack Socket Mode connection failed: ${reason}`);\n }\n return body.url;\n}\n\nfunction parseSocketEnvelope(data: RawData): SlackSocketModeEnvelope | null {\n try {\n return JSON.parse(rawDataToString(data)) as SlackSocketModeEnvelope;\n } catch {\n return null;\n }\n}\n\nasync function handleSocketMessage(input: {\n data: RawData;\n socket: WebSocket;\n processor: ReturnType<typeof createSlackEventProcessor>;\n slackApp: SlackAppRuntimeConfig;\n logError(message: string, error?: unknown): void;\n}): Promise<void> {\n const envelope = parseSocketEnvelope(input.data);\n if (!envelope?.envelope_id) {\n input.logError(\"[slack] ignored Socket Mode envelope without envelope_id\");\n return;\n }\n\n input.socket.send(JSON.stringify({ envelope_id: envelope.envelope_id }));\n\n if (envelope.type !== \"events_api\" || !envelope.payload) {\n return;\n }\n if (input.slackApp.appId && envelope.payload.api_app_id && envelope.payload.api_app_id !== input.slackApp.appId) {\n return;\n }\n\n await input.processor.process(envelope.payload, input.slackApp);\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function startSlackSocketModeApp(\n input: SlackSocketModeAppInput,\n dependencies: SlackSocketModeDependencies = {}\n): SlackSocketModeIngressHandle {\n const fetchImpl = dependencies.fetchImpl ?? fetch;\n const createWebSocket = dependencies.createWebSocket ?? ((url: string) => new WebSocket(url));\n const reconnectDelayMs = dependencies.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS;\n const log = dependencies.log ?? ((message: string) => console.log(message));\n const logError = dependencies.logError ?? ((message: string, error?: unknown) => (error ? console.error(message, error) : console.error(message)));\n const processor = createSlackEventProcessor(input);\n let closed = false;\n let activeSocket: WebSocket | undefined;\n\n async function runOneConnection(socketUrl: string): Promise<void> {\n await new Promise<void>((resolve) => {\n const socket = createWebSocket(socketUrl);\n activeSocket = socket;\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n if (activeSocket === socket) activeSocket = undefined;\n resolve();\n };\n\n socket.once(\"open\", () => {\n log(\"[slack] Socket Mode connected\");\n });\n socket.on(\"message\", (data) => {\n void handleSocketMessage({\n data,\n socket,\n processor,\n slackApp: input.slackApp,\n logError\n }).catch((error: unknown) => {\n logError(\"[slack] failed to handle Socket Mode event:\", error);\n });\n });\n socket.once(\"close\", finish);\n socket.once(\"error\", (error) => {\n if (!closed) {\n logError(\"[slack] Socket Mode connection error:\", error);\n }\n socket.close();\n finish();\n });\n });\n }\n\n const startPromise = (async () => {\n while (!closed) {\n const socketUrl = await openSlackSocketUrl({ appToken: input.appToken, fetchImpl });\n await runOneConnection(socketUrl);\n if (!closed) {\n await wait(reconnectDelayMs);\n }\n }\n })();\n\n return {\n startPromise,\n async close() {\n closed = true;\n activeSocket?.close();\n await startPromise.catch(() => undefined);\n }\n };\n}\n\nexport function startSlackSocketModeIngress(\n config: SlackSocketModeIngressConfig,\n dependencies: SlackSocketModeDependencies = {}\n): SlackSocketModeIngressHandle {\n return startSlackSocketModeApp(\n {\n appToken: config.appToken,\n slackApp: {\n agentId: config.agentId ?? \"opentag\",\n ...(config.appId ? { appId: config.appId } : {}),\n ...(config.callbackUri ? { callbackUri: config.callbackUri } : {})\n },\n ...createSlackDispatcherEventProcessorInput(config)\n },\n dependencies\n );\n}\n"],"mappings":"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","names":["text","text"]}
1
+ {"version":3,"sources":["../src/events.ts","../src/normalize.ts","../src/render.ts","../src/ingress.ts","../src/dispatcher-events.ts","../src/socket-mode.ts"],"sourcesContent":["import { parseThreadActionCommand, type OpenTagEvent } from \"@opentag/core\";\nimport { encodeSlackThreadKey, normalizeSlackAppMention, stripSlackAppMention, type SlackChannelBinding } from \"./normalize.js\";\nimport { parseSlackSuggestedActionButtonValue } from \"./render.js\";\n\nexport type SlackThreadActionInput = {\n id: string;\n rawText: string;\n actor: {\n provider: \"slack\";\n providerUserId: string;\n handle: string;\n organizationId: string;\n };\n callback: {\n provider: \"slack\";\n uri: string;\n threadKey: string;\n };\n metadata: Record<string, unknown>;\n};\n\nexport type SlackEventEnvelope = {\n token?: string;\n type: \"url_verification\" | \"event_callback\";\n challenge?: string;\n team_id?: string;\n api_app_id?: string;\n event?: {\n type: string;\n user?: string;\n text?: string;\n ts?: string;\n thread_ts?: string;\n channel?: string;\n subtype?: string;\n bot_id?: string;\n };\n event_id?: string;\n event_time?: number;\n authorizations?: Array<{ user_id?: string }>;\n};\n\nexport type SlackInteractiveBlockAction = {\n type?: string;\n action_id?: string;\n block_id?: string;\n value?: string;\n action_ts?: string;\n};\n\nexport type SlackInteractivePayload = {\n type: \"block_actions\";\n api_app_id?: string;\n team?: { id?: string; domain?: string };\n user?: { id?: string; username?: string; name?: string };\n channel?: { id?: string; name?: string };\n message?: { ts?: string; thread_ts?: string };\n container?: { type?: string; channel_id?: string; message_ts?: string; thread_ts?: string };\n trigger_id?: string;\n actions?: SlackInteractiveBlockAction[];\n};\n\nexport type SlackIngressPayload = SlackEventEnvelope | SlackInteractivePayload;\n\nexport type SlackAppRuntimeConfig = {\n agentId: string;\n appId?: string;\n callbackUri?: string;\n};\n\nexport type SlackEventProcessorInput = {\n resolveChannelBinding(input: { teamId: string; channelId: string }): Promise<SlackChannelBinding | null>;\n createRun(event: OpenTagEvent): Promise<{ runId: string }>;\n submitThreadAction?(action: SlackThreadActionInput): Promise<unknown>;\n now(): string;\n};\n\nexport type SlackEventProcessorStatus = 200 | 400;\n\nexport type SlackEventProcessorResult =\n | {\n kind: \"json\";\n status: SlackEventProcessorStatus;\n body: Record<string, unknown>;\n }\n | {\n kind: \"text\";\n status: SlackEventProcessorStatus;\n body: string;\n };\n\nfunction json(body: Record<string, unknown>, status: SlackEventProcessorStatus = 200): SlackEventProcessorResult {\n return { kind: \"json\", status, body };\n}\n\nfunction text(body: string, status: SlackEventProcessorStatus = 200): SlackEventProcessorResult {\n return { kind: \"text\", status, body };\n}\n\nexport function createSlackEventProcessor(input: SlackEventProcessorInput) {\n async function processBlockActions(payload: SlackInteractivePayload, slackApp: SlackAppRuntimeConfig): Promise<SlackEventProcessorResult> {\n const action = payload.actions?.find((candidate) => {\n if (candidate.action_id?.startsWith(\"opentag:\")) return true;\n return typeof candidate.value === \"string\" && parseSlackSuggestedActionButtonValue(candidate.value) !== null;\n });\n if (!action) {\n return json({ ok: true });\n }\n\n const parsedValue = typeof action.value === \"string\" ? parseSlackSuggestedActionButtonValue(action.value) : null;\n const rawText =\n parsedValue?.command ??\n (typeof action.value === \"string\" && parseThreadActionCommand(action.value) ? action.value.trim() : undefined);\n if (!rawText || !parseThreadActionCommand(rawText)) {\n return json({ error: \"invalid_interactive_action\" }, 400);\n }\n if (!input.submitThreadAction) {\n return json({ ok: true });\n }\n\n const teamId = payload.team?.id;\n const userId = payload.user?.id;\n const channelId = payload.channel?.id ?? payload.container?.channel_id;\n const messageTs = payload.message?.ts ?? payload.container?.message_ts;\n const threadTs = payload.message?.thread_ts ?? payload.container?.thread_ts ?? messageTs;\n if (!teamId || !userId || !channelId || !messageTs || !threadTs) {\n return json({ error: \"invalid_interactive_payload\" }, 400);\n }\n\n const binding = await input.resolveChannelBinding({\n teamId,\n channelId\n });\n if (!binding) {\n return json({ ok: true, ignored: \"unbound_channel\" });\n }\n\n await input.submitThreadAction({\n id: `approval_slack_block_${payload.trigger_id ?? `${action.action_id ?? \"action\"}_${action.action_ts ?? messageTs}`}`,\n rawText,\n actor: {\n provider: \"slack\",\n providerUserId: userId,\n handle: payload.user?.username ?? payload.user?.name ?? userId,\n organizationId: teamId\n },\n callback: {\n provider: \"slack\",\n uri: slackApp.callbackUri ?? \"https://slack.com/api/chat.postMessage\",\n threadKey: encodeSlackThreadKey({\n teamId,\n channelId,\n threadTs\n })\n },\n metadata: {\n source: \"slack_button\",\n teamId,\n channelId,\n messageTs,\n ...(payload.api_app_id ? { slackAppId: payload.api_app_id } : {}),\n ...(action.action_id ? { actionId: action.action_id } : {}),\n ...(action.block_id ? { blockId: action.block_id } : {}),\n ...(action.action_ts ? { actionTs: action.action_ts } : {}),\n ...(parsedValue ? { proposalId: parsedValue.proposalId, intentId: parsedValue.intentId } : {}),\n repoProvider: binding.repoProvider ?? \"github\",\n owner: binding.owner,\n repo: binding.repo\n }\n });\n return json({ ok: true });\n }\n\n return {\n async process(payload: SlackIngressPayload, slackApp: SlackAppRuntimeConfig): Promise<SlackEventProcessorResult> {\n if (payload.type === \"block_actions\") {\n return processBlockActions(payload, slackApp);\n }\n if (payload.type === \"url_verification\") {\n return text(payload.challenge ?? \"\");\n }\n if (payload.type !== \"event_callback\" || !payload.event || ![\"app_mention\", \"message\"].includes(payload.event.type)) {\n return json({ ok: true });\n }\n if (payload.event.type === \"message\" && (payload.event.subtype || payload.event.bot_id)) {\n return json({ ok: true });\n }\n if (!payload.team_id || !payload.event.channel || !payload.event.user || !payload.event.text || !payload.event.ts || !payload.event_id) {\n return json({ error: \"invalid_event_payload\" }, 400);\n }\n\n const rawThreadActionText =\n payload.event.type === \"app_mention\"\n ? stripSlackAppMention(payload.event.text, payload.authorizations?.[0]?.user_id)\n : payload.event.text.trim();\n if (payload.event.type === \"message\" && (!rawThreadActionText || !parseThreadActionCommand(rawThreadActionText))) {\n return json({ ok: true });\n }\n\n const binding = await input.resolveChannelBinding({\n teamId: payload.team_id,\n channelId: payload.event.channel\n });\n if (!binding) {\n return json({ ok: true, ignored: \"unbound_channel\" });\n }\n\n if (rawThreadActionText && parseThreadActionCommand(rawThreadActionText) && input.submitThreadAction) {\n await input.submitThreadAction({\n id: `approval_slack_${payload.event_id}`,\n rawText: rawThreadActionText,\n actor: {\n provider: \"slack\",\n providerUserId: payload.event.user,\n handle: payload.event.user,\n organizationId: payload.team_id\n },\n callback: {\n provider: \"slack\",\n uri: slackApp.callbackUri ?? \"https://slack.com/api/chat.postMessage\",\n threadKey: encodeSlackThreadKey({\n teamId: payload.team_id,\n channelId: payload.event.channel,\n threadTs: payload.event.thread_ts ?? payload.event.ts\n })\n },\n metadata: {\n teamId: payload.team_id,\n channelId: payload.event.channel,\n messageTs: payload.event.ts,\n ...(payload.api_app_id ? { slackAppId: payload.api_app_id } : {}),\n ...(payload.authorizations?.[0]?.user_id ? { slackBotUserId: payload.authorizations[0].user_id } : {}),\n repoProvider: binding.repoProvider ?? \"github\",\n owner: binding.owner,\n repo: binding.repo\n }\n });\n return json({ ok: true });\n }\n\n if (payload.event.type !== \"app_mention\") {\n return json({ ok: true });\n }\n\n const event = normalizeSlackAppMention({\n teamId: payload.team_id,\n channelId: payload.event.channel,\n userId: payload.event.user,\n text: payload.event.text,\n ts: payload.event.ts,\n eventId: payload.event_id,\n eventTime: payload.event_time ?? Math.floor(Date.parse(input.now()) / 1000),\n agentId: slackApp.agentId,\n binding,\n ...(payload.api_app_id ? { appId: payload.api_app_id } : {}),\n ...(payload.event.thread_ts ? { threadTs: payload.event.thread_ts } : {}),\n ...(payload.authorizations?.[0]?.user_id ? { botUserId: payload.authorizations[0].user_id } : {}),\n ...(slackApp.callbackUri ? { callbackUri: slackApp.callbackUri } : {})\n });\n if (!event) {\n return json({ ok: true, ignored: \"empty_command\" });\n }\n\n await input.createRun(event);\n return json({ ok: true });\n }\n };\n}\n","import { commandFromRawText, type ContextPointer, type OpenTagCommand, type OpenTagEvent, type PermissionGrant } from \"@opentag/core\";\n\nexport type SlackChannelBinding = {\n teamId: string;\n channelId: string;\n repoProvider?: string;\n owner: string;\n repo: string;\n};\n\nexport type SlackAppMentionInput = {\n teamId: string;\n channelId: string;\n userId: string;\n text: string;\n ts: string;\n threadTs?: string;\n eventId: string;\n eventTime: number;\n appId?: string;\n agentId?: string;\n botUserId?: string;\n callbackUri?: string;\n binding: SlackChannelBinding;\n};\n\n// Matches a run of one or more leading user mentions (e.g. a teammate mention\n// placed before the bot mention) along with the whitespace separating them.\nconst LEADING_MENTION_RUN = /^(?:<@[^>]+>\\s*)+/;\n// Matches a single mention token, used to confirm the bot itself appears in the\n// leading run so we only treat the message as an at-mention of the bot.\nconst MENTION_TOKEN = /<@([^>]+)>/g;\n\nexport function stripSlackAppMention(text: string, botUserId?: string): string | null {\n const run = text.match(LEADING_MENTION_RUN);\n if (!run) return null;\n\n // Only strip the *leading* run of mentions; mentions later in the message\n // (e.g. \"<@bot> ping <@teammate> now\") must be preserved as command text.\n const leadingRun = run[0];\n\n if (botUserId) {\n // Require that the bot is mentioned somewhere in the leading run before we\n // accept this as a command directed at the bot. This lets a teammate\n // mention precede the bot mention without breaking routing.\n const mentionedIds = leadingRun.match(MENTION_TOKEN) ?? [];\n const botIsMentioned = mentionedIds.some((token) => {\n // Slack mentions may carry a display-name/label suffix, e.g.\n // \"<@U12345|alice>\". Strip the label so we compare against the bare\n // user ID rather than \"U12345|alice\".\n const id = token.slice(2, -1).split(\"|\")[0] ?? \"\";\n return id.toLowerCase() === botUserId.toLowerCase();\n });\n if (!botIsMentioned) return null;\n }\n\n const stripped = text.slice(leadingRun.length).trim();\n return stripped.length > 0 ? stripped : null;\n}\n\nexport function encodeSlackThreadKey(input: { teamId: string; channelId: string; threadTs: string }): string {\n return `${input.teamId}|${input.channelId}|${input.threadTs}`;\n}\n\nexport function parseSlackThreadKey(threadKey: string): { teamId: string; channelId: string; threadTs: string } {\n const [teamId, channelId, threadTs] = threadKey.split(\"|\");\n if (!teamId || !channelId || !threadTs) {\n throw new Error(`Invalid Slack thread key: ${threadKey}`);\n }\n return { teamId, channelId, threadTs };\n}\n\nconst UNKNOWN_WRITE_VERB_PATTERN = /\\b(add|append|apply|change|commit|create|delete|edit|fix|modify|open\\s+a?\\s*pr|pull\\s+request|remove|update|write)\\b/i;\nconst REPO_WRITE_TARGET_PATTERN =\n /\\b(repo|repository|code|file|files|branch|commit|diff|patch|readme|pr|pull\\s+request|package\\.json|pnpm|npm|test|build)\\b|(?:^|\\s)[./\\w-]+\\.(?:cjs|css|gitignore|go|html|js|json|jsx|lock|md|mjs|py|rb|rs|sh|toml|ts|tsx|txt|yaml|yml)\\b|(?:^|[\\s`'\"(])(?:[./\\w-]+\\/)?(?:Dockerfile|Makefile|Procfile|Rakefile|Gemfile|Brewfile|Justfile|Taskfile|\\.dockerignore|\\.env(?:\\.[\\w-]+)?|\\.gitignore|\\.npmrc)(?=$|[\\s`'\",.):])/i;\n\nfunction commandLooksRepoWriteCapable(command: OpenTagCommand): boolean {\n return UNKNOWN_WRITE_VERB_PATTERN.test(command.rawText) && REPO_WRITE_TARGET_PATTERN.test(command.rawText);\n}\n\nfunction permissionsForCommand(command: OpenTagCommand): PermissionGrant[] {\n const permissions: PermissionGrant[] = [\n {\n scope: \"chat:postMessage\",\n reason: \"reply in the originating Slack thread\"\n },\n {\n scope: \"reactions:write\",\n reason: \"mark the originating Slack message as received without posting a thread reply\"\n },\n {\n scope: \"runner:local\",\n reason: \"execute the run on a paired local daemon\"\n }\n ];\n\n if (command.intent === \"fix\" || command.intent === \"run\" || (command.intent === \"unknown\" && commandLooksRepoWriteCapable(command))) {\n permissions.push(\n {\n scope: \"repo:read\",\n reason: \"inspect the repository in the paired local checkout\"\n },\n {\n scope: \"repo:write\",\n reason: \"commit code changes on an isolated run branch\"\n },\n {\n scope: \"pr:create\",\n reason: \"open a pull request for completed code changes\"\n }\n );\n }\n\n return permissions;\n}\n\nfunction contextPointersForCommand(command: OpenTagCommand): ContextPointer[] {\n const context: ContextPointer[] = [];\n\n for (const reference of command.parsed?.references ?? []) {\n if (reference.kind === \"url\") {\n context.push({\n kind: \"url\",\n uri: reference.uri,\n visibility: \"organization\",\n title: reference.title ?? \"Command URL reference\"\n });\n continue;\n }\n\n if (reference.kind === \"file\" || reference.kind === \"path\") {\n context.push({\n kind: \"file\",\n uri: reference.uri,\n ...(reference.line ? { line: reference.line } : {}),\n ...(reference.startLine ? { startLine: reference.startLine } : {}),\n ...(reference.endLine ? { endLine: reference.endLine } : {}),\n visibility: \"organization\",\n title: referenceTitle(reference)\n });\n }\n }\n\n return context;\n}\n\nfunction referenceTitle(reference: NonNullable<OpenTagCommand[\"parsed\"]>[\"references\"][number]): string {\n return reference.title ?? \"Command file reference\";\n}\n\nfunction commandMetadata(command: OpenTagCommand): Record<string, unknown> {\n if (!command.parsed) return {};\n return {\n commandParser: command.parsed.version,\n commandDiagnostics: command.parsed.diagnostics,\n ...(command.parsed.approval ? { approval: command.parsed.approval } : {}),\n ...(command.parsed.network ? { network: command.parsed.network } : {})\n };\n}\n\nexport function normalizeSlackAppMention(input: SlackAppMentionInput): OpenTagEvent | null {\n const rawText = stripSlackAppMention(input.text, input.botUserId);\n if (!rawText) return null;\n\n const command = commandFromRawText(rawText);\n const replyThreadTs = input.threadTs ?? input.ts;\n const agentId = input.agentId ?? \"opentag\";\n\n return {\n id: `evt_slack_app_mention_${input.eventId}`,\n source: \"slack\",\n sourceEventId: input.eventId,\n receivedAt: new Date(input.eventTime * 1000).toISOString(),\n actor: {\n provider: \"slack\",\n providerUserId: input.userId,\n handle: input.userId,\n organizationId: input.teamId\n },\n target: {\n mention: input.botUserId ? `<@${input.botUserId}>` : \"<@app>\",\n agentId,\n ...(command.parsed?.executorHint ? { executorHint: command.parsed.executorHint } : {})\n },\n command,\n context: [\n {\n provider: \"slack\",\n kind: \"message\",\n uri: `slack://team/${input.teamId}/channel/${input.channelId}/message/${input.ts}`,\n visibility: \"organization\",\n title: \"Slack message\"\n },\n {\n kind: \"text\",\n uri: input.text,\n visibility: \"organization\",\n title: \"Slack message text\"\n },\n ...contextPointersForCommand(command)\n ],\n permissions: permissionsForCommand(command),\n callback: {\n provider: \"slack\",\n uri: input.callbackUri ?? \"https://slack.com/api/chat.postMessage\",\n threadKey: encodeSlackThreadKey({\n teamId: input.teamId,\n channelId: input.channelId,\n threadTs: replyThreadTs\n })\n },\n metadata: {\n teamId: input.teamId,\n channelId: input.channelId,\n messageTs: input.ts,\n ...(input.appId ? { slackAppId: input.appId } : {}),\n ...(input.botUserId ? { slackBotUserId: input.botUserId } : {}),\n ...commandMetadata(command),\n repoProvider: input.binding.repoProvider ?? \"github\",\n owner: input.binding.owner,\n repo: input.binding.repo\n }\n };\n}\n","import { suggestedActionCandidatesFromResult, type OpenTagRunResult, type SuggestedActionCandidate } from \"@opentag/core\";\n\nexport type SlackTextBlock = {\n type: \"section\";\n text: {\n type: \"mrkdwn\";\n text: string;\n };\n};\n\nexport type SlackDividerBlock = {\n type: \"divider\";\n};\n\nexport type SlackButtonElement = {\n type: \"button\";\n text: {\n type: \"plain_text\";\n text: string;\n emoji?: boolean;\n };\n action_id: string;\n value: string;\n style?: \"primary\" | \"danger\";\n};\n\nexport type SlackActionsBlock = {\n type: \"actions\";\n block_id?: string;\n elements: SlackButtonElement[];\n};\n\nexport type SlackBlock = SlackTextBlock | SlackDividerBlock | SlackActionsBlock;\n\nexport type SlackSuggestedActionButtonValue = {\n version: 1;\n command: string;\n proposalId: string;\n intentId: string;\n};\n\nexport type SlackMessagePayload = {\n channel: string;\n text: string;\n thread_ts?: string;\n ts?: string;\n blocks?: SlackBlock[];\n};\n\nexport type SlackReactionPayload = {\n channel: string;\n timestamp: string;\n name: string;\n};\n\nexport type SlackSourceReceiptState = \"received\";\n\nconst MAX_SLACK_SUGGESTED_ACTION_CANDIDATES = 20;\n\nexport function buildSlackSuggestedActionButtonValue(input: SlackSuggestedActionButtonValue): string {\n return JSON.stringify(input);\n}\n\nexport function parseSlackSuggestedActionButtonValue(value: string): SlackSuggestedActionButtonValue | null {\n try {\n const parsed = JSON.parse(value) as Partial<SlackSuggestedActionButtonValue>;\n if (\n parsed.version !== 1 ||\n typeof parsed.command !== \"string\" ||\n parsed.command.trim().length === 0 ||\n typeof parsed.proposalId !== \"string\" ||\n parsed.proposalId.length === 0 ||\n typeof parsed.intentId !== \"string\" ||\n parsed.intentId.length === 0\n ) {\n return null;\n }\n return {\n version: 1,\n command: parsed.command.trim(),\n proposalId: parsed.proposalId,\n intentId: parsed.intentId\n };\n } catch {\n return null;\n }\n}\n\nfunction escapeSlackText(text: string): string {\n return text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\nexport function markdownToSlackMrkdwn(text: string): string {\n const links: string[] = [];\n const withoutLinks = text.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label: string, url: string) => {\n const token = `\\u0000SLACK_LINK_${links.length}\\u0000`;\n links.push(`<${url}|${escapeSlackText(label)}>`);\n return token;\n });\n const converted = escapeSlackText(withoutLinks)\n .replace(/\\*\\*(.+?)\\*\\*/g, \"*$1*\")\n .replace(/__(.+?)__/g, \"*$1*\");\n return links.reduce((output, link, index) => output.replace(`\\u0000SLACK_LINK_${index}\\u0000`, link), converted);\n}\n\nexport function renderSlackAcknowledgement(runId: string): string {\n void runId;\n return \"Working on it.\";\n}\n\nexport function slackSourceReceiptReactionName(state: SlackSourceReceiptState): string {\n if (state === \"received\") return \"eyes\";\n return \"eyes\";\n}\n\nexport function createSlackReactionPayload(input: { channelId: string; messageTs: string; name: string }): SlackReactionPayload {\n return {\n channel: input.channelId,\n timestamp: input.messageTs,\n name: input.name\n };\n}\n\nfunction nextActionSummary(result: OpenTagRunResult): string | undefined {\n if (!result.nextAction) return undefined;\n if (typeof result.nextAction === \"string\") return result.nextAction;\n return result.nextAction.summary;\n}\n\nfunction stringParam(params: Record<string, unknown> | undefined, key: string): string | undefined {\n const value = params?.[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction stringArrayParam(params: Record<string, unknown> | undefined, key: string): string[] {\n const value = params?.[key];\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n}\n\nfunction renderVerificationParams(params: Record<string, unknown> | undefined): string[] {\n const value = params?.[\"verification\"];\n if (!Array.isArray(value)) return [];\n return value\n .map((item) => {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return undefined;\n const command = (item as Record<string, unknown>)[\"command\"];\n const outcome = (item as Record<string, unknown>)[\"outcome\"];\n return typeof command === \"string\" && typeof outcome === \"string\" ? ` - \\`${command}\\`: ${outcome}` : undefined;\n })\n .filter((line): line is string => Boolean(line));\n}\n\nfunction renderSuggestedActionDetails(params: Record<string, unknown> | undefined, action: string): string[] {\n if (action !== \"create_pull_request\") return [];\n const lines: string[] = [];\n const title = stringParam(params, \"title\");\n const head = stringParam(params, \"head\") ?? stringParam(params, \"branch\");\n const base = stringParam(params, \"base\") ?? stringParam(params, \"baseBranch\");\n const changedFiles = stringArrayParam(params, \"changedFiles\");\n const risks = stringArrayParam(params, \"risks\");\n const verification = renderVerificationParams(params);\n if (title) lines.push(` Title: ${markdownToSlackMrkdwn(title)}`);\n if (head || base) lines.push(` Branch: \\`${head ?? \"unknown\"}\\` -> \\`${base ?? \"main\"}\\``);\n if (changedFiles.length > 0) lines.push(` Changed files: ${changedFiles.map((file) => `\\`${file}\\``).join(\", \")}`);\n if (risks.length > 0) {\n lines.push(\" Risks:\");\n for (const risk of risks) {\n lines.push(` - ${markdownToSlackMrkdwn(risk)}`);\n }\n }\n if (verification.length > 0) {\n lines.push(\" Verification:\");\n lines.push(...verification);\n }\n return lines;\n}\n\nfunction truncateSlackText(text: string, maxLength: number): string {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (normalized.length <= maxLength) return normalized;\n return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}…`;\n}\n\nfunction firstMarkdownSection(text: string, heading: string): string | undefined {\n const pattern = new RegExp(`\\\\*\\\\*${heading}:\\\\*\\\\*\\\\s*([\\\\s\\\\S]*?)(?=\\\\n\\\\s*\\\\n\\\\*\\\\*[^*]+:\\\\*\\\\*|\\\\n\\\\s*\\\\n[A-Z][^\\\\n]{0,60}:|$)`, \"i\");\n const match = text.match(pattern);\n return match?.[1]?.trim();\n}\n\nfunction compactSlackSummary(summary: string): string {\n const whatChanged = firstMarkdownSection(summary, \"What changed\");\n const firstParagraph = summary\n .split(/\\n\\s*\\n/)\n .map((part) => part.trim())\n .find(Boolean);\n const selected = whatChanged ?? firstParagraph ?? summary;\n return truncateSlackText(selected.replace(/^\\*\\*[^*]+:\\*\\*\\s*/i, \"\"), 360);\n}\n\nfunction compactNextAction(nextAction: string): string {\n return truncateSlackText(nextAction, 180);\n}\n\nfunction renderSuggestedActionCandidateLines(candidate: SuggestedActionCandidate): string[] {\n const lines = [`${candidate.index}. *${markdownToSlackMrkdwn(candidate.intent.summary)}*`];\n const details = renderSuggestedActionDetails(candidate.intent.params, candidate.intent.action)\n .filter((line) => line.trim().startsWith(\"Branch:\") || line.trim().startsWith(\"Changed files:\"))\n .map((line) => line.replace(/^\\s+/, \"\"));\n lines.push(...details);\n if (candidate.proposalPreconditions?.length) {\n lines.push(`Preconditions: ${candidate.proposalPreconditions.length} check(s) in the audit log.`);\n }\n return lines;\n}\n\nfunction renderSuggestedActionsMarkdown(result: OpenTagRunResult): string[] {\n const candidates = suggestedActionCandidatesFromResult(result);\n if (candidates.length === 0) return [];\n\n const lines = [\"*Suggested actions*\"];\n const visibleCandidates = candidates.slice(0, MAX_SLACK_SUGGESTED_ACTION_CANDIDATES);\n for (const candidate of visibleCandidates) {\n lines.push(\"\", ...renderSuggestedActionCandidateLines(candidate));\n }\n\n const remainingCount = candidates.length - visibleCandidates.length;\n if (remainingCount > 0) {\n lines.push(\"\", `Showing first ${visibleCandidates.length} of ${candidates.length} actions. Reply with an action number for the rest.`);\n }\n lines.push(\"\", \"Use the buttons below, or reply `apply 1`, `approve 1`, or `reject 1`.\");\n return lines;\n}\n\nfunction createSuggestedActionButtons(candidate: SuggestedActionCandidate): SlackButtonElement[] {\n return [\n {\n type: \"button\",\n text: { type: \"plain_text\", text: `Apply ${candidate.index}`, emoji: true },\n action_id: `opentag:apply:${candidate.index}`,\n value: buildSlackSuggestedActionButtonValue({\n version: 1,\n command: `apply ${candidate.index}`,\n proposalId: candidate.proposalId,\n intentId: candidate.intent.intentId\n }),\n style: \"primary\"\n },\n {\n type: \"button\",\n text: { type: \"plain_text\", text: \"Approve\", emoji: true },\n action_id: `opentag:approve:${candidate.index}`,\n value: buildSlackSuggestedActionButtonValue({\n version: 1,\n command: `approve ${candidate.index}`,\n proposalId: candidate.proposalId,\n intentId: candidate.intent.intentId\n })\n },\n {\n type: \"button\",\n text: { type: \"plain_text\", text: \"Reject\", emoji: true },\n action_id: `opentag:reject:${candidate.index}`,\n value: buildSlackSuggestedActionButtonValue({\n version: 1,\n command: `reject ${candidate.index}`,\n proposalId: candidate.proposalId,\n intentId: candidate.intent.intentId\n }),\n style: \"danger\"\n }\n ];\n}\n\nexport function renderSlackFinalResult(result: OpenTagRunResult): string {\n const lines = [`*Finished: ${result.conclusion}.*`, markdownToSlackMrkdwn(compactSlackSummary(result.summary))];\n\n if (result.verification?.length) {\n lines.push(\n `Verified: ${result.verification\n .slice(0, 3)\n .map((check) => `\\`${markdownToSlackMrkdwn(check.command)}\\` ${markdownToSlackMrkdwn(check.outcome)}`)\n .join(\", \")}`\n );\n }\n\n const nextAction = nextActionSummary(result);\n if (nextAction && !result.suggestedChanges?.length) {\n lines.push(`Next: ${markdownToSlackMrkdwn(compactNextAction(nextAction))}`);\n }\n\n const suggestedActions = renderSuggestedActionsMarkdown(result);\n if (suggestedActions.length > 0) {\n lines.push(\"\", ...suggestedActions);\n }\n\n return lines.join(\"\\n\");\n}\n\nexport function createSlackFinalResultBlocks(result: OpenTagRunResult): SlackBlock[] {\n const blocks: SlackBlock[] = [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `*Finished: ${result.conclusion}.*\\n${markdownToSlackMrkdwn(compactSlackSummary(result.summary))}`\n }\n }\n ];\n\n if (result.verification?.length) {\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `Verified: ${markdownToSlackMrkdwn(\n result.verification\n .slice(0, 3)\n .map((check) => `\\`${check.command}\\` ${check.outcome}`)\n .join(\", \")\n )}`\n }\n });\n }\n\n const nextAction = nextActionSummary(result);\n const suggestedActionCandidates = suggestedActionCandidatesFromResult(result);\n if (nextAction && suggestedActionCandidates.length === 0) {\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `Next: ${markdownToSlackMrkdwn(compactNextAction(nextAction))}`\n }\n });\n }\n\n if (suggestedActionCandidates.length > 0) {\n blocks.push({ type: \"divider\" });\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: \"*Suggested actions*\\nChoose an action in this thread. Details stay in the OpenTag audit log.\"\n }\n });\n const visibleCandidates = suggestedActionCandidates.slice(0, MAX_SLACK_SUGGESTED_ACTION_CANDIDATES);\n for (const candidate of visibleCandidates) {\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: renderSuggestedActionCandidateLines(candidate).join(\"\\n\")\n }\n });\n blocks.push({\n type: \"actions\",\n block_id: `opentag_actions_${candidate.index}`,\n elements: createSuggestedActionButtons(candidate)\n });\n }\n const remainingCount = suggestedActionCandidates.length - visibleCandidates.length;\n if (remainingCount > 0) {\n blocks.push({\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n text: `Showing first ${visibleCandidates.length} of ${suggestedActionCandidates.length} actions. Reply with an action number for the rest.`\n }\n });\n }\n }\n\n return blocks;\n}\n\nexport function createSlackPostMessagePayload(input: { channelId: string; text: string; threadTs: string; blocks?: SlackBlock[] }): SlackMessagePayload {\n return {\n channel: input.channelId,\n text: markdownToSlackMrkdwn(input.text),\n thread_ts: input.threadTs,\n ...(input.blocks?.length ? { blocks: input.blocks } : {})\n };\n}\n\nexport function createSlackUpdateMessagePayload(input: { channelId: string; text: string; messageTs: string; blocks?: SlackBlock[] }): SlackMessagePayload {\n return {\n channel: input.channelId,\n text: markdownToSlackMrkdwn(input.text),\n ts: input.messageTs,\n ...(input.blocks?.length ? { blocks: input.blocks } : {})\n };\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport { createSlackDispatcherEventProcessorInput } from \"./dispatcher-events.js\";\nimport { createSlackEventProcessor, type SlackAppRuntimeConfig, type SlackEventProcessorInput, type SlackIngressPayload } from \"./events.js\";\n\nexport type SlackEventsAppInput = {\n slackApps: Array<\n SlackAppRuntimeConfig & {\n signingSecret: string;\n }\n >;\n clock?: () => number;\n} & SlackEventProcessorInput;\n\nexport type SlackEventsApiIngressConfig = {\n signingSecret: string;\n dispatcherUrl: string;\n dispatcherToken?: string;\n port?: number;\n agentId?: string;\n appId?: string;\n callbackUri?: string;\n};\n\nexport type SlackIngressConfig = SlackEventsApiIngressConfig;\n\nexport type SlackIngressHandle = {\n url: string;\n server: ReturnType<typeof serve>;\n close(): Promise<void>;\n};\n\nexport function computeSlackSignature(input: {\n signingSecret: string;\n timestamp: string;\n rawBody: string;\n}): string {\n const base = `v0:${input.timestamp}:${input.rawBody}`;\n const digest = createHmac(\"sha256\", input.signingSecret).update(base).digest(\"hex\");\n return `v0=${digest}`;\n}\n\nexport function verifySlackSignature(input: {\n signingSecret: string;\n timestamp: string;\n rawBody: string;\n signature: string;\n}): boolean {\n const expected = computeSlackSignature(input);\n const expectedBuffer = Buffer.from(expected);\n const actualBuffer = Buffer.from(input.signature);\n return expectedBuffer.length === actualBuffer.length && timingSafeEqual(expectedBuffer, actualBuffer);\n}\n\nexport function verifySlackTimestamp(input: { timestamp: string; nowMs: number; toleranceSeconds?: number }): boolean {\n const timestampSeconds = Number(input.timestamp);\n if (!Number.isFinite(timestampSeconds)) return false;\n const toleranceSeconds = input.toleranceSeconds ?? 300;\n const ageSeconds = Math.abs(Math.floor(input.nowMs / 1000) - timestampSeconds);\n return ageSeconds <= toleranceSeconds;\n}\n\nexport function createSlackEventsApp(input: SlackEventsAppInput) {\n const app = new Hono();\n const processor = createSlackEventProcessor(input);\n\n function parseSlackPayload(rawBody: string, contentType?: string): SlackIngressPayload | null {\n try {\n if (contentType?.includes(\"application/x-www-form-urlencoded\") || rawBody.startsWith(\"payload=\")) {\n const interactivePayload = new URLSearchParams(rawBody).get(\"payload\");\n if (!interactivePayload) return null;\n return JSON.parse(interactivePayload) as SlackIngressPayload;\n }\n return JSON.parse(rawBody) as SlackIngressPayload;\n } catch {\n return null;\n }\n }\n\n function resolveSlackApp(inputValue: {\n apiAppId?: string;\n rawBody: string;\n signature: string;\n timestamp: string;\n }) {\n const candidates = inputValue.apiAppId\n ? input.slackApps.filter((candidate) => !candidate.appId || candidate.appId === inputValue.apiAppId)\n : input.slackApps;\n if (candidates.length === 0) {\n return { error: \"unknown_slack_app\" as const };\n }\n const slackApp = candidates.find((candidate) =>\n verifySlackSignature({\n signingSecret: candidate.signingSecret,\n timestamp: inputValue.timestamp,\n rawBody: inputValue.rawBody,\n signature: inputValue.signature\n })\n );\n return slackApp ? { slackApp } : { error: \"invalid_signature\" as const };\n }\n\n app.post(\"/slack/events\", async (c) => {\n const timestamp = c.req.header(\"x-slack-request-timestamp\");\n const signature = c.req.header(\"x-slack-signature\");\n if (!timestamp || !signature) {\n return c.json({ error: \"missing_signature_headers\" }, 401);\n }\n if (!verifySlackTimestamp({ timestamp, nowMs: input.clock?.() ?? Date.now() })) {\n return c.json({ error: \"stale_signature_timestamp\" }, 401);\n }\n const rawBody = await c.req.text();\n const payload = parseSlackPayload(rawBody, c.req.header(\"content-type\"));\n if (!payload) {\n return c.json({ error: \"invalid_json\" }, 400);\n }\n const resolvedSlackApp = resolveSlackApp({\n rawBody,\n signature,\n timestamp,\n ...(payload.api_app_id ? { apiAppId: payload.api_app_id } : {})\n });\n if (\"error\" in resolvedSlackApp) {\n return c.json({ error: resolvedSlackApp.error }, 401);\n }\n const result = await processor.process(payload, resolvedSlackApp.slackApp);\n if (result.kind === \"text\") {\n return c.text(result.body, result.status);\n }\n return c.json(result.body, result.status);\n });\n\n return app;\n}\n\nexport function startSlackIngress(config: SlackEventsApiIngressConfig): SlackIngressHandle {\n const port = config.port ?? 3040;\n const server = serve({\n fetch: createSlackEventsApp({\n slackApps: [\n {\n signingSecret: config.signingSecret,\n agentId: config.agentId ?? \"opentag\",\n ...(config.appId ? { appId: config.appId } : {}),\n ...(config.callbackUri ? { callbackUri: config.callbackUri } : {})\n }\n ],\n ...createSlackDispatcherEventProcessorInput(config)\n }).fetch,\n port\n });\n\n return {\n url: `http://localhost:${port}`,\n server,\n close() {\n return new Promise((resolve, reject) => {\n server.close((error?: Error) => {\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n });\n }\n };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { createOpenTagClient } from \"@opentag/client\";\nimport type { SlackEventProcessorInput } from \"./events.js\";\n\nexport type SlackDispatcherEventConfig = {\n dispatcherUrl: string;\n dispatcherToken?: string;\n};\n\nexport function createSlackDispatcherEventProcessorInput(config: SlackDispatcherEventConfig): SlackEventProcessorInput {\n const dispatcherClient = createOpenTagClient({\n dispatcherUrl: config.dispatcherUrl,\n ...(config.dispatcherToken ? { pairingToken: config.dispatcherToken } : {})\n });\n\n return {\n async resolveChannelBinding(input) {\n try {\n const { binding } = await dispatcherClient.getChannelBinding({\n provider: \"slack\",\n accountId: input.teamId,\n conversationId: input.channelId\n });\n return {\n teamId: binding.accountId,\n channelId: binding.conversationId,\n repoProvider: binding.repoProvider,\n owner: binding.owner,\n repo: binding.repo\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"channel_binding_not_found\")) {\n return null;\n }\n throw error;\n }\n },\n async createRun(event) {\n const runId = `run_${randomUUID()}`;\n const created = await dispatcherClient.createRun({ runId, event });\n return created.outcome === \"run_created\" ? { runId: created.run.id } : { runId };\n },\n async submitThreadAction(action) {\n await dispatcherClient.submitThreadAction(action);\n },\n now: () => new Date().toISOString()\n };\n}\n","import WebSocket, { type RawData } from \"ws\";\nimport { createSlackDispatcherEventProcessorInput, type SlackDispatcherEventConfig } from \"./dispatcher-events.js\";\nimport { createSlackEventProcessor, type SlackAppRuntimeConfig, type SlackEventProcessorInput, type SlackIngressPayload } from \"./events.js\";\n\nconst SLACK_CONNECTIONS_OPEN_URL = \"https://slack.com/api/apps.connections.open\";\nconst DEFAULT_RECONNECT_DELAY_MS = 1_000;\n\n// Slack Web API `error` codes that represent a terminal authentication or\n// configuration problem with the app token. Retrying these is pointless: the\n// request will fail identically forever, spamming logs and risking rate limits\n// or an API ban. Startup must fail loudly so the operator fixes the config,\n// rather than the daemon silently looping. Transient/network errors (e.g.\n// `ratelimited`, HTTP 5xx, fetch failures) are NOT in this set and are retried.\nconst TERMINAL_SLACK_ERROR_CODES = [\n \"invalid_auth\",\n \"not_authed\",\n \"account_inactive\",\n \"token_revoked\",\n \"token_expired\",\n \"not_allowed_token_type\",\n \"no_permission\",\n \"missing_scope\",\n \"ekm_access_denied\"\n] as const;\n\n/**\n * Returns true when the error from opening the Socket Mode connection is a\n * terminal auth/config failure that must propagate (reject startup) instead of\n * being retried. The Slack error code is embedded in the thrown Error message by\n * {@link openSlackSocketUrl} (e.g. \"...connection failed: invalid_auth\").\n */\nfunction isTerminalSlackAuthError(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return TERMINAL_SLACK_ERROR_CODES.some((code) => error.message.includes(code));\n}\n\nexport type SlackSocketModeEnvelope = {\n type?: string;\n envelope_id?: string;\n payload?: SlackIngressPayload;\n accepts_response_payload?: boolean;\n};\n\nexport type SlackSocketModeAppInput = {\n appToken: string;\n slackApp: SlackAppRuntimeConfig;\n} & SlackEventProcessorInput;\n\nexport type SlackSocketModeIngressConfig = SlackDispatcherEventConfig & {\n appToken: string;\n agentId?: string;\n appId?: string;\n callbackUri?: string;\n};\n\nexport type SlackSocketModeIngressHandle = {\n startPromise: Promise<void>;\n close(): Promise<void>;\n};\n\nexport type SlackSocketModeDependencies = {\n fetchImpl?: typeof fetch;\n createWebSocket?(url: string): WebSocket;\n reconnectDelayMs?: number;\n log?(message: string): void;\n logError?(message: string, error?: unknown): void;\n};\n\ntype SlackConnectionsOpenResponse = {\n ok?: boolean;\n url?: string;\n error?: string;\n needed?: string;\n provided?: string;\n};\n\nfunction rawDataToString(data: RawData): string {\n if (typeof data === \"string\") return data;\n if (Buffer.isBuffer(data)) return data.toString(\"utf8\");\n if (Array.isArray(data)) return Buffer.concat(data).toString(\"utf8\");\n if (data instanceof ArrayBuffer) return Buffer.from(data).toString(\"utf8\");\n return Buffer.from(data).toString(\"utf8\");\n}\n\nasync function openSlackSocketUrl(input: { appToken: string; fetchImpl: typeof fetch }): Promise<string> {\n const response = await input.fetchImpl(SLACK_CONNECTIONS_OPEN_URL, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${input.appToken}`\n }\n });\n const body = (await response.json().catch(() => ({}))) as SlackConnectionsOpenResponse;\n if (!response.ok || !body.ok || !body.url) {\n const reason = body.error ?? `http_${response.status}`;\n throw new Error(`Slack Socket Mode connection failed: ${reason}`);\n }\n return body.url;\n}\n\nfunction parseSocketEnvelope(data: RawData): SlackSocketModeEnvelope | null {\n try {\n return JSON.parse(rawDataToString(data)) as SlackSocketModeEnvelope;\n } catch {\n return null;\n }\n}\n\nasync function handleSocketMessage(input: {\n data: RawData;\n socket: WebSocket;\n processor: ReturnType<typeof createSlackEventProcessor>;\n slackApp: SlackAppRuntimeConfig;\n logError(message: string, error?: unknown): void;\n}): Promise<void> {\n const envelope = parseSocketEnvelope(input.data);\n if (!envelope?.envelope_id) {\n input.logError(\"[slack] ignored Socket Mode envelope without envelope_id\");\n return;\n }\n\n input.socket.send(JSON.stringify({ envelope_id: envelope.envelope_id }));\n\n if (!envelope.payload) {\n return;\n }\n if (input.slackApp.appId && envelope.payload.api_app_id && envelope.payload.api_app_id !== input.slackApp.appId) {\n return;\n }\n if (envelope.type !== \"events_api\" && envelope.payload.type !== \"block_actions\") {\n return;\n }\n\n await input.processor.process(envelope.payload, input.slackApp);\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function startSlackSocketModeApp(\n input: SlackSocketModeAppInput,\n dependencies: SlackSocketModeDependencies = {}\n): SlackSocketModeIngressHandle {\n const fetchImpl = dependencies.fetchImpl ?? fetch;\n const createWebSocket = dependencies.createWebSocket ?? ((url: string) => new WebSocket(url));\n const reconnectDelayMs = dependencies.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS;\n const log = dependencies.log ?? ((message: string) => console.log(message));\n const logError = dependencies.logError ?? ((message: string, error?: unknown) => (error ? console.error(message, error) : console.error(message)));\n const processor = createSlackEventProcessor(input);\n let closed = false;\n let activeSocket: WebSocket | undefined;\n\n async function runOneConnection(socketUrl: string): Promise<void> {\n await new Promise<void>((resolve) => {\n const socket = createWebSocket(socketUrl);\n activeSocket = socket;\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n if (activeSocket === socket) activeSocket = undefined;\n resolve();\n };\n\n socket.once(\"open\", () => {\n log(\"[slack] Socket Mode connected\");\n });\n socket.on(\"message\", (data) => {\n void handleSocketMessage({\n data,\n socket,\n processor,\n slackApp: input.slackApp,\n logError\n }).catch((error: unknown) => {\n logError(\"[slack] failed to handle Socket Mode event:\", error);\n });\n });\n socket.once(\"close\", finish);\n socket.once(\"error\", (error) => {\n if (!closed) {\n logError(\"[slack] Socket Mode connection error:\", error);\n }\n socket.close();\n finish();\n });\n });\n }\n\n const startPromise = (async () => {\n while (!closed) {\n try {\n const socketUrl = await openSlackSocketUrl({ appToken: input.appToken, fetchImpl });\n await runOneConnection(socketUrl);\n } catch (error) {\n // A terminal auth/config error (invalid app token, missing scope, etc.)\n // will never succeed on retry, so we must NOT swallow it: rethrow so\n // startPromise rejects and startup fails loudly instead of looping\n // forever against Slack's API.\n if (isTerminalSlackAuthError(error)) {\n if (!closed) {\n logError(\"[slack] terminal Socket Mode auth/config error, aborting:\", error);\n }\n throw error;\n }\n // A transient apps.connections.open failure (or any error opening the\n // connection) must NOT reject startPromise: the CLI aborts the entire\n // OpenTag daemon when this promise rejects, so one blip in Slack's API\n // would otherwise take down every other ingress and the dispatcher.\n // Log it and fall through to the shared backoff/retry below.\n if (!closed) {\n logError(\"[slack] failed to open Socket Mode connection, retrying:\", error);\n }\n }\n if (!closed) {\n await wait(reconnectDelayMs);\n }\n }\n })();\n\n return {\n startPromise,\n async close() {\n closed = true;\n activeSocket?.close();\n await startPromise.catch(() => undefined);\n }\n };\n}\n\nexport function startSlackSocketModeIngress(\n config: SlackSocketModeIngressConfig,\n dependencies: SlackSocketModeDependencies = {}\n): SlackSocketModeIngressHandle {\n return startSlackSocketModeApp(\n {\n appToken: config.appToken,\n slackApp: {\n agentId: config.agentId ?? \"opentag\",\n ...(config.appId ? { appId: config.appId } : {}),\n ...(config.callbackUri ? { callbackUri: config.callbackUri } : {})\n },\n ...createSlackDispatcherEventProcessorInput(config)\n },\n dependencies\n );\n}\n"],"mappings":"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","names":["text","text"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ingress.d.ts","sourceRoot":"","sources":["../src/ingress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAA6B,KAAK,qBAAqB,EAA2B,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAE5I,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,KAAK,CACd,qBAAqB,GAAG;QACtB,aAAa,EAAE,MAAM,CAAC;KACvB,CACF,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB,GAAG,wBAAwB,CAAC;AAE7B,MAAM,MAAM,2BAA2B,GAAG;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AAE7D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;IACjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAIT;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAKV;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAMpH;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,8EAkE9D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,2BAA2B,GAAG,kBAAkB,CAgCzF"}
1
+ {"version":3,"file":"ingress.d.ts","sourceRoot":"","sources":["../src/ingress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAA6B,KAAK,qBAAqB,EAAE,KAAK,wBAAwB,EAA4B,MAAM,aAAa,CAAC;AAE7I,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,KAAK,CACd,qBAAqB,GAAG;QACtB,aAAa,EAAE,MAAM,CAAC;KACvB,CACF,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB,GAAG,wBAAwB,CAAC;AAE7B,MAAM,MAAM,2BAA2B,GAAG;IACxC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AAE7D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;IACjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG,MAAM,CAIT;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAKV;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAMpH;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,8EAuE9D;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,2BAA2B,GAAG,kBAAkB,CAgCzF"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgE,KAAK,YAAY,EAAwB,MAAM,eAAe,CAAC;AAEtI,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAapF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE3G;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAM9G;AA8ED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,GAAG,IAAI,CA+DzF"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgE,KAAK,YAAY,EAAwB,MAAM,eAAe,CAAC;AAEtI,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AASF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyBpF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE3G;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAM9G;AA0FD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,GAAG,IAAI,CA+DzF"}
package/dist/render.d.ts CHANGED
@@ -9,7 +9,29 @@ export type SlackTextBlock = {
9
9
  export type SlackDividerBlock = {
10
10
  type: "divider";
11
11
  };
12
- export type SlackBlock = SlackTextBlock | SlackDividerBlock;
12
+ export type SlackButtonElement = {
13
+ type: "button";
14
+ text: {
15
+ type: "plain_text";
16
+ text: string;
17
+ emoji?: boolean;
18
+ };
19
+ action_id: string;
20
+ value: string;
21
+ style?: "primary" | "danger";
22
+ };
23
+ export type SlackActionsBlock = {
24
+ type: "actions";
25
+ block_id?: string;
26
+ elements: SlackButtonElement[];
27
+ };
28
+ export type SlackBlock = SlackTextBlock | SlackDividerBlock | SlackActionsBlock;
29
+ export type SlackSuggestedActionButtonValue = {
30
+ version: 1;
31
+ command: string;
32
+ proposalId: string;
33
+ intentId: string;
34
+ };
13
35
  export type SlackMessagePayload = {
14
36
  channel: string;
15
37
  text: string;
@@ -17,8 +39,22 @@ export type SlackMessagePayload = {
17
39
  ts?: string;
18
40
  blocks?: SlackBlock[];
19
41
  };
42
+ export type SlackReactionPayload = {
43
+ channel: string;
44
+ timestamp: string;
45
+ name: string;
46
+ };
47
+ export type SlackSourceReceiptState = "received";
48
+ export declare function buildSlackSuggestedActionButtonValue(input: SlackSuggestedActionButtonValue): string;
49
+ export declare function parseSlackSuggestedActionButtonValue(value: string): SlackSuggestedActionButtonValue | null;
20
50
  export declare function markdownToSlackMrkdwn(text: string): string;
21
51
  export declare function renderSlackAcknowledgement(runId: string): string;
52
+ export declare function slackSourceReceiptReactionName(state: SlackSourceReceiptState): string;
53
+ export declare function createSlackReactionPayload(input: {
54
+ channelId: string;
55
+ messageTs: string;
56
+ name: string;
57
+ }): SlackReactionPayload;
22
58
  export declare function renderSlackFinalResult(result: OpenTagRunResult): string;
23
59
  export declare function createSlackFinalResultBlocks(result: OpenTagRunResult): SlackBlock[];
24
60
  export declare function createSlackPostMessagePayload(input: {
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE3F,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE5D,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACvB,CAAC;AAMF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW1D;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhE;AA0FD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAqBvE;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,EAAE,CA8CnF;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAA;CAAE,GAAG,mBAAmB,CAOtJ;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAA;CAAE,GAAG,mBAAmB,CAOzJ"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,gBAAgB,EAAiC,MAAM,eAAe,CAAC;AAE1H,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,SAAS,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAEhF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,UAAU,CAAC;AAIjD,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,+BAA+B,GAAG,MAAM,CAEnG;AAED,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,MAAM,GAAG,+BAA+B,GAAG,IAAI,CAuB1G;AAMD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW1D;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGhE;AAED,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,uBAAuB,GAAG,MAAM,CAGrF;AAED,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,oBAAoB,CAM9H;AAyJD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAuBvE;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,EAAE,CA2EnF;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAA;CAAE,GAAG,mBAAmB,CAOtJ;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAA;CAAE,GAAG,mBAAmB,CAOzJ"}
@@ -1,10 +1,10 @@
1
1
  import WebSocket from "ws";
2
2
  import { type SlackDispatcherEventConfig } from "./dispatcher-events.js";
3
- import { type SlackAppRuntimeConfig, type SlackEventEnvelope, type SlackEventProcessorInput } from "./events.js";
3
+ import { type SlackAppRuntimeConfig, type SlackEventProcessorInput, type SlackIngressPayload } from "./events.js";
4
4
  export type SlackSocketModeEnvelope = {
5
5
  type?: string;
6
6
  envelope_id?: string;
7
- payload?: SlackEventEnvelope;
7
+ payload?: SlackIngressPayload;
8
8
  accepts_response_payload?: boolean;
9
9
  };
10
10
  export type SlackSocketModeAppInput = {
@@ -1 +1 @@
1
- {"version":3,"file":"socket-mode.d.ts","sourceRoot":"","sources":["../src/socket-mode.ts"],"names":[],"mappings":"AAAA,OAAO,SAA2B,MAAM,IAAI,CAAC;AAC7C,OAAO,EAA4C,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACnH,OAAO,EAA6B,KAAK,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAK5I,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,qBAAqB,CAAC;CACjC,GAAG,wBAAwB,CAAC;AAE7B,MAAM,MAAM,4BAA4B,GAAG,0BAA0B,GAAG;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,eAAe,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACnD,CAAC;AAsEF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,uBAAuB,EAC9B,YAAY,GAAE,2BAAgC,GAC7C,4BAA4B,CAiE9B;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,4BAA4B,EACpC,YAAY,GAAE,2BAAgC,GAC7C,4BAA4B,CAa9B"}
1
+ {"version":3,"file":"socket-mode.d.ts","sourceRoot":"","sources":["../src/socket-mode.ts"],"names":[],"mappings":"AAAA,OAAO,SAA2B,MAAM,IAAI,CAAC;AAC7C,OAAO,EAA4C,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AACnH,OAAO,EAA6B,KAAK,qBAAqB,EAAE,KAAK,wBAAwB,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAkC7I,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,qBAAqB,CAAC;CACjC,GAAG,wBAAwB,CAAC;AAE7B,MAAM,MAAM,4BAA4B,GAAG,0BAA0B,GAAG;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,eAAe,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CACnD,CAAC;AAyEF,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,uBAAuB,EAC9B,YAAY,GAAE,2BAAgC,GAC7C,4BAA4B,CAsF9B;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,4BAA4B,EACpC,YAAY,GAAE,2BAAgC,GAC7C,4BAA4B,CAa9B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentag/slack",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Slack app mention normalization and callback helpers for OpenTag.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -34,8 +34,8 @@
34
34
  "@hono/node-server": "^1.13.7",
35
35
  "hono": "^4.6.15",
36
36
  "ws": "^8.21.0",
37
- "@opentag/client": "0.2.0",
38
- "@opentag/core": "0.2.0"
37
+ "@opentag/client": "0.3.0",
38
+ "@opentag/core": "0.3.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/ws": "^8.18.1",