@render-harness/cap-slack 0.5.0 → 0.5.1
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/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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.
|
|
9
|
+
version: "0.5.1"};
|
|
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}`;
|
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.0\",\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":";;;;;;;AAAA,IAAA,eAAA,GAAA;AAAA,EAEE,OAAA,EAAW,OAmDb,CAAA;ACnDO,SAAS,oBAAoB,IAAA,EAIzB;AACT,EAAA,MAAM,MAAA,GAAS,WAAW,QAAQ,CAAA,CAC/B,OAAO,CAAA,EAAG,IAAA,CAAK,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,OAAO,CAAA,CAAA,EAAI,IAAA,CAAK,QAAQ,CAAA,CAAE,CAAA,CACxD,OAAO,KAAK,CAAA,CACZ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AACd,EAAA,OAAO,SAAS,MAAM,CAAA,CAAA;AACxB;;;ACOO,SAAS,mBAAA,CACd,IAAA,EACA,GAAA,GAA4B,EAAC,EACP;AACtB,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,SAAiB,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,cAAA,EAAe;AACrF,EAAA,MAAM,OAAA,GAAU,IAAA;AAChB,EAAA,IAAI,OAAA,CAAQ,SAAS,kBAAA,EAAoB;AACvC,IAAA,MAAM,SAAA,GAAY,WAAA,CAAY,OAAA,CAAQ,SAAS,CAAA;AAC/C,IAAA,OAAO,SAAA,GACH,EAAE,IAAA,EAAM,WAAA,EAAa,SAAA,KACrB,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,mBAAA,EAAoB;AAAA,EAClD;AACA,EAAA,IAAI,OAAA,CAAQ,SAAS,gBAAA,EAAkB,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAQ,kBAAA,EAAmB;AAEzF,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,OAAA,CAAQ,KAAK,CAAA;AACvC,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAQ,eAAA,EAAgB;AAC3D,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,KAAA,CAAM,IAAI,CAAA;AACxC,EAAA,IAAI,SAAA,KAAc,aAAA,IAAiB,SAAA,KAAc,SAAA,EAAW;AAC1D,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,mBAAA,EAAoB;AAAA,EACrD;AACA,EAAA,IAAI,KAAA,CAAM,MAAA,IAAU,KAAA,CAAM,OAAA,KAAY,aAAA;AACpC,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,aAAA,EAAc;AAC/C,EAAA,IAAI,KAAA,CAAM,OAAA,KAAY,iBAAA,IAAqB,CAAC,IAAI,YAAA,EAAc;AAC5D,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,cAAA,EAAe;AAAA,EAChD;AAEA,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,KAAA,CAAM,OAAO,CAAA;AACzC,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAQ,iBAAA,EAAkB;AAC/D,EAAA,IAAI,GAAA,CAAI,iBAAiB,MAAA,IAAU,CAAC,IAAI,eAAA,CAAgB,QAAA,CAAS,OAAO,CAAA,EAAG;AACzE,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,qBAAA,EAAsB;AAAA,EACvD;AAEA,EAAA,MAAM,SAAS,WAAA,CAAY,OAAA,CAAQ,OAAO,CAAA,IAAK,WAAA,CAAY,MAAM,IAAI,CAAA;AACrE,EAAA,MAAM,EAAA,GAAK,WAAA,CAAY,KAAA,CAAM,EAAE,CAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,KAAA,CAAM,IAAI,CAAA,IAAK,EAAA;AACxC,EAAA,MAAM,OAAA,GACJ,WAAA,CAAY,OAAA,CAAQ,QAAQ,CAAA,IAAK,CAAA,EAAG,MAAA,IAAU,MAAM,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,EAAI,EAAA,IAAM,OAAO,CAAA,CAAA;AAClF,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,EAAA,IAAM,KAAK,IAAA,EAAK,CAAE,MAAA,KAAW,CAAA,EAAG,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,QAAQ,gBAAA,EAAiB;AAChG,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,KAAA,CAAM,IAAI,CAAA;AAErC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,SAAA;AAAA,IACN,IAAA;AAAA,IACA,MAAA;AAAA,IACA,OAAA;AAAA,IACA,EAAA;AAAA,IACA,QAAA,EAAU,WAAA,CAAY,KAAA,CAAM,SAAS,CAAA,IAAK,EAAA;AAAA,IAC1C,OAAA;AAAA,IACA,GAAI,MAAA,GAAS,EAAE,MAAA,KAAW;AAAC,GAC7B;AACF;AAEA,SAAS,YAAY,KAAA,EAAgD;AACnE,EAAA,OAAO,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GAC5D,KAAA,GACD,IAAA;AACN;AAEA,SAAS,YAAY,KAAA,EAAoC;AACvD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,MAAA,GAAS,IAAI,KAAA,GAAQ,MAAA;AACjE;ACrEA,IAAM,wBAAA,GAA2B,IAAA;AACjC,IAAM,oBAAA,GAAqC;AAAA,EACzC,OAAA,EAAS,CAAA;AAAA,EACT,MAAA,EAAQ,CAAA;AAAA,EACR,UAAA,EAAY,GAAA;AAAA,EACZ,UAAA,EAAY;AACd,CAAA;AA2CA,IAAM,kBAAA,GAAqB,qBAAA;AAC3B,IAAM,eAAA,GAAkB,iBAAA;AAEjB,SAAS,WAAW,IAAA,EAIJ;AACrB,EAAA,MAAM,MAAA,GAAS,IAAI,SAAA,CAAU,IAAA,CAAK,QAAA,EAAU;AAAA,IAC1C,OAAA,EAAS,wBAAA;AAAA,IACT,WAAA,EAAa;AAAA,GACd,CAAA;AACD,EAAA,MAAM,QAAA,GAAW,eAAe,MAAM,CAAA;AAEtC,EAAA,MAAM,KAAA,GAA4B;AAAA,IAChC,QAAA;AAAA,MACE,kBAAA;AAAA,MACA,kOAAA;AAAA,MACA,YAAA,CAAa;AAAA,QACX,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,QAC1B,SAAA,EAAW,EAAE,IAAA,EAAM,QAAA;AAAS,OAC7B,CAAA;AAAA,MACD,OAAO,KAAA,KAAU;AACf,QAAA,MAAM,EAAE,OAAA,EAAS,SAAA,EAAU,GAAI,KAAA;AAC/B,QAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA;AACrD,QAAA,oBAAA,CAAqB,SAAA,EAAW,KAAK,eAAe,CAAA;AACpD,QAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,aAAA,CAAc,OAAA,CAAQ,EAAE,OAAA,EAAS,SAAA,EAAW,EAAA,EAAI,SAAA,EAAW,CAAA;AACrF,QAAA,OAAO,0BAAA,CAA2B,IAAA,EAAM,SAAA,EAAW,QAAQ,CAAA;AAAA,MAC7D;AAAA,KACF;AAAA,IACA,QAAA;AAAA,MACE,2BAAA;AAAA,MACA,sOAAA;AAAA,MACA,YAAA,CAAa;AAAA,QACX,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,QAC1B,KAAA,EAAO,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,IAAA;AAAK,OACzC,CAAA;AAAA,MACD,OAAO,KAAA,KAAU;AACf,QAAA,MAAM,EAAE,OAAA,EAAS,KAAA,EAAM,GAAI,KAAA;AAC3B,QAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA;AACrD,QAAA,oBAAA,CAAqB,SAAA,EAAW,KAAK,eAAe,CAAA;AACpD,QAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,aAAA,CAAc,OAAA,CAAQ;AAAA,UAC9C,OAAA,EAAS,SAAA;AAAA,UACT,OAAO,KAAA,IAAS;AAAA,SACjB,CAAA;AACD,QAAA,OAAO,0BAAA,CAA2B,IAAA,EAAM,SAAA,EAAW,QAAQ,CAAA;AAAA,MAC7D;AAAA,KACF;AAAA,IACA,QAAA;AAAA,MACE,qBAAA;AAAA,MACA,+HAAA;AAAA,MACA,YAAA,CAAa;AAAA,QACX,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA;AAAS,OACxB,CAAA;AAAA,MACD,OAAO,KAAA,KAAU;AACf,QAAA,MAAM,EAAE,MAAK,GAAI,KAAA;AACjB,QAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,SAAA,CAAU,IAAI,CAAA;AAC5C,QAAA,OAAO,QAAA,CAAS,KAAK,MAAM,CAAA;AAAA,MAC7B;AAAA,KACF;AAAA,IACA,QAAA;AAAA,MACE,wBAAA;AAAA,MACA,yIAAA;AAAA,MACA,YAAA,CAAa;AAAA,QACX,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA;AAAS,OAC3B,CAAA;AAAA,MACD,OAAO,KAAA,KAAU;AACf,QAAA,MAAM,EAAE,SAAQ,GAAI,KAAA;AACpB,QAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA;AACrD,QAAA,oBAAA,CAAqB,SAAA,EAAW,KAAK,eAAe,CAAA;AACpD,QAAA,OAAO,QAAA,CAAS,QAAQ,SAAS,CAAA;AAAA,MACnC;AAAA;AACF,GACF;AAEA,EAAA,IAAI,IAAA,CAAK,eAAe,YAAA,EAAc;AACpC,IAAA,KAAA,CAAM,IAAA;AAAA,MACJ,QAAA;AAAA,QACE,oBAAA;AAAA,QACA,mKAAA;AAAA,QACA,YAAA,CAAa;AAAA,UACX,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,UAC1B,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,UACvB,SAAA,EAAW,EAAE,IAAA,EAAM,QAAA,EAAU,UAAU,IAAA;AAAK,SAC7C,CAAA;AAAA,QACD,OAAO,KAAA,KAAU;AACf,UAAA,MAAM,EAAE,OAAA,EAAS,IAAA,EAAM,SAAA,EAAU,GAAI,KAAA;AAKrC,UAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA;AACrD,UAAA,oBAAA,CAAqB,SAAA,EAAW,KAAK,eAAe,CAAA;AACpD,UAAA,OAAO,MAAA,CAAO,KAAK,WAAA,CAAY;AAAA,YAC7B,OAAA,EAAS,SAAA;AAAA,YACT,IAAA;AAAA,YACA,GAAI,SAAA,GAAY,EAAE,SAAA,KAAc;AAAC,WAClC,CAAA;AAAA,QACH;AAAA,OACF;AAAA,MACA,QAAA;AAAA,QACE,oBAAA;AAAA,QACA,2GAAA;AAAA,QACA,YAAA,CAAa;AAAA,UACX,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,UAC1B,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,UACrB,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA;AAAS,SACxB,CAAA;AAAA,QACD,OAAO,KAAA,KAAU;AACf,UAAA,MAAM,EAAE,OAAA,EAAS,EAAA,EAAI,IAAA,EAAK,GAAI,KAAA;AAC9B,UAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA;AACrD,UAAA,oBAAA,CAAqB,SAAA,EAAW,KAAK,eAAe,CAAA;AACpD,UAAA,OAAO,MAAA,CAAO,UAAU,GAAA,CAAI,EAAE,SAAS,SAAA,EAAW,SAAA,EAAW,EAAA,EAAI,IAAA,EAAM,CAAA;AAAA,QACzE;AAAA,OACF;AAAA,MACA,QAAA;AAAA,QACE,sBAAA;AAAA,QACA,gGAAA;AAAA,QACA,YAAA,CAAa;AAAA,UACX,OAAA,EAAS,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,UAC1B,EAAA,EAAI,EAAE,IAAA,EAAM,QAAA,EAAS;AAAA,UACrB,IAAA,EAAM,EAAE,IAAA,EAAM,QAAA;AAAS,SACxB,CAAA;AAAA,QACD,OAAO,KAAA,KAAU;AACf,UAAA,MAAM,EAAE,OAAA,EAAS,EAAA,EAAI,IAAA,EAAK,GAAI,KAAA;AAC9B,UAAA,MAAM,SAAA,GAAY,MAAM,QAAA,CAAS,YAAA,CAAa,OAAO,CAAA;AACrD,UAAA,oBAAA,CAAqB,SAAA,EAAW,KAAK,eAAe,CAAA;AACpD,UAAA,OAAO,MAAA,CAAO,KAAK,MAAA,CAAO,EAAE,SAAS,SAAA,EAAW,EAAA,EAAI,MAAM,CAAA;AAAA,QAC5D;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,QAAA,CACP,IAAA,EACA,WAAA,EACA,WAAA,EACA,IAAA,EACkB;AAClB,EAAA,OAAO;AAAA,IACL,YAAY,EAAE,IAAA,EAAM,WAAA,EAAa,WAAA,EAAa,QAAQ,gBAAA,EAAiB;AAAA,IACvE,OAAA,EAAS,OAAO,EAAE,KAAA,EAAM,KAAM;AAC5B,MAAA,IAAI;AACF,QAAA,OAAO,EAAE,OAAA,EAAS,IAAA,CAAK,SAAA,CAAU,MAAM,KAAK,KAAK,CAAA,EAAG,IAAA,EAAM,CAAC,CAAA,EAAE;AAAA,MAC/D,SAAS,GAAA,EAAK;AACZ,QAAA,OAAO,EAAE,OAAA,EAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,UAAU,MAAA,CAAO,GAAG,CAAA,EAAG,OAAA,EAAS,IAAA,EAAK;AAAA,MACpF;AAAA,IACF;AAAA,GACF;AACF;AAEA,SAAS,oBAAA,CAAqB,SAAiB,eAAA,EAA6C;AAC1F,EAAA,IAAI,iBAAiB,MAAA,IAAU,CAAC,eAAA,CAAgB,QAAA,CAAS,OAAO,CAAA,EAAG;AACjE,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,OAAO,CAAA,oCAAA,CAAsC,CAAA;AAAA,EACjF;AACF;AAEA,SAAS,aAAa,UAAA,EAAqC;AACzD,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,oBAAA,EAAsB,KAAA;AAAA,IACtB,UAAA;AAAA,IACA,QAAA,EAAU,OAAO,OAAA,CAAQ,UAAU,EAChC,MAAA,CAAO,CAAC,GAAG,KAAK,MAAM,CAAE,KAAA,CAAiC,QAAQ,CAAA,CACjE,GAAA,CAAI,CAAC,CAAC,GAAG,MAAM,GAAG;AAAA,GACvB;AACF;AAEA,SAAS,eAAe,MAAA,EAAkC;AACxD,EAAA,MAAM,KAAA,uBAAY,GAAA,EAA0B;AAC5C,EAAA,MAAM,QAAA,uBAAe,GAAA,EAA6B;AAClD,EAAA,MAAM,YAAA,uBAAmB,GAAA,EAAmC;AAC5D,EAAA,MAAM,eAAA,uBAAsB,GAAA,EAAsC;AAQlE,EAAA,IAAI,aAAA,GAAqD,IAAA;AACzD,EAAA,IAAI,UAAA,GAAkD,IAAA;AACtD,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAoB;AAE3C,EAAA,MAAM,sBAAsB,MAAoC;AAC9D,IAAA,IAAI,eAAe,OAAO,aAAA;AAC1B,IAAA,aAAA,GAAA,CAAiB,YAAY;AAC3B,MAAA,MAAM,MAAA,uBAAa,GAAA,EAAoB;AACvC,MAAA,IAAI,MAAA;AACJ,MAAA,GAAG;AACD,QAAA,MAAM,IAAA,GAAQ,MAAM,MAAA,CAAO,aAAA,CAAc,IAAA,CAAK;AAAA,UAC5C,KAAA,EAAO,GAAA;AAAA,UACP,KAAA,EAAO,gCAAA;AAAA,UACP,gBAAA,EAAkB,IAAA;AAAA,UAClB,GAAI,MAAA,GAAS,EAAE,MAAA,KAAW;AAAC,SAC5B,CAAA;AAID,QAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,QAAA,IAAY,EAAC,EAAG;AACnC,UAAA,IAAI,OAAO,CAAA,CAAE,EAAA,KAAO,YAAY,OAAO,CAAA,CAAE,SAAS,QAAA,EAAU;AAC1D,YAAA,MAAA,CAAO,IAAI,CAAA,CAAE,IAAA,CAAK,WAAA,EAAY,EAAG,EAAE,EAAE,CAAA;AAGrC,YAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,EAAE,GAAG,QAAA,CAAS,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,EAAE,EAAA,EAAI,CAAA,CAAE,IAAI,IAAA,EAAM,CAAA,CAAE,MAAM,CAAA;AAAA,UACxE;AAAA,QACF;AACA,QAAA,MAAA,GACE,OAAO,IAAA,CAAK,iBAAA,EAAmB,WAAA,KAAgB,QAAA,IAC/C,IAAA,CAAK,iBAAA,CAAkB,WAAA,CAAY,MAAA,GAAS,CAAA,GACxC,IAAA,CAAK,iBAAA,CAAkB,WAAA,GACvB,MAAA;AAAA,MACR,CAAA,QAAS,MAAA;AACT,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,GAAG,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAGlB,MAAA,aAAA,GAAgB,IAAA;AAChB,MAAA,MAAM,GAAA;AAAA,IACR,CAAC,CAAA;AACD,IAAA,OAAO,aAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,mBAAmB,MAAoC;AAC3D,IAAA,IAAI,YAAY,OAAO,UAAA;AACvB,IAAA,UAAA,GAAA,CAAc,YAAY;AACxB,MAAA,MAAM,QAAA,uBAAe,GAAA,EAAoB;AACzC,MAAA,IAAI,MAAA;AACJ,MAAA,GAAG;AACD,QAAA,MAAM,IAAA,GAAQ,MAAM,MAAA,CAAO,KAAA,CAAM,IAAA,CAAK;AAAA,UACpC,KAAA,EAAO,GAAA;AAAA,UACP,GAAI,MAAA,GAAS,EAAE,MAAA,KAAW;AAAC,SAC5B,CAAA;AAUD,QAAA,KAAA,MAAW,CAAA,IAAK,IAAA,CAAK,OAAA,IAAW,EAAC,EAAG;AAClC,UAAA,IAAI,OAAO,CAAA,CAAE,EAAA,KAAO,QAAA,IAAY,CAAA,CAAE,YAAY,IAAA,EAAM;AAIpD,UAAA,KAAA,MAAW,SAAA,IAAa;AAAA,YACtB,CAAA,CAAE,IAAA;AAAA,YACF,CAAA,CAAE,SAAA;AAAA,YACF,EAAE,OAAA,EAAS,YAAA;AAAA,YACX,EAAE,OAAA,EAAS;AAAA,WACb,EAAG;AACD,YAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,CAAU,SAAS,CAAA,EAAG;AACzD,cAAA,QAAA,CAAS,GAAA,CAAI,SAAA,CAAU,WAAA,EAAY,EAAG,EAAE,EAAE,CAAA;AAAA,YAC5C;AAAA,UACF;AACA,UAAA,IAAI,CAAC,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA,EAAG;AACpB,YAAA,KAAA,CAAM,IAAI,CAAA,CAAE,EAAA,EAAI,kBAAkB,CAAA,CAAE,EAAA,EAAI,CAAuC,CAAC,CAAA;AAAA,UAClF;AAAA,QACF;AACA,QAAA,MAAA,GACE,OAAO,IAAA,CAAK,iBAAA,EAAmB,WAAA,KAAgB,QAAA,IAC/C,IAAA,CAAK,iBAAA,CAAkB,WAAA,CAAY,MAAA,GAAS,CAAA,GACxC,IAAA,CAAK,iBAAA,CAAkB,WAAA,GACvB,MAAA;AAAA,MACR,CAAA,QAAS,MAAA;AACT,MAAA,OAAO,QAAA;AAAA,IACT,CAAA,GAAG,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAClB,MAAA,UAAA,GAAa,IAAA;AACb,MAAA,MAAM,GAAA;AAAA,IACR,CAAC,CAAA;AACD,IAAA,OAAO,UAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,OAAO,MAAA,KAAoC;AAC3D,IAAA,MAAM,MAAA,GAAS,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AACpC,IAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,IAAA,MAAM,IAAA,GAAQ,MAAM,MAAA,CAAO,aAAA,CAAc,KAAK,EAAE,KAAA,EAAO,QAAQ,CAAA;AAG/D,IAAA,MAAM,SAAA,GAAY,KAAK,OAAA,EAAS,EAAA;AAChC,IAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uBAAA,EAA0B,MAAM,CAAA,uBAAA,CAAyB,CAAA;AAAA,IAC3E;AACA,IAAA,UAAA,CAAW,GAAA,CAAI,QAAQ,SAAS,CAAA;AAChC,IAAA,OAAO,SAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAO,KAAA,KAAmC;AACjE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,QAAQ,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,2BAA2B,CAAA;AAErE,IAAA,MAAM,OAAA,GAAU,+BAAA,CAAgC,IAAA,CAAK,OAAO,CAAA;AAC5D,IAAA,IAAI,OAAA,GAAU,CAAC,CAAA,EAAG,OAAO,QAAQ,CAAC,CAAA;AAClC,IAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,OAAO,CAAA,EAAG,OAAO,OAAA;AAC1C,IAAA,MAAM,MAAA,GAAS,QAAQ,UAAA,CAAW,GAAG,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,OAAA;AAC5D,IAAA,IAAI,OAAO,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,0CAA0C,CAAA;AACnF,IAAA,MAAM,KAAA,GAAQ,MAAM,gBAAA,EAAiB;AACrC,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,GAAA,CAAI,MAAA,CAAO,aAAa,CAAA;AACzC,IAAA,IAAI,CAAC,EAAA,EAAI;AACP,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,eAAe,KAAK,CAAA,wEAAA;AAAA,OACtB;AAAA,IACF;AACA,IAAA,OAAO,EAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,mBAAA,GAAsB,OAAO,KAAA,KAAmC;AACpE,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,QAAQ,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAExE,IAAA,MAAM,OAAA,GAAU,mCAAA,CAAoC,IAAA,CAAK,OAAO,CAAA;AAChE,IAAA,IAAI,OAAA,GAAU,CAAC,CAAA,EAAG,OAAO,QAAQ,CAAC,CAAA;AAClC,IAAA,IAAI,kBAAA,CAAmB,IAAA,CAAK,OAAO,CAAA,EAAG,OAAO,OAAA;AAC7C,IAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAG;AAC3B,MAAA,MAAM,MAAA,GAAS,MAAM,gBAAA,CAAiB,OAAO,CAAA;AAC7C,MAAA,OAAO,UAAU,MAAM,CAAA;AAAA,IACzB;AACA,IAAA,MAAM,IAAA,GAAO,QAAQ,UAAA,CAAW,GAAG,IAAI,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA,GAAI,OAAA;AAC1D,IAAA,IAAI,KAAK,MAAA,KAAW,CAAA,EAAG,MAAM,IAAI,MAAM,2CAA2C,CAAA;AAClF,IAAA,MAAM,KAAA,GAAQ,MAAM,mBAAA,EAAoB;AACxC,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,GAAA,CAAI,IAAA,CAAK,aAAa,CAAA;AACvC,IAAA,IAAI,CAAC,EAAA,EAAI;AACP,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,kBAAkB,KAAK,CAAA,wHAAA;AAAA,OACzB;AAAA,IACF;AACA,IAAA,OAAO,EAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,KAAK,EAAA,EAAmC;AAC5C,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,GAAA,CAAI,EAAE,CAAA;AAC3B,MAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,MAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,EAAE,CAAA;AACnC,MAAA,IAAI,SAAS,OAAO,OAAA;AACpB,MAAA,MAAM,YAAY,YAAmC;AACnD,QAAA,IAAI;AACF,UAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,IAAI,CAAA;AACjD,UAAA,MAAM,MAAO,IAAA,CAAuD,IAAA;AACpE,UAAA,MAAM,IAAA,GAAO,iBAAA,CAAkB,EAAA,EAAI,GAAG,CAAA;AACtC,UAAA,KAAA,CAAM,GAAA,CAAI,IAAI,IAAI,CAAA;AAClB,UAAA,OAAO,IAAA;AAAA,QACT,CAAA,CAAA,MAAQ;AACN,UAAA,MAAM,IAAA,GAAqB,EAAE,EAAA,EAAG;AAChC,UAAA,KAAA,CAAM,GAAA,CAAI,IAAI,IAAI,CAAA;AAClB,UAAA,OAAO,IAAA;AAAA,QACT,CAAA,SAAE;AACA,UAAA,YAAA,CAAa,OAAO,EAAE,CAAA;AAAA,QACxB;AAAA,MACF,CAAA,GAAG;AACH,MAAA,YAAA,CAAa,GAAA,CAAI,IAAI,QAAQ,CAAA;AAC7B,MAAA,OAAO,QAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,QAAQ,EAAA,EAAsC;AAClD,MAAA,MAAM,MAAA,GAAS,QAAA,CAAS,GAAA,CAAI,EAAE,CAAA;AAC9B,MAAA,IAAI,QAAQ,OAAO,MAAA;AACnB,MAAA,MAAM,OAAA,GAAU,eAAA,CAAgB,GAAA,CAAI,EAAE,CAAA;AACtC,MAAA,IAAI,SAAS,OAAO,OAAA;AACpB,MAAA,MAAM,YAAY,YAAsC;AACtD,QAAA,IAAI;AACF,UAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,aAAA,CAAc,KAAK,EAAE,OAAA,EAAS,IAAI,CAAA;AAC5D,UAAA,MAAM,MAAO,IAAA,CAA0D,OAAA;AACvE,UAAA,MAAM,IAAA,GAAO,oBAAA,CAAqB,EAAA,EAAI,GAAG,CAAA;AACzC,UAAA,QAAA,CAAS,GAAA,CAAI,IAAI,IAAI,CAAA;AACrB,UAAA,OAAO,IAAA;AAAA,QACT,CAAA,CAAA,MAAQ;AACN,UAAA,MAAM,IAAA,GAAwB,EAAE,EAAA,EAAG;AACnC,UAAA,QAAA,CAAS,GAAA,CAAI,IAAI,IAAI,CAAA;AACrB,UAAA,OAAO,IAAA;AAAA,QACT,CAAA,SAAE;AACA,UAAA,eAAA,CAAgB,OAAO,EAAE,CAAA;AAAA,QAC3B;AAAA,MACF,CAAA,GAAG;AACH,MAAA,eAAA,CAAgB,GAAA,CAAI,IAAI,QAAQ,CAAA;AAChC,MAAA,OAAO,QAAA;AAAA,IACT,CAAA;AAAA,IACA,YAAA,EAAc,mBAAA;AAAA,IACd,SAAA,EAAW;AAAA,GACb;AACF;AAEA,SAAS,iBAAA,CAAkB,IAAY,GAAA,EAAwD;AAC7F,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAE,EAAA,EAAG;AACtB,EAAA,MAAM,OAAA,GAAW,IAAI,OAAA,IAAmD,MAAA;AACxE,EAAA,MAAM,IAAA,GAAqB,EAAE,EAAA,EAAG;AAChC,EAAA,MAAM,OAAO,OAAO,GAAA,CAAI,IAAA,KAAS,QAAA,GAAW,IAAI,IAAA,GAAO,MAAA;AACvD,EAAA,IAAI,IAAA,OAAW,IAAA,GAAO,IAAA;AACtB,EAAA,MAAM,QAAA,GACJ,OAAO,GAAA,CAAI,SAAA,KAAc,QAAA,GACrB,GAAA,CAAI,SAAA,GACJ,OAAO,OAAA,EAAS,SAAA,KAAc,QAAA,GAC3B,OAAA,CAAQ,SAAA,GACT,MAAA;AACR,EAAA,IAAI,QAAA,OAAe,SAAA,GAAY,QAAA;AAC/B,EAAA,MAAM,WAAA,GACJ,OAAO,OAAA,EAAS,YAAA,KAAiB,QAAA,IAAa,QAAQ,YAAA,CAAwB,MAAA,GAAS,CAAA,GAClF,OAAA,CAAQ,YAAA,GACT,MAAA;AACN,EAAA,IAAI,WAAA,OAAkB,YAAA,GAAe,WAAA;AACrC,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,IAAA,EAAM,IAAA,CAAK,MAAA,GAAS,IAAA;AACvC,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,oBAAA,CACP,IACA,GAAA,EACiB;AACjB,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAE,EAAA,EAAG;AACtB,EAAA,MAAM,IAAA,GAAwB,EAAE,EAAA,EAAG;AACnC,EAAA,IAAI,OAAO,GAAA,CAAI,IAAA,KAAS,QAAA,EAAU,IAAA,CAAK,OAAO,GAAA,CAAI,IAAA;AAClD,EAAA,IAAI,GAAA,CAAI,UAAA,KAAe,IAAA,EAAM,IAAA,CAAK,UAAA,GAAa,IAAA;AAC/C,EAAA,IAAI,GAAA,CAAI,WAAA,KAAgB,IAAA,EAAM,IAAA,CAAK,WAAA,GAAc,IAAA;AACjD,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,aAAa,IAAA,EAAoD;AACxE,EAAA,OAAO,IAAA,EAAM,YAAA,IAAgB,IAAA,EAAM,SAAA,IAAa,IAAA,EAAM,IAAA;AACxD;AAEA,IAAM,YAAA,GAAe,8BAAA;AACrB,IAAM,eAAA,GAAkB,gCAAA;AAExB,eAAe,0BAAA,CACb,IAAA,EACA,SAAA,EACA,QAAA,EACkB;AAClB,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAC9C,EAAA,MAAM,IAAA,GAAO,IAAA;AACb,EAAA,MAAM,WAAA,GAAc,MAAM,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,GAAK,IAAA,CAAK,WAAyB,EAAC;AACnF,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,MAAM,UAAA,mBAAa,IAAI,GAAA,CAAY,CAAC,SAAS,CAAC,CAAA;AAC9C,EAAA,KAAA,MAAW,OAAO,WAAA,EAAa;AAC7B,IAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,EAAU;AACrC,IAAA,MAAM,CAAA,GAAI,GAAA;AACV,IAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,UAAU,OAAA,CAAQ,GAAA,CAAI,EAAE,IAAI,CAAA;AAClD,IAAA,IAAI,OAAO,EAAE,IAAA,KAAS,QAAA,kBAA0B,CAAA,CAAE,IAAA,EAAM,SAAS,UAAU,CAAA;AAAA,EAC7E;AAEA,EAAA,MAAM,CAAC,gBAAA,EAAkB,mBAAmB,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,IAChE,QAAQ,GAAA,CAAI,CAAC,GAAG,OAAO,EAAE,GAAA,CAAI,OAAO,EAAA,KAAO,CAAC,IAAI,MAAM,QAAA,CAAS,KAAK,EAAE,CAAC,CAAU,CAAC,CAAA;AAAA,IAClF,QAAQ,GAAA,CAAI,CAAC,GAAG,UAAU,EAAE,GAAA,CAAI,OAAO,EAAA,KAAO,CAAC,IAAI,MAAM,QAAA,CAAS,QAAQ,EAAE,CAAC,CAAU,CAAC;AAAA,GACzF,CAAA;AACD,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAA0B,gBAAgB,CAAA;AAChE,EAAA,MAAM,YAAA,GAAe,IAAI,GAAA,CAA6B,mBAAmB,CAAA;AAEzE,EAAA,MAAM,gBAAA,GAAmB,WAAA,CAAY,GAAA,CAAI,CAAC,GAAA,KAAQ;AAChD,IAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,GAAA;AAC5C,IAAA,MAAM,CAAA,GAAI,GAAA;AACV,IAAA,MAAM,GAAA,GAA+B,EAAE,GAAG,CAAA,EAAE;AAC5C,IAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,EAAU;AAC9B,MAAA,MAAM,QAAQ,YAAA,CAAa,SAAA,CAAU,GAAA,CAAI,CAAA,CAAE,IAAI,CAAC,CAAA;AAChD,MAAA,IAAI,KAAA,MAAW,iBAAA,GAAoB,KAAA;AAAA,IACrC;AACA,IAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,QAAA,EAAU;AAC9B,MAAA,GAAA,CAAI,aAAA,GAAgB,eAAA,CAAgB,CAAA,CAAE,IAAA,EAAM,WAAW,YAAY,CAAA;AAAA,IACrE;AACA,IAAA,OAAO,GAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,MAAM,gBAA8C,EAAC;AACrD,EAAA,KAAA,MAAW,CAAC,EAAA,EAAI,IAAI,KAAK,SAAA,EAAW,aAAA,CAAc,EAAE,CAAA,GAAI,IAAA;AACxD,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,GAAA,CAAI,SAAS,CAAA;AAE9C,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,QAAA,EAAU,gBAAA;AAAA,IACV,cAAA,EAAgB,aAAA;AAAA,IAChB,GAAI,WAAA,GAAc,EAAE,gBAAA,EAAkB,WAAA,KAAgB;AAAC,GACzD;AACF;AAEA,SAAS,eAAA,CAAgB,IAAA,EAAc,OAAA,EAAsB,UAAA,EAA+B;AAC1F,EAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,QAAA,CAAS,YAAY,CAAA,EAAG;AAC/C,IAAA,MAAM,EAAA,GAAK,MAAM,CAAC,CAAA;AAClB,IAAA,IAAI,EAAA,EAAI,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AAAA,EACxB;AACA,EAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,QAAA,CAAS,eAAe,CAAA,EAAG;AAClD,IAAA,MAAM,EAAA,GAAK,MAAM,CAAC,CAAA;AAClB,IAAA,IAAI,EAAA,EAAI,UAAA,CAAW,GAAA,CAAI,EAAE,CAAA;AAAA,EAC3B;AACF;AAEA,SAAS,eAAA,CACP,IAAA,EACA,KAAA,EACA,QAAA,EACQ;AACR,EAAA,OAAO,IAAA,CACJ,OAAA,CAAQ,YAAA,EAAc,CAAC,QAAQ,EAAA,KAAe;AAC7C,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,KAAA,CAAM,GAAA,CAAI,EAAE,CAAC,CAAA;AACxC,IAAA,OAAO,KAAA,GAAQ,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,GAAK,KAAK,EAAE,CAAA,CAAA,CAAA;AAAA,EACtC,CAAC,CAAA,CACA,OAAA,CAAQ,iBAAiB,CAAC,MAAA,EAAQ,IAAY,YAAA,KAA0B;AACvE,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,EAAE,GAAG,IAAA,IAAQ,YAAA;AACvC,IAAA,OAAO,IAAA,GAAO,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,GAAK,KAAK,EAAE,CAAA,CAAA,CAAA;AAAA,EACpC,CAAC,CAAA;AACL;AC/iBA,IAAM,uBAAuB,EAAA,GAAK,CAAA;AAE3B,SAAS,qBAAqB,IAAA,EAMzB;AACV,EAAA,IAAI,CAAC,KAAK,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA,IAAK,CAAC,IAAA,CAAK,SAAA,EAAW,OAAO,KAAA;AAClE,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,IAAA,CAAK,SAAS,CAAA;AAChC,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,GAAG,OAAO,KAAA;AACjC,EAAA,MAAM,GAAA,GAAM,KAAK,UAAA,IAAc,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,KAAQ,GAAI,CAAA;AAC3D,EAAA,IAAI,KAAK,GAAA,CAAI,GAAA,GAAM,EAAE,CAAA,GAAI,sBAAsB,OAAO,KAAA;AAEtD,EAAA,MAAM,OAAO,CAAA,GAAA,EAAM,IAAA,CAAK,SAAS,CAAA,CAAA,EAAI,KAAK,OAAO,CAAA,CAAA;AACjD,EAAA,MAAM,QAAA,GAAW,CAAA,GAAA,EAAM,UAAA,CAAW,QAAA,EAAU,IAAA,CAAK,aAAa,CAAA,CAAE,MAAA,CAAO,IAAI,CAAA,CAAE,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAC1F,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,IAAA,CAAK,QAAA,EAAU,MAAM,CAAA;AAChD,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,WAAW,MAAM,CAAA;AACpD,EAAA,IAAI,WAAA,CAAY,MAAA,KAAW,SAAA,CAAU,MAAA,EAAQ,OAAO,KAAA;AACpD,EAAA,OAAO,eAAA,CAAgB,aAAa,SAAS,CAAA;AAC/C;;;ACNA,IAAM,0BAAA,GAA6B,sBAAA;AACnC,IAAM,qBAAA,GAAwB,iBAAA;AAE9B,IAAM,OAAO,UAAA,CAAW;AAAA,EACtB,IAAA,EAAM,WAAA;AAAA,EACN,SAAS,eAAA,CAAI,OAAA;AAAA,EACb,SAAA,EAAW;AAAA,IACT;AAAA,MACE,IAAA,EAAM,0BAAA;AAAA,MACN,QAAA,EAAU,IAAA;AAAA,MACV,MAAA,EAAQ,IAAA;AAAA,MACR,WAAA,EAAa;AAAA,KACf;AAAA,IACA;AAAA,MACE,IAAA,EAAM,qBAAA;AAAA,MACN,QAAA,EAAU,IAAA;AAAA,MACV,MAAA,EAAQ,IAAA;AAAA,MACR,WAAA,EAAa;AAAA;AACf,GACF;AAAA,EACA,WAAW,GAAA,EAAsC;AAC/C,IAAA,MAAM,GAAA,GAAM,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AACjC,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,WAAW,CAAA;AACxC,IAAA,IAAI,CAAC,QAAA,EAAU,OAAO,EAAC;AACvB,IAAA,OAAO,UAAA,CAAW;AAAA,MAChB,QAAA;AAAA,MACA,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,GAAI,IAAI,eAAA,GAAkB,EAAE,iBAAiB,GAAA,CAAI,eAAA,KAAoB;AAAC,KACvE,CAAA;AAAA,EACH,CAAA;AAAA,EACA,WAAW,GAAA,EAA2C;AACpD,IAAA,MAAM,GAAA,GAAM,UAAA,CAAW,GAAA,CAAI,MAAM,CAAA;AACjC,IAAA,OAAO;AAAA,MACL;AAAA,QACE,GAAA,EAAK,OAAA;AAAA,QACL,OAAA,EAAS,OAAO,GAAA,EAAK,MAAA,KAAW;AAC9B,UAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,IAAA,EAAK;AAC/B,UAAA,MAAM,aAAA,GAAgB,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,gBAAgB,CAAA;AAClD,UAAA,IAAI,CAAC,aAAA,EAAe;AAClB,YAAA,OAAO,IAAA,CAAK,EAAE,KAAA,EAAO,gBAAA,EAAkB,KAAK,GAAA,CAAI,gBAAA,IAAoB,GAAG,CAAA;AAAA,UACzE;AACA,UAAA,IACE,CAAC,oBAAA,CAAqB;AAAA,YACpB,OAAA;AAAA,YACA,aAAA;AAAA,YACA,SAAA,EAAW,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,mBAAmB,CAAA;AAAA,YAC9C,SAAA,EAAW,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,2BAA2B;AAAA,WACvD,CAAA,EACD;AACA,YAAA,OAAO,IAAA,CAAK,EAAE,KAAA,EAAO,mBAAA,IAAuB,GAAG,CAAA;AAAA,UACjD;AAEA,UAAA,MAAM,MAAA,GAAS,UAAU,OAAO,CAAA;AAChC,UAAA,MAAM,UAAA,GAAa,mBAAA,CAAoB,MAAA,EAAQ,GAAG,CAAA;AAClD,UAAA,IAAI,UAAA,CAAW,SAAS,WAAA,EAAa,OAAO,KAAK,EAAE,SAAA,EAAW,UAAA,CAAW,SAAA,EAAW,CAAA;AACpF,UAAA,IAAI,WAAW,IAAA,KAAS,MAAA;AACtB,YAAA,OAAO,IAAA,CAAK,EAAE,EAAA,EAAI,IAAA,EAAM,SAAS,IAAA,EAAM,MAAA,EAAQ,UAAA,CAAW,MAAA,EAAQ,CAAA;AAEpE,UAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA;AAC3C,UAAA,MAAM,iBAAiB,mBAAA,CAAoB;AAAA,YACzC,QAAQ,UAAA,CAAW,MAAA;AAAA,YACnB,SAAS,UAAA,CAAW,OAAA;AAAA,YACpB,UAAU,UAAA,CAAW;AAAA,WACtB,CAAA;AACD,UAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,uBAAA,CAAwB;AAAA,YAClD,cAAA;AAAA,YACA,WAAW,KAAA,CAAM,IAAA;AAAA,YACjB,cAAc,KAAA,CAAM,OAAA;AAAA,YACpB,MAAA,EAAQ,IAAI,MAAA,IAAU,WAAA;AAAA,YACtB,KAAA,EAAO,CAAA,MAAA,EAAS,IAAA,CAAK,UAAA,CAAW,OAAO,CAAC,CAAA,CAAA;AAAA,YACxC,OAAO,CAAA,MAAA,EAAS,UAAA,CAAW,OAAO,CAAA,CAAA,EAAI,WAAW,QAAQ,CAAA,CAAA;AAAA,YACzD,cAAA,EAAgB,CAAC,EAAE,IAAA,EAAM,QAAQ,IAAA,EAAM,UAAA,CAAW,MAAM,CAAA;AAAA,YACxD,QAAA,EAAU;AAAA,cACR,SAAA,EAAW,WAAA;AAAA,cACX,QAAQ,UAAA,CAAW,MAAA;AAAA,cACnB,SAAS,UAAA,CAAW,OAAA;AAAA,cACpB,UAAU,UAAA,CAAW,QAAA;AAAA,cACrB,IAAI,UAAA,CAAW,EAAA;AAAA,cACf,GAAI,WAAW,MAAA,GAAS,EAAE,QAAQ,UAAA,CAAW,MAAA,KAAW;AAAC;AAC3D,WACD,CAAA;AACD,UAAA,OAAO,KAAK,MAAA,EAAQ,MAAA,CAAO,MAAA,KAAW,UAAA,GAAa,MAAM,GAAG,CAAA;AAAA,QAC9D;AAAA;AACF,KACF;AAAA,EACF;AACF,CAAC,CAAA;AAED,IAAO,WAAA,GAAQ;AAOf,SAAS,WAAW,GAAA,EAAmD;AACrE,EAAA,MAAM,GAAA,GAA2B;AAAA,IAC/B,gBAAA,EAAkBA,YAAAA,CAAY,GAAA,CAAI,gBAAgB,CAAA,IAAK,0BAAA;AAAA,IACvD,WAAA,EAAaA,YAAAA,CAAY,GAAA,CAAI,WAAW,CAAA,IAAK,qBAAA;AAAA,IAC7C,UAAA,EAAY,GAAA,CAAI,UAAA,KAAe,YAAA,GAAe,YAAA,GAAe,MAAA;AAAA,IAC7D,YAAA,EAAc,IAAI,YAAA,KAAiB;AAAA,GACrC;AACA,EAAA,MAAM,KAAA,GAAQA,YAAAA,CAAY,GAAA,CAAI,KAAK,CAAA;AACnC,EAAA,IAAI,KAAA,MAAW,KAAA,GAAQ,KAAA;AACvB,EAAA,MAAM,MAAA,GAASA,YAAAA,CAAY,GAAA,CAAI,MAAM,CAAA;AACrC,EAAA,IAAI,MAAA,MAAY,MAAA,GAAS,MAAA;AACzB,EAAA,MAAM,eAAA,GAAkB,WAAA,CAAY,GAAA,CAAI,eAAe,CAAA;AACvD,EAAA,IAAI,eAAA,MAAqB,eAAA,GAAkB,eAAA;AAC3C,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,UAAU,OAAA,EAA0B;AAC3C,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,EAC3B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,KAAK,KAAA,EAAuB;AACnC,EAAA,OAAOC,UAAAA,CAAW,QAAQ,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AACrE;AAEA,SAAS,IAAA,CAAK,IAAA,EAAe,MAAA,GAAS,GAAA,EAAe;AACnD,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,IAAA,EAAM,EAAE,QAAQ,CAAA;AACvC;AAEA,SAASD,aAAY,KAAA,EAAoC;AACvD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,CAAM,MAAA,GAAS,IAAI,KAAA,GAAQ,MAAA;AACjE;AAEA,SAAS,YAAY,KAAA,EAAsC;AACzD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,GACtB,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAyB,OAAO,IAAA,KAAS,QAAQ,CAAA,GAC/D,MAAA;AACN","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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@render-harness/cap-slack",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Slack Events and Web API capability pack for the Render agent harness.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@slack/web-api": "^7.12.0",
|
|
32
|
-
"@render-harness/registry": "0.5.
|
|
32
|
+
"@render-harness/registry": "0.5.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^25.6.2",
|