agent-desk-mcp 0.1.5 → 1.0.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # agent-desk-mcp
2
2
 
3
- npx wrapper for Agent Desk MCP Server - enables multi-agent blocking question capability with message queue management.
3
+ MCP server for multi-agent interaction with users - enables blocking question capability with message queue management.
4
4
 
5
5
  ## Installation
6
6
 
@@ -9,6 +9,11 @@ npx wrapper for Agent Desk MCP Server - enables multi-agent blocking question ca
9
9
  npx agent-desk-mcp --api-url http://localhost:8080
10
10
  ```
11
11
 
12
+ ## Requirements
13
+
14
+ - Node.js >= 18.0.0
15
+ - API Server running (see [agent-desk](https://github.com/weidwonder/agent-desk))
16
+
12
17
  ## Usage
13
18
 
14
19
  ### Basic Usage
@@ -18,31 +23,21 @@ npx agent-desk-mcp --api-url http://localhost:8080
18
23
  npx agent-desk-mcp --api-url http://localhost:8080
19
24
  ```
20
25
 
21
- ### With Custom Database
22
-
23
- ```bash
24
- # Use custom database path
25
- npx agent-desk-mcp --api-url http://localhost:8080 --db-path /path/to/data.db
26
- ```
27
-
28
- ### Environment Variables
26
+ ### With Claude Desktop
29
27
 
30
- - `AGENT_DESK_SOURCE`: Path to agent-desk source directory (if not using installed package)
28
+ Add to your Claude Desktop configuration:
31
29
 
32
- ## Requirements
33
-
34
- - Node.js >= 18.0.0
35
- - Python >= 3.10
36
- - agent-desk package installed (or source available)
37
-
38
- ## For Development
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "agent-desk": {
34
+ "command": "npx",
35
+ "args": ["agent-desk-mcp", "--api-url", "http://localhost:8080"]
36
+ }
37
+ }
38
+ }
39
+ ```
39
40
 
40
- ```bash
41
- # Clone and link
42
- git clone https://github.com/weidwonder/agent-desk.git
43
- cd agent-desk/mcp-wrapper
44
- npm link
41
+ ## License
45
42
 
