@kkweon/agent-orchestrator-mcp 1.0.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/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # Agent Orchestrator MCP Server
2
+
3
+ This is an MCP (Model Context Protocol) server that enables a "Master" agent (e.g., Gemini CLI) to orchestrate multiple sub-agents within `tmux` panes.
4
+
5
+ ## Features
6
+
7
+ - **Tmux Integration**: Automatically splits the current tmux window to create panes for sub-agents.
8
+ - **Agent Management**: Create, list, and delete sub-agents.
9
+ - **Task Orchestration**: Enqueue tasks for specific agents.
10
+ - **Inter-Agent Communication**: Agents can emit events and poll for commands.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install -g @kkweon/agent-orchestrator-mcp
16
+ ```
17
+
18
+ ## Configuration
19
+
20
+ Add this server to your MCP client configuration (e.g., `gemini-cli`'s `settings.json` or `mcpServers` config).
21
+
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "agent-orchestrator": {
26
+ "command": "agent-orchestrator-mcp",
27
+ "args": [],
28
+ "env": {}
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ ## Tools
35
+
36
+ ### `agent_create`
37
+ Create a new agent in a new tmux pane.
38
+ - `name` (string): Name of the agent.
39
+ - `role` (string): Role/instruction for the agent.
40
+ - `cwd` (string, optional): Working directory.
41
+
42
+ ### `agent_list`
43
+ List all active agents managed by this server.
44
+
45
+ ### `agent_delete`
46
+ Delete an agent and close its tmux pane.
47
+ - `agent_id` (string): The ID of the agent to delete.
48
+
49
+ ### `task_enqueue`
50
+ Enqueue a task for an agent.
51
+ - `agent_id` (string): Target agent ID.
52
+ - `task` (object): Task payload.
53
+
54
+ ### `wait_for_command` (Internal)
55
+ Used by sub-agents to poll for new commands/tasks.
56
+
57
+ ### `emit_event` (Internal)
58
+ Used by sub-agents to report progress or results.
59
+
60
+ ## Development
61
+
62
+ 1. Clone the repository.
63
+ 2. Install dependencies: `npm install`
64
+ 3. Build: `npm run build`
65
+ 4. Run locally: `npm start`
@@ -0,0 +1,183 @@
1
+ import * as tmux from "./tmux.js";
2
+ import { randomUUID } from "crypto";
3
+ import fs from "fs/promises";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+ // Get directory of current module
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ // Helper to get workspace root
10
+ const AGENTS_DIR = ".agents";
11
+ export class AgentManager {
12
+ workspaceRoot;
13
+ sessionId; // Expose sessionId for tests
14
+ constructor(workspaceRoot = process.cwd()) {
15
+ this.workspaceRoot = workspaceRoot;
16
+ // If we are a sub-agent, we might be passed a session ID?
17
+ // But usually the orchestrator *starts* a new session or manages one.
18
+ // Let's stick to generating one for the orchestrator instance.
19
+ // If the user wants to resume, they'd need to pass it, but for now we generate new.
20
+ this.sessionId = randomUUID();
21
+ }
22
+ getSessionDir() {
23
+ return path.join(this.workspaceRoot, AGENTS_DIR, "sessions", this.sessionId);
24
+ }
25
+ getAgentDir(agentId) {
26
+ return path.join(this.getSessionDir(), "agents", agentId);
27
+ }
28
+ async ensureSessionDir() {
29
+ await fs.mkdir(path.join(this.getSessionDir(), "agents"), { recursive: true });
30
+ }
31
+ async createAgent(params) {
32
+ await this.ensureSessionDir();
33
+ const id = randomUUID();
34
+ const agentDir = this.getAgentDir(id);
35
+ await fs.mkdir(agentDir, { recursive: true });
36
+ await fs.mkdir(path.join(agentDir, "artifacts"), { recursive: true });
37
+ // Initialize files
38
+ await fs.writeFile(path.join(agentDir, "inbox.jsonl"), "");
39
+ await fs.writeFile(path.join(agentDir, "outbox.jsonl"), "");
40
+ let context = await tmux.getCurrentTmuxContext();
41
+ if (!context) {
42
+ try {
43
+ context = await tmux.createTmuxSession("openclaw-agents");
44
+ }
45
+ catch (e) {
46
+ console.error("Warning: Could not determine tmux context", e);
47
+ throw e;
48
+ }
49
+ }
50
+ const pane = await tmux.splitPane(context.paneId, "horizontal", params.cwd);
51
+ const agent = {
52
+ id,
53
+ name: params.name,
54
+ role: params.role,
55
+ tmuxPaneId: `${pane.sessionId}:${pane.windowId}:${pane.paneId}`,
56
+ status: "created",
57
+ queue: [],
58
+ lastEventSeq: 0,
59
+ createdAt: Date.now(),
60
+ metadata: {},
61
+ };
62
+ await fs.writeFile(path.join(agentDir, "meta.json"), JSON.stringify(agent, null, 2));
63
+ // 1. Prepare Environment
64
+ await tmux.sendKeys(pane.paneId, `export AGENT_ID=${id}`);
65
+ await tmux.sendKeys(pane.paneId, `export AGENT_SESSION_ID=${this.sessionId}`);
66
+ // 2. Launch Gemini CLI
67
+ // Model preference: params > env > default
68
+ const model = params.model || process.env.GEMINI_MODEL || "auto";
69
+ const cmd = `gemini -m ${model}`;
70
+ // We assume 'gemini' is in the PATH.
71
+ await tmux.sendKeys(pane.paneId, cmd);
72
+ // 3. Inject Inception Prompt (Brain Bootstrapping)
73
+ // We send this as input to the running Gemini CLI.
74
+ const inceptionPrompt = `
75
+ You are a specialized sub-agent with ID "${id}" and Role "${params.role}".
76
+ Your goal is to autonomously process tasks from the orchestrator.
77
+
78
+ PROTOCOL:
79
+ 1. Loop indefinitely.
80
+ 2. Inside the loop, call the tool 'wait_for_command' with agent_id="${id}" and timeout_ms=30000.
81
+ 3. If 'wait_for_command' returns a task, execute it using your capabilities.
82
+ 4. After execution, call the tool 'emit_event' with agent_id="${id}" and type="task_completed" (include the result).
83
+ 5. If it times out or fails, just retry the loop.
84
+
85
+ Start your loop now.
86
+ `.trim();
87
+ // Send the prompt.
88
+ // Warning: Large prompts might be flaky with send-keys if buffer overflows,
89
+ // but for this length it should be fine.
90
+ await tmux.sendKeys(pane.paneId, inceptionPrompt);
91
+ return agent;
92
+ }
93
+ async listAgents() {
94
+ await this.ensureSessionDir();
95
+ const agentsDir = path.join(this.getSessionDir(), "agents");
96
+ try {
97
+ const dirs = await fs.readdir(agentsDir);
98
+ const agents = [];
99
+ for (const dir of dirs) {
100
+ try {
101
+ const meta = JSON.parse(await fs.readFile(path.join(agentsDir, dir, "meta.json"), "utf-8"));
102
+ agents.push(meta);
103
+ }
104
+ catch (e) {
105
+ // ignore invalid dirs
106
+ }
107
+ }
108
+ return agents;
109
+ }
110
+ catch (e) {
111
+ return [];
112
+ }
113
+ }
114
+ async deleteAgent(id) {
115
+ const agentDir = this.getAgentDir(id);
116
+ try {
117
+ const meta = JSON.parse(await fs.readFile(path.join(agentDir, "meta.json"), "utf-8"));
118
+ const parts = meta.tmuxPaneId.split(":");
119
+ const paneId = parts[2] || parts[0];
120
+ await tmux.killPane(paneId);
121
+ }
122
+ catch (e) {
123
+ // ignore
124
+ }
125
+ }
126
+ async enqueueTask(agentId, taskPayload) {
127
+ const agentDir = this.getAgentDir(agentId);
128
+ const taskId = randomUUID();
129
+ const taskEvent = {
130
+ type: "task",
131
+ taskId,
132
+ payload: taskPayload,
133
+ timestamp: Date.now()
134
+ };
135
+ try {
136
+ await fs.access(agentDir);
137
+ }
138
+ catch {
139
+ throw new Error(`Agent ${agentId} not found in session ${this.sessionId}`);
140
+ }
141
+ await fs.appendFile(path.join(agentDir, "inbox.jsonl"), JSON.stringify(taskEvent) + "\n");
142
+ return taskId;
143
+ }
144
+ async waitForCommand(agentId, cursor = 0, timeoutMs = 10000) {
145
+ const agentDir = this.getAgentDir(agentId);
146
+ const inboxPath = path.join(agentDir, "inbox.jsonl");
147
+ const startTime = Date.now();
148
+ while (Date.now() - startTime < timeoutMs) {
149
+ try {
150
+ const content = await fs.readFile(inboxPath, "utf-8");
151
+ const lines = content.split("\n").filter(line => line.trim() !== "");
152
+ if (lines.length > cursor) {
153
+ const line = lines[cursor];
154
+ const command = JSON.parse(line);
155
+ return {
156
+ status: "command",
157
+ command,
158
+ next_cursor: cursor + 1
159
+ };
160
+ }
161
+ }
162
+ catch (e) {
163
+ // file might not exist yet
164
+ }
165
+ await new Promise(r => setTimeout(r, 500));
166
+ }
167
+ return { status: "timeout", next_cursor: cursor };
168
+ }
169
+ async emitEvent(agentId, event) {
170
+ const agentDir = this.getAgentDir(agentId);
171
+ const outboxPath = path.join(agentDir, "outbox.jsonl");
172
+ const broadcastPath = path.join(this.getSessionDir(), "broadcast.jsonl");
173
+ const entry = {
174
+ ...event,
175
+ agentId,
176
+ timestamp: Date.now()
177
+ };
178
+ const line = JSON.stringify(entry) + "\n";
179
+ await fs.appendFile(outboxPath, line);
180
+ await fs.appendFile(broadcastPath, line);
181
+ }
182
+ }
183
+ //# sourceMappingURL=agent-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-manager.js","sourceRoot":"","sources":["../src/agent-manager.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { AgentManager } from "./agent-manager.js";
6
+ const server = new Server({
7
+ name: "agent-orchestrator-mcp",
8
+ version: "1.0.0",
9
+ }, {
10
+ capabilities: {
11
+ tools: {},
12
+ resources: {},
13
+ },
14
+ });
15
+ const agentManager = new AgentManager();
16
+ const TOOLS = [
17
+ {
18
+ name: "agent_create",
19
+ description: "Create a new agent in a new tmux pane",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ name: { type: "string" },
24
+ role: { type: "string" },
25
+ cwd: { type: "string" },
26
+ },
27
+ required: ["name", "role"],
28
+ },
29
+ },
30
+ {
31
+ name: "agent_list",
32
+ description: "List all active agents",
33
+ inputSchema: {
34
+ type: "object",
35
+ properties: {},
36
+ },
37
+ },
38
+ {
39
+ name: "agent_delete",
40
+ description: "Delete an agent and its tmux pane",
41
+ inputSchema: {
42
+ type: "object",
43
+ properties: {
44
+ agent_id: { type: "string" },
45
+ },
46
+ required: ["agent_id"],
47
+ },
48
+ },
49
+ {
50
+ name: "task_enqueue",
51
+ description: "Enqueue a task for an agent",
52
+ inputSchema: {
53
+ type: "object",
54
+ properties: {
55
+ agent_id: { type: "string" },
56
+ task: { type: "object" },
57
+ },
58
+ required: ["agent_id", "task"],
59
+ },
60
+ },
61
+ {
62
+ name: "wait_for_command",
63
+ description: "Internal: Agent polls for new commands",
64
+ inputSchema: {
65
+ type: "object",
66
+ properties: {
67
+ agent_id: { type: "string" },
68
+ timeout_ms: { type: "number" },
69
+ cursor: { type: "number" },
70
+ },
71
+ required: ["agent_id", "timeout_ms"],
72
+ },
73
+ },
74
+ {
75
+ name: "emit_event",
76
+ description: "Internal: Agent emits an event (result/log)",
77
+ inputSchema: {
78
+ type: "object",
79
+ properties: {
80
+ agent_id: { type: "string" },
81
+ event: { type: "object" },
82
+ },
83
+ required: ["agent_id", "event"],
84
+ },
85
+ }
86
+ ];
87
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
88
+ tools: TOOLS,
89
+ }));
90
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
91
+ const { name, arguments: args } = request.params;
92
+ try {
93
+ if (name === "agent_create") {
94
+ const params = args;
95
+ const agent = await agentManager.createAgent(params);
96
+ return {
97
+ content: [{ type: "text", text: JSON.stringify(agent, null, 2) }],
98
+ };
99
+ }
100
+ if (name === "agent_list") {
101
+ const agents = await agentManager.listAgents();
102
+ return {
103
+ content: [{ type: "text", text: JSON.stringify(agents, null, 2) }],
104
+ };
105
+ }
106
+ if (name === "agent_delete") {
107
+ const { agent_id } = args;
108
+ await agentManager.deleteAgent(agent_id);
109
+ return {
110
+ content: [{ type: "text", text: `Agent ${agent_id} deleted` }],
111
+ };
112
+ }
113
+ if (name === "task_enqueue") {
114
+ const { agent_id, task } = args;
115
+ const taskId = await agentManager.enqueueTask(agent_id, task);
116
+ return {
117
+ content: [{ type: "text", text: JSON.stringify({ task_id: taskId }) }],
118
+ };
119
+ }
120
+ if (name === "wait_for_command") {
121
+ const { agent_id, timeout_ms, cursor } = args;
122
+ const result = await agentManager.waitForCommand(agent_id, cursor || 0, timeout_ms);
123
+ return {
124
+ content: [{ type: "text", text: JSON.stringify(result) }],
125
+ };
126
+ }
127
+ if (name === "emit_event") {
128
+ const { agent_id, event } = args;
129
+ await agentManager.emitEvent(agent_id, event);
130
+ return {
131
+ content: [{ type: "text", text: "ok" }],
132
+ };
133
+ }
134
+ throw new Error(`Tool not found: ${name}`);
135
+ }
136
+ catch (error) {
137
+ return {
138
+ content: [
139
+ {
140
+ type: "text",
141
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
142
+ },
143
+ ],
144
+ isError: true,
145
+ };
146
+ }
147
+ });
148
+ async function main() {
149
+ const transport = new StdioServerTransport();
150
+ await server.connect(transport);
151
+ console.error("Agent Orchestrator MCP Server running on stdio");
152
+ }
153
+ main().catch((error) => {
154
+ console.error("Fatal error in main():", error);
155
+ process.exit(1);
156
+ });
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/tmux.js ADDED
@@ -0,0 +1,37 @@
1
+ import { exec } from "child_process";
2
+ import { promisify } from "util";
3
+ const execAsync = promisify(exec);
4
+ export async function getCurrentTmuxContext() {
5
+ try {
6
+ const { stdout } = await execAsync("tmux display-message -p '#{session_id}:#{window_id}:#{pane_id}'");
7
+ const [sessionId, windowId, paneId] = stdout.trim().split(":");
8
+ return { sessionId, windowId, paneId };
9
+ }
10
+ catch (error) {
11
+ return null; // Not inside tmux
12
+ }
13
+ }
14
+ export async function createTmuxSession(sessionName) {
15
+ await execAsync(`tmux new-session -d -s ${sessionName}`);
16
+ const { stdout } = await execAsync(`tmux display-message -t ${sessionName} -p '#{session_id}:#{window_id}:#{pane_id}'`);
17
+ const [sessionId, windowId, paneId] = stdout.trim().split(":");
18
+ return { sessionId, windowId, paneId };
19
+ }
20
+ export async function splitPane(targetPaneId, direction = "horizontal", cwd) {
21
+ const flag = direction === "horizontal" ? "-h" : "-v";
22
+ const cwdCmd = cwd ? `-c ${cwd}` : "";
23
+ const { stdout } = await execAsync(`tmux split-window -d ${flag} -t ${targetPaneId} ${cwdCmd} -P -F '#{session_id}:#{window_id}:#{pane_id}'`);
24
+ const [sessionId, windowId, paneId] = stdout.trim().split(":");
25
+ return { sessionId, windowId, paneId };
26
+ }
27
+ export async function sendKeys(paneId, keys) {
28
+ await execAsync(`tmux send-keys -t ${paneId} "${keys}" Enter`);
29
+ }
30
+ export async function capturePane(paneId, lines = 100) {
31
+ const { stdout } = await execAsync(`tmux capture-pane -p -t ${paneId} -S -${lines}`);
32
+ return stdout;
33
+ }
34
+ export async function killPane(paneId) {
35
+ await execAsync(`tmux kill-pane -t ${paneId}`);
36
+ }
37
+ //# sourceMappingURL=tmux.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux.js","sourceRoot":"","sources":["../src/tmux.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAQlC,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,iEAAiE,CAAC,CAAC;QACtG,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,CAAC,kBAAkB;IACjC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,WAAmB;IACzD,MAAM,SAAS,CAAC,0BAA0B,WAAW,EAAE,CAAC,CAAC;IACzD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,2BAA2B,WAAW,6CAA6C,CAAC,CAAC;IACxH,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,YAAoB,EAAE,YAAuC,YAAY,EAAE,GAAY;IACrH,MAAM,IAAI,GAAG,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACtD,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,wBAAwB,IAAI,OAAO,YAAY,IAAI,MAAM,gDAAgD,CAAC,CAAC;IAC9I,MAAM,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc,EAAE,IAAY;IACzD,MAAM,SAAS,CAAC,qBAAqB,MAAM,KAAK,IAAI,SAAS,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAc,EAAE,KAAK,GAAG,GAAG;IAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,2BAA2B,MAAM,QAAQ,KAAK,EAAE,CAAC,CAAC;IACrF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc;IAC3C,MAAM,SAAS,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAC;AACjD,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "agent-orchestrator",
3
+ "version": "1.0.0",
4
+ "mcpServers": {
5
+ "orchestrator": {
6
+ "command": "node",
7
+ "args": ["${extensionPath}${/}dist${/}index.js"],
8
+ "cwd": "${extensionPath}"
9
+ }
10
+ }
11
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@kkweon/agent-orchestrator-mcp",
3
+ "version": "1.0.0",
4
+ "description": "Agent Orchestrator MCP Server for tmux-based sub-agents",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/kkweon/agent-orchestrator-mcp.git"
8
+ },
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "bin": {
12
+ "agent-orchestrator-mcp": "./dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "gemini-extension.json",
17
+ "README.md"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "start": "node dist/index.js",
25
+ "dev": "ts-node src/index.ts",
26
+ "test": "NODE_OPTIONS='--experimental-vm-modules' jest",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.0.1",
31
+ "zod": "^3.23.8"
32
+ },
33
+ "devDependencies": {
34
+ "@semantic-release/changelog": "^6.0.3",
35
+ "@semantic-release/git": "^10.0.1",
36
+ "@types/jest": "^30.0.0",
37
+ "@types/node": "^20.12.7",
38
+ "jest": "^30.2.0",
39
+ "semantic-release": "^25.0.3",
40
+ "ts-jest": "^29.4.6",
41
+ "ts-node": "^10.9.2",
42
+ "typescript": "^5.4.5"
43
+ }
44
+ }