bluera-knowledge 0.34.1 → 0.35.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 (32) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +21 -0
  3. package/dist/{chunk-V5MWZM5X.js → chunk-DNGE7FZ4.js} +53 -2
  4. package/dist/chunk-DNGE7FZ4.js.map +1 -0
  5. package/dist/{chunk-VELBEZVB.js → chunk-L2SC6J4K.js} +10 -2
  6. package/dist/{chunk-VELBEZVB.js.map → chunk-L2SC6J4K.js.map} +1 -1
  7. package/dist/{chunk-TD3VX74F.js → chunk-MQQ46BST.js} +2 -2
  8. package/dist/index.js +3 -3
  9. package/dist/mcp/server.js +2 -2
  10. package/dist/workers/background-worker-cli.js +2 -2
  11. package/hooks/posttooluse-bk-reminder.py +0 -0
  12. package/hooks/posttooluse-web-research.py +0 -0
  13. package/hooks/posttooluse-websearch-bk.py +0 -0
  14. package/package.json +1 -1
  15. package/python/ast_worker.py +10 -0
  16. package/scripts/auto-setup.sh +3 -0
  17. package/skills/advanced-workflows/SKILL.md +26 -246
  18. package/skills/advanced-workflows/references/examples.md +86 -0
  19. package/skills/eval/SKILL.md +16 -203
  20. package/skills/eval/references/output-format.md +73 -0
  21. package/skills/eval/references/procedures.md +61 -0
  22. package/skills/store-lifecycle/SKILL.md +16 -441
  23. package/skills/store-lifecycle/references/operations.md +75 -0
  24. package/skills/store-lifecycle/references/source-types.md +48 -0
  25. package/skills/test-plugin/SKILL.md +8 -515
  26. package/skills/test-plugin/references/output-format.md +43 -0
  27. package/skills/test-plugin/references/test-procedures.md +107 -0
  28. package/dist/chunk-V5MWZM5X.js.map +0 -1
  29. package/hooks/pretooluse-bk-suggest.py +0 -296
  30. package/hooks/skill-activation.py +0 -221
  31. package/hooks/skill-rules.json +0 -131
  32. /package/dist/{chunk-TD3VX74F.js.map → chunk-MQQ46BST.js.map} +0 -0
@@ -1,296 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- PreToolUse hook for bluera-knowledge plugin.
4
-
5
- Fires before Claude reads/greps in dependency directories.
6
- - If library IS indexed in BK: BLOCKS the read and suggests BK search
7
- - If library NOT indexed: suggests BK but allows the read
8
-
9
- Escape hatch: Set BK_ALLOW_DIRECT_READ=1 env var to bypass all blocking.
10
- """
11
-
12
- import json
13
- import logging
14
- import os
15
- import re
16
- import sys
17
- from pathlib import Path
18
- from typing import TypedDict
19
-
20
-
21
- class StoreDict(TypedDict, total=False):
22
- """Store structure from stores.json."""
23
-
24
- name: str
25
- tags: list[str] | None
26
- url: str | None
27
-
28
-
29
- class ToolInputDict(TypedDict, total=False):
30
- """Tool input structure from hook."""
31
-
32
- path: str # For Grep
33
- file_path: str # For Read
34
-
35
- # Configure logging to stderr (stdout is for hook output)
36
- logging.basicConfig(
37
- level=logging.DEBUG if os.environ.get("BK_DEBUG") else logging.WARNING,
38
- format="%(name)s: %(message)s",
39
- stream=sys.stderr,
40
- )
41
- logger = logging.getLogger("bk-suggest")
42
-
43
- # Dependency path patterns with boundary markers to avoid false positives
44
- # like "my-node_modules-backup/"
45
- DEPENDENCY_PATTERNS = (
46
- "/node_modules/",
47
- "/vendor/",
48
- "/site-packages/",
49
- "/.venv/",
50
- "/venv/",
51
- "/bower_components/",
52
- "/.npm/",
53
- "/.cargo/registry/",
54
- "/go/pkg/mod/",
55
- )
56
-
57
- # Blocking criteria - avoid false positives on ultra-common names
58
- MIN_NAME_LENGTH = 3
59
- COMMON_NAME_DENYLIST = frozenset([
60
- "fs", "os", "core", "util", "utils", "lib", "src", "app", "api",
61
- "test", "tests", "spec", "dist", "build", "bin", "pkg", "mod",
62
- ])
63
-
64
- # Module-level cache for stores.json
65
- _stores_cache: list[StoreDict] = []
66
- _stores_mtime: float = 0.0
67
- _stores_path: Path | None = None
68
-
69
-
70
- def is_dependency_path(path: str) -> bool:
71
- """Return True only if path is inside a dependency directory.
72
-
73
- Uses boundary markers to avoid false positives like 'my-node_modules-backup/'.
74
- """
75
- # Normalize path separators and ensure leading slash for boundary matching
76
- normalized = "/" + path.replace("\\", "/").lower()
77
- return any(pattern in normalized for pattern in DEPENDENCY_PATTERNS)
78
-
79
-
80
- def extract_library_name(path: str) -> str | None:
81
- """Extract library name from dependency path."""
82
- # node_modules/package-name/... or node_modules/@scope/package/...
83
- match = re.search(r"node_modules/(@[^/]+/[^/]+|[^/]+)", path)
84
- if match:
85
- return match.group(1)
86
-
87
- # site-packages/package_name/...
88
- match = re.search(r"site-packages/([^/]+)", path)
89
- if match:
90
- return match.group(1)
91
-
92
- # vendor/package/...
93
- match = re.search(r"vendor/([^/]+)", path)
94
- if match:
95
- return match.group(1)
96
-
97
- # .cargo/registry/.../package-name-version/...
98
- match = re.search(r"\.cargo/registry/[^/]+/([^/]+)-\d", path)
99
- if match:
100
- return match.group(1)
101
-
102
- # go/pkg/mod/package@version/...
103
- match = re.search(r"go/pkg/mod/([^@]+)@", path)
104
- if match:
105
- return match.group(1)
106
-
107
- return None
108
-
109
-
110
- def normalize_name(name: str) -> str:
111
- """Normalize library name for matching.
112
-
113
- - Strips scope: @scope/pkg -> pkg
114
- - Removes hyphens and underscores
115
- - Lowercases
116
- """
117
- # Strip scope: @scope/pkg -> pkg
118
- if "/" in name:
119
- name = name.split("/")[-1]
120
- # Remove hyphens, underscores, lowercase
121
- return name.replace("-", "").replace("_", "").lower()
122
-
123
-
124
- def extract_repo_name(url: str | None) -> str | None:
125
- """Extract repo name from URL like github.com/owner/repo."""
126
- if not url:
127
- return None
128
- # github.com/owner/repo -> repo
129
- # github.com/owner/repo.git -> repo
130
- match = re.search(r"/([^/]+?)(?:\.git)?$", url)
131
- return match.group(1) if match else None
132
-
133
-
134
- def get_stores_path() -> Path | None:
135
- """Get path to stores.json from project root."""
136
- project_root = os.environ.get("PROJECT_ROOT") or os.environ.get("PWD")
137
- if not project_root:
138
- return None
139
- return Path(project_root) / ".bluera" / "bluera-knowledge" / "data" / "stores.json"
140
-
141
-
142
- def load_stores(stores_path: Path) -> list[StoreDict]:
143
- """Load stores from stores.json. Returns empty list on error."""
144
- if not stores_path.exists():
145
- logger.debug("stores.json not found: %s", stores_path)
146
- return []
147
-
148
- try:
149
- with open(stores_path, encoding="utf-8") as f:
150
- data = json.load(f)
151
- # Registry format: {"version": 1, "stores": [...]}
152
- if isinstance(data, dict):
153
- stores = data.get("stores", [])
154
- return stores if isinstance(stores, list) else []
155
- # Direct list format: [...]
156
- return data if isinstance(data, list) else []
157
- except (json.JSONDecodeError, IOError, OSError) as e:
158
- logger.debug("Failed to read stores.json: %s", e)
159
- return []
160
-
161
-
162
- def get_cached_stores() -> list[StoreDict]:
163
- """Get stores with mtime-based cache invalidation."""
164
- global _stores_cache, _stores_mtime, _stores_path
165
-
166
- if _stores_path is None:
167
- _stores_path = get_stores_path()
168
- if _stores_path is None:
169
- logger.debug("No project root found, skipping store check")
170
- return []
171
-
172
- try:
173
- current_mtime = _stores_path.stat().st_mtime
174
- if current_mtime != _stores_mtime:
175
- logger.debug(
176
- "Cache refresh: stores.json mtime changed (%.3f -> %.3f)",
177
- _stores_mtime,
178
- current_mtime,
179
- )
180
- _stores_cache = load_stores(_stores_path)
181
- _stores_mtime = current_mtime
182
- except (OSError, FileNotFoundError):
183
- _stores_cache = []
184
- _stores_mtime = 0.0
185
-
186
- return _stores_cache
187
-
188
-
189
- def library_is_indexed(lib_name: str, stores: list[StoreDict]) -> str | None:
190
- """Return matching store name if library is indexed, None otherwise.
191
-
192
- Denylist is soft - if an EXACT store name match exists,
193
- the denylist is overridden (user explicitly created a store for that name).
194
- Tag/URL fuzzy matching is skipped for denylisted names.
195
- """
196
- if len(lib_name) < MIN_NAME_LENGTH:
197
- return None # Too short, skip
198
-
199
- normalized = normalize_name(lib_name)
200
- is_denylisted = lib_name.lower() in COMMON_NAME_DENYLIST
201
-
202
- for store in stores:
203
- store_name = store.get("name", "")
204
-
205
- # Check store name - exact match overrides denylist
206
- if normalize_name(store_name) == normalized:
207
- return store_name
208
-
209
- # If denylisted, skip tag/URL fuzzy matching (only exact store name counts)
210
- if is_denylisted:
211
- continue
212
-
213
- # Check tags (only if not denylisted)
214
- for tag in store.get("tags") or []:
215
- if normalize_name(tag) == normalized:
216
- return store_name
217
-
218
- # Check repo URL (only if not denylisted)
219
- repo_name = extract_repo_name(store.get("url"))
220
- if repo_name and normalize_name(repo_name) == normalized:
221
- return store_name
222
-
223
- return None
224
-
225
-
226
- def get_path_from_input(tool_name: str, tool_input: ToolInputDict) -> str | None:
227
- """Extract the path being accessed from tool input."""
228
- if tool_name == "Grep":
229
- return tool_input.get("path", "")
230
- elif tool_name == "Read":
231
- return tool_input.get("file_path", "")
232
- return None
233
-
234
-
235
- def main() -> int:
236
- try:
237
- # Escape hatch: bypass all blocking if env var is set
238
- if os.environ.get("BK_ALLOW_DIRECT_READ"):
239
- logger.debug("Escape hatch: BK_ALLOW_DIRECT_READ env var set, bypassing")
240
- return 0
241
-
242
- stdin_data = sys.stdin.read()
243
- if not stdin_data.strip():
244
- return 0
245
- hook_input = json.loads(stdin_data)
246
-
247
- tool_name = hook_input.get("tool_name", "")
248
- tool_input = hook_input.get("tool_input", {})
249
-
250
- path = get_path_from_input(tool_name, tool_input)
251
- if not path:
252
- return 0
253
-
254
- # Fast path: skip if not a dependency path (with boundary checking)
255
- if not is_dependency_path(path):
256
- return 0
257
-
258
- lib_name = extract_library_name(path)
259
- if not lib_name:
260
- return 0
261
-
262
- # Check if library is indexed in BK
263
- stores = get_cached_stores()
264
- matching_store = library_is_indexed(lib_name, stores)
265
-
266
- if matching_store:
267
- # BLOCK: Library is indexed, force BK usage
268
- reason = f"'{lib_name}' is indexed in BK store '{matching_store}'. Use BK search tool instead."
269
- output = {
270
- "hookSpecificOutput": {
271
- "hookEventName": "PreToolUse",
272
- "permissionDecision": "deny",
273
- "reasonForDecision": reason,
274
- }
275
- }
276
- print(json.dumps(output))
277
- else:
278
- # SUGGEST: Library not indexed, allow but suggest
279
- suggestion = f"TIP: '{lib_name}' isn't indexed in BK. Consider /bluera-knowledge:add-repo after this task."
280
- output = {
281
- "hookSpecificOutput": {
282
- "hookEventName": "PreToolUse",
283
- "additionalContext": suggestion,
284
- }
285
- }
286
- print(json.dumps(output))
287
-
288
- return 0
289
-
290
- except Exception as e:
291
- logger.debug("Hook error, allowing: %s", e)
292
- return 0 # Never block on unexpected errors
293
-
294
-
295
- if __name__ == "__main__":
296
- raise SystemExit(main())
@@ -1,221 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Skill activation hook for bluera-knowledge plugin.
4
- Matches user prompts against skill rules and injects activation reminders.
5
-
6
- Runs on UserPromptSubmit to detect users who would benefit from learning
7
- about BK skills, while excluding users who already know BK terminology.
8
- """
9
-
10
- import json
11
- import os
12
- import re
13
- import sys
14
- from pathlib import Path
15
- from typing import Any
16
-
17
- DEFAULT_CONFIG: dict[str, Any] = {
18
- "enabled": True,
19
- "threshold": 1,
20
- "skills": {
21
- "knowledge-search": True,
22
- "when-to-query": True,
23
- "search-optimization": True,
24
- "advanced-workflows": True,
25
- "store-lifecycle": True,
26
- },
27
- }
28
-
29
-
30
- def get_project_root() -> Path | None:
31
- """Get project root from environment variables (per-repo config)."""
32
- # Check environment variables in priority order
33
- for env_var in ["PROJECT_ROOT", "PWD"]:
34
- value = os.environ.get(env_var, "")
35
- if value:
36
- return Path(value)
37
- return None
38
-
39
-
40
- def get_config_path() -> Path | None:
41
- """Get per-repo config path for skill activation."""
42
- project_root = get_project_root()
43
- if project_root is None:
44
- return None
45
- return project_root / ".bluera" / "bluera-knowledge" / "skill-activation.json"
46
-
47
-
48
- def load_config() -> dict[str, Any]:
49
- """Load skill activation configuration from per-repo path."""
50
- config_path = get_config_path()
51
- if config_path is None or not config_path.exists():
52
- return DEFAULT_CONFIG.copy()
53
- try:
54
- with open(config_path, encoding="utf-8") as f:
55
- return json.load(f)
56
- except (json.JSONDecodeError, IOError):
57
- return DEFAULT_CONFIG.copy()
58
-
59
-
60
- def load_rules(plugin_root: Path) -> dict[str, Any]:
61
- """Load skill rules from plugin hooks directory."""
62
- rules_path = plugin_root / "hooks" / "skill-rules.json"
63
- if not rules_path.exists():
64
- return {"skills": [], "threshold": 1, "globalExclusions": []}
65
- with open(rules_path, encoding="utf-8") as f:
66
- return json.load(f)
67
-
68
-
69
- def matches_condition(prompt: str, condition: dict[str, Any]) -> bool:
70
- """Check if prompt matches a single condition (keyword or regex)."""
71
- prompt_lower = prompt.lower()
72
- if "keyword" in condition:
73
- return condition["keyword"].lower() in prompt_lower
74
- if "regex" in condition:
75
- return bool(re.search(condition["regex"], prompt, flags=re.IGNORECASE))
76
- return False
77
-
78
-
79
- def check_exclusions(
80
- prompt: str, exclusions: list[dict[str, Any]]
81
- ) -> bool:
82
- """Check if any exclusion pattern matches. Returns True if excluded."""
83
- for exc in exclusions:
84
- if matches_condition(prompt, exc):
85
- return True
86
- return False
87
-
88
-
89
- def score_skill(
90
- prompt: str, skill: dict[str, Any]
91
- ) -> tuple[int, list[str]]:
92
- """Score a skill against the user prompt. Returns (score, reasons)."""
93
- reasons: list[str] = []
94
- score = 0
95
-
96
- # Check skill-specific exclusions first
97
- if check_exclusions(prompt, skill.get("exclusions", [])):
98
- return 0, []
99
-
100
- for trigger in skill.get("triggers", []):
101
- if matches_condition(prompt, trigger):
102
- weight = trigger.get("weight", 1)
103
- score += weight
104
- if "keyword" in trigger:
105
- reasons.append(f'keyword "{trigger["keyword"]}"')
106
- elif "regex" in trigger:
107
- reasons.append(f'pattern match')
108
-
109
- return score, reasons
110
-
111
-
112
- def generate_reminder(
113
- matches: list[tuple[str, int, list[str], str]]
114
- ) -> str:
115
- """Generate assertive skill activation reminder using forced evaluation pattern."""
116
- lines = [
117
- "CRITICAL DIRECTIVE: Library/Dependency Question Detected",
118
- "",
119
- "BEFORE answering, you MUST:",
120
- "",
121
- "1. CHECK if a bluera-knowledge store exists for this library:",
122
- " → Use mcp__bluera-knowledge__execute(command='stores') to list indexed libraries",
123
- "",
124
- "2. IF INDEXED: Query the indexed source FIRST:",
125
- " → mcp__bluera-knowledge__search(query='your question', intent='find-implementation')",
126
- " → This is FASTER and more accurate than grepping node_modules/vendor",
127
- "",
128
- "3. IF NOT INDEXED: Suggest adding it:",
129
- " → Tell the user: '/bluera-knowledge:add-repo to index this library for future queries'",
130
- "",
131
- "MATCHED SKILLS (invoke for guidance):",
132
- ]
133
-
134
- for name, score, reasons, description in matches:
135
- lines.append(f" • Skill(skill='bluera-knowledge:{name}') - {description}")
136
- lines.append(f" Triggered by: {', '.join(reasons[:2])}")
137
-
138
- lines.append("")
139
- lines.append("WHY THIS MATTERS:")
140
- lines.append(" - Grepping node_modules is SLOW (reads thousands of files)")
141
- lines.append(" - Indexed search returns pre-chunked, semantic results")
142
- lines.append(" - Token cost is 10-100x lower with indexed search")
143
- lines.append("")
144
- lines.append("FAILURE TO CONSULT INDEXED SOURCES = SUBOPTIMAL RESPONSE")
145
-
146
- return "\n".join(lines)
147
-
148
-
149
- def main() -> int:
150
- # Load configuration
151
- config = load_config()
152
-
153
- # Check if skill activation is enabled
154
- if not config.get("enabled", True):
155
- return 0
156
-
157
- # Get plugin root from environment
158
- plugin_root_env = os.environ.get("CLAUDE_PLUGIN_ROOT", "")
159
- if not plugin_root_env:
160
- return 0
161
- plugin_root = Path(plugin_root_env)
162
-
163
- # Read hook input from stdin
164
- try:
165
- stdin_data = sys.stdin.read()
166
- if not stdin_data.strip():
167
- return 0
168
- hook_input = json.loads(stdin_data)
169
- except json.JSONDecodeError:
170
- return 0
171
-
172
- prompt = hook_input.get("prompt", "")
173
- if not prompt.strip():
174
- return 0
175
-
176
- # Load rules
177
- rules = load_rules(plugin_root)
178
-
179
- # Check global exclusions first
180
- if check_exclusions(prompt, rules.get("globalExclusions", [])):
181
- return 0
182
-
183
- threshold = config.get("threshold", rules.get("threshold", 1))
184
- enabled_skills = config.get("skills", {})
185
-
186
- # Score each skill
187
- matches: list[tuple[str, int, list[str], str]] = []
188
-
189
- for skill in rules.get("skills", []):
190
- name = skill["name"]
191
-
192
- # Skip disabled skills
193
- if not enabled_skills.get(name, True):
194
- continue
195
-
196
- score, reasons = score_skill(prompt, skill)
197
- if score >= threshold:
198
- matches.append((name, score, reasons, skill.get("description", "")))
199
-
200
- # No matches - silent exit
201
- if not matches:
202
- return 0
203
-
204
- # Sort by score (highest first)
205
- matches.sort(key=lambda t: t[1], reverse=True)
206
-
207
- # Generate and output the reminder using proper JSON format
208
- reminder = generate_reminder(matches)
209
- output = {
210
- "hookSpecificOutput": {
211
- "hookEventName": "UserPromptSubmit",
212
- "additionalContext": reminder,
213
- }
214
- }
215
- print(json.dumps(output))
216
-
217
- return 0
218
-
219
-
220
- if __name__ == "__main__":
221
- raise SystemExit(main())
@@ -1,131 +0,0 @@
1
- {
2
- "description": "bluera-knowledge skill activation rules - technology-agnostic patterns for development scenarios",
3
- "version": 2,
4
- "globalExclusions": [
5
- { "keyword": "bluera-knowledge" },
6
- { "keyword": "bluera knowledge" },
7
- { "keyword": "/bluera-knowledge:" },
8
- { "regex": "mcp__.*bluera" }
9
- ],
10
- "threshold": 2,
11
- "skills": [
12
- {
13
- "name": "knowledge-search",
14
- "description": "How to query Bluera Knowledge for library/dependency questions",
15
- "triggers": [
16
- { "regex": "the\\s+\\w+(-\\w+)*\\s+(package|library|module|framework|dependency)", "weight": 3 },
17
- { "regex": "\\w+(-\\w+)*\\s+(package|library|module)\\s+(is|does|keeps|isn't|won't|doesn't)", "weight": 3 },
18
- { "regex": "\\w+(-\\w+)*\\s+(documentation|docs)\\b", "weight": 2 },
19
- { "regex": "error\\s+(from|in|with)\\s+(the\\s+)?\\w+(-\\w+)*\\s+(package|library|module)", "weight": 3 },
20
- { "regex": "(package|library|dependency|module)\\s+(is\\s+)?(throwing|throws|error|failing)", "weight": 3 },
21
- { "regex": "how\\s+does\\s+(the\\s+)?\\w+(-\\w+)*\\s+(package|library|module|framework)\\s+(handle|work|process)", "weight": 3 },
22
- { "regex": "what\\s+does\\s+(the\\s+)?\\w+(-\\w+)*\\s+(package|library)\\s+(do|return|accept)", "weight": 3 },
23
- { "regex": "why\\s+does\\s+(the\\s+)?\\w+(-\\w+)*\\s+(package|library|module)", "weight": 3 },
24
- { "regex": "(configure|config|settings)\\s+(for\\s+)?(the\\s+)?\\w+(-\\w+)*\\s+(package|library)", "weight": 3 },
25
- { "regex": "(upgraded?|updated?)\\s+(the\\s+)?\\w+(-\\w+)*\\s+(package|library|dependency)", "weight": 2 },
26
- { "regex": "integrate\\s+(the\\s+)?\\w+(-\\w+)*\\s+(package|library)", "weight": 2 },
27
- { "regex": "dependency\\s+(is|keeps|isn't|won't|error|issue|problem)", "weight": 2 },
28
- { "regex": "third[- ]party\\s+(library|package|code)", "weight": 2 },
29
- { "regex": "look\\s+(at|in|into)\\s+(the\\s+)?\\w+(-\\w+)*\\s+(source|code|internals)", "weight": 3 },
30
- { "regex": "\\w+(-\\w+)*\\s+source\\s+code", "weight": 2 },
31
- { "regex": "(find|show|get)\\s+(me\\s+)?(the\\s+)?\\w+(-\\w+)*\\s+(implementation|source|code)", "weight": 3 },
32
- { "regex": "TypeError|ImportError|ModuleNotFoundError|AttributeError", "weight": 2 },
33
- { "regex": "\\w+(-\\w+)*\\s+is\\s+(deprecated|removed|changed)", "weight": 2 },
34
- { "regex": "breaking\\s+change.*(\\w+(-\\w+)*\\s+)?(package|library|dependency)", "weight": 3 },
35
- { "regex": "migrate\\s+(from|to)\\s+\\w+(-\\w+)*", "weight": 2 }
36
- ],
37
- "exclusions": [
38
- { "keyword": "my code" },
39
- { "keyword": "our code" },
40
- { "keyword": "this function" },
41
- { "keyword": "this file" },
42
- { "keyword": "this component" },
43
- { "keyword": "this class" },
44
- { "keyword": "this project" },
45
- { "keyword": "I wrote" },
46
- { "keyword": "we wrote" },
47
- { "keyword": "my implementation" },
48
- { "keyword": "store" },
49
- { "keyword": "index" },
50
- { "keyword": "in my" },
51
- { "keyword": "in our" }
52
- ]
53
- },
54
- {
55
- "name": "when-to-query",
56
- "description": "Decision guide for Bluera Knowledge vs Grep/Read",
57
- "triggers": [
58
- { "keyword": "should i grep", "weight": 2 },
59
- { "keyword": "where should i look", "weight": 2 },
60
- { "keyword": "grep or search", "weight": 2 },
61
- { "keyword": "search or grep", "weight": 2 },
62
- { "regex": "where\\s+(should|do)\\s+i\\s+(find|look)\\s+.*(library|package|dependency)", "weight": 3 },
63
- { "regex": "is\\s+there\\s+a\\s+better\\s+way\\s+to\\s+(search|find)", "weight": 2 },
64
- { "regex": "should\\s+i\\s+(use\\s+)?grep\\s+(for|to)", "weight": 2 },
65
- { "regex": "how\\s+(do|should)\\s+i\\s+find.*(in|from)\\s+(a\\s+)?(library|package|dependency)", "weight": 3 }
66
- ],
67
- "exclusions": [
68
- { "keyword": "store" },
69
- { "keyword": "index" }
70
- ]
71
- },
72
- {
73
- "name": "search-optimization",
74
- "description": "Optimizing search parameters and token usage",
75
- "triggers": [
76
- { "keyword": "too many results", "weight": 2 },
77
- { "keyword": "too few results", "weight": 2 },
78
- { "keyword": "limit results", "weight": 2 },
79
- { "keyword": "reduce tokens", "weight": 2 },
80
- { "keyword": "token usage", "weight": 2 },
81
- { "keyword": "optimize search", "weight": 2 },
82
- { "keyword": "detail level", "weight": 2 },
83
- { "regex": "\\b(minimal|contextual|full)\\s+detail", "weight": 2 },
84
- { "regex": "\\b(vector|fts|hybrid)\\s+(search|mode)", "weight": 2 },
85
- { "regex": "narrow\\s+(down\\s+)?(the\\s+)?results", "weight": 2 },
86
- { "regex": "search\\s+(is\\s+)?(returning|giving)\\s+(too\\s+)?(many|few)", "weight": 2 }
87
- ],
88
- "exclusions": [
89
- { "regex": "--?(limit|detail|mode|threshold)\\s*=" }
90
- ]
91
- },
92
- {
93
- "name": "advanced-workflows",
94
- "description": "Multi-tool orchestration patterns",
95
- "triggers": [
96
- { "keyword": "multi-step", "weight": 2 },
97
- { "keyword": "orchestration", "weight": 2 },
98
- { "keyword": "job monitoring", "weight": 2 },
99
- { "keyword": "background job", "weight": 2 },
100
- { "keyword": "combine tools", "weight": 2 },
101
- { "keyword": "chain operations", "weight": 2 },
102
- { "regex": "chain.*searches", "weight": 2 },
103
- { "regex": "multiple.*searches", "weight": 2 },
104
- { "regex": "search.*then\\s+(summarize|extract|filter)", "weight": 2 },
105
- { "regex": "for\\s+each\\s+(search\\s+)?(result|match)", "weight": 2 }
106
- ],
107
- "exclusions": []
108
- },
109
- {
110
- "name": "store-lifecycle",
111
- "description": "Managing knowledge stores",
112
- "triggers": [
113
- { "keyword": "add store", "weight": 2 },
114
- { "keyword": "create store", "weight": 2 },
115
- { "keyword": "delete store", "weight": 2 },
116
- { "keyword": "remove store", "weight": 2 },
117
- { "keyword": "index store", "weight": 2 },
118
- { "keyword": "re-index", "weight": 2 },
119
- { "keyword": "reindex", "weight": 2 },
120
- { "keyword": "knowledge store", "weight": 2 },
121
- { "regex": "add\\s+(a\\s+)?(repo|repository|folder|directory)\\s+(to|for)\\s+(knowledge|indexing|search)", "weight": 3 },
122
- { "regex": "index\\s+(a|the|my)\\s+(repo|repository|folder|directory|library|package)", "weight": 2 },
123
- { "regex": "set\\s+up.*(knowledge|search)\\s*(store|index)", "weight": 2 },
124
- { "regex": "(backup|snapshot|archive).*(knowledge|search)\\s*(store|index)", "weight": 2 }
125
- ],
126
- "exclusions": [
127
- { "regex": "/bluera-knowledge:(add-repo|add-folder|remove-store|index)" }
128
- ]
129
- }
130
- ]
131
- }