fix(memory): FTS5-safe search-term quoting — "TSK-0037"-style queries no longer crash (TSK-0043)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8b17baae96
commit
caf60ea939
@ -101,6 +101,8 @@ export class Index {
|
|||||||
}
|
}
|
||||||
|
|
||||||
search(query: string): Array<{ id: string; type: string; title: string }> {
|
search(query: string): Array<{ id: string; type: string; title: string }> {
|
||||||
|
const ftsQuery = toFts5Phrase(query);
|
||||||
|
if (!ftsQuery) return [];
|
||||||
const stmt = this.db.prepare(`
|
const stmt = this.db.prepare(`
|
||||||
SELECT e.id, e.type, e.title
|
SELECT e.id, e.type, e.title
|
||||||
FROM search s
|
FROM search s
|
||||||
@ -108,7 +110,7 @@ export class Index {
|
|||||||
WHERE search MATCH @query
|
WHERE search MATCH @query
|
||||||
ORDER BY rank
|
ORDER BY rank
|
||||||
`);
|
`);
|
||||||
return stmt.all({ query }) as Array<{ id: string; type: string; title: string }>;
|
return stmt.all({ query: ftsQuery }) as Array<{ id: string; type: string; title: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
list(type?: string, filters?: { status?: string; role?: string; assignedTo?: string }): IndexEntry[] {
|
list(type?: string, filters?: { status?: string; role?: string; assignedTo?: string }): IndexEntry[] {
|
||||||
@ -162,3 +164,9 @@ export class Index {
|
|||||||
this.db.close();
|
this.db.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toFts5Phrase(query: string): string {
|
||||||
|
const trimmed = query.trim();
|
||||||
|
if (!trimmed) return '';
|
||||||
|
return `"${trimmed.replace(/"/g, '""')}"`;
|
||||||
|
}
|
||||||
|
|||||||
@ -18,6 +18,29 @@ describe('memoryService', () => {
|
|||||||
expect(listMemory(cwd)).toHaveLength(1);
|
expect(listMemory(cwd)).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('searches literal task IDs and other FTS5-special strings without throwing', () => {
|
||||||
|
addMemory(cwd, {
|
||||||
|
title: 'TSK-0037 result',
|
||||||
|
category: 'implementation',
|
||||||
|
content: 'Linked HOF-0030 and a:b plus foo-bar all belong to this note.',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(searchMemory(cwd, 'TSK-0037')).toHaveLength(1);
|
||||||
|
expect(searchMemory(cwd, 'HOF-0030')).toHaveLength(1);
|
||||||
|
expect(searchMemory(cwd, 'a:b')).toHaveLength(1);
|
||||||
|
expect(searchMemory(cwd, 'foo-bar')).toHaveLength(1);
|
||||||
|
expect(searchMemory(cwd, 'TTL')).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps normal word search functional after FTS5 quoting', () => {
|
||||||
|
addMemory(cwd, { title: 'DNS cache', category: 'technical', content: 'Use TTL' });
|
||||||
|
addMemory(cwd, { title: 'Other note', category: 'technical', content: 'No cache keyword here' });
|
||||||
|
|
||||||
|
const results = searchMemory(cwd, 'TTL');
|
||||||
|
expect(results).toHaveLength(1);
|
||||||
|
expect(results[0].title).toBe('DNS cache');
|
||||||
|
});
|
||||||
|
|
||||||
it('stores relatedTasks in the memory object', () => {
|
it('stores relatedTasks in the memory object', () => {
|
||||||
const m = addMemory(cwd, {
|
const m = addMemory(cwd, {
|
||||||
title: 'TTL lesson',
|
title: 'TTL lesson',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user