security-detections-mcp 1.4.1 → 2.1.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 (86) hide show
  1. package/README.md +279 -2
  2. package/dist/db/cache.d.ts +61 -0
  3. package/dist/db/cache.js +141 -0
  4. package/dist/db/connection.d.ts +42 -0
  5. package/dist/db/connection.js +206 -0
  6. package/dist/db/detections.d.ts +224 -0
  7. package/dist/db/detections.js +944 -0
  8. package/dist/db/dynamic.d.ts +83 -0
  9. package/dist/db/dynamic.js +462 -0
  10. package/dist/db/index.d.ts +13 -0
  11. package/dist/db/index.js +58 -0
  12. package/dist/db/knowledge.d.ts +150 -0
  13. package/dist/db/knowledge.js +762 -0
  14. package/dist/db/patterns.d.ts +117 -0
  15. package/dist/db/patterns.js +912 -0
  16. package/dist/db/schema.d.ts +17 -0
  17. package/dist/db/schema.js +213 -0
  18. package/dist/db/stories.d.ts +34 -0
  19. package/dist/db/stories.js +122 -0
  20. package/dist/db.d.ts +38 -0
  21. package/dist/db.js +237 -3
  22. package/dist/handlers/index.d.ts +3 -0
  23. package/dist/handlers/index.js +4 -0
  24. package/dist/handlers/prompts.d.ts +23 -0
  25. package/dist/handlers/prompts.js +128 -0
  26. package/dist/handlers/resources.d.ts +27 -0
  27. package/dist/handlers/resources.js +326 -0
  28. package/dist/handlers/sampling.d.ts +62 -0
  29. package/dist/handlers/sampling.js +181 -0
  30. package/dist/handlers/tools.d.ts +15 -0
  31. package/dist/handlers/tools.js +8 -0
  32. package/dist/index.d.ts +11 -0
  33. package/dist/index.js +35 -3659
  34. package/dist/resources/index.d.ts +48 -0
  35. package/dist/resources/index.js +483 -0
  36. package/dist/server.d.ts +19 -0
  37. package/dist/server.js +232 -0
  38. package/dist/tools/autonomous/index.d.ts +23 -0
  39. package/dist/tools/autonomous/index.js +712 -0
  40. package/dist/tools/cache/index.d.ts +11 -0
  41. package/dist/tools/cache/index.js +257 -0
  42. package/dist/tools/detections/analysis.d.ts +1 -0
  43. package/dist/tools/detections/analysis.js +160 -0
  44. package/dist/tools/detections/comparison.d.ts +1 -0
  45. package/dist/tools/detections/comparison.js +317 -0
  46. package/dist/tools/detections/filters.d.ts +1 -0
  47. package/dist/tools/detections/filters.js +455 -0
  48. package/dist/tools/detections/index.d.ts +12 -0
  49. package/dist/tools/detections/index.js +25 -0
  50. package/dist/tools/detections/search.d.ts +1 -0
  51. package/dist/tools/detections/search.js +154 -0
  52. package/dist/tools/dynamic/index.d.ts +16 -0
  53. package/dist/tools/dynamic/index.js +426 -0
  54. package/dist/tools/engineering/index.d.ts +12 -0
  55. package/dist/tools/engineering/index.js +645 -0
  56. package/dist/tools/index.d.ts +20 -0
  57. package/dist/tools/index.js +61 -0
  58. package/dist/tools/knowledge/index.d.ts +13 -0
  59. package/dist/tools/knowledge/index.js +630 -0
  60. package/dist/tools/meta/index.d.ts +27 -0
  61. package/dist/tools/meta/index.js +419 -0
  62. package/dist/tools/registry.d.ts +41 -0
  63. package/dist/tools/registry.js +76 -0
  64. package/dist/tools/stories/index.d.ts +1 -0
  65. package/dist/tools/stories/index.js +125 -0
  66. package/dist/types/detection.d.ts +165 -0
  67. package/dist/types/detection.js +5 -0
  68. package/dist/types/dynamic.d.ts +116 -0
  69. package/dist/types/dynamic.js +6 -0
  70. package/dist/types/index.d.ts +19 -0
  71. package/dist/types/index.js +14 -0
  72. package/dist/types/knowledge.d.ts +146 -0
  73. package/dist/types/knowledge.js +6 -0
  74. package/dist/types/meta.d.ts +190 -0
  75. package/dist/types/meta.js +6 -0
  76. package/dist/types/stats.d.ts +59 -0
  77. package/dist/types/stats.js +5 -0
  78. package/dist/types/story.d.ts +42 -0
  79. package/dist/types/story.js +5 -0
  80. package/dist/types.d.ts +10 -177
  81. package/dist/types.js +10 -2
  82. package/dist/utils/helpers.d.ts +66 -0
  83. package/dist/utils/helpers.js +135 -0
  84. package/dist/utils/index.d.ts +6 -0
  85. package/dist/utils/index.js +6 -0
  86. package/package.json +11 -4
