@co-engram/core 0.1.5 → 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.
Files changed (99) hide show
  1. package/dist/dreaming/decay.d.ts.map +1 -1
  2. package/dist/dreaming/decay.js +1 -1
  3. package/dist/dreaming/decay.js.map +1 -1
  4. package/dist/i18n/en.d.ts.map +1 -1
  5. package/dist/i18n/en.js +40 -11
  6. package/dist/i18n/en.js.map +1 -1
  7. package/dist/i18n/zh.d.ts +27 -8
  8. package/dist/i18n/zh.d.ts.map +1 -1
  9. package/dist/i18n/zh.js +40 -9
  10. package/dist/i18n/zh.js.map +1 -1
  11. package/dist/importance/vector.d.ts +4 -4
  12. package/dist/importance/vector.d.ts.map +1 -1
  13. package/dist/importance/vector.js +7 -12
  14. package/dist/importance/vector.js.map +1 -1
  15. package/dist/lifecycle/freshness.d.ts +25 -6
  16. package/dist/lifecycle/freshness.d.ts.map +1 -1
  17. package/dist/lifecycle/freshness.js +37 -21
  18. package/dist/lifecycle/freshness.js.map +1 -1
  19. package/dist/merge-driver.cjs +1 -1
  20. package/dist/observability/proposal-engine.d.ts +2 -1
  21. package/dist/observability/proposal-engine.d.ts.map +1 -1
  22. package/dist/observability/proposal-engine.js +6 -3
  23. package/dist/observability/proposal-engine.js.map +1 -1
  24. package/dist/prompt-builder/builder.d.ts +3 -0
  25. package/dist/prompt-builder/builder.d.ts.map +1 -1
  26. package/dist/prompt-builder/builder.js +45 -3
  27. package/dist/prompt-builder/builder.js.map +1 -1
  28. package/dist/prompt-builder/index.d.ts +1 -0
  29. package/dist/prompt-builder/index.d.ts.map +1 -1
  30. package/dist/prompt-builder/index.js +1 -0
  31. package/dist/prompt-builder/index.js.map +1 -1
  32. package/dist/prompt-builder/path-overview.d.ts +35 -0
  33. package/dist/prompt-builder/path-overview.d.ts.map +1 -0
  34. package/dist/prompt-builder/path-overview.js +44 -0
  35. package/dist/prompt-builder/path-overview.js.map +1 -0
  36. package/dist/prompt-builder/types.d.ts +11 -0
  37. package/dist/prompt-builder/types.d.ts.map +1 -1
  38. package/dist/retrieval/index.d.ts +2 -0
  39. package/dist/retrieval/index.d.ts.map +1 -1
  40. package/dist/retrieval/index.js +2 -0
  41. package/dist/retrieval/index.js.map +1 -1
  42. package/dist/retrieval/orchestrator.d.ts +34 -7
  43. package/dist/retrieval/orchestrator.d.ts.map +1 -1
  44. package/dist/retrieval/orchestrator.js +75 -40
  45. package/dist/retrieval/orchestrator.js.map +1 -1
  46. package/dist/retrieval/scoring.d.ts +7 -4
  47. package/dist/retrieval/scoring.d.ts.map +1 -1
  48. package/dist/retrieval/scoring.js +9 -16
  49. package/dist/retrieval/scoring.js.map +1 -1
  50. package/dist/retrieval/search-engine.d.ts +58 -0
  51. package/dist/retrieval/search-engine.d.ts.map +1 -0
  52. package/dist/retrieval/search-engine.js +53 -0
  53. package/dist/retrieval/search-engine.js.map +1 -0
  54. package/dist/retrieval/sqlite-orchestrator.d.ts +68 -0
  55. package/dist/retrieval/sqlite-orchestrator.d.ts.map +1 -0
  56. package/dist/retrieval/sqlite-orchestrator.js +148 -0
  57. package/dist/retrieval/sqlite-orchestrator.js.map +1 -0
  58. package/dist/storage/bootstrap.d.ts +31 -0
  59. package/dist/storage/bootstrap.d.ts.map +1 -0
  60. package/dist/storage/bootstrap.js +89 -0
  61. package/dist/storage/bootstrap.js.map +1 -0
  62. package/dist/storage/index-db-cursor.d.ts +27 -0
  63. package/dist/storage/index-db-cursor.d.ts.map +1 -0
  64. package/dist/storage/index-db-cursor.js +59 -0
  65. package/dist/storage/index-db-cursor.js.map +1 -0
  66. package/dist/storage/index-db.d.ts +112 -0
  67. package/dist/storage/index-db.d.ts.map +1 -0
  68. package/dist/storage/index-db.js +183 -0
  69. package/dist/storage/index-db.js.map +1 -0
  70. package/dist/storage/index.d.ts +3 -0
  71. package/dist/storage/index.d.ts.map +1 -1
  72. package/dist/storage/index.js +5 -0
  73. package/dist/storage/index.js.map +1 -1
  74. package/dist/storage/repository.d.ts +30 -2
  75. package/dist/storage/repository.d.ts.map +1 -1
  76. package/dist/storage/repository.js +73 -2
  77. package/dist/storage/repository.js.map +1 -1
  78. package/dist/tools/audit-query-tool.d.ts +34 -9
  79. package/dist/tools/audit-query-tool.d.ts.map +1 -1
  80. package/dist/tools/audit-query-tool.js +47 -14
  81. package/dist/tools/audit-query-tool.js.map +1 -1
  82. package/dist/tools/doctor-tools.d.ts.map +1 -1
  83. package/dist/tools/doctor-tools.js +5 -0
  84. package/dist/tools/doctor-tools.js.map +1 -1
  85. package/dist/tools/engram-tools.d.ts +2 -6
  86. package/dist/tools/engram-tools.d.ts.map +1 -1
  87. package/dist/tools/engram-tools.js +50 -13
  88. package/dist/tools/engram-tools.js.map +1 -1
  89. package/dist/tools/proposal-tools.d.ts +2 -33
  90. package/dist/tools/proposal-tools.d.ts.map +1 -1
  91. package/dist/tools/proposal-tools.js +64 -3
  92. package/dist/tools/proposal-tools.js.map +1 -1
  93. package/dist/tools/schemas.d.ts +84 -4
  94. package/dist/tools/schemas.d.ts.map +1 -1
  95. package/dist/tools/schemas.js +30 -5
  96. package/dist/tools/schemas.js.map +1 -1
  97. package/dist/tools/tool.d.ts +1 -1
  98. package/dist/tools/tool.d.ts.map +1 -1
  99. package/package.json +1 -1
