infrawise 0.5.0 → 0.6.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.
@@ -1,31 +1,20 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.currentFindings = exports.currentGraph = void 0;
7
- exports.setGraphState = setGraphState;
8
- exports.createMcpServer = createMcpServer;
9
- exports.createServer = createServer;
10
- const fs_1 = require("fs");
11
- const path_1 = require("path");
12
- const fastify_1 = __importDefault(require("fastify"));
13
- const cors_1 = __importDefault(require("@fastify/cors"));
14
- const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
15
- const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
16
- const zod_1 = require("zod");
17
- const core_1 = require("../core");
18
- const { version } = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../package.json'), 'utf8'));
19
- const analyzers_1 = require("../analyzers");
20
- const graph_1 = require("../graph");
1
+ import { readFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import Fastify from 'fastify';
4
+ import cors from '@fastify/cors';
5
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
7
+ import { z } from 'zod';
8
+ import { logger } from '../core/index.js';
9
+ const { version } = JSON.parse(readFileSync(join(import.meta.dirname, '../../package.json'), 'utf8'));
10
+ import { summarizeFindings } from '../analyzers/index.js';
11
+ import { getTableNodes, getFunctionNodes, getQueueNodes, getTopicNodes, getSecretNodes, getParameterNodes, getLogGroupNodes, getLambdaNodes, getScanEdges, getOutgoingEdges, } from '../graph/index.js';
21
12
  // ── State ────────────────────────────────────────────────────────────────────
22
13
  let currentGraph = { nodes: [], edges: [] };
23
- exports.currentGraph = currentGraph;
24
14
  let currentFindings = [];
25
- exports.currentFindings = currentFindings;
26
- function setGraphState(graph, findings) {
27
- exports.currentGraph = currentGraph = graph;
28
- exports.currentFindings = currentFindings = findings;
15
+ export function setGraphState(graph, findings) {
16
+ currentGraph = graph;
17
+ currentFindings = findings;
29
18
  }
30
19
  // ── Helpers ──────────────────────────────────────────────────────────────────
31
20
  function toText(data) {
@@ -34,25 +23,25 @@ function toText(data) {
34
23
  function logged(name, fn) {
35
24
  return async (args) => {
36
25
  const hasArgs = Object.keys(args).length > 0;
37
- core_1.logger.info(`→ ${name}${hasArgs ? ` ${JSON.stringify(args)}` : ''}`);
26
+ logger.info(`→ ${name}${hasArgs ? ` ${JSON.stringify(args)}` : ''}`);
38
27
  return fn(args);
39
28
  };
40
29
  }
41
30
  // ── MCP Server ────────────────────────────────────────────────────────────────
42
- function createMcpServer() {
43
- const mcp = new mcp_js_1.McpServer({ name: 'infrawise', version });
31
+ export function createMcpServer() {
32
+ const mcp = new McpServer({ name: 'infrawise', version });
44
33
  mcp.registerTool('get_infra_overview', {
45
34
  description: 'Returns a complete snapshot of all infrastructure: databases, queues, topics, secrets, parameters, log groups, lambdas, and all findings. Start here for a full picture.',
46
- inputSchema: zod_1.z.object({}),
35
+ inputSchema: z.object({}),
47
36
  }, logged('get_infra_overview', async () => {
48
- const tables = (0, graph_1.getTableNodes)(currentGraph);
49
- const queues = (0, graph_1.getQueueNodes)(currentGraph);
50
- const topics = (0, graph_1.getTopicNodes)(currentGraph);
51
- const secrets = (0, graph_1.getSecretNodes)(currentGraph);
52
- const parameters = (0, graph_1.getParameterNodes)(currentGraph);
53
- const logGroups = (0, graph_1.getLogGroupNodes)(currentGraph);
54
- const lambdas = (0, graph_1.getLambdaNodes)(currentGraph);
55
- const functions = (0, graph_1.getFunctionNodes)(currentGraph);
37
+ const tables = getTableNodes(currentGraph);
38
+ const queues = getQueueNodes(currentGraph);
39
+ const topics = getTopicNodes(currentGraph);
40
+ const secrets = getSecretNodes(currentGraph);
41
+ const parameters = getParameterNodes(currentGraph);
42
+ const logGroups = getLogGroupNodes(currentGraph);
43
+ const lambdas = getLambdaNodes(currentGraph);
44
+ const functions = getFunctionNodes(currentGraph);
56
45
  return toText({
57
46
  summary: {
58
47
  tables: tables.length, functions: functions.length,
@@ -60,7 +49,7 @@ function createMcpServer() {
60
49
  secrets: secrets.length, parameters: parameters.length,
61
50
  logGroups: logGroups.length, lambdas: lambdas.length,
62
51
  totalNodes: currentGraph.nodes.length, totalEdges: currentGraph.edges.length,
63
- findings: (0, analyzers_1.summarizeFindings)(currentFindings),
52
+ findings: summarizeFindings(currentFindings),
64
53
  },
65
54
  databases: tables.map((t) => ({ name: t.name, type: t.databaseType })),
66
55
  queues: queues.map((q) => ({ name: q.name, hasDLQ: q.hasDLQ, encrypted: q.encrypted, approximateMessages: q.approximateMessages })),
@@ -74,27 +63,27 @@ function createMcpServer() {
74
63
  }));
75
64
  mcp.registerTool('get_graph_summary', {
76
65
  description: 'Returns the full infrastructure graph (all nodes and edges) plus findings summary.',
77
- inputSchema: zod_1.z.object({}),
66
+ inputSchema: z.object({}),
78
67
  }, logged('get_graph_summary', async () => toText({
79
68
  nodes: currentGraph.nodes,
80
69
  edges: currentGraph.edges,
81
70
  findings: currentFindings,
82
71
  summary: {
83
72
  totalNodes: currentGraph.nodes.length, totalEdges: currentGraph.edges.length,
84
- tables: (0, graph_1.getTableNodes)(currentGraph).length, functions: (0, graph_1.getFunctionNodes)(currentGraph).length,
85
- queues: (0, graph_1.getQueueNodes)(currentGraph).length, scans: (0, graph_1.getScanEdges)(currentGraph).length,
86
- ...(0, analyzers_1.summarizeFindings)(currentFindings),
73
+ tables: getTableNodes(currentGraph).length, functions: getFunctionNodes(currentGraph).length,
74
+ queues: getQueueNodes(currentGraph).length, scans: getScanEdges(currentGraph).length,
75
+ ...summarizeFindings(currentFindings),
87
76
  },
88
77
  })));
89
78
  mcp.registerTool('analyze_function', {
90
79
  description: 'Analyze a specific function for all infrastructure issues: DB queries, queue publishing, secret access, etc.',
91
- inputSchema: zod_1.z.object({ function: zod_1.z.string().describe('Function name to analyze') }),
80
+ inputSchema: z.object({ function: z.string().describe('Function name to analyze') }),
92
81
  }, logged('analyze_function', async ({ function: functionName }) => {
93
82
  const funcNode = currentGraph.nodes.find((n) => n.type === 'function' && n.name === functionName);
94
83
  if (!funcNode) {
95
84
  return toText({ function: functionName, found: false, issues: [], recommendations: [`Function "${functionName}" not found in the analyzed codebase.`] });
96
85
  }
97
- const outEdges = (0, graph_1.getOutgoingEdges)(currentGraph, funcNode.id);
86
+ const outEdges = getOutgoingEdges(currentGraph, funcNode.id);
98
87
  const relatedFindings = currentFindings.filter((f) => {
99
88
  const meta = f.metadata;
100
89
  return meta?.functionName === functionName || String(meta?.callerFunctions ?? '').includes(functionName);
@@ -112,13 +101,14 @@ function createMcpServer() {
112
101
  }));
113
102
  mcp.registerTool('suggest_gsi', {
114
103
  description: 'Get GSI suggestions for a DynamoDB table and attribute',
115
- inputSchema: zod_1.z.object({
116
- table: zod_1.z.string().describe('DynamoDB table name'),
117
- attribute: zod_1.z.string().describe('Attribute to create the GSI on'),
104
+ inputSchema: z.object({
105
+ table: z.string().describe('DynamoDB table name'),
106
+ attribute: z.string().describe('Attribute to create the GSI on'),
118
107
  }),
119
108
  }, logged('suggest_gsi', async ({ table: tableName, attribute }) => {
120
109
  const sanitizedAttr = attribute.replace(/[^a-zA-Z0-9_]/g, '_');
121
- const indexName = `${tableName}-${sanitizedAttr}-index`;
110
+ const sanitizedTable = tableName.replace(/[^a-zA-Z0-9_-]/g, '_');
111
+ const indexName = `${sanitizedTable}-${sanitizedAttr}-index`;
122
112
  const tableNode = currentGraph.nodes.find((n) => n.type === 'table' && n.databaseType === 'dynamodb' && 'name' in n && n.name === tableName);
123
113
  return toText({
124
114
  table: tableName, attribute, found: !!tableNode,
@@ -129,9 +119,9 @@ function createMcpServer() {
129
119
  }));
130
120
  mcp.registerTool('postgres_index_suggestions', {
131
121
  description: 'Get PostgreSQL index suggestions for a table column',
132
- inputSchema: zod_1.z.object({
133
- table: zod_1.z.string().describe('PostgreSQL table name'),
134
- column: zod_1.z.string().describe('Column name to index'),
122
+ inputSchema: z.object({
123
+ table: z.string().describe('PostgreSQL table name'),
124
+ column: z.string().describe('Column name to index'),
135
125
  }),
136
126
  }, logged('postgres_index_suggestions', async ({ table: tableName, column }) => {
137
127
  const sanitizedCol = column.replace(/[^a-zA-Z0-9_]/g, '_');
@@ -139,33 +129,37 @@ function createMcpServer() {
139
129
  const indexName = `idx_${sanitizedTable}_${sanitizedCol}`;
140
130
  return toText({
141
131
  table: tableName, column,
142
- recommendation: `CREATE INDEX CONCURRENTLY ${indexName} ON ${tableName} (${column});`,
132
+ recommendation: `CREATE INDEX CONCURRENTLY ${indexName} ON ${sanitizedTable} (${sanitizedCol});`,
143
133
  rationale: `An index on "${column}" eliminates sequential scans when filtering on this column.`,
144
134
  notes: ['Use CONCURRENTLY to avoid locking the table', 'Run ANALYZE after creation',
145
- `Partial index: CREATE INDEX CONCURRENTLY ${indexName}_partial ON ${tableName} (${column}) WHERE ${column} IS NOT NULL;`],
135
+ `Partial index: CREATE INDEX CONCURRENTLY ${indexName}_partial ON ${sanitizedTable} (${sanitizedCol}) WHERE ${sanitizedCol} IS NOT NULL;`],
146
136
  });
147
137
  }));
148
138
  mcp.registerTool('suggest_mongo_index', {
149
139
  description: 'Get index suggestions for a MongoDB collection field',
150
- inputSchema: zod_1.z.object({
151
- collection: zod_1.z.string().describe('MongoDB collection name'),
152
- field: zod_1.z.string().describe('Field name to index'),
140
+ inputSchema: z.object({
141
+ collection: z.string().describe('MongoDB collection name'),
142
+ field: z.string().describe('Field name to index'),
153
143
  }),
154
- }, logged('suggest_mongo_index', async ({ collection, field }) => toText({
155
- collection, field,
156
- recommendation: `db.${collection}.createIndex({ ${field}: 1 })`,
157
- rationale: `An index on "${field}" eliminates full collection scans when filtering on this field.`,
158
- notes: [
159
- `Compound: db.${collection}.createIndex({ ${field}: 1, otherField: 1 })`,
160
- `Text: db.${collection}.createIndex({ ${field}: "text" })`,
161
- `Verify: db.${collection}.explain("executionStats").find({ ${field}: value })`,
162
- ],
163
- })));
144
+ }, logged('suggest_mongo_index', async ({ collection, field }) => {
145
+ const sanitizedCollection = collection.replace(/[^a-zA-Z0-9_]/g, '_');
146
+ const sanitizedField = field.replace(/[^a-zA-Z0-9_.]/g, '_');
147
+ return toText({
148
+ collection, field,
149
+ recommendation: `db.${sanitizedCollection}.createIndex({ ${sanitizedField}: 1 })`,
150
+ rationale: `An index on "${field}" eliminates full collection scans when filtering on this field.`,
151
+ notes: [
152
+ `Compound: db.${sanitizedCollection}.createIndex({ ${sanitizedField}: 1, otherField: 1 })`,
153
+ `Text: db.${sanitizedCollection}.createIndex({ ${sanitizedField}: "text" })`,
154
+ `Verify: db.${sanitizedCollection}.explain("executionStats").find({ ${sanitizedField}: value })`,
155
+ ],
156
+ });
157
+ }));
164
158
  mcp.registerTool('mysql_index_suggestions', {
165
159
  description: 'Get MySQL index suggestions for a table column',
166
- inputSchema: zod_1.z.object({
167
- table: zod_1.z.string().describe('MySQL table name'),
168
- column: zod_1.z.string().describe('Column name to index'),
160
+ inputSchema: z.object({
161
+ table: z.string().describe('MySQL table name'),
162
+ column: z.string().describe('Column name to index'),
169
163
  }),
170
164
  }, logged('mysql_index_suggestions', async ({ table: tableName, column }) => {
171
165
  const sanitizedCol = column.replace(/[^a-zA-Z0-9_]/g, '_');
@@ -173,17 +167,17 @@ function createMcpServer() {
173
167
  const indexName = `idx_${sanitizedTable}_${sanitizedCol}`;
174
168
  return toText({
175
169
  table: tableName, column,
176
- recommendation: `ALTER TABLE ${tableName} ADD INDEX ${indexName} (${column});`,
170
+ recommendation: `ALTER TABLE ${sanitizedTable} ADD INDEX ${indexName} (${sanitizedCol});`,
177
171
  rationale: `An index on "${column}" eliminates full table scans when filtering on this column.`,
178
172
  notes: ['MySQL InnoDB adds indexes online (no full lock for 5.6+)', 'EXPLAIN SELECT ... to verify after adding',
179
- `Composite: ALTER TABLE ${tableName} ADD INDEX idx_composite (${column}, other_column);`],
173
+ `Composite: ALTER TABLE ${sanitizedTable} ADD INDEX idx_composite (${sanitizedCol}, other_column);`],
180
174
  });
181
175
  }));
182
176
  mcp.registerTool('get_queue_details', {
183
177
  description: 'Returns all SQS queues with DLQ status, encryption, message counts, and retention.',
184
- inputSchema: zod_1.z.object({}),
178
+ inputSchema: z.object({}),
185
179
  }, logged('get_queue_details', async () => {
186
- const queues = (0, graph_1.getQueueNodes)(currentGraph);
180
+ const queues = getQueueNodes(currentGraph);
187
181
  const queueFindings = currentFindings.filter((f) => f.metadata?.queueName);
188
182
  return toText({
189
183
  total: queues.length,
@@ -196,16 +190,16 @@ function createMcpServer() {
196
190
  }));
197
191
  mcp.registerTool('get_topic_details', {
198
192
  description: 'Returns all SNS topics with subscription counts and protocols.',
199
- inputSchema: zod_1.z.object({}),
193
+ inputSchema: z.object({}),
200
194
  }, logged('get_topic_details', async () => {
201
- const topics = (0, graph_1.getTopicNodes)(currentGraph);
195
+ const topics = getTopicNodes(currentGraph);
202
196
  return toText({ total: topics.length, topics: topics.map((t) => ({ name: t.name, provider: t.provider, subscriptionCount: t.subscriptionCount, encrypted: t.encrypted })) });
203
197
  }));
204
198
  mcp.registerTool('get_secrets_overview', {
205
199
  description: 'Returns all Secrets Manager secrets: names, rotation status. Secret VALUES are never included.',
206
- inputSchema: zod_1.z.object({}),
200
+ inputSchema: z.object({}),
207
201
  }, logged('get_secrets_overview', async () => {
208
- const secrets = (0, graph_1.getSecretNodes)(currentGraph);
202
+ const secrets = getSecretNodes(currentGraph);
209
203
  const secretFindings = currentFindings.filter((f) => f.metadata?.secretName);
210
204
  return toText({
211
205
  total: secrets.length, note: 'Secret values are never included in this response.',
@@ -217,9 +211,9 @@ function createMcpServer() {
217
211
  }));
218
212
  mcp.registerTool('get_parameter_overview', {
219
213
  description: 'Returns all SSM Parameter Store parameters: names, types, tiers. Parameter VALUES are never included.',
220
- inputSchema: zod_1.z.object({}),
214
+ inputSchema: z.object({}),
221
215
  }, logged('get_parameter_overview', async () => {
222
- const parameters = (0, graph_1.getParameterNodes)(currentGraph);
216
+ const parameters = getParameterNodes(currentGraph);
223
217
  return toText({
224
218
  total: parameters.length, note: 'Parameter values are never included in this response.',
225
219
  parameters: parameters.map((p) => ({ name: p.name, provider: p.provider, type: p.paramType, tier: p.tier })),
@@ -227,9 +221,9 @@ function createMcpServer() {
227
221
  }));
228
222
  mcp.registerTool('get_lambda_overview', {
229
223
  description: 'Returns all Lambda functions: runtime, memory, timeout, env var key names (values never included).',
230
- inputSchema: zod_1.z.object({}),
224
+ inputSchema: z.object({}),
231
225
  }, logged('get_lambda_overview', async () => {
232
- const lambdas = (0, graph_1.getLambdaNodes)(currentGraph);
226
+ const lambdas = getLambdaNodes(currentGraph);
233
227
  const lambdaFindings = currentFindings.filter((f) => f.metadata?.functionName);
234
228
  return toText({
235
229
  total: lambdas.length, note: 'Environment variable values are never included.',
@@ -242,9 +236,9 @@ function createMcpServer() {
242
236
  }));
243
237
  mcp.registerTool('get_log_errors', {
244
238
  description: 'Returns recent error patterns from CloudWatch log groups. Returns pattern counts and frequencies — never raw log messages.',
245
- inputSchema: zod_1.z.object({ logGroup: zod_1.z.string().describe('Filter to a specific log group name (optional)').optional() }),
239
+ inputSchema: z.object({ logGroup: z.string().describe('Filter to a specific log group name (optional)').optional() }),
246
240
  }, logged('get_log_errors', async ({ logGroup: filterName }) => {
247
- const logGroups = (0, graph_1.getLogGroupNodes)(currentGraph).filter((lg) => !filterName || lg.name.includes(filterName));
241
+ const logGroups = getLogGroupNodes(currentGraph).filter((lg) => !filterName || lg.name.includes(filterName));
248
242
  return toText({
249
243
  note: 'Only error patterns and counts are returned — no raw log messages.',
250
244
  windowHours: 24,
@@ -254,9 +248,9 @@ function createMcpServer() {
254
248
  return mcp;
255
249
  }
256
250
  // ── Fastify server ────────────────────────────────────────────────────────────
257
- function createServer(port = 3000) {
258
- const fastify = (0, fastify_1.default)({ logger: false });
259
- fastify.register(cors_1.default, { origin: true });
251
+ export function createServer(port = 3000) {
252
+ const fastify = Fastify({ logger: false });
253
+ fastify.register(cors, { origin: true });
260
254
  const mcp = createMcpServer();
261
255
  fastify.get('/health', async () => ({
262
256
  status: 'ok', version,
@@ -265,7 +259,7 @@ function createServer(port = 3000) {
265
259
  findings: currentFindings.length,
266
260
  }));
267
261
  fastify.post('/mcp', async (request, reply) => {
268
- const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
262
+ const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
269
263
  reply.raw.on('close', () => transport.close());
270
264
  await mcp.connect(transport);
271
265
  await transport.handleRequest(request.raw, reply.raw, request.body);
@@ -276,12 +270,13 @@ function createServer(port = 3000) {
276
270
  start: async () => {
277
271
  try {
278
272
  await fastify.listen({ port, host: '0.0.0.0' });
279
- core_1.logger.info(`Infrawise MCP server running at http://localhost:${port}`);
273
+ logger.info(`Infrawise MCP server running at http://localhost:${port}`);
280
274
  }
281
275
  catch (e) {
282
- core_1.logger.error(`Failed to start server: ${e instanceof Error ? e.message : String(e)}`);
276
+ logger.error(`Failed to start server: ${e instanceof Error ? e.message : String(e)}`);
283
277
  process.exit(1);
284
278
  }
285
279
  },
286
280
  };
287
281
  }
282
+ export { currentGraph, currentFindings };
package/dist/types.js CHANGED
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infrawise",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "mcpName": "io.github.Sidd27/infrawise",
5
5
  "description": "CLI-first infrastructure intelligence platform — analyzes DynamoDB, PostgreSQL, MySQL, MongoDB, SQS, SNS, SSM, Secrets Manager, Lambda, CloudWatch Logs and exposes findings as an MCP server for Claude Code",
6
6
  "keywords": [
@@ -32,6 +32,7 @@
32
32
  "url": "git+https://github.com/Sidd27/infrawise.git"
33
33
  },
34
34
  "license": "MIT",
35
+ "type": "module",
35
36
  "bin": {
36
37
  "infrawise": "dist/cli/index.js"
37
38
  },
@@ -48,46 +49,46 @@
48
49
  "lint": "eslint src",
49
50
  "typecheck": "tsc",
50
51
  "dev": "node dist/cli/index.js dev",
51
- "release": "node scripts/release.mjs"
52
+ "release": "node scripts/release.js"
52
53
  },
53
54
  "dependencies": {
54
- "@aws-sdk/client-cloudwatch-logs": "^3.0.0",
55
- "@aws-sdk/client-dynamodb": "^3.0.0",
56
- "@aws-sdk/client-lambda": "^3.0.0",
57
- "@aws-sdk/client-rds": "^3.0.0",
58
- "@aws-sdk/client-secrets-manager": "^3.0.0",
59
- "@aws-sdk/client-sns": "^3.0.0",
60
- "@aws-sdk/client-sqs": "^3.0.0",
61
- "@aws-sdk/client-ssm": "^3.0.0",
62
- "@aws-sdk/credential-providers": "^3.0.0",
63
- "@fastify/cors": "^9.0.0",
55
+ "@aws-sdk/client-cloudwatch-logs": "^3.1048.0",
56
+ "@aws-sdk/client-dynamodb": "^3.1048.0",
57
+ "@aws-sdk/client-lambda": "^3.1048.0",
58
+ "@aws-sdk/client-rds": "^3.1048.0",
59
+ "@aws-sdk/client-secrets-manager": "^3.1048.0",
60
+ "@aws-sdk/client-sns": "^3.1048.0",
61
+ "@aws-sdk/client-sqs": "^3.1048.0",
62
+ "@aws-sdk/client-ssm": "^3.1048.0",
63
+ "@aws-sdk/credential-providers": "^3.1048.0",
64
64
  "@modelcontextprotocol/sdk": "^1.29.0",
65
- "chalk": "^4.1.2",
65
+ "chalk": "^5.6.2",
66
66
  "commander": "^14.0.3",
67
- "fastify": "^4.26.0",
68
- "inquirer": "^8.2.7",
67
+ "fastify": "^5.8.5",
68
+ "inquirer": "^13.4.3",
69
69
  "js-yaml": "^4.1.0",
70
- "mongodb": "^6.5.0",
70
+ "mongodb": "^7.2.0",
71
71
  "mysql2": "^3.9.0",
72
- "ora": "^5.4.1",
72
+ "ora": "^9.4.0",
73
73
  "pg": "^8.11.0",
74
- "pino": "^8.19.0",
75
- "pino-pretty": "^11.0.0",
76
- "ts-morph": "^22.0.0",
77
- "typescript": "^5.9.3",
78
- "zod": "^3.25.76"
74
+ "pino": "^10.3.1",
75
+ "pino-pretty": "^13.1.3",
76
+ "ts-morph": "^28.0.0",
77
+ "zod": "^4.4.3"
79
78
  },
80
79
  "devDependencies": {
81
- "@types/inquirer": "^8.2.12",
80
+ "@fastify/cors": "^11.2.0",
81
+ "@types/inquirer": "^9.0.9",
82
82
  "@types/js-yaml": "^4.0.9",
83
- "@types/node": "^22.0.0",
83
+ "@types/node": "^25.8.0",
84
84
  "@types/pg": "^8.11.0",
85
- "@typescript-eslint/eslint-plugin": "^7.0.0",
86
- "@typescript-eslint/parser": "^7.0.0",
87
- "@vitest/coverage-v8": "^1.6.1",
88
- "eslint": "^8.57.0",
89
- "typescript": "^5.9.3",
90
- "vitest": "^1.5.0"
85
+ "@typescript-eslint/eslint-plugin": "^8.59.3",
86
+ "@typescript-eslint/parser": "^8.59.3",
87
+ "@vitest/coverage-v8": "^4.1.6",
88
+ "eslint": "^10.4.0",
89
+ "typescript": "^6.0.3",
90
+ "vite": "^8.0.13",
91
+ "vitest": "^4.1.6"
91
92
  },
92
93
  "files": [
93
94
  "dist",