package/README.md CHANGED
@@ -4,6 +4,57 @@ An MCP (Model Context Protocol) server that lets LLMs query a unified database o
4
4
 
5
5
  [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=security-detections&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInNlY3VyaXR5LWRldGVjdGlvbnMtbWNwIl0sImVudiI6eyJTSUdNQV9QQVRIUyI6Ii9wYXRoL3RvL3NpZ21hL3J1bGVzLC9wYXRoL3RvL3NpZ21hL3J1bGVzLXRocmVhdC1odW50aW5nIiwiU1BMVU5LX1BBVEhTIjoiL3BhdGgvdG8vc2VjdXJpdHlfY29udGVudC9kZXRlY3Rpb25zIiwiU1RPUllfUEFUSFMiOiIvcGF0aC90by9zZWN1cml0eV9jb250ZW50L3N0b3JpZXMiLCJFTEFTVElDX1BBVEhTIjoiL3BhdGgvdG8vZGV0ZWN0aW9uLXJ1bGVzL3J1bGVzIiwiS1FMX1BBVEhTIjoiL3BhdGgvdG8va3FsLXJ1bGVzIn19)
6
6
 
7
+ ## 🐛 Version 2.1.1 (Bug Fix)
8
+
9
+ - **Fixed Windows EBUSY crash** - SQLite database recreation now handles Windows file locking with retry logic. Previously, Windows users would get `EBUSY: resource busy or locked` on startup.
10
+ - **SQLite journal cleanup** - WAL, SHM, and journal companion files are now cleaned up during database recreation.
11
+ - **Windows CI** - Added Windows to the CI matrix. Build, tests, and full Sigma indexing pipeline now run on both Linux and Windows.
12
+ - **Cross-platform test suite** - New `tests/cross-platform-test.js` validates database lifecycle on all platforms. New `tests/ci-integration-test.js` downloads and indexes 3,200+ Sigma rules to validate the full pipeline.
13
+
14
+ ## 🚀 Version 2.1 Features
15
+
16
+ **Security Detections MCP v2.1** introduces powerful new capabilities for detection engineering intelligence, analytical memory, autonomous analysis, and advanced MCP protocol features:
17
+
18
+ ### What's New in v2.1
19
+ - **Elicitation Support** - Server can request user confirmation for destructive operations (when client supports it)
20
+ - **Sampling Integration** - LLM-enhanced analysis via MCP sampling (when client supports it)
21
+ - **Resource Subscriptions** - Subscribe to resource changes for live updates
22
+ - **Enhanced Error Handling** - Safe JSON parsing and comprehensive error wrapping
23
+ - **Dynamic Pattern Extraction** - Improved field/function extraction without hardcoded limitations
24
+ - **71+ Tools** - Extended tool suite with 2 new sampling-related tools
25
+
26
+ ### Detection Engineering Intelligence (8 Tools)
27
+ - **Pattern Learning** - Automatically extracts and learns patterns from 4 detection formats (SPL, Sigma, KQL, Elastic)
28
+ - **Template Generation** - Creates reusable detection templates from learned patterns
29
+ - **Field & Macro References** - Tracks commonly used fields, macros, and functions across detections
30
+ - **Feedback Learning** - Learns from user corrections and improvements to enhance future suggestions
31
+
32
+ ### Knowledge Graph / Tribal Knowledge (12 Tools)
33
+ - **Analytical Memory** - Persistent knowledge graph that remembers WHY decisions were made, not just WHAT was detected
34
+ - **Entity Management** - Create and relate entities (threats, techniques, detections, data sources)
35
+ - **Decision Logging** - Record analytical reasoning and decision-making context for future reference
36
+ - **Learning Capture** - Store insights, patterns, and lessons learned that help future agents understand context
37
+
38
+ ### Dynamic Tables (6 Tools)
39
+ - **Custom Analysis Storage** - Create tables on-the-fly for storing analysis results, gap assessments, or custom data
40
+ - **Flexible Schema** - Define your own table structure for any analysis workflow
41
+ - **Query Interface** - Query stored analysis data with SQL-like operations
42
+ - **Persistent Storage** - Tables persist across sessions for long-term analysis tracking
43
+
44
+ ### Comprehensive Pattern Extraction
45
+ - **Multi-Format Support** - Extracts patterns from Sigma, Splunk SPL, KQL, and Elastic queries
46
+ - **10,235+ Indexed Patterns** - Comprehensive pattern library covering 528+ MITRE techniques
47
+ - **Cross-Format Insights** - Learn how different platforms detect the same techniques
48
+
49
+ ### Expanded Tool Suite
50
+ - **71+ Total Tools** (vs ~40 in v1.0)
51
+ - **Engineering Tools** (8) - Pattern learning, template generation, field analysis
52
+ - **Knowledge Tools** (12) - Knowledge graph, entity relations, decision logging
53
+ - **Dynamic Tools** (6) - Custom table creation and querying
54
+ - **Autonomous Tools** (5) - Self-directed analysis, LLM-enhanced analysis, sampling status
55
+ - **Meta/Template Tools** (5) - Query templates and workflow shortcuts
56
+ - **Cache Tools** (4) - Index management, saved queries
57
+
7
58
  ## 🆕 MCP Prompts - Expert Detection Workflows
