@lih-x-x/kmr 1.0.60 → 1.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,12 +5,13 @@
5
5
  ## 功能
6
6
 
7
7
  - **会议纪要提取**:发送飞书云文档链接给机器人,自动提取会议摘要、待办事项、风险项、关键共识、可复用知识
8
- - **飞书任务创建**:提取待办后自动发送确认消息,回复 `/confirm` 创建飞书任务,`/reject` 取消,3 分钟超时自动取消。自动通过群成员列表解析负责人并指派任务
9
- - **任务状态同步**:每小时自动从飞书拉取任务最新状态,查询时也会实时刷新。通过 `/task` 指令或 `kmr task` 命令查看所有任务详情
10
- - **首次启动自动引导**:无配置文件时自动初始化并打开 Web 设置页引导填写飞书凭证,配置完成后自动继续启动,无需手动 `kmr init`
8
+ - **任务闭环**:提取待办后自动发送确认消息,回复 `/confirm` 创建飞书任务,`/reject` 取消,3 分钟超时自动取消。自动通过群成员列表解析负责人并指派任务,同步回写会议记录
9
+ - **本地 AI · 零成本接入**:基于 [acpx](https://www.npmjs.com/package/acpx) 复用本地 Claude / Codex,接入飞书机器人实现私有化部署,数据不出本机,无额外 API 费用
10
+ - **历史信息搜索**:会议记录和任务均可通过 AI 对话查询;`/find` 指令与自然语言双支持,返回最相关的 3 条结果
11
+ - **指令 / 自然语言双支持**:`/list`、`/show`、`/del`、`/find`、`/task` 等精确指令,与自由对话文本均可使用,AI 理解意图自动路由到对应操作
11
12
  - **AI 自由对话**:发送非指令文本即可与 AI 自由对话,基于 acpx 持久化 session,按用户隔离,支持 claude 和 codex 两种 agent。AI 可直接调用 `kmr` 命令创建任务、查询记录,回复通过飞书机器人发送,处理中显示表情回应
12
13
  - **独立任务创建**:通过 `kmr create-task` 命令(或 AI 对话)直接创建飞书任务,支持关联到指定会议记录(`--meeting <id>`),无关联时存入独立任务记录
13
- - **历史会议查询**:通过 `/find` 指令用自然语言搜索历史会议记录
14
+ - **首次启动自动引导**:无配置文件时自动初始化并打开 Web 设置页引导填写飞书凭证,配置完成后自动继续启动,无需手动 `kmr init`
14
15
  - **记录管理**:`/list` 列出所有记录,`/show <id>` 查看详情,`/del <id>` 删除记录,`/task` 查看所有任务
15
16
  - **CLI 命令**:`kmr list`、`kmr show`、`kmr task`、`kmr del`、`kmr find` 等子命令可在终端直接操作,无需启动服务
16
17
  - **群聊智能识别**:群聊中非 @消息仅自动识别会议纪要文档链接(通过文档标题判断),其他操作需 @机器人
@@ -21,7 +22,7 @@
21
22
 
22
23
  ## 核心理念:不是记录员,而是分析师
23
24
 
24
- KMR 不做流水账式的会议记录搬运。每条提取结果都围绕两个核心目标:
25
+ KMR 不做流水账式的会议记录搬运。每条提取结果都围绕三个核心目标:
25
26
 
26
27
  ### 1. 溯源追责 — 关键共识与承诺
27
28
 
@@ -38,7 +39,13 @@ KMR 不做流水账式的会议记录搬运。每条提取结果都围绕两个
38
39
  }
