@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,428 +0,0 @@
1
- *, *::before, *::after {
2
- margin: 0;
3
- padding: 0;
4
- box-sizing: border-box;
5
- }
6
-
7
- :root {
8
- --bg-primary: #0a0a0a;
9
- --bg-card: rgba(255, 255, 255, 0.03);
10
- --bg-input: rgba(255, 255, 255, 0.06);
11
- --border: rgba(255, 255, 255, 0.1);
12
- --border-hover: rgba(59, 130, 246, 0.5);
13
- --text-primary: #fafafa;
14
- --text-secondary: #a1a1aa;
15
- --text-muted: #71717a;
16
- --accent: #3b82f6;
17
- --accent-hover: #2563eb;
18
- --success: #22c55e;
19
- --danger: #ef4444;
20
- --warning: #f59e0b;
21
- --font-sans: system-ui, -apple-system, 'Segoe UI', sans-serif;
22
- --font-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
23
- --radius: 8px;
24
- --transition: 0.2s ease;
25
- }
26
-
27
- body {
28
- font-family: var(--font-sans);
29
- background: var(--bg-primary);
30
- color: var(--text-primary);
31
- line-height: 1.6;
32
- min-height: 100vh;
33
- }
34
-
35
- .nav {
36
- display: flex;
37
- align-items: center;
38
- justify-content: space-between;
39
- padding: 16px 32px;
40
- border-bottom: 1px solid var(--border);
41
- backdrop-filter: blur(12px);
42
- position: sticky;
43
- top: 0;
44
- z-index: 100;
45
- background: rgba(10, 10, 10, 0.8);
46
- }
47
-
48
- .nav-logo {
49
- font-size: 20px;
50
- font-weight: 700;
51
- letter-spacing: 2px;
52
- color: var(--accent);
53
- text-decoration: none;
54
- font-family: var(--font-mono);
55
- }
56
-
57
- .nav-links {
58
- display: flex;
59
- align-items: center;
60
- gap: 4px;
61
- }
62
-
63
- .nav-link {
64
- color: var(--text-muted);
65
- text-decoration: none;
66
- font-size: 14px;
67
- padding: 6px 14px;
68
- border-radius: var(--radius);
69
- transition: all var(--transition);
70
- }
71
-
72
- .nav-link:hover {
73
- color: var(--text-primary);
74
- background: var(--bg-input);
75
- }
76
-
77
- .nav-link.active {
78
- color: var(--text-primary);
79
- background: var(--bg-input);
80
- border: 1px solid var(--border);
81
- }
82
-
83
- .nav-settings {
84
- display: flex;
85
- align-items: center;
86
- gap: 8px;
87
- color: var(--text-secondary);
88
- text-decoration: none;
89
- font-size: 14px;
90
- padding: 6px 12px;
91
- border-radius: var(--radius);
92
- border: 1px solid transparent;
93
- transition: all var(--transition);
94
- }
95
-
96
- .nav-settings:hover {
97
- color: var(--text-primary);
98
- border-color: var(--border);
99
- }
100
-
101
- .container {
102
- max-width: 900px;
103
- margin: 0 auto;
104
- padding: 32px 24px;
105
- }
106
-
107
- .page-title {
108
- font-size: 24px;
109
- font-weight: 600;
110
- margin-bottom: 24px;
111
- }
112
-
113
- .meeting-card {
114
- background: var(--bg-card);
115
- border: 1px solid var(--border);
116
- border-radius: var(--radius);
117
- padding: 20px 24px;
118
- margin-bottom: 12px;
119
- cursor: pointer;
120
- transition: all var(--transition);
121
- backdrop-filter: blur(8px);
122
- }
123
-
124
- .meeting-card:hover {
125
- border-color: var(--border-hover);
126
- box-shadow: 0 0 20px rgba(59, 130, 246, 0.08);
127
- }
128
-
129
- .meeting-card-header {
130
- display: flex;
131
- align-items: center;
132
- justify-content: space-between;
133
- margin-bottom: 8px;
134
- }
135
-
136
- .meeting-title {
137
- font-size: 16px;
138
- font-weight: 600;
139
- }
140
-
141
- .meeting-date {
142
- font-size: 13px;
143
- color: var(--text-muted);
144
- font-family: var(--font-mono);
145
- }
146
-
147
- .meeting-participants {
148
- display: flex;
149
- gap: 6px;
150
- flex-wrap: wrap;
151
- margin-bottom: 10px;
152
- }
153
-
154
- .tag {
155
- font-size: 12px;
156
- padding: 2px 8px;
157
- border-radius: 12px;
158
- background: rgba(59, 130, 246, 0.12);
159
- color: var(--accent);
160
- }
161
-
162
- .meeting-keypoints {
163
- font-size: 14px;
164
- color: var(--text-secondary);
165
- margin-bottom: 10px;
166
- }
167
-
168
- .meeting-keypoints li {
169
- margin-left: 16px;
170
- margin-bottom: 2px;
171
- }
172
-
173
- .meeting-badges {
174
- display: flex;
175
- gap: 12px;
176
- }
177
-
178
- .badge {
179
- font-size: 12px;
180
- color: var(--text-muted);
181
- font-family: var(--font-mono);
182
- }
183
-
184
- .badge-count {
185
- color: var(--text-secondary);
186
- font-weight: 600;
187
- }
188
-
189
- .meeting-detail {
190
- display: none;
191
- margin-top: 16px;
192
- padding-top: 16px;
193
- border-top: 1px solid var(--border);
194
- }
195
-
196
- .meeting-card.expanded .meeting-detail {
197
- display: block;
198
- }
199
-
200
- .detail-section {
201
- margin-bottom: 16px;
202
- }
203
-
204
- .detail-section h4 {
205
- font-size: 13px;
206
- color: var(--text-muted);
207
- text-transform: uppercase;
208
- letter-spacing: 1px;
209
- margin-bottom: 8px;
210
- }
211
-
212
- .detail-section ul {
213
- list-style: none;
214
- }
215
-
216
- .detail-section li {
217
- font-size: 14px;
218
- color: var(--text-secondary);
219
- padding: 4px 0;
220
- padding-left: 12px;
221
- border-left: 2px solid var(--border);
222
- margin-bottom: 4px;
223
- }
224
-
225
- .detail-link {
226
- display: inline-block;
227
- color: var(--accent);
228
- text-decoration: none;
229
- font-size: 14px;
230
- }
231
-
232
- .detail-link:hover {
233
- text-decoration: underline;
234
- }
235
-
236
- .detail-actions {
237
- display: flex;
238
- align-items: center;
239
- justify-content: space-between;
240
- margin-top: 16px;
241
- padding-top: 12px;
242
- border-top: 1px solid var(--border);
243
- }
244
-
245
- .empty-state {
246
- text-align: center;
247
- padding: 80px 24px;
248
- color: var(--text-muted);
249
- }
250
-
251
- .empty-state h3 {
252
- font-size: 18px;
253
- margin-bottom: 8px;
254
- color: var(--text-secondary);
255
- }
256
-
257
- .empty-state p {
258
- font-size: 14px;
259
- }
260
-
261
- .settings-group {
262
- margin-bottom: 32px;
263
- }
264
-
265
- .settings-group-title {
266
- font-size: 14px;
267
- color: var(--text-muted);
268
- text-transform: uppercase;
269
- letter-spacing: 1px;
270
- margin-bottom: 16px;
271
- padding-bottom: 8px;
272
- border-bottom: 1px solid var(--border);
273
- }
274
-
275
- .form-field {
276
- margin-bottom: 16px;
277
- }
278
-
279
- .form-label {
280
- display: block;
281
- font-size: 14px;
282
- color: var(--text-secondary);
283
- margin-bottom: 6px;
284
- }
285
-
286
- .form-input,
287
- .form-select {
288
- width: 100%;
289
- padding: 10px 14px;
290
- background: var(--bg-input);
291
- border: 1px solid var(--border);
292
- border-radius: var(--radius);
293
- color: var(--text-primary);
294
- font-size: 14px;
295
- font-family: var(--font-mono);
296
- outline: none;
297
- transition: border-color var(--transition);
298
- }
299
-
300
- .form-input:focus,
301
- .form-select:focus {
302
- border-color: var(--accent);
303
- }
304
-
305
- .form-select {
306
- cursor: pointer;
307
- appearance: none;
308
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='%23a1a1aa' viewBox='0 0 16 16'%3E%3Cpath d='M8 11L3 6h10z'/%3E%3C/svg%3E");
309
- background-repeat: no-repeat;
310
- background-position: right 12px center;
311
- }
312
-
313
- .btn {
314
- padding: 10px 24px;
315
- border: none;
316
- border-radius: var(--radius);
317
- font-size: 14px;
318
- font-weight: 600;
319
- cursor: pointer;
320
- transition: all var(--transition);
321
- }
322
-
323
- .btn-primary {
324
- background: var(--accent);
325
- color: white;
326
- }
327
-
328
- .btn-primary:hover {
329
- background: var(--accent-hover);
330
- }
331
-
332
- .btn-danger {
333
- background: transparent;
334
- color: var(--text-muted);
335
- border: 1px solid var(--border);
336
- margin-top: 16px;
337
- font-size: 12px;
338
- padding: 6px 14px;
339
- font-weight: 400;
340
- }
341
-
342
- .btn-danger:hover {
343
- color: var(--danger);
344
- border-color: var(--danger);
345
- background: rgba(239, 68, 68, 0.08);
346
- }
347
-
348
- .toast {
349
- position: fixed;
350
- top: 80px;
351
- right: 24px;
352
- padding: 12px 20px;
353
- border-radius: var(--radius);
354
- font-size: 14px;
355
- color: white;
356
- opacity: 0;
357
- transform: translateY(-10px);
358
- transition: all 0.3s ease;
359
- z-index: 200;
360
- }
361
-
362
- .toast.show {
363
- opacity: 1;
364
- transform: translateY(0);
365
- }
366
-
367
- .toast-success {
368
- background: rgba(10, 10, 10, 0.9);
369
- border: 1px solid var(--success);
370
- color: var(--success);
371
- backdrop-filter: blur(12px);
372
- }
373
-
374
- .toast-error {
375
- background: rgba(10, 10, 10, 0.9);
376
- border: 1px solid var(--danger);
377
- color: var(--danger);
378
- backdrop-filter: blur(12px);
379
- }
380
-
381
- .insight-context {
382
- color: var(--text-muted);
383
- font-size: 13px;
384
- font-style: italic;
385
- }
386
-
387
- .insight-source {
388
- color: var(--text-muted);
389
- font-size: 12px;
390
- }
391
-
392
- .tag-row {
393
- font-size: 13px;
394
- color: var(--text-secondary);
395
- }
396
-
397
- .detail-section ul li {
398
- margin-bottom: 12px;
399
- line-height: 1.6;
400
- }
401
-
402
- .session-preview {
403
- font-size: 13px;
404
- color: var(--text-muted);
405
- margin-top: 8px;
406
- overflow: hidden;
407
- text-overflow: ellipsis;
408
- white-space: nowrap;
409
- }
410
-
411
- .session-content {
412
- margin-bottom: 12px;
413
- }
414
-
415
- .session-transcript {
416
- font-size: 13px;
417
- font-family: var(--font-sans);
418
- color: var(--text-secondary);
419
- line-height: 1.8;
420
- white-space: pre-wrap;
421
- word-break: break-word;
422
- max-height: 400px;
423
- overflow-y: auto;
424
- padding: 12px;
425
- background: var(--bg-input);
426
- border-radius: var(--radius);
427
- border: 1px solid var(--border);
428
- }
@@ -1,6 +0,0 @@
1
- import http from 'node:http';
2
- import { JsonStore } from '../storage/jsonStore';
3
- export declare function startWebServer(store: JsonStore, kmrDir: string, port?: number): Promise<{
4
- server: http.Server;
5
- port: number;
6
- }>;
@@ -1,209 +0,0 @@
1
- import http from 'node:http';
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
- const PUBLIC_DIR = path.join(__dirname, 'public');
7
- const MIME_TYPES = {
8
- '.html': 'text/html; charset=utf-8',
9
- '.css': 'text/css; charset=utf-8',
10
- '.js': 'application/javascript; charset=utf-8',
11
- '.json': 'application/json; charset=utf-8',
12
- '.png': 'image/png',
13
- '.svg': 'image/svg+xml',
14
- };
15
- function serveStatic(res, urlPath) {
16
- const safePath = path.normalize(urlPath).replace(/^(\.\.[/\\])+/, '');
17
- let filePath = path.join(PUBLIC_DIR, safePath === '/' ? 'index.html' : safePath);
18
- if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
19
- filePath = path.join(PUBLIC_DIR, 'index.html');
20
- }
21
- const ext = path.extname(filePath);
22
- const contentType = MIME_TYPES[ext] || 'application/octet-stream';
23
- const content = fs.readFileSync(filePath);
24
- res.writeHead(200, { 'Content-Type': contentType });
25
- res.end(content);
26
- }
27
- function listSessions(kmrDir) {
28
- const sessionsDir = path.join(kmrDir, 'sessions');
29
- if (!fs.existsSync(sessionsDir))
30
- return [];
31
- return fs.readdirSync(sessionsDir)
32
- .filter((d) => {
33
- const full = path.join(sessionsDir, d);
34
- return fs.statSync(full).isDirectory();
35
- })
36
- .map((userId) => {
37
- const summaryPath = path.join(sessionsDir, userId, 'summary.md');
38
- let summaryPreview = '';
39
- let messageCount = 0;
40
- let lastActivity = '';
41
- if (fs.existsSync(summaryPath)) {
42
- const content = fs.readFileSync(summaryPath, 'utf-8');
43
- const lines = content.split('\n').filter((l) => l.trim().length > 0);
44
- messageCount = lines.length;
45
- // 取最后一条用户消息作为预览
46
- for (let i = lines.length - 1; i >= 0; i--) {
47
- if (lines[i].includes('] 用户:')) {
48
- summaryPreview = lines[i].replace(/^\[.*?\]\s*用户:\s*/, '').slice(0, 80);
49
- break;
50
- }
51
- }
52
- // 最后活动时间
53
- const lastLine = lines[lines.length - 1] || '';
54
- const timeMatch = lastLine.match(/^\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]/);
55
- if (timeMatch)
56
- lastActivity = timeMatch[1];
57
- const stat = fs.statSync(summaryPath);
58
- if (!lastActivity)
59
- lastActivity = stat.mtime.toISOString().replace('T', ' ').slice(0, 19);
60
- }
61
- else {
62
- const userDir = path.join(sessionsDir, userId);
63
- const stat = fs.statSync(userDir);
64
- lastActivity = stat.mtime.toISOString().replace('T', ' ').slice(0, 19);
65
- }
66
- return { userId, summaryPreview, messageCount, lastActivity };
67
- })
68
- .sort((a, b) => b.lastActivity.localeCompare(a.lastActivity));
69
- }
70
- function deleteSession(kmrDir, userId) {
71
- const sessionDir = path.join(kmrDir, 'sessions', userId);
72
- if (!fs.existsSync(sessionDir))
73
- return false;
74
- fs.rmSync(sessionDir, { recursive: true, force: true });
75
- return true;
76
- }
77
- function getSessionDetail(kmrDir, userId) {
78
- const summaryPath = path.join(kmrDir, 'sessions', userId, 'summary.md');
79
- if (!fs.existsSync(summaryPath))
80
- return null;
81
- return fs.readFileSync(summaryPath, 'utf-8');
82
- }
83
- export function startWebServer(store, kmrDir, port = 3000) {
84
- return new Promise((resolve, reject) => {
85
- const server = http.createServer((req, res) => {
86
- const url = new URL(req.url || '/', `http://localhost`);
87
- if (url.pathname.startsWith('/api/')) {
88
- handleApi(req, res, url, store, kmrDir);
89
- return;
90
- }
91
- serveStatic(res, url.pathname);
92
- });
93
- server.on('error', (err) => {
94
- if (err.code === 'EADDRINUSE' && port < 3010) {
95
- startWebServer(store, kmrDir, port + 1).then(resolve, reject);
96
- }
97
- else {
98
- reject(err);
99
- }
100
- });
101
- server.listen(port, () => {
102
- const addr = server.address();
103
- const actualPort = typeof addr === 'object' && addr ? addr.port : port;
104
- resolve({ server, port: actualPort });
105
- });
106
- });
107
- }
108
- function readBody(req) {
109
- return new Promise((resolve, reject) => {
110
- let body = '';
111
- req.on('data', (chunk) => (body += chunk));
112
- req.on('end', () => resolve(body));
113
- req.on('error', reject);
114
- });
115
- }
116
- function jsonResponse(res, status, data) {
117
- res.writeHead(status, {
118
- 'Content-Type': 'application/json; charset=utf-8',
119
- 'Access-Control-Allow-Origin': '*',
120
- });
121
- res.end(JSON.stringify(data));
122
- }
123
- async function handleApi(req, res, url, store, kmrDir) {
124
- const method = req.method || 'GET';
125
- const pathname = url.pathname;
126
- try {
127
- // GET /api/meetings
128
- if (pathname === '/api/meetings' && method === 'GET') {
129
- const meetings = await store.list();
130
- jsonResponse(res, 200, { ok: true, data: meetings });
131
- return;
132
- }
133
- // GET /api/meetings/:id
134
- const meetingMatch = pathname.match(/^\/api\/meetings\/(.+)$/);
135
- if (meetingMatch && method === 'GET') {
136
- const record = await store.load(meetingMatch[1]);
137
- if (!record) {
138
- jsonResponse(res, 404, { ok: false, error: '会议记录不存在' });
139
- return;
140
- }
141
- jsonResponse(res, 200, { ok: true, data: record });
142
- return;
143
- }
144
- // DELETE /api/meetings/:id
145
- if (meetingMatch && method === 'DELETE') {
146
- const deleted = await store.delete(meetingMatch[1]);
147
- if (!deleted) {
148
- jsonResponse(res, 404, { ok: false, error: '会议记录不存在' });
149
- return;
150
- }
151
- jsonResponse(res, 200, { ok: true, data: null });
152
- return;
153
- }
154
- // GET /api/config
155
- if (pathname === '/api/config' && method === 'GET') {
156
- const configPath = path.join(kmrDir, 'config.json');
157
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
158
- jsonResponse(res, 200, { ok: true, data: config });
159
- return;
160
- }
161
- // PUT /api/config
162
- if (pathname === '/api/config' && method === 'PUT') {
163
- const body = await readBody(req);
164
- let parsed;
165
- try {
166
- parsed = JSON.parse(body);
167
- }
168
- catch {
169
- jsonResponse(res, 400, { ok: false, error: '无效的 JSON 格式' });
170
- return;
171
- }
172
- const configPath = path.join(kmrDir, 'config.json');
173
- fs.writeFileSync(configPath, JSON.stringify(parsed, null, 2), 'utf-8');
174
- jsonResponse(res, 200, { ok: true, data: parsed });
175
- return;
176
- }
177
- // GET /api/sessions
178
- if (pathname === '/api/sessions' && method === 'GET') {
179
- const sessions = listSessions(kmrDir);
180
- jsonResponse(res, 200, { ok: true, data: sessions });
181
- return;
182
- }
183
- // GET /api/sessions/:userId
184
- const sessionMatch = pathname.match(/^\/api\/sessions\/(.+)$/);
185
- if (sessionMatch && method === 'GET') {
186
- const content = getSessionDetail(kmrDir, sessionMatch[1]);
187
- if (content === null) {
188
- jsonResponse(res, 404, { ok: false, error: '会话不存在' });
189
- return;
190
- }
191
- jsonResponse(res, 200, { ok: true, data: { userId: sessionMatch[1], content } });
192
- return;
193
- }
194
- // DELETE /api/sessions/:userId
195
- if (sessionMatch && method === 'DELETE') {
196
- const deleted = deleteSession(kmrDir, sessionMatch[1]);
197
- if (!deleted) {
198
- jsonResponse(res, 404, { ok: false, error: '会话不存在' });
199
- return;
200
- }
201
- jsonResponse(res, 200, { ok: true, data: null });
202
- return;
203
- }
204
- jsonResponse(res, 404, { ok: false, error: 'API 路由不存在' });
205
- }
206
- catch (err) {
207
- jsonResponse(res, 500, { ok: false, error: err.message });
208
- }
209
- }
File without changes
File without changes
File without changes