@lih-x-x/kmr 1.0.0 → 1.0.2

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.
Files changed (49) hide show
  1. package/dist/chunk-X36FOW5Y.js +47 -0
  2. package/dist/cli.js +51 -34
  3. package/dist/config-KM4HTJA2.js +12 -0
  4. package/dist/index.js +1134 -207
  5. package/package.json +11 -3
  6. package/dist/agent/claudeCode.d.ts +0 -12
  7. package/dist/agent/claudeCode.js +0 -109
  8. package/dist/agent/prompt.d.ts +0 -3
  9. package/dist/agent/prompt.js +0 -33
  10. package/dist/agent/types.d.ts +0 -7
  11. package/dist/agent/types.js +0 -1
  12. package/dist/cli-init.d.ts +0 -1
  13. package/dist/cli-init.js +0 -12
  14. package/dist/cli.d.ts +0 -2
  15. package/dist/config.d.ts +0 -17
  16. package/dist/config.js +0 -38
  17. package/dist/index.d.ts +0 -1
  18. package/dist/lark/client.d.ts +0 -8
  19. package/dist/lark/client.js +0 -68
  20. package/dist/lark/docReader.d.ts +0 -9
  21. package/dist/lark/docReader.js +0 -75
  22. package/dist/lark/messenger.d.ts +0 -22
  23. package/dist/lark/messenger.js +0 -156
  24. package/dist/lark/router.d.ts +0 -20
  25. package/dist/lark/router.js +0 -75
  26. package/dist/lark/taskCreator.d.ts +0 -15
  27. package/dist/lark/taskCreator.js +0 -41
  28. package/dist/query/finder.d.ts +0 -2
  29. package/dist/query/finder.js +0 -18
  30. package/dist/query/handler.d.ts +0 -8
  31. package/dist/query/handler.js +0 -17
  32. package/dist/session/manager.d.ts +0 -12
  33. package/dist/session/manager.js +0 -114
  34. package/dist/session/skill.d.ts +0 -1
  35. package/dist/session/skill.js +0 -19
  36. package/dist/storage/jsonStore.d.ts +0 -11
  37. package/dist/storage/jsonStore.js +0 -51
  38. package/dist/storage/types.d.ts +0 -52
  39. package/dist/storage/types.js +0 -1
  40. package/dist/web/openBrowser.d.ts +0 -1
  41. package/dist/web/openBrowser.js +0 -15
  42. package/dist/web/public/public/app.js +0 -344
  43. package/dist/web/public/public/index.html +0 -28
  44. package/dist/web/public/style.css +0 -428
  45. package/dist/web/server.d.ts +0 -6
  46. package/dist/web/server.js +0 -209
  47. /package/dist/{web → public}/public/app.js +0 -0
  48. /package/dist/{web → public}/public/index.html +0 -0
  49. /package/dist/{web/public → public}/public/style.css +0 -0