@@ -18,6 +18,52 @@
18
18
  import { buildFtsIndex, searchFts } from "./fts.js";
19
19
  import { applyFilter } from "./filter.js";
20
20
  import { computeThreeFactorScore, DEFAULT_WEIGHTS, validateWeights, } from "./scoring.js";
21
+ import { compareSortKey, decodeCursor, encodeCursor, } from "../storage/index-db-cursor.js";
22
+ /**
23
+ * 把 DigestLine 投影成 SortKey。
24
+ *
25
+ * 排序顺序与 compareSortKey 严格一致:importance DESC, updatedAt DESC, id ASC。
26
+ * 缺省 updatedAt 兜底为 epoch,避免 Date.parse(undefined) 返回 NaN 干扰排序。
27
+ */
28
+ function digestLineToSortKey(line) {
29
+ return {
30
+ importance: line.importance,
31
+ updatedAt: Date.parse(line.updatedAt ?? "1970-01-01"),
32
+ id: line.id,
33
+ };
34
+ }
35
+ /**
36
+ * 从排序后的 lines + cursor 计算 { items, nextCursor }。
37
+ *
38
+ * caller 必须先按 SortKey 排序好 lines,再传入。本函数只做 cursor 过滤 + slice。
39
+ */
40
+ function paginateSortedLines(sorted, limit, cursor) {
41
+ let startIdx = 0;
42
+ if (cursor) {
43
+ const ck = decodeCursor(cursor);
44
+ startIdx = sorted.findIndex((line) => {
45
+ return compareSortKey(digestLineToSortKey(line), ck) > 0;
46
+ });
47
+ if (startIdx === -1)
48
+ startIdx = sorted.length;
49
+ }
50
+ const slice = sorted.slice(startIdx, startIdx + limit);
51
+ const items = slice.map((line) => ({
52
+ id: line.id,
53
+ score: 0,
54
+ entry: {
55
+ id: line.id,
56
+ title: line.title,
57
+ kind: line.kind,
58
+ domainTags: line.domainTags,
59
+ },
60
+ }));
61
+ const hasMore = startIdx + limit < sorted.length && items.length > 0;
62
+ const nextCursor = hasMore && slice.length > 0
63
+ ? encodeCursor(digestLineToSortKey(slice[slice.length - 1]))
64
+ : null;
65
+ return { items, nextCursor };
66
+ }
21
67
  /**
22
68
  * 检索器
23
69
  *
@@ -105,52 +151,41 @@ export class SearchOrchestrator {
105
151
  }));
106
152
  }
107
153
  /**
108
- * 按过滤器列出(无查询)
154
+ * 按过滤器列出(无查询,cursor 分页)
155
+ *
156
+ * Phase 3 PR3:opts signature + cursor。排序键 = SortKey(importance DESC,
157
+ * updatedAt DESC, id ASC),与 cursor encoding 一致,翻页稳定。
109
158
  *
110
- * 不打相关度分(score=0),按原顺序返回。
111
- * 可通过 listByImportance() 获取按 importance 排序的列表。
159
+ * 不打相关度分(score=0)。原顺序不再保留 —— 如需原顺序,直接读 repository。
112
160
  */
