Feature/semantic similarity (#36)
* fix: mixed up migrations * feat: semantic similarity first take * feat: semantic similarity first round of fixes * feat: more work on making semantic similarity work properly * feat: getPostBySlug for the AI * feat: show similarity in post-link-insert-modal * chore: remove done doc --------- Co-authored-by: hugo <hugoms@me.com>
This commit is contained in:
@@ -7,6 +7,7 @@ function createMockPostEngine() {
|
||||
return {
|
||||
getAllPosts: vi.fn().mockResolvedValue({ items: [], hasMore: false, total: 0 }),
|
||||
getPost: vi.fn().mockResolvedValue(null),
|
||||
getPostBySlug: vi.fn().mockResolvedValue(null),
|
||||
searchPosts: vi.fn().mockResolvedValue([]),
|
||||
searchPostsFiltered: vi.fn().mockResolvedValue({ posts: [], total: 0 }),
|
||||
createPost: vi.fn().mockResolvedValue({
|
||||
@@ -205,6 +206,11 @@ describe('MCPServer', () => {
|
||||
const mcpServer = server.createMcpServer();
|
||||
expect(hasRegistered(mcpServer, '_registeredTools', 'discard_proposal')).toBe(true);
|
||||
});
|
||||
|
||||
it('registers read_post_by_slug tool', () => {
|
||||
const mcpServer = server.createMcpServer();
|
||||
expect(hasRegistered(mcpServer, '_registeredTools', 'read_post_by_slug')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('registered resources', () => {
|
||||
@@ -1165,6 +1171,33 @@ describe('MCPServer', () => {
|
||||
const result = await tool.handler({ category: 'tech' }, {}) as { content: Array<{ text: string }> };
|
||||
expect(result.content).toHaveLength(1);
|
||||
});
|
||||
|
||||
// ── read_post_by_slug tool ───────────────────────────────────────
|
||||
|
||||
it('read_post_by_slug returns post with backlinks when found', async () => {
|
||||
const post = { id: 'p1', title: 'Found', slug: 'found-post', content: 'body', status: 'published', tags: [], categories: [], createdAt: new Date(), updatedAt: new Date() };
|
||||
mockPostEngine.getPostBySlug.mockResolvedValue(post);
|
||||
mockPostEngine.getLinkedBy.mockResolvedValue([{ id: 'px', title: 'Ref', slug: 'ref' }]);
|
||||
mockPostEngine.getLinksTo.mockResolvedValue([]);
|
||||
const mcpServer = server.createMcpServer();
|
||||
const tool = getTool(mcpServer, 'read_post_by_slug');
|
||||
const result = await tool.handler({ slug: 'found-post' }, {}) as { content: Array<{ text: string }> };
|
||||
const parsed = JSON.parse(result.content[0].text);
|
||||
expect(parsed.post.id).toBe('p1');
|
||||
expect(parsed.post.slug).toBe('found-post');
|
||||
expect(parsed.post.backlinks).toEqual([{ id: 'px', title: 'Ref', slug: 'ref' }]);
|
||||
expect(mockPostEngine.getPostBySlug).toHaveBeenCalledWith('found-post');
|
||||
});
|
||||
|
||||
it('read_post_by_slug returns error for nonexistent slug', async () => {
|
||||
mockPostEngine.getPostBySlug.mockResolvedValue(null);
|
||||
const mcpServer = server.createMcpServer();
|
||||
const tool = getTool(mcpServer, 'read_post_by_slug');
|
||||
const result = await tool.handler({ slug: 'no-such-slug' }, {}) as { content: Array<{ text: string }>; isError?: boolean };
|
||||
expect(result.isError).toBe(true);
|
||||
const parsed = JSON.parse(result.content[0].text);
|
||||
expect(parsed.error).toContain('not found');
|
||||
});
|
||||
});
|
||||
|
||||
// ── Prompt handler behavior ────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user