@cyanheads/git-mcp-server 2.4.9 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +299 -37
  2. package/package.json +29 -31
package/dist/index.js CHANGED
@@ -4261,7 +4261,7 @@ var package_default;
4261
4261
  var init_package = __esm(() => {
4262
4262
  package_default = {
4263
4263
  name: "@cyanheads/git-mcp-server",
4264
- version: "2.4.9",
4264
+ version: "2.5.1",
4265
4265
  mcpName: "io.github.cyanheads/git-mcp-server",
4266
4266
  description: "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
4267
4267
  main: "dist/index.js",
@@ -4327,33 +4327,12 @@ var init_package = __esm(() => {
4327
4327
  zod: "3.23.8",
4328
4328
  typescript: "5.9.3"
4329
4329
  },
4330
- dependencies: {
4330
+ devDependencies: {
4331
+ "@cloudflare/workers-types": "^4.20251011.0",
4332
+ "@eslint/js": "^9.37.0",
4331
4333
  "@hono/mcp": "^0.1.4",
4332
4334
  "@hono/node-server": "^1.19.5",
4333
4335
  "@modelcontextprotocol/sdk": "^1.20.0",
4334
- "@supabase/supabase-js": "^2.75.0",
4335
- axios: "^1.12.2",
4336
- "chrono-node": "^2.9.0",
4337
- dotenv: "^17.2.3",
4338
- "fast-xml-parser": "^5.3.0",
4339
- hono: "^4.9.12",
4340
- ignore: "^7.0.5",
4341
- jose: "^6.1.0",
4342
- "js-yaml": "^4.1.0",
4343
- "node-cron": "^4.2.1",
4344
- openai: "^6.3.0",
4345
- papaparse: "^5.5.3",
4346
- "partial-json": "^0.1.7",
4347
- "pdf-lib": "^1.17.1",
4348
- pino: "^10.0.0",
4349
- "pino-pretty": "^13.1.2",
4350
- "reflect-metadata": "^0.2.2",
4351
- repomix: "^1.7.0",
4352
- "sanitize-html": "^2.17.0",
4353
- tslib: "^2.8.1",
4354
- tsyringe: "^4.10.0",
4355
- validator: "13.15.15",
4356
- zod: "^3.23.8",
4357
4336
  "@opentelemetry/api": "^1.9.0",
4358
4337
  "@opentelemetry/auto-instrumentations-node": "^0.65.0",
4359
4338
  "@opentelemetry/exporter-metrics-otlp-http": "^0.206.0",
@@ -4363,11 +4342,8 @@ var init_package = __esm(() => {
4363
4342
  "@opentelemetry/sdk-metrics": "^2.1.0",
4364
4343
  "@opentelemetry/sdk-node": "^0.206.0",
4365
4344
  "@opentelemetry/sdk-trace-node": "^2.1.0",
4366
- "@opentelemetry/semantic-conventions": "^1.37.0"
4367
- },
4368
- devDependencies: {
4369
- "@cloudflare/workers-types": "^4.20251011.0",
4370
- "@eslint/js": "^9.37.0",
4345
+ "@opentelemetry/semantic-conventions": "^1.37.0",
4346
+ "@supabase/supabase-js": "^2.75.0",
4371
4347
  "@types/bun": "^1.3.0",
4372
4348
  "@types/js-yaml": "^4.0.9",
4373
4349
  "@types/node": "^24.7.2",
@@ -4378,21 +4354,43 @@ var init_package = __esm(() => {
4378
4354
  "@vitest/coverage-v8": "3.2.4",
4379
4355
  ajv: "^8.17.1",
4380
4356
  "ajv-formats": "^3.0.1",
4357
+ axios: "^1.12.2",
4381
4358
  "bun-types": "^1.3.0",
4359
+ "chrono-node": "^2.9.0",
4382
4360
  clipboardy: "^5.0.0",
4383
4361
  depcheck: "^1.4.7",
4362
+ dotenv: "^17.2.3",
4384
4363
  eslint: "^9.37.0",
4385
4364
  execa: "^9.6.0",
4365
+ "fast-xml-parser": "^5.3.0",
4386
4366
  globals: "^16.4.0",
4367
+ hono: "^4.9.12",
4387
4368
  husky: "^9.1.7",
4369
+ ignore: "^7.0.5",
4370
+ jose: "^6.1.0",
4371
+ "js-yaml": "^4.1.0",
4388
4372
  msw: "^2.11.5",
4373
+ "node-cron": "^4.2.1",
4374
+ openai: "^6.3.0",
4375
+ papaparse: "^5.5.3",
4376
+ "partial-json": "^0.1.7",
4377
+ "pdf-lib": "^1.17.1",
4378
+ pino: "^10.0.0",
4379
+ "pino-pretty": "^13.1.2",
4389
4380
  prettier: "^3.6.2",
4381
+ "reflect-metadata": "^0.2.2",
4382
+ repomix: "^1.7.0",
4383
+ "sanitize-html": "^2.17.0",
4384
+ tslib: "^2.8.1",
4385
+ tsyringe: "^4.10.0",
4390
4386
  typedoc: "^0.28.14",
4391
4387
  typescript: "^5.9.3",
4392
4388
  "typescript-eslint": "8.46.0",
4389
+ validator: "13.15.15",
4393
4390
  vite: "7.1.9",
4394
4391
  "vite-tsconfig-paths": "^5.1.4",
4395
- vitest: "^3.2.4"
4392
+ vitest: "^3.2.4",
4393
+ zod: "^3.23.8"
4396
4394
  },
4397
4395
  keywords: [
4398
4396
  "ai-agent",
@@ -151931,13 +151929,24 @@ function detectRuntime2() {
151931
151929
  }
151932
151930
  return "node";
151933
151931
  }
151934
- async function spawnWithBun(args, cwd, env, timeout) {
151932
+ async function spawnWithBun(args, cwd, env, timeout, signal) {
151935
151933
  const bunApi = globalThis.Bun;
151934
+ if (signal?.aborted) {
151935
+ throw new Error(`Git command cancelled before execution: git ${args.join(" ")}`);
151936
+ }
151936
151937
  const proc = bunApi.spawn(["git", ...args], {
151937
151938
  cwd,
151938
151939
  env,
151939
151940
  stdio: ["ignore", "pipe", "pipe"]
151940
151941
  });
151942
+ const abortPromise = new Promise((_, reject) => {
151943
+ if (signal) {
151944
+ signal.addEventListener("abort", () => {
151945
+ proc.kill();
151946
+ reject(new Error(`Git command cancelled: git ${args.join(" ")}`));
151947
+ }, { once: true });
151948
+ }
151949
+ });
151941
151950
  const timeoutPromise = new Promise((_, reject) => {
151942
151951
  const timeoutId = setTimeout(() => {
151943
151952
  proc.kill();
@@ -151945,7 +151954,11 @@ async function spawnWithBun(args, cwd, env, timeout) {
151945
151954
  }, timeout);
151946
151955
  proc.exited.finally(() => clearTimeout(timeoutId));
151947
151956
  });
151948
- const exitCode = await Promise.race([proc.exited, timeoutPromise]);
151957
+ const exitCode = await Promise.race([
151958
+ proc.exited,
151959
+ timeoutPromise,
151960
+ ...signal ? [abortPromise] : []
151961
+ ]);
151949
151962
  const [stdout, stderr] = await Promise.all([
151950
151963
  proc.stdout.text(),
151951
151964
  proc.stderr.text()
@@ -151958,8 +151971,12 @@ Stdout: ${stdout}`;
151958
151971
  }
151959
151972
  return { stdout, stderr };
151960
151973
  }
151961
- async function spawnWithNode(args, cwd, env, timeout) {
151974
+ async function spawnWithNode(args, cwd, env, timeout, signal) {
151962
151975
  return new Promise((resolve, reject) => {
151976
+ if (signal?.aborted) {
151977
+ reject(new Error(`Git command cancelled before execution: ${args.join(" ")}`));
151978
+ return;
151979
+ }
151963
151980
  const proc = spawn("git", args, {
151964
151981
  cwd,
151965
151982
  env,
@@ -151973,16 +151990,29 @@ async function spawnWithNode(args, cwd, env, timeout) {
151973
151990
  proc.stderr.on("data", (chunk) => {
151974
151991
  stderrChunks.push(chunk);
151975
151992
  });
151993
+ const abortHandler = () => {
151994
+ proc.kill("SIGTERM");
151995
+ reject(new Error(`Git command cancelled: ${args.join(" ")}`));
151996
+ };
151997
+ if (signal) {
151998
+ signal.addEventListener("abort", abortHandler, { once: true });
151999
+ }
151976
152000
  const timeoutHandle = setTimeout(() => {
151977
152001
  proc.kill("SIGTERM");
151978
152002
  reject(new Error(`Git command timed out after ${timeout / 1000}s: ${args.join(" ")}`));
151979
152003
  }, timeout);
151980
152004
  proc.on("error", (error) => {
151981
152005
  clearTimeout(timeoutHandle);
152006
+ if (signal) {
152007
+ signal.removeEventListener("abort", abortHandler);
152008
+ }
151982
152009
  reject(error);
151983
152010
  });
151984
152011
  proc.on("close", (exitCode) => {
151985
152012
  clearTimeout(timeoutHandle);
152013
+ if (signal) {
152014
+ signal.removeEventListener("abort", abortHandler);
152015
+ }
151986
152016
  const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
151987
152017
  const stderr = Buffer.concat(stderrChunks).toString("utf-8");
151988
152018
  if (exitCode !== 0) {
@@ -151996,12 +152026,12 @@ Stdout: ${stdout}`;
151996
152026
  });
151997
152027
  });
151998
152028
  }
151999
- async function spawnGitCommand(args, cwd, env, timeout = 60000) {
152029
+ async function spawnGitCommand(args, cwd, env, timeout = 60000, signal) {
152000
152030
  const runtime2 = detectRuntime2();
152001
152031
  if (runtime2 === "bun") {
152002
- return spawnWithBun(args, cwd, env, timeout);
152032
+ return spawnWithBun(args, cwd, env, timeout, signal);
152003
152033
  } else {
152004
- return spawnWithNode(args, cwd, env, timeout);
152034
+ return spawnWithNode(args, cwd, env, timeout, signal);
152005
152035
  }
152006
152036
  }
152007
152037
 
@@ -172126,6 +172156,163 @@ var httpErrorHandler = async (err, c) => {
172126
172156
  return c.json(errorResponse);
172127
172157
  };
172128
172158
 
172159
+ // src/mcp-server/transports/http/sessionManager.ts
172160
+ init_utils();
172161
+
172162
+ class SessionManager {
172163
+ static instance = null;
172164
+ sessions = new Map;
172165
+ cleanupIntervalId = null;
172166
+ staleTimeoutMs;
172167
+ cleanupIntervalMs;
172168
+ constructor(staleTimeoutMs = 30 * 60 * 1000, cleanupIntervalMs = 5 * 60 * 1000) {
172169
+ this.staleTimeoutMs = staleTimeoutMs;
172170
+ this.cleanupIntervalMs = cleanupIntervalMs;
172171
+ this.startCleanupInterval();
172172
+ }
172173
+ static getInstance(staleTimeoutMs, cleanupIntervalMs) {
172174
+ if (!SessionManager.instance) {
172175
+ SessionManager.instance = new SessionManager(staleTimeoutMs, cleanupIntervalMs);
172176
+ }
172177
+ return SessionManager.instance;
172178
+ }
172179
+ static resetInstance() {
172180
+ if (SessionManager.instance) {
172181
+ SessionManager.instance.stopCleanupInterval();
172182
+ SessionManager.instance = null;
172183
+ }
172184
+ }
172185
+ createSession(sessionId, clientId, tenantId) {
172186
+ const now2 = Date.now();
172187
+ const metadata = {
172188
+ sessionId,
172189
+ createdAt: now2,
172190
+ lastActivityAt: now2,
172191
+ ...clientId !== undefined && { clientId },
172192
+ ...tenantId !== undefined && { tenantId }
172193
+ };
172194
+ this.sessions.set(sessionId, metadata);
172195
+ logger.debug("Created new MCP session", {
172196
+ ...requestContextService.createRequestContext({
172197
+ operation: "SessionManager.createSession"
172198
+ }),
172199
+ sessionId,
172200
+ ...clientId !== undefined && { clientId },
172201
+ ...tenantId !== undefined && { tenantId },
172202
+ totalSessions: this.sessions.size
172203
+ });
172204
+ return sessionId;
172205
+ }
172206
+ isSessionValid(sessionId) {
172207
+ const session = this.sessions.get(sessionId);
172208
+ if (!session) {
172209
+ return false;
172210
+ }
172211
+ const now2 = Date.now();
172212
+ const age = now2 - session.lastActivityAt;
172213
+ if (age > this.staleTimeoutMs) {
172214
+ logger.info("Session expired due to inactivity", {
172215
+ ...requestContextService.createRequestContext({
172216
+ operation: "SessionManager.isSessionValid"
172217
+ }),
172218
+ sessionId,
172219
+ ageMs: age,
172220
+ staleTimeoutMs: this.staleTimeoutMs
172221
+ });
172222
+ this.sessions.delete(sessionId);
172223
+ return false;
172224
+ }
172225
+ return true;
172226
+ }
172227
+ touchSession(sessionId) {
172228
+ const session = this.sessions.get(sessionId);
172229
+ if (session) {
172230
+ session.lastActivityAt = Date.now();
172231
+ }
172232
+ }
172233
+ terminateSession(sessionId) {
172234
+ const existed = this.sessions.has(sessionId);
172235
+ this.sessions.delete(sessionId);
172236
+ if (existed) {
172237
+ logger.info("Session explicitly terminated", {
172238
+ ...requestContextService.createRequestContext({
172239
+ operation: "SessionManager.terminateSession"
172240
+ }),
172241
+ sessionId,
172242
+ remainingSessions: this.sessions.size
172243
+ });
172244
+ }
172245
+ return existed;
172246
+ }
172247
+ getSessionMetadata(sessionId) {
172248
+ if (!this.isSessionValid(sessionId)) {
172249
+ return null;
172250
+ }
172251
+ return this.sessions.get(sessionId) ?? null;
172252
+ }
172253
+ getActiveSessionCount() {
172254
+ return this.sessions.size;
172255
+ }
172256
+ startCleanupInterval() {
172257
+ if (this.cleanupIntervalId) {
172258
+ return;
172259
+ }
172260
+ this.cleanupIntervalId = setInterval(() => {
172261
+ this.cleanupStaleSessions();
172262
+ }, this.cleanupIntervalMs);
172263
+ logger.info("Session cleanup interval started", {
172264
+ ...requestContextService.createRequestContext({
172265
+ operation: "SessionManager.startCleanupInterval"
172266
+ }),
172267
+ cleanupIntervalMs: this.cleanupIntervalMs,
172268
+ staleTimeoutMs: this.staleTimeoutMs
172269
+ });
172270
+ }
172271
+ stopCleanupInterval() {
172272
+ if (this.cleanupIntervalId) {
172273
+ clearInterval(this.cleanupIntervalId);
172274
+ this.cleanupIntervalId = null;
172275
+ logger.info("Session cleanup interval stopped", {
172276
+ ...requestContextService.createRequestContext({
172277
+ operation: "SessionManager.stopCleanupInterval"
172278
+ })
172279
+ });
172280
+ }
172281
+ }
172282
+ cleanupStaleSessions() {
172283
+ const now2 = Date.now();
172284
+ const sessionsBefore = this.sessions.size;
172285
+ let removedCount = 0;
172286
+ for (const [sessionId, metadata] of this.sessions.entries()) {
172287
+ const age = now2 - metadata.lastActivityAt;
172288
+ if (age > this.staleTimeoutMs) {
172289
+ this.sessions.delete(sessionId);
172290
+ removedCount++;
172291
+ }
172292
+ }
172293
+ if (removedCount > 0) {
172294
+ logger.notice("Cleaned up stale sessions", {
172295
+ ...requestContextService.createRequestContext({
172296
+ operation: "SessionManager.cleanupStaleSessions"
172297
+ }),
172298
+ removedCount,
172299
+ sessionsBefore,
172300
+ sessionsAfter: this.sessions.size
172301
+ });
172302
+ }
172303
+ }
172304
+ clearAllSessions() {
172305
+ const count = this.sessions.size;
172306
+ this.sessions.clear();
172307
+ logger.warning("All sessions cleared", {
172308
+ ...requestContextService.createRequestContext({
172309
+ operation: "SessionManager.clearAllSessions"
172310
+ }),
172311
+ clearedCount: count
172312
+ });
172313
+ }
172314
+ }
172315
+
172129
172316
  // src/mcp-server/transports/http/httpTransport.ts
172130
172317
  init_utils();
172131
172318
 
@@ -172142,6 +172329,11 @@ function createHttpApp(mcpServer, parentContext) {
172142
172329
  ...parentContext,
172143
172330
  component: "HttpTransportSetup"
172144
172331
  };
172332
+ const sessionManager = SessionManager.getInstance(config.mcpStatefulSessionStaleTimeoutMs);
172333
+ logger.info("Session manager initialized", {
172334
+ ...transportContext,
172335
+ staleTimeoutMs: config.mcpStatefulSessionStaleTimeoutMs
172336
+ });
172145
172337
  const allowedOrigin = Array.isArray(config.mcpAllowedOrigins) && config.mcpAllowedOrigins.length > 0 ? config.mcpAllowedOrigins : "*";
172146
172338
  app.use("*", cors({
172147
172339
  origin: allowedOrigin,
@@ -172190,6 +172382,35 @@ function createHttpApp(mcpServer, parentContext) {
172190
172382
  } else {
172191
172383
  logger.info("Authentication is disabled; MCP endpoint is unprotected.", transportContext);
172192
172384
  }
172385
+ app.delete(config.mcpHttpEndpointPath, (c) => {
172386
+ const sessionId = c.req.header("mcp-session-id");
172387
+ if (!sessionId) {
172388
+ return c.json({
172389
+ jsonrpc: "2.0",
172390
+ error: {
172391
+ code: -32600,
172392
+ message: "Mcp-Session-Id header required for DELETE"
172393
+ },
172394
+ id: null
172395
+ }, 400);
172396
+ }
172397
+ const terminated = sessionManager.terminateSession(sessionId);
172398
+ if (!terminated) {
172399
+ return c.json({
172400
+ jsonrpc: "2.0",
172401
+ error: {
172402
+ code: -32001,
172403
+ message: "Session not found or already expired"
172404
+ },
172405
+ id: null
172406
+ }, 404);
172407
+ }
172408
+ logger.info("Session terminated via DELETE", {
172409
+ ...transportContext,
172410
+ sessionId
172411
+ });
172412
+ return c.body(null, 204);
172413
+ });
172193
172414
  app.all(config.mcpHttpEndpointPath, async (c) => {
172194
172415
  const protocolVersion = c.req.header("mcp-protocol-version") ?? "2025-03-26";
172195
172416
  logger.debug("Handling MCP request.", {
@@ -172205,12 +172426,50 @@ function createHttpApp(mcpServer, parentContext) {
172205
172426
  protocolVersion,
172206
172427
  supportedVersions
172207
172428
  });
172429
+ return c.json({
172430
+ jsonrpc: "2.0",
172431
+ error: {
172432
+ code: -32600,
172433
+ message: `Unsupported MCP protocol version: ${protocolVersion}`,
172434
+ data: {
172435
+ requested: protocolVersion,
172436
+ supported: supportedVersions
172437
+ }
172438
+ },
172439
+ id: null
172440
+ }, 400);
172208
172441
  }
172209
172442
  const sessionId = c.req.header("mcp-session-id") ?? randomUUID();
172443
+ if (c.req.header("mcp-session-id") && !sessionManager.isSessionValid(sessionId)) {
172444
+ logger.warning("Invalid or expired session ID", {
172445
+ ...transportContext,
172446
+ sessionId
172447
+ });
172448
+ return c.json({
172449
+ jsonrpc: "2.0",
172450
+ error: {
172451
+ code: -32001,
172452
+ message: "Session expired or invalid. Please reinitialize."
172453
+ },
172454
+ id: null
172455
+ }, 404);
172456
+ }
172457
+ if (!c.req.header("mcp-session-id")) {
172458
+ logger.debug("New session will be created", {
172459
+ ...transportContext,
172460
+ sessionId
172461
+ });
172462
+ } else {
172463
+ sessionManager.touchSession(sessionId);
172464
+ }
172210
172465
  const transport = new McpSessionTransport(sessionId);
172211
172466
  const handleRpc = async () => {
172212
172467
  await mcpServer.connect(transport);
172213
172468
  const response = await transport.handleRequest(c);
172469
+ if (response && !c.req.header("mcp-session-id")) {
172470
+ const store = authContext.getStore();
172471
+ sessionManager.createSession(sessionId, store?.authInfo.clientId, store?.authInfo.tenantId);
172472
+ }
172214
172473
  if (response) {
172215
172474
  return response;
172216
172475
  }
@@ -172306,6 +172565,9 @@ async function stopHttpTransport(server, parentContext) {
172306
172565
  transportType: "Http"
172307
172566
  };
172308
172567
  logger.info("Attempting to stop http transport...", operationContext);
172568
+ const sessionManager = SessionManager.getInstance();
172569
+ sessionManager.stopCleanupInterval();
172570
+ logger.info("Session cleanup interval stopped", operationContext);
172309
172571
  return new Promise((resolve, reject) => {
172310
172572
  server.close((err) => {
172311
172573
  if (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/git-mcp-server",
3
- "version": "2.4.9",
3
+ "version": "2.5.1",
4
4
  "mcpName": "io.github.cyanheads/git-mcp-server",
5
5
  "description": "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
6
6
  "main": "dist/index.js",
@@ -66,33 +66,12 @@
66
66
  "zod": "3.23.8",
67
67
  "typescript": "5.9.3"
68
68
  },
69
- "dependencies": {
69
+ "devDependencies": {
70
+ "@cloudflare/workers-types": "^4.20251011.0",
71
+ "@eslint/js": "^9.37.0",
70
72
  "@hono/mcp": "^0.1.4",
71
73
  "@hono/node-server": "^1.19.5",
72
74
  "@modelcontextprotocol/sdk": "^1.20.0",
73
- "@supabase/supabase-js": "^2.75.0",
74
- "axios": "^1.12.2",
75
- "chrono-node": "^2.9.0",
76
- "dotenv": "^17.2.3",
77
- "fast-xml-parser": "^5.3.0",
78
- "hono": "^4.9.12",
79
- "ignore": "^7.0.5",
80
- "jose": "^6.1.0",
81
- "js-yaml": "^4.1.0",
82
- "node-cron": "^4.2.1",
83
- "openai": "^6.3.0",
84
- "papaparse": "^5.5.3",
85
- "partial-json": "^0.1.7",
86
- "pdf-lib": "^1.17.1",
87
- "pino": "^10.0.0",
88
- "pino-pretty": "^13.1.2",
89
- "reflect-metadata": "^0.2.2",
90
- "repomix": "^1.7.0",
91
- "sanitize-html": "^2.17.0",
92
- "tslib": "^2.8.1",
93
- "tsyringe": "^4.10.0",
94
- "validator": "13.15.15",
95
- "zod": "^3.23.8",
96
75
  "@opentelemetry/api": "^1.9.0",
97
76
  "@opentelemetry/auto-instrumentations-node": "^0.65.0",
98
77
  "@opentelemetry/exporter-metrics-otlp-http": "^0.206.0",
@@ -102,11 +81,8 @@
102
81
  "@opentelemetry/sdk-metrics": "^2.1.0",
103
82
  "@opentelemetry/sdk-node": "^0.206.0",
104
83
  "@opentelemetry/sdk-trace-node": "^2.1.0",
105
- "@opentelemetry/semantic-conventions": "^1.37.0"
106
- },
107
- "devDependencies": {
108
- "@cloudflare/workers-types": "^4.20251011.0",
109
- "@eslint/js": "^9.37.0",
84
+ "@opentelemetry/semantic-conventions": "^1.37.0",
85
+ "@supabase/supabase-js": "^2.75.0",
110
86
  "@types/bun": "^1.3.0",
111
87
  "@types/js-yaml": "^4.0.9",
112
88
  "@types/node": "^24.7.2",
@@ -117,21 +93,43 @@
117
93
  "@vitest/coverage-v8": "3.2.4",
118
94
  "ajv": "^8.17.1",
119
95
  "ajv-formats": "^3.0.1",
96
+ "axios": "^1.12.2",
120
97
  "bun-types": "^1.3.0",
98
+ "chrono-node": "^2.9.0",
121
99
  "clipboardy": "^5.0.0",
122
100
  "depcheck": "^1.4.7",
101
+ "dotenv": "^17.2.3",
123
102
  "eslint": "^9.37.0",
124
103
  "execa": "^9.6.0",
104
+ "fast-xml-parser": "^5.3.0",
125
105
  "globals": "^16.4.0",
106
+ "hono": "^4.9.12",
126
107
  "husky": "^9.1.7",
108
+ "ignore": "^7.0.5",
109
+ "jose": "^6.1.0",
110
+ "js-yaml": "^4.1.0",
127
111
  "msw": "^2.11.5",
112
+ "node-cron": "^4.2.1",
113
+ "openai": "^6.3.0",
114
+ "papaparse": "^5.5.3",
115
+ "partial-json": "^0.1.7",
116
+ "pdf-lib": "^1.17.1",
117
+ "pino": "^10.0.0",
118
+ "pino-pretty": "^13.1.2",
128
119
  "prettier": "^3.6.2",
120
+ "reflect-metadata": "^0.2.2",
121
+ "repomix": "^1.7.0",
122
+ "sanitize-html": "^2.17.0",
123
+ "tslib": "^2.8.1",
124
+ "tsyringe": "^4.10.0",
129
125
  "typedoc": "^0.28.14",
130
126
  "typescript": "^5.9.3",
131
127
  "typescript-eslint": "8.46.0",
128
+ "validator": "13.15.15",
132
129
  "vite": "7.1.9",
133
130
  "vite-tsconfig-paths": "^5.1.4",
134
- "vitest": "^3.2.4"
131
+ "vitest": "^3.2.4",
132
+ "zod": "^3.23.8"
135
133
  },
136
134
  "keywords": [
137
135
  "ai-agent",