@mseep/core 3.0.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 (312) hide show
  1. package/CHANGELOG.md +285 -0
  2. package/LICENSE +21 -0
  3. package/README.ja.md +14 -0
  4. package/README.ko.md +14 -0
  5. package/README.md +227 -0
  6. package/README.pt-BR.md +14 -0
  7. package/README.skills.md +50 -0
  8. package/README.uk.md +14 -0
  9. package/README.zh-CN.md +14 -0
  10. package/bin/booklib-mcp.js +458 -0
  11. package/bin/booklib.js +2394 -0
  12. package/bin/skills.cjs +1292 -0
  13. package/community/registry.json +1616 -0
  14. package/hooks/hooks.json +52 -0
  15. package/hooks/posttooluse-capture.mjs +67 -0
  16. package/hooks/posttooluse-contradict.mjs +76 -0
  17. package/hooks/posttooluse-imports.mjs +67 -0
  18. package/hooks/pretooluse-inject.mjs +82 -0
  19. package/hooks/suggest.js +153 -0
  20. package/lib/agent-detector.js +96 -0
  21. package/lib/config-loader.js +39 -0
  22. package/lib/conflict-resolver.js +148 -0
  23. package/lib/connectors/context7.js +167 -0
  24. package/lib/connectors/github.js +223 -0
  25. package/lib/connectors/local.js +120 -0
  26. package/lib/connectors/notion.js +436 -0
  27. package/lib/connectors/web.js +134 -0
  28. package/lib/context-builder.js +574 -0
  29. package/lib/discovery-engine.js +298 -0
  30. package/lib/doctor/hook-installer.js +83 -0
  31. package/lib/doctor/usage-tracker.js +87 -0
  32. package/lib/engine/auditor.js +103 -0
  33. package/lib/engine/auto-linker.js +177 -0
  34. package/lib/engine/bm25-index.js +178 -0
  35. package/lib/engine/capture.js +120 -0
  36. package/lib/engine/context-map.js +641 -0
  37. package/lib/engine/corrections.js +194 -0
  38. package/lib/engine/decision-checker.js +203 -0
  39. package/lib/engine/doctor.js +207 -0
  40. package/lib/engine/embedding-provider.js +72 -0
  41. package/lib/engine/gap-detector.js +138 -0
  42. package/lib/engine/gap-resolver.js +135 -0
  43. package/lib/engine/graph-injector.js +137 -0
  44. package/lib/engine/graph-search.js +183 -0
  45. package/lib/engine/graph.js +170 -0
  46. package/lib/engine/handoff.js +411 -0
  47. package/lib/engine/import-checker.js +249 -0
  48. package/lib/engine/import-parser.js +145 -0
  49. package/lib/engine/indexer.js +334 -0
  50. package/lib/engine/lookup-priority.js +15 -0
  51. package/lib/engine/parser.js +257 -0
  52. package/lib/engine/principle-extractor.js +116 -0
  53. package/lib/engine/project-analyzer.js +353 -0
  54. package/lib/engine/query-expander.js +42 -0
  55. package/lib/engine/reasoning-modes.js +353 -0
  56. package/lib/engine/registries.js +524 -0
  57. package/lib/engine/reranker.js +45 -0
  58. package/lib/engine/rrf.js +59 -0
  59. package/lib/engine/scanner.js +151 -0
  60. package/lib/engine/searcher.js +223 -0
  61. package/lib/engine/session-coordinator.js +291 -0
  62. package/lib/engine/session-manager.js +375 -0
  63. package/lib/engine/source-detector.js +240 -0
  64. package/lib/engine/source-manager.js +142 -0
  65. package/lib/engine/structured-response.js +47 -0
  66. package/lib/engine/synthesis-templates.js +364 -0
  67. package/lib/installer.js +70 -0
  68. package/lib/instinct-block.js +21 -0
  69. package/lib/mcp-config-writer.js +107 -0
  70. package/lib/paths.js +62 -0
  71. package/lib/project-initializer.js +856 -0
  72. package/lib/registry/skills.js +102 -0
  73. package/lib/registry-searcher.js +107 -0
  74. package/lib/rules/rules-manager.js +169 -0
  75. package/lib/skill-fetcher.js +333 -0
  76. package/lib/well-known-builder.js +74 -0
  77. package/lib/wizard/index.js +1389 -0
  78. package/lib/wizard/integration-detector.js +41 -0
  79. package/lib/wizard/project-detector.js +146 -0
  80. package/lib/wizard/prompt.js +221 -0
  81. package/lib/wizard/registry-embeddings.js +107 -0
  82. package/lib/wizard/skill-recommender.js +69 -0
  83. package/package.json +70 -0
  84. package/skills/animation-at-work/SKILL.md +270 -0
  85. package/skills/animation-at-work/assets/example_asset.txt +1 -0
  86. package/skills/animation-at-work/evals/evals.json +44 -0
  87. package/skills/animation-at-work/evals/results.json +13 -0
  88. package/skills/animation-at-work/examples/after.md +64 -0
  89. package/skills/animation-at-work/examples/before.md +35 -0
  90. package/skills/animation-at-work/references/api_reference.md +369 -0
  91. package/skills/animation-at-work/references/review-checklist.md +79 -0
  92. package/skills/animation-at-work/scripts/audit_animations.py +295 -0
  93. package/skills/animation-at-work/scripts/example.py +1 -0
  94. package/skills/booklib-mcp-guide/SKILL.md +129 -0
  95. package/skills/booklib-mcp-guide/evals/evals.json +37 -0
  96. package/skills/booklib-mcp-guide/examples/after.md +34 -0
  97. package/skills/booklib-mcp-guide/examples/before.md +27 -0
  98. package/skills/booklib-mcp-guide/references/tool-catalog.md +9 -0
  99. package/skills/clean-code-reviewer/SKILL.md +444 -0
  100. package/skills/clean-code-reviewer/audit.json +35 -0
  101. package/skills/clean-code-reviewer/evals/evals.json +185 -0
  102. package/skills/clean-code-reviewer/evals/results.json +13 -0
  103. package/skills/clean-code-reviewer/examples/after.md +48 -0
  104. package/skills/clean-code-reviewer/examples/before.md +33 -0
  105. package/skills/clean-code-reviewer/references/api_reference.md +158 -0
  106. package/skills/clean-code-reviewer/references/practices-catalog.md +282 -0
  107. package/skills/clean-code-reviewer/references/review-checklist.md +254 -0
  108. package/skills/clean-code-reviewer/scripts/pre-review.py +206 -0
  109. package/skills/data-intensive-patterns/SKILL.md +267 -0
  110. package/skills/data-intensive-patterns/assets/example_asset.txt +1 -0
  111. package/skills/data-intensive-patterns/evals/evals.json +54 -0
  112. package/skills/data-intensive-patterns/evals/results.json +13 -0
  113. package/skills/data-intensive-patterns/examples/after.md +61 -0
  114. package/skills/data-intensive-patterns/examples/before.md +38 -0
  115. package/skills/data-intensive-patterns/references/api_reference.md +34 -0
  116. package/skills/data-intensive-patterns/references/patterns-catalog.md +551 -0
  117. package/skills/data-intensive-patterns/references/review-checklist.md +193 -0
  118. package/skills/data-intensive-patterns/scripts/adr.py +213 -0
  119. package/skills/data-intensive-patterns/scripts/example.py +1 -0
  120. package/skills/data-pipelines/SKILL.md +259 -0
  121. package/skills/data-pipelines/assets/example_asset.txt +1 -0
  122. package/skills/data-pipelines/evals/evals.json +45 -0
  123. package/skills/data-pipelines/evals/results.json +13 -0
  124. package/skills/data-pipelines/examples/after.md +97 -0
  125. package/skills/data-pipelines/examples/before.md +37 -0
  126. package/skills/data-pipelines/references/api_reference.md +301 -0
  127. package/skills/data-pipelines/references/review-checklist.md +181 -0
  128. package/skills/data-pipelines/scripts/example.py +1 -0
  129. package/skills/data-pipelines/scripts/new_pipeline.py +444 -0
  130. package/skills/design-patterns/SKILL.md +271 -0
  131. package/skills/design-patterns/assets/example_asset.txt +1 -0
  132. package/skills/design-patterns/evals/evals.json +46 -0
  133. package/skills/design-patterns/evals/results.json +13 -0
  134. package/skills/design-patterns/examples/after.md +52 -0
  135. package/skills/design-patterns/examples/before.md +29 -0
  136. package/skills/design-patterns/references/api_reference.md +1 -0
  137. package/skills/design-patterns/references/patterns-catalog.md +726 -0
  138. package/skills/design-patterns/references/review-checklist.md +173 -0
  139. package/skills/design-patterns/scripts/example.py +1 -0
  140. package/skills/design-patterns/scripts/scaffold.py +807 -0
  141. package/skills/domain-driven-design/SKILL.md +142 -0
  142. package/skills/domain-driven-design/assets/example_asset.txt +1 -0
  143. package/skills/domain-driven-design/evals/evals.json +48 -0
  144. package/skills/domain-driven-design/evals/results.json +13 -0
  145. package/skills/domain-driven-design/examples/after.md +80 -0
  146. package/skills/domain-driven-design/examples/before.md +43 -0
  147. package/skills/domain-driven-design/references/api_reference.md +1 -0
  148. package/skills/domain-driven-design/references/patterns-catalog.md +545 -0
  149. package/skills/domain-driven-design/references/review-checklist.md +158 -0
  150. package/skills/domain-driven-design/scripts/example.py +1 -0
  151. package/skills/domain-driven-design/scripts/scaffold.py +421 -0
  152. package/skills/effective-java/SKILL.md +227 -0
  153. package/skills/effective-java/assets/example_asset.txt +1 -0
  154. package/skills/effective-java/evals/evals.json +46 -0
  155. package/skills/effective-java/evals/results.json +13 -0
  156. package/skills/effective-java/examples/after.md +83 -0
  157. package/skills/effective-java/examples/before.md +37 -0
  158. package/skills/effective-java/references/api_reference.md +1 -0
  159. package/skills/effective-java/references/items-catalog.md +955 -0
  160. package/skills/effective-java/references/review-checklist.md +216 -0
  161. package/skills/effective-java/scripts/checkstyle_setup.py +211 -0
  162. package/skills/effective-java/scripts/example.py +1 -0
  163. package/skills/effective-kotlin/SKILL.md +271 -0
  164. package/skills/effective-kotlin/assets/example_asset.txt +1 -0
  165. package/skills/effective-kotlin/audit.json +29 -0
  166. package/skills/effective-kotlin/evals/evals.json +45 -0
  167. package/skills/effective-kotlin/evals/results.json +13 -0
  168. package/skills/effective-kotlin/examples/after.md +36 -0
  169. package/skills/effective-kotlin/examples/before.md +38 -0
  170. package/skills/effective-kotlin/references/api_reference.md +1 -0
  171. package/skills/effective-kotlin/references/practices-catalog.md +1228 -0
  172. package/skills/effective-kotlin/references/review-checklist.md +126 -0
  173. package/skills/effective-kotlin/scripts/example.py +1 -0
  174. package/skills/effective-python/SKILL.md +441 -0
  175. package/skills/effective-python/evals/evals.json +44 -0
  176. package/skills/effective-python/evals/results.json +13 -0
  177. package/skills/effective-python/examples/after.md +56 -0
  178. package/skills/effective-python/examples/before.md +40 -0
  179. package/skills/effective-python/ref-01-pythonic-thinking.md +202 -0
  180. package/skills/effective-python/ref-02-lists-and-dicts.md +146 -0
  181. package/skills/effective-python/ref-03-functions.md +186 -0
  182. package/skills/effective-python/ref-04-comprehensions-generators.md +211 -0
  183. package/skills/effective-python/ref-05-classes-interfaces.md +188 -0
  184. package/skills/effective-python/ref-06-metaclasses-attributes.md +209 -0
  185. package/skills/effective-python/ref-07-concurrency.md +213 -0
  186. package/skills/effective-python/ref-08-robustness-performance.md +248 -0
  187. package/skills/effective-python/ref-09-testing-debugging.md +253 -0
  188. package/skills/effective-python/ref-10-collaboration.md +175 -0
  189. package/skills/effective-python/references/api_reference.md +218 -0
  190. package/skills/effective-python/references/practices-catalog.md +483 -0
  191. package/skills/effective-python/references/review-checklist.md +190 -0
  192. package/skills/effective-python/scripts/lint.py +173 -0
  193. package/skills/effective-typescript/SKILL.md +262 -0
  194. package/skills/effective-typescript/audit.json +29 -0
  195. package/skills/effective-typescript/evals/evals.json +37 -0
  196. package/skills/effective-typescript/evals/results.json +13 -0
  197. package/skills/effective-typescript/examples/after.md +70 -0
  198. package/skills/effective-typescript/examples/before.md +47 -0
  199. package/skills/effective-typescript/references/api_reference.md +118 -0
  200. package/skills/effective-typescript/references/practices-catalog.md +371 -0
  201. package/skills/effective-typescript/scripts/review.py +169 -0
  202. package/skills/kotlin-in-action/SKILL.md +261 -0
  203. package/skills/kotlin-in-action/assets/example_asset.txt +1 -0
  204. package/skills/kotlin-in-action/evals/evals.json +43 -0
  205. package/skills/kotlin-in-action/evals/results.json +13 -0
  206. package/skills/kotlin-in-action/examples/after.md +53 -0
  207. package/skills/kotlin-in-action/examples/before.md +39 -0
  208. package/skills/kotlin-in-action/references/api_reference.md +1 -0
  209. package/skills/kotlin-in-action/references/practices-catalog.md +436 -0
  210. package/skills/kotlin-in-action/references/review-checklist.md +204 -0
  211. package/skills/kotlin-in-action/scripts/example.py +1 -0
  212. package/skills/kotlin-in-action/scripts/setup_detekt.py +224 -0
  213. package/skills/lean-startup/SKILL.md +160 -0
  214. package/skills/lean-startup/assets/example_asset.txt +1 -0
  215. package/skills/lean-startup/evals/evals.json +43 -0
  216. package/skills/lean-startup/evals/results.json +13 -0
  217. package/skills/lean-startup/examples/after.md +80 -0
  218. package/skills/lean-startup/examples/before.md +34 -0
  219. package/skills/lean-startup/references/api_reference.md +319 -0
  220. package/skills/lean-startup/references/review-checklist.md +137 -0
  221. package/skills/lean-startup/scripts/example.py +1 -0
  222. package/skills/lean-startup/scripts/new_experiment.py +286 -0
  223. package/skills/microservices-patterns/SKILL.md +384 -0
  224. package/skills/microservices-patterns/evals/evals.json +45 -0
  225. package/skills/microservices-patterns/evals/results.json +13 -0
  226. package/skills/microservices-patterns/examples/after.md +69 -0
  227. package/skills/microservices-patterns/examples/before.md +40 -0
  228. package/skills/microservices-patterns/references/patterns-catalog.md +391 -0
  229. package/skills/microservices-patterns/references/review-checklist.md +169 -0
  230. package/skills/microservices-patterns/scripts/new_service.py +583 -0
  231. package/skills/programming-with-rust/SKILL.md +209 -0
  232. package/skills/programming-with-rust/evals/evals.json +37 -0
  233. package/skills/programming-with-rust/evals/results.json +13 -0
  234. package/skills/programming-with-rust/examples/after.md +107 -0
  235. package/skills/programming-with-rust/examples/before.md +59 -0
  236. package/skills/programming-with-rust/references/api_reference.md +152 -0
  237. package/skills/programming-with-rust/references/practices-catalog.md +335 -0
  238. package/skills/programming-with-rust/scripts/review.py +142 -0
  239. package/skills/refactoring-ui/SKILL.md +362 -0
  240. package/skills/refactoring-ui/assets/example_asset.txt +1 -0
  241. package/skills/refactoring-ui/evals/evals.json +45 -0
  242. package/skills/refactoring-ui/evals/results.json +13 -0
  243. package/skills/refactoring-ui/examples/after.md +85 -0
  244. package/skills/refactoring-ui/examples/before.md +58 -0
  245. package/skills/refactoring-ui/references/api_reference.md +355 -0
  246. package/skills/refactoring-ui/references/review-checklist.md +114 -0
  247. package/skills/refactoring-ui/scripts/audit_css.py +250 -0
  248. package/skills/refactoring-ui/scripts/example.py +1 -0
  249. package/skills/rust-in-action/SKILL.md +350 -0
  250. package/skills/rust-in-action/evals/evals.json +38 -0
  251. package/skills/rust-in-action/evals/results.json +13 -0
  252. package/skills/rust-in-action/examples/after.md +156 -0
  253. package/skills/rust-in-action/examples/before.md +56 -0
  254. package/skills/rust-in-action/references/practices-catalog.md +346 -0
  255. package/skills/rust-in-action/scripts/review.py +147 -0
  256. package/skills/skill-router/SKILL.md +186 -0
  257. package/skills/skill-router/evals/evals.json +38 -0
  258. package/skills/skill-router/evals/results.json +13 -0
  259. package/skills/skill-router/examples/after.md +63 -0
  260. package/skills/skill-router/examples/before.md +39 -0
  261. package/skills/skill-router/references/api_reference.md +24 -0
  262. package/skills/skill-router/references/routing-heuristics.md +89 -0
  263. package/skills/skill-router/references/skill-catalog.md +174 -0
  264. package/skills/skill-router/scripts/route.py +266 -0
  265. package/skills/spring-boot-in-action/SKILL.md +340 -0
  266. package/skills/spring-boot-in-action/evals/evals.json +39 -0
  267. package/skills/spring-boot-in-action/evals/results.json +13 -0
  268. package/skills/spring-boot-in-action/examples/after.md +185 -0
  269. package/skills/spring-boot-in-action/examples/before.md +84 -0
  270. package/skills/spring-boot-in-action/references/practices-catalog.md +403 -0
  271. package/skills/spring-boot-in-action/scripts/review.py +184 -0
  272. package/skills/storytelling-with-data/SKILL.md +241 -0
  273. package/skills/storytelling-with-data/assets/example_asset.txt +1 -0
  274. package/skills/storytelling-with-data/evals/evals.json +47 -0
  275. package/skills/storytelling-with-data/evals/results.json +13 -0
  276. package/skills/storytelling-with-data/examples/after.md +50 -0
  277. package/skills/storytelling-with-data/examples/before.md +33 -0
  278. package/skills/storytelling-with-data/references/api_reference.md +379 -0
  279. package/skills/storytelling-with-data/references/review-checklist.md +111 -0
  280. package/skills/storytelling-with-data/scripts/chart_review.py +301 -0
  281. package/skills/storytelling-with-data/scripts/example.py +1 -0
  282. package/skills/system-design-interview/SKILL.md +233 -0
  283. package/skills/system-design-interview/assets/example_asset.txt +1 -0
  284. package/skills/system-design-interview/evals/evals.json +46 -0
  285. package/skills/system-design-interview/evals/results.json +13 -0
  286. package/skills/system-design-interview/examples/after.md +94 -0
  287. package/skills/system-design-interview/examples/before.md +27 -0
  288. package/skills/system-design-interview/references/api_reference.md +582 -0
  289. package/skills/system-design-interview/references/review-checklist.md +201 -0
  290. package/skills/system-design-interview/scripts/example.py +1 -0
  291. package/skills/system-design-interview/scripts/new_design.py +421 -0
  292. package/skills/using-asyncio-python/SKILL.md +290 -0
  293. package/skills/using-asyncio-python/assets/example_asset.txt +1 -0
  294. package/skills/using-asyncio-python/evals/evals.json +43 -0
  295. package/skills/using-asyncio-python/evals/results.json +13 -0
  296. package/skills/using-asyncio-python/examples/after.md +68 -0
  297. package/skills/using-asyncio-python/examples/before.md +39 -0
  298. package/skills/using-asyncio-python/references/api_reference.md +267 -0
  299. package/skills/using-asyncio-python/references/review-checklist.md +149 -0
  300. package/skills/using-asyncio-python/scripts/check_blocking.py +270 -0
  301. package/skills/using-asyncio-python/scripts/example.py +1 -0
  302. package/skills/web-scraping-python/SKILL.md +280 -0
  303. package/skills/web-scraping-python/assets/example_asset.txt +1 -0
  304. package/skills/web-scraping-python/evals/evals.json +46 -0
  305. package/skills/web-scraping-python/evals/results.json +13 -0
  306. package/skills/web-scraping-python/examples/after.md +109 -0
  307. package/skills/web-scraping-python/examples/before.md +40 -0
  308. package/skills/web-scraping-python/references/api_reference.md +393 -0
  309. package/skills/web-scraping-python/references/review-checklist.md +163 -0
  310. package/skills/web-scraping-python/scripts/example.py +1 -0
  311. package/skills/web-scraping-python/scripts/new_scraper.py +231 -0
  312. package/skills/writing-plans/audit.json +34 -0