8
59
 
9
60
  This server includes **11 pre-built MCP Prompts** that provide structured, expert-level workflows for common security detection tasks. Instead of figuring out which tools to use and in what order, just ask for a prompt by name and get a comprehensive, professional analysis.
@@ -413,6 +464,77 @@ These tools do heavy processing server-side and return minimal, actionable data:
413
464
  | `prioritize_gaps(threat_profile, source_type?)` | Analyze gaps with P0/P1/P2 prioritization and selection guidance |
414
465
  | `plan_detection_sprint()` | Generate sprint configuration options with recommended backlog |
415
466
 
467
+ ### Engineering Tools (8)
468
+
469
+ Detection engineering intelligence tools for pattern learning and template generation:
470
+
471
+ | Tool | Description |
472
+ |------|-------------|
473
+ | `extract_patterns(technique_id, source_type?)` | Extract detection patterns for a technique from all sources |
474
+ | `learn_pattern(technique_id, pattern, format)` | Teach the system a new pattern for a technique |
475
+ | `get_patterns(technique_id, format?)` | Retrieve learned patterns for a technique |
476
+ | `generate_template(technique_id, format, data_source)` | Generate detection template from learned patterns |
477
+ | `analyze_fields(technique_id)` | Analyze commonly used fields/macros for a technique |
478
+ | `get_field_references(field_name)` | Find all detections using a specific field or macro |
479
+ | `suggest_improvements(detection_id)` | Get AI suggestions for improving a detection based on patterns |
480
+ | `compare_patterns(technique_id)` | Compare patterns across different detection formats |
481
+
482
+ ### Knowledge Tools (12)
483
+
484
+ Knowledge graph and tribal knowledge tools for analytical memory:
485
+
486
+ | Tool | Description |
487
+ |------|-------------|
488
+ | `create_entity(name, type, properties)` | Create an entity in the knowledge graph (threat, technique, detection, etc.) |
489
+ | `create_relation(source_entity, relation_type, target_entity, reasoning)` | Create a relationship between entities with reasoning |
490
+ | `search_knowledge(query, entity_type?)` | Search the knowledge graph for entities and relations |
491
+ | `get_entity(name)` | Get full details of an entity including all relations |
492
+ | `log_decision(context, decision, reasoning, tags)` | Log an analytical decision with full context for future reference |
493
+ | `get_relevant_decisions(context, tags?)` | Retrieve relevant past decisions for current context |
494
+ | `add_learning(insight, category, tags)` | Store a learning or insight for future agents |
495
+ | `get_learnings(category?, tags?)` | Retrieve stored learnings by category or tags |
496
+ | `link_detection_to_entity(detection_id, entity_name, relation_type)` | Link a detection to a knowledge graph entity |
497
+ | `get_entity_detections(entity_name)` | Get all detections related to an entity |
498
+ | `update_entity(name, properties)` | Update entity properties in the knowledge graph |
499
+ | `delete_entity(name)` | Remove an entity from the knowledge graph |
500
+
501
+ ### Dynamic Tools (6)
502
+
503
+ Custom table creation and querying for flexible analysis storage:
504
+
505
+ | Tool | Description |
506
+ |------|-------------|
507
+ | `create_table(table_name, schema)` | Create a custom table with defined schema for analysis storage |
508
+ | `insert_row(table_name, row_data)` | Insert a row of data into a custom table |
509
+ | `query_table(table_name, query, limit?)` | Query a custom table with SQL-like syntax |
510
+ | `list_tables()` | List all custom tables you've created |
511
+ | `get_table_schema(table_name)` | Get the schema of a custom table |
512
+ | `delete_table(table_name)` | Delete a custom table |
513
+
514
+ ### Autonomous Tools (5)
515
+
516
+ Self-directed analysis tools that work independently:
517
+
518
+ | Tool | Description |
519
+ |------|-------------|
520
+ | `auto_analyze_coverage(threat_profiles?, store_results?)` | Comprehensive coverage analysis across threat profiles |
521
+ | `auto_gap_report(report_name?, compare_sources?)` | Generate executive-level gap reports with prioritized recommendations |
522
+ | `auto_compare_sources(techniques?, focus_tactic?)` | Compare detection coverage across all sources with reasoning |
523
+ | `llm_enhanced_analysis(analysis_type, threat_profile?)` | LLM-enhanced analysis via MCP sampling (when supported) |
524
+ | `check_sampling_status()` | Check if MCP sampling is available for LLM-enhanced analysis |
525
+
526
+ ### Meta/Template Tools (5)
527
+
528
+ Query templates and workflow shortcuts:
529
+
530
+ | Tool | Description |
531
+ |------|-------------|
532
+ | `save_template(name, tool_calls, description)` | Save a sequence of tool calls as a reusable template |
533
+ | `run_template(template_name, variables?)` | Execute a saved template with optional variable substitution |
534
+ | `list_templates()` | List all saved templates |
535
+ | `get_template(template_name)` | Get details of a saved template |
536
+ | `delete_template(template_name)` | Delete a saved template |
537
+
416
538
  ## MCP Prompts - Detailed Reference
417
539
 
418
540
  MCP Prompts are pre-built, expert-level workflows that guide Claude through complex analysis tasks. They ensure consistent, comprehensive results by defining exactly which tools to use and in what order.
@@ -753,6 +875,55 @@ Supports multiple KQL repositories:
753
875
  - Title derived from filename
754
876
  - Lightweight queries for kqlsearch.com
755
877
 
878
+ ## ⚠️ Limitations & Transparency
879
+
880
+ We believe in being honest about what this tool can and cannot do. Here are the current limitations:
881
+
882
+ ### Pattern Extraction Limitations
883
+
884
+ The Detection Engineering Intelligence features extract patterns **dynamically** from your detection corpus, but have some inherent limitations:
885
+
886
+ | Format | Field Extraction | Notes |
887
+ |--------|-----------------|-------|
888
+ | **Splunk SPL** | ✅ Excellent | Extracts from data models, `by` clauses, `stats` commands, `where` filters |
889
+ | **Sigma** | ✅ Excellent | Full YAML parsing of detection logic |
890
+ | **KQL** | ⚠️ Good | Dynamic extraction from `project`, `extend`, `where`, `summarize by`, `join on` |
891
+ | **Elastic** | ⚠️ Good | Dynamic extraction from `field:value` patterns, EQL `where` clauses |
892
+
893
+ **What this means:**
894
+ - **SPL and Sigma**: Highly accurate pattern extraction from full detection corpus
895
+ - **KQL and Elastic**: Uses regex-based dynamic extraction that catches most patterns, but may miss:
896
+ - Unusual field naming conventions
897
+ - Complex nested expressions
898
+ - Custom functions or operators
899
+
900
+ ### Coverage Analysis Limitations
901
+
902
+ - **MITRE mappings depend on source data** - If a detection doesn't have MITRE tags, we can't map it
903
+ - **Gap analysis is relative** - "Gaps" are based on threat profiles, not absolute coverage requirements
904
+ - **Cross-platform comparisons** - Different platforms have different capabilities; raw counts don't tell the whole story
905
+
906
+ ### Client Feature Availability
907
+
908
+ Some v2.1 features depend on **client support**:
909
+
910
+ | Feature | Requires | Fallback |
911
+ |---------|----------|----------|
912
+ | **Elicitation** | Client MCP elicitation support | Parameter-based confirmation (`confirm: true`) |
913
+ | **Sampling** | Client MCP sampling support | Direct analysis without LLM enhancement |
914
+ | **Resource Subscriptions** | Client subscription support | Poll resources manually |
915
+
916
+ **Note**: As of January 2025, Cursor may not fully support elicitation and sampling. The MCP gracefully falls back to alternative methods when these features aren't available.
917
+
918
+ ### Reporting Issues
919
+
920
+ Found a limitation or inaccuracy? Please [open an issue](https://github.com/MHaggis/Security-Detections-MCP/issues) with:
921
+ 1. The detection format (Sigma, Splunk, Elastic, KQL)
922
+ 2. An example query that wasn't extracted correctly
923
+ 3. Expected vs actual behavior
924
+
925
+ We continuously improve the pattern extraction based on community feedback.
926
+
756
927
  ## Development
757
928
 
758
929
  ```bash
@@ -762,6 +933,12 @@ npm install
762
933
  # Build
763
934
  npm run build
764
935
 
936
+ # Run tests
937
+ npm test
938
+
939
+ # Lint (TypeScript strict mode)
940
+ npm run lint
941
+
765
942
  # Run with paths
766
943
  SIGMA_PATHS="./detections/sigma/rules" \
767
944
  SPLUNK_PATHS="./detections/splunk/detections" \
@@ -777,12 +954,112 @@ When fully indexed with all sources:
777
954
 
778
955
  | Source | Count |
779
956
  |--------|-------|
780
- | Sigma Rules | ~3,000+ |
957
+ | Sigma Rules | ~3,200+ |
781
958
  | Splunk ESCU | ~2,000+ |
782
959
  | Elastic Rules | ~1,500+ |
783
960
  | KQL Queries | ~420+ |
784
961
  | Analytic Stories | ~330 |
785
- | **Total** | **~7,200+** |
962
+ | **Total Detections** | **~7,200+** |
963
+ | **Indexed Patterns** | **10,235+** |
964
+ | **Techniques with Patterns** | **528+** |
965
+ | **Detection Formats** | **4** (Sigma, Splunk, Elastic, KQL) |
966
+ | **Total Tools** | **71+** |
967
+ | **MCP Prompts** | **11** |
968
+ | **MCP Resources** | **9 static + 5 templates** |
969
+
970
+ ## 🧠 Tribal Knowledge
971
+
972
+ **Tribal Knowledge** is the analytical memory system that helps future agents understand WHY decisions were made, not just WHAT was detected. It's like having a senior analyst's notebook that persists across sessions.
973
+
974
+ ### What is Tribal Knowledge?
975
+
976
+ Traditional detection systems store facts: "We have 5 detections for T1059.001." Tribal Knowledge stores reasoning: "We prioritized T1059.001 because it's used in 80% of ransomware attacks, and our current detections miss base64-encoded PowerShell, which is why we added detection X."
977
+
978
+ ### Knowledge Graph Tables
979
+
980
+ The knowledge graph consists of four interconnected tables:
981
+
982
+ 1. **Entities** - Things you care about (threats, techniques, detections, data sources, campaigns)
983
+ 2. **Relations** - How entities connect ("APT29 uses T1059.001", "Detection X covers T1059.001")
984
+ 3. **Decisions** - Analytical reasoning and decision-making context
985
+ 4. **Learnings** - Insights, patterns, and lessons learned
986
+
987
+ ### How It Helps Future Agents
988
+
989
+ When you log a decision like:
990
+ ```json
991
+ log_decision(
992
+ context: "Ransomware gap analysis",
993
+ decision: "Prioritize T1486 (Data Encrypted for Impact)",
994
+ reasoning: "This is the final stage of ransomware attacks. Without detection here, we can't prevent data loss.",
995
+ tags: ["ransomware", "priority", "data-protection"]
996
+ )
997
+ ```
998
+
999
+ Future agents can retrieve this context when analyzing ransomware coverage, understanding not just that T1486 is important, but WHY it was prioritized.
1000
+
1001
+ ### Example Workflow
1002
+
1003
+ ```
1004
+ 1. Analyze ransomware gaps → identify_gaps("ransomware")
1005
+ 2. Log decision → log_decision("Prioritized T1486 because...")
1006
+ 3. Create entity → create_entity("Ransomware Campaign 2024", "threat")
1007
+ 4. Link detection → link_detection_to_entity("det_123", "Ransomware Campaign 2024", "detects")
1008
+ 5. Future agent → get_relevant_decisions("ransomware") → understands context
1009
+ ```
1010
+
1011
+ ## 🔬 Detection Engineering Intelligence
1012
+
1013
+ **Detection Engineering Intelligence** learns patterns from your detection corpus and helps you create better detections faster.
1014
+
1015
+ ### Pattern Learning from 4 Sources
1016
+
1017
+ The system automatically extracts patterns from:
1018
+ - **Sigma rules** - YAML-based detection logic
1019
+ - **Splunk SPL** - Search Processing Language queries
1020
+ - **KQL queries** - Microsoft Kusto Query Language
1021
+ - **Elastic queries** - Elastic Detection Rules (EQL, KQL, Lucene)
1022
+
1023
+ ### Automatic Template Generation
1024
+
1025
+ When you need a detection for T1059.001 (PowerShell), the system:
1026
+ 1. Analyzes all existing T1059.001 detections across formats
1027
+ 2. Extracts common patterns (process names, command-line arguments, base64 encoding)
1028
+ 3. Generates a template with placeholders for your specific environment
1029
+ 4. Suggests improvements based on learned patterns
1030
+
1031
+ ### Field and Macro References
1032
+
1033
+ The system tracks:
1034
+ - Which fields/macros are commonly used for each technique
1035
+ - Cross-platform field mappings (e.g., `process_name` in Splunk vs `ProcessName` in KQL)
1036
+ - Best practices for field usage in different contexts
1037
+
1038
+ ### Learning from User Feedback
1039
+
1040
+ When you improve a detection or correct a pattern:
1041
+ - The system learns from your changes
1042
+ - Future template generation incorporates your improvements
1043
+ - Field suggestions become more accurate over time
1044
+
1045
+ ### Example Workflow
1046
+
1047
+ ```
1048
+ 1. Extract patterns → extract_patterns("T1059.001")
1049
+ 2. Review patterns → get_patterns("T1059.001", "splunk")
1050
+ 3. Generate template → generate_template("T1059.001", "splunk", "Sysmon")
1051
+ 4. Customize template → (edit generated detection)
1052
+ 5. System learns → (automatically improves future templates)
1053
+ ```
1054
+
1055
+ ## 📚 Documentation
1056
+
1057
+ For detailed information on v2.1 features:
1058
+
1059
+ - **[Architecture](docs/wiki/Architecture.md)** - System architecture and design decisions
1060
+ - **[Knowledge Graph](docs/wiki/Knowledge-Graph.md)** - Deep dive into tribal knowledge and knowledge graph usage
1061
+ - **[Engineering Intelligence](docs/wiki/Engineering-Intelligence.md)** - Pattern learning and template generation guide
1062
+ - **[Tools Reference](docs/wiki/Tools-Reference.md)** - Complete reference for all 71+ tools
786
1063
 
787
1064
  ## 🔗 Using with MITRE ATT&CK MCP
788
1065
 
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Cache Database Module
3
+ *
4
+ * Saved queries and results caching functionality.
5
+ */
6
+ /**
7
+ * Initialize the saved queries table.
8
+ * Called automatically when needed.
9
+ */
10
+ export declare function initSavedQueriesTable(): void;
11
+ /**
12
+ * Save a query result to the cache.
13
+ *
14
+ * @param name - Unique name for the saved query
15
+ * @param queryType - Type of query (e.g., 'search', 'coverage', 'gaps')
16
+ * @param queryParams - Parameters used for the query
17
+ * @param result - The result to cache
18
+ * @param ttlMinutes - Optional time-to-live in minutes
19
+ * @returns The generated ID for the saved query
20
+ */
21
+ export declare function saveQueryResult(name: string, queryType: string, queryParams: Record<string, unknown>, result: unknown, ttlMinutes?: number): string;
22
+ /**
23
+ * Get a saved query result by name.
24
+ * Returns null if not found or expired.
25
+ *
26
+ * @param name - Name of the saved query
27
+ * @returns The cached result or null
28
+ */
29
+ export declare function getSavedQuery(name: string): unknown | null;
30
+ /**
31
+ * List all saved queries, optionally filtered by type.
32
+ *
33
+ * @param queryType - Optional filter by query type
34
+ * @returns Array of saved query metadata
35
+ */
36
+ export declare function listSavedQueries(queryType?: string): Array<{
37
+ id: string;
38
+ name: string;
39
+ query_type: string;
40
+ created_at: string;
41
+ }>;
42
+ /**
43
+ * Delete a saved query by name.
44
+ *
45
+ * @param name - Name of the saved query to delete
46
+ * @returns True if a query was deleted, false otherwise
47
+ */
48
+ export declare function deleteSavedQuery(name: string): boolean;
49
+ /**
50
+ * Delete all expired saved queries.
51
+ *
52
+ * @returns Number of queries deleted
53
+ */
54
+ export declare function cleanupExpiredQueries(): number;
55
+ /**
56
+ * Get a saved query result by ID.
57
+ *
58
+ * @param id - ID of the saved query
59
+ * @returns The cached result or null
60
+ */
61
+ export declare function getSavedQueryById(id: string): unknown | null;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Cache Database Module
3
+ *
4
+ * Saved queries and results caching functionality.
5
+ */
6
+ import { getDb } from './connection.js';
7
+ import { createSavedQueriesTable } from './schema.js';
8
+ // Track if saved queries table has been initialized
9
+ let savedQueriesTableInitialized = false;
10
+ /**
11
+ * Ensure the saved queries table exists.
12
+ */
13
+ function ensureSavedQueriesTable() {
14
+ if (savedQueriesTableInitialized)
15
+ return;
16
+ const database = getDb();
17
+ createSavedQueriesTable(database);
18
+ savedQueriesTableInitialized = true;
19
+ }
20
+ /**
21
+ * Initialize the saved queries table.
22
+ * Called automatically when needed.
23
+ */
24
+ export function initSavedQueriesTable() {
25
+ ensureSavedQueriesTable();
26
+ }
27
+ /**
28
+ * Save a query result to the cache.
29
+ *
30
+ * @param name - Unique name for the saved query
31
+ * @param queryType - Type of query (e.g., 'search', 'coverage', 'gaps')
32
+ * @param queryParams - Parameters used for the query
33
+ * @param result - The result to cache
34
+ * @param ttlMinutes - Optional time-to-live in minutes
35
+ * @returns The generated ID for the saved query
36
+ */
37
+ export function saveQueryResult(name, queryType, queryParams, result, ttlMinutes) {
38
+ ensureSavedQueriesTable();
39
+ const database = getDb();
40
+ const id = `sq_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
41
+ const expiresAt = ttlMinutes
42
+ ? new Date(Date.now() + ttlMinutes * 60 * 1000).toISOString()
43
+ : null;
44
+ const stmt = database.prepare(`
45
+ INSERT OR REPLACE INTO saved_queries (id, name, query_type, query_params, result_json, expires_at)
46
+ VALUES (?, ?, ?, ?, ?, ?)
47
+ `);
48
+ stmt.run(id, name, queryType, JSON.stringify(queryParams), JSON.stringify(result), expiresAt);
49
+ return id;
50
+ }
51
+ /**
52
+ * Get a saved query result by name.
53
+ * Returns null if not found or expired.
54
+ *
55
+ * @param name - Name of the saved query
56
+ * @returns The cached result or null
57
+ */
58
+ export function getSavedQuery(name) {
59
+ ensureSavedQueriesTable();
60
+ const database = getDb();
61
+ const stmt = database.prepare(`
62
+ SELECT result_json, expires_at FROM saved_queries
63
+ WHERE name = ?
64
+ ORDER BY created_at DESC
65
+ LIMIT 1
66
+ `);
67
+ const row = stmt.get(name);
68
+ if (!row)
69
+ return null;
70
+ // Check expiry
71
+ if (row.expires_at && new Date(row.expires_at) < new Date()) {
72
+ return null;
73
+ }
74
+ return JSON.parse(row.result_json);
75
+ }
76
+ /**
77
+ * List all saved queries, optionally filtered by type.
78
+ *
79
+ * @param queryType - Optional filter by query type
80
+ * @returns Array of saved query metadata
81
+ */
82
+ export function listSavedQueries(queryType) {
83
+ ensureSavedQueriesTable();
84
+ const database = getDb();
85
+ let sql = 'SELECT id, name, query_type, created_at FROM saved_queries';
86
+ const params = [];
87
+ if (queryType) {
88
+ sql += ' WHERE query_type = ?';
89
+ params.push(queryType);
90
+ }
91
+ sql += ' ORDER BY created_at DESC LIMIT 50';
92
+ return database.prepare(sql).all(...params);
93
+ }
94
+ /**
95
+ * Delete a saved query by name.
96
+ *
97
+ * @param name - Name of the saved query to delete
98
+ * @returns True if a query was deleted, false otherwise
99
+ */
100
+ export function deleteSavedQuery(name) {
101
+ ensureSavedQueriesTable();
102
+ const database = getDb();
103
+ const result = database.prepare('DELETE FROM saved_queries WHERE name = ?').run(name);
104
+ return result.changes > 0;
105
+ }
106
+ /**
107
+ * Delete all expired saved queries.
108
+ *
109
+ * @returns Number of queries deleted
110
+ */
111
+ export function cleanupExpiredQueries() {
112
+ ensureSavedQueriesTable();
113
+ const database = getDb();
114
+ const result = database.prepare(`
115
+ DELETE FROM saved_queries
116
+ WHERE expires_at IS NOT NULL AND expires_at < datetime('now')
117
+ `).run();
118
+ return result.changes;
119
+ }
120
+ /**
121
+ * Get a saved query result by ID.
122
+ *
123
+ * @param id - ID of the saved query
124
+ * @returns The cached result or null
125
+ */
126
+ export function getSavedQueryById(id) {
127
+ ensureSavedQueriesTable();
128
+ const database = getDb();
129
+ const stmt = database.prepare(`
130
+ SELECT result_json, expires_at FROM saved_queries
131
+ WHERE id = ?
132
+ `);
133
+ const row = stmt.get(id);
134
+ if (!row)
135
+ return null;
136
+ // Check expiry
137
+ if (row.expires_at && new Date(row.expires_at) < new Date()) {
138
+ return null;
139
+ }
140
+ return JSON.parse(row.result_json);
141
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Database Connection Module
3
+ *
4
+ * Manages SQLite connection singleton, path management, and database lifecycle.
5
+ */
6
+ import Database from 'better-sqlite3';
7
+ /**
8
+ * Get the path to the SQLite database file.
9
+ */
10
+ export declare function getDbPath(): string;
11
+ /**
12
+ * Get the cache directory path.
13
+ */
14
+ export declare function getCacheDir(): string;
15
+ /**
16
+ * Initialize and return the database connection singleton.
17
+ * Creates the database file and schema if they don't exist.
18
+ */
19
+ export declare function initDb(): Database.Database;
20
+ /**
21
+ * Get the database connection, initializing if necessary.
22
+ * This is the primary way other modules should access the database.
23
+ */
24
+ export declare function getDb(): Database.Database;
25
+ /**
26
+ * Clear all detections from the database.
27
+ */
28
+ export declare function clearDb(): void;
29
+ /**
30
+ * Force recreation of the database.
31
+ * Useful when schema changes require a fresh start.
32
+ * Handles Windows file locking (EBUSY) with retry logic.
33
+ */
34
+ export declare function recreateDb(): void;
35
+ /**
36
+ * Check if the database file exists.
37
+ */
38
+ export declare function dbExists(): boolean;
39
+ /**
40
+ * Close the database connection.
41
+ */
42
+ export declare function closeDb(): void;