@lih-x-x/kmr 1.0.39 → 1.0.41

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.
@@ -0,0 +1,60 @@
1
+ // src/lark/userResolver.ts
2
+ var UserResolver = class {
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ client;
7
+ // name -> openId 映射(支持多个群的成员合并)
8
+ nameMap = /* @__PURE__ */ new Map();
9
+ loadedChats = /* @__PURE__ */ new Set();
10
+ /**
11
+ * 根据姓名解析 open_id
12
+ * 如果缓存中没有,返回 undefined
13
+ */
14
+ resolve(name) {
15
+ if (this.nameMap.has(name)) return this.nameMap.get(name);
16
+ for (const [key, value] of this.nameMap) {
17
+ if (key.includes(name) || name.includes(key)) return value;
18
+ }
19
+ return void 0;
20
+ }
21
+ /**
22
+ * 加载某个群的成员列表到缓存
23
+ */
24
+ async loadChatMembers(chatId) {
25
+ if (this.loadedChats.has(chatId)) return;
26
+ try {
27
+ let pageToken;
28
+ do {
29
+ const response = await this.client.im.chatMembers.get({
30
+ path: { chat_id: chatId },
31
+ params: {
32
+ member_id_type: "open_id",
33
+ page_size: 100,
34
+ ...pageToken ? { page_token: pageToken } : {}
35
+ }
36
+ });
37
+ const items = response.data?.items || [];
38
+ for (const item of items) {
39
+ if (item.name && item.member_id) {
40
+ this.nameMap.set(item.name, item.member_id);
41
+ }
42
+ }
43
+ pageToken = response.data?.has_more ? response.data?.page_token : void 0;
44
+ } while (pageToken);
45
+ this.loadedChats.add(chatId);
46
+ } catch (err) {
47
+ console.error(`[user-resolver] \u52A0\u8F7D\u7FA4\u6210\u5458\u5931\u8D25:`, err.message);
48
+ }
49
+ }
50
+ /**
51
+ * 获取当前所有已缓存的映射
52
+ */
53
+ getAll() {
54
+ return new Map(this.nameMap);
55
+ }
56
+ };
57
+
58
+ export {
59
+ UserResolver
60
+ };
@@ -0,0 +1,193 @@
1
+ // src/lark/messenger.ts
2
+ var Messenger = class {
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ client;
7
+ async replyText(messageId, text) {
8
+ await this.client.im.message.reply({
9
+ path: { message_id: messageId },
10
+ data: {
11
+ content: JSON.stringify({ text }),
12
+ msg_type: "text"
13
+ }
14
+ });
15
+ }
16
+ async replyMeetingSummary(messageId, record) {
17
+ const lines = [
18
+ `\u2705 \u4F1A\u8BAE\u5173\u952E\u4FE1\u606F\u63D0\u53D6\u5B8C\u6210`,
19
+ "",
20
+ `\u{1F4CB} **${record.summary.title}**`,
21
+ `\u{1F4C5} \u65E5\u671F\uFF1A${record.summary.date}`,
22
+ `\u{1F465} \u53C2\u4E0E\u4EBA\uFF1A${record.summary.participants.join("\u3001")}`,
23
+ "",
24
+ "**\u6838\u5FC3\u8981\u70B9\uFF1A**",
25
+ ...record.summary.keyPoints.map((p) => `\u2022 ${p}`)
26
+ ];
27
+ if (record.todos.length > 0) {
28
+ lines.push("", "**\u5F85\u529E\u4E8B\u9879\uFF1A**");
29
+ for (const todo of record.todos) {
30
+ lines.push(`\u2022 ${todo.content}\uFF08${todo.owner}\uFF0C\u622A\u6B62 ${todo.deadline}\uFF09`);
31
+ }
32
+ }
33
+ if (record.risks.length > 0) {
34
+ lines.push("", "**\u98CE\u9669\u9879\uFF1A**");
35
+ for (const risk of record.risks) {
36
+ lines.push(`\u2022 [${risk.severity}] ${risk.description}`);
37
+ }
38
+ }
39
+ if (record.commitments.length > 0) {
40
+ lines.push("", "\u{1F91D} **\u5173\u952E\u5171\u8BC6\u4E0E\u627F\u8BFA\uFF1A**");
41
+ for (const c of record.commitments) {
42
+ lines.push(`\u2022 ${c.content}`);
43
+ lines.push(` \u76F8\u5173\u65B9\uFF1A${c.participants.join("\u3001")}${c.deadline ? `\uFF0C\u622A\u6B62 ${c.deadline}` : ""}`);
44
+ lines.push(` \u{1F4A1} ${c.context}`);
45
+ }
46
+ }
47
+ if (record.reusableInsights.length > 0) {
48
+ lines.push("", "\u{1F9E0} **\u53EF\u590D\u7528\u77E5\u8BC6\uFF1A**");
49
+ for (const r of record.reusableInsights) {
50
+ lines.push(`\u2022 [${r.category}] ${r.content}`);
51
+ lines.push(` \u9002\u7528\u573A\u666F\uFF1A${r.scenario}`);
52
+ }
53
+ }
54
+ await this.replyText(messageId, lines.join("\n"));
55
+ }
56
+ async replyRecordList(messageId, records) {
57
+ if (records.length === 0) {
58
+ await this.replyText(messageId, "\u6682\u65E0\u4F1A\u8BAE\u8BB0\u5F55");
59
+ return;
60
+ }
61
+ const lines = [`\u{1F4C2} \u5171 ${records.length} \u6761\u4F1A\u8BAE\u8BB0\u5F55\uFF1A`, ""];
62
+ for (const r of records) {
63
+ lines.push(`\u2022 ${r.id}`);
64
+ lines.push(` ${r.summary.title}\uFF08${r.summary.date}\uFF09`);
65
+ if (r.documentUrl) lines.push(` ${r.documentUrl}`);
66
+ lines.push("");
67
+ }
68
+ lines.push("\u4F7F\u7528 /show <id> \u67E5\u770B\u8BE6\u60C5\uFF0C/del <id> \u5220\u9664\u8BB0\u5F55");
69
+ await this.replyText(messageId, lines.join("\n"));
70
+ }
71
+ async replyRecordDetail(messageId, record) {
72
+ const lines = [
73
+ `\u{1F4CB} **${record.summary.title}**`,
74
+ `\u{1F4C5} \u65E5\u671F\uFF1A${record.summary.date}`,
75
+ `\u{1F465} \u53C2\u4E0E\u4EBA\uFF1A${record.summary.participants.join("\u3001")}`,
76
+ `\u{1F194} ${record.id}`
77
+ ];
78
+ if (record.documentUrl) {
79
+ lines.push(`\u{1F517} ${record.documentUrl}`);
80
+ }
81
+ lines.push("", "**\u6838\u5FC3\u8981\u70B9\uFF1A**");
82
+ for (const p of record.summary.keyPoints) {
83
+ lines.push(`\u2022 ${p}`);
84
+ }
85
+ if (record.commitments && record.commitments.length > 0) {
86
+ lines.push("", "\u{1F91D} **\u5173\u952E\u5171\u8BC6\u4E0E\u627F\u8BFA\uFF1A**");
87
+ for (const c of record.commitments) {
88
+ lines.push(`\u2022 ${c.content}`);
89
+ lines.push(` \u76F8\u5173\u65B9\uFF1A${c.participants.join("\u3001")}${c.deadline ? `\uFF0C\u622A\u6B62 ${c.deadline}` : ""}`);
90
+ lines.push(` \u{1F4A1} ${c.context}`);
91
+ }
92
+ }
93
+ if (record.reusableInsights && record.reusableInsights.length > 0) {
94
+ lines.push("", "\u{1F9E0} **\u53EF\u590D\u7528\u77E5\u8BC6\uFF1A**");
95
+ for (const r of record.reusableInsights) {
96
+ lines.push(`\u2022 [${r.category}] ${r.content}`);
97
+ lines.push(` \u9002\u7528\u573A\u666F\uFF1A${r.scenario}`);
98
+ }
99
+ }
100
+ if (record.todos && record.todos.length > 0) {
101
+ lines.push("", "**\u5F85\u529E\u4E8B\u9879\uFF1A**");
102
+ for (const t of record.todos) {
103
+ lines.push(`\u2022 ${t.content}\uFF08${t.owner}\uFF0C\u622A\u6B62 ${t.deadline}\uFF09`);
104
+ }
105
+ }
106
+ if (record.risks && record.risks.length > 0) {
107
+ lines.push("", "**\u98CE\u9669\u9879\uFF1A**");
108
+ for (const r of record.risks) {
109
+ lines.push(`\u2022 [${r.severity}] ${r.description}`);
110
+ }
111
+ }
112
+ await this.replyText(messageId, lines.join("\n"));
113
+ }
114
+ async replySearchResults(messageId, results) {
115
+ if (results.length === 0) {
116
+ await this.replyText(messageId, "\u672A\u627E\u5230\u76F8\u5173\u4F1A\u8BAE\u8BB0\u5F55");
117
+ return;
118
+ }
119
+ const lines = ["\u{1F50D} \u627E\u5230\u4EE5\u4E0B\u76F8\u5173\u4F1A\u8BAE\uFF1A", ""];
120
+ for (const r of results.slice(0, 3)) {
121
+ lines.push(`\u2022 **${r.summary.title}**\uFF08${r.summary.date}\uFF09`);
122
+ lines.push(` \u8981\u70B9\uFF1A${r.summary.keyPoints[0] || "\u65E0"}`);
123
+ lines.push(` \u94FE\u63A5\uFF1A${r.documentUrl}`);
124
+ lines.push("");
125
+ }
126
+ await this.replyText(messageId, lines.join("\n"));
127
+ }
128
+ async replyTodoConfirmation(messageId, todos) {
129
+ const lines = [
130
+ `\u{1F4DD} \u68C0\u6D4B\u5230 ${todos.length} \u6761\u5F85\u529E\uFF0C\u662F\u5426\u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1\uFF1F`,
131
+ ""
132
+ ];
133
+ todos.forEach((t, i) => {
134
+ lines.push(`${i + 1}. [${t.owner}] ${t.content}${t.deadline ? `\uFF08\u622A\u6B62 ${t.deadline}\uFF09` : ""}`);
135
+ });
136
+ lines.push("", "\u56DE\u590D /confirm all \u521B\u5EFA\u5168\u90E8");
137
+ lines.push("\u56DE\u590D /confirm 1,2 \u521B\u5EFA\u9009\u4E2D\u7684\u4EFB\u52A1");
138
+ lines.push("\u56DE\u590D /reject \u53D6\u6D88\u521B\u5EFA");
139
+ lines.push("", "\u23F1 3 \u5206\u949F\u5185\u672A\u56DE\u590D\u5C06\u81EA\u52A8\u53D6\u6D88");
140
+ await this.replyText(messageId, lines.join("\n"));
141
+ }
142
+ async replyTaskResults(messageId, results) {
143
+ const lines = ["\u{1F4CB} \u98DE\u4E66\u4EFB\u52A1\u521B\u5EFA\u7ED3\u679C\uFF1A", ""];
144
+ for (const r of results) {
145
+ if (r.success) {
146
+ lines.push(`\u2705 ${r.summary}`);
147
+ if (r.url) lines.push(` ${r.url}`);
148
+ } else {
149
+ lines.push(`\u274C ${r.summary} \u2014 ${r.error || "\u521B\u5EFA\u5931\u8D25"}`);
150
+ }
151
+ }
152
+ await this.replyText(messageId, lines.join("\n"));
153
+ }
154
+ /**
155
+ * 给消息添加表情回应(Reaction),返回 reaction_id
156
+ */
157
+ async addReaction(messageId, emojiType) {
158
+ const res = await this.client.im.messageReaction.create({
159
+ path: { message_id: messageId },
160
+ data: { reaction_type: { emoji_type: emojiType } }
161
+ });
162
+ return res.data?.reaction_id || "";
163
+ }
164
+ /**
165
+ * 删除指定的表情回应
166
+ */
167
+ async removeReaction(messageId, reactionId) {
168
+ try {
169
+ if (!reactionId) return;
170
+ await this.client.im.messageReaction.delete({
171
+ path: { message_id: messageId, reaction_id: reactionId }
172
+ });
173
+ } catch {
174
+ }
175
+ }
176
+ /**
177
+ * 主动向指定用户发送消息(不需要先收到消息)
178
+ */
179
+ async sendToUser(openId, text) {
180
+ await this.client.im.message.create({
181
+ params: { receive_id_type: "open_id" },
182
+ data: {
183
+ receive_id: openId,
184
+ content: JSON.stringify({ text }),
185
+ msg_type: "text"
186
+ }
187
+ });
188
+ }
189
+ };
190
+
191
+ export {
192
+ Messenger
193
+ };
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.39") {
9
+ if (data.version && data.version !== "1.0.41") {
10
10
  console.log(`
11
- \u2B06\uFE0F \u65B0\u7248\u672C\u53EF\u7528: ${"1.0.39"} \u2192 ${data.version}`);
11
+ \u2B06\uFE0F \u65B0\u7248\u672C\u53EF\u7528: ${"1.0.41"} \u2192 ${data.version}`);
12
12
  console.log(` \u8FD0\u884C npm install -g ${"@lih-x-x/kmr"} \u66F4\u65B0
13
13
  `);
14
14
  }
@@ -52,10 +52,12 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
52
52
  kmr task \u67E5\u770B\u6240\u6709\u4EFB\u52A1
53
53
  kmr del <id> \u5220\u9664\u8BB0\u5F55
54
54
  kmr find <q> \u641C\u7D22\u4F1A\u8BAE\u8BB0\u5F55
55
+ kmr create-task <\u6807\u9898> [--due YYYY-MM-DD] [--assignee \u59D3\u540D] [--desc \u63CF\u8FF0] \u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1
56
+ kmr send <\u5185\u5BB9> \u5411\u7BA1\u7406\u5458\u53D1\u9001\u98DE\u4E66\u6D88\u606F
55
57
  kmr --help \u663E\u793A\u5E2E\u52A9
56
58
  `);