46
- # Now you can run directly
47
- agent-desk-mcp --api-url http://localhost:8080
48
- ```
43
+ MIT
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * agent-desk-mcp
4
+ *
5
+ * MCP Server for multi-agent interaction with users
6
+ * Usage: npx agent-desk-mcp --api-url http://localhost:8080
7
+ */
8
+
9
+ const { spawn } = require('child_process');
10
+ const path = require('path');
11
+ const fs = require('fs');
12
+
13
+ function main() {
14
+ const args = process.argv.slice(2);
15
+
16
+ // Find the dist/index.js
17
+ const scriptDir = path.dirname(__filename);
18
+ const distPath = path.join(scriptDir, '..', 'dist', 'index.js');
19
+
20
+ if (!fs.existsSync(distPath)) {
21
+ console.error("Error: agent-desk-mcp not built. Run 'npm install && npm run build' first.");
22
+ process.exit(1);
23
+ }
24
+
25
+ // Spawn the server
26
+ const proc = spawn(process.execPath, [distPath, ...args], {
27
+ stdio: 'inherit',
28
+ env: { ...process.env },
29
+ });
30
+
31
+ proc.on('error', (err) => {
32
+ console.error('Failed to start MCP server:', err.message);
33
+ process.exit(1);
34
+ });
35
+
36
+ proc.on('exit', (code) => {
37
+ process.exit(code || 0);
38
+ });
39
+
40
+ process.on('SIGINT', () => proc.kill('SIGINT'));
41
+ process.on('SIGTERM', () => proc.kill('SIGTERM'));
42
+ }
43
+
44
+ main();
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,209 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import axios from "axios";
5
+ class APIClient {
6
+ client;
7
+ constructor(baseUrl) {
8
+ this.client = axios.create({
9
+ baseURL: baseUrl.replace(/\/$/, ""),
10
+ });
11
+ }
12
+ async healthCheck() {
13
+ try {
14
+ const resp = await this.client.get("/api/health");
15
+ return resp.status === 200;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ async addAgent(sessionId, agentSummary, context, questions, timeoutSeconds) {
22
+ await this.client.post("/api/agents", {
23
+ session_id: sessionId,
24
+ agent_summary: agentSummary,
25
+ context: context.slice(0, 1000),
26
+ questions,
27
+ timeout_seconds: timeoutSeconds,
28
+ });
29
+ }
30
+ async getAgent(sessionId) {
31
+ try {
32
+ const resp = await this.client.get(`/api/agents/${sessionId}`);
33
+ return resp.data;
34
+ }
35
+ catch (e) {
36
+ if (axios.isAxiosError(e) && e.response?.status === 404) {
37
+ return null;
38
+ }
39
+ throw e;
40
+ }
41
+ }
42
+ }
43
+ class AgentDeskServer {
44
+ server;
45
+ apiClient = null;
46
+ apiUrl;
47
+ constructor(apiUrl) {
48
+ this.apiUrl = apiUrl;
49
+ this.server = new Server({
50
+ name: "agent-desk",
51
+ version: "1.0.0",
52
+ });
53
+ this.setupHandlers();
54
+ }
55
+ setupHandlers() {
56
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
57
+ return {
58
+ tools: [
59
+ {
60
+ name: "ask_user",
61
+ description: `Ask user questions, block and wait for answer.
62
+
63
+ Arguments:
64
+ - agent_summary: Brief summary of your role/identity.
65
+ - context: Brief context (max 1000 chars) explaining why you are asking these questions.
66
+ - questions: List of questions with id, content, and optional options.
67
+ - timeout_seconds: Timeout in seconds. None means no timeout.
68
+
69
+ Returns: User's answers concatenated with newlines, or timeout message.`,
70
+ inputSchema: {
71
+ type: "object",
72
+ properties: {
73
+ agent_summary: {
74
+ type: "string",
75
+ description: "Brief summary of your role/identity",
76
+ },
77
+ context: {
78
+ type: "string",
79
+ description: "Brief context explaining why you are asking these questions",
80
+ },
81
+ questions: {
82
+ type: "array",
83
+ description: "List of questions",
84
+ items: {
85
+ type: "object",
86
+ properties: {
87
+ id: {
88
+ type: "string",
89
+ description: "Unique question identifier",
90
+ },
91
+ content: {
92
+ type: "string",
93
+ description: "Question text",
94
+ },
95
+ options: {
96
+ type: "array",
97
+ description: "Optional list of choices",
98
+ items: {
99
+ type: "object",
100
+ properties: {
101
+ value: { type: "string" },
102
+ label: { type: "string" },
103
+ },
104
+ },
105
+ },
106
+ },
107
+ required: ["id", "content"],
108
+ },
109
+ },
110
+ timeout_seconds: {
111
+ type: "number",
112
+ description: "Timeout in seconds",
113
+ },
114
+ },
115
+ required: ["agent_summary", "context", "questions"],
116
+ },
117
+ },
118
+ ],
119
+ };
120
+ });
121
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
122
+ const { name, arguments: args } = request.params;
123
+ if (name !== "ask_user") {
124
+ return {
125
+ content: [
126
+ {
127
+ type: "text",
128
+ text: `Unknown tool: ${name}`,
129
+ },
130
+ ],
131
+ };
132
+ }
133
+ return this.handleAskUser(args ?? {});
134
+ });
135
+ }
136
+ async handleAskUser(args) {
137
+ const { agent_summary, context, questions, timeout_seconds, } = args;
138
+ const sessionId = crypto.randomUUID();
139
+ // Ensure questions have IDs
140
+ const processedQuestions = questions.map((q, i) => ({
141
+ ...q,
142
+ id: q.id || `Q${i + 1}`,
143
+ }));
144
+ await this.apiClient.addAgent(sessionId, agent_summary, context, processedQuestions, timeout_seconds);
145
+ // Poll for answer
146
+ const pollInterval = 1000; // 1 second
147
+ const startTime = Date.now();
148
+ while (true) {
149
+ // Check timeout
150
+ if (timeout_seconds && (Date.now() - startTime) >= timeout_seconds * 1000) {
151
+ return {
152
+ content: [
153
+ {
154
+ type: "text",
155
+ text: "User did not respond within the timeout period.",
156
+ },
157
+ ],
158
+ };
159
+ }
160
+ // Check for answer
161
+ const agent = await this.apiClient.getAgent(sessionId);
162
+ if (agent && agent.status === "answered") {
163
+ const answers = agent.questions
164
+ .filter((q) => q.answer)
165
+ .map((q) => `${q.id}: ${q.answer}`);
166
+ return {
167
+ content: [
168
+ {
169
+ type: "text",
170
+ text: answers.join("\n"),
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
176
+ }
177
+ }
178
+ async run() {
179
+ this.apiClient = new APIClient(this.apiUrl);
180
+ // Check API health
181
+ const healthy = await this.apiClient.healthCheck();
182
+ if (!healthy) {
183
+ console.error(`Error: API Server at ${this.apiUrl} is not available.`);
184
+ console.error("Please ensure the API Server is running.");
185
+ process.exit(1);
186
+ }
187
+ const transport = new StdioServerTransport();
188
+ await this.server.connect(transport);
189
+ console.error("Agent Desk MCP Server started");
190
+ }
191
+ }
192
+ // CLI entry point
193
+ async function main() {
194
+ const args = process.argv.slice(2);
195
+ let apiUrl = "http://localhost:8080";
196
+ // Parse arguments
197
+ for (let i = 0; i < args.length; i++) {
198
+ if (args[i] === "--api-url" && i + 1 < args.length) {
199
+ apiUrl = args[i + 1];
200
+ i++;
201
+ }
202
+ }
203
+ const server = new AgentDeskServer(apiUrl);
204
+ await server.run();
205
+ }
206
+ main().catch((err) => {
207
+ console.error("Fatal error:", err);
208
+ process.exit(1);
209
+ });
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "agent-desk-mcp",
3
- "version": "0.1.5",
4
- "description": "MCP server for multi-agent interaction with users - npx wrapper",
5
- "main": "bin/agent-desk-mcp.js",
3
+ "version": "1.0.1",
4
+ "description": "MCP server for multi-agent interaction with users",
5
+ "main": "dist/index.js",
6
+ "type": "module",
6
7
  "bin": {
7
- "agent-desk-mcp": "bin/agent-desk-mcp.js"
8
+ "agent-desk-mcp": "bin/agent-desk-mcp.cjs"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepublishOnly": "npm run build"
8
13
  },
9
14
  "keywords": [
10
15
  "mcp",
@@ -14,9 +19,13 @@
14
19
  ],
15
20
  "author": "weidwonder",
16
21
  "license": "MIT",
17
- "repository": {
18
- "type": "git",
19
- "url": "https://github.com/weidwonder/agent-desk"
22
+ "dependencies": {
23
+ "@modelcontextprotocol/sdk": "^1.0.0",
24
+ "axios": "^1.7.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^20.0.0",
28
+ "typescript": "^5.0.0"
20
29
  },
21
30
  "engines": {
22
31
  "node": ">=18.0.0"
package/src/index.ts ADDED
@@ -0,0 +1,276 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import {
4
+ CallToolRequestSchema,
5
+ ListToolsRequestSchema,
6
+ } from "@modelcontextprotocol/sdk/types.js";
7
+ import axios, { AxiosInstance } from "axios";
8
+
9
+ interface Question {
10
+ id: string;
11
+ content: string;
12
+ options?: Array<{ value: string; label: string }>;
13
+ answer?: string;
14
+ }
15
+
16
+ interface AgentData {
17
+ session_id: string;
18
+ agent_summary: string;
19
+ context: string;
20
+ questions: Question[];
21
+ status: "pending" | "answered" | "ignored";
22
+ }
23
+
24
+ class APIClient {
25
+ private client: AxiosInstance;
26
+
27
+ constructor(baseUrl: string) {
28
+ this.client = axios.create({
29
+ baseURL: baseUrl.replace(/\/$/, ""),
30
+ });
31
+ }
32
+
33
+ async healthCheck(): Promise<boolean> {
34
+ try {
35
+ const resp = await this.client.get("/api/health");
36
+ return resp.status === 200;
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ async addAgent(
43
+ sessionId: string,
44
+ agentSummary: string,
45
+ context: string,
46
+ questions: Question[],
47
+ timeoutSeconds?: number
48
+ ): Promise<void> {
49
+ await this.client.post("/api/agents", {
50
+ session_id: sessionId,
51
+ agent_summary: agentSummary,
52
+ context: context.slice(0, 1000),
53
+ questions,
54
+ timeout_seconds: timeoutSeconds,
55
+ });
56
+ }
57
+
58
+ async getAgent(sessionId: string): Promise<AgentData | null> {
59
+ try {
60
+ const resp = await this.client.get(`/api/agents/${sessionId}`);
61
+ return resp.data;
62
+ } catch (e) {
63
+ if (axios.isAxiosError(e) && e.response?.status === 404) {
64
+ return null;
65
+ }
66
+ throw e;
67
+ }
68
+ }
69
+ }
70
+
71
+ class AgentDeskServer {
72
+ private server: Server;
73
+ private apiClient: APIClient | null = null;
74
+ private apiUrl: string;
75
+
76
+ constructor(apiUrl: string) {
77
+ this.apiUrl = apiUrl;
78
+ this.server = new Server({
79
+ name: "agent-desk",
80
+ version: "1.0.0",
81
+ });
82
+ this.setupHandlers();
83
+ }
84
+
85
+ private setupHandlers(): void {
86
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => {
87
+ return {
88
+ tools: [
89
+ {
90
+ name: "ask_user",
91
+ description: `Ask user questions, block and wait for answer.
92
+
93
+ Arguments:
94
+ - agent_summary: Brief summary of your role/identity.
95
+ - context: Brief context (max 1000 chars) explaining why you are asking these questions.
96
+ - questions: List of questions with id, content, and optional options.
97
+ - timeout_seconds: Timeout in seconds. None means no timeout.
98
+
99
+ Returns: User's answers concatenated with newlines, or timeout message.`,
100
+ inputSchema: {
101
+ type: "object",
102
+ properties: {
103
+ agent_summary: {
104
+ type: "string",
105
+ description: "Brief summary of your role/identity",
106
+ },
107
+ context: {
108
+ type: "string",
109
+ description: "Brief context explaining why you are asking these questions",
110
+ },
111
+ questions: {
112
+ type: "array",
113
+ description: "List of questions",
114
+ items: {
115
+ type: "object",
116
+ properties: {
117
+ id: {
118
+ type: "string",
119
+ description: "Unique question identifier",
120
+ },
121
+ content: {
122
+ type: "string",
123
+ description: "Question text",
124
+ },
125
+ options: {
126
+ type: "array",
127
+ description: "Optional list of choices",
128
+ items: {
129
+ type: "object",
130
+ properties: {
131
+ value: { type: "string" },
132
+ label: { type: "string" },
133
+ },
134
+ },
135
+ },
136
+ },
137
+ required: ["id", "content"],
138
+ },
139
+ },
140
+ timeout_seconds: {
141
+ type: "number",
142
+ description: "Timeout in seconds",
143
+ },
144
+ },
145
+ required: ["agent_summary", "context", "questions"],
146
+ },
147
+ },
148
+ ],
149
+ };
150
+ });
151
+
152
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
153
+ const { name, arguments: args } = request.params;
154
+
155
+ if (name !== "ask_user") {
156
+ return {
157
+ content: [
158
+ {
159
+ type: "text",
160
+ text: `Unknown tool: ${name}`,
161
+ },
162
+ ],
163
+ };
164
+ }
165
+
166
+ return this.handleAskUser(args ?? {});
167
+ });
168
+ }
169
+
170
+ private async handleAskUser(args: Record<string, unknown>): Promise<{
171
+ content: Array<{ type: string; text: string }>;
172
+ }> {
173
+ const {
174
+ agent_summary,
175
+ context,
176
+ questions,
177
+ timeout_seconds,
178
+ } = args as {
179
+ agent_summary: string;
180
+ context: string;
181
+ questions: Question[];
182
+ timeout_seconds?: number;
183
+ };
184
+
185
+ const sessionId = crypto.randomUUID();
186
+
187
+ // Ensure questions have IDs
188
+ const processedQuestions = questions.map((q, i) => ({
189
+ ...q,
190
+ id: q.id || `Q${i + 1}`,
191
+ }));
192
+
193
+ await this.apiClient!.addAgent(
194
+ sessionId,
195
+ agent_summary,
196
+ context,
197
+ processedQuestions,
198
+ timeout_seconds
199
+ );
200
+
201
+ // Poll for answer
202
+ const pollInterval = 1000; // 1 second
203
+ const startTime = Date.now();
204
+
205
+ while (true) {
206
+ // Check timeout
207
+ if (timeout_seconds && (Date.now() - startTime) >= timeout_seconds * 1000) {
208
+ return {
209
+ content: [
210
+ {
211
+ type: "text",
212
+ text: "User did not respond within the timeout period.",
213
+ },
214
+ ],
215
+ };
216
+ }
217
+
218
+ // Check for answer
219
+ const agent = await this.apiClient!.getAgent(sessionId);
220
+ if (agent && agent.status === "answered") {
221
+ const answers = agent.questions
222
+ .filter((q) => q.answer)
223
+ .map((q) => `${q.id}: ${q.answer}`);
224
+ return {
225
+ content: [
226
+ {
227
+ type: "text",
228
+ text: answers.join("\n"),
229
+ },
230
+ ],
231
+ };
232
+ }
233
+
234
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
235
+ }
236
+ }
237
+
238
+ async run(): Promise<void> {
239
+ this.apiClient = new APIClient(this.apiUrl);
240
+
241
+ // Check API health
242
+ const healthy = await this.apiClient.healthCheck();
243
+ if (!healthy) {
244
+ console.error(`Error: API Server at ${this.apiUrl} is not available.`);
245
+ console.error("Please ensure the API Server is running.");
246
+ process.exit(1);
247
+ }
248
+
249
+ const transport = new StdioServerTransport();
250
+ await this.server.connect(transport);
251
+
252
+ console.error("Agent Desk MCP Server started");
253
+ }
254
+ }
255
+
256
+ // CLI entry point
257
+ async function main(): Promise<void> {
258
+ const args = process.argv.slice(2);
259
+ let apiUrl = "http://localhost:8080";
260
+
261
+ // Parse arguments
262
+ for (let i = 0; i < args.length; i++) {
263
+ if (args[i] === "--api-url" && i + 1 < args.length) {
264
+ apiUrl = args[i + 1];
265
+ i++;
266
+ }
267
+ }
268
+
269
+ const server = new AgentDeskServer(apiUrl);
270
+ await server.run();
271
+ }
272
+
273
+ main().catch((err) => {
274
+ console.error("Fatal error:", err);
275
+ process.exit(1);
276
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "node",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "outDir": "./dist",
9
+ "rootDir": "./src",
10
+ "declaration": true,
11
+ "skipLibCheck": true
12
+ },
13
+ "include": ["src/**/*"]
14
+ }
@@ -1,114 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * agent-desk-mcp
4
- *
5
- * npx wrapper for Agent Desk MCP Server
6
- * Usage: npx agent-desk-mcp --api-url http://localhost:8080
7
- */
8
-
9
- const { spawn } = require('child_process');
10
- const path = require('path');
11
- const fs = require('fs');
12
-
13
- // Find Python interpreter
14
- function findPython() {
15
- // Check for python3 first, then python
16
- const candidates = ['python3', 'python'];
17
-
18
- for (const candidate of candidates) {
19
- try {
20
- const result = require('child_process').execSync(`which ${candidate}`, { encoding: 'utf8' }).trim();
21
- if (result) return candidate;
22
- } catch (e) {
23
- // Continue to next candidate
24
- }
25
- }
26
-
27
- // Try common paths
28
- const commonPaths = [
29
- '/usr/bin/python3',
30
- '/usr/local/bin/python3',
31
- '/opt/homebrew/bin/python3',
32
- ];
33
-
34
- for (const p of commonPaths) {
35
- if (fs.existsSync(p)) return p;
36
- }
37
-
38
- return 'python3';
39
- }
40
-
41
- // Find agent-desk source directory
42
- function findAgentDeskSource() {
43
- // First check AGENT_DESK_SOURCE env variable
44
- if (process.env.AGENT_DESK_SOURCE) {
45
- return process.env.AGENT_DESK_SOURCE;
46
- }
47
-
48
- // Look for src/cli.py relative to this script (for local dev)
49
- const scriptDir = path.dirname(__filename);
50
- const wrapperDir = path.dirname(scriptDir);
51
- const projectDir = path.dirname(wrapperDir);
52
- const cliPath = path.join(projectDir, 'src', 'cli.py');
53
-
54
- if (fs.existsSync(cliPath)) {
55
- return projectDir;
56
- }
57
-
58
- // Check current working directory
59
- const cwdCliPath = path.join(process.cwd(), 'src', 'cli.py');
60
- if (fs.existsSync(cwdCliPath)) {
61
- return process.cwd();
62
- }
63
-
64
- // Return empty string - will use pip installed package instead
65
- return '';
66
- }
67
-
68
- function main() {
69
- const args = process.argv.slice(2);
70
- const python = findPython();
71
- const sourceDir = findAgentDeskSource();
72
-
73
- // Build command arguments
74
- let commandArgs;
75
- if (sourceDir && fs.existsSync(path.join(sourceDir, 'src', 'cli.py'))) {
76
- // Use source directory if found
77
- commandArgs = ['-m', 'src.cli', 'mcp', ...args];
78
- console.error(`Agent Desk MCP Server (using source)`);
79
- console.error(`Python: ${python}`);
80
- console.error(`Source: ${sourceDir}`);
81
- } else {
82
- // Use pip installed package (agent-desk)
83
- commandArgs = ['-m', 'agent_desk.cli', 'mcp', ...args];
84
- console.error(`Agent Desk MCP Server (using pip package)`);
85
- console.error(`Python: ${python}`);
86
- }
87
- console.error(`Command: ${python} ${commandArgs.join(' ')}`);
88
-
89
- // Spawn MCP server
90
- const spawnOptions = {
91
- stdio: 'inherit',
92
- env: { ...process.env },
93
- };
94
- if (sourceDir) {
95
- spawnOptions.cwd = sourceDir;
96
- spawnOptions.env.PYTHONPATH = sourceDir;
97
- }
98
- const proc = spawn(python, commandArgs, spawnOptions);
99
-
100
- proc.on('error', (err) => {
101
- console.error('Failed to start MCP server:', err.message);
102
- process.exit(1);
103
- });
104
-
105
- proc.on('exit', (code) => {
106
- process.exit(code || 0);
107
- });
108
-
109
- // Handle signals
110
- process.on('SIGINT', () => proc.kill('SIGINT'));
111
- process.on('SIGTERM', () => proc.kill('SIGTERM'));
112
- }
113
-
114
- main();