@lih-x-x/kmr 1.0.23 → 1.0.25

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,171 @@
1
+ import {
2
+ getAgentProvider
3
+ } from "./chunk-ZXGVA5QX.js";
4
+
5
+ // src/agent/claudeCode.ts
6
+ import { execFile } from "child_process";
7
+ import { promisify } from "util";
8
+
9
+ // src/agent/prompt.ts
10
+ var EXTRACT_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u9AD8\u7EA7\u4F1A\u8BAE\u5206\u6790\u5E08\uFF0C\u4E0D\u662F\u8BB0\u5F55\u5458\u3002\u4F60\u7684\u4EFB\u52A1\u662F\u4ECE\u4F1A\u8BAE\u7EAA\u8981\u4E2D\u63D0\u70BC\u771F\u6B63\u6709\u4EF7\u503C\u7684\u4FE1\u606F\uFF0C\u800C\u4E0D\u662F\u6D41\u6C34\u8D26\u5F0F\u590D\u8FF0\u3002
11
+
12
+ \u4F60\u9700\u8981\u5E26\u7740\u4E24\u4E2A\u6838\u5FC3\u76EE\u6807\u5206\u6790\u4F1A\u8BAE\u5185\u5BB9\uFF1A
13
+ 1. **\u6EAF\u6E90\u8FFD\u8D23**\uFF1A\u63D0\u53D6\u6240\u6709\u660E\u786E\u7684\u627F\u8BFA\u3001\u7EA6\u5B9A\u3001\u51B3\u8BAE\u2014\u2014\u8C01\u7B54\u5E94\u4E86\u4EC0\u4E48\u3001\u4EC0\u4E48\u65F6\u5019\u5B8C\u6210\u3001\u8FBE\u6210\u4E86\u4EC0\u4E48\u5171\u8BC6\u3002\u5177\u4F53\u7684\u4EBA\u548C\u5177\u4F53\u7684\u65F6\u95F4\u662F\u6838\u5FC3\u951A\u70B9\uFF0C\u8FD9\u4E9B\u4FE1\u606F\u7528\u4E8E\u4E8B\u540E\u5FEB\u901F\u6EAF\u6E90\u3002
14
+ 2. **\u77E5\u8BC6\u590D\u7528**\uFF1A\u63D0\u53D6\u4F1A\u8BAE\u4E2D\u63D0\u5230\u7684\u5DE5\u5177\u7528\u6CD5\u3001\u65B9\u6CD5\u8BBA\u3001\u7ECF\u9A8C\u6559\u8BAD\u3001\u6700\u4F73\u5B9E\u8DF5\u2014\u2014\u8FD9\u4E9B\u53EF\u4EE5\u63D0\u5347\u5DE5\u4F5C\u6548\u7387\u7684\u53EF\u590D\u7528\u77E5\u8BC6\u3002
15
+
16
+ \u5206\u6790\u8981\u6C42\uFF1A
17
+ - participants\uFF1A\u5FC5\u987B\u5217\u51FA\u7EAA\u8981\u6587\u6863\u4E2D\u8BB0\u5F55\u7684\u53C2\u4E0E\u8BA8\u8BBA\u548C\u51B3\u7B56\u6216\u8005\u88AB\u63D0\u53CA\u7684\u6838\u5FC3\u6210\u5458\u540D\u5B57
18
+ - keyPoints\uFF1A\u53EA\u4FDD\u7559\u6700\u5173\u952E\u7684 3-8 \u4E2A\u51B3\u7B56\u6027\u8981\u70B9\uFF0C\u7F57\u5217\u7B80\u8981\u8BA8\u8BBA\u8FC7\u7A0B
19
+ - todos\uFF1A\u53EA\u63D0\u53D6\u6709\u660E\u786E\u8D1F\u8D23\u4EBA\u548C\u53EF\u6267\u884C\u5185\u5BB9\u7684\u5F85\u529E\uFF0C\u4E0D\u8981\u6A21\u7CCA\u7684"\u540E\u7EED\u8DDF\u8FDB"
20
+ - risks\uFF1A\u53EA\u63D0\u53D6\u771F\u6B63\u7684\u98CE\u9669\u548C\u672A\u51B3\u4E8B\u9879\uFF0C\u8981\u6709\u5177\u4F53\u7684\u7F13\u89E3\u65B9\u6848
21
+ - commitments\u3010\u6700\u91CD\u8981\u3011\uFF1A\u63D0\u53D6\u6240\u6709\u627F\u8BFA\u3001\u7EA6\u5B9A\u3001\u51B3\u8BAE\u3002context \u5B57\u6BB5\u5FC5\u987B\u5199\u4F60\u7684\u5206\u6790\u2014\u2014\u4E3A\u4EC0\u4E48\u4F1A\u8FBE\u6210\u8FD9\u4E2A\u5171\u8BC6\uFF0C\u80CC\u666F\u662F\u4EC0\u4E48\uFF0C\u8C01\u8FBE\u6210\u7684\uFF0C\u4E0D\u80FD\u53EA\u642C\u8FD0\u539F\u6587
22
+ - reusableInsights\u3010\u6700\u91CD\u8981\u3011\uFF1A\u63D0\u53D6\u53EF\u590D\u7528\u7684\u77E5\u8BC6\u3002scenario \u5B57\u6BB5\u5FC5\u987B\u5199\u8FD9\u4E2A\u77E5\u8BC6\u5728\u4EC0\u4E48\u573A\u666F\u4E0B\u6709\u7528\uFF0C\u4E0D\u80FD\u6CDB\u6CDB\u800C\u8C08\uFF0C\u8981\u6709\u5177\u4F53\u64CD\u4F5C\u5B9E\u8DF5\u6B65\u9AA4\u6307\u5BFC
23
+
24
+ \u3010\u91CD\u8981\u3011\u76F4\u63A5\u8F93\u51FA JSON\uFF0C\u4E0D\u8981\u8F93\u51FA\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3001\u89E3\u91CA\u6216 markdown \u4EE3\u7801\u5757\u3002\u4EC5\u8F93\u51FA\u4EE5\u4E0B\u683C\u5F0F\u7684 JSON\uFF1A
25
+ {"summary":{"title":"\u4F1A\u8BAE\u6807\u9898","date":"YYYY-MM-DD","participants":["\u53C2\u4E0E\u4EBA1"],"keyPoints":["\u51B3\u7B56\u6027\u8981\u70B9\uFF0C\u4E0D\u662F\u6D41\u6C34\u8D26"]},"todos":[{"content":"\u5177\u4F53\u53EF\u6267\u884C\u5185\u5BB9","owner":"\u8D1F\u8D23\u4EBA","deadline":"YYYY-MM-DD","status":"pending"}],"risks":[{"description":"\u5177\u4F53\u98CE\u9669","severity":"high|medium|low","mitigation":"\u5177\u4F53\u7F13\u89E3\u65B9\u6848"}],"projectRelations":[{"project":"\u9879\u76EE\u540D","relation":"\u5173\u8054\u63CF\u8FF0"}],"commitments":[{"content":"\u627F\u8BFA/\u7EA6\u5B9A/\u51B3\u8BAE\u7684\u5177\u4F53\u5185\u5BB9","participants":["\u76F8\u5173\u65B91","\u76F8\u5173\u65B92"],"deadline":"YYYY-MM-DD","context":"\u4F60\u7684\u5206\u6790\uFF1A\u4E3A\u4EC0\u4E48\u8FBE\u6210\u8FD9\u4E2A\u5171\u8BC6\uFF0C\u80CC\u666F\u548C\u5F71\u54CD\u662F\u4EC0\u4E48"}],"reusableInsights":[{"category":"tool|methodology|lesson|best-practice","content":"\u77E5\u8BC6\u70B9\u7684\u5177\u4F53\u5185\u5BB9","scenario":"\u5728\u4EC0\u4E48\u573A\u666F\u4E0B\u53EF\u4EE5\u590D\u7528\u8FD9\u4E2A\u77E5\u8BC6","source":"\u8C01\u63D0\u51FA\u7684"}]}
26
+
27
+ \u4F1A\u8BAE\u7EAA\u8981\u5185\u5BB9\uFF1A
28
+ `;
29
+ var SEARCH_KEYWORDS_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u641C\u7D22\u52A9\u624B\u3002\u7528\u6237\u60F3\u67E5\u627E\u5386\u53F2\u4F1A\u8BAE\u8BB0\u5F55\uFF0C\u8BF7\u5C06\u7528\u6237\u7684\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2\u8F6C\u6362\u4E3A\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868\u3002
30
+
31
+ \u8981\u6C42\uFF1A
32
+ - \u8FD4\u56DE 3-5 \u4E2A\u6700\u76F8\u5173\u7684\u5173\u952E\u8BCD
33
+ - \u4EC5\u8FD4\u56DE JSON \u6570\u7EC4\u683C\u5F0F\uFF0C\u4E0D\u8981\u5176\u4ED6\u5185\u5BB9
34
+ - \u793A\u4F8B\uFF1A["\u5173\u952E\u8BCD1", "\u5173\u952E\u8BCD2", "\u5173\u952E\u8BCD3"]
35
+
36
+ \u7528\u6237\u67E5\u8BE2\uFF1A`;
37
+ var RANK_RESULTS_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u641C\u7D22\u6392\u5E8F\u52A9\u624B\u3002\u7528\u6237\u67E5\u8BE2\u548C\u5019\u9009\u4F1A\u8BAE\u8BB0\u5F55\u5982\u4E0B\uFF0C\u8BF7\u6309\u76F8\u5173\u6027\u4ECE\u9AD8\u5230\u4F4E\u6392\u5E8F\u3002
38
+
39
+ \u4EC5\u8FD4\u56DE\u6392\u5E8F\u540E\u7684\u4F1A\u8BAE ID JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u5176\u4ED6\u5185\u5BB9\u3002
40
+ \u793A\u4F8B\uFF1A["meeting_003", "meeting_001"]
41
+
42
+ \u7528\u6237\u67E5\u8BE2\uFF1A`;
43
+
44
+ // src/utils/claudeEnv.ts
45
+ import fs from "fs";
46
+ import path from "path";
47
+ import os from "os";
48
+ var cachedEnv = null;
49
+ function getClaudeEnv() {
50
+ if (cachedEnv) return cachedEnv;
51
+ const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
52
+ let settingsEnv = {};
53
+ try {
54
+ const content = fs.readFileSync(settingsPath, "utf-8");
55
+ const settings = JSON.parse(content);
56
+ if (settings.env && typeof settings.env === "object") {
57
+ settingsEnv = settings.env;
58
+ }
59
+ } catch {
60
+ }
61
+ cachedEnv = { ...settingsEnv };
62
+ for (const key of Object.keys(settingsEnv)) {
63
+ if (process.env[key]) {
64
+ cachedEnv[key] = process.env[key];
65
+ }
66
+ }
67
+ return cachedEnv;
68
+ }
69
+ function getExecEnv() {
70
+ const claudeEnv = getClaudeEnv();
71
+ return { ...process.env, ...claudeEnv };
72
+ }
73
+
74
+ // src/agent/claudeCode.ts
75
+ var execFileAsync = promisify(execFile);
76
+ var ClaudeCodeProvider = class {
77
+ constructor(timeout = 12e4) {
78
+ this.timeout = timeout;
79
+ }
80
+ timeout;
81
+ name = "claude";
82
+ async extract(content) {
83
+ const prompt = EXTRACT_PROMPT + content;
84
+ console.log(`[ClaudeCodeProvider] \u63D0\u53D6\u4FE1\u606F\u7684 prompt:
85
+ ${prompt}
86
+ --- End of Prompt ---`);
87
+ const output = await this.callAcpx(prompt);
88
+ const parsed = JSON.parse(output);
89
+ return {
90
+ id: `meeting_${Date.now()}`,
91
+ documentUrl: "",
92
+ extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
93
+ summary: parsed.summary,
94
+ todos: (parsed.todos || []).map((t) => ({ ...t, status: "invalid_cause_no_task" })),
95
+ risks: parsed.risks || [],
96
+ projectRelations: parsed.projectRelations || [],
97
+ commitments: parsed.commitments || [],
98
+ reusableInsights: parsed.reusableInsights || [],
99
+ rawContent: content
100
+ };
101
+ }
102
+ async searchKeywords(query) {
103
+ const prompt = SEARCH_KEYWORDS_PROMPT + query;
104
+ const output = await this.callAcpx(prompt);
105
+ return JSON.parse(output);
106
+ }
107
+ async rankResults(query, candidates) {
108
+ if (candidates.length <= 1) return candidates;
109
+ const summaries = candidates.map((c) => ({
110
+ id: c.id,
111
+ title: c.summary.title,
112
+ keyPoints: c.summary.keyPoints
113
+ }));
114
+ const prompt = RANK_RESULTS_PROMPT + query + "\n\n\u5019\u9009\u4F1A\u8BAE\uFF1A\n" + JSON.stringify(summaries, null, 2);
115
+ const output = await this.callAcpx(prompt);
116
+ const rankedIds = JSON.parse(output);
117
+ const indexed = new Map(candidates.map((c) => [c.id, c]));
118
+ return rankedIds.map((id) => indexed.get(id)).filter(Boolean);
119
+ }
120
+ async callAcpx(prompt) {
121
+ const provider = getAgentProvider();
122
+ const agentCmd = provider === "codex" ? "codex" : provider;
123
+ console.log(`[agent] \u4F7F\u7528 ${agentCmd} \u6267\u884C\u63D0\u53D6`);
124
+ try {
125
+ const { stdout } = await execFileAsync("acpx", ["--allowed-tools", "", agentCmd, "exec", prompt], {
126
+ timeout: this.timeout,
127
+ maxBuffer: 1024 * 1024,
128
+ env: getExecEnv()
129
+ });
130
+ return this.extractJson(stdout);
131
+ } catch (err) {
132
+ if (err.killed) {
133
+ throw new Error(`acpx \u8C03\u7528\u8D85\u65F6 (${this.timeout}ms)`);
134
+ }
135
+ throw new Error(`acpx \u8C03\u7528\u5931\u8D25: ${err.message}`);
136
+ }
137
+ }
138
+ extractJson(output) {
139
+ const lines = output.split("\n");
140
+ let jsonStart = -1;
141
+ let jsonEnd = -1;
142
+ for (let i = 0; i < lines.length; i++) {
143
+ const trimmed = lines[i].trim();
144
+ if (jsonStart === -1 && (trimmed.startsWith("{") || trimmed.startsWith("["))) {
145
+ jsonStart = i;
146
+ }
147
+ if (trimmed.endsWith("}") || trimmed.endsWith("]")) {
148
+ jsonEnd = i;
149
+ }
150
+ }
151
+ if (jsonStart !== -1 && jsonEnd >= jsonStart) {
152
+ const candidate = lines.slice(jsonStart, jsonEnd + 1).join("\n").trim();
153
+ try {
154
+ JSON.parse(candidate);
155
+ return candidate;
156
+ } catch {
157
+ }
158
+ }
159
+ const filtered = lines.filter((line) => {
160
+ const t = line.trim();
161
+ return t.length > 0 && !t.startsWith("[client]") && !t.startsWith("[tool]") && !t.startsWith("[thinking]") && !t.startsWith("[done]") && !t.startsWith("[error]") && !t.startsWith("[warn]") && !t.startsWith("[info]");
162
+ }).join("\n").trim();
163
+ if (filtered.length > 0) return filtered;
164
+ return output.trim();
165
+ }
166
+ };
167
+
168
+ export {
169
+ getExecEnv,
170
+ ClaudeCodeProvider
171
+ };
@@ -0,0 +1,38 @@
1
+ // src/query/finder.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ async function grepMeetings(dataDir, keywords) {
5
+ if (!fs.existsSync(dataDir)) return [];
6
+ const files = fs.readdirSync(dataDir).filter((f) => f.endsWith(".json"));
7
+ const matches = [];
8
+ for (const file of files) {
9
+ const filePath = path.join(dataDir, file);
10
+ const raw = fs.readFileSync(filePath, "utf-8");
11
+ const hasMatch = keywords.some((kw) => raw.includes(kw));
12
+ if (hasMatch) {
13
+ matches.push(JSON.parse(raw));
14
+ }
15
+ }
16
+ return matches;
17
+ }
18
+
19
+ // src/query/handler.ts
20
+ var QueryHandler = class {
21
+ constructor(agent, dataDir) {
22
+ this.agent = agent;
23
+ this.dataDir = dataDir;
24
+ }
25
+ agent;
26
+ dataDir;
27
+ async find(query) {
28
+ const keywords = await this.agent.searchKeywords(query);
29
+ const candidates = await grepMeetings(this.dataDir, keywords);
30
+ if (candidates.length === 0) return [];
31
+ const ranked = await this.agent.rankResults(query, candidates);
32
+ return ranked.slice(0, 3);
33
+ }
34
+ };
35
+
36
+ export {
37
+ QueryHandler
38
+ };
@@ -0,0 +1,50 @@
1
+ // src/storage/jsonStore.ts
2
+ import fs from "fs";
3
+ import path from "path";
4
+ var JsonStore = class {
5
+ constructor(dataDir) {
6
+ this.dataDir = dataDir;
7
+ fs.mkdirSync(dataDir, { recursive: true });
8
+ }
9
+ dataDir;
10
+ async save(record) {
11
+ const date = record.summary.date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
12
+ const fileName = `${date}_${record.id}.json`;
13
+ const filePath = path.join(this.dataDir, fileName);
14
+ fs.writeFileSync(filePath, JSON.stringify(record, null, 2), "utf-8");
15
+ return filePath;
16
+ }
17
+ async load(id) {
18
+ const files = this.getFiles();
19
+ const target = files.find((f) => f.includes(id));
20
+ if (!target) return null;
21
+ const raw = fs.readFileSync(target, "utf-8");
22
+ return JSON.parse(raw);
23
+ }
24
+ async list() {
25
+ const files = this.getFiles();
26
+ return files.map((f) => JSON.parse(fs.readFileSync(f, "utf-8")));
27
+ }
28
+ async search(keywords) {
29
+ const all = await this.list();
30
+ return all.filter((record) => {
31
+ const text = record.rawContent + " " + record.summary.title + " " + record.summary.keyPoints.join(" ");
32
+ return keywords.some((kw) => text.includes(kw));
33
+ });
34
+ }
35
+ async delete(id) {
36
+ const files = this.getFiles();
37
+ const target = files.find((f) => f.includes(id));
38
+ if (!target) return false;
39
+ fs.unlinkSync(target);
40
+ return true;
41
+ }
42
+ getFiles() {
43
+ if (!fs.existsSync(this.dataDir)) return [];
44
+ return fs.readdirSync(this.dataDir).filter((f) => f.endsWith(".json")).map((f) => path.join(this.dataDir, f));
45
+ }
46
+ };
47
+
48
+ export {
49
+ JsonStore
50
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ ClaudeCodeProvider
3
+ } from "./chunk-KJPAKNVA.js";
4
+ import "./chunk-ZXGVA5QX.js";
5
+ export {
6
+ ClaudeCodeProvider
7
+ };
package/dist/cli.js CHANGED
@@ -49,14 +49,74 @@ KMR\uFF08Key Meetings Record\uFF09\u2014 \u4F1A\u8BAE\u6316\u6398\u673A
49
49
 
50
50
  \u7528\u6CD5:
51
51
  kmr init \u521D\u59CB\u5316\u914D\u7F6E\u76EE\u5F55 ~/.kmr/
52
- kmr --help \u663E\u793A\u5E2E\u52A9
53
52
  kmr \u542F\u52A8\u670D\u52A1\uFF08\u98DE\u4E66\u673A\u5668\u4EBA + Web \u7BA1\u7406\u754C\u9762\uFF09
53
+ kmr list \u5217\u51FA\u6240\u6709\u4F1A\u8BAE\u8BB0\u5F55
54
+ kmr show <id> \u67E5\u770B\u8BB0\u5F55\u8BE6\u60C5
55
+ kmr del <id> \u5220\u9664\u8BB0\u5F55
56
+ kmr find <q> \u641C\u7D22\u4F1A\u8BAE\u8BB0\u5F55
57
+ kmr --help \u663E\u793A\u5E2E\u52A9
54
58
  `);
