@lih-x-x/kmr 1.0.40 → 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.40") {
9
+ if (data.version && data.version !== "1.0.41") {
10
10
  console.log(`
11
- \u2B06\uFE0F \u65B0\u7248\u672C\u53EF\u7528: ${"1.0.40"} \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.40");
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,196 +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),返回 reaction_id
264
- */
265
- async addReaction(messageId, emojiType) {
266
- const res = await this.client.im.messageReaction.create({
267
- path: { message_id: messageId },
268
- data: { reaction_type: { emoji_type: emojiType } }
269
- });
270
- return res.data?.reaction_id || "";
271
- }
272
- /**
273
- * 删除指定的表情回应
274
- */
275
- async removeReaction(messageId, reactionId) {
276
- try {
277
- if (!reactionId) return;
278
- await this.client.im.messageReaction.delete({
279
- path: { message_id: messageId, reaction_id: reactionId }
280
- });
281
- } catch {
282
- }
283
- }
284
- /**
285
- * 主动向指定用户发送消息(不需要先收到消息)
286
- */
287
- async sendToUser(openId, text) {
288
- await this.client.im.message.create({
289
- params: { receive_id_type: "open_id" },
290
- data: {
291
- receive_id: openId,
292
- content: JSON.stringify({ text }),
293
- msg_type: "text"
294
- }
295
- });
296
- }
297
- };
298
-
299
115
  // src/lark/router.ts
300
116
  function parseMessage(text) {
301
117
  const trimmed = text.trim();
@@ -570,28 +386,41 @@ import fs2 from "fs";
570
386
  import path2 from "path";
571
387
 
572
388
  // src/session/skill.ts
573
- 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
574
390
 
575
391
  \u4F60\u7684\u804C\u8D23\uFF1A
576
392
  1. \u5E2E\u52A9\u7528\u6237\u7406\u89E3\u548C\u7BA1\u7406\u4F1A\u8BAE\u8BB0\u5F55
577
393
  2. \u56DE\u7B54\u5173\u4E8E\u5386\u53F2\u4F1A\u8BAE\u5185\u5BB9\u7684\u95EE\u9898
578
394
  3. \u5E2E\u52A9\u7528\u6237\u6574\u7406\u3001\u603B\u7ED3\u5DE5\u4F5C\u4E2D\u7684\u4FE1\u606F
579
- 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
580
396
 
581
397
  \u80CC\u666F\u4FE1\u606F\uFF1A
582
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
583
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
584
400
 
585
- \u6570\u636E\u8BBF\u95EE\uFF1A
586
- - \u4F1A\u8BAE\u8BB0\u5F55\u5B58\u50A8\u5728 ~/.kmr/data/meetings/ \u76EE\u5F55\u4E0B\uFF0C\u6BCF\u4E2A\u4F1A\u8BAE\u662F\u4E00\u4E2A JSON \u6587\u4EF6
587
- - \u6BCF\u4E2A JSON \u6587\u4EF6\u5305\u542B\uFF1Asummary\uFF08\u6807\u9898/\u65E5\u671F/\u53C2\u4E0E\u4EBA/\u8981\u70B9\uFF09\u3001todos\u3001risks\u3001commitments\u3001reusableInsights\u3001rawContent
588
- - \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
589
- - \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
590
- - \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
591
420
 
592
421
  \u5BF9\u8BDD\u8981\u6C42\uFF1A
593
422
  - \u7B80\u6D01\u3001\u4E13\u4E1A\u3001\u6709\u5E2E\u52A9
594
- - \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
595
424
  - \u6BCF\u6B21\u56DE\u590D\u63A7\u5236\u5728\u5408\u7406\u957F\u5EA6\uFF0C\u9002\u5408\u98DE\u4E66\u6D88\u606F\u9605\u8BFB
596
425
 
597
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`;
@@ -727,63 +556,6 @@ var SessionManager = class {
727
556
  }
728
557
  };
729
558
 
730
- // src/lark/userResolver.ts
731
- var UserResolver = class {
732
- constructor(client) {
733
- this.client = client;
734
- }
735
- client;
736
- // name -> openId 映射(支持多个群的成员合并)
737
- nameMap = /* @__PURE__ */ new Map();
738
- loadedChats = /* @__PURE__ */ new Set();
739
- /**
740
- * 根据姓名解析 open_id
741
- * 如果缓存中没有,返回 undefined
742
- */
743
- resolve(name) {
744
- if (this.nameMap.has(name)) return this.nameMap.get(name);
745
- for (const [key, value] of this.nameMap) {
746
- if (key.includes(name) || name.includes(key)) return value;
747
- }
748
- return void 0;
749
- }
750
- /**
751
- * 加载某个群的成员列表到缓存
752
- */
753
- async loadChatMembers(chatId) {
754
- if (this.loadedChats.has(chatId)) return;
755
- try {
756
- let pageToken;
757
- do {
758
- const response = await this.client.im.chatMembers.get({
759
- path: { chat_id: chatId },
760
- params: {
761
- member_id_type: "open_id",
762
- page_size: 100,
763
- ...pageToken ? { page_token: pageToken } : {}
764
- }
765
- });
766
- const items = response.data?.items || [];
767
- for (const item of items) {
768
- if (item.name && item.member_id) {
769
- this.nameMap.set(item.name, item.member_id);
770
- }
771
- }
772
- pageToken = response.data?.has_more ? response.data?.page_token : void 0;
773
- } while (pageToken);
774
- this.loadedChats.add(chatId);
775
- } catch (err) {
776
- console.error(`[user-resolver] \u52A0\u8F7D\u7FA4\u6210\u5458\u5931\u8D25:`, err.message);
777
- }
778
- }
779
- /**
780
- * 获取当前所有已缓存的映射
781
- */
782
- getAll() {
783
- return new Map(this.nameMap);
784
- }
785
- };
786
-
787
559
  // src/index.ts
788
560
  async function main() {
789
561
  const config = loadConfig();
@@ -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.40",
3
+ "version": "1.0.41",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {