@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.
- package/CHANGELOG.md +285 -0
- package/LICENSE +21 -0
- package/README.ja.md +14 -0
- package/README.ko.md +14 -0
- package/README.md +227 -0
- package/README.pt-BR.md +14 -0
- package/README.skills.md +50 -0
- package/README.uk.md +14 -0
- package/README.zh-CN.md +14 -0
- package/bin/booklib-mcp.js +458 -0
- package/bin/booklib.js +2394 -0
- package/bin/skills.cjs +1292 -0
- package/community/registry.json +1616 -0
- package/hooks/hooks.json +52 -0
- package/hooks/posttooluse-capture.mjs +67 -0
- package/hooks/posttooluse-contradict.mjs +76 -0
- package/hooks/posttooluse-imports.mjs +67 -0
- package/hooks/pretooluse-inject.mjs +82 -0
- package/hooks/suggest.js +153 -0
- package/lib/agent-detector.js +96 -0
- package/lib/config-loader.js +39 -0
- package/lib/conflict-resolver.js +148 -0
- package/lib/connectors/context7.js +167 -0
- package/lib/connectors/github.js +223 -0
- package/lib/connectors/local.js +120 -0
- package/lib/connectors/notion.js +436 -0
- package/lib/connectors/web.js +134 -0
- package/lib/context-builder.js +574 -0
- package/lib/discovery-engine.js +298 -0
- package/lib/doctor/hook-installer.js +83 -0
- package/lib/doctor/usage-tracker.js +87 -0
- package/lib/engine/auditor.js +103 -0
- package/lib/engine/auto-linker.js +177 -0
- package/lib/engine/bm25-index.js +178 -0
- package/lib/engine/capture.js +120 -0
- package/lib/engine/context-map.js +641 -0
- package/lib/engine/corrections.js +194 -0
- package/lib/engine/decision-checker.js +203 -0
- package/lib/engine/doctor.js +207 -0
- package/lib/engine/embedding-provider.js +72 -0
- package/lib/engine/gap-detector.js +138 -0
- package/lib/engine/gap-resolver.js +135 -0
- package/lib/engine/graph-injector.js +137 -0
- package/lib/engine/graph-search.js +183 -0
- package/lib/engine/graph.js +170 -0
- package/lib/engine/handoff.js +411 -0
- package/lib/engine/import-checker.js +249 -0
- package/lib/engine/import-parser.js +145 -0
- package/lib/engine/indexer.js +334 -0
- package/lib/engine/lookup-priority.js +15 -0
- package/lib/engine/parser.js +257 -0
- package/lib/engine/principle-extractor.js +116 -0
- package/lib/engine/project-analyzer.js +353 -0
- package/lib/engine/query-expander.js +42 -0
- package/lib/engine/reasoning-modes.js +353 -0
- package/lib/engine/registries.js +524 -0
- package/lib/engine/reranker.js +45 -0
- package/lib/engine/rrf.js +59 -0
- package/lib/engine/scanner.js +151 -0
- package/lib/engine/searcher.js +223 -0
- package/lib/engine/session-coordinator.js +291 -0
- package/lib/engine/session-manager.js +375 -0
- package/lib/engine/source-detector.js +240 -0
- package/lib/engine/source-manager.js +142 -0
- package/lib/engine/structured-response.js +47 -0
- package/lib/engine/synthesis-templates.js +364 -0
- package/lib/installer.js +70 -0
- package/lib/instinct-block.js +21 -0
- package/lib/mcp-config-writer.js +107 -0
- package/lib/paths.js +62 -0
- package/lib/project-initializer.js +856 -0
- package/lib/registry/skills.js +102 -0
- package/lib/registry-searcher.js +107 -0
- package/lib/rules/rules-manager.js +169 -0
- package/lib/skill-fetcher.js +333 -0
- package/lib/well-known-builder.js +74 -0
- package/lib/wizard/index.js +1389 -0
- package/lib/wizard/integration-detector.js +41 -0
- package/lib/wizard/project-detector.js +146 -0
- package/lib/wizard/prompt.js +221 -0
- package/lib/wizard/registry-embeddings.js +107 -0
- package/lib/wizard/skill-recommender.js +69 -0
- package/package.json +70 -0
- package/skills/animation-at-work/SKILL.md +270 -0
- package/skills/animation-at-work/assets/example_asset.txt +1 -0
- package/skills/animation-at-work/evals/evals.json +44 -0
- package/skills/animation-at-work/evals/results.json +13 -0
- package/skills/animation-at-work/examples/after.md +64 -0
- package/skills/animation-at-work/examples/before.md +35 -0
- package/skills/animation-at-work/references/api_reference.md +369 -0
- package/skills/animation-at-work/references/review-checklist.md +79 -0
- package/skills/animation-at-work/scripts/audit_animations.py +295 -0
- package/skills/animation-at-work/scripts/example.py +1 -0
- package/skills/booklib-mcp-guide/SKILL.md +129 -0
- package/skills/booklib-mcp-guide/evals/evals.json +37 -0
- package/skills/booklib-mcp-guide/examples/after.md +34 -0
- package/skills/booklib-mcp-guide/examples/before.md +27 -0
- package/skills/booklib-mcp-guide/references/tool-catalog.md +9 -0
- package/skills/clean-code-reviewer/SKILL.md +444 -0
- package/skills/clean-code-reviewer/audit.json +35 -0
- package/skills/clean-code-reviewer/evals/evals.json +185 -0
- package/skills/clean-code-reviewer/evals/results.json +13 -0
- package/skills/clean-code-reviewer/examples/after.md +48 -0
- package/skills/clean-code-reviewer/examples/before.md +33 -0
- package/skills/clean-code-reviewer/references/api_reference.md +158 -0
- package/skills/clean-code-reviewer/references/practices-catalog.md +282 -0
- package/skills/clean-code-reviewer/references/review-checklist.md +254 -0
- package/skills/clean-code-reviewer/scripts/pre-review.py +206 -0
- package/skills/data-intensive-patterns/SKILL.md +267 -0
- package/skills/data-intensive-patterns/assets/example_asset.txt +1 -0
- package/skills/data-intensive-patterns/evals/evals.json +54 -0
- package/skills/data-intensive-patterns/evals/results.json +13 -0
- package/skills/data-intensive-patterns/examples/after.md +61 -0
- package/skills/data-intensive-patterns/examples/before.md +38 -0
- package/skills/data-intensive-patterns/references/api_reference.md +34 -0
- package/skills/data-intensive-patterns/references/patterns-catalog.md +551 -0
- package/skills/data-intensive-patterns/references/review-checklist.md +193 -0
- package/skills/data-intensive-patterns/scripts/adr.py +213 -0
- package/skills/data-intensive-patterns/scripts/example.py +1 -0
- package/skills/data-pipelines/SKILL.md +259 -0
- package/skills/data-pipelines/assets/example_asset.txt +1 -0
- package/skills/data-pipelines/evals/evals.json +45 -0
- package/skills/data-pipelines/evals/results.json +13 -0
- package/skills/data-pipelines/examples/after.md +97 -0
- package/skills/data-pipelines/examples/before.md +37 -0
- package/skills/data-pipelines/references/api_reference.md +301 -0
- package/skills/data-pipelines/references/review-checklist.md +181 -0
- package/skills/data-pipelines/scripts/example.py +1 -0
- package/skills/data-pipelines/scripts/new_pipeline.py +444 -0
- package/skills/design-patterns/SKILL.md +271 -0
- package/skills/design-patterns/assets/example_asset.txt +1 -0
- package/skills/design-patterns/evals/evals.json +46 -0
- package/skills/design-patterns/evals/results.json +13 -0
- package/skills/design-patterns/examples/after.md +52 -0
- package/skills/design-patterns/examples/before.md +29 -0
- package/skills/design-patterns/references/api_reference.md +1 -0
- package/skills/design-patterns/references/patterns-catalog.md +726 -0
- package/skills/design-patterns/references/review-checklist.md +173 -0
- package/skills/design-patterns/scripts/example.py +1 -0
- package/skills/design-patterns/scripts/scaffold.py +807 -0
- package/skills/domain-driven-design/SKILL.md +142 -0
- package/skills/domain-driven-design/assets/example_asset.txt +1 -0
- package/skills/domain-driven-design/evals/evals.json +48 -0
- package/skills/domain-driven-design/evals/results.json +13 -0
- package/skills/domain-driven-design/examples/after.md +80 -0
- package/skills/domain-driven-design/examples/before.md +43 -0
- package/skills/domain-driven-design/references/api_reference.md +1 -0
- package/skills/domain-driven-design/references/patterns-catalog.md +545 -0
- package/skills/domain-driven-design/references/review-checklist.md +158 -0
- package/skills/domain-driven-design/scripts/example.py +1 -0
- package/skills/domain-driven-design/scripts/scaffold.py +421 -0
- package/skills/effective-java/SKILL.md +227 -0
- package/skills/effective-java/assets/example_asset.txt +1 -0
- package/skills/effective-java/evals/evals.json +46 -0
- package/skills/effective-java/evals/results.json +13 -0
- package/skills/effective-java/examples/after.md +83 -0
- package/skills/effective-java/examples/before.md +37 -0
- package/skills/effective-java/references/api_reference.md +1 -0
- package/skills/effective-java/references/items-catalog.md +955 -0
- package/skills/effective-java/references/review-checklist.md +216 -0
- package/skills/effective-java/scripts/checkstyle_setup.py +211 -0
- package/skills/effective-java/scripts/example.py +1 -0
- package/skills/effective-kotlin/SKILL.md +271 -0
- package/skills/effective-kotlin/assets/example_asset.txt +1 -0
- package/skills/effective-kotlin/audit.json +29 -0
- package/skills/effective-kotlin/evals/evals.json +45 -0
- package/skills/effective-kotlin/evals/results.json +13 -0
- package/skills/effective-kotlin/examples/after.md +36 -0
- package/skills/effective-kotlin/examples/before.md +38 -0
- package/skills/effective-kotlin/references/api_reference.md +1 -0
- package/skills/effective-kotlin/references/practices-catalog.md +1228 -0
- package/skills/effective-kotlin/references/review-checklist.md +126 -0
- package/skills/effective-kotlin/scripts/example.py +1 -0
- package/skills/effective-python/SKILL.md +441 -0
- package/skills/effective-python/evals/evals.json +44 -0
- package/skills/effective-python/evals/results.json +13 -0
- package/skills/effective-python/examples/after.md +56 -0
- package/skills/effective-python/examples/before.md +40 -0
- package/skills/effective-python/ref-01-pythonic-thinking.md +202 -0
- package/skills/effective-python/ref-02-lists-and-dicts.md +146 -0
- package/skills/effective-python/ref-03-functions.md +186 -0
- package/skills/effective-python/ref-04-comprehensions-generators.md +211 -0
- package/skills/effective-python/ref-05-classes-interfaces.md +188 -0
- package/skills/effective-python/ref-06-metaclasses-attributes.md +209 -0
- package/skills/effective-python/ref-07-concurrency.md +213 -0
- package/skills/effective-python/ref-08-robustness-performance.md +248 -0
- package/skills/effective-python/ref-09-testing-debugging.md +253 -0
- package/skills/effective-python/ref-10-collaboration.md +175 -0
- package/skills/effective-python/references/api_reference.md +218 -0
- package/skills/effective-python/references/practices-catalog.md +483 -0
- package/skills/effective-python/references/review-checklist.md +190 -0
- package/skills/effective-python/scripts/lint.py +173 -0
- package/skills/effective-typescript/SKILL.md +262 -0
- package/skills/effective-typescript/audit.json +29 -0
- package/skills/effective-typescript/evals/evals.json +37 -0
- package/skills/effective-typescript/evals/results.json +13 -0
- package/skills/effective-typescript/examples/after.md +70 -0
- package/skills/effective-typescript/examples/before.md +47 -0
- package/skills/effective-typescript/references/api_reference.md +118 -0
- package/skills/effective-typescript/references/practices-catalog.md +371 -0
- package/skills/effective-typescript/scripts/review.py +169 -0
- package/skills/kotlin-in-action/SKILL.md +261 -0
- package/skills/kotlin-in-action/assets/example_asset.txt +1 -0
- package/skills/kotlin-in-action/evals/evals.json +43 -0
- package/skills/kotlin-in-action/evals/results.json +13 -0
- package/skills/kotlin-in-action/examples/after.md +53 -0
- package/skills/kotlin-in-action/examples/before.md +39 -0
- package/skills/kotlin-in-action/references/api_reference.md +1 -0
- package/skills/kotlin-in-action/references/practices-catalog.md +436 -0
- package/skills/kotlin-in-action/references/review-checklist.md +204 -0
- package/skills/kotlin-in-action/scripts/example.py +1 -0
- package/skills/kotlin-in-action/scripts/setup_detekt.py +224 -0
- package/skills/lean-startup/SKILL.md +160 -0
- package/skills/lean-startup/assets/example_asset.txt +1 -0
- package/skills/lean-startup/evals/evals.json +43 -0
- package/skills/lean-startup/evals/results.json +13 -0
- package/skills/lean-startup/examples/after.md +80 -0
- package/skills/lean-startup/examples/before.md +34 -0
- package/skills/lean-startup/references/api_reference.md +319 -0
- package/skills/lean-startup/references/review-checklist.md +137 -0
- package/skills/lean-startup/scripts/example.py +1 -0
- package/skills/lean-startup/scripts/new_experiment.py +286 -0
- package/skills/microservices-patterns/SKILL.md +384 -0
- package/skills/microservices-patterns/evals/evals.json +45 -0
- package/skills/microservices-patterns/evals/results.json +13 -0
- package/skills/microservices-patterns/examples/after.md +69 -0
- package/skills/microservices-patterns/examples/before.md +40 -0
- package/skills/microservices-patterns/references/patterns-catalog.md +391 -0
- package/skills/microservices-patterns/references/review-checklist.md +169 -0
- package/skills/microservices-patterns/scripts/new_service.py +583 -0
- package/skills/programming-with-rust/SKILL.md +209 -0
- package/skills/programming-with-rust/evals/evals.json +37 -0
- package/skills/programming-with-rust/evals/results.json +13 -0
- package/skills/programming-with-rust/examples/after.md +107 -0
- package/skills/programming-with-rust/examples/before.md +59 -0
- package/skills/programming-with-rust/references/api_reference.md +152 -0
- package/skills/programming-with-rust/references/practices-catalog.md +335 -0
- package/skills/programming-with-rust/scripts/review.py +142 -0
- package/skills/refactoring-ui/SKILL.md +362 -0
- package/skills/refactoring-ui/assets/example_asset.txt +1 -0
- package/skills/refactoring-ui/evals/evals.json +45 -0
- package/skills/refactoring-ui/evals/results.json +13 -0
- package/skills/refactoring-ui/examples/after.md +85 -0
- package/skills/refactoring-ui/examples/before.md +58 -0
- package/skills/refactoring-ui/references/api_reference.md +355 -0
- package/skills/refactoring-ui/references/review-checklist.md +114 -0
- package/skills/refactoring-ui/scripts/audit_css.py +250 -0
- package/skills/refactoring-ui/scripts/example.py +1 -0
- package/skills/rust-in-action/SKILL.md +350 -0
- package/skills/rust-in-action/evals/evals.json +38 -0
- package/skills/rust-in-action/evals/results.json +13 -0
- package/skills/rust-in-action/examples/after.md +156 -0
- package/skills/rust-in-action/examples/before.md +56 -0
- package/skills/rust-in-action/references/practices-catalog.md +346 -0
- package/skills/rust-in-action/scripts/review.py +147 -0
- package/skills/skill-router/SKILL.md +186 -0
- package/skills/skill-router/evals/evals.json +38 -0
- package/skills/skill-router/evals/results.json +13 -0
- package/skills/skill-router/examples/after.md +63 -0
- package/skills/skill-router/examples/before.md +39 -0
- package/skills/skill-router/references/api_reference.md +24 -0
- package/skills/skill-router/references/routing-heuristics.md +89 -0
- package/skills/skill-router/references/skill-catalog.md +174 -0
- package/skills/skill-router/scripts/route.py +266 -0
- package/skills/spring-boot-in-action/SKILL.md +340 -0
- package/skills/spring-boot-in-action/evals/evals.json +39 -0
- package/skills/spring-boot-in-action/evals/results.json +13 -0
- package/skills/spring-boot-in-action/examples/after.md +185 -0
- package/skills/spring-boot-in-action/examples/before.md +84 -0
- package/skills/spring-boot-in-action/references/practices-catalog.md +403 -0
- package/skills/spring-boot-in-action/scripts/review.py +184 -0
- package/skills/storytelling-with-data/SKILL.md +241 -0
- package/skills/storytelling-with-data/assets/example_asset.txt +1 -0
- package/skills/storytelling-with-data/evals/evals.json +47 -0
- package/skills/storytelling-with-data/evals/results.json +13 -0
- package/skills/storytelling-with-data/examples/after.md +50 -0
- package/skills/storytelling-with-data/examples/before.md +33 -0
- package/skills/storytelling-with-data/references/api_reference.md +379 -0
- package/skills/storytelling-with-data/references/review-checklist.md +111 -0
- package/skills/storytelling-with-data/scripts/chart_review.py +301 -0
- package/skills/storytelling-with-data/scripts/example.py +1 -0
- package/skills/system-design-interview/SKILL.md +233 -0
- package/skills/system-design-interview/assets/example_asset.txt +1 -0
- package/skills/system-design-interview/evals/evals.json +46 -0
- package/skills/system-design-interview/evals/results.json +13 -0
- package/skills/system-design-interview/examples/after.md +94 -0
- package/skills/system-design-interview/examples/before.md +27 -0
- package/skills/system-design-interview/references/api_reference.md +582 -0
- package/skills/system-design-interview/references/review-checklist.md +201 -0
- package/skills/system-design-interview/scripts/example.py +1 -0
- package/skills/system-design-interview/scripts/new_design.py +421 -0
- package/skills/using-asyncio-python/SKILL.md +290 -0
- package/skills/using-asyncio-python/assets/example_asset.txt +1 -0
- package/skills/using-asyncio-python/evals/evals.json +43 -0
- package/skills/using-asyncio-python/evals/results.json +13 -0
- package/skills/using-asyncio-python/examples/after.md +68 -0
- package/skills/using-asyncio-python/examples/before.md +39 -0
- package/skills/using-asyncio-python/references/api_reference.md +267 -0
- package/skills/using-asyncio-python/references/review-checklist.md +149 -0
- package/skills/using-asyncio-python/scripts/check_blocking.py +270 -0
- package/skills/using-asyncio-python/scripts/example.py +1 -0
- package/skills/web-scraping-python/SKILL.md +280 -0
- package/skills/web-scraping-python/assets/example_asset.txt +1 -0
- package/skills/web-scraping-python/evals/evals.json +46 -0
- package/skills/web-scraping-python/evals/results.json +13 -0
- package/skills/web-scraping-python/examples/after.md +109 -0
- package/skills/web-scraping-python/examples/before.md +40 -0
- package/skills/web-scraping-python/references/api_reference.md +393 -0
- package/skills/web-scraping-python/references/review-checklist.md +163 -0
- package/skills/web-scraping-python/scripts/example.py +1 -0
- package/skills/web-scraping-python/scripts/new_scraper.py +231 -0
- 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
|
+
}
|
package/lib/installer.js
ADDED
|
@@ -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
|
+
}
|