libero-mcp 0.2.15 → 0.2.17
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/data/migrations/013_identity_managed_by.sql +3 -0
- package/dist/data/migrations/013_identity_managed_by.sql +3 -0
- package/dist/mcp/server-core.js +45 -2
- package/dist/mcp/src/identity/in-memory.js +36 -1
- package/dist/mcp/src/profile/index.js +29 -0
- package/dist/mcp/src/repo/sqlite-identity.js +43 -1
- package/package.json +1 -1
package/dist/mcp/server-core.js
CHANGED
|
@@ -373,7 +373,9 @@ function buildToolRegistry(ctx) {
|
|
|
373
373
|
// ============================================================
|
|
374
374
|
tools.push({
|
|
375
375
|
name: "matrix.renderMatrix",
|
|
376
|
-
description: "
|
|
376
|
+
description: "时间×评分四象限矩阵(能耗黑洞/保持区/亮点区/可放弃)。" +
|
|
377
|
+
"⚠️ 用户说「时间矩阵 / 时间表 / 看日程 / 今天时间表」时**不要**调本工具——那些是指 emoji 时间块视图,请改调 schedule.timeline。" +
|
|
378
|
+
"本工具仅用于:阶段复盘(这周/最近 N 天)+ 已评分记录的象限分析。",
|
|
377
379
|
inputSchema: {
|
|
378
380
|
user_id: z.string().optional(),
|
|
379
381
|
from: z.string().optional(),
|
|
@@ -393,7 +395,7 @@ function buildToolRegistry(ctx) {
|
|
|
393
395
|
tools.push({
|
|
394
396
|
name: "schedule.timeline",
|
|
395
397
|
description: "看日程/复盘的首选视图:emoji 矩阵+细项表格,含计划/计时中/未回应/实绩全状态。" +
|
|
396
|
-
"用户说「看今天/看日程/在干啥/复盘/接下来 N
|
|
398
|
+
"用户说「看今天/看日程/在干啥/复盘/接下来 N 小时/时间矩阵/时间表/今天时间表」时调本工具,并直接 echo rendered_text(不重写、不改格式)。" +
|
|
397
399
|
"不要调 scheduler.listSchedules(那是内部排程查询,不是用户视图)。",
|
|
398
400
|
inputSchema: {
|
|
399
401
|
user_id: z.string().optional(),
|
|
@@ -644,6 +646,47 @@ function buildToolRegistry(ctx) {
|
|
|
644
646
|
}
|
|
645
647
|
},
|
|
646
648
|
});
|
|
649
|
+
tools.push({
|
|
650
|
+
name: "profile.getManager",
|
|
651
|
+
description: "S44 代管转发:查某用户的代管人(managed_by + 代管人 display_name)。" +
|
|
652
|
+
"用途:扫描 cron 发现用户没自己渠道时,查 managed_by 把追问发给代管人。" +
|
|
653
|
+
"返回 managed_by=null 表示该用户没代管人(普通独立用户)。",
|
|
654
|
+
inputSchema: {
|
|
655
|
+
user_id: z.string().min(1),
|
|
656
|
+
},
|
|
657
|
+
handler: async (rawInput) => {
|
|
658
|
+
try {
|
|
659
|
+
const result = await profile.getManager({ user_id: rawInput.user_id });
|
|
660
|
+
return asContent(result);
|
|
661
|
+
}
|
|
662
|
+
catch (e) {
|
|
663
|
+
return errorContent(e.message);
|
|
664
|
+
}
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
tools.push({
|
|
668
|
+
name: "profile.setManager",
|
|
669
|
+
description: "S44 代管转发:设置或清除某用户的代管人。" +
|
|
670
|
+
"用法:profile.setManager({ user_id: '<被代管人>', managed_by: '<代管人 libero_user_id>' })。" +
|
|
671
|
+
"managed_by=null 清除代管关系;非 null 必须指向存在的 libero_user_id(FK 校验)。" +
|
|
672
|
+
"典型场景:父母给孩子建账户后,profile.setManager({ user_id: '<孩子>', managed_by: '<父母>' })。",
|
|
673
|
+
inputSchema: {
|
|
674
|
+
user_id: z.string().min(1),
|
|
675
|
+
managed_by: z.string().nullable(),
|
|
676
|
+
},
|
|
677
|
+
handler: async (rawInput) => {
|
|
678
|
+
try {
|
|
679
|
+
const result = await profile.setManager({
|
|
680
|
+
user_id: rawInput.user_id,
|
|
681
|
+
managed_by: rawInput.managed_by,
|
|
682
|
+
});
|
|
683
|
+
return asContent(result);
|
|
684
|
+
}
|
|
685
|
+
catch (e) {
|
|
686
|
+
return errorContent(e.message);
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
});
|
|
647
690
|
// ============================================================
|
|
648
691
|
// reminder (6 tools — S11)
|
|
649
692
|
// ============================================================
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
export class InMemoryIdentityRepo {
|
|
9
9
|
identities = new Map();
|
|
10
10
|
aliases = new Map(); // key = `${platform}:${platform_user_id}`
|
|
11
|
+
managers = new Map(); // user_id → manager_user_id
|
|
11
12
|
async createIdentity(input) {
|
|
12
13
|
if (this.identities.has(input.libero_user_id)) {
|
|
13
14
|
throw new Error(`identity already exists: libero_user_id=${input.libero_user_id}`);
|
|
@@ -60,6 +61,40 @@ export class InMemoryIdentityRepo {
|
|
|
60
61
|
return null;
|
|
61
62
|
}
|
|
62
63
|
async listAllIdentities() {
|
|
63
|
-
return Array.from(this.identities.values())
|
|
64
|
+
return Array.from(this.identities.values()).map((i) => ({
|
|
65
|
+
...i,
|
|
66
|
+
managed_by: this.managers.get(i.libero_user_id) ?? null,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
async getManager(libero_user_id) {
|
|
70
|
+
const id = this.identities.get(libero_user_id);
|
|
71
|
+
if (!id) {
|
|
72
|
+
throw new Error(`getManager: libero_user_id not found: ${libero_user_id}`);
|
|
73
|
+
}
|
|
74
|
+
const managedBy = this.managers.get(libero_user_id) ?? null;
|
|
75
|
+
const mgr = managedBy ? this.identities.get(managedBy) : null;
|
|
76
|
+
return {
|
|
77
|
+
libero_user_id,
|
|
78
|
+
managed_by: managedBy,
|
|
79
|
+
manager_display_name: mgr?.display_name ?? null,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async setManager(input) {
|
|
83
|
+
if (!this.identities.has(input.libero_user_id)) {
|
|
84
|
+
throw new Error(`setManager: libero_user_id not found: ${input.libero_user_id}`);
|
|
85
|
+
}
|
|
86
|
+
if (input.managed_by !== null) {
|
|
87
|
+
if (!this.identities.has(input.managed_by)) {
|
|
88
|
+
throw new Error(`setManager: manager libero_user_id not found: ${input.managed_by}`);
|
|
89
|
+
}
|
|
90
|
+
this.managers.set(input.libero_user_id, input.managed_by);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.managers.delete(input.libero_user_id);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
libero_user_id: input.libero_user_id,
|
|
97
|
+
managed_by: input.managed_by,
|
|
98
|
+
};
|
|
64
99
|
}
|
|
65
100
|
}
|
|
@@ -188,5 +188,34 @@ export function createProfileTools(repo, identityRepo) {
|
|
|
188
188
|
display_name: i.display_name,
|
|
189
189
|
}));
|
|
190
190
|
},
|
|
191
|
+
/**
|
|
192
|
+
* S44(2026-08-07):查某用户的代管人。
|
|
193
|
+
* 用途:扫描 cron 发现用户没自己渠道时,查 managed_by 把追问发给代管人。
|
|
194
|
+
*/
|
|
195
|
+
async getManager(input) {
|
|
196
|
+
if (!identityRepo) {
|
|
197
|
+
throw new Error("getManager 需要 identityRepo(本部署不支持代管转发)");
|
|
198
|
+
}
|
|
199
|
+
if (!input.user_id) {
|
|
200
|
+
throw new Error("user_id 为必填参数");
|
|
201
|
+
}
|
|
202
|
+
return identityRepo.getManager(input.user_id);
|
|
203
|
+
},
|
|
204
|
+
/**
|
|
205
|
+
* S44(2026-08-07):设置/清除某用户的代管人。
|
|
206
|
+
* managed_by=null 清除;非 null 必须指向存在的 libero_user_id。
|
|
207
|
+
*/
|
|
208
|
+
async setManager(input) {
|
|
209
|
+
if (!identityRepo) {
|
|
210
|
+
throw new Error("setManager 需要 identityRepo(本部署不支持代管转发)");
|
|
211
|
+
}
|
|
212
|
+
if (!input.user_id) {
|
|
213
|
+
throw new Error("user_id 为必填参数");
|
|
214
|
+
}
|
|
215
|
+
return identityRepo.setManager({
|
|
216
|
+
libero_user_id: input.user_id,
|
|
217
|
+
managed_by: input.managed_by,
|
|
218
|
+
});
|
|
219
|
+
},
|
|
191
220
|
};
|
|
192
221
|
}
|
|
@@ -78,10 +78,52 @@ export class SqliteIdentityRepo {
|
|
|
78
78
|
}
|
|
79
79
|
async listAllIdentities() {
|
|
80
80
|
const rows = this.db
|
|
81
|
-
.prepare(`SELECT libero_user_id, display_name, created_at, updated_at
|
|
81
|
+
.prepare(`SELECT libero_user_id, display_name, managed_by, created_at, updated_at
|
|
82
82
|
FROM user_identity
|
|
83
83
|
ORDER BY created_at ASC`)
|
|
84
84
|
.all();
|
|
85
85
|
return rows.map((r) => ({ ...r }));
|
|
86
86
|
}
|
|
87
|
+
async getManager(libero_user_id) {
|
|
88
|
+
const row = this.db
|
|
89
|
+
.prepare(`SELECT ui.libero_user_id, ui.managed_by, mgr.display_name as manager_display_name
|
|
90
|
+
FROM user_identity ui
|
|
91
|
+
LEFT JOIN user_identity mgr ON mgr.libero_user_id = ui.managed_by
|
|
92
|
+
WHERE ui.libero_user_id = ?`)
|
|
93
|
+
.get(libero_user_id);
|
|
94
|
+
if (!row) {
|
|
95
|
+
throw new Error(`getManager: libero_user_id not found: ${libero_user_id}`);
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
libero_user_id: row.libero_user_id,
|
|
99
|
+
managed_by: row.managed_by,
|
|
100
|
+
manager_display_name: row.manager_display_name,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
async setManager(input) {
|
|
104
|
+
// User existence check
|
|
105
|
+
const user = this.db
|
|
106
|
+
.prepare("SELECT 1 FROM user_identity WHERE libero_user_id = ?")
|
|
107
|
+
.get(input.libero_user_id);
|
|
108
|
+
if (!user) {
|
|
109
|
+
throw new Error(`setManager: libero_user_id not found: ${input.libero_user_id}`);
|
|
110
|
+
}
|
|
111
|
+
// Manager FK check (if non-null)
|
|
112
|
+
if (input.managed_by !== null) {
|
|
113
|
+
const mgr = this.db
|
|
114
|
+
.prepare("SELECT 1 FROM user_identity WHERE libero_user_id = ?")
|
|
115
|
+
.get(input.managed_by);
|
|
116
|
+
if (!mgr) {
|
|
117
|
+
throw new Error(`setManager: manager libero_user_id not found: ${input.managed_by}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const now = new Date().toISOString().replace("T", " ").replace("Z", "");
|
|
121
|
+
this.db
|
|
122
|
+
.prepare("UPDATE user_identity SET managed_by = ?, updated_at = ? WHERE libero_user_id = ?")
|
|
123
|
+
.run(input.managed_by, now, input.libero_user_id);
|
|
124
|
+
return {
|
|
125
|
+
libero_user_id: input.libero_user_id,
|
|
126
|
+
managed_by: input.managed_by,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
87
129
|
}
|