39
40
  ```
40
41
 
41
- ### 2. 知识复用可提效的工具与方法
42
+ ### 2. 任务闭环会议待办变真实任务
43
+
44
+ > 会议待办不再悬空,从纪要到飞书任务全程自动。
45
+
46
+ 会议结束不是终点。KMR 提取待办后自动发起确认消息,回复 `/confirm` 即可在飞书创建任务并自动解析负责人,任务状态同步回写到会议记录——会开了,事就该定下来。
47
+
48
+ ### 3. 知识复用 — 可提效的工具与方法
42
49
 
43
50
  > 会上提到的工具用法、方法论、经验教训,下次用得上吗?
44
51
 
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.60") {
9
+ if (data.version && data.version !== "1.0.61") {
10
10
  console.log(`
11
- \u2B06\uFE0F \u65B0\u7248\u672C\u53EF\u7528: ${"1.0.60"} \u2192 ${data.version}`);
11
+ \u2B06\uFE0F \u65B0\u7248\u672C\u53EF\u7528: ${"1.0.61"} \u2192 ${data.version}`);
12
12
  console.log(` \u8FD0\u884C npm install -g ${"@lih-x-x/kmr"} \u66F4\u65B0
13
13
  `);
14
14
  }
@@ -56,7 +56,7 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
56
56
  kmr --help \u663E\u793A\u5E2E\u52A9
57
57
  `);
58
58
  } else if (command === "--version" || command === "-v") {
59
- console.log("1.0.60");
59
+ console.log("1.0.61");
60
60
  } else if (command === "list") {
61
61
  const { loadConfig } = await import("./config-WIQGW5OC.js");
62
62
  const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
package/dist/index.js CHANGED
@@ -590,6 +590,7 @@ var SESSION_SKILL = `\u4F60\u662F KMR\uFF08Key Meetings Record\uFF09\u7684\u667A
590
590
  - \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
591
591
  - \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
592
592
  - \u4F60\u6709\u80FD\u529B\u901A\u8FC7 kmr \u547D\u4EE4\u67E5\u8BE2\u6570\u636E\u3001\u521B\u5EFA\u4EFB\u52A1\u3001\u7BA1\u7406\u8BB0\u5F55
593
+ - \u652F\u6301\u7684 agent provider\uFF1Aclaude\u3001codex\u3001cursor\u3001kiro\u3001openclaw\u3001opencode\u3001gemini\uFF08\u7531\u914D\u7F6E\u51B3\u5B9A\uFF0C\u8FD0\u884C\u65F6\u4E0D\u53EF\u5207\u6362\uFF09
593
594
 
594
595
  \u53EF\u7528\u7684 kmr \u547D\u4EE4\uFF08\u901A\u8FC7 bash \u6267\u884C\uFF09\uFF1A
595
596
  - kmr list \u2014 \u5217\u51FA\u6240\u6709\u4F1A\u8BAE\u8BB0\u5F55
