@render-harness/cap-slack 0.2.0 → 0.2.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 CHANGED
@@ -178,12 +178,16 @@ function verifySlackSignature(args) {
178
178
  return timingSafeEqual(expectedBuf, actualBuf);
179
179
  }
180
180
 
181
+ // package.json
182
+ var package_default = {
183
+ version: "0.2.0"};
184
+
181
185
  // src/index.ts
182
186
  var DEFAULT_SIGNING_SECRET_ENV = "SLACK_SIGNING_SECRET";
183
187
  var DEFAULT_BOT_TOKEN_ENV = "SLACK_BOT_TOKEN";
184
188
  var pack = definePack({
185
189
  name: "cap-slack",
186
- version: "0.1.0",
190
+ version: package_default.version,
187
191
  envSchema: [
188
192
  {
189
193
  name: DEFAULT_SIGNING_SECRET_ENV,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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":["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 { WebClient } from \"@slack/web-api\";\n\nexport type SlackAccessMode = \"read\" | \"read_write\";\n\nexport function slackTools(args: {\n botToken: string;\n accessMode: SlackAccessMode;\n allowedChannels?: string[];\n}): LocalToolHandler[] {\n const client = new WebClient(args.botToken);\n const tools: LocalToolHandler[] = [\n jsonTool(\n \"slack.get_thread\",\n \"Read a Slack thread's messages.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.conversations.replies({ channel, ts: thread_ts });\n },\n ),\n jsonTool(\n \"slack.get_channel_history\",\n \"Read recent Slack channel messages.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.conversations.history({ channel, limit: limit ?? 20 });\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.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.chat.postMessage({\n channel,\n text,\n ...(thread_ts ? { thread_ts } : {}),\n });\n },\n ),\n jsonTool(\n \"slack.add_reaction\",\n \"Add a reaction to a Slack message.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.reactions.add({ channel, timestamp: ts, name });\n },\n ),\n jsonTool(\n \"slack.update_message\",\n \"Update a Slack message.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.chat.update({ channel, 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","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 { 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: \"0.1.0\",\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) throw new Error(`cap-slack: ${cfg.botTokenEnv} is not set`);\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":["../src/convid.ts","../src/normalize.ts","../src/tools.ts","../src/verify.ts","../package.json","../src/index.ts"],"names":["stringValue","createHash"],"mappings":"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","file":"index.js","sourcesContent":["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 { WebClient } from \"@slack/web-api\";\n\nexport type SlackAccessMode = \"read\" | \"read_write\";\n\nexport function slackTools(args: {\n botToken: string;\n accessMode: SlackAccessMode;\n allowedChannels?: string[];\n}): LocalToolHandler[] {\n const client = new WebClient(args.botToken);\n const tools: LocalToolHandler[] = [\n jsonTool(\n \"slack.get_thread\",\n \"Read a Slack thread's messages.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.conversations.replies({ channel, ts: thread_ts });\n },\n ),\n jsonTool(\n \"slack.get_channel_history\",\n \"Read recent Slack channel messages.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.conversations.history({ channel, limit: limit ?? 20 });\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.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.chat.postMessage({\n channel,\n text,\n ...(thread_ts ? { thread_ts } : {}),\n });\n },\n ),\n jsonTool(\n \"slack.add_reaction\",\n \"Add a reaction to a Slack message.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.reactions.add({ channel, timestamp: ts, name });\n },\n ),\n jsonTool(\n \"slack.update_message\",\n \"Update a Slack message.\",\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 assertAllowedChannel(channel, args.allowedChannels);\n return client.chat.update({ channel, 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","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","{\n \"name\": \"@render-harness/cap-slack\",\n \"version\": \"0.2.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 },\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}\n","import { createHash } from \"node:crypto\";\nimport type { LocalToolHandler } from \"@render-harness/core\";\nimport { type ConnectorContribution, definePack, type PackContext } from \"@render-harness/registry\";\nimport { slackConversationId } from \"./convid.js\";\nimport { normalizeSlackEvent, type SlackNormalizeConfig } from \"./normalize.js\";\nimport { type SlackAccessMode, slackTools } from \"./tools.js\";\nimport { verifySlackSignature } from \"./verify.js\";\nimport pkg from \"../package.json\" with { type: \"json\" };\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) throw new Error(`cap-slack: ${cfg.botTokenEnv} is not set`);\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.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Slack Events and Web API capability pack for the Render agent harness.",
5
5
  "type": "module",
6
6
  "license": "MIT",