@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.
- package/dist/chunk-X36FOW5Y.js +47 -0
- package/dist/cli.js +51 -34
- package/dist/config-KM4HTJA2.js +12 -0
- package/dist/index.js +1134 -207
- package/package.json +11 -3
- package/dist/agent/claudeCode.d.ts +0 -12
- package/dist/agent/claudeCode.js +0 -109
- package/dist/agent/prompt.d.ts +0 -3
- package/dist/agent/prompt.js +0 -33
- package/dist/agent/types.d.ts +0 -7
- package/dist/agent/types.js +0 -1
- package/dist/cli-init.d.ts +0 -1
- package/dist/cli-init.js +0 -12
- package/dist/cli.d.ts +0 -2
- package/dist/config.d.ts +0 -17
- package/dist/config.js +0 -38
- package/dist/index.d.ts +0 -1
- package/dist/lark/client.d.ts +0 -8
- package/dist/lark/client.js +0 -68
- package/dist/lark/docReader.d.ts +0 -9
- package/dist/lark/docReader.js +0 -75
- package/dist/lark/messenger.d.ts +0 -22
- package/dist/lark/messenger.js +0 -156
- package/dist/lark/router.d.ts +0 -20
- package/dist/lark/router.js +0 -75
- package/dist/lark/taskCreator.d.ts +0 -15
- package/dist/lark/taskCreator.js +0 -41
- package/dist/query/finder.d.ts +0 -2
- package/dist/query/finder.js +0 -18
- package/dist/query/handler.d.ts +0 -8
- package/dist/query/handler.js +0 -17
- package/dist/session/manager.d.ts +0 -12
- package/dist/session/manager.js +0 -114
- package/dist/session/skill.d.ts +0 -1
- package/dist/session/skill.js +0 -19
- package/dist/storage/jsonStore.d.ts +0 -11
- package/dist/storage/jsonStore.js +0 -51
- package/dist/storage/types.d.ts +0 -52
- package/dist/storage/types.js +0 -1
- package/dist/web/openBrowser.d.ts +0 -1
- package/dist/web/openBrowser.js +0 -15
- package/dist/web/public/public/app.js +0 -344
- package/dist/web/public/public/index.html +0 -28
- package/dist/web/public/style.css +0 -428
- package/dist/web/server.d.ts +0 -6
- package/dist/web/server.js +0 -209
- /package/dist/{web → public}/public/app.js +0 -0
- /package/dist/{web → public}/public/index.html +0 -0
- /package/dist/{web/public → public}/public/style.css +0 -0
package/dist/lark/router.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export declare enum MessageType {
|
|
2
|
-
DOCUMENT_LINK = "document_link",
|
|
3
|
-
FIND_QUERY = "find_query",
|
|
4
|
-
LIST_ALL = "list_all",
|
|
5
|
-
DELETE_RECORD = "delete_record",
|
|
6
|
-
SHOW_DETAIL = "show_detail",
|
|
7
|
-
CONFIRM_TASKS = "confirm_tasks",
|
|
8
|
-
REJECT_TASKS = "reject_tasks",
|
|
9
|
-
UNKNOWN = "unknown"
|
|
10
|
-
}
|
|
11
|
-
export interface ParsedMessage {
|
|
12
|
-
type: MessageType;
|
|
13
|
-
documentId?: string;
|
|
14
|
-
query?: string;
|
|
15
|
-
deleteId?: string;
|
|
16
|
-
showId?: string;
|
|
17
|
-
confirmIds?: number[] | 'all';
|
|
18
|
-
raw: string;
|
|
19
|
-
}
|
|
20
|
-
export declare function parseMessage(text: string): ParsedMessage;
|
package/dist/lark/router.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { extractDocumentId } from './docReader';
|
|
2
|
-
export var MessageType;
|
|
3
|
-
(function (MessageType) {
|
|
4
|
-
MessageType["DOCUMENT_LINK"] = "document_link";
|
|
5
|
-
MessageType["FIND_QUERY"] = "find_query";
|
|
6
|
-
MessageType["LIST_ALL"] = "list_all";
|
|
7
|
-
MessageType["DELETE_RECORD"] = "delete_record";
|
|
8
|
-
MessageType["SHOW_DETAIL"] = "show_detail";
|
|
9
|
-
MessageType["CONFIRM_TASKS"] = "confirm_tasks";
|
|
10
|
-
MessageType["REJECT_TASKS"] = "reject_tasks";
|
|
11
|
-
MessageType["UNKNOWN"] = "unknown";
|
|
12
|
-
})(MessageType || (MessageType = {}));
|
|
13
|
-
export function parseMessage(text) {
|
|
14
|
-
const trimmed = text.trim();
|
|
15
|
-
// /reject 或 "取消创建"/"不创建"/"跳过待办"
|
|
16
|
-
if (/^(?:\/reject|取消创建|不创建|不用创建|跳过待办|跳过|算了)$/i.test(trimmed)) {
|
|
17
|
-
return { type: MessageType.REJECT_TASKS, raw: text };
|
|
18
|
-
}
|
|
19
|
-
// /confirm all 或 /confirm 1,2,3 或自然语言"确认创建全部/确认创建 1,2"
|
|
20
|
-
const confirmAllMatch = /^(?:\/confirm\s+all|确认创建全部|全部创建)$/i.test(trimmed);
|
|
21
|
-
if (confirmAllMatch) {
|
|
22
|
-
return { type: MessageType.CONFIRM_TASKS, confirmIds: 'all', raw: text };
|
|
23
|
-
}
|
|
24
|
-
const confirmMatch = trimmed.match(/^(?:\/confirm|确认创建)\s+([\d,\s]+)/);
|
|
25
|
-
if (confirmMatch) {
|
|
26
|
-
const ids = confirmMatch[1].split(/[,\s,]+/).map(Number).filter((n) => n > 0);
|
|
27
|
-
if (ids.length > 0) {
|
|
28
|
-
return { type: MessageType.CONFIRM_TASKS, confirmIds: ids, raw: text };
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
// /del <id> 或 "删掉/删除 <id>"
|
|
32
|
-
const delMatch = trimmed.match(/^(?:\/del|删掉|删除)\s+(.+)/);
|
|
33
|
-
if (delMatch) {
|
|
34
|
-
return {
|
|
35
|
-
type: MessageType.DELETE_RECORD,
|
|
36
|
-
deleteId: delMatch[1].trim(),
|
|
37
|
-
raw: text,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
// /show <id> 或 "展示/列出/查看 <id> 的详情" 等
|
|
41
|
-
const showMatch = trimmed.match(/^(?:\/show)\s+(.+)/) ||
|
|
42
|
-
trimmed.match(/^(?:展示|列出|显示|查看)\s*(meeting_\w+)/) ||
|
|
43
|
-
trimmed.match(/^(?:展示|列出|显示|查看)\s*(.+?)的?详情/);
|
|
44
|
-
if (showMatch) {
|
|
45
|
-
return {
|
|
46
|
-
type: MessageType.SHOW_DETAIL,
|
|
47
|
-
showId: showMatch[1].trim(),
|
|
48
|
-
raw: text,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// /listall 或自然语言匹配
|
|
52
|
-
if (/^\/listall$/i.test(trimmed) || /^(展示|列出|显示|查看)(所有|全部|历史)(记录|会议)/.test(trimmed)) {
|
|
53
|
-
return { type: MessageType.LIST_ALL, raw: text };
|
|
54
|
-
}
|
|
55
|
-
const findMatch = text.match(/^\/find\s+(.+)/);
|
|
56
|
-
if (findMatch) {
|
|
57
|
-
return {
|
|
58
|
-
type: MessageType.FIND_QUERY,
|
|
59
|
-
query: findMatch[1].trim(),
|
|
60
|
-
raw: text,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
const urlMatch = text.match(/(https?:\/\/[^\s]*feishu\.cn\/[^\s]+)/);
|
|
64
|
-
if (urlMatch) {
|
|
65
|
-
const docId = extractDocumentId(urlMatch[1]);
|
|
66
|
-
if (docId) {
|
|
67
|
-
return {
|
|
68
|
-
type: MessageType.DOCUMENT_LINK,
|
|
69
|
-
documentId: docId,
|
|
70
|
-
raw: text,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return { type: MessageType.UNKNOWN, raw: text };
|
|
75
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import * as lark from '@larksuiteoapi/node-sdk';
|
|
2
|
-
export interface CreateTaskResult {
|
|
3
|
-
taskId: string;
|
|
4
|
-
url: string;
|
|
5
|
-
}
|
|
6
|
-
export declare class TaskCreator {
|
|
7
|
-
private readonly client;
|
|
8
|
-
constructor(client: lark.Client);
|
|
9
|
-
createTask(params: {
|
|
10
|
-
summary: string;
|
|
11
|
-
due?: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
assigneeOpenId?: string;
|
|
14
|
-
}): Promise<CreateTaskResult>;
|
|
15
|
-
}
|
package/dist/lark/taskCreator.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export class TaskCreator {
|
|
2
|
-
client;
|
|
3
|
-
constructor(client) {
|
|
4
|
-
this.client = client;
|
|
5
|
-
}
|
|
6
|
-
async createTask(params) {
|
|
7
|
-
const taskBody = {
|
|
8
|
-
summary: params.summary,
|
|
9
|
-
};
|
|
10
|
-
if (params.due) {
|
|
11
|
-
const dueDate = new Date(params.due + 'T23:59:59+08:00');
|
|
12
|
-
taskBody.due = {
|
|
13
|
-
timestamp: dueDate.getTime().toString(),
|
|
14
|
-
is_all_day: true,
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
if (params.description) {
|
|
18
|
-
taskBody.description = params.description;
|
|
19
|
-
}
|
|
20
|
-
if (params.assigneeOpenId) {
|
|
21
|
-
taskBody.members = [
|
|
22
|
-
{
|
|
23
|
-
id: params.assigneeOpenId,
|
|
24
|
-
type: 'user',
|
|
25
|
-
role: 'assignee',
|
|
26
|
-
},
|
|
27
|
-
];
|
|
28
|
-
}
|
|
29
|
-
console.log(`[task] 创建飞书任务: ${params.summary}`);
|
|
30
|
-
console.log(`[task] 请求体:`, JSON.stringify(taskBody, null, 2));
|
|
31
|
-
const response = await this.client.task.v2.task.create({
|
|
32
|
-
params: { user_id_type: 'open_id' },
|
|
33
|
-
data: taskBody,
|
|
34
|
-
});
|
|
35
|
-
console.log(`[task] API 返回:`, JSON.stringify(response.data, null, 2));
|
|
36
|
-
const taskId = response.data?.task?.guid || '';
|
|
37
|
-
const url = response.data?.task?.url || '';
|
|
38
|
-
console.log(`[task] 任务创建成功: taskId=${taskId}`);
|
|
39
|
-
return { taskId, url };
|
|
40
|
-
}
|
|
41
|
-
}
|
package/dist/query/finder.d.ts
DELETED
package/dist/query/finder.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// src/query/finder.ts
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
export async function grepMeetings(dataDir, keywords) {
|
|
5
|
-
if (!fs.existsSync(dataDir))
|
|
6
|
-
return [];
|
|
7
|
-
const files = fs.readdirSync(dataDir).filter((f) => f.endsWith('.json'));
|
|
8
|
-
const matches = [];
|
|
9
|
-
for (const file of files) {
|
|
10
|
-
const filePath = path.join(dataDir, file);
|
|
11
|
-
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
12
|
-
const hasMatch = keywords.some((kw) => raw.includes(kw));
|
|
13
|
-
if (hasMatch) {
|
|
14
|
-
matches.push(JSON.parse(raw));
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return matches;
|
|
18
|
-
}
|
package/dist/query/handler.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { AgentProvider } from '../agent/types';
|
|
2
|
-
import { MeetingRecord } from '../storage/types';
|
|
3
|
-
export declare class QueryHandler {
|
|
4
|
-
private readonly agent;
|
|
5
|
-
private readonly dataDir;
|
|
6
|
-
constructor(agent: AgentProvider, dataDir: string);
|
|
7
|
-
find(query: string): Promise<MeetingRecord[]>;
|
|
8
|
-
}
|
package/dist/query/handler.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { grepMeetings } from './finder';
|
|
2
|
-
export class QueryHandler {
|
|
3
|
-
agent;
|
|
4
|
-
dataDir;
|
|
5
|
-
constructor(agent, dataDir) {
|
|
6
|
-
this.agent = agent;
|
|
7
|
-
this.dataDir = dataDir;
|
|
8
|
-
}
|
|
9
|
-
async find(query) {
|
|
10
|
-
const keywords = await this.agent.searchKeywords(query);
|
|
11
|
-
const candidates = await grepMeetings(this.dataDir, keywords);
|
|
12
|
-
if (candidates.length === 0)
|
|
13
|
-
return [];
|
|
14
|
-
const ranked = await this.agent.rankResults(query, candidates);
|
|
15
|
-
return ranked.slice(0, 3);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare class SessionManager {
|
|
2
|
-
private readonly timeout;
|
|
3
|
-
private activeSessions;
|
|
4
|
-
private sessionDir;
|
|
5
|
-
constructor(kmrDir: string, timeout?: number);
|
|
6
|
-
handleMessage(userId: string, text: string): Promise<string>;
|
|
7
|
-
private ensureSession;
|
|
8
|
-
private sendToSession;
|
|
9
|
-
private extractReply;
|
|
10
|
-
private appendSummary;
|
|
11
|
-
closeSession(userId: string): Promise<void>;
|
|
12
|
-
}
|
package/dist/session/manager.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { SESSION_SKILL } from './skill';
|
|
6
|
-
const execFileAsync = promisify(execFile);
|
|
7
|
-
export class SessionManager {
|
|
8
|
-
timeout;
|
|
9
|
-
activeSessions = new Map();
|
|
10
|
-
sessionDir;
|
|
11
|
-
constructor(kmrDir, timeout = 60000) {
|
|
12
|
-
this.timeout = timeout;
|
|
13
|
-
this.sessionDir = path.join(kmrDir, 'sessions');
|
|
14
|
-
fs.mkdirSync(this.sessionDir, { recursive: true });
|
|
15
|
-
}
|
|
16
|
-
async handleMessage(userId, text) {
|
|
17
|
-
const sessionName = await this.ensureSession(userId);
|
|
18
|
-
console.log(`[session] 发送消息到 session: ${sessionName}`);
|
|
19
|
-
const reply = await this.sendToSession(sessionName, text);
|
|
20
|
-
await this.appendSummary(userId, text, reply);
|
|
21
|
-
return reply;
|
|
22
|
-
}
|
|
23
|
-
async ensureSession(userId) {
|
|
24
|
-
const existing = this.activeSessions.get(userId);
|
|
25
|
-
if (existing) {
|
|
26
|
-
console.log(`[session] 复用已有 session: ${existing.name}`);
|
|
27
|
-
return existing.name;
|
|
28
|
-
}
|
|
29
|
-
const sessionName = `kmr-${userId}`;
|
|
30
|
-
const userDir = path.join(this.sessionDir, userId);
|
|
31
|
-
fs.mkdirSync(userDir, { recursive: true });
|
|
32
|
-
// 写入 skill.md
|
|
33
|
-
const skillPath = path.join(userDir, 'skill.md');
|
|
34
|
-
fs.writeFileSync(skillPath, SESSION_SKILL, 'utf-8');
|
|
35
|
-
// 创建 acpx session
|
|
36
|
-
console.log(`[session] 创建新 session: ${sessionName}`);
|
|
37
|
-
try {
|
|
38
|
-
await execFileAsync('acpx', ['claude', 'sessions', 'ensure', '--name', sessionName], {
|
|
39
|
-
timeout: this.timeout,
|
|
40
|
-
maxBuffer: 1024 * 1024,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
catch (err) {
|
|
44
|
-
console.error(`[session] 创建 session 失败:`, err.message);
|
|
45
|
-
throw new Error(`创建会话失败: ${err.message}`);
|
|
46
|
-
}
|
|
47
|
-
// 发送角色设定作为第一条消息
|
|
48
|
-
console.log(`[session] 发送角色设定...`);
|
|
49
|
-
try {
|
|
50
|
-
await execFileAsync('acpx', ['--approve-all', 'claude', '-s', sessionName, SESSION_SKILL], { timeout: this.timeout, maxBuffer: 1024 * 1024 });
|
|
51
|
-
}
|
|
52
|
-
catch (err) {
|
|
53
|
-
console.error(`[session] 角色设定失败:`, err.message);
|
|
54
|
-
// 不阻断,继续
|
|
55
|
-
}
|
|
56
|
-
this.activeSessions.set(userId, {
|
|
57
|
-
name: sessionName,
|
|
58
|
-
createdAt: new Date().toISOString(),
|
|
59
|
-
});
|
|
60
|
-
return sessionName;
|
|
61
|
-
}
|
|
62
|
-
async sendToSession(sessionName, text) {
|
|
63
|
-
try {
|
|
64
|
-
const { stdout } = await execFileAsync('acpx', ['--approve-all', 'claude', '-s', sessionName, text], { timeout: this.timeout, maxBuffer: 1024 * 1024 });
|
|
65
|
-
return this.extractReply(stdout);
|
|
66
|
-
}
|
|
67
|
-
catch (err) {
|
|
68
|
-
if (err.killed) {
|
|
69
|
-
throw new Error(`AI 回复超时 (${this.timeout}ms)`);
|
|
70
|
-
}
|
|
71
|
-
throw new Error(`AI 回复失败: ${err.message}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
extractReply(output) {
|
|
75
|
-
const lines = output.split('\n');
|
|
76
|
-
const filtered = lines
|
|
77
|
-
.filter((line) => {
|
|
78
|
-
const t = line.trim();
|
|
79
|
-
return (t.length > 0 &&
|
|
80
|
-
!t.startsWith('[client]') &&
|
|
81
|
-
!t.startsWith('[tool]') &&
|
|
82
|
-
!t.startsWith('[thinking]') &&
|
|
83
|
-
!t.startsWith('[done]') &&
|
|
84
|
-
!t.startsWith('[error]') &&
|
|
85
|
-
!t.startsWith('[warn]') &&
|
|
86
|
-
!t.startsWith('[info]'));
|
|
87
|
-
})
|
|
88
|
-
.join('\n')
|
|
89
|
-
.trim();
|
|
90
|
-
return filtered || output.trim();
|
|
91
|
-
}
|
|
92
|
-
async appendSummary(userId, userText, aiReply) {
|
|
93
|
-
const userDir = path.join(this.sessionDir, userId);
|
|
94
|
-
const summaryPath = path.join(userDir, 'summary.md');
|
|
95
|
-
const now = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
|
96
|
-
const entry = `\n[${now}] 用户: ${userText}\n[${now}] AI: ${aiReply}\n`;
|
|
97
|
-
fs.appendFileSync(summaryPath, entry, 'utf-8');
|
|
98
|
-
}
|
|
99
|
-
async closeSession(userId) {
|
|
100
|
-
const info = this.activeSessions.get(userId);
|
|
101
|
-
if (!info)
|
|
102
|
-
return;
|
|
103
|
-
try {
|
|
104
|
-
await execFileAsync('acpx', ['claude', 'sessions', 'close', info.name], {
|
|
105
|
-
timeout: 10000,
|
|
106
|
-
});
|
|
107
|
-
console.log(`[session] 已关闭 session: ${info.name}`);
|
|
108
|
-
}
|
|
109
|
-
catch (err) {
|
|
110
|
-
console.error(`[session] 关闭 session 失败:`, err.message);
|
|
111
|
-
}
|
|
112
|
-
this.activeSessions.delete(userId);
|
|
113
|
-
}
|
|
114
|
-
}
|
package/dist/session/skill.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const SESSION_SKILL = "\u4F60\u662F KMR\uFF08Key Meetings Record\uFF09\u7684\u667A\u80FD\u52A9\u624B\u3002\n\n\u4F60\u7684\u804C\u8D23\uFF1A\n1. \u5E2E\u52A9\u7528\u6237\u7406\u89E3\u548C\u7BA1\u7406\u4F1A\u8BAE\u8BB0\u5F55\n2. \u56DE\u7B54\u5173\u4E8E\u5386\u53F2\u4F1A\u8BAE\u5185\u5BB9\u7684\u95EE\u9898\n3. \u5E2E\u52A9\u7528\u6237\u6574\u7406\u3001\u603B\u7ED3\u5DE5\u4F5C\u4E2D\u7684\u4FE1\u606F\n4. \u63D0\u4F9B\u5DE5\u4F5C\u5EFA\u8BAE\u548C\u77E5\u8BC6\u68C0\u7D22\n\n\u80CC\u666F\u4FE1\u606F\uFF1A\n- KMR \u662F\u4E00\u4E2A\u4ECE\u98DE\u4E66\u4F1A\u8BAE\u7EAA\u8981\u4E2D\u63D0\u53D6\u5173\u952E\u4FE1\u606F\u7684\u670D\u52A1\n- \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\n- \u7528\u6237\u53EF\u4EE5\u901A\u8FC7 /find \u641C\u7D22\u5386\u53F2\u4F1A\u8BAE\uFF0C/listall \u5217\u51FA\u6240\u6709\u8BB0\u5F55\uFF0C/show \u67E5\u770B\u8BE6\u60C5\uFF0C/del \u5220\u9664\u8BB0\u5F55\n\n\u5BF9\u8BDD\u8981\u6C42\uFF1A\n- \u7B80\u6D01\u3001\u4E13\u4E1A\u3001\u6709\u5E2E\u52A9\n- \u5982\u679C\u7528\u6237\u7684\u95EE\u9898\u6D89\u53CA\u4F1A\u8BAE\u8BB0\u5F55\u64CD\u4F5C\uFF0C\u5F15\u5BFC\u4ED6\u4EEC\u4F7F\u7528\u5BF9\u5E94\u7684\u547D\u4EE4\n- \u6BCF\u6B21\u56DE\u590D\u63A7\u5236\u5728\u5408\u7406\u957F\u5EA6\uFF0C\u9002\u5408\u98DE\u4E66\u6D88\u606F\u9605\u8BFB\n\n\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";
|
package/dist/session/skill.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export const SESSION_SKILL = `你是 KMR(Key Meetings Record)的智能助手。
|
|
2
|
-
|
|
3
|
-
你的职责:
|
|
4
|
-
1. 帮助用户理解和管理会议记录
|
|
5
|
-
2. 回答关于历史会议内容的问题
|
|
6
|
-
3. 帮助用户整理、总结工作中的信息
|
|
7
|
-
4. 提供工作建议和知识检索
|
|
8
|
-
|
|
9
|
-
背景信息:
|
|
10
|
-
- KMR 是一个从飞书会议纪要中提取关键信息的服务
|
|
11
|
-
- 核心提取维度:关键共识与承诺(溯源追责)、可复用知识(工具/方法/经验)
|
|
12
|
-
- 用户可以通过 /find 搜索历史会议,/listall 列出所有记录,/show 查看详情,/del 删除记录
|
|
13
|
-
|
|
14
|
-
对话要求:
|
|
15
|
-
- 简洁、专业、有帮助
|
|
16
|
-
- 如果用户的问题涉及会议记录操作,引导他们使用对应的命令
|
|
17
|
-
- 每次回复控制在合理长度,适合飞书消息阅读
|
|
18
|
-
|
|
19
|
-
【重要】直接输出纯文本回复,不要输出 JSON、markdown 代码块等格式。`;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { MeetingRecord, StorageProvider } from './types';
|
|
2
|
-
export declare class JsonStore implements StorageProvider {
|
|
3
|
-
private readonly dataDir;
|
|
4
|
-
constructor(dataDir: string);
|
|
5
|
-
save(record: MeetingRecord): Promise<string>;
|
|
6
|
-
load(id: string): Promise<MeetingRecord | null>;
|
|
7
|
-
list(): Promise<MeetingRecord[]>;
|
|
8
|
-
search(keywords: string[]): Promise<MeetingRecord[]>;
|
|
9
|
-
delete(id: string): Promise<boolean>;
|
|
10
|
-
private getFiles;
|
|
11
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
export class JsonStore {
|
|
4
|
-
dataDir;
|
|
5
|
-
constructor(dataDir) {
|
|
6
|
-
this.dataDir = dataDir;
|
|
7
|
-
fs.mkdirSync(dataDir, { recursive: true });
|
|
8
|
-
}
|
|
9
|
-
async save(record) {
|
|
10
|
-
const date = record.summary.date || new Date().toISOString().slice(0, 10);
|
|
11
|
-
const fileName = `${date}_${record.id}.json`;
|
|
12
|
-
const filePath = path.join(this.dataDir, fileName);
|
|
13
|
-
fs.writeFileSync(filePath, JSON.stringify(record, null, 2), 'utf-8');
|
|
14
|
-
return filePath;
|
|
15
|
-
}
|
|
16
|
-
async load(id) {
|
|
17
|
-
const files = this.getFiles();
|
|
18
|
-
const target = files.find((f) => f.includes(id));
|
|
19
|
-
if (!target)
|
|
20
|
-
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)
|
|
39
|
-
return false;
|
|
40
|
-
fs.unlinkSync(target);
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
getFiles() {
|
|
44
|
-
if (!fs.existsSync(this.dataDir))
|
|
45
|
-
return [];
|
|
46
|
-
return fs
|
|
47
|
-
.readdirSync(this.dataDir)
|
|
48
|
-
.filter((f) => f.endsWith('.json'))
|
|
49
|
-
.map((f) => path.join(this.dataDir, f));
|
|
50
|
-
}
|
|
51
|
-
}
|
package/dist/storage/types.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export interface MeetingRecord {
|
|
2
|
-
id: string;
|
|
3
|
-
documentUrl: string;
|
|
4
|
-
extractedAt: string;
|
|
5
|
-
summary: {
|
|
6
|
-
title: string;
|
|
7
|
-
date: string;
|
|
8
|
-
participants: string[];
|
|
9
|
-
keyPoints: string[];
|
|
10
|
-
};
|
|
11
|
-
todos: {
|
|
12
|
-
content: string;
|
|
13
|
-
owner: string;
|
|
14
|
-
deadline: string;
|
|
15
|
-
status: string;
|
|
16
|
-
}[];
|
|
17
|
-
risks: {
|
|
18
|
-
description: string;
|
|
19
|
-
severity: string;
|
|
20
|
-
mitigation: string;
|
|
21
|
-
}[];
|
|
22
|
-
projectRelations: {
|
|
23
|
-
project: string;
|
|
24
|
-
relation: string;
|
|
25
|
-
}[];
|
|
26
|
-
commitments: {
|
|
27
|
-
content: string;
|
|
28
|
-
participants: string[];
|
|
29
|
-
deadline?: string;
|
|
30
|
-
context: string;
|
|
31
|
-
}[];
|
|
32
|
-
reusableInsights: {
|
|
33
|
-
category: 'tool' | 'methodology' | 'lesson' | 'best-practice';
|
|
34
|
-
content: string;
|
|
35
|
-
scenario: string;
|
|
36
|
-
source: string;
|
|
37
|
-
}[];
|
|
38
|
-
createdTasks?: {
|
|
39
|
-
summary: string;
|
|
40
|
-
taskId: string;
|
|
41
|
-
url: string;
|
|
42
|
-
createdAt: string;
|
|
43
|
-
}[];
|
|
44
|
-
rawContent: string;
|
|
45
|
-
}
|
|
46
|
-
export interface StorageProvider {
|
|
47
|
-
save(record: MeetingRecord): Promise<string>;
|
|
48
|
-
load(id: string): Promise<MeetingRecord | null>;
|
|
49
|
-
list(): Promise<MeetingRecord[]>;
|
|
50
|
-
search(keywords: string[]): Promise<MeetingRecord[]>;
|
|
51
|
-
delete(id: string): Promise<boolean>;
|
|
52
|
-
}
|
package/dist/storage/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function openBrowser(url: string): void;
|
package/dist/web/openBrowser.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
|
-
export function openBrowser(url) {
|
|
3
|
-
const platform = process.platform;
|
|
4
|
-
switch (platform) {
|
|
5
|
-
case 'darwin':
|
|
6
|
-
execFile('open', [url]);
|
|
7
|
-
break;
|
|
8
|
-
case 'win32':
|
|
9
|
-
execFile('cmd', ['/c', 'start', url]);
|
|
10
|
-
break;
|
|
11
|
-
default:
|
|
12
|
-
execFile('xdg-open', [url]);
|
|
13
|
-
break;
|
|
14
|
-
}
|
|
15
|
-
}
|