@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.
- package/README.md +224 -0
- package/dist/admin.d.ts +25 -0
- package/dist/admin.js +109 -0
- package/dist/admin.js.map +1 -0
- package/dist/app.d.ts +7 -0
- package/dist/app.js +18 -0
- package/dist/app.js.map +1 -0
- package/dist/bot.d.ts +15 -0
- package/dist/bot.js +42 -0
- package/dist/bot.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +21 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +151 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +15 -0
- package/dist/context.js +36 -0
- package/dist/context.js.map +1 -0
- package/dist/events/app-mention.d.ts +3 -0
- package/dist/events/app-mention.js +66 -0
- package/dist/events/app-mention.js.map +1 -0
- package/dist/events/message.d.ts +3 -0
- package/dist/events/message.js +48 -0
- package/dist/events/message.js.map +1 -0
- package/dist/gateway/chat-client.d.ts +14 -0
- package/dist/gateway/chat-client.js +159 -0
- package/dist/gateway/chat-client.js.map +1 -0
- package/dist/handlers/reply.d.ts +4 -0
- package/dist/handlers/reply.js +4 -0
- package/dist/handlers/reply.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +84 -0
- package/dist/plugin.js +98 -0
- package/dist/plugin.js.map +1 -0
- package/dist/router.d.ts +11 -0
- package/dist/router.js +40 -0
- package/dist/router.js.map +1 -0
- package/dist/subagents/index.d.ts +7 -0
- package/dist/subagents/index.js +10 -0
- package/dist/subagents/index.js.map +1 -0
- package/dist/subagents/openclaw-gateway.d.ts +7 -0
- package/dist/subagents/openclaw-gateway.js +30 -0
- package/dist/subagents/openclaw-gateway.js.map +1 -0
- package/dist/subagents/types.d.ts +6 -0
- package/dist/subagents/types.js +2 -0
- package/dist/subagents/types.js.map +1 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/openclaw.plugin.json +17 -0
- package/package.json +57 -0
package/dist/config.d.ts
ADDED
|
@@ -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>;
|
package/dist/context.js
ADDED
|
@@ -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,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,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 @@
|
|
|
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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -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;
|