@@ -597,11 +598,12 @@ var SESSION_SKILL = `\u4F60\u662F KMR\uFF08Key Meetings Record\uFF09\u7684\u667A
597
598
  - kmr find <query> \u2014 \u641C\u7D22\u4F1A\u8BAE\u8BB0\u5F55
598
599
  - kmr task \u2014 \u67E5\u770B\u6240\u6709\u4EFB\u52A1
599
600
  - kmr del <id> \u2014 \u5220\u9664\u8BB0\u5F55
600
- - kmr create-task <\u4EFB\u52A1\u6807\u9898> [--due YYYY-MM-DD] [--assignee \u59D3\u540D] [--desc \u63CF\u8FF0] [--meeting <id>] \u2014 \u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1\u5E76\u4FDD\u5B58\u5230\u672C\u5730\uFF08--meeting \u53EF\u5173\u8054\u5230\u6307\u5B9A\u4F1A\u8BAE\u8BB0\u5F55\uFF09
601
+ - kmr create-task <\u4EFB\u52A1\u6807\u9898> [--due YYYY-MM-DD] [--assignee \u59D3\u540D] [--desc \u63CF\u8FF0] [--meeting <id>] \u2014 \u521B\u5EFA\u98DE\u4E66\u4EFB\u52A1\u5E76\u4FDD\u5B58\u5230\u672C\u5730\uFF08--meeting \u53EF\u5173\u8054\u5230\u6307\u5B9A\u4F1A\u8BAE\u8BB0\u5F55\uFF0C\u82E5\u6709\uFF0C\u53EF\u9009\uFF09
601
602
 
602
603
  \u64CD\u4F5C\u6307\u5357\uFF1A
603
604
  - \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\uFF1B\u5982\u679C\u80FD\u5173\u8054\u5230\u67D0\u6761\u4F1A\u8BAE\u8BB0\u5F55\uFF0C\u52A0\u4E0A --meeting <id>
604
605
  - \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
606
+ - \u5F53\u7528\u6237\u95EE\u597D\u6216\u8005\u8BF7\u4F60\u4ECB\u7ECD\u65F6\uFF0C\u8981\u8F83\u4E3A\u8BE6\u7EC6\u5730\u4ECB\u7ECD\u81EA\u5DF1\u548C\u529F\u80FD\uFF0C\u5E2E\u52A9\u7528\u6237\u7406\u89E3\u4F60\u80FD\u505A\u4EC0\u4E48\u4EE5\u53CA\u4ED6\u80FD\u600E\u4E48\u4F7F\u7528
605
607
  - \u6BCF\u6761\u6D88\u606F\u5F00\u5934\u4F1A\u6709\u3010\u5F53\u524D\u73AF\u5883\u3011\u63D0\u793A\uFF0C\u544A\u8BC9\u4F60\u662F\u7FA4\u804A\u8FD8\u662F\u79C1\u804A\uFF1A
606
608
  - \u7FA4\u804A\uFF1A\u4F60\u7684\u56DE\u590D\u76F4\u63A5\u53D1\u5230\u7FA4\u91CC\uFF0C\u5982\u679C\u9700\u8981\u6307\u5B9A\u5BF9\u8C61\u5BF9\u8BDD\uFF0C\u53EF\u4EE5\u7528 @\u59D3\u540D \u6765\u63D0\u9192\u7FA4\u5185\u6210\u5458\uFF0C\u4E0D\u9700\u8981\u8BA9\u7528\u6237\u8F6C\u53D1
607
609
  - \u79C1\u804A\uFF1A\u65E0\u6CD5 @\u4ED6\u4EBA\uFF0C\u5982\u9700\u901A\u77E5\u4ED6\u4EBA\u8BF7\u62DF\u5236\u6D88\u606F\u5185\u5BB9\u5EFA\u8BAE\u7528\u6237\u8F6C\u53D1
@@ -630,7 +632,6 @@ var SessionManager = class {
630
632
  sessionDir;
631
633
  async handleMessage(userId, text, context) {
632
634
  const sessionName = await this.ensureSession(userId);
633
- console.log(`[session] \u53D1\u9001\u6D88\u606F\u5230 session: ${sessionName}`);
634
635
  let fullText = text;
635
636
  if (context) {
636
637
  const env = context.isGroup ? "\u3010\u5F53\u524D\u73AF\u5883\uFF1A\u7FA4\u804A\u3002\u4F60\u7684\u56DE\u590D\u4F1A\u53D1\u9001\u5230\u7FA4\u91CC\uFF0C\u5982\u679C\u9700\u8981\u6307\u5B9A\u5BF9\u8C61\u5BF9\u8BDD\uFF0C\u53EF\u4EE5\u76F4\u63A5\u7528 @\u59D3\u540D \u6765\u63D0\u9192\u7FA4\u5185\u6210\u5458\u3002\u3011" : "\u3010\u5F53\u524D\u73AF\u5883\uFF1A\u79C1\u804A\u3002\u65E0\u6CD5\u76F4\u63A5 @\u4ED6\u4EBA\uFF0C\u5982\u9700\u901A\u77E5\u4ED6\u4EBA\u8BF7\u62DF\u5236\u6D88\u606F\u5185\u5BB9\u8BA9\u7528\u6237\u8F6C\u53D1\u3002\u3011";
@@ -643,7 +644,8 @@ ${text}`;
643
644
  }
