opencode-haimati 1.0.4 → 1.0.5

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/README.md CHANGED
@@ -53,7 +53,7 @@ bun add -g opencode-haimati
53
53
  | 工具 | 说明 |
54
54
  |------|------|
55
55
  | `haimati_read` | 读取记忆内容(只支持序号查询,支持分页,返回带行号和版本号) |
56
- | `haimati_write` | 写入新记忆(覆盖已有内容时版本+1) |
56
+ | `haimati_write` | 写入新记忆(如果已存在相同分类和标题的记忆则报错) |
57
57
  | `haimati_search` | 搜索记忆内容(标题、分类、序号、书页内容) |
58
58
  | `haimati_edit` | 修改记忆内容(部分替换,支持版本并发控制) |
59
59
  | `haimati_move` | 修改记忆的分类路径 |
package/dist/index.js CHANGED
@@ -1,1061 +1,92 @@
1
- // index.ts
2
- import fs from "fs";
3
- import path from "path";
4
- import os from "os";
5
- import { tool } from "@opencode-ai/plugin";
6
- import { promisify } from "util";
7
- var fsReadFile = promisify(fs.readFile);
8
- var fsWriteFile = promisify(fs.writeFile);
9
- var fsUnlink = promisify(fs.unlink);
10
- var fsMkdir = promisify(fs.mkdir);
11
- var fsExists = promisify(fs.exists);
12
- var fsStat = promisify(fs.stat);
13
- var HAIMATI_DIR = ".haimati";
14
- var INDEX_FILE = "\u7D22\u5F15.md";
15
- var PAGES_DIR = "\u4E66\u9875";
16
- var NEXT_ID_FILE = "next-id.txt";
17
- var LOG_FILE = "haimati.log";
18
- var LOCK_MAX_WAIT = 5e3;
19
- var HAIMATI_CONFIG_FILE = "opencode-haimati.conf";
20
- var HAIMATI_PATH_KEY = "haimati-path";
21
- var VERSION_SEPARATOR = "\n---\nversion:";
22
- var DEFAULT_VERSION = 1;
23
- var AUTO_INJECT_CONTEXT = false;
24
- async function getConfigHaimatiPath(directory) {
25
- const configPath = path.join(directory, HAIMATI_CONFIG_FILE);
26
- if (!await fsExists(configPath)) {
27
- return null;
28
- }
29
- try {
30
- const content = await fsReadFile(configPath, "utf-8");
31
- const lines = content.split("\n");
32
- for (const line of lines) {
33
- const trimmed = line.trim();
34
- if (!trimmed || trimmed.startsWith("#")) {
35
- continue;
36
- }
37
- const keyValueMatch = trimmed.match(/^([^:]+):\s*(.+)$/);
38
- if (keyValueMatch) {
39
- const key = keyValueMatch[1].trim();
40
- const value = keyValueMatch[2].trim();
41
- if (key === HAIMATI_PATH_KEY && value) {
42
- return path.resolve(directory, value);
43
- }
44
- }
45
- }
46
- } catch (error) {
47
- console.error(`[haimati] \u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25:`, error);
48
- }
49
- return null;
50
- }
51
- async function getHaimatiDir(directory) {
52
- const configPath = await getConfigHaimatiPath(directory);
53
- if (configPath) {
54
- return configPath;
55
- }
56
- return path.join(directory, HAIMATI_DIR);
57
- }
58
- async function getIndexPath(directory) {
59
- return path.join(await getHaimatiDir(directory), INDEX_FILE);
60
- }
61
- async function getNextIdPath(directory) {
62
- return path.join(await getHaimatiDir(directory), NEXT_ID_FILE);
63
- }
64
- async function getLockPath(directory) {
65
- return path.join(await getHaimatiDir(directory), ".lock");
66
- }
67
- async function getPagesDir(directory) {
68
- return path.join(await getHaimatiDir(directory), PAGES_DIR);
69
- }
70
- async function getPageGroupDir(directory, id) {
71
- const n = parseInt(id, 10);
72
- const groupStart = Math.floor((n - 1) / 50) * 50 + 1;
73
- const groupEnd = groupStart + 49;
74
- const groupName = `${String(groupStart).padStart(3, "0")}-${String(groupEnd).padStart(3, "0")}`;
75
- return path.join(await getPagesDir(directory), groupName);
76
- }
77
- async function getPagePath(directory, id) {
78
- return path.join(await getPageGroupDir(directory, id), `${id}.md`);
79
- }
80
- var fsAppendFile = promisify(fs.appendFile);
81
- function getLogFilePath() {
82
- const osTmpDir = os.tmpdir();
83
- return path.join(osTmpDir, "haimati_logs", LOG_FILE);
84
- }
85
- async function writeLogToFile(message) {
86
- try {
87
- const now = /* @__PURE__ */ new Date();
88
- const dateStr = now.toISOString().split("T")[0];
89
- const timeStr = now.toISOString().replace("T", " ").split(".")[0];
90
- const logPath = getLogFilePath();
91
- const logDir = path.dirname(logPath);
92
- if (!await fsExists(logDir)) {
93
- await fsMkdir(logDir, { recursive: true });
94
- }
95
- let shouldOverwrite = false;
96
- if (await fsExists(logPath)) {
97
- const mtime = (await fsStat(logPath)).mtime;
98
- const fileDate = mtime.toISOString().split("T")[0];
99
- if (fileDate !== dateStr) {
100
- shouldOverwrite = true;
101
- }
102
- }
103
- const logLine = `[${timeStr}] ${message}`;
104
- if (shouldOverwrite) {
105
- await fsWriteFile(logPath, logLine + "\n", "utf-8");
106
- } else {
107
- await fsAppendFile(logPath, logLine + "\n", "utf-8");
108
- }
109
- } catch (error) {
110
- console.error(`[haimati] \u5199\u5165\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25:`, error);
111
- }
112
- }
113
- function truncateForLog(content, maxLen = 500) {
114
- if (content.length <= maxLen) return content;
115
- const half = Math.floor((maxLen - 20) / 2);
116
- return content.substring(0, half) + "...(\u7701\u7565" + (content.length - maxLen) + "\u5B57\u7B26)..." + content.substring(content.length - half);
117
- }
118
- async function log(level, message) {
119
- await writeLogToFile(`[${level.toUpperCase()}] ${message}`);
120
- }
121
- function getTreeDepth(line) {
122
- let depth = 0;
123
- let i = 0;
124
- const len = line.length;
125
- while (i < len) {
126
- if (line[i] === "\u2502" && i + 3 < len && line.slice(i + 1, i + 4) === " ") {
127
- depth++;
128
- i += 4;
129
- } else if (line.slice(i, i + 4) === " ") {
130
- depth++;
131
- i += 4;
132
- } else if ((line[i] === "\u251C" || line[i] === "\u2514") && i + 3 < len && line.slice(i + 1, i + 4) === "\u2500\u2500 ") {
133
- break;
134
- } else {
135
- break;
136
- }
137
- }
138
- return depth;
139
- }
140
- function extractCategoryName(line) {
141
- const trimmed = line.trim();
142
- let name = trimmed.replace(/^[│├└─\s]+/, "").trim();
143
- if (name === "/") {
144
- return "/";
145
- }
146
- if (!name.endsWith("/")) {
147
- return null;
148
- }
149
- name = name.slice(0, -1);
150
- if (!name) return null;
151
- return name;
152
- }
153
- function parseIndex(content) {
154
- const entries = [];
155
- const lines = content.split("\n");
156
- const categoryPath = [];
157
- for (const line of lines) {
158
- if (!line.trim()) continue;
159
- const depth = getTreeDepth(line);
160
- const entryMatch = line.match(/^\s*[│├└─\s]*(.+?)\s*-\s*(\d+)\s*$/);
161
- if (entryMatch) {
162
- const title = entryMatch[1].trim();
163
- const id = entryMatch[2];
164
- const entryCategoryParts = categoryPath.slice(0, depth).filter((p) => p !== "");
165
- const category = entryCategoryParts.join("/");
166
- entries.push({ id, category, title });
167
- } else {
168
- const name = extractCategoryName(line);
169
- if (name) {
170
- if (name === "/") {
171
- categoryPath[depth] = "";
172
- for (let j = depth + 1; j < categoryPath.length; j++) {
173
- delete categoryPath[j];
174
- }
175
- } else {
176
- categoryPath[depth] = name;
177
- for (let j = depth + 1; j < categoryPath.length; j++) {
178
- delete categoryPath[j];
179
- }
180
- }
181
- }
182
- }
183
- }
184
- return entries;
185
- }
186
- function findEntryById(entries, id) {
187
- return entries.find((e) => e.id === id) || null;
188
- }
189
- function findEntryByPath(entries, categoryPath, title) {
190
- return entries.find((e) => e.category === categoryPath && e.title === title) || null;
191
- }
192
- async function searchEntries(entries, keyword, matchMode, directory, searchContent = false) {
193
- const keywords = keyword.toLowerCase().split(/\s+/).filter((k) => k.length > 0);
194
- if (keywords.length === 0) return [];
195
- const matchedWithScore = [];
196
- for (const e of entries) {
197
- const titleLower = e.title.toLowerCase();
198
- const categoryLower = e.category.toLowerCase();
199
- const idLower = e.id.toLowerCase();
200
- let metaKeywordsCount = 0;
201
- let contentKeywordsCount = 0;
202
- for (const kw of keywords) {
203
- if (titleLower.includes(kw) || categoryLower.includes(kw) || idLower.includes(kw)) {
204
- metaKeywordsCount++;
205
- }
206
- }
207
- if (searchContent && directory) {
208
- const page = await readPage(directory, e.id);
209
- if (page && page.content) {
210
- const contentLower = page.content.toLowerCase();
211
- for (const kw of keywords) {
212
- if (contentLower.includes(kw)) {
213
- contentKeywordsCount++;
214
- }
215
- }
216
- }
217
- }
218
- const totalMatchCount = metaKeywordsCount + contentKeywordsCount;
219
- if (matchMode === "and") {
220
- if (totalMatchCount >= keywords.length) {
221
- matchedWithScore.push({ entry: e, score: totalMatchCount });
222
- }
223
- } else {
224
- if (metaKeywordsCount > 0 || searchContent && contentKeywordsCount > 0) {
225
- matchedWithScore.push({ entry: e, score: totalMatchCount });
226
- }
227
- }
228
- }
229
- matchedWithScore.sort((a, b) => b.score - a.score);
230
- return matchedWithScore.map((item) => item.entry);
231
- }
232
- async function readNextIdFromFile(directory) {
233
- const nextIdPath = await getNextIdPath(directory);
234
- if (!await fsExists(nextIdPath)) {
235
- return 1;
236
- }
237
- const content = await fsReadFile(nextIdPath, "utf-8");
238
- const trimmed = content.trim();
239
- const parsed = parseInt(trimmed, 10);
240
- if (!isNaN(parsed) && parsed > 0) {
241
- return parsed;
242
- }
243
- return 1;
244
- }
245
- async function initializeNextIdIfNeeded(directory) {
246
- const nextIdPath = await getNextIdPath(directory);
247
- if (await fsExists(nextIdPath)) {
248
- return;
249
- }
250
- const entries = await readIndex(directory);
251
- let maxId = 0;
252
- for (const e of entries) {
253
- const n = parseInt(e.id, 10);
254
- if (n > maxId) maxId = n;
255
- }
256
- await writeNextIdToFile(directory, maxId + 1);
257
- }
258
- async function writeNextIdToFile(directory, nextId) {
259
- const haimatiDir = await getHaimatiDir(directory);
260
- if (!await fsExists(haimatiDir)) {
261
- await fsMkdir(haimatiDir, { recursive: true });
262
- }
263
- const nextIdPath = await getNextIdPath(directory);
264
- await fsWriteFile(nextIdPath, String(nextId), "utf-8");
265
- }
266
- async function acquireLock(directory) {
267
- const haimatiDir = await getHaimatiDir(directory);
268
- if (!await fsExists(haimatiDir)) {
269
- await fsMkdir(haimatiDir, { recursive: true });
270
- }
271
- const lockPath = await getLockPath(directory);
272
- const startTime = Date.now();
273
- while (await fsExists(lockPath)) {
274
- if (Date.now() - startTime > LOCK_MAX_WAIT) {
275
- return false;
276
- }
277
- await new Promise((resolve) => setTimeout(resolve, 50 + Math.random() * 20));
278
- }
279
- await fsWriteFile(lockPath, String(process.pid), "utf-8");
280
- return true;
281
- }
282
- async function releaseLock(directory) {
283
- const lockPath = await getLockPath(directory);
284
- if (await fsExists(lockPath)) {
285
- await fsUnlink(lockPath);
286
- }
287
- }
288
- async function readPage(directory, id) {
289
- const pagePath = await getPagePath(directory, id);
290
- if (!await fsExists(pagePath)) {
291
- return null;
292
- }
293
- const content = await fsReadFile(pagePath, "utf-8");
294
- const lines = content.split("\n");
295
- if (lines.length < 2) {
296
- return null;
297
- }
298
- let version = 1;
299
- let actualContentLines = lines.slice(2);
300
- const versionMatchIndex = content.lastIndexOf(VERSION_SEPARATOR);
301
- if (versionMatchIndex !== -1) {
302
- const versionStr = content.substring(versionMatchIndex + VERSION_SEPARATOR.length);
303
- version = parseInt(versionStr.trim(), 10) || DEFAULT_VERSION;
304
- actualContentLines = lines.slice(2, lines.length - 2);
305
- }
306
- return {
307
- title: lines[0],
308
- createdAt: lines[1],
309
- content: actualContentLines.join("\n"),
310
- version
311
- };
312
- }
313
- async function writePage(directory, id, title, createdAt, content, version = 1) {
314
- const pagesDir = await getPagesDir(directory);
315
- if (!await fsExists(pagesDir)) {
316
- await fsMkdir(pagesDir, { recursive: true });
317
- }
318
- const pageGroupDir = await getPageGroupDir(directory, id);
319
- if (!await fsExists(pageGroupDir)) {
320
- await fsMkdir(pageGroupDir, { recursive: true });
321
- }
322
- const pagePath = await getPagePath(directory, id);
323
- const fileContent = `${title}
324
- ${createdAt}
325
- ${content}${VERSION_SEPARATOR}${version}`;
326
- await fsWriteFile(pagePath, fileContent, "utf-8");
327
- }
328
- async function deletePage(directory, id) {
329
- const pagePath = await getPagePath(directory, id);
330
- if (await fsExists(pagePath)) {
331
- await fsUnlink(pagePath);
332
- return true;
333
- }
334
- return false;
335
- }
336
- function buildIndexTree(entries) {
337
- if (entries.length === 0) {
338
- return "";
339
- }
340
- const root = { name: "/", children: [], entry: null };
341
- for (const entry of entries) {
342
- const parts = entry.category.split("/");
343
- let current = root;
344
- for (let i = 0; i < parts.length; i++) {
345
- const part = parts[i];
346
- if (!part) continue;
347
- let child = current.children.find((c) => c.name === part);
348
- if (!child) {
349
- child = { name: part, children: [], entry: null };
350
- current.children.push(child);
351
- }
352
- current = child;
353
- }
354
- const entryNode = {
355
- name: entry.id,
356
- children: [],
357
- entry
358
- };
359
- current.children.push(entryNode);
360
- }
361
- function sortNode(node) {
362
- node.children.sort((a, b) => a.name.localeCompare(b.name, void 0, { sensitivity: "base" }));
363
- for (const child of node.children) {
364
- sortNode(child);
365
- }
366
- }
367
- sortNode(root);
368
- function nodeToLines(node, prefix, isLast) {
369
- const lines = [];
370
- const displayPrefix = prefix + (isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ");
371
- const nodeName = node.name === "/" ? "/" : node.name + "/";
372
- lines.push(`${displayPrefix}${nodeName}`);
373
- prefix = prefix + (isLast ? " " : "\u2502 ");
374
- const categories = node.children.filter((c) => c.entry === null);
375
- const items = node.children.filter((c) => c.entry !== null);
376
- const allChildren = [...categories, ...items];
377
- for (let i = 0; i < allChildren.length; i++) {
378
- const child = allChildren[i];
379
- const childIsLast = i === allChildren.length - 1;
380
- if (child.entry) {
381
- const itemPrefix = prefix + (childIsLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ");
382
- lines.push(`${itemPrefix}${child.entry.title} - ${child.entry.id}`);
383
- } else {
384
- lines.push(...nodeToLines(child, prefix, childIsLast));
385
- }
386
- }
387
- return lines;
388
- }
389
- return nodeToLines(root, "", true).join("\n");
390
- }
391
- function removeIndexEntry(entries, id) {
392
- return entries.filter((e) => e.id !== id);
393
- }
394
- async function readIndex(directory) {
395
- const indexPath = await getIndexPath(directory);
396
- if (!await fsExists(indexPath)) {
397
- return [];
398
- }
399
- const content = await fsReadFile(indexPath, "utf-8");
400
- return parseIndex(content);
401
- }
402
- async function writeIndex(directory, entries) {
403
- const haimatiDir = await getHaimatiDir(directory);
404
- if (!await fsExists(haimatiDir)) {
405
- await fsMkdir(haimatiDir, { recursive: true });
406
- }
407
- const tree = buildIndexTree(entries);
408
- const indexPath = await getIndexPath(directory);
409
- await fsWriteFile(indexPath, tree, "utf-8");
410
- }
411
- async function allocateIdWithLock(directory, category, title, now, content) {
412
- if (!await acquireLock(directory)) {
413
- return null;
414
- }
415
- try {
416
- await initializeNextIdIfNeeded(directory);
417
- const entries = await readIndex(directory);
418
- const existingEntry = entries.find((e) => e.category === category && e.title === title);
419
- if (existingEntry) {
420
- const page = await readPage(directory, existingEntry.id);
421
- const createdAt = page ? page.createdAt : now;
422
- const newVersion = page ? page.version + 1 : 1;
423
- await writePage(directory, existingEntry.id, title, createdAt, content, newVersion);
424
- await log("info", `[allocateIdWithLock] \u66F4\u65B0\u5DF2\u6709\u6761\u76EE: #${existingEntry.id} ${category}/${title}, \u65B0\u7248\u672C: ${newVersion}`);
425
- return null;
426
- }
427
- const currentNext = await readNextIdFromFile(directory);
428
- const newId = String(currentNext).padStart(3, "0");
429
- await writePage(directory, newId, title, now, content, 1);
430
- const newEntry = {
431
- id: newId,
432
- category,
433
- title
434
- };
435
- entries.push(newEntry);
436
- await writeIndex(directory, entries);
437
- await writeNextIdToFile(directory, currentNext + 1);
438
- return newId;
439
- } catch (error) {
440
- const errMsg = error instanceof Error ? error.message : String(error);
441
- await log("error", `[allocateIdWithLock] \u5206\u914D\u5E8F\u53F7\u5931\u8D25: ${errMsg}`);
442
- return null;
443
- } finally {
444
- await releaseLock(directory);
445
- }
446
- }
447
- var HaimatiPlugin = async (ctx) => {
448
- await log("info", `\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u63D2\u4EF6(\u6587\u4EF6\u7248)\u5DF2\u52A0\u8F7D`);
449
- return {
450
- tool: {
451
- /**
452
- * haimati_read - 从海马体读取记忆
453
- *
454
- * 只支持序号查询:如 "086"
455
- */
456
- haimati_read: tool({
457
- description: "\u4ECE\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u8BFB\u53D6\u5185\u5BB9\u3002\u901A\u8FC7\u5E8F\u53F7\uFF08\u5982 '086'\uFF09\u6765\u5B9A\u4F4D\u5E76\u8BFB\u53D6\u8BB0\u5FC6\u5185\u5BB9\u3002\u652F\u6301\u5206\u9875\u8BFB\u53D6\uFF08offset/limit\uFF09\uFF0C\u8FD4\u56DE\u5185\u5BB9\u5E26\u884C\u53F7\u548C\u7248\u672C\u53F7\u3002",
458
- args: {
459
- query: tool.schema.string().describe("\u5E8F\u53F7\u3002\u4F8B\u5982\uFF1A'086'"),
460
- offset: tool.schema.number().optional().default(1).describe("\u8D77\u59CB\u884C\u53F7\uFF08\u9ED8\u8BA4 1\uFF09"),
461
- limit: tool.schema.number().optional().default(2e3).describe("\u6700\u5927\u8BFB\u53D6\u884C\u6570\uFF08\u9ED8\u8BA4 2000\uFF09")
462
- },
463
- /**
464
- * 返回格式:
465
- * version:1
466
- * 1|第一行内容
467
- * 2|第二行内容
468
- * ...
469
- *
470
- * version 用于后续 haimati_edit 的并发控制,请妥善保存
471
- */
472
- async execute(args, context) {
473
- const { directory } = context;
474
- const indexPath = await getIndexPath(directory);
475
- await log("info", `[haimati_read] \u5165\u53C2: query="${args.query}", offset=${args.offset || 1}, limit=${args.limit || 2e3}`);
476
- if (!await fsExists(indexPath)) {
477
- const result = `\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728\u4E8E ${indexPath}`;
478
- await log("warn", `[haimati_read] \u51FA\u53C2:
479
- ${truncateForLog(result)}`);
480
- return result;
481
- }
482
- try {
483
- const entries = await readIndex(directory);
484
- await log("debug", `[haimati_read] \u8BFB\u53D6\u7D22\u5F15: \u5171 ${entries.length} \u6761\u8BB0\u5F55`);
485
- const query = args.query.trim();
486
- if (!/^\d+$/.test(query)) {
487
- const result2 = `\u9519\u8BEF\uFF1Aquery \u5FC5\u987B\u662F\u5E8F\u53F7\uFF0C\u53EA\u652F\u6301\u5E8F\u53F7\u67E5\u8BE2`;
488
- await log("warn", `[haimati_read] \u51FA\u53C2:
489
- ${truncateForLog(result2)}`);
490
- return result2;
491
- }
492
- const entry = findEntryById(entries, query);
493
- await log("debug", `[haimati_read] \u5E8F\u53F7\u67E5\u8BE2 #${query}: ${entry ? "\u627E\u5230" : "\u672A\u627E\u5230"}`);
494
- if (!entry) {
495
- const result2 = `\u672A\u627E\u5230\u8BB0\u5FC6: ${args.query}`;
496
- await log("info", `[haimati_read] \u51FA\u53C2:
497
- ${truncateForLog(result2)}`);
498
- return result2;
499
- }
500
- const page = await readPage(directory, entry.id);
501
- if (!page) {
502
- const result2 = `\u672A\u627E\u5230\u4E66\u9875: #${entry.id}`;
503
- await log("error", `[haimati_read] \u51FA\u53C2:
504
- ${truncateForLog(result2)}`);
505
- return result2;
506
- }
507
- const pageGroupDir = await getPageGroupDir(directory, entry.id);
508
- await log("debug", `[haimati_read] \u8BFB\u53D6\u4E66\u9875: \u4E66\u9875/${pageGroupDir.split(/[\\/]/).pop()}/${entry.id}.md, version=${page.version}`);
509
- const contentLines = page.content.split("\n");
510
- const offset = args.offset || 1;
511
- const limit = args.limit || 2e3;
512
- const totalLines = contentLines.length;
513
- const startIndex = Math.max(0, offset - 1);
514
- const endIndex = Math.min(totalLines, startIndex + limit);
515
- const linesOutput = [];
516
- linesOutput.push(`version:${page.version}`);
517
- for (let i = startIndex; i < endIndex; i++) {
518
- linesOutput.push(`${i + 1}|${contentLines[i]}`);
519
- }
520
- const result = linesOutput.join("\n");
521
- await log("info", `[haimati_read] \u51FA\u53C2:
522
- ${truncateForLog(result)}`);
523
- return result;
524
- } catch (error) {
525
- const errorMsg = error instanceof Error ? error.message : String(error);
526
- const stack = error instanceof Error ? error.stack : "";
527
- await log("error", `[haimati_read] \u51FA\u53C2: \u9519\u8BEF: ${errorMsg}
528
- \u5806\u6808: ${stack}`);
529
- return `\u9519\u8BEF: ${errorMsg}`;
530
- }
531
- }
532
- }),
533
- /**
534
- * haimati_write - 将新信息写入海马体记忆系统
535
- *
536
- * 会自动分配新的序号并存储到文件
537
- */
538
- haimati_write: tool({
539
- description: "\u5C06\u65B0\u4FE1\u606F\u5199\u5165\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u3002\u9700\u8981\u63D0\u4F9B\u5206\u7C7B\u8DEF\u5F84\uFF08\u5982 'xxx\u9879\u76EE/\u7B7E\u7AE0'\uFF09\u3001\u6807\u9898\u548C\u5185\u5BB9\u3002",
540
- args: {
541
- category: tool.schema.string().describe("\u5206\u7C7B\u8DEF\u5F84\uFF0C\u5982 'xxx\u9879\u76EE/\u7B7E\u7AE0' \u6216 '\u901A\u7528'"),
542
- title: tool.schema.string().describe("\u8BB0\u5FC6\u6807\u9898\uFF0C\u5982 '\u7B7E\u7AE0\u670D\u52A1WS\u901A\u4FE1\u673A\u5236'"),
543
- content: tool.schema.string().describe("\u8981\u5199\u5165\u7684\u8BE6\u7EC6\u5185\u5BB9")
544
- },
545
- async execute(args, context) {
546
- const { directory } = context;
547
- await log("info", `[haimati_write] \u5165\u53C2: category="${args.category}", title="${args.title}", content\u957F\u5EA6=${args.content.length}\u5B57\u7B26, content=
548
- ${truncateForLog(args.content)}
549
- `);
550
- try {
551
- const now = (/* @__PURE__ */ new Date()).toISOString();
552
- let newId = null;
553
- for (let retry = 0; retry < 3; retry++) {
554
- newId = await allocateIdWithLock(directory, args.category, args.title, now, args.content);
555
- if (newId) break;
556
- await log("warn", `[haimati_write] \u9501\u83B7\u53D6\u5931\u8D25\uFF0C\u91CD\u8BD5\u7B2C ${retry + 1} \u6B21`);
557
- }
558
- if (newId) {
559
- const pageGroupDir = await getPageGroupDir(directory, newId);
560
- await log("debug", `[haimati_write] \u5206\u914D\u65B0\u5E8F\u53F7: #${newId}`);
561
- await log("debug", `[haimati_write] \u4E66\u9875\u548C\u7D22\u5F15\u5DF2\u66F4\u65B0: \u4E66\u9875/${pageGroupDir.split(/[\\/]/).pop()}/${newId}.md`);
562
- const result2 = `\u5DF2\u5199\u5165\u6D77\u9A6C\u4F53 #${newId}
563
- \u8DEF\u5F84: ${args.category}/${args.title}
564
- \u7248\u672C: 1`;
565
- await log("info", `[haimati_write] \u51FA\u53C2:
566
- ${truncateForLog(result2)}`);
567
- return result2;
568
- }
569
- const entries = await readIndex(directory);
570
- const existingEntry = findEntryByPath(entries, args.category, args.title);
571
- if (existingEntry) {
572
- const page = await readPage(directory, existingEntry.id);
573
- const version = page ? page.version : 1;
574
- const result2 = `\u5DF2\u66F4\u65B0\u6D77\u9A6C\u4F53 #${existingEntry.id}
575
- \u8DEF\u5F84: ${args.category}/${args.title}
576
- \u7248\u672C: ${version}`;
577
- await log("info", `[haimati_write] \u51FA\u53C2:
578
- ${truncateForLog(result2)}`);
579
- return result2;
580
- }
581
- const result = `\u9519\u8BEF\uFF1A\u65E0\u6CD5\u5206\u914D\u5E8F\u53F7\uFF08\u9501\u7B49\u5F85\u8D85\u65F6\uFF09`;
582
- await log("error", `[haimati_write] \u51FA\u53C2:
583
- ${truncateForLog(result)}`);
584
- return result;
585
- } catch (error) {
586
- const errorMsg = error instanceof Error ? error.message : String(error);
587
- const stack = error instanceof Error ? error.stack : "";
588
- await log("error", `[haimati_write] \u51FA\u53C2: \u9519\u8BEF: ${errorMsg}
589
- \u5806\u6808: ${stack}`);
590
- return `\u9519\u8BEF: ${errorMsg}`;
591
- }
592
- }
593
- }),
594
- /**
595
- * haimati_search - 搜索海马体记忆系统
596
- *
597
- * 在标题、分类、序号和书页内容中进行搜索
598
- */
599
- haimati_search: tool({
600
- description: "\u641C\u7D22\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\uFF08\u652F\u6301\u591A\u5173\u952E\u5B57\uFF0C\u7528\u7A7A\u683C\u5206\u9694\uFF09\u3002\u641C\u7D22\u8303\u56F4\u5305\u62EC\uFF1A\u6807\u9898\u3001\u5206\u7C7B\u3001\u5E8F\u53F7\u3001\u4E66\u9875\u5185\u5BB9\u3002\u8F93\u5165\u5173\u952E\u8BCD\uFF0C\u8FD4\u56DE\u5339\u914D\u7684\u6761\u76EE\u5217\u8868\u548C\u5185\u5BB9\u7247\u6BB5\uFF0C\u652F\u6301\u5206\u9875\uFF08limit/offset\uFF09\u3002",
601
- args: {
602
- keyword: tool.schema.string().describe("\u641C\u7D22\u5173\u952E\u8BCD\uFF08\u652F\u6301\u591A\u5173\u952E\u5B57\uFF0C\u7528\u7A7A\u683C\u5206\u9694\uFF09"),
603
- match: tool.schema.string().describe("\u5339\u914D\u6A21\u5F0F\uFF1Aand=\u6240\u6709\u5173\u952E\u5B57\u90FD\u5339\u914D\uFF0Cor=\u4EFB\u610F\u5173\u952E\u5B57\u5339\u914D"),
604
- limit: tool.schema.number().default(10).describe("\u8FD4\u56DE\u7ED3\u679C\u6570\u91CF\u9650\u5236"),
605
- offset: tool.schema.number().default(0).describe("\u5206\u9875\u504F\u79FB\u91CF\uFF0C\u7528\u4E8E\u83B7\u53D6\u540E\u7EED\u9875\u9762")
606
- },
607
- async execute(args, context) {
608
- const { directory } = context;
609
- const indexPath = await getIndexPath(directory);
610
- await log("info", `[haimati_search] \u5165\u53C2: keyword="${args.keyword}", match="${args.match}", limit=${args.limit || 10}, offset=${args.offset || 0}`);
611
- if (!await fsExists(indexPath)) {
612
- const result = `\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728`;
613
- await log("warn", `[haimati_search] \u51FA\u53C2:
614
- ${truncateForLog(result)}`);
615
- return result;
616
- }
617
- try {
618
- const entries = await readIndex(directory);
619
- const keyword = args.keyword.trim();
620
- const match = args.match;
621
- const limit = args.limit || 10;
622
- const offset = args.offset || 0;
623
- const allMatched = await searchEntries(entries, keyword, match, directory, true);
624
- const totalCount = allMatched.length;
625
- const matched = allMatched.slice(offset, offset + limit);
626
- if (matched.length === 0) {
627
- const result2 = `\u672A\u627E\u5230\u5305\u542B '${keyword}' \u7684\u8BB0\u5FC6`;
628
- await log("info", `[haimati_search] \u51FA\u53C2:
629
- ${truncateForLog(result2)}`);
630
- return result2;
631
- }
632
- const results = [];
633
- const hasMore = offset + matched.length < totalCount;
634
- const displayCount = hasMore ? `${offset + 1}-${offset + matched.length}/${totalCount}` : `${offset + 1}-${offset + matched.length}/${totalCount}`;
635
- results.push(`\u627E\u5230 ${displayCount} \u6761\u5339\u914D\uFF1A
636
- `);
637
- if (hasMore) {
638
- results.push(`\uFF08\u5982\u9700\u83B7\u53D6\u66F4\u591A\uFF0C\u8BF7\u4F7F\u7528 offset=${offset + limit} \u7EE7\u7EED\u7FFB\u9875\uFF09
639
- `);
640
- }
641
- for (const entry of matched) {
642
- const page = await readPage(directory, entry.id);
643
- const fullPath = `${entry.category}/${entry.title}`;
644
- let excerpt = "";
645
- if (page) {
646
- const lines = page.content.split("\n").filter((l) => l.trim());
647
- excerpt = lines.slice(0, 3).join(" | ").substring(0, 150);
648
- if (excerpt.length === 150) excerpt += "...";
649
- }
650
- results.push(`## ${fullPath} [${entry.id}]`);
651
- if (excerpt) {
652
- results.push(`> ${excerpt}`);
653
- }
654
- results.push("");
655
- }
656
- const result = results.join("\n");
657
- await log("info", `[haimati_search] \u51FA\u53C2:
658
- ${truncateForLog(result)}`);
659
- return result;
660
- } catch (error) {
661
- const errorMsg = error instanceof Error ? error.message : String(error);
662
- const stack = error instanceof Error ? error.stack : "";
663
- await log("error", `[haimati_search] \u51FA\u53C2: \u9519\u8BEF: ${errorMsg}
664
- \u5806\u6808: ${stack}`);
665
- return `\u9519\u8BEF: ${errorMsg}`;
666
- }
667
- }
668
- }),
669
- /**
670
- * haimati_edit - 修改海马体中的记忆内容(部分替换)
671
- *
672
- * 使用流程:
673
- * 1. 先调用 haimati_read 获取当前内容的行号和 version
674
- * 2. 传入 offsetBegin/offsetEnd 指定替换范围,传入 content 替换内容
675
- * 3. 传入 read 返回的 version 进行并发控制
676
- *
677
- * 并发控制原理:
678
- * - 如果在你读取后、其他会话修改了该记忆,version会变化
679
- * - 写入时检查 version 是否匹配,不匹配则拒绝写入
680
- * - 写入成功后 version 自动+1
681
- */
682
- haimati_edit: tool({
683
- description: "\u4FEE\u6539\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7684\u90E8\u5206\u5185\u5BB9\u3002\u5C06\u6307\u5B9A\u884C\u53F7\u8303\u56F4 [offsetBegin, offsetEnd) \u7684\u5185\u5BB9\u66FF\u6362\u4E3A\u65B0 content\u3002\u9700\u8981\u63D0\u4F9B read \u65F6\u8FD4\u56DE\u7684 version \u8FDB\u884C\u5E76\u53D1\u63A7\u5236\u3002",
684
- args: {
685
- query: tool.schema.string().describe("\u5E8F\u53F7\uFF0C\u7528\u4E8E\u5B9A\u4F4D\u8981\u66F4\u65B0\u7684\u8BB0\u5FC6"),
686
- offsetBegin: tool.schema.number().describe("\u8D77\u59CB\u884C\u53F7\uFF08\u5305\u62EC\uFF09"),
687
- offsetEnd: tool.schema.number().describe("\u7ED3\u675F\u884C\u53F7\uFF08\u4E0D\u5305\u62EC\uFF09"),
688
- content: tool.schema.string().describe("\u66FF\u6362\u5185\u5BB9"),
689
- version: tool.schema.number().describe("read \u65F6\u8FD4\u56DE\u7684 version\uFF0C\u7528\u4E8E\u5E76\u53D1\u63A7\u5236")
690
- },
691
- async execute(args, context) {
692
- const { directory } = context;
693
- const indexPath = await getIndexPath(directory);
694
- await log("info", `[haimati_edit] \u5165\u53C2: query="${args.query}", offsetBegin=${args.offsetBegin}, offsetEnd=${args.offsetEnd}, content\u957F\u5EA6=${args.content.length}\u5B57\u7B26, version=${args.version}, content=
695
- ${truncateForLog(args.content)}
696
- `);
697
- if (!await fsExists(indexPath)) {
698
- const result = `\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728`;
699
- await log("warn", `[haimati_edit] \u51FA\u53C2:
700
- ${truncateForLog(result)}`);
701
- return result;
702
- }
703
- try {
704
- const entries = await readIndex(directory);
705
- const query = args.query.trim();
706
- if (!/^\d+$/.test(query)) {
707
- const result2 = `\u9519\u8BEF\uFF1Aquery \u5FC5\u987B\u662F\u5E8F\u53F7\uFF0C\u53EA\u652F\u6301\u5E8F\u53F7\u67E5\u8BE2`;
708
- await log("warn", `[haimati_edit] \u51FA\u53C2:
709
- ${truncateForLog(result2)}`);
710
- return result2;
711
- }
712
- const entry = findEntryById(entries, query);
713
- if (!entry) {
714
- const result2 = `\u672A\u627E\u5230\u4E0E '${query}' \u76F8\u5173\u7684\u8BB0\u5FC6`;
715
- await log("info", `[haimati_edit] \u51FA\u53C2:
716
- ${truncateForLog(result2)}`);
717
- return result2;
718
- }
719
- const page = await readPage(directory, entry.id);
720
- if (!page) {
721
- const result2 = `\u672A\u627E\u5230\u4E66\u9875: #${entry.id}`;
722
- await log("error", `[haimati_edit] \u51FA\u53C2:
723
- ${truncateForLog(result2)}`);
724
- return result2;
725
- }
726
- const offsetBegin = args.offsetBegin;
727
- const offsetEnd = args.offsetEnd;
728
- if (offsetBegin > page.content.split("\n").length || offsetBegin >= offsetEnd) {
729
- const result2 = `\u9519\u8BEF\uFF1Aoffset \u975E\u6CD5\uFF0CoffsetBegin=${offsetBegin}, offsetEnd=${offsetEnd}, \u6587\u4EF6\u603B\u884C\u6570=${page.content.split("\n").length}`;
730
- await log("warn", `[haimati_edit] \u51FA\u53C2:
731
- ${truncateForLog(result2)}`);
732
- return result2;
733
- }
734
- if (page.version !== args.version) {
735
- const result2 = `\u9519\u8BEF\uFF1A\u7248\u672C\u51B2\u7A81\uFF0C\u5F53\u524D version=${page.version}\uFF0C\u4F20\u5165 version=${args.version}\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u540E\u518D\u64CD\u4F5C`;
736
- await log("warn", `[haimati_edit] \u51FA\u53C2:
737
- ${truncateForLog(result2)}`);
738
- return result2;
739
- }
740
- const contentLines = page.content.split("\n");
741
- const newContentLines = [
742
- ...contentLines.slice(0, offsetBegin - 1),
743
- ...args.content.split("\n"),
744
- ...contentLines.slice(offsetEnd - 1)
745
- ];
746
- const newContent = newContentLines.join("\n");
747
- const newVersion = page.version + 1;
748
- await writePage(directory, entry.id, entry.title, page.createdAt, newContent, newVersion);
749
- const fullPath = `${entry.category}/${entry.title}`;
750
- const result = `\u5DF2\u66F4\u65B0\u6D77\u9A6C\u4F53 #${entry.id}
751
- \u8DEF\u5F84: ${fullPath}
752
- \u65B0\u7248\u672C: ${newVersion}`;
753
- await log("info", `[haimati_edit] \u51FA\u53C2:
754
- ${truncateForLog(result)}`);
755
- return result;
756
- } catch (error) {
757
- const errorMsg = error instanceof Error ? error.message : String(error);
758
- const stack = error instanceof Error ? error.stack : "";
759
- await log("error", `[haimati_edit] \u51FA\u53C2: \u9519\u8BEF: ${errorMsg}
760
- \u5806\u6808: ${stack}`);
761
- return `\u9519\u8BEF: ${errorMsg}`;
762
- }
763
- }
764
- }),
765
- /**
766
- * haimati_delete - 删除海马体中的记忆
767
- */
768
- haimati_delete: tool({
769
- description: "\u5220\u9664\u6D77\u9A6C\u4F53\u4E2D\u7684\u8BB0\u5FC6\u3002\u901A\u8FC7\u5E8F\u53F7\uFF08\u5982 '086'\uFF09\u6216\u5B8C\u6574\u8DEF\u5F84\uFF08\u5982 'xxx\u9879\u76EE/\u7B7E\u7AE0/\u7B7E\u7AE0\u670D\u52A1WS\u901A\u4FE1\u673A\u5236'\uFF09\u6765\u5B9A\u4F4D\u8981\u5220\u9664\u7684\u8BB0\u5FC6\u3002",
770
- args: {
771
- query: tool.schema.string().describe("\u5E8F\u53F7\u6216\u5B8C\u6574\u8DEF\u5F84\uFF0C\u7528\u4E8E\u5B9A\u4F4D\u8981\u5220\u9664\u7684\u8BB0\u5FC6")
772
- },
773
- async execute(args, context) {
774
- const { directory } = context;
775
- const indexPath = await getIndexPath(directory);
776
- await log("info", `[haimati_delete] \u5165\u53C2: query="${args.query}"`);
777
- if (!await fsExists(indexPath)) {
778
- const result = `\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728`;
779
- await log("warn", `[haimati_delete] \u51FA\u53C2:
780
- ${truncateForLog(result)}`);
781
- return result;
782
- }
783
- try {
784
- const entries = await readIndex(directory);
785
- const query = args.query.trim();
786
- let entry = null;
787
- if (/^\d+$/.test(query)) {
788
- entry = findEntryById(entries, query);
789
- } else {
790
- const parts = query.split("/").filter(Boolean);
791
- if (parts.length >= 2) {
792
- const title = parts.pop();
793
- const category = parts.join("/");
794
- entry = findEntryByPath(entries, category, title);
795
- } else {
796
- const results = await searchEntries(entries, query, "or", directory);
797
- if (results.length === 1) {
798
- entry = results[0];
799
- } else if (results.length > 1) {
800
- const list = results.slice(0, 10).map((e) => ` - ${e.category}/${e.title} [${e.id}]`).join("\n");
801
- return `\u627E\u5230\u591A\u6761\u5339\u914D\uFF0C\u8BF7\u4F7F\u7528\u5E8F\u53F7\u7CBE\u786E\u6307\u5B9A\uFF1A
802
- ${list}`;
803
- }
804
- }
805
- }
806
- if (!entry) {
807
- const result2 = `\u672A\u627E\u5230\u4E0E '${query}' \u76F8\u5173\u7684\u8BB0\u5FC6`;
808
- await log("info", `[haimati_delete] \u51FA\u53C2:
809
- ${truncateForLog(result2)}`);
810
- return result2;
811
- }
812
- await deletePage(directory, entry.id);
813
- const newEntries = removeIndexEntry(entries, entry.id);
814
- await writeIndex(directory, newEntries);
815
- const fullPath = `${entry.category}/${entry.title}`;
816
- const result = `\u5DF2\u5220\u9664\u6D77\u9A6C\u4F53 #${entry.id}
817
- \u8DEF\u5F84: ${fullPath}`;
818
- await log("info", `[haimati_delete] \u51FA\u53C2:
819
- ${truncateForLog(result)}`);
820
- return result;
821
- } catch (error) {
822
- const errorMsg = error instanceof Error ? error.message : String(error);
823
- const stack = error instanceof Error ? error.stack : "";
824
- await log("error", `[haimati_delete] \u51FA\u53C2: \u9519\u8BEF: ${errorMsg}
825
- \u5806\u6808: ${stack}`);
826
- return `\u9519\u8BEF: ${errorMsg}`;
827
- }
828
- }
829
- }),
830
- /**
831
- * haimati_move - 修改记忆的分类路径
832
- */
833
- haimati_move: tool({
834
- description: "\u4FEE\u6539\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7684\u5206\u7C7B\u8DEF\u5F84\u3002\u901A\u8FC7\u5E8F\u53F7\u6216\u5B8C\u6574\u8DEF\u5F84\u5B9A\u4F4D\u8BB0\u5FC6\uFF0C\u7136\u540E\u5C06\u5176\u79FB\u52A8\u5230\u65B0\u7684\u5206\u7C7B\u3002",
835
- args: {
836
- query: tool.schema.string().describe("\u5E8F\u53F7\u6216\u5B8C\u6574\u8DEF\u5F84\uFF0C\u7528\u4E8E\u5B9A\u4F4D\u8981\u79FB\u52A8\u7684\u8BB0\u5FC6"),
837
- newCategory: tool.schema.string().describe("\u65B0\u7684\u5206\u7C7B\u8DEF\u5F84\uFF0C\u5982 'xxx\u9879\u76EE/\u5BA2\u6237\u7AEF' \u6216 '\u901A\u7528'")
838
- },
839
- async execute(args, context) {
840
- const { directory } = context;
841
- const indexPath = await getIndexPath(directory);
842
- await log("info", `[haimati_move] \u5165\u53C2: query="${args.query}", newCategory="${args.newCategory}"`);
843
- if (!await fsExists(indexPath)) {
844
- const result = `\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728`;
845
- await log("warn", `[haimati_move] \u51FA\u53C2:
846
- ${truncateForLog(result)}`);
847
- return result;
848
- }
849
- try {
850
- const entries = await readIndex(directory);
851
- const query = args.query.trim();
852
- let entry = null;
853
- if (/^\d+$/.test(query)) {
854
- entry = findEntryById(entries, query);
855
- } else {
856
- const parts = query.split("/").filter(Boolean);
857
- if (parts.length >= 2) {
858
- const title = parts.pop();
859
- const category = parts.join("/");
860
- entry = findEntryByPath(entries, category, title);
861
- } else {
862
- const results = await searchEntries(entries, query, "or", directory);
863
- if (results.length === 1) {
864
- entry = results[0];
865
- } else if (results.length > 1) {
866
- const list = results.slice(0, 10).map((e) => ` - ${e.category}/${e.title} [${e.id}]`).join("\n");
867
- return `\u627E\u5230\u591A\u6761\u5339\u914D\uFF0C\u8BF7\u4F7F\u7528\u5E8F\u53F7\u7CBE\u786E\u6307\u5B9A\uFF1A
868
- ${list}`;
869
- }
870
- }
871
- }
872
- if (!entry) {
873
- const result2 = `\u672A\u627E\u5230\u4E0E '${query}' \u76F8\u5173\u7684\u8BB0\u5FC6`;
874
- await log("info", `[haimati_move] \u51FA\u53C2:
875
- ${truncateForLog(result2)}`);
876
- return result2;
877
- }
878
- const oldCategory = entry.category;
879
- const oldPath = `${oldCategory}/${entry.title}`;
880
- const newCategory = args.newCategory;
881
- const newPath = `${newCategory}/${entry.title}`;
882
- const newEntries = entries.map((e) => {
883
- if (e.id === entry.id) {
884
- return { ...e, category: newCategory };
885
- }
886
- return e;
887
- });
888
- await writeIndex(directory, newEntries);
889
- const result = `\u5DF2\u79FB\u52A8\u6D77\u9A6C\u4F53 #${entry.id}
890
- \u65E7\u8DEF\u5F84: ${oldPath}
891
- \u65B0\u8DEF\u5F84: ${newPath}`;
892
- await log("info", `[haimati_move] \u51FA\u53C2:
893
- ${truncateForLog(result)}`);
894
- return result;
895
- } catch (error) {
896
- const errorMsg = error instanceof Error ? error.message : String(error);
897
- const stack = error instanceof Error ? error.stack : "";
898
- await log("error", `[haimati_move] \u51FA\u53C2: \u9519\u8BEF: ${errorMsg}
899
- \u5806\u6808: ${stack}`);
900
- return `\u9519\u8BEF: ${errorMsg}`;
901
- }
902
- }
903
- }),
904
- /**
905
- * haimati_list - 列出海马体索引结构
906
- */
907
- haimati_list: tool({
908
- description: "\u5217\u51FA\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u7684\u5B8C\u6574\u7D22\u5F15\u7ED3\u6784\u3002",
909
- args: {
910
- category: tool.schema.string().optional().describe("\u53EF\u9009\u7684\u5206\u7C7B\u8DEF\u5F84\uFF0C\u5217\u51FA\u8BE5\u5206\u7C7B\u4E0B\u7684\u6761\u76EE"),
911
- recursive: tool.schema.boolean().optional().default(false).describe("\u662F\u5426\u9012\u5F52\u904D\u5386\u5B50\u5206\u7C7B\uFF0C\u9ED8\u8BA4false")
912
- },
913
- async execute(args, context) {
914
- const { directory } = context;
915
- const indexPath = await getIndexPath(directory);
916
- await log("info", `[haimati_list] \u5165\u53C2: category="${args.category || "(\u65E0)"}, recursive=${args.recursive}"`);
917
- if (!await fsExists(indexPath)) {
918
- const result = `\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728`;
919
- await log("warn", `[haimati_list] \u51FA\u53C2:
920
- ${truncateForLog(result)}`);
921
- return result;
922
- }
923
- try {
924
- const entries = await readIndex(directory);
925
- if (args.category) {
926
- const indexContent = await fsReadFile(await getIndexPath(directory), "utf-8");
927
- const lines = indexContent.split("\n");
928
- let targetDepth = 0;
929
- let currentPath = [];
930
- for (const line of lines) {
931
- if (!line.trim()) continue;
932
- const depth = getTreeDepth(line);
933
- const entryMatch = line.match(/^\s*[│├└─\s]*(.+?)\s*-\s*(\d+)\s*$/);
934
- if (entryMatch) continue;
935
- const name = extractCategoryName(line);
936
- if (name) {
937
- if (name === "/") {
938
- currentPath[depth] = "";
939
- } else {
940
- currentPath[depth] = name;
941
- }
942
- currentPath = currentPath.slice(0, depth + 1);
943
- const fullPath = currentPath.filter(Boolean).join("/");
944
- if (fullPath === args.category) {
945
- targetDepth = depth;
946
- break;
947
- }
948
- }
949
- }
950
- const subCategories = [];
951
- const directEntries = [];
952
- currentPath = [];
953
- for (const line of lines) {
954
- if (!line.trim()) continue;
955
- const depth = getTreeDepth(line);
956
- const entryMatch = line.match(/^\s*[│├└─\s]*(.+?)\s*-\s*(\d+)\s*$/);
957
- if (entryMatch) {
958
- const title = entryMatch[1].trim();
959
- const id = entryMatch[2];
960
- if (depth === targetDepth + 1) {
961
- const entryCategory = currentPath.slice(1, depth).filter(Boolean).join("/");
962
- if (entryCategory === args.category) {
963
- directEntries.push({ category: entryCategory, title, id });
964
- }
965
- }
966
- continue;
967
- }
968
- const name = extractCategoryName(line);
969
- if (name) {
970
- if (name === "/") {
971
- currentPath[depth] = "";
972
- } else {
973
- currentPath[depth] = name;
974
- }
975
- currentPath = currentPath.slice(0, depth + 1);
976
- if (depth === targetDepth + 1) {
977
- const fullPath = currentPath.filter(Boolean).join("/");
978
- if (fullPath === args.category) {
979
- subCategories.push(name);
980
- }
981
- }
982
- }
983
- }
984
- let result2 = `## ${args.category}
1
+ var Y=Object.defineProperty;var Nt=Object.getOwnPropertyDescriptor;var qt=Object.getOwnPropertyNames;var jt=Object.prototype.hasOwnProperty;var pt=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(i,n)=>(typeof require<"u"?require:i)[n]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var Z=(t,i)=>()=>(t&&(i=t(t=0)),i);var yt=(t,i)=>{for(var n in i)Y(t,n,{get:i[n],enumerable:!0})},Ot=(t,i,n,s)=>{if(i&&typeof i=="object"||typeof i=="function")for(let e of qt(i))!jt.call(t,e)&&e!==n&&Y(t,e,{get:()=>i[e],enumerable:!(s=Nt(i,e))||s.enumerable});return t};var z=t=>Ot(Y({},"__esModule",{value:!0}),t);var wt={};yt(wt,{AUTO_INJECT_CONTEXT:()=>at,DEFAULT_VERSION:()=>W,HAIMATI_CONFIG_FILE:()=>ot,HAIMATI_DIR:()=>Q,HAIMATI_PATH_KEY:()=>st,INDEX_FILE:()=>tt,LOCK_MAX_WAIT:()=>rt,LOG_FILE:()=>it,NEXT_ID_FILE:()=>nt,PAGES_DIR:()=>et,PAGE_GROUP_SIZE:()=>N,VERSION_SEPARATOR:()=>A});var Q,tt,et,nt,it,rt,ot,st,A,W,at,N,C=Z(()=>{"use strict";Q=".haimati",tt="\u7D22\u5F15.md",et="\u4E66\u9875",nt="next-id.txt",it="haimati.log",rt=5e3,ot="opencode-haimati.conf",st="haimati-path",A=`
2
+ ---
3
+ version:`,W=1,at=!1,N=50});import b from"path";import Rt from"os";import B from"fs";function Wt(t){let i=b.join(t,ot);if(!B.existsSync(i))return null;try{let s=B.readFileSync(i,"utf-8").split(`
4
+ `);for(let e of s){let o=e.trim();if(!o||o.startsWith("#"))continue;let r=o.match(/^([^:]+):\s*(.+)$/);if(r){let a=r[1].trim(),c=r[2].trim();if(a===st&&c)return b.resolve(t,c)}}}catch(n){console.error("[haimati] \u8BFB\u53D6\u914D\u7F6E\u6587\u4EF6\u5931\u8D25:",n)}return null}function T(t){let i=Wt(t);return i||b.join(t,Q)}function I(t){return b.join(T(t),tt)}function G(t){return b.join(T(t),nt)}function ct(t){return b.join(T(t),".lock")}function lt(t){return b.join(T(t),"\u4E66\u9875")}function L(t,i){let n=parseInt(i,10),s=Math.floor((n-1)/50)*50+1,e=s+50-1,o=`${String(s).padStart(3,"0")}-${String(e).padStart(3,"0")}`;return b.join(lt(t),o)}function H(t,i){return b.join(L(t,i),`${i}.md`)}function $t(){let t=Rt.tmpdir();return b.join(t,"haimati_logs",it)}function v(t){return B.promises.mkdir(t,{recursive:!0}).then(()=>{})}function x(t){return B.promises.access(t).then(()=>!0).catch(()=>!1)}var k=Z(()=>{"use strict";C()});var dt={};yt(dt,{buildIndexTree:()=>U,extractCategoryName:()=>j,findEntryById:()=>S,findEntryByPath:()=>O,getTreeDepth:()=>q,parseIndex:()=>Pt,readIndex:()=>P,readIndexContent:()=>mt,removeIndexEntry:()=>ft,writeIndex:()=>ut});import xt from"fs";import{promisify as _t}from"util";function q(t){let i=0,n=0,s=t.length;for(;n<s;)if(t[n]==="\u2502"&&n+3<s&&t.slice(n+1,n+4)===" ")i++,n+=4;else if(t.slice(n,n+4)===" ")i++,n+=4;else{if((t[n]==="\u251C"||t[n]==="\u2514")&&n+3<s&&t.slice(n+1,n+4)==="\u2500\u2500 ")break;break}return i}function j(t){let n=t.trim().replace(/^[│├└─\s]+/,"").trim();return n==="/"?"/":!n.endsWith("/")||(n=n.slice(0,-1),!n)?null:n}function Pt(t){let i=[],n=t.split(`
5
+ `),s=[];for(let e of n){if(!e.trim())continue;let o=q(e),r=e.match(/^\s*[│├└─\s]*(.+?)\s*-\s*(\d+)\s*$/);if(r){let a=r[1].trim(),c=r[2],m=s.slice(0,o).filter(h=>h!=="").join("/");i.push({id:c,category:m,title:a})}else{let a=j(e);if(a)if(a==="/"){s[o]="";for(let c=o+1;c<s.length;c++)delete s[c]}else{s[o]=a;for(let c=o+1;c<s.length;c++)delete s[c]}}}return i}function S(t,i){return t.find(n=>n.id===i)||null}function O(t,i,n){return t.find(s=>s.category===i&&s.title===n)||null}function ft(t,i){return t.filter(n=>n.id!==i)}function U(t){if(t.length===0)return"";let i={name:"/",children:[],entry:null};for(let e of t){let o=e.category.split("/"),r=i;for(let c=0;c<o.length;c++){let g=o[c];if(!g)continue;let m=r.children.find(h=>h.name===g);m||(m={name:g,children:[],entry:null},r.children.push(m)),r=m}let a={name:e.id,children:[],entry:e};r.children.push(a)}function n(e){e.children.sort((o,r)=>o.name.localeCompare(r.name,void 0,{sensitivity:"base"}));for(let o of e.children)n(o)}n(i);function s(e,o,r){let a=[],c=o+(r?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 "),g=e.name==="/"?"/":e.name+"/";a.push(`${c}${g}`),o=o+(r?" ":"\u2502 ");let m=e.children.filter(f=>f.entry===null),h=e.children.filter(f=>f.entry!==null),p=[...m,...h];for(let f=0;f<p.length;f++){let d=p[f],y=f===p.length-1;if(d.entry){let u=o+(y?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ");a.push(`${u}${d.entry.title} - ${d.entry.id}`)}else a.push(...s(d,o,y))}return a}return s(i,"",!0).join(`
6
+ `)}async function P(t){let i=I(t);if(!await x(i))return[];let n=await Et(i,"utf-8");return Pt(n)}async function ut(t,i){let n=pt("path").join(t,(C(),z(wt)).HAIMATI_DIR);await x(n)||await v(n);let s=U(i),e=I(t);await Bt(e,s,"utf-8")}async function mt(t){let i=I(t);return await x(i)?Et(i,"utf-8"):""}var Et,Bt,F=Z(()=>{"use strict";k();Et=_t(xt.readFile),Bt=_t(xt.writeFile)});k();F();import{tool as _}from"@opencode-ai/plugin";k();C();import X from"fs";import{promisify as K}from"util";var Gt=K(X.readFile),Ht=K(X.writeFile),Ut=K(X.unlink),It=K(X.mkdir);async function M(t,i){let n=H(t,i);if(!await x(n))return null;let s=await Gt(n,"utf-8"),e=s.indexOf(A);if(e===-1){let p=s.split(`
7
+ `);return p.length<2?null:{title:p[0],createdAt:p[1],content:p.slice(2).join(`
8
+ `),version:1}}let o=s.substring(0,e).split(`
9
+ `)[0],a=s.substring(0,e).split(`
10
+ `)[1]||"",c=s.substring(e+A.length),g=parseInt(c.trim(),10)||1,h=s.substring(0,e).substring(o.length+1+a.length+1);return{title:o,createdAt:a,content:h,version:g}}async function R(t,i,n,s,e,o=1){let r=lt(t);await x(r)||await It(r,{recursive:!0});let a=L(t,i);await x(a)||await It(a,{recursive:!0});let c=H(t,i),g=`${n}
11
+ ${s}
12
+ ${e}${A}${o}`;await Ht(c,g,"utf-8")}async function bt(t,i){let n=H(t,i);return await x(n)?(await Ut(n),!0):!1}async function V(t,i,n,s,e=!1){let o=i.toLowerCase().split(/\s+/).filter(a=>a.length>0);if(o.length===0)return[];let r=[];for(let a of t){let c=a.title.toLowerCase(),g=a.category.toLowerCase(),m=a.id.toLowerCase(),h=0,p=0;for(let d of o)(c.includes(d)||g.includes(d)||m.includes(d))&&h++;if(e&&s){let d=await M(s,a.id);if(d&&d.content){let y=d.content.toLowerCase();for(let u of o)y.includes(u)&&p++}}let f=h+p;n==="and"?f>=o.length&&r.push({entry:a,score:f}):(h>0||e&&p>0)&&r.push({entry:a,score:f})}return r.sort((a,c)=>c.score-a.score),r.map(a=>a.entry)}F();k();F();import kt from"fs";import{promisify as Ct}from"util";k();C();import Tt from"fs";import{promisify as vt}from"util";var Xt=vt(Tt.writeFile),Kt=vt(Tt.unlink);async function Mt(t){let i=T(t);await x(i)||await v(i);let n=ct(t),s=Date.now(),e=50+Math.random()*20;for(;await x(n);){if(Date.now()-s>5e3)return!1;await new Promise(o=>setTimeout(o,e))}return await Xt(n,String(process.pid),"utf-8"),!0}async function Dt(t){let i=ct(t);await x(i)&&await Kt(i)}k();import ht from"fs";import{promisify as gt}from"util";var Vt=gt(ht.appendFile),Jt=gt(ht.writeFile),Yt=gt(ht.stat);function w(t,i=500){if(t.length<=i)return t;let n=Math.floor((i-20)/2);return t.substring(0,n)+"...(\u7701\u7565"+(t.length-i)+"\u5B57\u7B26)..."+t.substring(t.length-n)}async function Zt(t){try{let i=new Date,n=i.toISOString().split("T")[0],s=i.toISOString().replace("T"," ").split(".")[0],e=$t(),o=pt("path").dirname(e);await x(o)||await v(o);let r=!1;await x(e)&&(await Yt(e)).mtime.toISOString().split("T")[0]!==n&&(r=!0);let a=`[${s}] ${t}`;r?await Jt(e,a+`
13
+ `,"utf-8"):await Vt(e,a+`
14
+ `,"utf-8")}catch(i){console.error("[haimati] \u5199\u5165\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25:",i)}}async function l(t,i){await Zt(`[${t.toUpperCase()}] ${i}`)}var zt=Ct(kt.readFile),Qt=Ct(kt.writeFile);async function te(t){let i=G(t);if(!await x(i))return 1;let s=(await zt(i,"utf-8")).trim(),e=parseInt(s,10);return!isNaN(e)&&e>0?e:1}async function ee(t){let i=G(t);if(await x(i))return;let n=await P(t),s=0;for(let e of n){let o=parseInt(e.id,10);o>s&&(s=o)}await Lt(t,s+1)}async function Lt(t,i){let n=T(t);await x(n)||await v(n);let s=G(t);await Qt(s,String(i),"utf-8")}async function St(t,i,n,s,e,o=!1){if(!await Mt(t))return null;try{await ee(t);let r=await P(t),a=r.find(h=>h.category===i&&h.title===n);if(a){if(!o)throw new Error(`\u8BB0\u5FC6\u5DF2\u5B58\u5728: ${i}/${n}\uFF0C\u5982\u9700\u66F4\u65B0\u8BF7\u4F7F\u7528 haimati_edit \u5DE5\u5177`);let h=await M(t,a.id),p=h?h.createdAt:s,f=h?h.version+1:1;return await R(t,a.id,n,p,e,f),await l("info",`[allocateIdWithLock] \u66F4\u65B0\u5DF2\u6709\u6761\u76EE: #${a.id} ${i}/${n}, \u65B0\u7248\u672C: ${f}`),null}let c=await te(t),g=String(c).padStart(3,"0");await R(t,g,n,s,e,1);let m={id:g,category:i,title:n};return r.push(m),await ut(t,r),await Lt(t,c+1),g}catch(r){let a=r instanceof Error?r.message:String(r);return await l("error",`[allocateIdWithLock] \u5206\u914D\u5E8F\u53F7\u5931\u8D25: ${a}`),null}finally{await Dt(t)}}function Ft(){return{haimati_read:_({description:"\u4ECE\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u8BFB\u53D6\u5185\u5BB9\u3002\u901A\u8FC7\u5E8F\u53F7\uFF08\u5982 '086'\uFF09\u6765\u5B9A\u4F4D\u5E76\u8BFB\u53D6\u8BB0\u5FC6\u5185\u5BB9\u3002\u652F\u6301\u5206\u9875\u8BFB\u53D6\uFF08offset/limit\uFF09\uFF0C\u8FD4\u56DE\u5185\u5BB9\u5E26\u884C\u53F7\u548C\u7248\u672C\u53F7\u3002",args:{query:_.schema.string().describe("\u5E8F\u53F7\u3002\u4F8B\u5982\uFF1A'086'"),offset:_.schema.number().optional().default(1).describe("\u8D77\u59CB\u884C\u53F7\uFF08\u9ED8\u8BA4 1\uFF09"),limit:_.schema.number().optional().default(2e3).describe("\u6700\u5927\u8BFB\u53D6\u884C\u6570\uFF08\u9ED8\u8BA4 2000\uFF09")},async execute(t,i){let{directory:n}=i,s=I(n);if(await l("info",`[haimati_read] \u5165\u53C2: query="${t.query}", offset=${t.offset||1}, limit=${t.limit||2e3}`),!await x(s)){let e=`\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728\u4E8E ${s}`;return await l("warn",`[haimati_read] \u51FA\u53C2:
15
+ ${w(e)}`),e}try{let e=await P(n);await l("debug",`[haimati_read] \u8BFB\u53D6\u7D22\u5F15: \u5171 ${e.length} \u6761\u8BB0\u5F55`);let o=t.query.trim();if(!/^\d+$/.test(o)){let $="\u9519\u8BEF\uFF1Aquery \u5FC5\u987B\u662F\u5E8F\u53F7\uFF0C\u53EA\u652F\u6301\u5E8F\u53F7\u67E5\u8BE2";return await l("warn",`[haimati_read] \u51FA\u53C2:
16
+ ${w($)}`),$}let r=S(e,o);if(await l("debug",`[haimati_read] \u5E8F\u53F7\u67E5\u8BE2 #${o}: ${r?"\u627E\u5230":"\u672A\u627E\u5230"}`),!r){let $=`\u672A\u627E\u5230\u8BB0\u5FC6: ${t.query}`;return await l("info",`[haimati_read] \u51FA\u53C2:
17
+ ${w($)}`),$}let a=await M(n,r.id);if(!a){let $=`\u672A\u627E\u5230\u4E66\u9875: #${r.id}`;return await l("error",`[haimati_read] \u51FA\u53C2:
18
+ ${w($)}`),$}let c=L(n,r.id);await l("debug",`[haimati_read] \u8BFB\u53D6\u4E66\u9875: \u4E66\u9875/${c.split(/[\\/]/).pop()}/${r.id}.md, version=${a.version}`);let g=a.content.split(`
19
+ `),m=t.offset||1,h=t.limit||2e3,p=g.length,f=Math.max(0,m-1),d=Math.min(p,f+h),y=[];y.push(`version:${a.version}`);for(let $=f;$<d;$++)y.push(`${$+1}|${g[$]}`);let u=y.join(`
20
+ `);return await l("info",`[haimati_read] \u51FA\u53C2:
21
+ ${w(u)}`),u}catch(e){let o=e instanceof Error?e.message:String(e),r=e instanceof Error?e.stack:"";return await l("error",`[haimati_read] \u51FA\u53C2: \u9519\u8BEF: ${o}
22
+ \u5806\u6808: ${r}`),`\u9519\u8BEF: ${o}`}}}),haimati_write:_({description:"\u5C06\u65B0\u4FE1\u606F\u5199\u5165\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u3002\u9700\u8981\u63D0\u4F9B\u5206\u7C7B\u8DEF\u5F84\uFF08\u5982 'xxx\u9879\u76EE/\u7B7E\u7AE0'\uFF09\u3001\u6807\u9898\u548C\u5185\u5BB9\u3002\u5982\u679C\u76F8\u540C\u5206\u7C7B\u548C\u6807\u9898\u7684\u8BB0\u5FC6\u5DF2\u5B58\u5728\uFF0C\u5219\u4F1A\u62A5\u9519\u3002",args:{category:_.schema.string().describe("\u5206\u7C7B\u8DEF\u5F84\uFF0C\u5982 'xxx\u9879\u76EE/\u7B7E\u7AE0' \u6216 '\u901A\u7528'"),title:_.schema.string().describe("\u8BB0\u5FC6\u6807\u9898\uFF0C\u5982 '\u7B7E\u7AE0\u670D\u52A1WS\u901A\u4FE1\u673A\u5236'"),content:_.schema.string().describe("\u8981\u5199\u5165\u7684\u8BE6\u7EC6\u5185\u5BB9")},async execute(t,i){let{directory:n}=i;await l("info",`[haimati_write] \u5165\u53C2: category="${t.category}", title="${t.title}", content\u957F\u5EA6=${t.content.length}\u5B57\u7B26, content=
23
+ ${w(t.content)}
24
+ `);try{let s=new Date().toISOString(),e=null;for(let c=0;c<3&&(e=await St(n,t.category,t.title,s,t.content,!1),!e);c++)await l("warn",`[haimati_write] \u9501\u83B7\u53D6\u5931\u8D25\uFF0C\u91CD\u8BD5\u7B2C ${c+1} \u6B21`);if(e){let c=L(n,e);await l("debug",`[haimati_write] \u5206\u914D\u65B0\u5E8F\u53F7: #${e}`),await l("debug",`[haimati_write] \u4E66\u9875\u548C\u7D22\u5F15\u5DF2\u66F4\u65B0: \u4E66\u9875/${c.split(/[\\/]/).pop()}/${e}.md`);let g=`\u5DF2\u5199\u5165\u6D77\u9A6C\u4F53 #${e}
25
+ \u8DEF\u5F84: ${t.category}/${t.title}
26
+ \u7248\u672C: 1`;return await l("info",`[haimati_write] \u51FA\u53C2:
27
+ ${w(g)}`),g}let o=await P(n),r=O(o,t.category,t.title);if(r){let c=`\u9519\u8BEF\uFF1A\u8BB0\u5FC6\u5DF2\u5B58\u5728 #${r.id} (${t.category}/${t.title})\uFF0C\u5982\u9700\u66F4\u65B0\u8BF7\u4F7F\u7528 haimati_edit \u5DE5\u5177`;return await l("error",`[haimati_write] \u51FA\u53C2:
28
+ ${w(c)}`),c}let a="\u9519\u8BEF\uFF1A\u65E0\u6CD5\u5206\u914D\u5E8F\u53F7\uFF08\u9501\u7B49\u5F85\u8D85\u65F6\uFF09";return await l("error",`[haimati_write] \u51FA\u53C2:
29
+ ${w(a)}`),a}catch(s){let e=s instanceof Error?s.message:String(s),o=s instanceof Error?s.stack:"";return await l("error",`[haimati_write] \u51FA\u53C2: \u9519\u8BEF: ${e}
30
+ \u5806\u6808: ${o}`),`\u9519\u8BEF: ${e}`}}}),haimati_search:_({description:"\u641C\u7D22\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\uFF08\u652F\u6301\u591A\u5173\u952E\u5B57\uFF0C\u7528\u7A7A\u683C\u5206\u9694\uFF09\u3002\u641C\u7D22\u8303\u56F4\u5305\u62EC\uFF1A\u6807\u9898\u3001\u5206\u7C7B\u3001\u5E8F\u53F7\u3001\u4E66\u9875\u5185\u5BB9\u3002\u8F93\u5165\u5173\u952E\u8BCD\uFF0C\u8FD4\u56DE\u5339\u914D\u7684\u6761\u76EE\u5217\u8868\u548C\u5185\u5BB9\u7247\u6BB5\uFF0C\u652F\u6301\u5206\u9875\uFF08limit/offset\uFF09\u3002",args:{keyword:_.schema.string().describe("\u641C\u7D22\u5173\u952E\u8BCD\uFF08\u652F\u6301\u591A\u5173\u952E\u5B57\uFF0C\u7528\u7A7A\u683C\u5206\u9694\uFF09"),match:_.schema.string().describe("\u5339\u914D\u6A21\u5F0F\uFF1Aand=\u6240\u6709\u5173\u952E\u5B57\u90FD\u5339\u914D\uFF0Cor=\u4EFB\u610F\u5173\u952E\u5B57\u5339\u914D"),limit:_.schema.number().default(10).describe("\u8FD4\u56DE\u7ED3\u679C\u6570\u91CF\u9650\u5236"),offset:_.schema.number().default(0).describe("\u5206\u9875\u504F\u79FB\u91CF\uFF0C\u7528\u4E8E\u83B7\u53D6\u540E\u7EED\u9875\u9762")},async execute(t,i){let{directory:n}=i,s=I(n);if(await l("info",`[haimati_search] \u5165\u53C2: keyword="${t.keyword}", match="${t.match}", limit=${t.limit||10}, offset=${t.offset||0}`),!await x(s)){let e="\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728";return await l("warn",`[haimati_search] \u51FA\u53C2:
31
+ ${w(e)}`),e}try{let e=await P(n),o=t.keyword.trim(),r=t.match,a=t.limit||10,c=t.offset||0,g=await V(e,o,r,n,!0),m=g.length,h=g.slice(c,c+a);if(h.length===0){let u=`\u672A\u627E\u5230\u5305\u542B '${o}' \u7684\u8BB0\u5FC6`;return await l("info",`[haimati_search] \u51FA\u53C2:
32
+ ${w(u)}`),u}let p=[],f=c+h.length<m,d=f?`${c+1}-${c+h.length}/${m}`:`${c+1}-${c+h.length}/${m}`;p.push(`\u627E\u5230 ${d} \u6761\u5339\u914D\uFF1A
33
+ `),f&&p.push(`\uFF08\u5982\u9700\u83B7\u53D6\u66F4\u591A\uFF0C\u8BF7\u4F7F\u7528 offset=${c+a} \u7EE7\u7EED\u7FFB\u9875\uFF09
34
+ `);for(let u of h){let $=await M(n,u.id),E=`${u.category}/${u.title}`,D="";$&&(D=$.content.split(`
35
+ `).filter(At=>At.trim()).slice(0,3).join(" | ").substring(0,150),D.length===150&&(D+="...")),p.push(`## ${E} [${u.id}]`),D&&p.push(`> ${D}`),p.push("")}let y=p.join(`
36
+ `);return await l("info",`[haimati_search] \u51FA\u53C2:
37
+ ${w(y)}`),y}catch(e){let o=e instanceof Error?e.message:String(e),r=e instanceof Error?e.stack:"";return await l("error",`[haimati_search] \u51FA\u53C2: \u9519\u8BEF: ${o}
38
+ \u5806\u6808: ${r}`),`\u9519\u8BEF: ${o}`}}}),haimati_edit:_({description:"\u4FEE\u6539\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7684\u90E8\u5206\u5185\u5BB9\u3002\u5C06\u6307\u5B9A\u884C\u53F7\u8303\u56F4 [offsetBegin, offsetEnd) \u7684\u5185\u5BB9\u66FF\u6362\u4E3A\u65B0 content\u3002\u9700\u8981\u63D0\u4F9B read \u65F6\u8FD4\u56DE\u7684 version \u8FDB\u884C\u5E76\u53D1\u63A7\u5236\u3002",args:{query:_.schema.string().describe("\u5E8F\u53F7\uFF0C\u7528\u4E8E\u5B9A\u4F4D\u8981\u66F4\u65B0\u7684\u8BB0\u5FC6"),offsetBegin:_.schema.number().describe("\u8D77\u59CB\u884C\u53F7\uFF08\u5305\u62EC\uFF09"),offsetEnd:_.schema.number().describe("\u7ED3\u675F\u884C\u53F7\uFF08\u4E0D\u5305\u62EC\uFF09"),content:_.schema.string().describe("\u66FF\u6362\u5185\u5BB9"),version:_.schema.number().describe("read \u65F6\u8FD4\u56DE\u7684 version\uFF0C\u7528\u4E8E\u5E76\u53D1\u63A7\u5236")},async execute(t,i){let{directory:n}=i,s=I(n);if(await l("info",`[haimati_edit] \u5165\u53C2: query="${t.query}", offsetBegin=${t.offsetBegin}, offsetEnd=${t.offsetEnd}, content\u957F\u5EA6=${t.content.length}\u5B57\u7B26, version=${t.version}, content=
39
+ ${w(t.content)}
40
+ `),!await x(s)){let e="\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728";return await l("warn",`[haimati_edit] \u51FA\u53C2:
41
+ ${w(e)}`),e}try{let e=await P(n),o=t.query.trim();if(!/^\d+$/.test(o)){let u="\u9519\u8BEF\uFF1Aquery \u5FC5\u987B\u662F\u5E8F\u53F7\uFF0C\u53EA\u652F\u6301\u5E8F\u53F7\u67E5\u8BE2";return await l("warn",`[haimati_edit] \u51FA\u53C2:
42
+ ${w(u)}`),u}let r=S(e,o);if(!r){let u=`\u672A\u627E\u5230\u4E0E '${o}' \u76F8\u5173\u7684\u8BB0\u5FC6`;return await l("info",`[haimati_edit] \u51FA\u53C2:
43
+ ${w(u)}`),u}let a=await M(n,r.id);if(!a){let u=`\u672A\u627E\u5230\u4E66\u9875: #${r.id}`;return await l("error",`[haimati_edit] \u51FA\u53C2:
44
+ ${w(u)}`),u}let c=t.offsetBegin,g=t.offsetEnd;if(c>a.content.split(`
45
+ `).length||c>=g){let u=`\u9519\u8BEF\uFF1Aoffset \u975E\u6CD5\uFF0CoffsetBegin=${c}, offsetEnd=${g}, \u6587\u4EF6\u603B\u884C\u6570=${a.content.split(`
46
+ `).length}`;return await l("warn",`[haimati_edit] \u51FA\u53C2:
47
+ ${w(u)}`),u}if(a.version!==t.version){let u=`\u9519\u8BEF\uFF1A\u7248\u672C\u51B2\u7A81\uFF0C\u5F53\u524D version=${a.version}\uFF0C\u4F20\u5165 version=${t.version}\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u540E\u518D\u64CD\u4F5C`;return await l("warn",`[haimati_edit] \u51FA\u53C2:
48
+ ${w(u)}`),u}let m=a.content.split(`
49
+ `),p=[...m.slice(0,c-1),...t.content.split(`
50
+ `),...m.slice(g-1)].join(`
51
+ `),f=a.version+1;await R(n,r.id,r.title,a.createdAt,p,f);let d=`${r.category}/${r.title}`,y=`\u5DF2\u66F4\u65B0\u6D77\u9A6C\u4F53 #${r.id}
52
+ \u8DEF\u5F84: ${d}
53
+ \u65B0\u7248\u672C: ${f}`;return await l("info",`[haimati_edit] \u51FA\u53C2:
54
+ ${w(y)}`),y}catch(e){let o=e instanceof Error?e.message:String(e),r=e instanceof Error?e.stack:"";return await l("error",`[haimati_edit] \u51FA\u53C2: \u9519\u8BEF: ${o}
55
+ \u5806\u6808: ${r}`),`\u9519\u8BEF: ${o}`}}}),haimati_delete:_({description:"\u5220\u9664\u6D77\u9A6C\u4F53\u4E2D\u7684\u8BB0\u5FC6\u3002\u901A\u8FC7\u5E8F\u53F7\uFF08\u5982 '086'\uFF09\u6216\u5B8C\u6574\u8DEF\u5F84\uFF08\u5982 'xxx\u9879\u76EE/\u7B7E\u7AE0/\u7B7E\u7AE0\u670D\u52A1WS\u901A\u4FE1\u673A\u5236'\uFF09\u6765\u5B9A\u4F4D\u8981\u5220\u9664\u7684\u8BB0\u5FC6\u3002",args:{query:_.schema.string().describe("\u5E8F\u53F7\u6216\u5B8C\u6574\u8DEF\u5F84\uFF0C\u7528\u4E8E\u5B9A\u4F4D\u8981\u5220\u9664\u7684\u8BB0\u5FC6")},async execute(t,i){let{directory:n}=i,s=I(n);if(await l("info",`[haimati_delete] \u5165\u53C2: query="${t.query}"`),!await x(s)){let e="\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728";return await l("warn",`[haimati_delete] \u51FA\u53C2:
56
+ ${w(e)}`),e}try{let e=await P(n),o=t.query.trim(),r=null;if(/^\d+$/.test(o))r=S(e,o);else{let m=o.split("/").filter(Boolean);if(m.length>=2){let h=m.pop(),p=m.join("/");r=O(e,p,h)}else{let h=await V(e,o,"or",n);if(h.length===1)r=h[0];else if(h.length>1)return`\u627E\u5230\u591A\u6761\u5339\u914D\uFF0C\u8BF7\u4F7F\u7528\u5E8F\u53F7\u7CBE\u786E\u6307\u5B9A\uFF1A
57
+ ${h.slice(0,10).map(f=>` - ${f.category}/${f.title} [${f.id}]`).join(`
58
+ `)}`}}if(!r){let m=`\u672A\u627E\u5230\u4E0E '${o}' \u76F8\u5173\u7684\u8BB0\u5FC6`;return await l("info",`[haimati_delete] \u51FA\u53C2:
59
+ ${w(m)}`),m}await bt(n,r.id);let a=ft(e,r.id);await(F(),z(dt)).writeIndex(n,a);let c=`${r.category}/${r.title}`,g=`\u5DF2\u5220\u9664\u6D77\u9A6C\u4F53 #${r.id}
60
+ \u8DEF\u5F84: ${c}`;return await l("info",`[haimati_delete] \u51FA\u53C2:
61
+ ${w(g)}`),g}catch(e){let o=e instanceof Error?e.message:String(e),r=e instanceof Error?e.stack:"";return await l("error",`[haimati_delete] \u51FA\u53C2: \u9519\u8BEF: ${o}
62
+ \u5806\u6808: ${r}`),`\u9519\u8BEF: ${o}`}}}),haimati_move:_({description:"\u4FEE\u6539\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7684\u5206\u7C7B\u8DEF\u5F84\u3002\u901A\u8FC7\u5E8F\u53F7\u6216\u5B8C\u6574\u8DEF\u5F84\u5B9A\u4F4D\u8BB0\u5FC6\uFF0C\u7136\u540E\u5C06\u5176\u79FB\u52A8\u5230\u65B0\u7684\u5206\u7C7B\u3002",args:{query:_.schema.string().describe("\u5E8F\u53F7\u6216\u5B8C\u6574\u8DEF\u5F84\uFF0C\u7528\u4E8E\u5B9A\u4F4D\u8981\u79FB\u52A8\u7684\u8BB0\u5FC6"),newCategory:_.schema.string().describe("\u65B0\u7684\u5206\u7C7B\u8DEF\u5F84\uFF0C\u5982 'xxx\u9879\u76EE/\u5BA2\u6237\u7AEF' \u6216 '\u901A\u7528'")},async execute(t,i){let{directory:n}=i,s=I(n);if(await l("info",`[haimati_move] \u5165\u53C2: query="${t.query}", newCategory="${t.newCategory}"`),!await x(s)){let e="\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728";return await l("warn",`[haimati_move] \u51FA\u53C2:
63
+ ${w(e)}`),e}try{let e=await P(n),o=t.query.trim(),r=null;if(/^\d+$/.test(o))r=S(e,o);else{let f=o.split("/").filter(Boolean);if(f.length>=2){let d=f.pop(),y=f.join("/");r=O(e,y,d)}else{let d=await V(e,o,"or",n);if(d.length===1)r=d[0];else if(d.length>1)return`\u627E\u5230\u591A\u6761\u5339\u914D\uFF0C\u8BF7\u4F7F\u7528\u5E8F\u53F7\u7CBE\u786E\u6307\u5B9A\uFF1A
64
+ ${d.slice(0,10).map(u=>` - ${u.category}/${u.title} [${u.id}]`).join(`
65
+ `)}`}}if(!r){let f=`\u672A\u627E\u5230\u4E0E '${o}' \u76F8\u5173\u7684\u8BB0\u5FC6`;return await l("info",`[haimati_move] \u51FA\u53C2:
66
+ ${w(f)}`),f}let c=`${r.category}/${r.title}`,g=t.newCategory,m=`${g}/${r.title}`,h=e.map(f=>f.id===r.id?{...f,category:g}:f);await(F(),z(dt)).writeIndex(n,h);let p=`\u5DF2\u79FB\u52A8\u6D77\u9A6C\u4F53 #${r.id}
67
+ \u65E7\u8DEF\u5F84: ${c}
68
+ \u65B0\u8DEF\u5F84: ${m}`;return await l("info",`[haimati_move] \u51FA\u53C2:
69
+ ${w(p)}`),p}catch(e){let o=e instanceof Error?e.message:String(e),r=e instanceof Error?e.stack:"";return await l("error",`[haimati_move] \u51FA\u53C2: \u9519\u8BEF: ${o}
70
+ \u5806\u6808: ${r}`),`\u9519\u8BEF: ${o}`}}}),haimati_list:_({description:"\u5217\u51FA\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u7684\u5B8C\u6574\u7D22\u5F15\u7ED3\u6784\u3002",args:{category:_.schema.string().optional().describe("\u53EF\u9009\u7684\u5206\u7C7B\u8DEF\u5F84\uFF0C\u5217\u51FA\u8BE5\u5206\u7C7B\u4E0B\u7684\u6761\u76EE"),recursive:_.schema.boolean().optional().default(!1).describe("\u662F\u5426\u9012\u5F52\u904D\u5386\u5B50\u5206\u7C7B\uFF0C\u9ED8\u8BA4false")},async execute(t,i){let{directory:n}=i,s=I(n);if(await l("info",`[haimati_list] \u5165\u53C2: category="${t.category||"(\u65E0)"}, recursive=${t.recursive}"`),!await x(s)){let e="\u9519\u8BEF\uFF1A\u6D77\u9A6C\u4F53\u7D22\u5F15\u4E0D\u5B58\u5728";return await l("warn",`[haimati_list] \u51FA\u53C2:
71
+ ${w(e)}`),e}try{let e=await P(n);if(t.category){let c=(await mt(n)).split(`
72
+ `),g=0,m=[];for(let d of c){if(!d.trim())continue;let y=q(d);if(d.match(/^\s*[│├└─\s]*(.+?)\s*-\s*(\d+)\s*$/))continue;let $=j(d);if($&&($==="/"?m[y]="":m[y]=$,m=m.slice(0,y+1),m.filter(Boolean).join("/")===t.category)){g=y;break}}let h=[],p=[];m=[];for(let d of c){if(!d.trim())continue;let y=q(d),u=d.match(/^\s*[│├└─\s]*(.+?)\s*-\s*(\d+)\s*$/);if(u){let E=u[1].trim(),D=u[2];if(y===g+1){let J=m.slice(1,y).filter(Boolean).join("/");J===t.category&&p.push({category:J,title:E,id:D})}continue}let $=j(d);$&&($==="/"?m[y]="":m[y]=$,m=m.slice(0,y+1),y===g+1&&m.filter(Boolean).join("/")===t.category&&h.push($))}let f=`## ${t.category}
985
73
 
986
- `;
987
- if (args.recursive) {
988
- const allDescendants = entries.filter(
989
- (e) => e.category === args.category || e.category.startsWith(args.category + "/")
990
- );
991
- const grouped = /* @__PURE__ */ new Map();
992
- for (const entry of allDescendants) {
993
- const rel = entry.category.slice(args.category.length + 1);
994
- const firstPart = rel.split("/")[0] || "(\u76F4\u63A5)";
995
- if (!grouped.has(firstPart)) {
996
- grouped.set(firstPart, []);
997
- }
998
- grouped.get(firstPart).push(entry);
999
- }
1000
- for (const [group, groupEntries] of grouped) {
1001
- result2 += `### ${group}/
1002
- `;
1003
- result2 += groupEntries.map((e) => `- ${e.title} - ${e.id}`).join("\n") + "\n\n";
1004
- }
1005
- } else {
1006
- if (subCategories.length > 0) {
1007
- result2 += "**\u5B50\u5206\u7C7B\uFF1A**\n" + subCategories.map((c) => `- ${c}/`).join("\n") + "\n\n";
1008
- }
1009
- if (directEntries.length > 0) {
1010
- result2 += "**\u76F4\u63A5\u6761\u76EE\uFF1A**\n" + directEntries.map((e) => `- ${e.title} - ${e.id}`).join("\n");
1011
- }
1012
- }
1013
- await log("info", `[haimati_list] \u51FA\u53C2:
1014
- ${truncateForLog(result2)}`);
1015
- return result2;
1016
- }
1017
- const tree = buildIndexTree(entries);
1018
- const result = `## \u6D77\u9A6C\u4F53\u7D22\u5F15
74
+ `;if(t.recursive){let d=e.filter(u=>u.category===t.category||u.category.startsWith(t.category+"/")),y=new Map;for(let u of d){let E=u.category.slice(t.category.length+1).split("/")[0]||"(\u76F4\u63A5)";y.has(E)||y.set(E,[]),y.get(E).push(u)}for(let[u,$]of y)f+=`### ${u}/
75
+ `,f+=$.map(E=>`- ${E.title} - ${E.id}`).join(`
76
+ `)+`
1019
77
 
1020
- ${tree || "(\u7A7A)"}`;
1021
- await log("info", `[haimati_list] \u51FA\u53C2:
1022
- ${truncateForLog(result)}`);
1023
- return result;
1024
- } catch (error) {
1025
- const errorMsg = error instanceof Error ? error.message : String(error);
1026
- const stack = error instanceof Error ? error.stack : "";
1027
- await log("error", `[haimati_list] \u51FA\u53C2: \u9519\u8BEF: ${errorMsg}
1028
- \u5806\u6808: ${stack}`);
1029
- return `\u9519\u8BEF: ${errorMsg}`;
1030
- }
1031
- }
1032
- })
1033
- },
1034
- /**
1035
- * session.created - 会话创建时注入海马体规则
1036
- * 在每次新会话开始时,自动将海马体三大原则注入到上下文中
1037
- */
1038
- event: async ({ event: evt }) => {
1039
- if (evt.type !== "session.created") {
1040
- return;
1041
- }
1042
- try {
1043
- const sessionId = evt.properties?.info?.id;
1044
- if (!sessionId) {
1045
- await log("warn", "[session.created] \u65E0\u6CD5\u83B7\u53D6 sessionID\uFF0C\u8DF3\u8FC7\u6CE8\u5165");
1046
- return;
1047
- }
1048
- if (!AUTO_INJECT_CONTEXT) {
1049
- await log("info", "[session.created] \u81EA\u52A8\u6CE8\u5165\u5DF2\u5173\u95ED\uFF0C\u8DF3\u8FC7\u6CE8\u5165 (AUTO_INJECT_CONTEXT=false)");
1050
- return;
1051
- }
1052
- await ctx.client.session.prompt({
1053
- path: { id: sessionId },
1054
- body: {
1055
- noReply: true,
1056
- parts: [{
1057
- type: "text",
1058
- text: `## \u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u4F7F\u7528\u89C4\u5219
78
+ `}else h.length>0&&(f+=`**\u5B50\u5206\u7C7B\uFF1A**
79
+ `+h.map(d=>`- ${d}/`).join(`
80
+ `)+`
81
+
82
+ `),p.length>0&&(f+=`**\u76F4\u63A5\u6761\u76EE\uFF1A**
83
+ `+p.map(d=>`- ${d.title} - ${d.id}`).join(`
84
+ `));return await l("info",`[haimati_list] \u51FA\u53C2:
85
+ ${w(f)}`),f}let r=`## \u6D77\u9A6C\u4F53\u7D22\u5F15
86
+
87
+ ${U(e)||"(\u7A7A)"}`;return await l("info",`[haimati_list] \u51FA\u53C2:
88
+ ${w(r)}`),r}catch(e){let o=e instanceof Error?e.message:String(e),r=e instanceof Error?e.stack:"";return await l("error",`[haimati_list] \u51FA\u53C2: \u9519\u8BEF: ${o}
89
+ \u5806\u6808: ${r}`),`\u9519\u8BEF: ${o}`}}})}}C();var Je=async t=>(await l("info","\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u63D2\u4EF6(\u6587\u4EF6\u7248)\u5DF2\u52A0\u8F7D"),{tool:Ft(),event:async({event:n})=>{if(n.type==="session.created")try{let s=n.properties?.info?.id;if(!s){await l("warn","[session.created] \u65E0\u6CD5\u83B7\u53D6 sessionID\uFF0C\u8DF3\u8FC7\u6CE8\u5165");return}if(!!1){await l("info","[session.created] \u81EA\u52A8\u6CE8\u5165\u5DF2\u5173\u95ED\uFF0C\u8DF3\u8FC7\u6CE8\u5165 (AUTO_INJECT_CONTEXT=false)");return}await t.client.session.prompt({path:{id:s},body:{noReply:!0,parts:[{type:"text",text:`## \u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u4F7F\u7528\u89C4\u5219
1059
90
 
1060
91
  \u4F60\u6709\u4E00\u4E2A\u6D77\u9A6C\u4F53\u8BB0\u5FC6\u7CFB\u7EDF\u53EF\u7528\uFF0C\u7528\u4E8E\u5B58\u50A8\u548C\u68C0\u7D22\u8DE8\u4F1A\u8BDD\u7684\u77E5\u8BC6\u3002
1061
92
 
@@ -1078,7 +109,7 @@ ${truncateForLog(result)}`);
1078
109
  **\u6CE8\u610F**\uFF1A\u4EE5\u4E0B\u5DE5\u5177\u5217\u8868\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u4F7F\u7528\u5E8F\u53F7\u67E5\u8BE2\u4EE3\u66FF\u8DEF\u5F84\u67E5\u8BE2\u3002haimati_read/haimati_edit \u8FD4\u56DE\u7684 version \u7528\u4E8E\u5E76\u53D1\u63A7\u5236\u3002
1079
110
 
1080
111
  - \`haimati_read\` - \u8BFB\u53D6\u8BB0\u5FC6\u5185\u5BB9\uFF08\u53EA\u652F\u6301\u5E8F\u53F7\u67E5\u8BE2\uFF0C\u652F\u6301\u5206\u9875\uFF0C\u8FD4\u56DE\u5E26\u884C\u53F7\u548C\u7248\u672C\u53F7\uFF09
1081
- - \`haimati_write\` - \u5199\u5165\u65B0\u8BB0\u5FC6\uFF08\u8986\u76D6\u5DF2\u6709\u5185\u5BB9\u65F6\u7248\u672C+1\uFF09
112
+ - \`haimati_write\` - \u5199\u5165\u65B0\u8BB0\u5FC6\uFF08\u5982\u679C\u5DF2\u5B58\u5728\u76F8\u540C\u5206\u7C7B\u548C\u6807\u9898\u7684\u8BB0\u5FC6\u5219\u62A5\u9519\uFF0C\u4E0D\u5141\u8BB8\u8986\u76D6\uFF09
1082
113
  - \`haimati_search\` - \u641C\u7D22\u8BB0\u5FC6\u5185\u5BB9\uFF08\u641C\u7D22\u8303\u56F4\uFF1A\u6807\u9898\u3001\u5206\u7C7B\u3001\u5E8F\u53F7\u3001\u4E66\u9875\u5185\u5BB9\u3002**\u6CE8\u610F\uFF1Amatch\u53C2\u6570\u5FC5\u586B\uFF0Cand=\u6240\u6709\u5173\u952E\u5B57\u90FD\u5339\u914D\uFF0Cor=\u4EFB\u610F\u5173\u952E\u5B57\u5339\u914D**\uFF09
1083
114
  - \`haimati_edit\` - \u4FEE\u6539\u8BB0\u5FC6\u5185\u5BB9\uFF08\u90E8\u5206\u66FF\u6362\uFF0C\u901A\u8FC7\u884C\u53F7\u8303\u56F4\u66FF\u6362\u5185\u5BB9\uFF0C\u652F\u6301\u7248\u672C\u5E76\u53D1\u63A7\u5236\uFF09
1084
115
  - \`haimati_move\` - \u4FEE\u6539\u8BB0\u5FC6\u7684\u5206\u7C7B\u8DEF\u5F84
@@ -1089,18 +120,4 @@ ${truncateForLog(result)}`);
1089
120
 
1090
121
  **\u4F1A\u8BDD\u5F00\u59CB\u524D**: \u4F7F\u7528 haimati_list \u6216 haimati_search \u8BFB\u53D6\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u8BB0\u5FC6\u5185\u5BB9\uFF0C\u518D\u5F00\u59CB\u5DE5\u4F5C\u3002
1091
122
 
1092
- **\u4F1A\u8BDD\u7ED3\u675F\u540E**: \u4F7F\u7528 haimati_write \u5C06\u65B0\u83B7\u5F97\u7684\u77E5\u8BC6\u3001\u7ECF\u9A8C\u3001\u51B3\u7B56\u5199\u5165\u6D77\u9A6C\u4F53\uFF0C\u4FDD\u6301\u4FE1\u606F\u7684\u6301\u7EED\u79EF\u7D2F\u3002`
1093
- }]
1094
- }
1095
- });
1096
- await log("info", `[session.created] \u6D77\u9A6C\u4F53\u89C4\u5219\u5DF2\u6CE8\u5165\u65B0\u4F1A\u8BDD (sessionID: ${sessionId})`);
1097
- } catch (error) {
1098
- const errorMsg = error instanceof Error ? error.message : String(error);
1099
- await log("error", `[session.created] \u6CE8\u5165\u6D77\u9A6C\u4F53\u89C4\u5219\u5931\u8D25: ${errorMsg}`);
1100
- }
1101
- }
1102
- };
1103
- };
1104
- export {
1105
- HaimatiPlugin
1106
- };
123
+ **\u4F1A\u8BDD\u7ED3\u675F\u540E**: \u4F7F\u7528 haimati_write \u5C06\u65B0\u83B7\u5F97\u7684\u77E5\u8BC6\u3001\u7ECF\u9A8C\u3001\u51B3\u7B56\u5199\u5165\u6D77\u9A6C\u4F53\uFF0C\u4FDD\u6301\u4FE1\u606F\u7684\u6301\u7EED\u79EF\u7D2F\u3002`}]}}),await l("info",`[session.created] \u6D77\u9A6C\u4F53\u89C4\u5219\u5DF2\u6CE8\u5165\u65B0\u4F1A\u8BDD (sessionID: ${s})`)}catch(s){let e=s instanceof Error?s.message:String(s);await l("error",`[session.created] \u6CE8\u5165\u6D77\u9A6C\u4F53\u89C4\u5219\u5931\u8D25: ${e}`)}}});export{Je as HaimatiPlugin};
package/dist/package.json CHANGED
@@ -1,13 +1,17 @@
1
1
  {
2
2
  "name": "opencode-haimati",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "OpenCode plugin for a file-based memory system inspired by the hippocampus, providing long-term memory storage and retrieval across sessions.",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",
7
7
  "license": "MIT",
8
- "files": ["dist"],
8
+ "files": [
9
+ "dist"
10
+ ],
9
11
  "scripts": {
10
- "build": "npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin && cp package.json dist/",
12
+ "build": "rm -rf dist && npx esbuild src/index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin --minify && cp package.json dist/",
13
+ "build:uncompressed": "rm -rf dist && npx esbuild src/index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin && cp package.json dist/",
14
+ "typecheck": "tsc --noEmit",
11
15
  "prepublishOnly": "npm run build",
12
16
  "test": "npx tsx test/index.ts"
13
17
  },
@@ -20,4 +24,4 @@
20
24
  "@types/bun": "^1.3.1",
21
25
  "typescript": "^5.9.3"
22
26
  }
23
- }
27
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-haimati",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "OpenCode plugin for a file-based memory system inspired by the hippocampus, providing long-term memory storage and retrieval across sessions.",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",
@@ -9,7 +9,9 @@
9
9
  "dist"
10
10
  ],
11
11
  "scripts": {
12
- "build": "npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin && cp package.json dist/",
12
+ "build": "rm -rf dist && npx esbuild src/index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin --minify && cp package.json dist/",
13
+ "build:uncompressed": "rm -rf dist && npx esbuild src/index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin && cp package.json dist/",
14
+ "typecheck": "tsc --noEmit",
13
15
  "prepublishOnly": "npm run build",
14
16
  "test": "npx tsx test/index.ts"
15
17
  },