@@ -1,344 +0,0 @@
1
- // ===== 路由 =====
2
- function getRoute() {
3
- const hash = location.hash || '#/';
4
- if (hash.startsWith('#/settings')) return 'settings';
5
- if (hash.startsWith('#/sessions')) return 'sessions';
6
- return 'meetings';
7
- }
8
-
9
- function onRouteChange() {
10
- const route = getRoute();
11
- // 更新导航高亮
12
- document.querySelectorAll('.nav-link').forEach(function (el) { el.classList.remove('active'); });
13
- var activeNav = document.getElementById('nav-' + (route === 'settings' ? 'meetings' : route));
14
- if (activeNav) activeNav.classList.add('active');
15
-
16
- if (route === 'settings') renderSettings();
17
- else if (route === 'sessions') renderSessions();
18
- else renderMeetings();
19
- }
20
-
21
- window.addEventListener('hashchange', onRouteChange);
22
-
23
- // ===== Toast 提示 =====
24
- function showToast(message, type) {
25
- const el = document.getElementById('toast');
26
- el.textContent = message;
27
- el.className = 'toast toast-' + type + ' show';
28
- setTimeout(function () { el.className = 'toast'; }, 2500);
29
- }
30
-
31
- // ===== API 调用 =====
32
- async function api(path, options) {
33
- const res = await fetch('/api' + path, options);
34
- const data = await res.json();
35
- if (!res.ok || !data.ok) throw new Error(data.error || '请求失败');
36
- return data.data;
37
- }
38
-
39
- // ===== 会议列表页 =====
40
- async function renderMeetings() {
41
- const app = document.getElementById('app');
42
- app.innerHTML = '<h2 class="page-title">会议记录</h2><div id="meeting-list"></div>';
43
-
44
- try {
45
- var meetings = await api('/meetings');
46
- } catch (err) {
47
- app.innerHTML += '<p style="color:var(--danger)">加载失败: ' + err.message + '</p>';
48
- return;
49
- }
50
-
51
- var list = document.getElementById('meeting-list');
52
-
53
- if (meetings.length === 0) {
54
- list.innerHTML =
55
- '<div class="empty-state">' +
56
- '<h3>暂无会议记录</h3>' +
57
- '<p>向飞书机器人发送会议文档链接开始使用</p>' +
58
- '</div>';
59
- return;
60
- }
61
-
62
- // 按日期倒序
63
- meetings.sort(function (a, b) {
64
- return b.extractedAt.localeCompare(a.extractedAt);
65
- });
66
-
67
- list.innerHTML = meetings.map(function (m) {
68
- var participants = m.summary.participants.map(function (p) {
69
- return '<span class="tag">' + escapeHtml(p) + '</span>';
70
- }).join('');
71
-
72
- var keyPoints = m.summary.keyPoints.slice(0, 2).map(function (kp) {
73
- return '<li>' + escapeHtml(kp) + '</li>';
74
- }).join('');
75
-
76
- var todoCount = m.todos ? m.todos.length : 0;
77
- var riskCount = m.risks ? m.risks.length : 0;
78
- var commitmentCount = m.commitments ? m.commitments.length : 0;
79
- var insightCount = m.reusableInsights ? m.reusableInsights.length : 0;
80
- var taskCount = m.createdTasks ? m.createdTasks.length : 0;
81
-
82
- // 详情区域
83
- var detail = '<div class="meeting-detail">';
84
-
85
- if (m.todos && m.todos.length > 0) {
86
- detail += '<div class="detail-section"><h4>待办事项</h4><ul>' +
87
- m.todos.map(function (t) {
88
- return '<li>' + escapeHtml(t.content) + ' — ' + escapeHtml(t.owner) +
89
- (t.deadline ? '(截止 ' + escapeHtml(t.deadline) + ')' : '') + '</li>';
90
- }).join('') + '</ul></div>';
91
- }
92
-
93
- if (m.risks && m.risks.length > 0) {
94
- detail += '<div class="detail-section"><h4>风险项</h4><ul>' +
95
- m.risks.map(function (r) {
96
- return '<li>' + escapeHtml(r.description) +
97
- (r.mitigation ? ' — 缓解: ' + escapeHtml(r.mitigation) : '') + '</li>';
98
- }).join('') + '</ul></div>';
99
- }
100
-
101
- if (m.projectRelations && m.projectRelations.length > 0) {
102
- detail += '<div class="detail-section"><h4>项目关联</h4><ul>' +
103
- m.projectRelations.map(function (pr) {
104
- return '<li>' + escapeHtml(pr.project) + ': ' + escapeHtml(pr.relation) + '</li>';
105
- }).join('') + '</ul></div>';
106
- }
107
-
108
- if (m.commitments && m.commitments.length > 0) {
109
- detail += '<div class="detail-section"><h4>🤝 关键共识与承诺</h4><ul>' +
110
- m.commitments.map(function (c) {
111
- return '<li><strong>' + escapeHtml(c.content) + '</strong>' +
112
- '<br><span class="tag-row">相关方:' + c.participants.map(function (p) {
113
- return '<span class="tag">' + escapeHtml(p) + '</span>';
114
- }).join('') + (c.deadline ? ' 截止 ' + escapeHtml(c.deadline) : '') + '</span>' +
115
- '<br><em class="insight-context">💡 ' + escapeHtml(c.context) + '</em></li>';
116
- }).join('') + '</ul></div>';
117
- }
118
-
119
- if (m.reusableInsights && m.reusableInsights.length > 0) {
120
- detail += '<div class="detail-section"><h4>🧠 可复用知识</h4><ul>' +
121
- m.reusableInsights.map(function (r) {
122
- return '<li><span class="badge">' + escapeHtml(r.category) + '</span> ' +
123
- '<strong>' + escapeHtml(r.content) + '</strong>' +
124
- '<br><em class="insight-context">适用场景:' + escapeHtml(r.scenario) + '</em>' +
125
- (r.source ? '<br><span class="insight-source">来源:' + escapeHtml(r.source) + '</span>' : '') + '</li>';
126
- }).join('') + '</ul></div>';
127
- }
128
-
129
- if (m.createdTasks && m.createdTasks.length > 0) {
130
- detail += '<div class="detail-section"><h4>📋 已创建任务</h4><ul>' +
131
- m.createdTasks.map(function (t) {
132
- return '<li>' + escapeHtml(t.summary) +
133
- (t.url ? ' <a class="detail-link" href="' + escapeAttr(t.url) + '" target="_blank">查看 →</a>' : '') +
134
- '<br><span class="insight-source">创建于 ' + escapeHtml(t.createdAt) + '</span></li>';
135
- }).join('') + '</ul></div>';
136
- }
137
-
138
- detail += '<div class="detail-actions">';
139
- if (m.documentUrl) {
140
- detail += '<a class="detail-link" href="' + escapeHtml(m.documentUrl) + '" target="_blank">查看原始文档 →</a>';
141
- }
142
- detail += '<button class="btn btn-danger" onclick="deleteMeeting(event, \'' + escapeAttr(m.id) + '\')">删除</button>';
143
- detail += '</div>';
144
- detail += '</div>';
145
-
146
- return '<div class="meeting-card" onclick="toggleCard(this)">' +
147
- '<div class="meeting-card-header">' +
148
- '<span class="meeting-title">' + escapeHtml(m.summary.title) + '</span>' +
149
- '<span class="meeting-date">' + escapeHtml(m.summary.date) + '</span>' +
150
- '</div>' +
151
- '<div class="meeting-participants">' + participants + '</div>' +
152
- (keyPoints ? '<ul class="meeting-keypoints">' + keyPoints + '</ul>' : '') +
153
- '<div class="meeting-badges">' +
154
- '<span class="badge">待办 <span class="badge-count">' + todoCount + '</span></span>' +
155
- '<span class="badge">风险 <span class="badge-count">' + riskCount + '</span></span>' +
156
- '<span class="badge">共识 <span class="badge-count">' + commitmentCount + '</span></span>' +
157
- '<span class="badge">知识 <span class="badge-count">' + insightCount + '</span></span>' +
158
- '<span class="badge">任务 <span class="badge-count">' + taskCount + '</span></span>' +
159
- '</div>' +
160
- detail +
161
- '</div>';
162
- }).join('');
163
- }
164
-
165
- function toggleCard(el) {
166
- el.classList.toggle('expanded');
167
- }
168
-
169
- async function deleteMeeting(event, id) {
170
- event.stopPropagation();
171
- if (!confirm('确认删除此会议记录?')) return;
172
- try {
173
- await api('/meetings/' + id, { method: 'DELETE' });
174
- showToast('已删除', 'success');
175
- renderMeetings();
176
- } catch (err) {
177
- showToast('删除失败: ' + err.message, 'error');
178
- }
179
- }
180
-
181
- // ===== 会话列表页 =====
182
- async function renderSessions() {
183
- var app = document.getElementById('app');
184
- app.innerHTML = '<h2 class="page-title">AI 会话</h2><div id="session-list"></div>';
185
-
186
- try {
187
- var sessions = await api('/sessions');
188
- } catch (err) {
189
- app.innerHTML += '<p style="color:var(--danger)">加载失败: ' + err.message + '</p>';
190
- return;
191
- }
192
-
193
- var list = document.getElementById('session-list');
194
-
195
- if (sessions.length === 0) {
196
- list.innerHTML =
197
- '<div class="empty-state">' +
198
- '<h3>暂无会话记录</h3>' +
199
- '<p>向飞书机器人发送自由文本消息即可开启 AI 会话</p>' +
200
- '</div>';
201
- return;
202
- }
203
-
204
- list.innerHTML = sessions.map(function (s) {
205
- return '<div class="meeting-card" onclick="toggleCard(this)">' +
206
- '<div class="meeting-card-header">' +
207
- '<span class="meeting-title">' + escapeHtml(s.userId) + '</span>' +
208
- '<span class="meeting-date">' + escapeHtml(s.lastActivity) + '</span>' +
209
- '</div>' +
210
- '<div class="meeting-badges">' +
211
- '<span class="badge">消息 <span class="badge-count">' + s.messageCount + '</span></span>' +
212
- '</div>' +
213
- (s.summaryPreview ? '<p class="session-preview">' + escapeHtml(s.summaryPreview) + '</p>' : '') +
214
- '<div class="meeting-detail">' +
215
- '<div id="session-content-' + escapeAttr(s.userId) + '" class="session-content">加载中...</div>' +
216
- '<div class="detail-actions">' +
217
- '<button class="btn btn-danger" onclick="deleteSession(event, \'' + escapeAttr(s.userId) + '\')">删除</button>' +
218
- '</div>' +
219
- '</div>' +
220
- '</div>';
221
- }).join('');
222
-
223
- // 给每个卡片绑定展开时加载详情
224
- document.querySelectorAll('#session-list .meeting-card').forEach(function (card) {
225
- card.addEventListener('click', function () {
226
- if (card.classList.contains('expanded')) {
227
- var userId = card.querySelector('.session-content')?.id?.replace('session-content-', '');
228
- if (userId) loadSessionContent(userId);
229
- }
230
- });
231
- });
232
- }
233
-
234
- async function loadSessionContent(userId) {
235
- var el = document.getElementById('session-content-' + userId);
236
- if (!el || el.dataset.loaded) return;
237
- try {
238
- var data = await api('/sessions/' + userId);
239
- el.innerHTML = '<pre class="session-transcript">' + escapeHtml(data.content) + '</pre>';
240
- el.dataset.loaded = 'true';
241
- } catch (err) {
242
- el.innerHTML = '<p style="color:var(--danger)">加载失败: ' + err.message + '</p>';
243
- }
244
- }
245
-
246
- async function deleteSession(event, userId) {
247
- event.stopPropagation();
248
- if (!confirm('确认删除此会话记录?')) return;
249
- try {
250
- await api('/sessions/' + userId, { method: 'DELETE' });
251
- showToast('已删除', 'success');
252
- renderSessions();
253
- } catch (err) {
254
- showToast('删除失败: ' + err.message, 'error');
255
- }
256
- }
257
-
258
- // ===== 设置页 =====
259
- async function renderSettings() {
260
- var app = document.getElementById('app');
261
- app.innerHTML = '<h2 class="page-title">设置</h2><div id="settings-form">加载中...</div>';
262
-
263
- try {
264
- var config = await api('/config');
265
- } catch (err) {
266
- document.getElementById('settings-form').innerHTML = '<p style="color:var(--danger)">加载失败: ' + err.message + '</p>';
267
- return;
268
- }
269
-
270
- document.getElementById('settings-form').innerHTML =
271
- '<div class="settings-group">' +
272
- '<div class="settings-group-title">飞书配置</div>' +
273
- '<div class="form-field">' +
274
- '<label class="form-label">App ID</label>' +
275
- '<input class="form-input" id="cfg-appId" type="text" value="' + escapeAttr(config.lark.appId) + '">' +
276
- '</div>' +
277
- '<div class="form-field">' +
278
- '<label class="form-label">App Secret</label>' +
279
- '<input class="form-input" id="cfg-appSecret" type="password" value="' + escapeAttr(config.lark.appSecret) + '">' +
280
- '</div>' +
281
- '</div>' +
282
- '<div class="settings-group">' +
283
- '<div class="settings-group-title">Agent 配置</div>' +
284
- '<div class="form-field">' +
285
- '<label class="form-label">Provider</label>' +
286
- '<select class="form-select" id="cfg-provider">' +
287
- '<option value="claude-code"' + (config.agent.provider === 'claude-code' ? ' selected' : '') + '>Claude Code</option>' +
288
- '</select>' +
289
- '</div>' +
290
- '<div class="form-field">' +
291
- '<label class="form-label">Timeout(毫秒)</label>' +
292
- '<input class="form-input" id="cfg-timeout" type="number" value="' + config.agent.timeout + '">' +
293
- '</div>' +
294
- '</div>' +
295
- '<div class="settings-group">' +
296
- '<div class="settings-group-title">存储配置</div>' +
297
- '<div class="form-field">' +
298
- '<label class="form-label">数据目录</label>' +
299
- '<input class="form-input" id="cfg-dataDir" type="text" value="' + escapeAttr(config.storage.dataDir) + '">' +
300
- '</div>' +
301
- '</div>' +
302
- '<button class="btn btn-primary" onclick="saveSettings()">保存配置</button>';
303
- }
304
-
305
- async function saveSettings() {
306
- var config = {
307
- lark: {
308
- appId: document.getElementById('cfg-appId').value,
309
- appSecret: document.getElementById('cfg-appSecret').value,
310
- },
311
- agent: {
312
- provider: document.getElementById('cfg-provider').value,
313
- timeout: parseInt(document.getElementById('cfg-timeout').value, 10) || 30000,
314
- },
315
- storage: {
316
- dataDir: document.getElementById('cfg-dataDir').value,
317
- },
318
- };
319
-
320
- try {
321
- await api('/config', {
322
- method: 'PUT',
323
- headers: { 'Content-Type': 'application/json' },
324
- body: JSON.stringify(config),
325
- });
326
- showToast('配置已保存', 'success');
327
- } catch (err) {
328
- showToast('保存失败: ' + err.message, 'error');
329
- }
330
- }
331
-
332
- // ===== 工具函数 =====
333
- function escapeHtml(str) {
334
- if (!str) return '';
335
- return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
336
- }
337
-
338
- function escapeAttr(str) {
339
- if (!str) return '';
340
- return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
341
- }
342
-
343
- // ===== 初始化 =====
344
- onRouteChange();
@@ -1,28 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>KMR — Key Meetings Record</title>
7
- <link rel="stylesheet" href="/style.css">
8
- </head>
9
- <body>
10
- <nav class="nav">
11
- <a href="#/" class="nav-logo">KMR</a>
12
- <div class="nav-links">
13
- <a href="#/" class="nav-link" id="nav-meetings">会议</a>
14
- <a href="#/sessions" class="nav-link" id="nav-sessions">会话</a>
15
- <a href="#/settings" class="nav-settings">
16
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
17
- <circle cx="12" cy="12" r="3"></circle>
18
- <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
19
- </svg>
20
- 设置
21
- </a>
22
- </div>
23
- </nav>
24
- <main class="container" id="app"></main>
25
- <div id="toast" class="toast"></div>
26
- <script src="/app.js"></script>
27
- </body>
28
- </html>