tapps-agents 3.5.40__py3-none-any.whl → 3.6.0__py3-none-any.whl
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.
- tapps_agents/__init__.py +2 -2
- tapps_agents/agents/__init__.py +22 -22
- tapps_agents/agents/analyst/__init__.py +5 -5
- tapps_agents/agents/architect/__init__.py +5 -5
- tapps_agents/agents/architect/agent.py +1033 -1033
- tapps_agents/agents/architect/pattern_detector.py +75 -75
- tapps_agents/agents/cleanup/__init__.py +7 -7
- tapps_agents/agents/cleanup/agent.py +445 -445
- tapps_agents/agents/debugger/__init__.py +7 -7
- tapps_agents/agents/debugger/agent.py +310 -310
- tapps_agents/agents/debugger/error_analyzer.py +437 -437
- tapps_agents/agents/designer/__init__.py +5 -5
- tapps_agents/agents/designer/agent.py +786 -786
- tapps_agents/agents/designer/visual_designer.py +638 -638
- tapps_agents/agents/documenter/__init__.py +7 -7
- tapps_agents/agents/documenter/agent.py +531 -531
- tapps_agents/agents/documenter/doc_generator.py +472 -472
- tapps_agents/agents/documenter/doc_validator.py +393 -393
- tapps_agents/agents/documenter/framework_doc_updater.py +493 -493
- tapps_agents/agents/enhancer/__init__.py +7 -7
- tapps_agents/agents/evaluator/__init__.py +7 -7
- tapps_agents/agents/evaluator/agent.py +443 -443
- tapps_agents/agents/evaluator/priority_evaluator.py +641 -641
- tapps_agents/agents/evaluator/quality_analyzer.py +147 -147
- tapps_agents/agents/evaluator/report_generator.py +344 -344
- tapps_agents/agents/evaluator/usage_analyzer.py +192 -192
- tapps_agents/agents/evaluator/workflow_analyzer.py +189 -189
- tapps_agents/agents/implementer/__init__.py +7 -7
- tapps_agents/agents/implementer/agent.py +798 -798
- tapps_agents/agents/implementer/auto_fix.py +1119 -1119
- tapps_agents/agents/implementer/code_generator.py +73 -73
- tapps_agents/agents/improver/__init__.py +1 -1
- tapps_agents/agents/improver/agent.py +753 -753
- tapps_agents/agents/ops/__init__.py +1 -1
- tapps_agents/agents/ops/agent.py +619 -619
- tapps_agents/agents/ops/dependency_analyzer.py +600 -600
- tapps_agents/agents/orchestrator/__init__.py +5 -5
- tapps_agents/agents/orchestrator/agent.py +522 -522
- tapps_agents/agents/planner/__init__.py +7 -7
- tapps_agents/agents/planner/agent.py +1127 -1127
- tapps_agents/agents/reviewer/__init__.py +24 -24
- tapps_agents/agents/reviewer/agent.py +3513 -3513
- tapps_agents/agents/reviewer/aggregator.py +213 -213
- tapps_agents/agents/reviewer/batch_review.py +448 -448
- tapps_agents/agents/reviewer/cache.py +443 -443
- tapps_agents/agents/reviewer/context7_enhancer.py +630 -630
- tapps_agents/agents/reviewer/context_detector.py +203 -203
- tapps_agents/agents/reviewer/docker_compose_validator.py +158 -158
- tapps_agents/agents/reviewer/dockerfile_validator.py +176 -176
- tapps_agents/agents/reviewer/error_handling.py +126 -126
- tapps_agents/agents/reviewer/feedback_generator.py +490 -490
- tapps_agents/agents/reviewer/influxdb_validator.py +316 -316
- tapps_agents/agents/reviewer/issue_tracking.py +169 -169
- tapps_agents/agents/reviewer/library_detector.py +295 -295
- tapps_agents/agents/reviewer/library_patterns.py +268 -268
- tapps_agents/agents/reviewer/maintainability_scorer.py +593 -593
- tapps_agents/agents/reviewer/metric_strategies.py +276 -276
- tapps_agents/agents/reviewer/mqtt_validator.py +160 -160
- tapps_agents/agents/reviewer/output_enhancer.py +105 -105
- tapps_agents/agents/reviewer/pattern_detector.py +241 -241
- tapps_agents/agents/reviewer/performance_scorer.py +357 -357
- tapps_agents/agents/reviewer/phased_review.py +516 -516
- tapps_agents/agents/reviewer/progressive_review.py +435 -435
- tapps_agents/agents/reviewer/react_scorer.py +331 -331
- tapps_agents/agents/reviewer/score_constants.py +228 -228
- tapps_agents/agents/reviewer/score_validator.py +507 -507
- tapps_agents/agents/reviewer/scorer_registry.py +373 -373
- tapps_agents/agents/reviewer/scoring.py +1566 -1566
- tapps_agents/agents/reviewer/service_discovery.py +534 -534
- tapps_agents/agents/reviewer/tools/__init__.py +41 -41
- tapps_agents/agents/reviewer/tools/parallel_executor.py +581 -581
- tapps_agents/agents/reviewer/tools/ruff_grouping.py +250 -250
- tapps_agents/agents/reviewer/tools/scoped_mypy.py +284 -284
- tapps_agents/agents/reviewer/typescript_scorer.py +1142 -1142
- tapps_agents/agents/reviewer/validation.py +208 -208
- tapps_agents/agents/reviewer/websocket_validator.py +132 -132
- tapps_agents/agents/tester/__init__.py +7 -7
- tapps_agents/agents/tester/accessibility_auditor.py +309 -309
- tapps_agents/agents/tester/agent.py +1080 -1080
- tapps_agents/agents/tester/batch_generator.py +54 -54
- tapps_agents/agents/tester/context_learner.py +51 -51
- tapps_agents/agents/tester/coverage_analyzer.py +386 -386
- tapps_agents/agents/tester/coverage_test_generator.py +290 -290
- tapps_agents/agents/tester/debug_enhancer.py +238 -238
- tapps_agents/agents/tester/device_emulator.py +241 -241
- tapps_agents/agents/tester/integration_generator.py +62 -62
- tapps_agents/agents/tester/network_recorder.py +300 -300
- tapps_agents/agents/tester/performance_monitor.py +320 -320
- tapps_agents/agents/tester/test_fixer.py +316 -316
- tapps_agents/agents/tester/test_generator.py +632 -632
- tapps_agents/agents/tester/trace_manager.py +234 -234
- tapps_agents/agents/tester/visual_regression.py +291 -291
- tapps_agents/analysis/pattern_detector.py +36 -36
- tapps_agents/beads/hydration.py +213 -213
- tapps_agents/beads/parse.py +32 -32
- tapps_agents/beads/specs.py +206 -206
- tapps_agents/cli/__init__.py +9 -9
- tapps_agents/cli/__main__.py +8 -8
- tapps_agents/cli/base.py +478 -478
- tapps_agents/cli/command_classifier.py +72 -72
- tapps_agents/cli/commands/__init__.py +2 -2
- tapps_agents/cli/commands/analyst.py +173 -173
- tapps_agents/cli/commands/architect.py +109 -109
- tapps_agents/cli/commands/cleanup_agent.py +92 -92
- tapps_agents/cli/commands/common.py +126 -126
- tapps_agents/cli/commands/debugger.py +90 -90
- tapps_agents/cli/commands/designer.py +112 -112
- tapps_agents/cli/commands/documenter.py +136 -136
- tapps_agents/cli/commands/enhancer.py +110 -110
- tapps_agents/cli/commands/evaluator.py +255 -255
- tapps_agents/cli/commands/health.py +665 -665
- tapps_agents/cli/commands/implementer.py +301 -301
- tapps_agents/cli/commands/improver.py +91 -91
- tapps_agents/cli/commands/knowledge.py +111 -111
- tapps_agents/cli/commands/learning.py +172 -172
- tapps_agents/cli/commands/observability.py +283 -283
- tapps_agents/cli/commands/ops.py +135 -135
- tapps_agents/cli/commands/orchestrator.py +116 -116
- tapps_agents/cli/commands/planner.py +237 -237
- tapps_agents/cli/commands/reviewer.py +1872 -1872
- tapps_agents/cli/commands/status.py +285 -285
- tapps_agents/cli/commands/task.py +227 -219
- tapps_agents/cli/commands/tester.py +191 -191
- tapps_agents/cli/commands/top_level.py +3586 -3586
- tapps_agents/cli/feedback.py +936 -936
- tapps_agents/cli/formatters.py +608 -608
- tapps_agents/cli/help/__init__.py +7 -7
- tapps_agents/cli/help/static_help.py +425 -425
- tapps_agents/cli/network_detection.py +110 -110
- tapps_agents/cli/output_compactor.py +274 -274
- tapps_agents/cli/parsers/__init__.py +2 -2
- tapps_agents/cli/parsers/analyst.py +186 -186
- tapps_agents/cli/parsers/architect.py +167 -167
- tapps_agents/cli/parsers/cleanup_agent.py +228 -228
- tapps_agents/cli/parsers/debugger.py +116 -116
- tapps_agents/cli/parsers/designer.py +182 -182
- tapps_agents/cli/parsers/documenter.py +134 -134
- tapps_agents/cli/parsers/enhancer.py +113 -113
- tapps_agents/cli/parsers/evaluator.py +213 -213
- tapps_agents/cli/parsers/implementer.py +168 -168
- tapps_agents/cli/parsers/improver.py +132 -132
- tapps_agents/cli/parsers/ops.py +159 -159
- tapps_agents/cli/parsers/orchestrator.py +98 -98
- tapps_agents/cli/parsers/planner.py +145 -145
- tapps_agents/cli/parsers/reviewer.py +462 -462
- tapps_agents/cli/parsers/tester.py +124 -124
- tapps_agents/cli/progress_heartbeat.py +254 -254
- tapps_agents/cli/streaming_progress.py +336 -336
- tapps_agents/cli/utils/__init__.py +6 -6
- tapps_agents/cli/utils/agent_lifecycle.py +48 -48
- tapps_agents/cli/utils/error_formatter.py +82 -82
- tapps_agents/cli/utils/error_recovery.py +188 -188
- tapps_agents/cli/utils/output_handler.py +59 -59
- tapps_agents/cli/utils/prompt_enhancer.py +319 -319
- tapps_agents/cli/validators/__init__.py +9 -9
- tapps_agents/cli/validators/command_validator.py +81 -81
- tapps_agents/context7/__init__.py +112 -112
- tapps_agents/context7/agent_integration.py +869 -869
- tapps_agents/context7/analytics.py +382 -382
- tapps_agents/context7/analytics_dashboard.py +299 -299
- tapps_agents/context7/async_cache.py +681 -681
- tapps_agents/context7/backup_client.py +958 -958
- tapps_agents/context7/cache_locking.py +194 -194
- tapps_agents/context7/cache_metadata.py +214 -214
- tapps_agents/context7/cache_prewarm.py +488 -488
- tapps_agents/context7/cache_structure.py +168 -168
- tapps_agents/context7/cache_warming.py +604 -604
- tapps_agents/context7/circuit_breaker.py +376 -376
- tapps_agents/context7/cleanup.py +461 -461
- tapps_agents/context7/commands.py +858 -858
- tapps_agents/context7/credential_validation.py +276 -276
- tapps_agents/context7/cross_reference_resolver.py +168 -168
- tapps_agents/context7/cross_references.py +424 -424
- tapps_agents/context7/doc_manager.py +225 -225
- tapps_agents/context7/fuzzy_matcher.py +369 -369
- tapps_agents/context7/kb_cache.py +404 -404
- tapps_agents/context7/language_detector.py +219 -219
- tapps_agents/context7/library_detector.py +725 -725
- tapps_agents/context7/lookup.py +738 -738
- tapps_agents/context7/metadata.py +258 -258
- tapps_agents/context7/refresh_queue.py +300 -300
- tapps_agents/context7/security.py +373 -373
- tapps_agents/context7/staleness_policies.py +278 -278
- tapps_agents/context7/tiles_integration.py +47 -47
- tapps_agents/continuous_bug_fix/__init__.py +20 -20
- tapps_agents/continuous_bug_fix/bug_finder.py +306 -306
- tapps_agents/continuous_bug_fix/bug_fix_coordinator.py +177 -177
- tapps_agents/continuous_bug_fix/commit_manager.py +178 -178
- tapps_agents/continuous_bug_fix/continuous_bug_fixer.py +322 -322
- tapps_agents/continuous_bug_fix/proactive_bug_finder.py +285 -285
- tapps_agents/core/__init__.py +298 -298
- tapps_agents/core/adaptive_cache_config.py +432 -432
- tapps_agents/core/agent_base.py +647 -647
- tapps_agents/core/agent_cache.py +466 -466
- tapps_agents/core/agent_learning.py +1865 -1865
- tapps_agents/core/analytics_dashboard.py +563 -563
- tapps_agents/core/analytics_enhancements.py +597 -597
- tapps_agents/core/anonymization.py +274 -274
- tapps_agents/core/artifact_context_builder.py +293 -0
- tapps_agents/core/ast_parser.py +228 -228
- tapps_agents/core/async_file_ops.py +402 -402
- tapps_agents/core/best_practice_consultant.py +299 -299
- tapps_agents/core/brownfield_analyzer.py +299 -299
- tapps_agents/core/brownfield_review.py +541 -541
- tapps_agents/core/browser_controller.py +513 -513
- tapps_agents/core/capability_registry.py +418 -418
- tapps_agents/core/change_impact_analyzer.py +190 -190
- tapps_agents/core/checkpoint_manager.py +377 -377
- tapps_agents/core/code_generator.py +329 -329
- tapps_agents/core/code_validator.py +276 -276
- tapps_agents/core/command_registry.py +327 -327
- tapps_agents/core/config.py +33 -0
- tapps_agents/core/context_gathering/__init__.py +2 -2
- tapps_agents/core/context_gathering/repository_explorer.py +28 -28
- tapps_agents/core/context_intelligence/__init__.py +2 -2
- tapps_agents/core/context_intelligence/relevance_scorer.py +24 -24
- tapps_agents/core/context_intelligence/token_budget_manager.py +27 -27
- tapps_agents/core/context_manager.py +240 -240
- tapps_agents/core/cursor_feedback_monitor.py +146 -146
- tapps_agents/core/cursor_verification.py +290 -290
- tapps_agents/core/customization_loader.py +280 -280
- tapps_agents/core/customization_schema.py +260 -260
- tapps_agents/core/customization_template.py +238 -238
- tapps_agents/core/debug_logger.py +124 -124
- tapps_agents/core/design_validator.py +298 -298
- tapps_agents/core/diagram_generator.py +226 -226
- tapps_agents/core/docker_utils.py +232 -232
- tapps_agents/core/document_generator.py +617 -617
- tapps_agents/core/domain_detector.py +30 -30
- tapps_agents/core/error_envelope.py +454 -454
- tapps_agents/core/error_handler.py +270 -270
- tapps_agents/core/estimation_tracker.py +189 -189
- tapps_agents/core/eval_prompt_engine.py +116 -116
- tapps_agents/core/evaluation_base.py +119 -119
- tapps_agents/core/evaluation_models.py +320 -320
- tapps_agents/core/evaluation_orchestrator.py +225 -225
- tapps_agents/core/evaluators/__init__.py +7 -7
- tapps_agents/core/evaluators/architectural_evaluator.py +205 -205
- tapps_agents/core/evaluators/behavioral_evaluator.py +160 -160
- tapps_agents/core/evaluators/performance_profile_evaluator.py +160 -160
- tapps_agents/core/evaluators/security_posture_evaluator.py +148 -148
- tapps_agents/core/evaluators/spec_compliance_evaluator.py +181 -181
- tapps_agents/core/exceptions.py +107 -107
- tapps_agents/core/expert_config_generator.py +293 -293
- tapps_agents/core/export_schema.py +202 -202
- tapps_agents/core/external_feedback_models.py +102 -102
- tapps_agents/core/external_feedback_storage.py +213 -213
- tapps_agents/core/fallback_strategy.py +314 -314
- tapps_agents/core/feedback_analyzer.py +162 -162
- tapps_agents/core/feedback_collector.py +178 -178
- tapps_agents/core/git_operations.py +445 -445
- tapps_agents/core/hardware_profiler.py +151 -151
- tapps_agents/core/instructions.py +324 -324
- tapps_agents/core/io_guardrails.py +69 -69
- tapps_agents/core/issue_manifest.py +249 -249
- tapps_agents/core/issue_schema.py +139 -139
- tapps_agents/core/json_utils.py +128 -128
- tapps_agents/core/knowledge_graph.py +446 -446
- tapps_agents/core/language_detector.py +296 -296
- tapps_agents/core/learning_confidence.py +242 -242
- tapps_agents/core/learning_dashboard.py +246 -246
- tapps_agents/core/learning_decision.py +384 -384
- tapps_agents/core/learning_explainability.py +578 -578
- tapps_agents/core/learning_export.py +287 -287
- tapps_agents/core/learning_integration.py +228 -228
- tapps_agents/core/llm_behavior.py +232 -232
- tapps_agents/core/long_duration_support.py +786 -786
- tapps_agents/core/mcp_setup.py +106 -106
- tapps_agents/core/memory_integration.py +396 -396
- tapps_agents/core/meta_learning.py +666 -666
- tapps_agents/core/module_path_sanitizer.py +199 -199
- tapps_agents/core/multi_agent_orchestrator.py +382 -382
- tapps_agents/core/network_errors.py +125 -125
- tapps_agents/core/nfr_validator.py +336 -336
- tapps_agents/core/offline_mode.py +158 -158
- tapps_agents/core/output_contracts.py +300 -300
- tapps_agents/core/output_formatter.py +300 -300
- tapps_agents/core/path_normalizer.py +174 -174
- tapps_agents/core/path_validator.py +322 -322
- tapps_agents/core/pattern_library.py +250 -250
- tapps_agents/core/performance_benchmark.py +301 -301
- tapps_agents/core/performance_monitor.py +184 -184
- tapps_agents/core/playwright_mcp_controller.py +771 -771
- tapps_agents/core/policy_loader.py +135 -135
- tapps_agents/core/progress.py +166 -166
- tapps_agents/core/project_profile.py +354 -354
- tapps_agents/core/project_type_detector.py +454 -454
- tapps_agents/core/prompt_base.py +223 -223
- tapps_agents/core/prompt_learning/__init__.py +2 -2
- tapps_agents/core/prompt_learning/learning_loop.py +24 -24
- tapps_agents/core/prompt_learning/project_prompt_store.py +25 -25
- tapps_agents/core/prompt_learning/skills_prompt_analyzer.py +35 -35
- tapps_agents/core/prompt_optimization/__init__.py +6 -6
- tapps_agents/core/prompt_optimization/ab_tester.py +114 -114
- tapps_agents/core/prompt_optimization/correlation_analyzer.py +160 -160
- tapps_agents/core/prompt_optimization/progressive_refiner.py +129 -129
- tapps_agents/core/prompt_optimization/prompt_library.py +37 -37
- tapps_agents/core/requirements_evaluator.py +431 -431
- tapps_agents/core/resource_aware_executor.py +449 -449
- tapps_agents/core/resource_monitor.py +343 -343
- tapps_agents/core/resume_handler.py +298 -298
- tapps_agents/core/retry_handler.py +197 -197
- tapps_agents/core/review_checklists.py +479 -479
- tapps_agents/core/role_loader.py +201 -201
- tapps_agents/core/role_template_loader.py +201 -201
- tapps_agents/core/runtime_mode.py +60 -60
- tapps_agents/core/security_scanner.py +342 -342
- tapps_agents/core/skill_agent_registry.py +194 -194
- tapps_agents/core/skill_integration.py +208 -208
- tapps_agents/core/skill_loader.py +492 -492
- tapps_agents/core/skill_template.py +341 -341
- tapps_agents/core/skill_validator.py +478 -478
- tapps_agents/core/stack_analyzer.py +35 -35
- tapps_agents/core/startup.py +174 -174
- tapps_agents/core/storage_manager.py +397 -397
- tapps_agents/core/storage_models.py +166 -166
- tapps_agents/core/story_evaluator.py +410 -410
- tapps_agents/core/subprocess_utils.py +170 -170
- tapps_agents/core/task_duration.py +296 -296
- tapps_agents/core/task_memory.py +582 -582
- tapps_agents/core/task_state.py +226 -226
- tapps_agents/core/tech_stack_priorities.py +208 -208
- tapps_agents/core/temp_directory.py +194 -194
- tapps_agents/core/template_merger.py +600 -600
- tapps_agents/core/template_selector.py +280 -280
- tapps_agents/core/test_generator.py +286 -286
- tapps_agents/core/tiered_context.py +253 -253
- tapps_agents/core/token_monitor.py +345 -345
- tapps_agents/core/traceability.py +254 -254
- tapps_agents/core/trajectory_tracker.py +50 -50
- tapps_agents/core/unicode_safe.py +143 -143
- tapps_agents/core/unified_cache_config.py +170 -170
- tapps_agents/core/unified_state.py +324 -324
- tapps_agents/core/validate_cursor_setup.py +237 -237
- tapps_agents/core/validation_registry.py +136 -136
- tapps_agents/core/validators/__init__.py +4 -4
- tapps_agents/core/validators/python_validator.py +87 -87
- tapps_agents/core/verification_agent.py +90 -90
- tapps_agents/core/visual_feedback.py +644 -644
- tapps_agents/core/workflow_validator.py +197 -197
- tapps_agents/core/worktree.py +367 -367
- tapps_agents/docker/__init__.py +10 -10
- tapps_agents/docker/analyzer.py +186 -186
- tapps_agents/docker/debugger.py +229 -229
- tapps_agents/docker/error_patterns.py +216 -216
- tapps_agents/epic/__init__.py +22 -22
- tapps_agents/epic/beads_sync.py +115 -115
- tapps_agents/epic/markdown_sync.py +105 -105
- tapps_agents/epic/models.py +96 -96
- tapps_agents/experts/__init__.py +163 -163
- tapps_agents/experts/agent_integration.py +243 -243
- tapps_agents/experts/auto_generator.py +331 -331
- tapps_agents/experts/base_expert.py +536 -536
- tapps_agents/experts/builtin_registry.py +261 -261
- tapps_agents/experts/business_metrics.py +565 -565
- tapps_agents/experts/cache.py +266 -266
- tapps_agents/experts/confidence_breakdown.py +306 -306
- tapps_agents/experts/confidence_calculator.py +336 -336
- tapps_agents/experts/confidence_metrics.py +236 -236
- tapps_agents/experts/domain_config.py +311 -311
- tapps_agents/experts/domain_detector.py +550 -550
- tapps_agents/experts/domain_utils.py +84 -84
- tapps_agents/experts/expert_config.py +113 -113
- tapps_agents/experts/expert_engine.py +465 -465
- tapps_agents/experts/expert_registry.py +744 -744
- tapps_agents/experts/expert_synthesizer.py +70 -70
- tapps_agents/experts/governance.py +197 -197
- tapps_agents/experts/history_logger.py +312 -312
- tapps_agents/experts/knowledge/README.md +180 -180
- tapps_agents/experts/knowledge/accessibility/accessible-forms.md +331 -331
- tapps_agents/experts/knowledge/accessibility/aria-patterns.md +344 -344
- tapps_agents/experts/knowledge/accessibility/color-contrast.md +285 -285
- tapps_agents/experts/knowledge/accessibility/keyboard-navigation.md +332 -332
- tapps_agents/experts/knowledge/accessibility/screen-readers.md +282 -282
- tapps_agents/experts/knowledge/accessibility/semantic-html.md +355 -355
- tapps_agents/experts/knowledge/accessibility/testing-accessibility.md +369 -369
- tapps_agents/experts/knowledge/accessibility/wcag-2.1.md +296 -296
- tapps_agents/experts/knowledge/accessibility/wcag-2.2.md +211 -211
- tapps_agents/experts/knowledge/agent-learning/best-practices.md +715 -715
- tapps_agents/experts/knowledge/agent-learning/pattern-extraction.md +282 -282
- tapps_agents/experts/knowledge/agent-learning/prompt-optimization.md +320 -320
- tapps_agents/experts/knowledge/ai-frameworks/model-optimization.md +90 -90
- tapps_agents/experts/knowledge/ai-frameworks/openvino-patterns.md +260 -260
- tapps_agents/experts/knowledge/api-design-integration/api-gateway-patterns.md +309 -309
- tapps_agents/experts/knowledge/api-design-integration/api-security-patterns.md +521 -521
- tapps_agents/experts/knowledge/api-design-integration/api-versioning.md +421 -421
- tapps_agents/experts/knowledge/api-design-integration/async-protocol-patterns.md +61 -61
- tapps_agents/experts/knowledge/api-design-integration/contract-testing.md +221 -221
- tapps_agents/experts/knowledge/api-design-integration/external-api-integration.md +489 -489
- tapps_agents/experts/knowledge/api-design-integration/fastapi-patterns.md +360 -360
- tapps_agents/experts/knowledge/api-design-integration/fastapi-testing.md +262 -262
- tapps_agents/experts/knowledge/api-design-integration/graphql-patterns.md +582 -582
- tapps_agents/experts/knowledge/api-design-integration/grpc-best-practices.md +499 -499
- tapps_agents/experts/knowledge/api-design-integration/mqtt-patterns.md +455 -455
- tapps_agents/experts/knowledge/api-design-integration/rate-limiting.md +507 -507
- tapps_agents/experts/knowledge/api-design-integration/restful-api-design.md +618 -618
- tapps_agents/experts/knowledge/api-design-integration/websocket-patterns.md +480 -480
- tapps_agents/experts/knowledge/cloud-infrastructure/cloud-native-patterns.md +175 -175
- tapps_agents/experts/knowledge/cloud-infrastructure/container-health-checks.md +261 -261
- tapps_agents/experts/knowledge/cloud-infrastructure/containerization.md +222 -222
- tapps_agents/experts/knowledge/cloud-infrastructure/cost-optimization.md +122 -122
- tapps_agents/experts/knowledge/cloud-infrastructure/disaster-recovery.md +153 -153
- tapps_agents/experts/knowledge/cloud-infrastructure/dockerfile-patterns.md +285 -285
- tapps_agents/experts/knowledge/cloud-infrastructure/infrastructure-as-code.md +187 -187
- tapps_agents/experts/knowledge/cloud-infrastructure/kubernetes-patterns.md +253 -253
- tapps_agents/experts/knowledge/cloud-infrastructure/multi-cloud-strategies.md +155 -155
- tapps_agents/experts/knowledge/cloud-infrastructure/serverless-architecture.md +200 -200
- tapps_agents/experts/knowledge/code-quality-analysis/README.md +16 -16
- tapps_agents/experts/knowledge/code-quality-analysis/code-metrics.md +137 -137
- tapps_agents/experts/knowledge/code-quality-analysis/complexity-analysis.md +181 -181
- tapps_agents/experts/knowledge/code-quality-analysis/technical-debt-patterns.md +191 -191
- tapps_agents/experts/knowledge/data-privacy-compliance/anonymization.md +313 -313
- tapps_agents/experts/knowledge/data-privacy-compliance/ccpa.md +255 -255
- tapps_agents/experts/knowledge/data-privacy-compliance/consent-management.md +282 -282
- tapps_agents/experts/knowledge/data-privacy-compliance/data-minimization.md +275 -275
- tapps_agents/experts/knowledge/data-privacy-compliance/data-retention.md +297 -297
- tapps_agents/experts/knowledge/data-privacy-compliance/data-subject-rights.md +383 -383
- tapps_agents/experts/knowledge/data-privacy-compliance/encryption-privacy.md +285 -285
- tapps_agents/experts/knowledge/data-privacy-compliance/gdpr.md +344 -344
- tapps_agents/experts/knowledge/data-privacy-compliance/hipaa.md +385 -385
- tapps_agents/experts/knowledge/data-privacy-compliance/privacy-by-design.md +280 -280
- tapps_agents/experts/knowledge/database-data-management/acid-vs-cap.md +164 -164
- tapps_agents/experts/knowledge/database-data-management/backup-and-recovery.md +182 -182
- tapps_agents/experts/knowledge/database-data-management/data-modeling.md +172 -172
- tapps_agents/experts/knowledge/database-data-management/database-design.md +187 -187
- tapps_agents/experts/knowledge/database-data-management/flux-query-optimization.md +342 -342
- tapps_agents/experts/knowledge/database-data-management/influxdb-connection-patterns.md +432 -432
- tapps_agents/experts/knowledge/database-data-management/influxdb-patterns.md +442 -442
- tapps_agents/experts/knowledge/database-data-management/migration-strategies.md +216 -216
- tapps_agents/experts/knowledge/database-data-management/nosql-patterns.md +259 -259
- tapps_agents/experts/knowledge/database-data-management/scalability-patterns.md +184 -184
- tapps_agents/experts/knowledge/database-data-management/sql-optimization.md +175 -175
- tapps_agents/experts/knowledge/database-data-management/time-series-modeling.md +444 -444
- tapps_agents/experts/knowledge/development-workflow/README.md +16 -16
- tapps_agents/experts/knowledge/development-workflow/automation-best-practices.md +216 -216
- tapps_agents/experts/knowledge/development-workflow/build-strategies.md +198 -198
- tapps_agents/experts/knowledge/development-workflow/deployment-patterns.md +205 -205
- tapps_agents/experts/knowledge/development-workflow/git-workflows.md +205 -205
- tapps_agents/experts/knowledge/documentation-knowledge-management/README.md +16 -16
- tapps_agents/experts/knowledge/documentation-knowledge-management/api-documentation-patterns.md +231 -231
- tapps_agents/experts/knowledge/documentation-knowledge-management/documentation-standards.md +191 -191
- tapps_agents/experts/knowledge/documentation-knowledge-management/knowledge-management.md +171 -171
- tapps_agents/experts/knowledge/documentation-knowledge-management/technical-writing-guide.md +192 -192
- tapps_agents/experts/knowledge/observability-monitoring/alerting-patterns.md +461 -461
- tapps_agents/experts/knowledge/observability-monitoring/apm-tools.md +459 -459
- tapps_agents/experts/knowledge/observability-monitoring/distributed-tracing.md +367 -367
- tapps_agents/experts/knowledge/observability-monitoring/logging-strategies.md +478 -478
- tapps_agents/experts/knowledge/observability-monitoring/metrics-and-monitoring.md +510 -510
- tapps_agents/experts/knowledge/observability-monitoring/observability-best-practices.md +492 -492
- tapps_agents/experts/knowledge/observability-monitoring/open-telemetry.md +573 -573
- tapps_agents/experts/knowledge/observability-monitoring/slo-sli-sla.md +419 -419
- tapps_agents/experts/knowledge/performance/anti-patterns.md +284 -284
- tapps_agents/experts/knowledge/performance/api-performance.md +256 -256
- tapps_agents/experts/knowledge/performance/caching.md +327 -327
- tapps_agents/experts/knowledge/performance/database-performance.md +252 -252
- tapps_agents/experts/knowledge/performance/optimization-patterns.md +327 -327
- tapps_agents/experts/knowledge/performance/profiling.md +297 -297
- tapps_agents/experts/knowledge/performance/resource-management.md +293 -293
- tapps_agents/experts/knowledge/performance/scalability.md +306 -306
- tapps_agents/experts/knowledge/security/owasp-top10.md +209 -209
- tapps_agents/experts/knowledge/security/secure-coding-practices.md +207 -207
- tapps_agents/experts/knowledge/security/threat-modeling.md +220 -220
- tapps_agents/experts/knowledge/security/vulnerability-patterns.md +342 -342
- tapps_agents/experts/knowledge/software-architecture/docker-compose-patterns.md +314 -314
- tapps_agents/experts/knowledge/software-architecture/microservices-patterns.md +379 -379
- tapps_agents/experts/knowledge/software-architecture/service-communication.md +316 -316
- tapps_agents/experts/knowledge/testing/best-practices.md +310 -310
- tapps_agents/experts/knowledge/testing/coverage-analysis.md +293 -293
- tapps_agents/experts/knowledge/testing/mocking.md +256 -256
- tapps_agents/experts/knowledge/testing/test-automation.md +276 -276
- tapps_agents/experts/knowledge/testing/test-data.md +271 -271
- tapps_agents/experts/knowledge/testing/test-design-patterns.md +280 -280
- tapps_agents/experts/knowledge/testing/test-maintenance.md +236 -236
- tapps_agents/experts/knowledge/testing/test-strategies.md +311 -311
- tapps_agents/experts/knowledge/user-experience/information-architecture.md +325 -325
- tapps_agents/experts/knowledge/user-experience/interaction-design.md +363 -363
- tapps_agents/experts/knowledge/user-experience/prototyping.md +293 -293
- tapps_agents/experts/knowledge/user-experience/usability-heuristics.md +337 -337
- tapps_agents/experts/knowledge/user-experience/usability-testing.md +311 -311
- tapps_agents/experts/knowledge/user-experience/user-journeys.md +296 -296
- tapps_agents/experts/knowledge/user-experience/user-research.md +373 -373
- tapps_agents/experts/knowledge/user-experience/ux-principles.md +340 -340
- tapps_agents/experts/knowledge_freshness.py +321 -321
- tapps_agents/experts/knowledge_ingestion.py +438 -438
- tapps_agents/experts/knowledge_need_detector.py +93 -93
- tapps_agents/experts/knowledge_validator.py +382 -382
- tapps_agents/experts/observability.py +440 -440
- tapps_agents/experts/passive_notifier.py +238 -238
- tapps_agents/experts/proactive_orchestrator.py +32 -32
- tapps_agents/experts/rag_chunker.py +205 -205
- tapps_agents/experts/rag_embedder.py +152 -152
- tapps_agents/experts/rag_evaluation.py +299 -299
- tapps_agents/experts/rag_index.py +303 -303
- tapps_agents/experts/rag_metrics.py +293 -293
- tapps_agents/experts/rag_safety.py +263 -263
- tapps_agents/experts/report_generator.py +296 -296
- tapps_agents/experts/setup_wizard.py +441 -441
- tapps_agents/experts/simple_rag.py +431 -431
- tapps_agents/experts/vector_rag.py +354 -354
- tapps_agents/experts/weight_distributor.py +304 -304
- tapps_agents/health/__init__.py +24 -24
- tapps_agents/health/base.py +75 -75
- tapps_agents/health/checks/__init__.py +22 -22
- tapps_agents/health/checks/automation.py +127 -127
- tapps_agents/health/checks/context7_cache.py +210 -210
- tapps_agents/health/checks/environment.py +116 -116
- tapps_agents/health/checks/execution.py +170 -170
- tapps_agents/health/checks/knowledge_base.py +187 -187
- tapps_agents/health/checks/outcomes.py +324 -324
- tapps_agents/health/collector.py +280 -280
- tapps_agents/health/dashboard.py +137 -137
- tapps_agents/health/metrics.py +151 -151
- tapps_agents/health/orchestrator.py +271 -271
- tapps_agents/health/registry.py +166 -166
- tapps_agents/hooks/__init__.py +33 -33
- tapps_agents/hooks/config.py +140 -140
- tapps_agents/hooks/events.py +135 -135
- tapps_agents/hooks/executor.py +128 -128
- tapps_agents/hooks/manager.py +143 -143
- tapps_agents/integration/__init__.py +8 -8
- tapps_agents/integration/service_integrator.py +121 -121
- tapps_agents/integrations/__init__.py +10 -10
- tapps_agents/integrations/clawdbot.py +525 -525
- tapps_agents/integrations/memory_bridge.py +356 -356
- tapps_agents/mcp/__init__.py +18 -18
- tapps_agents/mcp/gateway.py +112 -112
- tapps_agents/mcp/servers/__init__.py +13 -13
- tapps_agents/mcp/servers/analysis.py +204 -204
- tapps_agents/mcp/servers/context7.py +198 -198
- tapps_agents/mcp/servers/filesystem.py +218 -218
- tapps_agents/mcp/servers/git.py +201 -201
- tapps_agents/mcp/tool_registry.py +115 -115
- tapps_agents/quality/__init__.py +54 -54
- tapps_agents/quality/coverage_analyzer.py +379 -379
- tapps_agents/quality/enforcement.py +82 -82
- tapps_agents/quality/gates/__init__.py +37 -37
- tapps_agents/quality/gates/approval_gate.py +255 -255
- tapps_agents/quality/gates/base.py +84 -84
- tapps_agents/quality/gates/exceptions.py +43 -43
- tapps_agents/quality/gates/policy_gate.py +195 -195
- tapps_agents/quality/gates/registry.py +239 -239
- tapps_agents/quality/gates/security_gate.py +156 -156
- tapps_agents/quality/quality_gates.py +369 -369
- tapps_agents/quality/secret_scanner.py +335 -335
- tapps_agents/session/__init__.py +19 -19
- tapps_agents/session/manager.py +256 -256
- tapps_agents/simple_mode/__init__.py +66 -66
- tapps_agents/simple_mode/agent_contracts.py +357 -357
- tapps_agents/simple_mode/beads_hooks.py +151 -151
- tapps_agents/simple_mode/code_snippet_handler.py +382 -382
- tapps_agents/simple_mode/documentation_manager.py +395 -395
- tapps_agents/simple_mode/documentation_reader.py +187 -187
- tapps_agents/simple_mode/file_inference.py +292 -292
- tapps_agents/simple_mode/framework_change_detector.py +268 -268
- tapps_agents/simple_mode/intent_parser.py +510 -510
- tapps_agents/simple_mode/learning_progression.py +358 -358
- tapps_agents/simple_mode/nl_handler.py +700 -700
- tapps_agents/simple_mode/onboarding.py +253 -253
- tapps_agents/simple_mode/orchestrators/__init__.py +38 -38
- tapps_agents/simple_mode/orchestrators/base.py +185 -185
- tapps_agents/simple_mode/orchestrators/breakdown_orchestrator.py +49 -49
- tapps_agents/simple_mode/orchestrators/brownfield_orchestrator.py +135 -135
- tapps_agents/simple_mode/orchestrators/build_orchestrator.py +2700 -2667
- tapps_agents/simple_mode/orchestrators/deliverable_checklist.py +349 -349
- tapps_agents/simple_mode/orchestrators/enhance_orchestrator.py +53 -53
- tapps_agents/simple_mode/orchestrators/epic_orchestrator.py +122 -122
- tapps_agents/simple_mode/orchestrators/explore_orchestrator.py +184 -184
- tapps_agents/simple_mode/orchestrators/fix_orchestrator.py +723 -723
- tapps_agents/simple_mode/orchestrators/plan_analysis_orchestrator.py +206 -206
- tapps_agents/simple_mode/orchestrators/pr_orchestrator.py +237 -237
- tapps_agents/simple_mode/orchestrators/refactor_orchestrator.py +222 -222
- tapps_agents/simple_mode/orchestrators/requirements_tracer.py +262 -262
- tapps_agents/simple_mode/orchestrators/resume_orchestrator.py +210 -210
- tapps_agents/simple_mode/orchestrators/review_orchestrator.py +161 -161
- tapps_agents/simple_mode/orchestrators/test_orchestrator.py +82 -82
- tapps_agents/simple_mode/output_aggregator.py +340 -340
- tapps_agents/simple_mode/result_formatters.py +598 -598
- tapps_agents/simple_mode/step_dependencies.py +382 -382
- tapps_agents/simple_mode/step_results.py +276 -276
- tapps_agents/simple_mode/streaming.py +388 -388
- tapps_agents/simple_mode/variations.py +129 -129
- tapps_agents/simple_mode/visual_feedback.py +238 -238
- tapps_agents/simple_mode/zero_config.py +274 -274
- tapps_agents/suggestions/__init__.py +8 -8
- tapps_agents/suggestions/inline_suggester.py +52 -52
- tapps_agents/templates/__init__.py +8 -8
- tapps_agents/templates/microservice_generator.py +274 -274
- tapps_agents/utils/env_validator.py +291 -291
- tapps_agents/workflow/__init__.py +171 -171
- tapps_agents/workflow/acceptance_verifier.py +132 -132
- tapps_agents/workflow/agent_handlers/__init__.py +41 -41
- tapps_agents/workflow/agent_handlers/analyst_handler.py +75 -75
- tapps_agents/workflow/agent_handlers/architect_handler.py +107 -107
- tapps_agents/workflow/agent_handlers/base.py +84 -84
- tapps_agents/workflow/agent_handlers/debugger_handler.py +100 -100
- tapps_agents/workflow/agent_handlers/designer_handler.py +110 -110
- tapps_agents/workflow/agent_handlers/documenter_handler.py +94 -94
- tapps_agents/workflow/agent_handlers/implementer_handler.py +235 -235
- tapps_agents/workflow/agent_handlers/ops_handler.py +62 -62
- tapps_agents/workflow/agent_handlers/orchestrator_handler.py +43 -43
- tapps_agents/workflow/agent_handlers/planner_handler.py +98 -98
- tapps_agents/workflow/agent_handlers/registry.py +119 -119
- tapps_agents/workflow/agent_handlers/reviewer_handler.py +119 -119
- tapps_agents/workflow/agent_handlers/tester_handler.py +69 -69
- tapps_agents/workflow/analytics_accessor.py +337 -337
- tapps_agents/workflow/analytics_alerts.py +416 -416
- tapps_agents/workflow/analytics_dashboard_cursor.py +281 -281
- tapps_agents/workflow/analytics_dual_write.py +103 -103
- tapps_agents/workflow/analytics_integration.py +119 -119
- tapps_agents/workflow/analytics_query_parser.py +278 -278
- tapps_agents/workflow/analytics_visualizer.py +259 -259
- tapps_agents/workflow/artifact_helper.py +204 -204
- tapps_agents/workflow/audit_logger.py +263 -263
- tapps_agents/workflow/auto_execution_config.py +340 -340
- tapps_agents/workflow/auto_progression.py +586 -586
- tapps_agents/workflow/branch_cleanup.py +349 -349
- tapps_agents/workflow/checkpoint.py +256 -256
- tapps_agents/workflow/checkpoint_manager.py +178 -178
- tapps_agents/workflow/code_artifact.py +179 -179
- tapps_agents/workflow/common_enums.py +96 -96
- tapps_agents/workflow/confirmation_handler.py +130 -130
- tapps_agents/workflow/context_analyzer.py +222 -222
- tapps_agents/workflow/context_artifact.py +230 -230
- tapps_agents/workflow/cursor_chat.py +94 -94
- tapps_agents/workflow/cursor_executor.py +2337 -2196
- tapps_agents/workflow/cursor_skill_helper.py +516 -516
- tapps_agents/workflow/dependency_resolver.py +244 -244
- tapps_agents/workflow/design_artifact.py +156 -156
- tapps_agents/workflow/detector.py +751 -751
- tapps_agents/workflow/direct_execution_fallback.py +301 -301
- tapps_agents/workflow/docs_artifact.py +168 -168
- tapps_agents/workflow/enforcer.py +389 -389
- tapps_agents/workflow/enhancement_artifact.py +142 -142
- tapps_agents/workflow/error_recovery.py +806 -806
- tapps_agents/workflow/event_bus.py +183 -183
- tapps_agents/workflow/event_log.py +612 -612
- tapps_agents/workflow/events.py +63 -63
- tapps_agents/workflow/exceptions.py +43 -43
- tapps_agents/workflow/execution_graph.py +498 -498
- tapps_agents/workflow/execution_plan.py +126 -126
- tapps_agents/workflow/file_utils.py +186 -186
- tapps_agents/workflow/gate_evaluator.py +182 -182
- tapps_agents/workflow/gate_integration.py +200 -200
- tapps_agents/workflow/graph_visualizer.py +130 -130
- tapps_agents/workflow/health_checker.py +206 -206
- tapps_agents/workflow/logging_helper.py +243 -243
- tapps_agents/workflow/manifest.py +582 -582
- tapps_agents/workflow/marker_writer.py +250 -250
- tapps_agents/workflow/message_formatter.py +188 -188
- tapps_agents/workflow/messaging.py +325 -325
- tapps_agents/workflow/metadata_models.py +91 -91
- tapps_agents/workflow/metrics_integration.py +226 -226
- tapps_agents/workflow/migration_utils.py +116 -116
- tapps_agents/workflow/models.py +148 -111
- tapps_agents/workflow/nlp_config.py +198 -198
- tapps_agents/workflow/nlp_error_handler.py +207 -207
- tapps_agents/workflow/nlp_executor.py +163 -163
- tapps_agents/workflow/nlp_parser.py +528 -528
- tapps_agents/workflow/observability_dashboard.py +451 -451
- tapps_agents/workflow/observer.py +170 -170
- tapps_agents/workflow/ops_artifact.py +257 -257
- tapps_agents/workflow/output_passing.py +214 -214
- tapps_agents/workflow/parallel_executor.py +463 -463
- tapps_agents/workflow/planning_artifact.py +179 -179
- tapps_agents/workflow/preset_loader.py +285 -285
- tapps_agents/workflow/preset_recommender.py +270 -270
- tapps_agents/workflow/progress_logger.py +145 -145
- tapps_agents/workflow/progress_manager.py +303 -303
- tapps_agents/workflow/progress_monitor.py +186 -186
- tapps_agents/workflow/progress_updates.py +423 -423
- tapps_agents/workflow/quality_artifact.py +158 -158
- tapps_agents/workflow/quality_loopback.py +101 -101
- tapps_agents/workflow/recommender.py +387 -387
- tapps_agents/workflow/remediation_loop.py +166 -166
- tapps_agents/workflow/result_aggregator.py +300 -300
- tapps_agents/workflow/review_artifact.py +185 -185
- tapps_agents/workflow/schema_validator.py +522 -522
- tapps_agents/workflow/session_handoff.py +178 -178
- tapps_agents/workflow/skill_invoker.py +648 -648
- tapps_agents/workflow/state_manager.py +756 -756
- tapps_agents/workflow/state_persistence_config.py +331 -331
- tapps_agents/workflow/status_monitor.py +449 -449
- tapps_agents/workflow/step_checkpoint.py +314 -314
- tapps_agents/workflow/step_details.py +201 -201
- tapps_agents/workflow/story_models.py +147 -147
- tapps_agents/workflow/streaming.py +416 -416
- tapps_agents/workflow/suggestion_engine.py +552 -552
- tapps_agents/workflow/testing_artifact.py +186 -186
- tapps_agents/workflow/timeline.py +158 -158
- tapps_agents/workflow/token_integration.py +209 -209
- tapps_agents/workflow/validation.py +217 -217
- tapps_agents/workflow/visual_feedback.py +391 -391
- tapps_agents/workflow/workflow_chain.py +95 -95
- tapps_agents/workflow/workflow_summary.py +219 -219
- tapps_agents/workflow/worktree_manager.py +724 -724
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/METADATA +672 -672
- tapps_agents-3.6.0.dist-info/RECORD +758 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/licenses/LICENSE +22 -22
- tapps_agents/health/checks/outcomes.backup_20260204_064058.py +0 -324
- tapps_agents/health/checks/outcomes.backup_20260204_064256.py +0 -324
- tapps_agents/health/checks/outcomes.backup_20260204_064600.py +0 -324
- tapps_agents-3.5.40.dist-info/RECORD +0 -760
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/WHEEL +0 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/top_level.txt +0 -0
|
@@ -1,858 +1,858 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Context7 Commands - CLI commands for Context7 KB management.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import re
|
|
6
|
-
from datetime import UTC, datetime
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from typing import Any
|
|
9
|
-
|
|
10
|
-
from ..core.config import ProjectConfig
|
|
11
|
-
from .analytics import Analytics
|
|
12
|
-
from .cache_structure import CacheStructure
|
|
13
|
-
from .cache_warming import CacheWarmer
|
|
14
|
-
from .cleanup import KBCleanup
|
|
15
|
-
from .cross_references import CrossReferenceManager
|
|
16
|
-
from .fuzzy_matcher import FuzzyMatcher
|
|
17
|
-
from .kb_cache import KBCache
|
|
18
|
-
from .lookup import KBLookup
|
|
19
|
-
from .metadata import MetadataManager
|
|
20
|
-
from .refresh_queue import RefreshQueue
|
|
21
|
-
from .staleness_policies import StalenessPolicyManager
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _parse_size_string(size_str: str) -> int:
|
|
25
|
-
"""
|
|
26
|
-
Parse size string like "100MB" or "1GB" into bytes.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
size_str: Size string (e.g., "100MB", "1GB", "500KB")
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
Size in bytes
|
|
33
|
-
"""
|
|
34
|
-
if not size_str:
|
|
35
|
-
return 100 * 1024 * 1024 # Default 100MB
|
|
36
|
-
|
|
37
|
-
# Match pattern like "100MB", "1.5GB", etc.
|
|
38
|
-
match = re.match(r"^(\d+(?:\.\d+)?)\s*([KMGT]?B?)$", size_str.upper().strip())
|
|
39
|
-
if not match:
|
|
40
|
-
# If parsing fails, default to 100MB
|
|
41
|
-
return 100 * 1024 * 1024
|
|
42
|
-
|
|
43
|
-
value = float(match.group(1))
|
|
44
|
-
unit = match.group(2) or "B"
|
|
45
|
-
|
|
46
|
-
multipliers = {
|
|
47
|
-
"B": 1,
|
|
48
|
-
"KB": 1024,
|
|
49
|
-
"MB": 1024 * 1024,
|
|
50
|
-
"GB": 1024 * 1024 * 1024,
|
|
51
|
-
"TB": 1024 * 1024 * 1024 * 1024,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return int(value * multipliers.get(unit, 1))
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
class Context7Commands:
|
|
58
|
-
"""
|
|
59
|
-
Context7 KB commands for CLI/agent interface.
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
def __init__(
|
|
63
|
-
self,
|
|
64
|
-
project_root: Path | None = None,
|
|
65
|
-
config: ProjectConfig | None = None,
|
|
66
|
-
):
|
|
67
|
-
"""
|
|
68
|
-
Initialize Context7 commands.
|
|
69
|
-
|
|
70
|
-
Args:
|
|
71
|
-
project_root: Optional project root path (defaults to cwd)
|
|
72
|
-
config: Optional ProjectConfig instance (loads if not provided)
|
|
73
|
-
"""
|
|
74
|
-
if project_root is None:
|
|
75
|
-
project_root = Path.cwd()
|
|
76
|
-
|
|
77
|
-
if config is None:
|
|
78
|
-
from ..core.config import load_config
|
|
79
|
-
|
|
80
|
-
config = load_config()
|
|
81
|
-
|
|
82
|
-
context7_config = config.context7
|
|
83
|
-
if not context7_config or not context7_config.enabled:
|
|
84
|
-
self.enabled = False
|
|
85
|
-
return
|
|
86
|
-
|
|
87
|
-
# Wrap initialization in try-except to prevent failures from breaking commands
|
|
88
|
-
try:
|
|
89
|
-
self.enabled = True
|
|
90
|
-
self.config = context7_config
|
|
91
|
-
self.project_root = project_root
|
|
92
|
-
|
|
93
|
-
# Initialize cache structure
|
|
94
|
-
cache_root = project_root / context7_config.knowledge_base.location
|
|
95
|
-
self.cache_structure = CacheStructure(cache_root)
|
|
96
|
-
self.cache_structure.initialize()
|
|
97
|
-
|
|
98
|
-
# Initialize components
|
|
99
|
-
self.metadata_manager = MetadataManager(self.cache_structure)
|
|
100
|
-
self.kb_cache = KBCache(self.cache_structure.cache_root, self.metadata_manager)
|
|
101
|
-
self.fuzzy_matcher = FuzzyMatcher(threshold=0.7)
|
|
102
|
-
self.analytics = Analytics(self.cache_structure, self.metadata_manager)
|
|
103
|
-
self.staleness_policy_manager = StalenessPolicyManager()
|
|
104
|
-
self.refresh_queue = RefreshQueue(
|
|
105
|
-
self.cache_structure.refresh_queue_file, self.staleness_policy_manager
|
|
106
|
-
)
|
|
107
|
-
# Parse max_cache_size string (e.g., "100MB") to bytes
|
|
108
|
-
max_cache_size_bytes = _parse_size_string(
|
|
109
|
-
context7_config.knowledge_base.max_cache_size
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
self.cleanup = KBCleanup(
|
|
113
|
-
self.cache_structure,
|
|
114
|
-
self.metadata_manager,
|
|
115
|
-
self.staleness_policy_manager,
|
|
116
|
-
self.analytics,
|
|
117
|
-
max_cache_size_bytes=max_cache_size_bytes,
|
|
118
|
-
)
|
|
119
|
-
self.cross_refs = CrossReferenceManager(self.cache_structure)
|
|
120
|
-
|
|
121
|
-
# KB lookup (will need MCP Gateway for API calls)
|
|
122
|
-
self.kb_lookup = KBLookup(
|
|
123
|
-
kb_cache=self.kb_cache,
|
|
124
|
-
mcp_gateway=None, # Set via set_mcp_gateway
|
|
125
|
-
fuzzy_threshold=0.7,
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
# Cache warmer
|
|
129
|
-
self.cache_warmer = CacheWarmer(
|
|
130
|
-
kb_cache=self.kb_cache,
|
|
131
|
-
kb_lookup=self.kb_lookup,
|
|
132
|
-
cache_structure=self.cache_structure,
|
|
133
|
-
metadata_manager=self.metadata_manager,
|
|
134
|
-
project_root=self.project_root,
|
|
135
|
-
)
|
|
136
|
-
except Exception as e:
|
|
137
|
-
# If Context7 initialization fails, disable it gracefully
|
|
138
|
-
import logging
|
|
139
|
-
logger = logging.getLogger(__name__)
|
|
140
|
-
logger.warning(
|
|
141
|
-
f"Context7Commands initialization failed, disabling Context7 features: {e}. "
|
|
142
|
-
f"Commands will continue to work without Context7."
|
|
143
|
-
)
|
|
144
|
-
self.enabled = False
|
|
145
|
-
# Set minimal attributes to prevent AttributeError
|
|
146
|
-
self.config = context7_config
|
|
147
|
-
self.project_root = project_root
|
|
148
|
-
self.cache_structure = None
|
|
149
|
-
self.metadata_manager = None
|
|
150
|
-
self.kb_cache = None
|
|
151
|
-
self.fuzzy_matcher = None
|
|
152
|
-
self.analytics = None
|
|
153
|
-
self.staleness_policy_manager = None
|
|
154
|
-
self.refresh_queue = None
|
|
155
|
-
self.cleanup = None
|
|
156
|
-
self.cross_refs = None
|
|
157
|
-
self.kb_lookup = None
|
|
158
|
-
self.cache_warmer = None
|
|
159
|
-
|
|
160
|
-
def set_mcp_gateway(self, mcp_gateway):
|
|
161
|
-
"""Set MCP Gateway for API calls."""
|
|
162
|
-
if not self.enabled or self.kb_lookup is None:
|
|
163
|
-
return
|
|
164
|
-
self.kb_lookup.mcp_gateway = mcp_gateway
|
|
165
|
-
if self.cache_warmer is not None:
|
|
166
|
-
self.cache_warmer.kb_lookup = self.kb_lookup
|
|
167
|
-
|
|
168
|
-
async def cmd_docs(self, library: str, topic: str | None = None) -> dict[str, Any]:
|
|
169
|
-
"""
|
|
170
|
-
Get KB-first documentation for a library/topic.
|
|
171
|
-
|
|
172
|
-
Command: *context7-docs {library} [topic]
|
|
173
|
-
|
|
174
|
-
Args:
|
|
175
|
-
library: Library name
|
|
176
|
-
topic: Optional topic name
|
|
177
|
-
|
|
178
|
-
Returns:
|
|
179
|
-
Dictionary with documentation result
|
|
180
|
-
"""
|
|
181
|
-
if not self.enabled or self.kb_lookup is None:
|
|
182
|
-
return {"error": "Context7 is not enabled"}
|
|
183
|
-
|
|
184
|
-
try:
|
|
185
|
-
result = await self.kb_lookup.lookup(
|
|
186
|
-
library=library, topic=topic, use_fuzzy_match=True
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
if result.success:
|
|
190
|
-
return {
|
|
191
|
-
"success": True,
|
|
192
|
-
"library": result.library,
|
|
193
|
-
"topic": result.topic,
|
|
194
|
-
"content": result.content,
|
|
195
|
-
"source": result.source,
|
|
196
|
-
"fuzzy_score": result.fuzzy_score,
|
|
197
|
-
"matched_topic": result.matched_topic,
|
|
198
|
-
"response_time_ms": result.response_time_ms,
|
|
199
|
-
}
|
|
200
|
-
else:
|
|
201
|
-
return {
|
|
202
|
-
"success": False,
|
|
203
|
-
"error": result.error or "Documentation not found",
|
|
204
|
-
"library": library,
|
|
205
|
-
"topic": topic,
|
|
206
|
-
}
|
|
207
|
-
except Exception as e:
|
|
208
|
-
return {"success": False, "error": str(e)}
|
|
209
|
-
|
|
210
|
-
async def cmd_resolve(self, library: str) -> dict[str, Any]:
|
|
211
|
-
"""
|
|
212
|
-
Resolve library name to Context7 ID.
|
|
213
|
-
|
|
214
|
-
Command: *context7-resolve {library}
|
|
215
|
-
|
|
216
|
-
Args:
|
|
217
|
-
library: Library name to resolve
|
|
218
|
-
|
|
219
|
-
Returns:
|
|
220
|
-
Dictionary with resolution result
|
|
221
|
-
"""
|
|
222
|
-
if not self.enabled or self.kb_lookup is None:
|
|
223
|
-
return {"error": "Context7 is not enabled"}
|
|
224
|
-
|
|
225
|
-
# Use backup client with automatic fallback (MCP Gateway -> HTTP)
|
|
226
|
-
from .backup_client import call_context7_resolve_with_fallback
|
|
227
|
-
|
|
228
|
-
try:
|
|
229
|
-
result = await call_context7_resolve_with_fallback(
|
|
230
|
-
library, self.kb_lookup.mcp_gateway if self.kb_lookup else None
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
if result.get("success"):
|
|
234
|
-
matches = result.get("result", {}).get("matches", [])
|
|
235
|
-
return {"success": True, "library": library, "matches": matches}
|
|
236
|
-
else:
|
|
237
|
-
return {
|
|
238
|
-
"success": False,
|
|
239
|
-
"error": result.get("error", "Failed to resolve library"),
|
|
240
|
-
"library": library,
|
|
241
|
-
}
|
|
242
|
-
except Exception as e:
|
|
243
|
-
return {"success": False, "error": str(e)}
|
|
244
|
-
|
|
245
|
-
async def cmd_status(self) -> dict[str, Any]:
|
|
246
|
-
"""
|
|
247
|
-
Get KB status and statistics.
|
|
248
|
-
|
|
249
|
-
Command: *context7-kb-status
|
|
250
|
-
|
|
251
|
-
Returns:
|
|
252
|
-
Dictionary with status information
|
|
253
|
-
"""
|
|
254
|
-
if not self.enabled or self.analytics is None or self.cleanup is None:
|
|
255
|
-
return {"error": "Context7 is not enabled"}
|
|
256
|
-
|
|
257
|
-
try:
|
|
258
|
-
metrics = self.analytics.get_cache_metrics()
|
|
259
|
-
status_report = self.analytics.get_status_report()
|
|
260
|
-
|
|
261
|
-
# Get cache size
|
|
262
|
-
cache_size = self.cleanup.get_cache_size()
|
|
263
|
-
|
|
264
|
-
return {
|
|
265
|
-
"success": True,
|
|
266
|
-
"status": status_report.get("status", "unknown"),
|
|
267
|
-
"health_issues": status_report.get("health_issues", []),
|
|
268
|
-
"cache_size_bytes": cache_size,
|
|
269
|
-
"cache_size_mb": cache_size / (1024 * 1024),
|
|
270
|
-
"metrics": {
|
|
271
|
-
"total_entries": metrics.total_entries,
|
|
272
|
-
"total_libraries": metrics.total_libraries,
|
|
273
|
-
"cache_hits": metrics.cache_hits,
|
|
274
|
-
"cache_misses": metrics.cache_misses,
|
|
275
|
-
"api_calls": metrics.api_calls,
|
|
276
|
-
"hit_rate": metrics.hit_rate,
|
|
277
|
-
"avg_response_time_ms": metrics.avg_response_time_ms,
|
|
278
|
-
},
|
|
279
|
-
"top_libraries": status_report.get("top_libraries", []),
|
|
280
|
-
"timestamp": status_report.get("timestamp"),
|
|
281
|
-
}
|
|
282
|
-
except Exception as e:
|
|
283
|
-
return {"success": False, "error": str(e)}
|
|
284
|
-
|
|
285
|
-
async def cmd_health(self) -> dict[str, Any]:
|
|
286
|
-
"""
|
|
287
|
-
Get detailed health check report.
|
|
288
|
-
|
|
289
|
-
Command: *context7-kb-health
|
|
290
|
-
|
|
291
|
-
Returns:
|
|
292
|
-
Dictionary with health check information
|
|
293
|
-
"""
|
|
294
|
-
if not self.enabled or self.analytics is None:
|
|
295
|
-
return {"error": "Context7 is not enabled"}
|
|
296
|
-
|
|
297
|
-
try:
|
|
298
|
-
health_check = self.analytics.get_health_check()
|
|
299
|
-
return {"success": True, **health_check}
|
|
300
|
-
except Exception as e:
|
|
301
|
-
return {"success": False, "error": str(e)}
|
|
302
|
-
|
|
303
|
-
async def cmd_search(self, query: str, limit: int = 10) -> dict[str, Any]:
|
|
304
|
-
"""
|
|
305
|
-
Search cached documentation.
|
|
306
|
-
|
|
307
|
-
Command: *context7-kb-search {query} [limit]
|
|
308
|
-
|
|
309
|
-
Args:
|
|
310
|
-
query: Search query
|
|
311
|
-
limit: Maximum number of results
|
|
312
|
-
|
|
313
|
-
Returns:
|
|
314
|
-
Dictionary with search results
|
|
315
|
-
"""
|
|
316
|
-
if not self.enabled or self.metadata_manager is None or self.fuzzy_matcher is None:
|
|
317
|
-
return {"error": "Context7 is not enabled"}
|
|
318
|
-
|
|
319
|
-
try:
|
|
320
|
-
cache_index = self.metadata_manager.load_cache_index()
|
|
321
|
-
results = []
|
|
322
|
-
|
|
323
|
-
# Simple keyword search in library/topic names
|
|
324
|
-
query_lower = query.lower()
|
|
325
|
-
|
|
326
|
-
for library_name, library_data in cache_index.libraries.items():
|
|
327
|
-
topics = library_data.get("topics", {})
|
|
328
|
-
|
|
329
|
-
# Check library name
|
|
330
|
-
if query_lower in library_name.lower():
|
|
331
|
-
for topic_name in topics.keys():
|
|
332
|
-
results.append(
|
|
333
|
-
{
|
|
334
|
-
"library": library_name,
|
|
335
|
-
"topic": topic_name,
|
|
336
|
-
"match_type": "library_name",
|
|
337
|
-
}
|
|
338
|
-
)
|
|
339
|
-
|
|
340
|
-
# Check topic names
|
|
341
|
-
for topic_name in topics.keys():
|
|
342
|
-
if query_lower in topic_name.lower():
|
|
343
|
-
results.append(
|
|
344
|
-
{
|
|
345
|
-
"library": library_name,
|
|
346
|
-
"topic": topic_name,
|
|
347
|
-
"match_type": "topic_name",
|
|
348
|
-
}
|
|
349
|
-
)
|
|
350
|
-
|
|
351
|
-
# Use fuzzy matching for better results
|
|
352
|
-
if len(results) < limit:
|
|
353
|
-
fuzzy_results = self.fuzzy_matcher.find_best_match(
|
|
354
|
-
query, None, cache_index
|
|
355
|
-
)
|
|
356
|
-
if fuzzy_results:
|
|
357
|
-
for match in fuzzy_results[: limit - len(results)]:
|
|
358
|
-
if match not in results:
|
|
359
|
-
results.append(
|
|
360
|
-
{
|
|
361
|
-
"library": match.library,
|
|
362
|
-
"topic": match.topic,
|
|
363
|
-
"match_type": "fuzzy",
|
|
364
|
-
"score": match.score,
|
|
365
|
-
}
|
|
366
|
-
)
|
|
367
|
-
|
|
368
|
-
return {
|
|
369
|
-
"success": True,
|
|
370
|
-
"query": query,
|
|
371
|
-
"results": results[:limit],
|
|
372
|
-
"count": len(results[:limit]),
|
|
373
|
-
}
|
|
374
|
-
except Exception as e:
|
|
375
|
-
return {"success": False, "error": str(e)}
|
|
376
|
-
|
|
377
|
-
async def cmd_refresh_process(self, max_items: int = 10) -> dict[str, Any]:
|
|
378
|
-
"""
|
|
379
|
-
Process queued refresh tasks (best-effort).
|
|
380
|
-
|
|
381
|
-
This is used by startup routines to refresh stale entries incrementally.
|
|
382
|
-
If the MCP gateway is not available, we soft-fail with a clear error.
|
|
383
|
-
"""
|
|
384
|
-
if not self.enabled or self.kb_lookup is None or self.refresh_queue is None or self.kb_cache is None:
|
|
385
|
-
return {
|
|
386
|
-
"success": False,
|
|
387
|
-
"error": "Context7 is not enabled",
|
|
388
|
-
"items_processed": 0,
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if not self.kb_lookup.mcp_gateway:
|
|
392
|
-
return {
|
|
393
|
-
"success": False,
|
|
394
|
-
"error": "MCP Gateway not available",
|
|
395
|
-
"items_processed": 0,
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
processed = 0
|
|
399
|
-
errors: list[str] = []
|
|
400
|
-
|
|
401
|
-
while processed < max_items:
|
|
402
|
-
task = self.refresh_queue.get_next_task()
|
|
403
|
-
if task is None:
|
|
404
|
-
break
|
|
405
|
-
|
|
406
|
-
topic = task.topic or "overview"
|
|
407
|
-
try:
|
|
408
|
-
# Resolve library -> Context7 ID (with backup fallback)
|
|
409
|
-
from .backup_client import (
|
|
410
|
-
call_context7_get_docs_with_fallback,
|
|
411
|
-
call_context7_resolve_with_fallback,
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
resolve = await call_context7_resolve_with_fallback(
|
|
415
|
-
task.library, self.kb_lookup.mcp_gateway
|
|
416
|
-
)
|
|
417
|
-
matches = (
|
|
418
|
-
resolve.get("result", {}).get("matches", [])
|
|
419
|
-
if resolve.get("success")
|
|
420
|
-
else []
|
|
421
|
-
)
|
|
422
|
-
context7_id = None
|
|
423
|
-
if matches:
|
|
424
|
-
first = matches[0]
|
|
425
|
-
context7_id = (
|
|
426
|
-
first.get("id") if isinstance(first, dict) else str(first)
|
|
427
|
-
)
|
|
428
|
-
|
|
429
|
-
if not context7_id:
|
|
430
|
-
raise RuntimeError("Could not resolve Context7 library ID")
|
|
431
|
-
|
|
432
|
-
# Fetch docs (with backup fallback)
|
|
433
|
-
docs = await call_context7_get_docs_with_fallback(
|
|
434
|
-
context7_id, topic, mode="code", page=1, mcp_gateway=self.kb_lookup.mcp_gateway
|
|
435
|
-
)
|
|
436
|
-
if not docs.get("success"):
|
|
437
|
-
raise RuntimeError(docs.get("error") or "Failed to fetch docs")
|
|
438
|
-
|
|
439
|
-
result_data = docs.get("result", {})
|
|
440
|
-
content = (
|
|
441
|
-
result_data.get("content")
|
|
442
|
-
if isinstance(result_data, dict)
|
|
443
|
-
else (result_data if isinstance(result_data, str) else None)
|
|
444
|
-
)
|
|
445
|
-
if not content:
|
|
446
|
-
raise RuntimeError("No content returned from Context7 docs tool")
|
|
447
|
-
|
|
448
|
-
# Store (refresh) content
|
|
449
|
-
self.kb_cache.store(
|
|
450
|
-
library=task.library,
|
|
451
|
-
topic=topic,
|
|
452
|
-
content=content,
|
|
453
|
-
context7_id=context7_id,
|
|
454
|
-
)
|
|
455
|
-
|
|
456
|
-
self.refresh_queue.mark_task_completed(
|
|
457
|
-
task.library, task.topic, error=None
|
|
458
|
-
)
|
|
459
|
-
processed += 1
|
|
460
|
-
|
|
461
|
-
except Exception as e:
|
|
462
|
-
err = f"{task.library}/{topic}: {e}"
|
|
463
|
-
errors.append(err)
|
|
464
|
-
self.refresh_queue.mark_task_completed(
|
|
465
|
-
task.library, task.topic, error=str(e)
|
|
466
|
-
)
|
|
467
|
-
# Avoid infinite loop on a permanently failing head task.
|
|
468
|
-
break
|
|
469
|
-
|
|
470
|
-
return {
|
|
471
|
-
"success": processed > 0 and not errors,
|
|
472
|
-
"items_processed": processed,
|
|
473
|
-
"errors": errors,
|
|
474
|
-
"queue_remaining": self.refresh_queue.size(),
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
async def cmd_refresh(
|
|
478
|
-
self, library: str | None = None, topic: str | None = None
|
|
479
|
-
) -> dict[str, Any]:
|
|
480
|
-
"""
|
|
481
|
-
Refresh stale KB entries.
|
|
482
|
-
|
|
483
|
-
Command: *context7-kb-refresh [library] [topic]
|
|
484
|
-
|
|
485
|
-
Args:
|
|
486
|
-
library: Optional library name (refreshes all if not provided)
|
|
487
|
-
topic: Optional topic name
|
|
488
|
-
|
|
489
|
-
Returns:
|
|
490
|
-
Dictionary with refresh result
|
|
491
|
-
"""
|
|
492
|
-
if not self.enabled or self.refresh_queue is None or self.metadata_manager is None:
|
|
493
|
-
return {"error": "Context7 is not enabled"}
|
|
494
|
-
|
|
495
|
-
try:
|
|
496
|
-
if library:
|
|
497
|
-
# Refresh specific library/topic
|
|
498
|
-
if topic:
|
|
499
|
-
priority = 8 # High priority for manual refresh
|
|
500
|
-
self.refresh_queue.add_task(library, topic, priority=priority)
|
|
501
|
-
return {
|
|
502
|
-
"success": True,
|
|
503
|
-
"message": f"Queued refresh for {library}/{topic}",
|
|
504
|
-
"library": library,
|
|
505
|
-
"topic": topic,
|
|
506
|
-
}
|
|
507
|
-
else:
|
|
508
|
-
# Refresh all topics for library
|
|
509
|
-
cache_index = self.metadata_manager.load_cache_index()
|
|
510
|
-
library_data = cache_index.libraries.get(library, {})
|
|
511
|
-
topics = library_data.get("topics", {})
|
|
512
|
-
|
|
513
|
-
queued = 0
|
|
514
|
-
for topic_name in topics.keys():
|
|
515
|
-
self.refresh_queue.add_task(library, topic_name, priority=7)
|
|
516
|
-
queued += 1
|
|
517
|
-
|
|
518
|
-
return {
|
|
519
|
-
"success": True,
|
|
520
|
-
"message": f"Queued refresh for {queued} topics in {library}",
|
|
521
|
-
"library": library,
|
|
522
|
-
"topics_queued": queued,
|
|
523
|
-
}
|
|
524
|
-
else:
|
|
525
|
-
# Refresh all stale entries
|
|
526
|
-
cache_index = self.metadata_manager.load_cache_index()
|
|
527
|
-
entries = []
|
|
528
|
-
|
|
529
|
-
for lib_name, lib_data in cache_index.libraries.items():
|
|
530
|
-
topics = lib_data.get("topics", {})
|
|
531
|
-
for topic_name, topic_data in topics.items():
|
|
532
|
-
last_updated = topic_data.get("last_updated") or topic_data.get(
|
|
533
|
-
"cached_at"
|
|
534
|
-
)
|
|
535
|
-
if last_updated:
|
|
536
|
-
entries.append(
|
|
537
|
-
{
|
|
538
|
-
"library": lib_name,
|
|
539
|
-
"topic": topic_name,
|
|
540
|
-
"last_updated": last_updated,
|
|
541
|
-
}
|
|
542
|
-
)
|
|
543
|
-
|
|
544
|
-
queued = self.refresh_queue.queue_stale_entries(entries)
|
|
545
|
-
|
|
546
|
-
return {
|
|
547
|
-
"success": True,
|
|
548
|
-
"message": f"Queued refresh for {queued} stale entries",
|
|
549
|
-
"entries_queued": queued,
|
|
550
|
-
}
|
|
551
|
-
except Exception as e:
|
|
552
|
-
return {"success": False, "error": str(e)}
|
|
553
|
-
|
|
554
|
-
async def cmd_cleanup(
|
|
555
|
-
self,
|
|
556
|
-
strategy: str = "all",
|
|
557
|
-
target_size_mb: float | None = None,
|
|
558
|
-
max_age_days: int | None = None,
|
|
559
|
-
) -> dict[str, Any]:
|
|
560
|
-
"""
|
|
561
|
-
Clean up old/unused KB entries.
|
|
562
|
-
|
|
563
|
-
Command: *context7-kb-cleanup [strategy] [options]
|
|
564
|
-
|
|
565
|
-
Args:
|
|
566
|
-
strategy: Cleanup strategy ("size", "age", "unused", "all")
|
|
567
|
-
target_size_mb: Target size in MB (for size strategy)
|
|
568
|
-
max_age_days: Maximum age in days (for age strategy)
|
|
569
|
-
|
|
570
|
-
Returns:
|
|
571
|
-
Dictionary with cleanup result
|
|
572
|
-
"""
|
|
573
|
-
if not self.enabled or self.cleanup is None:
|
|
574
|
-
return {"error": "Context7 is not enabled"}
|
|
575
|
-
|
|
576
|
-
try:
|
|
577
|
-
if strategy == "size":
|
|
578
|
-
target_bytes = (
|
|
579
|
-
int(target_size_mb * 1024 * 1024) if target_size_mb else None
|
|
580
|
-
)
|
|
581
|
-
result = self.cleanup.cleanup_by_size(target_size_bytes=target_bytes)
|
|
582
|
-
elif strategy == "age":
|
|
583
|
-
result = self.cleanup.cleanup_by_age(max_age_days=max_age_days)
|
|
584
|
-
elif strategy == "unused":
|
|
585
|
-
result = self.cleanup.cleanup_unused()
|
|
586
|
-
else: # "all"
|
|
587
|
-
result = self.cleanup.cleanup_all(
|
|
588
|
-
target_size_bytes=(
|
|
589
|
-
int(target_size_mb * 1024 * 1024) if target_size_mb else None
|
|
590
|
-
),
|
|
591
|
-
max_age_days=max_age_days,
|
|
592
|
-
)
|
|
593
|
-
|
|
594
|
-
return {"success": True, "strategy": strategy, "result": result.to_dict()}
|
|
595
|
-
except Exception as e:
|
|
596
|
-
return {"success": False, "error": str(e)}
|
|
597
|
-
|
|
598
|
-
async def cmd_rebuild_index(self) -> dict[str, Any]:
|
|
599
|
-
"""
|
|
600
|
-
Rebuild KB cache index.
|
|
601
|
-
|
|
602
|
-
Command: *context7-kb-rebuild
|
|
603
|
-
|
|
604
|
-
Returns:
|
|
605
|
-
Dictionary with rebuild result
|
|
606
|
-
"""
|
|
607
|
-
if not self.enabled or self.metadata_manager is None or self.cache_structure is None:
|
|
608
|
-
return {"error": "Context7 is not enabled"}
|
|
609
|
-
|
|
610
|
-
try:
|
|
611
|
-
# Rebuild index from filesystem
|
|
612
|
-
cache_index = self.metadata_manager.load_cache_index()
|
|
613
|
-
cache_index.libraries = {}
|
|
614
|
-
cache_index.total_entries = 0
|
|
615
|
-
|
|
616
|
-
# Scan filesystem
|
|
617
|
-
for lib_dir in self.cache_structure.libraries_dir.iterdir():
|
|
618
|
-
if lib_dir.is_dir():
|
|
619
|
-
library_name = lib_dir.name
|
|
620
|
-
topics = {}
|
|
621
|
-
|
|
622
|
-
for doc_file in lib_dir.glob("*.md"):
|
|
623
|
-
if doc_file.name != "index.md": # Skip index files
|
|
624
|
-
topic = doc_file.stem
|
|
625
|
-
topics[topic] = {
|
|
626
|
-
"cached_at": datetime.now(UTC).isoformat() + "Z"
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
if topics:
|
|
630
|
-
cache_index.libraries[library_name] = {"topics": topics}
|
|
631
|
-
cache_index.total_entries += len(topics)
|
|
632
|
-
|
|
633
|
-
self.metadata_manager.save_cache_index(cache_index)
|
|
634
|
-
|
|
635
|
-
return {
|
|
636
|
-
"success": True,
|
|
637
|
-
"message": "Index rebuilt successfully",
|
|
638
|
-
"libraries": len(cache_index.libraries),
|
|
639
|
-
"total_entries": cache_index.total_entries,
|
|
640
|
-
}
|
|
641
|
-
except Exception as e:
|
|
642
|
-
return {"success": False, "error": str(e)}
|
|
643
|
-
|
|
644
|
-
async def cmd_warm(
|
|
645
|
-
self,
|
|
646
|
-
auto_detect: bool = True,
|
|
647
|
-
libraries: list[str] | None = None,
|
|
648
|
-
priority: int = 5,
|
|
649
|
-
) -> dict[str, Any]:
|
|
650
|
-
"""
|
|
651
|
-
Warm cache with project libraries and common topics.
|
|
652
|
-
|
|
653
|
-
Command: *context7-kb-warm [--auto-detect] [libraries...]
|
|
654
|
-
|
|
655
|
-
Args:
|
|
656
|
-
auto_detect: Whether to auto-detect libraries from project (default: True)
|
|
657
|
-
libraries: Optional list of library names
|
|
658
|
-
priority: Priority for warming (1-10)
|
|
659
|
-
|
|
660
|
-
Returns:
|
|
661
|
-
Dictionary with warming result
|
|
662
|
-
"""
|
|
663
|
-
if not self.enabled or self.kb_lookup is None or self.cache_warmer is None:
|
|
664
|
-
return {"error": "Context7 is not enabled"}
|
|
665
|
-
|
|
666
|
-
if not self.kb_lookup.mcp_gateway:
|
|
667
|
-
return {"error": "MCP Gateway not available"}
|
|
668
|
-
|
|
669
|
-
try:
|
|
670
|
-
result = await self.cache_warmer.warm_cache(
|
|
671
|
-
libraries=libraries,
|
|
672
|
-
topics=None, # Auto-detect topics
|
|
673
|
-
priority=priority,
|
|
674
|
-
auto_detect=auto_detect,
|
|
675
|
-
)
|
|
676
|
-
return result
|
|
677
|
-
except Exception as e:
|
|
678
|
-
return {"success": False, "error": str(e)}
|
|
679
|
-
|
|
680
|
-
async def cmd_populate(
|
|
681
|
-
self,
|
|
682
|
-
libraries: list[str] | None = None,
|
|
683
|
-
topics: list[str] | None = None,
|
|
684
|
-
force: bool = False,
|
|
685
|
-
) -> dict[str, Any]:
|
|
686
|
-
"""
|
|
687
|
-
Pre-populate cache with library documentation.
|
|
688
|
-
|
|
689
|
-
Command: *context7-kb-populate [libraries...] [--topics topics...] [--force]
|
|
690
|
-
|
|
691
|
-
Args:
|
|
692
|
-
libraries: List of library names to populate (defaults to common libraries)
|
|
693
|
-
topics: Optional list of topics to populate (defaults to ["overview"])
|
|
694
|
-
force: Whether to force refresh even if already cached
|
|
695
|
-
|
|
696
|
-
Returns:
|
|
697
|
-
Dictionary with populate result
|
|
698
|
-
"""
|
|
699
|
-
if not self.enabled or self.kb_lookup is None or self.kb_cache is None:
|
|
700
|
-
return {"error": "Context7 is not enabled"}
|
|
701
|
-
|
|
702
|
-
if not self.kb_lookup.mcp_gateway:
|
|
703
|
-
return {"error": "MCP Gateway not available"}
|
|
704
|
-
|
|
705
|
-
# Default libraries if not provided
|
|
706
|
-
if libraries is None:
|
|
707
|
-
libraries = [
|
|
708
|
-
"fastapi",
|
|
709
|
-
"pytest",
|
|
710
|
-
"react",
|
|
711
|
-
"typescript",
|
|
712
|
-
"python",
|
|
713
|
-
"pydantic",
|
|
714
|
-
"sqlalchemy",
|
|
715
|
-
"playwright",
|
|
716
|
-
]
|
|
717
|
-
|
|
718
|
-
# Default topics if not provided
|
|
719
|
-
if topics is None:
|
|
720
|
-
topics = ["overview"]
|
|
721
|
-
|
|
722
|
-
populated = 0
|
|
723
|
-
errors: list[str] = []
|
|
724
|
-
|
|
725
|
-
for library in libraries:
|
|
726
|
-
for topic in topics:
|
|
727
|
-
# Check if already cached (unless force)
|
|
728
|
-
if not force and self.kb_cache.exists(library, topic):
|
|
729
|
-
continue
|
|
730
|
-
|
|
731
|
-
try:
|
|
732
|
-
# Resolve library -> Context7 ID (with backup fallback)
|
|
733
|
-
from .backup_client import (
|
|
734
|
-
call_context7_get_docs_with_fallback,
|
|
735
|
-
call_context7_resolve_with_fallback,
|
|
736
|
-
)
|
|
737
|
-
|
|
738
|
-
resolve = await call_context7_resolve_with_fallback(
|
|
739
|
-
library, self.kb_lookup.mcp_gateway
|
|
740
|
-
)
|
|
741
|
-
matches = (
|
|
742
|
-
resolve.get("result", {}).get("matches", [])
|
|
743
|
-
if resolve.get("success")
|
|
744
|
-
else []
|
|
745
|
-
)
|
|
746
|
-
context7_id = None
|
|
747
|
-
if matches:
|
|
748
|
-
first = matches[0]
|
|
749
|
-
context7_id = (
|
|
750
|
-
first.get("id") if isinstance(first, dict) else str(first)
|
|
751
|
-
)
|
|
752
|
-
|
|
753
|
-
if not context7_id:
|
|
754
|
-
errors.append(f"{library}/{topic}: Could not resolve library ID")
|
|
755
|
-
continue
|
|
756
|
-
|
|
757
|
-
# Fetch docs (with backup fallback)
|
|
758
|
-
docs = await call_context7_get_docs_with_fallback(
|
|
759
|
-
context7_id, topic, mode="code", page=1, mcp_gateway=self.kb_lookup.mcp_gateway
|
|
760
|
-
)
|
|
761
|
-
if not docs.get("success"):
|
|
762
|
-
errors.append(
|
|
763
|
-
f"{library}/{topic}: {docs.get('error', 'Failed to fetch docs')}"
|
|
764
|
-
)
|
|
765
|
-
continue
|
|
766
|
-
|
|
767
|
-
result_data = docs.get("result", {})
|
|
768
|
-
content = (
|
|
769
|
-
result_data.get("content")
|
|
770
|
-
if isinstance(result_data, dict)
|
|
771
|
-
else (result_data if isinstance(result_data, str) else None)
|
|
772
|
-
)
|
|
773
|
-
if not content:
|
|
774
|
-
errors.append(f"{library}/{topic}: No content returned")
|
|
775
|
-
continue
|
|
776
|
-
|
|
777
|
-
# Store in cache
|
|
778
|
-
self.kb_cache.store(
|
|
779
|
-
library=library,
|
|
780
|
-
topic=topic,
|
|
781
|
-
content=content,
|
|
782
|
-
context7_id=context7_id,
|
|
783
|
-
)
|
|
784
|
-
populated += 1
|
|
785
|
-
|
|
786
|
-
except Exception as e:
|
|
787
|
-
errors.append(f"{library}/{topic}: {str(e)}")
|
|
788
|
-
|
|
789
|
-
return {
|
|
790
|
-
"success": populated > 0,
|
|
791
|
-
"populated": populated,
|
|
792
|
-
"total_requested": len(libraries) * len(topics),
|
|
793
|
-
"errors": errors,
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
def cmd_help(self) -> dict[str, Any]:
|
|
797
|
-
"""
|
|
798
|
-
Show Context7 usage examples.
|
|
799
|
-
|
|
800
|
-
Command: *context7-help
|
|
801
|
-
|
|
802
|
-
Returns:
|
|
803
|
-
Dictionary with help content
|
|
804
|
-
"""
|
|
805
|
-
help_text = """
|
|
806
|
-
Context7 KB Commands
|
|
807
|
-
|
|
808
|
-
Documentation Commands:
|
|
809
|
-
*context7-docs {library} [topic]
|
|
810
|
-
Get KB-first documentation for a library/topic.
|
|
811
|
-
Example: *context7-docs react hooks
|
|
812
|
-
|
|
813
|
-
*context7-resolve {library}
|
|
814
|
-
Resolve library name to Context7 ID.
|
|
815
|
-
Example: *context7-resolve fastapi
|
|
816
|
-
|
|
817
|
-
Status & Search:
|
|
818
|
-
*context7-kb-status
|
|
819
|
-
Show KB cache statistics and performance metrics.
|
|
820
|
-
|
|
821
|
-
*context7-kb-health
|
|
822
|
-
Get detailed health check report with recommendations.
|
|
823
|
-
|
|
824
|
-
*context7-kb-validate-cache
|
|
825
|
-
Validate cache coverage and identify missing/stale libraries.
|
|
826
|
-
Example: *context7-kb-validate-cache
|
|
827
|
-
|
|
828
|
-
*context7-kb-search {query} [limit]
|
|
829
|
-
Search cached documentation.
|
|
830
|
-
Example: *context7-kb-search authentication 5
|
|
831
|
-
|
|
832
|
-
Management Commands:
|
|
833
|
-
*context7-kb-populate [libraries...] [--topics topics...] [--force]
|
|
834
|
-
Pre-populate cache with library documentation.
|
|
835
|
-
Example: *context7-kb-populate fastapi pytest react --topics overview hooks
|
|
836
|
-
|
|
837
|
-
*context7-kb-warm [--auto-detect] [libraries...]
|
|
838
|
-
Warm cache with project libraries and common topics.
|
|
839
|
-
Example: *context7-kb-warm --auto-detect
|
|
840
|
-
|
|
841
|
-
*context7-kb-refresh [library] [topic]
|
|
842
|
-
Refresh stale KB entries.
|
|
843
|
-
Examples:
|
|
844
|
-
*context7-kb-refresh # Refresh all stale entries
|
|
845
|
-
*context7-kb-refresh react # Refresh all topics in react
|
|
846
|
-
*context7-kb-refresh react hooks # Refresh specific topic
|
|
847
|
-
|
|
848
|
-
*context7-kb-cleanup [strategy] [options]
|
|
849
|
-
Clean up old/unused KB entries.
|
|
850
|
-
Strategies: size, age, unused, all
|
|
851
|
-
Example: *context7-kb-cleanup size target_size_mb=50
|
|
852
|
-
|
|
853
|
-
*context7-kb-rebuild
|
|
854
|
-
Rebuild KB cache index from filesystem.
|
|
855
|
-
|
|
856
|
-
For more information, see: docs/CONTEXT7_GUIDE.md
|
|
857
|
-
"""
|
|
858
|
-
return {"success": True, "help": help_text.strip()}
|
|
1
|
+
"""
|
|
2
|
+
Context7 Commands - CLI commands for Context7 KB management.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from datetime import UTC, datetime
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from ..core.config import ProjectConfig
|
|
11
|
+
from .analytics import Analytics
|
|
12
|
+
from .cache_structure import CacheStructure
|
|
13
|
+
from .cache_warming import CacheWarmer
|
|
14
|
+
from .cleanup import KBCleanup
|
|
15
|
+
from .cross_references import CrossReferenceManager
|
|
16
|
+
from .fuzzy_matcher import FuzzyMatcher
|
|
17
|
+
from .kb_cache import KBCache
|
|
18
|
+
from .lookup import KBLookup
|
|
19
|
+
from .metadata import MetadataManager
|
|
20
|
+
from .refresh_queue import RefreshQueue
|
|
21
|
+
from .staleness_policies import StalenessPolicyManager
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _parse_size_string(size_str: str) -> int:
|
|
25
|
+
"""
|
|
26
|
+
Parse size string like "100MB" or "1GB" into bytes.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
size_str: Size string (e.g., "100MB", "1GB", "500KB")
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Size in bytes
|
|
33
|
+
"""
|
|
34
|
+
if not size_str:
|
|
35
|
+
return 100 * 1024 * 1024 # Default 100MB
|
|
36
|
+
|
|
37
|
+
# Match pattern like "100MB", "1.5GB", etc.
|
|
38
|
+
match = re.match(r"^(\d+(?:\.\d+)?)\s*([KMGT]?B?)$", size_str.upper().strip())
|
|
39
|
+
if not match:
|
|
40
|
+
# If parsing fails, default to 100MB
|
|
41
|
+
return 100 * 1024 * 1024
|
|
42
|
+
|
|
43
|
+
value = float(match.group(1))
|
|
44
|
+
unit = match.group(2) or "B"
|
|
45
|
+
|
|
46
|
+
multipliers = {
|
|
47
|
+
"B": 1,
|
|
48
|
+
"KB": 1024,
|
|
49
|
+
"MB": 1024 * 1024,
|
|
50
|
+
"GB": 1024 * 1024 * 1024,
|
|
51
|
+
"TB": 1024 * 1024 * 1024 * 1024,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return int(value * multipliers.get(unit, 1))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Context7Commands:
|
|
58
|
+
"""
|
|
59
|
+
Context7 KB commands for CLI/agent interface.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
project_root: Path | None = None,
|
|
65
|
+
config: ProjectConfig | None = None,
|
|
66
|
+
):
|
|
67
|
+
"""
|
|
68
|
+
Initialize Context7 commands.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
project_root: Optional project root path (defaults to cwd)
|
|
72
|
+
config: Optional ProjectConfig instance (loads if not provided)
|
|
73
|
+
"""
|
|
74
|
+
if project_root is None:
|
|
75
|
+
project_root = Path.cwd()
|
|
76
|
+
|
|
77
|
+
if config is None:
|
|
78
|
+
from ..core.config import load_config
|
|
79
|
+
|
|
80
|
+
config = load_config()
|
|
81
|
+
|
|
82
|
+
context7_config = config.context7
|
|
83
|
+
if not context7_config or not context7_config.enabled:
|
|
84
|
+
self.enabled = False
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
# Wrap initialization in try-except to prevent failures from breaking commands
|
|
88
|
+
try:
|
|
89
|
+
self.enabled = True
|
|
90
|
+
self.config = context7_config
|
|
91
|
+
self.project_root = project_root
|
|
92
|
+
|
|
93
|
+
# Initialize cache structure
|
|
94
|
+
cache_root = project_root / context7_config.knowledge_base.location
|
|
95
|
+
self.cache_structure = CacheStructure(cache_root)
|
|
96
|
+
self.cache_structure.initialize()
|
|
97
|
+
|
|
98
|
+
# Initialize components
|
|
99
|
+
self.metadata_manager = MetadataManager(self.cache_structure)
|
|
100
|
+
self.kb_cache = KBCache(self.cache_structure.cache_root, self.metadata_manager)
|
|
101
|
+
self.fuzzy_matcher = FuzzyMatcher(threshold=0.7)
|
|
102
|
+
self.analytics = Analytics(self.cache_structure, self.metadata_manager)
|
|
103
|
+
self.staleness_policy_manager = StalenessPolicyManager()
|
|
104
|
+
self.refresh_queue = RefreshQueue(
|
|
105
|
+
self.cache_structure.refresh_queue_file, self.staleness_policy_manager
|
|
106
|
+
)
|
|
107
|
+
# Parse max_cache_size string (e.g., "100MB") to bytes
|
|
108
|
+
max_cache_size_bytes = _parse_size_string(
|
|
109
|
+
context7_config.knowledge_base.max_cache_size
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
self.cleanup = KBCleanup(
|
|
113
|
+
self.cache_structure,
|
|
114
|
+
self.metadata_manager,
|
|
115
|
+
self.staleness_policy_manager,
|
|
116
|
+
self.analytics,
|
|
117
|
+
max_cache_size_bytes=max_cache_size_bytes,
|
|
118
|
+
)
|
|
119
|
+
self.cross_refs = CrossReferenceManager(self.cache_structure)
|
|
120
|
+
|
|
121
|
+
# KB lookup (will need MCP Gateway for API calls)
|
|
122
|
+
self.kb_lookup = KBLookup(
|
|
123
|
+
kb_cache=self.kb_cache,
|
|
124
|
+
mcp_gateway=None, # Set via set_mcp_gateway
|
|
125
|
+
fuzzy_threshold=0.7,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Cache warmer
|
|
129
|
+
self.cache_warmer = CacheWarmer(
|
|
130
|
+
kb_cache=self.kb_cache,
|
|
131
|
+
kb_lookup=self.kb_lookup,
|
|
132
|
+
cache_structure=self.cache_structure,
|
|
133
|
+
metadata_manager=self.metadata_manager,
|
|
134
|
+
project_root=self.project_root,
|
|
135
|
+
)
|
|
136
|
+
except Exception as e:
|
|
137
|
+
# If Context7 initialization fails, disable it gracefully
|
|
138
|
+
import logging
|
|
139
|
+
logger = logging.getLogger(__name__)
|
|
140
|
+
logger.warning(
|
|
141
|
+
f"Context7Commands initialization failed, disabling Context7 features: {e}. "
|
|
142
|
+
f"Commands will continue to work without Context7."
|
|
143
|
+
)
|
|
144
|
+
self.enabled = False
|
|
145
|
+
# Set minimal attributes to prevent AttributeError
|
|
146
|
+
self.config = context7_config
|
|
147
|
+
self.project_root = project_root
|
|
148
|
+
self.cache_structure = None
|
|
149
|
+
self.metadata_manager = None
|
|
150
|
+
self.kb_cache = None
|
|
151
|
+
self.fuzzy_matcher = None
|
|
152
|
+
self.analytics = None
|
|
153
|
+
self.staleness_policy_manager = None
|
|
154
|
+
self.refresh_queue = None
|
|
155
|
+
self.cleanup = None
|
|
156
|
+
self.cross_refs = None
|
|
157
|
+
self.kb_lookup = None
|
|
158
|
+
self.cache_warmer = None
|
|
159
|
+
|
|
160
|
+
def set_mcp_gateway(self, mcp_gateway):
|
|
161
|
+
"""Set MCP Gateway for API calls."""
|
|
162
|
+
if not self.enabled or self.kb_lookup is None:
|
|
163
|
+
return
|
|
164
|
+
self.kb_lookup.mcp_gateway = mcp_gateway
|
|
165
|
+
if self.cache_warmer is not None:
|
|
166
|
+
self.cache_warmer.kb_lookup = self.kb_lookup
|
|
167
|
+
|
|
168
|
+
async def cmd_docs(self, library: str, topic: str | None = None) -> dict[str, Any]:
|
|
169
|
+
"""
|
|
170
|
+
Get KB-first documentation for a library/topic.
|
|
171
|
+
|
|
172
|
+
Command: *context7-docs {library} [topic]
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
library: Library name
|
|
176
|
+
topic: Optional topic name
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
Dictionary with documentation result
|
|
180
|
+
"""
|
|
181
|
+
if not self.enabled or self.kb_lookup is None:
|
|
182
|
+
return {"error": "Context7 is not enabled"}
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
result = await self.kb_lookup.lookup(
|
|
186
|
+
library=library, topic=topic, use_fuzzy_match=True
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if result.success:
|
|
190
|
+
return {
|
|
191
|
+
"success": True,
|
|
192
|
+
"library": result.library,
|
|
193
|
+
"topic": result.topic,
|
|
194
|
+
"content": result.content,
|
|
195
|
+
"source": result.source,
|
|
196
|
+
"fuzzy_score": result.fuzzy_score,
|
|
197
|
+
"matched_topic": result.matched_topic,
|
|
198
|
+
"response_time_ms": result.response_time_ms,
|
|
199
|
+
}
|
|
200
|
+
else:
|
|
201
|
+
return {
|
|
202
|
+
"success": False,
|
|
203
|
+
"error": result.error or "Documentation not found",
|
|
204
|
+
"library": library,
|
|
205
|
+
"topic": topic,
|
|
206
|
+
}
|
|
207
|
+
except Exception as e:
|
|
208
|
+
return {"success": False, "error": str(e)}
|
|
209
|
+
|
|
210
|
+
async def cmd_resolve(self, library: str) -> dict[str, Any]:
|
|
211
|
+
"""
|
|
212
|
+
Resolve library name to Context7 ID.
|
|
213
|
+
|
|
214
|
+
Command: *context7-resolve {library}
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
library: Library name to resolve
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Dictionary with resolution result
|
|
221
|
+
"""
|
|
222
|
+
if not self.enabled or self.kb_lookup is None:
|
|
223
|
+
return {"error": "Context7 is not enabled"}
|
|
224
|
+
|
|
225
|
+
# Use backup client with automatic fallback (MCP Gateway -> HTTP)
|
|
226
|
+
from .backup_client import call_context7_resolve_with_fallback
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
result = await call_context7_resolve_with_fallback(
|
|
230
|
+
library, self.kb_lookup.mcp_gateway if self.kb_lookup else None
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
if result.get("success"):
|
|
234
|
+
matches = result.get("result", {}).get("matches", [])
|
|
235
|
+
return {"success": True, "library": library, "matches": matches}
|
|
236
|
+
else:
|
|
237
|
+
return {
|
|
238
|
+
"success": False,
|
|
239
|
+
"error": result.get("error", "Failed to resolve library"),
|
|
240
|
+
"library": library,
|
|
241
|
+
}
|
|
242
|
+
except Exception as e:
|
|
243
|
+
return {"success": False, "error": str(e)}
|
|
244
|
+
|
|
245
|
+
async def cmd_status(self) -> dict[str, Any]:
|
|
246
|
+
"""
|
|
247
|
+
Get KB status and statistics.
|
|
248
|
+
|
|
249
|
+
Command: *context7-kb-status
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
Dictionary with status information
|
|
253
|
+
"""
|
|
254
|
+
if not self.enabled or self.analytics is None or self.cleanup is None:
|
|
255
|
+
return {"error": "Context7 is not enabled"}
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
metrics = self.analytics.get_cache_metrics()
|
|
259
|
+
status_report = self.analytics.get_status_report()
|
|
260
|
+
|
|
261
|
+
# Get cache size
|
|
262
|
+
cache_size = self.cleanup.get_cache_size()
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
"success": True,
|
|
266
|
+
"status": status_report.get("status", "unknown"),
|
|
267
|
+
"health_issues": status_report.get("health_issues", []),
|
|
268
|
+
"cache_size_bytes": cache_size,
|
|
269
|
+
"cache_size_mb": cache_size / (1024 * 1024),
|
|
270
|
+
"metrics": {
|
|
271
|
+
"total_entries": metrics.total_entries,
|
|
272
|
+
"total_libraries": metrics.total_libraries,
|
|
273
|
+
"cache_hits": metrics.cache_hits,
|
|
274
|
+
"cache_misses": metrics.cache_misses,
|
|
275
|
+
"api_calls": metrics.api_calls,
|
|
276
|
+
"hit_rate": metrics.hit_rate,
|
|
277
|
+
"avg_response_time_ms": metrics.avg_response_time_ms,
|
|
278
|
+
},
|
|
279
|
+
"top_libraries": status_report.get("top_libraries", []),
|
|
280
|
+
"timestamp": status_report.get("timestamp"),
|
|
281
|
+
}
|
|
282
|
+
except Exception as e:
|
|
283
|
+
return {"success": False, "error": str(e)}
|
|
284
|
+
|
|
285
|
+
async def cmd_health(self) -> dict[str, Any]:
|
|
286
|
+
"""
|
|
287
|
+
Get detailed health check report.
|
|
288
|
+
|
|
289
|
+
Command: *context7-kb-health
|
|
290
|
+
|
|
291
|
+
Returns:
|
|
292
|
+
Dictionary with health check information
|
|
293
|
+
"""
|
|
294
|
+
if not self.enabled or self.analytics is None:
|
|
295
|
+
return {"error": "Context7 is not enabled"}
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
health_check = self.analytics.get_health_check()
|
|
299
|
+
return {"success": True, **health_check}
|
|
300
|
+
except Exception as e:
|
|
301
|
+
return {"success": False, "error": str(e)}
|
|
302
|
+
|
|
303
|
+
async def cmd_search(self, query: str, limit: int = 10) -> dict[str, Any]:
|
|
304
|
+
"""
|
|
305
|
+
Search cached documentation.
|
|
306
|
+
|
|
307
|
+
Command: *context7-kb-search {query} [limit]
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
query: Search query
|
|
311
|
+
limit: Maximum number of results
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Dictionary with search results
|
|
315
|
+
"""
|
|
316
|
+
if not self.enabled or self.metadata_manager is None or self.fuzzy_matcher is None:
|
|
317
|
+
return {"error": "Context7 is not enabled"}
|
|
318
|
+
|
|
319
|
+
try:
|
|
320
|
+
cache_index = self.metadata_manager.load_cache_index()
|
|
321
|
+
results = []
|
|
322
|
+
|
|
323
|
+
# Simple keyword search in library/topic names
|
|
324
|
+
query_lower = query.lower()
|
|
325
|
+
|
|
326
|
+
for library_name, library_data in cache_index.libraries.items():
|
|
327
|
+
topics = library_data.get("topics", {})
|
|
328
|
+
|
|
329
|
+
# Check library name
|
|
330
|
+
if query_lower in library_name.lower():
|
|
331
|
+
for topic_name in topics.keys():
|
|
332
|
+
results.append(
|
|
333
|
+
{
|
|
334
|
+
"library": library_name,
|
|
335
|
+
"topic": topic_name,
|
|
336
|
+
"match_type": "library_name",
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
# Check topic names
|
|
341
|
+
for topic_name in topics.keys():
|
|
342
|
+
if query_lower in topic_name.lower():
|
|
343
|
+
results.append(
|
|
344
|
+
{
|
|
345
|
+
"library": library_name,
|
|
346
|
+
"topic": topic_name,
|
|
347
|
+
"match_type": "topic_name",
|
|
348
|
+
}
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# Use fuzzy matching for better results
|
|
352
|
+
if len(results) < limit:
|
|
353
|
+
fuzzy_results = self.fuzzy_matcher.find_best_match(
|
|
354
|
+
query, None, cache_index
|
|
355
|
+
)
|
|
356
|
+
if fuzzy_results:
|
|
357
|
+
for match in fuzzy_results[: limit - len(results)]:
|
|
358
|
+
if match not in results:
|
|
359
|
+
results.append(
|
|
360
|
+
{
|
|
361
|
+
"library": match.library,
|
|
362
|
+
"topic": match.topic,
|
|
363
|
+
"match_type": "fuzzy",
|
|
364
|
+
"score": match.score,
|
|
365
|
+
}
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
"success": True,
|
|
370
|
+
"query": query,
|
|
371
|
+
"results": results[:limit],
|
|
372
|
+
"count": len(results[:limit]),
|
|
373
|
+
}
|
|
374
|
+
except Exception as e:
|
|
375
|
+
return {"success": False, "error": str(e)}
|
|
376
|
+
|
|
377
|
+
async def cmd_refresh_process(self, max_items: int = 10) -> dict[str, Any]:
|
|
378
|
+
"""
|
|
379
|
+
Process queued refresh tasks (best-effort).
|
|
380
|
+
|
|
381
|
+
This is used by startup routines to refresh stale entries incrementally.
|
|
382
|
+
If the MCP gateway is not available, we soft-fail with a clear error.
|
|
383
|
+
"""
|
|
384
|
+
if not self.enabled or self.kb_lookup is None or self.refresh_queue is None or self.kb_cache is None:
|
|
385
|
+
return {
|
|
386
|
+
"success": False,
|
|
387
|
+
"error": "Context7 is not enabled",
|
|
388
|
+
"items_processed": 0,
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if not self.kb_lookup.mcp_gateway:
|
|
392
|
+
return {
|
|
393
|
+
"success": False,
|
|
394
|
+
"error": "MCP Gateway not available",
|
|
395
|
+
"items_processed": 0,
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
processed = 0
|
|
399
|
+
errors: list[str] = []
|
|
400
|
+
|
|
401
|
+
while processed < max_items:
|
|
402
|
+
task = self.refresh_queue.get_next_task()
|
|
403
|
+
if task is None:
|
|
404
|
+
break
|
|
405
|
+
|
|
406
|
+
topic = task.topic or "overview"
|
|
407
|
+
try:
|
|
408
|
+
# Resolve library -> Context7 ID (with backup fallback)
|
|
409
|
+
from .backup_client import (
|
|
410
|
+
call_context7_get_docs_with_fallback,
|
|
411
|
+
call_context7_resolve_with_fallback,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
resolve = await call_context7_resolve_with_fallback(
|
|
415
|
+
task.library, self.kb_lookup.mcp_gateway
|
|
416
|
+
)
|
|
417
|
+
matches = (
|
|
418
|
+
resolve.get("result", {}).get("matches", [])
|
|
419
|
+
if resolve.get("success")
|
|
420
|
+
else []
|
|
421
|
+
)
|
|
422
|
+
context7_id = None
|
|
423
|
+
if matches:
|
|
424
|
+
first = matches[0]
|
|
425
|
+
context7_id = (
|
|
426
|
+
first.get("id") if isinstance(first, dict) else str(first)
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
if not context7_id:
|
|
430
|
+
raise RuntimeError("Could not resolve Context7 library ID")
|
|
431
|
+
|
|
432
|
+
# Fetch docs (with backup fallback)
|
|
433
|
+
docs = await call_context7_get_docs_with_fallback(
|
|
434
|
+
context7_id, topic, mode="code", page=1, mcp_gateway=self.kb_lookup.mcp_gateway
|
|
435
|
+
)
|
|
436
|
+
if not docs.get("success"):
|
|
437
|
+
raise RuntimeError(docs.get("error") or "Failed to fetch docs")
|
|
438
|
+
|
|
439
|
+
result_data = docs.get("result", {})
|
|
440
|
+
content = (
|
|
441
|
+
result_data.get("content")
|
|
442
|
+
if isinstance(result_data, dict)
|
|
443
|
+
else (result_data if isinstance(result_data, str) else None)
|
|
444
|
+
)
|
|
445
|
+
if not content:
|
|
446
|
+
raise RuntimeError("No content returned from Context7 docs tool")
|
|
447
|
+
|
|
448
|
+
# Store (refresh) content
|
|
449
|
+
self.kb_cache.store(
|
|
450
|
+
library=task.library,
|
|
451
|
+
topic=topic,
|
|
452
|
+
content=content,
|
|
453
|
+
context7_id=context7_id,
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
self.refresh_queue.mark_task_completed(
|
|
457
|
+
task.library, task.topic, error=None
|
|
458
|
+
)
|
|
459
|
+
processed += 1
|
|
460
|
+
|
|
461
|
+
except Exception as e:
|
|
462
|
+
err = f"{task.library}/{topic}: {e}"
|
|
463
|
+
errors.append(err)
|
|
464
|
+
self.refresh_queue.mark_task_completed(
|
|
465
|
+
task.library, task.topic, error=str(e)
|
|
466
|
+
)
|
|
467
|
+
# Avoid infinite loop on a permanently failing head task.
|
|
468
|
+
break
|
|
469
|
+
|
|
470
|
+
return {
|
|
471
|
+
"success": processed > 0 and not errors,
|
|
472
|
+
"items_processed": processed,
|
|
473
|
+
"errors": errors,
|
|
474
|
+
"queue_remaining": self.refresh_queue.size(),
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async def cmd_refresh(
|
|
478
|
+
self, library: str | None = None, topic: str | None = None
|
|
479
|
+
) -> dict[str, Any]:
|
|
480
|
+
"""
|
|
481
|
+
Refresh stale KB entries.
|
|
482
|
+
|
|
483
|
+
Command: *context7-kb-refresh [library] [topic]
|
|
484
|
+
|
|
485
|
+
Args:
|
|
486
|
+
library: Optional library name (refreshes all if not provided)
|
|
487
|
+
topic: Optional topic name
|
|
488
|
+
|
|
489
|
+
Returns:
|
|
490
|
+
Dictionary with refresh result
|
|
491
|
+
"""
|
|
492
|
+
if not self.enabled or self.refresh_queue is None or self.metadata_manager is None:
|
|
493
|
+
return {"error": "Context7 is not enabled"}
|
|
494
|
+
|
|
495
|
+
try:
|
|
496
|
+
if library:
|
|
497
|
+
# Refresh specific library/topic
|
|
498
|
+
if topic:
|
|
499
|
+
priority = 8 # High priority for manual refresh
|
|
500
|
+
self.refresh_queue.add_task(library, topic, priority=priority)
|
|
501
|
+
return {
|
|
502
|
+
"success": True,
|
|
503
|
+
"message": f"Queued refresh for {library}/{topic}",
|
|
504
|
+
"library": library,
|
|
505
|
+
"topic": topic,
|
|
506
|
+
}
|
|
507
|
+
else:
|
|
508
|
+
# Refresh all topics for library
|
|
509
|
+
cache_index = self.metadata_manager.load_cache_index()
|
|
510
|
+
library_data = cache_index.libraries.get(library, {})
|
|
511
|
+
topics = library_data.get("topics", {})
|
|
512
|
+
|
|
513
|
+
queued = 0
|
|
514
|
+
for topic_name in topics.keys():
|
|
515
|
+
self.refresh_queue.add_task(library, topic_name, priority=7)
|
|
516
|
+
queued += 1
|
|
517
|
+
|
|
518
|
+
return {
|
|
519
|
+
"success": True,
|
|
520
|
+
"message": f"Queued refresh for {queued} topics in {library}",
|
|
521
|
+
"library": library,
|
|
522
|
+
"topics_queued": queued,
|
|
523
|
+
}
|
|
524
|
+
else:
|
|
525
|
+
# Refresh all stale entries
|
|
526
|
+
cache_index = self.metadata_manager.load_cache_index()
|
|
527
|
+
entries = []
|
|
528
|
+
|
|
529
|
+
for lib_name, lib_data in cache_index.libraries.items():
|
|
530
|
+
topics = lib_data.get("topics", {})
|
|
531
|
+
for topic_name, topic_data in topics.items():
|
|
532
|
+
last_updated = topic_data.get("last_updated") or topic_data.get(
|
|
533
|
+
"cached_at"
|
|
534
|
+
)
|
|
535
|
+
if last_updated:
|
|
536
|
+
entries.append(
|
|
537
|
+
{
|
|
538
|
+
"library": lib_name,
|
|
539
|
+
"topic": topic_name,
|
|
540
|
+
"last_updated": last_updated,
|
|
541
|
+
}
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
queued = self.refresh_queue.queue_stale_entries(entries)
|
|
545
|
+
|
|
546
|
+
return {
|
|
547
|
+
"success": True,
|
|
548
|
+
"message": f"Queued refresh for {queued} stale entries",
|
|
549
|
+
"entries_queued": queued,
|
|
550
|
+
}
|
|
551
|
+
except Exception as e:
|
|
552
|
+
return {"success": False, "error": str(e)}
|
|
553
|
+
|
|
554
|
+
async def cmd_cleanup(
|
|
555
|
+
self,
|
|
556
|
+
strategy: str = "all",
|
|
557
|
+
target_size_mb: float | None = None,
|
|
558
|
+
max_age_days: int | None = None,
|
|
559
|
+
) -> dict[str, Any]:
|
|
560
|
+
"""
|
|
561
|
+
Clean up old/unused KB entries.
|
|
562
|
+
|
|
563
|
+
Command: *context7-kb-cleanup [strategy] [options]
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
strategy: Cleanup strategy ("size", "age", "unused", "all")
|
|
567
|
+
target_size_mb: Target size in MB (for size strategy)
|
|
568
|
+
max_age_days: Maximum age in days (for age strategy)
|
|
569
|
+
|
|
570
|
+
Returns:
|
|
571
|
+
Dictionary with cleanup result
|
|
572
|
+
"""
|
|
573
|
+
if not self.enabled or self.cleanup is None:
|
|
574
|
+
return {"error": "Context7 is not enabled"}
|
|
575
|
+
|
|
576
|
+
try:
|
|
577
|
+
if strategy == "size":
|
|
578
|
+
target_bytes = (
|
|
579
|
+
int(target_size_mb * 1024 * 1024) if target_size_mb else None
|
|
580
|
+
)
|
|
581
|
+
result = self.cleanup.cleanup_by_size(target_size_bytes=target_bytes)
|
|
582
|
+
elif strategy == "age":
|
|
583
|
+
result = self.cleanup.cleanup_by_age(max_age_days=max_age_days)
|
|
584
|
+
elif strategy == "unused":
|
|
585
|
+
result = self.cleanup.cleanup_unused()
|
|
586
|
+
else: # "all"
|
|
587
|
+
result = self.cleanup.cleanup_all(
|
|
588
|
+
target_size_bytes=(
|
|
589
|
+
int(target_size_mb * 1024 * 1024) if target_size_mb else None
|
|
590
|
+
),
|
|
591
|
+
max_age_days=max_age_days,
|
|
592
|
+
)
|
|
593
|
+
|
|
594
|
+
return {"success": True, "strategy": strategy, "result": result.to_dict()}
|
|
595
|
+
except Exception as e:
|
|
596
|
+
return {"success": False, "error": str(e)}
|
|
597
|
+
|
|
598
|
+
async def cmd_rebuild_index(self) -> dict[str, Any]:
|
|
599
|
+
"""
|
|
600
|
+
Rebuild KB cache index.
|
|
601
|
+
|
|
602
|
+
Command: *context7-kb-rebuild
|
|
603
|
+
|
|
604
|
+
Returns:
|
|
605
|
+
Dictionary with rebuild result
|
|
606
|
+
"""
|
|
607
|
+
if not self.enabled or self.metadata_manager is None or self.cache_structure is None:
|
|
608
|
+
return {"error": "Context7 is not enabled"}
|
|
609
|
+
|
|
610
|
+
try:
|
|
611
|
+
# Rebuild index from filesystem
|
|
612
|
+
cache_index = self.metadata_manager.load_cache_index()
|
|
613
|
+
cache_index.libraries = {}
|
|
614
|
+
cache_index.total_entries = 0
|
|
615
|
+
|
|
616
|
+
# Scan filesystem
|
|
617
|
+
for lib_dir in self.cache_structure.libraries_dir.iterdir():
|
|
618
|
+
if lib_dir.is_dir():
|
|
619
|
+
library_name = lib_dir.name
|
|
620
|
+
topics = {}
|
|
621
|
+
|
|
622
|
+
for doc_file in lib_dir.glob("*.md"):
|
|
623
|
+
if doc_file.name != "index.md": # Skip index files
|
|
624
|
+
topic = doc_file.stem
|
|
625
|
+
topics[topic] = {
|
|
626
|
+
"cached_at": datetime.now(UTC).isoformat() + "Z"
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if topics:
|
|
630
|
+
cache_index.libraries[library_name] = {"topics": topics}
|
|
631
|
+
cache_index.total_entries += len(topics)
|
|
632
|
+
|
|
633
|
+
self.metadata_manager.save_cache_index(cache_index)
|
|
634
|
+
|
|
635
|
+
return {
|
|
636
|
+
"success": True,
|
|
637
|
+
"message": "Index rebuilt successfully",
|
|
638
|
+
"libraries": len(cache_index.libraries),
|
|
639
|
+
"total_entries": cache_index.total_entries,
|
|
640
|
+
}
|
|
641
|
+
except Exception as e:
|
|
642
|
+
return {"success": False, "error": str(e)}
|
|
643
|
+
|
|
644
|
+
async def cmd_warm(
|
|
645
|
+
self,
|
|
646
|
+
auto_detect: bool = True,
|
|
647
|
+
libraries: list[str] | None = None,
|
|
648
|
+
priority: int = 5,
|
|
649
|
+
) -> dict[str, Any]:
|
|
650
|
+
"""
|
|
651
|
+
Warm cache with project libraries and common topics.
|
|
652
|
+
|
|
653
|
+
Command: *context7-kb-warm [--auto-detect] [libraries...]
|
|
654
|
+
|
|
655
|
+
Args:
|
|
656
|
+
auto_detect: Whether to auto-detect libraries from project (default: True)
|
|
657
|
+
libraries: Optional list of library names
|
|
658
|
+
priority: Priority for warming (1-10)
|
|
659
|
+
|
|
660
|
+
Returns:
|
|
661
|
+
Dictionary with warming result
|
|
662
|
+
"""
|
|
663
|
+
if not self.enabled or self.kb_lookup is None or self.cache_warmer is None:
|
|
664
|
+
return {"error": "Context7 is not enabled"}
|
|
665
|
+
|
|
666
|
+
if not self.kb_lookup.mcp_gateway:
|
|
667
|
+
return {"error": "MCP Gateway not available"}
|
|
668
|
+
|
|
669
|
+
try:
|
|
670
|
+
result = await self.cache_warmer.warm_cache(
|
|
671
|
+
libraries=libraries,
|
|
672
|
+
topics=None, # Auto-detect topics
|
|
673
|
+
priority=priority,
|
|
674
|
+
auto_detect=auto_detect,
|
|
675
|
+
)
|
|
676
|
+
return result
|
|
677
|
+
except Exception as e:
|
|
678
|
+
return {"success": False, "error": str(e)}
|
|
679
|
+
|
|
680
|
+
async def cmd_populate(
|
|
681
|
+
self,
|
|
682
|
+
libraries: list[str] | None = None,
|
|
683
|
+
topics: list[str] | None = None,
|
|
684
|
+
force: bool = False,
|
|
685
|
+
) -> dict[str, Any]:
|
|
686
|
+
"""
|
|
687
|
+
Pre-populate cache with library documentation.
|
|
688
|
+
|
|
689
|
+
Command: *context7-kb-populate [libraries...] [--topics topics...] [--force]
|
|
690
|
+
|
|
691
|
+
Args:
|
|
692
|
+
libraries: List of library names to populate (defaults to common libraries)
|
|
693
|
+
topics: Optional list of topics to populate (defaults to ["overview"])
|
|
694
|
+
force: Whether to force refresh even if already cached
|
|
695
|
+
|
|
696
|
+
Returns:
|
|
697
|
+
Dictionary with populate result
|
|
698
|
+
"""
|
|
699
|
+
if not self.enabled or self.kb_lookup is None or self.kb_cache is None:
|
|
700
|
+
return {"error": "Context7 is not enabled"}
|
|
701
|
+
|
|
702
|
+
if not self.kb_lookup.mcp_gateway:
|
|
703
|
+
return {"error": "MCP Gateway not available"}
|
|
704
|
+
|
|
705
|
+
# Default libraries if not provided
|
|
706
|
+
if libraries is None:
|
|
707
|
+
libraries = [
|
|
708
|
+
"fastapi",
|
|
709
|
+
"pytest",
|
|
710
|
+
"react",
|
|
711
|
+
"typescript",
|
|
712
|
+
"python",
|
|
713
|
+
"pydantic",
|
|
714
|
+
"sqlalchemy",
|
|
715
|
+
"playwright",
|
|
716
|
+
]
|
|
717
|
+
|
|
718
|
+
# Default topics if not provided
|
|
719
|
+
if topics is None:
|
|
720
|
+
topics = ["overview"]
|
|
721
|
+
|
|
722
|
+
populated = 0
|
|
723
|
+
errors: list[str] = []
|
|
724
|
+
|
|
725
|
+
for library in libraries:
|
|
726
|
+
for topic in topics:
|
|
727
|
+
# Check if already cached (unless force)
|
|
728
|
+
if not force and self.kb_cache.exists(library, topic):
|
|
729
|
+
continue
|
|
730
|
+
|
|
731
|
+
try:
|
|
732
|
+
# Resolve library -> Context7 ID (with backup fallback)
|
|
733
|
+
from .backup_client import (
|
|
734
|
+
call_context7_get_docs_with_fallback,
|
|
735
|
+
call_context7_resolve_with_fallback,
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
resolve = await call_context7_resolve_with_fallback(
|
|
739
|
+
library, self.kb_lookup.mcp_gateway
|
|
740
|
+
)
|
|
741
|
+
matches = (
|
|
742
|
+
resolve.get("result", {}).get("matches", [])
|
|
743
|
+
if resolve.get("success")
|
|
744
|
+
else []
|
|
745
|
+
)
|
|
746
|
+
context7_id = None
|
|
747
|
+
if matches:
|
|
748
|
+
first = matches[0]
|
|
749
|
+
context7_id = (
|
|
750
|
+
first.get("id") if isinstance(first, dict) else str(first)
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
if not context7_id:
|
|
754
|
+
errors.append(f"{library}/{topic}: Could not resolve library ID")
|
|
755
|
+
continue
|
|
756
|
+
|
|
757
|
+
# Fetch docs (with backup fallback)
|
|
758
|
+
docs = await call_context7_get_docs_with_fallback(
|
|
759
|
+
context7_id, topic, mode="code", page=1, mcp_gateway=self.kb_lookup.mcp_gateway
|
|
760
|
+
)
|
|
761
|
+
if not docs.get("success"):
|
|
762
|
+
errors.append(
|
|
763
|
+
f"{library}/{topic}: {docs.get('error', 'Failed to fetch docs')}"
|
|
764
|
+
)
|
|
765
|
+
continue
|
|
766
|
+
|
|
767
|
+
result_data = docs.get("result", {})
|
|
768
|
+
content = (
|
|
769
|
+
result_data.get("content")
|
|
770
|
+
if isinstance(result_data, dict)
|
|
771
|
+
else (result_data if isinstance(result_data, str) else None)
|
|
772
|
+
)
|
|
773
|
+
if not content:
|
|
774
|
+
errors.append(f"{library}/{topic}: No content returned")
|
|
775
|
+
continue
|
|
776
|
+
|
|
777
|
+
# Store in cache
|
|
778
|
+
self.kb_cache.store(
|
|
779
|
+
library=library,
|
|
780
|
+
topic=topic,
|
|
781
|
+
content=content,
|
|
782
|
+
context7_id=context7_id,
|
|
783
|
+
)
|
|
784
|
+
populated += 1
|
|
785
|
+
|
|
786
|
+
except Exception as e:
|
|
787
|
+
errors.append(f"{library}/{topic}: {str(e)}")
|
|
788
|
+
|
|
789
|
+
return {
|
|
790
|
+
"success": populated > 0,
|
|
791
|
+
"populated": populated,
|
|
792
|
+
"total_requested": len(libraries) * len(topics),
|
|
793
|
+
"errors": errors,
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
def cmd_help(self) -> dict[str, Any]:
|
|
797
|
+
"""
|
|
798
|
+
Show Context7 usage examples.
|
|
799
|
+
|
|
800
|
+
Command: *context7-help
|
|
801
|
+
|
|
802
|
+
Returns:
|
|
803
|
+
Dictionary with help content
|
|
804
|
+
"""
|
|
805
|
+
help_text = """
|
|
806
|
+
Context7 KB Commands
|
|
807
|
+
|
|
808
|
+
Documentation Commands:
|
|
809
|
+
*context7-docs {library} [topic]
|
|
810
|
+
Get KB-first documentation for a library/topic.
|
|
811
|
+
Example: *context7-docs react hooks
|
|
812
|
+
|
|
813
|
+
*context7-resolve {library}
|
|
814
|
+
Resolve library name to Context7 ID.
|
|
815
|
+
Example: *context7-resolve fastapi
|
|
816
|
+
|
|
817
|
+
Status & Search:
|
|
818
|
+
*context7-kb-status
|
|
819
|
+
Show KB cache statistics and performance metrics.
|
|
820
|
+
|
|
821
|
+
*context7-kb-health
|
|
822
|
+
Get detailed health check report with recommendations.
|
|
823
|
+
|
|
824
|
+
*context7-kb-validate-cache
|
|
825
|
+
Validate cache coverage and identify missing/stale libraries.
|
|
826
|
+
Example: *context7-kb-validate-cache
|
|
827
|
+
|
|
828
|
+
*context7-kb-search {query} [limit]
|
|
829
|
+
Search cached documentation.
|
|
830
|
+
Example: *context7-kb-search authentication 5
|
|
831
|
+
|
|
832
|
+
Management Commands:
|
|
833
|
+
*context7-kb-populate [libraries...] [--topics topics...] [--force]
|
|
834
|
+
Pre-populate cache with library documentation.
|
|
835
|
+
Example: *context7-kb-populate fastapi pytest react --topics overview hooks
|
|
836
|
+
|
|
837
|
+
*context7-kb-warm [--auto-detect] [libraries...]
|
|
838
|
+
Warm cache with project libraries and common topics.
|
|
839
|
+
Example: *context7-kb-warm --auto-detect
|
|
840
|
+
|
|
841
|
+
*context7-kb-refresh [library] [topic]
|
|
842
|
+
Refresh stale KB entries.
|
|
843
|
+
Examples:
|
|
844
|
+
*context7-kb-refresh # Refresh all stale entries
|
|
845
|
+
*context7-kb-refresh react # Refresh all topics in react
|
|
846
|
+
*context7-kb-refresh react hooks # Refresh specific topic
|
|
847
|
+
|
|
848
|
+
*context7-kb-cleanup [strategy] [options]
|
|
849
|
+
Clean up old/unused KB entries.
|
|
850
|
+
Strategies: size, age, unused, all
|
|
851
|
+
Example: *context7-kb-cleanup size target_size_mb=50
|
|
852
|
+
|
|
853
|
+
*context7-kb-rebuild
|
|
854
|
+
Rebuild KB cache index from filesystem.
|
|
855
|
+
|
|
856
|
+
For more information, see: docs/CONTEXT7_GUIDE.md
|
|
857
|
+
"""
|
|
858
|
+
return {"success": True, "help": help_text.strip()}
|