@@ -0,0 +1,142 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ /**
5
+ * Manages documentation source registration, listing, and removal.
6
+ * Sources are persisted in .booklib/sources.json.
7
+ */
8
+ export class SourceManager {
9
+ constructor(booklibDir) {
10
+ this.booklibDir = booklibDir;
11
+ this.registryPath = path.join(booklibDir, 'sources.json');
12
+ }
13
+
14
+ /** Load registry from disk, returning empty structure if file missing or corrupt. */
15
+ _loadRegistry() {
16
+ if (!fs.existsSync(this.registryPath)) {
17
+ return { sources: [] };
18
+ }
19
+ try {
20
+ const raw = fs.readFileSync(this.registryPath, 'utf8');
21
+ return JSON.parse(raw);
22
+ } catch {
23
+ return { sources: [] };
24
+ }
25
+ }
26
+
27
+ /** Persist registry to disk, creating the directory if needed. */
28
+ _saveRegistry(registry) {
29
+ fs.mkdirSync(this.booklibDir, { recursive: true });
30
+ fs.writeFileSync(this.registryPath, JSON.stringify(registry, null, 2), 'utf8');
31
+ }
32
+
33
+ /**
34
+ * Register a new documentation source.
35
+ * @param {object} opts
36
+ * @param {string} [opts.name] - Display name (derived from path basename if omitted).
37
+ * @param {string} opts.sourcePath - Absolute path to the documentation directory.
38
+ * @param {string} opts.type - Source type (e.g. 'local', 'git', 'url').
39
+ * @param {string} [opts.url] - Optional remote URL.
40
+ * @returns {object} The registered source entry.
41
+ */
42
+ registerSource({ name, sourcePath, type, url }) {
43
+ const registry = this._loadRegistry();
44
+ const resolvedName = name ?? path.basename(sourcePath);
45
+
46
+ if (!/^[a-zA-Z0-9._-]+$/.test(resolvedName)) {
47
+ throw new Error(
48
+ `Invalid source name: "${resolvedName}". Names may only contain letters, digits, dots, hyphens, and underscores.`
49
+ );
50
+ }
51
+
52
+ const existing = registry.sources.find(s => s.name === resolvedName);
53
+ if (existing) {
54
+ throw new Error(`Source already exists: "${resolvedName}". Use a different --name.`);
55
+ }
56
+
57
+ const entry = {
58
+ name: resolvedName,
59
+ sourcePath,
60
+ type,
61
+ ...(url ? { url } : {}),
62
+ created_at: new Date().toISOString(),
63
+ indexed_at: null,
64
+ chunk_count: 0,
65
+ };
66
+
67
+ registry.sources.push(entry);
68
+ this._saveRegistry(registry);
69
+ return entry;
70
+ }
71
+
72
+ /** Return all registered sources. */
73
+ listSources() {
74
+ return this._loadRegistry().sources;
75
+ }
76
+
77
+ /**
78
+ * Return a single source by name, or null if not found.
79
+ * @param {string} name
80
+ * @returns {object|null}
81
+ */
82
+ getSource(name) {
83
+ const registry = this._loadRegistry();
84
+ return registry.sources.find(s => s.name === name) ?? null;
85
+ }
86
+
87
+ /**
88
+ * Remove a source from the registry by name.
89
+ * Does not delete indexed chunks -- caller handles that separately.
90
+ * @param {string} name
91
+ */
92
+ removeSource(name) {
93
+ const registry = this._loadRegistry();
94
+ const idx = registry.sources.findIndex(s => s.name === name);
95
+ if (idx === -1) {
96
+ throw new Error(`Source not found: "${name}". Run 'booklib sources' to see registered sources.`);
97
+ }
98
+ registry.sources.splice(idx, 1);
99
+ this._saveRegistry(registry);
100
+ }
101
+
102
+ /**
103
+ * Update the indexed_at timestamp and chunk count after indexing completes.
104
+ * @param {string} name
105
+ * @param {number} chunkCount
106
+ */
107
+ markIndexed(name, chunkCount) {
108
+ const registry = this._loadRegistry();
109
+ const source = registry.sources.find(s => s.name === name);
110
+ if (!source) {
111
+ throw new Error(`Source not found: "${name}". Register it first with 'booklib connect'.`);
112
+ }
113
+ source.indexed_at = new Date().toISOString();
114
+ source.chunk_count = chunkCount;
115
+ this._saveRegistry(registry);
116
+ }
117
+
118
+ /**
119
+ * Store file modification times for incremental re-indexing.
120
+ * @param {string} name - Source name.
121
+ * @param {Object} mtimes - { [relativePath]: mtimeMs }
122
+ */
123
+ updateMtimes(name, mtimes) {
124
+ const registry = this._loadRegistry();
125
+ const source = registry.sources.find(s => s.name === name);
126
+ if (!source) {
127
+ throw new Error(`Source not found: "${name}".`);
128
+ }
129
+ source.file_mtimes = mtimes;
130
+ this._saveRegistry(registry);
131
+ }
132
+
133
+ /**
134
+ * Retrieve stored file modification times for a source.
135
+ * @param {string} name - Source name.
136
+ * @returns {Object} { [relativePath]: mtimeMs } or empty object.
137
+ */
138
+ getMtimes(name) {
139
+ const source = this.getSource(name);
140
+ return source?.file_mtimes ?? {};
141
+ }
142
+ }
@@ -0,0 +1,47 @@
1
+ import { extractFromResults } from './principle-extractor.js';
2
+
3
+ /**
4
+ * Transforms raw search results into structured MCP response format.
5
+ * Returns actionable principles or "no relevant knowledge found."
6
+ *
7
+ * @param {string} query - the original query
8
+ * @param {Array} results - raw search results from BookLibSearcher.search()
9
+ * @param {object} [opts]
10
+ * @param {number} [opts.maxPrinciples=3] - max principles to return
11
+ * @param {string} [opts.file] - optional file path for context
12
+ * @returns {object} structured response
13
+ */
14
+ export function buildStructuredResponse(query, results, opts = {}) {
15
+ const { maxPrinciples = 3, file } = opts;
16
+
17
+ if (!results || results.length === 0) {
18
+ return {
19
+ query,
20
+ file: file ?? null,
21
+ results: [],
22
+ note: 'No relevant knowledge found.',
23
+ };
24
+ }
25
+
26
+ const principles = extractFromResults(results, maxPrinciples);
27
+
28
+ if (principles.length === 0) {
29
+ return {
30
+ query,
31
+ file: file ?? null,
32
+ results: [],
33
+ note: 'Search returned results but no extractable principles found.',
34
+ };
35
+ }
36
+
37
+ // Count unique sources
38
+ const sources = new Set(principles.map(p => p.source));
39
+ const note = `${principles.length} result${principles.length > 1 ? 's' : ''} from ${sources.size} source${sources.size > 1 ? 's' : ''}.`;
40
+
41
+ return {
42
+ query,
43
+ file: file ?? null,
44
+ results: principles,
45
+ note,
46
+ };
47
+ }
@@ -0,0 +1,364 @@
1
+ export const SYNTHESIS_TEMPLATES = {
2
+ 'framework-docs': `You are synthesizing a context injection from framework documentation. The agent needs to use a specific API correctly.
3
+
4
+ Task: {query}
5
+ {fileContext}
6
+
7
+ Search results from indexed docs:
8
+ {results}
9
+
10
+ Structure as:
11
+
12
+ ## API Reference
13
+ - [Exact function/component name with signature and parameters]
14
+ - [Required configuration or setup steps]
15
+
16
+ ## Migration (if applicable)
17
+ - [Old API → New API with specific method names]
18
+ - [What changed and why]
19
+
20
+ ## Code Example
21
+ [Working code example from the search results — not invented]
22
+
23
+ ## Gotchas
24
+ - [Non-obvious behavior, common mistakes, or breaking changes]
25
+
26
+ Only include what's IN the search results. Don't add knowledge from training data.
27
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
28
+
29
+ 'api-reference': `You are synthesizing a context injection from API documentation.
30
+
31
+ Task: {query}
32
+ {fileContext}
33
+
34
+ Search results:
35
+ {results}
36
+
37
+ Structure as:
38
+
39
+ ## Endpoints
40
+ - [Method + path + description]
41
+
42
+ ## Request Format
43
+ - [Parameters, headers, body schema]
44
+
45
+ ## Response Format
46
+ - [Status codes + response body]
47
+
48
+ ## Error Handling
49
+ - [Error codes and what they mean]
50
+
51
+ Only include what's IN the search results.
52
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
53
+
54
+ 'release-notes': `You are synthesizing a context injection from release notes and changelogs.
55
+
56
+ Task: {query}
57
+ {fileContext}
58
+
59
+ Search results:
60
+ {results}
61
+
62
+ Structure as:
63
+
64
+ ## What Changed
65
+ - [Specific API or behavior change with version number]
66
+
67
+ ## Before → After
68
+ - Before: [old pattern] → After: [new pattern]
69
+
70
+ ## Migration Code
71
+ [Code showing the new way to do it]
72
+
73
+ ## Breaking Changes
74
+ - [What will break if old patterns are used]
75
+
76
+ Only include what's IN the search results. Flag deprecated APIs explicitly.
77
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
78
+
79
+ 'spec': `You are synthesizing a context injection from project specifications.
80
+
81
+ Task: {query}
82
+ {fileContext}
83
+
84
+ Search results:
85
+ {results}
86
+
87
+ Structure as:
88
+
89
+ ## Requirements
90
+ - [Specific requirement with acceptance criteria]
91
+
92
+ ## Constraints
93
+ - [Technical or business constraint that limits implementation]
94
+
95
+ ## Dependencies
96
+ - [Other features or systems this depends on]
97
+
98
+ Only include what's IN the search results. Don't add assumptions.
99
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
100
+
101
+ 'team-decision': `You are synthesizing a context injection from team architecture decisions.
102
+
103
+ Task: {query}
104
+ {fileContext}
105
+
106
+ Search results:
107
+ {results}
108
+
109
+ Structure as:
110
+
111
+ ## Decision
112
+ - [What was decided and when]
113
+
114
+ ## Context
115
+ - [Why this decision was made — the problem it solves]
116
+
117
+ ## Constraints
118
+ - [What this decision requires or prohibits in the codebase]
119
+
120
+ ## Consequences
121
+ - [Trade-offs accepted with this decision]
122
+
123
+ Only include what's IN the search results.
124
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
125
+
126
+ 'tutorial': `You are synthesizing a context injection from a tutorial or guide.
127
+
128
+ Task: {query}
129
+ {fileContext}
130
+
131
+ Search results:
132
+ {results}
133
+
134
+ Structure as:
135
+
136
+ ## Steps
137
+ 1. [First step with specific command or action]
138
+ 2. [Next step]
139
+ 3. [Continue...]
140
+
141
+ ## Key Concepts
142
+ - [Important concept the agent needs to understand]
143
+
144
+ ## Common Mistakes
145
+ - [What beginners get wrong]
146
+
147
+ Only include what's IN the search results.
148
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
149
+
150
+ 'sdd-spec': `You are synthesizing a context injection from a spec-driven development artifact (SpecKit, GSD, Kiro, Superpowers, or similar).
151
+
152
+ Task: {query}
153
+ {fileContext}
154
+
155
+ Search results:
156
+ {results}
157
+
158
+ Structure as:
159
+
160
+ ## Goal
161
+ - [What the spec is trying to achieve]
162
+
163
+ ## Requirements
164
+ - [Specific deliverables or acceptance criteria]
165
+
166
+ ## Constraints
167
+ - [What is explicitly out of scope or not allowed]
168
+
169
+ ## Architecture / Approach
170
+ - [Technical approach, key files, dependencies]
171
+
172
+ ## Tasks
173
+ - [Implementation steps if defined in the spec]
174
+
175
+ Only include what's IN the search results.
176
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
177
+
178
+ 'api-spec': `You are synthesizing a context injection from a structured API specification (OpenAPI, AsyncAPI, GraphQL, gRPC/Proto).
179
+
180
+ Task: {query}
181
+ {fileContext}
182
+
183
+ Search results:
184
+ {results}
185
+
186
+ Structure as:
187
+
188
+ ## Endpoints / Operations
189
+ - [Method + path + description, or query/mutation/subscription name]
190
+
191
+ ## Schema
192
+ - [Request/response types, message definitions, input types]
193
+
194
+ ## Parameters
195
+ - [Path params, query params, headers, field arguments]
196
+
197
+ ## Authentication
198
+ - [Security schemes, required headers/tokens]
199
+
200
+ ## Errors
201
+ - [Error codes, error types, validation rules]
202
+
203
+ Only include what's IN the search results. Preserve exact type names and field definitions.
204
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
205
+
206
+ 'bdd-spec': `You are synthesizing a context injection from BDD/Gherkin specifications.
207
+
208
+ Task: {query}
209
+ {fileContext}
210
+
211
+ Search results:
212
+ {results}
213
+
214
+ Structure as:
215
+
216
+ ## Features
217
+ - [Feature name and description]
218
+
219
+ ## Scenarios
220
+ - [Scenario name: Given/When/Then steps summarized]
221
+
222
+ ## Business Rules
223
+ - [Rules or constraints implied by the scenarios]
224
+
225
+ ## Test Coverage
226
+ - [What behaviors are specified vs gaps]
227
+
228
+ Only include what's IN the search results. Preserve exact Given/When/Then language.
229
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
230
+
231
+ 'architecture': `You are synthesizing a context injection from architecture documentation (C4 model, Structurizr, arc42, or similar).
232
+
233
+ Task: {query}
234
+ {fileContext}
235
+
236
+ Search results:
237
+ {results}
238
+
239
+ Structure as:
240
+
241
+ ## System Overview
242
+ - [Systems, containers, and their purposes]
243
+
244
+ ## Components
245
+ - [Key components and their responsibilities]
246
+
247
+ ## Relationships
248
+ - [How components interact — protocols, data flow]
249
+
250
+ ## Constraints
251
+ - [Technology choices, deployment requirements, quality attributes]
252
+
253
+ Only include what's IN the search results. Preserve exact component and system names.
254
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
255
+
256
+ 'pkm': `You are synthesizing a context injection from a personal knowledge base (Obsidian, Logseq, Foam, or similar PKM vault).
257
+
258
+ Task: {query}
259
+ {fileContext}
260
+
261
+ Search results:
262
+ {results}
263
+
264
+ Structure as:
265
+
266
+ ## Key Insights
267
+ - [Main ideas and conclusions relevant to the task]
268
+
269
+ ## Decisions & Agreements
270
+ - [Any decisions, commitments, or agreements captured in the notes]
271
+
272
+ ## Connected Topics
273
+ - [Related notes, linked concepts, and cross-references mentioned]
274
+
275
+ ## Context & Background
276
+ - [Relevant context, meeting notes, or research findings]
277
+
278
+ Only include what's IN the search results. Preserve note titles and link references.
279
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
280
+
281
+ 'project-docs': `You are synthesizing a context injection from internal project documentation that contains both specifications and code examples.
282
+
283
+ Task: {query}
284
+ {fileContext}
285
+
286
+ Search results from project docs:
287
+ {results}
288
+
289
+ Structure as:
290
+
291
+ ## Requirements & Decisions
292
+ - [Relevant requirements, acceptance criteria, or architectural decisions]
293
+
294
+ ## Implementation Notes
295
+ - [Code patterns, conventions, or technical constraints from the project]
296
+
297
+ ## Code Context
298
+ [Relevant code examples from the project docs -- not from external frameworks]
299
+
300
+ ## Dependencies & Risks
301
+ - [Related components, migration concerns, or known issues]
302
+
303
+ Only include what's IN the search results. Don't add external knowledge.
304
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
305
+
306
+ 'wiki': `You are synthesizing a context injection from general documentation.
307
+
308
+ Task: {query}
309
+ {fileContext}
310
+
311
+ Search results:
312
+ {results}
313
+
314
+ Structure as:
315
+
316
+ ## Summary
317
+ - [Key points relevant to the task]
318
+
319
+ ## Details
320
+ - [Specific information the agent needs]
321
+
322
+ ## Related
323
+ - [Connected topics or references mentioned]
324
+
325
+ Only include what's IN the search results.
326
+ If not relevant: NO_RELEVANT_KNOWLEDGE`,
327
+ };
328
+
329
+ /**
330
+ * Get the synthesis prompt for a source type.
331
+ * Falls back to 'wiki' template for unknown types.
332
+ *
333
+ * @param {string} sourceType
334
+ * @param {object} vars - { query, file, results }
335
+ * @returns {string} filled prompt
336
+ */
337
+ export function getSynthesisPrompt(sourceType, vars) {
338
+ const template = SYNTHESIS_TEMPLATES[sourceType] ?? SYNTHESIS_TEMPLATES['wiki'];
339
+ // Sanitize inputs: length-limit to prevent prompt injection and context overflow
340
+ const query = String(vars.query ?? '').slice(0, 500);
341
+ const file = vars.file ? `File: ${String(vars.file).slice(0, 200)}` : '';
342
+ const results = String(vars.results ?? '').slice(0, 10000);
343
+ return template
344
+ .replace('{query}', query)
345
+ .replace('{fileContext}', file)
346
+ .replace('{results}', results);
347
+ }
348
+
349
+ /**
350
+ * Detect the majority source type from search result metadata.
351
+ * @param {Array} results - search results with metadata
352
+ * @returns {string|null} majority source type or null
353
+ */
354
+ export function detectResultSourceType(results) {
355
+ const counts = {};
356
+ for (const r of results) {
357
+ const st = r.metadata?.sourceType ?? r.metadata?.sourceName;
358
+ if (st) counts[st] = (counts[st] ?? 0) + 1;
359
+ }
360
+ if (Object.keys(counts).length === 0) return null;
361
+
362
+ // Return the most frequent
363
+ return Object.entries(counts).sort((a, b) => b[1] - a[1])[0][0];
364
+ }
@@ -0,0 +1,70 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import https from 'https';
4
+ import { SKILL_REGISTRY } from './registry/skills.js';
5
+ import { BookLibIndexer } from './engine/indexer.js';
6
+ import { resolveBookLibPaths } from './paths.js';
7
+
8
+ /**
9
+ * Handles adding new skills from the registry or external URLs.
10
+ */
11
+ export class BookLibInstaller {
12
+ constructor() {
13
+ this.indexer = new BookLibIndexer();
14
+ }
15
+
16
+ async add(skillId) {
17
+ const registryEntry = SKILL_REGISTRY.find(s => s.id === skillId);
18
+ let url = registryEntry ? registryEntry.url : skillId;
19
+
20
+ if (!url.startsWith('http')) {
21
+ throw new Error(`Invalid skill ID or URL: ${skillId}`);
22
+ }
23
+
24
+ console.log(`Fetching skill from ${url}...`);
25
+ let content = await this.fetchUrl(url);
26
+
27
+ // Universal Adapter: Ensure the content is wrapped in BookLib tags for retrieval
28
+ if (!content.includes('<framework>') && !content.includes('<core_principles>')) {
29
+ console.log('External skill detected. Applying Universal Wrap...');
30
+ content = `
31
+ ---
32
+ name: ${registryEntry ? registryEntry.id : 'external-skill'}
33
+ source: ${url}
34
+ ---
35
+
36
+ # ${registryEntry ? registryEntry.name : 'External Skill'}
37
+
38
+ <framework>
39
+ ${content}
40
+ </framework>
41
+
42
+ > **Note**: This skill was automatically optimized by the BookLib Universal Engine.
43
+ `;
44
+ }
45
+
46
+ const { cachePath } = resolveBookLibPaths();
47
+ const targetDir = path.join(cachePath, 'skills', registryEntry ? registryEntry.name : 'external');
48
+ if (!fs.existsSync(targetDir)) {
49
+ fs.mkdirSync(targetDir, { recursive: true });
50
+ }
51
+
52
+ const targetFile = path.join(targetDir, 'SKILL.md');
53
+ fs.writeFileSync(targetFile, content);
54
+ console.log(`Skill saved to ${targetFile}`);
55
+
56
+ console.log('Re-indexing to include new skill...');
57
+ await this.indexer.indexDirectory(targetDir);
58
+ console.log('Success.');
59
+ }
60
+
61
+ fetchUrl(url) {
62
+ return new Promise((resolve, reject) => {
63
+ https.get(url, (res) => {
64
+ let data = '';
65
+ res.on('data', (chunk) => data += chunk);
66
+ res.on('end', () => resolve(data));
67
+ }).on('error', reject);
68
+ });
69
+ }
70
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns CLI command instructions for non-MCP tools.
3
+ * MCP-capable tools return null — they discover BookLib via MCP protocol.
4
+ *
5
+ * @param {string} target - Tool target (claude, cursor, junie, etc.)
6
+ * @returns {string|null} Markdown block for non-MCP tools, null for MCP tools
7
+ */
8
+
9
+ const MCP_TOOLS = new Set([
10
+ 'claude', 'cursor', 'copilot', 'gemini', 'codex',
11
+ 'windsurf', 'roo-code', 'goose', 'zed', 'continue',
12
+ ]);
13
+
14
+ export function renderInstinctBlock(target) {
15
+ if (MCP_TOOLS.has(target)) return null;
16
+
17
+ return `## BookLib
18
+ Run \`booklib search "query"\` for relevant principles.
19
+ Run \`booklib capture --title "..." --type decision\` to save knowledge.
20
+ Run \`booklib doctor\` for health check.`;
21
+ }