@nielspeter/sonarlint-mcp-server 0.1.3 → 0.2.2
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/CHANGELOG.md +40 -0
- package/README.md +6 -12
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +44 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.js +115 -1330
- package/dist/index.js.map +1 -1
- package/dist/resources/session.d.ts +18 -0
- package/dist/resources/session.d.ts.map +1 -0
- package/dist/resources/session.js +84 -0
- package/dist/resources/session.js.map +1 -0
- package/dist/sloop-bridge.d.ts +0 -3
- package/dist/sloop-bridge.d.ts.map +1 -1
- package/dist/sloop-bridge.js +0 -19
- package/dist/sloop-bridge.js.map +1 -1
- package/dist/state.d.ts +19 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +25 -0
- package/dist/state.js.map +1 -0
- package/dist/tools/analyze-content.d.ts +7 -0
- package/dist/tools/analyze-content.d.ts.map +1 -0
- package/dist/tools/analyze-content.js +78 -0
- package/dist/tools/analyze-content.js.map +1 -0
- package/dist/tools/analyze-file.d.ts +7 -0
- package/dist/tools/analyze-file.d.ts.map +1 -0
- package/dist/tools/analyze-file.js +66 -0
- package/dist/tools/analyze-file.js.map +1 -0
- package/dist/tools/analyze-files.d.ts +7 -0
- package/dist/tools/analyze-files.d.ts.map +1 -0
- package/dist/tools/analyze-files.js +106 -0
- package/dist/tools/analyze-files.js.map +1 -0
- package/dist/tools/analyze-project.d.ts +7 -0
- package/dist/tools/analyze-project.d.ts.map +1 -0
- package/dist/tools/analyze-project.js +109 -0
- package/dist/tools/analyze-project.js.map +1 -0
- package/dist/tools/apply-all-quick-fixes.d.ts +7 -0
- package/dist/tools/apply-all-quick-fixes.d.ts.map +1 -0
- package/dist/tools/apply-all-quick-fixes.js +166 -0
- package/dist/tools/apply-all-quick-fixes.js.map +1 -0
- package/dist/tools/apply-quick-fix.d.ts +7 -0
- package/dist/tools/apply-quick-fix.d.ts.map +1 -0
- package/dist/tools/apply-quick-fix.js +113 -0
- package/dist/tools/apply-quick-fix.js.map +1 -0
- package/dist/tools/health-check.d.ts +7 -0
- package/dist/tools/health-check.d.ts.map +1 -0
- package/dist/tools/health-check.js +113 -0
- package/dist/tools/health-check.js.map +1 -0
- package/dist/tools/list-active-rules.d.ts +7 -0
- package/dist/tools/list-active-rules.d.ts.map +1 -0
- package/dist/tools/list-active-rules.js +48 -0
- package/dist/tools/list-active-rules.js.map +1 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/filesystem.d.ts +8 -0
- package/dist/utils/filesystem.d.ts.map +1 -0
- package/dist/utils/filesystem.js +74 -0
- package/dist/utils/filesystem.js.map +1 -0
- package/dist/utils/formatting.d.ts +13 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/formatting.js +94 -0
- package/dist/utils/formatting.js.map +1 -0
- package/dist/utils/language.d.ts +12 -0
- package/dist/utils/language.d.ts.map +1 -0
- package/dist/utils/language.js +44 -0
- package/dist/utils/language.js.map +1 -0
- package/dist/utils/scope.d.ts +8 -0
- package/dist/utils/scope.d.ts.map +1 -0
- package/dist/utils/scope.js +30 -0
- package/dist/utils/scope.js.map +1 -0
- package/dist/utils/sloop.d.ts +10 -0
- package/dist/utils/sloop.d.ts.map +1 -0
- package/dist/utils/sloop.js +39 -0
- package/dist/utils/sloop.js.map +1 -0
- package/dist/utils/transforms.d.ts +23 -0
- package/dist/utils/transforms.d.ts.map +1 -0
- package/dist/utils/transforms.js +64 -0
- package/dist/utils/transforms.js.map +1 -0
- package/package.json +10 -7
- package/scripts/setup-sonarlint.sh +115 -39
- package/dist/sonarlint-bridge.d.ts +0 -33
- package/dist/sonarlint-bridge.d.ts.map +0 -1
- package/dist/sonarlint-bridge.js +0 -91
- package/dist/sonarlint-bridge.js.map +0 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { dirname } from "path";
|
|
5
|
+
import { sessionResults, batchResults, sloopBridge, serverStartTime } from "../state.js";
|
|
6
|
+
// Get package root directory (where sonarlint-backend is installed)
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
const PACKAGE_ROOT = join(__dirname, '..', '..'); // Go up from dist/tools/ to package root
|
|
10
|
+
export async function handleHealthCheck() {
|
|
11
|
+
console.error(`[MCP] Running health check...`);
|
|
12
|
+
const uptimeMs = Date.now() - serverStartTime;
|
|
13
|
+
const uptimeSeconds = Math.floor(uptimeMs / 1000);
|
|
14
|
+
const uptimeMinutes = Math.floor(uptimeSeconds / 60);
|
|
15
|
+
const uptimeHours = Math.floor(uptimeMinutes / 60);
|
|
16
|
+
const memoryUsage = process.memoryUsage();
|
|
17
|
+
const memoryMB = Math.round(memoryUsage.heapUsed / 1024 / 1024);
|
|
18
|
+
// Check SLOOP status
|
|
19
|
+
const sloopStatus = sloopBridge ? "running" : "not started";
|
|
20
|
+
// Get plugin information
|
|
21
|
+
const pluginsDir = join(PACKAGE_ROOT, "sonarlint-backend", "plugins");
|
|
22
|
+
const pluginsExist = existsSync(pluginsDir);
|
|
23
|
+
let plugins = [];
|
|
24
|
+
if (pluginsExist) {
|
|
25
|
+
const files = readdirSync(pluginsDir);
|
|
26
|
+
const jarFiles = files.filter(f => f.endsWith('.jar'));
|
|
27
|
+
for (const jarFile of jarFiles) {
|
|
28
|
+
// Parse plugin name and version from filename
|
|
29
|
+
const match = jarFile.match(/sonar-(\w+)-plugin-([\d.]+)\.jar/);
|
|
30
|
+
if (match) {
|
|
31
|
+
plugins.push({
|
|
32
|
+
name: match[1].charAt(0).toUpperCase() + match[1].slice(1),
|
|
33
|
+
version: match[2],
|
|
34
|
+
status: "active",
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Cache statistics
|
|
40
|
+
const cacheStats = {
|
|
41
|
+
sessionResults: sessionResults.size,
|
|
42
|
+
batchResults: batchResults.size,
|
|
43
|
+
};
|
|
44
|
+
const healthStatus = {
|
|
45
|
+
status: sloopStatus === "running" && pluginsExist ? "healthy" : "degraded",
|
|
46
|
+
version: "1.0.0 (Phase 3)",
|
|
47
|
+
uptime: {
|
|
48
|
+
milliseconds: uptimeMs,
|
|
49
|
+
seconds: uptimeSeconds,
|
|
50
|
+
minutes: uptimeMinutes,
|
|
51
|
+
hours: uptimeHours,
|
|
52
|
+
formatted: `${uptimeHours}h ${uptimeMinutes % 60}m ${uptimeSeconds % 60}s`,
|
|
53
|
+
},
|
|
54
|
+
backend: {
|
|
55
|
+
status: sloopStatus,
|
|
56
|
+
pluginsDirectory: pluginsExist ? "found" : "missing",
|
|
57
|
+
},
|
|
58
|
+
plugins,
|
|
59
|
+
memory: {
|
|
60
|
+
heapUsed: `${memoryMB}MB`,
|
|
61
|
+
heapTotal: `${Math.round(memoryUsage.heapTotal / 1024 / 1024)}MB`,
|
|
62
|
+
rss: `${Math.round(memoryUsage.rss / 1024 / 1024)}MB`,
|
|
63
|
+
},
|
|
64
|
+
cache: cacheStats,
|
|
65
|
+
tools: ["analyze_file", "analyze_files", "analyze_content", "list_active_rules", "health_check"],
|
|
66
|
+
features: [
|
|
67
|
+
"Session storage for multi-turn conversations",
|
|
68
|
+
"Batch analysis",
|
|
69
|
+
"Content analysis (unsaved files)",
|
|
70
|
+
"MCP resources",
|
|
71
|
+
"Quick fixes support",
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
let output = `# SonarLint MCP Server Health Check\n\n`;
|
|
75
|
+
output += `**Status**: ${healthStatus.status === "healthy" ? "✅ Healthy" : "⚠️ Degraded"}\n`;
|
|
76
|
+
output += `**Version**: ${healthStatus.version}\n`;
|
|
77
|
+
output += `**Uptime**: ${healthStatus.uptime.formatted}\n\n`;
|
|
78
|
+
output += `## Backend Status\n\n`;
|
|
79
|
+
output += `- **SLOOP Backend**: ${healthStatus.backend.status}\n`;
|
|
80
|
+
output += `- **Plugins Directory**: ${healthStatus.backend.pluginsDirectory}\n\n`;
|
|
81
|
+
if (plugins.length > 0) {
|
|
82
|
+
output += `## Active Plugins\n\n`;
|
|
83
|
+
for (const plugin of plugins) {
|
|
84
|
+
output += `- **${plugin.name}**: v${plugin.version} (${plugin.status})\n`;
|
|
85
|
+
}
|
|
86
|
+
output += `\n`;
|
|
87
|
+
}
|
|
88
|
+
output += `## Memory Usage\n\n`;
|
|
89
|
+
output += `- **Heap Used**: ${healthStatus.memory.heapUsed}\n`;
|
|
90
|
+
output += `- **Heap Total**: ${healthStatus.memory.heapTotal}\n`;
|
|
91
|
+
output += `- **RSS**: ${healthStatus.memory.rss}\n\n`;
|
|
92
|
+
output += `## Cache Statistics\n\n`;
|
|
93
|
+
output += `- **Session Results**: ${healthStatus.cache.sessionResults} stored\n`;
|
|
94
|
+
output += `- **Batch Results**: ${healthStatus.cache.batchResults} stored\n\n`;
|
|
95
|
+
output += `## Available Tools\n\n`;
|
|
96
|
+
for (const tool of healthStatus.tools) {
|
|
97
|
+
output += `- ${tool}\n`;
|
|
98
|
+
}
|
|
99
|
+
output += `\n`;
|
|
100
|
+
output += `## Features\n\n`;
|
|
101
|
+
for (const feature of healthStatus.features) {
|
|
102
|
+
output += `- ${feature}\n`;
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: "text",
|
|
108
|
+
text: output,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=health-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-check.js","sourceRoot":"","sources":["../../src/tools/health-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-active-rules.d.ts","sourceRoot":"","sources":["../../src/tools/list-active-rules.ts"],"names":[],"mappings":"AAAA,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,GAAG;;;;;GAoDpD"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export async function handleListActiveRules(args) {
|
|
2
|
+
const { language } = args;
|
|
3
|
+
console.error(`[MCP] Listing active rules${language ? ` for ${language}` : ''}`);
|
|
4
|
+
// TODO: Extract actual rules from SLOOP plugins via RPC
|
|
5
|
+
// For now, return a summary of known rules
|
|
6
|
+
let output = `# Active SonarLint Rules\n\n`;
|
|
7
|
+
if (!language || language === 'javascript' || language === 'typescript') {
|
|
8
|
+
output += `## JavaScript/TypeScript Rules\n\n`;
|
|
9
|
+
output += `**Total Rules**: 265\n\n`;
|
|
10
|
+
output += `### Rule Categories\n\n`;
|
|
11
|
+
output += `- **Code Smells**: Rules that detect maintainability issues\n`;
|
|
12
|
+
output += ` - \`S1481\`: Unused local variables\n`;
|
|
13
|
+
output += ` - \`S1854\`: Useless assignments\n`;
|
|
14
|
+
output += ` - \`S3504\`: Prefer let/const over var\n`;
|
|
15
|
+
output += ` - \`S107\`: Too many parameters\n`;
|
|
16
|
+
output += ` - \`S4144\`: Duplicate implementations\n`;
|
|
17
|
+
output += ` - \`S2589\`: Always-truthy expressions\n\n`;
|
|
18
|
+
output += `- **Bugs**: Rules that detect potential errors\n`;
|
|
19
|
+
output += ` - \`S2259\`: Null pointer dereference\n`;
|
|
20
|
+
output += ` - \`S3776\`: Cognitive complexity\n\n`;
|
|
21
|
+
output += `- **Security**: Rules that detect security vulnerabilities\n`;
|
|
22
|
+
output += ` - \`S5852\`: Regular expression DoS\n`;
|
|
23
|
+
output += ` - \`S2068\`: Hard-coded credentials\n\n`;
|
|
24
|
+
}
|
|
25
|
+
if (!language || language === 'python') {
|
|
26
|
+
output += `## Python Rules\n\n`;
|
|
27
|
+
output += `**Total Rules**: ~200\n\n`;
|
|
28
|
+
output += `### Rule Categories\n\n`;
|
|
29
|
+
output += `- **Code Smells**: Maintainability issues\n`;
|
|
30
|
+
output += ` - \`S1066\`: Nested if statements\n`;
|
|
31
|
+
output += ` - \`S1192\`: String literals duplicated\n\n`;
|
|
32
|
+
output += `- **Bugs**: Potential errors\n`;
|
|
33
|
+
output += ` - \`S5754\`: Unreachable code\n\n`;
|
|
34
|
+
output += `- **Security**: Security vulnerabilities\n`;
|
|
35
|
+
output += ` - \`S5659\`: Weak encryption\n\n`;
|
|
36
|
+
}
|
|
37
|
+
output += `\n---\n\n`;
|
|
38
|
+
output += `*Note: This is a summary of active rules. Full rule details are available at https://rules.sonarsource.com/*\n`;
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: output,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=list-active-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-active-rules.js","sourceRoot":"","sources":["../../src/tools/list-active-rules.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAAS;IACnD,MAAM,EAAE,QAAQ,EAAE,GAAG,IAA6B,CAAC;IAEnD,OAAO,CAAC,KAAK,CAAC,6BAA6B,QAAQ,CAAC,CAAC,CAAC,QAAQ,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEjF,wDAAwD;IACxD,2CAA2C;IAC3C,IAAI,MAAM,GAAG,8BAA8B,CAAC;IAE5C,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,YAAY,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;QACxE,MAAM,IAAI,oCAAoC,CAAC;QAC/C,MAAM,IAAI,0BAA0B,CAAC;QACrC,MAAM,IAAI,yBAAyB,CAAC;QACpC,MAAM,IAAI,+DAA+D,CAAC;QAC1E,MAAM,IAAI,yCAAyC,CAAC;QACpD,MAAM,IAAI,sCAAsC,CAAC;QACjD,MAAM,IAAI,4CAA4C,CAAC;QACvD,MAAM,IAAI,qCAAqC,CAAC;QAChD,MAAM,IAAI,4CAA4C,CAAC;QACvD,MAAM,IAAI,8CAA8C,CAAC;QACzD,MAAM,IAAI,kDAAkD,CAAC;QAC7D,MAAM,IAAI,2CAA2C,CAAC;QACtD,MAAM,IAAI,yCAAyC,CAAC;QACpD,MAAM,IAAI,8DAA8D,CAAC;QACzE,MAAM,IAAI,yCAAyC,CAAC;QACpD,MAAM,IAAI,2CAA2C,CAAC;IACxD,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,qBAAqB,CAAC;QAChC,MAAM,IAAI,2BAA2B,CAAC;QACtC,MAAM,IAAI,yBAAyB,CAAC;QACpC,MAAM,IAAI,6CAA6C,CAAC;QACxD,MAAM,IAAI,uCAAuC,CAAC;QAClD,MAAM,IAAI,+CAA+C,CAAC;QAC1D,MAAM,IAAI,gCAAgC,CAAC;QAC3C,MAAM,IAAI,qCAAqC,CAAC;QAChD,MAAM,IAAI,4CAA4C,CAAC;QACvD,MAAM,IAAI,oCAAoC,CAAC;IACjD,CAAC;IAED,MAAM,IAAI,WAAW,CAAC;IACtB,MAAM,IAAI,gHAAgH,CAAC;IAE3H,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,MAAM;aACb;SACF;KACF,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for the SonarLint MCP Server
|
|
3
|
+
*/
|
|
4
|
+
export interface AnalysisIssue {
|
|
5
|
+
line: number;
|
|
6
|
+
column: number;
|
|
7
|
+
endLine: number;
|
|
8
|
+
endColumn: number;
|
|
9
|
+
severity: "INFO" | "MINOR" | "MAJOR" | "CRITICAL" | "BLOCKER";
|
|
10
|
+
rule: string;
|
|
11
|
+
ruleDescription: string;
|
|
12
|
+
message: string;
|
|
13
|
+
quickFix?: QuickFix;
|
|
14
|
+
}
|
|
15
|
+
export interface QuickFix {
|
|
16
|
+
description: string;
|
|
17
|
+
edits: TextEdit[];
|
|
18
|
+
}
|
|
19
|
+
export interface TextEdit {
|
|
20
|
+
startLine: number;
|
|
21
|
+
startColumn: number;
|
|
22
|
+
endLine: number;
|
|
23
|
+
endColumn: number;
|
|
24
|
+
newText: string;
|
|
25
|
+
}
|
|
26
|
+
export interface AnalysisResult {
|
|
27
|
+
filePath: string;
|
|
28
|
+
language: string;
|
|
29
|
+
issues: AnalysisIssue[];
|
|
30
|
+
summary: {
|
|
31
|
+
total: number;
|
|
32
|
+
bySeverity: {
|
|
33
|
+
blocker: number;
|
|
34
|
+
critical: number;
|
|
35
|
+
major: number;
|
|
36
|
+
minor: number;
|
|
37
|
+
info: number;
|
|
38
|
+
};
|
|
39
|
+
rulesChecked: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export interface BatchAnalysisResult {
|
|
43
|
+
files: Array<{
|
|
44
|
+
filePath: string;
|
|
45
|
+
language: string;
|
|
46
|
+
issueCount: number;
|
|
47
|
+
issues: AnalysisIssue[];
|
|
48
|
+
}>;
|
|
49
|
+
summary: {
|
|
50
|
+
totalFiles: number;
|
|
51
|
+
totalIssues: number;
|
|
52
|
+
filesWithIssues: number;
|
|
53
|
+
bySeverity: {
|
|
54
|
+
blocker: number;
|
|
55
|
+
critical: number;
|
|
56
|
+
major: number;
|
|
57
|
+
minor: number;
|
|
58
|
+
info: number;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE;YACV,OAAO,EAAE,MAAM,CAAC;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;QACF,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAC;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,aAAa,EAAE,CAAC;KACzB,CAAC,CAAC;IACH,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE;YACV,OAAO,EAAE,MAAM,CAAC;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;YACd,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;KACH,CAAC;CACH"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File system utilities for SLOOP integration
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Notify SLOOP that file system was updated (proper cache invalidation)
|
|
6
|
+
*/
|
|
7
|
+
export declare function notifyFileSystemChanged(filePath: string, configScopeId: string): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=filesystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/utils/filesystem.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEpG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File system utilities for SLOOP integration
|
|
3
|
+
*/
|
|
4
|
+
import { dirname, relative } from "path";
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { scopeMap } from "../state.js";
|
|
7
|
+
import { detectLanguage, languageToEnum } from "./language.js";
|
|
8
|
+
import { ensureSloopBridge } from "./sloop.js";
|
|
9
|
+
/**
|
|
10
|
+
* Notify SLOOP that file system was updated (proper cache invalidation)
|
|
11
|
+
*/
|
|
12
|
+
export async function notifyFileSystemChanged(filePath, configScopeId) {
|
|
13
|
+
const uri = `file://${filePath}`;
|
|
14
|
+
// Get project root from scopeMap (reverse lookup)
|
|
15
|
+
let projectRoot;
|
|
16
|
+
for (const [root, scopeId] of scopeMap.entries()) {
|
|
17
|
+
if (scopeId === configScopeId) {
|
|
18
|
+
projectRoot = root;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// If no project root found, use file's directory
|
|
23
|
+
if (!projectRoot) {
|
|
24
|
+
projectRoot = dirname(filePath);
|
|
25
|
+
}
|
|
26
|
+
const relativePath = relative(projectRoot, filePath);
|
|
27
|
+
try {
|
|
28
|
+
const bridge = await ensureSloopBridge();
|
|
29
|
+
// Detect language from file extension
|
|
30
|
+
const language = detectLanguage(filePath);
|
|
31
|
+
const languageEnum = languageToEnum(language);
|
|
32
|
+
// CRITICAL: Tell SLOOP the file is "open" so it will re-analyze on file system updates
|
|
33
|
+
// Without this, SLOOP ignores changes to "closed" files
|
|
34
|
+
bridge.sendNotification('file/didOpenFile', {
|
|
35
|
+
configurationScopeId: configScopeId,
|
|
36
|
+
fileUri: uri
|
|
37
|
+
});
|
|
38
|
+
console.error(`[FS] Marked file as open: ${filePath}`);
|
|
39
|
+
// Read the actual file content to pass to SLOOP
|
|
40
|
+
// This ensures SLOOP gets the latest content instead of reading from its cache
|
|
41
|
+
const fileContent = readFileSync(filePath, 'utf-8');
|
|
42
|
+
// Build ClientFileDto
|
|
43
|
+
// Pass BOTH fsPath and content - fromDto will call setDirty(content) which takes precedence
|
|
44
|
+
const clientFileDto = {
|
|
45
|
+
uri,
|
|
46
|
+
ideRelativePath: relativePath,
|
|
47
|
+
configScopeId,
|
|
48
|
+
isTest: null,
|
|
49
|
+
charset: 'UTF-8',
|
|
50
|
+
fsPath: filePath, // Provide fsPath for analyzers that need it
|
|
51
|
+
content: fileContent, // Providing content calls setDirty(), which takes precedence over fsPath
|
|
52
|
+
detectedLanguage: languageEnum, // e.g., "JS", "TS", "PYTHON"
|
|
53
|
+
isUserDefined: true // CRITICAL: Must be true for SLOOP to analyze!
|
|
54
|
+
};
|
|
55
|
+
// Send file/didUpdateFileSystem notification
|
|
56
|
+
bridge.sendNotification('file/didUpdateFileSystem', {
|
|
57
|
+
addedFiles: [],
|
|
58
|
+
changedFiles: [clientFileDto],
|
|
59
|
+
removedFiles: []
|
|
60
|
+
});
|
|
61
|
+
console.error(`[FS] Notified file system update:`);
|
|
62
|
+
console.error(`[FS] URI: ${uri}`);
|
|
63
|
+
console.error(`[FS] Language: ${languageEnum}`);
|
|
64
|
+
console.error(`[FS] Relative: ${relativePath}`);
|
|
65
|
+
console.error(`[FS] ConfigScopeId: ${configScopeId}`);
|
|
66
|
+
console.error(`[FS] Content length: ${fileContent.length} chars`);
|
|
67
|
+
console.error(`[FS] First 100 chars: ${fileContent.substring(0, 100)}`);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
console.error(`[FS] Failed to notify file system update for ${filePath}:`, err);
|
|
71
|
+
// Don't throw - this is not critical
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=filesystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/utils/filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
import type { AnalysisResult, BatchAnalysisResult } from "../types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Format analysis result for display
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatAnalysisResult(result: AnalysisResult): string;
|
|
9
|
+
/**
|
|
10
|
+
* Format batch analysis result for display
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatBatchAnalysisResult(result: BatchAnalysisResult): string;
|
|
13
|
+
//# sourceMappingURL=formatting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.d.ts","sourceRoot":"","sources":["../../src/utils/formatting.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAiB,MAAM,aAAa,CAAC;AAEtF;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAyCnE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CA8C7E"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Format analysis result for display
|
|
6
|
+
*/
|
|
7
|
+
export function formatAnalysisResult(result) {
|
|
8
|
+
const { filePath, language, issues, summary } = result;
|
|
9
|
+
let output = `# Analysis Results: ${filePath}\n\n`;
|
|
10
|
+
output += `**Language**: ${language}\n`;
|
|
11
|
+
output += `**Rules Checked**: ${summary.rulesChecked}\n`;
|
|
12
|
+
output += `**Total Issues**: ${summary.total}\n\n`;
|
|
13
|
+
if (summary.total === 0) {
|
|
14
|
+
output += "✅ No issues found!\n";
|
|
15
|
+
return output;
|
|
16
|
+
}
|
|
17
|
+
// Severity breakdown
|
|
18
|
+
output += `## Issues by Severity\n\n`;
|
|
19
|
+
if (summary.bySeverity.blocker > 0)
|
|
20
|
+
output += `- 🔴 **BLOCKER**: ${summary.bySeverity.blocker}\n`;
|
|
21
|
+
if (summary.bySeverity.critical > 0)
|
|
22
|
+
output += `- 🟠 **CRITICAL**: ${summary.bySeverity.critical}\n`;
|
|
23
|
+
if (summary.bySeverity.major > 0)
|
|
24
|
+
output += `- 🟡 **MAJOR**: ${summary.bySeverity.major}\n`;
|
|
25
|
+
if (summary.bySeverity.minor > 0)
|
|
26
|
+
output += `- 🔵 **MINOR**: ${summary.bySeverity.minor}\n`;
|
|
27
|
+
if (summary.bySeverity.info > 0)
|
|
28
|
+
output += `- ⚪ **INFO**: ${summary.bySeverity.info}\n`;
|
|
29
|
+
output += `\n`;
|
|
30
|
+
// Detailed issues
|
|
31
|
+
output += `## Detailed Issues\n\n`;
|
|
32
|
+
// Sort by line number
|
|
33
|
+
const sortedIssues = [...issues].sort((a, b) => a.line - b.line);
|
|
34
|
+
for (const issue of sortedIssues) {
|
|
35
|
+
output += `### Line ${issue.line}:${issue.column} - ${issue.severity}\n\n`;
|
|
36
|
+
output += `**Rule**: \`${issue.rule}\`\n\n`;
|
|
37
|
+
output += `**Message**: ${issue.message}\n\n`;
|
|
38
|
+
if (issue.quickFix) {
|
|
39
|
+
output += `**Quick Fix Available**: ${issue.quickFix.description}\n\n`;
|
|
40
|
+
}
|
|
41
|
+
output += `---\n\n`;
|
|
42
|
+
}
|
|
43
|
+
return output;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Format batch analysis result for display
|
|
47
|
+
*/
|
|
48
|
+
export function formatBatchAnalysisResult(result) {
|
|
49
|
+
const { files, summary } = result;
|
|
50
|
+
let output = `# Batch Analysis Results\n\n`;
|
|
51
|
+
output += `**Total Files**: ${summary.totalFiles}\n`;
|
|
52
|
+
output += `**Files with Issues**: ${summary.filesWithIssues}\n`;
|
|
53
|
+
output += `**Total Issues**: ${summary.totalIssues}\n\n`;
|
|
54
|
+
// Overall severity breakdown
|
|
55
|
+
output += `## Overall Issues by Severity\n\n`;
|
|
56
|
+
if (summary.bySeverity.blocker > 0)
|
|
57
|
+
output += `- 🔴 **BLOCKER**: ${summary.bySeverity.blocker}\n`;
|
|
58
|
+
if (summary.bySeverity.critical > 0)
|
|
59
|
+
output += `- 🟠 **CRITICAL**: ${summary.bySeverity.critical}\n`;
|
|
60
|
+
if (summary.bySeverity.major > 0)
|
|
61
|
+
output += `- 🟡 **MAJOR**: ${summary.bySeverity.major}\n`;
|
|
62
|
+
if (summary.bySeverity.minor > 0)
|
|
63
|
+
output += `- 🔵 **MINOR**: ${summary.bySeverity.minor}\n`;
|
|
64
|
+
if (summary.bySeverity.info > 0)
|
|
65
|
+
output += `- ⚪ **INFO**: ${summary.bySeverity.info}\n`;
|
|
66
|
+
output += `\n`;
|
|
67
|
+
// File-by-file breakdown
|
|
68
|
+
output += `## Issues by File\n\n`;
|
|
69
|
+
for (const file of files) {
|
|
70
|
+
if (file.issueCount === 0) {
|
|
71
|
+
output += `### ✅ ${file.filePath}\n\nNo issues found.\n\n`;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
output += `### ${file.filePath} (${file.issueCount} issue${file.issueCount > 1 ? 's' : ''})\n\n`;
|
|
75
|
+
// Group by severity
|
|
76
|
+
const bySeverity = {};
|
|
77
|
+
for (const issue of file.issues) {
|
|
78
|
+
if (!bySeverity[issue.severity]) {
|
|
79
|
+
bySeverity[issue.severity] = [];
|
|
80
|
+
}
|
|
81
|
+
bySeverity[issue.severity].push(issue);
|
|
82
|
+
}
|
|
83
|
+
for (const [severity, issues] of Object.entries(bySeverity)) {
|
|
84
|
+
output += `**${severity}** (${issues.length}):\n`;
|
|
85
|
+
for (const issue of issues) {
|
|
86
|
+
output += `- Line ${issue.line}: ${issue.message} [\`${issue.rule}\`]\n`;
|
|
87
|
+
}
|
|
88
|
+
output += `\n`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return output;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=formatting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting.js","sourceRoot":"","sources":["../../src/utils/formatting.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language detection and mapping utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Detect language from file extension
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectLanguage(filePath: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Map language name to SLOOP Language enum
|
|
10
|
+
*/
|
|
11
|
+
export declare function languageToEnum(language: string): string;
|
|
12
|
+
//# sourceMappingURL=language.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language.d.ts","sourceRoot":"","sources":["../../src/utils/language.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiBvD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAcvD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language detection and mapping utilities
|
|
3
|
+
*/
|
|
4
|
+
import { extname } from "path";
|
|
5
|
+
/**
|
|
6
|
+
* Detect language from file extension
|
|
7
|
+
*/
|
|
8
|
+
export function detectLanguage(filePath) {
|
|
9
|
+
const ext = extname(filePath).toLowerCase();
|
|
10
|
+
const languageMap = {
|
|
11
|
+
'.js': 'javascript',
|
|
12
|
+
'.jsx': 'javascript',
|
|
13
|
+
'.ts': 'typescript',
|
|
14
|
+
'.tsx': 'typescript',
|
|
15
|
+
'.py': 'python',
|
|
16
|
+
'.java': 'java',
|
|
17
|
+
'.go': 'go',
|
|
18
|
+
'.php': 'php',
|
|
19
|
+
'.rb': 'ruby',
|
|
20
|
+
'.html': 'html',
|
|
21
|
+
'.css': 'css',
|
|
22
|
+
'.xml': 'xml',
|
|
23
|
+
};
|
|
24
|
+
return languageMap[ext] || 'unknown';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Map language name to SLOOP Language enum
|
|
28
|
+
*/
|
|
29
|
+
export function languageToEnum(language) {
|
|
30
|
+
const enumMap = {
|
|
31
|
+
'javascript': 'JS',
|
|
32
|
+
'typescript': 'TS',
|
|
33
|
+
'python': 'PYTHON',
|
|
34
|
+
'java': 'JAVA',
|
|
35
|
+
'go': 'GO',
|
|
36
|
+
'php': 'PHP',
|
|
37
|
+
'ruby': 'RUBY',
|
|
38
|
+
'html': 'HTML',
|
|
39
|
+
'css': 'CSS',
|
|
40
|
+
'xml': 'XML',
|
|
41
|
+
};
|
|
42
|
+
return enumMap[language] || language.toUpperCase();
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=language.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language.js","sourceRoot":"","sources":["../../src/utils/language.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5C,MAAM,WAAW,GAA2B;QAC1C,KAAK,EAAE,YAAY;QACnB,MAAM,EAAE,YAAY;QACpB,KAAK,EAAE,YAAY;QACnB,MAAM,EAAE,YAAY;QACpB,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE,MAAM;QACf,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,KAAK;KACd,CAAC;IACF,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,OAAO,GAA2B;QACtC,YAAY,EAAE,IAAI;QAClB,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,QAAQ;QAClB,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,KAAK;KACb,CAAC;IACF,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/utils/scope.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAwBzD"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration scope management utilities
|
|
3
|
+
*/
|
|
4
|
+
import { dirname } from "path";
|
|
5
|
+
import { createHash } from "crypto";
|
|
6
|
+
import { scopeMap, getSloopBridge } from "../state.js";
|
|
7
|
+
/**
|
|
8
|
+
* Get or create configuration scope for a project
|
|
9
|
+
*/
|
|
10
|
+
export function getOrCreateScope(filePath) {
|
|
11
|
+
const projectRoot = dirname(filePath);
|
|
12
|
+
const scopeId = scopeMap.get(projectRoot);
|
|
13
|
+
if (scopeId) {
|
|
14
|
+
return scopeId;
|
|
15
|
+
}
|
|
16
|
+
// Create new scope ID based on project root hash
|
|
17
|
+
const hash = createHash('md5').update(projectRoot).digest('hex').substring(0, 8);
|
|
18
|
+
const newScopeId = `scope-${hash}`;
|
|
19
|
+
console.error(`[MCP] Creating new configuration scope: ${newScopeId} for ${projectRoot}`);
|
|
20
|
+
// Add scope to SLOOP
|
|
21
|
+
const sloopBridge = getSloopBridge();
|
|
22
|
+
if (sloopBridge) {
|
|
23
|
+
sloopBridge.addConfigurationScope(newScopeId, {
|
|
24
|
+
name: `Project: ${projectRoot}`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
scopeMap.set(projectRoot, newScopeId);
|
|
28
|
+
return newScopeId;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/utils/scope.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEvD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE1C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,iDAAiD;IACjD,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjF,MAAM,UAAU,GAAG,SAAS,IAAI,EAAE,CAAC;IAEnC,OAAO,CAAC,KAAK,CAAC,2CAA2C,UAAU,QAAQ,WAAW,EAAE,CAAC,CAAC;IAE1F,qBAAqB;IACrB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,IAAI,WAAW,EAAE,CAAC;QAChB,WAAW,CAAC,qBAAqB,CAAC,UAAU,EAAE;YAC5C,IAAI,EAAE,YAAY,WAAW,EAAE;SAChC,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACtC,OAAO,UAAU,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SLOOP bridge initialization and management
|
|
3
|
+
*/
|
|
4
|
+
import { SloopBridge } from "../sloop-bridge.js";
|
|
5
|
+
export declare const PACKAGE_ROOT: string;
|
|
6
|
+
/**
|
|
7
|
+
* Ensure SLOOP bridge is initialized
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureSloopBridge(): Promise<SloopBridge>;
|
|
10
|
+
//# sourceMappingURL=sloop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sloop.d.ts","sourceRoot":"","sources":["../../src/utils/sloop.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOjD,eAAO,MAAM,YAAY,QAA2B,CAAC;AAErD;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC,CA+B9D"}
|