57
59
  } else if (command === "--version" || command === "-v") {
58
- console.log("1.0.39");
60
+ console.log("1.0.41");
59
61
  } else if (command === "list") {
60
62
  const { loadConfig } = await import("./config-L2SVVMAR.js");
61
63
  const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
@@ -133,6 +135,73 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
133
135
  const store = new JsonStore(loadConfig().storage.dataDir);
134
136
  const ok = await store.delete(id);
135
137
  console.log(ok ? `\u2705 \u5DF2\u5220\u9664: ${id}` : `\u274C \u672A\u627E\u5230: ${id}`);
138
+ } else if (command === "create-task") {
139
+ const args = argv.slice(3);
140
+ let summary = "";
141
+ let due;
142
+ let assignee;
143
+ let desc;
144
+ const positional = [];
145
+ for (let i = 0; i < args.length; i++) {
146
+ if (args[i] === "--due" && args[i + 1]) {
147
+ due = args[++i];
148
+ } else if (args[i] === "--assignee" && args[i + 1]) {
149
+ assignee = args[++i];
150
+ } else if (args[i] === "--desc" && args[i + 1]) {
151
+ desc = args[++i];
152
+ } else {
153
+ positional.push(args[i]);
154
+ }
155
+ }
156
+ summary = positional.join(" ");
157
+ if (!summary) {
158
+ console.error("\u7528\u6CD5: kmr create-task <\u4EFB\u52A1\u6807\u9898> [--due YYYY-MM-DD] [--assignee \u59D3\u540D] [--desc \u63CF\u8FF0]");
159
+ process.exit(1);
160
+ }
161
+ const { loadConfig } = await import("./config-L2SVVMAR.js");
162
+ const { createLarkClient } = await import("./client-DFBBDD77.js");
163
+ const { TaskCreator } = await import("./taskCreator-TCI3VB5D.js");
164
+ const { UserResolver } = await import("./userResolver-DTWOTVP6.js");
165
+ const config = loadConfig();
166
+ const client = createLarkClient(config);
167
+ const taskCreator = new TaskCreator(client);
168
+ let assigneeOpenId;
169
+ if (assignee) {
170
+ const userResolver = new UserResolver(client);
171
+ try {
172
+ const chatListRes = await client.im.chat.list({ params: { page_size: 50 } });
173
+ const chats = chatListRes.data?.items || [];
174
+ for (const chat of chats) {
175
+ await userResolver.loadChatMembers(chat.chat_id);
176
+ }
177
+ } catch {
178
+ }
179
+ assigneeOpenId = userResolver.resolve(assignee);
180
+ if (!assigneeOpenId) {
181
+ console.error(`\u26A0\uFE0F \u672A\u627E\u5230\u7528\u6237 "${assignee}"\uFF0C\u5C06\u521B\u5EFA\u65E0\u8D1F\u8D23\u4EBA\u7684\u4EFB\u52A1`);
182
+ }
183
+ }
184
+ const result = await taskCreator.createTask({ summary, due, description: desc, assigneeOpenId });
185
+ console.log(`\u2705 \u4EFB\u52A1\u5DF2\u521B\u5EFA: ${result.taskId}`);
186
+ if (result.url) console.log(` ${result.url}`);
187
+ } else if (command === "send") {
188
+ const text = argv.slice(3).join(" ");
189
+ if (!text) {
190
+ console.error("\u7528\u6CD5: kmr send <\u6D88\u606F\u5185\u5BB9>");
191
+ process.exit(1);
192
+ }
193
+ const { loadConfig } = await import("./config-L2SVVMAR.js");
194
+ const { createLarkClient } = await import("./client-DFBBDD77.js");
195
+ const { Messenger } = await import("./messenger-O4LNWO4P.js");
196
+ const config = loadConfig();
197
+ if (!config.lark.adminOpenId) {
198
+ console.error("\u274C \u672A\u914D\u7F6E adminOpenId\uFF0C\u65E0\u6CD5\u53D1\u9001\u6D88\u606F");
199
+ process.exit(1);
200
+ }
201
+ const client = createLarkClient(config);
202
+ const messenger = new Messenger(client);
203
+ await messenger.sendToUser(config.lark.adminOpenId, text);
204
+ console.log("\u2705 \u6D88\u606F\u5DF2\u53D1\u9001");
136
205
  } else if (command === "find") {
137
206
  const query = argv.slice(3).join(" ");
138
207
  if (!query) {
@@ -170,6 +239,8 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
170
239
  kmr task \u67E5\u770B\u6240\u6709\u4EFB\u52A1
171
240
  kmr del <id> \u5220\u9664\u8BB0\u5F55
172
241
  kmr find <q> \u641C\u7D22\u4F1A\u8BAE\u8BB0\u5F55
242
+ kmr create-task <\u6807\u9898> [--due DATE] [--assignee \u59D3\u540D] [--desc \u63CF\u8FF0] \u521B\u5EFA\u4EFB\u52A1
243
+ kmr send <\u5185\u5BB9> \u5411\u7BA1\u7406\u5458\u53D1\u6D88\u606F
173
244
  kmr --help \u663E\u793A\u5B8C\u6574\u5E2E\u52A9
174
245
  `);
175
246
  await import("./index.js");
package/dist/index.js CHANGED
@@ -1,6 +1,18 @@
1
+ import {
2
+ Messenger
3
+ } from "./chunk-VYFCZATK.js";
4
+ import {
5
+ ClaudeCodeProvider,
6
+ getExecEnv
7
+ } from "./chunk-WMK5MYOU.js";
1
8
  import {
2
9
  QueryHandler
3
10
  } from "./chunk-SGTENG37.js";
11
+ import {
12
+ KMR_DIR,
13
+ getAgentProvider,
14
+ loadConfig
15
+ } from "./chunk-ZXGVA5QX.js";
4
16
  import {
5
17
  JsonStore
6
18
  } from "./chunk-TUCCS6QJ.js";
@@ -17,14 +29,8 @@ import {
17
29
  syncTaskStatuses
18
30
  } from "./chunk-XQVLJTP4.js";
19
31
  import {
20
- ClaudeCodeProvider,
21
- getExecEnv
22
- } from "./chunk-WMK5MYOU.js";
23
- import {
24
- KMR_DIR,
25
- getAgentProvider,
26
- loadConfig
27
- } from "./chunk-ZXGVA5QX.js";
32
+ UserResolver
33
+ } from "./chunk-2IG4NXRZ.js";
28
34
 
29
35
  // src/index.ts
30
36
  import fs3 from "fs";
@@ -106,203 +112,6 @@ var DocReader = class {
106
112
  }
107
113
  };
108
114
 
109
- // src/lark/messenger.ts
110
- var Messenger = class {
111
- constructor(client) {
112
- this.client = client;
113
- }
114
- client;
115
- async replyText(messageId, text) {
116
- await this.client.im.message.reply({
117
- path: { message_id: messageId },
118
- data: {
119
- content: JSON.stringify({ text }),
120
- msg_type: "text"
121
- }
122
- });
123
- }
124
- async replyMeetingSummary(messageId, record) {
125
- const lines = [
126
- `\u2705 \u4F1A\u8BAE\u5173\u952E\u4FE1\u606F\u63D0\u53D6\u5B8C\u6210`,
127
- "",
128
- `\u{1F4CB} **${record.summary.title}**`,
129
- `\u{1F4C5} \u65E5\u671F\uFF1A${record.summary.date}`,
130
- `\u{1F465} \u53C2\u4E0E\u4EBA\uFF1A${record.summary.participants.join("\u3001")}`,
131
- "",
132
- "**\u6838\u5FC3\u8981\u70B9\uFF1A**",
133
- ...record.summary.keyPoints.map((p) => `\u2022 ${p}`)
134
- ];
135
- if (record.todos.length > 0) {
136
- lines.push("", "**\u5F85\u529E\u4E8B\u9879\uFF1A**");
137
- for (const todo of record.todos) {
138
- lines.push(`\u2022 ${todo.content}\uFF08${todo.owner}\uFF0C\u622A\u6B62 ${todo.deadline}\uFF09`);
139
- }
140
- }
141
- if (record.risks.length > 0) {
142
- lines.push("", "**\u98CE\u9669\u9879\uFF1A**");
143
- for (const risk of record.risks) {
144
- lines.push(`\u2022 [${risk.severity}] ${risk.description}`);
145
- }
146
- }
147
- if (record.commitments.length > 0) {
148
- lines.push("", "\u{1F91D} **\u5173\u952E\u5171\u8BC6\u4E0E\u627F\u8BFA\uFF1A**");
149
- for (const c of record.commitments) {
150
- lines.push(`\u2022 ${c.content}`);
151
- lines.push(` \u76F8\u5173\u65B9\uFF1A${c.participants.join("\u3001")}${c.deadline ? `\uFF0C\u622A\u6B62 ${c.deadline}` : ""}`);
152
- lines.push(` \u{1F4A1} ${c.context}`);
153
- }
154
- }
155
- if (record.reusableInsights.length > 0) {
156
- lines.push("", "\u{1F9E0} **\u53EF\u590D\u7528\u77E5\u8BC6\uFF1A**");
157
- for (const r of record.reusableInsights) {
158
- lines.push(`\u2022 [${r.category}] ${r.content}`);
159
- lines.push(` \u9002\u7528\u573A\u666F\uFF1A${r.scenario}`);
160
- }
161
- }
162
- await this.replyText(messageId, lines.join("\n"));
163
- }
164
- async replyRecordList(messageId, records) {
165
- if (records.length === 0) {
166
- await this.replyText(messageId, "\u6682\u65E0\u4F1A\u8BAE\u8BB0\u5F55");
167
- return;
168
- }
169
- const lines = [`\u{1F4C2} \u5171 ${records.length} \u6761\u4F1A\u8BAE\u8BB0\u5F55\uFF1A`, ""];
170
- for (const r of records) {
171
- lines.push(`\u2022 ${r.id}`);
172
- lines.push(` ${r.summary.title}\uFF08${r.summary.date}\uFF09`);
173
- if (r.documentUrl) lines.push(` ${r.documentUrl}`);
174
- lines.push("");
175
- }
176
- lines.push("\u4F7F\u7528 /show <id> \u67E5\u770B\u8BE6\u60C5\uFF0C/del <id> \u5220\u9664\u8BB0\u5F55");
177
- await this.replyText(messageId, lines.join("\n"));
178
- }
179
- async replyRecordDetail(messageId, record) {
180
- const lines = [
181
- `\u{1F4CB} **${record.summary.title}**`,
182
- `\u{1F4C5} \u65E5\u671F\uFF1A${record.summary.date}`,
183
- `\u{1F465} \u53C2\u4E0E\u4EBA\uFF1A${record.summary.participants.join("\u3001")}`,
184
- `\u{1F194} ${record.id}`
185
- ];
186
- if (record.documentUrl) {
187
- lines.push(`\u{1F517} ${record.documentUrl}`);
188
- }
189
- lines.push("", "**\u6838\u5FC3\u8981\u70B9\uFF1A**");
190
- for (const p of record.summary.keyPoints) {
191
- lines.push(`\u2022 ${p}`);
192
- }
193
- if (record.commitments && record.commitments.length > 0) {
194
- lines.push("", "\u{1F91D} **\u5173\u952E\u5171\u8BC6\u4E0E\u627F\u8BFA\uFF1A**");
195
- for (const c of record.commitments) {
196
- lines.push(`\u2022 ${c.content}`);
197
- lines.push(` \u76F8\u5173\u65B9\uFF1A${c.participants.join("\u3001")}${c.deadline ? `\uFF0C\u622A\u6B62 ${c.deadline}` : ""}`);
198
- lines.push(` \u{1F4A1} ${c.context}`);
199
- }
200
- }
201
- if (record.reusableInsights && record.reusableInsights.length > 0) {
202
- lines.push("", "\u{1F9E0} **\u53EF\u590D\u7528\u77E5\u8BC6\uFF1A**");
203
- for (const r of record.reusableInsights) {
204
- lines.push(`\u2022 [${r.category}] ${r.content}`);
205
- lines.push(` \u9002\u7528\u573A\u666F\uFF1A${r.scenario}`);
206
- }
207
- }
208
- if (record.todos && record.todos.length > 0) {
209
- lines.push("", "**\u5F85\u529E\u4E8B\u9879\uFF1A**");
210
- for (const t of record.todos) {
211
- lines.push(`\u2022 ${t.content}\uFF08${t.owner}\uFF0C\u622A\u6B62 ${t.deadline}\uFF09`);
212
- }
213
- }
214
- if (record.risks && record.risks.length > 0) {
215
- lines.push("", "**\u98CE\u9669\u9879\uFF1A**");
216
- for (const r of record.risks) {
217
- lines.push(`\u2022 [${r.severity}] ${r.description}`);
218
- }
219
- }
220
- await this.replyText(messageId, lines.join("\n"));
221
- }
222
- async replySearchResults(messageId, results) {
223
- if (results.length === 0) {
224
- await this.replyText(messageId, "\u672A\u627E\u5230\u76F8\u5173\u4F1A\u8BAE\u8BB0\u5F55");
225
- return;
226
- }
227
- const lines = ["\u{1F50D} \u627E\u5230\u4EE5\u4E0B\u76F8\u5173\u4F1A\u8BAE\uFF1A", ""];
228
- for (const r of results.slice(0, 3)) {
229
- lines.push(`\u2022 **${r.summary.title}**\uFF08${r.summary.date}\uFF09`);
230
- lines.push(` \u8981\u70B9\uFF1A${r.summary.keyPoints[0] || "\u65E0"}`);
231
- lines.push(` \u94FE\u63A5\uFF1A${r.documentUrl}`);
232
- lines.push("");
233
- }
234
- await this.replyText(messageId, lines.join("\n"));
235
- }
236
- async replyTodoConfirmation(messageId, todos) {
237
- const lines = [
238
- `\u{1F4DD} \u68C0\u6D4B\u5230 ${todos.length} \u6761\u5F85\u529E\uFF0C\u662F\u5426\u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1\uFF1F`,
239
- ""
240
- ];
241
- todos.forEach((t, i) => {
242
- lines.push(`${i + 1}. [${t.owner}] ${t.content}${t.deadline ? `\uFF08\u622A\u6B62 ${t.deadline}\uFF09` : ""}`);
243
- });
244
- lines.push("", "\u56DE\u590D /confirm all \u521B\u5EFA\u5168\u90E8");
245
- lines.push("\u56DE\u590D /confirm 1,2 \u521B\u5EFA\u9009\u4E2D\u7684\u4EFB\u52A1");
246
- lines.push("\u56DE\u590D /reject \u53D6\u6D88\u521B\u5EFA");
247
- lines.push("", "\u23F1 3 \u5206\u949F\u5185\u672A\u56DE\u590D\u5C06\u81EA\u52A8\u53D6\u6D88");
248
- await this.replyText(messageId, lines.join("\n"));
249
- }
250
- async replyTaskResults(messageId, results) {
251
- const lines = ["\u{1F4CB} \u98DE\u4E66\u4EFB\u52A1\u521B\u5EFA\u7ED3\u679C\uFF1A", ""];
252
- for (const r of results) {
253
- if (r.success) {
254
- lines.push(`\u2705 ${r.summary}`);
255
- if (r.url) lines.push(` ${r.url}`);
256
- } else {
257
- lines.push(`\u274C ${r.summary} \u2014 ${r.error || "\u521B\u5EFA\u5931\u8D25"}`);
258
- }
259
- }
260
- await this.replyText(messageId, lines.join("\n"));
261
- }
262
- /**
263
- * 给消息添加表情回应(Reaction)
264
- */
265
- async addReaction(messageId, emojiType) {
266
- await this.client.im.messageReaction.create({
267
- path: { message_id: messageId },
268
- data: { reaction_type: { emoji_type: emojiType } }
269
- });
270
- }
271
- /**
272
- * 删除消息上的表情回应
273
- */
274
- async removeReaction(messageId, emojiType) {
275
- try {
276
- const res = await this.client.im.messageReaction.list({
277
- path: { message_id: messageId }
278
- });
279
- const reactions = res.data?.reaction_list || [];
280
- for (const r of reactions) {
281
- if (r.reaction_type?.emoji_type === emojiType) {
282
- await this.client.im.messageReaction.delete({
283
- path: { message_id: messageId, reaction_id: r.reaction_id }
284
- });
285
- break;
286
- }
287
- }
288
- } catch {
289
- }
290
- }
291
- /**
292
- * 主动向指定用户发送消息(不需要先收到消息)
293
- */
294
- async sendToUser(openId, text) {
295
- await this.client.im.message.create({
296
- params: { receive_id_type: "open_id" },
297
- data: {
298
- receive_id: openId,
299
- content: JSON.stringify({ text }),
300
- msg_type: "text"
301
- }
302
- });
303
- }
304
- };
305
-
306
115
  // src/lark/router.ts
307
116
  function parseMessage(text) {
308
117
  const trimmed = text.trim();
@@ -577,28 +386,41 @@ import fs2 from "fs";
577
386
  import path2 from "path";
578
387
 
579
388
  // src/session/skill.ts
580
- var SESSION_SKILL = `\u4F60\u662F KMR\uFF08Key Meetings Record\uFF09\u7684\u667A\u80FD\u52A9\u624B\u3002
389
+ var SESSION_SKILL = `\u4F60\u662F KMR\uFF08Key Meetings Record\uFF09\u7684\u667A\u80FD\u52A9\u624B\uFF0C\u8FD0\u884C\u5728\u98DE\u4E66\u673A\u5668\u4EBA\u4E2D\u3002
581
390
 
582
391
  \u4F60\u7684\u804C\u8D23\uFF1A
583
392
  1. \u5E2E\u52A9\u7528\u6237\u7406\u89E3\u548C\u7BA1\u7406\u4F1A\u8BAE\u8BB0\u5F55
584
393
  2. \u56DE\u7B54\u5173\u4E8E\u5386\u53F2\u4F1A\u8BAE\u5185\u5BB9\u7684\u95EE\u9898
585
394
  3. \u5E2E\u52A9\u7528\u6237\u6574\u7406\u3001\u603B\u7ED3\u5DE5\u4F5C\u4E2D\u7684\u4FE1\u606F
586
- 4. \u63D0\u4F9B\u5DE5\u4F5C\u5EFA\u8BAE\u548C\u77E5\u8BC6\u68C0\u7D22
395
+ 4. \u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1\u3001\u53D1\u9001\u98DE\u4E66\u6D88\u606F\u7B49\u64CD\u4F5C
587
396
 
588
397
  \u80CC\u666F\u4FE1\u606F\uFF1A
589
398
  - KMR \u662F\u4E00\u4E2A\u4ECE\u98DE\u4E66\u4F1A\u8BAE\u7EAA\u8981\u4E2D\u63D0\u53D6\u5173\u952E\u4FE1\u606F\u5E76\u6316\u6398\u51FA\u5171\u8BC6\u3001\u627F\u8BFA\u3001\u98CE\u9669\u3001\u5F85\u529E\u3001\u77E5\u8BC6\u7684\u670D\u52A1
590
399
  - \u6838\u5FC3\u63D0\u53D6\u7EF4\u5EA6\uFF1A\u5173\u952E\u5171\u8BC6\u4E0E\u627F\u8BFA\uFF08\u6EAF\u6E90\u8FFD\u8D23\uFF09\u3001\u53EF\u590D\u7528\u77E5\u8BC6\uFF08\u5DE5\u5177/\u65B9\u6CD5/\u7ECF\u9A8C\uFF09\u3001\u98CE\u9669\u4E0E\u5F85\u529E\uFF08\u98CE\u9669\u9884\u8B66/\u4EFB\u52A1\u8DDF\u8E2A\uFF09
591
400
 
592
- \u6570\u636E\u8BBF\u95EE\uFF1A
593
- - \u4F1A\u8BAE\u8BB0\u5F55\u5B58\u50A8\u5728 ~/.kmr/data/meetings/ \u76EE\u5F55\u4E0B\uFF0C\u6BCF\u4E2A\u4F1A\u8BAE\u662F\u4E00\u4E2A JSON \u6587\u4EF6
594
- - \u6BCF\u4E2A JSON \u6587\u4EF6\u5305\u542B\uFF1Asummary\uFF08\u6807\u9898/\u65E5\u671F/\u53C2\u4E0E\u4EBA/\u8981\u70B9\uFF09\u3001todos\u3001risks\u3001commitments\u3001reusableInsights\u3001rawContent
595
- - \u4F60\u53EF\u4EE5\u901A\u8FC7\u4EE5\u4E0B\u547D\u4EE4\u67E5\u8BE2\u4F1A\u8BAE\u6570\u636E\uFF1Akmr list\uFF08\u5217\u51FA\u5168\u90E8\uFF09\u3001kmr show <id>\uFF08\u67E5\u770B\u8BE6\u60C5\uFF09\u3001kmr find <query>\uFF08\u641C\u7D22\uFF09
596
- - \u5F53\u7528\u6237\u95EE\u5230\u4F1A\u8BAE/\u4EFB\u52A1\u76F8\u5173\u7684\u95EE\u9898\u65F6\uFF0C\u76F4\u63A5\u6267\u884C kmr \u547D\u4EE4\u83B7\u53D6\u6570\u636E\u5E76\u56DE\u7B54
597
- - \u63D0\u793A\u7528\u6237\u5728\u98DE\u4E66\u5BF9\u8BDD\u4E2D\u53EF\u4EE5\u4F7F\u7528\uFF1A/find \u641C\u7D22\u3001/list \u5217\u51FA\u5168\u90E8\u3001/show <id> \u67E5\u770B\u8BE6\u60C5\u3001/del <id> \u5220\u9664; \u6216\u8005\u5728\u7EC8\u7AEF\u4F7F\u7528\u4E0A\u8FF0kmr\u547D\u4EE4\u8FDB\u884C\u64CD\u4F5C
401
+ \u8FD0\u884C\u73AF\u5883\uFF1A
402
+ - \u4F60\u8FD0\u884C\u5728\u98DE\u4E66\u673A\u5668\u4EBA\u4E2D\uFF0C\u4F60\u7684\u56DE\u590D\u4F1A\u76F4\u63A5\u4F5C\u4E3A\u98DE\u4E66\u6D88\u606F\u53D1\u9001\u5230\u7528\u6237\u6240\u5728\u7684\u5BF9\u8BDD\u4E2D
403
+ - \u4E0D\u8981\u8BF4"\u6211\u6CA1\u6709\u53D1\u6D88\u606F/\u521B\u5EFA\u4EFB\u52A1\u7684\u80FD\u529B"\u2014\u2014\u4F60\u53EF\u4EE5\u901A\u8FC7 kmr \u547D\u4EE4\u6765\u5B8C\u6210\u8FD9\u4E9B\u64CD\u4F5C
404
+ - \u4F60\u6709\u80FD\u529B\u901A\u8FC7 kmr \u547D\u4EE4\u67E5\u8BE2\u6570\u636E\u3001\u521B\u5EFA\u4EFB\u52A1\u3001\u53D1\u9001\u6D88\u606F
405
+
406
+ \u53EF\u7528\u7684 kmr \u547D\u4EE4\uFF08\u901A\u8FC7 bash \u6267\u884C\uFF09\uFF1A
407
+ - kmr list \u2014 \u5217\u51FA\u6240\u6709\u4F1A\u8BAE\u8BB0\u5F55
408
+ - kmr show <id> \u2014 \u67E5\u770B\u4F1A\u8BAE\u8BB0\u5F55\u8BE6\u60C5
409
+ - kmr find <query> \u2014 \u641C\u7D22\u4F1A\u8BAE\u8BB0\u5F55
410
+ - kmr task \u2014 \u67E5\u770B\u6240\u6709\u4EFB\u52A1
411
+ - kmr del <id> \u2014 \u5220\u9664\u8BB0\u5F55
412
+ - kmr create-task <\u4EFB\u52A1\u6807\u9898> [--due YYYY-MM-DD] [--assignee \u59D3\u540D] [--desc \u63CF\u8FF0] \u2014 \u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1
413
+ - kmr send <\u6D88\u606F\u5185\u5BB9> \u2014 \u5411\u7BA1\u7406\u5458\u53D1\u9001\u98DE\u4E66\u6D88\u606F
414
+
415
+ \u64CD\u4F5C\u6307\u5357\uFF1A
416
+ - \u5F53\u7528\u6237\u8981\u6C42\u521B\u5EFA\u4EFB\u52A1\u65F6\uFF0C\u76F4\u63A5\u6267\u884C kmr create-task \u547D\u4EE4\uFF0C\u4F8B\u5982\uFF1Akmr create-task "\u5B8C\u6210\u65B9\u6848\u8BBE\u8BA1" --due 2026-05-15 --assignee \u5F20\u4E09
417
+ - \u5F53\u7528\u6237\u8981\u6C42\u53D1\u6D88\u606F\u7ED9\u7BA1\u7406\u5458\u6216\u901A\u77E5\u67D0\u4EBA\u65F6\uFF0C\u4F7F\u7528 kmr send \u547D\u4EE4
418
+ - \u5F53\u7528\u6237\u95EE\u5230\u4F1A\u8BAE/\u4EFB\u52A1\u76F8\u5173\u7684\u95EE\u9898\u65F6\uFF0C\u5148\u6267\u884C kmr \u547D\u4EE4\u83B7\u53D6\u6570\u636E\u518D\u56DE\u7B54
419
+ - \u63D0\u793A\u7528\u6237\u5728\u98DE\u4E66\u5BF9\u8BDD\u4E2D\u4E5F\u53EF\u4EE5\u76F4\u63A5\u4F7F\u7528\uFF1A/find \u641C\u7D22\u3001/list \u5217\u51FA\u5168\u90E8\u3001/show <id> \u67E5\u770B\u8BE6\u60C5\u3001/del <id> \u5220\u9664\u3001/task \u67E5\u770B\u4EFB\u52A1
598
420
 
599
421
  \u5BF9\u8BDD\u8981\u6C42\uFF1A
600
422
  - \u7B80\u6D01\u3001\u4E13\u4E1A\u3001\u6709\u5E2E\u52A9
601
- - \u4F18\u5148\u901A\u8FC7 kmr \u547D\u4EE4\u83B7\u53D6\u6570\u636E\u56DE\u7B54\u95EE\u9898\uFF1B\u5982\u679C\u7528\u6237\u660E\u786E\u60F3\u81EA\u5DF1\u64CD\u4F5C\uFF0C\u4E5F\u53EF\u4EE5\u544A\u77E5\u5BF9\u5E94\u547D\u4EE4
423
+ - \u4F18\u5148\u901A\u8FC7 kmr \u547D\u4EE4\u83B7\u53D6\u6570\u636E\u548C\u6267\u884C\u64CD\u4F5C\uFF1B\u5982\u679C\u7528\u6237\u660E\u786E\u60F3\u81EA\u5DF1\u64CD\u4F5C\uFF0C\u4E5F\u53EF\u4EE5\u544A\u77E5\u5BF9\u5E94\u547D\u4EE4
602
424
  - \u6BCF\u6B21\u56DE\u590D\u63A7\u5236\u5728\u5408\u7406\u957F\u5EA6\uFF0C\u9002\u5408\u98DE\u4E66\u6D88\u606F\u9605\u8BFB
603
425
 
604
426
  \u3010\u91CD\u8981\u3011\u76F4\u63A5\u8F93\u51FA\u7EAF\u6587\u672C\u56DE\u590D\uFF0C\u4E0D\u8981\u8F93\u51FA JSON\u3001markdown \u4EE3\u7801\u5757\u7B49\u683C\u5F0F\u3002`;
@@ -734,63 +556,6 @@ var SessionManager = class {
734
556
  }
735
557
  };
736
558
 
737
- // src/lark/userResolver.ts
738
- var UserResolver = class {
739
- constructor(client) {
740
- this.client = client;
741
- }
742
- client;
743
- // name -> openId 映射(支持多个群的成员合并)
744
- nameMap = /* @__PURE__ */ new Map();
745
- loadedChats = /* @__PURE__ */ new Set();
746
- /**
747
- * 根据姓名解析 open_id
748
- * 如果缓存中没有,返回 undefined
749
- */
750
- resolve(name) {
751
- if (this.nameMap.has(name)) return this.nameMap.get(name);
752
- for (const [key, value] of this.nameMap) {
753
- if (key.includes(name) || name.includes(key)) return value;
754
- }
755
- return void 0;
756
- }
757
- /**
758
- * 加载某个群的成员列表到缓存
759
- */
760
- async loadChatMembers(chatId) {
761
- if (this.loadedChats.has(chatId)) return;
762
- try {
763
- let pageToken;
764
- do {
765
- const response = await this.client.im.chatMembers.get({
766
- path: { chat_id: chatId },
767
- params: {
768
- member_id_type: "open_id",
769
- page_size: 100,
770
- ...pageToken ? { page_token: pageToken } : {}
771
- }
772
- });
773
- const items = response.data?.items || [];
774
- for (const item of items) {
775
- if (item.name && item.member_id) {
776
- this.nameMap.set(item.name, item.member_id);
777
- }
778
- }
779
- pageToken = response.data?.has_more ? response.data?.page_token : void 0;
780
- } while (pageToken);
781
- this.loadedChats.add(chatId);
782
- } catch (err) {
783
- console.error(`[user-resolver] \u52A0\u8F7D\u7FA4\u6210\u5458\u5931\u8D25:`, err.message);
784
- }
785
- }
786
- /**
787
- * 获取当前所有已缓存的映射
788
- */
789
- getAll() {
790
- return new Map(this.nameMap);
791
- }
792
- };
793
-
794
559
  // src/index.ts
795
560
  async function main() {
796
561
  const config = loadConfig();
@@ -992,9 +757,9 @@ async function main() {
992
757
  break;
993
758
  }
994
759
  console.log(`[process] \u81EA\u7531\u5BF9\u8BDD, userId=${senderId}`);
995
- await messenger.addReaction(messageId, "OnIt");
760
+ const reactionId = await messenger.addReaction(messageId, "OnIt");
996
761
  const reply = await sessionManager.handleMessage(senderId, text);
997
- await messenger.removeReaction(messageId, "OnIt");
762
+ await messenger.removeReaction(messageId, reactionId);
998
763
  await messenger.replyText(messageId, reply);
999
764
  break;
1000
765
  }
@@ -0,0 +1,6 @@
1
+ import {
2
+ Messenger
3
+ } from "./chunk-VYFCZATK.js";
4
+ export {
5
+ Messenger
6
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ UserResolver
3
+ } from "./chunk-2IG4NXRZ.js";
4
+ export {
5
+ UserResolver
6
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lih-x-x/kmr",
3
- "version": "1.0.39",
3
+ "version": "1.0.41",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {