sdlc-agent-4-enterprise-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +244 -0
- package/dist/admin/__tests__/admin-db.test.d.ts +5 -0
- package/dist/admin/__tests__/admin-db.test.js +357 -0
- package/dist/admin/__tests__/admin-db.test.js.map +1 -0
- package/dist/admin/admin-db.d.ts +120 -0
- package/dist/admin/admin-db.js +1056 -0
- package/dist/admin/admin-db.js.map +1 -0
- package/dist/admin/index.d.ts +13 -0
- package/dist/admin/index.js +73 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/middleware/audit.middleware.d.ts +13 -0
- package/dist/admin/middleware/audit.middleware.js +57 -0
- package/dist/admin/middleware/audit.middleware.js.map +1 -0
- package/dist/admin/middleware/rate-limit.middleware.d.ts +2 -0
- package/dist/admin/middleware/rate-limit.middleware.js +47 -0
- package/dist/admin/middleware/rate-limit.middleware.js.map +1 -0
- package/dist/admin/middleware/rbac.middleware.d.ts +8 -0
- package/dist/admin/middleware/rbac.middleware.js +111 -0
- package/dist/admin/middleware/rbac.middleware.js.map +1 -0
- package/dist/admin/routes/analytics.router.d.ts +3 -0
- package/dist/admin/routes/analytics.router.js +47 -0
- package/dist/admin/routes/analytics.router.js.map +1 -0
- package/dist/admin/routes/audit.router.d.ts +4 -0
- package/dist/admin/routes/audit.router.js +27 -0
- package/dist/admin/routes/audit.router.js.map +1 -0
- package/dist/admin/routes/config.router.d.ts +4 -0
- package/dist/admin/routes/config.router.js +23 -0
- package/dist/admin/routes/config.router.js.map +1 -0
- package/dist/admin/routes/dashboard.router.d.ts +5 -0
- package/dist/admin/routes/dashboard.router.js +11 -0
- package/dist/admin/routes/dashboard.router.js.map +1 -0
- package/dist/admin/routes/helpers.d.ts +26 -0
- package/dist/admin/routes/helpers.js +13 -0
- package/dist/admin/routes/helpers.js.map +1 -0
- package/dist/admin/routes/kb-admin.router.d.ts +5 -0
- package/dist/admin/routes/kb-admin.router.js +49 -0
- package/dist/admin/routes/kb-admin.router.js.map +1 -0
- package/dist/admin/routes/mcp-admin.router.d.ts +4 -0
- package/dist/admin/routes/mcp-admin.router.js +35 -0
- package/dist/admin/routes/mcp-admin.router.js.map +1 -0
- package/dist/admin/routes/rbac.router.d.ts +4 -0
- package/dist/admin/routes/rbac.router.js +71 -0
- package/dist/admin/routes/rbac.router.js.map +1 -0
- package/dist/admin/routes/search.router.d.ts +3 -0
- package/dist/admin/routes/search.router.js +20 -0
- package/dist/admin/routes/search.router.js.map +1 -0
- package/dist/admin/routes/user.router.d.ts +4 -0
- package/dist/admin/routes/user.router.js +53 -0
- package/dist/admin/routes/user.router.js.map +1 -0
- package/dist/admin/services/audit.service.d.ts +13 -0
- package/dist/admin/services/audit.service.js +40 -0
- package/dist/admin/services/audit.service.js.map +1 -0
- package/dist/admin/services/config.service.d.ts +10 -0
- package/dist/admin/services/config.service.js +31 -0
- package/dist/admin/services/config.service.js.map +1 -0
- package/dist/admin/services/dashboard.service.d.ts +9 -0
- package/dist/admin/services/dashboard.service.js +46 -0
- package/dist/admin/services/dashboard.service.js.map +1 -0
- package/dist/admin/services/kb-admin.service.d.ts +27 -0
- package/dist/admin/services/kb-admin.service.js +74 -0
- package/dist/admin/services/kb-admin.service.js.map +1 -0
- package/dist/admin/services/mcp-admin.service.d.ts +13 -0
- package/dist/admin/services/mcp-admin.service.js +40 -0
- package/dist/admin/services/mcp-admin.service.js.map +1 -0
- package/dist/admin/services/rbac.service.d.ts +16 -0
- package/dist/admin/services/rbac.service.js +104 -0
- package/dist/admin/services/rbac.service.js.map +1 -0
- package/dist/admin/services/search.service.d.ts +23 -0
- package/dist/admin/services/search.service.js +36 -0
- package/dist/admin/services/search.service.js.map +1 -0
- package/dist/admin/services/sse.manager.d.ts +12 -0
- package/dist/admin/services/sse.manager.js +55 -0
- package/dist/admin/services/sse.manager.js.map +1 -0
- package/dist/admin/services/user.service.d.ts +25 -0
- package/dist/admin/services/user.service.js +69 -0
- package/dist/admin/services/user.service.js.map +1 -0
- package/dist/admin/standalone-server.d.ts +1 -0
- package/dist/admin/standalone-server.js +94 -0
- package/dist/admin/standalone-server.js.map +1 -0
- package/dist/admin/types/admin.types.d.ts +187 -0
- package/dist/admin/types/admin.types.js +28 -0
- package/dist/admin/types/admin.types.js.map +1 -0
- package/dist/admin/types/api.types.d.ts +41 -0
- package/dist/admin/types/api.types.js +44 -0
- package/dist/admin/types/api.types.js.map +1 -0
- package/dist/admin/types/rbac.types.d.ts +86 -0
- package/dist/admin/types/rbac.types.js +6 -0
- package/dist/admin/types/rbac.types.js.map +1 -0
- package/dist/config/BackendConfig.d.ts +32 -0
- package/dist/config/BackendConfig.js +41 -0
- package/dist/config/BackendConfig.js.map +1 -0
- package/dist/engine/analyzers/complexity/ComplexityAnalyzer.d.ts +24 -0
- package/dist/engine/analyzers/complexity/ComplexityAnalyzer.js +90 -0
- package/dist/engine/analyzers/complexity/ComplexityAnalyzer.js.map +1 -0
- package/dist/engine/analyzers/complexity/ComplexityCalculator.d.ts +19 -0
- package/dist/engine/analyzers/complexity/ComplexityCalculator.js +54 -0
- package/dist/engine/analyzers/complexity/ComplexityCalculator.js.map +1 -0
- package/dist/engine/analyzers/complexity/ComplexityStore.d.ts +22 -0
- package/dist/engine/analyzers/complexity/ComplexityStore.js +152 -0
- package/dist/engine/analyzers/complexity/ComplexityStore.js.map +1 -0
- package/dist/engine/analyzers/complexity/ComplexityTool.d.ts +45 -0
- package/dist/engine/analyzers/complexity/ComplexityTool.js +58 -0
- package/dist/engine/analyzers/complexity/ComplexityTool.js.map +1 -0
- package/dist/engine/analyzers/complexity/GradeAssigner.d.ts +12 -0
- package/dist/engine/analyzers/complexity/GradeAssigner.js +32 -0
- package/dist/engine/analyzers/complexity/GradeAssigner.js.map +1 -0
- package/dist/engine/analyzers/complexity/counters/BaseNodeCounter.d.ts +25 -0
- package/dist/engine/analyzers/complexity/counters/BaseNodeCounter.js +85 -0
- package/dist/engine/analyzers/complexity/counters/BaseNodeCounter.js.map +1 -0
- package/dist/engine/analyzers/complexity/counters/GoCounter.d.ts +14 -0
- package/dist/engine/analyzers/complexity/counters/GoCounter.js +31 -0
- package/dist/engine/analyzers/complexity/counters/GoCounter.js.map +1 -0
- package/dist/engine/analyzers/complexity/counters/JavaCounter.d.ts +13 -0
- package/dist/engine/analyzers/complexity/counters/JavaCounter.js +29 -0
- package/dist/engine/analyzers/complexity/counters/JavaCounter.js.map +1 -0
- package/dist/engine/analyzers/complexity/counters/KotlinCounter.d.ts +14 -0
- package/dist/engine/analyzers/complexity/counters/KotlinCounter.js +34 -0
- package/dist/engine/analyzers/complexity/counters/KotlinCounter.js.map +1 -0
- package/dist/engine/analyzers/complexity/counters/PythonCounter.d.ts +14 -0
- package/dist/engine/analyzers/complexity/counters/PythonCounter.js +36 -0
- package/dist/engine/analyzers/complexity/counters/PythonCounter.js.map +1 -0
- package/dist/engine/analyzers/complexity/counters/TypeScriptCounter.d.ts +13 -0
- package/dist/engine/analyzers/complexity/counters/TypeScriptCounter.js +33 -0
- package/dist/engine/analyzers/complexity/counters/TypeScriptCounter.js.map +1 -0
- package/dist/engine/analyzers/complexity/index.d.ts +16 -0
- package/dist/engine/analyzers/complexity/index.js +16 -0
- package/dist/engine/analyzers/complexity/index.js.map +1 -0
- package/dist/engine/analyzers/complexity/types.d.ts +53 -0
- package/dist/engine/analyzers/complexity/types.js +5 -0
- package/dist/engine/analyzers/complexity/types.js.map +1 -0
- package/dist/engine/analyzers/entry-points/EntryPointDetector.d.ts +27 -0
- package/dist/engine/analyzers/entry-points/EntryPointDetector.js +60 -0
- package/dist/engine/analyzers/entry-points/EntryPointDetector.js.map +1 -0
- package/dist/engine/analyzers/entry-points/EntryPointStore.d.ts +20 -0
- package/dist/engine/analyzers/entry-points/EntryPointStore.js +133 -0
- package/dist/engine/analyzers/entry-points/EntryPointStore.js.map +1 -0
- package/dist/engine/analyzers/entry-points/EntryPointTool.d.ts +43 -0
- package/dist/engine/analyzers/entry-points/EntryPointTool.js +55 -0
- package/dist/engine/analyzers/entry-points/EntryPointTool.js.map +1 -0
- package/dist/engine/analyzers/entry-points/FrameworkDetector.d.ts +13 -0
- package/dist/engine/analyzers/entry-points/FrameworkDetector.js +49 -0
- package/dist/engine/analyzers/entry-points/FrameworkDetector.js.map +1 -0
- package/dist/engine/analyzers/entry-points/PatternRegistry.d.ts +27 -0
- package/dist/engine/analyzers/entry-points/PatternRegistry.js +105 -0
- package/dist/engine/analyzers/entry-points/PatternRegistry.js.map +1 -0
- package/dist/engine/analyzers/entry-points/RouteResolver.d.ts +12 -0
- package/dist/engine/analyzers/entry-points/RouteResolver.js +43 -0
- package/dist/engine/analyzers/entry-points/RouteResolver.js.map +1 -0
- package/dist/engine/analyzers/entry-points/detectors/CLIDetector.d.ts +14 -0
- package/dist/engine/analyzers/entry-points/detectors/CLIDetector.js +39 -0
- package/dist/engine/analyzers/entry-points/detectors/CLIDetector.js.map +1 -0
- package/dist/engine/analyzers/entry-points/detectors/EventDetector.d.ts +16 -0
- package/dist/engine/analyzers/entry-points/detectors/EventDetector.js +67 -0
- package/dist/engine/analyzers/entry-points/detectors/EventDetector.js.map +1 -0
- package/dist/engine/analyzers/entry-points/detectors/HTTPHandlerDetector.d.ts +30 -0
- package/dist/engine/analyzers/entry-points/detectors/HTTPHandlerDetector.js +140 -0
- package/dist/engine/analyzers/entry-points/detectors/HTTPHandlerDetector.js.map +1 -0
- package/dist/engine/analyzers/entry-points/detectors/MainDetector.d.ts +17 -0
- package/dist/engine/analyzers/entry-points/detectors/MainDetector.js +51 -0
- package/dist/engine/analyzers/entry-points/detectors/MainDetector.js.map +1 -0
- package/dist/engine/analyzers/entry-points/index.d.ts +14 -0
- package/dist/engine/analyzers/entry-points/index.js +14 -0
- package/dist/engine/analyzers/entry-points/index.js.map +1 -0
- package/dist/engine/analyzers/entry-points/types.d.ts +77 -0
- package/dist/engine/analyzers/entry-points/types.js +5 -0
- package/dist/engine/analyzers/entry-points/types.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/CircularDepDetector.d.ts +16 -0
- package/dist/engine/analyzers/graph-analysis/CircularDepDetector.js +80 -0
- package/dist/engine/analyzers/graph-analysis/CircularDepDetector.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/DeadImportDetector.d.ts +15 -0
- package/dist/engine/analyzers/graph-analysis/DeadImportDetector.js +56 -0
- package/dist/engine/analyzers/graph-analysis/DeadImportDetector.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/GraphAnalysisTools.d.ts +123 -0
- package/dist/engine/analyzers/graph-analysis/GraphAnalysisTools.js +187 -0
- package/dist/engine/analyzers/graph-analysis/GraphAnalysisTools.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/HotPathAnalyzer.d.ts +17 -0
- package/dist/engine/analyzers/graph-analysis/HotPathAnalyzer.js +55 -0
- package/dist/engine/analyzers/graph-analysis/HotPathAnalyzer.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/ModuleSummarizer.d.ts +14 -0
- package/dist/engine/analyzers/graph-analysis/ModuleSummarizer.js +59 -0
- package/dist/engine/analyzers/graph-analysis/ModuleSummarizer.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/RelatedTestFinder.d.ts +16 -0
- package/dist/engine/analyzers/graph-analysis/RelatedTestFinder.js +87 -0
- package/dist/engine/analyzers/graph-analysis/RelatedTestFinder.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/index.d.ts +13 -0
- package/dist/engine/analyzers/graph-analysis/index.js +13 -0
- package/dist/engine/analyzers/graph-analysis/index.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/types.d.ts +67 -0
- package/dist/engine/analyzers/graph-analysis/types.js +5 -0
- package/dist/engine/analyzers/graph-analysis/types.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/utils/GraphLoader.d.ts +27 -0
- package/dist/engine/analyzers/graph-analysis/utils/GraphLoader.js +124 -0
- package/dist/engine/analyzers/graph-analysis/utils/GraphLoader.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/utils/TarjanSCC.d.ts +17 -0
- package/dist/engine/analyzers/graph-analysis/utils/TarjanSCC.js +59 -0
- package/dist/engine/analyzers/graph-analysis/utils/TarjanSCC.js.map +1 -0
- package/dist/engine/analyzers/graph-analysis/utils/TestFileDetector.d.ts +11 -0
- package/dist/engine/analyzers/graph-analysis/utils/TestFileDetector.js +29 -0
- package/dist/engine/analyzers/graph-analysis/utils/TestFileDetector.js.map +1 -0
- package/dist/engine/analyzers/security/cfg/BasicBlock.d.ts +19 -0
- package/dist/engine/analyzers/security/cfg/BasicBlock.js +115 -0
- package/dist/engine/analyzers/security/cfg/BasicBlock.js.map +1 -0
- package/dist/engine/analyzers/security/cfg/CFGBuilder.d.ts +22 -0
- package/dist/engine/analyzers/security/cfg/CFGBuilder.js +244 -0
- package/dist/engine/analyzers/security/cfg/CFGBuilder.js.map +1 -0
- package/dist/engine/analyzers/security/cfg/CFGEdge.d.ts +13 -0
- package/dist/engine/analyzers/security/cfg/CFGEdge.js +19 -0
- package/dist/engine/analyzers/security/cfg/CFGEdge.js.map +1 -0
- package/dist/engine/analyzers/security/cfg/ControlFlowGraph.d.ts +29 -0
- package/dist/engine/analyzers/security/cfg/ControlFlowGraph.js +87 -0
- package/dist/engine/analyzers/security/cfg/ControlFlowGraph.js.map +1 -0
- package/dist/engine/analyzers/security/dataflow/DataFlowAnalyzer.d.ts +14 -0
- package/dist/engine/analyzers/security/dataflow/DataFlowAnalyzer.js +61 -0
- package/dist/engine/analyzers/security/dataflow/DataFlowAnalyzer.js.map +1 -0
- package/dist/engine/analyzers/security/dataflow/ReachingDefinitions.d.ts +16 -0
- package/dist/engine/analyzers/security/dataflow/ReachingDefinitions.js +79 -0
- package/dist/engine/analyzers/security/dataflow/ReachingDefinitions.js.map +1 -0
- package/dist/engine/analyzers/security/idor/IDORDetector.d.ts +21 -0
- package/dist/engine/analyzers/security/idor/IDORDetector.js +124 -0
- package/dist/engine/analyzers/security/idor/IDORDetector.js.map +1 -0
- package/dist/engine/analyzers/security/injection/InjectionScanner.d.ts +28 -0
- package/dist/engine/analyzers/security/injection/InjectionScanner.js +134 -0
- package/dist/engine/analyzers/security/injection/InjectionScanner.js.map +1 -0
- package/dist/engine/analyzers/security/injection/PatternMatcher.d.ts +25 -0
- package/dist/engine/analyzers/security/injection/PatternMatcher.js +72 -0
- package/dist/engine/analyzers/security/injection/PatternMatcher.js.map +1 -0
- package/dist/engine/analyzers/security/injection/SuppressionChecker.d.ts +17 -0
- package/dist/engine/analyzers/security/injection/SuppressionChecker.js +52 -0
- package/dist/engine/analyzers/security/injection/SuppressionChecker.js.map +1 -0
- package/dist/engine/analyzers/security/injection/patterns/CommandInjectionMatcher.d.ts +9 -0
- package/dist/engine/analyzers/security/injection/patterns/CommandInjectionMatcher.js +54 -0
- package/dist/engine/analyzers/security/injection/patterns/CommandInjectionMatcher.js.map +1 -0
- package/dist/engine/analyzers/security/injection/patterns/DeserializationMatcher.d.ts +9 -0
- package/dist/engine/analyzers/security/injection/patterns/DeserializationMatcher.js +43 -0
- package/dist/engine/analyzers/security/injection/patterns/DeserializationMatcher.js.map +1 -0
- package/dist/engine/analyzers/security/injection/patterns/LDAPXMLMatcher.d.ts +9 -0
- package/dist/engine/analyzers/security/injection/patterns/LDAPXMLMatcher.js +32 -0
- package/dist/engine/analyzers/security/injection/patterns/LDAPXMLMatcher.js.map +1 -0
- package/dist/engine/analyzers/security/injection/patterns/PathTraversalMatcher.d.ts +9 -0
- package/dist/engine/analyzers/security/injection/patterns/PathTraversalMatcher.js +43 -0
- package/dist/engine/analyzers/security/injection/patterns/PathTraversalMatcher.js.map +1 -0
- package/dist/engine/analyzers/security/injection/patterns/SQLInjectionMatcher.d.ts +9 -0
- package/dist/engine/analyzers/security/injection/patterns/SQLInjectionMatcher.js +54 -0
- package/dist/engine/analyzers/security/injection/patterns/SQLInjectionMatcher.js.map +1 -0
- package/dist/engine/analyzers/security/injection/patterns/XSSMatcher.d.ts +9 -0
- package/dist/engine/analyzers/security/injection/patterns/XSSMatcher.js +54 -0
- package/dist/engine/analyzers/security/injection/patterns/XSSMatcher.js.map +1 -0
- package/dist/engine/analyzers/security/ssrf/SSRFDetector.d.ts +16 -0
- package/dist/engine/analyzers/security/ssrf/SSRFDetector.js +89 -0
- package/dist/engine/analyzers/security/ssrf/SSRFDetector.js.map +1 -0
- package/dist/engine/analyzers/security/taint/TaintAnalyzer.d.ts +24 -0
- package/dist/engine/analyzers/security/taint/TaintAnalyzer.js +202 -0
- package/dist/engine/analyzers/security/taint/TaintAnalyzer.js.map +1 -0
- package/dist/engine/analyzers/security/taint/TaintPropagator.d.ts +35 -0
- package/dist/engine/analyzers/security/taint/TaintPropagator.js +223 -0
- package/dist/engine/analyzers/security/taint/TaintPropagator.js.map +1 -0
- package/dist/engine/analyzers/security/taint/TaintRegistry.d.ts +47 -0
- package/dist/engine/analyzers/security/taint/TaintRegistry.js +109 -0
- package/dist/engine/analyzers/security/taint/TaintRegistry.js.map +1 -0
- package/dist/engine/analyzers/security/types.d.ts +291 -0
- package/dist/engine/analyzers/security/types.js +5 -0
- package/dist/engine/analyzers/security/types.js.map +1 -0
- package/dist/engine/analyzers/similarity/ClusterBuilder.d.ts +18 -0
- package/dist/engine/analyzers/similarity/ClusterBuilder.js +66 -0
- package/dist/engine/analyzers/similarity/ClusterBuilder.js.map +1 -0
- package/dist/engine/analyzers/similarity/DeadCodeDetector.d.ts +23 -0
- package/dist/engine/analyzers/similarity/DeadCodeDetector.js +180 -0
- package/dist/engine/analyzers/similarity/DeadCodeDetector.js.map +1 -0
- package/dist/engine/analyzers/similarity/DuplicateDetector.d.ts +22 -0
- package/dist/engine/analyzers/similarity/DuplicateDetector.js +163 -0
- package/dist/engine/analyzers/similarity/DuplicateDetector.js.map +1 -0
- package/dist/engine/analyzers/similarity/GitMiner.d.ts +27 -0
- package/dist/engine/analyzers/similarity/GitMiner.js +184 -0
- package/dist/engine/analyzers/similarity/GitMiner.js.map +1 -0
- package/dist/engine/analyzers/similarity/SimilarityTools.d.ts +125 -0
- package/dist/engine/analyzers/similarity/SimilarityTools.js +156 -0
- package/dist/engine/analyzers/similarity/SimilarityTools.js.map +1 -0
- package/dist/engine/analyzers/similarity/types.d.ts +67 -0
- package/dist/engine/analyzers/similarity/types.js +6 -0
- package/dist/engine/analyzers/similarity/types.js.map +1 -0
- package/dist/engine/config.d.ts +29 -0
- package/dist/engine/config.js +133 -0
- package/dist/engine/config.js.map +1 -0
- package/dist/engine/context/ai-context-service.d.ts +33 -0
- package/dist/engine/context/ai-context-service.js +277 -0
- package/dist/engine/context/ai-context-service.js.map +1 -0
- package/dist/engine/context/budget-allocator.d.ts +16 -0
- package/dist/engine/context/budget-allocator.js +52 -0
- package/dist/engine/context/budget-allocator.js.map +1 -0
- package/dist/engine/context/curated-context-service.d.ts +25 -0
- package/dist/engine/context/curated-context-service.js +217 -0
- package/dist/engine/context/curated-context-service.js.map +1 -0
- package/dist/engine/context/edit-context-service.d.ts +32 -0
- package/dist/engine/context/edit-context-service.js +232 -0
- package/dist/engine/context/edit-context-service.js.map +1 -0
- package/dist/engine/context/git-service.d.ts +12 -0
- package/dist/engine/context/git-service.js +41 -0
- package/dist/engine/context/git-service.js.map +1 -0
- package/dist/engine/context/index.d.ts +14 -0
- package/dist/engine/context/index.js +15 -0
- package/dist/engine/context/index.js.map +1 -0
- package/dist/engine/context/intent-strategies.d.ts +16 -0
- package/dist/engine/context/intent-strategies.js +62 -0
- package/dist/engine/context/intent-strategies.js.map +1 -0
- package/dist/engine/context/query-analyzer.d.ts +8 -0
- package/dist/engine/context/query-analyzer.js +40 -0
- package/dist/engine/context/query-analyzer.js.map +1 -0
- package/dist/engine/context/rrf-merger.d.ts +20 -0
- package/dist/engine/context/rrf-merger.js +46 -0
- package/dist/engine/context/rrf-merger.js.map +1 -0
- package/dist/engine/context/token-budget-manager.d.ts +38 -0
- package/dist/engine/context/token-budget-manager.js +114 -0
- package/dist/engine/context/token-budget-manager.js.map +1 -0
- package/dist/engine/context/types.d.ts +147 -0
- package/dist/engine/context/types.js +5 -0
- package/dist/engine/context/types.js.map +1 -0
- package/dist/engine/database/graph-repository.d.ts +55 -0
- package/dist/engine/database/graph-repository.js +101 -0
- package/dist/engine/database/graph-repository.js.map +1 -0
- package/dist/engine/database/incremental-updater.d.ts +29 -0
- package/dist/engine/database/incremental-updater.js +92 -0
- package/dist/engine/database/incremental-updater.js.map +1 -0
- package/dist/engine/database/index.d.ts +10 -0
- package/dist/engine/database/index.js +9 -0
- package/dist/engine/database/index.js.map +1 -0
- package/dist/engine/database/migrator.d.ts +12 -0
- package/dist/engine/database/migrator.js +132 -0
- package/dist/engine/database/migrator.js.map +1 -0
- package/dist/engine/db/database-manager.d.ts +26 -0
- package/dist/engine/db/database-manager.js +80 -0
- package/dist/engine/db/database-manager.js.map +1 -0
- package/dist/engine/db/migrations.d.ts +9 -0
- package/dist/engine/db/migrations.js +135 -0
- package/dist/engine/db/migrations.js.map +1 -0
- package/dist/engine/db/native-addon-resolver.d.ts +22 -0
- package/dist/engine/db/native-addon-resolver.js +333 -0
- package/dist/engine/db/native-addon-resolver.js.map +1 -0
- package/dist/engine/db/schema.d.ts +5 -0
- package/dist/engine/db/schema.js +122 -0
- package/dist/engine/db/schema.js.map +1 -0
- package/dist/engine/graph/__tests__/graph-services.test.d.ts +5 -0
- package/dist/engine/graph/__tests__/graph-services.test.js +407 -0
- package/dist/engine/graph/__tests__/graph-services.test.js.map +1 -0
- package/dist/engine/graph/call-graph-service.d.ts +44 -0
- package/dist/engine/graph/call-graph-service.js +153 -0
- package/dist/engine/graph/call-graph-service.js.map +1 -0
- package/dist/engine/graph/dependency-formatters.d.ts +16 -0
- package/dist/engine/graph/dependency-formatters.js +76 -0
- package/dist/engine/graph/dependency-formatters.js.map +1 -0
- package/dist/engine/graph/dependency-graph-service.d.ts +39 -0
- package/dist/engine/graph/dependency-graph-service.js +180 -0
- package/dist/engine/graph/dependency-graph-service.js.map +1 -0
- package/dist/engine/graph/file-resolver.d.ts +22 -0
- package/dist/engine/graph/file-resolver.js +92 -0
- package/dist/engine/graph/file-resolver.js.map +1 -0
- package/dist/engine/graph/impact-analysis-service.d.ts +56 -0
- package/dist/engine/graph/impact-analysis-service.js +216 -0
- package/dist/engine/graph/impact-analysis-service.js.map +1 -0
- package/dist/engine/graph/index.d.ts +12 -0
- package/dist/engine/graph/index.js +13 -0
- package/dist/engine/graph/index.js.map +1 -0
- package/dist/engine/graph/symbol-resolver.d.ts +22 -0
- package/dist/engine/graph/symbol-resolver.js +71 -0
- package/dist/engine/graph/symbol-resolver.js.map +1 -0
- package/dist/engine/graph/test-detector.d.ts +19 -0
- package/dist/engine/graph/test-detector.js +56 -0
- package/dist/engine/graph/test-detector.js.map +1 -0
- package/dist/engine/graph/traverser.d.ts +65 -0
- package/dist/engine/graph/traverser.js +171 -0
- package/dist/engine/graph/traverser.js.map +1 -0
- package/dist/engine/indexer/__tests__/tree-sitter-pipeline.test.d.ts +6 -0
- package/dist/engine/indexer/__tests__/tree-sitter-pipeline.test.js +167 -0
- package/dist/engine/indexer/__tests__/tree-sitter-pipeline.test.js.map +1 -0
- package/dist/engine/indexer/file-watcher.d.ts +22 -0
- package/dist/engine/indexer/file-watcher.js +63 -0
- package/dist/engine/indexer/file-watcher.js.map +1 -0
- package/dist/engine/indexer/indexing-engine.d.ts +66 -0
- package/dist/engine/indexer/indexing-engine.js +411 -0
- package/dist/engine/indexer/indexing-engine.js.map +1 -0
- package/dist/engine/parsers/ast-utils.d.ts +31 -0
- package/dist/engine/parsers/ast-utils.js +133 -0
- package/dist/engine/parsers/ast-utils.js.map +1 -0
- package/dist/engine/parsers/embedding/EmbeddingService.d.ts +19 -0
- package/dist/engine/parsers/embedding/EmbeddingService.js +59 -0
- package/dist/engine/parsers/embedding/EmbeddingService.js.map +1 -0
- package/dist/engine/parsers/embedding/body-extractor.d.ts +25 -0
- package/dist/engine/parsers/embedding/body-extractor.js +99 -0
- package/dist/engine/parsers/embedding/body-extractor.js.map +1 -0
- package/dist/engine/parsers/embedding/chunker.d.ts +20 -0
- package/dist/engine/parsers/embedding/chunker.js +53 -0
- package/dist/engine/parsers/embedding/chunker.js.map +1 -0
- package/dist/engine/parsers/embedding/index.d.ts +5 -0
- package/dist/engine/parsers/embedding/index.js +6 -0
- package/dist/engine/parsers/embedding/index.js.map +1 -0
- package/dist/engine/parsers/grammar-registry.d.ts +44 -0
- package/dist/engine/parsers/grammar-registry.js +131 -0
- package/dist/engine/parsers/grammar-registry.js.map +1 -0
- package/dist/engine/parsers/grammars/grammar-config-loader.d.ts +57 -0
- package/dist/engine/parsers/grammars/grammar-config-loader.js +127 -0
- package/dist/engine/parsers/grammars/grammar-config-loader.js.map +1 -0
- package/dist/engine/parsers/ignore/ignore-parser.d.ts +23 -0
- package/dist/engine/parsers/ignore/ignore-parser.js +96 -0
- package/dist/engine/parsers/ignore/ignore-parser.js.map +1 -0
- package/dist/engine/parsers/ignore/index.d.ts +1 -0
- package/dist/engine/parsers/ignore/index.js +2 -0
- package/dist/engine/parsers/ignore/index.js.map +1 -0
- package/dist/engine/parsers/index.d.ts +10 -0
- package/dist/engine/parsers/index.js +9 -0
- package/dist/engine/parsers/index.js.map +1 -0
- package/dist/engine/parsers/languages/__tests__/apex-parser.test.d.ts +6 -0
- package/dist/engine/parsers/languages/__tests__/apex-parser.test.js +225 -0
- package/dist/engine/parsers/languages/__tests__/apex-parser.test.js.map +1 -0
- package/dist/engine/parsers/languages/__tests__/go-parser.test.d.ts +5 -0
- package/dist/engine/parsers/languages/__tests__/go-parser.test.js +243 -0
- package/dist/engine/parsers/languages/__tests__/go-parser.test.js.map +1 -0
- package/dist/engine/parsers/languages/__tests__/java-parser.test.d.ts +5 -0
- package/dist/engine/parsers/languages/__tests__/java-parser.test.js +257 -0
- package/dist/engine/parsers/languages/__tests__/java-parser.test.js.map +1 -0
- package/dist/engine/parsers/languages/__tests__/python-parser.test.d.ts +5 -0
- package/dist/engine/parsers/languages/__tests__/python-parser.test.js +224 -0
- package/dist/engine/parsers/languages/__tests__/python-parser.test.js.map +1 -0
- package/dist/engine/parsers/languages/__tests__/rust-parser.test.d.ts +5 -0
- package/dist/engine/parsers/languages/__tests__/rust-parser.test.js +329 -0
- package/dist/engine/parsers/languages/__tests__/rust-parser.test.js.map +1 -0
- package/dist/engine/parsers/languages/__tests__/salesforce-meta-parser.test.d.ts +6 -0
- package/dist/engine/parsers/languages/__tests__/salesforce-meta-parser.test.js +174 -0
- package/dist/engine/parsers/languages/__tests__/salesforce-meta-parser.test.js.map +1 -0
- package/dist/engine/parsers/languages/apex-parser.d.ts +36 -0
- package/dist/engine/parsers/languages/apex-parser.js +550 -0
- package/dist/engine/parsers/languages/apex-parser.js.map +1 -0
- package/dist/engine/parsers/languages/go-parser.d.ts +31 -0
- package/dist/engine/parsers/languages/go-parser.js +347 -0
- package/dist/engine/parsers/languages/go-parser.js.map +1 -0
- package/dist/engine/parsers/languages/java-parser.d.ts +32 -0
- package/dist/engine/parsers/languages/java-parser.js +538 -0
- package/dist/engine/parsers/languages/java-parser.js.map +1 -0
- package/dist/engine/parsers/languages/kotlin-parser.d.ts +37 -0
- package/dist/engine/parsers/languages/kotlin-parser.js +509 -0
- package/dist/engine/parsers/languages/kotlin-parser.js.map +1 -0
- package/dist/engine/parsers/languages/python-parser.d.ts +28 -0
- package/dist/engine/parsers/languages/python-parser.js +436 -0
- package/dist/engine/parsers/languages/python-parser.js.map +1 -0
- package/dist/engine/parsers/languages/rust-parser.d.ts +34 -0
- package/dist/engine/parsers/languages/rust-parser.js +535 -0
- package/dist/engine/parsers/languages/rust-parser.js.map +1 -0
- package/dist/engine/parsers/languages/salesforce-meta-parser.d.ts +27 -0
- package/dist/engine/parsers/languages/salesforce-meta-parser.js +352 -0
- package/dist/engine/parsers/languages/salesforce-meta-parser.js.map +1 -0
- package/dist/engine/parsers/languages/ts-call-extractor.d.ts +13 -0
- package/dist/engine/parsers/languages/ts-call-extractor.js +136 -0
- package/dist/engine/parsers/languages/ts-call-extractor.js.map +1 -0
- package/dist/engine/parsers/languages/ts-import-extractor.d.ts +10 -0
- package/dist/engine/parsers/languages/ts-import-extractor.js +112 -0
- package/dist/engine/parsers/languages/ts-import-extractor.js.map +1 -0
- package/dist/engine/parsers/languages/ts-inheritance-extractor.d.ts +9 -0
- package/dist/engine/parsers/languages/ts-inheritance-extractor.js +47 -0
- package/dist/engine/parsers/languages/ts-inheritance-extractor.js.map +1 -0
- package/dist/engine/parsers/languages/ts-symbol-extractor.d.ts +18 -0
- package/dist/engine/parsers/languages/ts-symbol-extractor.js +262 -0
- package/dist/engine/parsers/languages/ts-symbol-extractor.js.map +1 -0
- package/dist/engine/parsers/languages/ts-utils.d.ts +24 -0
- package/dist/engine/parsers/languages/ts-utils.js +77 -0
- package/dist/engine/parsers/languages/ts-utils.js.map +1 -0
- package/dist/engine/parsers/languages/typescript-parser.d.ts +17 -0
- package/dist/engine/parsers/languages/typescript-parser.js +60 -0
- package/dist/engine/parsers/languages/typescript-parser.js.map +1 -0
- package/dist/engine/parsers/tree-sitter-indexer.d.ts +28 -0
- package/dist/engine/parsers/tree-sitter-indexer.js +212 -0
- package/dist/engine/parsers/tree-sitter-indexer.js.map +1 -0
- package/dist/engine/parsers/types.d.ts +59 -0
- package/dist/engine/parsers/types.js +6 -0
- package/dist/engine/parsers/types.js.map +1 -0
- package/dist/engine/query/query-layer.d.ts +63 -0
- package/dist/engine/query/query-layer.js +112 -0
- package/dist/engine/query/query-layer.js.map +1 -0
- package/dist/engine/scanner/file-scanner.d.ts +20 -0
- package/dist/engine/scanner/file-scanner.js +151 -0
- package/dist/engine/scanner/file-scanner.js.map +1 -0
- package/dist/engine/scanner/pattern-detector.d.ts +16 -0
- package/dist/engine/scanner/pattern-detector.js +90 -0
- package/dist/engine/scanner/pattern-detector.js.map +1 -0
- package/dist/engine/scanner/signature-extractor.d.ts +17 -0
- package/dist/engine/scanner/signature-extractor.js +148 -0
- package/dist/engine/scanner/signature-extractor.js.map +1 -0
- package/dist/engine/tools/ai-context-tools.d.ts +138 -0
- package/dist/engine/tools/ai-context-tools.js +136 -0
- package/dist/engine/tools/ai-context-tools.js.map +1 -0
- package/dist/engine/tools/call-graph-tools.d.ts +67 -0
- package/dist/engine/tools/call-graph-tools.js +95 -0
- package/dist/engine/tools/call-graph-tools.js.map +1 -0
- package/dist/engine/tools/code-context.d.ts +7 -0
- package/dist/engine/tools/code-context.js +48 -0
- package/dist/engine/tools/code-context.js.map +1 -0
- package/dist/engine/tools/code-index-status.d.ts +8 -0
- package/dist/engine/tools/code-index-status.js +63 -0
- package/dist/engine/tools/code-index-status.js.map +1 -0
- package/dist/engine/tools/code-kb-export.d.ts +7 -0
- package/dist/engine/tools/code-kb-export.js +67 -0
- package/dist/engine/tools/code-kb-export.js.map +1 -0
- package/dist/engine/tools/code-modules.d.ts +6 -0
- package/dist/engine/tools/code-modules.js +52 -0
- package/dist/engine/tools/code-modules.js.map +1 -0
- package/dist/engine/tools/code-search.d.ts +6 -0
- package/dist/engine/tools/code-search.js +31 -0
- package/dist/engine/tools/code-search.js.map +1 -0
- package/dist/engine/tools/code-symbols.d.ts +6 -0
- package/dist/engine/tools/code-symbols.js +48 -0
- package/dist/engine/tools/code-symbols.js.map +1 -0
- package/dist/engine/tools/code-traverse.d.ts +54 -0
- package/dist/engine/tools/code-traverse.js +66 -0
- package/dist/engine/tools/code-traverse.js.map +1 -0
- package/dist/engine/tools/dependency-tools.d.ts +41 -0
- package/dist/engine/tools/dependency-tools.js +46 -0
- package/dist/engine/tools/dependency-tools.js.map +1 -0
- package/dist/engine/tools/drawio-export-png.d.ts +44 -0
- package/dist/engine/tools/drawio-export-png.js +214 -0
- package/dist/engine/tools/drawio-export-png.js.map +1 -0
- package/dist/engine/tools/drawio-layout.d.ts +6 -0
- package/dist/engine/tools/drawio-layout.js +179 -0
- package/dist/engine/tools/drawio-layout.js.map +1 -0
- package/dist/engine/tools/drawio-parser.d.ts +30 -0
- package/dist/engine/tools/drawio-parser.js +92 -0
- package/dist/engine/tools/drawio-parser.js.map +1 -0
- package/dist/engine/tools/drawio-router.d.ts +10 -0
- package/dist/engine/tools/drawio-router.js +112 -0
- package/dist/engine/tools/drawio-router.js.map +1 -0
- package/dist/engine/tools/drawio-tool.d.ts +39 -0
- package/dist/engine/tools/drawio-tool.js +174 -0
- package/dist/engine/tools/drawio-tool.js.map +1 -0
- package/dist/engine/tools/drawio-writer.d.ts +6 -0
- package/dist/engine/tools/drawio-writer.js +120 -0
- package/dist/engine/tools/drawio-writer.js.map +1 -0
- package/dist/engine/tools/impact-tools.d.ts +37 -0
- package/dist/engine/tools/impact-tools.js +85 -0
- package/dist/engine/tools/impact-tools.js.map +1 -0
- package/dist/engine/tools/register-tools.d.ts +862 -0
- package/dist/engine/tools/register-tools.js +226 -0
- package/dist/engine/tools/register-tools.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +98 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +15 -0
- package/dist/logger.js +23 -0
- package/dist/logger.js.map +1 -0
- package/dist/modules/ModuleRegistry.d.ts +23 -0
- package/dist/modules/ModuleRegistry.js +86 -0
- package/dist/modules/ModuleRegistry.js.map +1 -0
- package/dist/modules/analytics/AnalyticsModule.d.ts +17 -0
- package/dist/modules/analytics/AnalyticsModule.js +36 -0
- package/dist/modules/analytics/AnalyticsModule.js.map +1 -0
- package/dist/modules/code-intel/CodeIntelModule.d.ts +23 -0
- package/dist/modules/code-intel/CodeIntelModule.js +73 -0
- package/dist/modules/code-intel/CodeIntelModule.js.map +1 -0
- package/dist/modules/kb-graph/KBGraphModule.d.ts +18 -0
- package/dist/modules/kb-graph/KBGraphModule.js +49 -0
- package/dist/modules/kb-graph/KBGraphModule.js.map +1 -0
- package/dist/modules/kb-graph/SqliteGraphService.d.ts +95 -0
- package/dist/modules/kb-graph/SqliteGraphService.js +417 -0
- package/dist/modules/kb-graph/SqliteGraphService.js.map +1 -0
- package/dist/modules/memory/MemoryDb.d.ts +9 -0
- package/dist/modules/memory/MemoryDb.js +51 -0
- package/dist/modules/memory/MemoryDb.js.map +1 -0
- package/dist/modules/memory/MemoryEngine.d.ts +43 -0
- package/dist/modules/memory/MemoryEngine.js +185 -0
- package/dist/modules/memory/MemoryEngine.js.map +1 -0
- package/dist/modules/memory/MemoryEngineFull.d.ts +0 -0
- package/dist/modules/memory/MemoryEngineFull.js +2 -0
- package/dist/modules/memory/MemoryEngineFull.js.map +1 -0
- package/dist/modules/memory/MemoryModule.d.ts +26 -0
- package/dist/modules/memory/MemoryModule.js +146 -0
- package/dist/modules/memory/MemoryModule.js.map +1 -0
- package/dist/modules/memory/MemoryToolDefinitions.d.ts +2400 -0
- package/dist/modules/memory/MemoryToolDefinitions.js +294 -0
- package/dist/modules/memory/MemoryToolDefinitions.js.map +1 -0
- package/dist/modules/memory/MemoryToolDispatcher.d.ts +50 -0
- package/dist/modules/memory/MemoryToolDispatcher.js +523 -0
- package/dist/modules/memory/MemoryToolDispatcher.js.map +1 -0
- package/dist/modules/memory/ScopePromotionService.d.ts +86 -0
- package/dist/modules/memory/ScopePromotionService.js +263 -0
- package/dist/modules/memory/ScopePromotionService.js.map +1 -0
- package/dist/modules/memory/__tests__/MemoryToolDispatcher.test.d.ts +1 -0
- package/dist/modules/memory/__tests__/MemoryToolDispatcher.test.js +72 -0
- package/dist/modules/memory/__tests__/MemoryToolDispatcher.test.js.map +1 -0
- package/dist/modules/memory/__tests__/ScopePromotionService.test.d.ts +1 -0
- package/dist/modules/memory/__tests__/ScopePromotionService.test.js +142 -0
- package/dist/modules/memory/__tests__/ScopePromotionService.test.js.map +1 -0
- package/dist/modules/memory/llm/LLMService.d.ts +17 -0
- package/dist/modules/memory/llm/LLMService.js +64 -0
- package/dist/modules/memory/llm/LLMService.js.map +1 -0
- package/dist/modules/memory/llm/TagAnalyzerService.d.ts +37 -0
- package/dist/modules/memory/llm/TagAnalyzerService.js +198 -0
- package/dist/modules/memory/llm/TagAnalyzerService.js.map +1 -0
- package/dist/modules/memory/llm/index.d.ts +2 -0
- package/dist/modules/memory/llm/index.js +2 -0
- package/dist/modules/memory/llm/index.js.map +1 -0
- package/dist/modules/memory/llm/ollama-adapter.d.ts +9 -0
- package/dist/modules/memory/llm/ollama-adapter.js +55 -0
- package/dist/modules/memory/llm/ollama-adapter.js.map +1 -0
- package/dist/modules/memory/llm/openai-adapter.d.ts +8 -0
- package/dist/modules/memory/llm/openai-adapter.js +43 -0
- package/dist/modules/memory/llm/openai-adapter.js.map +1 -0
- package/dist/modules/memory/llm/types.d.ts +26 -0
- package/dist/modules/memory/llm/types.js +5 -0
- package/dist/modules/memory/llm/types.js.map +1 -0
- package/dist/modules/memory/masking/MaskingMiddleware.d.ts +23 -0
- package/dist/modules/memory/masking/MaskingMiddleware.js +118 -0
- package/dist/modules/memory/masking/MaskingMiddleware.js.map +1 -0
- package/dist/modules/memory/masking/__tests__/CredentialDetector.test.d.ts +1 -0
- package/dist/modules/memory/masking/__tests__/CredentialDetector.test.js +41 -0
- package/dist/modules/memory/masking/__tests__/CredentialDetector.test.js.map +1 -0
- package/dist/modules/memory/masking/__tests__/MaskingMiddleware.test.d.ts +1 -0
- package/dist/modules/memory/masking/__tests__/MaskingMiddleware.test.js +65 -0
- package/dist/modules/memory/masking/__tests__/MaskingMiddleware.test.js.map +1 -0
- package/dist/modules/memory/masking/__tests__/PiiDetector.test.d.ts +1 -0
- package/dist/modules/memory/masking/__tests__/PiiDetector.test.js +52 -0
- package/dist/modules/memory/masking/__tests__/PiiDetector.test.js.map +1 -0
- package/dist/modules/memory/masking/detectors/CredentialDetector.d.ts +13 -0
- package/dist/modules/memory/masking/detectors/CredentialDetector.js +50 -0
- package/dist/modules/memory/masking/detectors/CredentialDetector.js.map +1 -0
- package/dist/modules/memory/masking/detectors/DetectorStrategy.d.ts +9 -0
- package/dist/modules/memory/masking/detectors/DetectorStrategy.js +2 -0
- package/dist/modules/memory/masking/detectors/DetectorStrategy.js.map +1 -0
- package/dist/modules/memory/masking/detectors/PiiDetector.d.ts +13 -0
- package/dist/modules/memory/masking/detectors/PiiDetector.js +50 -0
- package/dist/modules/memory/masking/detectors/PiiDetector.js.map +1 -0
- package/dist/modules/memory/masking/index.d.ts +8 -0
- package/dist/modules/memory/masking/index.js +9 -0
- package/dist/modules/memory/masking/index.js.map +1 -0
- package/dist/modules/memory/masking/maskers/ContentMasker.d.ts +22 -0
- package/dist/modules/memory/masking/maskers/ContentMasker.js +89 -0
- package/dist/modules/memory/masking/maskers/ContentMasker.js.map +1 -0
- package/dist/modules/memory/masking/models/MaskingTypes.d.ts +73 -0
- package/dist/modules/memory/masking/models/MaskingTypes.js +5 -0
- package/dist/modules/memory/masking/models/MaskingTypes.js.map +1 -0
- package/dist/modules/memory/masking/services/AllowlistService.d.ts +11 -0
- package/dist/modules/memory/masking/services/AllowlistService.js +34 -0
- package/dist/modules/memory/masking/services/AllowlistService.js.map +1 -0
- package/dist/modules/memory/masking/services/AuditService.d.ts +14 -0
- package/dist/modules/memory/masking/services/AuditService.js +39 -0
- package/dist/modules/memory/masking/services/AuditService.js.map +1 -0
- package/dist/modules/memory/masking/services/ConfigCacheService.d.ts +19 -0
- package/dist/modules/memory/masking/services/ConfigCacheService.js +36 -0
- package/dist/modules/memory/masking/services/ConfigCacheService.js.map +1 -0
- package/dist/modules/memory/migrations/001-add-scope-columns.d.ts +9 -0
- package/dist/modules/memory/migrations/001-add-scope-columns.js +16 -0
- package/dist/modules/memory/migrations/001-add-scope-columns.js.map +1 -0
- package/dist/modules/memory/models.d.ts +95 -0
- package/dist/modules/memory/models.js +5 -0
- package/dist/modules/memory/models.js.map +1 -0
- package/dist/modules/memory/schema.d.ts +5 -0
- package/dist/modules/memory/schema.js +269 -0
- package/dist/modules/memory/schema.js.map +1 -0
- package/dist/modules/memory/tool-definitions.d.ts +5 -0
- package/dist/modules/memory/tool-definitions.js +26 -0
- package/dist/modules/memory/tool-definitions.js.map +1 -0
- package/dist/modules/orchestration/McpClientManager.d.ts +18 -0
- package/dist/modules/orchestration/McpClientManager.js +196 -0
- package/dist/modules/orchestration/McpClientManager.js.map +1 -0
- package/dist/modules/orchestration/McpConfigRoutes.d.ts +9 -0
- package/dist/modules/orchestration/McpConfigRoutes.js +123 -0
- package/dist/modules/orchestration/McpConfigRoutes.js.map +1 -0
- package/dist/modules/orchestration/McpConfigService.d.ts +50 -0
- package/dist/modules/orchestration/McpConfigService.js +115 -0
- package/dist/modules/orchestration/McpConfigService.js.map +1 -0
- package/dist/modules/orchestration/OrchestrationModule.d.ts +23 -0
- package/dist/modules/orchestration/OrchestrationModule.js +140 -0
- package/dist/modules/orchestration/OrchestrationModule.js.map +1 -0
- package/dist/modules/utility/UtilityModule.d.ts +18 -0
- package/dist/modules/utility/UtilityModule.js +50 -0
- package/dist/modules/utility/UtilityModule.js.map +1 -0
- package/dist/modules/web/WebModule.d.ts +25 -0
- package/dist/modules/web/WebModule.js +70 -0
- package/dist/modules/web/WebModule.js.map +1 -0
- package/dist/modules/web/handlers/ApiCallHandler.d.ts +16 -0
- package/dist/modules/web/handlers/ApiCallHandler.js +54 -0
- package/dist/modules/web/handlers/ApiCallHandler.js.map +1 -0
- package/dist/modules/web/handlers/DownloadFileHandler.d.ts +18 -0
- package/dist/modules/web/handlers/DownloadFileHandler.js +73 -0
- package/dist/modules/web/handlers/DownloadFileHandler.js.map +1 -0
- package/dist/modules/web/handlers/FetchUrlHandler.d.ts +21 -0
- package/dist/modules/web/handlers/FetchUrlHandler.js +87 -0
- package/dist/modules/web/handlers/FetchUrlHandler.js.map +1 -0
- package/dist/modules/web/handlers/GitBrowseHandler.d.ts +16 -0
- package/dist/modules/web/handlers/GitBrowseHandler.js +73 -0
- package/dist/modules/web/handlers/GitBrowseHandler.js.map +1 -0
- package/dist/modules/web/handlers/ReadWebpageHandler.d.ts +20 -0
- package/dist/modules/web/handlers/ReadWebpageHandler.js +70 -0
- package/dist/modules/web/handlers/ReadWebpageHandler.js.map +1 -0
- package/dist/modules/web/handlers/WebSearchHandler.d.ts +15 -0
- package/dist/modules/web/handlers/WebSearchHandler.js +50 -0
- package/dist/modules/web/handlers/WebSearchHandler.js.map +1 -0
- package/dist/modules/web/middleware/ContentTruncator.d.ts +14 -0
- package/dist/modules/web/middleware/ContentTruncator.js +23 -0
- package/dist/modules/web/middleware/ContentTruncator.js.map +1 -0
- package/dist/modules/web/middleware/RateLimiter.d.ts +19 -0
- package/dist/modules/web/middleware/RateLimiter.js +49 -0
- package/dist/modules/web/middleware/RateLimiter.js.map +1 -0
- package/dist/modules/web/middleware/SsrfGuard.d.ts +18 -0
- package/dist/modules/web/middleware/SsrfGuard.js +89 -0
- package/dist/modules/web/middleware/SsrfGuard.js.map +1 -0
- package/dist/modules/web/models/WebError.d.ts +10 -0
- package/dist/modules/web/models/WebError.js +15 -0
- package/dist/modules/web/models/WebError.js.map +1 -0
- package/dist/modules/web/models/WebModuleConfig.d.ts +17 -0
- package/dist/modules/web/models/WebModuleConfig.js +22 -0
- package/dist/modules/web/models/WebModuleConfig.js.map +1 -0
- package/dist/modules/web/models/WebToolResult.d.ts +7 -0
- package/dist/modules/web/models/WebToolResult.js +19 -0
- package/dist/modules/web/models/WebToolResult.js.map +1 -0
- package/dist/modules/web/utils/GitUrlParser.d.ts +12 -0
- package/dist/modules/web/utils/GitUrlParser.js +32 -0
- package/dist/modules/web/utils/GitUrlParser.js.map +1 -0
- package/dist/modules/web/utils/HtmlExtractor.d.ts +9 -0
- package/dist/modules/web/utils/HtmlExtractor.js +46 -0
- package/dist/modules/web/utils/HtmlExtractor.js.map +1 -0
- package/dist/modules/web/utils/UrlValidator.d.ts +5 -0
- package/dist/modules/web/utils/UrlValidator.js +23 -0
- package/dist/modules/web/utils/UrlValidator.js.map +1 -0
- package/dist/server/HttpServer.d.ts +30 -0
- package/dist/server/HttpServer.js +108 -0
- package/dist/server/HttpServer.js.map +1 -0
- package/dist/server/mcpServer.d.ts +6 -0
- package/dist/server/mcpServer.js +83 -0
- package/dist/server/mcpServer.js.map +1 -0
- package/dist/server/middleware/error-handler.d.ts +7 -0
- package/dist/server/middleware/error-handler.js +16 -0
- package/dist/server/middleware/error-handler.js.map +1 -0
- package/dist/server/middleware/localhost-only.d.ts +6 -0
- package/dist/server/middleware/localhost-only.js +15 -0
- package/dist/server/middleware/localhost-only.js.map +1 -0
- package/dist/server/middleware/rate-limiter.d.ts +11 -0
- package/dist/server/middleware/rate-limiter.js +44 -0
- package/dist/server/middleware/rate-limiter.js.map +1 -0
- package/dist/server/middleware/request-logger.d.ts +7 -0
- package/dist/server/middleware/request-logger.js +21 -0
- package/dist/server/middleware/request-logger.js.map +1 -0
- package/dist/server/routes/__tests__/admin.test.d.ts +8 -0
- package/dist/server/routes/__tests__/admin.test.js +607 -0
- package/dist/server/routes/__tests__/admin.test.js.map +1 -0
- package/dist/server/routes/admin.d.ts +8 -0
- package/dist/server/routes/admin.js +2314 -0
- package/dist/server/routes/admin.js.map +1 -0
- package/dist/server/routes/api.d.ts +9 -0
- package/dist/server/routes/api.js +181 -0
- package/dist/server/routes/api.js.map +1 -0
- package/dist/server/routes/health.d.ts +8 -0
- package/dist/server/routes/health.js +26 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/tools.d.ts +8 -0
- package/dist/server/routes/tools.js +50 -0
- package/dist/server/routes/tools.js.map +1 -0
- package/dist/shared/protocol.d.ts +194 -0
- package/dist/shared/protocol.js +8 -0
- package/dist/shared/protocol.js.map +1 -0
- package/dist/tool-router/ToolDefinitions.d.ts +11 -0
- package/dist/tool-router/ToolDefinitions.js +15 -0
- package/dist/tool-router/ToolDefinitions.js.map +1 -0
- package/dist/tool-router/ToolRouter.d.ts +17 -0
- package/dist/tool-router/ToolRouter.js +53 -0
- package/dist/tool-router/ToolRouter.js.map +1 -0
- package/dist/tool-router/ToolValidator.d.ts +12 -0
- package/dist/tool-router/ToolValidator.js +48 -0
- package/dist/tool-router/ToolValidator.js.map +1 -0
- package/dist/types/module.d.ts +19 -0
- package/dist/types/module.js +6 -0
- package/dist/types/module.js.map +1 -0
- package/dist/types/tool.d.ts +32 -0
- package/dist/types/tool.js +6 -0
- package/dist/types/tool.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/vitest.config.d.ts +2 -0
- package/dist/vitest.config.js +9 -0
- package/dist/vitest.config.js.map +1 -0
- package/dist/vitest.ksa252.config.d.ts +2 -0
- package/dist/vitest.ksa252.config.js +10 -0
- package/dist/vitest.ksa252.config.js.map +1 -0
- package/extension/build-platform-swap.mjs +16 -0
- package/extension/esbuild.js +36 -0
- package/extension/resources/webview-assets/chat/chat.js +1907 -0
- package/extension/resources/webview-assets/chat/graph-viz.js +144 -0
- package/extension/resources/webview-assets/chat/markdown-renderer.js +254 -0
- package/extension/resources/webview-assets/settings/settings.js +575 -0
- package/extension/scripts/capture-screenshots.py +45 -0
- package/extension/scripts/copy-resources.js +75 -0
- package/extension/scripts/gen-checksums.js +68 -0
- package/extension/scripts/update-onnx-manifest.js +119 -0
- package/extension/src/__tests__/converter.test.ts +286 -0
- package/extension/src/__tests__/indexer.test.ts +204 -0
- package/extension/src/addon-download-helpers.ts +135 -0
- package/extension/src/ai-context-commands.ts +97 -0
- package/extension/src/anthropic/__tests__/converter.test.ts +201 -0
- package/extension/src/anthropic/__tests__/handlers.test.ts +255 -0
- package/extension/src/anthropic/converter.ts +95 -0
- package/extension/src/anthropic/handlers.ts +106 -0
- package/extension/src/anthropic/types.ts +124 -0
- package/extension/src/auth/AuthManager.ts +200 -0
- package/extension/src/auth/PkceService.ts +32 -0
- package/extension/src/auth/TokenRefreshTimer.ts +38 -0
- package/extension/src/backend-local-tools.ts +44 -0
- package/extension/src/chat-panel/ChatContextPicker.ts +191 -0
- package/extension/src/chat-panel/ChatHtmlBuilder.ts +67 -0
- package/extension/src/chat-panel/ChatModelManager.ts +49 -0
- package/extension/src/chat-panel/ChatStateManager.ts +129 -0
- package/extension/src/chat-panel/ChatStatusManager.ts +49 -0
- package/extension/src/chat-panel/__tests__/chat-models.test.ts +134 -0
- package/extension/src/chat-panel/__tests__/context-usage-tracker.test.ts +170 -0
- package/extension/src/chat-panel/__tests__/conversation-manager.test.ts +152 -0
- package/extension/src/chat-panel/__tests__/token-counter.test.ts +93 -0
- package/extension/src/chat-panel/chat-models.ts +167 -0
- package/extension/src/chat-panel/chat-panel-provider.ts +221 -0
- package/extension/src/chat-panel/context-usage-tracker.ts +144 -0
- package/extension/src/chat-panel/conversation-manager.ts +180 -0
- package/extension/src/chat-panel/conversation-types.ts +47 -0
- package/extension/src/chat-panel/message-handler.ts +116 -0
- package/extension/src/chat-panel/message-protocol.ts +107 -0
- package/extension/src/chat-panel/message-routing.ts +111 -0
- package/extension/src/chat-panel/token-counter.ts +103 -0
- package/extension/src/checksum.ts +197 -0
- package/extension/src/commands/CommandRegistrar.ts +177 -0
- package/extension/src/commands/LlmCommands.ts +111 -0
- package/extension/src/config-watcher.ts +171 -0
- package/extension/src/config.ts +106 -0
- package/extension/src/connection/ConnectionManager.ts +128 -0
- package/extension/src/connection/HealthChecker.ts +45 -0
- package/extension/src/converter/FileConverterService.ts +62 -0
- package/extension/src/converter/IFileConverter.ts +15 -0
- package/extension/src/converter/LocalFallbackConverter.ts +89 -0
- package/extension/src/converter/RemoteConverter.ts +86 -0
- package/extension/src/converter/TextConverter.ts +41 -0
- package/extension/src/converter/index.ts +31 -0
- package/extension/src/converter-helpers.ts +125 -0
- package/extension/src/converter.ts +17 -0
- package/extension/src/debug-logger.ts +23 -0
- package/extension/src/diagnostics-provider.ts +150 -0
- package/extension/src/extension.ts +187 -0
- package/extension/src/file-utils.ts +64 -0
- package/extension/src/history/conversation.ts +91 -0
- package/extension/src/indexer-discovery.ts +95 -0
- package/extension/src/indexer-http.ts +106 -0
- package/extension/src/indexer.ts +91 -0
- package/extension/src/injector-helpers.ts +72 -0
- package/extension/src/injector.ts +86 -0
- package/extension/src/kb-event-bus.ts +125 -0
- package/extension/src/langgraph/__tests__/anthropic-provider-content-guard.test.ts +95 -0
- package/extension/src/langgraph/__tests__/base-node-retry.test.ts +277 -0
- package/extension/src/langgraph/__tests__/chat-graph-agent-step.test.ts +99 -0
- package/extension/src/langgraph/__tests__/chat-graph-loop.test.ts +155 -0
- package/extension/src/langgraph/__tests__/chat-panel-e2e.test.ts +616 -0
- package/extension/src/langgraph/__tests__/edges-self-correction.test.ts +148 -0
- package/extension/src/langgraph/__tests__/hook-commands.test.ts +203 -0
- package/extension/src/langgraph/__tests__/hook-events.test.ts +273 -0
- package/extension/src/langgraph/__tests__/hook-executor.test.ts +257 -0
- package/extension/src/langgraph/__tests__/hook-loader.test.ts +204 -0
- package/extension/src/langgraph/__tests__/stream-handler-events.test.ts +158 -0
- package/extension/src/langgraph/__tests__/verify-node.test.ts +275 -0
- package/extension/src/langgraph/checkpointer-helpers.ts +78 -0
- package/extension/src/langgraph/checkpointer.ts +83 -0
- package/extension/src/langgraph/config/alternate-strategies.ts +49 -0
- package/extension/src/langgraph/config/verify-criteria.ts +87 -0
- package/extension/src/langgraph/context-budget.ts +194 -0
- package/extension/src/langgraph/edges-feedback.ts +63 -0
- package/extension/src/langgraph/edges.ts +137 -0
- package/extension/src/langgraph/engine-chat-handler.ts +66 -0
- package/extension/src/langgraph/errors/non-recoverable-error.ts +13 -0
- package/extension/src/langgraph/graph-builder.ts +36 -0
- package/extension/src/langgraph/graphs/GraphFactory.ts +85 -0
- package/extension/src/langgraph/graphs/chat-graph-nodes.ts +285 -0
- package/extension/src/langgraph/graphs/chat-graph.ts +177 -0
- package/extension/src/langgraph/graphs/code-review-graph.ts +112 -0
- package/extension/src/langgraph/graphs/docs-graph.ts +89 -0
- package/extension/src/langgraph/graphs/hotfix-graph.ts +106 -0
- package/extension/src/langgraph/graphs/rag-grader-nodes.ts +237 -0
- package/extension/src/langgraph/graphs/rag-grader-prompts.ts +54 -0
- package/extension/src/langgraph/graphs/sdlc-graph.ts +132 -0
- package/extension/src/langgraph/graphs/sdlc-node-factory.ts +72 -0
- package/extension/src/langgraph/graphs/security-audit-graph.ts +98 -0
- package/extension/src/langgraph/graphs/verify-node.ts +161 -0
- package/extension/src/langgraph/graphs/verify-prompt.ts +45 -0
- package/extension/src/langgraph/hook-commands.ts +84 -0
- package/extension/src/langgraph/hook-emitter.ts +37 -0
- package/extension/src/langgraph/hook-engine.ts +171 -0
- package/extension/src/langgraph/hook-events.ts +195 -0
- package/extension/src/langgraph/hook-executor.ts +192 -0
- package/extension/src/langgraph/hook-filters.ts +94 -0
- package/extension/src/langgraph/hook-loader.ts +86 -0
- package/extension/src/langgraph/hook-tool-matcher.ts +64 -0
- package/extension/src/langgraph/index.ts +69 -0
- package/extension/src/langgraph/langgraph-engine.ts +190 -0
- package/extension/src/langgraph/llm-provider.ts +83 -0
- package/extension/src/langgraph/mcp-bridge.ts +118 -0
- package/extension/src/langgraph/nodes/agent-prompt-loader.ts +84 -0
- package/extension/src/langgraph/nodes/approval-node.ts +165 -0
- package/extension/src/langgraph/nodes/ba-node.ts +58 -0
- package/extension/src/langgraph/nodes/ba-prompts.ts +40 -0
- package/extension/src/langgraph/nodes/base-node.ts +198 -0
- package/extension/src/langgraph/nodes/dev-node.ts +77 -0
- package/extension/src/langgraph/nodes/dev-prompts.ts +23 -0
- package/extension/src/langgraph/nodes/devops-node.ts +180 -0
- package/extension/src/langgraph/nodes/feedback-node.ts +68 -0
- package/extension/src/langgraph/nodes/hook-helpers.ts +122 -0
- package/extension/src/langgraph/nodes/jira-helpers.ts +86 -0
- package/extension/src/langgraph/nodes/qa-node.ts +82 -0
- package/extension/src/langgraph/nodes/qa-prompts.ts +35 -0
- package/extension/src/langgraph/nodes/sa-node.ts +152 -0
- package/extension/src/langgraph/nodes/security-node.ts +94 -0
- package/extension/src/langgraph/nodes/sm-node.ts +35 -0
- package/extension/src/langgraph/nodes/ta-node.ts +113 -0
- package/extension/src/langgraph/nodes/ui-node.ts +93 -0
- package/extension/src/langgraph/nodes/verify-node.ts +158 -0
- package/extension/src/langgraph/nodes/workspace-file-ops.ts +155 -0
- package/extension/src/langgraph/providers/BaseLlmProvider.ts +113 -0
- package/extension/src/langgraph/providers/anthropic-adapter.ts +165 -0
- package/extension/src/langgraph/providers/anthropic-helpers.ts +26 -0
- package/extension/src/langgraph/providers/anthropic-provider.ts +142 -0
- package/extension/src/langgraph/providers/index.ts +114 -0
- package/extension/src/langgraph/providers/kiro-client.ts +151 -0
- package/extension/src/langgraph/providers/kiro-http-helpers.ts +93 -0
- package/extension/src/langgraph/providers/model-parser.ts +33 -0
- package/extension/src/langgraph/providers/model-registry.ts +98 -0
- package/extension/src/langgraph/providers/ollama-provider.ts +114 -0
- package/extension/src/langgraph/providers/ollama-tools.ts +52 -0
- package/extension/src/langgraph/providers/onnx-provider.ts +151 -0
- package/extension/src/langgraph/providers/onnx-tokenizer.ts +47 -0
- package/extension/src/langgraph/providers/openai-helpers.ts +38 -0
- package/extension/src/langgraph/providers/openai-provider.ts +168 -0
- package/extension/src/langgraph/providers/stream-handler.ts +187 -0
- package/extension/src/langgraph/providers/token-manager.ts +180 -0
- package/extension/src/langgraph/providers/token-refresh.ts +94 -0
- package/extension/src/langgraph/router/intent-classifier.ts +131 -0
- package/extension/src/langgraph/router/router-graph.ts +187 -0
- package/extension/src/langgraph/router/router-state.ts +19 -0
- package/extension/src/langgraph/state-types.ts +21 -0
- package/extension/src/langgraph/state.ts +61 -0
- package/extension/src/langgraph/steering-loader.ts +192 -0
- package/extension/src/langgraph/stream-handler.ts +185 -0
- package/extension/src/langgraph/tool-registry.ts +85 -0
- package/extension/src/langgraph/vscode-tool-definitions.ts +44 -0
- package/extension/src/langgraph/vscode-tools.ts +146 -0
- package/extension/src/langgraph/workflow-executor-actions.ts +144 -0
- package/extension/src/langgraph/workflow-executor.ts +87 -0
- package/extension/src/langgraph/workflow-graph-data.ts +132 -0
- package/extension/src/langgraph/workflow-parser-actions.ts +87 -0
- package/extension/src/langgraph/workflow-parser.ts +74 -0
- package/extension/src/logger.ts +34 -0
- package/extension/src/mcp-config-builder.ts +118 -0
- package/extension/src/mcp-injector.ts +68 -0
- package/extension/src/mcp-server-manager.ts +24 -0
- package/extension/src/models/LlmProviderConfig.ts +25 -0
- package/extension/src/models/LlmTestResult.ts +9 -0
- package/extension/src/models/SettingsState.ts +16 -0
- package/extension/src/models/index.ts +3 -0
- package/extension/src/native-addon-manager.ts +194 -0
- package/extension/src/panels/analytics-panel.ts +31 -0
- package/extension/src/panels/base-panel.ts +95 -0
- package/extension/src/panels/dashboard-panel.ts +29 -0
- package/extension/src/panels/graph-panel.ts +27 -0
- package/extension/src/panels/impact-panel.ts +167 -0
- package/extension/src/panels/login-panel.ts +100 -0
- package/extension/src/panels/panel-html.ts +124 -0
- package/extension/src/panels/quality-panel.ts +31 -0
- package/extension/src/panels/security-panel.ts +162 -0
- package/extension/src/panels/settings/SettingsMessageHandler.ts +190 -0
- package/extension/src/panels/settings/SettingsPanel.ts +121 -0
- package/extension/src/panels/settings-panel.ts +10 -0
- package/extension/src/panels/tags-panel.ts +31 -0
- package/extension/src/panels/workflow-panel.ts +80 -0
- package/extension/src/platform-swap/backup-manager.ts +156 -0
- package/extension/src/platform-swap/index.ts +62 -0
- package/extension/src/platform-swap/platform-config.ts +84 -0
- package/extension/src/platform-swap/platform-detector.ts +90 -0
- package/extension/src/platform-swap/platform-status-bar.ts +71 -0
- package/extension/src/platform-swap/state-manager.ts +101 -0
- package/extension/src/platform-swap/swap-commands.ts +161 -0
- package/extension/src/platform-swap/swap-executor.ts +193 -0
- package/extension/src/platform-swap/types.ts +68 -0
- package/extension/src/proxy/HttpClient.ts +120 -0
- package/extension/src/proxy/ToolProxy.ts +58 -0
- package/extension/src/remote-backend-client.ts +185 -0
- package/extension/src/services/IndexerHttpClient.ts +129 -0
- package/extension/src/services/IndexingService.ts +101 -0
- package/extension/src/services/LlmTestService.ts +96 -0
- package/extension/src/services/ProviderConfigService.ts +85 -0
- package/extension/src/services/WorkspaceSyncService.ts +48 -0
- package/extension/src/sf-indexer.ts +85 -0
- package/extension/src/sidebar/tree-view-provider.ts +173 -0
- package/extension/src/symbol-search.ts +135 -0
- package/extension/src/test/base-panel.test.ts +168 -0
- package/extension/src/test/mcp-server-manager.test.ts +322 -0
- package/extension/src/test/mocks/vscode.ts +148 -0
- package/extension/src/test/setup.ts +18 -0
- package/extension/src/test/tree-view-provider.test.ts +208 -0
- package/extension/src/test/webview-panel-manager.test.ts +160 -0
- package/extension/src/types/index.ts +6 -0
- package/extension/src/types/panel-types.ts +81 -0
- package/extension/src/types/server-types.ts +96 -0
- package/extension/src/types.ts +5 -0
- package/extension/src/ui/status-bar.ts +55 -0
- package/extension/src/webview/__tests__/integration.test.ts +341 -0
- package/extension/src/webview/__tests__/options.integration.test.ts +269 -0
- package/extension/src/webview/__tests__/options.pbt.test.ts +222 -0
- package/extension/src/webview/__tests__/options.unit.test.ts +413 -0
- package/extension/src/webview/__tests__/pbt.test.ts +251 -0
- package/extension/src/webview/__tests__/slash-menu.integration.test.ts +259 -0
- package/extension/src/webview/__tests__/slash-menu.pbt.test.ts +229 -0
- package/extension/src/webview/__tests__/slash-menu.unit.test.ts +244 -0
- package/extension/src/webview/__tests__/spinner.integration.test.ts +214 -0
- package/extension/src/webview/__tests__/spinner.pbt.test.ts +151 -0
- package/extension/src/webview/__tests__/spinner.unit.test.ts +263 -0
- package/extension/src/webview/__tests__/unit-part2.test.ts +377 -0
- package/extension/src/webview/__tests__/unit.test.ts +101 -0
- package/extension/src/webview/badges/BadgeManager.ts +94 -0
- package/extension/src/webview/badges/BadgeRenderer.ts +66 -0
- package/extension/src/webview/badges/types.ts +12 -0
- package/extension/src/webview/bridge/MessageBridge.ts +107 -0
- package/extension/src/webview/bridge/types.ts +15 -0
- package/extension/src/webview/context-menu/ContextMenuController.ts +275 -0
- package/extension/src/webview/context-menu/ContextMenuItems.ts +72 -0
- package/extension/src/webview/context-menu/ContextMenuView.ts +154 -0
- package/extension/src/webview/context-menu/FilePicker.ts +100 -0
- package/extension/src/webview/context-menu/FolderPicker.ts +98 -0
- package/extension/src/webview/context-menu/FuzzyFilter.ts +67 -0
- package/extension/src/webview/context-menu/ListPicker.ts +172 -0
- package/extension/src/webview/context-menu/PickerPanel.ts +205 -0
- package/extension/src/webview/context-menu/types.ts +49 -0
- package/extension/src/webview/graph/lod/BudgetManager.ts +53 -0
- package/extension/src/webview/graph/lod/ClusteringAlgorithm.ts +186 -0
- package/extension/src/webview/graph/lod/DistanceChecker.ts +51 -0
- package/extension/src/webview/graph/lod/LODManager.ts +177 -0
- package/extension/src/webview/graph/lod/OrbitalLayout.ts +52 -0
- package/extension/src/webview/graph/lod/__tests__/lod.test.ts +269 -0
- package/extension/src/webview/graph/lod/clustering-helpers.ts +62 -0
- package/extension/src/webview/graph/lod/config.ts +36 -0
- package/extension/src/webview/graph/lod/index.ts +25 -0
- package/extension/src/webview/graph/lod/types.ts +91 -0
- package/extension/src/webview/input/InputAreaIntegration.ts +408 -0
- package/extension/src/webview/options/OptionsController.ts +203 -0
- package/extension/src/webview/options/OptionsView.ts +169 -0
- package/extension/src/webview/options/types.ts +42 -0
- package/extension/src/webview/protocol.ts +134 -0
- package/extension/src/webview/slash-menu/SlashMenuController.ts +249 -0
- package/extension/src/webview/slash-menu/SlashMenuItems.ts +89 -0
- package/extension/src/webview/slash-menu/SlashMenuView.ts +216 -0
- package/extension/src/webview/slash-menu/types.ts +61 -0
- package/extension/src/webview/spinner/SpinnerController.ts +114 -0
- package/extension/src/webview/spinner/SpinnerView.ts +67 -0
- package/extension/src/webview/spinner/types.ts +35 -0
- package/extension/src/webview-panel-manager.ts +117 -0
- package/extension/vitest.config.ts +10 -0
- package/extension/webview-assets/3d-force-graph.min.js +5 -0
- package/extension/webview-assets/analytics.js +174 -0
- package/extension/webview-assets/chart.min.js +14 -0
- package/extension/webview-assets/chat/chat.js +1907 -0
- package/extension/webview-assets/chat/graph-viz.js +144 -0
- package/extension/webview-assets/chat/markdown-renderer.js +254 -0
- package/extension/webview-assets/dashboard.js +246 -0
- package/extension/webview-assets/graph.js +636 -0
- package/extension/webview-assets/quality.js +203 -0
- package/extension/webview-assets/settings/settings.css +391 -0
- package/extension/webview-assets/settings/settings.js +575 -0
- package/extension/webview-assets/tags.js +182 -0
- package/extension/webview-assets/three.min.js +6 -0
- package/extension/webview-assets/workflow-graph.js +108 -0
- package/package.json +61 -0
- package/scripts/debug/check_tools.js +76 -0
- package/scripts/debug/clear_graph.cjs +12 -0
- package/scripts/debug/fetch_ticket.mjs +18 -0
- package/scripts/debug/get-jira.js +27 -0
- package/scripts/debug/get_tools.js +14 -0
- package/scripts/debug/inject_all_logs.js +15 -0
- package/scripts/debug/inject_debug.js +14 -0
- package/scripts/debug/inject_error.js +14 -0
- package/scripts/debug/migrate-db-types.js +91 -0
- package/scripts/debug/read-ksa-295.mjs +15 -0
- package/scripts/debug/scratch.cjs +17 -0
- package/scripts/debug/scratch_admin.cjs +11 -0
- package/scripts/debug/sm-discovery.mjs +33 -0
- package/scripts/debug/test-atlassian-endpoints.js +32 -0
- package/scripts/debug/test-convert.js +33 -0
- package/scripts/debug/test-db-debug.cjs +24 -0
- package/scripts/debug/test-db.js +22 -0
- package/scripts/debug/test-find-tools.mjs +32 -0
- package/scripts/debug/test-mcp-sdk.js +28 -0
- package/scripts/debug/test-post.js +31 -0
- package/scripts/debug/test-stream.mjs +57 -0
- package/scripts/debug/test-ws.js +25 -0
- package/scripts/debug/test.js +12 -0
- package/scripts/debug/test2.ts +9 -0
- package/scripts/debug/test_activate.js +130 -0
- package/scripts/debug/test_api.py +19 -0
- package/scripts/debug/tmp-jira-call.js +38 -0
- package/src/admin/__tests__/admin-db.test.ts +450 -0
- package/src/admin/admin-db.ts +1134 -0
- package/src/admin/index.ts +83 -0
- package/src/admin/middleware/audit.middleware.ts +60 -0
- package/src/admin/middleware/rate-limit.middleware.ts +48 -0
- package/src/admin/middleware/rbac.middleware.ts +116 -0
- package/src/admin/routes/analytics.router.ts +60 -0
- package/src/admin/routes/audit.router.ts +28 -0
- package/src/admin/routes/config.router.ts +23 -0
- package/src/admin/routes/dashboard.router.ts +14 -0
- package/src/admin/routes/helpers.ts +15 -0
- package/src/admin/routes/kb-admin.router.ts +42 -0
- package/src/admin/routes/mcp-admin.router.ts +34 -0
- package/src/admin/routes/rbac.router.ts +53 -0
- package/src/admin/routes/search.router.ts +24 -0
- package/src/admin/routes/user.router.ts +40 -0
- package/src/admin/services/audit.service.ts +29 -0
- package/src/admin/services/config.service.ts +28 -0
- package/src/admin/services/dashboard.service.ts +46 -0
- package/src/admin/services/kb-admin.service.ts +65 -0
- package/src/admin/services/mcp-admin.service.ts +42 -0
- package/src/admin/services/rbac.service.ts +99 -0
- package/src/admin/services/search.service.ts +47 -0
- package/src/admin/services/sse.manager.ts +41 -0
- package/src/admin/services/user.service.ts +55 -0
- package/src/admin/standalone-server.ts +105 -0
- package/src/admin/types/admin.types.ts +185 -0
- package/src/admin/types/api.types.ts +66 -0
- package/src/admin/types/rbac.types.ts +111 -0
- package/src/config/BackendConfig.ts +48 -0
- package/src/engine/analyzers/complexity/ComplexityAnalyzer.ts +115 -0
- package/src/engine/analyzers/complexity/ComplexityCalculator.ts +65 -0
- package/src/engine/analyzers/complexity/ComplexityStore.ts +177 -0
- package/src/engine/analyzers/complexity/ComplexityTool.ts +71 -0
- package/src/engine/analyzers/complexity/GradeAssigner.ts +34 -0
- package/src/engine/analyzers/complexity/counters/BaseNodeCounter.ts +94 -0
- package/src/engine/analyzers/complexity/counters/GoCounter.ts +34 -0
- package/src/engine/analyzers/complexity/counters/JavaCounter.ts +31 -0
- package/src/engine/analyzers/complexity/counters/KotlinCounter.ts +37 -0
- package/src/engine/analyzers/complexity/counters/PythonCounter.ts +38 -0
- package/src/engine/analyzers/complexity/counters/TypeScriptCounter.ts +34 -0
- package/src/engine/analyzers/complexity/index.ts +25 -0
- package/src/engine/analyzers/complexity/types.ts +62 -0
- package/src/engine/analyzers/entry-points/EntryPointDetector.ts +76 -0
- package/src/engine/analyzers/entry-points/EntryPointStore.ts +162 -0
- package/src/engine/analyzers/entry-points/EntryPointTool.ts +63 -0
- package/src/engine/analyzers/entry-points/FrameworkDetector.ts +57 -0
- package/src/engine/analyzers/entry-points/PatternRegistry.ts +114 -0
- package/src/engine/analyzers/entry-points/RouteResolver.ts +44 -0
- package/src/engine/analyzers/entry-points/detectors/CLIDetector.ts +48 -0
- package/src/engine/analyzers/entry-points/detectors/EventDetector.ts +77 -0
- package/src/engine/analyzers/entry-points/detectors/HTTPHandlerDetector.ts +158 -0
- package/src/engine/analyzers/entry-points/detectors/MainDetector.ts +64 -0
- package/src/engine/analyzers/entry-points/index.ts +23 -0
- package/src/engine/analyzers/entry-points/types.ts +74 -0
- package/src/engine/analyzers/graph-analysis/CircularDepDetector.ts +93 -0
- package/src/engine/analyzers/graph-analysis/DeadImportDetector.ts +70 -0
- package/src/engine/analyzers/graph-analysis/GraphAnalysisTools.ts +202 -0
- package/src/engine/analyzers/graph-analysis/HotPathAnalyzer.ts +67 -0
- package/src/engine/analyzers/graph-analysis/ModuleSummarizer.ts +72 -0
- package/src/engine/analyzers/graph-analysis/RelatedTestFinder.ts +97 -0
- package/src/engine/analyzers/graph-analysis/index.ts +23 -0
- package/src/engine/analyzers/graph-analysis/types.ts +73 -0
- package/src/engine/analyzers/graph-analysis/utils/GraphLoader.ts +149 -0
- package/src/engine/analyzers/graph-analysis/utils/TarjanSCC.ts +65 -0
- package/src/engine/analyzers/graph-analysis/utils/TestFileDetector.ts +35 -0
- package/src/engine/analyzers/security/cfg/BasicBlock.ts +130 -0
- package/src/engine/analyzers/security/cfg/CFGBuilder.ts +266 -0
- package/src/engine/analyzers/security/cfg/CFGEdge.ts +24 -0
- package/src/engine/analyzers/security/cfg/ControlFlowGraph.ts +102 -0
- package/src/engine/analyzers/security/dataflow/DataFlowAnalyzer.ts +78 -0
- package/src/engine/analyzers/security/dataflow/ReachingDefinitions.ts +91 -0
- package/src/engine/analyzers/security/idor/IDORDetector.ts +143 -0
- package/src/engine/analyzers/security/injection/InjectionScanner.ts +164 -0
- package/src/engine/analyzers/security/injection/PatternMatcher.ts +85 -0
- package/src/engine/analyzers/security/injection/SuppressionChecker.ts +65 -0
- package/src/engine/analyzers/security/injection/patterns/CommandInjectionMatcher.ts +56 -0
- package/src/engine/analyzers/security/injection/patterns/DeserializationMatcher.ts +45 -0
- package/src/engine/analyzers/security/injection/patterns/LDAPXMLMatcher.ts +34 -0
- package/src/engine/analyzers/security/injection/patterns/PathTraversalMatcher.ts +45 -0
- package/src/engine/analyzers/security/injection/patterns/SQLInjectionMatcher.ts +56 -0
- package/src/engine/analyzers/security/injection/patterns/XSSMatcher.ts +56 -0
- package/src/engine/analyzers/security/ssrf/SSRFDetector.ts +103 -0
- package/src/engine/analyzers/security/taint/TaintAnalyzer.ts +230 -0
- package/src/engine/analyzers/security/taint/TaintPropagator.ts +250 -0
- package/src/engine/analyzers/security/taint/TaintRegistry.ts +139 -0
- package/src/engine/analyzers/security/types.ts +326 -0
- package/src/engine/analyzers/similarity/ClusterBuilder.ts +68 -0
- package/src/engine/analyzers/similarity/DeadCodeDetector.ts +227 -0
- package/src/engine/analyzers/similarity/DuplicateDetector.ts +211 -0
- package/src/engine/analyzers/similarity/GitMiner.ts +227 -0
- package/src/engine/analyzers/similarity/SimilarityTools.ts +181 -0
- package/src/engine/analyzers/similarity/types.ts +76 -0
- package/src/engine/config.ts +153 -0
- package/src/engine/context/ai-context-service.ts +302 -0
- package/src/engine/context/budget-allocator.ts +66 -0
- package/src/engine/context/curated-context-service.ts +268 -0
- package/src/engine/context/edit-context-service.ts +279 -0
- package/src/engine/context/git-service.ts +48 -0
- package/src/engine/context/index.ts +15 -0
- package/src/engine/context/intent-strategies.ts +75 -0
- package/src/engine/context/query-analyzer.ts +49 -0
- package/src/engine/context/rrf-merger.ts +63 -0
- package/src/engine/context/token-budget-manager.ts +129 -0
- package/src/engine/context/types.ts +164 -0
- package/src/engine/database/graph-repository.ts +166 -0
- package/src/engine/database/incremental-updater.ts +117 -0
- package/src/engine/database/index.ts +13 -0
- package/src/engine/database/migrations/002-graph-schema.sql +24 -0
- package/src/engine/database/migrator.ts +148 -0
- package/src/engine/db/database-manager.ts +89 -0
- package/src/engine/db/migrations.ts +159 -0
- package/src/engine/db/native-addon-resolver.ts +386 -0
- package/src/engine/db/schema.ts +123 -0
- package/src/engine/graph/__tests__/graph-services.test.ts +476 -0
- package/src/engine/graph/call-graph-service.ts +216 -0
- package/src/engine/graph/dependency-formatters.ts +95 -0
- package/src/engine/graph/dependency-graph-service.ts +236 -0
- package/src/engine/graph/file-resolver.ts +102 -0
- package/src/engine/graph/impact-analysis-service.ts +293 -0
- package/src/engine/graph/index.ts +13 -0
- package/src/engine/graph/symbol-resolver.ts +90 -0
- package/src/engine/graph/test-detector.ts +77 -0
- package/src/engine/graph/traverser.ts +237 -0
- package/src/engine/indexer/__tests__/tree-sitter-pipeline.test.ts +205 -0
- package/src/engine/indexer/file-watcher.ts +77 -0
- package/src/engine/indexer/indexing-engine.ts +468 -0
- package/src/engine/parsers/ast-utils.ts +140 -0
- package/src/engine/parsers/embedding/EmbeddingService.ts +64 -0
- package/src/engine/parsers/embedding/body-extractor.ts +123 -0
- package/src/engine/parsers/embedding/chunker.ts +71 -0
- package/src/engine/parsers/embedding/index.ts +6 -0
- package/src/engine/parsers/grammar-config.json +58 -0
- package/src/engine/parsers/grammar-registry.ts +162 -0
- package/src/engine/parsers/grammars/config-schema.json +1 -0
- package/src/engine/parsers/grammars/grammar-config-loader.ts +192 -0
- package/src/engine/parsers/grammars/tree-sitter-apex.wasm +0 -0
- package/src/engine/parsers/grammars/tree-sitter-go.wasm +0 -0
- package/src/engine/parsers/grammars/tree-sitter-java.wasm +0 -0
- package/src/engine/parsers/grammars/tree-sitter-javascript.wasm +0 -0
- package/src/engine/parsers/grammars/tree-sitter-python.wasm +0 -0
- package/src/engine/parsers/grammars/tree-sitter-rust.wasm +0 -0
- package/src/engine/parsers/grammars/tree-sitter-typescript.wasm +0 -0
- package/src/engine/parsers/grammars/typescript.grammar.json +67 -0
- package/src/engine/parsers/ignore/ignore-parser.ts +112 -0
- package/src/engine/parsers/ignore/index.ts +1 -0
- package/src/engine/parsers/index.ts +17 -0
- package/src/engine/parsers/languages/__tests__/apex-parser.test.ts +253 -0
- package/src/engine/parsers/languages/__tests__/fixtures/Annotations.java +57 -0
- package/src/engine/parsers/languages/__tests__/fixtures/SimpleClass.java +72 -0
- package/src/engine/parsers/languages/__tests__/fixtures/UserController.java +57 -0
- package/src/engine/parsers/languages/__tests__/fixtures/UserService.java +72 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/ClassWithDML.cls +17 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/ClassWithMethods.cls +24 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/ClassWithSOQL.cls +9 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/InheritanceExample.cls +18 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/InterfaceExample.cls +5 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/MalformedClass.cls +5 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/SimpleClass.cls +2 -0
- package/src/engine/parsers/languages/__tests__/fixtures/apex/TriggerExample.trigger +8 -0
- package/src/engine/parsers/languages/__tests__/fixtures/protocol-class.py +63 -0
- package/src/engine/parsers/languages/__tests__/fixtures/salesforce-meta/CustomObject.object-meta.xml +21 -0
- package/src/engine/parsers/languages/__tests__/fixtures/salesforce-meta/LWCMeta.js-meta.xml +9 -0
- package/src/engine/parsers/languages/__tests__/fixtures/salesforce-meta/LookupField.field-meta.xml +7 -0
- package/src/engine/parsers/languages/__tests__/fixtures/salesforce-meta/SimpleFlow.flow-meta.xml +32 -0
- package/src/engine/parsers/languages/__tests__/fixtures/simple-function.py +57 -0
- package/src/engine/parsers/languages/__tests__/fixtures/simple.go +55 -0
- package/src/engine/parsers/languages/__tests__/fixtures/simple.rs +109 -0
- package/src/engine/parsers/languages/__tests__/go-parser.test.ts +254 -0
- package/src/engine/parsers/languages/__tests__/java-parser.test.ts +296 -0
- package/src/engine/parsers/languages/__tests__/python-parser.test.ts +256 -0
- package/src/engine/parsers/languages/__tests__/rust-parser.test.ts +354 -0
- package/src/engine/parsers/languages/__tests__/salesforce-meta-parser.test.ts +216 -0
- package/src/engine/parsers/languages/apex-parser.ts +665 -0
- package/src/engine/parsers/languages/go-parser.ts +429 -0
- package/src/engine/parsers/languages/java-parser.ts +651 -0
- package/src/engine/parsers/languages/kotlin-parser.ts +624 -0
- package/src/engine/parsers/languages/python-parser.ts +502 -0
- package/src/engine/parsers/languages/rust-parser.ts +644 -0
- package/src/engine/parsers/languages/salesforce-meta-parser.ts +404 -0
- package/src/engine/parsers/languages/ts-call-extractor.ts +155 -0
- package/src/engine/parsers/languages/ts-import-extractor.ts +132 -0
- package/src/engine/parsers/languages/ts-inheritance-extractor.ts +54 -0
- package/src/engine/parsers/languages/ts-symbol-extractor.ts +319 -0
- package/src/engine/parsers/languages/ts-utils.ts +88 -0
- package/src/engine/parsers/languages/typescript-parser.ts +72 -0
- package/src/engine/parsers/tree-sitter-indexer.ts +263 -0
- package/src/engine/parsers/types.ts +78 -0
- package/src/engine/query/query-layer.ts +177 -0
- package/src/engine/scanner/file-scanner.ts +173 -0
- package/src/engine/scanner/pattern-detector.ts +112 -0
- package/src/engine/scanner/signature-extractor.ts +173 -0
- package/src/engine/tools/ai-context-tools.ts +155 -0
- package/src/engine/tools/call-graph-tools.ts +109 -0
- package/src/engine/tools/code-context.ts +70 -0
- package/src/engine/tools/code-index-status.ts +85 -0
- package/src/engine/tools/code-kb-export.ts +84 -0
- package/src/engine/tools/code-modules.ts +53 -0
- package/src/engine/tools/code-search.ts +39 -0
- package/src/engine/tools/code-symbols.ts +53 -0
- package/src/engine/tools/code-traverse.ts +75 -0
- package/src/engine/tools/dependency-tools.ts +54 -0
- package/src/engine/tools/drawio-export-png.ts +272 -0
- package/src/engine/tools/drawio-layout.ts +143 -0
- package/src/engine/tools/drawio-parser.ts +118 -0
- package/src/engine/tools/drawio-router.ts +112 -0
- package/src/engine/tools/drawio-tool.ts +167 -0
- package/src/engine/tools/drawio-writer.ts +133 -0
- package/src/engine/tools/impact-tools.ts +97 -0
- package/src/engine/tools/register-tools.ts +230 -0
- package/src/index.ts +131 -0
- package/src/logger.ts +34 -0
- package/src/modules/ModuleRegistry.ts +106 -0
- package/src/modules/analytics/AnalyticsModule.ts +49 -0
- package/src/modules/code-intel/CodeIntelModule.ts +84 -0
- package/src/modules/kb-graph/KBGraphModule.ts +63 -0
- package/src/modules/kb-graph/SqliteGraphService.ts +488 -0
- package/src/modules/memory/MemoryDb.ts +53 -0
- package/src/modules/memory/MemoryEngine.ts +239 -0
- package/src/modules/memory/MemoryEngineFull.ts +0 -0
- package/src/modules/memory/MemoryModule.ts +163 -0
- package/src/modules/memory/MemoryToolDefinitions.ts +301 -0
- package/src/modules/memory/MemoryToolDispatcher.ts +488 -0
- package/src/modules/memory/ScopePromotionService.ts +339 -0
- package/src/modules/memory/__tests__/MemoryToolDispatcher.test.ts +85 -0
- package/src/modules/memory/__tests__/ScopePromotionService.test.ts +160 -0
- package/src/modules/memory/llm/LLMService.ts +75 -0
- package/src/modules/memory/llm/TagAnalyzerService.ts +255 -0
- package/src/modules/memory/llm/index.ts +2 -0
- package/src/modules/memory/llm/ollama-adapter.ts +60 -0
- package/src/modules/memory/llm/openai-adapter.ts +44 -0
- package/src/modules/memory/llm/types.ts +31 -0
- package/src/modules/memory/masking/MaskingMiddleware.ts +143 -0
- package/src/modules/memory/masking/__tests__/CredentialDetector.test.ts +48 -0
- package/src/modules/memory/masking/__tests__/MaskingMiddleware.test.ts +74 -0
- package/src/modules/memory/masking/__tests__/PiiDetector.test.ts +59 -0
- package/src/modules/memory/masking/db/migrations/001-masking-tables.sql +60 -0
- package/src/modules/memory/masking/detectors/CredentialDetector.ts +54 -0
- package/src/modules/memory/masking/detectors/DetectorStrategy.ts +10 -0
- package/src/modules/memory/masking/detectors/PiiDetector.ts +54 -0
- package/src/modules/memory/masking/index.ts +8 -0
- package/src/modules/memory/masking/maskers/ContentMasker.ts +111 -0
- package/src/modules/memory/masking/models/MaskingTypes.ts +91 -0
- package/src/modules/memory/masking/services/AllowlistService.ts +34 -0
- package/src/modules/memory/masking/services/AuditService.ts +42 -0
- package/src/modules/memory/masking/services/ConfigCacheService.ts +45 -0
- package/src/modules/memory/migrations/001-add-scope-columns.ts +25 -0
- package/src/modules/memory/models.ts +106 -0
- package/src/modules/memory/schema.ts +269 -0
- package/src/modules/memory/tool-definitions.ts +31 -0
- package/src/modules/orchestration/McpClientManager.ts +209 -0
- package/src/modules/orchestration/McpConfigRoutes.ts +133 -0
- package/src/modules/orchestration/McpConfigService.ts +158 -0
- package/src/modules/orchestration/OrchestrationModule.ts +168 -0
- package/src/modules/utility/UtilityModule.ts +67 -0
- package/src/modules/web/WebModule.ts +79 -0
- package/src/modules/web/handlers/ApiCallHandler.ts +48 -0
- package/src/modules/web/handlers/DownloadFileHandler.ts +66 -0
- package/src/modules/web/handlers/FetchUrlHandler.ts +93 -0
- package/src/modules/web/handlers/GitBrowseHandler.ts +70 -0
- package/src/modules/web/handlers/ReadWebpageHandler.ts +59 -0
- package/src/modules/web/handlers/WebSearchHandler.ts +50 -0
- package/src/modules/web/middleware/ContentTruncator.ts +31 -0
- package/src/modules/web/middleware/RateLimiter.ts +70 -0
- package/src/modules/web/middleware/SsrfGuard.ts +82 -0
- package/src/modules/web/models/WebError.ts +25 -0
- package/src/modules/web/models/WebModuleConfig.ts +35 -0
- package/src/modules/web/models/WebToolResult.ts +23 -0
- package/src/modules/web/utils/GitUrlParser.ts +46 -0
- package/src/modules/web/utils/HtmlExtractor.ts +46 -0
- package/src/modules/web/utils/UrlValidator.ts +24 -0
- package/src/server/HttpServer.ts +135 -0
- package/src/server/mcpServer.ts +91 -0
- package/src/server/middleware/error-handler.ts +23 -0
- package/src/server/middleware/localhost-only.ts +22 -0
- package/src/server/middleware/rate-limiter.ts +61 -0
- package/src/server/middleware/request-logger.ts +26 -0
- package/src/server/routes/__tests__/admin.test.ts +667 -0
- package/src/server/routes/admin.ts +2511 -0
- package/src/server/routes/api.ts +208 -0
- package/src/server/routes/health.ts +33 -0
- package/src/server/routes/tools.ts +70 -0
- package/src/shared/protocol.ts +134 -0
- package/src/tool-router/ToolDefinitions.ts +17 -0
- package/src/tool-router/ToolRouter.ts +65 -0
- package/src/tool-router/ToolValidator.ts +55 -0
- package/src/types/module.ts +23 -0
- package/src/types/tool.ts +39 -0
- package/src/types.ts +6 -0
- package/src/viewer/3d-force-graph.min.js +5 -0
- package/src/viewer/__tests__/lod-manager.test.js +300 -0
- package/src/viewer/admin/camera-physics.js +102 -0
- package/src/viewer/admin/gesture-fsm.js +195 -0
- package/src/viewer/admin/index.html +338 -0
- package/src/viewer/admin/kb-graph-renderer.js +601 -0
- package/src/viewer/admin/lod-animation.js +202 -0
- package/src/viewer/admin/lod-clustering.js +229 -0
- package/src/viewer/admin/lod-manager.js +341 -0
- package/src/viewer/admin/map-controls.js +195 -0
- package/src/viewer/admin/zoom-animator.js +90 -0
- package/src/viewer/analytics.js +73 -0
- package/src/viewer/browser.js +82 -0
- package/src/viewer/dashboard.js +193 -0
- package/src/viewer/graph.js +249 -0
- package/src/viewer/lod-animation.js +200 -0
- package/src/viewer/lod-clustering.js +227 -0
- package/src/viewer/lod-manager.js +274 -0
- package/src/viewer/modules/empty-states.js +123 -0
- package/src/viewer/modules/event-bus.js +37 -0
- package/src/viewer/modules/graph-analysis.js +131 -0
- package/src/viewer/modules/help-panel.js +104 -0
- package/src/viewer/modules/markdown-renderer.js +70 -0
- package/src/viewer/modules/recommendations.js +116 -0
- package/src/viewer/modules/tooltips.js +119 -0
- package/src/viewer/modules/tour-ui.js +136 -0
- package/src/viewer/modules/tour.js +99 -0
- package/src/viewer/quality.js +122 -0
- package/src/viewer/session-export.js +37 -0
- package/src/viewer/session-playback.js +80 -0
- package/src/viewer/session-timeline.js +112 -0
- package/src/viewer/sessions.js +84 -0
- package/src/viewer/stream.js +109 -0
- package/src/viewer/tags.js +101 -0
- package/src/vitest.config.ts +9 -0
- package/src/vitest.ksa252.config.ts +10 -0
- package/tests/e2e/admin-api.e2e.test.ts +702 -0
- package/tests/e2e/admin-ui.e2e.test.ts +703 -0
- package/tests/e2e/check-lod.mjs +33 -0
- package/tests/e2e/debug-collapse.mjs +79 -0
- package/tests/e2e/debug-expand.mjs +38 -0
- package/tests/e2e/debug-lod.mjs +41 -0
- package/tests/e2e/debug-realtime.mjs +39 -0
- package/tests/e2e/lod-collapse.e2e.test.ts +163 -0
- package/tests/e2e/mcp-api.e2e.test.ts +280 -0
- package/tests/e2e/multi-tenant.e2e.test.ts +440 -0
- package/tests/e2e/test-progressive.mjs +72 -0
- package/tests/e2e/test-user-zoom.mjs +63 -0
- package/tests/e2e/tool-forwarding.e2e.test.ts +128 -0
- package/tests/integration/auth.test.ts +342 -0
- package/tests/integration/mcp-tools.test.ts +288 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +18 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
6
|
+
<title>Admin Portal - Code Intelligence</title>
|
|
7
|
+
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
|
|
8
|
+
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
|
|
9
|
+
<script src="https://unpkg.com/d3@7/dist/d3.min.js"></script>
|
|
10
|
+
<script src="https://unpkg.com/three@0.128.0/build/three.min.js"></script>
|
|
11
|
+
<script src="https://cdn.jsdelivr.net/npm/marked@9.1.6/marked.min.js"></script>
|
|
12
|
+
<script src="/admin/gesture-fsm.js?v=1"></script>
|
|
13
|
+
<script src="/admin/camera-physics.js?v=1"></script>
|
|
14
|
+
<script src="/admin/zoom-animator.js?v=1"></script>
|
|
15
|
+
<script src="/admin/map-controls.js?v=1"></script>
|
|
16
|
+
<script src="/admin/kb-graph-renderer.js?v=3"></script>
|
|
17
|
+
<script src="/admin/lod-clustering.js?v=4"></script>
|
|
18
|
+
<script src="/admin/lod-animation.js?v=4"></script>
|
|
19
|
+
<script src="/admin/lod-manager.js?v=4"></script>
|
|
20
|
+
<style>
|
|
21
|
+
*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#f8fafc;color:#1e293b}.app{display:flex;min-height:100vh}.sidebar{width:240px;background:#1e293b;color:#e2e8f0;padding:16px 0;position:fixed;height:100vh;overflow-y:auto}.sidebar h1{font-size:14px;padding:0 16px 16px;color:#94a3b8;border-bottom:1px solid #334155;margin-bottom:8px}.sidebar h1 span{display:block;font-size:18px;color:#fff;margin-top:4px}.nav-item{padding:10px 16px;cursor:pointer;display:flex;align-items:center;gap:8px;font-size:14px;transition:background .15s}.nav-item:hover{background:#334155}.nav-item.active{background:#3b82f6;color:#fff}.nav-item .icon{width:18px;text-align:center}.main{margin-left:240px;flex:1;padding:24px}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}.header h2{font-size:24px;font-weight:600}.card{background:#fff;border-radius:8px;padding:20px;box-shadow:0 1px 3px rgba(0,0,0,.1);margin-bottom:16px}.card h3{font-size:14px;color:#64748b;margin-bottom:8px}.card .value{font-size:28px;font-weight:700;color:#1e293b}.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:16px}table{width:100%;border-collapse:collapse}th,td{padding:10px 12px;text-align:left;border-bottom:1px solid #e2e8f0;font-size:14px}th{background:#f1f5f9;font-weight:600;color:#475569}tr:hover td{background:#f8fafc}tr.expanded-row td{background:#eff6ff}.badge{display:inline-block;padding:2px 8px;border-radius:12px;font-size:12px;font-weight:500}.badge-green{background:#dcfce7;color:#166534}.badge-red{background:#fee2e2;color:#991b1b}.badge-yellow{background:#fef3c7;color:#92400e}.badge-blue{background:#dbeafe;color:#1e40af}.badge-purple{background:#f3e8ff;color:#6b21a8}.btn{padding:8px 16px;border-radius:6px;border:none;cursor:pointer;font-size:13px;font-weight:500;transition:opacity .15s}.btn:hover{opacity:.85}.btn-primary{background:#3b82f6;color:#fff}.btn-danger{background:#ef4444;color:#fff}.btn-success{background:#22c55e;color:#fff}.btn-outline{background:transparent;border:1px solid #cbd5e1;color:#475569}.btn-sm{padding:4px 10px;font-size:12px}.login-container{display:flex;align-items:center;justify-content:center;min-height:100vh;background:#1e293b}.login-box{background:#fff;padding:40px;border-radius:12px;width:360px;box-shadow:0 4px 24px rgba(0,0,0,.2)}.login-box h2{margin-bottom:24px;text-align:center}.input{width:100%;padding:10px 12px;border:1px solid #cbd5e1;border-radius:6px;font-size:14px;margin-bottom:12px}.input:focus{outline:none;border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,.1)}.filter-input{padding:6px 10px;border:1px solid #cbd5e1;border-radius:4px;font-size:13px;margin-bottom:8px;width:260px}.expand-btn{cursor:pointer;-webkit-user-select:none;user-select:none;font-size:13px;width:24px;display:inline-block;text-align:center}.sub-table{margin:4px 12px 12px 40px;background:#fff;border-radius:6px;border:1px solid #e2e8f0}.sub-table th{background:#f8fafc;font-size:13px}.sub-table td{font-size:13px}.perm-check{display:flex;flex-wrap:wrap;gap:8px}.perm-check label{display:flex;align-items:center;gap:4px;font-size:13px;padding:2px 6px;background:#f1f5f9;border-radius:4px;cursor:pointer}.locked{opacity:.5;pointer-events:none}.rule-row{display:flex;align-items:center;gap:12px;padding:8px 0;border-bottom:1px solid #f1f5f9}.rule-row:last-child{border-bottom:none}.rule-label{min-width:200px;font-size:13px;color:#475569}.mcp-detail{margin:8px 0 8px 24px;padding:12px;border:1px solid #e2e8f0;border-radius:6px;background:#fafbfc}.toolbar{display:flex;gap:8px;align-items:center;margin-bottom:12px}.toggle-switch{position:relative;display:inline-block;width:36px;height:20px}.toggle-switch input{opacity:0;width:0;height:0}.toggle-slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background:#cbd5e1;border-radius:20px;transition:.2s}.toggle-slider:before{content:'';position:absolute;height:14px;width:14px;left:3px;bottom:3px;background:#fff;border-radius:50%;transition:.2s}.toggle-switch input:checked+.toggle-slider{background:#22c55e}.toggle-switch input:checked+.toggle-slider:before{transform:translateX(16px)}.log-line{font-family:monospace;font-size:12px;padding:2px 8px;border-bottom:1px solid #334155}.log-line .ts{color:#94a3b8;margin-right:8px}.log-line .lvl-INFO{color:#60a5fa}.log-line .lvl-DEBUG{color:#9ca3af}.log-line .lvl-ERROR{color:#f87171}.log-line .lvl-WARN{color:#fbbf24}.tab-bar{display:flex;gap:0;border-bottom:2px solid #e2e8f0;margin-bottom:16px}.tab{padding:8px 16px;cursor:pointer;font-size:13px;font-weight:500;color:#64748b;border-bottom:2px solid transparent;margin-bottom:-2px}.tab.active{color:#3b82f6;border-bottom-color:#3b82f6}.score-bar{height:6px;border-radius:3px;background:#e2e8f0;margin-top:2px}.score-fill{height:100%;border-radius:3px}.md-content h1,.md-content h2,.md-content h3{font-size:13px;font-weight:600;margin:6px 0 4px;color:#e2e8f0}.md-content p{margin:4px 0}.md-content table{border-collapse:collapse;width:100%;font-size:11px;margin:6px 0}.md-content th,.md-content td{border:1px solid #475569;padding:3px 6px;text-align:left}.md-content th{background:#334155}.md-content code{background:#334155;padding:1px 4px;border-radius:3px;font-size:11px}.md-content pre{background:#1e293b;padding:8px;border-radius:4px;overflow-x:auto;font-size:11px}.md-content ul,.md-content ol{padding-left:16px;margin:4px 0}.md-content li{margin:2px 0}
|
|
22
|
+
</style>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<div id="root"></div>
|
|
26
|
+
<script src="https://unpkg.com/@babel/standalone@7.17.12/babel.min.js"></script>
|
|
27
|
+
<script type="text/babel">const{useState,useEffect,useCallback,useRef}=React;
|
|
28
|
+
const API='/api/admin';
|
|
29
|
+
let __impersonateUserId=null;
|
|
30
|
+
function api(path,options={}){const token=localStorage.getItem('admin_token')||'';const impHeaders=__impersonateUserId?{'X-Impersonate':__impersonateUserId}:{};return fetch(API+path,{...options,headers:{'Authorization':'Bearer '+token,'Content-Type':'application/json',...impHeaders,...options.headers}}).then(r=>{if(r.status===401){localStorage.removeItem('admin_token');localStorage.removeItem('admin_user');return null;}if(r.status===403){return r.json().then(d=>{showForbidden(d.error||'Access denied');return{__error:true,...d};}).catch(()=>({__error:true,error:'Forbidden'}));}if(!r.ok)return r.json().then(d=>({__error:true,...d})).catch(()=>null);return r.json();}).catch(()=>null);}
|
|
31
|
+
|
|
32
|
+
let __lastForbiddenMsg='';function showForbidden(msg){__lastForbiddenMsg=msg;setTimeout(()=>{__lastForbiddenMsg='';},3000);}
|
|
33
|
+
function exportCSV(data,filename){if(!data||data.length===0)return;const keys=Object.keys(data[0]);const csv=[keys.join(','),...data.map(row=>keys.map(k=>{const v=row[k];const s=v==null?'':String(v);return s.includes(',')||s.includes('"')||s.includes('\n')?'"'+s.replace(/"/g,'""')+'"':s;}).join(','))].join('\n');const blob=new Blob([csv],{type:'text/csv'});const url=URL.createObjectURL(blob);const a=document.createElement('a');a.href=url;a.download=filename;a.click();URL.revokeObjectURL(url);}
|
|
34
|
+
|
|
35
|
+
const RULES={DASHBOARD_VIEW:[{name:'exportAllowed',type:'boolean',allowed:[true,false],default:false,desc:'Allow exporting'}],KB_READ:[{name:'allowedTiers',type:'enum[]',allowed:['USER','PROJECT','SHARED'],default:['USER','PROJECT','SHARED'],desc:'Tiers'}],KB_WRITE:[{name:'allowedTiers',type:'enum[]',allowed:['USER','PROJECT','SHARED'],default:['USER'],desc:'Write tiers'},{name:'maxEntries',type:'number',min:1,max:100000,default:1000,desc:'Max'},{name:'allowedOperations',type:'enum[]',allowed:['CREATE','UPDATE','DELETE'],default:['CREATE','UPDATE'],desc:'Ops'}],KB_PROMOTE:[{name:'targetTiers',type:'enum[]',allowed:['PROJECT','SHARED'],default:['PROJECT'],desc:'Targets'}],KB_IMPORT_EXPORT:[{name:'allowedFormats',type:'enum[]',allowed:['JSON','CSV'],default:['JSON','CSV'],desc:'Formats'},{name:'allowImport',type:'boolean',allowed:[true,false],default:true,desc:'Import'},{name:'allowExport',type:'boolean',allowed:[true,false],default:true,desc:'Export'}],MCP_ACCESS:[{name:'toolAccess',type:'mcp-tool-access-table',default:{},desc:'Per-server tool access (which tools user can call)'}],MCP_MANAGE:[{name:'allowAdd',type:'boolean',allowed:[true,false],default:true,desc:'Add new servers'},{name:'serverPermissions',type:'mcp-server-table',default:{},desc:'Per-server permissions (Remove/Edit/Restart)'}],USER_MANAGE:[{name:'canDelete',type:'boolean',allowed:[true,false],default:false,desc:'Delete'},{name:'canForceLogout',type:'boolean',allowed:[true,false],default:false,desc:'Logout'},{name:'canDisable',type:'boolean',allowed:[true,false],default:true,desc:'Disable'}],RBAC_MANAGE:[{name:'canDeleteSystemGroups',type:'boolean',allowed:[true,false],default:false,locked:true,desc:'LOCKED'},{name:'canEditSystemPermissions',type:'boolean',allowed:[true,false],default:false,desc:'Edit'}],CONFIG_EDIT:[{name:'allowedSections',type:'enum[]',allowed:['server','embedding','llm','mcp-servers','kb','auth'],default:['server','embedding','llm'],desc:'Sections'},{name:'readOnly',type:'boolean',allowed:[true,false],default:true,desc:'ReadOnly'}],SEARCH_EXPLORE:[{name:'maxResults',type:'number',min:10,max:1000,default:100,desc:'Max'},{name:'allowDebugMode',type:'boolean',allowed:[true,false],default:false,desc:'Debug'}],AUDIT_VIEW:[{name:'exportAllowed',type:'boolean',allowed:[true,false],default:false,desc:'Export'},{name:'maxDaysVisible',type:'number',min:1,max:365,default:90,desc:'Days'}],GRAPH_VIEW:[{name:'exportAllowed',type:'boolean',allowed:[true,false],default:false,desc:'Export'},{name:'maxNodes',type:'number',min:50,max:5000,default:500,desc:'Nodes'}],ANALYTICS_VIEW:[{name:'exportAllowed',type:'boolean',allowed:[true,false],default:false,desc:'Export'},{name:'allowedMetrics',type:'enum[]',allowed:['quality-scores','embedding-space','usage-stats','health-monitor'],default:['quality-scores','usage-stats'],desc:'Metrics'}]};
|
|
36
|
+
|
|
37
|
+
function LoginPage({onLogin}){const[username,setUsername]=useState('');const[password,setPassword]=useState('');const[error,setError]=useState('');const[loading,setLoading]=useState(false);const handleLogin=async()=>{setError('');setLoading(true);const res=await fetch(API+'/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username,password})});const data=await res.json().catch(()=>null);setLoading(false);if(!res.ok||!data?.token){setError(data?.error||'Login failed');return;}localStorage.setItem('admin_token',data.token);localStorage.setItem('admin_user',JSON.stringify(data.user));onLogin();};return(<div className="login-container"><div className="login-box"><h2>Admin Portal</h2>{error&&<div style={{background:'#fee2e2',color:'#991b1b',padding:'8px 12px',borderRadius:6,marginBottom:12,fontSize:13}}>{error}</div>}<input className="input" placeholder="Username" value={username} onChange={e=>setUsername(e.target.value)} onKeyDown={e=>e.key==='Enter'&&handleLogin()}/><input className="input" type="password" placeholder="Password" value={password} onChange={e=>setPassword(e.target.value)} onKeyDown={e=>e.key==='Enter'&&handleLogin()}/><button className="btn btn-primary" style={{width:'100%'}} onClick={handleLogin} disabled={loading}>{loading?'Logging in...':'Login'}</button><p style={{fontSize:12,color:'#94a3b8',marginTop:12,textAlign:'center'}}>Default: admin / admin</p></div></div>);}
|
|
38
|
+
|
|
39
|
+
function DashboardPage(){const[stats,setStats]=useState({});const load=()=>{api('/stats').then(d=>{setStats(d||{});});};useEffect(()=>{load();const i=setInterval(load,30000);return()=>clearInterval(i);},[]);const activity=stats.recentActivity||[];return(<div><div className="header"><h2>Dashboard</h2></div><div className="grid"><div className="card"><h3>KB Entries</h3><div className="value">{(stats.kbEntries||0).toLocaleString()}</div></div><div className="card"><h3>Code Symbols</h3><div className="value">{(stats.codeSymbols||0).toLocaleString()}</div></div><div className="card"><h3>Graph Nodes</h3><div className="value">{(stats.graphTotalNodes||0).toLocaleString()}</div><div style={{fontSize:11,color:'#64748b',marginTop:4}}>{(stats.graphKbNodes||0).toLocaleString()} KB + {(stats.graphCodeNodes||0).toLocaleString()} Code</div></div>{stats.users!==undefined&&<div className="card"><h3>Users</h3><div className="value">{stats.users}</div></div>}<div className="card"><h3>MCP Servers</h3><div className="value">{stats.mcpServers||0}</div></div><div className="card"><h3>Uptime</h3><div className="value" style={{fontSize:20}}>{stats.uptime?.formatted||'--'}</div></div><div className="card"><h3>Memory</h3><div className="value" style={{fontSize:16}}>{stats.memory?.formatted||'--'}</div></div></div><div className="card" style={{marginTop:16}}><h3 style={{marginBottom:12}}>Recent Activity</h3>{activity.length===0?<p style={{color:'#94a3b8',fontSize:13}}>No recent activity</p>:<table><thead><tr><th>Time</th><th>User</th><th>Action</th><th>Resource</th></tr></thead><tbody>{activity.map((a,i)=>(<tr key={i}><td style={{fontSize:12}}>{a.timestamp?new Date(a.timestamp).toLocaleString():'-'}</td><td>{a.username}</td><td><span className="badge badge-blue">{a.action}</span></td><td>{a.resource}{a.resourceId?' / '+a.resourceId:''}</td></tr>))}</tbody></table>}</div></div>);}
|
|
40
|
+
|
|
41
|
+
function KBManagementPage(){const[entries,setEntries]=useState([]);const[total,setTotal]=useState(0);const[page,setPage]=useState(1);const pageSize=20;const[sortBy,setSortBy]=useState('created_at');const[sortDir,setSortDir]=useState('desc');const[filter,setFilter]=useState('');const[tab,setTab]=useState('entries');const[promotions,setPromotions]=useState([]);const[importText,setImportText]=useState('');const[msg,setMsg]=useState('');const[tagEntry,setTagEntry]=useState(null);const[tagInput,setTagInput]=useState('');const[linkEntry,setLinkEntry]=useState(null);const[linkTarget,setLinkTarget]=useState('');
|
|
42
|
+
const load=(p,sb,sd)=>{api('/kb/entries?page='+p+'&pageSize='+pageSize+'&sortBy='+sb+'&sortDir='+sd).then(d=>{if(d&&!d.__error){setEntries(d.entries||[]);setTotal(d.total||0);}});};
|
|
43
|
+
const loadPromos=()=>{api('/kb/promotions').then(d=>{if(d&&!d.__error)setPromotions(d.promotions||[]);});};
|
|
44
|
+
useEffect(()=>{load(page,sortBy,sortDir);loadPromos();},[page,sortBy,sortDir]);
|
|
45
|
+
const totalPages=Math.ceil(total/pageSize);const toggleSort=(col)=>{if(sortBy===col)setSortDir(d=>d==='asc'?'desc':'asc');else{setSortBy(col);setSortDir('desc');}setPage(1);};const sortIcon=(col)=>sortBy===col?(sortDir==='asc'?' β²':' βΌ'):'';
|
|
46
|
+
const filtered=entries.filter(e=>!filter||JSON.stringify(e).toLowerCase().includes(filter.toLowerCase()));
|
|
47
|
+
const doExport=()=>{api('/kb/export').then(d=>{if(d&&d.entries){const blob=new Blob([JSON.stringify(d,null,2)],{type:'application/json'});const url=URL.createObjectURL(blob);const a=document.createElement('a');a.href=url;a.download='kb-export.json';a.click();URL.revokeObjectURL(url);setMsg('Exported '+d.count+' entries');}});};
|
|
48
|
+
const doImport=()=>{try{const data=JSON.parse(importText);api('/kb/import',{method:'POST',body:JSON.stringify({entries:Array.isArray(data)?data:data.entries||[]})}).then(d=>{if(d&&!d.__error){setMsg(d.message);setImportText('');}else setMsg(d?.error||'Failed');});}catch{setMsg('Invalid JSON');}};
|
|
49
|
+
const doExportCSV=()=>{exportCSV(entries.map(e=>({id:e.id||e.entry_id,source:e.source||e.title,tier:e.tier||e.scope,type:e.type||e.content_type,created:e.created_at})),'kb-entries.csv');};
|
|
50
|
+
const saveTags=()=>{if(!tagEntry)return;api('/kb/entries/'+tagEntry+'/tags',{method:'POST',body:JSON.stringify({tags:tagInput.split(',').map(t=>t.trim()).filter(Boolean)})}).then(d=>{if(d&&!d.__error){setMsg('Tags saved');setTagEntry(null);}});};
|
|
51
|
+
const saveLink=()=>{if(!linkEntry||!linkTarget)return;api('/kb/entries/'+linkEntry+'/link',{method:'POST',body:JSON.stringify({targetId:linkTarget,linkType:'related'})}).then(d=>{if(d&&!d.__error){setMsg('Link created');setLinkEntry(null);setLinkTarget('');}});};
|
|
52
|
+
const reviewPromo=(id,action)=>{api('/kb/promotions/'+id+'/review',{method:'POST',body:JSON.stringify({action})}).then(()=>loadPromos());};
|
|
53
|
+
return(<div><div className="header"><h2>KB Management</h2><div style={{display:'flex',gap:8}}><button className="btn btn-sm btn-outline" onClick={doExportCSV}>Export CSV</button><button className="btn btn-sm btn-outline" onClick={doExport}>Export JSON</button><span className="badge badge-blue" style={{fontSize:14,padding:'4px 12px'}}>{total} entries</span></div></div>
|
|
54
|
+
{msg&&<div className="card" style={{background:'#f0fdf4',border:'1px solid #86efac'}}><span style={{fontSize:13}}>{msg}</span><button className="btn btn-sm btn-outline" style={{marginLeft:12}} onClick={()=>setMsg('')}>x</button></div>}
|
|
55
|
+
<div className="tab-bar"><div className={'tab'+(tab==='entries'?' active':'')} onClick={()=>setTab('entries')}>Entries</div><div className={'tab'+(tab==='promotions'?' active':'')} onClick={()=>setTab('promotions')}>Promotions ({promotions.filter(p=>p.status==='pending').length})</div><div className={'tab'+(tab==='import'?' active':'')} onClick={()=>setTab('import')}>Import</div></div>
|
|
56
|
+
{tab==='entries'&&<div className="card"><input className="filter-input" placeholder="Filter entries..." value={filter} onChange={e=>setFilter(e.target.value)}/>
|
|
57
|
+
{tagEntry&&<div style={{padding:8,background:'#eff6ff',borderRadius:6,marginBottom:8}}>Tags for {tagEntry}: <input className="input" style={{width:300,display:'inline-block',marginBottom:0,marginLeft:8}} value={tagInput} onChange={e=>setTagInput(e.target.value)} placeholder="tag1, tag2"/><button className="btn btn-sm btn-primary" style={{marginLeft:8}} onClick={saveTags}>Save</button><button className="btn btn-sm btn-outline" style={{marginLeft:4}} onClick={()=>setTagEntry(null)}>Cancel</button></div>}
|
|
58
|
+
{linkEntry&&<div style={{padding:8,background:'#fef3c7',borderRadius:6,marginBottom:8}}>Link {linkEntry} to: <input className="input" style={{width:300,display:'inline-block',marginBottom:0,marginLeft:8}} value={linkTarget} onChange={e=>setLinkTarget(e.target.value)} placeholder="Target entry ID"/><button className="btn btn-sm btn-primary" style={{marginLeft:8}} onClick={saveLink}>Link</button><button className="btn btn-sm btn-outline" style={{marginLeft:4}} onClick={()=>setLinkEntry(null)}>Cancel</button></div>}
|
|
59
|
+
<table><thead><tr><th>#</th><th style={{cursor:'pointer'}} onClick={()=>toggleSort('source')}>Source{sortIcon('source')}</th><th style={{cursor:'pointer'}} onClick={()=>toggleSort('tier')}>Tier{sortIcon('tier')}</th><th style={{cursor:'pointer'}} onClick={()=>toggleSort('type')}>Type{sortIcon('type')}</th><th style={{cursor:'pointer'}} onClick={()=>toggleSort('created_at')}>Created{sortIcon('created_at')}</th><th>Actions</th></tr></thead><tbody>
|
|
60
|
+
{filtered.map((e,i)=>{const eid=e.id||e.entry_id||'e'+i;return(<tr key={eid}><td>{(page-1)*pageSize+i+1}</td><td>{e.source||e.title||'-'}</td><td><span className="badge badge-blue">{e.tier||e.scope||'-'}</span></td><td>{e.type||e.content_type||'-'}</td><td style={{fontSize:12}}>{e.created_at?new Date(e.created_at).toLocaleString():'-'}</td><td><button className="btn btn-sm btn-outline" onClick={()=>{setTagEntry(eid);setTagInput('');}}>Tags</button>{' '}<button className="btn btn-sm btn-outline" onClick={()=>setLinkEntry(eid)}>Link</button></td></tr>);})}
|
|
61
|
+
{filtered.length===0&&<tr><td colSpan={6} style={{textAlign:'center',color:'#94a3b8'}}>No entries</td></tr>}</tbody></table>
|
|
62
|
+
{totalPages>1&&<div style={{marginTop:12,display:'flex',gap:8,alignItems:'center'}}><button className="btn btn-sm btn-outline" disabled={page<=1} onClick={()=>setPage(p=>p-1)}>Prev</button><span style={{fontSize:12,color:'#64748b'}}>Page {page}/{totalPages}</span><button className="btn btn-sm btn-outline" disabled={page>=totalPages} onClick={()=>setPage(p=>p+1)}>Next</button></div>}</div>}
|
|
63
|
+
{tab==='promotions'&&<div className="card"><h4 style={{marginBottom:12}}>Promotion Queue</h4>{promotions.length===0?<p style={{color:'#94a3b8'}}>No promotions</p>:<table><thead><tr><th>Entry</th><th>From</th><th>To</th><th>Reason</th><th>Requested</th><th>Status</th><th>Actions</th></tr></thead><tbody>{promotions.map(p=>(<tr key={p.id}><td>{p.entryId}</td><td><span className="badge badge-blue">{p.fromTier}</span></td><td><span className="badge badge-purple">{p.toTier}</span></td><td>{p.reason||'-'}</td><td style={{fontSize:12}}>{p.requestedBy}</td><td><span className={'badge '+(p.status==='pending'?'badge-yellow':p.status==='approved'?'badge-green':'badge-red')}>{p.status}</span></td><td>{p.status==='pending'&&<><button className="btn btn-sm btn-success" onClick={()=>reviewPromo(p.id,'approve')}>Approve</button>{' '}<button className="btn btn-sm btn-danger" onClick={()=>reviewPromo(p.id,'reject')}>Reject</button></>}</td></tr>))}</tbody></table>}</div>}
|
|
64
|
+
{tab==='import'&&<div className="card"><h4 style={{marginBottom:12}}>Import KB Entries (JSON)</h4><textarea className="input" style={{height:200,fontFamily:'monospace',fontSize:12}} value={importText} onChange={e=>setImportText(e.target.value)} placeholder='[{"source":"...", "content":"...", "tier":"USER"}]'/><button className="btn btn-primary" onClick={doImport} disabled={!importText}>Import</button></div>}
|
|
65
|
+
</div>);}
|
|
66
|
+
|
|
67
|
+
function KBGraphPage({activeTab}={}){
|
|
68
|
+
const mainRef=useRef(null);const miniRef=useRef(null);const rendererRef=useRef(null);
|
|
69
|
+
const[loading,setLoading]=useState(true);const[selectedNode,setSelectedNode]=useState(null);
|
|
70
|
+
const[nodeDetail,setNodeDetail]=useState(null);const[searchTerm,setSearchTerm]=useState('');
|
|
71
|
+
const[graphStats,setGraphStats]=useState(null);
|
|
72
|
+
const[typeFilters,setTypeFilters]=useState({REQUIREMENT:true,ARCHITECTURE:true,PROCEDURE:true,CONTEXT:true,CODE_ENTITY:true,DECISION:true,LESSON_LEARNED:true,ERROR_PATTERN:true,DOCUMENT:true,FUNCTION:true,METHOD:true,CLASS:true,INTERFACE:true,TYPE:true,CONSTRUCTOR:true,ENUM:true,CONSTANT:true,VARIABLE:true});
|
|
73
|
+
const[showFilterDrop,setShowFilterDrop]=useState(false);
|
|
74
|
+
const allNodesRef=useRef([]);
|
|
75
|
+
const colors={REQUIREMENT:'#3b82f6',ARCHITECTURE:'#10b981',PROCEDURE:'#f59e0b',CONTEXT:'#ec4899',CODE_ENTITY:'#ef4444',DECISION:'#06b6d4',LESSON_LEARNED:'#f97316',ERROR_PATTERN:'#dc2626',DOCUMENT:'#a855f7',FUNCTION:'#818cf8',METHOD:'#6366f1',CLASS:'#e879f9',INTERFACE:'#c084fc',TYPE:'#fb7185',CONSTRUCTOR:'#f472b6',ENUM:'#34d399',CONSTANT:'#fbbf24',VARIABLE:'#94a3b8'};
|
|
76
|
+
const basePath=window.__MCP_BASE||'';
|
|
77
|
+
|
|
78
|
+
useEffect(()=>{
|
|
79
|
+
if(!mainRef.current)return;
|
|
80
|
+
let destroyed=false;
|
|
81
|
+
setLoading(true);
|
|
82
|
+
// Load all positions
|
|
83
|
+
api('/kb/graph/positions').then(d=>{
|
|
84
|
+
if(destroyed||!d||d.__error)return;
|
|
85
|
+
allNodesRef.current=d.nodes||[];
|
|
86
|
+
setGraphStats({totalNodes:d.total||d.nodes.length,kbNodes:d.kbCount||0,codeNodes:d.codeCount||0,totalEdges:0});
|
|
87
|
+
// Create renderer
|
|
88
|
+
KBGraphRenderer.create(mainRef.current,{minimapCanvas:miniRef.current}).then(r=>{
|
|
89
|
+
if(destroyed){r.destroy();return;}
|
|
90
|
+
rendererRef.current=r;
|
|
91
|
+
r.loadPositions(allNodesRef.current);
|
|
92
|
+
r.zoomToFit();
|
|
93
|
+
// Edges loaded on-demand when zoom close (not on init β too many creates wireframe)
|
|
94
|
+
setLoading(false);
|
|
95
|
+
// Listen for node clicks
|
|
96
|
+
mainRef.current.addEventListener('graph-node-click',function(ev){
|
|
97
|
+
var node=ev.detail;
|
|
98
|
+
setSelectedNode(node);setNodeDetail(null);
|
|
99
|
+
api('/kb/entries/'+node.id).then(function(det){
|
|
100
|
+
if(det&&!det.__error)setNodeDetail(det);
|
|
101
|
+
else setNodeDetail({id:node.id,title:node.label,type:node.type,tier:node.tier,content:'No detail available'});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}).catch(function(){setLoading(false);});
|
|
106
|
+
return()=>{destroyed=true;if(rendererRef.current){rendererRef.current.destroy();rendererRef.current=null;}};
|
|
107
|
+
},[activeTab]);
|
|
108
|
+
|
|
109
|
+
// Auto-reload graph when RBAC changes
|
|
110
|
+
useEffect(()=>{
|
|
111
|
+
const onRbacChanged=()=>{
|
|
112
|
+
api('/kb/graph/positions').then(d=>{
|
|
113
|
+
if(!d||d.__error)return;
|
|
114
|
+
allNodesRef.current=d.nodes||[];
|
|
115
|
+
setGraphStats({totalNodes:d.total||d.nodes.length,kbNodes:d.kbCount||0,codeNodes:d.codeCount||0,totalEdges:0});
|
|
116
|
+
if(rendererRef.current)rendererRef.current.loadPositions(allNodesRef.current);
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
window.addEventListener('rbac-changed',onRbacChanged);
|
|
120
|
+
return()=>window.removeEventListener('rbac-changed',onRbacChanged);
|
|
121
|
+
},[]);
|
|
122
|
+
|
|
123
|
+
const doSearch=(term)=>{
|
|
124
|
+
setSearchTerm(term);
|
|
125
|
+
if(!term||!rendererRef.current)return;
|
|
126
|
+
var found=allNodesRef.current.find(n=>n.label&&n.label.toLowerCase().includes(term.toLowerCase()));
|
|
127
|
+
if(found){rendererRef.current.focusNode(found.id);setSelectedNode(found);setNodeDetail(null);api('/kb/entries/'+found.id).then(d=>{if(d&&!d.__error)setNodeDetail(d);else setNodeDetail({id:found.id,title:found.label,type:found.type,tier:found.tier,content:'No detail'});});}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
return(<div style={{position:'relative',width:'100%',height:'calc(100vh - 52px)',borderRadius:8,overflow:'hidden',background:'#0f172a'}}>{loading&&<p style={{color:'#94a3b8',padding:24,position:'absolute',zIndex:10}}>Loading {graphStats?graphStats.totalNodes+' nodes':''}...</p>}<div ref={mainRef} style={{width:'100%',height:'100%'}}/><div style={{position:'absolute',top:12,left:12,zIndex:9999,display:'flex',gap:8,alignItems:'center'}}><input className="filter-input" style={{width:180,marginBottom:0,background:'rgba(30,41,59,0.9)',border:'1px solid #475569',color:'#e2e8f0'}} placeholder="Search node..." value={searchTerm} onChange={e=>doSearch(e.target.value)}/><button className="btn btn-sm btn-outline" style={{background:'rgba(30,41,59,0.9)',color:'#e2e8f0',border:'1px solid #475569'}} onClick={()=>{if(rendererRef.current)rendererRef.current.zoomToFit();}}>Fit</button><div style={{position:'relative'}}><button className="btn btn-sm btn-outline" style={{background:'rgba(30,41,59,0.9)',color:'#e2e8f0',border:'1px solid #475569'}} onClick={()=>setShowFilterDrop(!showFilterDrop)}>Filter {showFilterDrop?'\u25B4':'\u25BE'}</button>{showFilterDrop&&<div style={{position:'absolute',top:32,left:0,zIndex:9999,background:'rgba(30,41,59,0.95)',border:'1px solid #475569',borderRadius:6,padding:8,boxShadow:'0 4px 12px rgba(0,0,0,0.3)',minWidth:150}}>{Object.entries(typeFilters).map(([type,on])=>(<label key={type} style={{display:'flex',alignItems:'center',gap:6,padding:'3px 0',fontSize:12,cursor:'pointer',color:'#e2e8f0'}}><input type="checkbox" checked={on} onChange={e=>{const nf={...typeFilters,[type]:e.target.checked};setTypeFilters(nf);if(rendererRef.current){var filtered=allNodesRef.current.filter(n=>nf[n.type]!==false);rendererRef.current.loadPositions(filtered);}}}/><span style={{width:8,height:8,borderRadius:'50%',background:colors[type]||'#64748b',display:'inline-block'}}/><span style={{textTransform:'capitalize'}}>{type}</span></label>))}</div>}</div>{graphStats&&<span style={{fontSize:11,color:'#94a3b8',background:'rgba(30,41,59,0.9)',padding:'4px 8px',borderRadius:4}}>{(graphStats.totalNodes||0).toLocaleString()} nodes ({(graphStats.kbNodes||0).toLocaleString()} KB + {(graphStats.codeNodes||0).toLocaleString()} Code)</span>}</div><canvas ref={miniRef} width={180} height={140} style={{position:'absolute',bottom:12,right:12,zIndex:9999,borderRadius:6,border:'1px solid #334155',cursor:'grab',background:'#1e293b'}}/>{selectedNode&&<div style={{position:'absolute',top:12,right:12,zIndex:9999,width:300,maxHeight:'70%',overflow:'auto',background:'rgba(30,41,59,0.95)',border:'1px solid #334155',borderRadius:8,padding:14,boxShadow:'0 4px 20px rgba(0,0,0,0.5)'}}><div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}><strong style={{color:'#e2e8f0',fontSize:13}}>{selectedNode.label||selectedNode.id}</strong><span style={{cursor:'pointer',color:'#94a3b8',fontSize:16}} onClick={()=>setSelectedNode(null)}>×</span></div><div style={{fontSize:11,color:'#94a3b8',marginBottom:6}}><span className='badge badge-blue' style={{marginRight:6}}>{selectedNode.type}</span><span className='badge badge-purple'>{selectedNode.tier||'SHARED'}</span></div>{nodeDetail?<div style={{fontSize:12,color:'#cbd5e1'}}>{nodeDetail.content&&<div className="md-content" style={{marginBottom:8,lineHeight:1.6,maxHeight:200,overflow:'auto',fontSize:12}} dangerouslySetInnerHTML={{__html:typeof marked!=='undefined'?marked.parse(nodeDetail.content.substring(0,800)):nodeDetail.content.substring(0,300)}}/>}{nodeDetail.tags&&nodeDetail.tags.length>0&&<div style={{marginBottom:6}}><span style={{color:'#94a3b8'}}>Tags:</span> {nodeDetail.tags.join(', ')}</div>}{nodeDetail.links&&nodeDetail.links.length>0&&<div style={{marginBottom:6}}><span style={{color:'#94a3b8'}}>Links:</span> {nodeDetail.links.length} connections</div>}{nodeDetail.qualityScore!=null&&<div><span style={{color:'#94a3b8'}}>Quality:</span> {(nodeDetail.qualityScore*100).toFixed(0)}%</div>}{nodeDetail.createdAt&&<div style={{marginTop:6,fontSize:10,color:'#64748b'}}>Created: {new Date(nodeDetail.createdAt).toLocaleString()}</div>}</div>:<p style={{fontSize:11,color:'#64748b'}}>Loading...</p>}</div>}<div style={{position:'absolute',bottom:12,left:12,zIndex:9999,background:'rgba(30,41,59,0.92)',border:'1px solid #334155',borderRadius:8,padding:'8px 12px'}}><div style={{fontSize:10,fontWeight:600,color:'#e2e8f0',marginBottom:4}}>Node Types</div>{Object.entries(colors).map(([type,color])=>(<div key={type} style={{display:'flex',alignItems:'center',gap:6,marginBottom:2}}><span style={{width:8,height:8,borderRadius:'50%',background:color,display:'inline-block'}}/><span style={{fontSize:10,color:'#cbd5e1',textTransform:'capitalize'}}>{type}</span></div>))}</div></div>);}
|
|
131
|
+
function AnalyticsPage(){const[data,setData]=useState(null);const[loading,setLoading]=useState(true);
|
|
132
|
+
useEffect(()=>{api('/analytics').then(d=>{if(d&&!d.__error)setData(d);setLoading(false);});},[]);
|
|
133
|
+
if(loading)return<div><div className="header"><h2>Analytics</h2></div><p style={{color:'#64748b'}}>Loading...</p></div>;
|
|
134
|
+
if(!data)return<div><div className="header"><h2>Analytics</h2></div><p>No data</p></div>;
|
|
135
|
+
const{summary,qualityScores,usageOverTime,embeddingSpace}=data;
|
|
136
|
+
const maxQ=Math.max(...(qualityScores||[]).map(d=>d.count),1);const maxU=Math.max(...(usageOverTime||[]).map(d=>Math.max(d.queries,d.ingestions)),1);
|
|
137
|
+
return(<div><div className="header"><h2>Analytics</h2></div>
|
|
138
|
+
<div className="grid"><div className="card"><h3>Total Entries</h3><div className="value">{summary?.totalEntries||0}</div></div><div className="card"><h3>Avg Quality</h3><div className="value">{((summary?.avgQuality||0)*100).toFixed(0)}%</div></div><div className="card"><h3>Avg Query Time</h3><div className="value">{summary?.avgQueryTime||0}ms</div></div><div className="card"><h3>Cache Hit Rate</h3><div className="value">{((summary?.cacheHitRate||0)*100).toFixed(0)}%</div></div></div>
|
|
139
|
+
<div className="card" style={{marginTop:16}}><h3 style={{marginBottom:12}}>Quality Score Distribution</h3><svg width="100%" viewBox="0 0 600 180" style={{display:'block'}}>{(qualityScores||[]).map((d,i)=>{const barH=(d.count/maxQ)*130;return(<g key={i}><rect x={50+i*52} y={150-barH} width={44} height={barH} fill="#8b5cf6" rx={3} opacity={0.8}/><text x={50+i*52+22} y={168} textAnchor="middle" fontSize="9" fill="#64748b">{d.range}</text><text x={50+i*52+22} y={145-barH} textAnchor="middle" fontSize="9" fill="#475569">{d.count}</text></g>);})}</svg></div>
|
|
140
|
+
<div className="card"><h3 style={{marginBottom:12}}>Usage Over Time (14 days)</h3><svg width="100%" viewBox="0 0 700 200" style={{display:'block'}}>{(()=>{const pts=usageOverTime||[];if(pts.length<2)return null;const xStep=600/(pts.length-1);const qLine=pts.map((d,i)=>(50+i*xStep)+','+(170-d.queries/maxU*140)).join(' ');const iLine=pts.map((d,i)=>(50+i*xStep)+','+(170-d.ingestions/maxU*140)).join(' ');return(<><polyline points={qLine} fill="none" stroke="#3b82f6" strokeWidth="2"/><polyline points={iLine} fill="none" stroke="#22c55e" strokeWidth="2"/>{pts.map((d,i)=>i%2===0&&<text key={i} x={50+i*xStep} y={186} textAnchor="middle" fontSize="9" fill="#94a3b8">{d.date?.slice(5)}</text>)}</>);})()}</svg><div style={{fontSize:11,color:'#64748b',marginTop:4}}>β <span style={{color:'#3b82f6'}}>queries</span> β <span style={{color:'#22c55e'}}>ingestions</span></div></div>
|
|
141
|
+
<div className="card"><h3 style={{marginBottom:12}}>Embedding Space (2D Scatter)</h3><svg width="100%" viewBox="0 0 600 300" style={{display:'block',background:'#fafbfc',borderRadius:8}}>{(embeddingSpace||[]).map((d,i)=>{const colors=['#3b82f6','#22c55e','#f59e0b','#8b5cf6','#ec4899'];return(<circle key={i} cx={40+d.x*520} cy={10+d.y*260} r={5} fill={colors[d.cluster%5]} opacity={0.7}><title>{d.label} ({d.type})</title></circle>);})}<text x="300" y="295" textAnchor="middle" fontSize="10" fill="#94a3b8">2D Embedding Projection</text></svg><div style={{marginTop:8,display:'flex',gap:12,fontSize:11,color:'#64748b'}}><span style={{color:'#3b82f6'}}>β document</span><span style={{color:'#22c55e'}}>β code</span><span style={{color:'#f59e0b'}}>β config</span><span style={{color:'#8b5cf6'}}>β api</span><span style={{color:'#ec4899'}}>β module</span></div></div>
|
|
142
|
+
</div>);}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
function KBQualityPage(){const[data,setData]=useState(null);const[loading,setLoading]=useState(true);const[page,setPage]=useState(1);const[tierFilter,setTierFilter]=useState('');const[sortBy,setSortBy]=useState('quality_score');const[sortDir,setSortDir]=useState('desc');
|
|
146
|
+
const load=(p,tier,sb,sd)=>{const params='?page='+p+'&pageSize=20&sortBy='+sb+'&sortDir='+sd+(tier?'&tier='+tier:'');api('/kb/quality'+params).then(d=>{if(d&&!d.__error)setData(d);setLoading(false);});};
|
|
147
|
+
useEffect(()=>{load(page,tierFilter,sortBy,sortDir);},[page,tierFilter,sortBy,sortDir]);
|
|
148
|
+
const toggleSort=(col)=>{if(sortBy===col)setSortDir(d=>d==='asc'?'desc':'asc');else{setSortBy(col);setSortDir('desc');}setPage(1);};
|
|
149
|
+
const sortIcon=(col)=>sortBy===col?(sortDir==='asc'?' \u25B2':' \u25BC'):'';
|
|
150
|
+
if(loading)return<div><div className="header"><h2>KB Quality</h2></div><p style={{color:'#64748b'}}>Loading...</p></div>;
|
|
151
|
+
if(!data)return<div><div className="header"><h2>KB Quality</h2></div><p>No data</p></div>;
|
|
152
|
+
const{entries,total,totalPages,distribution,summary}=data;
|
|
153
|
+
const maxD=Math.max(...(distribution||[]).map(d=>d.count),1);
|
|
154
|
+
const statusColor=(s)=>s==='good'?'badge-green':s==='fair'?'badge-yellow':'badge-red';
|
|
155
|
+
return(<div><div className="header"><h2>KB Quality</h2><span className="badge badge-blue" style={{fontSize:14,padding:'4px 12px'}}>{total} entries</span></div>
|
|
156
|
+
<div className="grid"><div className="card"><h3>Average Score</h3><div className="value">{((summary?.avgScore||0)*100).toFixed(0)}%</div></div><div className="card"><h3>Good (≥70%)</h3><div className="value" style={{color:'#166534'}}>{summary?.good||0}</div></div><div className="card"><h3>Fair (40-70%)</h3><div className="value" style={{color:'#92400e'}}>{summary?.fair||0}</div></div><div className="card"><h3>Poor (<40%)</h3><div className="value" style={{color:'#991b1b'}}>{summary?.poor||0}</div></div></div>
|
|
157
|
+
<div className="card" style={{marginTop:16}}><h3 style={{marginBottom:12}}>Quality Distribution</h3><svg width="100%" viewBox="0 0 600 160" style={{display:'block'}}>{(distribution||[]).map((d,i)=>{const barH=(d.count/maxD)*110;return(<g key={i}><rect x={50+i*52} y={130-barH} width={44} height={barH} fill={i<4?'#ef4444':i<7?'#f59e0b':'#22c55e'} rx={3} opacity={0.8}/><text x={50+i*52+22} y={148} textAnchor="middle" fontSize="9" fill="#64748b">{d.range}</text><text x={50+i*52+22} y={125-barH} textAnchor="middle" fontSize="9" fill="#475569">{d.count}</text></g>);})}</svg></div>
|
|
158
|
+
<div className="card" style={{marginTop:16}}><div className="toolbar"><select className="filter-input" style={{width:140}} value={tierFilter} onChange={e=>{setTierFilter(e.target.value);setPage(1);}}><option value="">All Tiers</option><option value="USER">USER</option><option value="PROJECT">PROJECT</option><option value="SHARED">SHARED</option></select></div>
|
|
159
|
+
<table><thead><tr><th>#</th><th style={{cursor:'pointer'}} onClick={()=>toggleSort('source')}>Entry{sortIcon('source')}</th><th>Type</th><th style={{cursor:'pointer'}} onClick={()=>toggleSort('tier')}>Tier{sortIcon('tier')}</th><th style={{cursor:'pointer'}} onClick={()=>toggleSort('quality_score')}>Quality Score{sortIcon('quality_score')}</th><th>Status</th></tr></thead><tbody>
|
|
160
|
+
{(entries||[]).map((e,i)=>(<tr key={e.id||i}><td>{(page-1)*20+i+1}</td><td>{e.source||'-'}</td><td style={{fontSize:12,color:'#64748b'}}>{e.type||'-'}</td><td><span className="badge badge-blue">{e.tier}</span></td><td><div style={{display:'flex',alignItems:'center',gap:8}}><div className="score-bar" style={{width:80}}><div className="score-fill" style={{width:(e.qualityScore*100)+'%',background:e.qualityScore>=0.7?'#22c55e':e.qualityScore>=0.4?'#f59e0b':'#ef4444'}}/></div><span style={{fontSize:12}}>{(e.qualityScore*100).toFixed(0)}%</span></div></td><td><span className={'badge '+statusColor(e.status)}>{e.status}</span></td></tr>))}
|
|
161
|
+
{(!entries||entries.length===0)&&<tr><td colSpan={6} style={{textAlign:'center',color:'#94a3b8'}}>No entries</td></tr>}</tbody></table>
|
|
162
|
+
{totalPages>1&&<div style={{marginTop:12,display:'flex',gap:8,alignItems:'center'}}><button className="btn btn-sm btn-outline" disabled={page<=1} onClick={()=>setPage(p=>p-1)}>Prev</button><span style={{fontSize:12,color:'#64748b'}}>Page {page}/{totalPages}</span><button className="btn btn-sm btn-outline" disabled={page>=totalPages} onClick={()=>setPage(p=>p+1)}>Next</button></div>}</div></div>);}
|
|
163
|
+
|
|
164
|
+
function KBTagsPage(){const[tags,setTags]=useState([]);const[loading,setLoading]=useState(true);const[newTag,setNewTag]=useState('');const[msg,setMsg]=useState('');const[renameTag,setRenameTag]=useState(null);const[renameTo,setRenameTo]=useState('');const[mergeSource,setMergeSource]=useState('');const[mergeTarget,setMergeTarget]=useState('');const[showMerge,setShowMerge]=useState(false);const[selectedTag,setSelectedTag]=useState(null);const[tagEntries,setTagEntries]=useState([]);
|
|
165
|
+
const load=()=>{api('/kb/tags').then(d=>{if(d&&!d.__error)setTags(d.tags||[]);setLoading(false);});};
|
|
166
|
+
useEffect(()=>{load();},[]);
|
|
167
|
+
const createTag=()=>{if(!newTag.trim())return;api('/kb/tags',{method:'POST',body:JSON.stringify({name:newTag.trim()})}).then(d=>{if(d&&!d.__error){setMsg('Tag created');setNewTag('');load();}else setMsg(d?.error||'Failed');});};
|
|
168
|
+
const deleteTag=(name)=>{if(!confirm('Delete tag "'+name+'"?'))return;api('/kb/tags/'+encodeURIComponent(name),{method:'DELETE'}).then(d=>{if(d&&!d.__error){setMsg('Tag deleted');load();}});};
|
|
169
|
+
const doRename=()=>{if(!renameTag||!renameTo.trim())return;api('/kb/tags/'+encodeURIComponent(renameTag),{method:'PUT',body:JSON.stringify({name:renameTo.trim()})}).then(d=>{if(d&&!d.__error){setMsg('Renamed ('+d.entriesAffected+' entries)');setRenameTag(null);setRenameTo('');load();}});};
|
|
170
|
+
const doMerge=()=>{if(!mergeSource||!mergeTarget)return;api('/kb/tags/merge',{method:'POST',body:JSON.stringify({sourceTag:mergeSource,targetTag:mergeTarget})}).then(d=>{if(d&&!d.__error){setMsg('Merged ('+d.entriesAffected+' entries)');setShowMerge(false);setMergeSource('');setMergeTarget('');load();}else setMsg(d?.error||'Failed');});};
|
|
171
|
+
const viewEntries=(name)=>{setSelectedTag(name);api('/kb/tags/'+encodeURIComponent(name)+'/entries').then(d=>{if(d&&!d.__error)setTagEntries(d.entries||[]);});};
|
|
172
|
+
if(loading)return<div><div className="header"><h2>KB Tags</h2></div><p style={{color:'#64748b'}}>Loading...</p></div>;
|
|
173
|
+
return(<div><div className="header"><h2>KB Tags</h2><span className="badge badge-blue" style={{fontSize:14,padding:'4px 12px'}}>{tags.length} tags</span></div>
|
|
174
|
+
{msg&&<div className="card" style={{background:'#f0fdf4',border:'1px solid #86efac'}}><span style={{fontSize:13}}>{msg}</span><button className="btn btn-sm btn-outline" style={{marginLeft:12}} onClick={()=>setMsg('')}>x</button></div>}
|
|
175
|
+
<div className="card"><div className="toolbar"><input className="filter-input" style={{width:200}} placeholder="New tag name..." value={newTag} onChange={e=>setNewTag(e.target.value)} onKeyDown={e=>e.key==='Enter'&&createTag()}/><button className="btn btn-sm btn-primary" onClick={createTag}>Create Tag</button><button className="btn btn-sm btn-outline" onClick={()=>setShowMerge(!showMerge)}>{showMerge?'Cancel Merge':'Merge Tags'}</button></div>
|
|
176
|
+
{showMerge&&<div style={{padding:8,background:'#fef3c7',borderRadius:6,marginBottom:8,display:'flex',gap:8,alignItems:'center'}}><select className="filter-input" style={{width:160,marginBottom:0}} value={mergeSource} onChange={e=>setMergeSource(e.target.value)}><option value="">Source tag...</option>{tags.map(t=>(<option key={t.name} value={t.name}>{t.name} ({t.entryCount})</option>))}</select><span>→</span><select className="filter-input" style={{width:160,marginBottom:0}} value={mergeTarget} onChange={e=>setMergeTarget(e.target.value)}><option value="">Target tag...</option>{tags.filter(t=>t.name!==mergeSource).map(t=>(<option key={t.name} value={t.name}>{t.name} ({t.entryCount})</option>))}</select><button className="btn btn-sm btn-primary" onClick={doMerge} disabled={!mergeSource||!mergeTarget}>Merge</button></div>}
|
|
177
|
+
{renameTag&&<div style={{padding:8,background:'#eff6ff',borderRadius:6,marginBottom:8,display:'flex',gap:8,alignItems:'center'}}>Rename "{renameTag}" to: <input className="filter-input" style={{width:200,marginBottom:0}} value={renameTo} onChange={e=>setRenameTo(e.target.value)} onKeyDown={e=>e.key==='Enter'&&doRename()}/><button className="btn btn-sm btn-primary" onClick={doRename}>Save</button><button className="btn btn-sm btn-outline" onClick={()=>setRenameTag(null)}>Cancel</button></div>}
|
|
178
|
+
<table><thead><tr><th>#</th><th>Tag Name</th><th>Entry Count</th><th>Last Used</th><th>Actions</th></tr></thead><tbody>
|
|
179
|
+
{tags.map((t,i)=>(<tr key={t.name}><td>{i+1}</td><td><span style={{cursor:'pointer',color:'#3b82f6',fontWeight:500}} onClick={()=>viewEntries(t.name)}>{t.name}</span></td><td><span className="badge badge-blue">{t.entryCount}</span></td><td style={{fontSize:12}}>{t.lastUsed?new Date(t.lastUsed).toLocaleDateString():'-'}</td><td><button className="btn btn-sm btn-outline" onClick={()=>{setRenameTag(t.name);setRenameTo(t.name);}}>Rename</button>{' '}<button className="btn btn-sm btn-danger" onClick={()=>deleteTag(t.name)}>Delete</button></td></tr>))}
|
|
180
|
+
{tags.length===0&&<tr><td colSpan={5} style={{textAlign:'center',color:'#94a3b8'}}>No tags yet</td></tr>}</tbody></table></div>
|
|
181
|
+
{selectedTag&&<div className="card" style={{marginTop:16}}><div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:12}}><h3>Entries tagged "{selectedTag}"</h3><button className="btn btn-sm btn-outline" onClick={()=>setSelectedTag(null)}>Close</button></div>
|
|
182
|
+
{tagEntries.length===0?<p style={{color:'#94a3b8',fontSize:13}}>No entries with this tag</p>:<table><thead><tr><th>#</th><th>Source</th><th>Tier</th><th>Type</th><th>Created</th></tr></thead><tbody>{tagEntries.map((e,i)=>(<tr key={e.id||i}><td>{i+1}</td><td>{e.source||'-'}</td><td><span className="badge badge-blue">{e.tier}</span></td><td>{e.type||'-'}</td><td style={{fontSize:12}}>{e.createdAt?new Date(e.createdAt).toLocaleDateString():'-'}</td></tr>))}</tbody></table>}</div>}
|
|
183
|
+
</div>);}
|
|
184
|
+
function MCPServersPage(){const[servers,setServers]=useState([]);const[expanded,setExpanded]=useState({});const[filter,setFilter]=useState('');const[toolFilters,setToolFilters]=useState({});const[logs,setLogs]=useState({});const[showLogs,setShowLogs]=useState(null);const[showAdd,setShowAdd]=useState(false);const[addForm,setAddForm]=useState({name:'',url:'',type:'stdio',command:'',args:[],env:{},disabled:false});const[addError,setAddError]=useState('');const[editServer,setEditServer]=useState(null);const[editForm,setEditForm]=useState({});const[editError,setEditError]=useState('');
|
|
185
|
+
const load=()=>{api('/mcp/servers').then(d=>{if(d)setServers(d.servers||[]);});};useEffect(()=>{load();},[]);
|
|
186
|
+
const toggle=(id)=>setExpanded(p=>({...p,[id]:!p[id]}));
|
|
187
|
+
const restart=(id)=>api('/mcp/servers/'+id+'/restart',{method:'POST'}).then(()=>{load();loadLogs(id);});
|
|
188
|
+
const toggleTool=(serverId,toolName,enabled)=>{api('/mcp/servers/'+serverId+'/tools/'+encodeURIComponent(toolName)+'/toggle',{method:'POST',body:JSON.stringify({enabled})}).then(load);};
|
|
189
|
+
const loadLogs=(id)=>{api('/mcp/servers/'+id+'/logs').then(d=>{if(d&&!d.__error)setLogs(p=>({...p,[id]:d.logs||[]}));});};
|
|
190
|
+
const viewLogs=(id)=>{setShowLogs(showLogs===id?null:id);if(showLogs!==id)loadLogs(id);};
|
|
191
|
+
const removeServer=(name)=>{if(!confirm('Remove server "'+name+'"?'))return;api('/mcp/servers/'+encodeURIComponent(name),{method:'DELETE'}).then(d=>{if(d&&!d.__error)load();});};
|
|
192
|
+
const startEdit=(s)=>{setEditServer(s.name);setEditForm({url:s.url||'',type:s.type||s.transportType||'stdio',command:s.command||'',args:s.args||[],env:s.env||{},disabled:s.disabled||false});setEditError('');};
|
|
193
|
+
const saveEdit=async()=>{setEditError('');const body={...editForm};delete body._mode;delete body._json;if(body.type!=='stdio'){delete body.command;delete body.args;}else{delete body.url;}if(!body.args||body.args.length===0)delete body.args;if(!body.env||Object.keys(body.env).length===0)delete body.env;const res=await api('/mcp/servers/'+encodeURIComponent(editServer),{method:'PUT',body:JSON.stringify(body)});if(res&&res.__error){setEditError(res.error||'Update failed');}else{setEditServer(null);load();}};
|
|
194
|
+
const addServer=async()=>{setAddError('');if(!addForm.name){setAddError('Name is required');return;}if(!addForm.url&&!addForm.command){setAddError('URL or command is required');return;}const body={...addForm};if(body.type!=='stdio'){delete body.command;delete body.args;}else{delete body.url;}if(!body.args||body.args.length===0)delete body.args;if(!body.env||Object.keys(body.env).length===0)delete body.env;const res=await api('/mcp/servers',{method:'POST',body:JSON.stringify(body)});if(res&&res.__error){setAddError(res.error||'Failed to add server');}else{setShowAdd(false);setAddForm({name:'',url:'',type:'httpStream',command:'',args:[],env:{},disabled:false});load();}};
|
|
195
|
+
const filtered=servers.filter(s=>!filter||s.name?.toLowerCase().includes(filter.toLowerCase()));
|
|
196
|
+
return(<div><div className="header"><h2>MCP Servers</h2><button className="btn btn-primary btn-sm" onClick={()=>setShowAdd(!showAdd)}>{showAdd?'Cancel':'+ Add Server'}</button></div>
|
|
197
|
+
{showAdd&&<div className="card" style={{marginBottom:12,padding:16}}><h3 style={{marginBottom:8}}>Add MCP Server</h3><div style={{display:'flex',gap:8,marginBottom:8}}><button className={'btn btn-sm '+(addForm._mode!=='json'?'btn-primary':'btn-outline')} onClick={()=>setAddForm(p=>({...p,_mode:'form'}))}>Form</button><button className={'btn btn-sm '+(addForm._mode==='json'?'btn-primary':'btn-outline')} onClick={()=>setAddForm(p=>({...p,_mode:'json',_json:JSON.stringify({name:p.name||'server-name',url:p.url||'',type:p.type||'httpStream',command:p.command||'',args:p.args||[],env:p.env||{}},null,2)}))}>JSON</button></div>{addError&&<div style={{background:'#fee2e2',color:'#991b1b',padding:'6px 10px',borderRadius:4,marginBottom:8,fontSize:12}}>{addError}</div>}{addForm._mode==='json'?<div><textarea className="input" style={{height:200,fontFamily:'monospace',fontSize:11,width:'100%'}} value={addForm._json||''} onChange={e=>setAddForm(p=>({...p,_json:e.target.value}))} placeholder='{"name":"stitch","command":"npx.cmd","args":["-y","@pkg/server"],"type":"stdio","env":{"KEY":"val"}}'/><div style={{marginTop:8}}><button className="btn btn-primary btn-sm" onClick={()=>{try{let raw=(addForm._json||'{}').trim();if(raw.startsWith('"'))raw='{'+raw+'}';const parsed=JSON.parse(raw);let body;if(parsed.name){body=parsed;}else{const keys=Object.keys(parsed);if(keys.length===1&&typeof parsed[keys[0]]==='object'){body={name:keys[0],...parsed[keys[0]]};}else{body=parsed;}}if(!body.name){setAddError('JSON must have "name" or be {"serverName":{...}}');return;}setAddError('');api('/mcp/servers',{method:'POST',body:JSON.stringify(body)}).then(r=>{if(r&&r.__error){setAddError(r.error||'Failed');}else{setShowAdd(false);setAddForm({name:'',url:'',type:'httpStream',command:'',args:[],env:{},disabled:false});load();}});}catch(e){setAddError('Invalid JSON: '+e.message);}}}>Save JSON</button></div></div>:<><div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:8}}><div><label style={{fontSize:11,color:'#64748b'}}>Name *</label><input className="input" value={addForm.name} onChange={e=>setAddForm(p=>({...p,name:e.target.value}))} placeholder="e.g. atlassian"/></div><div><label style={{fontSize:11,color:'#64748b'}}>Transport Type *</label><select className="input" value={addForm.type} onChange={e=>setAddForm(p=>({...p,type:e.target.value}))}><option value="httpStream">HTTP Stream</option><option value="sse">SSE</option><option value="stdio">stdio</option></select></div><div><label style={{fontSize:11,color:'#64748b'}}>{addForm.type==='stdio'?'Command *':'URL *'}</label><input className="input" value={addForm.type==='stdio'?addForm.command:addForm.url} onChange={e=>setAddForm(p=>addForm.type==='stdio'?{...p,command:e.target.value}:{...p,url:e.target.value})} placeholder={addForm.type==='stdio'?'npx.cmd':'http://localhost:3062/mcp'}/></div>{addForm.type==='stdio'&&<div><label style={{fontSize:11,color:'#64748b'}}>Args (comma-separated)</label><input className="input" value={(addForm.args||[]).join(', ')} onChange={e=>setAddForm(p=>({...p,args:e.target.value?e.target.value.split(',').map(a=>a.trim()):[]}))} placeholder="-y, @package/server, proxy"/></div>}<div style={{gridColumn:'1/3'}}><label style={{fontSize:11,color:'#64748b'}}>Env Variables (KEY=VALUE per line)</label><textarea className="input" style={{height:60,fontFamily:'monospace',fontSize:11}} value={Object.entries(addForm.env||{}).map(([k,v])=>k+'='+v).join('\n')} onChange={e=>{const env={};e.target.value.split('\n').forEach(line=>{const idx=line.indexOf('=');if(idx>0)env[line.slice(0,idx).trim()]=line.slice(idx+1);});setAddForm(p=>({...p,env}));}} placeholder="API_KEY=your-key-here PROJECT_ID=my-project"/></div></div><div style={{marginTop:8,display:'flex',gap:8,alignItems:'center'}}><label style={{fontSize:12}}><input type="checkbox" checked={addForm.disabled} onChange={e=>setAddForm(p=>({...p,disabled:e.target.checked}))}/> Disabled</label><button className="btn btn-primary btn-sm" onClick={addServer}>Save</button></div></>}</div>}
|
|
198
|
+
<div className="card"><input className="filter-input" placeholder="Filter servers..." value={filter} onChange={e=>setFilter(e.target.value)}/>
|
|
199
|
+
<table><thead><tr><th style={{width:30}}></th><th>Server</th><th>Status</th><th>Tools</th><th>Actions</th></tr></thead><tbody>
|
|
200
|
+
{filtered.map(s=>(<React.Fragment key={s.id||s.name}>
|
|
201
|
+
<tr className={expanded[s.name]?'expanded-row':''}><td><span className="expand-btn" onClick={()=>toggle(s.name)}>{expanded[s.name]?'βΌ':'βΆ'}</span></td><td><strong>{s.name}</strong></td><td><span className={'badge '+(s.status==='running'||s.status==='connected'?'badge-green':'badge-red')}>{s.status}</span></td><td>{(s.tools||[]).length}</td><td><button className="btn btn-sm btn-outline" onClick={()=>restart(s.name)}>Restart</button>{' '}<button className="btn btn-sm btn-outline" onClick={()=>startEdit(s)}>Edit</button>{' '}<button className="btn btn-sm btn-outline" onClick={()=>viewLogs(s.name)}>{showLogs===s.name?'Hide Logs':'Logs'}</button>{' '}<button className="btn btn-sm btn-outline" style={{color:'#ef4444'}} onClick={()=>removeServer(s.name)}>Remove</button></td></tr>
|
|
202
|
+
{editServer===s.name&&<tr><td colSpan={5}><div style={{padding:12,background:'#f1f5f9',borderRadius:6}}><div style={{display:'flex',gap:8,marginBottom:8}}><button className={'btn btn-sm '+(editForm._mode!=='json'?'btn-primary':'btn-outline')} onClick={()=>setEditForm(p=>({...p,_mode:'form'}))}>Form</button><button className={'btn btn-sm '+(editForm._mode==='json'?'btn-primary':'btn-outline')} onClick={()=>setEditForm(p=>({...p,_mode:'json',_json:JSON.stringify({url:p.url||undefined,type:p.type||'stdio',command:p.command||undefined,args:p.args&&p.args.length?p.args:undefined,env:p.env&&Object.keys(p.env).length?p.env:undefined,disabled:p.disabled||false},null,2)}))}>JSON</button></div>{editError&&<div style={{background:'#fee2e2',color:'#991b1b',padding:'4px 8px',borderRadius:4,marginBottom:8,fontSize:12}}>{editError}</div>}{editForm._mode==='json'?<div><textarea className="input" style={{height:160,fontFamily:'monospace',fontSize:11,width:'100%'}} value={editForm._json||''} onChange={e=>setEditForm(p=>({...p,_json:e.target.value}))}/><div style={{marginTop:8,display:'flex',gap:6}}><button className="btn btn-primary btn-sm" onClick={()=>{try{const parsed=JSON.parse(editForm._json||'{}');setEditError('');api('/mcp/servers/'+encodeURIComponent(editServer),{method:'PUT',body:JSON.stringify(parsed)}).then(r=>{if(r&&r.__error){setEditError(r.error||'Failed');}else{setEditServer(null);load();}});}catch(e){setEditError('Invalid JSON: '+e.message);}}}>Save JSON</button><button className="btn btn-sm btn-outline" onClick={()=>setEditServer(null)}>Cancel</button></div></div>:<div><div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:8}}><div><label style={{fontSize:11}}>Type</label><select className="input" value={editForm.type} onChange={e=>setEditForm(p=>({...p,type:e.target.value}))}><option value="httpStream">HTTP Stream</option><option value="sse">SSE</option><option value="stdio">stdio</option></select></div><div><label style={{fontSize:11}}>{editForm.type==='stdio'?'Command':'URL'}</label><input className="input" value={editForm.type==='stdio'?(editForm.command||''):(editForm.url||'')} onChange={e=>setEditForm(p=>editForm.type==='stdio'?{...p,command:e.target.value}:{...p,url:e.target.value})}/></div>{editForm.type==='stdio'&&<div><label style={{fontSize:11}}>Args (comma-separated)</label><input className="input" value={(editForm.args||[]).join(', ')} onChange={e=>setEditForm(p=>({...p,args:e.target.value?e.target.value.split(',').map(a=>a.trim()):[]}))} /></div>}<div style={{gridColumn:'1/3'}}><label style={{fontSize:11}}>Env Variables (KEY=VALUE per line)</label><textarea className="input" style={{height:50,fontFamily:'monospace',fontSize:11}} value={Object.entries(editForm.env||{}).map(([k,v])=>k+'='+v).join('\n')} onChange={e=>{const env={};e.target.value.split('\n').forEach(line=>{const idx=line.indexOf('=');if(idx>0)env[line.slice(0,idx).trim()]=line.slice(idx+1);});setEditForm(p=>({...p,env}));}}/></div></div><div style={{marginTop:8,display:'flex',gap:6,alignItems:'center'}}><label style={{fontSize:11}}><input type="checkbox" checked={editForm.disabled||false} onChange={e=>setEditForm(p=>({...p,disabled:e.target.checked}))}/> Disabled</label><button className="btn btn-primary btn-sm" onClick={saveEdit}>Save</button><button className="btn btn-sm btn-outline" onClick={()=>setEditServer(null)}>Cancel</button></div></div>}</div></td></tr>}
|
|
203
|
+
{expanded[s.name]&&<tr><td colSpan={5} style={{padding:0}}><div className="sub-table"><div style={{padding:'8px 12px'}}><input className="filter-input" placeholder="Filter tools..." value={toolFilters[s.name]||''} onChange={e=>setToolFilters(p=>({...p,[s.name]:e.target.value}))}/></div><table><thead><tr><th style={{width:40}}>#</th><th>Tool Name</th><th style={{width:80}}>Enabled</th></tr></thead><tbody>
|
|
204
|
+
{(s.tools||[]).filter(t=>{const n=typeof t==='string'?t:t.name;return!(toolFilters[s.name])||n.toLowerCase().includes((toolFilters[s.name]||'').toLowerCase());}).map((t,i)=>{const name=typeof t==='string'?t:t.name;const enabled=typeof t==='object'?t.enabled!==false:true;return(<tr key={name}><td>{i+1}</td><td>{name}</td><td><label className="toggle-switch"><input type="checkbox" checked={enabled} onChange={e=>toggleTool(s.name,name,e.target.checked)}/><span className="toggle-slider"></span></label></td></tr>);})}</tbody></table></div></td></tr>}
|
|
205
|
+
{showLogs===s.name&&<tr><td colSpan={5} style={{padding:0}}><div style={{maxHeight:250,overflow:'auto',background:'#1e293b',borderRadius:6,margin:8,padding:8}}>{(logs[s.name]||[]).length===0?<p style={{color:'#94a3b8',fontSize:12}}>No logs yet</p>:(logs[s.name]||[]).map((l,i)=>(<div key={i} className="log-line"><span className="ts">{new Date(l.timestamp).toLocaleTimeString()}</span><span className={'lvl-'+l.level}>[{l.level}]</span> <span style={{color:'#e2e8f0'}}>{l.message}</span></div>))}</div></td></tr>}
|
|
206
|
+
</React.Fragment>))}
|
|
207
|
+
{filtered.length===0&&<tr><td colSpan={5} style={{textAlign:'center',color:'#94a3b8'}}>No servers</td></tr>}
|
|
208
|
+
</tbody></table></div></div>);}
|
|
209
|
+
|
|
210
|
+
function UsersPage(){const[users,setUsers]=useState([]);const[filter,setFilter]=useState('');const[showCreate,setShowCreate]=useState(false);const[groups,setGroups]=useState([]);const[msg,setMsg]=useState('');const[page,setPage]=useState(1);const[total,setTotal]=useState(0);const pageSize=50;
|
|
211
|
+
const load=(p)=>{api('/users?page='+p+'&pageSize='+pageSize).then(d=>{if(d&&!d.__error){setUsers(d.users||[]);setTotal(d.total||0);}});};
|
|
212
|
+
useEffect(()=>{load(page);api('/rbac/groups').then(d=>{if(d&&!d.__error)setGroups(d.groups||[]);});},[page]);
|
|
213
|
+
const filtered=users.filter(u=>!filter||(u.username||'').toLowerCase().includes(filter.toLowerCase())||(u.email||'').toLowerCase().includes(filter.toLowerCase()));
|
|
214
|
+
const toggleStatus=(u)=>{const ns=u.status==='ACTIVE'?'DISABLED':'ACTIVE';if(!confirm((ns==='DISABLED'?'Disable':'Enable')+' "'+u.username+'"?'))return;api('/users/'+u.userId+'/status',{method:'PUT',body:JSON.stringify({status:ns})}).then(d=>{if(d&&!d.__error){setMsg(u.username+' '+ns.toLowerCase());load(page);}});};
|
|
215
|
+
const forceLogout=(u)=>{if(!confirm('Force logout?'))return;api('/users/'+u.userId+'/force-logout',{method:'POST'}).then(d=>{if(d&&!d.__error)setMsg('Terminated '+d.terminated+' sessions');});};
|
|
216
|
+
const resetPwd=(u)=>{if(!confirm('Reset password?'))return;api('/users/'+u.userId+'/reset-password',{method:'POST'}).then(d=>{if(d&&!d.__error)setMsg('Temp: '+d.temporaryPassword);});};
|
|
217
|
+
const del=(u)=>{if(!confirm('DELETE "'+u.username+'"?'))return;api('/users/'+u.userId,{method:'DELETE'}).then(d=>{if(d&&!d.__error){setMsg('Deleted');load(page);}else setMsg(d?.error||'Failed');});};
|
|
218
|
+
const doExportCSV=()=>{exportCSV(users.map(u=>({username:u.username,email:u.email,status:u.status,group:u.accessGroupName||u.accessGroupId,lastLogin:u.lastLogin||''})),'users.csv');};
|
|
219
|
+
const totalPages=Math.ceil(total/pageSize);
|
|
220
|
+
return(<div><div className="header"><h2>Users</h2><div style={{display:'flex',gap:8}}><button className="btn btn-sm btn-outline" onClick={doExportCSV}>Export CSV</button><button className="btn btn-primary" onClick={()=>setShowCreate(true)}>+ New User</button></div></div>
|
|
221
|
+
{msg&&<div className="card" style={{background:'#f0fdf4',border:'1px solid #86efac'}}><span style={{fontSize:13}}>{msg}</span><button className="btn btn-sm btn-outline" style={{marginLeft:12}} onClick={()=>setMsg('')}>x</button></div>}
|
|
222
|
+
{showCreate&&<CreateUserForm groups={groups} onDone={()=>{setShowCreate(false);load(page);}} onCancel={()=>setShowCreate(false)}/>}
|
|
223
|
+
<div className="card"><input className="filter-input" placeholder="Filter users..." value={filter} onChange={e=>setFilter(e.target.value)}/><table><thead><tr><th>Username</th><th>Email</th><th>Group</th><th>Status</th><th>Last Login</th><th>Actions</th></tr></thead><tbody>
|
|
224
|
+
{filtered.map(u=>(<tr key={u.userId}><td><strong>{u.username}</strong>{u.forcePasswordChange&&<span className="badge badge-yellow" style={{marginLeft:6}}>pwd</span>}</td><td>{u.email||'-'}</td><td><span className="badge badge-blue">{u.accessGroupName||u.accessGroupId}</span></td><td><span className={'badge '+(u.status==='ACTIVE'?'badge-green':'badge-red')}>{u.status}</span></td><td style={{fontSize:12}}>{u.lastLogin?new Date(u.lastLogin).toLocaleString():'-'}</td><td><button className="btn btn-sm btn-outline" onClick={()=>toggleStatus(u)}>{u.status==='ACTIVE'?'Disable':'Enable'}</button>{' '}<button className="btn btn-sm btn-outline" onClick={()=>forceLogout(u)}>Logout</button>{' '}<button className="btn btn-sm btn-outline" onClick={()=>resetPwd(u)}>Reset</button>{' '}{u.username!=='admin'&&<button className="btn btn-sm btn-danger" onClick={()=>del(u)}>Del</button>}</td></tr>))}
|
|
225
|
+
{filtered.length===0&&<tr><td colSpan={6} style={{textAlign:'center',color:'#94a3b8'}}>No users</td></tr>}</tbody></table>
|
|
226
|
+
{totalPages>1&&<div style={{marginTop:12,display:'flex',gap:8,alignItems:'center'}}><button className="btn btn-sm btn-outline" disabled={page<=1} onClick={()=>setPage(p=>p-1)}>Prev</button><span style={{fontSize:12,color:'#64748b'}}>Page {page}/{totalPages}</span><button className="btn btn-sm btn-outline" disabled={page>=totalPages} onClick={()=>setPage(p=>p+1)}>Next</button></div>}
|
|
227
|
+
</div></div>);}
|
|
228
|
+
|
|
229
|
+
function CreateUserForm({groups,onDone,onCancel}){const[username,setUsername]=useState('');const[email,setEmail]=useState('');const[password,setPassword]=useState('');const[groupId,setGroupId]=useState(groups[0]?.id||groups[0]?.accessGroupId||'');const[error,setError]=useState('');const submit=async()=>{setError('');if(!username||!password){setError('Required');return;}const res=await api('/users',{method:'POST',body:JSON.stringify({username,email,password,accessGroupId:groupId})});if(res&&!res.__error)onDone();else setError(res?.error||'Failed');};return(<div className="card" style={{border:'2px solid #3b82f6'}}><h4 style={{marginBottom:12}}>Create User</h4>{error&&<div style={{color:'#dc2626',fontSize:13,marginBottom:8}}>{error}</div>}<div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:8,marginBottom:12}}><input className="input" placeholder="Username" value={username} onChange={e=>setUsername(e.target.value)}/><input className="input" placeholder="Email" value={email} onChange={e=>setEmail(e.target.value)}/><input className="input" type="password" placeholder="Password" value={password} onChange={e=>setPassword(e.target.value)}/><select className="input" value={groupId} onChange={e=>setGroupId(e.target.value)}>{groups.map(g=>(<option key={g.id||g.accessGroupId} value={g.id||g.accessGroupId}>{g.name||g.accessGroupName}</option>))}</select></div><button className="btn btn-primary" onClick={submit}>Create</button>{' '}<button className="btn btn-outline" onClick={onCancel}>Cancel</button></div>);}
|
|
230
|
+
|
|
231
|
+
function RBACPage(){const[groups,setGroups]=useState([]);const[filter,setFilter]=useState('');const[editing,setEditing]=useState(null);const[mcpTools,setMcpTools]=useState({});
|
|
232
|
+
useEffect(()=>{api('/rbac/groups').then(d=>{if(d)setGroups(d.groups||[]);});api('/mcp/servers').then(d=>{if(!d)return;const map={};(d.servers||[]).forEach(s=>{map[s.name]=(s.tools||[]).map(t=>typeof t==='string'?t:t.name);});setMcpTools(map);});},[]);
|
|
233
|
+
const filtered=groups.filter(g=>!filter||(g.name||'').toLowerCase().includes(filter.toLowerCase()));
|
|
234
|
+
const startEdit=(g)=>setEditing(JSON.parse(JSON.stringify(g)));
|
|
235
|
+
const saveGroup=()=>{const method=editing.id?'PUT':'POST';const path=editing.id?'/rbac/groups/'+editing.id:'/rbac/groups';api(path,{method,body:JSON.stringify(editing)}).then(()=>{setEditing(null);api('/rbac/groups').then(d=>{if(d)setGroups(d.groups||[]);});window.dispatchEvent(new CustomEvent('rbac-changed'));});};
|
|
236
|
+
const deleteGroup=(g)=>{if(!confirm('Delete "'+g.name+'"?'))return;api('/rbac/groups/'+g.id,{method:'DELETE'}).then(()=>{api('/rbac/groups').then(d=>{if(d)setGroups(d.groups||[]);});window.dispatchEvent(new CustomEvent('rbac-changed'));});};
|
|
237
|
+
if(editing)return<RBACEditForm group={editing} setGroup={setEditing} onSave={saveGroup} onCancel={()=>setEditing(null)} mcpTools={mcpTools}/>;
|
|
238
|
+
return(<div><div className="header"><h2>RBAC</h2><button className="btn btn-primary" onClick={()=>startEdit({name:'',permissions:[],isSystem:false})}>+ New Group</button></div><div className="card"><input className="filter-input" placeholder="Filter..." value={filter} onChange={e=>setFilter(e.target.value)}/><table><thead><tr><th>Group</th><th>Users</th><th>Permissions</th><th>System</th><th>Actions</th></tr></thead><tbody>{filtered.map(g=>(<tr key={g.id||g.name}><td><strong>{g.name}</strong></td><td>{g.userCount||0}</td><td>{(g.permissions||[]).length}</td><td>{g.isSystem?'β':''}</td><td><button className="btn btn-sm btn-outline" onClick={()=>startEdit(g)}>Edit</button>{' '}{!g.isSystem&&<button className="btn btn-sm btn-danger" onClick={()=>deleteGroup(g)}>Delete</button>}</td></tr>))}{filtered.length===0&&<tr><td colSpan={5} style={{textAlign:'center',color:'#94a3b8'}}>No groups</td></tr>}</tbody></table></div></div>);}
|
|
239
|
+
|
|
240
|
+
function RBACEditForm({group,setGroup,onSave,onCancel,mcpTools}){const allPerms=Object.keys(RULES);const[permFilter,setPermFilter]=useState('');const[expandedPerms,setExpandedPerms]=useState({});
|
|
241
|
+
const filteredPerms=allPerms.filter(p=>!permFilter||p.toLowerCase().includes(permFilter.toLowerCase()));
|
|
242
|
+
const isOn=(perm)=>(group.permissions||[]).some(p=>(typeof p==='string'?p:p.name)===perm);
|
|
243
|
+
const togglePerm=(perm)=>{const perms=group.permissions||[];if(isOn(perm))setGroup({...group,permissions:perms.filter(p=>(typeof p==='string'?p:p.name)!==perm)});else setGroup({...group,permissions:[...perms,{name:perm,roleData:{}}]});};
|
|
244
|
+
const getObj=(perm)=>{const f=(group.permissions||[]).find(p=>(typeof p==='string'?p:p.name)===perm);if(!f)return null;return typeof f==='string'?{name:f,roleData:{}}:f;};
|
|
245
|
+
const updateRD=(perm,k,v)=>{const perms=[...(group.permissions||[])];const idx=perms.findIndex(p=>(typeof p==='string'?p:p.name)===perm);if(idx===-1)return;const obj=typeof perms[idx]==='string'?{name:perms[idx],roleData:{}}:{...perms[idx]};obj.roleData={...obj.roleData,[k]:v};perms[idx]=obj;setGroup({...group,permissions:perms});};
|
|
246
|
+
return(<div><div className="header"><h2>{group.id?'Edit':'New'} Group</h2></div><div className="card"><div style={{marginBottom:16}}><label style={{fontSize:13}}>Name</label><input className="input" style={{maxWidth:400}} value={group.name} onChange={e=>setGroup({...group,name:e.target.value})}/></div><h4 style={{marginBottom:8}}>Permissions</h4><input className="filter-input" placeholder="Filter..." value={permFilter} onChange={e=>setPermFilter(e.target.value)}/><table><thead><tr><th style={{width:40}}>β</th><th style={{width:30}}></th><th>Permission</th><th>Rules</th></tr></thead><tbody>{filteredPerms.map(perm=>{const en=isOn(perm);const rules=RULES[perm]||[];const isExp=expandedPerms[perm];return(<React.Fragment key={perm}><tr className={isExp?'expanded-row':''}><td><input type="checkbox" checked={en} onChange={()=>togglePerm(perm)}/></td><td>{en&&rules.length>0&&<span className="expand-btn" onClick={()=>setExpandedPerms(p=>({...p,[perm]:!p[perm]}))}>{isExp?'βΌ':'βΆ'}</span>}</td><td><strong>{perm}</strong></td><td><span className="badge badge-blue">{rules.length}</span></td></tr>{en&&isExp&&<tr><td colSpan={4} style={{padding:0}}><div style={{padding:'12px 16px 12px 48px',background:'#f8fafc'}}>{rules.map(rule=>(<div className="rule-row" key={rule.name}><span className="rule-label">{rule.name}</span>{rule.locked?<span className="locked"><input type="checkbox" disabled checked={rule.default}/> LOCKED</span>:rule.type==='boolean'?<input type="checkbox" checked={(getObj(perm)?.roleData||{})[rule.name]!==undefined?(getObj(perm)?.roleData||{})[rule.name]:rule.default} onChange={e=>updateRD(perm,rule.name,e.target.checked)}/>:rule.type==='number'?<input type="number" min={rule.min} max={rule.max} value={(getObj(perm)?.roleData||{})[rule.name]||rule.default} onChange={e=>updateRD(perm,rule.name,Number(e.target.value))} style={{width:80,padding:'4px',border:'1px solid #cbd5e1',borderRadius:4}}/>:rule.type==='enum[]'?<div className="perm-check">{rule.allowed.map(opt=>{const sel=(getObj(perm)?.roleData||{})[rule.name]||rule.default;const isAll=(sel||[]).includes('*');const checked=opt==='*'?isAll:(isAll||(sel||[]).includes(opt));return<label key={opt}><input type="checkbox" checked={checked} onChange={e=>{let next;if(opt==='*'){next=e.target.checked?['*']:[];}else{next=(sel||[]).filter(x=>x!=='*'&&x!==opt);if(e.target.checked)next.push(opt);if(next.length===rule.allowed.length-1)next=['*'];}updateRD(perm,rule.name,next);}}/>{opt}</label>;})}</div>:rule.type==='mcp-server-table'?(()=>{const sp=(getObj(perm)?.roleData||{})[rule.name]||{};const servers=Object.keys(mcpTools||{});return<div><table style={{fontSize:11,borderCollapse:'collapse',width:'100%'}}><thead><tr><th style={{textAlign:'left',padding:'4px 8px'}}>Server</th><th style={{padding:'4px 8px'}}>Remove</th><th style={{padding:'4px 8px'}}>Edit</th><th style={{padding:'4px 8px'}}>Restart</th></tr></thead><tbody>{servers.map(s=>{const perms=sp[s]||{allowRemove:true,allowEdit:true,allowRestart:true};return<tr key={s}><td style={{padding:'4px 8px'}}>{s}</td><td style={{textAlign:'center'}}><input type="checkbox" checked={perms.allowRemove!==false} onChange={e=>{const next={...sp,[s]:{...perms,allowRemove:e.target.checked}};updateRD(perm,rule.name,next);}}/></td><td style={{textAlign:'center'}}><input type="checkbox" checked={perms.allowEdit!==false} onChange={e=>{const next={...sp,[s]:{...perms,allowEdit:e.target.checked}};updateRD(perm,rule.name,next);}}/></td><td style={{textAlign:'center'}}><input type="checkbox" checked={perms.allowRestart!==false} onChange={e=>{const next={...sp,[s]:{...perms,allowRestart:e.target.checked}};updateRD(perm,rule.name,next);}}/></td></tr>;})}{servers.length===0&&<tr><td colSpan={4} style={{color:'#94a3b8',fontSize:11}}>No servers</td></tr>}</tbody></table></div>;})():rule.type==='mcp-tool-access-table'?(()=>{const ta=(getObj(perm)?.roleData||{})[rule.name]||{};const serverTools=mcpTools||{};return<div>{Object.entries(serverTools).map(([srv,tools])=>{const srvAccess=ta[srv]||{enabled:true,tools:{}};const isExp=expandedPerms['_tool_'+srv];return<div key={srv} style={{marginBottom:4,border:'1px solid #e2e8f0',borderRadius:4}}><div style={{display:'flex',alignItems:'center',padding:'4px 8px',background:'#f8fafc',cursor:'pointer'}} onClick={()=>setExpandedPerms(p=>({...p,['_tool_'+srv]:!p['_tool_'+srv]}))}><input type="checkbox" checked={srvAccess.enabled!==false} onClick={e=>e.stopPropagation()} onChange={e=>{const next={...ta,[srv]:{...srvAccess,enabled:e.target.checked}};updateRD(perm,rule.name,next);}}/><strong style={{marginLeft:6,fontSize:11}}>{srv}</strong><span style={{marginLeft:'auto',fontSize:10,color:'#64748b'}}>{isExp?'βΌ':'βΆ'} {(tools||[]).length} tools</span></div>{isExp&&srvAccess.enabled!==false&&<div style={{padding:'4px 8px 8px',maxHeight:200,overflow:'auto'}}>{(tools||[]).map(t=>{const allowed=(srvAccess.tools||{})[t]!==false;return<label key={t} style={{display:'block',fontSize:11,padding:'2px 0'}}><input type="checkbox" checked={allowed} onChange={e=>{const next={...ta,[srv]:{...srvAccess,tools:{...(srvAccess.tools||{}),[t]:e.target.checked}}};updateRD(perm,rule.name,next);}}/> {t}</label>;})}</div>}</div>;})}{Object.keys(serverTools).length===0&&<span style={{fontSize:11,color:'#94a3b8'}}>No MCP servers connected</span>}</div>;})():<span style={{fontSize:12,color:'#94a3b8'}}>complex</span>}</div>))}</div></td></tr>}</React.Fragment>);})}</tbody></table><div style={{marginTop:20,display:'flex',gap:8}}><button className="btn btn-primary" onClick={onSave}>Save</button><button className="btn btn-outline" onClick={onCancel}>Cancel</button></div></div></div>);}
|
|
247
|
+
|
|
248
|
+
function ConfigurationPage(){const[config,setConfig]=useState({});const[history,setHistory]=useState([]);const[restartKeys,setRestartKeys]=useState({});const[filter,setFilter]=useState('');const[editing,setEditing]=useState(null);const[editValue,setEditValue]=useState('');const[saving,setSaving]=useState(false);const[msg,setMsg]=useState('');const[activeTab,setActiveTab]=useState('all');
|
|
249
|
+
const[llmTesting,setLlmTesting]=useState(false);const[llmTestResult,setLlmTestResult]=useState(null);const[showApiKey,setShowApiKey]=useState(false);const[apiKeyInput,setApiKeyInput]=useState('');const[useDefaultUrl,setUseDefaultUrl]=useState(true);const[liveModels,setLiveModels]=useState(null);
|
|
250
|
+
const fetchModels=async(prov,baseUrl)=>{try{const d=await api('/llm/models?provider='+encodeURIComponent(prov||'')+'&baseUrl='+encodeURIComponent(baseUrl||''));if(d&&!d.__error&&d.models&&d.models.length>0)setLiveModels(d.models);else setLiveModels(null);}catch{setLiveModels(null);}};
|
|
251
|
+
const load=()=>{api('/config').then(d=>{if(d&&!d.__error){setConfig(d.config||{});setHistory(d.history||[]);setRestartKeys(d.restartRequired||{});const llm=d.config?.llm||{};const prov=llm.provider||'ollama';const defs={'ollama':'http://localhost:11434','lmstudio':'http://localhost:1234/v1','openrouter':'https://openrouter.ai/api/v1','anthropic':'https://api.anthropic.com','openai':'https://api.openai.com/v1','onnx':''};setUseDefaultUrl(!llm.baseUrl||llm.baseUrl===(defs[prov]||''));fetchModels(prov,llm.baseUrl||defs[prov]||'');}});};useEffect(()=>{load();},[]);
|
|
252
|
+
const sections=Object.keys(config).filter(s=>activeTab==='all'||s===activeTab).filter(s=>!filter||s.toLowerCase().includes(filter.toLowerCase())||Object.keys(config[s]||{}).some(k=>k.toLowerCase().includes(filter.toLowerCase())));
|
|
253
|
+
const needsRestart=(s,k)=>(restartKeys[s]||[]).includes(k);
|
|
254
|
+
const startEdit=(s,k,v)=>{setEditing({section:s,key:k});setEditValue(typeof v==='string'?v:JSON.stringify(v));};
|
|
255
|
+
const saveEdit=async()=>{if(!editing)return;setSaving(true);let pv;try{pv=JSON.parse(editValue);}catch{pv=editValue;}const res=await api('/config/'+editing.section+'/'+editing.key,{method:'PATCH',body:JSON.stringify({value:pv})});setSaving(false);if(res&&!res.__error){setMsg((res.requiresRestart?'β οΈ Restart needed β ':'β ')+'Updated');setEditing(null);load();}else setMsg('Failed');};
|
|
256
|
+
const saveLlmField=async(key,value)=>{setSaving(true);const res=await api('/config/llm/'+key,{method:'PATCH',body:JSON.stringify({value})});setSaving(false);if(res&&!res.__error){setMsg('β '+key+' updated'+(res.requiresRestart?' (restart needed)':''));load();}else setMsg('Failed to update '+key);};
|
|
257
|
+
const testLlm=async()=>{setLlmTesting(true);setLlmTestResult(null);try{const d=await api('/llm/test',{method:'POST'});if(d&&!d.__error){setLlmTestResult({success:d.success,message:(d.success?'β ':'β ')+d.message});}else{setLlmTestResult({success:false,message:d?.error||'Request failed'});}}catch(e){setLlmTestResult({success:false,message:e.message});}setLlmTesting(false);};
|
|
258
|
+
const PROVIDERS=[{id:'ollama',name:'Ollama β Local models (no API key needed)'},{id:'anthropic',name:'Anthropic β Claude models'},{id:'openai',name:'OpenAI β GPT models'},{id:'openrouter',name:'OpenRouter β Multi-model gateway'},{id:'lmstudio',name:'LM Studio β Local models'},{id:'onnx',name:'ONNX β CPU-only local (Phi-3, SmolLM2)'}];
|
|
259
|
+
const PROVIDER_DEFAULTS={'ollama':'http://localhost:11434','lmstudio':'http://localhost:1234/v1','openrouter':'https://openrouter.ai/api/v1','anthropic':'https://api.anthropic.com','openai':'https://api.openai.com/v1','onnx':''};
|
|
260
|
+
const PROVIDER_MODELS={'ollama':[{id:'llama3.1',name:'Llama 3.1'},{id:'llama3.2',name:'Llama 3.2'},{id:'codellama',name:'Code Llama'},{id:'mistral',name:'Mistral'},{id:'mixtral',name:'Mixtral'},{id:'deepseek-coder-v2',name:'DeepSeek Coder v2'},{id:'qwen2.5-coder',name:'Qwen 2.5 Coder'},{id:'qwen2.5:7b-instruct-q4_K_M',name:'Qwen 2.5 7B Q4'}],'anthropic':[{id:'claude-sonnet-4-20250514',name:'Claude Sonnet 4'},{id:'claude-opus-4-8',name:'Claude Opus 4.8'},{id:'claude-haiku-4-5-20251001',name:'Claude Haiku 4.5'}],'openai':[{id:'gpt-4o',name:'GPT-4o'},{id:'gpt-4o-mini',name:'GPT-4o Mini'},{id:'o3',name:'o3'},{id:'o4-mini',name:'o4 Mini'}],'openrouter':[{id:'anthropic/claude-sonnet-4',name:'Claude Sonnet 4'},{id:'openai/gpt-4o',name:'GPT-4o'},{id:'google/gemini-2.5-pro',name:'Gemini 2.5 Pro'},{id:'deepseek/deepseek-r1',name:'DeepSeek R1'}],'lmstudio':[{id:'local-model',name:'Local Model (auto-detect)'},{id:'qwen2.5-coder-32b',name:'Qwen 2.5 Coder 32B'}],'onnx':[{id:'phi-3-mini',name:'Phi-3 Mini (3.8B)'},{id:'smollm2-360m',name:'SmolLM2 (360M)'}]};
|
|
261
|
+
const renderLlmSection=()=>{const llm=config.llm||{};const prov=llm.provider||'ollama';const isLocal=['ollama','lmstudio','onnx'].includes(prov);const models=liveModels||PROVIDER_MODELS[prov]||[];const defUrl=PROVIDER_DEFAULTS[prov]||'';const currentModel=llm.model||'';const modelInList=models.some(m=>m.id===currentModel);return(<div style={{marginBottom:20}}><h4 style={{fontSize:14,color:'#334155',marginBottom:12}}>π€ LLM Configuration</h4><div className="card" style={{border:'2px solid #dbeafe'}}><div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:16}}><div style={{marginBottom:12}}><label style={{fontSize:13,fontWeight:600,color:'#334155',marginBottom:4,display:'block'}}>Provider</label><select className="input" style={{marginBottom:0}} value={prov} onChange={e=>{const np=e.target.value;saveLlmField('provider',np);setUseDefaultUrl(true);const nd=PROVIDER_DEFAULTS[np]||'';saveLlmField('baseUrl',nd);setLiveModels(null);fetchModels(np,nd);const dm=(PROVIDER_MODELS[np]||[])[0];if(dm)saveLlmField('model',dm.id);}}>{PROVIDERS.map(p=>(<option key={p.id} value={p.id}>{p.name}</option>))}</select></div><div style={{marginBottom:12}}><label style={{fontSize:13,fontWeight:600,color:'#334155',marginBottom:4,display:'block'}}>Model {liveModels&&<span style={{fontSize:10,color:'#16a34a'}}>β live ({models.length})</span>}{!liveModels&&<span style={{fontSize:10,color:'#94a3b8'}}>β static</span>}</label><select className="input" style={{marginBottom:0}} value={modelInList?currentModel:'__custom__'} onChange={e=>{if(e.target.value!=='__custom__')saveLlmField('model',e.target.value);}}>{models.map(m=>(<option key={m.id} value={m.id}>{m.name}</option>))}{!modelInList&¤tModel&&<option value="__custom__">β‘ {currentModel} (custom)</option>}</select>{!modelInList&¤tModel&&<div style={{fontSize:11,color:'#f59e0b',marginTop:2}}>Custom model not in list</div>}<button className="btn btn-sm btn-outline" style={{marginTop:4,fontSize:11}} onClick={()=>fetchModels(prov,llm.baseUrl||defUrl)}>β» Refresh models</button></div><div style={{marginBottom:12}}><label style={{fontSize:13,fontWeight:600,color:'#334155',marginBottom:4,display:'block'}}>Base URL {needsRestart('llm','baseUrl')&&<span className="badge badge-yellow" style={{marginLeft:6}}>Restart</span>}</label><label style={{fontSize:12,color:'#64748b',display:'flex',alignItems:'center',gap:4,marginBottom:4,cursor:'pointer'}}><input type="checkbox" checked={useDefaultUrl} onChange={e=>{setUseDefaultUrl(e.target.checked);if(e.target.checked)saveLlmField('baseUrl',defUrl);}}/> Use default URL {defUrl&&<code style={{fontSize:10,background:'#f1f5f9',padding:'1px 4px',borderRadius:3}}>{defUrl}</code>}</label><input className="input" style={{marginBottom:0,opacity:useDefaultUrl?0.5:1}} value={useDefaultUrl?defUrl:(llm.baseUrl||'')} disabled={useDefaultUrl} onChange={e=>setConfig(c=>({...c,llm:{...c.llm,baseUrl:e.target.value}}))} onBlur={e=>{if(!useDefaultUrl)saveLlmField('baseUrl',e.target.value);}}/></div><div style={{marginBottom:12}}><label style={{fontSize:13,fontWeight:600,color:'#334155',marginBottom:4,display:'block'}}>API Key {isLocal&&<span style={{fontSize:11,color:'#94a3b8'}}>(not needed)</span>}</label><div style={{display:'flex',gap:4}}><input className="input" style={{marginBottom:0,flex:1}} type={showApiKey?'text':'password'} value={apiKeyInput||(llm.apiKey==='***'?'':llm.apiKey)||''} onChange={e=>setApiKeyInput(e.target.value)} onBlur={e=>{if(e.target.value&&e.target.value!=='***')saveLlmField('apiKey',e.target.value);}} placeholder={llm.apiKey==='***'?'β’β’β’ (saved)':'Enter API key...'} disabled={isLocal}/><button className="btn btn-sm btn-outline" onClick={()=>setShowApiKey(!showApiKey)} disabled={isLocal}>{showApiKey?'π':'π'}</button>{llm.apiKey==='***'&&!isLocal&&<button className="btn btn-sm btn-danger" onClick={()=>saveLlmField('apiKey','')}>β</button>}</div>{llm.apiKey==='***'&&!isLocal&&<div style={{fontSize:11,color:'#16a34a',marginTop:2}}>β Key saved</div>}</div></div><div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr 1fr',gap:12,marginTop:8}}><div><label style={{fontSize:12,color:'#64748b'}}>Temperature</label><input className="input" style={{marginBottom:0}} type="number" step="0.1" min="0" max="2" value={llm.temperature??0.3} onChange={e=>setConfig(c=>({...c,llm:{...c.llm,temperature:parseFloat(e.target.value)}}))} onBlur={e=>saveLlmField('temperature',parseFloat(e.target.value))}/></div><div><label style={{fontSize:12,color:'#64748b'}}>Max Tokens</label><input className="input" style={{marginBottom:0}} type="number" min="1" max="8000" value={llm.maxTokens??300} onChange={e=>setConfig(c=>({...c,llm:{...c.llm,maxTokens:parseInt(e.target.value)}}))} onBlur={e=>saveLlmField('maxTokens',parseInt(e.target.value))}/></div><div><label style={{fontSize:12,color:'#64748b'}}>Tag Analysis</label><select className="input" style={{marginBottom:0}} value={String(llm.tagAnalysisEnabled??true)} onChange={e=>saveLlmField('tagAnalysisEnabled',e.target.value==='true')}><option value="true">Enabled</option><option value="false">Disabled</option></select></div><div><label style={{fontSize:12,color:'#64748b'}}>Tag Confidence</label><input className="input" style={{marginBottom:0}} type="number" step="0.1" min="0" max="1" value={llm.tagConfidenceThreshold??0.7} onChange={e=>setConfig(c=>({...c,llm:{...c.llm,tagConfidenceThreshold:parseFloat(e.target.value)}}))} onBlur={e=>saveLlmField('tagConfidenceThreshold',parseFloat(e.target.value))}/></div></div><div style={{marginTop:16,display:'flex',gap:8,alignItems:'center'}}><button className="btn btn-primary" onClick={testLlm} disabled={llmTesting}>{llmTesting?'Testing...':'π§ͺ Test LLM Connection'}</button>{llmTestResult&&<span style={{fontSize:13,color:llmTestResult.success?'#16a34a':'#dc2626'}}>{llmTestResult.message}</span>}</div></div></div>);};
|
|
262
|
+
return(<div><div className="header"><h2>Configuration</h2></div>{msg&&<div className="card" style={{background:'#f0fdf4',border:'1px solid #86efac'}}><span style={{fontSize:13}}>{msg}</span><button className="btn btn-sm btn-outline" style={{marginLeft:12}} onClick={()=>setMsg('')}>x</button></div>}<div style={{display:'flex',gap:4,marginBottom:12,flexWrap:'wrap'}}>{['all',...Object.keys(config)].map(tab=>(<button key={tab} className={'btn btn-sm '+(activeTab===tab?'btn-primary':'btn-outline')} onClick={()=>setActiveTab(tab)}>{tab==='all'?'All':tab}</button>))}</div><div className="card"><input className="filter-input" placeholder="Filter..." value={filter} onChange={e=>setFilter(e.target.value)}/>{sections.map(section=>{if(section==='llm'&&(activeTab==='all'||activeTab==='llm'))return<React.Fragment key={section}>{renderLlmSection()}</React.Fragment>;return(<div key={section} style={{marginBottom:20}}><h4 style={{fontSize:14,color:'#334155',marginBottom:8}}>{section}</h4><table><thead><tr><th>Key</th><th>Value</th><th style={{width:70}}>Restart</th><th style={{width:100}}>Actions</th></tr></thead><tbody>{Object.entries(config[section]||{}).map(([k,v])=>{const isE=editing&&editing.section===section&&editing.key===k;return(<tr key={k}><td><strong>{k}</strong></td><td>{isE?<input className="input" style={{marginBottom:0}} value={editValue} onChange={e=>setEditValue(e.target.value)}/>:<code style={{fontSize:12}}>{JSON.stringify(v)}</code>}</td><td>{needsRestart(section,k)&&<span className="badge badge-yellow">Yes</span>}</td><td>{isE?<><button className="btn btn-sm btn-primary" onClick={saveEdit} disabled={saving}>Save</button>{' '}<button className="btn btn-sm btn-outline" onClick={()=>setEditing(null)}>x</button></>:<button className="btn btn-sm btn-outline" onClick={()=>startEdit(section,k,v)}>Edit</button>}</td></tr>);})}</tbody></table></div>);})}</div>{history.length>0&&<div className="card"><h4 style={{marginBottom:8,fontSize:14}}>Recent Changes</h4><table><thead><tr><th>Time</th><th>Key</th><th>Old</th><th>New</th><th>By</th></tr></thead><tbody>{history.map((h,i)=>(<tr key={i}><td style={{fontSize:11}}>{h.changedAt?new Date(h.changedAt).toLocaleString():'-'}</td><td><code style={{fontSize:11}}>{h.section}.{h.key}</code></td><td style={{fontSize:11}}>{h.oldValue||'-'}</td><td style={{fontSize:11}}>{h.newValue}</td><td>{h.changedBy}</td></tr>))}</tbody></table></div>}</div>);}
|
|
263
|
+
|
|
264
|
+
function SearchExplorerPage(){const[query,setQuery]=useState('');const[results,setResults]=useState([]);const[debug,setDebug]=useState(true);const[debugInfo,setDebugInfo]=useState(null);
|
|
265
|
+
const doSearch=()=>{if(!query)return;api('/search',{method:'POST',body:JSON.stringify({query,debug})}).then(d=>{if(d){setResults(d.results||[]);setDebugInfo(d.debug||null);}});};
|
|
266
|
+
return(<div><div className="header"><h2>Search Explorer</h2></div><div className="card">
|
|
267
|
+
<div className="toolbar"><input className="input" style={{flex:1,marginBottom:0}} placeholder="Enter search query..." value={query} onChange={e=>setQuery(e.target.value)} onKeyDown={e=>e.key==='Enter'&&doSearch()}/><label style={{fontSize:13,display:'flex',alignItems:'center',gap:4}}><input type="checkbox" checked={debug} onChange={e=>setDebug(e.target.checked)}/>Debug</label><button className="btn btn-primary" onClick={doSearch}>Search</button></div>
|
|
268
|
+
{debugInfo&&<div style={{background:'#f8fafc',padding:8,borderRadius:6,marginBottom:12,fontSize:12}}><strong>Debug:</strong> Tokens: [{(debugInfo.queryTokens||[]).join(', ')}] | Candidates: {debugInfo.totalCandidates} | Time: {debugInfo.searchTimeMs}ms</div>}
|
|
269
|
+
{results.length>0&&<table><thead><tr><th>#</th><th>Source</th><th>Score</th>{debug&&<th>Breakdown</th>}<th>Snippet</th></tr></thead><tbody>
|
|
270
|
+
{results.map((r,i)=>(<tr key={i}><td>{i+1}</td><td><strong>{r.source}</strong><br/><span className="badge badge-blue" style={{fontSize:10}}>{r.tier}</span></td><td><strong>{r.score?.toFixed(3)}</strong></td>{debug&&<td style={{fontSize:11}}>{r.scores&&<div style={{display:'flex',flexDirection:'column',gap:2}}>{Object.entries(r.scores).map(([k,v])=>(<div key={k} style={{display:'flex',alignItems:'center',gap:4}}><span style={{width:60}}>{k}:</span><div className="score-bar" style={{width:80}}><div className="score-fill" style={{width:(v*100)+'%',background:v>0.8?'#22c55e':v>0.6?'#f59e0b':'#ef4444'}}/></div><span>{v.toFixed(2)}</span></div>))}</div>}</td>}<td style={{maxWidth:300,fontSize:12,overflow:'hidden',textOverflow:'ellipsis'}}>{r.content?.substring(0,100)}</td></tr>))}</tbody></table>}
|
|
271
|
+
</div></div>);}
|
|
272
|
+
|
|
273
|
+
function AuditTrailPage(){const[logs,setLogs]=useState([]);const[filter,setFilter]=useState('');const[total,setTotal]=useState(0);const[page,setPage]=useState(1);
|
|
274
|
+
const load=(p)=>{api('/audit?page='+p+'&pageSize=30').then(d=>{if(d&&!d.__error){setLogs(d.entries||[]);setTotal(d.total||0);}});};useEffect(()=>{load(page);},[page]);
|
|
275
|
+
const filtered=logs.filter(l=>!filter||JSON.stringify(l).toLowerCase().includes(filter.toLowerCase()));const totalPages=Math.ceil(total/30);
|
|
276
|
+
const doExportCSV=()=>{exportCSV(logs.map(l=>({time:l.timestamp,user:l.username,action:l.action,resource:l.resource,resourceId:l.resourceId,details:l.changes})),'audit-log.csv');};
|
|
277
|
+
return(<div><div className="header"><h2>Audit Trail</h2><div style={{display:'flex',gap:8}}><button className="btn btn-sm btn-outline" onClick={doExportCSV}>Export CSV</button><span className="badge badge-blue">{total} entries</span></div></div><div className="card"><input className="filter-input" placeholder="Filter..." value={filter} onChange={e=>setFilter(e.target.value)}/><table><thead><tr><th>Time</th><th>User</th><th>Action</th><th>Resource</th><th>Details</th></tr></thead><tbody>{filtered.map((l,i)=>(<tr key={l.auditId||i}><td style={{fontSize:12,whiteSpace:'nowrap'}}>{l.timestamp?new Date(l.timestamp).toLocaleString():'-'}</td><td>{l.username}</td><td><span className="badge badge-blue">{l.action}</span></td><td>{l.resource}{l.resourceId?' / '+l.resourceId:''}</td><td style={{fontSize:12,maxWidth:200,overflow:'hidden',textOverflow:'ellipsis'}}>{l.changes||'-'}</td></tr>))}{filtered.length===0&&<tr><td colSpan={5} style={{textAlign:'center',color:'#94a3b8'}}>No logs</td></tr>}</tbody></table>{totalPages>1&&<div style={{marginTop:12,display:'flex',gap:8,alignItems:'center'}}><button className="btn btn-sm btn-outline" disabled={page<=1} onClick={()=>setPage(p=>p-1)}>Prev</button><span style={{fontSize:13}}>Page {page}/{totalPages}</span><button className="btn btn-sm btn-outline" disabled={page>=totalPages} onClick={()=>setPage(p=>p+1)}>Next</button></div>}</div></div>);}
|
|
278
|
+
|
|
279
|
+
function ProfilePage(){const[profile,setProfile]=useState({});const[email,setEmail]=useState('');const[editing,setEditing]=useState(false);const[msg,setMsg]=useState('');
|
|
280
|
+
useEffect(()=>{api('/profile').then(d=>{if(d){setProfile(d);setEmail(d.email||'');}});},[]);
|
|
281
|
+
const save=()=>{api('/profile',{method:'POST',body:JSON.stringify({email})}).then(d=>{if(d&&!d.__error){setMsg('Profile updated');setEditing(false);setProfile(p=>({...p,email}));}});};
|
|
282
|
+
return(<div><div className="header"><h2>Profile</h2></div>{msg&&<div className="card" style={{background:'#f0fdf4',border:'1px solid #86efac'}}><span style={{fontSize:13}}>{msg}</span><button className="btn btn-sm btn-outline" style={{marginLeft:12}} onClick={()=>setMsg('')}>x</button></div>}<div className="card"><table><tbody>
|
|
283
|
+
<tr><td style={{width:150}}><strong>Username</strong></td><td>{profile.username||'admin'}</td></tr>
|
|
284
|
+
<tr><td><strong>Email</strong></td><td>{editing?<><input className="input" style={{width:300,display:'inline-block',marginBottom:0}} value={email} onChange={e=>setEmail(e.target.value)}/><button className="btn btn-sm btn-primary" style={{marginLeft:8}} onClick={save}>Save</button><button className="btn btn-sm btn-outline" style={{marginLeft:4}} onClick={()=>setEditing(false)}>Cancel</button></>:<>{profile.email||'-'} <button className="btn btn-sm btn-outline" style={{marginLeft:8}} onClick={()=>setEditing(true)}>Edit</button></>}</td></tr>
|
|
285
|
+
<tr><td><strong>Group</strong></td><td><span className="badge badge-blue">{profile.group||'Administrators'}</span></td></tr>
|
|
286
|
+
<tr><td><strong>Permissions</strong></td><td style={{fontSize:12}}>{(profile.permissions||[]).join(', ')||'All'}</td></tr>
|
|
287
|
+
<tr><td><strong>Last Login</strong></td><td>{profile.lastLogin?new Date(profile.lastLogin).toLocaleString():'Now'}</td></tr>
|
|
288
|
+
</tbody></table></div></div>);}
|
|
289
|
+
|
|
290
|
+
const PAGES=[{id:'dashboard',label:'Dashboard',perm:'DASHBOARD_VIEW',icon:'π'},{id:'kb',label:'KB Management',perm:'KB_READ',icon:'π'},{id:'graph',label:'KB Graph',perm:'GRAPH_VIEW',icon:'πΈοΈ'},{id:'quality',label:'KB Quality',perm:'KB_READ',icon:'β'},{id:'tags',label:'KB Tags',perm:'KB_READ',icon:'π·οΈ'},{id:'analytics',label:'Analytics',perm:'ANALYTICS_VIEW',icon:'π'},{id:'mcp',label:'MCP Servers',perm:'MCP_ACCESS',icon:'π₯οΈ'},{id:'users',label:'Users',perm:'USER_MANAGE',icon:'π₯'},{id:'rbac',label:'RBAC',perm:'RBAC_MANAGE',icon:'π'},{id:'config',label:'Configuration',perm:'CONFIG_EDIT',icon:'βοΈ'},{id:'search',label:'Search Explorer',perm:'SEARCH_EXPLORE',icon:'π'},{id:'audit',label:'Audit Trail',perm:'AUDIT_VIEW',icon:'π'},{id:'profile',label:'Profile',perm:null,icon:'π€'}];
|
|
291
|
+
|
|
292
|
+
function PortalInstance({permissions,username,isActive,impersonateUserId}){
|
|
293
|
+
const[page,setPage]=useState('dashboard');
|
|
294
|
+
const hasPerm=(p)=>!p||permissions.includes(p);
|
|
295
|
+
const visiblePages=PAGES.filter(p=>hasPerm(p.perm));
|
|
296
|
+
useEffect(()=>{__impersonateUserId=impersonateUserId||null;},[isActive]);
|
|
297
|
+
const renderPage=()=>{switch(page){case'dashboard':return<DashboardPage/>;case'kb':return<KBManagementPage/>;case'graph':return<KBGraphPage activeTab={impersonateUserId||'admin'}/>;case'quality':return<KBQualityPage/>;case'tags':return<KBTagsPage/>;case'analytics':return<AnalyticsPage/>;case'mcp':return<MCPServersPage/>;case'users':return<UsersPage/>;case'rbac':return<RBACPage/>;case'config':return<ConfigurationPage/>;case'search':return<SearchExplorerPage/>;case'audit':return<AuditTrailPage/>;case'profile':return<ProfilePage/>;default:return<DashboardPage/>;}};
|
|
298
|
+
return(<div style={{display:isActive?'flex':'none',flex:1,height:'100%'}}><div className="sidebar" style={{width:200,background:'#f8fafc',borderRight:'1px solid #e2e8f0',overflow:'auto',flexShrink:0,padding:'12px 0',position:'relative',height:'auto',color:'#1e293b'}}><div style={{padding:'6px 12px 10px',borderBottom:'1px solid #e2e8f0',marginBottom:4}}><div style={{fontSize:12,color:'#1e293b',fontWeight:600}}>{username}</div><div style={{fontSize:10,color:'#64748b'}}>{permissions.length} perms</div></div>{visiblePages.map(p=>(<div key={p.id} style={{padding:'7px 12px',fontSize:12,cursor:'pointer',background:page===p.id?'#dbeafe':'transparent',color:page===p.id?'#1e40af':'#475569',borderLeft:page===p.id?'3px solid #3b82f6':'3px solid transparent'}} className="nav-item" onClick={()=>{if(impersonateUserId)__impersonateUserId=impersonateUserId;else __impersonateUserId=null;setPage(p.id);}}><span style={{marginRight:6}}>{p.icon}</span>{p.label}</div>))}</div><div className="main" style={{flex:1,padding:20,overflow:'auto',marginLeft:0}}>{renderPage()}</div></div>);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function App(){const[loggedIn,setLoggedIn]=useState(!!localStorage.getItem('admin_token'));const[forceChange,setForceChange]=useState(false);const[cpwd,setCpwd]=useState({c:'',n1:'',n2:'',err:''});
|
|
302
|
+
const[tabs,setTabs]=useState([]);const[activeTab,setActiveTab]=useState('admin');const[usersList,setUsersList]=useState([]);const[showAddTab,setShowAddTab]=useState(false);
|
|
303
|
+
const userInfo=JSON.parse(localStorage.getItem('admin_user')||'{}');
|
|
304
|
+
const realPerms=userInfo.permissions||[];
|
|
305
|
+
const canCompare=realPerms.includes('RBAC_MANAGE');
|
|
306
|
+
useEffect(()=>{if(!loggedIn)return;if(userInfo.forcePasswordChange)setForceChange(true);if(canCompare)api('/users?pageSize=100').then(d=>{if(d&&!d.__error)setUsersList(d.users||[]);});},[loggedIn]);
|
|
307
|
+
if(!loggedIn)return<LoginPage onLogin={()=>setLoggedIn(true)}/>;
|
|
308
|
+
const logout=()=>{api('/auth/logout',{method:'POST'}).finally(()=>{localStorage.removeItem('admin_token');localStorage.removeItem('admin_user');setLoggedIn(false);});};
|
|
309
|
+
const doChangePwd=async()=>{if(cpwd.n1!==cpwd.n2){setCpwd(p=>({...p,err:'Mismatch'}));return;}const r=await api('/auth/change-password',{method:'POST',body:JSON.stringify({currentPassword:cpwd.c,newPassword:cpwd.n1})});if(r&&!r.__error){setForceChange(false);localStorage.setItem('admin_user',JSON.stringify({...userInfo,forcePasswordChange:false}));}else setCpwd(p=>({...p,err:r?.error||'Failed'}));};
|
|
310
|
+
if(forceChange)return(<div className="login-container"><div className="login-box"><h2>Change Password</h2>{cpwd.err&&<div style={{background:'#fee2e2',color:'#991b1b',padding:8,borderRadius:6,marginBottom:8,fontSize:13}}>{cpwd.err}</div>}<input className="input" type="password" placeholder="Current" value={cpwd.c} onChange={e=>setCpwd(p=>({...p,c:e.target.value}))}/><input className="input" type="password" placeholder="New" value={cpwd.n1} onChange={e=>setCpwd(p=>({...p,n1:e.target.value}))}/><input className="input" type="password" placeholder="Confirm" value={cpwd.n2} onChange={e=>setCpwd(p=>({...p,n2:e.target.value}))}/><button className="btn btn-primary" style={{width:'100%'}} onClick={doChangePwd}>Change</button></div></div>);
|
|
311
|
+
const addTab=(u)=>{api('/impersonate/'+u.userId).then(d=>{if(d&&!d.__error){setTabs(t=>[...t,{id:'tab-'+Date.now(),userId:d.userId,username:d.username,permissions:d.permissions}]);setShowAddTab(false);}});};
|
|
312
|
+
const removeTab=(tabId)=>{setTabs(t=>t.filter(x=>x.id!==tabId));if(activeTab===tabId)setActiveTab('admin');};
|
|
313
|
+
const switchTab=(id)=>{setActiveTab(id);const tab=tabs.find(t=>t.id===id);__impersonateUserId=tab?tab.userId:null;};
|
|
314
|
+
return(<div style={{display:'flex',flexDirection:'column',height:'100vh'}}>
|
|
315
|
+
<div style={{display:'flex',background:'#1e293b',alignItems:'center',padding:'0 12px',flexShrink:0,minHeight:38}}>
|
|
316
|
+
<div onClick={()=>switchTab('admin')} style={{padding:'8px 16px',fontSize:13,cursor:'pointer',color:activeTab==='admin'?'#fff':'#94a3b8',background:activeTab==='admin'?'#334155':'transparent',borderRadius:'6px 6px 0 0',fontWeight:activeTab==='admin'?600:400}}>Admin ({realPerms.length})</div>
|
|
317
|
+
{tabs.map(t=>(<div key={t.id} style={{display:'flex',alignItems:'center',gap:4,padding:'8px 12px',fontSize:13,cursor:'pointer',color:activeTab===t.id?'#fff':'#94a3b8',background:activeTab===t.id?'#334155':'transparent',borderRadius:'6px 6px 0 0'}} onClick={()=>switchTab(t.id)}><span style={{fontWeight:activeTab===t.id?600:400}}>{t.username}</span><span style={{fontSize:10,color:'#64748b'}}>({t.permissions.length})</span><span style={{marginLeft:4,fontSize:14,color:'#64748b'}} onClick={e=>{e.stopPropagation();removeTab(t.id);}}>×</span></div>))}
|
|
318
|
+
<div style={{position:'relative',marginLeft:8}}><button style={{background:'#475569',color:'#e2e8f0',border:'none',borderRadius:4,padding:'4px 10px',fontSize:12,cursor:'pointer'}} onClick={()=>setShowAddTab(!showAddTab)}>+</button>{showAddTab&&<div style={{position:'fixed',top:36,zIndex:99999,background:'#fff',border:'1px solid #e2e8f0',borderRadius:8,padding:6,maxHeight:300,overflow:'auto',width:220,boxShadow:'0 8px 24px rgba(0,0,0,0.15)'}}>{usersList.filter(u=>!tabs.some(t=>t.userId===u.userId)&&u.userId!==userInfo.userId).map(u=>(<div key={u.userId} style={{padding:'6px 10px',fontSize:13,color:'#1e293b',cursor:'pointer',borderRadius:4}} onMouseEnter={e=>e.currentTarget.style.background='#f0f9ff'} onMouseLeave={e=>e.currentTarget.style.background='transparent'} onClick={()=>addTab(u)}>{u.username} <span style={{color:'#64748b',fontSize:11}}>({u.accessGroupName||''})</span></div>))}{usersList.filter(u=>!tabs.some(t=>t.userId===u.userId)&&u.userId!==userInfo.userId).length===0&&<div style={{fontSize:12,color:'#64748b',padding:8}}>No users</div>}</div>}</div>
|
|
319
|
+
<div style={{marginLeft:'auto',padding:'0 12px'}}><span style={{fontSize:11,color:'#64748b'}} onClick={logout} style={{cursor:'pointer',fontSize:11,color:'#94a3b8'}}>Logout</span></div>
|
|
320
|
+
</div>
|
|
321
|
+
<div style={{flex:1,display:'flex',overflow:'hidden',position:'relative'}}>
|
|
322
|
+
<PortalInstance permissions={realPerms} username={userInfo.username||'admin'} isActive={activeTab==='admin'} impersonateUserId={null}/>
|
|
323
|
+
{tabs.map(t=>(<PortalInstance key={t.id} permissions={t.permissions} username={t.username} isActive={activeTab===t.id} impersonateUserId={t.userId}/>))}
|
|
324
|
+
</div>
|
|
325
|
+
</div>);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
|
|
329
|
+
</script>
|
|
330
|
+
<script>
|
|
331
|
+
// Disconnect Babel's MutationObserver to prevent it from transforming extension-injected scripts
|
|
332
|
+
try{var obs=window.__babelObserver||null;if(!obs){var allObservers=performance.getEntriesByType&&[];document.querySelectorAll('script').forEach(function(){});}}catch(e){}
|
|
333
|
+
// Disable Babel script tag processing for any future scripts
|
|
334
|
+
if(window.Babel&&window.Babel.transformScriptTags){window.Babel.transformScriptTags=function(){};}
|
|
335
|
+
if(window.Babel&&window.Babel.transform){var origTransform=window.Babel.transform;window.Babel.transform=function(code,opts){if(code&&code.indexOf&&code.indexOf('import ')===0)return{code:''};return origTransform.call(this,code,opts);};}
|
|
336
|
+
</script>
|
|
337
|
+
</body>
|
|
338
|
+
</html>
|