@dikolab/kbdb 0.1.6 → 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 (193) hide show
  1. package/README.md +30 -9
  2. package/dist/cli.cjs +181 -50
  3. package/dist/cli.cjs.map +3 -3
  4. package/dist/cli.mjs +181 -50
  5. package/dist/cli.mjs.map +3 -3
  6. package/dist/kbdb-worker.cjs +283 -29
  7. package/dist/kbdb-worker.cjs.map +4 -4
  8. package/dist/mod.cjs +13 -2
  9. package/dist/mod.cjs.map +2 -2
  10. package/dist/mod.mjs +13 -2
  11. package/dist/mod.mjs.map +2 -2
  12. package/dist/src/shared/cli/functions/format-output.function.d.ts +7 -7
  13. package/dist/src/shared/cli/functions/run-search.function.d.ts +25 -16
  14. package/dist/src/shared/cli/index.d.ts +1 -1
  15. package/dist/src/shared/cli/typings/cli-options.interface.d.ts +2 -0
  16. package/dist/src/shared/cli/typings/search-display.model.d.ts +25 -7
  17. package/dist/src/shared/mcp/functions/handle-recall.function.d.ts +29 -0
  18. package/dist/src/shared/mcp/typings/mcp-client.interface.d.ts +30 -11
  19. package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
  20. package/dist/src/shared/wasm-codec/functions/decode-recall-result.function.d.ts +28 -0
  21. package/dist/src/shared/wasm-codec/functions/decode-scored-results.function.d.ts +14 -7
  22. package/dist/src/shared/wasm-codec/functions/encode-recall-params.function.d.ts +21 -0
  23. package/dist/src/shared/wasm-codec/functions/encode-search-params.function.d.ts +1 -1
  24. package/dist/src/shared/wasm-codec/index.d.ts +5 -2
  25. package/dist/src/shared/worker-client/classes/worker-client.class.d.ts +13 -3
  26. package/dist/src/shared/worker-client/index.d.ts +2 -1
  27. package/dist/src/shared/worker-client/typings/recall-result.model.d.ts +94 -0
  28. package/dist/src/shared/worker-client/typings/search-params.model.d.ts +2 -0
  29. package/dist/src/shared/worker-client/typings/search-result.model.d.ts +23 -7
  30. package/dist/src/shared/worker-daemon/classes/worker-daemon.class.d.ts +1 -0
  31. package/dist/wasm/fs-database/kbdb_fs_database.d.ts +18 -0
  32. package/dist/wasm/fs-database/kbdb_fs_database.js +30 -0
  33. package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  34. package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm.d.ts +2 -0
  35. package/dist/wasm/kb-worker/kbdb_worker.d.ts +38 -0
  36. package/dist/wasm/kb-worker/kbdb_worker.js +56 -0
  37. package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
  38. package/dist/wasm/kb-worker/kbdb_worker_bg.wasm.d.ts +3 -0
  39. package/dist/worker.mjs +283 -29
  40. package/dist/worker.mjs.map +4 -4
  41. package/docs/details/README.md +26 -0
  42. package/docs/details/cli.md +608 -0
  43. package/docs/details/library-api.md +406 -0
  44. package/docs/details/mcp-server.md +430 -0
  45. package/docs/details/search-and-ranking.md +457 -0
  46. package/docs/details/storage.md +529 -0
  47. package/docs/goals/agents.md +751 -0
  48. package/docs/goals/architecture.svg +198 -0
  49. package/docs/goals/cli.md +2308 -0
  50. package/docs/goals/content-composer.md +609 -0
  51. package/docs/goals/content-parser.md +279 -0
  52. package/docs/goals/database.md +1452 -0
  53. package/docs/goals/document.md +368 -0
  54. package/docs/goals/mcp.md +1467 -0
  55. package/docs/goals/overview.md +124 -0
  56. package/docs/goals/query-parser.md +271 -0
  57. package/docs/goals/query-result.md +693 -0
  58. package/docs/goals/skills.md +738 -0
  59. package/docs/goals/worker-client.md +944 -0
  60. package/docs/goals/worker-daemon.md +1447 -0
  61. package/docs/modules/overview.md +298 -0
  62. package/docs/modules/rust/fs-database/functions/document.md +48 -0
  63. package/docs/modules/rust/fs-database/functions/integrity.md +68 -0
  64. package/docs/modules/rust/fs-database/functions/io.md +87 -0
  65. package/docs/modules/rust/fs-database/functions/module.md +22 -0
  66. package/docs/modules/rust/fs-database/functions/query-exec.md +44 -0
  67. package/docs/modules/rust/fs-database/functions/section.md +59 -0
  68. package/docs/modules/rust/fs-database/indexes/btree.md +35 -0
  69. package/docs/modules/rust/fs-database/indexes/corpus.md +61 -0
  70. package/docs/modules/rust/fs-database/indexes/inverted.md +60 -0
  71. package/docs/modules/rust/fs-database/indexes/module.md +64 -0
  72. package/docs/modules/rust/fs-database/indexes/positional.md +39 -0
  73. package/docs/modules/rust/fs-database/module.md +149 -0
  74. package/docs/modules/rust/fs-database/types/catalog.md +53 -0
  75. package/docs/modules/rust/fs-database/types/module.md +12 -0
  76. package/docs/modules/rust/fs-database/types/section.md +101 -0
  77. package/docs/modules/rust/kb-worker/functions/compose.md +57 -0
  78. package/docs/modules/rust/kb-worker/functions/module.md +20 -0
  79. package/docs/modules/rust/kb-worker/functions/retrieve.md +194 -0
  80. package/docs/modules/rust/kb-worker/functions/search.md +173 -0
  81. package/docs/modules/rust/kb-worker/functions/write.md +172 -0
  82. package/docs/modules/rust/kb-worker/module.md +171 -0
  83. package/docs/modules/rust/kb-worker/types/cache.md +90 -0
  84. package/docs/modules/rust/kb-worker/types/context.md +26 -0
  85. package/docs/modules/rust/kb-worker/types/module.md +16 -0
  86. package/docs/modules/rust/kb-worker/types/status.md +29 -0
  87. package/docs/modules/rust/kb-worker/types/token.md +50 -0
  88. package/docs/modules/rust/overview.md +495 -0
  89. package/docs/modules/rust/query-parser/functions/extract.md +56 -0
  90. package/docs/modules/rust/query-parser/functions/module.md +16 -0
  91. package/docs/modules/rust/query-parser/functions/parse.md +33 -0
  92. package/docs/modules/rust/query-parser/functions/pipeline.md +103 -0
  93. package/docs/modules/rust/query-parser/functions/rank.md +85 -0
  94. package/docs/modules/rust/query-parser/module.md +136 -0
  95. package/docs/modules/rust/query-parser/types/cache.md +39 -0
  96. package/docs/modules/rust/query-parser/types/keyphrase.md +60 -0
  97. package/docs/modules/rust/query-parser/types/module.md +17 -0
  98. package/docs/modules/rust/query-parser/types/token.md +42 -0
  99. package/docs/modules/rust/shared/content-composer/functions.md +114 -0
  100. package/docs/modules/rust/shared/content-composer/module.md +147 -0
  101. package/docs/modules/rust/shared/content-composer/types.md +93 -0
  102. package/docs/modules/rust/shared/content-parser/functions.md +72 -0
  103. package/docs/modules/rust/shared/content-parser/module.md +99 -0
  104. package/docs/modules/rust/shared/content-parser/types.md +71 -0
  105. package/docs/modules/rust/shared/corpus/module.md +24 -0
  106. package/docs/modules/rust/shared/corpus/types.md +141 -0
  107. package/docs/modules/rust/shared/document/module.md +25 -0
  108. package/docs/modules/rust/shared/document/types.md +154 -0
  109. package/docs/modules/rust/shared/encode/module.md +22 -0
  110. package/docs/modules/rust/shared/encode/traits.md +304 -0
  111. package/docs/modules/rust/shared/error/module.md +28 -0
  112. package/docs/modules/rust/shared/error/types.md +302 -0
  113. package/docs/modules/rust/shared/kbid/module.md +24 -0
  114. package/docs/modules/rust/shared/kbid/types.md +147 -0
  115. package/docs/modules/rust/shared/memory/functions.md +209 -0
  116. package/docs/modules/rust/shared/memory/module.md +24 -0
  117. package/docs/modules/rust/shared/module.md +168 -0
  118. package/docs/modules/rust/shared/query/module.md +27 -0
  119. package/docs/modules/rust/shared/query/types.md +236 -0
  120. package/docs/modules/rust/shared/section/module.md +25 -0
  121. package/docs/modules/rust/shared/section/types.md +294 -0
  122. package/docs/modules/rust/shared/term/module.md +25 -0
  123. package/docs/modules/rust/shared/term/types.md +139 -0
  124. package/docs/modules/typescript/cli.md +129 -0
  125. package/docs/modules/typescript/kbdb-worker.md +135 -0
  126. package/docs/modules/typescript/overview.md +378 -0
  127. package/docs/modules/typescript/shared/cli/constants.md +23 -0
  128. package/docs/modules/typescript/shared/cli/functions.md +630 -0
  129. package/docs/modules/typescript/shared/cli/module.md +125 -0
  130. package/docs/modules/typescript/shared/cli/typings.md +172 -0
  131. package/docs/modules/typescript/shared/hash/functions.md +20 -0
  132. package/docs/modules/typescript/shared/hash/module.md +21 -0
  133. package/docs/modules/typescript/shared/mcp/classes.md +179 -0
  134. package/docs/modules/typescript/shared/mcp/functions.md +386 -0
  135. package/docs/modules/typescript/shared/mcp/module.md +160 -0
  136. package/docs/modules/typescript/shared/mcp/typings.md +522 -0
  137. package/docs/modules/typescript/shared/module.md +94 -0
  138. package/docs/modules/typescript/shared/platform/functions.md +42 -0
  139. package/docs/modules/typescript/shared/platform/module.md +25 -0
  140. package/docs/modules/typescript/shared/runtime/functions.md +26 -0
  141. package/docs/modules/typescript/shared/runtime/module.md +27 -0
  142. package/docs/modules/typescript/shared/runtime/typings.md +13 -0
  143. package/docs/modules/typescript/shared/version/module.md +27 -0
  144. package/docs/modules/typescript/shared/wasm-codec/functions.md +391 -0
  145. package/docs/modules/typescript/shared/wasm-codec/module.md +98 -0
  146. package/docs/modules/typescript/shared/worker-client/classes.md +264 -0
  147. package/docs/modules/typescript/shared/worker-client/functions.md +175 -0
  148. package/docs/modules/typescript/shared/worker-client/module.md +84 -0
  149. package/docs/modules/typescript/shared/worker-client/typings.md +508 -0
  150. package/docs/modules/typescript/shared/worker-daemon/classes.md +239 -0
  151. package/docs/modules/typescript/shared/worker-daemon/constants.md +37 -0
  152. package/docs/modules/typescript/shared/worker-daemon/functions.md +221 -0
  153. package/docs/modules/typescript/shared/worker-daemon/module.md +112 -0
  154. package/docs/modules/typescript/shared/worker-daemon/typings.md +126 -0
  155. package/docs/overview.md +188 -0
  156. package/docs/release-notes/0.1.0.md +189 -0
  157. package/docs/release-notes/0.1.1.md +46 -0
  158. package/docs/release-notes/0.1.2.md +38 -0
  159. package/docs/release-notes/0.1.3.md +42 -0
  160. package/docs/release-notes/0.2.0.md +147 -0
  161. package/docs/release-notes/README.md +9 -0
  162. package/package.json +8 -2
  163. package/src/shared/cli/functions/dispatch-command.function.ts +3 -3
  164. package/src/shared/cli/functions/format-output.function.ts +41 -34
  165. package/src/shared/cli/functions/parse-args.function.ts +7 -0
  166. package/src/shared/cli/functions/run-search.function.ts +53 -27
  167. package/src/shared/cli/index.ts +4 -1
  168. package/src/shared/cli/typings/cli-options.interface.ts +2 -0
  169. package/src/shared/cli/typings/search-display.model.ts +26 -7
  170. package/src/shared/mcp/functions/create-tool-definitions.function.ts +64 -4
  171. package/src/shared/mcp/functions/handle-recall.function.ts +66 -0
  172. package/src/shared/mcp/functions/handle-tool-call.function.ts +11 -1
  173. package/src/shared/mcp/typings/mcp-client.interface.ts +33 -15
  174. package/src/shared/version/constants/version.constant.ts +1 -1
  175. package/src/shared/wasm-codec/functions/decode-recall-result.function.ts +267 -0
  176. package/src/shared/wasm-codec/functions/decode-scored-results.function.ts +81 -27
  177. package/src/shared/wasm-codec/functions/encode-recall-params.function.ts +68 -0
  178. package/src/shared/wasm-codec/functions/encode-search-params.function.ts +4 -1
  179. package/src/shared/wasm-codec/index.ts +11 -3
  180. package/src/shared/worker-client/classes/worker-client.class.ts +24 -4
  181. package/src/shared/worker-client/index.ts +11 -1
  182. package/src/shared/worker-client/typings/recall-result.model.ts +98 -0
  183. package/src/shared/worker-client/typings/search-params.model.ts +2 -0
  184. package/src/shared/worker-client/typings/search-result.model.ts +24 -7
  185. package/src/shared/worker-daemon/classes/worker-daemon.class.ts +25 -4
  186. package/src/wasm/fs-database/kbdb_fs_database.d.ts +18 -0
  187. package/src/wasm/fs-database/kbdb_fs_database.js +30 -0
  188. package/src/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  189. package/src/wasm/fs-database/kbdb_fs_database_bg.wasm.d.ts +2 -0
  190. package/src/wasm/kb-worker/kbdb_worker.d.ts +38 -0
  191. package/src/wasm/kb-worker/kbdb_worker.js +56 -0
  192. package/src/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
  193. package/src/wasm/kb-worker/kbdb_worker_bg.wasm.d.ts +3 -0
@@ -0,0 +1,147 @@
1
+ # 0.2.0
2
+
3
+ *Minor release -- 2026-06-21*
4
+
5
+ Adds progressive context recall, paginated search
6
+ results with rich metadata, and a bidirectional
7
+ reference graph. These features give AI agents
8
+ the ability to explore related content across
9
+ sections and documents without loading everything
10
+ at once.
11
+
12
+ ---
13
+
14
+ ## New Features
15
+
16
+ - **Recall with layered context (depths 0--3)** --
17
+ New `recall` command (CLI), MCP tool, and IPC
18
+ method. Accepts a `kbid` (or `kbids` for batch)
19
+ and a `depth` parameter that controls how much
20
+ context is returned:
21
+ - Depth 0: section content, heading, type, docids
22
+ - Depth 1: adds parent documents and
23
+ back-references
24
+ - Depth 2: adds sibling sections and forward
25
+ references
26
+ - Depth 3: referenced sections include full
27
+ content
28
+
29
+ - **Paginated search results** -- Search now
30
+ returns a `PagedSearchResult` envelope:
31
+ `{ items, total, offset, limit, has_more }`.
32
+ New `--offset` / `-o` CLI flag. The `offset`
33
+ parameter is available in MCP and IPC as well.
34
+
35
+ - **Rich search result metadata** -- Each search
36
+ result item now includes `heading`, `type`,
37
+ `snippet` (KWIC ~150 chars around matched terms),
38
+ `matched_terms`, and `docids`. Replaces the
39
+ previous `matches: [{term, frequency}]` format.
40
+
41
+ - **Bidirectional reference graph** -- New
42
+ `references.idx` tracks content-marker references
43
+ (`$(link: ...)`, `$(doclink: ...)`, etc.) between
44
+ sections. New WASM exports `db_get_forward_refs`
45
+ and `db_get_back_refs`. Built automatically on
46
+ `learn`/`update`, cleaned on `unlearn`,
47
+ regenerated on `rebuild`.
48
+
49
+ ---
50
+
51
+ ## Improvements
52
+
53
+ - **KWIC snippet generation** -- New
54
+ `extract_kwic_snippet()` in the Rust engine
55
+ produces ~150-character context windows around
56
+ matched terms with case-insensitive matching,
57
+ Unicode-safe boundaries, and ellipsis markers.
58
+
59
+ - **MCP search strips score** -- The MCP layer
60
+ omits the `score` field from search results.
61
+ Rank order is the signal for AI agents; raw
62
+ scores are kept in CLI and IPC output for
63
+ debugging.
64
+
65
+ - **Tool annotations** -- All 18 MCP tool
66
+ definitions now include `openWorldHint: false`,
67
+ `readOnlyHint`, `destructiveHint`, and
68
+ `idempotentHint` annotations per the MCP spec.
69
+
70
+ - **Text format paging** -- CLI text output now
71
+ shows a paging footer:
72
+ `Showing 1--20 of 42 results. Use --offset 20 to see more.`
73
+
74
+ - **MCP tool descriptions** -- `search` guides
75
+ agents to use `recall` for full content.
76
+ `retrieve` updated to prefer `recall`.
77
+
78
+ - **Documentation included in package** -- Both
79
+ npm and JSR packages now ship `docs/details/`,
80
+ `docs/goals/`, `docs/modules/`,
81
+ `docs/release-notes/`, and `docs/overview.md`.
82
+
83
+ ---
84
+
85
+ ## Testing
86
+
87
+ - **383 e2e assertions (Node.js), 378 (Deno)** --
88
+ up from ~300. All pass with 0 failures.
89
+
90
+ - **Recall depth testing** -- Cross-referenced
91
+ test data (sections with `$(link: ...)` markers)
92
+ validates depth 0--3 field presence across CLI,
93
+ MCP, and worker IPC.
94
+
95
+ - **Response shape validation** -- Every field in
96
+ the public API is asserted: paged search envelope,
97
+ search item metadata, recall depth fields, skill
98
+ and agent CRUD responses, MCP prompts protocol,
99
+ resource templates, and completions.
100
+
101
+ - **Rust unit tests** -- 21+ new tests for KWIC
102
+ snippet extraction, matched-terms ordering,
103
+ paged result pagination, and section matching.
104
+
105
+ ---
106
+
107
+ ## Breaking Changes
108
+
109
+ - **Search result shape changed** -- Results are
110
+ now wrapped in a `PagedSearchResult` envelope.
111
+ Code that expected a flat array of results must
112
+ read `result.items` instead. Each item's
113
+ `matches` array is replaced by `snippet`,
114
+ `matched_terms`, `heading`, `type`, and `docids`.
115
+
116
+ - **Codec exports renamed** -- `decodeScoredResults`
117
+ is now `decodePagedSearchResult`. `ScoredResult`
118
+ is now `SectionMatch`.
119
+
120
+ ---
121
+
122
+ ## Internal
123
+
124
+ - Rust engine: reference tracking wired into
125
+ `db_add_section`, `db_update_section`, and
126
+ `db_remove_section`. `worker_search` parses
127
+ 4-part format (query/mode/limit/offset).
128
+ `worker_recall` WASM export added.
129
+ - `content-creator` renamed to `content-composer`
130
+ across all code and docs.
131
+ - WASM binaries rebuilt (~8KB and ~35KB larger).
132
+
133
+ ---
134
+
135
+ ## Upgrade
136
+
137
+ ```sh
138
+ # Node.js
139
+ npm install -g @dikolab/kbdb@0.2.0
140
+
141
+ # Deno
142
+ deno install -Agf jsr:@dikolab/kbdb/cli
143
+ ```
144
+
145
+ Review the **Breaking Changes** section above if
146
+ you use the library API or parse search results
147
+ programmatically.
@@ -0,0 +1,9 @@
1
+ # Release Notes
2
+
3
+ ## Releases
4
+
5
+ - [0.2.0](0.2.0.md) -- Recall, paginated search, reference graph
6
+ - [0.1.3](0.1.3.md) -- Include WASM binaries in JSR package
7
+ - [0.1.2](0.1.2.md) -- Fix WASM loading from JSR
8
+ - [0.1.1](0.1.1.md) -- Deno type fix, build pipeline cleanup
9
+ - [0.1.0](0.1.0.md) -- Initial release
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dikolab/kbdb",
3
- "version": "0.1.6",
3
+ "version": "0.2.0",
4
4
  "description": "CLI tool and MCP server for a file-based knowledge base database",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -24,7 +24,13 @@
24
24
  "mod.ts",
25
25
  "src/**/*",
26
26
  "!src/**/*.spec.ts",
27
- "LICENSE"
27
+ "LICENSE",
28
+ "README.md",
29
+ "docs/details/**/*.md",
30
+ "docs/goals/**",
31
+ "docs/modules/**/*.md",
32
+ "docs/release-notes/**/*.md",
33
+ "docs/overview.md"
28
34
  ],
29
35
  "type": "module",
30
36
  "main": "./dist/mod.cjs",
@@ -1,6 +1,6 @@
1
1
  import type { CliOptions } from '../typings/cli-options.interface.ts';
2
2
  import type { CommandResult } from '../typings/command-result.model.ts';
3
- import type { SearchDisplay } from '../typings/search-display.model.ts';
3
+ import type { PagedSearchDisplay } from '../typings/search-display.model.ts';
4
4
  import type { LearnIO } from './run-learn.function.ts';
5
5
  import type { SearchClient } from './run-search.function.ts';
6
6
  import type { LearnClient } from './run-learn.function.ts';
@@ -323,10 +323,10 @@ async function handleDbMigrate(
323
323
  */
324
324
  async function hydrateSearchPreviews(
325
325
  client: ContentClient,
326
- results: SearchDisplay[],
326
+ paged: PagedSearchDisplay,
327
327
  ): Promise<void> {
328
328
  await Promise.all(
329
- results.map(async (result) => {
329
+ paged.items.map(async (result) => {
330
330
  try {
331
331
  const contentResult = await client.content([result.kbid]);
332
332
  result.preview = contentResult.data;
@@ -1,63 +1,70 @@
1
1
  import type { OutputFormat } from '../typings/cli-options.interface.ts';
2
- import type { SearchDisplay } from '../typings/search-display.model.ts';
2
+ import type { PagedSearchDisplay } from '../typings/search-display.model.ts';
3
3
 
4
4
  /**
5
- * Serialises an array of search results into the requested output
5
+ * Serialises a paged search result into the requested output
6
6
  * format string.
7
7
  *
8
- * - `'json'` -- pretty-printed JSON array
9
- * - `'text'` -- numbered human-readable list
10
- * - `'mcp'` -- JSON envelope compatible with MCP protocol consumers
8
+ * - `'json'` -- pretty-printed JSON envelope
9
+ * - `'text'` -- numbered human-readable list with paging footer
10
+ * - `'mcp'` -- JSON envelope compatible with MCP protocol
11
11
  *
12
- * @param results - ranked search results to format
12
+ * @param paged - paginated search results to format
13
13
  * @param format - target output format
14
14
  * @returns formatted string ready for stdout
15
15
  */
16
16
  export function formatOutput(
17
- results: SearchDisplay[],
17
+ paged: PagedSearchDisplay,
18
18
  format: OutputFormat,
19
19
  ): string {
20
20
  switch (format) {
21
21
  case 'json':
22
- return JSON.stringify(results, null, 2);
22
+ return JSON.stringify(paged, null, 2);
23
23
  case 'text':
24
- return formatText(results);
24
+ return formatText(paged);
25
25
  case 'mcp':
26
- return formatMcp(results);
26
+ return formatMcp(paged);
27
27
  }
28
28
  }
29
29
 
30
- /**
31
- * Renders results as a numbered human-readable list.
32
- *
33
- * @param results - search results to render
34
- */
35
- function formatText(results: SearchDisplay[]): string {
36
- if (results.length === 0) return 'No results found.';
37
- return results
38
- .map(
39
- (r, i) =>
40
- `${String(i + 1)}. [${r.kbid}] ` +
41
- `(score: ${r.score.toFixed(4)})\n` +
42
- ` ${r.preview}\n` +
43
- ` matches: ${r.matches.map((m) => m.term).join(', ')}`,
44
- )
30
+ function formatText(paged: PagedSearchDisplay): string {
31
+ if (paged.items.length === 0) return 'No results found.';
32
+ const start = paged.offset + 1;
33
+ const end = paged.offset + paged.items.length;
34
+
35
+ const lines = paged.items
36
+ .map((r, i) => {
37
+ const num = paged.offset + i + 1;
38
+ const heading = r.heading ?? '(untitled)';
39
+ const terms = r.matched_terms.join(', ');
40
+ return (
41
+ `${String(num)}. [${r.kbid}] ${heading}` +
42
+ ` (score: ${r.score.toFixed(4)})\n` +
43
+ ` ${r.snippet || r.preview || '(no snippet)'}\n` +
44
+ ` type: ${r.type}` +
45
+ ` terms: ${terms}`
46
+ );
47
+ })
45
48
  .join('\n\n');
49
+
50
+ const footer =
51
+ `\nShowing ${String(start)}-${String(end)}` +
52
+ ` of ${String(paged.total)} results`;
53
+ const hint = paged.has_more
54
+ ? `\nUse --offset ${String(end)} to see more`
55
+ : '';
56
+
57
+ return lines + footer + hint;
46
58
  }
47
59
 
48
- /**
49
- * Renders results as a JSON envelope for MCP protocol consumers.
50
- *
51
- * @param results - search results to render
52
- */
53
- function formatMcp(results: SearchDisplay[]): string {
60
+ function formatMcp(paged: PagedSearchDisplay): string {
54
61
  return JSON.stringify({
55
62
  type: 'text',
56
- text: results
63
+ text: paged.items
57
64
  .map(
58
65
  (r) =>
59
- `[${r.kbid}] score=${r.score.toFixed(4)}` +
60
- ` — ${r.preview}`,
66
+ `[${r.kbid}] ${r.heading ?? '(untitled)'}` +
67
+ ` — ${r.snippet || r.preview}`,
61
68
  )
62
69
  .join('\n'),
63
70
  });
@@ -87,6 +87,13 @@ export function parseArgs(argv: string[]): CliOptions {
87
87
  options.limit =
88
88
  parseInt(argv[++i] ?? '', 10) || DEFAULT_LIMIT;
89
89
  break;
90
+ case '--offset':
91
+ case '-o':
92
+ options.offset = Math.max(
93
+ 0,
94
+ parseInt(argv[++i] ?? '', 10) || 0,
95
+ );
96
+ break;
90
97
  case '--title':
91
98
  options.title = argv[++i];
92
99
  break;
@@ -1,5 +1,5 @@
1
1
  import type { CliOptions } from '../typings/cli-options.interface.ts';
2
- import type { SearchDisplay } from '../typings/search-display.model.ts';
2
+ import type { PagedSearchDisplay } from '../typings/search-display.model.ts';
3
3
 
4
4
  /**
5
5
  * Minimal client interface required by `runSearch`.
@@ -9,54 +9,80 @@ import type { SearchDisplay } from '../typings/search-display.model.ts';
9
9
  */
10
10
  export interface SearchClient {
11
11
  /**
12
- * Searches the knowledge base and returns ranked results.
12
+ * Searches the knowledge base and returns paginated results.
13
13
  *
14
- * @param params - query, mode, and result limit
14
+ * @param params - query, mode, limit, and offset
15
15
  */
16
16
  search(params: {
17
17
  query: string;
18
18
  mode?: string;
19
19
  limit?: number;
20
- }): Promise<
21
- {
22
- kbid: string;
23
- score: number;
24
- readonly matches: readonly {
25
- readonly term: string;
26
- readonly frequency: number;
27
- }[];
28
- }[]
29
- >;
20
+ offset?: number;
21
+ }): Promise<{
22
+ readonly items: readonly {
23
+ readonly kbid: string;
24
+ readonly heading: string | null;
25
+ readonly type: string;
26
+ readonly docids: readonly string[];
27
+ readonly score: number;
28
+ readonly snippet: string;
29
+ readonly matched_terms: readonly string[];
30
+ }[];
31
+ readonly total: number;
32
+ readonly offset: number;
33
+ readonly limit: number;
34
+ readonly has_more: boolean;
35
+ }>;
30
36
  }
31
37
 
32
38
  /**
33
- * Executes a search query via the provided client and maps the raw
34
- * daemon results to the `SearchDisplay` format used by the CLI.
39
+ * Executes a search query via the provided client and maps the
40
+ * daemon results to the `PagedSearchDisplay` format used by the
41
+ * CLI.
35
42
  *
36
- * Returns an empty array without calling the client when `options.args`
37
- * contains no query terms.
43
+ * Returns an empty paged result without calling the client when
44
+ * `options.args` contains no query terms.
38
45
  *
39
46
  * @param client - search client to delegate to
40
- * @param options - parsed CLI options supplying query args and search
41
- * parameters
47
+ * @param options - parsed CLI options supplying query args and
48
+ * search parameters
42
49
  */
43
50
  export async function runSearch(
44
51
  client: SearchClient,
45
52
  options: CliOptions,
46
- ): Promise<SearchDisplay[]> {
53
+ ): Promise<PagedSearchDisplay> {
47
54
  const query = options.args.join(' ').trim();
48
- if (!query) return [];
55
+ if (!query) {
56
+ return {
57
+ items: [],
58
+ total: 0,
59
+ offset: 0,
60
+ limit: options.limit,
61
+ has_more: false,
62
+ };
63
+ }
49
64
 
50
65
  const results = await client.search({
51
66
  query,
52
67
  mode: options.mode,
53
68
  limit: options.limit,
69
+ offset: options.offset,
54
70
  });
55
71
 
56
- return results.map((r) => ({
57
- kbid: r.kbid,
58
- score: r.score,
59
- preview: '',
60
- matches: r.matches,
61
- }));
72
+ return {
73
+ items: results.items.map((r) => ({
74
+ kbid: r.kbid,
75
+ heading: r.heading,
76
+ type: r.type,
77
+ docids: r.docids,
78
+ score: r.score,
79
+ snippet: r.snippet,
80
+ matched_terms: r.matched_terms,
81
+ preview: '',
82
+ })),
83
+ total: results.total,
84
+ offset: results.offset,
85
+ limit: results.limit,
86
+ has_more: results.has_more,
87
+ };
62
88
  }
@@ -23,7 +23,10 @@ export type {
23
23
  SearchMode,
24
24
  } from './typings/cli-options.interface.ts';
25
25
  export type { LearnResult } from './typings/learn-result.model.ts';
26
- export type { SearchDisplay } from './typings/search-display.model.ts';
26
+ export type {
27
+ SearchDisplay,
28
+ PagedSearchDisplay,
29
+ } from './typings/search-display.model.ts';
27
30
  export type { SearchClient } from './functions/run-search.function.ts';
28
31
  export type { LearnClient } from './functions/run-learn.function.ts';
29
32
  export type {
@@ -31,6 +31,8 @@ export interface CliOptions {
31
31
  mode: SearchMode;
32
32
  /** Maximum number of results to return. Defaults to 20. */
33
33
  limit: number;
34
+ /** Number of results to skip for pagination. */
35
+ offset?: number;
34
36
  /** Section title for learn command. */
35
37
  title?: string;
36
38
  /** Section description for learn command. */
@@ -2,16 +2,35 @@
2
2
  export interface SearchDisplay {
3
3
  /** Knowledge-base identifier of the matched section. */
4
4
  kbid: string;
5
+ /** Section heading, or null when untitled. */
6
+ heading: string | null;
7
+ /** MIME type of the section content. */
8
+ type: string;
9
+ /** Document IDs this section belongs to. */
10
+ docids: readonly string[];
5
11
  /** Relevance score assigned by the ranking engine. */
6
12
  score: number;
13
+ /** KWIC snippet from the WASM engine (~150 chars). */
14
+ snippet: string;
15
+ /** Query terms that matched within this section. */
16
+ matched_terms: readonly string[];
7
17
  /**
8
- * Short excerpt from the section content.
9
- * Empty string when no preview text is available.
18
+ * CLI-side truncated content preview for terminal display.
19
+ * Populated when `--content` / `-c` is used.
10
20
  */
11
21
  preview: string;
12
- /** Terms that matched within this section and their frequencies. */
13
- readonly matches: readonly {
14
- readonly term: string;
15
- readonly frequency: number;
16
- }[];
22
+ }
23
+
24
+ /** Paginated search display envelope for CLI output. */
25
+ export interface PagedSearchDisplay {
26
+ /** Search results for the current page. */
27
+ items: SearchDisplay[];
28
+ /** Total number of matches across all pages. */
29
+ total: number;
30
+ /** Number of results skipped. */
31
+ offset: number;
32
+ /** Maximum results per page. */
33
+ limit: number;
34
+ /** Whether more results exist beyond this page. */
35
+ has_more: boolean;
17
36
  }