bluera-knowledge 0.16.6 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/{chunk-OMC3RAZT.js → chunk-RAXRD23K.js} +2 -2
  3. package/dist/{chunk-WYZQUKUD.js → chunk-VKTVMW45.js} +28 -18
  4. package/dist/chunk-VKTVMW45.js.map +1 -0
  5. package/dist/{chunk-3EQRQOXD.js → chunk-ZGEQCLOZ.js} +2 -2
  6. package/dist/index.js +3 -3
  7. package/dist/mcp/bootstrap.js +19 -2
  8. package/dist/mcp/bootstrap.js.map +1 -1
  9. package/dist/mcp/server.d.ts +1 -0
  10. package/dist/mcp/server.js +2 -2
  11. package/dist/workers/background-worker-cli.js +2 -2
  12. package/package.json +1 -5
  13. package/.claude-plugin/plugin.json +0 -9
  14. package/commands/add-folder.md +0 -48
  15. package/commands/add-repo.md +0 -50
  16. package/commands/cancel.md +0 -63
  17. package/commands/check-status.md +0 -78
  18. package/commands/crawl.md +0 -54
  19. package/commands/index.md +0 -48
  20. package/commands/remove-store.md +0 -52
  21. package/commands/search.md +0 -86
  22. package/commands/search.sh +0 -63
  23. package/commands/skill-activation.md +0 -130
  24. package/commands/stores.md +0 -54
  25. package/commands/suggest.md +0 -82
  26. package/commands/sync.md +0 -96
  27. package/commands/test-plugin.md +0 -408
  28. package/commands/uninstall.md +0 -65
  29. package/dist/chunk-WYZQUKUD.js.map +0 -1
  30. package/hooks/check-dependencies.sh +0 -145
  31. package/hooks/format-search-results.py +0 -132
  32. package/hooks/hooks.json +0 -54
  33. package/hooks/job-status-hook.sh +0 -51
  34. package/hooks/posttooluse-bk-reminder.py +0 -166
  35. package/hooks/skill-activation.py +0 -194
  36. package/hooks/skill-rules.json +0 -122
  37. package/skills/advanced-workflows/SKILL.md +0 -273
  38. package/skills/knowledge-search/SKILL.md +0 -110
  39. package/skills/search-optimization/SKILL.md +0 -396
  40. package/skills/store-lifecycle/SKILL.md +0 -470
  41. package/skills/when-to-query/SKILL.md +0 -160
  42. /package/dist/{chunk-OMC3RAZT.js.map → chunk-RAXRD23K.js.map} +0 -0
  43. /package/dist/{chunk-3EQRQOXD.js.map → chunk-ZGEQCLOZ.js.map} +0 -0
