@datanovallc/openclaw-slack-router 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +224 -0
  2. package/dist/admin.d.ts +25 -0
  3. package/dist/admin.js +109 -0
  4. package/dist/admin.js.map +1 -0
  5. package/dist/app.d.ts +7 -0
  6. package/dist/app.js +18 -0
  7. package/dist/app.js.map +1 -0
  8. package/dist/bot.d.ts +15 -0
  9. package/dist/bot.js +42 -0
  10. package/dist/bot.js.map +1 -0
  11. package/dist/cli.d.ts +2 -0
  12. package/dist/cli.js +21 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/commands/init.d.ts +1 -0
  15. package/dist/commands/init.js +151 -0
  16. package/dist/commands/init.js.map +1 -0
  17. package/dist/config.d.ts +18 -0
  18. package/dist/config.js +41 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/context.d.ts +15 -0
  21. package/dist/context.js +36 -0
  22. package/dist/context.js.map +1 -0
  23. package/dist/events/app-mention.d.ts +3 -0
  24. package/dist/events/app-mention.js +66 -0
  25. package/dist/events/app-mention.js.map +1 -0
  26. package/dist/events/message.d.ts +3 -0
  27. package/dist/events/message.js +48 -0
  28. package/dist/events/message.js.map +1 -0
  29. package/dist/gateway/chat-client.d.ts +14 -0
  30. package/dist/gateway/chat-client.js +159 -0
  31. package/dist/gateway/chat-client.js.map +1 -0
  32. package/dist/handlers/reply.d.ts +4 -0
  33. package/dist/handlers/reply.js +4 -0
  34. package/dist/handlers/reply.js.map +1 -0
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.js +22 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/plugin.d.ts +84 -0
  39. package/dist/plugin.js +98 -0
  40. package/dist/plugin.js.map +1 -0
  41. package/dist/router.d.ts +11 -0
  42. package/dist/router.js +40 -0
  43. package/dist/router.js.map +1 -0
  44. package/dist/subagents/index.d.ts +7 -0
  45. package/dist/subagents/index.js +10 -0
  46. package/dist/subagents/index.js.map +1 -0
  47. package/dist/subagents/openclaw-gateway.d.ts +7 -0
  48. package/dist/subagents/openclaw-gateway.js +30 -0
  49. package/dist/subagents/openclaw-gateway.js.map +1 -0
  50. package/dist/subagents/types.d.ts +6 -0
  51. package/dist/subagents/types.js +2 -0
  52. package/dist/subagents/types.js.map +1 -0
  53. package/dist/types.d.ts +28 -0
  54. package/dist/types.js +2 -0
  55. package/dist/types.js.map +1 -0
  56. package/openclaw.plugin.json +17 -0
  57. package/package.json +57 -0
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import type { SubagentConfig } from "./types.js";
3
+ declare const envSchema: z.ZodObject<{
4
+ SLACK_BOT_TOKEN: z.ZodString;
5
+ SLACK_APP_TOKEN: z.ZodString;
6
+ }, "strip", z.ZodTypeAny, {
7
+ SLACK_BOT_TOKEN: string;
8
+ SLACK_APP_TOKEN: string;
9
+ }, {
10
+ SLACK_BOT_TOKEN: string;
11
+ SLACK_APP_TOKEN: string;
12
+ }>;
13
+ export type AppConfig = z.infer<typeof envSchema>;
14
+ export declare function loadConfig(): AppConfig;
15
+ export declare const DEFAULT_CONFIG_PATH = "./openclaw-slack-router.config.json";
16
+ export declare function loadSubagentConfig(path?: string): SubagentConfig;
17
+ export declare function saveSubagentConfig(config: SubagentConfig, path?: string): void;
18
+ export {};
package/dist/config.js ADDED
@@ -0,0 +1,41 @@
1
+ import { z } from "zod";
2
+ import { readFileSync, writeFileSync } from "node:fs";
3
+ const envSchema = z.object({
4
+ SLACK_BOT_TOKEN: z.string().startsWith("xoxb-", "Must be a bot token (xoxb-)"),
5
+ SLACK_APP_TOKEN: z.string().startsWith("xapp-", "Must be an app token (xapp-)"),
6
+ });
7
+ export function loadConfig() {
8
+ const result = envSchema.safeParse(process.env);
9
+ if (!result.success) {
10
+ const messages = result.error.issues
11
+ .map((i) => ` ${i.path.join(".")}: ${i.message}`)
12
+ .join("\n");
13
+ throw new Error(`Invalid configuration:\n${messages}`);
14
+ }
15
+ return result.data;
16
+ }
17
+ const channelEntrySchema = z.object({
18
+ name: z.string(),
19
+ historyLimit: z.number().int().positive().optional(),
20
+ });
21
+ const subagentEntrySchema = z.object({
22
+ name: z.string(),
23
+ description: z.string(),
24
+ });
25
+ const subagentConfigSchema = z.object({
26
+ botName: z.string().default("Rook"),
27
+ mainChannelId: z.string().nullable().default(null),
28
+ introPosted: z.boolean().default(false),
29
+ defaultAgent: z.string(),
30
+ agents: z.record(subagentEntrySchema),
31
+ channels: z.record(channelEntrySchema).default({}),
32
+ });
33
+ export const DEFAULT_CONFIG_PATH = "./openclaw-slack-router.config.json";
34
+ export function loadSubagentConfig(path = DEFAULT_CONFIG_PATH) {
35
+ const raw = readFileSync(path, "utf-8");
36
+ return subagentConfigSchema.parse(JSON.parse(raw));
37
+ }
38
+ export function saveSubagentConfig(config, path = DEFAULT_CONFIG_PATH) {
39
+ writeFileSync(path, JSON.stringify(config, null, 2) + "\n", "utf-8");
40
+ }
41
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGtD,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,6BAA6B,CAAC;IAC9E,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,8BAA8B,CAAC;CAChF,CAAC,CAAC;AAIH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM;aACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;aACjD,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACnC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACvC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC;IACrC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACnD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,qCAAqC,CAAC;AAEzE,MAAM,UAAU,kBAAkB,CAChC,IAAI,GAAG,mBAAmB;IAE1B,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAsB,EACtB,IAAI,GAAG,mBAAmB;IAE1B,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { SubagentConfig, SubagentContext } from "./types.js";
2
+ export declare function buildSubagentContext(params: {
3
+ client: {
4
+ conversations: {
5
+ history: Function;
6
+ };
7
+ };
8
+ channelId: string;
9
+ currentMessage: string;
10
+ userId: string;
11
+ threadTs: string;
12
+ agentName: string;
13
+ config: SubagentConfig;
14
+ botUserId: string;
15
+ }): Promise<SubagentContext>;
@@ -0,0 +1,36 @@
1
+ export async function buildSubagentContext(params) {
2
+ const { client, channelId, currentMessage, userId, threadTs, agentName, config, botUserId, } = params;
3
+ // CTX-04: per-channel historyLimit, default 50
4
+ const historyLimit = config.channels?.[channelId]?.historyLimit ?? 50;
5
+ // CTX-01: fetch channel history (channel-scoped, not thread-scoped)
6
+ const result = await client.conversations.history({
7
+ channel: channelId,
8
+ limit: historyLimit,
9
+ });
10
+ const rawMessages = result.messages ?? [];
11
+ // CTX-02: format as HistoryMessage[]
12
+ // conversations.history returns newest-first — reverse for chronological order
13
+ const chronological = [...rawMessages].reverse();
14
+ const history = chronological
15
+ // filter subtype messages (channel_join, topic changes, etc.)
16
+ // also filter messages with no text content
17
+ .filter((msg) => !msg.subtype && Boolean(msg.text))
18
+ .map((msg) => {
19
+ // Bot messages have bot_id field; also match own botUserId as fallback
20
+ const isBot = Boolean(msg.bot_id) ||
21
+ (botUserId ? msg.user === botUserId : false);
22
+ return {
23
+ role: isBot ? "assistant" : "user",
24
+ content: msg.text,
25
+ };
26
+ });
27
+ return {
28
+ channelId,
29
+ userId,
30
+ threadTs,
31
+ currentMessage,
32
+ threadHistory: history,
33
+ agentName,
34
+ };
35
+ }
36
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,MAS1C;IACC,MAAM,EACJ,MAAM,EACN,SAAS,EACT,cAAc,EACd,MAAM,EACN,QAAQ,EACR,SAAS,EACT,MAAM,EACN,SAAS,GACV,GAAG,MAAM,CAAC;IAEX,+CAA+C;IAC/C,MAAM,YAAY,GAChB,MAAM,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,YAAY,IAAI,EAAE,CAAC;IAEnD,oEAAoE;IACpE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC;QAChD,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,YAAY;KACpB,CAAC,CAAC;IAEH,MAAM,WAAW,GAAc,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IAErD,qCAAqC;IACrC,+EAA+E;IAC/E,MAAM,aAAa,GAAG,CAAC,GAAG,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;IAEjD,MAAM,OAAO,GAAqB,aAAa;QAC7C,8DAA8D;QAC9D,4CAA4C;SAC3C,MAAM,CACL,CAAC,GAAQ,EAAkC,EAAE,CAC3C,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CACpC;SACA,GAAG,CAAC,CAAC,GAAQ,EAAkB,EAAE;QAChC,uEAAuE;QACvE,MAAM,KAAK,GACT,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YACnB,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC/C,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM;YAClC,OAAO,EAAE,GAAG,CAAC,IAAc;SAC5B,CAAC;IACJ,CAAC,CAAC,CAAC;IAEL,OAAO;QACL,SAAS;QACT,MAAM;QACN,QAAQ;QACR,cAAc;QACd,aAAa,EAAE,OAAO;QACtB,SAAS;KACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SubagentConfig } from "../types.js";
2
+ import type { SubagentRegistry } from "../subagents/index.js";
3
+ export declare function registerAppMentionHandler(app: any, config: SubagentConfig, botUserId: string, subagentRegistry: SubagentRegistry): void;
@@ -0,0 +1,66 @@
1
+ import { resolveThreadTs } from "../handlers/reply.js";
2
+ import { resolveRoute, UnknownAgentError } from "../router.js";
3
+ import { buildSubagentContext } from "../context.js";
4
+ import { handleAdminCommand } from "../admin.js";
5
+ // Using `any` for app parameter to avoid ESM/CJS type import issues with @slack/bolt.
6
+ // The runtime behavior is verified by tests; TypeScript types for Bolt's App class
7
+ // are not reliably importable as a type-only import in all ESM/CJS interop scenarios.
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ export function registerAppMentionHandler(app, config, botUserId, subagentRegistry) {
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ app.event("app_mention", async ({ event, client, say }) => {
12
+ // SLACK-06: Join channel on mention (idempotent, fails gracefully for private channels)
13
+ try {
14
+ await client.conversations.join({ channel: event.channel });
15
+ }
16
+ catch {
17
+ // Private channel or already joined — continue
18
+ }
19
+ // SLACK-03: Reply in thread
20
+ const threadTs = resolveThreadTs(event);
21
+ // Strip bot mention from text for command parsing
22
+ const rawText = event.text ?? "";
23
+ const MENTION_RE = /^<@[A-Z0-9]+>\s*/;
24
+ const textWithoutMention = rawText.replace(MENTION_RE, "").trim();
25
+ // Admin commands: handle in main channel (and any channel for convenience)
26
+ if (config.mainChannelId && event.channel === config.mainChannelId) {
27
+ const adminResponse = await handleAdminCommand({
28
+ text: textWithoutMention,
29
+ client,
30
+ threadTs,
31
+ config,
32
+ });
33
+ if (adminResponse !== null) {
34
+ await say({ text: adminResponse, thread_ts: threadTs });
35
+ return;
36
+ }
37
+ }
38
+ try {
39
+ const route = resolveRoute(event.text, botUserId, config);
40
+ const context = await buildSubagentContext({
41
+ client,
42
+ channelId: event.channel,
43
+ currentMessage: route.text,
44
+ userId: event.user,
45
+ threadTs,
46
+ agentName: route.agentName,
47
+ config,
48
+ botUserId,
49
+ });
50
+ const subagent = subagentRegistry[route.agentName];
51
+ if (!subagent) {
52
+ await say({ text: `No subagent implementation registered for "${route.agentName}"`, thread_ts: threadTs });
53
+ return;
54
+ }
55
+ const response = await subagent.handle(context);
56
+ await say({ text: response, thread_ts: threadTs });
57
+ }
58
+ catch (err) {
59
+ const message = err instanceof UnknownAgentError
60
+ ? err.message
61
+ : "An error occurred processing your request.";
62
+ await say({ text: message, thread_ts: threadTs });
63
+ }
64
+ });
65
+ }
66
+ //# sourceMappingURL=app-mention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-mention.js","sourceRoot":"","sources":["../../src/events/app-mention.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SubagentConfig } from "../types.js";
2
+ import type { SubagentRegistry } from "../subagents/index.js";
3
+ export declare function registerMessageHandler(app: any, config: SubagentConfig, botUserId: string, subagentRegistry: SubagentRegistry): void;
@@ -0,0 +1,48 @@
1
+ import { resolveThreadTs } from "../handlers/reply.js";
2
+ import { resolveRoute, UnknownAgentError } from "../router.js";
3
+ import { buildSubagentContext } from "../context.js";
4
+ // Using `any` for app parameter to avoid ESM/CJS type import issues with @slack/bolt.
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ export function registerMessageHandler(app, config, botUserId, subagentRegistry) {
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ app.event("message", async ({ event, client, say }) => {
9
+ // SLACK-02: Only handle DMs
10
+ if (event.channel_type !== "im")
11
+ return;
12
+ // Skip message subtypes (edits, deletes, etc.)
13
+ if (event.subtype)
14
+ return;
15
+ // Skip bot messages to avoid infinite loops
16
+ if (event.bot_id)
17
+ return;
18
+ // SLACK-03: Reply in thread
19
+ const threadTs = resolveThreadTs(event);
20
+ try {
21
+ const route = resolveRoute(event.text ?? "", botUserId, config);
22
+ const context = await buildSubagentContext({
23
+ client,
24
+ channelId: event.channel,
25
+ currentMessage: route.text,
26
+ userId: event.user,
27
+ threadTs,
28
+ agentName: route.agentName,
29
+ config,
30
+ botUserId,
31
+ });
32
+ const subagent = subagentRegistry[route.agentName];
33
+ if (!subagent) {
34
+ await say({ text: `No subagent implementation registered for "${route.agentName}"`, thread_ts: threadTs });
35
+ return;
36
+ }
37
+ const response = await subagent.handle(context);
38
+ await say({ text: response, thread_ts: threadTs });
39
+ }
40
+ catch (err) {
41
+ const message = err instanceof UnknownAgentError
42
+ ? err.message
43
+ : "An error occurred processing your request.";
44
+ await say({ text: message, thread_ts: threadTs });
45
+ }
46
+ });
47
+ }
48
+ //# sourceMappingURL=message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../src/events/message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAIrD,sFAAsF;AACtF,8DAA8D;AAC9D,MAAM,UAAU,sBAAsB,CACpC,GAAQ,EACR,MAAsB,EACtB,SAAiB,EACjB,gBAAkC;IAElC,8DAA8D;IAC9D,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAO,EAAE,EAAE;QACzD,4BAA4B;QAC5B,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI;YAAE,OAAO;QACxC,+CAA+C;QAC/C,IAAI,KAAK,CAAC,OAAO;YAAE,OAAO;QAC1B,4CAA4C;QAC5C,IAAI,KAAK,CAAC,MAAM;YAAE,OAAO;QAEzB,4BAA4B;QAC5B,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QAExC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAChE,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC;gBACzC,MAAM;gBACN,SAAS,EAAE,KAAK,CAAC,OAAO;gBACxB,cAAc,EAAE,KAAK,CAAC,IAAI;gBAC1B,MAAM,EAAE,KAAK,CAAC,IAAI;gBAClB,QAAQ;gBACR,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,MAAM;gBACN,SAAS;aACV,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,gBAAgB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACnD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,8CAA8C,KAAK,CAAC,SAAS,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAC3G,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAChD,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GACX,GAAG,YAAY,iBAAiB;gBAC9B,CAAC,CAAC,GAAG,CAAC,OAAO;gBACb,CAAC,CAAC,4CAA4C,CAAC;YACnD,MAAM,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface GatewayChatOptions {
2
+ url: string;
3
+ token?: string;
4
+ timeoutMs?: number;
5
+ }
6
+ export interface ChatSendResult {
7
+ text: string;
8
+ runId: string;
9
+ }
10
+ export declare function gatewayChatSend(options: GatewayChatOptions, params: {
11
+ sessionKey: string;
12
+ message: string;
13
+ idempotencyKey: string;
14
+ }): Promise<ChatSendResult>;
@@ -0,0 +1,159 @@
1
+ import WebSocket from "ws";
2
+ import { randomUUID } from "node:crypto";
3
+ export async function gatewayChatSend(options, params) {
4
+ const { url, token, timeoutMs = 120_000 } = options;
5
+ const { sessionKey, message, idempotencyKey } = params;
6
+ return new Promise((resolve, reject) => {
7
+ let settled = false;
8
+ const ws = new WebSocket(url, { maxPayload: 25 * 1024 * 1024 });
9
+ const timer = setTimeout(() => {
10
+ if (!settled) {
11
+ settled = true;
12
+ ws.close();
13
+ reject(new Error(`gateway timeout after ${timeoutMs}ms`));
14
+ }
15
+ }, timeoutMs);
16
+ const cleanup = () => {
17
+ clearTimeout(timer);
18
+ ws.close();
19
+ };
20
+ const sendReq = (method, reqParams) => {
21
+ const id = randomUUID();
22
+ ws.send(JSON.stringify({ type: "req", id, method, params: reqParams }));
23
+ return id;
24
+ };
25
+ let connectReqId = null;
26
+ let chatSendReqId = null;
27
+ let chatRunId = null;
28
+ let deltaText = "";
29
+ ws.on("open", () => {
30
+ /* wait for connect.challenge event */
31
+ });
32
+ ws.on("message", (data) => {
33
+ if (settled)
34
+ return;
35
+ const raw = typeof data === "string" ? data : data.toString();
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ let frame;
38
+ try {
39
+ frame = JSON.parse(raw);
40
+ }
41
+ catch {
42
+ return;
43
+ }
44
+ // Event frames
45
+ if (frame.type === "evt") {
46
+ if (frame.event === "connect.challenge") {
47
+ connectReqId = sendReq("connect", {
48
+ minProtocol: 1,
49
+ maxProtocol: 1,
50
+ client: {
51
+ id: "slack-router",
52
+ version: "0.1.0",
53
+ platform: process.platform,
54
+ mode: "backend",
55
+ },
56
+ caps: [],
57
+ role: "operator",
58
+ scopes: ["operator.admin"],
59
+ ...(token ? { auth: { token } } : {}),
60
+ });
61
+ return;
62
+ }
63
+ if (frame.event === "chat") {
64
+ const p = frame.payload;
65
+ if (p?.runId !== chatRunId)
66
+ return;
67
+ if (p.state === "delta" && p.message) {
68
+ const content = p.message.content;
69
+ const text =
70
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
71
+ content?.find((c) => c.type === "text")?.text ?? "";
72
+ if (text)
73
+ deltaText = text; // delta text is cumulative
74
+ }
75
+ if (p.state === "final") {
76
+ settled = true;
77
+ const text = extractTextFromMessage(p.message) || deltaText;
78
+ cleanup();
79
+ resolve({ text, runId: chatRunId });
80
+ return;
81
+ }
82
+ if (p.state === "error") {
83
+ settled = true;
84
+ cleanup();
85
+ reject(new Error(p.errorMessage ?? "gateway chat error"));
86
+ return;
87
+ }
88
+ if (p.state === "aborted") {
89
+ settled = true;
90
+ cleanup();
91
+ reject(new Error("gateway chat aborted"));
92
+ return;
93
+ }
94
+ }
95
+ return;
96
+ }
97
+ // Response frames
98
+ if (frame.type === "res") {
99
+ if (frame.id === connectReqId) {
100
+ if (!frame.ok) {
101
+ settled = true;
102
+ cleanup();
103
+ reject(new Error(frame.error?.message ?? "gateway connect failed"));
104
+ return;
105
+ }
106
+ // Connected -- send chat.send
107
+ chatSendReqId = sendReq("chat.send", {
108
+ sessionKey,
109
+ message,
110
+ idempotencyKey,
111
+ });
112
+ return;
113
+ }
114
+ if (frame.id === chatSendReqId) {
115
+ if (!frame.ok) {
116
+ settled = true;
117
+ cleanup();
118
+ reject(new Error(frame.error?.message ?? "chat.send failed"));
119
+ return;
120
+ }
121
+ chatRunId = frame.payload?.runId ?? idempotencyKey;
122
+ // Now wait for chat events...
123
+ return;
124
+ }
125
+ }
126
+ });
127
+ ws.on("error", (err) => {
128
+ if (!settled) {
129
+ settled = true;
130
+ cleanup();
131
+ reject(err);
132
+ }
133
+ });
134
+ ws.on("close", (code, reason) => {
135
+ if (!settled) {
136
+ settled = true;
137
+ clearTimeout(timer);
138
+ reject(new Error(`gateway closed (${code}): ${reason?.toString() ?? ""}`));
139
+ }
140
+ });
141
+ });
142
+ }
143
+ function extractTextFromMessage(message) {
144
+ if (!message || typeof message !== "object")
145
+ return "";
146
+ const msg = message;
147
+ if (typeof msg.content === "string")
148
+ return msg.content;
149
+ if (Array.isArray(msg.content)) {
150
+ return msg.content
151
+ .filter((c) => c.type === "text" && c.text)
152
+ .map((c) => c.text)
153
+ .join("\n");
154
+ }
155
+ if (typeof msg.text === "string")
156
+ return msg.text;
157
+ return "";
158
+ }
159
+ //# sourceMappingURL=chat-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-client.js","sourceRoot":"","sources":["../../src/gateway/chat-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function resolveThreadTs(event: {
2
+ ts?: string;
3
+ thread_ts?: string;
4
+ }): string;
@@ -0,0 +1,4 @@
1
+ export function resolveThreadTs(event) {
2
+ return event.thread_ts ?? event.ts;
3
+ }
4
+ //# sourceMappingURL=reply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply.js","sourceRoot":"","sources":["../../src/handlers/reply.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe,CAAC,KAG/B;IACC,OAAO,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,EAAG,CAAC;AACtC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ import { config as dotenvConfig } from "dotenv";
2
+ import { join } from "node:path";
3
+ import { homedir } from "node:os";
4
+ // Load ~/.openclaw/.env first (openclaw's canonical env store), then fall back to local .env
5
+ dotenvConfig({ path: join(homedir(), ".openclaw", ".env") });
6
+ dotenvConfig(); // local .env — skips keys already set
7
+ import { loadConfig } from "./config.js";
8
+ import { startSlackBot } from "./bot.js";
9
+ async function main() {
10
+ const config = loadConfig();
11
+ await startSlackBot({
12
+ botToken: config.SLACK_BOT_TOKEN,
13
+ appToken: config.SLACK_APP_TOKEN,
14
+ gatewayUrl: process.env.OPENCLAW_GATEWAY_URL ?? "ws://127.0.0.1:18789",
15
+ gatewayToken: process.env.OPENCLAW_GATEWAY_TOKEN,
16
+ });
17
+ }
18
+ main().catch((err) => {
19
+ console.error("Fatal error:", err);
20
+ process.exit(1);
21
+ });
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,6FAA6F;AAC7F,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;AAC7D,YAAY,EAAE,CAAC,CAAC,sCAAsC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,MAAM,aAAa,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC,eAAe;QAChC,QAAQ,EAAE,MAAM,CAAC,eAAe;QAChC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,sBAAsB;QACtE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;KACjD,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,84 @@
1
+ type PluginServiceContext = {
2
+ config: Record<string, unknown>;
3
+ stateDir: string;
4
+ logger: {
5
+ info: (m: string) => void;
6
+ warn: (m: string) => void;
7
+ error: (m: string) => void;
8
+ };
9
+ };
10
+ type PluginApi = {
11
+ pluginConfig?: Record<string, unknown>;
12
+ registerService: (service: {
13
+ id: string;
14
+ start: (ctx: PluginServiceContext) => void | Promise<void>;
15
+ stop?: () => void | Promise<void>;
16
+ }) => void;
17
+ registerCli: (registrar: (ctx: {
18
+ program: any;
19
+ }) => void, opts?: {
20
+ commands?: string[];
21
+ }) => void;
22
+ };
23
+ declare const plugin: {
24
+ id: string;
25
+ name: string;
26
+ description: string;
27
+ configSchema: {
28
+ jsonSchema: {
29
+ type: string;
30
+ additionalProperties: boolean;
31
+ properties: {
32
+ botToken: {
33
+ type: string;
34
+ description: string;
35
+ };
36
+ appToken: {
37
+ type: string;
38
+ description: string;
39
+ };
40
+ mainChannelId: {
41
+ type: string;
42
+ description: string;
43
+ };
44
+ gatewayUrl: {
45
+ type: string;
46
+ description: string;
47
+ default: string;
48
+ };
49
+ gatewayToken: {
50
+ type: string;
51
+ description: string;
52
+ };
53
+ };
54
+ required: string[];
55
+ };
56
+ uiHints: {
57
+ botToken: {
58
+ label: string;
59
+ sensitive: boolean;
60
+ placeholder: string;
61
+ };
62
+ appToken: {
63
+ label: string;
64
+ sensitive: boolean;
65
+ placeholder: string;
66
+ };
67
+ mainChannelId: {
68
+ label: string;
69
+ help: string;
70
+ placeholder: string;
71
+ };
72
+ gatewayUrl: {
73
+ label: string;
74
+ placeholder: string;
75
+ };
76
+ gatewayToken: {
77
+ label: string;
78
+ sensitive: boolean;
79
+ };
80
+ };
81
+ };
82
+ register(api: PluginApi): void;
83
+ };
84
+ export default plugin;