@bsbofmusic/memos-memu-local-memory-tools-for-agent 1.0.5 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsbofmusic/memos-memu-local-memory-tools-for-agent",
3
- "version": "1.0.5",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server — one-shot install + query for memos (PostgreSQL) and memuK (SQLite) local memory. Designed for OpenClaw agents.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/shared/db.js CHANGED
@@ -44,7 +44,7 @@ export function sqlite(sql, dbPath) {
44
44
  const safeSql = sql.replace(/"/g, '""');
45
45
  try {
46
46
  const out = execSync(
47
- `/usr/bin/sqlite3 "${db}" "${safeSql}"`,
47
+ `/usr/bin/sqlite3 -json "${db}" "${safeSql}"`,
48
48
  { timeout: 10000 }
49
49
  ).toString();
50
50
  return out;
@@ -92,16 +92,12 @@ export function dockerContainerRunning(name) {
92
92
  }
93
93
 
94
94
  export function parseSqlite(output) {
95
- const lines = output.split('\n').filter(l => l.trim() && !l.startsWith('--'));
96
- return lines.map(line => {
97
- const pipe = line.split('|');
98
- return {
99
- id: pipe[0]?.trim() ?? '',
100
- summary: pipe[1]?.trim() ?? '',
101
- memory_type: pipe[2]?.trim() ?? '',
102
- happened_at: pipe[3]?.trim() ?? '',
103
- };
104
- });
95
+ try {
96
+ const rows = JSON.parse(output.trim());
97
+ return Array.isArray(rows) ? rows : [];
98
+ } catch {
99
+ return [];
100
+ }
105
101
  }
106
102
 
107
103
  export function parsePsqlJson(output) {
@@ -11,7 +11,8 @@ export async function memos_query({ query, limit = 10 }) {
11
11
  const safe = s => s.replace(/'/g, "''");
12
12
  const lim = Math.min(parseInt(limit) || 10, 20);
13
13
 
14
- const sql = `
14
+ // 方案4:先整句搜索,没结果再拆关键词OR
15
+ let sql = `
15
16
  SELECT jsonb_agg(q ORDER BY created_ts DESC)
16
17
  FROM (
17
18
  SELECT
@@ -39,6 +40,34 @@ FROM (
39
40
 
40
41
  let rows = parsePsqlJson(raw);
41
42
 
43
+ // 方案4:如果整句没结果,再拆关键词OR搜索
44
+ if (!Array.isArray(rows) || rows.length === 0) {
45
+ // 方案2:按空格拆关键词,OR连接
46
+ const keywords = query.split(/\s+/).filter(k => k.trim().length > 0);
47
+ if (keywords.length > 0) {
48
+ const whereClauses = keywords.map(k => `content ILIKE '%${safe(k)}%'`).join(' OR ');
49
+ sql = `
50
+ SELECT jsonb_agg(q ORDER BY created_ts DESC)
51
+ FROM (
52
+ SELECT
53
+ id,
54
+ substr(content, 1, 500) AS content,
55
+ created_ts,
56
+ visibility
57
+ FROM memo
58
+ WHERE ${whereClauses}
59
+ ORDER BY created_ts DESC
60
+ LIMIT ${lim}
61
+ ) q;`.trim();
62
+ try {
63
+ raw = psql(sql);
64
+ rows = parsePsqlJson(raw);
65
+ } catch (err) {
66
+ // 关键词OR搜索也失败,返回空
67
+ }
68
+ }
69
+ }
70
+
42
71
  // Defensive slice: enforce limit cap at application level
43
72
  if (!Array.isArray(rows)) rows = [];
44
73
  if (rows.length > lim) rows = rows.slice(0, lim);
@@ -47,7 +47,7 @@ LIMIT ${lim};`.trim();
47
47
  }
48
48
 
49
49
  const lines = rows.map(
50
- (r, i) => `─── ${i + 1}. [${r.memory_type}] ${r.happened_at || 'n/a'} ───\n${r.summary}`
50
+ (r, i) => `─── ${i + 1}. [${r.memory_type || 'imported'}] ${r.happened_at || 'n/a'} ───\n${r.summary || ''}`
51
51
  );
52
52
 
53
53
  return {