644
645
  getAgentCmd() {
645
646
  const provider = getAgentProvider();
646
- return provider === "codex" ? "codex" : provider;
647
+ const supported = ["claude", "codex", "cursor", "kiro", "openclaw", "opencode", "gemini"];
648
+ return supported.includes(provider) ? provider : "claude";
647
649
  }
648
650
  /**
649
651
  * 获取当前所有 claude-agent-acp 进程的 PID
@@ -686,7 +688,6 @@ ${text}`;
686
688
  (line) => !line.includes("[closed]") && line.split(" ")[1]?.trim() === sessionName
687
689
  );
688
690
  if (hasExisting) {
689
- console.log(`[session] \u53D1\u73B0\u6B8B\u7559 session: ${sessionName}\uFF0C\u5148\u5173\u95ED`);
690
691
  try {
691
692
  await execFileAsync("acpx", [agentCmd, "sessions", "close", sessionName], {
692
693
  timeout: 1e4,
@@ -806,11 +807,9 @@ ${text}`;
806
807
  async closeAll() {
807
808
  const userIds = [...this.activeSessions.keys()];
808
809
  if (userIds.length > 0) {
809
- console.log(`[session] \u6B63\u5728\u5173\u95ED ${userIds.length} \u4E2A\u6D3B\u8DC3 session...`);
810
810
  await Promise.all(userIds.map((uid) => this.closeSession(uid)));
811
811
  }
812
812
  if (this.ownedPids.size > 0) {
813
- console.log(`[session] \u6B63\u5728\u6E05\u7406 ${this.ownedPids.size} \u4E2A agent \u8FDB\u7A0B...`);
814
813
  for (const pid of this.ownedPids) {
815
814
  try {
816
815
  process.kill(pid, "SIGTERM");
@@ -874,7 +873,7 @@ async function main() {
874
873
  const botOpenId = await getBotOpenId(client);
875
874
  const dispatcher = createEventDispatcher(botOpenId, async (messageId, text, chatId, senderId, meta) => {
876
875
  const parsed = parseMessage(text);
877
- console.log(`[route] type=${parsed.type}, isGroup=${meta.isGroup}, isMentioned=${meta.isMentioned}`);
876
+ console.log(`[message] \u6536\u5230\u6D88\u606F: "${text}" (chatId=${chatId}, senderId=${senderId})`);
878
877
  if (meta.isGroup && !meta.isMentioned && parsed.type === "document_link" /* DOCUMENT_LINK */) {
879
878
  const title = await docReader.getDocumentTitle(parsed.documentId);
880
879
  const isMeetingNote = /纪要|会议记录|meeting/i.test(title) || /from=vc_assistant/.test(text);
@@ -290,8 +290,9 @@ async function renderSettings() {
290
290
  '<div class="form-field">' +
291
291
  '<label class="form-label">Provider</label>' +
292
292
  '<select class="form-select" id="cfg-provider">' +
293
- '<option value="claude"' + (config.agent.provider === 'claude' ? ' selected' : '') + '>claude</option>' +
294
- '<option value="codex"' + (config.agent.provider === 'codex' ? ' selected' : '') + '>codex</option>' +
293
+ ['claude', 'codex', 'cursor', 'kiro', 'openclaw', 'opencode', 'gemini'].map(function(p) {
294
+ return '<option value="' + p + '"' + (config.agent.provider === p ? ' selected' : '') + '>' + p + '</option>';
295
+ }).join('') +
295
296
  '</select>' +
296
297
  '</div>' +
297
298
  '<div class="form-field">' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lih-x-x/kmr",
3
- "version": "1.0.60",
3
+ "version": "1.0.61",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {