@dikolab/kbdb 0.5.0 → 0.6.1

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 (224) hide show
  1. package/CLA.md +68 -0
  2. package/LICENSE +676 -12
  3. package/LICENSING.md +58 -0
  4. package/README.md +50 -25
  5. package/README.md.bak +322 -0
  6. package/dist/README.md +322 -0
  7. package/dist/{chunk-BJXEVALU.mjs → chunk-QLJ33C74.mjs} +44 -44
  8. package/dist/chunk-QLJ33C74.mjs.map +7 -0
  9. package/dist/cli.cjs +550 -232
  10. package/dist/cli.cjs.map +4 -4
  11. package/dist/cli.d.ts +0 -8
  12. package/dist/cli.mjs +483 -154
  13. package/dist/cli.mjs.map +4 -4
  14. package/dist/kbdb-worker.cjs +36 -5
  15. package/dist/kbdb-worker.cjs.map +3 -3
  16. package/dist/mod.cjs +89 -30
  17. package/dist/mod.cjs.map +4 -4
  18. package/dist/mod.mjs +88 -30
  19. package/dist/mod.mjs.map +4 -4
  20. package/dist/src/cli.d.ts +0 -8
  21. package/dist/src/shared/cli/constants/defaults.constant.d.ts +1 -1
  22. package/dist/src/shared/cli/constants/recfile-command-field-map.constant.d.ts +8 -0
  23. package/dist/src/shared/cli/constants/recfile-field-maps.constant.d.ts +21 -0
  24. package/dist/src/shared/cli/functions/compute-directory-level.function.d.ts +14 -0
  25. package/dist/src/shared/cli/functions/dispatch-command.function.d.ts +2 -28
  26. package/dist/src/shared/cli/functions/format-command-output.function.d.ts +14 -0
  27. package/dist/src/shared/cli/functions/format-db-not-found.function.d.ts +20 -0
  28. package/dist/src/shared/cli/functions/format-output.function.d.ts +1 -0
  29. package/dist/src/shared/cli/functions/format-recfile-output.function.d.ts +11 -0
  30. package/dist/src/shared/cli/functions/render-recfile-value.function.d.ts +11 -0
  31. package/dist/src/shared/cli/functions/resolve-db-dir.function.d.ts +24 -0
  32. package/dist/src/shared/cli/functions/resolve-recfile-key.function.d.ts +9 -0
  33. package/dist/src/shared/cli/functions/run-db-path.function.d.ts +10 -0
  34. package/dist/src/shared/cli/functions/run-export.function.d.ts +8 -4
  35. package/dist/src/shared/cli/functions/run-import.function.d.ts +4 -0
  36. package/dist/src/shared/cli/functions/run-learn.function.d.ts +12 -0
  37. package/dist/src/shared/cli/index.d.ts +4 -1
  38. package/dist/src/shared/cli/typings/cli-options.interface.d.ts +9 -2
  39. package/dist/src/shared/cli/typings/db-resolution.interface.d.ts +9 -0
  40. package/dist/src/shared/cli/typings/recfile-field-map.type.d.ts +10 -0
  41. package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
  42. package/dist/src/shared/wasm-codec/functions/decode-option-u8.function.d.ts +9 -0
  43. package/dist/src/shared/wasm-codec/functions/decode-section-records.function.d.ts +4 -0
  44. package/dist/src/shared/wasm-codec/functions/encode-add-section-params.function.d.ts +2 -45
  45. package/dist/src/shared/wasm-codec/functions/encode-update-section-params.function.d.ts +10 -1
  46. package/dist/src/shared/wasm-codec/index.d.ts +1 -1
  47. package/dist/src/shared/wasm-codec/typings/add-section-input.model.d.ts +6 -0
  48. package/dist/src/shared/wasm-codec/typings/section-record-trailing.model.d.ts +5 -0
  49. package/dist/src/shared/wasm-codec/typings/section-record.model.d.ts +5 -0
  50. package/dist/src/shared/worker-client/functions/build-deno-permissions.function.d.ts +11 -0
  51. package/dist/src/shared/worker-client/functions/read-crash-reason.function.d.ts +9 -0
  52. package/dist/src/shared/worker-client/functions/resolve-spawn-script.function.d.ts +6 -0
  53. package/dist/src/shared/worker-client/functions/spawn-daemon.function.d.ts +1 -1
  54. package/dist/src/shared/worker-client/typings/section.model.d.ts +5 -0
  55. package/dist/src/shared/worker-client/typings/worker-client-options.interface.d.ts +0 -6
  56. package/dist/src/shared/worker-daemon/functions/count-files.function.d.ts +12 -0
  57. package/dist/src/shared/worker-daemon/functions/handle-import.function.d.ts +2 -0
  58. package/dist/src/shared/worker-daemon/functions/handle-read-ops.function.d.ts +8 -0
  59. package/dist/src/shared/worker-daemon/functions/validate-daemon-path.function.d.ts +15 -0
  60. package/dist/src/worker.d.ts +0 -7
  61. package/dist/wasm/default-embedding/kbdb_default_embedding_bg.wasm +0 -0
  62. package/dist/wasm/default-embedding/package.json +1 -1
  63. package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  64. package/dist/wasm/fs-database/package.json +1 -1
  65. package/dist/wasm/fs-migration/package.json +1 -1
  66. package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
  67. package/dist/wasm/kb-worker/package.json +1 -1
  68. package/dist/wasm/query-parser/kbdb_query_parser_bg.wasm +0 -0
  69. package/dist/wasm/query-parser/package.json +1 -1
  70. package/dist/worker.d.ts +0 -7
  71. package/dist/worker.mjs +37 -6
  72. package/dist/worker.mjs.map +3 -3
  73. package/package.json +11 -10
  74. package/dist/chunk-BJXEVALU.mjs.map +0 -7
  75. package/dist/src/shared/cli/functions/resolve-raw-db-path.function.d.ts +0 -10
  76. package/docs/details/README.md +0 -30
  77. package/docs/details/agent-tooling.md +0 -132
  78. package/docs/details/cli.md +0 -777
  79. package/docs/details/knowledge-base.md +0 -180
  80. package/docs/details/library-api.md +0 -495
  81. package/docs/details/mcp-server.md +0 -482
  82. package/docs/details/search-and-ranking.md +0 -575
  83. package/docs/details/storage.md +0 -531
  84. package/docs/goals/agents.md +0 -751
  85. package/docs/goals/architecture.svg +0 -198
  86. package/docs/goals/auto-capture.md +0 -378
  87. package/docs/goals/benchmarking.md +0 -296
  88. package/docs/goals/cli.md +0 -2654
  89. package/docs/goals/concurrency.md +0 -259
  90. package/docs/goals/content-composer.md +0 -609
  91. package/docs/goals/content-parser.md +0 -279
  92. package/docs/goals/database.md +0 -1679
  93. package/docs/goals/document.md +0 -368
  94. package/docs/goals/hybrid-search.md +0 -465
  95. package/docs/goals/mcp.md +0 -1541
  96. package/docs/goals/overview.md +0 -124
  97. package/docs/goals/query-parser.md +0 -373
  98. package/docs/goals/query-result.md +0 -860
  99. package/docs/goals/semantic-dedup.md +0 -233
  100. package/docs/goals/skills.md +0 -810
  101. package/docs/goals/sync.md +0 -217
  102. package/docs/goals/worker-client.md +0 -1005
  103. package/docs/goals/worker-daemon.md +0 -1547
  104. package/docs/modules/overview.md +0 -319
  105. package/docs/modules/rust/embedding/module.md +0 -91
  106. package/docs/modules/rust/fs-database/functions/document.md +0 -48
  107. package/docs/modules/rust/fs-database/functions/integrity.md +0 -79
  108. package/docs/modules/rust/fs-database/functions/io.md +0 -87
  109. package/docs/modules/rust/fs-database/functions/module.md +0 -22
  110. package/docs/modules/rust/fs-database/functions/query-exec.md +0 -44
  111. package/docs/modules/rust/fs-database/functions/section.md +0 -76
  112. package/docs/modules/rust/fs-database/indexes/btree.md +0 -35
  113. package/docs/modules/rust/fs-database/indexes/corpus.md +0 -61
  114. package/docs/modules/rust/fs-database/indexes/inverted.md +0 -60
  115. package/docs/modules/rust/fs-database/indexes/module.md +0 -64
  116. package/docs/modules/rust/fs-database/indexes/positional.md +0 -39
  117. package/docs/modules/rust/fs-database/indexes/vectors.md +0 -110
  118. package/docs/modules/rust/fs-database/module.md +0 -150
  119. package/docs/modules/rust/fs-database/types/catalog.md +0 -53
  120. package/docs/modules/rust/fs-database/types/module.md +0 -12
  121. package/docs/modules/rust/fs-database/types/section.md +0 -127
  122. package/docs/modules/rust/kb-worker/functions/compose.md +0 -57
  123. package/docs/modules/rust/kb-worker/functions/module.md +0 -20
  124. package/docs/modules/rust/kb-worker/functions/retrieve.md +0 -194
  125. package/docs/modules/rust/kb-worker/functions/search.md +0 -173
  126. package/docs/modules/rust/kb-worker/functions/write.md +0 -172
  127. package/docs/modules/rust/kb-worker/module.md +0 -171
  128. package/docs/modules/rust/kb-worker/types/cache.md +0 -90
  129. package/docs/modules/rust/kb-worker/types/context.md +0 -26
  130. package/docs/modules/rust/kb-worker/types/module.md +0 -16
  131. package/docs/modules/rust/kb-worker/types/status.md +0 -29
  132. package/docs/modules/rust/kb-worker/types/token.md +0 -50
  133. package/docs/modules/rust/overview.md +0 -531
  134. package/docs/modules/rust/query-parser/functions/extract.md +0 -56
  135. package/docs/modules/rust/query-parser/functions/module.md +0 -18
  136. package/docs/modules/rust/query-parser/functions/parse.md +0 -33
  137. package/docs/modules/rust/query-parser/functions/pipeline.md +0 -9
  138. package/docs/modules/rust/query-parser/functions/rank.md +0 -85
  139. package/docs/modules/rust/query-parser/module.md +0 -131
  140. package/docs/modules/rust/query-parser/types/cache.md +0 -39
  141. package/docs/modules/rust/query-parser/types/keyphrase.md +0 -71
  142. package/docs/modules/rust/query-parser/types/module.md +0 -18
  143. package/docs/modules/rust/query-parser/types/token.md +0 -46
  144. package/docs/modules/rust/shared/content-composer/functions.md +0 -114
  145. package/docs/modules/rust/shared/content-composer/module.md +0 -147
  146. package/docs/modules/rust/shared/content-composer/types.md +0 -93
  147. package/docs/modules/rust/shared/content-parser/functions.md +0 -72
  148. package/docs/modules/rust/shared/content-parser/module.md +0 -99
  149. package/docs/modules/rust/shared/content-parser/types.md +0 -71
  150. package/docs/modules/rust/shared/corpus/module.md +0 -24
  151. package/docs/modules/rust/shared/corpus/types.md +0 -141
  152. package/docs/modules/rust/shared/document/module.md +0 -25
  153. package/docs/modules/rust/shared/document/types.md +0 -154
  154. package/docs/modules/rust/shared/encode/module.md +0 -22
  155. package/docs/modules/rust/shared/encode/traits.md +0 -304
  156. package/docs/modules/rust/shared/error/module.md +0 -28
  157. package/docs/modules/rust/shared/error/types.md +0 -302
  158. package/docs/modules/rust/shared/kbid/module.md +0 -24
  159. package/docs/modules/rust/shared/kbid/types.md +0 -147
  160. package/docs/modules/rust/shared/memory/functions.md +0 -209
  161. package/docs/modules/rust/shared/memory/module.md +0 -24
  162. package/docs/modules/rust/shared/module.md +0 -196
  163. package/docs/modules/rust/shared/pipeline/functions.md +0 -141
  164. package/docs/modules/rust/shared/pipeline/module.md +0 -62
  165. package/docs/modules/rust/shared/pipeline/types.md +0 -43
  166. package/docs/modules/rust/shared/query/module.md +0 -27
  167. package/docs/modules/rust/shared/query/types.md +0 -236
  168. package/docs/modules/rust/shared/section/module.md +0 -25
  169. package/docs/modules/rust/shared/section/types.md +0 -294
  170. package/docs/modules/rust/shared/term/module.md +0 -25
  171. package/docs/modules/rust/shared/term/types.md +0 -139
  172. package/docs/modules/typescript/cli.md +0 -131
  173. package/docs/modules/typescript/kbdb-worker.md +0 -150
  174. package/docs/modules/typescript/overview.md +0 -400
  175. package/docs/modules/typescript/shared/auto-capture/module.md +0 -73
  176. package/docs/modules/typescript/shared/cli/constants.md +0 -23
  177. package/docs/modules/typescript/shared/cli/functions.md +0 -809
  178. package/docs/modules/typescript/shared/cli/module.md +0 -138
  179. package/docs/modules/typescript/shared/cli/typings.md +0 -197
  180. package/docs/modules/typescript/shared/embedding/functions.md +0 -200
  181. package/docs/modules/typescript/shared/embedding/module.md +0 -77
  182. package/docs/modules/typescript/shared/embedding/typings.md +0 -124
  183. package/docs/modules/typescript/shared/hash/functions.md +0 -20
  184. package/docs/modules/typescript/shared/hash/module.md +0 -21
  185. package/docs/modules/typescript/shared/log/constants.md +0 -82
  186. package/docs/modules/typescript/shared/log/functions.md +0 -131
  187. package/docs/modules/typescript/shared/log/module.md +0 -153
  188. package/docs/modules/typescript/shared/log/typings.md +0 -82
  189. package/docs/modules/typescript/shared/mcp/classes.md +0 -179
  190. package/docs/modules/typescript/shared/mcp/functions.md +0 -386
  191. package/docs/modules/typescript/shared/mcp/module.md +0 -160
  192. package/docs/modules/typescript/shared/mcp/typings.md +0 -529
  193. package/docs/modules/typescript/shared/module.md +0 -110
  194. package/docs/modules/typescript/shared/platform/functions.md +0 -42
  195. package/docs/modules/typescript/shared/platform/module.md +0 -25
  196. package/docs/modules/typescript/shared/runtime/functions.md +0 -26
  197. package/docs/modules/typescript/shared/runtime/module.md +0 -27
  198. package/docs/modules/typescript/shared/runtime/typings.md +0 -13
  199. package/docs/modules/typescript/shared/version/module.md +0 -27
  200. package/docs/modules/typescript/shared/wasm-codec/functions.md +0 -391
  201. package/docs/modules/typescript/shared/wasm-codec/module.md +0 -98
  202. package/docs/modules/typescript/shared/worker-client/classes.md +0 -264
  203. package/docs/modules/typescript/shared/worker-client/functions.md +0 -175
  204. package/docs/modules/typescript/shared/worker-client/module.md +0 -92
  205. package/docs/modules/typescript/shared/worker-client/typings.md +0 -511
  206. package/docs/modules/typescript/shared/worker-daemon/classes.md +0 -239
  207. package/docs/modules/typescript/shared/worker-daemon/constants.md +0 -37
  208. package/docs/modules/typescript/shared/worker-daemon/functions.md +0 -234
  209. package/docs/modules/typescript/shared/worker-daemon/module.md +0 -118
  210. package/docs/modules/typescript/shared/worker-daemon/typings.md +0 -132
  211. package/docs/overview.md +0 -191
  212. package/docs/release-notes/0.1.0.md +0 -189
  213. package/docs/release-notes/0.1.1.md +0 -46
  214. package/docs/release-notes/0.1.2.md +0 -38
  215. package/docs/release-notes/0.1.3.md +0 -42
  216. package/docs/release-notes/0.2.0.md +0 -147
  217. package/docs/release-notes/0.3.0.md +0 -89
  218. package/docs/release-notes/0.3.1.md +0 -121
  219. package/docs/release-notes/0.3.2.md +0 -64
  220. package/docs/release-notes/0.4.0.md +0 -80
  221. package/docs/release-notes/0.4.1.md +0 -149
  222. package/docs/release-notes/0.4.3.md +0 -60
  223. package/docs/release-notes/0.5.0.md +0 -41
  224. package/docs/release-notes/README.md +0 -16
@@ -1,609 +0,0 @@
1
- # Content Composer -- Content Composition
2
-
3
- *A composition engine that resolves sections and
4
- documents from identifiers, processes markers
5
- recursively, and produces a single rendered Markdown
6
- document.*
7
-
8
- ## Goal
9
-
10
- The content composer takes one or more identifiers
11
- (kbids or docids, mixed) and produces a composed
12
- Markdown document. It resolves each identifier to
13
- its sections, follows embedding and link markers
14
- recursively, and renders everything into a single
15
- UTF-8 Markdown string with named anchors for
16
- cross-referencing.
17
-
18
- This is the **rendering engine** -- it performs what
19
- the marker descriptions in [Document](document.md)
20
- specify as "at render time" behaviour. It is distinct
21
- from the [Content Parser](content-parser.md) (which
22
- extracts markers as structured data) and the
23
- [Document](document.md) spec (which defines marker
24
- syntax and semantics).
25
-
26
- The rendering logic lives in the `content-composer`
27
- module in the `kbdb-shared` Rust crate as pure
28
- composition -- no I/O. Resolution and fetching of
29
- sections from the database is handled by `kb-worker`.
30
-
31
- ## CLI Command
32
-
33
- ```
34
- kbdb content <id>... [--db <path>]
35
- ```
36
-
37
- Compose and output a rendered Markdown document from
38
- one or more knowledge base identifiers.
39
-
40
- **Arguments:**
41
- - `<id>...` -- one or more kbid or docid identifiers.
42
- The two types can be mixed freely. Each identifier
43
- is resolved via trial-and-error: the system first
44
- attempts to look up the identifier as a kbid
45
- (section); if not found, it tries as a docid
46
- (document). If neither matches, an error is
47
- reported for that identifier.
48
-
49
- **Output:**
50
- - **stdout**: UTF-8 Markdown text. The composed
51
- document contains all requested sections and
52
- documents with markers rendered, named anchors
53
- assigned, and cross-references linked.
54
- - **stderr**: errors only.
55
-
56
- **Exit code:** `0` on success, `1` on error.
57
-
58
- **Delegation chain:**
59
- ```
60
- src/cli.ts parseArgs()
61
- -> ensureDb() / findDb()
62
- -> createWorkerClient({ contextPath })
63
- -> runContent(client, options)
64
- -> client.content(ids)
65
- -> IPC -> worker daemon
66
- -> kb-worker.wasm
67
- -> fs-database.wasm (fetch)
68
- -> kbdb-shared content-composer
69
- (compose_content)
70
- -> stdout
71
- ```
72
-
73
- ## MCP Tool
74
-
75
- ### content
76
-
77
- Compose a rendered Markdown document from one or
78
- more kbid or docid identifiers.
79
-
80
- **Parameters:**
81
-
82
- | Name | Type | Required | Description |
83
- |-------|----------|----------|-------------------|
84
- | `ids` | string[] | yes | One or more kbid or docid identifiers (mixed) |
85
-
86
- **Returns:** Tool result with text content containing
87
- JSON:
88
-
89
- ```json
90
- {
91
- "type": "text/markdown",
92
- "data": "<composed markdown>",
93
- "total": 4567
94
- }
95
- ```
96
-
97
- The `total` field is the character count of `data`
98
- (not byte count).
99
-
100
- Maps to `client.content()`.
101
-
102
- ## Phase 1 -- Resolve and Gather
103
-
104
- The resolution phase collects all sections needed
105
- for composition. This phase runs in `kb-worker`,
106
- which has access to `fs-database` for lookups.
107
-
108
- ### Step 1: Resolve identifiers
109
-
110
- For each input identifier:
111
-
112
- 1. Try to find it as a **kbid** (section lookup via
113
- `fs-database`).
114
- 2. If not found, try to find it as a **docid**
115
- (document lookup via `fs-database`).
116
- 3. If neither matches, report an error for that
117
- identifier and skip it.
118
-
119
- Identifiers are processed in the order given. The
120
- resolved identifiers form the **main list** -- the
121
- ordered set of sections and documents that become
122
- the primary content of the composed Markdown.
123
-
124
- ### Step 2: Expand documents
125
-
126
- For each resolved docid in the main list, expand it
127
- to its ordered section kbids. The docid itself is
128
- retained as a document reference for rendering (see
129
- Document Rendering below). Its sections join the
130
- main kbid list in their document-defined order.
131
-
132
- ### Step 3: Deduplicate
133
-
134
- Remove duplicate kbids from the main list while
135
- preserving order. If the same kbid appears from
136
- multiple sources (directly specified and also part
137
- of a document), the first occurrence wins.
138
-
139
- ### Step 4: Fetch main sections
140
-
141
- Fetch the content of all main kbids from
142
- `fs-database`. Each section includes its kbid,
143
- section type, content body, and optional docid.
144
-
145
- ### Step 5: Extract references recursively
146
-
147
- For each main section, call `extract_content_markers()`
148
- from the `content_parser` module to find all markers in
149
- its
150
- content. Build a **references** set of unique kbids
151
- and docids:
152
-
153
- - **All marker types** add their referenced kbid or
154
- docid to the references set.
155
- - **Recursive markers** -- `$(text: {kbid})` and
156
- `$(document: {docid})` -- follow into the
157
- referenced content and extract markers from it
158
- too, recursing until no new references are found.
159
- - A **visited set** tracks which kbids and docids
160
- have already been processed to detect and break
161
- circular references.
162
-
163
- ### Step 6: Fetch reference content
164
-
165
- Fetch section content for all kbids in the references
166
- set that are not already fetched (from step 4). For
167
- docids in the references set, fetch the document
168
- manifest and its section content.
169
-
170
- ### Step 7: Assign named anchors
171
-
172
- Assign HTML anchors to every section and document:
173
-
174
- - Sections: `<a id="{kbid}"></a>`
175
- - Documents: `<a id="{docid}"></a>`
176
-
177
- Anchors are assigned to all entities -- main sections,
178
- reference sections, main documents, and reference
179
- documents.
180
-
181
- ## Phase 2 -- Content Composition
182
-
183
- The composition phase takes the pre-fetched sections
184
- and documents from Phase 1 and produces a Markdown
185
- string. This phase runs in the `content-composer`
186
- module in `kbdb-shared` as pure logic -- no I/O.
187
-
188
- ### State
189
-
190
- The composer maintains two tracking sets:
191
-
192
- - **`renderedSections`** -- set of kbids that have
193
- been rendered into the output.
194
- - **`renderedDocuments`** -- set of docids that have
195
- been rendered into the output.
196
-
197
- ### Main sections
198
-
199
- For each kbid in the main list (in order):
200
-
201
- 1. Emit the section's anchor tag:
202
- `<a id="{kbid}"></a>`
203
- 2. Emit a heading for the section.
204
- 3. Render the section's content body, processing
205
- any markers found (see Marker Rendering below).
206
- 4. Add the kbid to `renderedSections`.
207
-
208
- If a main list entry is a docid, render it as a
209
- document section (see Document Rendering below).
210
-
211
- ### Marker Rendering
212
-
213
- When processing a section's content body, each
214
- `$(type: value)` marker is replaced by its rendered
215
- form:
216
-
217
- #### `$(image: {kbid})`
218
-
219
- Replace with an inline image. The referenced section
220
- must be of type `image/*`. The image data is the
221
- base64-decoded content of the referenced section.
222
-
223
- #### `$(code: {kbid})`
224
-
225
- Replace with a fenced code block. The referenced
226
- section must be of type `text/*` or
227
- `application/json`. The language tag is derived from
228
- the section's MIME type using the mapping in
229
- [Document -- MIME-to-Language](
230
- document.md#mime-to-language-mapping).
231
-
232
- #### `$(text: {kbid})`
233
-
234
- Render the referenced text section's content
235
- **inline**. The referenced section's content body
236
- replaces the marker, and any markers within the
237
- referenced content are processed recursively.
238
-
239
- If the kbid is already in the current **render
240
- stack** (i.e. we are currently in the process of
241
- rendering it), this is a **cyclic embed**. Instead of
242
- expanding inline, emit a Markdown link to the
243
- section's anchor:
244
-
245
- ```
246
- [{kbid}](#{kbid})
247
- ```
248
-
249
- The referenced section is added to `renderedSections`
250
- after its content is fully rendered.
251
-
252
- #### `$(document: {docid})`
253
-
254
- Render the referenced document as a **document
255
- section** (see Document Rendering below).
256
-
257
- If the docid is already in the current render stack,
258
- this is a cyclic embed. Emit a Markdown link to the
259
- document's anchor:
260
-
261
- ```
262
- [{docid}](#{docid})
263
- ```
264
-
265
- #### `$(link: {kbid})`
266
-
267
- Emit a Markdown link pointing to the section's named
268
- anchor:
269
-
270
- ```
271
- [{kbid}](#{kbid})
272
- ```
273
-
274
- The link marker does **not** expand the referenced
275
- content inline. If the linked section has not been
276
- rendered yet, it will be rendered at the bottom of
277
- the document in the remaining references pass.
278
-
279
- #### `$(doc-link: {docid})`
280
-
281
- Emit a Markdown link pointing to the document's
282
- named anchor:
283
-
284
- ```
285
- [{docid}](#{docid})
286
- ```
287
-
288
- The link points to the document's container heading,
289
- not to any individual section within the document.
290
- If the document has not been rendered yet, it will
291
- be rendered at the bottom in the remaining
292
- references pass.
293
-
294
- ## Document Rendering
295
-
296
- When a document is rendered -- whether from a
297
- `$(document: {docid})` marker, as a `$(doc-link:)`
298
- target, or as a main docid input -- it appears as a
299
- **structural document section** in the Markdown
300
- output.
301
-
302
- Structure:
303
-
304
- 1. Emit the document's anchor tag:
305
- `<a id="{docid}"></a>`
306
- 2. Emit a heading with the document title.
307
- 3. For each section in the document (in position
308
- order):
309
- - Emit the section's anchor tag:
310
- `<a id="{kbid}"></a>`
311
- - Emit a sub-heading for the section.
312
- - Render the section's content body with marker
313
- processing (same rules as Marker Rendering).
314
- - Add the kbid to `renderedSections`.
315
- 4. Add the docid to `renderedDocuments`.
316
-
317
- The document heading is the parent; its sections are
318
- subsections beneath it. `$(doc-link:)` links point to
319
- the document's anchor (the container heading), giving
320
- the reader a view of the entire document rather than
321
- an individual section.
322
-
323
- If a section within the document contains markers,
324
- they are processed recursively using the same
325
- embed/link rules. Cyclic detection uses the same
326
- render stack.
327
-
328
- ## Remaining References
329
-
330
- After all main sections and documents have been
331
- rendered, the composer traverses the references set
332
- and renders any entities not yet in
333
- `renderedSections` or `renderedDocuments`.
334
-
335
- These are typically sections or documents referenced
336
- by `$(link:)` or `$(doc-link:)` markers whose targets
337
- were not directly requested or embedded. They appear
338
- at the bottom of the composed document, each with its
339
- own anchor and heading.
340
-
341
- For each unrendered reference:
342
-
343
- - If it is a kbid: render as a section (anchor +
344
- heading + content with marker processing).
345
- - If it is a docid: render as a document section
346
- (see Document Rendering above).
347
-
348
- ## Cyclic Reference Handling
349
-
350
- There are two distinct cycle-detection mechanisms:
351
-
352
- ### Resolution cycle detection (Phase 1)
353
-
354
- During recursive marker extraction (step 5), a
355
- **visited set** tracks which kbids and docids have
356
- been processed. If `extract_content_markers()` encounters a
357
- reference already in the visited set, it stops
358
- recursing into that reference. This prevents infinite
359
- loops during the gathering phase.
360
-
361
- ### Render cycle detection (Phase 2)
362
-
363
- During content composition, a **render stack** tracks
364
- which kbids and docids are currently being rendered
365
- (i.e. their content is in the process of expanding).
366
- If a `$(text:)` or `$(document:)` marker references
367
- an entity already in the render stack, it is a cyclic
368
- embed. Instead of expanding inline, the composer
369
- emits a Markdown link to the entity's anchor.
370
-
371
- The render stack is distinct from `renderedSections`
372
- / `renderedDocuments`. An entity in the render stack
373
- is currently being expanded (not yet complete). An
374
- entity in `renderedSections` has been fully rendered
375
- and will not be rendered again.
376
-
377
- ## Rust Module
378
-
379
- The composition logic lives in the `content-composer`
380
- module in the `kbdb-shared` rlib crate.
381
-
382
- ### Module Path
383
-
384
- ```
385
- engine/crates/shared/src/content-composer/
386
- ├── mod.rs -- re-exports
387
- ├── types.rs -- ComposeRequest, ComposeResult,
388
- │ RenderedSection
389
- ├── compose.rs -- compose_content()
390
- └── render.rs -- section and marker rendering
391
- ```
392
-
393
- Added to `lib.rs`:
394
-
395
- ```rust
396
- #[path = "content-composer/mod.rs"]
397
- pub mod content_composer;
398
- ```
399
-
400
- ### Types
401
-
402
- ```rust
403
- pub struct ComposeRequest {
404
- pub main_ids: Vec<ResolvedId>,
405
- pub sections: HashMap<String, SectionData>,
406
- pub documents: HashMap<String, DocumentData>,
407
- }
408
-
409
- pub enum ResolvedId {
410
- Section(String),
411
- Document(String),
412
- }
413
-
414
- pub struct SectionData {
415
- pub kbid: String,
416
- pub section_type: SectionType,
417
- pub content: String,
418
- pub markers: Vec<ExtractedContentMarker>,
419
- }
420
-
421
- pub struct DocumentData {
422
- pub docid: String,
423
- pub title: String,
424
- pub section_kbids: Vec<String>,
425
- }
426
-
427
- pub struct ComposeResult {
428
- pub markdown: String,
429
- pub total_chars: usize,
430
- }
431
- ```
432
-
433
- ### API
434
-
435
- ```rust
436
- pub fn compose_content(
437
- request: &ComposeRequest,
438
- ) -> ComposeResult
439
- ```
440
-
441
- Takes a fully resolved request (all sections and
442
- documents pre-fetched, markers pre-extracted) and
443
- returns the composed Markdown string. The function
444
- is pure -- no I/O, no database access. Resolution
445
- and fetching are the caller's responsibility
446
- (`kb-worker`).
447
-
448
- ### Dependencies
449
-
450
- The module uses sibling modules within `kbdb-shared`:
451
-
452
- - `content_parser::extract_content_markers()` -- for
453
- processing markers within referenced content during
454
- recursive rendering.
455
- - `content_parser::ContentMarkerType` -- for
456
- dispatching marker rendering by type.
457
- - `section::SectionType` -- for type-specific
458
- rendering (text vs code vs image).
459
-
460
- ## Integration Points
461
-
462
- ### Worker Orchestration
463
-
464
- The `kb-worker` crate orchestrates the full flow:
465
-
466
- 1. Receives a `content` request with identifiers.
467
- 2. Resolves identifiers via `fs-database` (Phase 1,
468
- steps 1-3).
469
- 3. Fetches section and document content from
470
- `fs-database` (steps 4, 6).
471
- 4. Extracts markers recursively using
472
- `extract_content_markers()` (step 5).
473
- 5. Builds a `ComposeRequest` with all resolved data.
474
- 6. Calls `compose_content()` from `content-composer`.
475
- 7. Returns the `ComposeResult` to the daemon.
476
-
477
- ### Worker Client
478
-
479
- The `WorkerClient` class exposes a `content()`
480
- method:
481
-
482
- ```ts
483
- content(ids: string[]): Promise<ContentResult>;
484
- ```
485
-
486
- See [Worker Client](worker-client.md) for the full
487
- interface.
488
-
489
- ### CLI
490
-
491
- The `runContent()` function in `src/cli.ts` calls
492
- `client.content(ids)` and writes the resulting
493
- Markdown string to stdout.
494
-
495
- See [CLI](cli.md) for the full command specification.
496
-
497
- ### MCP
498
-
499
- The `handleToolCall()` function routes the `content`
500
- tool to `client.content(ids)` and wraps the result
501
- in the MCP tool response format.
502
-
503
- See [MCP](mcp.md) for the full tool specification.
504
-
505
- ## Example
506
-
507
- **Input:** `kbdb content abc12345 my-api-guide`
508
-
509
- Where `abc12345` is a kbid (text section) and
510
- `my-api-guide` is a docid with two sections
511
- (`def67890` and `ghi11111`).
512
-
513
- **Phase 1 resolves:**
514
- - Main list: `[abc12345, def67890, ghi11111]`
515
- - `my-api-guide` retained as document reference
516
- - Markers extracted: `abc12345` contains
517
- `$(code: jkl22222)` and
518
- `$(link: mno33333)`
519
- - References: `{jkl22222, mno33333}`
520
-
521
- **Phase 2 composes:**
522
-
523
- ```markdown
524
- <a id="abc12345"></a>
525
-
526
- ## abc12345
527
-
528
- This section explains the API.
529
-
530
- Here is the implementation:
531
-
532
- ` ` `ts
533
- function greet(name: string) {
534
- return `Hello, ${name}!`;
535
- }
536
- ` ` `
537
-
538
- See also: [mno33333](#mno33333).
539
-
540
- ---
541
-
542
- <a id="my-api-guide"></a>
543
-
544
- ## my-api-guide
545
-
546
- <a id="def67890"></a>
547
-
548
- ### def67890
549
-
550
- First section of the API guide...
551
-
552
- <a id="ghi11111"></a>
553
-
554
- ### ghi11111
555
-
556
- Second section of the API guide...
557
-
558
- ---
559
-
560
- <a id="mno33333"></a>
561
-
562
- ## mno33333
563
-
564
- This section was referenced by a link marker. It
565
- is rendered here because it was not part of the
566
- main content or any embedded document.
567
- ```
568
-
569
- In this example:
570
- - `abc12345` is a main section with a code embed
571
- (`jkl22222` rendered as a fenced code block) and
572
- a link (`mno33333` rendered as a Markdown link).
573
- - `my-api-guide` is rendered as a document section
574
- with `def67890` and `ghi11111` as subsections.
575
- - `mno33333` appears at the bottom as a remaining
576
- reference (linked but not embedded).
577
-
578
- ## Testing
579
-
580
- Unit tests for `compose_content()`:
581
-
582
- - Empty request returns empty markdown.
583
- - Single text section with no markers.
584
- - Single section with `$(image:)` marker.
585
- - Single section with `$(code:)` marker and correct
586
- language tag.
587
- - Recursive `$(text:)` embedding.
588
- - `$(document:)` renders document heading with
589
- section subsections.
590
- - Cyclic `$(text:)` embed becomes link to anchor.
591
- - Cyclic `$(document:)` embed becomes link to
592
- document anchor.
593
- - `$(link:)` renders as Markdown link, target
594
- rendered at bottom.
595
- - `$(doc-link:)` renders as Markdown link pointing
596
- to document anchor.
597
- - Mixed kbids and docids in main list.
598
- - Named anchors assigned correctly to all entities.
599
- - `renderedSections` prevents duplicate rendering.
600
- - `renderedDocuments` prevents duplicate document
601
- rendering.
602
- - Remaining references rendered at bottom only for
603
- unrendered entities.
604
- - Unicode content preserved through composition.
605
-
606
- Tests live in the `kbdb-shared` crate:
607
- `engine/crates/shared/src/content-composer/compose.rs`
608
- and `engine/crates/shared/src/content-composer/render.rs`
609
- (inline `#[cfg(test)]` modules).