55
59
  } else if (command === "--version" || command === "-v") {
56
60
  const { createRequire } = await import("module");
57
61
  const require2 = createRequire(import.meta.url);
58
62
  const pkg = require2("../package.json");
59
63
  console.log(pkg.version);
64
+ } else if (command === "list") {
65
+ const { loadConfig } = await import("./config-L2SVVMAR.js");
66
+ const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
67
+ const config = loadConfig();
68
+ const store = new JsonStore(config.storage.dataDir);
69
+ const all = await store.list();
70
+ all.sort((a, b) => b.extractedAt.localeCompare(a.extractedAt));
71
+ if (all.length === 0) {
72
+ console.log("\u6682\u65E0\u4F1A\u8BAE\u8BB0\u5F55");
73
+ } else {
74
+ for (const m of all) console.log(`${m.id} ${m.summary.title} ${m.summary.date}`);
75
+ }
76
+ } else if (command === "show") {
77
+ const id = argv[3];
78
+ if (!id) {
79
+ console.error("\u7528\u6CD5: kmr show <id>");
80
+ process.exit(1);
81
+ }
82
+ const { loadConfig } = await import("./config-L2SVVMAR.js");
83
+ const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
84
+ const store = new JsonStore(loadConfig().storage.dataDir);
85
+ const record = await store.load(id);
86
+ if (!record) {
87
+ console.error(`\u672A\u627E\u5230\u8BB0\u5F55: ${id}`);
88
+ process.exit(1);
89
+ }
90
+ console.log(JSON.stringify(record, null, 2));
91
+ } else if (command === "del") {
92
+ const id = argv[3];
93
+ if (!id) {
94
+ console.error("\u7528\u6CD5: kmr del <id>");
95
+ process.exit(1);
96
+ }
97
+ const { loadConfig } = await import("./config-L2SVVMAR.js");
98
+ const { JsonStore } = await import("./jsonStore-AL73KEUG.js");
99
+ const store = new JsonStore(loadConfig().storage.dataDir);
100
+ const ok = await store.delete(id);
101
+ console.log(ok ? `\u2705 \u5DF2\u5220\u9664: ${id}` : `\u274C \u672A\u627E\u5230: ${id}`);
102
+ } else if (command === "find") {
103
+ const query = argv.slice(3).join(" ");
104
+ if (!query) {
105
+ console.error("\u7528\u6CD5: kmr find <query>");
106
+ process.exit(1);
107
+ }
108
+ const { loadConfig } = await import("./config-L2SVVMAR.js");
109
+ const { ClaudeCodeProvider } = await import("./claudeCode-PPRQZG5K.js");
110
+ const { QueryHandler } = await import("./handler-46CQQIA2.js");
111
+ const config = loadConfig();
112
+ const agent = new ClaudeCodeProvider(config.agent.timeout);
113
+ const handler = new QueryHandler(agent, config.storage.dataDir);
114
+ const results = await handler.find(query);
115
+ if (results.length === 0) {
116
+ console.log("\u672A\u627E\u5230\u5339\u914D\u7684\u4F1A\u8BAE\u8BB0\u5F55");
117
+ } else {
118
+ for (const r of results) console.log(`${r.id} ${r.summary.title} ${r.documentUrl || ""}`);
119
+ }
60
120
  } else {
61
121
  checkUpdate();
62
122
  await import("./index.js");
@@ -0,0 +1,6 @@
1
+ import {
2
+ QueryHandler
3
+ } from "./chunk-SGTENG37.js";
4
+ export {
5
+ QueryHandler
6
+ };
package/dist/index.js CHANGED
@@ -1,8 +1,18 @@
1
+ import {
2
+ JsonStore
3
+ } from "./chunk-TUCCS6QJ.js";
4
+ import {
5
+ ClaudeCodeProvider,
6
+ getExecEnv
7
+ } from "./chunk-KJPAKNVA.js";
1
8
  import {
2
9
  KMR_DIR,
3
10
  getAgentProvider,
4
11
  loadConfig
5
12
  } from "./chunk-ZXGVA5QX.js";
13
+ import {
14
+ QueryHandler
15
+ } from "./chunk-SGTENG37.js";
6
16
 
7
17
  // src/lark/client.ts
8
18
  import * as lark from "@larksuiteoapi/node-sdk";
@@ -408,258 +418,13 @@ function parseMessage(text) {
408
418
  return { type: "unknown" /* UNKNOWN */, raw: text };
409
419
  }
410
420
 
411
- // src/agent/claudeCode.ts
412
- import { execFile } from "child_process";
413
- import { promisify } from "util";
414
-
415
- // src/agent/prompt.ts
416
- var EXTRACT_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u9AD8\u7EA7\u4F1A\u8BAE\u5206\u6790\u5E08\uFF0C\u4E0D\u662F\u8BB0\u5F55\u5458\u3002\u4F60\u7684\u4EFB\u52A1\u662F\u4ECE\u4F1A\u8BAE\u7EAA\u8981\u4E2D\u63D0\u70BC\u771F\u6B63\u6709\u4EF7\u503C\u7684\u4FE1\u606F\uFF0C\u800C\u4E0D\u662F\u6D41\u6C34\u8D26\u5F0F\u590D\u8FF0\u3002
417
-
418
- \u4F60\u9700\u8981\u5E26\u7740\u4E24\u4E2A\u6838\u5FC3\u76EE\u6807\u5206\u6790\u4F1A\u8BAE\u5185\u5BB9\uFF1A
419
- 1. **\u6EAF\u6E90\u8FFD\u8D23**\uFF1A\u63D0\u53D6\u6240\u6709\u660E\u786E\u7684\u627F\u8BFA\u3001\u7EA6\u5B9A\u3001\u51B3\u8BAE\u2014\u2014\u8C01\u7B54\u5E94\u4E86\u4EC0\u4E48\u3001\u4EC0\u4E48\u65F6\u5019\u5B8C\u6210\u3001\u8FBE\u6210\u4E86\u4EC0\u4E48\u5171\u8BC6\u3002\u5177\u4F53\u7684\u4EBA\u548C\u5177\u4F53\u7684\u65F6\u95F4\u662F\u6838\u5FC3\u951A\u70B9\uFF0C\u8FD9\u4E9B\u4FE1\u606F\u7528\u4E8E\u4E8B\u540E\u5FEB\u901F\u6EAF\u6E90\u3002
420
- 2. **\u77E5\u8BC6\u590D\u7528**\uFF1A\u63D0\u53D6\u4F1A\u8BAE\u4E2D\u63D0\u5230\u7684\u5DE5\u5177\u7528\u6CD5\u3001\u65B9\u6CD5\u8BBA\u3001\u7ECF\u9A8C\u6559\u8BAD\u3001\u6700\u4F73\u5B9E\u8DF5\u2014\u2014\u8FD9\u4E9B\u53EF\u4EE5\u63D0\u5347\u5DE5\u4F5C\u6548\u7387\u7684\u53EF\u590D\u7528\u77E5\u8BC6\u3002
421
-
422
- \u5206\u6790\u8981\u6C42\uFF1A
423
- - participants\uFF1A\u5FC5\u987B\u5217\u51FA\u7EAA\u8981\u6587\u6863\u4E2D\u8BB0\u5F55\u7684\u53C2\u4E0E\u8BA8\u8BBA\u548C\u51B3\u7B56\u6216\u8005\u88AB\u63D0\u53CA\u7684\u6838\u5FC3\u6210\u5458\u540D\u5B57
424
- - keyPoints\uFF1A\u53EA\u4FDD\u7559\u6700\u5173\u952E\u7684 3-8 \u4E2A\u51B3\u7B56\u6027\u8981\u70B9\uFF0C\u7F57\u5217\u7B80\u8981\u8BA8\u8BBA\u8FC7\u7A0B
425
- - todos\uFF1A\u53EA\u63D0\u53D6\u6709\u660E\u786E\u8D1F\u8D23\u4EBA\u548C\u53EF\u6267\u884C\u5185\u5BB9\u7684\u5F85\u529E\uFF0C\u4E0D\u8981\u6A21\u7CCA\u7684"\u540E\u7EED\u8DDF\u8FDB"
426
- - risks\uFF1A\u53EA\u63D0\u53D6\u771F\u6B63\u7684\u98CE\u9669\u548C\u672A\u51B3\u4E8B\u9879\uFF0C\u8981\u6709\u5177\u4F53\u7684\u7F13\u89E3\u65B9\u6848
427
- - commitments\u3010\u6700\u91CD\u8981\u3011\uFF1A\u63D0\u53D6\u6240\u6709\u627F\u8BFA\u3001\u7EA6\u5B9A\u3001\u51B3\u8BAE\u3002context \u5B57\u6BB5\u5FC5\u987B\u5199\u4F60\u7684\u5206\u6790\u2014\u2014\u4E3A\u4EC0\u4E48\u4F1A\u8FBE\u6210\u8FD9\u4E2A\u5171\u8BC6\uFF0C\u80CC\u666F\u662F\u4EC0\u4E48\uFF0C\u8C01\u8FBE\u6210\u7684\uFF0C\u4E0D\u80FD\u53EA\u642C\u8FD0\u539F\u6587
428
- - reusableInsights\u3010\u6700\u91CD\u8981\u3011\uFF1A\u63D0\u53D6\u53EF\u590D\u7528\u7684\u77E5\u8BC6\u3002scenario \u5B57\u6BB5\u5FC5\u987B\u5199\u8FD9\u4E2A\u77E5\u8BC6\u5728\u4EC0\u4E48\u573A\u666F\u4E0B\u6709\u7528\uFF0C\u4E0D\u80FD\u6CDB\u6CDB\u800C\u8C08\uFF0C\u8981\u6709\u5177\u4F53\u64CD\u4F5C\u5B9E\u8DF5\u6B65\u9AA4\u6307\u5BFC
429
-
430
- \u3010\u91CD\u8981\u3011\u76F4\u63A5\u8F93\u51FA JSON\uFF0C\u4E0D\u8981\u8F93\u51FA\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3001\u89E3\u91CA\u6216 markdown \u4EE3\u7801\u5757\u3002\u4EC5\u8F93\u51FA\u4EE5\u4E0B\u683C\u5F0F\u7684 JSON\uFF1A
431
- {"summary":{"title":"\u4F1A\u8BAE\u6807\u9898","date":"YYYY-MM-DD","participants":["\u53C2\u4E0E\u4EBA1"],"keyPoints":["\u51B3\u7B56\u6027\u8981\u70B9\uFF0C\u4E0D\u662F\u6D41\u6C34\u8D26"]},"todos":[{"content":"\u5177\u4F53\u53EF\u6267\u884C\u5185\u5BB9","owner":"\u8D1F\u8D23\u4EBA","deadline":"YYYY-MM-DD","status":"pending"}],"risks":[{"description":"\u5177\u4F53\u98CE\u9669","severity":"high|medium|low","mitigation":"\u5177\u4F53\u7F13\u89E3\u65B9\u6848"}],"projectRelations":[{"project":"\u9879\u76EE\u540D","relation":"\u5173\u8054\u63CF\u8FF0"}],"commitments":[{"content":"\u627F\u8BFA/\u7EA6\u5B9A/\u51B3\u8BAE\u7684\u5177\u4F53\u5185\u5BB9","participants":["\u76F8\u5173\u65B91","\u76F8\u5173\u65B92"],"deadline":"YYYY-MM-DD","context":"\u4F60\u7684\u5206\u6790\uFF1A\u4E3A\u4EC0\u4E48\u8FBE\u6210\u8FD9\u4E2A\u5171\u8BC6\uFF0C\u80CC\u666F\u548C\u5F71\u54CD\u662F\u4EC0\u4E48"}],"reusableInsights":[{"category":"tool|methodology|lesson|best-practice","content":"\u77E5\u8BC6\u70B9\u7684\u5177\u4F53\u5185\u5BB9","scenario":"\u5728\u4EC0\u4E48\u573A\u666F\u4E0B\u53EF\u4EE5\u590D\u7528\u8FD9\u4E2A\u77E5\u8BC6","source":"\u8C01\u63D0\u51FA\u7684"}]}
432
-
433
- \u4F1A\u8BAE\u7EAA\u8981\u5185\u5BB9\uFF1A
434
- `;
435
- var SEARCH_KEYWORDS_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u641C\u7D22\u52A9\u624B\u3002\u7528\u6237\u60F3\u67E5\u627E\u5386\u53F2\u4F1A\u8BAE\u8BB0\u5F55\uFF0C\u8BF7\u5C06\u7528\u6237\u7684\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2\u8F6C\u6362\u4E3A\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868\u3002
436
-
437
- \u8981\u6C42\uFF1A
438
- - \u8FD4\u56DE 3-5 \u4E2A\u6700\u76F8\u5173\u7684\u5173\u952E\u8BCD
439
- - \u4EC5\u8FD4\u56DE JSON \u6570\u7EC4\u683C\u5F0F\uFF0C\u4E0D\u8981\u5176\u4ED6\u5185\u5BB9
440
- - \u793A\u4F8B\uFF1A["\u5173\u952E\u8BCD1", "\u5173\u952E\u8BCD2", "\u5173\u952E\u8BCD3"]
441
-
442
- \u7528\u6237\u67E5\u8BE2\uFF1A`;
443
- var RANK_RESULTS_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u641C\u7D22\u6392\u5E8F\u52A9\u624B\u3002\u7528\u6237\u67E5\u8BE2\u548C\u5019\u9009\u4F1A\u8BAE\u8BB0\u5F55\u5982\u4E0B\uFF0C\u8BF7\u6309\u76F8\u5173\u6027\u4ECE\u9AD8\u5230\u4F4E\u6392\u5E8F\u3002
444
-
445
- \u4EC5\u8FD4\u56DE\u6392\u5E8F\u540E\u7684\u4F1A\u8BAE ID JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u5176\u4ED6\u5185\u5BB9\u3002
446
- \u793A\u4F8B\uFF1A["meeting_003", "meeting_001"]
447
-
448
- \u7528\u6237\u67E5\u8BE2\uFF1A`;
449
-
450
- // src/utils/claudeEnv.ts
451
- import fs from "fs";
452
- import path from "path";
453
- import os from "os";
454
- var cachedEnv = null;
455
- function getClaudeEnv() {
456
- if (cachedEnv) return cachedEnv;
457
- const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
458
- let settingsEnv = {};
459
- try {
460
- const content = fs.readFileSync(settingsPath, "utf-8");
461
- const settings = JSON.parse(content);
462
- if (settings.env && typeof settings.env === "object") {
463
- settingsEnv = settings.env;
464
- }
465
- } catch {
466
- }
467
- cachedEnv = { ...settingsEnv };
468
- for (const key of Object.keys(settingsEnv)) {
469
- if (process.env[key]) {
470
- cachedEnv[key] = process.env[key];
471
- }
472
- }
473
- return cachedEnv;
474
- }
475
- function getExecEnv() {
476
- const claudeEnv = getClaudeEnv();
477
- return { ...process.env, ...claudeEnv };
478
- }
479
-
480
- // src/agent/claudeCode.ts
481
- var execFileAsync = promisify(execFile);
482
- var ClaudeCodeProvider = class {
483
- constructor(timeout = 12e4) {
484
- this.timeout = timeout;
485
- }
486
- timeout;
487
- name = "claude";
488
- async extract(content) {
489
- const prompt = EXTRACT_PROMPT + content;
490
- console.log(`[ClaudeCodeProvider] \u63D0\u53D6\u4FE1\u606F\u7684 prompt:
491
- ${prompt}
492
- --- End of Prompt ---`);
493
- const output = await this.callAcpx(prompt);
494
- const parsed = JSON.parse(output);
495
- return {
496
- id: `meeting_${Date.now()}`,
497
- documentUrl: "",
498
- extractedAt: (/* @__PURE__ */ new Date()).toISOString(),
499
- summary: parsed.summary,
500
- todos: (parsed.todos || []).map((t) => ({ ...t, status: "invalid_cause_no_task" })),
501
- risks: parsed.risks || [],
502
- projectRelations: parsed.projectRelations || [],
503
- commitments: parsed.commitments || [],
504
- reusableInsights: parsed.reusableInsights || [],
505
- rawContent: content
506
- };
507
- }
508
- async searchKeywords(query) {
509
- const prompt = SEARCH_KEYWORDS_PROMPT + query;
510
- const output = await this.callAcpx(prompt);
511
- return JSON.parse(output);
512
- }
513
- async rankResults(query, candidates) {
514
- if (candidates.length <= 1) return candidates;
515
- const summaries = candidates.map((c) => ({
516
- id: c.id,
517
- title: c.summary.title,
518
- keyPoints: c.summary.keyPoints
519
- }));
520
- const prompt = RANK_RESULTS_PROMPT + query + "\n\n\u5019\u9009\u4F1A\u8BAE\uFF1A\n" + JSON.stringify(summaries, null, 2);
521
- const output = await this.callAcpx(prompt);
522
- const rankedIds = JSON.parse(output);
523
- const indexed = new Map(candidates.map((c) => [c.id, c]));
524
- return rankedIds.map((id) => indexed.get(id)).filter(Boolean);
525
- }
526
- async callAcpx(prompt) {
527
- const provider = getAgentProvider();
528
- const agentCmd = provider === "codex" ? "codex" : provider;
529
- console.log(`[agent] \u4F7F\u7528 ${agentCmd} \u6267\u884C\u63D0\u53D6`);
530
- try {
531
- const { stdout } = await execFileAsync("acpx", ["--allowed-tools", "", agentCmd, "exec", prompt], {
532
- timeout: this.timeout,
533
- maxBuffer: 1024 * 1024,
534
- env: getExecEnv()
535
- });
536
- return this.extractJson(stdout);
537
- } catch (err) {
538
- if (err.killed) {
539
- throw new Error(`acpx \u8C03\u7528\u8D85\u65F6 (${this.timeout}ms)`);
540
- }
541
- throw new Error(`acpx \u8C03\u7528\u5931\u8D25: ${err.message}`);
542
- }
543
- }
544
- extractJson(output) {
545
- const lines = output.split("\n");
546
- let jsonStart = -1;
547
- let jsonEnd = -1;
548
- for (let i = 0; i < lines.length; i++) {
549
- const trimmed = lines[i].trim();
550
- if (jsonStart === -1 && (trimmed.startsWith("{") || trimmed.startsWith("["))) {
551
- jsonStart = i;
552
- }
553
- if (trimmed.endsWith("}") || trimmed.endsWith("]")) {
554
- jsonEnd = i;
555
- }
556
- }
557
- if (jsonStart !== -1 && jsonEnd >= jsonStart) {
558
- const candidate = lines.slice(jsonStart, jsonEnd + 1).join("\n").trim();
559
- try {
560
- JSON.parse(candidate);
561
- return candidate;
562
- } catch {
563
- }
564
- }
565
- const filtered = lines.filter((line) => {
566
- const t = line.trim();
567
- return t.length > 0 && !t.startsWith("[client]") && !t.startsWith("[tool]") && !t.startsWith("[thinking]") && !t.startsWith("[done]") && !t.startsWith("[error]") && !t.startsWith("[warn]") && !t.startsWith("[info]");
568
- }).join("\n").trim();
569
- if (filtered.length > 0) return filtered;
570
- return output.trim();
571
- }
572
- };
573
-
574
- // src/storage/jsonStore.ts
575
- import fs2 from "fs";
576
- import path2 from "path";
577
- var JsonStore = class {
578
- constructor(dataDir) {
579
- this.dataDir = dataDir;
580
- fs2.mkdirSync(dataDir, { recursive: true });
581
- }
582
- dataDir;
583
- async save(record) {
584
- const date = record.summary.date || (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
585
- const fileName = `${date}_${record.id}.json`;
586
- const filePath = path2.join(this.dataDir, fileName);
587
- fs2.writeFileSync(filePath, JSON.stringify(record, null, 2), "utf-8");
588
- return filePath;
589
- }
590
- async load(id) {
591
- const files = this.getFiles();
592
- const target = files.find((f) => f.includes(id));
593
- if (!target) return null;
594
- const raw = fs2.readFileSync(target, "utf-8");
595
- return JSON.parse(raw);
596
- }
597
- async list() {
598
- const files = this.getFiles();
599
- return files.map((f) => JSON.parse(fs2.readFileSync(f, "utf-8")));
600
- }
601
- async search(keywords) {
602
- const all = await this.list();
603
- return all.filter((record) => {
604
- const text = record.rawContent + " " + record.summary.title + " " + record.summary.keyPoints.join(" ");
605
- return keywords.some((kw) => text.includes(kw));
606
- });
607
- }
608
- async delete(id) {
609
- const files = this.getFiles();
610
- const target = files.find((f) => f.includes(id));
611
- if (!target) return false;
612
- fs2.unlinkSync(target);
613
- return true;
614
- }
615
- getFiles() {
616
- if (!fs2.existsSync(this.dataDir)) return [];
617
- return fs2.readdirSync(this.dataDir).filter((f) => f.endsWith(".json")).map((f) => path2.join(this.dataDir, f));
618
- }
619
- };
620
-
621
- // src/query/finder.ts
622
- import fs3 from "fs";
623
- import path3 from "path";
624
- async function grepMeetings(dataDir, keywords) {
625
- if (!fs3.existsSync(dataDir)) return [];
626
- const files = fs3.readdirSync(dataDir).filter((f) => f.endsWith(".json"));
627
- const matches = [];
628
- for (const file of files) {
629
- const filePath = path3.join(dataDir, file);
630
- const raw = fs3.readFileSync(filePath, "utf-8");
631
- const hasMatch = keywords.some((kw) => raw.includes(kw));
632
- if (hasMatch) {
633
- matches.push(JSON.parse(raw));
634
- }
635
- }
636
- return matches;
637
- }
638
-
639
- // src/query/handler.ts
640
- var QueryHandler = class {
641
- constructor(agent, dataDir) {
642
- this.agent = agent;
643
- this.dataDir = dataDir;
644
- }
645
- agent;
646
- dataDir;
647
- async find(query) {
648
- const keywords = await this.agent.searchKeywords(query);
649
- const candidates = await grepMeetings(this.dataDir, keywords);
650
- if (candidates.length === 0) return [];
651
- const ranked = await this.agent.rankResults(query, candidates);
652
- return ranked.slice(0, 3);
653
- }
654
- };
655
-
656
421
  // src/web/server.ts
657
422
  import http from "http";
658
- import fs4 from "fs";
659
- import path4 from "path";
423
+ import fs from "fs";
424
+ import path from "path";
660
425
  import { fileURLToPath } from "url";
661
- var __dirname = path4.dirname(fileURLToPath(import.meta.url));
662
- var PUBLIC_DIR = path4.join(__dirname, "public");
426
+ var __dirname = path.dirname(fileURLToPath(import.meta.url));
427
+ var PUBLIC_DIR = path.join(__dirname, "public");
663
428
  var MIME_TYPES = {
664
429
  ".html": "text/html; charset=utf-8",
665
430
  ".css": "text/css; charset=utf-8",
@@ -669,30 +434,30 @@ var MIME_TYPES = {
669
434
  ".svg": "image/svg+xml"
670
435
  };
671
436
  function serveStatic(res, urlPath) {
672
- const safePath = path4.normalize(urlPath).replace(/^(\.\.[/\\])+/, "");
673
- let filePath = path4.join(PUBLIC_DIR, safePath === "/" ? "index.html" : safePath);
674
- if (!fs4.existsSync(filePath) || fs4.statSync(filePath).isDirectory()) {
675
- filePath = path4.join(PUBLIC_DIR, "index.html");
437
+ const safePath = path.normalize(urlPath).replace(/^(\.\.[/\\])+/, "");
438
+ let filePath = path.join(PUBLIC_DIR, safePath === "/" ? "index.html" : safePath);
439
+ if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
440
+ filePath = path.join(PUBLIC_DIR, "index.html");
676
441
  }
677
- const ext = path4.extname(filePath);
442
+ const ext = path.extname(filePath);
678
443
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
679
- const content = fs4.readFileSync(filePath);
444
+ const content = fs.readFileSync(filePath);
680
445
  res.writeHead(200, { "Content-Type": contentType });
681
446
  res.end(content);
682
447
  }
683
448
  function listSessions(kmrDir) {
684
- const sessionsDir = path4.join(kmrDir, "sessions");
685
- if (!fs4.existsSync(sessionsDir)) return [];
686
- return fs4.readdirSync(sessionsDir).filter((d) => {
687
- const full = path4.join(sessionsDir, d);
688
- return fs4.statSync(full).isDirectory();
449
+ const sessionsDir = path.join(kmrDir, "sessions");
450
+ if (!fs.existsSync(sessionsDir)) return [];
451
+ return fs.readdirSync(sessionsDir).filter((d) => {
452
+ const full = path.join(sessionsDir, d);
453
+ return fs.statSync(full).isDirectory();
689
454
  }).map((userId) => {
690
- const summaryPath = path4.join(sessionsDir, userId, "summary.md");
455
+ const summaryPath = path.join(sessionsDir, userId, "summary.md");
691
456
  let summaryPreview = "";
692
457
  let messageCount = 0;
693
458
  let lastActivity = "";
694
- if (fs4.existsSync(summaryPath)) {
695
- const content = fs4.readFileSync(summaryPath, "utf-8");
459
+ if (fs.existsSync(summaryPath)) {
460
+ const content = fs.readFileSync(summaryPath, "utf-8");
696
461
  const lines = content.split("\n").filter((l) => l.trim().length > 0);
697
462
  messageCount = lines.length;
698
463
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -704,26 +469,26 @@ function listSessions(kmrDir) {
704
469
  const lastLine = lines[lines.length - 1] || "";
705
470
  const timeMatch = lastLine.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]/);
706
471
  if (timeMatch) lastActivity = timeMatch[1];
707
- const stat = fs4.statSync(summaryPath);
472
+ const stat = fs.statSync(summaryPath);
708
473
  if (!lastActivity) lastActivity = stat.mtime.toISOString().replace("T", " ").slice(0, 19);
709
474
  } else {
710
- const userDir = path4.join(sessionsDir, userId);
711
- const stat = fs4.statSync(userDir);
475
+ const userDir = path.join(sessionsDir, userId);
476
+ const stat = fs.statSync(userDir);
712
477
  lastActivity = stat.mtime.toISOString().replace("T", " ").slice(0, 19);
713
478
  }
714
479
  return { userId, summaryPreview, messageCount, lastActivity };
715
480
  }).sort((a, b) => b.lastActivity.localeCompare(a.lastActivity));
716
481
  }
717
482
  function deleteSession(kmrDir, userId) {
718
- const sessionDir = path4.join(kmrDir, "sessions", userId);
719
- if (!fs4.existsSync(sessionDir)) return false;
720
- fs4.rmSync(sessionDir, { recursive: true, force: true });
483
+ const sessionDir = path.join(kmrDir, "sessions", userId);
484
+ if (!fs.existsSync(sessionDir)) return false;
485
+ fs.rmSync(sessionDir, { recursive: true, force: true });
721
486
  return true;
722
487
  }
723
488
  function getSessionDetail(kmrDir, userId) {
724
- const summaryPath = path4.join(kmrDir, "sessions", userId, "summary.md");
725
- if (!fs4.existsSync(summaryPath)) return null;
726
- return fs4.readFileSync(summaryPath, "utf-8");
489
+ const summaryPath = path.join(kmrDir, "sessions", userId, "summary.md");
490
+ if (!fs.existsSync(summaryPath)) return null;
491
+ return fs.readFileSync(summaryPath, "utf-8");
727
492
  }
728
493
  function startWebServer(store, kmrDir, port = 3e3) {
729
494
  return new Promise((resolve, reject) => {
@@ -793,8 +558,8 @@ async function handleApi(req, res, url, store, kmrDir) {
793
558
  return;
794
559
  }
795
560
  if (pathname === "/api/config" && method === "GET") {
796
- const configPath = path4.join(kmrDir, "config.json");
797
- const config = JSON.parse(fs4.readFileSync(configPath, "utf-8"));
561
+ const configPath = path.join(kmrDir, "config.json");
562
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
798
563
  jsonResponse(res, 200, { ok: true, data: config });
799
564
  return;
800
565
  }
@@ -807,8 +572,8 @@ async function handleApi(req, res, url, store, kmrDir) {
807
572
  jsonResponse(res, 400, { ok: false, error: "\u65E0\u6548\u7684 JSON \u683C\u5F0F" });
808
573
  return;
809
574
  }
810
- const configPath = path4.join(kmrDir, "config.json");
811
- fs4.writeFileSync(configPath, JSON.stringify(parsed, null, 2), "utf-8");
575
+ const configPath = path.join(kmrDir, "config.json");
576
+ fs.writeFileSync(configPath, JSON.stringify(parsed, null, 2), "utf-8");
812
577
  jsonResponse(res, 200, { ok: true, data: parsed });
813
578
  return;
814
579
  }
@@ -843,27 +608,27 @@ async function handleApi(req, res, url, store, kmrDir) {
843
608
  }
844
609
 
845
610
  // src/web/openBrowser.ts
846
- import { execFile as execFile2 } from "child_process";
611
+ import { execFile } from "child_process";
847
612
  function openBrowser(url) {
848
613
  const platform = process.platform;
849
614
  switch (platform) {
850
615
  case "darwin":
851
- execFile2("open", [url]);
616
+ execFile("open", [url]);
852
617
  break;
853
618
  case "win32":
854
- execFile2("cmd", ["/c", "start", url]);
619
+ execFile("cmd", ["/c", "start", url]);
855
620
  break;
856
621
  default:
857
- execFile2("xdg-open", [url]);
622
+ execFile("xdg-open", [url]);
858
623
  break;
859
624
  }
860
625
  }
861
626
 
862
627
  // src/session/manager.ts
863
- import { execFile as execFile3 } from "child_process";
864
- import { promisify as promisify2 } from "util";
865
- import fs5 from "fs";
866
- import path5 from "path";
628
+ import { execFile as execFile2 } from "child_process";
629
+ import { promisify } from "util";
630
+ import fs2 from "fs";
631
+ import path2 from "path";
867
632
 
868
633
  // src/session/skill.ts
869
634
  var SESSION_SKILL = `\u4F60\u662F KMR\uFF08Key Meetings Record\uFF09\u7684\u667A\u80FD\u52A9\u624B\u3002
@@ -875,30 +640,30 @@ var SESSION_SKILL = `\u4F60\u662F KMR\uFF08Key Meetings Record\uFF09\u7684\u667A
875
640
  4. \u63D0\u4F9B\u5DE5\u4F5C\u5EFA\u8BAE\u548C\u77E5\u8BC6\u68C0\u7D22
876
641
 
877
642
  \u80CC\u666F\u4FE1\u606F\uFF1A
878
- - KMR \u662F\u4E00\u4E2A\u4ECE\u98DE\u4E66\u4F1A\u8BAE\u7EAA\u8981\u4E2D\u63D0\u53D6\u5173\u952E\u4FE1\u606F\u7684\u670D\u52A1
879
- - \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
643
+ - 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
644
+ - \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
880
645
 
881
646
  \u6570\u636E\u8BBF\u95EE\uFF1A
882
647
  - \u4F1A\u8BAE\u8BB0\u5F55\u5B58\u50A8\u5728 ~/.kmr/data/meetings/ \u76EE\u5F55\u4E0B\uFF0C\u6BCF\u4E2A\u4F1A\u8BAE\u662F\u4E00\u4E2A JSON \u6587\u4EF6
883
- - \u4F60\u53EF\u4EE5\u76F4\u63A5\u7528 ls\u3001cat\u3001grep \u7B49\u547D\u4EE4\u8BFB\u53D6\u8FD9\u4E9B\u6587\u4EF6\u6765\u56DE\u7B54\u7528\u6237\u7684\u95EE\u9898
884
648
  - \u6BCF\u4E2A JSON \u6587\u4EF6\u5305\u542B\uFF1Asummary\uFF08\u6807\u9898/\u65E5\u671F/\u53C2\u4E0E\u4EBA/\u8981\u70B9\uFF09\u3001todos\u3001risks\u3001commitments\u3001reusableInsights\u3001rawContent
885
- - \u5F53\u7528\u6237\u95EE"\u6700\u8FD1\u7684\u4F1A\u8BAE"\u3001"\u4E0A\u6B21\u8BA8\u8BBA\u4E86\u4EC0\u4E48"\u7B49\u4EFB\u4F55\u4F60\u9700\u8981\u901A\u8FC7\u6587\u4EF6\u5185\u5BB9\u56DE\u7B54\u7684\u95EE\u9898\u65F6\uFF0C\u76F4\u63A5\u8BFB\u53D6\u6587\u4EF6\u5E76\u52A0\u5DE5\u56DE\u7B54
886
- - \u7528\u6237\u4E5F\u53EF\u4EE5\u4F7F\u7528\u4EE5\u4E0B\u547D\u4EE4\uFF1A/find \u641C\u7D22\u3001/listall \u5217\u51FA\u5168\u90E8\u3001/show <id> \u67E5\u770B\u8BE6\u60C5\u3001/del <id> \u5220\u9664
649
+ - \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
650
+ - \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
651
+ - \u63D0\u793A\u7528\u6237\u5728\u98DE\u4E66\u5BF9\u8BDD\u4E2D\u53EF\u4EE5\u4F7F\u7528\uFF1A/find \u641C\u7D22\u3001/listall \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
887
652
 
888
653
  \u5BF9\u8BDD\u8981\u6C42\uFF1A
889
654
  - \u7B80\u6D01\u3001\u4E13\u4E1A\u3001\u6709\u5E2E\u52A9
890
- - \u4F18\u5148\u76F4\u63A5\u8BFB\u53D6\u6570\u636E\u56DE\u7B54\u95EE\u9898\uFF1B\u5982\u679C\u7528\u6237\u660E\u786E\u60F3\u7528\u547D\u4EE4\u64CD\u4F5C\uFF0C\u4E5F\u53EF\u4EE5\u544A\u77E5\u5BF9\u5E94\u547D\u4EE4
655
+ - \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
891
656
  - \u6BCF\u6B21\u56DE\u590D\u63A7\u5236\u5728\u5408\u7406\u957F\u5EA6\uFF0C\u9002\u5408\u98DE\u4E66\u6D88\u606F\u9605\u8BFB
892
657
 
893
658
  \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`;
894
659
 
895
660
  // src/session/manager.ts
896
- var execFileAsync2 = promisify2(execFile3);
661
+ var execFileAsync = promisify(execFile2);
897
662
  var SessionManager = class {
898
663
  constructor(kmrDir, timeout = 6e4) {
899
664
  this.timeout = timeout;
900
- this.sessionDir = path5.join(kmrDir, "sessions");
901
- fs5.mkdirSync(this.sessionDir, { recursive: true });
665
+ this.sessionDir = path2.join(kmrDir, "sessions");
666
+ fs2.mkdirSync(this.sessionDir, { recursive: true });
902
667
  }
903
668
  timeout;
904
669
  activeSessions = /* @__PURE__ */ new Map();
@@ -921,14 +686,14 @@ var SessionManager = class {
921
686
  return existing.name;
922
687
  }
923
688
  const sessionName = `kmr-${userId}`;
924
- const userDir = path5.join(this.sessionDir, userId);
925
- fs5.mkdirSync(userDir, { recursive: true });
926
- const skillPath = path5.join(userDir, "skill.md");
927
- fs5.writeFileSync(skillPath, SESSION_SKILL, "utf-8");
689
+ const userDir = path2.join(this.sessionDir, userId);
690
+ fs2.mkdirSync(userDir, { recursive: true });
691
+ const skillPath = path2.join(userDir, "skill.md");
692
+ fs2.writeFileSync(skillPath, SESSION_SKILL, "utf-8");
928
693
  console.log(`[session] \u521B\u5EFA\u65B0 session: ${sessionName}`);
929
694
  const agentCmd = this.getAgentCmd();
930
695
  try {
931
- await execFileAsync2("acpx", [agentCmd, "sessions", "ensure", "--name", sessionName], {
696
+ await execFileAsync("acpx", [agentCmd, "sessions", "ensure", "--name", sessionName], {
932
697
  timeout: this.timeout,
933
698
  maxBuffer: 1024 * 1024,
934
699
  env: getExecEnv()
@@ -939,7 +704,7 @@ var SessionManager = class {
939
704
  }
940
705
  console.log(`[session] \u53D1\u9001\u89D2\u8272\u8BBE\u5B9A...`);
941
706
  try {
942
- await execFileAsync2(
707
+ await execFileAsync(
943
708
  "acpx",
944
709
  ["--approve-all", agentCmd, "-s", sessionName, SESSION_SKILL],
945
710
  { timeout: this.timeout, maxBuffer: 1024 * 1024, env: getExecEnv() }
@@ -956,11 +721,13 @@ var SessionManager = class {
956
721
  async sendToSession(sessionName, text) {
957
722
  const agentCmd = this.getAgentCmd();
958
723
  try {
959
- const { stdout } = await execFileAsync2(
724
+ const { stdout } = await execFileAsync(
960
725
  "acpx",
961
726
  ["--approve-all", agentCmd, "-s", sessionName, text],
962
727
  { timeout: this.timeout, maxBuffer: 1024 * 1024, env: getExecEnv() }
963
728
  );
729
+ console.log(`[session] agent \u5B8C\u6574\u8F93\u51FA:
730
+ ${stdout}`);
964
731
  return this.extractReply(stdout);
965
732
  } catch (err) {
966
733
  if (err.killed) {
@@ -999,21 +766,21 @@ var SessionManager = class {
999
766
  return output.trim();
1000
767
  }
1001
768
  async appendSummary(userId, userText, aiReply) {
1002
- const userDir = path5.join(this.sessionDir, userId);
1003
- const summaryPath = path5.join(userDir, "summary.md");
769
+ const userDir = path2.join(this.sessionDir, userId);
770
+ const summaryPath = path2.join(userDir, "summary.md");
1004
771
  const now = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
1005
772
  const entry = `
1006
773
  [${now}] \u7528\u6237: ${userText}
1007
774
  [${now}] AI: ${aiReply}
1008
775
  `;
1009
- fs5.appendFileSync(summaryPath, entry, "utf-8");
776
+ fs2.appendFileSync(summaryPath, entry, "utf-8");
1010
777
  }
1011
778
  async closeSession(userId) {
1012
779
  const info = this.activeSessions.get(userId);
1013
780
  if (!info) return;
1014
781
  try {
1015
782
  const agentCmd = this.getAgentCmd();
1016
- await execFileAsync2("acpx", [agentCmd, "sessions", "close", info.name], {
783
+ await execFileAsync("acpx", [agentCmd, "sessions", "close", info.name], {
1017
784
  timeout: 1e4,
1018
785
  env: getExecEnv()
1019
786
  });
@@ -0,0 +1,6 @@
1
+ import {
2
+ JsonStore
3
+ } from "./chunk-TUCCS6QJ.js";
4
+ export {
5
+ JsonStore
6
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lih-x-x/kmr",
3
- "version": "1.0.23",
3
+ "version": "1.0.25",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {