@render-harness/cap-slack 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,7 +72,13 @@ Every tool that takes a `channel` parameter (`slack.send_message`, `slack.get_th
72
72
 
73
73
  `allowedChannels` is enforced **after** resolution, against the canonical channel ID. So `allowedChannels: ["C0AQ…"]` correctly accepts `slack.send_message({ channel: "#that-channels-name" })` because the resolver returns `C0AQ…` before the gate check fires.
74
74
 
75
- If the bot lacks the lookup scope, the tool returns a clear error naming the scope (`Slack channel "#general" not found. Check the name, or ensure the bot has 'channels:read' / 'groups:read' scope and is a member of the channel.`) instead of failing silently. Agents that only ever address channels by ID don't need the read scopes; the resolver fast-paths `C…` / `G…` / `D…` / `U…` inputs without any API call.
75
+ If the bot lacks the lookup scope, the tool returns an actionable error naming the scope (e.g. `Slack missing_scope: 'channels:read' needed (bot currently has: 'chat:write'). Add 'channels:read' to the bot's OAuth scopes in the Slack app config (api.slack.com OAuth & Permissions Bot Token Scopes), reinstall the app to the workspace, and redeploy.`) instead of failing silently. Agents that only ever address channels by ID don't need the read scopes; the resolver fast-paths `C…` / `G…` / `D…` / `U…` inputs without any API call.
76
+
77
+ ### Scope coverage for name lookups
78
+
79
+ The resolver lists public and private channels in **separate** `conversations.list` calls and aggregates results from whichever succeeds. A bot with only `channels:read` gets a working name → id index for public channels; the private-channel call fails (caught, ignored). A bot with both scopes indexes both. A bot with neither sees the actionable `missing_scope` error above with the first missing scope named.
80
+
81
+ Other common Slack errors are also rewritten with hints: `not_in_channel` → "invite the bot with `/invite @<bot>`", `channel_not_found` → "ID invalid, archived, or not visible to the bot", `invalid_auth` / `token_revoked` → "reissue `SLACK_BOT_TOKEN`". Any other Slack platform code passes through verbatim with the `slack.<code>` annotation appended so the agent can branch on it.
76
82
 
77
83
  Set `accessMode: read_write` to enable write tools:
78
84
 
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { WebClient } from '@slack/web-api';
6
6
 
7
7
  // package.json
8
8
  var package_default = {
9
- version: "0.5.1"};
9
+ version: "0.5.2"};
10
10
  function slackConversationId(args) {
11
11
  const digest = createHash("sha256").update(`${args.teamId}:${args.channel}:${args.threadTs}`).digest("hex").slice(0, 24);
12
12
  return `slack-${digest}`;
@@ -197,11 +197,38 @@ function jsonTool(name, description, inputSchema, call) {
197
197
  try {
198
198
  return { content: JSON.stringify(await call(input), null, 2) };
199
199
  } catch (err) {
200
- return { content: err instanceof Error ? err.message : String(err), isError: true };
200
+ return { content: formatSlackError(err), isError: true };
201
201
  }
202
202
  }
203
203
  };
204
204
  }
205
+ function formatSlackError(err) {
206
+ if (!err || typeof err !== "object") return String(err);
207
+ const e = err;
208
+ const code = typeof e.data?.error === "string" ? e.data.error : void 0;
209
+ if (!code) {
210
+ return typeof e.message === "string" ? e.message : String(err);
211
+ }
212
+ if (code === "missing_scope") {
213
+ const needed = typeof e.data?.needed === "string" ? e.data.needed : "?";
214
+ const provided = typeof e.data?.provided === "string" ? e.data.provided : "?";
215
+ return [
216
+ `Slack missing_scope: '${needed}' needed (bot currently has: '${provided}').`,
217
+ `Add '${needed}' to the bot's OAuth scopes in the Slack app config (api.slack.com \u2192 OAuth & Permissions \u2192 Bot Token Scopes), reinstall the app to the workspace, and redeploy.`
218
+ ].join(" ");
219
+ }
220
+ if (code === "not_in_channel") {
221
+ return "Slack not_in_channel: the bot must be a member of the channel before it can post. Invite it with `/invite @<bot-name>` in the channel.";
222
+ }
223
+ if (code === "channel_not_found") {
224
+ return "Slack channel_not_found: the channel ID is invalid, the bot doesn't have permission to see it, or it has been archived.";
225
+ }
226
+ if (code === "invalid_auth" || code === "token_revoked") {
227
+ return `Slack ${code}: SLACK_BOT_TOKEN is invalid or has been revoked. Re-issue the token from the Slack app config and redeploy.`;
228
+ }
229
+ const message = typeof e.message === "string" ? e.message : String(err);
230
+ return `${message} (slack.${code})`;
231
+ }
205
232
  function assertAllowedChannel(channel, allowedChannels) {
206
233
  if (allowedChannels?.length && !allowedChannels.includes(channel)) {
207
234
  throw new Error(`Slack channel "${channel}" is not allowed by cap-slack config`);
@@ -223,26 +250,41 @@ function createResolver(client) {
223
250
  let channelsIndex = null;
224
251
  let usersIndex = null;
225
252
  const dmByUserId = /* @__PURE__ */ new Map();
253
+ const drainChannelsByType = async (type, byName) => {
254
+ let cursor;
255
+ do {
256
+ const resp = await client.conversations.list({
257
+ limit: 1e3,
258
+ types: type,
259
+ exclude_archived: true,
260
+ ...cursor ? { cursor } : {}
261
+ });
262
+ for (const c of resp.channels ?? []) {
263
+ if (typeof c.id === "string" && typeof c.name === "string") {
264
+ byName.set(c.name.toLowerCase(), c.id);
265
+ if (!channels.has(c.id)) {
266
+ const cached = { id: c.id, name: c.name };
267
+ if (c.is_private === true) cached.is_private = true;
268
+ channels.set(c.id, cached);
269
+ }
270
+ }
271
+ }
272
+ cursor = typeof resp.response_metadata?.next_cursor === "string" && resp.response_metadata.next_cursor.length > 0 ? resp.response_metadata.next_cursor : void 0;
273
+ } while (cursor);
274
+ };
226
275
  const ensureChannelsIndex = () => {
227
276
  if (channelsIndex) return channelsIndex;
228
277
  channelsIndex = (async () => {
229
278
  const byName = /* @__PURE__ */ new Map();
230
- let cursor;
231
- do {
232
- const resp = await client.conversations.list({
233
- limit: 1e3,
234
- types: "public_channel,private_channel",
235
- exclude_archived: true,
236
- ...cursor ? { cursor } : {}
237
- });
238
- for (const c of resp.channels ?? []) {
239
- if (typeof c.id === "string" && typeof c.name === "string") {
240
- byName.set(c.name.toLowerCase(), c.id);
241
- if (!channels.has(c.id)) channels.set(c.id, { id: c.id, name: c.name });
242
- }
243
- }
244
- cursor = typeof resp.response_metadata?.next_cursor === "string" && resp.response_metadata.next_cursor.length > 0 ? resp.response_metadata.next_cursor : void 0;
245
- } while (cursor);
279
+ const attempts = await Promise.allSettled([
280
+ drainChannelsByType("public_channel", byName),
281
+ drainChannelsByType("private_channel", byName)
282
+ ]);
283
+ const allFailed = attempts.every((r) => r.status === "rejected");
284
+ if (allFailed) {
285
+ const first = attempts.find((r) => r.status === "rejected");
286
+ throw first?.reason ?? new Error("Slack conversations.list failed for all channel types");
287
+ }
246
288
  return byName;
247
289
  })().catch((err) => {
248
290
  channelsIndex = null;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../package.json","../src/convid.ts","../src/normalize.ts","../src/tools.ts","../src/verify.ts","../src/index.ts"],"names":["stringValue","createHash"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"name\": \"@render-harness/cap-slack\",\n \"version\": \"0.5.1\",\n \"description\": \"Slack Events and Web API capability pack for the Render agent harness.\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\"\n ],\n \"keywords\": [\n \"render-harness-cap\",\n \"render-harness\",\n \"slack\"\n ],\n \"renderHarness\": {\n \"gallery\": {\n \"label\": \"Slack\",\n \"envHint\": \"SLACK_BOT_TOKEN\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run --passWithNoTests\"\n },\n \"dependencies\": {\n \"@render-harness/registry\": \"workspace:*\",\n \"@slack/web-api\": \"^7.12.0\"\n },\n \"devDependencies\": {\n \"@render-harness/core\": \"workspace:*\",\n \"@types/node\": \"^25.6.2\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.5\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/render-lab/render-agent-harness.git\",\n \"directory\": \"packages/capabilities/cap-slack\"\n }\n}\n","import { createHash } from \"node:crypto\";\n\nexport function slackConversationId(args: {\n teamId: string;\n channel: string;\n threadTs: string;\n}): string {\n const digest = createHash(\"sha256\")\n .update(`${args.teamId}:${args.channel}:${args.threadTs}`)\n .digest(\"hex\")\n .slice(0, 24);\n return `slack-${digest}`;\n}\n","export type SlackNormalizedEvent =\n | { kind: \"challenge\"; challenge: string }\n | { kind: \"noop\"; reason: string }\n | {\n kind: \"message\";\n text: string;\n teamId: string;\n channel: string;\n ts: string;\n threadTs: string;\n eventId: string;\n userId?: string;\n };\n\nexport interface SlackNormalizeConfig {\n includeEdits?: boolean;\n allowedChannels?: string[];\n}\n\nexport function normalizeSlackEvent(\n body: unknown,\n cfg: SlackNormalizeConfig = {},\n): SlackNormalizedEvent {\n if (!body || typeof body !== \"object\") return { kind: \"noop\", reason: \"invalid_body\" };\n const payload = body as Record<string, unknown>;\n if (payload.type === \"url_verification\") {\n const challenge = stringValue(payload.challenge);\n return challenge\n ? { kind: \"challenge\", challenge }\n : { kind: \"noop\", reason: \"missing_challenge\" };\n }\n if (payload.type !== \"event_callback\") return { kind: \"noop\", reason: \"unsupported_type\" };\n\n const event = objectValue(payload.event);\n if (!event) return { kind: \"noop\", reason: \"missing_event\" };\n const eventType = stringValue(event.type);\n if (eventType !== \"app_mention\" && eventType !== \"message\") {\n return { kind: \"noop\", reason: \"unsupported_event\" };\n }\n if (event.bot_id || event.subtype === \"bot_message\")\n return { kind: \"noop\", reason: \"bot_message\" };\n if (event.subtype === \"message_changed\" && !cfg.includeEdits) {\n return { kind: \"noop\", reason: \"edit_ignored\" };\n }\n\n const channel = stringValue(event.channel);\n if (!channel) return { kind: \"noop\", reason: \"missing_channel\" };\n if (cfg.allowedChannels?.length && !cfg.allowedChannels.includes(channel)) {\n return { kind: \"noop\", reason: \"channel_not_allowed\" };\n }\n\n const teamId = stringValue(payload.team_id) ?? stringValue(event.team);\n const ts = stringValue(event.ts);\n const text = stringValue(event.text) ?? \"\";\n const eventId =\n stringValue(payload.event_id) ?? `${teamId ?? \"team\"}-${channel}-${ts ?? \"event\"}`;\n if (!teamId || !ts || text.trim().length === 0) return { kind: \"noop\", reason: \"missing_fields\" };\n const userId = stringValue(event.user);\n\n return {\n kind: \"message\",\n text,\n teamId,\n channel,\n ts,\n threadTs: stringValue(event.thread_ts) ?? ts,\n eventId,\n ...(userId ? { userId } : {}),\n };\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n","import type { LocalToolHandler } from \"@render-harness/core\";\nimport { type RetryOptions, WebClient } from \"@slack/web-api\";\n\nexport type SlackAccessMode = \"read\" | \"read_write\";\n\n// @slack/web-api defaults to `tenRetriesInAboutThirtyMinutes` and no per-request\n// timeout, which means a single rate-limited or transient-failure response can\n// hang a tool call for up to 30 minutes with no surfaced progress. We replace\n// that with a bounded retry policy + 15s per-request timeout so the agent gets a\n// clear error within ~70s worst case instead of appearing stuck forever.\nconst SLACK_REQUEST_TIMEOUT_MS = 15_000;\nconst BOUNDED_RETRY_CONFIG: RetryOptions = {\n retries: 3,\n factor: 2,\n minTimeout: 500,\n maxTimeout: 3_000,\n};\n\ninterface ResolvedUser {\n id: string;\n name?: string;\n real_name?: string;\n display_name?: string;\n is_bot?: boolean;\n}\n\ninterface ResolvedChannel {\n id: string;\n name?: string;\n is_private?: boolean;\n is_archived?: boolean;\n}\n\ninterface SlackResolver {\n /** Look up a user by ID. Backed by `users.info`, cached for the agent process. */\n user: (id: string) => Promise<ResolvedUser>;\n /** Look up a channel by ID. Backed by `conversations.info`, cached for the agent process. */\n channel: (id: string) => Promise<ResolvedChannel>;\n /**\n * Resolve a channel input — either a raw Slack ID (`C…` / `G…` / `D…`),\n * a `#channel-name` string, or an `@user-handle` string (which opens or\n * reuses a DM channel). Returns the canonical channel ID for `chat.*` /\n * `conversations.*` calls. Lazy-fetches `conversations.list` and\n * `users.list` and caches by name/handle for subsequent lookups.\n */\n channelInput: (input: string) => Promise<string>;\n /**\n * Resolve a user input — either a raw `U…` ID or an `@handle` string\n * (with or without the leading `@`). Returns the user ID. Lazy-fetches\n * `users.list` and caches by handle.\n */\n userInput: (input: string) => Promise<string>;\n}\n\n// Slack channel/user/DM IDs are always `<prefix><A-Z0-9>+`; channel names\n// are restricted to lowercase letters / digits / `-` / `_`, so an input\n// that matches one of these patterns is unambiguously an ID. The {2,}\n// lower bound is intentionally loose so short test fixtures (`C123`) work\n// the same as real-world ids (`C0AQHA6M3PS`).\nconst CHANNEL_ID_PATTERN = /^[CGD][A-Z0-9]{2,}$/;\nconst USER_ID_PATTERN = /^U[A-Z0-9]{2,}$/;\n\nexport function slackTools(args: {\n botToken: string;\n accessMode: SlackAccessMode;\n allowedChannels?: string[];\n}): LocalToolHandler[] {\n const client = new WebClient(args.botToken, {\n timeout: SLACK_REQUEST_TIMEOUT_MS,\n retryConfig: BOUNDED_RETRY_CONFIG,\n });\n const resolver = createResolver(client);\n\n const tools: LocalToolHandler[] = [\n jsonTool(\n \"slack.get_thread\",\n \"Read a Slack thread's messages. `channel` accepts a Slack ID (C…/G…/D…), a `#channel-name`, or an `@user-handle` (opens a DM). Responses include resolved user display names and a rewritten text_resolved field.\",\n objectSchema({\n channel: { type: \"string\" },\n thread_ts: { type: \"string\" },\n }),\n async (input) => {\n const { channel, thread_ts } = input as { channel: string; thread_ts: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n const resp = await client.conversations.replies({ channel: channelId, ts: thread_ts });\n return enrichConversationResponse(resp, channelId, resolver);\n },\n ),\n jsonTool(\n \"slack.get_channel_history\",\n \"Read recent Slack channel messages. `channel` accepts a Slack ID (C…/G…/D…), a `#channel-name`, or an `@user-handle` (opens a DM). Responses include resolved user display names and a rewritten text_resolved field.\",\n objectSchema({\n channel: { type: \"string\" },\n limit: { type: \"number\", optional: true },\n }),\n async (input) => {\n const { channel, limit } = input as { channel: string; limit?: number };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n const resp = await client.conversations.history({\n channel: channelId,\n limit: limit ?? 20,\n });\n return enrichConversationResponse(resp, channelId, resolver);\n },\n ),\n jsonTool(\n \"slack.get_user_info\",\n \"Resolve a Slack user to display name, real name, and handle. Accepts a user ID (U0B4357MH7H), an `@handle`, or a bare handle.\",\n objectSchema({\n user: { type: \"string\" },\n }),\n async (input) => {\n const { user } = input as { user: string };\n const userId = await resolver.userInput(user);\n return resolver.user(userId);\n },\n ),\n jsonTool(\n \"slack.get_channel_info\",\n \"Resolve a Slack channel to name and metadata. Accepts a channel ID (C0AQHA6M3PS), a `#channel-name`, or an `@user-handle` (opens a DM).\",\n objectSchema({\n channel: { type: \"string\" },\n }),\n async (input) => {\n const { channel } = input as { channel: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return resolver.channel(channelId);\n },\n ),\n ];\n\n if (args.accessMode === \"read_write\") {\n tools.push(\n jsonTool(\n \"slack.send_message\",\n \"Send a Slack message, optionally as a thread reply. `channel` accepts a Slack ID (C…/G…/D…), a `#channel-name`, or an `@user-handle` (opens a DM).\",\n objectSchema({\n channel: { type: \"string\" },\n text: { type: \"string\" },\n thread_ts: { type: \"string\", optional: true },\n }),\n async (input) => {\n const { channel, text, thread_ts } = input as {\n channel: string;\n text: string;\n thread_ts?: string;\n };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return client.chat.postMessage({\n channel: channelId,\n text,\n ...(thread_ts ? { thread_ts } : {}),\n });\n },\n ),\n jsonTool(\n \"slack.add_reaction\",\n \"Add a reaction to a Slack message. `channel` accepts a Slack ID, a `#channel-name`, or an `@user-handle`.\",\n objectSchema({\n channel: { type: \"string\" },\n ts: { type: \"string\" },\n name: { type: \"string\" },\n }),\n async (input) => {\n const { channel, ts, name } = input as { channel: string; ts: string; name: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return client.reactions.add({ channel: channelId, timestamp: ts, name });\n },\n ),\n jsonTool(\n \"slack.update_message\",\n \"Update a Slack message. `channel` accepts a Slack ID, a `#channel-name`, or an `@user-handle`.\",\n objectSchema({\n channel: { type: \"string\" },\n ts: { type: \"string\" },\n text: { type: \"string\" },\n }),\n async (input) => {\n const { channel, ts, text } = input as { channel: string; ts: string; text: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return client.chat.update({ channel: channelId, ts, text });\n },\n ),\n );\n }\n\n return tools;\n}\n\nfunction jsonTool(\n name: string,\n description: string,\n inputSchema: Record<string, unknown>,\n call: (input: unknown) => Promise<unknown>,\n): LocalToolHandler {\n return {\n definition: { name, description, inputSchema, source: \"pack:cap-slack\" },\n handler: async ({ input }) => {\n try {\n return { content: JSON.stringify(await call(input), null, 2) };\n } catch (err) {\n return { content: err instanceof Error ? err.message : String(err), isError: true };\n }\n },\n };\n}\n\nfunction assertAllowedChannel(channel: string, allowedChannels: string[] | undefined): void {\n if (allowedChannels?.length && !allowedChannels.includes(channel)) {\n throw new Error(`Slack channel \"${channel}\" is not allowed by cap-slack config`);\n }\n}\n\nfunction objectSchema(properties: Record<string, unknown>) {\n return {\n type: \"object\",\n additionalProperties: false,\n properties,\n required: Object.entries(properties)\n .filter(([, value]) => !(value as { optional?: boolean }).optional)\n .map(([key]) => key),\n };\n}\n\nfunction createResolver(client: WebClient): SlackResolver {\n const users = new Map<string, ResolvedUser>();\n const channels = new Map<string, ResolvedChannel>();\n const pendingUsers = new Map<string, Promise<ResolvedUser>>();\n const pendingChannels = new Map<string, Promise<ResolvedChannel>>();\n\n // Name → ID indexes for reverse lookup. Populated lazily by\n // `ensureChannelsIndex` / `ensureUsersIndex` (which page through\n // `conversations.list` / `users.list` once and cache the full map for\n // the lifetime of this resolver — i.e. the agent process). DM channel\n // ids opened via `conversations.open` are written back into `dmByUserId`\n // so repeated `@handle` sends only hit the API once.\n let channelsIndex: Promise<Map<string, string>> | null = null;\n let usersIndex: Promise<Map<string, string>> | null = null;\n const dmByUserId = new Map<string, string>();\n\n const ensureChannelsIndex = (): Promise<Map<string, string>> => {\n if (channelsIndex) return channelsIndex;\n channelsIndex = (async () => {\n const byName = new Map<string, string>();\n let cursor: string | undefined;\n do {\n const resp = (await client.conversations.list({\n limit: 1000,\n types: \"public_channel,private_channel\",\n exclude_archived: true,\n ...(cursor ? { cursor } : {}),\n })) as unknown as {\n channels?: Array<{ id?: unknown; name?: unknown }>;\n response_metadata?: { next_cursor?: unknown };\n };\n for (const c of resp.channels ?? []) {\n if (typeof c.id === \"string\" && typeof c.name === \"string\") {\n byName.set(c.name.toLowerCase(), c.id);\n // Also warm the by-ID resolver cache so a later\n // `slack.get_channel_info` lookup is a hit.\n if (!channels.has(c.id)) channels.set(c.id, { id: c.id, name: c.name });\n }\n }\n cursor =\n typeof resp.response_metadata?.next_cursor === \"string\" &&\n resp.response_metadata.next_cursor.length > 0\n ? resp.response_metadata.next_cursor\n : undefined;\n } while (cursor);\n return byName;\n })().catch((err) => {\n // Reset on failure so a subsequent lookup retries (e.g. once\n // `channels:read` scope is added without the agent restarting).\n channelsIndex = null;\n throw err;\n });\n return channelsIndex;\n };\n\n const ensureUsersIndex = (): Promise<Map<string, string>> => {\n if (usersIndex) return usersIndex;\n usersIndex = (async () => {\n const byHandle = new Map<string, string>();\n let cursor: string | undefined;\n do {\n const resp = (await client.users.list({\n limit: 200,\n ...(cursor ? { cursor } : {}),\n })) as unknown as {\n members?: Array<{\n id?: unknown;\n name?: unknown;\n real_name?: unknown;\n profile?: { display_name?: unknown; display_name_normalized?: unknown };\n deleted?: unknown;\n }>;\n response_metadata?: { next_cursor?: unknown };\n };\n for (const u of resp.members ?? []) {\n if (typeof u.id !== \"string\" || u.deleted === true) continue;\n // Index every name variant the agent might use. Slack handles\n // are unique, but display names + real names can collide — last\n // writer wins, which is acceptable for an LLM hint.\n for (const candidate of [\n u.name,\n u.real_name,\n u.profile?.display_name,\n u.profile?.display_name_normalized,\n ]) {\n if (typeof candidate === \"string\" && candidate.length > 0) {\n byHandle.set(candidate.toLowerCase(), u.id);\n }\n }\n if (!users.has(u.id)) {\n users.set(u.id, buildResolvedUser(u.id, u as unknown as Record<string, unknown>));\n }\n }\n cursor =\n typeof resp.response_metadata?.next_cursor === \"string\" &&\n resp.response_metadata.next_cursor.length > 0\n ? resp.response_metadata.next_cursor\n : undefined;\n } while (cursor);\n return byHandle;\n })().catch((err) => {\n usersIndex = null;\n throw err;\n });\n return usersIndex;\n };\n\n const openDmFor = async (userId: string): Promise<string> => {\n const cached = dmByUserId.get(userId);\n if (cached) return cached;\n const resp = (await client.conversations.open({ users: userId })) as unknown as {\n channel?: { id?: unknown };\n };\n const channelId = resp.channel?.id;\n if (typeof channelId !== \"string\") {\n throw new Error(`conversations.open for ${userId} returned no channel id`);\n }\n dmByUserId.set(userId, channelId);\n return channelId;\n };\n\n const resolveUserInput = async (input: string): Promise<string> => {\n const trimmed = input.trim();\n if (trimmed.length === 0) throw new Error(\"Slack user input is empty\");\n // Accept Slack's `<@U123>` mention wrapping verbatim.\n const mention = /^<@(U[A-Z0-9]+)(?:\\|[^>]+)?>$/.exec(trimmed);\n if (mention?.[1]) return mention[1];\n if (USER_ID_PATTERN.test(trimmed)) return trimmed;\n const handle = trimmed.startsWith(\"@\") ? trimmed.slice(1) : trimmed;\n if (handle.length === 0) throw new Error(\"Slack user input has no handle after '@'\");\n const index = await ensureUsersIndex();\n const id = index.get(handle.toLowerCase());\n if (!id) {\n throw new Error(\n `Slack user \"${input}\" not found. Check the handle, or ensure the bot has 'users:read' scope.`,\n );\n }\n return id;\n };\n\n const resolveChannelInput = async (input: string): Promise<string> => {\n const trimmed = input.trim();\n if (trimmed.length === 0) throw new Error(\"Slack channel input is empty\");\n // Accept Slack's `<#C123|name>` mention wrapping verbatim.\n const mention = /^<#([CGD][A-Z0-9]+)(?:\\|[^>]+)?>$/.exec(trimmed);\n if (mention?.[1]) return mention[1];\n if (CHANNEL_ID_PATTERN.test(trimmed)) return trimmed;\n if (trimmed.startsWith(\"@\")) {\n const userId = await resolveUserInput(trimmed);\n return openDmFor(userId);\n }\n const name = trimmed.startsWith(\"#\") ? trimmed.slice(1) : trimmed;\n if (name.length === 0) throw new Error(\"Slack channel input has no name after '#'\");\n const index = await ensureChannelsIndex();\n const id = index.get(name.toLowerCase());\n if (!id) {\n throw new Error(\n `Slack channel \"${input}\" not found. Check the name, or ensure the bot has 'channels:read' / 'groups:read' scope and is a member of the channel.`,\n );\n }\n return id;\n };\n\n return {\n async user(id: string): Promise<ResolvedUser> {\n const cached = users.get(id);\n if (cached) return cached;\n const pending = pendingUsers.get(id);\n if (pending) return pending;\n const fetchOne = (async (): Promise<ResolvedUser> => {\n try {\n const resp = await client.users.info({ user: id });\n const raw = (resp as unknown as { user?: Record<string, unknown> }).user;\n const info = buildResolvedUser(id, raw);\n users.set(id, info);\n return info;\n } catch {\n const info: ResolvedUser = { id };\n users.set(id, info);\n return info;\n } finally {\n pendingUsers.delete(id);\n }\n })();\n pendingUsers.set(id, fetchOne);\n return fetchOne;\n },\n async channel(id: string): Promise<ResolvedChannel> {\n const cached = channels.get(id);\n if (cached) return cached;\n const pending = pendingChannels.get(id);\n if (pending) return pending;\n const fetchOne = (async (): Promise<ResolvedChannel> => {\n try {\n const resp = await client.conversations.info({ channel: id });\n const raw = (resp as unknown as { channel?: Record<string, unknown> }).channel;\n const info = buildResolvedChannel(id, raw);\n channels.set(id, info);\n return info;\n } catch {\n const info: ResolvedChannel = { id };\n channels.set(id, info);\n return info;\n } finally {\n pendingChannels.delete(id);\n }\n })();\n pendingChannels.set(id, fetchOne);\n return fetchOne;\n },\n channelInput: resolveChannelInput,\n userInput: resolveUserInput,\n };\n}\n\nfunction buildResolvedUser(id: string, raw: Record<string, unknown> | undefined): ResolvedUser {\n if (!raw) return { id };\n const profile = (raw.profile as Record<string, unknown> | undefined) ?? undefined;\n const info: ResolvedUser = { id };\n const name = typeof raw.name === \"string\" ? raw.name : undefined;\n if (name) info.name = name;\n const realName =\n typeof raw.real_name === \"string\"\n ? raw.real_name\n : typeof profile?.real_name === \"string\"\n ? (profile.real_name as string)\n : undefined;\n if (realName) info.real_name = realName;\n const displayName =\n typeof profile?.display_name === \"string\" && (profile.display_name as string).length > 0\n ? (profile.display_name as string)\n : undefined;\n if (displayName) info.display_name = displayName;\n if (raw.is_bot === true) info.is_bot = true;\n return info;\n}\n\nfunction buildResolvedChannel(\n id: string,\n raw: Record<string, unknown> | undefined,\n): ResolvedChannel {\n if (!raw) return { id };\n const info: ResolvedChannel = { id };\n if (typeof raw.name === \"string\") info.name = raw.name;\n if (raw.is_private === true) info.is_private = true;\n if (raw.is_archived === true) info.is_archived = true;\n return info;\n}\n\nfunction displayLabel(user: ResolvedUser | undefined): string | undefined {\n return user?.display_name ?? user?.real_name ?? user?.name;\n}\n\nconst USER_MENTION = /<@(U[A-Z0-9]+)(?:\\|[^>]+)?>/g;\nconst CHANNEL_MENTION = /<#(C[A-Z0-9]+)(?:\\|([^>]+))?>/g;\n\nasync function enrichConversationResponse(\n resp: unknown,\n channelId: string,\n resolver: SlackResolver,\n): Promise<unknown> {\n if (!resp || typeof resp !== \"object\") return resp;\n const body = resp as Record<string, unknown>;\n const rawMessages = Array.isArray(body.messages) ? (body.messages as unknown[]) : [];\n const userIds = new Set<string>();\n const channelIds = new Set<string>([channelId]);\n for (const msg of rawMessages) {\n if (!msg || typeof msg !== \"object\") continue;\n const m = msg as Record<string, unknown>;\n if (typeof m.user === \"string\") userIds.add(m.user);\n if (typeof m.text === \"string\") collectMentions(m.text, userIds, channelIds);\n }\n\n const [resolvedUserList, resolvedChannelList] = await Promise.all([\n Promise.all([...userIds].map(async (id) => [id, await resolver.user(id)] as const)),\n Promise.all([...channelIds].map(async (id) => [id, await resolver.channel(id)] as const)),\n ]);\n const usersById = new Map<string, ResolvedUser>(resolvedUserList);\n const channelsById = new Map<string, ResolvedChannel>(resolvedChannelList);\n\n const enrichedMessages = rawMessages.map((msg) => {\n if (!msg || typeof msg !== \"object\") return msg;\n const m = msg as Record<string, unknown>;\n const out: Record<string, unknown> = { ...m };\n if (typeof m.user === \"string\") {\n const label = displayLabel(usersById.get(m.user));\n if (label) out.user_display_name = label;\n }\n if (typeof m.text === \"string\") {\n out.text_resolved = rewriteMentions(m.text, usersById, channelsById);\n }\n return out;\n });\n\n const resolvedUsers: Record<string, ResolvedUser> = {};\n for (const [id, info] of usersById) resolvedUsers[id] = info;\n const channelInfo = channelsById.get(channelId);\n\n return {\n ...body,\n messages: enrichedMessages,\n resolved_users: resolvedUsers,\n ...(channelInfo ? { resolved_channel: channelInfo } : {}),\n };\n}\n\nfunction collectMentions(text: string, userIds: Set<string>, channelIds: Set<string>): void {\n for (const match of text.matchAll(USER_MENTION)) {\n const id = match[1];\n if (id) userIds.add(id);\n }\n for (const match of text.matchAll(CHANNEL_MENTION)) {\n const id = match[1];\n if (id) channelIds.add(id);\n }\n}\n\nfunction rewriteMentions(\n text: string,\n users: Map<string, ResolvedUser>,\n channels: Map<string, ResolvedChannel>,\n): string {\n return text\n .replace(USER_MENTION, (_match, id: string) => {\n const label = displayLabel(users.get(id));\n return label ? `@${label}` : `<@${id}>`;\n })\n .replace(CHANNEL_MENTION, (_match, id: string, fallbackName?: string) => {\n const name = channels.get(id)?.name ?? fallbackName;\n return name ? `#${name}` : `<#${id}>`;\n });\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nconst FIVE_MINUTES_SECONDS = 60 * 5;\n\nexport function verifySlackSignature(args: {\n rawBody: string;\n signingSecret: string;\n signature: string | null;\n timestamp: string | null;\n nowSeconds?: number;\n}): boolean {\n if (!args.signature?.startsWith(\"v0=\") || !args.timestamp) return false;\n const ts = Number(args.timestamp);\n if (!Number.isFinite(ts)) return false;\n const now = args.nowSeconds ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > FIVE_MINUTES_SECONDS) return false;\n\n const base = `v0:${args.timestamp}:${args.rawBody}`;\n const expected = `v0=${createHmac(\"sha256\", args.signingSecret).update(base).digest(\"hex\")}`;\n const expectedBuf = Buffer.from(expected, \"utf8\");\n const actualBuf = Buffer.from(args.signature, \"utf8\");\n if (expectedBuf.length !== actualBuf.length) return false;\n return timingSafeEqual(expectedBuf, actualBuf);\n}\n","import { createHash } from \"node:crypto\";\nimport type { LocalToolHandler } from \"@render-harness/core\";\nimport { type ConnectorContribution, definePack, type PackContext } from \"@render-harness/registry\";\nimport pkg from \"../package.json\" with { type: \"json\" };\nimport { slackConversationId } from \"./convid.js\";\nimport { normalizeSlackEvent, type SlackNormalizeConfig } from \"./normalize.js\";\nimport { type SlackAccessMode, slackTools } from \"./tools.js\";\nimport { verifySlackSignature } from \"./verify.js\";\n\ninterface SlackConfig extends SlackNormalizeConfig {\n agent?: string;\n userId?: string;\n signingSecretEnv?: string;\n botTokenEnv?: string;\n accessMode?: SlackAccessMode;\n}\n\nconst DEFAULT_SIGNING_SECRET_ENV = \"SLACK_SIGNING_SECRET\";\nconst DEFAULT_BOT_TOKEN_ENV = \"SLACK_BOT_TOKEN\";\n\nconst pack = definePack({\n name: \"cap-slack\",\n version: pkg.version,\n envSchema: [\n {\n name: DEFAULT_SIGNING_SECRET_ENV,\n required: true,\n secret: true,\n description: \"Slack signing secret used to verify Events API requests.\",\n },\n {\n name: DEFAULT_BOT_TOKEN_ENV,\n required: true,\n secret: true,\n description: \"Slack bot token used for read tools and optional write tools.\",\n },\n ],\n localTools(ctx: PackContext): LocalToolHandler[] {\n const cfg = readConfig(ctx.config);\n const botToken = ctx.env(cfg.botTokenEnv);\n if (!botToken) return [];\n return slackTools({\n botToken,\n accessMode: cfg.accessMode,\n ...(cfg.allowedChannels ? { allowedChannels: cfg.allowedChannels } : {}),\n });\n },\n connectors(ctx: PackContext): ConnectorContribution[] {\n const cfg = readConfig(ctx.config);\n return [\n {\n key: \"slack\",\n webhook: async (req, webCtx) => {\n const rawBody = await req.text();\n const signingSecret = ctx.env(cfg.signingSecretEnv);\n if (!signingSecret) {\n return json({ error: \"missing_secret\", env: cfg.signingSecretEnv }, 500);\n }\n if (\n !verifySlackSignature({\n rawBody,\n signingSecret,\n signature: req.headers.get(\"x-slack-signature\"),\n timestamp: req.headers.get(\"x-slack-request-timestamp\"),\n })\n ) {\n return json({ error: \"invalid_signature\" }, 401);\n }\n\n const parsed = parseBody(rawBody);\n const normalized = normalizeSlackEvent(parsed, cfg);\n if (normalized.kind === \"challenge\") return json({ challenge: normalized.challenge });\n if (normalized.kind === \"noop\")\n return json({ ok: true, skipped: true, reason: normalized.reason });\n\n const agent = webCtx.resolveAgent(cfg.agent);\n const conversationId = slackConversationId({\n teamId: normalized.teamId,\n channel: normalized.channel,\n threadTs: normalized.threadTs,\n });\n const result = await webCtx.enqueueIntoConversation({\n conversationId,\n agentName: agent.name,\n agentVersion: agent.version,\n userId: cfg.userId ?? \"cap-slack\",\n runId: `slack-${hash(normalized.eventId)}`,\n title: `Slack ${normalized.channel}/${normalized.threadTs}`,\n initialContent: [{ type: \"text\", text: normalized.text }],\n metadata: {\n connector: \"cap-slack\",\n teamId: normalized.teamId,\n channel: normalized.channel,\n threadTs: normalized.threadTs,\n ts: normalized.ts,\n ...(normalized.userId ? { userId: normalized.userId } : {}),\n },\n });\n return json(result, result.status === \"enqueued\" ? 202 : 200);\n },\n },\n ];\n },\n});\n\nexport default pack;\n\ntype ResolvedSlackConfig = Required<\n Pick<SlackConfig, \"signingSecretEnv\" | \"botTokenEnv\" | \"accessMode\" | \"includeEdits\">\n> &\n Omit<SlackConfig, \"signingSecretEnv\" | \"botTokenEnv\" | \"accessMode\" | \"includeEdits\">;\n\nfunction readConfig(raw: Record<string, unknown>): ResolvedSlackConfig {\n const cfg: ResolvedSlackConfig = {\n signingSecretEnv: stringValue(raw.signingSecretEnv) ?? DEFAULT_SIGNING_SECRET_ENV,\n botTokenEnv: stringValue(raw.botTokenEnv) ?? DEFAULT_BOT_TOKEN_ENV,\n accessMode: raw.accessMode === \"read_write\" ? \"read_write\" : \"read\",\n includeEdits: raw.includeEdits === true,\n };\n const agent = stringValue(raw.agent);\n if (agent) cfg.agent = agent;\n const userId = stringValue(raw.userId);\n if (userId) cfg.userId = userId;\n const allowedChannels = stringArray(raw.allowedChannels);\n if (allowedChannels) cfg.allowedChannels = allowedChannels;\n return cfg;\n}\n\nfunction parseBody(rawBody: string): unknown {\n try {\n return JSON.parse(rawBody);\n } catch {\n return null;\n }\n}\n\nfunction hash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 32);\n}\n\nfunction json(body: unknown, status = 200): Response {\n return Response.json(body, { status });\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction stringArray(value: unknown): string[] | undefined {\n return Array.isArray(value)\n ? value.filter((item): item is string => typeof item === \"string\")\n : undefined;\n}\n"]}
1
+ {"version":3,"sources":["../package.json","../src/convid.ts","../src/normalize.ts","../src/tools.ts","../src/verify.ts","../src/index.ts"],"names":["stringValue","createHash"],"mappings":"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","file":"index.js","sourcesContent":["{\n \"name\": \"@render-harness/cap-slack\",\n \"version\": \"0.5.2\",\n \"description\": \"Slack Events and Web API capability pack for the Render agent harness.\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\"\n ],\n \"keywords\": [\n \"render-harness-cap\",\n \"render-harness\",\n \"slack\"\n ],\n \"renderHarness\": {\n \"gallery\": {\n \"label\": \"Slack\",\n \"envHint\": \"SLACK_BOT_TOKEN\"\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run --passWithNoTests\"\n },\n \"dependencies\": {\n \"@render-harness/registry\": \"workspace:*\",\n \"@slack/web-api\": \"^7.12.0\"\n },\n \"devDependencies\": {\n \"@render-harness/core\": \"workspace:*\",\n \"@types/node\": \"^25.6.2\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^6.0.3\",\n \"vitest\": \"^4.1.5\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/render-lab/render-agent-harness.git\",\n \"directory\": \"packages/capabilities/cap-slack\"\n }\n}\n","import { createHash } from \"node:crypto\";\n\nexport function slackConversationId(args: {\n teamId: string;\n channel: string;\n threadTs: string;\n}): string {\n const digest = createHash(\"sha256\")\n .update(`${args.teamId}:${args.channel}:${args.threadTs}`)\n .digest(\"hex\")\n .slice(0, 24);\n return `slack-${digest}`;\n}\n","export type SlackNormalizedEvent =\n | { kind: \"challenge\"; challenge: string }\n | { kind: \"noop\"; reason: string }\n | {\n kind: \"message\";\n text: string;\n teamId: string;\n channel: string;\n ts: string;\n threadTs: string;\n eventId: string;\n userId?: string;\n };\n\nexport interface SlackNormalizeConfig {\n includeEdits?: boolean;\n allowedChannels?: string[];\n}\n\nexport function normalizeSlackEvent(\n body: unknown,\n cfg: SlackNormalizeConfig = {},\n): SlackNormalizedEvent {\n if (!body || typeof body !== \"object\") return { kind: \"noop\", reason: \"invalid_body\" };\n const payload = body as Record<string, unknown>;\n if (payload.type === \"url_verification\") {\n const challenge = stringValue(payload.challenge);\n return challenge\n ? { kind: \"challenge\", challenge }\n : { kind: \"noop\", reason: \"missing_challenge\" };\n }\n if (payload.type !== \"event_callback\") return { kind: \"noop\", reason: \"unsupported_type\" };\n\n const event = objectValue(payload.event);\n if (!event) return { kind: \"noop\", reason: \"missing_event\" };\n const eventType = stringValue(event.type);\n if (eventType !== \"app_mention\" && eventType !== \"message\") {\n return { kind: \"noop\", reason: \"unsupported_event\" };\n }\n if (event.bot_id || event.subtype === \"bot_message\")\n return { kind: \"noop\", reason: \"bot_message\" };\n if (event.subtype === \"message_changed\" && !cfg.includeEdits) {\n return { kind: \"noop\", reason: \"edit_ignored\" };\n }\n\n const channel = stringValue(event.channel);\n if (!channel) return { kind: \"noop\", reason: \"missing_channel\" };\n if (cfg.allowedChannels?.length && !cfg.allowedChannels.includes(channel)) {\n return { kind: \"noop\", reason: \"channel_not_allowed\" };\n }\n\n const teamId = stringValue(payload.team_id) ?? stringValue(event.team);\n const ts = stringValue(event.ts);\n const text = stringValue(event.text) ?? \"\";\n const eventId =\n stringValue(payload.event_id) ?? `${teamId ?? \"team\"}-${channel}-${ts ?? \"event\"}`;\n if (!teamId || !ts || text.trim().length === 0) return { kind: \"noop\", reason: \"missing_fields\" };\n const userId = stringValue(event.user);\n\n return {\n kind: \"message\",\n text,\n teamId,\n channel,\n ts,\n threadTs: stringValue(event.thread_ts) ?? ts,\n eventId,\n ...(userId ? { userId } : {}),\n };\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> | null {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n","import type { LocalToolHandler } from \"@render-harness/core\";\nimport { type RetryOptions, WebClient } from \"@slack/web-api\";\n\nexport type SlackAccessMode = \"read\" | \"read_write\";\n\n// @slack/web-api defaults to `tenRetriesInAboutThirtyMinutes` and no per-request\n// timeout, which means a single rate-limited or transient-failure response can\n// hang a tool call for up to 30 minutes with no surfaced progress. We replace\n// that with a bounded retry policy + 15s per-request timeout so the agent gets a\n// clear error within ~70s worst case instead of appearing stuck forever.\nconst SLACK_REQUEST_TIMEOUT_MS = 15_000;\nconst BOUNDED_RETRY_CONFIG: RetryOptions = {\n retries: 3,\n factor: 2,\n minTimeout: 500,\n maxTimeout: 3_000,\n};\n\ninterface ResolvedUser {\n id: string;\n name?: string;\n real_name?: string;\n display_name?: string;\n is_bot?: boolean;\n}\n\ninterface ResolvedChannel {\n id: string;\n name?: string;\n is_private?: boolean;\n is_archived?: boolean;\n}\n\ninterface SlackResolver {\n /** Look up a user by ID. Backed by `users.info`, cached for the agent process. */\n user: (id: string) => Promise<ResolvedUser>;\n /** Look up a channel by ID. Backed by `conversations.info`, cached for the agent process. */\n channel: (id: string) => Promise<ResolvedChannel>;\n /**\n * Resolve a channel input — either a raw Slack ID (`C…` / `G…` / `D…`),\n * a `#channel-name` string, or an `@user-handle` string (which opens or\n * reuses a DM channel). Returns the canonical channel ID for `chat.*` /\n * `conversations.*` calls. Lazy-fetches `conversations.list` and\n * `users.list` and caches by name/handle for subsequent lookups.\n */\n channelInput: (input: string) => Promise<string>;\n /**\n * Resolve a user input — either a raw `U…` ID or an `@handle` string\n * (with or without the leading `@`). Returns the user ID. Lazy-fetches\n * `users.list` and caches by handle.\n */\n userInput: (input: string) => Promise<string>;\n}\n\n// Slack channel/user/DM IDs are always `<prefix><A-Z0-9>+`; channel names\n// are restricted to lowercase letters / digits / `-` / `_`, so an input\n// that matches one of these patterns is unambiguously an ID. The {2,}\n// lower bound is intentionally loose so short test fixtures (`C123`) work\n// the same as real-world ids (`C0AQHA6M3PS`).\nconst CHANNEL_ID_PATTERN = /^[CGD][A-Z0-9]{2,}$/;\nconst USER_ID_PATTERN = /^U[A-Z0-9]{2,}$/;\n\nexport function slackTools(args: {\n botToken: string;\n accessMode: SlackAccessMode;\n allowedChannels?: string[];\n}): LocalToolHandler[] {\n const client = new WebClient(args.botToken, {\n timeout: SLACK_REQUEST_TIMEOUT_MS,\n retryConfig: BOUNDED_RETRY_CONFIG,\n });\n const resolver = createResolver(client);\n\n const tools: LocalToolHandler[] = [\n jsonTool(\n \"slack.get_thread\",\n \"Read a Slack thread's messages. `channel` accepts a Slack ID (C…/G…/D…), a `#channel-name`, or an `@user-handle` (opens a DM). Responses include resolved user display names and a rewritten text_resolved field.\",\n objectSchema({\n channel: { type: \"string\" },\n thread_ts: { type: \"string\" },\n }),\n async (input) => {\n const { channel, thread_ts } = input as { channel: string; thread_ts: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n const resp = await client.conversations.replies({ channel: channelId, ts: thread_ts });\n return enrichConversationResponse(resp, channelId, resolver);\n },\n ),\n jsonTool(\n \"slack.get_channel_history\",\n \"Read recent Slack channel messages. `channel` accepts a Slack ID (C…/G…/D…), a `#channel-name`, or an `@user-handle` (opens a DM). Responses include resolved user display names and a rewritten text_resolved field.\",\n objectSchema({\n channel: { type: \"string\" },\n limit: { type: \"number\", optional: true },\n }),\n async (input) => {\n const { channel, limit } = input as { channel: string; limit?: number };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n const resp = await client.conversations.history({\n channel: channelId,\n limit: limit ?? 20,\n });\n return enrichConversationResponse(resp, channelId, resolver);\n },\n ),\n jsonTool(\n \"slack.get_user_info\",\n \"Resolve a Slack user to display name, real name, and handle. Accepts a user ID (U0B4357MH7H), an `@handle`, or a bare handle.\",\n objectSchema({\n user: { type: \"string\" },\n }),\n async (input) => {\n const { user } = input as { user: string };\n const userId = await resolver.userInput(user);\n return resolver.user(userId);\n },\n ),\n jsonTool(\n \"slack.get_channel_info\",\n \"Resolve a Slack channel to name and metadata. Accepts a channel ID (C0AQHA6M3PS), a `#channel-name`, or an `@user-handle` (opens a DM).\",\n objectSchema({\n channel: { type: \"string\" },\n }),\n async (input) => {\n const { channel } = input as { channel: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return resolver.channel(channelId);\n },\n ),\n ];\n\n if (args.accessMode === \"read_write\") {\n tools.push(\n jsonTool(\n \"slack.send_message\",\n \"Send a Slack message, optionally as a thread reply. `channel` accepts a Slack ID (C…/G…/D…), a `#channel-name`, or an `@user-handle` (opens a DM).\",\n objectSchema({\n channel: { type: \"string\" },\n text: { type: \"string\" },\n thread_ts: { type: \"string\", optional: true },\n }),\n async (input) => {\n const { channel, text, thread_ts } = input as {\n channel: string;\n text: string;\n thread_ts?: string;\n };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return client.chat.postMessage({\n channel: channelId,\n text,\n ...(thread_ts ? { thread_ts } : {}),\n });\n },\n ),\n jsonTool(\n \"slack.add_reaction\",\n \"Add a reaction to a Slack message. `channel` accepts a Slack ID, a `#channel-name`, or an `@user-handle`.\",\n objectSchema({\n channel: { type: \"string\" },\n ts: { type: \"string\" },\n name: { type: \"string\" },\n }),\n async (input) => {\n const { channel, ts, name } = input as { channel: string; ts: string; name: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return client.reactions.add({ channel: channelId, timestamp: ts, name });\n },\n ),\n jsonTool(\n \"slack.update_message\",\n \"Update a Slack message. `channel` accepts a Slack ID, a `#channel-name`, or an `@user-handle`.\",\n objectSchema({\n channel: { type: \"string\" },\n ts: { type: \"string\" },\n text: { type: \"string\" },\n }),\n async (input) => {\n const { channel, ts, text } = input as { channel: string; ts: string; text: string };\n const channelId = await resolver.channelInput(channel);\n assertAllowedChannel(channelId, args.allowedChannels);\n return client.chat.update({ channel: channelId, ts, text });\n },\n ),\n );\n }\n\n return tools;\n}\n\nfunction jsonTool(\n name: string,\n description: string,\n inputSchema: Record<string, unknown>,\n call: (input: unknown) => Promise<unknown>,\n): LocalToolHandler {\n return {\n definition: { name, description, inputSchema, source: \"pack:cap-slack\" },\n handler: async ({ input }) => {\n try {\n return { content: JSON.stringify(await call(input), null, 2) };\n } catch (err) {\n return { content: formatSlackError(err), isError: true };\n }\n },\n };\n}\n\n/**\n * Rewrite `@slack/web-api`'s generic `\"An API error occurred:\n * missing_scope\"` errors into something an agent (and the operator\n * reading logs) can act on. The Slack response carries the needed\n * scope under `err.data.needed` and what the bot currently has under\n * `err.data.provided` — surface both, plus a one-line fix instruction.\n *\n * Other Slack platform errors (e.g. `not_in_channel`, `channel_not_found`,\n * `invalid_auth`) get a hint appended where useful but otherwise pass\n * through verbatim.\n */\nfunction formatSlackError(err: unknown): string {\n if (!err || typeof err !== \"object\") return String(err);\n const e = err as { message?: unknown; code?: unknown; data?: Record<string, unknown> };\n const code = typeof e.data?.error === \"string\" ? e.data.error : undefined;\n if (!code) {\n return typeof e.message === \"string\" ? e.message : String(err);\n }\n if (code === \"missing_scope\") {\n const needed = typeof e.data?.needed === \"string\" ? e.data.needed : \"?\";\n const provided = typeof e.data?.provided === \"string\" ? e.data.provided : \"?\";\n return [\n `Slack missing_scope: '${needed}' needed (bot currently has: '${provided}').`,\n `Add '${needed}' to the bot's OAuth scopes in the Slack app config (api.slack.com → OAuth & Permissions → Bot Token Scopes), reinstall the app to the workspace, and redeploy.`,\n ].join(\" \");\n }\n if (code === \"not_in_channel\") {\n return \"Slack not_in_channel: the bot must be a member of the channel before it can post. Invite it with `/invite @<bot-name>` in the channel.\";\n }\n if (code === \"channel_not_found\") {\n return \"Slack channel_not_found: the channel ID is invalid, the bot doesn't have permission to see it, or it has been archived.\";\n }\n if (code === \"invalid_auth\" || code === \"token_revoked\") {\n return `Slack ${code}: SLACK_BOT_TOKEN is invalid or has been revoked. Re-issue the token from the Slack app config and redeploy.`;\n }\n // Pass through any other Slack platform code so the agent can decide\n // (e.g. rate_limited, account_inactive, internal_error).\n const message = typeof e.message === \"string\" ? e.message : String(err);\n return `${message} (slack.${code})`;\n}\n\nfunction assertAllowedChannel(channel: string, allowedChannels: string[] | undefined): void {\n if (allowedChannels?.length && !allowedChannels.includes(channel)) {\n throw new Error(`Slack channel \"${channel}\" is not allowed by cap-slack config`);\n }\n}\n\nfunction objectSchema(properties: Record<string, unknown>) {\n return {\n type: \"object\",\n additionalProperties: false,\n properties,\n required: Object.entries(properties)\n .filter(([, value]) => !(value as { optional?: boolean }).optional)\n .map(([key]) => key),\n };\n}\n\nfunction createResolver(client: WebClient): SlackResolver {\n const users = new Map<string, ResolvedUser>();\n const channels = new Map<string, ResolvedChannel>();\n const pendingUsers = new Map<string, Promise<ResolvedUser>>();\n const pendingChannels = new Map<string, Promise<ResolvedChannel>>();\n\n // Name → ID indexes for reverse lookup. Populated lazily by\n // `ensureChannelsIndex` / `ensureUsersIndex` (which page through\n // `conversations.list` / `users.list` once and cache the full map for\n // the lifetime of this resolver — i.e. the agent process). DM channel\n // ids opened via `conversations.open` are written back into `dmByUserId`\n // so repeated `@handle` sends only hit the API once.\n let channelsIndex: Promise<Map<string, string>> | null = null;\n let usersIndex: Promise<Map<string, string>> | null = null;\n const dmByUserId = new Map<string, string>();\n\n // Drain `conversations.list` for one channel kind, paging through all\n // results. Each kind requires a different OAuth scope on the bot:\n // public_channel → channels:read\n // private_channel → groups:read\n // mpim → mpim:read\n // im → im:read\n // The previous implementation requested every kind in a single call,\n // which made the whole index unbuildable for bots that only had\n // `channels:read` — Slack refuses `types=public_channel,private_channel`\n // with `missing_scope: groups:read` unless both scopes are granted, even\n // when the caller only cares about public channels. Now we list each\n // kind independently and aggregate results from whichever succeeded;\n // bots that only granted `channels:read` get a working name → id index\n // for public channels and a clear error for private ones.\n const drainChannelsByType = async (type: string, byName: Map<string, string>): Promise<void> => {\n let cursor: string | undefined;\n do {\n const resp = (await client.conversations.list({\n limit: 1000,\n types: type,\n exclude_archived: true,\n ...(cursor ? { cursor } : {}),\n })) as unknown as {\n channels?: Array<{ id?: unknown; name?: unknown; is_private?: unknown }>;\n response_metadata?: { next_cursor?: unknown };\n };\n for (const c of resp.channels ?? []) {\n if (typeof c.id === \"string\" && typeof c.name === \"string\") {\n byName.set(c.name.toLowerCase(), c.id);\n if (!channels.has(c.id)) {\n const cached: ResolvedChannel = { id: c.id, name: c.name };\n if (c.is_private === true) cached.is_private = true;\n channels.set(c.id, cached);\n }\n }\n }\n cursor =\n typeof resp.response_metadata?.next_cursor === \"string\" &&\n resp.response_metadata.next_cursor.length > 0\n ? resp.response_metadata.next_cursor\n : undefined;\n } while (cursor);\n };\n\n const ensureChannelsIndex = (): Promise<Map<string, string>> => {\n if (channelsIndex) return channelsIndex;\n channelsIndex = (async () => {\n const byName = new Map<string, string>();\n // Try each channel kind independently. A bot with only\n // `channels:read` succeeds on public and fails on private (caught,\n // ignored). A bot with both scopes succeeds on both. A bot with\n // neither fails on both, surfacing the first missing scope error.\n const attempts = await Promise.allSettled([\n drainChannelsByType(\"public_channel\", byName),\n drainChannelsByType(\"private_channel\", byName),\n ]);\n const allFailed = attempts.every((r) => r.status === \"rejected\");\n if (allFailed) {\n const first = attempts.find((r): r is PromiseRejectedResult => r.status === \"rejected\");\n throw first?.reason ?? new Error(\"Slack conversations.list failed for all channel types\");\n }\n return byName;\n })().catch((err) => {\n // Reset on failure so a subsequent lookup retries (e.g. once\n // `channels:read` scope is added without the agent restarting).\n channelsIndex = null;\n throw err;\n });\n return channelsIndex;\n };\n\n const ensureUsersIndex = (): Promise<Map<string, string>> => {\n if (usersIndex) return usersIndex;\n usersIndex = (async () => {\n const byHandle = new Map<string, string>();\n let cursor: string | undefined;\n do {\n const resp = (await client.users.list({\n limit: 200,\n ...(cursor ? { cursor } : {}),\n })) as unknown as {\n members?: Array<{\n id?: unknown;\n name?: unknown;\n real_name?: unknown;\n profile?: { display_name?: unknown; display_name_normalized?: unknown };\n deleted?: unknown;\n }>;\n response_metadata?: { next_cursor?: unknown };\n };\n for (const u of resp.members ?? []) {\n if (typeof u.id !== \"string\" || u.deleted === true) continue;\n // Index every name variant the agent might use. Slack handles\n // are unique, but display names + real names can collide — last\n // writer wins, which is acceptable for an LLM hint.\n for (const candidate of [\n u.name,\n u.real_name,\n u.profile?.display_name,\n u.profile?.display_name_normalized,\n ]) {\n if (typeof candidate === \"string\" && candidate.length > 0) {\n byHandle.set(candidate.toLowerCase(), u.id);\n }\n }\n if (!users.has(u.id)) {\n users.set(u.id, buildResolvedUser(u.id, u as unknown as Record<string, unknown>));\n }\n }\n cursor =\n typeof resp.response_metadata?.next_cursor === \"string\" &&\n resp.response_metadata.next_cursor.length > 0\n ? resp.response_metadata.next_cursor\n : undefined;\n } while (cursor);\n return byHandle;\n })().catch((err) => {\n usersIndex = null;\n throw err;\n });\n return usersIndex;\n };\n\n const openDmFor = async (userId: string): Promise<string> => {\n const cached = dmByUserId.get(userId);\n if (cached) return cached;\n const resp = (await client.conversations.open({ users: userId })) as unknown as {\n channel?: { id?: unknown };\n };\n const channelId = resp.channel?.id;\n if (typeof channelId !== \"string\") {\n throw new Error(`conversations.open for ${userId} returned no channel id`);\n }\n dmByUserId.set(userId, channelId);\n return channelId;\n };\n\n const resolveUserInput = async (input: string): Promise<string> => {\n const trimmed = input.trim();\n if (trimmed.length === 0) throw new Error(\"Slack user input is empty\");\n // Accept Slack's `<@U123>` mention wrapping verbatim.\n const mention = /^<@(U[A-Z0-9]+)(?:\\|[^>]+)?>$/.exec(trimmed);\n if (mention?.[1]) return mention[1];\n if (USER_ID_PATTERN.test(trimmed)) return trimmed;\n const handle = trimmed.startsWith(\"@\") ? trimmed.slice(1) : trimmed;\n if (handle.length === 0) throw new Error(\"Slack user input has no handle after '@'\");\n const index = await ensureUsersIndex();\n const id = index.get(handle.toLowerCase());\n if (!id) {\n throw new Error(\n `Slack user \"${input}\" not found. Check the handle, or ensure the bot has 'users:read' scope.`,\n );\n }\n return id;\n };\n\n const resolveChannelInput = async (input: string): Promise<string> => {\n const trimmed = input.trim();\n if (trimmed.length === 0) throw new Error(\"Slack channel input is empty\");\n // Accept Slack's `<#C123|name>` mention wrapping verbatim.\n const mention = /^<#([CGD][A-Z0-9]+)(?:\\|[^>]+)?>$/.exec(trimmed);\n if (mention?.[1]) return mention[1];\n if (CHANNEL_ID_PATTERN.test(trimmed)) return trimmed;\n if (trimmed.startsWith(\"@\")) {\n const userId = await resolveUserInput(trimmed);\n return openDmFor(userId);\n }\n const name = trimmed.startsWith(\"#\") ? trimmed.slice(1) : trimmed;\n if (name.length === 0) throw new Error(\"Slack channel input has no name after '#'\");\n const index = await ensureChannelsIndex();\n const id = index.get(name.toLowerCase());\n if (!id) {\n throw new Error(\n `Slack channel \"${input}\" not found. Check the name, or ensure the bot has 'channels:read' / 'groups:read' scope and is a member of the channel.`,\n );\n }\n return id;\n };\n\n return {\n async user(id: string): Promise<ResolvedUser> {\n const cached = users.get(id);\n if (cached) return cached;\n const pending = pendingUsers.get(id);\n if (pending) return pending;\n const fetchOne = (async (): Promise<ResolvedUser> => {\n try {\n const resp = await client.users.info({ user: id });\n const raw = (resp as unknown as { user?: Record<string, unknown> }).user;\n const info = buildResolvedUser(id, raw);\n users.set(id, info);\n return info;\n } catch {\n const info: ResolvedUser = { id };\n users.set(id, info);\n return info;\n } finally {\n pendingUsers.delete(id);\n }\n })();\n pendingUsers.set(id, fetchOne);\n return fetchOne;\n },\n async channel(id: string): Promise<ResolvedChannel> {\n const cached = channels.get(id);\n if (cached) return cached;\n const pending = pendingChannels.get(id);\n if (pending) return pending;\n const fetchOne = (async (): Promise<ResolvedChannel> => {\n try {\n const resp = await client.conversations.info({ channel: id });\n const raw = (resp as unknown as { channel?: Record<string, unknown> }).channel;\n const info = buildResolvedChannel(id, raw);\n channels.set(id, info);\n return info;\n } catch {\n const info: ResolvedChannel = { id };\n channels.set(id, info);\n return info;\n } finally {\n pendingChannels.delete(id);\n }\n })();\n pendingChannels.set(id, fetchOne);\n return fetchOne;\n },\n channelInput: resolveChannelInput,\n userInput: resolveUserInput,\n };\n}\n\nfunction buildResolvedUser(id: string, raw: Record<string, unknown> | undefined): ResolvedUser {\n if (!raw) return { id };\n const profile = (raw.profile as Record<string, unknown> | undefined) ?? undefined;\n const info: ResolvedUser = { id };\n const name = typeof raw.name === \"string\" ? raw.name : undefined;\n if (name) info.name = name;\n const realName =\n typeof raw.real_name === \"string\"\n ? raw.real_name\n : typeof profile?.real_name === \"string\"\n ? (profile.real_name as string)\n : undefined;\n if (realName) info.real_name = realName;\n const displayName =\n typeof profile?.display_name === \"string\" && (profile.display_name as string).length > 0\n ? (profile.display_name as string)\n : undefined;\n if (displayName) info.display_name = displayName;\n if (raw.is_bot === true) info.is_bot = true;\n return info;\n}\n\nfunction buildResolvedChannel(\n id: string,\n raw: Record<string, unknown> | undefined,\n): ResolvedChannel {\n if (!raw) return { id };\n const info: ResolvedChannel = { id };\n if (typeof raw.name === \"string\") info.name = raw.name;\n if (raw.is_private === true) info.is_private = true;\n if (raw.is_archived === true) info.is_archived = true;\n return info;\n}\n\nfunction displayLabel(user: ResolvedUser | undefined): string | undefined {\n return user?.display_name ?? user?.real_name ?? user?.name;\n}\n\nconst USER_MENTION = /<@(U[A-Z0-9]+)(?:\\|[^>]+)?>/g;\nconst CHANNEL_MENTION = /<#(C[A-Z0-9]+)(?:\\|([^>]+))?>/g;\n\nasync function enrichConversationResponse(\n resp: unknown,\n channelId: string,\n resolver: SlackResolver,\n): Promise<unknown> {\n if (!resp || typeof resp !== \"object\") return resp;\n const body = resp as Record<string, unknown>;\n const rawMessages = Array.isArray(body.messages) ? (body.messages as unknown[]) : [];\n const userIds = new Set<string>();\n const channelIds = new Set<string>([channelId]);\n for (const msg of rawMessages) {\n if (!msg || typeof msg !== \"object\") continue;\n const m = msg as Record<string, unknown>;\n if (typeof m.user === \"string\") userIds.add(m.user);\n if (typeof m.text === \"string\") collectMentions(m.text, userIds, channelIds);\n }\n\n const [resolvedUserList, resolvedChannelList] = await Promise.all([\n Promise.all([...userIds].map(async (id) => [id, await resolver.user(id)] as const)),\n Promise.all([...channelIds].map(async (id) => [id, await resolver.channel(id)] as const)),\n ]);\n const usersById = new Map<string, ResolvedUser>(resolvedUserList);\n const channelsById = new Map<string, ResolvedChannel>(resolvedChannelList);\n\n const enrichedMessages = rawMessages.map((msg) => {\n if (!msg || typeof msg !== \"object\") return msg;\n const m = msg as Record<string, unknown>;\n const out: Record<string, unknown> = { ...m };\n if (typeof m.user === \"string\") {\n const label = displayLabel(usersById.get(m.user));\n if (label) out.user_display_name = label;\n }\n if (typeof m.text === \"string\") {\n out.text_resolved = rewriteMentions(m.text, usersById, channelsById);\n }\n return out;\n });\n\n const resolvedUsers: Record<string, ResolvedUser> = {};\n for (const [id, info] of usersById) resolvedUsers[id] = info;\n const channelInfo = channelsById.get(channelId);\n\n return {\n ...body,\n messages: enrichedMessages,\n resolved_users: resolvedUsers,\n ...(channelInfo ? { resolved_channel: channelInfo } : {}),\n };\n}\n\nfunction collectMentions(text: string, userIds: Set<string>, channelIds: Set<string>): void {\n for (const match of text.matchAll(USER_MENTION)) {\n const id = match[1];\n if (id) userIds.add(id);\n }\n for (const match of text.matchAll(CHANNEL_MENTION)) {\n const id = match[1];\n if (id) channelIds.add(id);\n }\n}\n\nfunction rewriteMentions(\n text: string,\n users: Map<string, ResolvedUser>,\n channels: Map<string, ResolvedChannel>,\n): string {\n return text\n .replace(USER_MENTION, (_match, id: string) => {\n const label = displayLabel(users.get(id));\n return label ? `@${label}` : `<@${id}>`;\n })\n .replace(CHANNEL_MENTION, (_match, id: string, fallbackName?: string) => {\n const name = channels.get(id)?.name ?? fallbackName;\n return name ? `#${name}` : `<#${id}>`;\n });\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\n\nconst FIVE_MINUTES_SECONDS = 60 * 5;\n\nexport function verifySlackSignature(args: {\n rawBody: string;\n signingSecret: string;\n signature: string | null;\n timestamp: string | null;\n nowSeconds?: number;\n}): boolean {\n if (!args.signature?.startsWith(\"v0=\") || !args.timestamp) return false;\n const ts = Number(args.timestamp);\n if (!Number.isFinite(ts)) return false;\n const now = args.nowSeconds ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - ts) > FIVE_MINUTES_SECONDS) return false;\n\n const base = `v0:${args.timestamp}:${args.rawBody}`;\n const expected = `v0=${createHmac(\"sha256\", args.signingSecret).update(base).digest(\"hex\")}`;\n const expectedBuf = Buffer.from(expected, \"utf8\");\n const actualBuf = Buffer.from(args.signature, \"utf8\");\n if (expectedBuf.length !== actualBuf.length) return false;\n return timingSafeEqual(expectedBuf, actualBuf);\n}\n","import { createHash } from \"node:crypto\";\nimport type { LocalToolHandler } from \"@render-harness/core\";\nimport { type ConnectorContribution, definePack, type PackContext } from \"@render-harness/registry\";\nimport pkg from \"../package.json\" with { type: \"json\" };\nimport { slackConversationId } from \"./convid.js\";\nimport { normalizeSlackEvent, type SlackNormalizeConfig } from \"./normalize.js\";\nimport { type SlackAccessMode, slackTools } from \"./tools.js\";\nimport { verifySlackSignature } from \"./verify.js\";\n\ninterface SlackConfig extends SlackNormalizeConfig {\n agent?: string;\n userId?: string;\n signingSecretEnv?: string;\n botTokenEnv?: string;\n accessMode?: SlackAccessMode;\n}\n\nconst DEFAULT_SIGNING_SECRET_ENV = \"SLACK_SIGNING_SECRET\";\nconst DEFAULT_BOT_TOKEN_ENV = \"SLACK_BOT_TOKEN\";\n\nconst pack = definePack({\n name: \"cap-slack\",\n version: pkg.version,\n envSchema: [\n {\n name: DEFAULT_SIGNING_SECRET_ENV,\n required: true,\n secret: true,\n description: \"Slack signing secret used to verify Events API requests.\",\n },\n {\n name: DEFAULT_BOT_TOKEN_ENV,\n required: true,\n secret: true,\n description: \"Slack bot token used for read tools and optional write tools.\",\n },\n ],\n localTools(ctx: PackContext): LocalToolHandler[] {\n const cfg = readConfig(ctx.config);\n const botToken = ctx.env(cfg.botTokenEnv);\n if (!botToken) return [];\n return slackTools({\n botToken,\n accessMode: cfg.accessMode,\n ...(cfg.allowedChannels ? { allowedChannels: cfg.allowedChannels } : {}),\n });\n },\n connectors(ctx: PackContext): ConnectorContribution[] {\n const cfg = readConfig(ctx.config);\n return [\n {\n key: \"slack\",\n webhook: async (req, webCtx) => {\n const rawBody = await req.text();\n const signingSecret = ctx.env(cfg.signingSecretEnv);\n if (!signingSecret) {\n return json({ error: \"missing_secret\", env: cfg.signingSecretEnv }, 500);\n }\n if (\n !verifySlackSignature({\n rawBody,\n signingSecret,\n signature: req.headers.get(\"x-slack-signature\"),\n timestamp: req.headers.get(\"x-slack-request-timestamp\"),\n })\n ) {\n return json({ error: \"invalid_signature\" }, 401);\n }\n\n const parsed = parseBody(rawBody);\n const normalized = normalizeSlackEvent(parsed, cfg);\n if (normalized.kind === \"challenge\") return json({ challenge: normalized.challenge });\n if (normalized.kind === \"noop\")\n return json({ ok: true, skipped: true, reason: normalized.reason });\n\n const agent = webCtx.resolveAgent(cfg.agent);\n const conversationId = slackConversationId({\n teamId: normalized.teamId,\n channel: normalized.channel,\n threadTs: normalized.threadTs,\n });\n const result = await webCtx.enqueueIntoConversation({\n conversationId,\n agentName: agent.name,\n agentVersion: agent.version,\n userId: cfg.userId ?? \"cap-slack\",\n runId: `slack-${hash(normalized.eventId)}`,\n title: `Slack ${normalized.channel}/${normalized.threadTs}`,\n initialContent: [{ type: \"text\", text: normalized.text }],\n metadata: {\n connector: \"cap-slack\",\n teamId: normalized.teamId,\n channel: normalized.channel,\n threadTs: normalized.threadTs,\n ts: normalized.ts,\n ...(normalized.userId ? { userId: normalized.userId } : {}),\n },\n });\n return json(result, result.status === \"enqueued\" ? 202 : 200);\n },\n },\n ];\n },\n});\n\nexport default pack;\n\ntype ResolvedSlackConfig = Required<\n Pick<SlackConfig, \"signingSecretEnv\" | \"botTokenEnv\" | \"accessMode\" | \"includeEdits\">\n> &\n Omit<SlackConfig, \"signingSecretEnv\" | \"botTokenEnv\" | \"accessMode\" | \"includeEdits\">;\n\nfunction readConfig(raw: Record<string, unknown>): ResolvedSlackConfig {\n const cfg: ResolvedSlackConfig = {\n signingSecretEnv: stringValue(raw.signingSecretEnv) ?? DEFAULT_SIGNING_SECRET_ENV,\n botTokenEnv: stringValue(raw.botTokenEnv) ?? DEFAULT_BOT_TOKEN_ENV,\n accessMode: raw.accessMode === \"read_write\" ? \"read_write\" : \"read\",\n includeEdits: raw.includeEdits === true,\n };\n const agent = stringValue(raw.agent);\n if (agent) cfg.agent = agent;\n const userId = stringValue(raw.userId);\n if (userId) cfg.userId = userId;\n const allowedChannels = stringArray(raw.allowedChannels);\n if (allowedChannels) cfg.allowedChannels = allowedChannels;\n return cfg;\n}\n\nfunction parseBody(rawBody: string): unknown {\n try {\n return JSON.parse(rawBody);\n } catch {\n return null;\n }\n}\n\nfunction hash(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 32);\n}\n\nfunction json(body: unknown, status = 200): Response {\n return Response.json(body, { status });\n}\n\nfunction stringValue(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction stringArray(value: unknown): string[] | undefined {\n return Array.isArray(value)\n ? value.filter((item): item is string => typeof item === \"string\")\n : undefined;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@render-harness/cap-slack",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Slack Events and Web API capability pack for the Render agent harness.",
5
5
  "type": "module",
6
6
  "license": "MIT",