@@ -1,145 +0,0 @@
1
- #!/bin/bash
2
- # Bluera Knowledge Plugin - Dependency Checker
3
- # Automatically checks and installs dependencies for the plugin
4
- #
5
- # Environment variables:
6
- # BK_SKIP_AUTO_INSTALL=1 - Skip automatic installation of crawl4ai
7
- # Set this if you prefer to manage Python packages manually
8
- #
9
- # What this script auto-installs (if missing):
10
- # - Node.js dependencies (via bun or npm, from package.json)
11
- # - Python virtual environment with crawl4ai (isolated from system Python)
12
- # - Playwright Chromium browser (via playwright CLI, for headless crawling)
13
-
14
- set -e
15
-
16
- # Get the plugin root directory
17
- PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$(dirname "$0")")}"
18
-
19
- # Venv location within plugin (isolated from system Python)
20
- VENV_DIR="$PLUGIN_ROOT/.venv"
21
- VENV_PYTHON="$VENV_DIR/bin/python3"
22
- VENV_PIP="$VENV_DIR/bin/pip"
23
-
24
- # Colors for output
25
- RED='\033[0;31m'
26
- GREEN='\033[0;32m'
27
- YELLOW='\033[1;33m'
28
- NC='\033[0m' # No Color
29
-
30
- # =====================
31
- # Helper Functions
32
- # =====================
33
-
34
- # Install Playwright browser using specified python
35
- # Args: $1 = python path to use
36
- install_playwright_browser() {
37
- local PYTHON_CMD="${1:-python3}"
38
-
39
- # Check if Playwright Chromium is already installed by testing if browser can be launched
40
- if "$PYTHON_CMD" -c "from playwright.sync_api import sync_playwright; p = sync_playwright().start(); b = p.chromium.launch(); b.close(); p.stop()" 2>/dev/null; then
41
- echo -e "${GREEN}[bluera-knowledge] Playwright Chromium ready ✓${NC}"
42
- return 0
43
- fi
44
-
45
- echo -e "${YELLOW}[bluera-knowledge] Installing Playwright browser (one-time setup)...${NC}"
46
- if "$PYTHON_CMD" -m playwright install chromium 2>/dev/null; then
47
- echo -e "${GREEN}[bluera-knowledge] Playwright Chromium installed ✓${NC}"
48
- return 0
49
- else
50
- echo -e "${YELLOW}[bluera-knowledge] Playwright browser install failed.${NC}"
51
- echo -e "${YELLOW}Manual fix: $PYTHON_CMD -m playwright install chromium${NC}"
52
- return 1
53
- fi
54
- }
55
-
56
- # =====================
57
- # Node.js Dependencies
58
- # =====================
59
-
60
- # Check if node_modules exists
61
- if [ ! -d "$PLUGIN_ROOT/node_modules" ]; then
62
- echo -e "${YELLOW}[bluera-knowledge] Installing Node.js dependencies...${NC}"
63
-
64
- # Try bun first (faster), fall back to npm
65
- if command -v bun &> /dev/null; then
66
- (cd "$PLUGIN_ROOT" && bun install --frozen-lockfile 2>/dev/null) && \
67
- echo -e "${GREEN}[bluera-knowledge] Node.js dependencies installed ✓${NC}" || \
68
- echo -e "${RED}[bluera-knowledge] Failed to install Node.js dependencies${NC}"
69
- elif command -v npm &> /dev/null; then
70
- (cd "$PLUGIN_ROOT" && npm ci --silent 2>/dev/null) && \
71
- echo -e "${GREEN}[bluera-knowledge] Node.js dependencies installed ✓${NC}" || \
72
- echo -e "${RED}[bluera-knowledge] Failed to install Node.js dependencies${NC}"
73
- else
74
- echo -e "${RED}[bluera-knowledge] Neither bun nor npm found. Please install Node.js dependencies manually.${NC}"
75
- fi
76
- fi
77
-
78
- # =====================
79
- # Python Dependencies (using venv)
80
- # =====================
81
-
82
- # Check if Python3 is installed
83
- if ! command -v python3 &> /dev/null; then
84
- echo -e "${RED}[bluera-knowledge] Python3 is not installed${NC}"
85
- echo -e "${YELLOW}Web crawling features require Python 3.x${NC}"
86
- echo -e "${YELLOW}Install Python3: https://www.python.org/downloads/${NC}"
87
- exit 0 # Don't block the session, just warn
88
- fi
89
-
90
- # Check Python version (require 3.8+)
91
- python_version=$(python3 -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')
92
-
93
- if ! python3 -c "import sys; exit(0 if sys.version_info >= (3, 8) else 1)"; then
94
- echo -e "${YELLOW}[bluera-knowledge] Python ${python_version} detected. Python 3.8+ recommended for crawl4ai${NC}"
95
- fi
96
-
97
- # Check if venv exists and has crawl4ai installed
98
- if [ -f "$VENV_PYTHON" ] && "$VENV_PYTHON" -c "import crawl4ai" 2>/dev/null; then
99
- crawl4ai_version=$("$VENV_PYTHON" -c "import crawl4ai; print(crawl4ai.__version__)" 2>/dev/null || echo "unknown")
100
- echo -e "${GREEN}[bluera-knowledge] crawl4ai ${crawl4ai_version} ready (venv) ✓${NC}"
101
- # Ensure Playwright browser is installed for headless crawling
102
- install_playwright_browser "$VENV_PYTHON"
103
- exit 0
104
- fi
105
-
106
- # Check if auto-install is disabled
107
- if [ "${BK_SKIP_AUTO_INSTALL:-}" = "1" ]; then
108
- echo -e "${YELLOW}[bluera-knowledge] Auto-install disabled (BK_SKIP_AUTO_INSTALL=1)${NC}"
109
- echo -e "${YELLOW}To enable web crawling, create venv manually:${NC}"
110
- echo -e " ${GREEN}python3 -m venv $VENV_DIR${NC}"
111
- echo -e " ${GREEN}$VENV_PIP install crawl4ai${NC}"
112
- echo -e " ${GREEN}$VENV_PYTHON -m playwright install chromium${NC}"
113
- exit 0
114
- fi
115
-
116
- # Create venv if it doesn't exist
117
- if [ ! -d "$VENV_DIR" ]; then
118
- echo -e "${YELLOW}[bluera-knowledge] Creating Python virtual environment...${NC}"
119
- if python3 -m venv "$VENV_DIR" 2>/dev/null; then
120
- echo -e "${GREEN}[bluera-knowledge] Virtual environment created ✓${NC}"
121
- else
122
- echo -e "${RED}[bluera-knowledge] Failed to create virtual environment${NC}"
123
- echo -e "${YELLOW}Manual fix: python3 -m venv $VENV_DIR${NC}"
124
- exit 0
125
- fi
126
- fi
127
-
128
- # Install crawl4ai into venv
129
- echo -e "${YELLOW}[bluera-knowledge] Installing crawl4ai into virtual environment...${NC}"
130
- echo -e "${YELLOW}(Set BK_SKIP_AUTO_INSTALL=1 to disable auto-install)${NC}"
131
-
132
- if "$VENV_PIP" install --quiet crawl4ai 2>/dev/null; then
133
- crawl4ai_version=$("$VENV_PYTHON" -c "import crawl4ai; print(crawl4ai.__version__)" 2>/dev/null || echo "installed")
134
- echo -e "${GREEN}[bluera-knowledge] crawl4ai ${crawl4ai_version} installed (venv) ✓${NC}"
135
- # Install Playwright browser for headless crawling
136
- install_playwright_browser "$VENV_PYTHON"
137
- else
138
- echo -e "${RED}[bluera-knowledge] Failed to install crawl4ai${NC}"
139
- echo -e "${YELLOW}Manual fix:${NC}"
140
- echo -e " ${GREEN}$VENV_PIP install crawl4ai${NC}"
141
- echo -e " ${GREEN}$VENV_PYTHON -m playwright install chromium${NC}"
142
- fi
143
-
144
- # Always exit 0 to not block the session
145
- exit 0
@@ -1,132 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- PostToolUse hook to format mcp__bluera-knowledge__search results
4
- into a fixed-width table with deterministic output.
5
- """
6
-
7
- import json
8
- import sys
9
- import os
10
-
11
- # Column widths (content only, not including | separators)
12
- SCORE_WIDTH = 6 # Right-aligned: " 1.00 "
13
- STORE_WIDTH = 12 # Left-aligned: "store "
14
- FILE_WIDTH = 45 # Left-aligned: "path/to/file..."
15
- PURPOSE_WIDTH = 48 # Left-aligned: "Purpose text..."
16
-
17
-
18
- def truncate(text: str, max_len: int) -> str:
19
- """Truncate text with ellipsis if needed."""
20
- if len(text) <= max_len:
21
- return text
22
- return text[:max_len - 3] + "..."
23
-
24
-
25
- def format_score(score: float) -> str:
26
- """Format score as right-aligned fixed-width string."""
27
- return f"{score:5.2f}".rjust(SCORE_WIDTH)
28
-
29
-
30
- def format_store(store_name: str) -> str:
31
- """Format store name as left-aligned fixed-width string."""
32
- truncated = truncate(store_name, STORE_WIDTH)
33
- return truncated.ljust(STORE_WIDTH)
34
-
35
-
36
- def format_file(location: str, repo_root: str) -> str:
37
- """Format file path as left-aligned fixed-width string."""
38
- # Strip repo root prefix
39
- if repo_root and location.startswith(repo_root):
40
- path = location[len(repo_root):].lstrip("/")
41
- else:
42
- path = location
43
- truncated = truncate(path, FILE_WIDTH)
44
- return truncated.ljust(FILE_WIDTH)
45
-
46
-
47
- def format_purpose(purpose: str) -> str:
48
- """Format purpose as left-aligned fixed-width string."""
49
- # Clean up purpose text
50
- clean = purpose.replace("\n", " ").strip()
51
- truncated = truncate(clean, PURPOSE_WIDTH)
52
- return truncated.ljust(PURPOSE_WIDTH)
53
-
54
-
55
- def format_table(results: list, query: str) -> str:
56
- """Format search results into a fixed-width markdown table."""
57
- lines = []
58
-
59
- # Header
60
- lines.append(f"## Search Results for \"{query}\"")
61
- lines.append("")
62
-
63
- if not results:
64
- lines.append(f"No results found for \"{query}\"")
65
- lines.append("")
66
- lines.append("Try:")
67
- lines.append("- Broadening your search terms")
68
- lines.append("- Checking if the relevant stores are indexed")
69
- lines.append("- Using /bluera-knowledge:stores to see available stores")
70
- return "\n".join(lines)
71
-
72
- # Table header
73
- header = f"| {'Score'.rjust(SCORE_WIDTH)} | {'Store'.ljust(STORE_WIDTH)} | {'File'.ljust(FILE_WIDTH)} | {'Purpose'.ljust(PURPOSE_WIDTH)} |"
74
- # Separator: Score is right-aligned (colon at end), others are left-aligned
75
- # The +2 accounts for the spaces around content, -1 for the colon on Score column
76
- separator = f"|{'-' * (SCORE_WIDTH + 1)}:|{'-' * (STORE_WIDTH + 2)}|{'-' * (FILE_WIDTH + 2)}|{'-' * (PURPOSE_WIDTH + 2)}|"
77
-
78
- lines.append(header)
79
- lines.append(separator)
80
-
81
- # Data rows
82
- for result in results:
83
- score = result.get("score", 0)
84
- summary = result.get("summary", {})
85
- store_name = summary.get("storeName", "unknown")
86
- location = summary.get("location", "")
87
- repo_root = summary.get("repoRoot", "")
88
- purpose = summary.get("purpose", "")
89
-
90
- row = f"| {format_score(score)} | {format_store(store_name)} | {format_file(location, repo_root)} | {format_purpose(purpose)} |"
91
- lines.append(row)
92
-
93
- lines.append("")
94
- lines.append(f"**Found**: {len(results)} results")
95
-
96
- return "\n".join(lines)
97
-
98
-
99
- def main():
100
- try:
101
- # Read hook input from stdin
102
- input_data = json.load(sys.stdin)
103
-
104
- tool_name = input_data.get("tool_name", "")
105
- tool_input = input_data.get("tool_input", {})
106
- tool_result = input_data.get("tool_result", {})
107
-
108
- # Only process search results
109
- if tool_name != "mcp__bluera-knowledge__search":
110
- sys.exit(0)
111
-
112
- # Extract results and query
113
- results = tool_result.get("results", [])
114
- query = tool_input.get("query", "")
115
-
116
- # Format the table
117
- formatted = format_table(results, query)
118
-
119
- # Output the formatted table
120
- # For PostToolUse, stdout is shown in the transcript
121
- print(formatted)
122
-
123
- except json.JSONDecodeError as e:
124
- print(f"Error parsing hook input: {e}", file=sys.stderr)
125
- sys.exit(1)
126
- except Exception as e:
127
- print(f"Error formatting results: {e}", file=sys.stderr)
128
- sys.exit(1)
129
-
130
-
131
- if __name__ == "__main__":
132
- main()
package/hooks/hooks.json DELETED
@@ -1,54 +0,0 @@
1
- {
2
- "description": "bluera-knowledge plugin hooks - dependency checking, job monitoring, and BK suggestions",
3
- "hooks": {
4
- "PostToolUse": [
5
- {
6
- "matcher": "Grep",
7
- "hooks": [
8
- {
9
- "type": "command",
10
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/posttooluse-bk-reminder.py",
11
- "timeout": 3
12
- }
13
- ]
14
- },
15
- {
16
- "matcher": "Read",
17
- "hooks": [
18
- {
19
- "type": "command",
20
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/posttooluse-bk-reminder.py",
21
- "timeout": 3
22
- }
23
- ]
24
- }
25
- ],
26
- "SessionStart": [
27
- {
28
- "hooks": [
29
- {
30
- "type": "command",
31
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/check-dependencies.sh",
32
- "timeout": 30
33
- }
34
- ]
35
- }
36
- ],
37
- "UserPromptSubmit": [
38
- {
39
- "hooks": [
40
- {
41
- "type": "command",
42
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/job-status-hook.sh",
43
- "timeout": 2
44
- },
45
- {
46
- "type": "command",
47
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/skill-activation.py",
48
- "timeout": 2
49
- }
50
- ]
51
- }
52
- ]
53
- }
54
- }
@@ -1,51 +0,0 @@
1
- #!/bin/bash
2
- # Show active jobs in context when user submits a prompt
3
- #
4
- # This hook runs on UserPromptSubmit events and injects
5
- # information about active background jobs into the context.
6
-
7
- JOBS_DIR="$HOME/.local/share/bluera-knowledge/jobs"
8
-
9
- # Exit silently if jobs directory doesn't exist
10
- if [ ! -d "$JOBS_DIR" ]; then
11
- exit 0
12
- fi
13
-
14
- # Find active jobs (modified in last 60 minutes)
15
- active_jobs=$(find "$JOBS_DIR" -name "*.json" -type f -not -name "*.pid" -mmin -60 2>/dev/null | while read -r file; do
16
- # Skip if file doesn't exist or isn't readable
17
- if [ ! -r "$file" ]; then
18
- continue
19
- fi
20
-
21
- # Extract job details using jq (if available) or grep fallback
22
- if command -v jq >/dev/null 2>&1; then
23
- status=$(jq -r '.status' "$file" 2>/dev/null || echo "unknown")
24
- if [ "$status" = "running" ] || [ "$status" = "pending" ]; then
25
- job_id=$(basename "$file" .json)
26
- type=$(jq -r '.type' "$file" 2>/dev/null || echo "unknown")
27
- progress=$(jq -r '.progress' "$file" 2>/dev/null || echo "0")
28
- message=$(jq -r '.message' "$file" 2>/dev/null || echo "No message")
29
- echo "- $type job ($job_id): ${progress}% - $message"
30
- fi
31
- else
32
- # Fallback using grep if jq not available
33
- status=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | cut -d'"' -f4)
34
- if [ "$status" = "running" ] || [ "$status" = "pending" ]; then
35
- job_id=$(basename "$file" .json)
36
- type=$(grep -o '"type"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | cut -d'"' -f4)
37
- progress=$(grep -o '"progress"[[:space:]]*:[[:space:]]*[0-9.]*' "$file" | awk '{print $NF}')
38
- message=$(grep -o '"message"[[:space:]]*:[[:space:]]*"[^"]*"' "$file" | cut -d'"' -f4)
39
- echo "- $type job ($job_id): ${progress}% - $message"
40
- fi
41
- fi
42
- done)
43
-
44
- # Output active jobs if any found
45
- if [ -n "$active_jobs" ]; then
46
- echo ""
47
- echo "Active background jobs:"
48
- echo "$active_jobs"
49
- echo ""
50
- echo "Check status with: /bluera-knowledge:check-status"
51
- fi
@@ -1,166 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- PostToolUse hook for bluera-knowledge plugin.
4
- Fires after Claude reads/greps in dependency directories,
5
- reminding to consider using BK for similar future queries.
6
- """
7
-
8
- import json
9
- import re
10
- import sys
11
- from typing import Any
12
-
13
- # Fast string checks - if none of these are in the path, skip regex entirely
14
- # This avoids regex overhead for the vast majority of file accesses
15
- LIBRARY_QUICK_CHECKS = frozenset([
16
- "node_modules",
17
- "vendor",
18
- "site-packages",
19
- "venv",
20
- "bower_components",
21
- "packages",
22
- ".npm",
23
- ".cargo",
24
- "go/pkg",
25
- ])
26
-
27
- # Patterns indicating library/dependency code
28
- LIBRARY_PATH_PATTERNS = [
29
- r"node_modules/",
30
- r"vendor/",
31
- r"site-packages/",
32
- r"\.venv/",
33
- r"venv/",
34
- r"bower_components/",
35
- r"packages/.*/node_modules/",
36
- r"\.npm/",
37
- r"\.cargo/registry/",
38
- r"go/pkg/mod/",
39
- ]
40
-
41
- # Compile patterns for efficiency
42
- LIBRARY_PATTERNS_RE = re.compile("|".join(LIBRARY_PATH_PATTERNS), re.IGNORECASE)
43
-
44
-
45
- def quick_path_check(path: str) -> bool:
46
- """Fast check if path might contain library code. Avoids regex for most paths."""
47
- path_lower = path.lower()
48
- return any(keyword in path_lower for keyword in LIBRARY_QUICK_CHECKS)
49
-
50
-
51
- def extract_library_name(path: str) -> str | None:
52
- """Extract library name from dependency path."""
53
- # node_modules/package-name/...
54
- match = re.search(r"node_modules/(@[^/]+/[^/]+|[^/]+)", path)
55
- if match:
56
- return match.group(1)
57
-
58
- # site-packages/package_name/...
59
- match = re.search(r"site-packages/([^/]+)", path)
60
- if match:
61
- return match.group(1)
62
-
63
- # vendor/package/...
64
- match = re.search(r"vendor/([^/]+)", path)
65
- if match:
66
- return match.group(1)
67
-
68
- # .cargo/registry/.../package-name-version/...
69
- match = re.search(r"\.cargo/registry/[^/]+/([^/]+)-\d", path)
70
- if match:
71
- return match.group(1)
72
-
73
- # go/pkg/mod/package@version/...
74
- match = re.search(r"go/pkg/mod/([^@]+)@", path)
75
- if match:
76
- return match.group(1)
77
-
78
- return None
79
-
80
-
81
- def check_grep_tool(tool_input: dict[str, Any]) -> tuple[str | None, str | None]:
82
- """Check if Grep targeted library code. Returns (action, library_name)."""
83
- path = tool_input.get("path", "")
84
-
85
- # Fast path: skip regex if no library keywords present
86
- if not path or not quick_path_check(path):
87
- return None, None
88
-
89
- if LIBRARY_PATTERNS_RE.search(path):
90
- lib_name = extract_library_name(path)
91
- return f"grepped in `{path}`", lib_name
92
-
93
- return None, None
94
-
95
-
96
- def check_read_tool(tool_input: dict[str, Any]) -> tuple[str | None, str | None]:
97
- """Check if Read targeted library code. Returns (action, library_name)."""
98
- file_path = tool_input.get("file_path", "")
99
-
100
- # Fast path: skip regex if no library keywords present
101
- if not file_path or not quick_path_check(file_path):
102
- return None, None
103
-
104
- if LIBRARY_PATTERNS_RE.search(file_path):
105
- lib_name = extract_library_name(file_path)
106
- return f"read `{file_path}`", lib_name
107
-
108
- return None, None
109
-
110
-
111
- def main() -> int:
112
- try:
113
- stdin_data = sys.stdin.read()
114
- if not stdin_data.strip():
115
- return 0
116
- hook_input = json.loads(stdin_data)
117
- except json.JSONDecodeError:
118
- return 0
119
-
120
- tool_name = hook_input.get("tool_name", "")
121
- tool_input = hook_input.get("tool_input", {})
122
-
123
- action = None
124
- lib_name = None
125
-
126
- if tool_name == "Grep":
127
- action, lib_name = check_grep_tool(tool_input)
128
- elif tool_name == "Read":
129
- action, lib_name = check_read_tool(tool_input)
130
-
131
- if not action:
132
- return 0
133
-
134
- # Build context-aware reminder
135
- lib_hint = f" ({lib_name})" if lib_name else ""
136
- add_suggestion = (
137
- f"If {lib_name} is not indexed, consider: /bluera-knowledge:add-repo"
138
- if lib_name
139
- else "Consider indexing frequently-used libraries with /bluera-knowledge:add-repo"
140
- )
141
-
142
- reminder_text = f"""BLUERA-KNOWLEDGE REMINDER
143
-
144
- You just {action} - this is dependency/library code{lib_hint}.
145
-
146
- For FUTURE queries about this library, use Bluera Knowledge instead:
147
- - MCP tool: search(query="your question about {lib_name or 'the library'}")
148
- - Slash command: /bluera-knowledge:search <query>
149
-
150
- BK provides indexed, semantic search across library sources - significantly faster
151
- and more context-efficient than reading through dependency directories.
152
-
153
- {add_suggestion}"""
154
-
155
- output = {
156
- "hookSpecificOutput": {
157
- "hookEventName": "PostToolUse",
158
- "additionalContext": reminder_text,
159
- }
160
- }
161
- print(json.dumps(output))
162
- return 0
163
-
164
-
165
- if __name__ == "__main__":
166
- raise SystemExit(main())