opencode-lark 0.1.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/CHANGELOG.md +50 -0
- package/LICENSE +21 -0
- package/README.md +322 -0
- package/README.zh-CN.md +324 -0
- package/bin/opencode-lark.js +2 -0
- package/dist/channel/base-plugin.d.ts +31 -0
- package/dist/channel/base-plugin.d.ts.map +1 -0
- package/dist/channel/base-plugin.js +42 -0
- package/dist/channel/base-plugin.js.map +1 -0
- package/dist/channel/feishu/feishu-plugin.d.ts +36 -0
- package/dist/channel/feishu/feishu-plugin.d.ts.map +1 -0
- package/dist/channel/feishu/feishu-plugin.js +149 -0
- package/dist/channel/feishu/feishu-plugin.js.map +1 -0
- package/dist/channel/feishu/index.d.ts +2 -0
- package/dist/channel/feishu/index.d.ts.map +1 -0
- package/dist/channel/feishu/index.js +2 -0
- package/dist/channel/feishu/index.js.map +1 -0
- package/dist/channel/index.d.ts +4 -0
- package/dist/channel/index.d.ts.map +1 -0
- package/dist/channel/index.js +4 -0
- package/dist/channel/index.js.map +1 -0
- package/dist/channel/manager.d.ts +37 -0
- package/dist/channel/manager.d.ts.map +1 -0
- package/dist/channel/manager.js +68 -0
- package/dist/channel/manager.js.map +1 -0
- package/dist/channel/mock/mock-plugin.d.ts +24 -0
- package/dist/channel/mock/mock-plugin.d.ts.map +1 -0
- package/dist/channel/mock/mock-plugin.js +42 -0
- package/dist/channel/mock/mock-plugin.js.map +1 -0
- package/dist/channel/types.d.ts +226 -0
- package/dist/channel/types.d.ts.map +1 -0
- package/dist/channel/types.js +7 -0
- package/dist/channel/types.js.map +1 -0
- package/dist/cron/cron-service.d.ts +40 -0
- package/dist/cron/cron-service.d.ts.map +1 -0
- package/dist/cron/cron-service.js +140 -0
- package/dist/cron/cron-service.js.map +1 -0
- package/dist/cron/heartbeat.d.ts +30 -0
- package/dist/cron/heartbeat.d.ts.map +1 -0
- package/dist/cron/heartbeat.js +76 -0
- package/dist/cron/heartbeat.js.map +1 -0
- package/dist/feishu/api-client.d.ts +19 -0
- package/dist/feishu/api-client.d.ts.map +1 -0
- package/dist/feishu/api-client.js +98 -0
- package/dist/feishu/api-client.js.map +1 -0
- package/dist/feishu/card-builder.d.ts +10 -0
- package/dist/feishu/card-builder.d.ts.map +1 -0
- package/dist/feishu/card-builder.js +74 -0
- package/dist/feishu/card-builder.js.map +1 -0
- package/dist/feishu/cardkit-client.d.ts +48 -0
- package/dist/feishu/cardkit-client.d.ts.map +1 -0
- package/dist/feishu/cardkit-client.js +97 -0
- package/dist/feishu/cardkit-client.js.map +1 -0
- package/dist/feishu/message-dedup.d.ts +28 -0
- package/dist/feishu/message-dedup.d.ts.map +1 -0
- package/dist/feishu/message-dedup.js +58 -0
- package/dist/feishu/message-dedup.js.map +1 -0
- package/dist/feishu/webhook-server.d.ts +20 -0
- package/dist/feishu/webhook-server.d.ts.map +1 -0
- package/dist/feishu/webhook-server.js +111 -0
- package/dist/feishu/webhook-server.js.map +1 -0
- package/dist/feishu/ws-client.d.ts +17 -0
- package/dist/feishu/ws-client.d.ts.map +1 -0
- package/dist/feishu/ws-client.js +158 -0
- package/dist/feishu/ws-client.js.map +1 -0
- package/dist/handler/interactive-handler.d.ts +16 -0
- package/dist/handler/interactive-handler.d.ts.map +1 -0
- package/dist/handler/interactive-handler.js +86 -0
- package/dist/handler/interactive-handler.js.map +1 -0
- package/dist/handler/interactive-poller.d.ts +16 -0
- package/dist/handler/interactive-poller.d.ts.map +1 -0
- package/dist/handler/interactive-poller.js +147 -0
- package/dist/handler/interactive-poller.js.map +1 -0
- package/dist/handler/message-handler.d.ts +34 -0
- package/dist/handler/message-handler.d.ts.map +1 -0
- package/dist/handler/message-handler.js +305 -0
- package/dist/handler/message-handler.js.map +1 -0
- package/dist/handler/streaming-integration.d.ts +21 -0
- package/dist/handler/streaming-integration.d.ts.map +1 -0
- package/dist/handler/streaming-integration.js +325 -0
- package/dist/handler/streaming-integration.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +281 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +16 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +58 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/session/progress-tracker.d.ts +12 -0
- package/dist/session/progress-tracker.d.ts.map +1 -0
- package/dist/session/progress-tracker.js +46 -0
- package/dist/session/progress-tracker.js.map +1 -0
- package/dist/session/session-manager.d.ts +15 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +91 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/streaming/event-processor.d.ts +74 -0
- package/dist/streaming/event-processor.d.ts.map +1 -0
- package/dist/streaming/event-processor.js +240 -0
- package/dist/streaming/event-processor.js.map +1 -0
- package/dist/streaming/session-observer.d.ts +19 -0
- package/dist/streaming/session-observer.d.ts.map +1 -0
- package/dist/streaming/session-observer.js +140 -0
- package/dist/streaming/session-observer.js.map +1 -0
- package/dist/streaming/streaming-card.d.ts +37 -0
- package/dist/streaming/streaming-card.d.ts.map +1 -0
- package/dist/streaming/streaming-card.js +139 -0
- package/dist/streaming/streaming-card.js.map +1 -0
- package/dist/streaming/subagent-card.d.ts +32 -0
- package/dist/streaming/subagent-card.d.ts.map +1 -0
- package/dist/streaming/subagent-card.js +103 -0
- package/dist/streaming/subagent-card.js.map +1 -0
- package/dist/streaming/subagent-tracker.d.ts +45 -0
- package/dist/streaming/subagent-tracker.d.ts.map +1 -0
- package/dist/streaming/subagent-tracker.js +118 -0
- package/dist/streaming/subagent-tracker.js.map +1 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/config.d.ts +197 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +87 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/db.d.ts +12 -0
- package/dist/utils/db.d.ts.map +1 -0
- package/dist/utils/db.js +35 -0
- package/dist/utils/db.js.map +1 -0
- package/dist/utils/event-listeners.d.ts +12 -0
- package/dist/utils/event-listeners.d.ts.map +1 -0
- package/dist/utils/event-listeners.js +21 -0
- package/dist/utils/event-listeners.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +38 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feishu Webhook server.
|
|
3
|
+
* Receives Feishu event subscription callbacks and card action callbacks.
|
|
4
|
+
*/
|
|
5
|
+
import express from "express";
|
|
6
|
+
import { createLogger } from "../utils/logger.js";
|
|
7
|
+
const logger = createLogger("feishu-webhook");
|
|
8
|
+
export async function createFeishuGateway(options) {
|
|
9
|
+
const { port, verificationToken, onMessage, onCardAction } = options;
|
|
10
|
+
const app = express();
|
|
11
|
+
const dedup = options.dedup;
|
|
12
|
+
app.use(express.json());
|
|
13
|
+
// ── Feishu event subscription endpoint ──
|
|
14
|
+
app.post("/feishu/webhook", (req, res) => {
|
|
15
|
+
const body = req.body;
|
|
16
|
+
// URL verification (Feishu sends challenge on first webhook setup)
|
|
17
|
+
if (body["type"] === "url_verification") {
|
|
18
|
+
logger.info("URL verification received");
|
|
19
|
+
res.json({ challenge: body["challenge"] });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Verify token
|
|
23
|
+
if (body["token"] !== verificationToken) {
|
|
24
|
+
logger.warn("Invalid verification token");
|
|
25
|
+
res.status(403).json({ error: "Invalid token" });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Respond within 3s (Feishu requirement)
|
|
29
|
+
res.status(200).json({ code: 0 });
|
|
30
|
+
// Async processing
|
|
31
|
+
const header = body["header"];
|
|
32
|
+
const event = body["event"];
|
|
33
|
+
if (!header || !event)
|
|
34
|
+
return;
|
|
35
|
+
const eventId = header["event_id"];
|
|
36
|
+
if (!eventId)
|
|
37
|
+
return;
|
|
38
|
+
// Dedup
|
|
39
|
+
if (dedup.isDuplicate(eventId)) {
|
|
40
|
+
logger.debug(`Duplicate event: ${eventId}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Ignore bot's own messages
|
|
44
|
+
const sender = event["sender"];
|
|
45
|
+
if (sender?.["sender_type"] === "app")
|
|
46
|
+
return;
|
|
47
|
+
const eventType = header["event_type"];
|
|
48
|
+
if (eventType !== "im.message.receive_v1")
|
|
49
|
+
return;
|
|
50
|
+
const message = event["message"];
|
|
51
|
+
if (!message)
|
|
52
|
+
return;
|
|
53
|
+
const messageEvent = {
|
|
54
|
+
event_id: eventId,
|
|
55
|
+
event_type: eventType,
|
|
56
|
+
chat_id: message["chat_id"],
|
|
57
|
+
chat_type: message["chat_type"],
|
|
58
|
+
message_id: message["message_id"],
|
|
59
|
+
root_id: message["root_id"],
|
|
60
|
+
parent_id: message["parent_id"],
|
|
61
|
+
sender: {
|
|
62
|
+
sender_id: sender?.["sender_id"] ?? {
|
|
63
|
+
open_id: "unknown",
|
|
64
|
+
},
|
|
65
|
+
sender_type: sender?.["sender_type"] ?? "unknown",
|
|
66
|
+
tenant_key: sender?.["tenant_key"] ?? "unknown",
|
|
67
|
+
},
|
|
68
|
+
message: {
|
|
69
|
+
message_type: message["message_type"],
|
|
70
|
+
content: message["content"],
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
onMessage(messageEvent).catch((err) => {
|
|
74
|
+
logger.error("Error processing webhook event:", err);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
// ── Card action callback endpoint ──
|
|
78
|
+
app.post("/feishu/card/action", (req, res) => {
|
|
79
|
+
const body = req.body;
|
|
80
|
+
if (body["token"] !== verificationToken) {
|
|
81
|
+
res.status(403).json({ error: "Invalid token" });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
res.status(200).json({ code: 0 });
|
|
85
|
+
const action = {
|
|
86
|
+
action: body["action"],
|
|
87
|
+
open_message_id: body["open_message_id"],
|
|
88
|
+
open_chat_id: body["open_chat_id"],
|
|
89
|
+
operator: body["operator"],
|
|
90
|
+
};
|
|
91
|
+
onCardAction(action).catch((err) => {
|
|
92
|
+
logger.error("Error processing card action:", err);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
// ── Health check ──
|
|
96
|
+
app.get("/health", (_req, res) => {
|
|
97
|
+
res.json({ status: "ok", timestamp: Date.now() });
|
|
98
|
+
});
|
|
99
|
+
// ── Start server ──
|
|
100
|
+
const server = await new Promise((resolve) => {
|
|
101
|
+
const s = app.listen(port, () => {
|
|
102
|
+
logger.info(`Feishu webhook server listening on port ${port}`);
|
|
103
|
+
resolve(s);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
port,
|
|
108
|
+
close: () => new Promise((resolve) => server.close(() => resolve())),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=webhook-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-server.js","sourceRoot":"","sources":["../../src/feishu/webhook-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feishu WebSocket long-connection client.
|
|
3
|
+
* No public URL needed — connects outbound to Feishu's servers.
|
|
4
|
+
* Reference: ~/openclaw/extensions/feishu/src/monitor.ts
|
|
5
|
+
*/
|
|
6
|
+
import type { FeishuMessageEvent, FeishuCardAction } from "../types.js";
|
|
7
|
+
interface WSClientOptions {
|
|
8
|
+
appId: string;
|
|
9
|
+
appSecret: string;
|
|
10
|
+
onMessage: (event: FeishuMessageEvent) => Promise<void>;
|
|
11
|
+
onCardAction?: (action: FeishuCardAction) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export declare function createFeishuWSGateway(options: WSClientOptions): {
|
|
14
|
+
start(): void;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=ws-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-client.d.ts","sourceRoot":"","sources":["../../src/feishu/ws-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGvE,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,eAAe;;EA2F7D"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feishu WebSocket long-connection client.
|
|
3
|
+
* No public URL needed — connects outbound to Feishu's servers.
|
|
4
|
+
* Reference: ~/openclaw/extensions/feishu/src/monitor.ts
|
|
5
|
+
*/
|
|
6
|
+
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
7
|
+
import { createLogger } from "../utils/logger.js";
|
|
8
|
+
const logger = createLogger("feishu-ws");
|
|
9
|
+
export function createFeishuWSGateway(options) {
|
|
10
|
+
const { appId, appSecret, onMessage, onCardAction } = options;
|
|
11
|
+
const eventDispatcher = new Lark.EventDispatcher({});
|
|
12
|
+
// Register im.message.receive_v1 handler
|
|
13
|
+
eventDispatcher.register({
|
|
14
|
+
"im.message.receive_v1": async (data) => {
|
|
15
|
+
try {
|
|
16
|
+
const msg = data.message;
|
|
17
|
+
const sender = data.sender;
|
|
18
|
+
// Ignore bot's own messages
|
|
19
|
+
if (sender?.sender_type === "app")
|
|
20
|
+
return;
|
|
21
|
+
const messageEvent = {
|
|
22
|
+
event_id: data.event_id ?? data.header?.event_id ?? msg.message_id ?? `ws_${Date.now()}`,
|
|
23
|
+
event_type: "im.message.receive_v1",
|
|
24
|
+
chat_id: msg.chat_id,
|
|
25
|
+
chat_type: msg.chat_type,
|
|
26
|
+
message_id: msg.message_id,
|
|
27
|
+
root_id: msg.root_id,
|
|
28
|
+
parent_id: msg.parent_id,
|
|
29
|
+
sender: {
|
|
30
|
+
sender_id: sender?.sender_id ?? { open_id: "unknown" },
|
|
31
|
+
sender_type: sender?.sender_type ?? "unknown",
|
|
32
|
+
tenant_key: sender?.tenant_key ?? "unknown",
|
|
33
|
+
},
|
|
34
|
+
message: {
|
|
35
|
+
message_type: msg.message_type,
|
|
36
|
+
content: msg.content,
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
await onMessage(messageEvent);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
logger.error("Error handling WS message:", err);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
// Register card.action.trigger callback (receives card button clicks via WebSocket)
|
|
47
|
+
// See: https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/feishu-cards/card-callback-communication
|
|
48
|
+
// CRITICAL: Feishu requires a response within 3 seconds or it shows error 200340.
|
|
49
|
+
// After EventDispatcher v2 parse, the data is flattened:
|
|
50
|
+
// { operator: { open_id }, action: { value, tag }, context?: { open_message_id, open_chat_id }, ... }
|
|
51
|
+
if (onCardAction) {
|
|
52
|
+
eventDispatcher.register({
|
|
53
|
+
"card.action.trigger": async (data) => {
|
|
54
|
+
try {
|
|
55
|
+
const action = {
|
|
56
|
+
action: data.action ?? { tag: "button", value: {} },
|
|
57
|
+
open_message_id: data.context?.open_message_id ?? data.open_message_id ?? "",
|
|
58
|
+
open_chat_id: data.context?.open_chat_id ?? data.open_chat_id ?? "",
|
|
59
|
+
operator: { open_id: data.operator?.open_id ?? "unknown" },
|
|
60
|
+
};
|
|
61
|
+
const actionType = action.action?.value?.action ?? "unknown";
|
|
62
|
+
logger.info(`Card action received via WS: ${actionType}`, {
|
|
63
|
+
open_message_id: action.open_message_id,
|
|
64
|
+
operator: action.operator.open_id,
|
|
65
|
+
});
|
|
66
|
+
// Fire and forget — do NOT await.
|
|
67
|
+
// The opencode POST may take >3s and Feishu will timeout the callback.
|
|
68
|
+
void onCardAction(action).catch((err) => {
|
|
69
|
+
logger.error("Error in card action handler:", err);
|
|
70
|
+
});
|
|
71
|
+
// Return toast + updated card to give instant feedback and disable buttons.
|
|
72
|
+
// WSClient sends this back to Feishu as the callback response.
|
|
73
|
+
return buildCallbackResponse(action);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
logger.error("Error handling card action:", err);
|
|
77
|
+
// Return empty object even on error to avoid Feishu error 200340.
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const wsClient = new Lark.WSClient({
|
|
84
|
+
appId,
|
|
85
|
+
appSecret,
|
|
86
|
+
loggerLevel: Lark.LoggerLevel.info,
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
start() {
|
|
90
|
+
logger.info("Starting Feishu WebSocket connection...");
|
|
91
|
+
wsClient.start({ eventDispatcher });
|
|
92
|
+
logger.info("Feishu WebSocket client started (long-polling Feishu servers)");
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// ── Callback Response Builder ──
|
|
97
|
+
const PERMISSION_LABELS = {
|
|
98
|
+
once: "Allowed (once)",
|
|
99
|
+
always: "Always allowed",
|
|
100
|
+
reject: "Rejected",
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Build the Feishu card callback response.
|
|
104
|
+
* Returns a toast notification + an updated card with buttons disabled.
|
|
105
|
+
* See: https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/feishu-cards/card-callback-communication
|
|
106
|
+
*/
|
|
107
|
+
function buildCallbackResponse(action) {
|
|
108
|
+
const actionType = action.action?.value?.action;
|
|
109
|
+
const value = action.action?.value ?? {};
|
|
110
|
+
if (actionType === "question_answer") {
|
|
111
|
+
let answerLabel = "(unknown)";
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(value.answers ?? "[]");
|
|
114
|
+
answerLabel = parsed[0]?.[0] ?? answerLabel;
|
|
115
|
+
}
|
|
116
|
+
catch { /* ignore parse errors */ }
|
|
117
|
+
return {
|
|
118
|
+
toast: { type: "success", content: `✅ Answered: ${answerLabel}` },
|
|
119
|
+
card: {
|
|
120
|
+
type: "raw",
|
|
121
|
+
data: {
|
|
122
|
+
config: { wide_screen_mode: true },
|
|
123
|
+
header: {
|
|
124
|
+
title: { tag: "plain_text", content: "✅ Question Answered" },
|
|
125
|
+
template: "green",
|
|
126
|
+
},
|
|
127
|
+
elements: [
|
|
128
|
+
{ tag: "div", text: { tag: "lark_md", content: `**Answer:** ${answerLabel}` } },
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (actionType === "permission_reply") {
|
|
135
|
+
const reply = value.reply ?? "unknown";
|
|
136
|
+
const label = PERMISSION_LABELS[reply] ?? reply;
|
|
137
|
+
const isRejected = reply === "reject";
|
|
138
|
+
return {
|
|
139
|
+
toast: { type: isRejected ? "warning" : "success", content: `${isRejected ? "❌" : "✅"} ${label}` },
|
|
140
|
+
card: {
|
|
141
|
+
type: "raw",
|
|
142
|
+
data: {
|
|
143
|
+
config: { wide_screen_mode: true },
|
|
144
|
+
header: {
|
|
145
|
+
title: { tag: "plain_text", content: `${isRejected ? "❌" : "✅"} Permission: ${label}` },
|
|
146
|
+
template: isRejected ? "red" : "green",
|
|
147
|
+
},
|
|
148
|
+
elements: [
|
|
149
|
+
{ tag: "div", text: { tag: "lark_md", content: `**Decision:** ${label}` } },
|
|
150
|
+
],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// Unknown action type — just acknowledge
|
|
156
|
+
return {};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=ws-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-client.js","sourceRoot":"","sources":["../../src/feishu/ws-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive card action handler.
|
|
3
|
+
* Handles question answers and permission replies from Feishu card button clicks,
|
|
4
|
+
* forwarding responses back to the opencode server.
|
|
5
|
+
*
|
|
6
|
+
* Feedback to the user is handled by the card callback response (toast + card update)
|
|
7
|
+
* in ws-client.ts — this module only handles the opencode POST.
|
|
8
|
+
*/
|
|
9
|
+
import type { Logger } from "../utils/logger.js";
|
|
10
|
+
import type { FeishuCardAction } from "../types.js";
|
|
11
|
+
export interface InteractiveHandlerDeps {
|
|
12
|
+
serverUrl: string;
|
|
13
|
+
logger: Logger;
|
|
14
|
+
}
|
|
15
|
+
export declare function createInteractiveHandler(deps: InteractiveHandlerDeps): (action: FeishuCardAction) => Promise<void>;
|
|
16
|
+
//# sourceMappingURL=interactive-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-handler.d.ts","sourceRoot":"","sources":["../../src/handler/interactive-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAInD,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAID,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,sBAAsB,IAGrD,QAAQ,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAAC,CA+EvD"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive card action handler.
|
|
3
|
+
* Handles question answers and permission replies from Feishu card button clicks,
|
|
4
|
+
* forwarding responses back to the opencode server.
|
|
5
|
+
*
|
|
6
|
+
* Feedback to the user is handled by the card callback response (toast + card update)
|
|
7
|
+
* in ws-client.ts — this module only handles the opencode POST.
|
|
8
|
+
*/
|
|
9
|
+
// ── Factory ──
|
|
10
|
+
export function createInteractiveHandler(deps) {
|
|
11
|
+
const { serverUrl, logger } = deps;
|
|
12
|
+
return async (action) => {
|
|
13
|
+
const actionValue = action.action?.value;
|
|
14
|
+
if (!actionValue)
|
|
15
|
+
return;
|
|
16
|
+
const actionType = actionValue.action;
|
|
17
|
+
if (actionType === "question_answer") {
|
|
18
|
+
await handleQuestionAnswer(actionValue);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (actionType === "permission_reply") {
|
|
22
|
+
await handlePermissionReply(actionValue);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
async function handleQuestionAnswer(value) {
|
|
27
|
+
const { requestId, answers } = value;
|
|
28
|
+
if (!requestId || !answers) {
|
|
29
|
+
logger.warn("Missing requestId or answers in question_answer action");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let parsedAnswers;
|
|
33
|
+
try {
|
|
34
|
+
parsedAnswers = JSON.parse(answers);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
logger.warn(`Failed to parse question answers: ${answers}`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const resp = await fetch(`${serverUrl}/question/${requestId}/reply`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { "Content-Type": "application/json" },
|
|
44
|
+
body: JSON.stringify({ answers: parsedAnswers }),
|
|
45
|
+
});
|
|
46
|
+
if (!resp.ok) {
|
|
47
|
+
logger.warn(`Question reply failed: ${resp.status} ${resp.statusText}`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
logger.info(`Question ${requestId} answered: ${parsedAnswers[0]?.[0] ?? ""}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
logger.warn(`Question reply request failed: ${err}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function handlePermissionReply(value) {
|
|
58
|
+
const { requestId, reply } = value;
|
|
59
|
+
if (!requestId || !reply) {
|
|
60
|
+
logger.warn("Missing requestId or reply in permission_reply action");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const resp = await fetch(`${serverUrl}/permission/${requestId}/reply`, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: { "Content-Type": "application/json" },
|
|
67
|
+
body: JSON.stringify({ reply }),
|
|
68
|
+
});
|
|
69
|
+
if (!resp.ok) {
|
|
70
|
+
logger.warn(`Permission reply failed: ${resp.status} ${resp.statusText}`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const labelMap = {
|
|
74
|
+
once: "Allowed (once)",
|
|
75
|
+
always: "Always allowed",
|
|
76
|
+
reject: "Rejected",
|
|
77
|
+
};
|
|
78
|
+
logger.info(`Permission ${requestId}: ${labelMap[reply] ?? reply}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
logger.warn(`Permission reply request failed: ${err}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=interactive-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-handler.js","sourceRoot":"","sources":["../../src/handler/interactive-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FeishuApiClient } from "../feishu/api-client.js";
|
|
2
|
+
import type { Logger } from "../utils/logger.js";
|
|
3
|
+
export interface InteractivePollerDeps {
|
|
4
|
+
serverUrl: string;
|
|
5
|
+
feishuClient: Pick<FeishuApiClient, "sendMessage">;
|
|
6
|
+
logger: Logger;
|
|
7
|
+
getChatForSession: (sessionId: string) => string | undefined;
|
|
8
|
+
/** Shared dedup set — IDs added here are also checked by SSE handlers */
|
|
9
|
+
seenInteractiveIds: Set<string>;
|
|
10
|
+
}
|
|
11
|
+
export interface InteractivePoller {
|
|
12
|
+
start(): void;
|
|
13
|
+
stop(): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createInteractivePoller(deps: InteractivePollerDeps): InteractivePoller;
|
|
16
|
+
//# sourceMappingURL=interactive-poller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-poller.d.ts","sourceRoot":"","sources":["../../src/handler/interactive-poller.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAQhD,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;IAClD,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IAC5D,yEAAyE;IACzE,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;CACb;AAmCD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,qBAAqB,GAC1B,iBAAiB,CAuInB"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// Interactive Poller
|
|
3
|
+
// Polls opencode for pending questions/permissions
|
|
4
|
+
// as a reliable fallback when SSE events don't arrive.
|
|
5
|
+
// ═══════════════════════════════════════════
|
|
6
|
+
import { buildQuestionCard, buildPermissionCard } from "./streaming-integration.js";
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Constants
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
const POLL_INTERVAL_MS = 3_000;
|
|
11
|
+
const FETCH_TIMEOUT_MS = 5_000;
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Factory
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
export function createInteractivePoller(deps) {
|
|
16
|
+
const { serverUrl, feishuClient, logger, getChatForSession, seenInteractiveIds } = deps;
|
|
17
|
+
let timer = null;
|
|
18
|
+
async function poll() {
|
|
19
|
+
try {
|
|
20
|
+
await Promise.all([pollQuestions(), pollPermissions()]);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Individual poll methods handle their own errors
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function pollQuestions() {
|
|
27
|
+
let resp;
|
|
28
|
+
try {
|
|
29
|
+
resp = await fetch(`${serverUrl}/question`, {
|
|
30
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return; // Network error, will retry next interval
|
|
35
|
+
}
|
|
36
|
+
if (!resp.ok)
|
|
37
|
+
return;
|
|
38
|
+
let questions;
|
|
39
|
+
try {
|
|
40
|
+
questions = await resp.json();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!Array.isArray(questions))
|
|
46
|
+
return;
|
|
47
|
+
for (const q of questions) {
|
|
48
|
+
if (!q.id || !q.sessionID || !Array.isArray(q.questions))
|
|
49
|
+
continue;
|
|
50
|
+
if (seenInteractiveIds.has(q.id))
|
|
51
|
+
continue;
|
|
52
|
+
seenInteractiveIds.add(q.id);
|
|
53
|
+
const chatId = getChatForSession(q.sessionID);
|
|
54
|
+
if (!chatId)
|
|
55
|
+
continue;
|
|
56
|
+
logger.info(`Poller: pending question ${q.id} for session ${q.sessionID}`);
|
|
57
|
+
const action = {
|
|
58
|
+
type: "QuestionAsked",
|
|
59
|
+
sessionId: q.sessionID,
|
|
60
|
+
requestId: q.id,
|
|
61
|
+
questions: q.questions,
|
|
62
|
+
};
|
|
63
|
+
const card = buildQuestionCard(action);
|
|
64
|
+
feishuClient
|
|
65
|
+
.sendMessage(chatId, {
|
|
66
|
+
msg_type: "interactive",
|
|
67
|
+
content: JSON.stringify(card),
|
|
68
|
+
})
|
|
69
|
+
.catch((err) => {
|
|
70
|
+
logger.warn(`Poller question card send failed: ${err}`);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function pollPermissions() {
|
|
75
|
+
let resp;
|
|
76
|
+
try {
|
|
77
|
+
resp = await fetch(`${serverUrl}/permission`, {
|
|
78
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (!resp.ok)
|
|
85
|
+
return;
|
|
86
|
+
let permissions;
|
|
87
|
+
try {
|
|
88
|
+
permissions = await resp.json();
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (!Array.isArray(permissions))
|
|
94
|
+
return;
|
|
95
|
+
for (const p of permissions) {
|
|
96
|
+
if (!p.id || !p.sessionID)
|
|
97
|
+
continue;
|
|
98
|
+
if (seenInteractiveIds.has(p.id))
|
|
99
|
+
continue;
|
|
100
|
+
seenInteractiveIds.add(p.id);
|
|
101
|
+
const chatId = getChatForSession(p.sessionID);
|
|
102
|
+
if (!chatId)
|
|
103
|
+
continue;
|
|
104
|
+
logger.info(`Poller: pending permission ${p.id} for session ${p.sessionID}`);
|
|
105
|
+
const patternList = Array.isArray(p.patterns)
|
|
106
|
+
? p.patterns.filter((s) => typeof s === "string")
|
|
107
|
+
: [];
|
|
108
|
+
const action = {
|
|
109
|
+
type: "PermissionRequested",
|
|
110
|
+
sessionId: p.sessionID,
|
|
111
|
+
requestId: p.id,
|
|
112
|
+
permissionType: p.permission ?? "unknown",
|
|
113
|
+
title: patternList.length > 0 ? patternList.join(", ") : (p.permission ?? "Permission"),
|
|
114
|
+
metadata: p.metadata ?? {},
|
|
115
|
+
};
|
|
116
|
+
const card = buildPermissionCard(action);
|
|
117
|
+
feishuClient
|
|
118
|
+
.sendMessage(chatId, {
|
|
119
|
+
msg_type: "interactive",
|
|
120
|
+
content: JSON.stringify(card),
|
|
121
|
+
})
|
|
122
|
+
.catch((err) => {
|
|
123
|
+
logger.warn(`Poller permission card send failed: ${err}`);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
start() {
|
|
129
|
+
if (timer)
|
|
130
|
+
return;
|
|
131
|
+
timer = setInterval(() => {
|
|
132
|
+
poll();
|
|
133
|
+
}, POLL_INTERVAL_MS);
|
|
134
|
+
logger.info(`Interactive poller started (interval=${POLL_INTERVAL_MS}ms)`);
|
|
135
|
+
// Run first poll immediately
|
|
136
|
+
poll();
|
|
137
|
+
},
|
|
138
|
+
stop() {
|
|
139
|
+
if (timer) {
|
|
140
|
+
clearInterval(timer);
|
|
141
|
+
timer = null;
|
|
142
|
+
}
|
|
143
|
+
logger.info("Interactive poller stopped");
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=interactive-poller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive-poller.js","sourceRoot":"","sources":["../../src/handler/interactive-poller.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,qBAAqB;AACrB,mDAAmD;AACnD,uDAAuD;AACvD,8CAA8C;AAK9C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AA0CnF,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,gBAAgB,GAAG,KAAK,CAAA;AAC9B,MAAM,gBAAgB,GAAG,KAAK,CAAA;AAE9B,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,UAAU,uBAAuB,CACrC,IAA2B;IAE3B,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,GAAG,IAAI,CAAA;IACvF,IAAI,KAAK,GAA0C,IAAI,CAAA;IAEvD,KAAK,UAAU,IAAI;QACjB,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,EAAE,eAAe,EAAE,CAAC,CAAC,CAAA;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;QACpD,CAAC;IACH,CAAC;IAED,KAAK,UAAU,aAAa;QAC1B,IAAI,IAAc,CAAA;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,WAAW,EAAE;gBAC1C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,gBAAgB,CAAC;aAC9C,CAAC,CAAA;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAM,CAAC,0CAA0C;QACnD,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAM;QAEpB,IAAI,SAAkB,CAAA;QACtB,IAAI,CAAC;YACH,SAAS,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAM;QACR,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;YAAE,OAAM;QAErC,KAAK,MAAM,CAAC,IAAI,SAA8B,EAAE,CAAC;YAC/C,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;gBAAE,SAAQ;YAClE,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAE,SAAQ;YAC1C,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;YAE5B,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YAC7C,IAAI,CAAC,MAAM;gBAAE,SAAQ;YAErB,MAAM,CAAC,IAAI,CACT,4BAA4B,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,SAAS,EAAE,CAC9D,CAAA;YAED,MAAM,MAAM,GAAkB;gBAC5B,IAAI,EAAE,eAAe;gBACrB,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,SAAS,EAAE,CAAC,CAAC,EAAE;gBACf,SAAS,EAAE,CAAC,CAAC,SAAS;aACvB,CAAA;YACD,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAA;YACtC,YAAY;iBACT,WAAW,CAAC,MAAM,EAAE;gBACnB,QAAQ,EAAE,aAAa;gBACvB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC9B,CAAC;iBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACb,MAAM,CAAC,IAAI,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAA;YACzD,CAAC,CAAC,CAAA;QACN,CAAC;IACH,CAAC;IAED,KAAK,UAAU,eAAe;QAC5B,IAAI,IAAc,CAAA;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,aAAa,EAAE;gBAC5C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,gBAAgB,CAAC;aAC9C,CAAC,CAAA;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAM;QACR,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAM;QAEpB,IAAI,WAAoB,CAAA;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAM;QACR,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;YAAE,OAAM;QAEvC,KAAK,MAAM,CAAC,IAAI,WAAkC,EAAE,CAAC;YACnD,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS;gBAAE,SAAQ;YACnC,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAE,SAAQ;YAC1C,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;YAE5B,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;YAC7C,IAAI,CAAC,MAAM;gBAAE,SAAQ;YAErB,MAAM,CAAC,IAAI,CACT,8BAA8B,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,SAAS,EAAE,CAChE,CAAA;YAED,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAC3C,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;gBAC9D,CAAC,CAAC,EAAE,CAAA;YAEN,MAAM,MAAM,GAAwB;gBAClC,IAAI,EAAE,qBAAqB;gBAC3B,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,SAAS,EAAE,CAAC,CAAC,EAAE;gBACf,cAAc,EAAE,CAAC,CAAC,UAAU,IAAI,SAAS;gBACzC,KAAK,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,YAAY,CAAC;gBACvF,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;aAC3B,CAAA;YACD,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;YACxC,YAAY;iBACT,WAAW,CAAC,MAAM,EAAE;gBACnB,QAAQ,EAAE,aAAa;gBACvB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC9B,CAAC;iBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACb,MAAM,CAAC,IAAI,CAAC,uCAAuC,GAAG,EAAE,CAAC,CAAA;YAC3D,CAAC,CAAC,CAAA;QACN,CAAC;IACH,CAAC;IAED,OAAO;QACL,KAAK;YACH,IAAI,KAAK;gBAAE,OAAM;YACjB,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;gBACvB,IAAI,EAAE,CAAA;YACR,CAAC,EAAE,gBAAgB,CAAC,CAAA;YACpB,MAAM,CAAC,IAAI,CAAC,wCAAwC,gBAAgB,KAAK,CAAC,CAAA;YAC1E,6BAA6B;YAC7B,IAAI,EAAE,CAAA;QACR,CAAC;QAED,IAAI;YACF,IAAI,KAAK,EAAE,CAAC;gBACV,aAAa,CAAC,KAAK,CAAC,CAAA;gBACpB,KAAK,GAAG,IAAI,CAAA;YACd,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;QAC3C,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message handler — extracted from index.ts handleMessage().
|
|
3
|
+
*
|
|
4
|
+
* Supports two modes:
|
|
5
|
+
* 1. Event-driven (preferred): POST message → subscribe to SSE events → collect TextDelta → respond on SessionIdle
|
|
6
|
+
* 2. Sync fallback: POST message → parse response body → respond immediately
|
|
7
|
+
*/
|
|
8
|
+
import type { SessionManager } from "../session/session-manager.js";
|
|
9
|
+
import type { MemoryManager } from "../memory/memory-manager.js";
|
|
10
|
+
import type { MessageDedup } from "../feishu/message-dedup.js";
|
|
11
|
+
import type { EventProcessor } from "../streaming/event-processor.js";
|
|
12
|
+
import type { FeishuApiClient } from "../feishu/api-client.js";
|
|
13
|
+
import type { ProgressTracker } from "../session/progress-tracker.js";
|
|
14
|
+
import type { Logger } from "../utils/logger.js";
|
|
15
|
+
import type { FeishuMessageEvent } from "../types.js";
|
|
16
|
+
import type { StreamingBridge } from "./streaming-integration.js";
|
|
17
|
+
import type { SessionObserver } from "../streaming/session-observer.js";
|
|
18
|
+
import type { EventListenerMap } from "../utils/event-listeners.js";
|
|
19
|
+
export interface HandlerDeps {
|
|
20
|
+
serverUrl: string;
|
|
21
|
+
sessionManager: SessionManager;
|
|
22
|
+
memoryManager: MemoryManager;
|
|
23
|
+
dedup: MessageDedup;
|
|
24
|
+
eventProcessor: EventProcessor;
|
|
25
|
+
feishuClient: FeishuApiClient;
|
|
26
|
+
progressTracker: ProgressTracker;
|
|
27
|
+
eventListeners: EventListenerMap;
|
|
28
|
+
ownedSessions: Set<string>;
|
|
29
|
+
logger: Logger;
|
|
30
|
+
streamingBridge?: StreamingBridge;
|
|
31
|
+
observer?: SessionObserver;
|
|
32
|
+
}
|
|
33
|
+
export declare function createMessageHandler(deps: HandlerDeps): (event: FeishuMessageEvent) => Promise<void>;
|
|
34
|
+
//# sourceMappingURL=message-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-handler.d.ts","sourceRoot":"","sources":["../../src/handler/message-handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAA;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAKnE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,cAAc,CAAA;IAC9B,aAAa,EAAE,aAAa,CAAA;IAC5B,KAAK,EAAE,YAAY,CAAA;IACnB,cAAc,EAAE,cAAc,CAAA;IAC9B,YAAY,EAAE,eAAe,CAAA;IAC7B,eAAe,EAAE,eAAe,CAAA;IAChC,cAAc,EAAE,gBAAgB,CAAA;IAChC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,CAAC,EAAE,eAAe,CAAA;IACjC,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B;AAQD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,WAAW,GAChB,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,CAyY9C"}
|