@aspect-guard/core 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +44 -2
- package/dist/index.js +204 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -160,15 +160,57 @@ declare class ExtensionGuardScanner {
|
|
|
160
160
|
private hashDatabase;
|
|
161
161
|
constructor(options?: Partial<ScanOptions>);
|
|
162
162
|
scan(options?: Partial<ScanOptions>): Promise<FullScanReport>;
|
|
163
|
+
/**
|
|
164
|
+
* Scan multiple extensions concurrently with a configurable pool size.
|
|
165
|
+
* Uses a simple semaphore pattern to limit concurrent operations.
|
|
166
|
+
*/
|
|
167
|
+
private scanExtensionsConcurrently;
|
|
163
168
|
private scanExtension;
|
|
164
169
|
private calculateTrustScore;
|
|
165
170
|
private calculateRiskLevel;
|
|
166
171
|
private calculateSummary;
|
|
167
172
|
}
|
|
168
173
|
|
|
174
|
+
/**
|
|
175
|
+
* IDE extension paths organized by IDE name.
|
|
176
|
+
* Each IDE has multiple possible paths to support:
|
|
177
|
+
* - Different OS (Windows, macOS, Linux)
|
|
178
|
+
* - Different installation methods (user, system, portable)
|
|
179
|
+
* - Remote development scenarios (SSH, WSL, containers)
|
|
180
|
+
*
|
|
181
|
+
* Paths use these placeholders:
|
|
182
|
+
* - ~ : User home directory
|
|
183
|
+
* - %USERPROFILE% : Windows user profile
|
|
184
|
+
* - %APPDATA% : Windows AppData/Roaming
|
|
185
|
+
* - %LOCALAPPDATA% : Windows AppData/Local
|
|
186
|
+
*
|
|
187
|
+
* References:
|
|
188
|
+
* - https://code.visualstudio.com/docs/editor/extension-marketplace
|
|
189
|
+
* - https://code.visualstudio.com/docs/remote/troubleshooting
|
|
190
|
+
* - https://vscodium.com/
|
|
191
|
+
* - https://zed.dev/docs/extensions/installing-extensions
|
|
192
|
+
*/
|
|
169
193
|
declare const IDE_PATHS: Record<string, string[]>;
|
|
194
|
+
/**
|
|
195
|
+
* Expand path placeholders to actual paths
|
|
196
|
+
*/
|
|
170
197
|
declare function expandPath(inputPath: string): string;
|
|
198
|
+
/**
|
|
199
|
+
* Detect all installed IDE extension paths
|
|
200
|
+
*/
|
|
171
201
|
declare function detectIDEPaths(): DetectedIDE[];
|
|
202
|
+
/**
|
|
203
|
+
* Get list of all supported IDE names
|
|
204
|
+
*/
|
|
205
|
+
declare function getSupportedIDEs(): string[];
|
|
206
|
+
/**
|
|
207
|
+
* Check if a specific IDE is installed
|
|
208
|
+
*/
|
|
209
|
+
declare function isIDEInstalled(ideName: string): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Get the extension path for a specific IDE
|
|
212
|
+
*/
|
|
213
|
+
declare function getIDEExtensionPath(ideName: string): string | null;
|
|
172
214
|
|
|
173
215
|
declare function readExtension(extensionPath: string): Promise<ExtensionInfo | null>;
|
|
174
216
|
declare function readExtensionsFromDirectory(directoryPath: string): Promise<ExtensionInfo[]>;
|
|
@@ -710,6 +752,6 @@ declare function generateBaseline(_extensionPaths: string[], _outputPath?: strin
|
|
|
710
752
|
errors: string[];
|
|
711
753
|
}>;
|
|
712
754
|
|
|
713
|
-
declare const VERSION = "0.
|
|
755
|
+
declare const VERSION = "0.5.1";
|
|
714
756
|
|
|
715
|
-
export { ALL_POPULAR_EXTENSIONS, type AdjustFindingsOptions, type AuditReport, type BundleDetectionResult, DETECTION_RULES, type DetectedIDE, type DetectionRule, type Evidence, type ExtensionCategory, ExtensionGuardScanner, type ExtensionHash, type ExtensionInfo, type ExtensionManifest, type Finding, type FindingCategory, type FullScanReport, type HashDatabase, IDE_PATHS, type InspectOptions, type IntegrityInfo, type IntegrityResult, type IntegrityStatus, JsonReporter, MEGA_POPULAR_EXTENSIONS, MarkdownReporter, POPULAR_EXTENSIONS, type PolicyAction, type PolicyConfig, PolicyEngine, type PolicyRules, type PolicyViolation, type PopularExtension, type Reporter, type ReporterOptions, type RiskLevel, RuleEngine, type RuleEngineOptions, SEVERITY_ORDER, SarifReporter, type ScanOptions, type ScanResult, type ScanSummary, type Severity, TRUSTED_EXTENSION_IDS, TRUSTED_PUBLISHERS, VERIFIED_PUBLISHERS, VERSION, addHash, adjustFindings, categorizeExtension, clearHashCache, collectFiles, compareSeverity, computeExtensionHashes, createHashRecord, detectBundle, detectIDEPaths, expandPath, generateBaseline, getDefaultDatabasePath, getHash, getPopularityTier, isAtLeastSeverity, isBundleOutputPath, isMegaPopular, isPopular, isTrustedExtension, isTrustedPublisher, isVerifiedPublisher, loadHashDatabase, loadPolicyConfig, readExtension, readExtensionsFromDirectory, registerBuiltInRules, ruleRegistry, saveHashDatabase, sha256, shouldCollectFile, shouldReduceSeverityForBundle, verifyIntegrity };
|
|
757
|
+
export { ALL_POPULAR_EXTENSIONS, type AdjustFindingsOptions, type AuditReport, type BundleDetectionResult, DETECTION_RULES, type DetectedIDE, type DetectionRule, type Evidence, type ExtensionCategory, ExtensionGuardScanner, type ExtensionHash, type ExtensionInfo, type ExtensionManifest, type Finding, type FindingCategory, type FullScanReport, type HashDatabase, IDE_PATHS, type InspectOptions, type IntegrityInfo, type IntegrityResult, type IntegrityStatus, JsonReporter, MEGA_POPULAR_EXTENSIONS, MarkdownReporter, POPULAR_EXTENSIONS, type PolicyAction, type PolicyConfig, PolicyEngine, type PolicyRules, type PolicyViolation, type PopularExtension, type Reporter, type ReporterOptions, type RiskLevel, RuleEngine, type RuleEngineOptions, SEVERITY_ORDER, SarifReporter, type ScanOptions, type ScanResult, type ScanSummary, type Severity, TRUSTED_EXTENSION_IDS, TRUSTED_PUBLISHERS, VERIFIED_PUBLISHERS, VERSION, addHash, adjustFindings, categorizeExtension, clearHashCache, collectFiles, compareSeverity, computeExtensionHashes, createHashRecord, detectBundle, detectIDEPaths, expandPath, generateBaseline, getDefaultDatabasePath, getHash, getIDEExtensionPath, getPopularityTier, getSupportedIDEs, isAtLeastSeverity, isBundleOutputPath, isIDEInstalled, isMegaPopular, isPopular, isTrustedExtension, isTrustedPublisher, isVerifiedPublisher, loadHashDatabase, loadPolicyConfig, readExtension, readExtensionsFromDirectory, registerBuiltInRules, ruleRegistry, saveHashDatabase, sha256, shouldCollectFile, shouldReduceSeverityForBundle, verifyIntegrity };
|
package/dist/index.js
CHANGED
|
@@ -22,27 +22,151 @@ import * as fs from "fs";
|
|
|
22
22
|
import * as os from "os";
|
|
23
23
|
import * as path from "path";
|
|
24
24
|
var IDE_PATHS = {
|
|
25
|
-
|
|
26
|
-
"VS Code
|
|
25
|
+
// VS Code - Standard installation
|
|
26
|
+
"VS Code": [
|
|
27
|
+
// Linux & macOS
|
|
28
|
+
"~/.vscode/extensions",
|
|
29
|
+
// Windows
|
|
30
|
+
"%USERPROFILE%/.vscode/extensions",
|
|
31
|
+
"%USERPROFILE%\\.vscode\\extensions"
|
|
32
|
+
],
|
|
33
|
+
// VS Code Insiders - Preview builds
|
|
34
|
+
"VS Code Insiders": [
|
|
35
|
+
// Linux & macOS
|
|
36
|
+
"~/.vscode-insiders/extensions",
|
|
37
|
+
// Windows
|
|
38
|
+
"%USERPROFILE%/.vscode-insiders/extensions",
|
|
39
|
+
"%USERPROFILE%\\.vscode-insiders\\extensions"
|
|
40
|
+
],
|
|
41
|
+
// VS Code Server - Remote SSH connections
|
|
27
42
|
"VS Code Server": ["~/.vscode-server/extensions"],
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
// VS Code Server Insiders - Remote SSH for Insiders
|
|
44
|
+
"VS Code Server Insiders": ["~/.vscode-server-insiders/extensions"],
|
|
45
|
+
// Cursor - AI-powered code editor (VS Code fork)
|
|
46
|
+
// https://cursor.com
|
|
47
|
+
Cursor: [
|
|
48
|
+
// Linux & macOS
|
|
49
|
+
"~/.cursor/extensions",
|
|
50
|
+
// Windows
|
|
51
|
+
"%USERPROFILE%/.cursor/extensions",
|
|
52
|
+
"%USERPROFILE%\\.cursor\\extensions",
|
|
53
|
+
// macOS alternate location
|
|
54
|
+
"~/Library/Application Support/Cursor/User/extensions"
|
|
55
|
+
],
|
|
56
|
+
// Cursor Server - Remote Cursor connections
|
|
57
|
+
"Cursor Server": ["~/.cursor-server/extensions"],
|
|
58
|
+
// Windsurf - Codeium AI IDE (VS Code fork)
|
|
59
|
+
// https://codeium.com/windsurf
|
|
60
|
+
Windsurf: [
|
|
61
|
+
// Linux & macOS
|
|
62
|
+
"~/.windsurf/extensions",
|
|
63
|
+
// Windows
|
|
64
|
+
"%USERPROFILE%/.windsurf/extensions",
|
|
65
|
+
"%USERPROFILE%\\.windsurf\\extensions",
|
|
66
|
+
// macOS alternate location
|
|
67
|
+
"~/Library/Application Support/Windsurf/extensions"
|
|
68
|
+
],
|
|
69
|
+
// Windsurf Server - Remote Windsurf connections
|
|
70
|
+
"Windsurf Server": ["~/.windsurf-server/extensions"],
|
|
71
|
+
// Trae - ByteDance AI IDE (VS Code fork)
|
|
72
|
+
// https://www.trae.ai / https://www.marscode.com
|
|
73
|
+
Trae: [
|
|
74
|
+
// Linux & macOS
|
|
75
|
+
"~/.trae/extensions",
|
|
76
|
+
// Windows
|
|
77
|
+
"%USERPROFILE%/.trae/extensions",
|
|
78
|
+
"%USERPROFILE%\\.trae\\extensions"
|
|
79
|
+
],
|
|
80
|
+
// VSCodium - Open source VS Code without telemetry
|
|
81
|
+
// https://vscodium.com
|
|
82
|
+
VSCodium: [
|
|
83
|
+
// Linux & macOS
|
|
84
|
+
"~/.vscode-oss/extensions",
|
|
85
|
+
// Windows
|
|
86
|
+
"%USERPROFILE%/.vscode-oss/extensions",
|
|
87
|
+
"%USERPROFILE%\\.vscode-oss\\extensions",
|
|
88
|
+
// Flatpak installation (Linux)
|
|
89
|
+
"~/.var/app/com.vscodium.codium/data/codium/extensions"
|
|
90
|
+
],
|
|
91
|
+
// VSCodium Insiders
|
|
92
|
+
"VSCodium Insiders": [
|
|
93
|
+
"~/.vscode-oss-insiders/extensions",
|
|
94
|
+
"%USERPROFILE%/.vscode-oss-insiders/extensions"
|
|
95
|
+
],
|
|
96
|
+
// Code - OSS (open source build from Microsoft repo)
|
|
97
|
+
"Code - OSS": ["~/.config/Code - OSS/extensions", "~/.vscode-oss/extensions"],
|
|
98
|
+
// Positron - Posit's data science IDE (VS Code fork)
|
|
99
|
+
// https://github.com/posit-dev/positron
|
|
100
|
+
Positron: [
|
|
101
|
+
"~/.positron/extensions",
|
|
102
|
+
"%USERPROFILE%/.positron/extensions",
|
|
103
|
+
"~/Library/Application Support/Positron/extensions"
|
|
104
|
+
],
|
|
105
|
+
// Theia - Eclipse Theia IDE (VS Code compatible)
|
|
106
|
+
// https://theia-ide.org
|
|
107
|
+
Theia: ["~/.theia/extensions", "%USERPROFILE%/.theia/extensions"],
|
|
108
|
+
// OpenVSCode Server - Web-based VS Code
|
|
109
|
+
// https://github.com/gitpod-io/openvscode-server
|
|
110
|
+
"OpenVSCode Server": ["~/.openvscode-server/extensions"],
|
|
111
|
+
// code-server - VS Code in the browser
|
|
112
|
+
// https://github.com/coder/code-server
|
|
113
|
+
"code-server": ["~/.local/share/code-server/extensions", "~/.config/code-server/extensions"],
|
|
114
|
+
// GitHub Codespaces (when accessed locally)
|
|
115
|
+
"GitHub Codespaces": ["~/.codespaces/.vscode-remote/extensions"],
|
|
116
|
+
// Gitpod
|
|
117
|
+
Gitpod: ["/workspace/.gitpod/extensions", "~/.gitpod/extensions"],
|
|
118
|
+
// DevPod
|
|
119
|
+
DevPod: ["~/.devpod/extensions"]
|
|
120
|
+
// Lapce - Lightning-fast native code editor (has its own extension format but partially compatible)
|
|
121
|
+
// https://lapce.dev
|
|
122
|
+
// Note: Lapce uses a different extension format, included for future compatibility
|
|
123
|
+
// Lapce: [
|
|
124
|
+
// '~/.lapce/plugins',
|
|
125
|
+
// '~/Library/Application Support/Lapce/plugins',
|
|
126
|
+
// ],
|
|
127
|
+
// Zed - High-performance editor (different extension format, not VS Code compatible)
|
|
128
|
+
// https://zed.dev
|
|
129
|
+
// Note: Zed uses its own extension format, not VS Code compatible
|
|
130
|
+
// Included as reference for potential future support
|
|
131
|
+
// Zed: [
|
|
132
|
+
// '~/Library/Application Support/Zed/extensions',
|
|
133
|
+
// '~/.local/share/zed/extensions',
|
|
134
|
+
// ],
|
|
32
135
|
};
|
|
33
136
|
function expandPath(inputPath) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
137
|
+
let result = inputPath;
|
|
138
|
+
const home = os.homedir();
|
|
139
|
+
if (result.startsWith("~/")) {
|
|
140
|
+
result = path.join(home, result.slice(2));
|
|
141
|
+
} else if (result.startsWith("~\\")) {
|
|
142
|
+
result = path.join(home, result.slice(2));
|
|
143
|
+
} else if (result === "~") {
|
|
144
|
+
result = home;
|
|
145
|
+
}
|
|
146
|
+
if (process.platform === "win32") {
|
|
147
|
+
result = result.replace(/%USERPROFILE%/gi, home);
|
|
148
|
+
result = result.replace(
|
|
149
|
+
/%APPDATA%/gi,
|
|
150
|
+
process.env.APPDATA || path.join(home, "AppData", "Roaming")
|
|
151
|
+
);
|
|
152
|
+
result = result.replace(
|
|
153
|
+
/%LOCALAPPDATA%/gi,
|
|
154
|
+
process.env.LOCALAPPDATA || path.join(home, "AppData", "Local")
|
|
155
|
+
);
|
|
156
|
+
} else {
|
|
157
|
+
result = result.replace(/%USERPROFILE%/gi, home);
|
|
39
158
|
}
|
|
40
|
-
return
|
|
159
|
+
return path.normalize(result);
|
|
41
160
|
}
|
|
42
161
|
function countExtensions(dirPath) {
|
|
43
162
|
try {
|
|
44
163
|
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
45
|
-
return entries.filter((entry) =>
|
|
164
|
+
return entries.filter((entry) => {
|
|
165
|
+
if (!entry.isDirectory()) return false;
|
|
166
|
+
if (entry.name.startsWith(".")) return false;
|
|
167
|
+
if (entry.name === "node_modules") return false;
|
|
168
|
+
return true;
|
|
169
|
+
}).length;
|
|
46
170
|
} catch {
|
|
47
171
|
return 0;
|
|
48
172
|
}
|
|
@@ -53,17 +177,42 @@ function detectIDEPaths() {
|
|
|
53
177
|
for (const idePath of paths) {
|
|
54
178
|
const expandedPath = expandPath(idePath);
|
|
55
179
|
if (fs.existsSync(expandedPath)) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
180
|
+
const extensionCount = countExtensions(expandedPath);
|
|
181
|
+
if (extensionCount > 0) {
|
|
182
|
+
detected.push({
|
|
183
|
+
name: ideName,
|
|
184
|
+
path: expandedPath,
|
|
185
|
+
extensionCount
|
|
186
|
+
});
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
62
189
|
}
|
|
63
190
|
}
|
|
64
191
|
}
|
|
65
192
|
return detected;
|
|
66
193
|
}
|
|
194
|
+
function getSupportedIDEs() {
|
|
195
|
+
return Object.keys(IDE_PATHS);
|
|
196
|
+
}
|
|
197
|
+
function isIDEInstalled(ideName) {
|
|
198
|
+
const paths = IDE_PATHS[ideName];
|
|
199
|
+
if (!paths) return false;
|
|
200
|
+
return paths.some((p) => {
|
|
201
|
+
const expanded = expandPath(p);
|
|
202
|
+
return fs.existsSync(expanded) && countExtensions(expanded) > 0;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
function getIDEExtensionPath(ideName) {
|
|
206
|
+
const paths = IDE_PATHS[ideName];
|
|
207
|
+
if (!paths) return null;
|
|
208
|
+
for (const p of paths) {
|
|
209
|
+
const expanded = expandPath(p);
|
|
210
|
+
if (fs.existsSync(expanded)) {
|
|
211
|
+
return expanded;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
67
216
|
|
|
68
217
|
// src/scanner/extension-reader.ts
|
|
69
218
|
import * as fs2 from "fs/promises";
|
|
@@ -641,7 +790,11 @@ var EXPECTED_BEHAVIORS = {
|
|
|
641
790
|
{
|
|
642
791
|
// SCM extensions may spawn git processes
|
|
643
792
|
ruleIds: ["EG-CRIT-002"],
|
|
644
|
-
matchedPatterns: [
|
|
793
|
+
matchedPatterns: [
|
|
794
|
+
"child_process-exec",
|
|
795
|
+
"child_process-execSync",
|
|
796
|
+
"child_process-spawn-shell"
|
|
797
|
+
]
|
|
645
798
|
}
|
|
646
799
|
],
|
|
647
800
|
debugger: [
|
|
@@ -1996,9 +2149,7 @@ var ExtensionGuardScanner = class {
|
|
|
1996
2149
|
minSeverity: this.options.severity
|
|
1997
2150
|
});
|
|
1998
2151
|
if (this.options.verifyIntegrity) {
|
|
1999
|
-
this.hashDatabase = loadHashDatabase(
|
|
2000
|
-
this.options.hashDatabasePath || void 0
|
|
2001
|
-
);
|
|
2152
|
+
this.hashDatabase = loadHashDatabase(this.options.hashDatabasePath || void 0);
|
|
2002
2153
|
}
|
|
2003
2154
|
}
|
|
2004
2155
|
async scan(options) {
|
|
@@ -2027,11 +2178,8 @@ var ExtensionGuardScanner = class {
|
|
|
2027
2178
|
}
|
|
2028
2179
|
ide.extensionCount = allExtensions[i].length;
|
|
2029
2180
|
}
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
const result = await this.scanExtension(ext);
|
|
2033
|
-
results.push(result);
|
|
2034
|
-
}
|
|
2181
|
+
const extensions = Array.from(extensionMap.values()).map(({ ext }) => ext);
|
|
2182
|
+
const results = await this.scanExtensionsConcurrently(extensions, mergedOptions.concurrency);
|
|
2035
2183
|
const summary = this.calculateSummary(results);
|
|
2036
2184
|
return {
|
|
2037
2185
|
scanId: randomUUID2(),
|
|
@@ -2048,6 +2196,29 @@ var ExtensionGuardScanner = class {
|
|
|
2048
2196
|
scanDurationMs: Date.now() - startTime
|
|
2049
2197
|
};
|
|
2050
2198
|
}
|
|
2199
|
+
/**
|
|
2200
|
+
* Scan multiple extensions concurrently with a configurable pool size.
|
|
2201
|
+
* Uses a simple semaphore pattern to limit concurrent operations.
|
|
2202
|
+
*/
|
|
2203
|
+
async scanExtensionsConcurrently(extensions, concurrency) {
|
|
2204
|
+
const results = new Array(extensions.length);
|
|
2205
|
+
let currentIndex = 0;
|
|
2206
|
+
const worker = async () => {
|
|
2207
|
+
while (currentIndex < extensions.length) {
|
|
2208
|
+
const index = currentIndex++;
|
|
2209
|
+
const ext = extensions[index];
|
|
2210
|
+
if (ext) {
|
|
2211
|
+
results[index] = await this.scanExtension(ext);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
};
|
|
2215
|
+
const workers = Array.from(
|
|
2216
|
+
{ length: Math.min(concurrency, extensions.length) },
|
|
2217
|
+
() => worker()
|
|
2218
|
+
);
|
|
2219
|
+
await Promise.all(workers);
|
|
2220
|
+
return results.filter((r) => r !== void 0);
|
|
2221
|
+
}
|
|
2051
2222
|
async scanExtension(ext) {
|
|
2052
2223
|
const startTime = Date.now();
|
|
2053
2224
|
const files = await collectFiles(ext.installPath);
|
|
@@ -2124,9 +2295,7 @@ var ExtensionGuardScanner = class {
|
|
|
2124
2295
|
return Math.max(0, Math.min(100, score));
|
|
2125
2296
|
}
|
|
2126
2297
|
calculateRiskLevel(trustScore, findings) {
|
|
2127
|
-
const realFindings = findings.filter(
|
|
2128
|
-
(f) => !f.description?.includes("[Downgraded:")
|
|
2129
|
-
);
|
|
2298
|
+
const realFindings = findings.filter((f) => !f.description?.includes("[Downgraded:"));
|
|
2130
2299
|
if (realFindings.some((f) => f.severity === "critical")) {
|
|
2131
2300
|
return "critical";
|
|
2132
2301
|
}
|
|
@@ -2847,7 +3016,7 @@ var PolicyEngine = class {
|
|
|
2847
3016
|
};
|
|
2848
3017
|
|
|
2849
3018
|
// src/index.ts
|
|
2850
|
-
var VERSION = "0.
|
|
3019
|
+
var VERSION = "0.5.1";
|
|
2851
3020
|
export {
|
|
2852
3021
|
ALL_POPULAR_EXTENSIONS,
|
|
2853
3022
|
DETECTION_RULES,
|
|
@@ -2879,9 +3048,12 @@ export {
|
|
|
2879
3048
|
generateBaseline,
|
|
2880
3049
|
getDefaultDatabasePath,
|
|
2881
3050
|
getHash,
|
|
3051
|
+
getIDEExtensionPath,
|
|
2882
3052
|
getPopularityTier,
|
|
3053
|
+
getSupportedIDEs,
|
|
2883
3054
|
isAtLeastSeverity,
|
|
2884
3055
|
isBundleOutputPath,
|
|
3056
|
+
isIDEInstalled,
|
|
2885
3057
|
isMegaPopular,
|
|
2886
3058
|
isPopular,
|
|
2887
3059
|
isTrustedExtension,
|