@ellery/terminal-mcp 0.1.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/LICENSE +21 -0
- package/README.md +207 -0
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +185 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +192 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +79 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +58 -0
- package/dist/server.js.map +1 -0
- package/dist/terminal/index.d.ts +4 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +3 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/manager.d.ts +54 -0
- package/dist/terminal/manager.d.ts.map +1 -0
- package/dist/terminal/manager.js +79 -0
- package/dist/terminal/manager.js.map +1 -0
- package/dist/terminal/session.d.ts +85 -0
- package/dist/terminal/session.d.ts.map +1 -0
- package/dist/terminal/session.js +246 -0
- package/dist/terminal/session.js.map +1 -0
- package/dist/tools/getContent.d.ts +32 -0
- package/dist/tools/getContent.d.ts.map +1 -0
- package/dist/tools/getContent.js +38 -0
- package/dist/tools/getContent.js.map +1 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +43 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/screenshot.d.ts +20 -0
- package/dist/tools/screenshot.d.ts.map +1 -0
- package/dist/tools/screenshot.js +28 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/sendKey.d.ts +31 -0
- package/dist/tools/sendKey.d.ts.map +1 -0
- package/dist/tools/sendKey.js +38 -0
- package/dist/tools/sendKey.js.map +1 -0
- package/dist/tools/type.d.ts +31 -0
- package/dist/tools/type.d.ts.map +1 -0
- package/dist/tools/type.js +31 -0
- package/dist/tools/type.js.map +1 -0
- package/dist/transport/index.d.ts +2 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +2 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/socket.d.ts +30 -0
- package/dist/transport/socket.d.ts.map +1 -0
- package/dist/transport/socket.js +168 -0
- package/dist/transport/socket.js.map +1 -0
- package/dist/ui/index.d.ts +24 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +124 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/utils/keys.d.ts +16 -0
- package/dist/utils/keys.d.ts.map +1 -0
- package/dist/utils/keys.js +98 -0
- package/dist/utils/keys.js.map +1 -0
- package/dist/utils/stats.d.ts +46 -0
- package/dist/utils/stats.d.ts.map +1 -0
- package/dist/utils/stats.js +89 -0
- package/dist/utils/stats.js.map +1 -0
- package/logo.png +0 -0
- package/package.json +47 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
const TOOL_USAGE_PROMPT = `# Terminal MCP Tool Usage Guide
|
|
3
|
+
|
|
4
|
+
## Overview
|
|
5
|
+
This MCP server provides tools to interact with a terminal emulator. Use these tools to execute commands and read output.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
### type
|
|
10
|
+
Send text input to the terminal. Text is written exactly as provided - no Enter key is sent automatically.
|
|
11
|
+
|
|
12
|
+
To execute a command, use type() followed by sendKey('Enter').
|
|
13
|
+
|
|
14
|
+
**Example workflow:**
|
|
15
|
+
1. type('ls -la') - types the command
|
|
16
|
+
2. sendKey('Enter') - executes it
|
|
17
|
+
3. getContent() - reads the output
|
|
18
|
+
|
|
19
|
+
### sendKey
|
|
20
|
+
Send a special key or key combination to the terminal.
|
|
21
|
+
|
|
22
|
+
**Common keys:** Enter, Tab, Escape, Backspace, Delete, ArrowUp, ArrowDown, ArrowLeft, ArrowRight
|
|
23
|
+
|
|
24
|
+
**Navigation:** Home, End, PageUp, PageDown
|
|
25
|
+
|
|
26
|
+
**Control sequences:**
|
|
27
|
+
- Ctrl+C - interrupt current process
|
|
28
|
+
- Ctrl+D - EOF/exit
|
|
29
|
+
- Ctrl+Z - suspend process
|
|
30
|
+
- Ctrl+L - clear screen
|
|
31
|
+
- Ctrl+A - move to start of line
|
|
32
|
+
- Ctrl+E - move to end of line
|
|
33
|
+
|
|
34
|
+
**Function keys:** F1-F12
|
|
35
|
+
|
|
36
|
+
### getContent
|
|
37
|
+
Get terminal content as plain text. Use after sending commands to see output.
|
|
38
|
+
|
|
39
|
+
Returns full scrollback buffer by default (up to 1000 lines). Set visibleOnly=true for just the current viewport (useful when output is very long).
|
|
40
|
+
|
|
41
|
+
Prefer this over takeScreenshot when you only need text content.
|
|
42
|
+
|
|
43
|
+
### takeScreenshot
|
|
44
|
+
Capture terminal state as structured JSON with:
|
|
45
|
+
- content: visible text
|
|
46
|
+
- cursor: {x, y} position
|
|
47
|
+
- dimensions: {cols, rows}
|
|
48
|
+
|
|
49
|
+
Use when you need cursor position (e.g., for interactive apps, editors) or terminal dimensions. For simple command output, prefer getContent().
|
|
50
|
+
`;
|
|
51
|
+
const prompts = [
|
|
52
|
+
{
|
|
53
|
+
name: "tool-usage",
|
|
54
|
+
description: "Instructions for effectively using terminal-mcp tools",
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
export function registerPrompts(server) {
|
|
58
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
59
|
+
prompts,
|
|
60
|
+
}));
|
|
61
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
62
|
+
const { name } = request.params;
|
|
63
|
+
if (name === "tool-usage") {
|
|
64
|
+
return {
|
|
65
|
+
messages: [
|
|
66
|
+
{
|
|
67
|
+
role: "user",
|
|
68
|
+
content: {
|
|
69
|
+
type: "text",
|
|
70
|
+
text: TOOL_USAGE_PROMPT,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,wBAAwB,EACxB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAE5C,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDzB,CAAC;AAEF,MAAM,OAAO,GAAG;IACd;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,uDAAuD;KACrE;CACF,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,CAAC,iBAAiB,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC9D,OAAO;KACR,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACjE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QAEhC,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC1B,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,IAAI,EAAE,MAAe;wBACrB,OAAO,EAAE;4BACP,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,iBAAiB;yBACxB;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
3
|
+
import { TerminalManager } from "./terminal/index.js";
|
|
4
|
+
export interface ServerOptions {
|
|
5
|
+
cols?: number;
|
|
6
|
+
rows?: number;
|
|
7
|
+
shell?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create and configure the MCP server with an existing terminal manager
|
|
11
|
+
*/
|
|
12
|
+
export declare function createServerWithManager(manager: TerminalManager): Server;
|
|
13
|
+
/**
|
|
14
|
+
* Create and configure the MCP server with a new terminal manager
|
|
15
|
+
*/
|
|
16
|
+
export declare function createServer(options?: ServerOptions): {
|
|
17
|
+
server: Server;
|
|
18
|
+
manager: TerminalManager;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Connect an MCP server to a transport
|
|
22
|
+
*/
|
|
23
|
+
export declare function connectServer(server: Server, transport: Transport): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Start the MCP server with stdio transport (legacy mode)
|
|
26
|
+
*/
|
|
27
|
+
export declare function startServer(options?: ServerOptions): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAItD,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAkBxE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,aAAkB,GAAG;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,CAAC;CAC1B,CAUA;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB5E"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { TerminalManager } from "./terminal/index.js";
|
|
4
|
+
import { registerTools } from "./tools/index.js";
|
|
5
|
+
import { registerPrompts } from "./prompts/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create and configure the MCP server with an existing terminal manager
|
|
8
|
+
*/
|
|
9
|
+
export function createServerWithManager(manager) {
|
|
10
|
+
const server = new Server({
|
|
11
|
+
name: "terminal-mcp",
|
|
12
|
+
version: "0.1.0",
|
|
13
|
+
}, {
|
|
14
|
+
capabilities: {
|
|
15
|
+
tools: {},
|
|
16
|
+
prompts: {},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
registerTools(server, manager);
|
|
20
|
+
registerPrompts(server);
|
|
21
|
+
return server;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create and configure the MCP server with a new terminal manager
|
|
25
|
+
*/
|
|
26
|
+
export function createServer(options = {}) {
|
|
27
|
+
const manager = new TerminalManager({
|
|
28
|
+
cols: options.cols,
|
|
29
|
+
rows: options.rows,
|
|
30
|
+
shell: options.shell,
|
|
31
|
+
});
|
|
32
|
+
const server = createServerWithManager(manager);
|
|
33
|
+
return { server, manager };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Connect an MCP server to a transport
|
|
37
|
+
*/
|
|
38
|
+
export async function connectServer(server, transport) {
|
|
39
|
+
await server.connect(transport);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Start the MCP server with stdio transport (legacy mode)
|
|
43
|
+
*/
|
|
44
|
+
export async function startServer(options = {}) {
|
|
45
|
+
const { server, manager } = createServer(options);
|
|
46
|
+
const transport = new StdioServerTransport();
|
|
47
|
+
// Handle graceful shutdown
|
|
48
|
+
process.on("SIGINT", () => {
|
|
49
|
+
manager.dispose();
|
|
50
|
+
process.exit(0);
|
|
51
|
+
});
|
|
52
|
+
process.on("SIGTERM", () => {
|
|
53
|
+
manager.dispose();
|
|
54
|
+
process.exit(0);
|
|
55
|
+
});
|
|
56
|
+
await server.connect(transport);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAQrD;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAwB;IAC9D,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;SACZ;KACF,CACF,CAAC;IAEF,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,UAAyB,EAAE;IAItD,MAAM,OAAO,GAAG,IAAI,eAAe,CAAC;QAClC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAEhD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,SAAoB;IACtE,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAyB,EAAE;IAC3D,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,2BAA2B;IAC3B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/terminal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/terminal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { TerminalSession, TerminalSessionOptions, ScreenshotResult } from "./session.js";
|
|
2
|
+
/**
|
|
3
|
+
* Manages the terminal session lifecycle
|
|
4
|
+
* Currently supports a single session for simplicity
|
|
5
|
+
*/
|
|
6
|
+
export declare class TerminalManager {
|
|
7
|
+
private session;
|
|
8
|
+
private options;
|
|
9
|
+
constructor(options?: TerminalSessionOptions);
|
|
10
|
+
/**
|
|
11
|
+
* Get or create the terminal session
|
|
12
|
+
*/
|
|
13
|
+
getSession(): TerminalSession;
|
|
14
|
+
/**
|
|
15
|
+
* Check if a session exists and is active
|
|
16
|
+
*/
|
|
17
|
+
hasActiveSession(): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Write data to the terminal
|
|
20
|
+
*/
|
|
21
|
+
write(data: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Get terminal content
|
|
24
|
+
*/
|
|
25
|
+
getContent(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Get visible content only
|
|
28
|
+
*/
|
|
29
|
+
getVisibleContent(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Take a screenshot
|
|
32
|
+
*/
|
|
33
|
+
takeScreenshot(): ScreenshotResult;
|
|
34
|
+
/**
|
|
35
|
+
* Clear the terminal
|
|
36
|
+
*/
|
|
37
|
+
clear(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Resize the terminal
|
|
40
|
+
*/
|
|
41
|
+
resize(cols: number, rows: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Get terminal dimensions
|
|
44
|
+
*/
|
|
45
|
+
getDimensions(): {
|
|
46
|
+
cols: number;
|
|
47
|
+
rows: number;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Dispose of the current session
|
|
51
|
+
*/
|
|
52
|
+
dispose(): void;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/terminal/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEzF;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,OAAO,CAAyB;gBAE5B,OAAO,GAAE,sBAA2B;IAIhD;;OAEG;IACH,UAAU,IAAI,eAAe;IAO7B;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAI3B;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIzB;;OAEG;IACH,UAAU,IAAI,MAAM;IAIpB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,cAAc,IAAI,gBAAgB;IAIlC;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIxC;;OAEG;IACH,aAAa,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAI/C;;OAEG;IACH,OAAO,IAAI,IAAI;CAMhB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { TerminalSession } from "./session.js";
|
|
2
|
+
/**
|
|
3
|
+
* Manages the terminal session lifecycle
|
|
4
|
+
* Currently supports a single session for simplicity
|
|
5
|
+
*/
|
|
6
|
+
export class TerminalManager {
|
|
7
|
+
session = null;
|
|
8
|
+
options;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.options = options;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get or create the terminal session
|
|
14
|
+
*/
|
|
15
|
+
getSession() {
|
|
16
|
+
if (!this.session || !this.session.isActive()) {
|
|
17
|
+
this.session = new TerminalSession(this.options);
|
|
18
|
+
}
|
|
19
|
+
return this.session;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Check if a session exists and is active
|
|
23
|
+
*/
|
|
24
|
+
hasActiveSession() {
|
|
25
|
+
return this.session !== null && this.session.isActive();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Write data to the terminal
|
|
29
|
+
*/
|
|
30
|
+
write(data) {
|
|
31
|
+
this.getSession().write(data);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get terminal content
|
|
35
|
+
*/
|
|
36
|
+
getContent() {
|
|
37
|
+
return this.getSession().getContent();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get visible content only
|
|
41
|
+
*/
|
|
42
|
+
getVisibleContent() {
|
|
43
|
+
return this.getSession().getVisibleContent();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Take a screenshot
|
|
47
|
+
*/
|
|
48
|
+
takeScreenshot() {
|
|
49
|
+
return this.getSession().takeScreenshot();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clear the terminal
|
|
53
|
+
*/
|
|
54
|
+
clear() {
|
|
55
|
+
this.getSession().clear();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resize the terminal
|
|
59
|
+
*/
|
|
60
|
+
resize(cols, rows) {
|
|
61
|
+
this.getSession().resize(cols, rows);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get terminal dimensions
|
|
65
|
+
*/
|
|
66
|
+
getDimensions() {
|
|
67
|
+
return this.getSession().getDimensions();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Dispose of the current session
|
|
71
|
+
*/
|
|
72
|
+
dispose() {
|
|
73
|
+
if (this.session) {
|
|
74
|
+
this.session.dispose();
|
|
75
|
+
this.session = null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/terminal/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA4C,MAAM,cAAc,CAAC;AAEzF;;;GAGG;AACH,MAAM,OAAO,eAAe;IAClB,OAAO,GAA2B,IAAI,CAAC;IACvC,OAAO,CAAyB;IAExC,YAAY,UAAkC,EAAE;QAC9C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC9C,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC1D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,UAAU,EAAE,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,iBAAiB,EAAE,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,cAAc,EAAE,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAY,EAAE,IAAY;QAC/B,IAAI,CAAC,UAAU,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,aAAa,EAAE,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export interface TerminalSessionOptions {
|
|
2
|
+
cols?: number;
|
|
3
|
+
rows?: number;
|
|
4
|
+
shell?: string;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
export interface ScreenshotResult {
|
|
9
|
+
content: string;
|
|
10
|
+
cursor: {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
};
|
|
14
|
+
dimensions: {
|
|
15
|
+
cols: number;
|
|
16
|
+
rows: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Terminal session that combines node-pty with xterm.js headless
|
|
21
|
+
* for full terminal emulation
|
|
22
|
+
*/
|
|
23
|
+
export declare class TerminalSession {
|
|
24
|
+
private ptyProcess;
|
|
25
|
+
private terminal;
|
|
26
|
+
private disposed;
|
|
27
|
+
private dataListeners;
|
|
28
|
+
private exitListeners;
|
|
29
|
+
private rcFile;
|
|
30
|
+
private zdotdir;
|
|
31
|
+
/**
|
|
32
|
+
* Set up shell-specific prompt customization
|
|
33
|
+
* Returns args to pass to shell and env modifications
|
|
34
|
+
*/
|
|
35
|
+
private setupShellPrompt;
|
|
36
|
+
constructor(options?: TerminalSessionOptions);
|
|
37
|
+
/**
|
|
38
|
+
* Subscribe to PTY output data
|
|
39
|
+
*/
|
|
40
|
+
onData(listener: (data: string) => void): void;
|
|
41
|
+
/**
|
|
42
|
+
* Subscribe to PTY exit
|
|
43
|
+
*/
|
|
44
|
+
onExit(listener: (code: number) => void): void;
|
|
45
|
+
/**
|
|
46
|
+
* Write data to the terminal (simulates typing)
|
|
47
|
+
*/
|
|
48
|
+
write(data: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Get the current terminal buffer content as plain text
|
|
51
|
+
*/
|
|
52
|
+
getContent(): string;
|
|
53
|
+
/**
|
|
54
|
+
* Get only the visible viewport content
|
|
55
|
+
*/
|
|
56
|
+
getVisibleContent(): string;
|
|
57
|
+
/**
|
|
58
|
+
* Take a screenshot of the terminal state
|
|
59
|
+
*/
|
|
60
|
+
takeScreenshot(): ScreenshotResult;
|
|
61
|
+
/**
|
|
62
|
+
* Clear the terminal screen
|
|
63
|
+
*/
|
|
64
|
+
clear(): void;
|
|
65
|
+
/**
|
|
66
|
+
* Resize the terminal
|
|
67
|
+
*/
|
|
68
|
+
resize(cols: number, rows: number): void;
|
|
69
|
+
/**
|
|
70
|
+
* Check if the session is still active
|
|
71
|
+
*/
|
|
72
|
+
isActive(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Get terminal dimensions
|
|
75
|
+
*/
|
|
76
|
+
getDimensions(): {
|
|
77
|
+
cols: number;
|
|
78
|
+
rows: number;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Dispose of the terminal session
|
|
82
|
+
*/
|
|
83
|
+
dispose(): void;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/terminal/session.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QACN,CAAC,EAAE,MAAM,CAAC;QACV,CAAC,EAAE,MAAM,CAAC;KACX,CAAC;IACF,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAW;IAC7B,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,aAAa,CAAqC;IAE1D,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAuB;IAEtC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;gBA+CZ,OAAO,GAAE,sBAA2B;IA6ChD;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI9C;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAI9C;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAOzB;;OAEG;IACH,UAAU,IAAI,MAAM;IAwBpB;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAmB3B;;OAEG;IACH,cAAc,IAAI,gBAAgB;IAoBlC;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAQxC;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,aAAa,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAO/C;;OAEG;IACH,OAAO,IAAI,IAAI;CAuBhB"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import * as pty from "node-pty";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import xtermHeadless from "@xterm/headless";
|
|
6
|
+
const { Terminal } = xtermHeadless;
|
|
7
|
+
// Custom prompt indicator for terminal-mcp
|
|
8
|
+
const PROMPT_INDICATOR = "⚡";
|
|
9
|
+
/**
|
|
10
|
+
* Terminal session that combines node-pty with xterm.js headless
|
|
11
|
+
* for full terminal emulation
|
|
12
|
+
*/
|
|
13
|
+
export class TerminalSession {
|
|
14
|
+
ptyProcess;
|
|
15
|
+
terminal;
|
|
16
|
+
disposed = false;
|
|
17
|
+
dataListeners = [];
|
|
18
|
+
exitListeners = [];
|
|
19
|
+
rcFile = null;
|
|
20
|
+
zdotdir = null;
|
|
21
|
+
/**
|
|
22
|
+
* Set up shell-specific prompt customization
|
|
23
|
+
* Returns args to pass to shell and env modifications
|
|
24
|
+
*/
|
|
25
|
+
setupShellPrompt(shellName, extraEnv) {
|
|
26
|
+
const env = {
|
|
27
|
+
TERMINAL_MCP: "1",
|
|
28
|
+
...extraEnv,
|
|
29
|
+
};
|
|
30
|
+
if (shellName === "bash" || shellName === "sh") {
|
|
31
|
+
// Create temp rcfile that sources user's .bashrc then sets our prompt
|
|
32
|
+
const homeDir = os.homedir();
|
|
33
|
+
const bashrcContent = `
|
|
34
|
+
# Source user's bashrc if it exists
|
|
35
|
+
[ -f "${homeDir}/.bashrc" ] && source "${homeDir}/.bashrc"
|
|
36
|
+
# Set terminal-mcp prompt
|
|
37
|
+
PS1="${PROMPT_INDICATOR} \\$ "
|
|
38
|
+
`;
|
|
39
|
+
this.rcFile = path.join(os.tmpdir(), `terminal-mcp-bashrc-${process.pid}`);
|
|
40
|
+
fs.writeFileSync(this.rcFile, bashrcContent);
|
|
41
|
+
return { args: ["--rcfile", this.rcFile], env };
|
|
42
|
+
}
|
|
43
|
+
if (shellName === "zsh") {
|
|
44
|
+
// Create temp ZDOTDIR with .zshrc that sources user's config then sets prompt
|
|
45
|
+
const homeDir = os.homedir();
|
|
46
|
+
this.zdotdir = path.join(os.tmpdir(), `terminal-mcp-zsh-${process.pid}`);
|
|
47
|
+
fs.mkdirSync(this.zdotdir, { recursive: true });
|
|
48
|
+
const zshrcContent = `
|
|
49
|
+
# Reset ZDOTDIR so nested zsh uses normal config
|
|
50
|
+
export ZDOTDIR="${homeDir}"
|
|
51
|
+
# Source user's zshrc if it exists
|
|
52
|
+
[ -f "${homeDir}/.zshrc" ] && source "${homeDir}/.zshrc"
|
|
53
|
+
# Set terminal-mcp prompt
|
|
54
|
+
PROMPT="${PROMPT_INDICATOR} %# "
|
|
55
|
+
`;
|
|
56
|
+
fs.writeFileSync(path.join(this.zdotdir, ".zshrc"), zshrcContent);
|
|
57
|
+
env.ZDOTDIR = this.zdotdir;
|
|
58
|
+
return { args: [], env };
|
|
59
|
+
}
|
|
60
|
+
// For other shells, just set env vars and hope for the best
|
|
61
|
+
env.PS1 = `${PROMPT_INDICATOR} $ `;
|
|
62
|
+
return { args: [], env };
|
|
63
|
+
}
|
|
64
|
+
constructor(options = {}) {
|
|
65
|
+
const cols = options.cols ?? 120;
|
|
66
|
+
const rows = options.rows ?? 40;
|
|
67
|
+
const shell = options.shell ?? process.env.SHELL ?? "bash";
|
|
68
|
+
// Create headless terminal emulator
|
|
69
|
+
this.terminal = new Terminal({
|
|
70
|
+
cols,
|
|
71
|
+
rows,
|
|
72
|
+
scrollback: 1000,
|
|
73
|
+
allowProposedApi: true,
|
|
74
|
+
});
|
|
75
|
+
// Determine shell type and set up custom prompt
|
|
76
|
+
const shellName = path.basename(shell);
|
|
77
|
+
const { args, env } = this.setupShellPrompt(shellName, options.env);
|
|
78
|
+
// Spawn PTY process
|
|
79
|
+
this.ptyProcess = pty.spawn(shell, args, {
|
|
80
|
+
name: "xterm-256color",
|
|
81
|
+
cols,
|
|
82
|
+
rows,
|
|
83
|
+
cwd: options.cwd ?? process.cwd(),
|
|
84
|
+
env: { ...process.env, ...env },
|
|
85
|
+
});
|
|
86
|
+
// Pipe PTY output to terminal emulator and listeners
|
|
87
|
+
this.ptyProcess.onData((data) => {
|
|
88
|
+
if (!this.disposed) {
|
|
89
|
+
this.terminal.write(data);
|
|
90
|
+
// Notify all data listeners
|
|
91
|
+
for (const listener of this.dataListeners) {
|
|
92
|
+
listener(data);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
this.ptyProcess.onExit(({ exitCode }) => {
|
|
97
|
+
this.disposed = true;
|
|
98
|
+
for (const listener of this.exitListeners) {
|
|
99
|
+
listener(exitCode);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Subscribe to PTY output data
|
|
105
|
+
*/
|
|
106
|
+
onData(listener) {
|
|
107
|
+
this.dataListeners.push(listener);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Subscribe to PTY exit
|
|
111
|
+
*/
|
|
112
|
+
onExit(listener) {
|
|
113
|
+
this.exitListeners.push(listener);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Write data to the terminal (simulates typing)
|
|
117
|
+
*/
|
|
118
|
+
write(data) {
|
|
119
|
+
if (this.disposed) {
|
|
120
|
+
throw new Error("Terminal session has been disposed");
|
|
121
|
+
}
|
|
122
|
+
this.ptyProcess.write(data);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get the current terminal buffer content as plain text
|
|
126
|
+
*/
|
|
127
|
+
getContent() {
|
|
128
|
+
if (this.disposed) {
|
|
129
|
+
throw new Error("Terminal session has been disposed");
|
|
130
|
+
}
|
|
131
|
+
const buffer = this.terminal.buffer.active;
|
|
132
|
+
const lines = [];
|
|
133
|
+
// Get all lines from the buffer (including scrollback)
|
|
134
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
135
|
+
const line = buffer.getLine(i);
|
|
136
|
+
if (line) {
|
|
137
|
+
lines.push(line.translateToString(true));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Trim trailing empty lines
|
|
141
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
|
|
142
|
+
lines.pop();
|
|
143
|
+
}
|
|
144
|
+
return lines.join("\n");
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get only the visible viewport content
|
|
148
|
+
*/
|
|
149
|
+
getVisibleContent() {
|
|
150
|
+
if (this.disposed) {
|
|
151
|
+
throw new Error("Terminal session has been disposed");
|
|
152
|
+
}
|
|
153
|
+
const buffer = this.terminal.buffer.active;
|
|
154
|
+
const lines = [];
|
|
155
|
+
const baseY = buffer.baseY;
|
|
156
|
+
for (let i = 0; i < this.terminal.rows; i++) {
|
|
157
|
+
const line = buffer.getLine(baseY + i);
|
|
158
|
+
if (line) {
|
|
159
|
+
lines.push(line.translateToString(true));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return lines.join("\n");
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Take a screenshot of the terminal state
|
|
166
|
+
*/
|
|
167
|
+
takeScreenshot() {
|
|
168
|
+
if (this.disposed) {
|
|
169
|
+
throw new Error("Terminal session has been disposed");
|
|
170
|
+
}
|
|
171
|
+
const buffer = this.terminal.buffer.active;
|
|
172
|
+
return {
|
|
173
|
+
content: this.getVisibleContent(),
|
|
174
|
+
cursor: {
|
|
175
|
+
x: buffer.cursorX,
|
|
176
|
+
y: buffer.cursorY,
|
|
177
|
+
},
|
|
178
|
+
dimensions: {
|
|
179
|
+
cols: this.terminal.cols,
|
|
180
|
+
rows: this.terminal.rows,
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Clear the terminal screen
|
|
186
|
+
*/
|
|
187
|
+
clear() {
|
|
188
|
+
if (this.disposed) {
|
|
189
|
+
throw new Error("Terminal session has been disposed");
|
|
190
|
+
}
|
|
191
|
+
this.terminal.clear();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Resize the terminal
|
|
195
|
+
*/
|
|
196
|
+
resize(cols, rows) {
|
|
197
|
+
if (this.disposed) {
|
|
198
|
+
throw new Error("Terminal session has been disposed");
|
|
199
|
+
}
|
|
200
|
+
this.terminal.resize(cols, rows);
|
|
201
|
+
this.ptyProcess.resize(cols, rows);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Check if the session is still active
|
|
205
|
+
*/
|
|
206
|
+
isActive() {
|
|
207
|
+
return !this.disposed;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get terminal dimensions
|
|
211
|
+
*/
|
|
212
|
+
getDimensions() {
|
|
213
|
+
return {
|
|
214
|
+
cols: this.terminal.cols,
|
|
215
|
+
rows: this.terminal.rows,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Dispose of the terminal session
|
|
220
|
+
*/
|
|
221
|
+
dispose() {
|
|
222
|
+
if (!this.disposed) {
|
|
223
|
+
this.disposed = true;
|
|
224
|
+
this.ptyProcess.kill();
|
|
225
|
+
this.terminal.dispose();
|
|
226
|
+
// Clean up temp rc files
|
|
227
|
+
if (this.rcFile) {
|
|
228
|
+
try {
|
|
229
|
+
fs.unlinkSync(this.rcFile);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// Ignore cleanup errors
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (this.zdotdir) {
|
|
236
|
+
try {
|
|
237
|
+
fs.rmSync(this.zdotdir, { recursive: true });
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Ignore cleanup errors
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=session.js.map
|