agent-remnote 0.1.0 → 0.2.0
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/CHANGELOG.md +11 -0
- package/README.md +28 -0
- package/dist/main.js +3563 -850
- package/package.json +19 -4
- package/dist/apps/cli/src/adapters/mcp.js +0 -1
- package/dist/apps/cli/src/commands/_enqueue.js +0 -138
- package/dist/apps/cli/src/commands/_shared.js +0 -57
- package/dist/apps/cli/src/commands/_tool.js +0 -28
- package/dist/apps/cli/src/commands/apply.js +0 -81
- package/dist/apps/cli/src/commands/config/index.js +0 -3
- package/dist/apps/cli/src/commands/config/print.js +0 -28
- package/dist/apps/cli/src/commands/daily/index.js +0 -4
- package/dist/apps/cli/src/commands/daily/summary.js +0 -25
- package/dist/apps/cli/src/commands/daily/write.js +0 -145
- package/dist/apps/cli/src/commands/db/backups.js +0 -23
- package/dist/apps/cli/src/commands/db/index.js +0 -4
- package/dist/apps/cli/src/commands/db/recent.js +0 -178
- package/dist/apps/cli/src/commands/doctor.js +0 -124
- package/dist/apps/cli/src/commands/index.js +0 -73
- package/dist/apps/cli/src/commands/ops/index.js +0 -4
- package/dist/apps/cli/src/commands/ops/list.js +0 -12
- package/dist/apps/cli/src/commands/ops/schema.js +0 -77
- package/dist/apps/cli/src/commands/queue/enqueue.js +0 -73
- package/dist/apps/cli/src/commands/queue/index.js +0 -5
- package/dist/apps/cli/src/commands/queue/inspect.js +0 -26
- package/dist/apps/cli/src/commands/queue/stats.js +0 -14
- package/dist/apps/cli/src/commands/read/by-reference.js +0 -35
- package/dist/apps/cli/src/commands/read/connections.js +0 -15
- package/dist/apps/cli/src/commands/read/index.js +0 -21
- package/dist/apps/cli/src/commands/read/inspect.js +0 -34
- package/dist/apps/cli/src/commands/read/outline.js +0 -59
- package/dist/apps/cli/src/commands/read/query.js +0 -95
- package/dist/apps/cli/src/commands/read/references.js +0 -41
- package/dist/apps/cli/src/commands/read/resolve-ref.js +0 -32
- package/dist/apps/cli/src/commands/read/search.js +0 -40
- package/dist/apps/cli/src/commands/read/table.js +0 -32
- package/dist/apps/cli/src/commands/todos/index.js +0 -3
- package/dist/apps/cli/src/commands/todos/list.js +0 -33
- package/dist/apps/cli/src/commands/topic/index.js +0 -3
- package/dist/apps/cli/src/commands/topic/summary.js +0 -44
- package/dist/apps/cli/src/commands/wechat/index.js +0 -3
- package/dist/apps/cli/src/commands/wechat/outline.js +0 -430
- package/dist/apps/cli/src/commands/write/bullet.js +0 -76
- package/dist/apps/cli/src/commands/write/index.js +0 -4
- package/dist/apps/cli/src/commands/write/md.js +0 -91
- package/dist/apps/cli/src/commands/ws/_shared.js +0 -129
- package/dist/apps/cli/src/commands/ws/ensure.js +0 -22
- package/dist/apps/cli/src/commands/ws/health.js +0 -15
- package/dist/apps/cli/src/commands/ws/index.js +0 -21
- package/dist/apps/cli/src/commands/ws/logs.js +0 -95
- package/dist/apps/cli/src/commands/ws/restart.js +0 -73
- package/dist/apps/cli/src/commands/ws/serve.js +0 -52
- package/dist/apps/cli/src/commands/ws/start.js +0 -70
- package/dist/apps/cli/src/commands/ws/status.js +0 -60
- package/dist/apps/cli/src/commands/ws/stop.js +0 -59
- package/dist/apps/cli/src/commands/ws/trigger.js +0 -20
- package/dist/apps/cli/src/main.js +0 -79
- package/dist/apps/cli/src/services/AppConfig.js +0 -3
- package/dist/apps/cli/src/services/Config.js +0 -91
- package/dist/apps/cli/src/services/DaemonFiles.js +0 -91
- package/dist/apps/cli/src/services/Errors.js +0 -49
- package/dist/apps/cli/src/services/Output.js +0 -16
- package/dist/apps/cli/src/services/Payload.js +0 -90
- package/dist/apps/cli/src/services/Process.js +0 -94
- package/dist/apps/cli/src/services/Queue.js +0 -120
- package/dist/apps/cli/src/services/RefResolver.js +0 -111
- package/dist/apps/cli/src/services/RemDb.js +0 -35
- package/dist/apps/cli/src/services/WsClient.js +0 -170
- package/dist/apps/cli/tests/apply.contract.test.js +0 -31
- package/dist/apps/cli/tests/db-recent.contract.test.js +0 -22
- package/dist/apps/cli/tests/help.contract.test.js +0 -30
- package/dist/apps/cli/tests/helpers/runCli.js +0 -45
- package/dist/apps/cli/tests/ids-output.contract.test.js +0 -30
- package/dist/apps/cli/tests/payload-stdin.contract.test.js +0 -15
- package/dist/apps/cli/tests/read-search.contract.test.js +0 -22
- package/dist/apps/cli/tests/ws-health.contract.test.js +0 -36
- package/dist/apps/cli/vitest.config.js +0 -7
- package/dist/packages/mcp/src/public.js +0 -18
- package/dist/packages/mcp/src/queue/dao.js +0 -165
- package/dist/packages/mcp/src/queue/db.js +0 -26
- package/dist/packages/mcp/src/tools/executeSearchQuery.js +0 -914
- package/dist/packages/mcp/src/tools/findRemsByReference.js +0 -447
- package/dist/packages/mcp/src/tools/getRemConnections.js +0 -566
- package/dist/packages/mcp/src/tools/inspectRemDoc.js +0 -60
- package/dist/packages/mcp/src/tools/listRemBackups.js +0 -35
- package/dist/packages/mcp/src/tools/listRemReferences.js +0 -421
- package/dist/packages/mcp/src/tools/listSupportedOps.js +0 -41
- package/dist/packages/mcp/src/tools/listTodos.js +0 -815
- package/dist/packages/mcp/src/tools/outlineRemSubtree.js +0 -203
- package/dist/packages/mcp/src/tools/readRemTable.js +0 -252
- package/dist/packages/mcp/src/tools/resolveRemReference.js +0 -174
- package/dist/packages/mcp/src/tools/searchQueryTypes.js +0 -127
- package/dist/packages/mcp/src/tools/searchRemOverview.js +0 -422
- package/dist/packages/mcp/src/tools/searchUtils.js +0 -32
- package/dist/packages/mcp/src/tools/shared.js +0 -393
- package/dist/packages/mcp/src/tools/summarizeDailyNotes.js +0 -221
- package/dist/packages/mcp/src/tools/summarizeTopicActivity.js +0 -605
- package/dist/packages/mcp/src/tools/timeFilters.js +0 -130
- package/dist/packages/mcp/src/ws/bridge.js +0 -377
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { buildGuidedResponse, safeJsonParse, summarizeKey, withResolvedDatabase, parseOrThrow, } from "./shared.js";
|
|
3
|
-
import { executeFindRemsByReference } from "./findRemsByReference.js";
|
|
4
|
-
const inputShape = {
|
|
5
|
-
id: z.string().min(1, "id 必填").describe("目标 Rem ID(统计该节点内的 [[引用]])"),
|
|
6
|
-
dbPath: z.string().optional().describe("数据库文件路径(默认自动发现)"),
|
|
7
|
-
includeOccurrences: z
|
|
8
|
-
.boolean()
|
|
9
|
-
.optional()
|
|
10
|
-
.describe("是否包含逐次出现的明细(默认 false,仅返回聚合统计)"),
|
|
11
|
-
resolveText: z.boolean().optional().describe("是否解析引用目标的文本摘要(默认 true)"),
|
|
12
|
-
includeDescendants: z
|
|
13
|
-
.boolean()
|
|
14
|
-
.optional()
|
|
15
|
-
.describe("是否连同子节点一并统计(默认 false)"),
|
|
16
|
-
maxDepth: z
|
|
17
|
-
.number()
|
|
18
|
-
.int()
|
|
19
|
-
.min(0)
|
|
20
|
-
.max(10)
|
|
21
|
-
.optional()
|
|
22
|
-
.describe("当 includeDescendants=true 时的最大子树深度(默认 5)"),
|
|
23
|
-
includeInbound: z
|
|
24
|
-
.boolean()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe("是否同时统计被哪些 Rem 引用(入站引用,默认 false)"),
|
|
27
|
-
inboundMaxDepth: z
|
|
28
|
-
.number()
|
|
29
|
-
.int()
|
|
30
|
-
.min(1)
|
|
31
|
-
.max(3)
|
|
32
|
-
.optional()
|
|
33
|
-
.describe("入站引用的最大深度(默认 1)"),
|
|
34
|
-
inboundMaxCandidates: z
|
|
35
|
-
.number()
|
|
36
|
-
.int()
|
|
37
|
-
.min(1)
|
|
38
|
-
.max(1000)
|
|
39
|
-
.optional()
|
|
40
|
-
.describe("入站引用候选上限(默认 200)"),
|
|
41
|
-
};
|
|
42
|
-
export const listRemReferencesSchema = z.object(inputShape);
|
|
43
|
-
export async function executeListRemReferences(params) {
|
|
44
|
-
const parsed = parseOrThrow(listRemReferencesSchema, params, { label: "list_rem_references" });
|
|
45
|
-
const includeOccurrences = parsed.includeOccurrences ?? false;
|
|
46
|
-
const resolveText = parsed.resolveText ?? true;
|
|
47
|
-
const includeDescendants = parsed.includeDescendants ?? false;
|
|
48
|
-
const maxDepth = parsed.maxDepth ?? 5;
|
|
49
|
-
const includeInbound = parsed.includeInbound ?? false;
|
|
50
|
-
const inboundMaxDepth = parsed.inboundMaxDepth ?? 1;
|
|
51
|
-
const inboundMaxCandidates = parsed.inboundMaxCandidates ?? 200;
|
|
52
|
-
const normalizedInboundCandidates = Math.min(inboundMaxCandidates, 200);
|
|
53
|
-
const { result, info } = await withResolvedDatabase(parsed.dbPath, async (db) => {
|
|
54
|
-
const docs = fetchDocs(db, parsed.id, includeDescendants, maxDepth);
|
|
55
|
-
const occurrences = [];
|
|
56
|
-
for (const doc of docs) {
|
|
57
|
-
collectReferences(doc.key, doc.id, ["key"], occurrences);
|
|
58
|
-
if (doc.value !== undefined) {
|
|
59
|
-
collectReferences(doc.value, doc.id, ["value"], occurrences);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
const aggregate = aggregateReferences(occurrences);
|
|
63
|
-
if (resolveText && aggregate.size > 0) {
|
|
64
|
-
enrichReferenceDetails(db, aggregate);
|
|
65
|
-
}
|
|
66
|
-
const references = Array.from(aggregate.values()).sort((a, b) => b.count - a.count);
|
|
67
|
-
let inbound = [];
|
|
68
|
-
if (includeInbound) {
|
|
69
|
-
const inboundResult = await executeFindRemsByReference({
|
|
70
|
-
targetIds: docs.map((doc) => doc.id),
|
|
71
|
-
maxDepth: inboundMaxDepth,
|
|
72
|
-
maxCandidates: normalizedInboundCandidates,
|
|
73
|
-
limit: normalizedInboundCandidates,
|
|
74
|
-
offset: 0,
|
|
75
|
-
dbPath: parsed.dbPath,
|
|
76
|
-
});
|
|
77
|
-
inbound = inboundResult.matches.map((match) => ({
|
|
78
|
-
remId: match.id,
|
|
79
|
-
title: match.title ?? null,
|
|
80
|
-
snippet: match.snippet ?? null,
|
|
81
|
-
matchedTargets: match.matchedTargets ?? [],
|
|
82
|
-
anchorIds: match.anchorIds ?? [],
|
|
83
|
-
sourceIds: match.sourceIds ?? [],
|
|
84
|
-
depth: match.depth ?? inboundMaxDepth,
|
|
85
|
-
updatedAt: match.updatedAt ?? null,
|
|
86
|
-
createdAt: match.createdAt ?? null,
|
|
87
|
-
ancestor: null,
|
|
88
|
-
ancestorIds: [],
|
|
89
|
-
}));
|
|
90
|
-
enrichInboundDetails(db, inbound);
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
remsScanned: docs.length,
|
|
94
|
-
references,
|
|
95
|
-
totalOccurrences: occurrences.length,
|
|
96
|
-
uniqueCount: references.length,
|
|
97
|
-
includeDescendants,
|
|
98
|
-
inbound,
|
|
99
|
-
inboundCount: inbound.length,
|
|
100
|
-
};
|
|
101
|
-
});
|
|
102
|
-
const guidance = result.uniqueCount > 0
|
|
103
|
-
? `共找到 ${result.uniqueCount} 个引用(总计 ${result.totalOccurrences} 次出现)。`
|
|
104
|
-
: `未在该 Rem 中发现引用。`;
|
|
105
|
-
const originalOutbound = result.references;
|
|
106
|
-
const markdown = buildReferencesMarkdown(params.id, guidance, originalOutbound.map((item) => simplifyReference(item)), result.inbound ?? [], includeInbound);
|
|
107
|
-
const outboundForResponse = includeOccurrences
|
|
108
|
-
? originalOutbound
|
|
109
|
-
: originalOutbound.map((item) => simplifyReference(item));
|
|
110
|
-
const inboundForResponse = includeInbound
|
|
111
|
-
? result.inbound?.map((item) => simplifyInbound(item)) ?? []
|
|
112
|
-
: [];
|
|
113
|
-
const payload = {
|
|
114
|
-
dbPath: info.dbPath,
|
|
115
|
-
resolution: info.source,
|
|
116
|
-
dirName: info.dirName,
|
|
117
|
-
remId: params.id,
|
|
118
|
-
guidance,
|
|
119
|
-
includeDescendants,
|
|
120
|
-
maxDepth,
|
|
121
|
-
remsScanned: result.remsScanned,
|
|
122
|
-
totalOccurrences: result.totalOccurrences,
|
|
123
|
-
uniqueCount: result.uniqueCount,
|
|
124
|
-
markdown,
|
|
125
|
-
references: outboundForResponse,
|
|
126
|
-
includeInbound,
|
|
127
|
-
inboundMaxDepth,
|
|
128
|
-
inboundMaxCandidates: normalizedInboundCandidates,
|
|
129
|
-
inboundCount: result.inboundCount ?? 0,
|
|
130
|
-
inbound: inboundForResponse,
|
|
131
|
-
};
|
|
132
|
-
const suggestions = result.uniqueCount > 0
|
|
133
|
-
? [
|
|
134
|
-
"如需展开引用内容,可调用 outline_rem_subtree id=<refId>",
|
|
135
|
-
"若需查看引用所在上下文,可结合 outline_rem_subtree id=<remId> includeEmpty=true",
|
|
136
|
-
]
|
|
137
|
-
: ["未包含引用,可确认是否为纯文本 Rem"];
|
|
138
|
-
if (!includeDescendants) {
|
|
139
|
-
suggestions.push("若需连同子节点的引用一并统计,可设置 includeDescendants=true");
|
|
140
|
-
}
|
|
141
|
-
if (!includeInbound) {
|
|
142
|
-
suggestions.push("若需查看被哪些 Rem 引用,可设置 includeInbound=true");
|
|
143
|
-
}
|
|
144
|
-
return { payload, suggestions };
|
|
145
|
-
}
|
|
146
|
-
export function registerListRemReferences(server) {
|
|
147
|
-
server.tool("list_rem_references", `<usecase>列出指定 Rem 中的所有 [[引用]]。</usecase>
|
|
148
|
-
<instructions>
|
|
149
|
-
- 默认去重统计并给出引用文本,必要时可设置 includeOccurrences=false 精简输出。
|
|
150
|
-
- 若需要展开引用的全文,可对返回的 refId 继续调用 outline_rem_subtree 或 inspect_rem_doc。
|
|
151
|
-
</instructions>`, inputShape, async (input) => {
|
|
152
|
-
const result = await executeListRemReferences(input);
|
|
153
|
-
return buildGuidedResponse(result.payload, result.suggestions);
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function fetchDocs(db, rootId, includeDescendants, maxDepth) {
|
|
157
|
-
const convertRow = (id, rawDoc) => {
|
|
158
|
-
const parsed = safeJsonParse(rawDoc);
|
|
159
|
-
return {
|
|
160
|
-
id,
|
|
161
|
-
doc: parsed ?? undefined,
|
|
162
|
-
key: parsed?.key,
|
|
163
|
-
value: parsed?.value,
|
|
164
|
-
};
|
|
165
|
-
};
|
|
166
|
-
if (!includeDescendants) {
|
|
167
|
-
const row = db
|
|
168
|
-
.prepare("SELECT doc FROM quanta WHERE _id = ?")
|
|
169
|
-
.get(rootId);
|
|
170
|
-
if (!row) {
|
|
171
|
-
throw new Error(`未找到该 Rem(id=${rootId}),请确认 ID 是否存在于当前数据库`);
|
|
172
|
-
}
|
|
173
|
-
return [convertRow(rootId, row.doc)];
|
|
174
|
-
}
|
|
175
|
-
const rows = db
|
|
176
|
-
.prepare(`WITH RECURSIVE tree(id, depth) AS (
|
|
177
|
-
SELECT _id, 0 FROM quanta WHERE _id = @root
|
|
178
|
-
UNION ALL
|
|
179
|
-
SELECT child._id, tree.depth + 1
|
|
180
|
-
FROM quanta child
|
|
181
|
-
JOIN tree ON json_extract(child.doc, '$.parent') = tree.id
|
|
182
|
-
WHERE tree.depth + 1 <= @maxDepth
|
|
183
|
-
)
|
|
184
|
-
SELECT tree.id, quanta.doc
|
|
185
|
-
FROM tree
|
|
186
|
-
JOIN quanta ON quanta._id = tree.id`)
|
|
187
|
-
.all({ root: rootId, maxDepth });
|
|
188
|
-
if (rows.length === 0) {
|
|
189
|
-
throw new Error(`未找到该 Rem(id=${rootId}),请确认 ID 是否存在于当前数据库`);
|
|
190
|
-
}
|
|
191
|
-
return rows.map((row) => convertRow(row.id, row.doc));
|
|
192
|
-
}
|
|
193
|
-
function collectReferences(value, remId, path, into) {
|
|
194
|
-
if (Array.isArray(value)) {
|
|
195
|
-
value.forEach((item, index) => {
|
|
196
|
-
collectReferences(item, remId, [...path, index], into);
|
|
197
|
-
});
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (value && typeof value === "object") {
|
|
201
|
-
const maybeRef = value;
|
|
202
|
-
if (maybeRef.i === "q" && typeof maybeRef._id === "string") {
|
|
203
|
-
into.push({
|
|
204
|
-
refId: maybeRef._id,
|
|
205
|
-
remId,
|
|
206
|
-
path: formatPath(path),
|
|
207
|
-
tokenKind: classifyToken(maybeRef),
|
|
208
|
-
});
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
if (maybeRef.i === "p" && typeof maybeRef._id === "string") {
|
|
212
|
-
into.push({
|
|
213
|
-
refId: maybeRef._id,
|
|
214
|
-
remId,
|
|
215
|
-
path: formatPath(path),
|
|
216
|
-
tokenKind: classifyToken(maybeRef),
|
|
217
|
-
});
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
for (const [key, child] of Object.entries(maybeRef)) {
|
|
221
|
-
collectReferences(child, remId, [...path, key], into);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
function formatPath(segments) {
|
|
226
|
-
return segments
|
|
227
|
-
.map((segment, index) => {
|
|
228
|
-
if (typeof segment === "number") {
|
|
229
|
-
return `[${segment}]`;
|
|
230
|
-
}
|
|
231
|
-
return index === 0 ? segment : `.${segment}`;
|
|
232
|
-
})
|
|
233
|
-
.join("");
|
|
234
|
-
}
|
|
235
|
-
function aggregateReferences(occurrences) {
|
|
236
|
-
const map = new Map();
|
|
237
|
-
for (const occurrence of occurrences) {
|
|
238
|
-
const existing = map.get(occurrence.refId);
|
|
239
|
-
if (existing) {
|
|
240
|
-
existing.count += 1;
|
|
241
|
-
existing.occurrences.push({
|
|
242
|
-
remId: occurrence.remId,
|
|
243
|
-
path: occurrence.path,
|
|
244
|
-
tokenKind: occurrence.tokenKind,
|
|
245
|
-
});
|
|
246
|
-
if (!existing.remIds.includes(occurrence.remId)) {
|
|
247
|
-
existing.remIds.push(occurrence.remId);
|
|
248
|
-
}
|
|
249
|
-
if (!existing.tokenKinds.includes(occurrence.tokenKind)) {
|
|
250
|
-
existing.tokenKinds.push(occurrence.tokenKind);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
map.set(occurrence.refId, {
|
|
255
|
-
refId: occurrence.refId,
|
|
256
|
-
count: 1,
|
|
257
|
-
text: null,
|
|
258
|
-
ancestor: null,
|
|
259
|
-
ancestorIds: [],
|
|
260
|
-
remIds: [occurrence.remId],
|
|
261
|
-
tokenKinds: [occurrence.tokenKind],
|
|
262
|
-
occurrences: [
|
|
263
|
-
{
|
|
264
|
-
remId: occurrence.remId,
|
|
265
|
-
path: occurrence.path,
|
|
266
|
-
tokenKind: occurrence.tokenKind,
|
|
267
|
-
},
|
|
268
|
-
],
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return map;
|
|
273
|
-
}
|
|
274
|
-
function enrichReferenceDetails(db, aggregate) {
|
|
275
|
-
if (aggregate.size === 0)
|
|
276
|
-
return;
|
|
277
|
-
const infoStmt = db.prepare(`SELECT
|
|
278
|
-
json_extract(doc, '$.kt') AS plainText,
|
|
279
|
-
ancestor_not_ref_text AS ancestorText,
|
|
280
|
-
ancestor_ids AS ancestorIds
|
|
281
|
-
FROM remsSearchInfos
|
|
282
|
-
WHERE id = ?`);
|
|
283
|
-
const fallbackStmt = db.prepare("SELECT doc FROM quanta WHERE _id = ?");
|
|
284
|
-
for (const entry of aggregate.values()) {
|
|
285
|
-
const infoRow = infoStmt.get(entry.refId);
|
|
286
|
-
if (infoRow) {
|
|
287
|
-
entry.text = normalizeSnippet(infoRow.plainText);
|
|
288
|
-
entry.ancestor = infoRow.ancestorText ? infoRow.ancestorText.trim() : null;
|
|
289
|
-
entry.ancestorIds = infoRow.ancestorIds
|
|
290
|
-
? infoRow.ancestorIds.trim().split(/\s+/).filter(Boolean)
|
|
291
|
-
: [];
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
const fallback = fallbackStmt.get(entry.refId);
|
|
295
|
-
if (fallback) {
|
|
296
|
-
const parsed = safeJsonParse(fallback.doc);
|
|
297
|
-
const summary = summarizeKey(parsed?.key, undefined, { expand: false, maxDepth: 0 });
|
|
298
|
-
entry.text = normalizeSnippet(summary.text);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
function normalizeSnippet(text) {
|
|
304
|
-
if (!text)
|
|
305
|
-
return null;
|
|
306
|
-
const normalized = text.replace(/\s+/g, " ").trim();
|
|
307
|
-
return normalized || null;
|
|
308
|
-
}
|
|
309
|
-
function simplifyReference(item) {
|
|
310
|
-
return {
|
|
311
|
-
refId: item.refId,
|
|
312
|
-
text: item.text,
|
|
313
|
-
count: item.count,
|
|
314
|
-
ancestor: item.ancestor,
|
|
315
|
-
remIds: item.remIds,
|
|
316
|
-
tokenKinds: item.tokenKinds,
|
|
317
|
-
representativePath: item.occurrences[0]?.path ?? null,
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
function simplifyInbound(item) {
|
|
321
|
-
return {
|
|
322
|
-
remId: item.remId,
|
|
323
|
-
title: item.title,
|
|
324
|
-
snippet: item.snippet,
|
|
325
|
-
depth: item.depth,
|
|
326
|
-
ancestor: item.ancestor,
|
|
327
|
-
matchedTargetsCount: item.matchedTargets.length,
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
function buildReferencesMarkdown(remId, guidance, outbound, inbound, includeInbound) {
|
|
331
|
-
const lines = [];
|
|
332
|
-
lines.push(`# Rem ${remId} 引用概览`);
|
|
333
|
-
lines.push(guidance);
|
|
334
|
-
lines.push("\n## 出站引用");
|
|
335
|
-
if (outbound.length === 0) {
|
|
336
|
-
lines.push("- 无出站引用");
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
outbound.forEach((ref) => {
|
|
340
|
-
const name = ref.text?.trim() ? ref.text.trim() : "(未命名)";
|
|
341
|
-
const tokenKind = Array.isArray(ref.tokenKinds)
|
|
342
|
-
? `类型:${formatTokenKinds(ref.tokenKinds)}`
|
|
343
|
-
: "";
|
|
344
|
-
const ancestor = ref.ancestor ? `,祖先:${ref.ancestor}` : "";
|
|
345
|
-
const count = typeof ref.count === "number" ? `${ref.count} 次` : "";
|
|
346
|
-
const path = ref.occurrences
|
|
347
|
-
? ref.occurrences[0]?.path ?? null
|
|
348
|
-
: ref.representativePath;
|
|
349
|
-
const samplePath = path ? `,示例位置:${path}` : "";
|
|
350
|
-
lines.push(`- **${name}**(ID: ${ref.refId},${count}${ancestor}${samplePath}${tokenKind ? `,${tokenKind}` : ""})`);
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
if (includeInbound) {
|
|
354
|
-
lines.push("\n## 入站引用");
|
|
355
|
-
if (inbound.length === 0) {
|
|
356
|
-
lines.push("- 无入站引用");
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
inbound.forEach((ref) => {
|
|
360
|
-
const name = ref.title?.trim() ? ref.title.trim() : "(未命名)";
|
|
361
|
-
const count = ref.matchedTargets.length > 0 ? `${ref.matchedTargets.length} 个目标` : "";
|
|
362
|
-
const breadcrumbs = ref.ancestor ? `,所在:${ref.ancestor}` : "";
|
|
363
|
-
lines.push(`- **${name}**(ID: ${ref.remId},${count}${breadcrumbs})`);
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return lines.join("\n");
|
|
368
|
-
}
|
|
369
|
-
function enrichInboundDetails(db, inbound) {
|
|
370
|
-
if (inbound.length === 0)
|
|
371
|
-
return;
|
|
372
|
-
const infoStmt = db.prepare(`SELECT
|
|
373
|
-
json_extract(doc, '$.kt') AS plainText,
|
|
374
|
-
ancestor_not_ref_text AS ancestorText,
|
|
375
|
-
ancestor_ids AS ancestorIds
|
|
376
|
-
FROM remsSearchInfos
|
|
377
|
-
WHERE id = ?`);
|
|
378
|
-
const fallbackStmt = db.prepare("SELECT doc FROM quanta WHERE _id = ?");
|
|
379
|
-
for (const entry of inbound) {
|
|
380
|
-
const infoRow = infoStmt.get(entry.remId);
|
|
381
|
-
if (infoRow) {
|
|
382
|
-
const snippet = normalizeSnippet(infoRow.plainText);
|
|
383
|
-
if (!entry.title || entry.title === "(空)") {
|
|
384
|
-
entry.title = snippet ?? entry.title;
|
|
385
|
-
}
|
|
386
|
-
entry.snippet = entry.snippet && entry.snippet.trim().length > 0 ? entry.snippet : snippet;
|
|
387
|
-
entry.ancestor = infoRow.ancestorText ? infoRow.ancestorText.trim() : null;
|
|
388
|
-
entry.ancestorIds = infoRow.ancestorIds
|
|
389
|
-
? infoRow.ancestorIds.trim().split(/\s+/).filter(Boolean)
|
|
390
|
-
: [];
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
const fallback = fallbackStmt.get(entry.remId);
|
|
394
|
-
if (fallback) {
|
|
395
|
-
const parsed = safeJsonParse(fallback.doc);
|
|
396
|
-
const summary = summarizeKey(parsed?.key, undefined, { expand: false, maxDepth: 0 });
|
|
397
|
-
const snippet = normalizeSnippet(summary.text);
|
|
398
|
-
if (!entry.title || entry.title === "(空)") {
|
|
399
|
-
entry.title = snippet ?? entry.title;
|
|
400
|
-
}
|
|
401
|
-
entry.snippet = entry.snippet && entry.snippet.trim().length > 0 ? entry.snippet : snippet;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
function classifyToken(token) {
|
|
407
|
-
const raw = typeof token.i === "string" ? token.i : "";
|
|
408
|
-
const tokenMap = {
|
|
409
|
-
q: "reference",
|
|
410
|
-
p: "portal",
|
|
411
|
-
u: "url",
|
|
412
|
-
m: "text",
|
|
413
|
-
t: "tag",
|
|
414
|
-
r: "rich_text",
|
|
415
|
-
};
|
|
416
|
-
return tokenMap[raw] ?? (raw || "unknown");
|
|
417
|
-
}
|
|
418
|
-
function formatTokenKinds(kinds) {
|
|
419
|
-
const unique = Array.from(new Set(kinds));
|
|
420
|
-
return unique.join("/");
|
|
421
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
// Export a concise, LLM-friendly catalog of supported op types and camelCase payload fields
|
|
3
|
-
export const TYPES = {
|
|
4
|
-
create_rem: { required: [], optional: ["parentId", "text", "tags", "isDocument", "clientTempId"], description: "创建一个 Rem,可选设置父级、文本、标签。" },
|
|
5
|
-
create_single_rem_with_markdown: { required: ["markdown"], optional: ["parentId", "clientTempId"], description: "使用 Markdown 创建单个 Rem。" },
|
|
6
|
-
create_tree_with_markdown: { required: ["markdown"], optional: ["parentId", "clientTempIds"], description: "使用 Markdown 批量创建树结构。" },
|
|
7
|
-
create_link_rem: { required: ["url"], optional: ["addTitle", "parentId", "clientTempId"], description: "创建一个链接 Rem。" },
|
|
8
|
-
create_table: { required: [], optional: ["tagId", "clientTempId"], description: "创建表(指定表头 Tag)。" },
|
|
9
|
-
add_property: { required: ["tagId"], optional: ["name", "propertyId", "type", "options"], description: "在表头下新增一个属性。" },
|
|
10
|
-
set_property_type: { required: ["propertyId", "type"], optional: [], description: "设置属性类型。" },
|
|
11
|
-
set_table_filter: { required: ["tagId"], optional: ["filter"], description: "设置表过滤条件。" },
|
|
12
|
-
add_option: { required: ["propertyId"], optional: ["optionId", "name"], description: "在属性下新增选项。" },
|
|
13
|
-
remove_option: { required: ["optionId"], optional: [], description: "移除选项。" },
|
|
14
|
-
table_add_row: { required: ["tagId"], optional: ["clientTempId", "afterRowId"], description: "在表中新增一行。" },
|
|
15
|
-
table_remove_row: { required: ["rowId"], optional: [], description: "删除一行。" },
|
|
16
|
-
set_cell_select: { required: ["rowId", "columnId", "optionId"], optional: [], description: "设置单选列的值(optionId 可为 null)。" },
|
|
17
|
-
set_cell_checkbox: { required: ["rowId", "columnId", "value"], optional: [], description: "设置复选列布尔值。" },
|
|
18
|
-
set_cell_number: { required: ["rowId", "columnId", "value"], optional: [], description: "设置数字列值(可为 null)。" },
|
|
19
|
-
set_cell_date: { required: ["rowId", "columnId", "value"], optional: [], description: "设置日期列值(时间戳或 ISO,可为 null)。" },
|
|
20
|
-
update_text: { required: ["remId", "text"], optional: [], description: "更新 Rem 文本。" },
|
|
21
|
-
move_rem: { required: ["remId", "newParentId"], optional: ["position"], description: "移动 Rem 到新父级。" },
|
|
22
|
-
add_tag: { required: ["remId", "tagId"], optional: [], description: "给 Rem 添加标签。" },
|
|
23
|
-
remove_tag: { required: ["remId", "tagId"], optional: [], description: "从 Rem 移除标签。" },
|
|
24
|
-
set_attribute: { required: ["remId", "attributeId"], optional: ["value"], description: "设置属性值(可为 null)。" },
|
|
25
|
-
table_cell_write: { required: ["rowId", "columnId", "text"], optional: [], description: "向单元格写纯文本(Markdown)。" },
|
|
26
|
-
add_source: { required: ["remId", "url"], optional: ["title"], description: "给 Rem 添加来源链接。" },
|
|
27
|
-
remove_source: { required: ["sourceId"], optional: [], description: "移除来源。" },
|
|
28
|
-
set_todo_status: { required: ["remId", "done"], optional: [], description: "设置待办完成状态。" },
|
|
29
|
-
delete_rem: { required: ["remId"], optional: [], description: "删除 Rem。" },
|
|
30
|
-
};
|
|
31
|
-
export function registerListSupportedOps(server) {
|
|
32
|
-
server.tool("list_supported_ops", `<usecase>列出支持的队列写入类型与参数(camelCase 形式)。</usecase>
|
|
33
|
-
<instructions>
|
|
34
|
-
- 返回标准类型列表;点式别名(如 rem.create)会自动映射为标准类型。
|
|
35
|
-
- 字段为 camelCase;入队后将自动转换为 snake_case 并进行严格校验。
|
|
36
|
-
</instructions>`, z.object({}).shape, async () => {
|
|
37
|
-
const types = Object.keys(TYPES);
|
|
38
|
-
const payloadSchemas = Object.fromEntries(Object.entries(TYPES).map(([type, spec]) => [type, spec]));
|
|
39
|
-
return { types, payloadSchemas };
|
|
40
|
-
});
|
|
41
|
-
}
|