feat(platform): forum search mesh merge API for Phase 128 (v0.8.93)
Add searchForumPostsWithMesh and _forumPostsFromMeshMessages to merge local forum haystack hits with guild MESSAGE_SEARCH mesh responses via pearcord-search.mergeForumSearchHits. _resolveSearchResults uses mesh for forum scope and records _lastSearchMeshMeta with scope forum for the desktop search UI. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -156,6 +156,8 @@ const {
|
||||
ingestGuildSearchIndexSlice,
|
||||
buildIndexRow,
|
||||
mergeSearchHits,
|
||||
mergeForumSearchHits,
|
||||
rankAndEnrichForumSearchHits,
|
||||
compactMeshSearchHit,
|
||||
meshHitToMessage
|
||||
} = require('pearcord-search')
|
||||
@@ -1044,7 +1046,17 @@ class PearcordPlatform extends EventEmitter {
|
||||
id: this.activeChannelId
|
||||
})
|
||||
if (!ch || !isForumChannel(ch)) return []
|
||||
return this.searchForumPosts(guildId, ch.id, q)
|
||||
const out = await this.searchForumPostsWithMesh(guildId, ch.id, q, {
|
||||
limit: 50,
|
||||
mesh: this._searchIncludeMesh
|
||||
})
|
||||
this._lastSearchMeshMeta = {
|
||||
mesh: out.mesh,
|
||||
meshHitCount: out.meshHitCount || 0,
|
||||
localHitCount: out.localHitCount || 0,
|
||||
scope: 'forum'
|
||||
}
|
||||
return out.hits
|
||||
}
|
||||
if (this._searchScope === 'guild') {
|
||||
const out = await this.searchGuildMessagesWithMesh(this.guild.guild.id, q, {
|
||||
@@ -1143,10 +1155,91 @@ class PearcordPlatform extends EventEmitter {
|
||||
snippet: String(content || '').slice(0, 160)
|
||||
})
|
||||
}
|
||||
const { rankAndEnrichForumSearchHits } = require('pearcord-search')
|
||||
return rankAndEnrichForumSearchHits(hits, q, { limit })
|
||||
}
|
||||
|
||||
async _forumPostsFromMeshMessages (guildId, forumChannelId, messages, query) {
|
||||
const q = String(query || '').trim()
|
||||
if (!q || !guildId || !forumChannelId) return []
|
||||
const channels =
|
||||
(await this.guild?.listChannels?.()) ||
|
||||
(await this.db.find(COLLECTIONS.CHANNELS, { guildId }))
|
||||
const forumCh = channels.find((c) => c.id === forumChannelId)
|
||||
const posts = listForumPostsForParent(channels, forumChannelId, {
|
||||
includeArchived: true
|
||||
})
|
||||
const byThread = new Map(posts.map((p) => [p.id, p]))
|
||||
const hits = []
|
||||
for (const m of messages || []) {
|
||||
const post = byThread.get(m.channelId)
|
||||
if (!post) continue
|
||||
let content = String(m.content || '')
|
||||
if (!content && post.rootMessageId) {
|
||||
const root = await this.db.get(COLLECTIONS.MESSAGES, {
|
||||
channelId: post.id,
|
||||
id: post.rootMessageId
|
||||
})
|
||||
if (root) content = this._messagePlaintext(enrichMessageRow(root))
|
||||
}
|
||||
const tags = this.forum
|
||||
? await this.forum.getPostTags(guildId, post.id).catch(() => [])
|
||||
: []
|
||||
hits.push({
|
||||
...post,
|
||||
tags,
|
||||
forumChannelId,
|
||||
forumChannelName: forumCh?.name || 'forum',
|
||||
searchHaystack: forumPostHaystack({
|
||||
title: post.name,
|
||||
content,
|
||||
tags,
|
||||
archived: post.archived
|
||||
}),
|
||||
snippet: String(content || '').slice(0, 160),
|
||||
fromMesh: true
|
||||
})
|
||||
}
|
||||
return rankAndEnrichForumSearchHits(hits, q, { limit: 50 })
|
||||
}
|
||||
|
||||
async searchForumPostsWithMesh (guildId, forumChannelId, query, opts = {}) {
|
||||
const local = await this.searchForumPosts(guildId, forumChannelId, query, opts)
|
||||
if (opts.mesh === false || !this.guild?.guild) {
|
||||
return {
|
||||
hits: local,
|
||||
mesh: false,
|
||||
meshHitCount: 0,
|
||||
localHitCount: local.length
|
||||
}
|
||||
}
|
||||
try {
|
||||
const meshMsgs = await this._fetchGuildSearchFromMeshOnce(guildId, query, opts)
|
||||
const meshPosts = await this._forumPostsFromMeshMessages(
|
||||
guildId,
|
||||
forumChannelId,
|
||||
meshMsgs.map((m) => enrichMessageRow(m)),
|
||||
query
|
||||
)
|
||||
const merged = mergeForumSearchHits(local, meshPosts, {
|
||||
limit: opts.limit || 50,
|
||||
query: String(query || '').trim()
|
||||
})
|
||||
return {
|
||||
hits: merged,
|
||||
mesh: true,
|
||||
meshHitCount: meshPosts.length,
|
||||
localHitCount: local.length
|
||||
}
|
||||
} catch {
|
||||
return {
|
||||
hits: local,
|
||||
mesh: false,
|
||||
meshHitCount: 0,
|
||||
localHitCount: local.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getSearchIndexStore () {
|
||||
if (!this._searchIndexStore) {
|
||||
this._searchIndexStore = new GuildSearchIndexStore(this.storagePath)
|
||||
|
||||
Reference in New Issue
Block a user