113
- listByFilter(filter, limit = 100) {
114
- const filtered = applyFilter(this.lines, filter);
115
- return filtered.slice(0, limit).map((line) => ({
116
- id: line.id,
117
- score: 0,
118
- entry: {
119
- id: line.id,
120
- title: line.title,
121
- kind: line.kind,
122
- domainTags: line.domainTags,
123
- },
124
- }));
161
+ listByFilter(opts) {
162
+ if (this.ftsIndex === null) {
163
+ throw new Error("SearchOrchestrator not built. Call build() first.");
164
+ }
165
+ const filtered = applyFilter(this.lines, opts.filter);
166
+ const sorted = [...filtered].sort((a, b) => compareSortKey(digestLineToSortKey(a), digestLineToSortKey(b)));
167
+ return paginateSortedLines(sorted, opts.limit, opts.cursor);
125
168
  }
126
169
  /**
127
- * 按 importance + recency 排序列出(无 query
170
+ * 按 importance + recency 排序列出(无 query,cursor 分页)
128
171
  *
129
- * 用于"最近有效的最重要 engram"类查询(如首页推荐)。
172
+ * Phase 3 PR3:opts signature + cursor。排序键与 listByFilter 一致(SortKey),
173
+ * 让翻页 cursor 精确;recency 因子已隐含在 updatedAt 字段(updatedAt 越
174
+ * 新排序越靠前,等效于"最近有效的最重要 engram")。
175
+ *
176
+ * 与历史实现差异:旧版用 computeThreeFactorScore 排序,新版用 SortKey。
177
+ * 行为变化:仅当两条 engram 的 importance 相同但 updatedAt 不同时,新版
178
+ * 严格按 updatedAt 排序,旧版按 computeThreeFactorScore 的 recency 因子
179
+ * 排序。两者语义等价(都是 "importance 主 + recency 次"),但公式不同。
180
+ * 由于 listByImportance 当前无外部 caller,这个变化无破坏性影响。
130
181
  */
131
- listByImportance(filter, limit = 100) {
132
- const filtered = applyFilter(this.lines, filter);
133
- const now = this.nowFn();
134
- const scored = filtered.map((line) => ({
135
- id: line.id,
136
- score: computeThreeFactorScore(0, line, { now, weights: this.weights }),
137
- line,
138
- }));
139
- scored.sort((a, b) => {
140
- if (a.score !== b.score)
141
- return b.score - a.score;
142
- return a.id < b.id ? -1 : 1;
143
- });
144
- return scored.slice(0, limit).map((item) => ({
145
- id: item.id,
146
- score: item.score,
147
- entry: {
148
- id: item.line.id,
149
- title: item.line.title,
150
- kind: item.line.kind,
151
- domainTags: item.line.domainTags,
152
- },
153
- }));
182
+ listByImportance(opts) {
183
+ if (this.ftsIndex === null) {
184
+ throw new Error("SearchOrchestrator not built. Call build() first.");
185
+ }
186
+ const filtered = applyFilter(this.lines, opts.filter);
187
+ const sorted = [...filtered].sort((a, b) => compareSortKey(digestLineToSortKey(a), digestLineToSortKey(b)));
188
+ return paginateSortedLines(sorted, opts.limit, opts.cursor);
154
189
  }
155
190
  }
156
191
  //# sourceMappingURL=orchestrator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/retrieval/orchestrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/retrieval/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -59,11 +59,14 @@ export declare function effectiveImportance(importance: number, reinforcementSco
59
59
  /**
60
60
  * 从 DigestLine + relevance 计算三因子得分
61
61
  *
62
+ * recency 维度的衰退计时起点 = `lastEffectiveAt ?? line.lastEffectiveAt ?? line.createdAt`:
63
+ * 未生效 engram 用 createdAt 兜底,新记忆从编码完成起开始衰退(艾宾浩斯模型)。
64
+ *
62
65
  * @param relevance - 归一化相关度 [0,1]
63
- * @param line - DigestLine(含 recency/importance 数据)
64
- * @param lastEffectiveAt - 最后有效检索时间(可选,省略则用 line.lastEffectiveAt
65
- * @param now - 当前时间(可选,便于测试;省略则 new Date()
66
- * @param weights - 权重配置(可选,省略用默认)
66
+ * @param line - DigestLine(含 recency/importance 数据,需有 createdAt)
67
+ * @param lastEffectiveAt - 最后有效检索时间(可选,省略则用 line.lastEffectiveAt)
68
+ * @param now - 当前时间(可选,便于测试;省略则 new Date())
69
+ * @param weights - 权重配置(可选,省略用默认)
67
70
  */
68
71
  export declare function computeThreeFactorScore(relevance: number, line: DigestLine, options?: {
69
72
  lastEffectiveAt?: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,cAAc;AACd,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,yCAAyC;AACzC,eAAO,MAAM,eAAe,EAAE,kBAI7B,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAY3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC3C,MAAM,CAIR;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAOR;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,kBAAkB,CAAC;CACzB,GACL,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,EACzE,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,kBAAkB,CAAC;CACzB,GACL,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAK9C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EACjD,CAAC,SAAK,GACL,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB9C"}
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,cAAc;AACd,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,yCAAyC;AACzC,eAAO,MAAM,eAAe,EAAE,kBAI7B,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAY3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC3C,MAAM,CAIR;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,MAAM,GACzB,MAAM,CAOR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,UAAU,EAChB,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,kBAAkB,CAAC;CACzB,GACL,MAAM,CAmBR;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,EACzE,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,kBAAkB,CAAC;CACzB,GACL,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAK9C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,EACjD,CAAC,SAAK,GACL,aAAa,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB9C"}
@@ -19,6 +19,7 @@
19
19
  *
20
20
  * @module @co-engram/core/retrieval
21
21
  */
22
+ import { effectiveAge } from "../lifecycle/freshness.js";
22
23
  /** 默认权重(spec 3.7:α=0.5, β=0.3, γ=0.2) */
23
24
  export const DEFAULT_WEIGHTS = {
24
25
  alpha: 0.5,
@@ -76,18 +77,21 @@ export function effectiveImportance(importance, reinforcementScore) {
76
77
  /**
77
78
  * 从 DigestLine + relevance 计算三因子得分
78
79
  *
80
+ * recency 维度的衰退计时起点 = `lastEffectiveAt ?? line.lastEffectiveAt ?? line.createdAt`:
81
+ * 未生效 engram 用 createdAt 兜底,新记忆从编码完成起开始衰退(艾宾浩斯模型)。
82
+ *
79
83
  * @param relevance - 归一化相关度 [0,1]
80
- * @param line - DigestLine(含 recency/importance 数据)
81
- * @param lastEffectiveAt - 最后有效检索时间(可选,省略则用 line.lastEffectiveAt
82
- * @param now - 当前时间(可选,便于测试;省略则 new Date()
83
- * @param weights - 权重配置(可选,省略用默认)
84
+ * @param line - DigestLine(含 recency/importance 数据,需有 createdAt)
85
+ * @param lastEffectiveAt - 最后有效检索时间(可选,省略则用 line.lastEffectiveAt)
86
+ * @param now - 当前时间(可选,便于测试;省略则 new Date())
87
+ * @param weights - 权重配置(可选,省略用默认)
84
88
  */
85
89
  export function computeThreeFactorScore(relevance, line, options = {}) {
86
90
  const weights = options.weights ?? DEFAULT_WEIGHTS;
87
91
  validateWeights(weights);
88
92
  const now = options.now ?? new Date();
89
93
  const lastEffective = options.lastEffectiveAt ?? line.lastEffectiveAt;
90
- const ageDays = computeAgeDays(lastEffective, now);
94
+ const ageDays = effectiveAge(lastEffective, line.createdAt, now);
91
95
  const recency = recencyDecay(ageDays, line.decayHalfLifeDays);
92
96
  const importance = effectiveImportance(line.importance, line.reinforcementScore);
93
97
  return (weights.alpha * clamp01(relevance) +
@@ -151,15 +155,4 @@ function clamp01(x) {
151
155
  return 1;
152
156
  return x;
153
157
  }
154
- function computeAgeDays(lastEffectiveAt, now) {
155
- if (!lastEffectiveAt)
156
- return Number.POSITIVE_INFINITY; // 从未有效 → age = ∞ → recency → 0
157
- const ts = new Date(lastEffectiveAt).getTime();
158
- if (Number.isNaN(ts))
159
- return Number.POSITIVE_INFINITY;
160
- const ageMs = now.getTime() - ts;
161
- if (ageMs < 0)
162
- return 0; // 时钟偏差/未来
163
- return ageMs / (1000 * 60 * 60 * 24);
164
- }
165
158
  //# sourceMappingURL=scoring.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../src/retrieval/scoring.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { IndexDb } from "../storage/index-db.js";
2
+ import type { DigestLine } from "../index/types.js";
3
+ import type { SearchFilter } from "../types/disclosure.js";
4
+ import { type SimpleSearchResult } from "./orchestrator.js";
5
+ import { SqliteSearchOrchestrator } from "./sqlite-orchestrator.js";
6
+ /** 引擎类型 */
7
+ export type SearchEngineType = "memory" | "sqlite";
8
+ /**
9
+ * 统一检索引擎接口 —— in-memory SearchOrchestrator 与 SQLite 适配器都满足。
10
+ *
11
+ * 只暴露工具调用方需要的两个方法:
12
+ * - search(query, filter?, limit?) —— 检索
13
+ * - build(lines) —— 索引重建(in-memory 必需;SQLite 模式 no-op,
14
+ * write-through 在 EngramRepository 写入路径已透明维护索引)
15
+ *
16
+ * SearchOrchestrator 自身的 setClock / setWeights / listByFilter /
17
+ * listByImportance 等方法不在此接口 —— 这些是 in-memory 引擎特有的
18
+ * 调优 hook,SQLite 端无对应概念(bm25 自带相关度,无需三因子融合调权)。
19
+ */
20
+ export interface SearchEngine {
21
+ search(query: string, filter?: SearchFilter, limit?: number): SimpleSearchResult[];
22
+ build(lines: readonly DigestLine[]): void;
23
+ }
24
+ /**
25
+ * SQLite 引擎适配器 —— 把 SqliteSearchOrchestrator 包装成 SearchEngine。
26
+ *
27
+ * - search():把 3-arg signature 转成 SqliteSearchOrchestrator 的
28
+ * { filter, limit } opts signature,丢掉 nextCursor(search 工具不强制分页)。
29
+ * - build():no-op。SQLite 索引由 EngramRepository 的 write-through 持续
30
+ * 维护,不需要外部触发重建。保留方法仅为接口兼容。
31
+ */
32
+ export declare class SqliteSearchEngineAdapter implements SearchEngine {
33
+ private readonly sqlite;
34
+ constructor(sqlite: SqliteSearchOrchestrator);
35
+ search(query: string, filter?: SearchFilter, limit?: number): SimpleSearchResult[];
36
+ build(_lines: readonly DigestLine[]): void;
37
+ }
38
+ /**
39
+ * 工厂:按 type 创建 SearchEngine。
40
+ *
41
+ * sqlite 模式必须提供 indexDb(已 open())。memory 模式忽略 indexDb。
42
+ *
43
+ * @throws sqlite 模式未提供 indexDb 时抛错(fail-loud,避免运行时静默退化)
44
+ */
45
+ export declare function createSearchEngine(opts: {
46
+ readonly type: SearchEngineType;
47
+ readonly indexDb?: IndexDb;
48
+ }): SearchEngine;
49
+ /**
50
+ * 从环境变量解析 engine flag。
51
+ *
52
+ * - CO_ENGRAM_SEARCH_ENGINE=sqlite → sqlite
53
+ * - 未设置 / 空 / 其他值 → memory(默认 + 灰度保守)
54
+ *
55
+ * 函数纯函数(可注入 env),便于测试。
56
+ */
57
+ export declare function resolveSearchEngineType(env?: NodeJS.ProcessEnv): SearchEngineType;
58
+ //# sourceMappingURL=search-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-engine.d.ts","sourceRoot":"","sources":["../../src/retrieval/search-engine.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAsB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,WAAW;AACX,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACnF,KAAK,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,qBAAa,yBAA0B,YAAW,YAAY;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,wBAAwB;IAE7D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,KAAK,SAAK,GAAG,kBAAkB,EAAE;IAI9E,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,IAAI;CAK3C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,YAAY,CAUf;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,gBAAgB,CAGlB"}
@@ -0,0 +1,53 @@
1
+ import { SearchOrchestrator } from "./orchestrator.js";
2
+ import { SqliteSearchOrchestrator } from "./sqlite-orchestrator.js";
3
+ /**
4
+ * SQLite 引擎适配器 —— 把 SqliteSearchOrchestrator 包装成 SearchEngine。
5
+ *
6
+ * - search():把 3-arg signature 转成 SqliteSearchOrchestrator 的
7
+ * { filter, limit } opts signature,丢掉 nextCursor(search 工具不强制分页)。
8
+ * - build():no-op。SQLite 索引由 EngramRepository 的 write-through 持续
9
+ * 维护,不需要外部触发重建。保留方法仅为接口兼容。
10
+ */
11
+ export class SqliteSearchEngineAdapter {
12
+ sqlite;
13
+ constructor(sqlite) {
14
+ this.sqlite = sqlite;
15
+ }
16
+ search(query, filter, limit = 20) {
17
+ return this.sqlite.search(query, { filter, limit }).results;
18
+ }
19
+ build(_lines) {
20
+ // intentional no-op:write-through 已维护 SQLite 索引。
21
+ // 参数保留是为了与 SearchOrchestrator.build 签名对齐,允许调用方
22
+ // 不感知底层引擎而透明调用。
23
+ }
24
+ }
25
+ /**
26
+ * 工厂:按 type 创建 SearchEngine。
27
+ *
28
+ * sqlite 模式必须提供 indexDb(已 open())。memory 模式忽略 indexDb。
29
+ *
30
+ * @throws sqlite 模式未提供 indexDb 时抛错(fail-loud,避免运行时静默退化)
31
+ */
32
+ export function createSearchEngine(opts) {
33
+ if (opts.type === "sqlite") {
34
+ if (!opts.indexDb) {
35
+ throw new Error("createSearchEngine: sqlite 模式必须提供 indexDb(已 open)。若要 fallback 到 memory,显式传 type='memory'。");
36
+ }
37
+ return new SqliteSearchEngineAdapter(new SqliteSearchOrchestrator({ db: opts.indexDb }));
38
+ }
39
+ return new SearchOrchestrator();
40
+ }
41
+ /**
42
+ * 从环境变量解析 engine flag。
43
+ *
44
+ * - CO_ENGRAM_SEARCH_ENGINE=sqlite → sqlite
45
+ * - 未设置 / 空 / 其他值 → memory(默认 + 灰度保守)
46
+ *
47
+ * 函数纯函数(可注入 env),便于测试。
48
+ */
49
+ export function resolveSearchEngineType(env = process.env) {
50
+ const v = (env.CO_ENGRAM_SEARCH_ENGINE ?? "memory").toString().toLowerCase().trim();
51
+ return v === "sqlite" ? "sqlite" : "memory";
52
+ }
53
+ //# sourceMappingURL=search-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-engine.js","sourceRoot":"","sources":["../../src/retrieval/search-engine.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,kBAAkB,EAA2B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAsBpE;;;;;;;GAOG;AACH,MAAM,OAAO,yBAAyB;IACP;IAA7B,YAA6B,MAAgC;QAAhC,WAAM,GAAN,MAAM,CAA0B;IAAG,CAAC;IAEjE,MAAM,CAAC,KAAa,EAAE,MAAqB,EAAE,KAAK,GAAG,EAAE;QACrD,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,MAA6B;QACjC,iDAAiD;QACjD,+CAA+C;QAC/C,gBAAgB;IAClB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAGlC;IACC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACb,2FAA2F,CAC5F,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,yBAAyB,CAAC,IAAI,wBAAwB,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,IAAI,kBAAkB,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACrC,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,uBAAuB,IAAI,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACpF,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,68 @@
1
+ import type { IndexDb } from "../storage/index-db.js";
2
+ import type { SearchFilter } from "../types/disclosure.js";
3
+ import type { SimpleSearchResult } from "./orchestrator.js";
4
+ /** SqliteSearchOrchestrator 构造参数 */
5
+ export interface SqliteSearchOptions {
6
+ readonly db: IndexDb;
7
+ /**
8
+ * 时钟注入(测试用);当前实现未依赖时间,但保留接口便于后续三因子融合。
9
+ */
10
+ readonly nowFn?: () => Date;
11
+ }
12
+ /** search() 调用选项 */
13
+ export interface SearchQueryOptions {
14
+ readonly filter?: SearchFilter;
15
+ readonly limit?: number;
16
+ /**
17
+ * 游标分页(Phase 3 启用);当前实现忽略,只返回 nextCursor=null。
18
+ */
19
+ readonly cursor?: string | null;
20
+ }
21
+ /** search() 返回结构 */
22
+ export interface SearchResponse {
23
+ readonly results: SimpleSearchResult[];
24
+ readonly nextCursor: string | null;
25
+ }
26
+ /**
27
+ * SQLite FTS5 召回编排器。
28
+ *
29
+ * 与 in-memory SearchOrchestrator 接口兼容(same query → SimpleSearchResult[]),
30
+ * 上层 engram_search 工具按 feature flag 切换引擎。
31
+ */
32
+ export declare class SqliteSearchOrchestrator {
33
+ private readonly db;
34
+ constructor(opts: SqliteSearchOptions);
35
+ search(query: string, opts?: SearchQueryOptions): SearchResponse;
36
+ /** FTS5 trigram MATCH,bm25 排序(负值越优,ASC 即最相关在前) */
37
+ private searchByFts;
38
+ /**
39
+ * LIKE 兜底:1-2 字符 query(trigram 无法处理)或 FTS5 MATCH 无命中时降级。
40
+ *
41
+ * LIKE 覆盖四个文本维度:engrams.title + engram_fts.summary +
42
+ * engram_fts.content_tokens + engram_domains.domain。仅靠 title 召回过窄
43
+ * (中文 1-2 字 query 经常只在 summary / content / domainTags 中出现),
44
+ * 必须扫全部索引文本,与 in-memory FTS 的索引字段对齐。
45
+ *
46
+ * 排序:importance + updatedAt DESC(无相关度信号,用静态质量分代替)。
47
+ */
48
+ private searchByLike;
49
+ /**
50
+ * 把用户 query 转成 FTS5 MATCH 表达式。
51
+ *
52
+ * 实现:整体作为 FTS5 string query(`"..."` 语法),FTS5 trigram tokenizer
53
+ * 自行切分。`"` 内的双引号 escape 为 `""`(FTS5 标准做法)。
54
+ *
55
+ * 不做手工 trigram 切分:trigram tokenizer 已在 SQL 层做,手工切分反而
56
+ * 会和 tokenizer 双重处理,导致短语匹配失效。
57
+ */
58
+ private buildFtsQuery;
59
+ /**
60
+ * 后置过滤(SQL 端已做 limit,这里做 filter 收紧)。
61
+ *
62
+ * 当前实现只处理 domainTags;其余 SearchFilter 字段(kinds / status /
63
+ * freshness / contextTags / 时间窗 / minImportance)留待 Phase 3 在 SQL
64
+ * 端实现以避免 N+1 拉取。
65
+ */
66
+ private applyPostFilter;
67
+ }
68
+ //# sourceMappingURL=sqlite-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-orchestrator.d.ts","sourceRoot":"","sources":["../../src/retrieval/sqlite-orchestrator.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,oCAAoC;AACpC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,oBAAoB;AACpB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,oBAAoB;AACpB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAKD;;;;;GAKG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAU;gBAEjB,IAAI,EAAE,mBAAmB;IAIrC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,cAAc;IA0BpE,kDAAkD;IAClD,OAAO,CAAC,WAAW;IA4BnB;;;;;;;;;OASG;IACH,OAAO,CAAC,YAAY;IA4BpB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAKrB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;CAmBxB"}
@@ -0,0 +1,148 @@
1
+ /** trigram tokenizer 命中所需的最小 UTF-16 code unit 数 */
2
+ const LIKE_FALLBACK_MIN_CHARS = 3;
3
+ /**
4
+ * SQLite FTS5 召回编排器。
5
+ *
6
+ * 与 in-memory SearchOrchestrator 接口兼容(same query → SimpleSearchResult[]),
7
+ * 上层 engram_search 工具按 feature flag 切换引擎。
8
+ */
9
+ export class SqliteSearchOrchestrator {
10
+ db;
11
+ constructor(opts) {
12
+ this.db = opts.db;
13
+ }
14
+ search(query, opts = {}) {
15
+ const limit = Math.min(Math.max(opts.limit ?? 20, 1), 500);
16
+ const q = query.trim();
17
+ if (!q)
18
+ return { results: [], nextCursor: null };
19
+ const useLike = q.length < LIKE_FALLBACK_MIN_CHARS;
20
+ const rows = useLike
21
+ ? this.searchByLike(q, limit)
22
+ : this.searchByFts(q, limit);
23
+ const filtered = this.applyPostFilter(rows, opts.filter);
24
+ const results = filtered.map((r) => ({
25
+ id: r.id,
26
+ score: r.score,
27
+ entry: {
28
+ id: r.id,
29
+ title: r.title,
30
+ kind: r.kind,
31
+ domainTags: r.domainTags,
32
+ },
33
+ }));
34
+ return { results, nextCursor: null };
35
+ }
36
+ /** FTS5 trigram MATCH,bm25 排序(负值越优,ASC 即最相关在前) */
37
+ searchByFts(q, limit) {
38
+ const ftsQuery = this.buildFtsQuery(q);
39
+ if (!ftsQuery)
40
+ return [];
41
+ const stmt = this.db.prepare(`
42
+ SELECT e.id AS id, e.title AS title, e.kind AS kind, e.importance AS importance,
43
+ (SELECT group_concat(domain, ',') FROM engram_domains d WHERE d.engram_id = e.id) AS domain_tags,
44
+ bm25(engram_fts) AS fts_score
45
+ FROM engram_fts
46
+ JOIN engrams e ON e.id = engram_fts.id
47
+ WHERE engram_fts MATCH ?
48
+ ORDER BY fts_score ASC
49
+ LIMIT ?
50
+ `);
51
+ const rows = stmt.all(ftsQuery, limit);
52
+ return rows.map((r) => ({
53
+ id: r.id,
54
+ title: r.title,
55
+ kind: r.kind,
56
+ importance: r.importance,
57
+ domainTags: splitCsv(r.domain_tags),
58
+ // bm25 返回负值,反转成正数(score 越大越优,与 in-memory 一致)
59
+ score: -r.fts_score,
60
+ }));
61
+ }
62
+ /**
63
+ * LIKE 兜底:1-2 字符 query(trigram 无法处理)或 FTS5 MATCH 无命中时降级。
64
+ *
65
+ * LIKE 覆盖四个文本维度:engrams.title + engram_fts.summary +
66
+ * engram_fts.content_tokens + engram_domains.domain。仅靠 title 召回过窄
67
+ * (中文 1-2 字 query 经常只在 summary / content / domainTags 中出现),
68
+ * 必须扫全部索引文本,与 in-memory FTS 的索引字段对齐。
69
+ *
70
+ * 排序:importance + updatedAt DESC(无相关度信号,用静态质量分代替)。
71
+ */
72
+ searchByLike(q, limit) {
73
+ const stmt = this.db.prepare(`
74
+ SELECT e.id AS id, e.title AS title, e.kind AS kind, e.importance AS importance,
75
+ (SELECT group_concat(domain, ',') FROM engram_domains d WHERE d.engram_id = e.id) AS domain_tags
76
+ FROM engrams e
77
+ JOIN engram_fts f ON f.id = e.id
78
+ WHERE e.title LIKE ? ESCAPE '\\'
79
+ OR f.summary LIKE ? ESCAPE '\\'
80
+ OR f.content_tokens LIKE ? ESCAPE '\\'
81
+ OR EXISTS (
82
+ SELECT 1 FROM engram_domains d
83
+ WHERE d.engram_id = e.id AND d.domain LIKE ? ESCAPE '\\'
84
+ )
85
+ ORDER BY e.importance DESC, e.updated_at DESC
86
+ LIMIT ?
87
+ `);
88
+ const pattern = `%${escapeLike(q)}%`;
89
+ const rows = stmt.all(pattern, pattern, pattern, pattern, limit);
90
+ return rows.map((r) => ({
91
+ id: r.id,
92
+ title: r.title,
93
+ kind: r.kind,
94
+ importance: r.importance,
95
+ domainTags: splitCsv(r.domain_tags),
96
+ score: 0,
97
+ }));
98
+ }
99
+ /**
100
+ * 把用户 query 转成 FTS5 MATCH 表达式。
101
+ *
102
+ * 实现:整体作为 FTS5 string query(`"..."` 语法),FTS5 trigram tokenizer
103
+ * 自行切分。`"` 内的双引号 escape 为 `""`(FTS5 标准做法)。
104
+ *
105
+ * 不做手工 trigram 切分:trigram tokenizer 已在 SQL 层做,手工切分反而
106
+ * 会和 tokenizer 双重处理,导致短语匹配失效。
107
+ */
108
+ buildFtsQuery(query) {
109
+ if (!query)
110
+ return null;
111
+ return `"${query.replace(/"/g, '""')}"`;
112
+ }
113
+ /**
114
+ * 后置过滤(SQL 端已做 limit,这里做 filter 收紧)。
115
+ *
116
+ * 当前实现只处理 domainTags;其余 SearchFilter 字段(kinds / status /
117
+ * freshness / contextTags / 时间窗 / minImportance)留待 Phase 3 在 SQL
118
+ * 端实现以避免 N+1 拉取。
119
+ */
120
+ applyPostFilter(rows, filter) {
121
+ if (!filter)
122
+ return rows;
123
+ if (filter.domainTags && filter.domainTags.length > 0) {
124
+ const want = new Set(filter.domainTags);
125
+ rows = rows.filter((r) => r.domainTags.some((t) => want.has(t)));
126
+ }
127
+ if (filter.kinds && filter.kinds.length > 0) {
128
+ const want = new Set(filter.kinds);
129
+ rows = rows.filter((r) => want.has(r.kind));
130
+ }
131
+ if (typeof filter.minImportance === "number") {
132
+ const floor = filter.minImportance;
133
+ rows = rows.filter((r) => r.importance >= floor);
134
+ }
135
+ return rows;
136
+ }
137
+ }
138
+ /** group_concat(domain, ',') 拆回数组(null / "" → []) */
139
+ function splitCsv(joined) {
140
+ if (!joined)
141
+ return [];
142
+ return joined.split(",").filter(Boolean);
143
+ }
144
+ /** LIKE escape:% _ \ 三个特殊字符转义,使用 ESCAPE '\' 子句 */
145
+ function escapeLike(s) {
146
+ return s.replace(/[\\%_]/g, (m) => `\\${m}`);
147
+ }
148
+ //# sourceMappingURL=sqlite-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-orchestrator.js","sourceRoot":"","sources":["../../src/retrieval/sqlite-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { Language } from "../i18n/index.js";
2
+ import { type SearchEngine, type SearchEngineType } from "../retrieval/search-engine.js";
3
+ import { EngramRepository } from "./repository.js";
4
+ import { IndexDb } from "./index-db.js";
5
+ export interface BootstrapOptions {
6
+ readonly dataRoot: string;
7
+ readonly language?: Language;
8
+ /** 注入 env(测试用);默认 process.env */
9
+ readonly env?: NodeJS.ProcessEnv;
10
+ }
11
+ export interface BootstrapResult {
12
+ readonly repository: EngramRepository;
13
+ readonly searchEngine: SearchEngine;
14
+ readonly engineType: SearchEngineType;
15
+ /** SQLite 模式下的 indexDb 引用;memory 模式为 undefined。host 持有以在
16
+ * 关闭时显式 close()(进程退出时 OS 自动回收 fd,但测试 / 显式资源管理
17
+ * 需要确定性释放)。 */
18
+ readonly indexDb?: IndexDb;
19
+ }
20
+ /**
21
+ * 装配 EngramRepository + SearchEngine。
22
+ *
23
+ * Engine 选择:env.CO_ENGRAM_SEARCH_ENGINE=sqlite → SQLite FTS5 模式;
24
+ * 未设置 / 其他值 → 默认 memory(in-memory Intl.Segmenter)。
25
+ *
26
+ * Cold start 行为(sqlite 模式):db 为空时,从 repository.listEngrams()
27
+ * 枚举全量 engram,readEngram() 读详情,转 EngramIndexEntry[] 后
28
+ * rebuildFromEntries() 一次性灌入。已有数据的 db 不重建。
29
+ */
30
+ export declare function bootstrapRepositoryAndSearch(opts: BootstrapOptions): BootstrapResult;
31
+ //# sourceMappingURL=bootstrap.d.ts.map