@lih-x-x/kmr 1.0.27 → 1.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-4KKCJLHW.js +107 -0
- package/dist/{chunk-KJPAKNVA.js → chunk-EIQS5WF7.js} +1 -1
- package/dist/chunk-KK3DMZOA.js +35 -0
- package/dist/chunk-RYCZGTCI.js +68 -0
- package/dist/{claudeCode-PPRQZG5K.js → claudeCode-HNZS3G7L.js} +1 -1
- package/dist/cli.js +26 -5
- package/dist/client-CKWRSYEN.js +12 -0
- package/dist/index.js +23 -204
- package/dist/sync-E4SW7QFZ.js +6 -0
- package/dist/taskCreator-QVSOLXXU.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/lark/client.ts
|
|
2
|
+
import * as lark from "@larksuiteoapi/node-sdk";
|
|
3
|
+
function createLarkClient(config) {
|
|
4
|
+
return new lark.Client({
|
|
5
|
+
appId: config.lark.appId,
|
|
6
|
+
appSecret: config.lark.appSecret,
|
|
7
|
+
appType: lark.AppType.SelfBuild
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
async function getBotOpenId(client) {
|
|
11
|
+
try {
|
|
12
|
+
const res = await client.request({
|
|
13
|
+
method: "GET",
|
|
14
|
+
url: "/open-apis/bot/v3/info"
|
|
15
|
+
});
|
|
16
|
+
console.log(`[bot] bot info response:`, JSON.stringify(res?.data || res, null, 2));
|
|
17
|
+
const openId = res.data?.bot?.open_id || res.bot?.open_id || "";
|
|
18
|
+
if (openId) {
|
|
19
|
+
console.log(`[bot] \u673A\u5668\u4EBA open_id: ${openId}`);
|
|
20
|
+
} else {
|
|
21
|
+
console.warn(`[bot] \u672A\u80FD\u83B7\u53D6\u673A\u5668\u4EBA open_id\uFF0C\u7FA4\u804A @\u5224\u65AD\u53EF\u80FD\u4E0D\u51C6\u786E`);
|
|
22
|
+
}
|
|
23
|
+
return openId;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.error(`[bot] \u83B7\u53D6\u673A\u5668\u4EBA\u4FE1\u606F\u5931\u8D25:`, err.message);
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function createEventDispatcher(botOpenId, onMessage) {
|
|
30
|
+
const dispatcher = new lark.EventDispatcher({});
|
|
31
|
+
const processedMessages = /* @__PURE__ */ new Set();
|
|
32
|
+
dispatcher.register({
|
|
33
|
+
"im.message.receive_v1": async (data) => {
|
|
34
|
+
console.log(`[recv] \u6536\u5230\u98DE\u4E66\u4E8B\u4EF6:`, JSON.stringify(data, null, 2));
|
|
35
|
+
const message = data.message;
|
|
36
|
+
if (message.message_type !== "text") {
|
|
37
|
+
console.log(`[recv] \u5FFD\u7565\u975E\u6587\u672C\u6D88\u606F, type=${message.message_type}`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const messageId = message.message_id;
|
|
41
|
+
const senderType = data.sender?.sender_type;
|
|
42
|
+
if (senderType === "app") {
|
|
43
|
+
console.log(`[recv] \u5FFD\u7565\u673A\u5668\u4EBA\u81EA\u8EAB\u6D88\u606F: ${messageId}`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (processedMessages.has(messageId)) {
|
|
47
|
+
console.log(`[dedup] \u8DF3\u8FC7\u91CD\u590D\u6D88\u606F: ${messageId}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
processedMessages.add(messageId);
|
|
51
|
+
const createTime = parseInt(message.create_time, 10);
|
|
52
|
+
if (createTime && Date.now() - createTime > 2 * 60 * 1e3) {
|
|
53
|
+
console.log(`[dedup] \u8DF3\u8FC7\u8FC7\u671F\u6D88\u606F: ${messageId}, \u521B\u5EFA\u4E8E ${new Date(createTime).toISOString()}`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (processedMessages.size > 1e3) {
|
|
57
|
+
const first = processedMessages.values().next().value;
|
|
58
|
+
processedMessages.delete(first);
|
|
59
|
+
}
|
|
60
|
+
const content = JSON.parse(message.content);
|
|
61
|
+
let text = content.text || "";
|
|
62
|
+
const chatId = message.chat_id;
|
|
63
|
+
const mentions = message.mentions || [];
|
|
64
|
+
if (mentions.length > 0) {
|
|
65
|
+
console.log(`[recv] mentions:`, JSON.stringify(mentions));
|
|
66
|
+
}
|
|
67
|
+
const isMentioned = mentions.length > 0 && (!botOpenId || mentions.some((m) => {
|
|
68
|
+
const mentionOpenId = m.id?.open_id || m.id_str || "";
|
|
69
|
+
return mentionOpenId === botOpenId;
|
|
70
|
+
}));
|
|
71
|
+
const isGroup = message.chat_type === "group";
|
|
72
|
+
if (mentions.length > 0) {
|
|
73
|
+
for (const mention of mentions) {
|
|
74
|
+
if (mention.key) {
|
|
75
|
+
text = text.replace(mention.key, "").trim();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (isGroup && !isMentioned) {
|
|
80
|
+
const hasDocLink = /(https?:\/\/[^\s]*feishu\.cn\/[^\s]+)/.test(text);
|
|
81
|
+
if (!hasDocLink) {
|
|
82
|
+
console.log(`[recv] \u7FA4\u804A\u975E@\u673A\u5668\u4EBA\u6D88\u606F\u4E14\u975E\u6587\u6863\u94FE\u63A5, \u5FFD\u7565`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
console.log(`[recv] \u89E3\u6790\u6D88\u606F: messageId=${messageId}, chatId=${chatId}, chatType=${message.chat_type}, text="${text}"`);
|
|
87
|
+
const senderId = data.sender?.sender_id?.open_id || "unknown";
|
|
88
|
+
await onMessage(messageId, text, chatId, senderId, { isGroup, isMentioned });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
return dispatcher;
|
|
92
|
+
}
|
|
93
|
+
function startWSClient(client, dispatcher) {
|
|
94
|
+
const wsClient = new lark.WSClient({
|
|
95
|
+
appId: client.appId,
|
|
96
|
+
appSecret: client.appSecret,
|
|
97
|
+
loggerLevel: lark.LoggerLevel.info
|
|
98
|
+
});
|
|
99
|
+
wsClient.start({ eventDispatcher: dispatcher });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
createLarkClient,
|
|
104
|
+
getBotOpenId,
|
|
105
|
+
createEventDispatcher,
|
|
106
|
+
startWSClient
|
|
107
|
+
};
|
|
@@ -89,7 +89,7 @@ ${prompt}
|
|
|
89
89
|
return {
|
|
90
90
|
id: `meeting_${Date.now()}`,
|
|
91
91
|
documentUrl: "",
|
|
92
|
-
extractedAt: (/* @__PURE__ */ new Date()).
|
|
92
|
+
extractedAt: (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai" }).replace(" ", "T"),
|
|
93
93
|
summary: parsed.summary,
|
|
94
94
|
todos: (parsed.todos || []).map((t) => ({ ...t, status: "invalid_cause_no_task" })),
|
|
95
95
|
risks: parsed.risks || [],
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// src/task/sync.ts
|
|
2
|
+
async function syncTaskStatuses(store, taskCreator) {
|
|
3
|
+
console.log("[task-sync] \u5F00\u59CB\u540C\u6B65\u98DE\u4E66\u4EFB\u52A1\u72B6\u6001...");
|
|
4
|
+
try {
|
|
5
|
+
const meetings = await store.list();
|
|
6
|
+
let updatedCount = 0;
|
|
7
|
+
for (const meeting of meetings) {
|
|
8
|
+
if (!meeting.createdTasks || meeting.createdTasks.length === 0) continue;
|
|
9
|
+
let changed = false;
|
|
10
|
+
for (const task of meeting.createdTasks) {
|
|
11
|
+
if (!task.taskId || task.status === "completed") continue;
|
|
12
|
+
const result = await taskCreator.getTaskStatus(task.taskId);
|
|
13
|
+
if (result && result.status !== (task.status || "open")) {
|
|
14
|
+
task.status = result.status;
|
|
15
|
+
task.completedAt = result.completedAt;
|
|
16
|
+
changed = true;
|
|
17
|
+
if (task.todoIndex != null && meeting.todos[task.todoIndex]) {
|
|
18
|
+
meeting.todos[task.todoIndex].status = result.status;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (changed) {
|
|
23
|
+
await store.save(meeting);
|
|
24
|
+
updatedCount++;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
console.log(`[task-sync] \u540C\u6B65\u5B8C\u6210, \u66F4\u65B0\u4E86 ${updatedCount} \u6761\u4F1A\u8BAE\u8BB0\u5F55`);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.error("[task-sync] \u540C\u6B65\u5931\u8D25:", err.message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
syncTaskStatuses
|
|
35
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/lark/taskCreator.ts
|
|
2
|
+
var TaskCreator = class {
|
|
3
|
+
constructor(client) {
|
|
4
|
+
this.client = client;
|
|
5
|
+
}
|
|
6
|
+
client;
|
|
7
|
+
async createTask(params) {
|
|
8
|
+
const taskBody = {
|
|
9
|
+
summary: params.summary
|
|
10
|
+
};
|
|
11
|
+
if (params.due) {
|
|
12
|
+
const dueDate = /* @__PURE__ */ new Date(params.due + "T23:59:59+08:00");
|
|
13
|
+
taskBody.due = {
|
|
14
|
+
timestamp: dueDate.getTime().toString(),
|
|
15
|
+
is_all_day: true
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (params.description) {
|
|
19
|
+
taskBody.description = params.description;
|
|
20
|
+
}
|
|
21
|
+
if (params.assigneeOpenId) {
|
|
22
|
+
taskBody.members = [
|
|
23
|
+
{
|
|
24
|
+
id: params.assigneeOpenId,
|
|
25
|
+
type: "user",
|
|
26
|
+
role: "assignee"
|
|
27
|
+
}
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
console.log(`[task] \u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1: ${params.summary}`);
|
|
31
|
+
console.log(`[task] \u8BF7\u6C42\u4F53:`, JSON.stringify(taskBody, null, 2));
|
|
32
|
+
const response = await this.client.task.v2.task.create({
|
|
33
|
+
params: { user_id_type: "open_id" },
|
|
34
|
+
data: taskBody
|
|
35
|
+
});
|
|
36
|
+
console.log(`[task] API \u8FD4\u56DE:`, JSON.stringify(response.data, null, 2));
|
|
37
|
+
const taskId = response.data?.task?.guid || "";
|
|
38
|
+
const url = response.data?.task?.url || "";
|
|
39
|
+
console.log(`[task] \u4EFB\u52A1\u521B\u5EFA\u6210\u529F: taskId=${taskId}`);
|
|
40
|
+
return { taskId, url };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 查询飞书任务的最新状态
|
|
44
|
+
*/
|
|
45
|
+
async getTaskStatus(taskId) {
|
|
46
|
+
try {
|
|
47
|
+
const response = await this.client.task.v2.task.get({
|
|
48
|
+
path: { task_guid: taskId }
|
|
49
|
+
});
|
|
50
|
+
const task = response.data?.task;
|
|
51
|
+
if (!task) return null;
|
|
52
|
+
console.log(`[task-sync] \u4EFB\u52A1 ${taskId} \u72B6\u6001: completed_at="${task.completed_at}"`);
|
|
53
|
+
const completedAt = task.completed_at || "";
|
|
54
|
+
const ts = parseInt(completedAt, 10);
|
|
55
|
+
const isCompleted = ts > 0;
|
|
56
|
+
const status = isCompleted ? "completed" : "open";
|
|
57
|
+
const completedAtISO = isCompleted ? new Date(ts).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai" }).replace(" ", "T") : void 0;
|
|
58
|
+
return { status, completedAt: completedAtISO };
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(`[task-sync] \u67E5\u8BE2\u4EFB\u52A1\u72B6\u6001\u5931\u8D25: taskId=${taskId}`, err.message);
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
TaskCreator
|
|
68
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -6,9 +6,9 @@ async function checkUpdate() {
|
|
|
6
6
|
try {
|
|
7
7
|
const res = await fetch(`https://registry.npmjs.org/${"@lih-x-x/kmr"}/latest`, { signal: AbortSignal.timeout(3e3) });
|
|
8
8
|
const data = await res.json();
|
|
9
|
-
if (data.version && data.version !== "1.0.
|
|
9
|
+
if (data.version && data.version !== "1.0.29") {
|
|
10
10
|
console.log(`
|
|
11
|
-
\u2B06\uFE0F \u65B0\u7248\u672C\u53EF\u7528: ${"1.0.
|
|
11
|
+
\u2B06\uFE0F \u65B0\u7248\u672C\u53EF\u7528: ${"1.0.29"} \u2192 ${data.version}`);
|
|
12
12
|
console.log(` \u8FD0\u884C npm install -g ${"@lih-x-x/kmr"} \u66F4\u65B0
|
|
13
13
|
`);
|
|
14
14
|
}
|
|
@@ -54,12 +54,18 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
|
|
|
54
54
|
kmr --help \u663E\u793A\u5E2E\u52A9
|
|
55
55
|
`);
|
|
56
56
|
} else if (command === "--version" || command === "-v") {
|
|
57
|
-
console.log("1.0.
|
|
57
|
+
console.log("1.0.29");
|
|
58
58
|
} else if (command === "list") {
|
|
59
59
|
const { loadConfig } = await import("./config-L2SVVMAR.js");
|
|
60
60
|
const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
|
|
61
|
+
const { createLarkClient } = await import("./client-CKWRSYEN.js");
|
|
62
|
+
const { TaskCreator } = await import("./taskCreator-QVSOLXXU.js");
|
|
63
|
+
const { syncTaskStatuses } = await import("./sync-E4SW7QFZ.js");
|
|
61
64
|
const config = loadConfig();
|
|
62
65
|
const store = new JsonStore(config.storage.dataDir);
|
|
66
|
+
const client = createLarkClient(config);
|
|
67
|
+
const taskCreator = new TaskCreator(client);
|
|
68
|
+
await syncTaskStatuses(store, taskCreator);
|
|
63
69
|
const all = await store.list();
|
|
64
70
|
all.sort((a, b) => b.extractedAt.localeCompare(a.extractedAt));
|
|
65
71
|
if (all.length === 0) {
|
|
@@ -75,7 +81,14 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
|
|
|
75
81
|
}
|
|
76
82
|
const { loadConfig } = await import("./config-L2SVVMAR.js");
|
|
77
83
|
const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
|
|
78
|
-
const
|
|
84
|
+
const { createLarkClient } = await import("./client-CKWRSYEN.js");
|
|
85
|
+
const { TaskCreator } = await import("./taskCreator-QVSOLXXU.js");
|
|
86
|
+
const { syncTaskStatuses } = await import("./sync-E4SW7QFZ.js");
|
|
87
|
+
const config = loadConfig();
|
|
88
|
+
const store = new JsonStore(config.storage.dataDir);
|
|
89
|
+
const client = createLarkClient(config);
|
|
90
|
+
const taskCreator = new TaskCreator(client);
|
|
91
|
+
await syncTaskStatuses(store, taskCreator);
|
|
79
92
|
const record = await store.load(id);
|
|
80
93
|
if (!record) {
|
|
81
94
|
console.error(`\u672A\u627E\u5230\u8BB0\u5F55: ${id}`);
|
|
@@ -100,9 +113,17 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
|
|
|
100
113
|
process.exit(1);
|
|
101
114
|
}
|
|
102
115
|
const { loadConfig } = await import("./config-L2SVVMAR.js");
|
|
103
|
-
const { ClaudeCodeProvider } = await import("./claudeCode-
|
|
116
|
+
const { ClaudeCodeProvider } = await import("./claudeCode-HNZS3G7L.js");
|
|
104
117
|
const { QueryHandler } = await import("./handler-46CQQIA2.js");
|
|
118
|
+
const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
|
|
119
|
+
const { createLarkClient } = await import("./client-CKWRSYEN.js");
|
|
120
|
+
const { TaskCreator } = await import("./taskCreator-QVSOLXXU.js");
|
|
121
|
+
const { syncTaskStatuses } = await import("./sync-E4SW7QFZ.js");
|
|
105
122
|
const config = loadConfig();
|
|
123
|
+
const store = new JsonStore(config.storage.dataDir);
|
|
124
|
+
const client = createLarkClient(config);
|
|
125
|
+
const taskCreator = new TaskCreator(client);
|
|
126
|
+
await syncTaskStatuses(store, taskCreator);
|
|
106
127
|
const agent = new ClaudeCodeProvider(config.agent.timeout);
|
|
107
128
|
const handler = new QueryHandler(agent, config.storage.dataDir);
|
|
108
129
|
const results = await handler.find(query);
|
package/dist/index.js
CHANGED
|
@@ -1,119 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
QueryHandler
|
|
3
|
+
} from "./chunk-SGTENG37.js";
|
|
1
4
|
import {
|
|
2
5
|
JsonStore
|
|
3
6
|
} from "./chunk-TUCCS6QJ.js";
|
|
7
|
+
import {
|
|
8
|
+
createEventDispatcher,
|
|
9
|
+
createLarkClient,
|
|
10
|
+
getBotOpenId,
|
|
11
|
+
startWSClient
|
|
12
|
+
} from "./chunk-4KKCJLHW.js";
|
|
13
|
+
import {
|
|
14
|
+
TaskCreator
|
|
15
|
+
} from "./chunk-RYCZGTCI.js";
|
|
16
|
+
import {
|
|
17
|
+
syncTaskStatuses
|
|
18
|
+
} from "./chunk-KK3DMZOA.js";
|
|
4
19
|
import {
|
|
5
20
|
ClaudeCodeProvider,
|
|
6
21
|
getExecEnv
|
|
7
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-EIQS5WF7.js";
|
|
8
23
|
import {
|
|
9
24
|
KMR_DIR,
|
|
10
25
|
getAgentProvider,
|
|
11
26
|
loadConfig
|
|
12
27
|
} from "./chunk-ZXGVA5QX.js";
|
|
13
|
-
import {
|
|
14
|
-
QueryHandler
|
|
15
|
-
} from "./chunk-SGTENG37.js";
|
|
16
|
-
|
|
17
|
-
// src/lark/client.ts
|
|
18
|
-
import * as lark from "@larksuiteoapi/node-sdk";
|
|
19
|
-
function createLarkClient(config) {
|
|
20
|
-
return new lark.Client({
|
|
21
|
-
appId: config.lark.appId,
|
|
22
|
-
appSecret: config.lark.appSecret,
|
|
23
|
-
appType: lark.AppType.SelfBuild
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
async function getBotOpenId(client) {
|
|
27
|
-
try {
|
|
28
|
-
const res = await client.request({
|
|
29
|
-
method: "GET",
|
|
30
|
-
url: "/open-apis/bot/v3/info"
|
|
31
|
-
});
|
|
32
|
-
console.log(`[bot] bot info response:`, JSON.stringify(res?.data || res, null, 2));
|
|
33
|
-
const openId = res.data?.bot?.open_id || res.bot?.open_id || "";
|
|
34
|
-
if (openId) {
|
|
35
|
-
console.log(`[bot] \u673A\u5668\u4EBA open_id: ${openId}`);
|
|
36
|
-
} else {
|
|
37
|
-
console.warn(`[bot] \u672A\u80FD\u83B7\u53D6\u673A\u5668\u4EBA open_id\uFF0C\u7FA4\u804A @\u5224\u65AD\u53EF\u80FD\u4E0D\u51C6\u786E`);
|
|
38
|
-
}
|
|
39
|
-
return openId;
|
|
40
|
-
} catch (err) {
|
|
41
|
-
console.error(`[bot] \u83B7\u53D6\u673A\u5668\u4EBA\u4FE1\u606F\u5931\u8D25:`, err.message);
|
|
42
|
-
return "";
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function createEventDispatcher(botOpenId, onMessage) {
|
|
46
|
-
const dispatcher = new lark.EventDispatcher({});
|
|
47
|
-
const processedMessages = /* @__PURE__ */ new Set();
|
|
48
|
-
dispatcher.register({
|
|
49
|
-
"im.message.receive_v1": async (data) => {
|
|
50
|
-
console.log(`[recv] \u6536\u5230\u98DE\u4E66\u4E8B\u4EF6:`, JSON.stringify(data, null, 2));
|
|
51
|
-
const message = data.message;
|
|
52
|
-
if (message.message_type !== "text") {
|
|
53
|
-
console.log(`[recv] \u5FFD\u7565\u975E\u6587\u672C\u6D88\u606F, type=${message.message_type}`);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
const messageId = message.message_id;
|
|
57
|
-
const senderType = data.sender?.sender_type;
|
|
58
|
-
if (senderType === "app") {
|
|
59
|
-
console.log(`[recv] \u5FFD\u7565\u673A\u5668\u4EBA\u81EA\u8EAB\u6D88\u606F: ${messageId}`);
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (processedMessages.has(messageId)) {
|
|
63
|
-
console.log(`[dedup] \u8DF3\u8FC7\u91CD\u590D\u6D88\u606F: ${messageId}`);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
processedMessages.add(messageId);
|
|
67
|
-
const createTime = parseInt(message.create_time, 10);
|
|
68
|
-
if (createTime && Date.now() - createTime > 2 * 60 * 1e3) {
|
|
69
|
-
console.log(`[dedup] \u8DF3\u8FC7\u8FC7\u671F\u6D88\u606F: ${messageId}, \u521B\u5EFA\u4E8E ${new Date(createTime).toISOString()}`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (processedMessages.size > 1e3) {
|
|
73
|
-
const first = processedMessages.values().next().value;
|
|
74
|
-
processedMessages.delete(first);
|
|
75
|
-
}
|
|
76
|
-
const content = JSON.parse(message.content);
|
|
77
|
-
let text = content.text || "";
|
|
78
|
-
const chatId = message.chat_id;
|
|
79
|
-
const mentions = message.mentions || [];
|
|
80
|
-
if (mentions.length > 0) {
|
|
81
|
-
console.log(`[recv] mentions:`, JSON.stringify(mentions));
|
|
82
|
-
}
|
|
83
|
-
const isMentioned = mentions.length > 0 && (!botOpenId || mentions.some((m) => {
|
|
84
|
-
const mentionOpenId = m.id?.open_id || m.id_str || "";
|
|
85
|
-
return mentionOpenId === botOpenId;
|
|
86
|
-
}));
|
|
87
|
-
const isGroup = message.chat_type === "group";
|
|
88
|
-
if (mentions.length > 0) {
|
|
89
|
-
for (const mention of mentions) {
|
|
90
|
-
if (mention.key) {
|
|
91
|
-
text = text.replace(mention.key, "").trim();
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
if (isGroup && !isMentioned) {
|
|
96
|
-
const hasDocLink = /(https?:\/\/[^\s]*feishu\.cn\/[^\s]+)/.test(text);
|
|
97
|
-
if (!hasDocLink) {
|
|
98
|
-
console.log(`[recv] \u7FA4\u804A\u975E@\u673A\u5668\u4EBA\u6D88\u606F\u4E14\u975E\u6587\u6863\u94FE\u63A5, \u5FFD\u7565`);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
console.log(`[recv] \u89E3\u6790\u6D88\u606F: messageId=${messageId}, chatId=${chatId}, chatType=${message.chat_type}, text="${text}"`);
|
|
103
|
-
const senderId = data.sender?.sender_id?.open_id || "unknown";
|
|
104
|
-
await onMessage(messageId, text, chatId, senderId, { isGroup, isMentioned });
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
return dispatcher;
|
|
108
|
-
}
|
|
109
|
-
function startWSClient(client, dispatcher) {
|
|
110
|
-
const wsClient = new lark.WSClient({
|
|
111
|
-
appId: client.appId,
|
|
112
|
-
appSecret: client.appSecret,
|
|
113
|
-
loggerLevel: lark.LoggerLevel.info
|
|
114
|
-
});
|
|
115
|
-
wsClient.start({ eventDispatcher: dispatcher });
|
|
116
|
-
}
|
|
117
28
|
|
|
118
29
|
// src/lark/docReader.ts
|
|
119
30
|
function extractDocumentId(url) {
|
|
@@ -792,71 +703,6 @@ ${stdout}`);
|
|
|
792
703
|
}
|
|
793
704
|
};
|
|
794
705
|
|
|
795
|
-
// src/lark/taskCreator.ts
|
|
796
|
-
var TaskCreator = class {
|
|
797
|
-
constructor(client) {
|
|
798
|
-
this.client = client;
|
|
799
|
-
}
|
|
800
|
-
client;
|
|
801
|
-
async createTask(params) {
|
|
802
|
-
const taskBody = {
|
|
803
|
-
summary: params.summary
|
|
804
|
-
};
|
|
805
|
-
if (params.due) {
|
|
806
|
-
const dueDate = /* @__PURE__ */ new Date(params.due + "T23:59:59+08:00");
|
|
807
|
-
taskBody.due = {
|
|
808
|
-
timestamp: dueDate.getTime().toString(),
|
|
809
|
-
is_all_day: true
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
if (params.description) {
|
|
813
|
-
taskBody.description = params.description;
|
|
814
|
-
}
|
|
815
|
-
if (params.assigneeOpenId) {
|
|
816
|
-
taskBody.members = [
|
|
817
|
-
{
|
|
818
|
-
id: params.assigneeOpenId,
|
|
819
|
-
type: "user",
|
|
820
|
-
role: "assignee"
|
|
821
|
-
}
|
|
822
|
-
];
|
|
823
|
-
}
|
|
824
|
-
console.log(`[task] \u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1: ${params.summary}`);
|
|
825
|
-
console.log(`[task] \u8BF7\u6C42\u4F53:`, JSON.stringify(taskBody, null, 2));
|
|
826
|
-
const response = await this.client.task.v2.task.create({
|
|
827
|
-
params: { user_id_type: "open_id" },
|
|
828
|
-
data: taskBody
|
|
829
|
-
});
|
|
830
|
-
console.log(`[task] API \u8FD4\u56DE:`, JSON.stringify(response.data, null, 2));
|
|
831
|
-
const taskId = response.data?.task?.guid || "";
|
|
832
|
-
const url = response.data?.task?.url || "";
|
|
833
|
-
console.log(`[task] \u4EFB\u52A1\u521B\u5EFA\u6210\u529F: taskId=${taskId}`);
|
|
834
|
-
return { taskId, url };
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* 查询飞书任务的最新状态
|
|
838
|
-
*/
|
|
839
|
-
async getTaskStatus(taskId) {
|
|
840
|
-
try {
|
|
841
|
-
const response = await this.client.task.v2.task.get({
|
|
842
|
-
path: { task_guid: taskId }
|
|
843
|
-
});
|
|
844
|
-
const task = response.data?.task;
|
|
845
|
-
if (!task) return null;
|
|
846
|
-
console.log(`[task-sync] \u4EFB\u52A1 ${taskId} \u72B6\u6001: completed_at="${task.completed_at}"`);
|
|
847
|
-
const completedAt = task.completed_at || "";
|
|
848
|
-
const ts = parseInt(completedAt, 10);
|
|
849
|
-
const isCompleted = ts > 0;
|
|
850
|
-
const status = isCompleted ? "completed" : "open";
|
|
851
|
-
const completedAtISO = isCompleted ? new Date(ts).toISOString() : void 0;
|
|
852
|
-
return { status, completedAt: completedAtISO };
|
|
853
|
-
} catch (err) {
|
|
854
|
-
console.error(`[task-sync] \u67E5\u8BE2\u4EFB\u52A1\u72B6\u6001\u5931\u8D25: taskId=${taskId}`, err.message);
|
|
855
|
-
return null;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
};
|
|
859
|
-
|
|
860
706
|
// src/lark/userResolver.ts
|
|
861
707
|
var UserResolver = class {
|
|
862
708
|
constructor(client) {
|
|
@@ -974,7 +820,7 @@ async function main() {
|
|
|
974
820
|
pendingConfirmations.set(senderId, {
|
|
975
821
|
meetingId: record.id,
|
|
976
822
|
todos: record.todos,
|
|
977
|
-
createdAt: (/* @__PURE__ */ new Date()).
|
|
823
|
+
createdAt: (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai" }).replace(" ", "T"),
|
|
978
824
|
chatId,
|
|
979
825
|
timer
|
|
980
826
|
});
|
|
@@ -985,6 +831,7 @@ async function main() {
|
|
|
985
831
|
}
|
|
986
832
|
case "find_query" /* FIND_QUERY */: {
|
|
987
833
|
console.log(`[process] \u5F00\u59CB\u641C\u7D22: query="${parsed.query}"`);
|
|
834
|
+
await syncTaskStatuses(store, taskCreator);
|
|
988
835
|
const results = await queryHandler.find(parsed.query);
|
|
989
836
|
console.log(`[process] \u641C\u7D22\u5B8C\u6210, \u7ED3\u679C\u6570=${results.length}`);
|
|
990
837
|
await messenger.replySearchResults(messageId, results);
|
|
@@ -993,6 +840,7 @@ async function main() {
|
|
|
993
840
|
}
|
|
994
841
|
case "list_all" /* LIST_ALL */: {
|
|
995
842
|
console.log(`[process] \u5217\u51FA\u6240\u6709\u8BB0\u5F55`);
|
|
843
|
+
await syncTaskStatuses(store, taskCreator);
|
|
996
844
|
const all = await store.list();
|
|
997
845
|
console.log(`[process] \u5171 ${all.length} \u6761\u8BB0\u5F55`);
|
|
998
846
|
await messenger.replyRecordList(messageId, all);
|
|
@@ -1013,6 +861,7 @@ async function main() {
|
|
|
1013
861
|
}
|
|
1014
862
|
case "show_detail" /* SHOW_DETAIL */: {
|
|
1015
863
|
console.log(`[process] \u67E5\u770B\u8BE6\u60C5: id=${parsed.showId}`);
|
|
864
|
+
await syncTaskStatuses(store, taskCreator);
|
|
1016
865
|
const detail = await store.load(parsed.showId);
|
|
1017
866
|
if (detail) {
|
|
1018
867
|
await messenger.replyRecordDetail(messageId, detail);
|
|
@@ -1062,7 +911,7 @@ async function main() {
|
|
|
1062
911
|
summary: r.summary,
|
|
1063
912
|
taskId: r.taskId || "",
|
|
1064
913
|
url: r.url || "",
|
|
1065
|
-
createdAt: (/* @__PURE__ */ new Date()).
|
|
914
|
+
createdAt: (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai" }).replace(" ", "T"),
|
|
1066
915
|
todoIndex: r.todoIndex
|
|
1067
916
|
}));
|
|
1068
917
|
if (createdTasks.length > 0) {
|
|
@@ -1123,38 +972,8 @@ async function main() {
|
|
|
1123
972
|
console.error("[notify] \u5411\u7BA1\u7406\u5458\u63A8\u9001\u542F\u52A8\u901A\u77E5\u5931\u8D25:", err.message);
|
|
1124
973
|
});
|
|
1125
974
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
try {
|
|
1129
|
-
const meetings = await store.list();
|
|
1130
|
-
let updatedCount = 0;
|
|
1131
|
-
for (const meeting of meetings) {
|
|
1132
|
-
if (!meeting.createdTasks || meeting.createdTasks.length === 0) continue;
|
|
1133
|
-
let changed = false;
|
|
1134
|
-
for (const task of meeting.createdTasks) {
|
|
1135
|
-
if (!task.taskId || task.status === "completed") continue;
|
|
1136
|
-
const result = await taskCreator.getTaskStatus(task.taskId);
|
|
1137
|
-
if (result && result.status !== (task.status || "open")) {
|
|
1138
|
-
task.status = result.status;
|
|
1139
|
-
task.completedAt = result.completedAt;
|
|
1140
|
-
changed = true;
|
|
1141
|
-
if (task.todoIndex != null && meeting.todos[task.todoIndex]) {
|
|
1142
|
-
meeting.todos[task.todoIndex].status = result.status;
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
if (changed) {
|
|
1147
|
-
await store.save(meeting);
|
|
1148
|
-
updatedCount++;
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
console.log(`[task-sync] \u540C\u6B65\u5B8C\u6210, \u66F4\u65B0\u4E86 ${updatedCount} \u6761\u4F1A\u8BAE\u8BB0\u5F55`);
|
|
1152
|
-
} catch (err) {
|
|
1153
|
-
console.error("[task-sync] \u540C\u6B65\u5931\u8D25:", err.message);
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
syncTaskStatuses();
|
|
1157
|
-
setInterval(syncTaskStatuses, 60 * 60 * 1e3);
|
|
975
|
+
syncTaskStatuses(store, taskCreator);
|
|
976
|
+
setInterval(() => syncTaskStatuses(store, taskCreator), 60 * 60 * 1e3);
|
|
1158
977
|
if (config.lark.adminOpenId) {
|
|
1159
978
|
const adminId = config.lark.adminOpenId;
|
|
1160
979
|
let exiting = false;
|