@heimdall-ai/heimdall 0.1.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/LICENSE +190 -0
- package/README.md +471 -0
- package/dist/config/constants.d.ts +24 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +70 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/core/bash-manager.d.ts +56 -0
- package/dist/core/bash-manager.d.ts.map +1 -0
- package/dist/core/bash-manager.js +106 -0
- package/dist/core/bash-manager.js.map +1 -0
- package/dist/core/pyodide-manager.d.ts +125 -0
- package/dist/core/pyodide-manager.d.ts.map +1 -0
- package/dist/core/pyodide-manager.js +669 -0
- package/dist/core/pyodide-manager.js.map +1 -0
- package/dist/core/pyodide-worker.d.ts +9 -0
- package/dist/core/pyodide-worker.d.ts.map +1 -0
- package/dist/core/pyodide-worker.js +295 -0
- package/dist/core/pyodide-worker.js.map +1 -0
- package/dist/core/secure-fs.d.ts +101 -0
- package/dist/core/secure-fs.d.ts.map +1 -0
- package/dist/core/secure-fs.js +279 -0
- package/dist/core/secure-fs.js.map +1 -0
- package/dist/integration.test.d.ts +10 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +439 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/resources/index.d.ts +12 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +13 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/workspace.d.ts +12 -0
- package/dist/resources/workspace.d.ts.map +1 -0
- package/dist/resources/workspace.js +105 -0
- package/dist/resources/workspace.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +51 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/bash-execution.d.ts +13 -0
- package/dist/tools/bash-execution.d.ts.map +1 -0
- package/dist/tools/bash-execution.js +135 -0
- package/dist/tools/bash-execution.js.map +1 -0
- package/dist/tools/filesystem.d.ts +12 -0
- package/dist/tools/filesystem.d.ts.map +1 -0
- package/dist/tools/filesystem.js +104 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +17 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/python-execution.d.ts +12 -0
- package/dist/tools/python-execution.d.ts.map +1 -0
- package/dist/tools/python-execution.js +77 -0
- package/dist/tools/python-execution.js.map +1 -0
- package/dist/types/index.d.ts +64 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/async-lock.d.ts +35 -0
- package/dist/utils/async-lock.d.ts.map +1 -0
- package/dist/utils/async-lock.js +57 -0
- package/dist/utils/async-lock.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +61 -0
package/dist/server.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Heimdall MCP Server
|
|
4
|
+
*
|
|
5
|
+
* A TypeScript MCP server providing sandboxed Python and Bash execution.
|
|
6
|
+
* Named after the Norse god who guards the Bifröst bridge, Heimdall watches
|
|
7
|
+
* over code execution with security and vigilance.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Secure Python execution via Pyodide (WebAssembly sandbox)
|
|
11
|
+
* - Bash command execution via just-bash
|
|
12
|
+
* - Virtual filesystem with host sync
|
|
13
|
+
* - Package installation via micropip
|
|
14
|
+
* - Session persistence
|
|
15
|
+
*/
|
|
16
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
18
|
+
import { PyodideManager } from "./core/pyodide-manager.js";
|
|
19
|
+
import { BashManager } from "./core/bash-manager.js";
|
|
20
|
+
import { registerAllTools } from "./tools/index.js";
|
|
21
|
+
import { registerAllResources } from "./resources/index.js";
|
|
22
|
+
/**
|
|
23
|
+
* Main entry point
|
|
24
|
+
*/
|
|
25
|
+
async function main() {
|
|
26
|
+
console.error("[Heimdall] Starting server...");
|
|
27
|
+
// Create manager instances
|
|
28
|
+
const pyodideManager = new PyodideManager();
|
|
29
|
+
const bashManager = new BashManager();
|
|
30
|
+
// Create MCP server
|
|
31
|
+
const server = new McpServer({
|
|
32
|
+
name: "heimdall",
|
|
33
|
+
version: "1.0.0",
|
|
34
|
+
});
|
|
35
|
+
// Register all tools and resources
|
|
36
|
+
registerAllTools(server, pyodideManager, bashManager);
|
|
37
|
+
registerAllResources(server, pyodideManager);
|
|
38
|
+
// Pre-initialize managers (optional, improves first tool call latency)
|
|
39
|
+
// Note: Disabled for now - managers will initialize lazily on first use
|
|
40
|
+
// await pyodideManager.initialize();
|
|
41
|
+
// await bashManager.initialize();
|
|
42
|
+
// Connect transport
|
|
43
|
+
const transport = new StdioServerTransport();
|
|
44
|
+
await server.connect(transport);
|
|
45
|
+
console.error("[Heimdall] Server connected and ready");
|
|
46
|
+
}
|
|
47
|
+
main().catch((error) => {
|
|
48
|
+
console.error("[Heimdall] Fatal error:", error);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAE/C,2BAA2B;IAC3B,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC;IAC5C,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IAEtC,oBAAoB;IACpB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,mCAAmC;IACnC,gBAAgB,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,CAAC,CAAC;IACtD,oBAAoB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAE7C,uEAAuE;IACvE,wEAAwE;IACxE,qCAAqC;IACrC,kCAAkC;IAElC,oBAAoB;IACpB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;AACzD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash Execution Tools
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for executing bash commands in the Heimdall environment
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import type { BashManager } from "../core/bash-manager.js";
|
|
8
|
+
import type { PyodideManager } from "../core/pyodide-manager.js";
|
|
9
|
+
/**
|
|
10
|
+
* Register bash execution tools with the MCP server
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerBashExecutionTools(server: McpServer, bashManager: BashManager, pyodideManager: PyodideManager): void;
|
|
13
|
+
//# sourceMappingURL=bash-execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-execution.d.ts","sourceRoot":"","sources":["../../src/tools/bash-execution.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAIjE;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,cAAc,GAC7B,IAAI,CAgIN"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash Execution Tools
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for executing bash commands in the Heimdall environment
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { posix as path } from "path";
|
|
8
|
+
/**
|
|
9
|
+
* Register bash execution tools with the MCP server
|
|
10
|
+
*/
|
|
11
|
+
export function registerBashExecutionTools(server, bashManager, pyodideManager) {
|
|
12
|
+
server.registerTool("execute_bash", {
|
|
13
|
+
title: "Execute Bash",
|
|
14
|
+
description: `Execute a bash command in the Heimdall environment.
|
|
15
|
+
|
|
16
|
+
Features:
|
|
17
|
+
- Supports 50+ built-in commands: grep, sed, awk, find, jq, curl, tar, etc.
|
|
18
|
+
- Pipes and redirections: |, >, >>, 2>, 2>&1
|
|
19
|
+
- Variables, loops, conditionals, and functions
|
|
20
|
+
- File operations: ls, cat, cp, mv, rm, mkdir, etc.
|
|
21
|
+
- Text processing: grep, sed, awk, cut, sort, uniq, wc, etc.
|
|
22
|
+
- Data tools: jq (JSON), sqlite3 (SQLite), xan (CSV), yq (YAML)
|
|
23
|
+
- Find and search: find, grep, rg (ripgrep)
|
|
24
|
+
|
|
25
|
+
The command runs with access to the /workspace directory. All file changes are immediately visible to Python code.
|
|
26
|
+
|
|
27
|
+
Security:
|
|
28
|
+
- No real processes spawned (TypeScript simulation)
|
|
29
|
+
- Execution limits prevent infinite loops
|
|
30
|
+
- Network access disabled by default
|
|
31
|
+
- Filesystem limited to workspace directory
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
- Find files: "find . -name '*.py' -type f"
|
|
35
|
+
- Process text: "cat data.txt | grep 'pattern' | wc -l"
|
|
36
|
+
- JSON query: "cat data.json | jq '.users[] | {name, email}'"
|
|
37
|
+
- Multiple commands: "ls -la && cat README.md | head -10"`,
|
|
38
|
+
inputSchema: {
|
|
39
|
+
command: z.string().describe("The bash command to execute"),
|
|
40
|
+
cwd: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Working directory (relative to /workspace, e.g., 'subdir' or '.')"),
|
|
44
|
+
},
|
|
45
|
+
}, async ({ command, cwd }) => {
|
|
46
|
+
try {
|
|
47
|
+
// Validate cwd to prevent path traversal attacks
|
|
48
|
+
if (cwd) {
|
|
49
|
+
// Normalize the path to resolve any '..' components
|
|
50
|
+
const normalizedCwd = path.normalize(cwd);
|
|
51
|
+
// Check if it's an absolute path
|
|
52
|
+
if (path.isAbsolute(normalizedCwd)) {
|
|
53
|
+
// Absolute paths must be exactly /workspace or start with /workspace/
|
|
54
|
+
if (normalizedCwd !== "/workspace" && !normalizedCwd.startsWith("/workspace/")) {
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `Invalid working directory: Absolute paths must be within /workspace (got: ${normalizedCwd})`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// Relative paths: resolve from /workspace and check if it stays within
|
|
68
|
+
const resolvedPath = path.join("/workspace", normalizedCwd);
|
|
69
|
+
if (resolvedPath !== "/workspace" && !resolvedPath.startsWith("/workspace/")) {
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: `Invalid working directory: Path traversal detected (resolved to: ${resolvedPath})`,
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Execute bash command
|
|
83
|
+
const result = await bashManager.execute(command, { cwd });
|
|
84
|
+
// Sync changes to Pyodide virtual filesystem
|
|
85
|
+
// This ensures Python sees any file modifications made by bash
|
|
86
|
+
await pyodideManager.syncHostToVirtual();
|
|
87
|
+
// Combine stdout and stderr for output
|
|
88
|
+
let output = "";
|
|
89
|
+
if (result.stdout) {
|
|
90
|
+
output += result.stdout;
|
|
91
|
+
}
|
|
92
|
+
if (result.stderr) {
|
|
93
|
+
if (output)
|
|
94
|
+
output += "\n";
|
|
95
|
+
output += result.stderr;
|
|
96
|
+
}
|
|
97
|
+
// Return based on exit code
|
|
98
|
+
if (result.exitCode === 0) {
|
|
99
|
+
return {
|
|
100
|
+
content: [
|
|
101
|
+
{
|
|
102
|
+
type: "text",
|
|
103
|
+
text: output || "Command executed successfully (no output)",
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Non-zero exit code indicates failure
|
|
110
|
+
return {
|
|
111
|
+
content: [
|
|
112
|
+
{
|
|
113
|
+
type: "text",
|
|
114
|
+
text: `Command failed with exit code ${result.exitCode}\n${output}`,
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
isError: true,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: "text",
|
|
127
|
+
text: `Error executing bash command: ${errorMessage}`,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
isError: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=bash-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-execution.js","sourceRoot":"","sources":["../../src/tools/bash-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem Tools
|
|
3
|
+
*
|
|
4
|
+
* MCP tools for file system operations in the Heimdall workspace
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import type { PyodideManager } from "../core/pyodide-manager.js";
|
|
8
|
+
/**
|
|
9
|
+
* Register filesystem tools with the MCP server
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerFilesystemTools(server: McpServer, pyodideManager: PyodideManager): void;
|
|
12
|
+
//# sourceMappingURL=filesystem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/tools/filesystem.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,QAmHxF"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem Tools
|
|
3
|
+
*
|
|
4
|
+
* MCP tools for file system operations in the Heimdall workspace
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
/**
|
|
8
|
+
* Register filesystem tools with the MCP server
|
|
9
|
+
*/
|
|
10
|
+
export function registerFilesystemTools(server, pyodideManager) {
|
|
11
|
+
// Write file
|
|
12
|
+
server.registerTool("write_file", {
|
|
13
|
+
title: "Write File",
|
|
14
|
+
description: `Write content to a file in the Heimdall workspace.
|
|
15
|
+
|
|
16
|
+
Creates parent directories automatically. Files persist between executions.`,
|
|
17
|
+
inputSchema: {
|
|
18
|
+
path: z.string().describe("File path relative to workspace"),
|
|
19
|
+
content: z.string().describe("Content to write"),
|
|
20
|
+
},
|
|
21
|
+
}, async ({ path: filePath, content }) => {
|
|
22
|
+
const result = await pyodideManager.writeFile(filePath, content);
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: result.success ? `✓ Written to ${filePath}` : `✗ Error: ${result.error}`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
structuredContent: result,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
// Read file
|
|
34
|
+
server.registerTool("read_file", {
|
|
35
|
+
title: "Read File",
|
|
36
|
+
description: "Read content from a file in the Heimdall workspace.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
path: z.string().describe("File path relative to workspace"),
|
|
39
|
+
},
|
|
40
|
+
}, async ({ path: filePath }) => {
|
|
41
|
+
const result = await pyodideManager.readFile(filePath);
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: result.success ? result.content : `Error: ${result.error}`,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
structuredContent: result,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
// List files
|
|
53
|
+
server.registerTool("list_files", {
|
|
54
|
+
title: "List Files",
|
|
55
|
+
description: "List files and directories in the Heimdall workspace.",
|
|
56
|
+
inputSchema: {
|
|
57
|
+
path: z.string().optional().describe("Directory path (empty for workspace root)"),
|
|
58
|
+
},
|
|
59
|
+
}, async ({ path: dirPath }) => {
|
|
60
|
+
const result = await pyodideManager.listFiles(dirPath || "");
|
|
61
|
+
let text;
|
|
62
|
+
if (result.success) {
|
|
63
|
+
if (result.files.length === 0) {
|
|
64
|
+
text = "Directory is empty";
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
text = result.files
|
|
68
|
+
.map((f) => {
|
|
69
|
+
const icon = f.isDirectory ? "📁" : "📄";
|
|
70
|
+
const size = f.isDirectory ? "" : ` (${f.size} bytes)`;
|
|
71
|
+
return `${icon} ${f.name}${size}`;
|
|
72
|
+
})
|
|
73
|
+
.join("\n");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
text = `Error: ${result.error}`;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text }],
|
|
81
|
+
structuredContent: result,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
// Delete file
|
|
85
|
+
server.registerTool("delete_file", {
|
|
86
|
+
title: "Delete File",
|
|
87
|
+
description: "Delete a file or empty directory from the Heimdall workspace.",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
path: z.string().describe("File or directory path"),
|
|
90
|
+
},
|
|
91
|
+
}, async ({ path: filePath }) => {
|
|
92
|
+
const result = await pyodideManager.deleteFile(filePath);
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: result.success ? `✓ Deleted ${filePath}` : `✗ Error: ${result.error}`,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
structuredContent: result,
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=filesystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/tools/filesystem.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools Registration
|
|
3
|
+
*
|
|
4
|
+
* Central module for registering all MCP tools
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import type { PyodideManager } from "../core/pyodide-manager.js";
|
|
8
|
+
import type { BashManager } from "../core/bash-manager.js";
|
|
9
|
+
/**
|
|
10
|
+
* Register all tools with the MCP server
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerAllTools(server: McpServer, pyodideManager: PyodideManager, bashManager: BashManager): void;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAK3D;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,EACjB,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,WAAW,GACvB,IAAI,CAIN"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools Registration
|
|
3
|
+
*
|
|
4
|
+
* Central module for registering all MCP tools
|
|
5
|
+
*/
|
|
6
|
+
import { registerPythonExecutionTools } from "./python-execution.js";
|
|
7
|
+
import { registerFilesystemTools } from "./filesystem.js";
|
|
8
|
+
import { registerBashExecutionTools } from "./bash-execution.js";
|
|
9
|
+
/**
|
|
10
|
+
* Register all tools with the MCP server
|
|
11
|
+
*/
|
|
12
|
+
export function registerAllTools(server, pyodideManager, bashManager) {
|
|
13
|
+
registerPythonExecutionTools(server, pyodideManager);
|
|
14
|
+
registerFilesystemTools(server, pyodideManager);
|
|
15
|
+
registerBashExecutionTools(server, bashManager, pyodideManager);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAiB,EACjB,cAA8B,EAC9B,WAAwB;IAExB,4BAA4B,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACrD,uBAAuB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAChD,0BAA0B,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python Execution Tools
|
|
3
|
+
*
|
|
4
|
+
* MCP tools for executing Python code and installing packages
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
import type { PyodideManager } from "../core/pyodide-manager.js";
|
|
8
|
+
/**
|
|
9
|
+
* Register Python execution tools with the MCP server
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerPythonExecutionTools(server: McpServer, pyodideManager: PyodideManager): void;
|
|
12
|
+
//# sourceMappingURL=python-execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-execution.d.ts","sourceRoot":"","sources":["../../src/tools/python-execution.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,cAAc,QA6E7F"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python Execution Tools
|
|
3
|
+
*
|
|
4
|
+
* MCP tools for executing Python code and installing packages
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
/**
|
|
8
|
+
* Register Python execution tools with the MCP server
|
|
9
|
+
*/
|
|
10
|
+
export function registerPythonExecutionTools(server, pyodideManager) {
|
|
11
|
+
// Execute Python code
|
|
12
|
+
server.registerTool("execute_python", {
|
|
13
|
+
title: "Execute Python",
|
|
14
|
+
description: `Execute Python code in the Heimdall environment (Pyodide sandbox).
|
|
15
|
+
|
|
16
|
+
The code runs in an isolated WebAssembly sandbox with:
|
|
17
|
+
- Access to /workspace directory for file I/O
|
|
18
|
+
- Standard library and auto-loaded packages
|
|
19
|
+
- stdout/stderr capture for output
|
|
20
|
+
- NO network access (WebAssembly security boundary)
|
|
21
|
+
- Execution time limits to prevent long-running scripts
|
|
22
|
+
|
|
23
|
+
Returns execution results including output and any errors.`,
|
|
24
|
+
inputSchema: {
|
|
25
|
+
code: z.string().describe("Python code to execute"),
|
|
26
|
+
packages: z
|
|
27
|
+
.array(z.string())
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Optional additional packages to install (most are auto-detected from imports)"),
|
|
30
|
+
},
|
|
31
|
+
}, async ({ code, packages }) => {
|
|
32
|
+
const result = await pyodideManager.executeCode(code, packages || []);
|
|
33
|
+
const output = {
|
|
34
|
+
success: result.success,
|
|
35
|
+
stdout: result.stdout,
|
|
36
|
+
stderr: result.stderr,
|
|
37
|
+
result: result.result,
|
|
38
|
+
error: result.error,
|
|
39
|
+
};
|
|
40
|
+
let text = "";
|
|
41
|
+
if (result.stdout)
|
|
42
|
+
text += `Output:\n${result.stdout}\n`;
|
|
43
|
+
if (result.stderr)
|
|
44
|
+
text += `Stderr:\n${result.stderr}\n`;
|
|
45
|
+
if (result.result)
|
|
46
|
+
text += `Result: ${result.result}\n`;
|
|
47
|
+
if (result.error)
|
|
48
|
+
text += `Error:\n${result.error}\n`;
|
|
49
|
+
if (!text)
|
|
50
|
+
text = "Code executed successfully (no output)";
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text", text }],
|
|
53
|
+
structuredContent: output,
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
// Install packages
|
|
57
|
+
server.registerTool("install_packages", {
|
|
58
|
+
title: "Install Packages",
|
|
59
|
+
description: `Install Python packages via micropip.
|
|
60
|
+
|
|
61
|
+
Note: Only pure Python packages or packages with WebAssembly wheels are supported.
|
|
62
|
+
Common data science packages like numpy, pandas, scipy are available.`,
|
|
63
|
+
inputSchema: {
|
|
64
|
+
packages: z.array(z.string()).describe("List of package names to install"),
|
|
65
|
+
},
|
|
66
|
+
}, async ({ packages }) => {
|
|
67
|
+
const results = await pyodideManager.installPackages(packages);
|
|
68
|
+
const text = results
|
|
69
|
+
.map((r) => `${r.package}: ${r.success ? "✓ installed" : `✗ ${r.error}`}`)
|
|
70
|
+
.join("\n");
|
|
71
|
+
return {
|
|
72
|
+
content: [{ type: "text", text }],
|
|
73
|
+
structuredContent: { results },
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=python-execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python-execution.js","sourceRoot":"","sources":["../../src/tools/python-execution.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;GAEG;AACH,MAAM,UAAU,4BAA4B,CAAC,MAAiB,EAAE,cAA8B;IAC5F,sBAAsB;IACtB,MAAM,CAAC,YAAY,CACjB,gBAAgB,EAChB;QACE,KAAK,EAAE,gBAAgB;QACvB,WAAW,EAAE;;;;;;;;;2DASwC;QACrD,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;YACnD,QAAQ,EAAE,CAAC;iBACR,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;iBACjB,QAAQ,EAAE;iBACV,QAAQ,CACP,+EAA+E,CAChF;SACJ;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;QAEtE,MAAM,MAAM,GAAG;YACb,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC;QAEF,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,MAAM,CAAC,MAAM;YAAE,IAAI,IAAI,YAAY,MAAM,CAAC,MAAM,IAAI,CAAC;QACzD,IAAI,MAAM,CAAC,MAAM;YAAE,IAAI,IAAI,YAAY,MAAM,CAAC,MAAM,IAAI,CAAC;QACzD,IAAI,MAAM,CAAC,MAAM;YAAE,IAAI,IAAI,WAAW,MAAM,CAAC,MAAM,IAAI,CAAC;QACxD,IAAI,MAAM,CAAC,KAAK;YAAE,IAAI,IAAI,WAAW,MAAM,CAAC,KAAK,IAAI,CAAC;QACtD,IAAI,CAAC,IAAI;YAAE,IAAI,GAAG,wCAAwC,CAAC;QAE3D,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACjC,iBAAiB,EAAE,MAAM;SAC1B,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,mBAAmB;IACnB,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE;;;sEAGmD;QAChE,WAAW,EAAE;YACX,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,kCAAkC,CAAC;SAC3E;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAE/D,MAAM,IAAI,GAAG,OAAO;aACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;aACzE,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YACjC,iBAAiB,EAAE,EAAE,OAAO,EAAE;SAC/B,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base interface with index signature for MCP SDK compatibility
|
|
3
|
+
*/
|
|
4
|
+
interface BaseResult {
|
|
5
|
+
[x: string]: unknown;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Result from executing Python code
|
|
9
|
+
*/
|
|
10
|
+
export interface ExecutionResult extends BaseResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
stdout: string;
|
|
13
|
+
stderr: string;
|
|
14
|
+
result: string | null;
|
|
15
|
+
error: string | null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Result from reading a file
|
|
19
|
+
*/
|
|
20
|
+
export interface FileReadResult extends BaseResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
content: string | null;
|
|
23
|
+
error: string | null;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Result from writing a file
|
|
27
|
+
*/
|
|
28
|
+
export interface FileWriteResult extends BaseResult {
|
|
29
|
+
success: boolean;
|
|
30
|
+
error: string | null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result from installing packages
|
|
34
|
+
*/
|
|
35
|
+
export interface PackageInstallResult extends BaseResult {
|
|
36
|
+
package: string;
|
|
37
|
+
success: boolean;
|
|
38
|
+
error: string | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* File information
|
|
42
|
+
*/
|
|
43
|
+
export interface FileInfo extends BaseResult {
|
|
44
|
+
name: string;
|
|
45
|
+
isDirectory: boolean;
|
|
46
|
+
size: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Result from listing files
|
|
50
|
+
*/
|
|
51
|
+
export interface FileListResult extends BaseResult {
|
|
52
|
+
success: boolean;
|
|
53
|
+
files: FileInfo[];
|
|
54
|
+
error: string | null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Result from deleting a file
|
|
58
|
+
*/
|
|
59
|
+
export interface FileDeleteResult extends BaseResult {
|
|
60
|
+
success: boolean;
|
|
61
|
+
error: string | null;
|
|
62
|
+
}
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,UAAU,UAAU;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,UAAU;IACtD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AsyncLock - A simple async mutex/lock implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides mutual exclusion for async operations, preventing race conditions
|
|
5
|
+
* in concurrent code. Used to protect critical sections like file writes
|
|
6
|
+
* where TOCTOU (time-of-check to time-of-use) vulnerabilities could occur.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const lock = new AsyncLock();
|
|
11
|
+
*
|
|
12
|
+
* // Multiple concurrent calls will be serialized
|
|
13
|
+
* await lock.acquire('write', async () => {
|
|
14
|
+
* await checkSize();
|
|
15
|
+
* await writeFile();
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare class AsyncLock {
|
|
20
|
+
private locks;
|
|
21
|
+
/**
|
|
22
|
+
* Acquire a lock for the given key, execute the function, then release.
|
|
23
|
+
* If another operation holds the lock, this will wait until it's released.
|
|
24
|
+
*
|
|
25
|
+
* @param key - The lock key (allows multiple independent locks)
|
|
26
|
+
* @param fn - The async function to execute while holding the lock
|
|
27
|
+
* @returns The result of the function
|
|
28
|
+
*/
|
|
29
|
+
acquire<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
30
|
+
/**
|
|
31
|
+
* Check if a lock is currently held for the given key
|
|
32
|
+
*/
|
|
33
|
+
isLocked(key: string): boolean;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=async-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-lock.d.ts","sourceRoot":"","sources":["../../src/utils/async-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAyC;IAEtD;;;;;;;OAOG;IACG,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAwB/D;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG/B"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AsyncLock - A simple async mutex/lock implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides mutual exclusion for async operations, preventing race conditions
|
|
5
|
+
* in concurrent code. Used to protect critical sections like file writes
|
|
6
|
+
* where TOCTOU (time-of-check to time-of-use) vulnerabilities could occur.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const lock = new AsyncLock();
|
|
11
|
+
*
|
|
12
|
+
* // Multiple concurrent calls will be serialized
|
|
13
|
+
* await lock.acquire('write', async () => {
|
|
14
|
+
* await checkSize();
|
|
15
|
+
* await writeFile();
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export class AsyncLock {
|
|
20
|
+
locks = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Acquire a lock for the given key, execute the function, then release.
|
|
23
|
+
* If another operation holds the lock, this will wait until it's released.
|
|
24
|
+
*
|
|
25
|
+
* @param key - The lock key (allows multiple independent locks)
|
|
26
|
+
* @param fn - The async function to execute while holding the lock
|
|
27
|
+
* @returns The result of the function
|
|
28
|
+
*/
|
|
29
|
+
async acquire(key, fn) {
|
|
30
|
+
// Wait for any existing lock on this key
|
|
31
|
+
while (this.locks.has(key)) {
|
|
32
|
+
await this.locks.get(key);
|
|
33
|
+
}
|
|
34
|
+
// Create a new lock promise
|
|
35
|
+
let releaseLock;
|
|
36
|
+
const lockPromise = new Promise((resolve) => {
|
|
37
|
+
releaseLock = resolve;
|
|
38
|
+
});
|
|
39
|
+
this.locks.set(key, lockPromise);
|
|
40
|
+
try {
|
|
41
|
+
// Execute the protected function
|
|
42
|
+
return await fn();
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
// Release the lock
|
|
46
|
+
this.locks.delete(key);
|
|
47
|
+
releaseLock();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if a lock is currently held for the given key
|
|
52
|
+
*/
|
|
53
|
+
isLocked(key) {
|
|
54
|
+
return this.locks.has(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=async-lock.js.map
|