dsh-reference-session-collector 0.2.0-beta.0 → 0.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/lib/index.d.ts CHANGED
@@ -388,6 +388,12 @@ interface GroupedSearchRequest {
388
388
  limit?: number;
389
389
  /** R3:true=snippet 取材切 redacted_search_text(命中/排序不变,fts 仍原文)。 */
390
390
  redact?: boolean;
391
+ /**
392
+ * 命中展开(steward「分开显示」开关,wire `expand=1`):true=每条候选行
393
+ * 各自成命中(同会话多行按全局分数序出现);缺省 false=会话分组各取
394
+ * 最强命中(既有聚合臂行为零改动,limit 语义随之从会话数变行数)。
395
+ */
396
+ expand?: boolean;
391
397
  }
392
398
  /** 分组命中(wire 蛇形,会话级最强命中)。 */
393
399
  interface GroupedSearchHit {
package/lib/index.js CHANGED
@@ -385,18 +385,20 @@ function searchGrouped(ctx, request) {
385
385
  WHERE segments_fts MATCH ?
386
386
  AND seg.kind IN (${placeholders}) ${surfaceClause} ${archivedClause} ${dateClause}
387
387
  ORDER BY rank LIMIT ?`;
388
- const docs = ctx.store.db.prepare(sql).all(match, ...kinds, ...dateParams, SEARCH_SCAN_LIMIT);
389
- const bestBySession = /* @__PURE__ */ new Map();
390
- for (const doc of docs) {
391
- const weight = SEARCH_TYPE_WEIGHT[doc.kind] ?? 1;
392
- const score = -Number(doc.rank) * weight;
393
- const best = bestBySession.get(doc.session_id);
394
- if (best === void 0 || score > best.score) bestBySession.set(doc.session_id, {
395
- doc,
396
- score
397
- });
388
+ const scored = ctx.store.db.prepare(sql).all(match, ...kinds, ...dateParams, SEARCH_SCAN_LIMIT).map((doc) => ({
389
+ doc,
390
+ score: -Number(doc.rank) * (SEARCH_TYPE_WEIGHT[doc.kind] ?? 1)
391
+ }));
392
+ let grouped;
393
+ if (request.expand === true) grouped = scored;
394
+ else {
395
+ const bestBySession = /* @__PURE__ */ new Map();
396
+ for (const entry of scored) {
397
+ const best = bestBySession.get(entry.doc.session_id);
398
+ if (best === void 0 || entry.score > best.score) bestBySession.set(entry.doc.session_id, entry);
399
+ }
400
+ grouped = [...bestBySession.values()];
398
401
  }
399
- const grouped = [...bestBySession.values()];
400
402
  if (request.sortBy === "time") grouped.sort((a, b) => b.doc.updated_at - a.doc.updated_at || b.score - a.score);
401
403
  else grouped.sort((a, b) => b.score - a.score);
402
404
  const hits = grouped.slice(0, limit).map(({ doc }) => ({
@@ -2388,6 +2390,7 @@ async function handleDrsRequest(deps, req, res) {
2388
2390
  ...url.searchParams.get("surface") === "0" ? { surfaceOnly: false } : {},
2389
2391
  ...url.searchParams.get("sort") === "time" ? { sortBy: "time" } : {},
2390
2392
  ...limitRaw !== null && Number.isFinite(Number(limitRaw)) ? { limit: Number(limitRaw) } : {},
2393
+ ...url.searchParams.get("expand") === "1" ? { expand: true } : {},
2391
2394
  ...redact ? { redact: true } : {}
2392
2395
  })
2393
2396
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-reference-session-collector",
3
- "version": "0.2.0-beta.0",
3
+ "version": "0.2.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org",
6
6
  "tag": "beta",
package/src/index.ts CHANGED
@@ -309,6 +309,7 @@ export async function handleDrsRequest(deps: DrsHandlerDeps, req: IncomingMessag
309
309
  ...(url.searchParams.get('surface') === '0' ? { surfaceOnly: false } : {}),
310
310
  ...(url.searchParams.get('sort') === 'time' ? { sortBy: 'time' as const } : {}),
311
311
  ...(limitRaw !== null && Number.isFinite(Number(limitRaw)) ? { limit: Number(limitRaw) } : {}),
312
+ ...(url.searchParams.get('expand') === '1' ? { expand: true } : {}),
312
313
  ...(redact ? { redact: true } : {}),
313
314
  })
314
315
  writeJson(res, 200, { ok: true, ...grouped })
package/src/surface.ts CHANGED
@@ -379,6 +379,12 @@ export interface GroupedSearchRequest {
379
379
  limit?: number
380
380
  /** R3:true=snippet 取材切 redacted_search_text(命中/排序不变,fts 仍原文)。 */
381
381
  redact?: boolean
382
+ /**
383
+ * 命中展开(steward「分开显示」开关,wire `expand=1`):true=每条候选行
384
+ * 各自成命中(同会话多行按全局分数序出现);缺省 false=会话分组各取
385
+ * 最强命中(既有聚合臂行为零改动,limit 语义随之从会话数变行数)。
386
+ */
387
+ expand?: boolean
382
388
  }
383
389
 
384
390
  /** 分组命中(wire 蛇形,会话级最强命中)。 */
@@ -445,14 +451,19 @@ export function searchGrouped(ctx: QueryContext, request: GroupedSearchRequest):
445
451
  title: string
446
452
  updated_at: number
447
453
  }[]
448
- const bestBySession = new Map<string, { doc: typeof docs[number]; score: number }>()
449
- for (const doc of docs) {
450
- const weight = SEARCH_TYPE_WEIGHT[doc.kind] ?? 1
451
- const score = -Number(doc.rank) * weight
452
- const best = bestBySession.get(doc.session_id)
453
- if (best === undefined || score > best.score) bestBySession.set(doc.session_id, { doc, score })
454
+ const scored = docs.map(doc => ({ doc, score: -Number(doc.rank) * (SEARCH_TYPE_WEIGHT[doc.kind] ?? 1) }))
455
+ let grouped: typeof scored
456
+ if (request.expand === true) {
457
+ // 命中展开:不折叠,每条候选行都是命中(同会话多行各自显示)。
458
+ grouped = scored
459
+ } else {
460
+ const bestBySession = new Map<string, { doc: typeof docs[number]; score: number }>()
461
+ for (const entry of scored) {
462
+ const best = bestBySession.get(entry.doc.session_id)
463
+ if (best === undefined || entry.score > best.score) bestBySession.set(entry.doc.session_id, entry)
464
+ }
465
+ grouped = [...bestBySession.values()]
454
466
  }
455
- const grouped = [...bestBySession.values()]
456
467
  if (request.sortBy === 'time') {
457
468
  grouped.sort((a, b) => (b.doc.updated_at - a.doc.updated_at) || (b.score - a.score))
458
469
  } else {