From 258abc7f37568153ab98cb2895dd6f4a0acf011e Mon Sep 17 00:00:00 2001
From: Ashu Ghildiyal
Date: Mon, 8 Sep 2025 22:43:08 +0530
Subject: [PATCH 01/72] app: Add langchain mcp adapter
---
app/package-lock.json | 1823 ++++++++++++++++++++++++++++++++++++++---
app/package.json | 2 +
2 files changed, 1723 insertions(+), 102 deletions(-)
diff --git a/app/package-lock.json b/app/package-lock.json
index 7f7d034d619..29151351e16 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -8,6 +8,7 @@
"name": "headlamp",
"version": "0.36.0",
"dependencies": {
+ "@langchain/mcp-adapters": "^0.6.0",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"dotenv": "^16.4.5",
@@ -1958,6 +1959,13 @@
"hasInstallScript": true,
"optional": true
},
+ "node_modules/@cfworker/json-schema": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz",
+ "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/@develar/schema-utils": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
@@ -3495,6 +3503,76 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@langchain/core": {
+ "version": "0.3.73",
+ "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.73.tgz",
+ "integrity": "sha512-E5dK9/MDH9671yuU3ZoMfSkMC7njtZrOZYrmLGk+2cvGk92yqxv/+MMxwOYoFtPMEWx9T8mTg2omHqcXXaEpGw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@cfworker/json-schema": "^4.0.2",
+ "ansi-styles": "^5.0.0",
+ "camelcase": "6",
+ "decamelize": "1.2.0",
+ "js-tiktoken": "^1.0.12",
+ "langsmith": "^0.3.46",
+ "mustache": "^4.2.0",
+ "p-queue": "^6.6.2",
+ "p-retry": "4",
+ "uuid": "^10.0.0",
+ "zod": "^3.25.32",
+ "zod-to-json-schema": "^3.22.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@langchain/core/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@langchain/core/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@langchain/mcp-adapters": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@langchain/mcp-adapters/-/mcp-adapters-0.6.0.tgz",
+ "integrity": "sha512-NHQNH9NciLhxlCnL/4HDebiYT3UQvpBfF5KPlIi/uSXn8te/bYjPV64gUyAloNNo+fjj4qDvKP1/nHj0r7fKFw==",
+ "license": "MIT",
+ "dependencies": {
+ "@modelcontextprotocol/sdk": "^1.12.1",
+ "debug": "^4.4.0",
+ "zod": "^3.24.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "extended-eventsource": "^1.x"
+ },
+ "peerDependencies": {
+ "@langchain/core": "^0.3.66"
+ }
+ },
"node_modules/@malept/cross-spawn-promise": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
@@ -3567,6 +3645,29 @@
"node": ">= 10.0.0"
}
},
+ "node_modules/@modelcontextprotocol/sdk": {
+ "version": "1.17.5",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.5.tgz",
+ "integrity": "sha512-QakrKIGniGuRVfWBdMsDea/dx1PNE739QJ7gCM41s9q+qaCYTHCdsIBXQVVXry3mfWAiaM9kT22Hyz53Uw8mfg==",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.6",
+ "content-type": "^1.0.5",
+ "cors": "^2.8.5",
+ "cross-spawn": "^7.0.5",
+ "eventsource": "^3.0.2",
+ "eventsource-parser": "^3.0.0",
+ "express": "^5.0.1",
+ "express-rate-limit": "^7.5.0",
+ "pkce-challenge": "^5.0.0",
+ "raw-body": "^3.0.0",
+ "zod": "^3.23.8",
+ "zod-to-json-schema": "^3.24.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@mswjs/interceptors": {
"version": "0.38.7",
"resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.38.7.tgz",
@@ -3857,6 +3958,13 @@
"@types/node": "*"
}
},
+ "node_modules/@types/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/@types/semver": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz",
@@ -3876,6 +3984,13 @@
"integrity": "sha512-Lja2xYuuf2B3knEsga8ShbOdsfNOtzT73GyJmZyY7eGl2+ajOqrs8yM5ze0fsSoYwvA6bw7/Qr7OZ7PEEmYwWg==",
"dev": true
},
+ "node_modules/@types/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/@types/verror": {
"version": "1.10.9",
"resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.9.tgz",
@@ -4138,6 +4253,40 @@
"integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==",
"dev": true
},
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/accepts/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/accepts/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -4175,7 +4324,6 @@
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -5031,7 +5179,6 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -5099,6 +5246,26 @@
"bluebird": "^3.5.5"
}
},
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -5382,6 +5549,15 @@
"node": ">= 10.0.0"
}
},
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
@@ -5406,7 +5582,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@@ -5416,6 +5591,22 @@
"node": ">= 0.4"
}
},
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -5784,12 +5975,81 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/console-table-printer": {
+ "version": "2.14.6",
+ "resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.14.6.tgz",
+ "integrity": "sha512-MCBl5HNVaFuuHW6FGbL/4fB7N/ormCy+tQ+sxTrF6QtSbSNETvPuOVbkJBhzDgYhvjWGrTma4eYJa37ZuoQsPw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "simple-wcswidth": "^1.0.1"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-disposition/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
"node_modules/copyfiles": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz",
@@ -5901,6 +6161,19 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/crc": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
@@ -6124,11 +6397,12 @@
}
},
"node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "license": "MIT",
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -6139,6 +6413,16 @@
}
}
},
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
@@ -6287,6 +6571,15 @@
"node": ">=0.4.0"
}
},
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -6510,7 +6803,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@@ -6526,6 +6818,12 @@
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
"node_modules/ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
@@ -6812,6 +7110,15 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/encoding-sniffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
@@ -6939,7 +7246,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -6949,7 +7255,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true,
"engines": {
"node": ">= 0.4"
}
@@ -7012,7 +7317,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@@ -7121,6 +7425,12 @@
"node": ">=6"
}
},
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
"node_modules/escape-string-regexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
@@ -7697,6 +8007,43 @@
"node": ">=0.10.0"
}
},
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/eventsource": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz",
+ "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==",
+ "license": "MIT",
+ "dependencies": {
+ "eventsource-parser": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/eventsource-parser": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz",
+ "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -7757,6 +8104,91 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express-rate-limit": {
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz",
+ "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/express-rate-limit"
+ },
+ "peerDependencies": {
+ "express": ">= 4.11"
+ }
+ },
+ "node_modules/express/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/extended-eventsource": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/extended-eventsource/-/extended-eventsource-1.7.0.tgz",
+ "integrity": "sha512-s8rtvZuYcKBpzytHb5g95cHbZ1J99WeMnV18oKc5wKoxkHzlzpPc/bNAm7Da2Db0BDw0CAu1z3LpH+7UsyzIpw==",
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/extract-zip": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
@@ -7790,8 +8222,7 @@
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-fifo": {
"version": "1.3.2",
@@ -7817,8 +8248,7 @@
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
@@ -7905,6 +8335,23 @@
"node": ">=8"
}
},
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/find-process": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.10.tgz",
@@ -8012,6 +8459,24 @@
"node": ">= 6"
}
},
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -8182,7 +8647,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -8216,7 +8680,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@@ -8420,7 +8883,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -8506,7 +8968,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -8625,6 +9086,31 @@
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
"dev": true
},
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-errors/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -8803,7 +9289,6 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dev": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
@@ -8931,6 +9416,15 @@
"node": ">= 0.10"
}
},
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -9265,6 +9759,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
"node_modules/is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
@@ -10224,6 +10724,16 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
+ "node_modules/js-tiktoken": {
+ "version": "1.0.21",
+ "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz",
+ "integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "base64-js": "^1.5.1"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -10270,8 +10780,7 @@
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -10347,6 +10856,42 @@
"node": ">=6"
}
},
+ "node_modules/langsmith": {
+ "version": "0.3.67",
+ "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.67.tgz",
+ "integrity": "sha512-l4y3RmJ9yWF5a29fLg3eWZQxn6Q6dxTOgLGgQHzPGZHF3NUynn+A+airYIe/Yt4rwjGbuVrABAPsXBkVu/Hi7g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/uuid": "^10.0.0",
+ "chalk": "^4.1.2",
+ "console-table-printer": "^2.12.1",
+ "p-queue": "^6.6.2",
+ "p-retry": "4",
+ "semver": "^7.6.3",
+ "uuid": "^10.0.0"
+ },
+ "peerDependencies": {
+ "@opentelemetry/api": "*",
+ "@opentelemetry/exporter-trace-otlp-proto": "*",
+ "@opentelemetry/sdk-trace-base": "*",
+ "openai": "*"
+ },
+ "peerDependenciesMeta": {
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@opentelemetry/exporter-trace-otlp-proto": {
+ "optional": true
+ },
+ "@opentelemetry/sdk-trace-base": {
+ "optional": true
+ },
+ "openai": {
+ "optional": true
+ }
+ }
+ },
"node_modules/language-subtag-registry": {
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
@@ -10604,12 +11149,32 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -10828,9 +11393,20 @@
}
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/mustache": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+ "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "mustache": "bin/mustache"
+ }
},
"node_modules/natural-compare": {
"version": "1.4.0",
@@ -10838,6 +11414,15 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -10955,17 +11540,15 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
- "version": "1.13.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
- "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
- "dev": true,
- "peer": true,
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -11085,6 +11668,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -11180,6 +11775,60 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/p-queue": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
+ "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "eventemitter3": "^4.0.4",
+ "p-timeout": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-retry": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
+ "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/retry": "0.12.0",
+ "retry": "^0.13.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-retry/node_modules/retry": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+ "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/p-timeout": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
+ "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "p-finally": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -11264,6 +11913,15 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -11323,6 +11981,16 @@
"node": "14 || >=16.14"
}
},
+ "node_modules/path-to-regexp": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -11364,6 +12032,15 @@
"node": ">= 6"
}
},
+ "node_modules/pkce-challenge": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
+ "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.20.0"
+ }
+ },
"node_modules/pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
@@ -11534,6 +12211,19 @@
"node": ">= 8"
}
},
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -11547,7 +12237,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true,
"engines": {
"node": ">=6"
}
@@ -11568,6 +12257,21 @@
}
]
},
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -11649,6 +12353,46 @@
"rimraf": "bin.js"
}
},
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz",
+ "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.7.0",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/raw-body/node_modules/iconv-lite": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
+ "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/rcedit": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rcedit/-/rcedit-4.0.1.tgz",
@@ -12047,6 +12791,22 @@
"node": ">=8.0"
}
},
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/rsvp": {
"version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@@ -12130,8 +12890,7 @@
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sanitize-filename": {
"version": "1.6.3",
@@ -12149,9 +12908,10 @@
"dev": true
},
"node_modules/semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -12166,6 +12926,49 @@
"dev": true,
"optional": true
},
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/send/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/send/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/serialize-error": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
@@ -12182,6 +12985,21 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -12216,6 +13034,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -12376,16 +13200,69 @@
}
},
"node_modules/side-channel": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
- "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
- "dev": true,
- "peer": true,
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
"es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "object-inspect": "^1.13.1"
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
@@ -12411,6 +13288,13 @@
"node": ">=10"
}
},
+ "node_modules/simple-wcswidth": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz",
+ "integrity": "sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -12513,6 +13397,15 @@
"node": ">= 6"
}
},
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/stop-iteration-iterator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
@@ -13013,6 +13906,15 @@
"node": ">=10.13.0"
}
},
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/truncate-utf8-bytes": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
@@ -13104,6 +14006,41 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/type-is/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/type-is/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/typed-array-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
@@ -13289,6 +14226,15 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/untildify": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
@@ -13331,7 +14277,6 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
"dependencies": {
"punycode": "^2.1.0"
}
@@ -13347,6 +14292,20 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
+ "node_modules/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
@@ -13370,6 +14329,15 @@
"node": ">= 10.13.0"
}
},
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/verror": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz",
@@ -13874,6 +14842,24 @@
"engines": {
"node": ">= 6"
}
+ },
+ "node_modules/zod": {
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-to-json-schema": {
+ "version": "3.24.6",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz",
+ "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==",
+ "license": "ISC",
+ "peerDependencies": {
+ "zod": "^3.24.1"
+ }
}
},
"dependencies": {
@@ -15209,6 +16195,12 @@
"integrity": "sha512-iTZ8cVGZ5dglNRyFdSj8U60mHIrC8XNIuOHN/NkM5/dQP4nsmpyqeQTAADLLQgoFCNJD+DiwQCv8dR2cCeWP4g==",
"optional": true
},
+ "@cfworker/json-schema": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz",
+ "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==",
+ "peer": true
+ },
"@develar/schema-utils": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
@@ -16205,6 +17197,51 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "@langchain/core": {
+ "version": "0.3.73",
+ "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.73.tgz",
+ "integrity": "sha512-E5dK9/MDH9671yuU3ZoMfSkMC7njtZrOZYrmLGk+2cvGk92yqxv/+MMxwOYoFtPMEWx9T8mTg2omHqcXXaEpGw==",
+ "peer": true,
+ "requires": {
+ "@cfworker/json-schema": "^4.0.2",
+ "ansi-styles": "^5.0.0",
+ "camelcase": "6",
+ "decamelize": "1.2.0",
+ "js-tiktoken": "^1.0.12",
+ "langsmith": "^0.3.46",
+ "mustache": "^4.2.0",
+ "p-queue": "^6.6.2",
+ "p-retry": "4",
+ "uuid": "^10.0.0",
+ "zod": "^3.25.32",
+ "zod-to-json-schema": "^3.22.3"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "peer": true
+ },
+ "camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "peer": true
+ }
+ }
+ },
+ "@langchain/mcp-adapters": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@langchain/mcp-adapters/-/mcp-adapters-0.6.0.tgz",
+ "integrity": "sha512-NHQNH9NciLhxlCnL/4HDebiYT3UQvpBfF5KPlIi/uSXn8te/bYjPV64gUyAloNNo+fjj4qDvKP1/nHj0r7fKFw==",
+ "requires": {
+ "@modelcontextprotocol/sdk": "^1.12.1",
+ "debug": "^4.4.0",
+ "extended-eventsource": "^1.x",
+ "zod": "^3.24.2"
+ }
+ },
"@malept/cross-spawn-promise": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
@@ -16255,6 +17292,25 @@
}
}
},
+ "@modelcontextprotocol/sdk": {
+ "version": "1.17.5",
+ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.5.tgz",
+ "integrity": "sha512-QakrKIGniGuRVfWBdMsDea/dx1PNE739QJ7gCM41s9q+qaCYTHCdsIBXQVVXry3mfWAiaM9kT22Hyz53Uw8mfg==",
+ "requires": {
+ "ajv": "^6.12.6",
+ "content-type": "^1.0.5",
+ "cors": "^2.8.5",
+ "cross-spawn": "^7.0.5",
+ "eventsource": "^3.0.2",
+ "eventsource-parser": "^3.0.0",
+ "express": "^5.0.1",
+ "express-rate-limit": "^7.5.0",
+ "pkce-challenge": "^5.0.0",
+ "raw-body": "^3.0.0",
+ "zod": "^3.23.8",
+ "zod-to-json-schema": "^3.24.1"
+ }
+ },
"@mswjs/interceptors": {
"version": "0.38.7",
"resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.38.7.tgz",
@@ -16529,6 +17585,12 @@
"@types/node": "*"
}
},
+ "@types/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
+ "peer": true
+ },
"@types/semver": {
"version": "7.7.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz",
@@ -16547,6 +17609,12 @@
"integrity": "sha512-Lja2xYuuf2B3knEsga8ShbOdsfNOtzT73GyJmZyY7eGl2+ajOqrs8yM5ze0fsSoYwvA6bw7/Qr7OZ7PEEmYwWg==",
"dev": true
},
+ "@types/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
+ "peer": true
+ },
"@types/verror": {
"version": "1.10.9",
"resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.9.tgz",
@@ -16716,6 +17784,30 @@
"integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==",
"dev": true
},
+ "accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "requires": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="
+ },
+ "mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "requires": {
+ "mime-db": "^1.54.0"
+ }
+ }
+ }
+ },
"acorn": {
"version": "8.12.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
@@ -16742,7 +17834,6 @@
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -17415,8 +18506,7 @@
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "dev": true
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"binary-extensions": {
"version": "2.2.0",
@@ -17466,6 +18556,22 @@
"bluebird": "^3.5.5"
}
},
+ "body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "requires": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ }
+ },
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@@ -17678,6 +18784,11 @@
"sax": "^1.2.4"
}
},
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
"call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
@@ -17696,12 +18807,20 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
- "dev": true,
"requires": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
}
},
+ "call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "requires": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ }
+ },
"callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -17971,12 +19090,51 @@
}
}
},
+ "console-table-printer": {
+ "version": "2.14.6",
+ "resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.14.6.tgz",
+ "integrity": "sha512-MCBl5HNVaFuuHW6FGbL/4fB7N/ormCy+tQ+sxTrF6QtSbSNETvPuOVbkJBhzDgYhvjWGrTma4eYJa37ZuoQsPw==",
+ "peer": true,
+ "requires": {
+ "simple-wcswidth": "^1.0.1"
+ }
+ },
+ "content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ },
+ "dependencies": {
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ }
+ }
+ },
+ "content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
+ },
"convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
"dev": true
},
+ "cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="
+ },
+ "cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="
+ },
"copyfiles": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz",
@@ -18063,6 +19221,15 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
+ "cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "requires": {
+ "object-assign": "^4",
+ "vary": "^1"
+ }
+ },
"crc": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
@@ -18216,13 +19383,19 @@
}
},
"debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+ "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"requires": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
}
},
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "peer": true
+ },
"decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
@@ -18329,6 +19502,11 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
"detect-newline": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@@ -18495,7 +19673,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
- "dev": true,
"requires": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
@@ -18507,6 +19684,11 @@
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
"ejs": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
@@ -18740,6 +19922,11 @@
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
+ "encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="
+ },
"encoding-sniffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
@@ -18849,14 +20036,12 @@
"es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
- "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
- "dev": true
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="
},
"es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
},
"es-get-iterator": {
"version": "1.1.3",
@@ -18912,7 +20097,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
- "dev": true,
"requires": {
"es-errors": "^1.3.0"
}
@@ -18996,6 +20180,11 @@
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
"integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA=="
},
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
"escape-string-regexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
@@ -19423,6 +20612,30 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+ },
+ "eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "peer": true
+ },
+ "eventsource": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz",
+ "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==",
+ "requires": {
+ "eventsource-parser": "^3.0.1"
+ }
+ },
+ "eventsource-parser": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz",
+ "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="
+ },
"execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -19467,6 +20680,67 @@
"jest-util": "^29.7.0"
}
},
+ "express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "requires": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="
+ },
+ "mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "requires": {
+ "mime-db": "^1.54.0"
+ }
+ }
+ }
+ },
+ "express-rate-limit": {
+ "version": "7.5.1",
+ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz",
+ "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==",
+ "requires": {}
+ },
+ "extended-eventsource": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/extended-eventsource/-/extended-eventsource-1.7.0.tgz",
+ "integrity": "sha512-s8rtvZuYcKBpzytHb5g95cHbZ1J99WeMnV18oKc5wKoxkHzlzpPc/bNAm7Da2Db0BDw0CAu1z3LpH+7UsyzIpw==",
+ "optional": true
+ },
"extract-zip": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
@@ -19489,8 +20763,7 @@
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-fifo": {
"version": "1.3.2",
@@ -19513,8 +20786,7 @@
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"fast-levenshtein": {
"version": "2.0.6",
@@ -19594,6 +20866,19 @@
"to-regex-range": "^5.0.1"
}
},
+ "finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "requires": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ }
+ },
"find-process": {
"version": "1.4.10",
"resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.10.tgz",
@@ -19677,6 +20962,16 @@
"mime-types": "^2.1.12"
}
},
+ "forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ },
+ "fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="
+ },
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -19809,7 +21104,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
- "dev": true,
"requires": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
@@ -19833,7 +21127,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
- "dev": true,
"requires": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
@@ -19973,8 +21266,7 @@
"gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
- "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
- "dev": true
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
},
"graceful-fs": {
"version": "4.2.11",
@@ -20039,8 +21331,7 @@
"has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
- "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
- "dev": true
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="
},
"has-tostringtag": {
"version": "1.0.2",
@@ -20136,6 +21427,25 @@
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
"dev": true
},
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "dependencies": {
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ }
+ }
+ },
"https-proxy-agent": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
@@ -20261,7 +21571,6 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
@@ -20343,6 +21652,11 @@
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="
},
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
"is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@@ -20557,6 +21871,11 @@
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
"dev": true
},
+ "is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
+ },
"is-regex": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
@@ -21272,6 +22591,15 @@
}
}
},
+ "js-tiktoken": {
+ "version": "1.0.21",
+ "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz",
+ "integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==",
+ "peer": true,
+ "requires": {
+ "base64-js": "^1.5.1"
+ }
+ },
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -21309,8 +22637,7 @@
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -21371,6 +22698,21 @@
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
"dev": true
},
+ "langsmith": {
+ "version": "0.3.67",
+ "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.67.tgz",
+ "integrity": "sha512-l4y3RmJ9yWF5a29fLg3eWZQxn6Q6dxTOgLGgQHzPGZHF3NUynn+A+airYIe/Yt4rwjGbuVrABAPsXBkVu/Hi7g==",
+ "peer": true,
+ "requires": {
+ "@types/uuid": "^10.0.0",
+ "chalk": "^4.1.2",
+ "console-table-printer": "^2.12.1",
+ "p-queue": "^6.6.2",
+ "p-retry": "4",
+ "semver": "^7.6.3",
+ "uuid": "^10.0.0"
+ }
+ },
"language-subtag-registry": {
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
@@ -21573,8 +22915,17 @@
"math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
- "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
- "dev": true
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="
+ },
+ "media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="
+ },
+ "merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="
},
"merge-stream": {
"version": "2.0.0",
@@ -21716,9 +23067,15 @@
"dev": true
},
"ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "mustache": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+ "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+ "peer": true
},
"natural-compare": {
"version": "1.4.0",
@@ -21726,6 +23083,11 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
+ "negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="
+ },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@@ -21828,15 +23190,12 @@
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
- "dev": true
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-inspect": {
- "version": "1.13.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
- "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
- "dev": true,
- "peer": true
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="
},
"object-is": {
"version": "1.1.6",
@@ -21917,6 +23276,14 @@
"es-object-atoms": "^1.0.0"
}
},
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -21987,6 +23354,43 @@
}
}
},
+ "p-queue": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
+ "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
+ "peer": true,
+ "requires": {
+ "eventemitter3": "^4.0.4",
+ "p-timeout": "^3.2.0"
+ }
+ },
+ "p-retry": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
+ "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
+ "peer": true,
+ "requires": {
+ "@types/retry": "0.12.0",
+ "retry": "^0.13.1"
+ },
+ "dependencies": {
+ "retry": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+ "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
+ "peer": true
+ }
+ }
+ },
+ "p-timeout": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
+ "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
+ "peer": true,
+ "requires": {
+ "p-finally": "^1.0.0"
+ }
+ },
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@@ -22047,6 +23451,11 @@
"parse5": "^7.0.0"
}
},
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -22090,6 +23499,11 @@
}
}
},
+ "path-to-regexp": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="
+ },
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -22119,6 +23533,11 @@
"integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
"dev": true
},
+ "pkce-challenge": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
+ "integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="
+ },
"pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
@@ -22249,6 +23668,15 @@
"resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz",
"integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag=="
},
+ "proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -22261,8 +23689,7 @@
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
- "dev": true
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"pure-rand": {
"version": "6.1.0",
@@ -22270,6 +23697,14 @@
"integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
"dev": true
},
+ "qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "requires": {
+ "side-channel": "^1.1.0"
+ }
+ },
"queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -22323,6 +23758,32 @@
}
}
},
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz",
+ "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.7.0",
+ "unpipe": "1.0.0"
+ },
+ "dependencies": {
+ "iconv-lite": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
+ "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ }
+ }
+ }
+ },
"rcedit": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rcedit/-/rcedit-4.0.1.tgz",
@@ -22640,6 +24101,18 @@
"sprintf-js": "^1.1.2"
}
},
+ "router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "requires": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ }
+ },
"rsvp": {
"version": "4.8.5",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
@@ -22696,8 +24169,7 @@
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sanitize-filename": {
"version": "1.6.3",
@@ -22715,9 +24187,9 @@
"dev": true
},
"semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w=="
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="
},
"semver-compare": {
"version": "1.0.0",
@@ -22726,6 +24198,39 @@
"dev": true,
"optional": true
},
+ "send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "requires": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="
+ },
+ "mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "requires": {
+ "mime-db": "^1.54.0"
+ }
+ }
+ }
+ },
"serialize-error": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
@@ -22736,6 +24241,17 @@
"type-fest": "^0.13.1"
}
},
+ "serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "requires": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ }
+ },
"set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -22764,6 +24280,11 @@
"has-property-descriptors": "^1.0.2"
}
},
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -22878,16 +24399,47 @@
}
},
"side-channel": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
- "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
- "dev": true,
- "peer": true,
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"requires": {
- "call-bind": "^1.0.7",
"es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "object-inspect": "^1.13.1"
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ }
+ },
+ "side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "requires": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ }
+ },
+ "side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "requires": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ }
+ },
+ "side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "requires": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
}
},
"signal-exit": {
@@ -22904,6 +24456,12 @@
"semver": "^7.5.3"
}
},
+ "simple-wcswidth": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.1.2.tgz",
+ "integrity": "sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==",
+ "peer": true
+ },
"sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -22981,6 +24539,11 @@
"integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==",
"dev": true
},
+ "statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="
+ },
"stop-iteration-iterator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
@@ -23380,6 +24943,11 @@
"streamx": "^2.12.5"
}
},
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
"truncate-utf8-bytes": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
@@ -23450,6 +25018,31 @@
"dev": true,
"optional": true
},
+ "type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "requires": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "dependencies": {
+ "mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="
+ },
+ "mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "requires": {
+ "mime-db": "^1.54.0"
+ }
+ }
+ }
+ },
"typed-array-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
@@ -23581,6 +25174,11 @@
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true
},
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+ },
"untildify": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
@@ -23600,7 +25198,6 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
"requires": {
"punycode": "^2.1.0"
}
@@ -23616,6 +25213,12 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
+ "uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+ "peer": true
+ },
"v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
@@ -23633,6 +25236,11 @@
"integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==",
"dev": true
},
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
+ },
"verror": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz",
@@ -24019,6 +25627,17 @@
}
}
}
+ },
+ "zod": {
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="
+ },
+ "zod-to-json-schema": {
+ "version": "3.24.6",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz",
+ "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==",
+ "requires": {}
}
}
}
diff --git a/app/package.json b/app/package.json
index 084aba83d76..c510f5eafac 100644
--- a/app/package.json
+++ b/app/package.json
@@ -118,6 +118,7 @@
"files": [
"electron/main.js",
"electron/preload.js",
+ "electron/mcp-client.js",
"electron/i18next.config.js",
"electron/i18n-helper.js",
"electron/windowSize.js",
@@ -171,6 +172,7 @@
"typescript": "5.5.4"
},
"dependencies": {
+ "@langchain/mcp-adapters": "^0.6.0",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"dotenv": "^16.4.5",
From e389f3d9cf67e5c2d6f3391d1be39942a219b597 Mon Sep 17 00:00:00 2001
From: Ashu Ghildiyal
Date: Mon, 8 Sep 2025 22:54:15 +0530
Subject: [PATCH 02/72] app: Add mcp client
---
app/electron/main.ts | 6 +
app/electron/mcp-client.ts | 376 +++++++++++++++++++++++++++++++++++++
app/electron/preload.ts | 11 ++
3 files changed, 393 insertions(+)
create mode 100644 app/electron/mcp-client.ts
diff --git a/app/electron/main.ts b/app/electron/main.ts
index 68beaba0e01..126b14b8519 100644
--- a/app/electron/main.ts
+++ b/app/electron/main.ts
@@ -40,6 +40,7 @@ import url from 'url';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import i18n from './i18next.config';
+import ElectronMCPClient from './mcp-client';
import {
addToPath,
ArtifactHubHeadlampPkg,
@@ -131,6 +132,7 @@ const shouldCheckForUpdates = process.env.HEADLAMP_CHECK_FOR_UPDATES !== 'false'
// make it global so that it doesn't get garbage collected
let mainWindow: BrowserWindow | null;
+let mcpClient: ElectronMCPClient;
/**
* `Action` is an interface for an action to be performed by the plugin manager.
@@ -1463,6 +1465,10 @@ function startElecron() {
if (mainWindow) {
mainWindow.removeAllListeners('close');
}
+ // Cleanup MCP client
+ if (mcpClient) {
+ mcpClient.cleanup().catch(console.error);
+ }
});
}
diff --git a/app/electron/mcp-client.ts b/app/electron/mcp-client.ts
new file mode 100644
index 00000000000..01d7c16b21e
--- /dev/null
+++ b/app/electron/mcp-client.ts
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2025 The Kubernetes Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { MultiServerMCPClient } from '@langchain/mcp-adapters';
+import { app, ipcMain } from 'electron';
+import * as fs from 'fs';
+import * as os from 'os';
+import * as path from 'path';
+
+interface MCPServer {
+ name: string;
+ command: string;
+ args: string[];
+ enabled: boolean;
+}
+
+interface MCPConfig {
+ enabled: boolean;
+ servers: MCPServer[];
+}
+
+class ElectronMCPClient {
+ private client: MultiServerMCPClient | null = null;
+ private tools: any[] = [];
+ private isInitialized = false;
+ private initializationPromise: Promise | null = null;
+
+ constructor() {
+ this.setupIpcHandlers();
+ }
+
+ /**
+ * Load MCP server configuration from settings
+ */
+ private loadMCPConfig(): MCPConfig | null {
+ try {
+ const settingsPath = path.join(app.getPath('userData'), 'settings.json');
+ if (!fs.existsSync(settingsPath)) {
+ return null;
+ }
+
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
+ return settings.mcpConfig || null;
+ } catch (error) {
+ console.error('Error loading MCP config:', error);
+ return null;
+ }
+ }
+
+ /**
+ * Expand environment variables and resolve paths in arguments
+ */
+ private expandArgs(args: string[]): string[] {
+ return args.map(arg => {
+ // Replace Windows environment variables like %USERPROFILE%
+ let expandedArg = arg;
+
+ // Handle %USERPROFILE%
+ if (expandedArg.includes('%USERPROFILE%')) {
+ expandedArg = expandedArg.replace(/%USERPROFILE%/g, os.homedir());
+ }
+
+ // Handle other common Windows environment variables
+ if (expandedArg.includes('%APPDATA%')) {
+ expandedArg = expandedArg.replace(/%APPDATA%/g, process.env.APPDATA || '');
+ }
+
+ if (expandedArg.includes('%LOCALAPPDATA%')) {
+ expandedArg = expandedArg.replace(/%LOCALAPPDATA%/g, process.env.LOCALAPPDATA || '');
+ }
+
+ // Convert Windows backslashes to forward slashes for Docker
+ if (process.platform === 'win32' && expandedArg.includes('\\')) {
+ expandedArg = expandedArg.replace(/\\/g, '/');
+ }
+
+ // Handle Docker volume mount format and ensure proper Windows path format
+ if (expandedArg.includes('type=bind,src=')) {
+ const match = expandedArg.match(/type=bind,src=(.+?),dst=(.+)/);
+ if (match) {
+ let srcPath = match[1];
+ const dstPath = match[2];
+
+ // Resolve the source path
+ if (process.platform === 'win32') {
+ srcPath = path.resolve(srcPath);
+ // For Docker on Windows, we might need to convert C:\ to /c/ format
+ if (srcPath.match(/^[A-Za-z]:/)) {
+ srcPath =
+ '/' + srcPath.charAt(0).toLowerCase() + srcPath.slice(2).replace(/\\/g, '/');
+ }
+ }
+
+ expandedArg = `type=bind,src=${srcPath},dst=${dstPath}`;
+ }
+ }
+
+ return expandedArg;
+ });
+ }
+
+ private async initializeClient(): Promise {
+ if (this.isInitialized) {
+ return;
+ }
+
+ if (this.initializationPromise) {
+ return this.initializationPromise;
+ }
+
+ this.initializationPromise = this.doInitialize();
+ return this.initializationPromise;
+ }
+
+ private async doInitialize(): Promise {
+ try {
+ console.log('Initializing MCP client in Electron main process...');
+
+ // Load MCP configuration from settings
+ const mcpConfig = this.loadMCPConfig();
+
+ if (
+ !mcpConfig ||
+ !mcpConfig.enabled ||
+ !mcpConfig.servers ||
+ mcpConfig.servers.length === 0
+ ) {
+ console.log('MCP is disabled or no servers configured');
+ this.isInitialized = true;
+ return;
+ }
+
+ // Build MCP servers configuration from settings
+ const mcpServers: any = {};
+
+ for (const server of mcpConfig.servers) {
+ if (!server.enabled || !server.name || !server.command) {
+ continue;
+ }
+
+ // Expand environment variables and resolve paths in arguments
+ const expandedArgs = this.expandArgs(server.args || []);
+ console.log(`Expanded args for ${server.name}:`, expandedArgs);
+
+ mcpServers[server.name] = {
+ transport: 'stdio',
+ command: server.command,
+ args: expandedArgs,
+ restart: {
+ enabled: true,
+ maxAttempts: 3,
+ delayMs: 2000,
+ },
+ };
+ }
+
+ // If no enabled servers, skip initialization
+ if (Object.keys(mcpServers).length === 0) {
+ console.log('No enabled MCP servers found');
+ this.isInitialized = true;
+ return;
+ }
+
+ console.log('Initializing MCP client with servers:', Object.keys(mcpServers));
+
+ this.client = new MultiServerMCPClient({
+ throwOnLoadError: false, // Don't throw on load error to allow partial initialization
+ prefixToolNameWithServerName: true, // Prefix to avoid name conflicts
+ additionalToolNamePrefix: '',
+ useStandardContentBlocks: true,
+ mcpServers,
+ });
+
+ // Get and cache the tools
+ this.tools = await this.client.getTools();
+ this.isInitialized = true;
+ console.log('MCP client initialized successfully with', this.tools.length, 'tools');
+ } catch (error) {
+ console.error('Failed to initialize MCP client:', error);
+ this.client = null;
+ this.isInitialized = false;
+ this.initializationPromise = null;
+ throw error;
+ }
+ }
+
+ private setupIpcHandlers(): void {
+ // Handle MCP tools request
+ ipcMain.handle('mcp-get-tools', async () => {
+ try {
+ await this.initializeClient();
+
+ if (!this.client || this.tools.length === 0) {
+ return { success: true, tools: [] };
+ }
+
+ // Convert LangChain tools to our format
+ const toolsInfo = this.tools.map(tool => ({
+ name: tool.name,
+ description: tool.description,
+ inputSchema: tool.schema,
+ }));
+
+ console.log('MCP tools retrieved:', toolsInfo.length, 'tools');
+ return { success: true, tools: toolsInfo };
+ } catch (error) {
+ console.error('Error getting MCP tools:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ tools: [],
+ };
+ }
+ });
+
+ // Handle MCP tool execution
+ ipcMain.handle('mcp-execute-tool', async (event, { toolName, args, toolCallId }) => {
+ try {
+ await this.initializeClient();
+
+ if (!this.client || this.tools.length === 0) {
+ throw new Error('MCP client not initialized or no tools available');
+ }
+
+ // Find the tool by name
+ const tool = this.tools.find(t => t.name === toolName);
+ if (!tool) {
+ throw new Error(`Tool ${toolName} not found`);
+ }
+
+ // Execute the tool directly using LangChain's invoke method
+ const result = await tool.invoke(args);
+ console.log(`MCP tool ${toolName} executed successfully`);
+
+ return {
+ success: true,
+ result,
+ toolCallId,
+ };
+ } catch (error) {
+ console.error(`Error executing MCP tool ${toolName}:`, error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ toolCallId,
+ };
+ }
+ });
+
+ // Handle MCP client status check
+ ipcMain.handle('mcp-get-status', async () => {
+ return {
+ isInitialized: this.isInitialized,
+ hasClient: this.client !== null,
+ };
+ });
+
+ // Handle MCP client reset/restart
+ ipcMain.handle('mcp-reset-client', async () => {
+ try {
+ console.log('Resetting MCP client...');
+
+ if (this.client) {
+ // If the client has a close/dispose method, call it
+ if (typeof (this.client as any).close === 'function') {
+ await (this.client as any).close();
+ }
+ }
+
+ this.client = null;
+ this.isInitialized = false;
+ this.initializationPromise = null;
+
+ // Re-initialize
+ await this.initializeClient();
+
+ return { success: true };
+ } catch (error) {
+ console.error('Error resetting MCP client:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ };
+ }
+ });
+
+ // Handle MCP configuration updates
+ ipcMain.handle('mcp-update-config', async (event, mcpConfig: MCPConfig) => {
+ try {
+ console.log('Updating MCP configuration...');
+
+ // Save to settings file
+ const settingsPath = path.join(app.getPath('userData'), 'settings.json');
+ let settings: any = {};
+
+ if (fs.existsSync(settingsPath)) {
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
+ }
+
+ settings.mcpConfig = mcpConfig;
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
+
+ // Reset and reinitialize client with new config
+ if (this.client) {
+ if (typeof (this.client as any).close === 'function') {
+ await (this.client as any).close();
+ }
+ }
+ this.client = null;
+ this.isInitialized = false;
+ this.initializationPromise = null;
+
+ // Re-initialize with new config
+ await this.initializeClient();
+
+ return { success: true };
+ } catch (error) {
+ console.error('Error updating MCP configuration:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ };
+ }
+ });
+
+ // Handle getting current MCP configuration
+ ipcMain.handle('mcp-get-config', async () => {
+ try {
+ const mcpConfig = this.loadMCPConfig();
+ return {
+ success: true,
+ config: mcpConfig || { enabled: false, servers: [] },
+ };
+ } catch (error) {
+ console.error('Error getting MCP configuration:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ config: { enabled: false, servers: [] },
+ };
+ }
+ });
+ }
+
+ /**
+ * Cleanup method to be called when the app is shutting down
+ */
+ async cleanup(): Promise {
+ if (this.client) {
+ try {
+ await this.client.close();
+ } catch (error) {
+ console.error('Error cleaning up MCP client:', error);
+ }
+ }
+ this.client = null;
+ this.tools = [];
+ this.isInitialized = false;
+ this.initializationPromise = null;
+ }
+}
+
+export default ElectronMCPClient;
diff --git a/app/electron/preload.ts b/app/electron/preload.ts
index e65c2c13404..072513a1b11 100644
--- a/app/electron/preload.ts
+++ b/app/electron/preload.ts
@@ -57,4 +57,15 @@ contextBridge.exposeInMainWorld('desktopApi', {
removeListener: (channel: string, func: (...args: unknown[]) => void) => {
ipcRenderer.removeListener(channel, func);
},
+
+ // MCP client APIs
+ mcp: {
+ getTools: () => ipcRenderer.invoke('mcp-get-tools'),
+ executeTool: (toolName: string, args: Record, toolCallId?: string) =>
+ ipcRenderer.invoke('mcp-execute-tool', { toolName, args, toolCallId }),
+ getStatus: () => ipcRenderer.invoke('mcp-get-status'),
+ resetClient: () => ipcRenderer.invoke('mcp-reset-client'),
+ getConfig: () => ipcRenderer.invoke('mcp-get-config'),
+ updateConfig: (config: any) => ipcRenderer.invoke('mcp-update-config', config),
+ },
});
From d986808dbaf9d959a48999ebed0c8969c2efca52 Mon Sep 17 00:00:00 2001
From: ashu8912
Date: Sun, 21 Sep 2025 20:36:21 +0530
Subject: [PATCH 03/72] app: Allo mcp server to accept env vars
---
app/electron/mcp-client.ts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/app/electron/mcp-client.ts b/app/electron/mcp-client.ts
index 01d7c16b21e..bc76608f616 100644
--- a/app/electron/mcp-client.ts
+++ b/app/electron/mcp-client.ts
@@ -25,6 +25,7 @@ interface MCPServer {
command: string;
args: string[];
enabled: boolean;
+ env?: Record;
}
interface MCPConfig {
@@ -155,10 +156,14 @@ class ElectronMCPClient {
const expandedArgs = this.expandArgs(server.args || []);
console.log(`Expanded args for ${server.name}:`, expandedArgs);
+ // Prepare environment variables
+ const serverEnv = server.env ? { ...process.env, ...server.env } : process.env;
+
mcpServers[server.name] = {
transport: 'stdio',
command: server.command,
args: expandedArgs,
+ env: serverEnv,
restart: {
enabled: true,
maxAttempts: 3,
@@ -228,6 +233,7 @@ class ElectronMCPClient {
// Handle MCP tool execution
ipcMain.handle('mcp-execute-tool', async (event, { toolName, args, toolCallId }) => {
+ console.log('args in mcp-execute-tool:', args);
try {
await this.initializeClient();
From 2c03c6ccca735e8678f5020df1b52f123b67e1a5 Mon Sep 17 00:00:00 2001
From: ashu8912
Date: Tue, 23 Sep 2025 13:05:05 +0530
Subject: [PATCH 04/72] ai-plugin: fix mcp client initialization
---
app/electron/main.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/electron/main.ts b/app/electron/main.ts
index 126b14b8519..50935408a08 100644
--- a/app/electron/main.ts
+++ b/app/electron/main.ts
@@ -1133,7 +1133,7 @@ function adjustZoom(delta: number) {
function startElecron() {
console.info('App starting...');
-
+ mcpClient = new ElectronMCPClient();
let appVersion: string;
if (isDev && process.env.HEADLAMP_APP_VERSION) {
appVersion = process.env.HEADLAMP_APP_VERSION;
From fe6db0f30230974603b17642dabf5dfb4ea56a21 Mon Sep 17 00:00:00 2001
From: ashu8912
Date: Mon, 13 Oct 2025 09:57:09 +0530
Subject: [PATCH 05/72] app: Add confirmation and mcp config update api
---
app/electron/main.ts | 7 +
app/electron/mcp-client.ts | 428 +++++++++++++++++++++++++++++++++++--
app/electron/mcp-config.ts | 222 +++++++++++++++++++
app/electron/preload.ts | 6 +
4 files changed, 649 insertions(+), 14 deletions(-)
create mode 100644 app/electron/mcp-config.ts
diff --git a/app/electron/main.ts b/app/electron/main.ts
index 50935408a08..f7ab6d32561 100644
--- a/app/electron/main.ts
+++ b/app/electron/main.ts
@@ -1249,6 +1249,9 @@ function startElecron() {
},
});
+ // Set the main window reference in the MCP client for dialogs
+ mcpClient.setMainWindow(mainWindow);
+
// Load the frontend
mainWindow.loadURL(startUrl);
@@ -1469,6 +1472,10 @@ function startElecron() {
if (mcpClient) {
mcpClient.cleanup().catch(console.error);
}
+ // Cleanup MCP client
+ if (mcpClient) {
+ mcpClient.cleanup().catch(console.error);
+ }
});
}
diff --git a/app/electron/mcp-client.ts b/app/electron/mcp-client.ts
index bc76608f616..74147a70c4c 100644
--- a/app/electron/mcp-client.ts
+++ b/app/electron/mcp-client.ts
@@ -15,10 +15,11 @@
*/
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
-import { app, ipcMain } from 'electron';
+import { app, BrowserWindow, dialog, ipcMain } from 'electron';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
+import { MCPConfigManager } from './mcp-config';
interface MCPServer {
name: string;
@@ -38,11 +39,286 @@ class ElectronMCPClient {
private tools: any[] = [];
private isInitialized = false;
private initializationPromise: Promise | null = null;
+ private configManager: MCPConfigManager;
+ private mainWindow: BrowserWindow | null = null;
- constructor() {
+ constructor(mainWindow: BrowserWindow | null = null) {
+ this.mainWindow = mainWindow;
+ this.configManager = new MCPConfigManager();
this.setupIpcHandlers();
}
+ /**
+ * Set the main window reference for dialogs
+ */
+ setMainWindow(mainWindow: BrowserWindow | null): void {
+ this.mainWindow = mainWindow;
+ }
+
+ /**
+ * Initialize tools configuration for all available tools
+ */
+ private initializeToolsConfiguration(): void {
+ if (!this.tools || this.tools.length === 0) {
+ return;
+ }
+
+ // Group tools by server name (assuming tool names are prefixed with server name)
+ const toolsByServer: Record = {};
+
+ for (const tool of this.tools) {
+ // Extract server name from tool name (format: "serverName__toolName")
+ const toolName = tool.name;
+ const parts = toolName.split('__');
+
+ if (parts.length >= 2) {
+ const serverName = parts[0];
+ const actualToolName = parts.slice(1).join('__');
+
+ if (!toolsByServer[serverName]) {
+ toolsByServer[serverName] = [];
+ }
+ toolsByServer[serverName].push(actualToolName);
+ } else {
+ // Fallback for tools without server prefix
+ if (!toolsByServer['default']) {
+ toolsByServer['default'] = [];
+ }
+ toolsByServer['default'].push(toolName);
+ }
+ }
+
+ // Initialize configuration for each server's tools
+ for (const [serverName, toolNames] of Object.entries(toolsByServer)) {
+ this.configManager.initializeToolsConfig(serverName, toolNames);
+ }
+ }
+
+ /**
+ * Show user confirmation dialog for MCP operations
+ */
+ private async showConfirmationDialog(
+ title: string,
+ message: string,
+ operation: string
+ ): Promise {
+ if (!this.mainWindow) {
+ console.warn('No main window available for confirmation dialog, allowing operation');
+ return true;
+ }
+
+ const result = await dialog.showMessageBox(this.mainWindow, {
+ type: 'question',
+ buttons: ['Allow', 'Cancel'],
+ defaultId: 1,
+ title,
+ message,
+ detail: `Operation: ${operation}\n\nDo you want to allow this MCP operation?`,
+ });
+
+ return result.response === 0; // 0 is "Allow"
+ }
+
+ /**
+ * Show detailed confirmation dialog for tools configuration changes
+ */
+ private async showToolsConfigConfirmationDialog(newConfig: any): Promise {
+ if (!this.mainWindow) {
+ console.warn('No main window available for confirmation dialog, allowing operation');
+ return true;
+ }
+
+ const currentConfig = this.configManager.getConfig();
+ const changes = this.compareToolsConfigs(currentConfig, newConfig);
+
+ if (changes.length === 0) {
+ return true; // No changes, allow operation
+ }
+
+ const changesText = changes.join('\n');
+
+ const result = await dialog.showMessageBox(this.mainWindow, {
+ type: 'question',
+ buttons: ['Apply Changes', 'Cancel'],
+ defaultId: 1,
+ title: 'MCP Tools Configuration Changes',
+ message: 'The following changes will be applied to your MCP tools configuration:',
+ detail: changesText + '\n\nDo you want to apply these changes?',
+ });
+
+ return result.response === 0; // 0 is "Apply Changes"
+ }
+
+ /**
+ * Compare two tools configurations and return a list of changes
+ */
+ private compareToolsConfigs(currentConfig: any, newConfig: any): string[] {
+ const changes: string[] = [];
+
+ // Get all server names from both configs
+ const allServers = new Set([
+ ...Object.keys(currentConfig || {}),
+ ...Object.keys(newConfig || {}),
+ ]);
+
+ for (const serverName of allServers) {
+ const currentServerConfig = currentConfig[serverName] || {};
+ const newServerConfig = newConfig[serverName] || {};
+
+ // Get all tool names from both configs
+ const allTools = new Set([
+ ...Object.keys(currentServerConfig),
+ ...Object.keys(newServerConfig),
+ ]);
+
+ for (const toolName of allTools) {
+ const currentTool = currentServerConfig[toolName];
+ const newTool = newServerConfig[toolName];
+
+ if (!currentTool && newTool) {
+ // New tool added
+ const status = newTool.enabled ? 'enabled' : 'disabled';
+ changes.push(`+ Add tool "${toolName}" on server "${serverName}" (${status})`);
+ } else if (currentTool && !newTool) {
+ // Tool removed
+ changes.push(`- Remove tool "${toolName}" from server "${serverName}"`);
+ } else if (currentTool && newTool) {
+ // Tool modified
+ if (currentTool.enabled !== newTool.enabled) {
+ const status = newTool.enabled ? 'enabled' : 'disabled';
+ changes.push(`~ Change tool "${toolName}" on server "${serverName}" to ${status}`);
+ }
+ }
+ }
+ }
+
+ return changes;
+ }
+
+ /**
+ * Show detailed configuration change confirmation dialog
+ */
+ private async showConfigChangeDialog(
+ currentConfig: MCPConfig | null,
+ newConfig: MCPConfig
+ ): Promise {
+ console.log('Current MCP Config:', currentConfig);
+ console.log('New MCP Config:', newConfig);
+ if (!this.mainWindow) {
+ console.warn('No main window available for confirmation dialog, allowing operation');
+ return true;
+ }
+
+ const changes = this.analyzeConfigChanges(currentConfig, newConfig);
+
+ const result = await dialog.showMessageBox(this.mainWindow, {
+ type: 'question',
+ buttons: ['Apply Changes', 'Cancel'],
+ defaultId: 1,
+ title: 'MCP Configuration Changes',
+ message: 'The application wants to update the MCP configuration.',
+ detail:
+ changes.length > 0
+ ? `The following changes will be applied:\n\n${changes.join(
+ '\n'
+ )}\n\nDo you want to apply these changes?`
+ : 'No changes detected in the configuration.\n\nDo you want to proceed anyway?',
+ });
+
+ return result.response === 0; // 0 is "Apply Changes"
+ }
+
+ /**
+ * Analyze differences between current and new configuration
+ */
+ private analyzeConfigChanges(currentConfig: MCPConfig | null, newConfig: MCPConfig): string[] {
+ const changes: string[] = [];
+
+ // Check if MCP is being enabled/disabled
+ const currentEnabled = currentConfig?.enabled ?? false;
+ const newEnabled = newConfig.enabled ?? false;
+
+ if (currentEnabled !== newEnabled) {
+ changes.push(`• MCP will be ${newEnabled ? 'ENABLED' : 'DISABLED'}`);
+ }
+
+ // Get current and new server lists
+ const currentServers = currentConfig?.servers ?? [];
+ const newServers = newConfig.servers ?? [];
+
+ // Check for added servers
+ const currentServerNames = new Set(currentServers.map(s => s.name));
+ const newServerNames = new Set(newServers.map(s => s.name));
+
+ for (const server of newServers) {
+ if (!currentServerNames.has(server.name)) {
+ changes.push(`• ADD server: "${server.name}" (${server.command})`);
+ }
+ }
+
+ // Check for removed servers
+ for (const server of currentServers) {
+ if (!newServerNames.has(server.name)) {
+ changes.push(`• REMOVE server: "${server.name}"`);
+ }
+ }
+
+ // Check for modified servers
+ for (const newServer of newServers) {
+ const currentServer = currentServers.find(s => s.name === newServer.name);
+ if (currentServer) {
+ const serverChanges: string[] = [];
+
+ // Check enabled status
+ if (currentServer.enabled !== newServer.enabled) {
+ serverChanges.push(`${newServer.enabled ? 'enable' : 'disable'}`);
+ }
+
+ // Check command
+ if (currentServer.command !== newServer.command) {
+ serverChanges.push(`change command: "${currentServer.command}" → "${newServer.command}"`);
+ }
+
+ // Check arguments
+ const currentArgs = JSON.stringify(currentServer.args || []);
+ const newArgs = JSON.stringify(newServer.args || []);
+ if (currentArgs !== newArgs) {
+ serverChanges.push(`change arguments: ${currentArgs} → ${newArgs}`);
+ }
+
+ // Check environment variables
+ const currentEnv = JSON.stringify(currentServer.env || {});
+ const newEnv = JSON.stringify(newServer.env || {});
+ if (currentEnv !== newEnv) {
+ serverChanges.push(`change environment variables`);
+ }
+
+ if (serverChanges.length > 0) {
+ changes.push(`• MODIFY server "${newServer.name}": ${serverChanges.join(', ')}`);
+ }
+ }
+ }
+
+ return changes;
+ }
+
+ /**
+ * Parse tool name to extract server and tool components
+ */
+ private parseToolName(fullToolName: string): { serverName: string; toolName: string } {
+ const parts = fullToolName.split('__');
+ if (parts.length >= 2) {
+ return {
+ serverName: parts[0],
+ toolName: parts.slice(1).join('__'),
+ };
+ }
+ return {
+ serverName: 'default',
+ toolName: fullToolName,
+ };
+ }
+
/**
* Load MCP server configuration from settings
*/
@@ -191,6 +467,10 @@ class ElectronMCPClient {
// Get and cache the tools
this.tools = await this.client.getTools();
+
+ // Initialize configuration for available tools
+ this.initializeToolsConfiguration();
+
this.isInitialized = true;
console.log('MCP client initialized successfully with', this.tools.length, 'tools');
} catch (error) {
@@ -212,15 +492,20 @@ class ElectronMCPClient {
return { success: true, tools: [] };
}
- // Convert LangChain tools to our format
- const toolsInfo = this.tools.map(tool => ({
- name: tool.name,
- description: tool.description,
- inputSchema: tool.schema,
- }));
-
- console.log('MCP tools retrieved:', toolsInfo.length, 'tools');
- return { success: true, tools: toolsInfo };
+ // Filter tools based on configuration and convert to our format
+ const enabledToolsInfo = this.tools
+ .filter(tool => {
+ const { serverName, toolName } = this.parseToolName(tool.name);
+ return this.configManager.isToolEnabled(serverName, toolName);
+ })
+ .map(tool => ({
+ name: tool.name,
+ description: tool.description,
+ inputSchema: tool.schema,
+ }));
+
+ console.log('MCP tools retrieved:', enabledToolsInfo.length, 'enabled tools');
+ return { success: true, tools: enabledToolsInfo };
} catch (error) {
console.error('Error getting MCP tools:', error);
return {
@@ -241,16 +526,29 @@ class ElectronMCPClient {
throw new Error('MCP client not initialized or no tools available');
}
+ // Parse tool name
+ const { serverName, toolName: actualToolName } = this.parseToolName(toolName);
+
+ // Check if tool is enabled
+ if (!this.configManager.isToolEnabled(serverName, actualToolName)) {
+ throw new Error(`Tool ${toolName} is disabled`);
+ }
+
// Find the tool by name
const tool = this.tools.find(t => t.name === toolName);
if (!tool) {
throw new Error(`Tool ${toolName} not found`);
}
+ console.log(`Executing MCP tool: ${toolName} with args:`, args);
+
// Execute the tool directly using LangChain's invoke method
const result = await tool.invoke(args);
console.log(`MCP tool ${toolName} executed successfully`);
+ // Record tool usage
+ this.configManager.recordToolUsage(serverName, actualToolName);
+
return {
success: true,
result,
@@ -274,9 +572,23 @@ class ElectronMCPClient {
};
});
- // Handle MCP client reset/restart
+ // Handle MCP client reset/restart with user confirmation
ipcMain.handle('mcp-reset-client', async () => {
try {
+ // Show confirmation dialog
+ const userConfirmed = await this.showConfirmationDialog(
+ 'MCP Client Reset',
+ 'The application wants to reset the MCP client. This will restart all MCP server connections.',
+ 'Reset MCP client'
+ );
+
+ if (!userConfirmed) {
+ return {
+ success: false,
+ error: 'User cancelled the operation',
+ };
+ }
+
console.log('Resetting MCP client...');
if (this.client) {
@@ -303,10 +615,23 @@ class ElectronMCPClient {
}
});
- // Handle MCP configuration updates
+ // Handle MCP configuration updates with detailed user confirmation
ipcMain.handle('mcp-update-config', async (event, mcpConfig: MCPConfig) => {
try {
- console.log('Updating MCP configuration...');
+ // Get current configuration for comparison
+ const currentConfig = this.loadMCPConfig();
+ console.log('Requested MCP configuration update:', mcpConfig);
+ // Show detailed confirmation dialog with changes
+ const userConfirmed = await this.showConfigChangeDialog(currentConfig, mcpConfig);
+
+ if (!userConfirmed) {
+ return {
+ success: false,
+ error: 'User cancelled the configuration update',
+ };
+ }
+
+ console.log('Updating MCP configuration with user confirmation...');
// Save to settings file
const settingsPath = path.join(app.getPath('userData'), 'settings.json');
@@ -332,6 +657,7 @@ class ElectronMCPClient {
// Re-initialize with new config
await this.initializeClient();
+ console.log('MCP configuration updated successfully');
return { success: true };
} catch (error) {
console.error('Error updating MCP configuration:', error);
@@ -359,6 +685,80 @@ class ElectronMCPClient {
};
}
});
+
+ // Handle getting MCP tools configuration
+ ipcMain.handle('mcp-get-tools-config', async () => {
+ try {
+ const toolsConfig = this.configManager.getConfig();
+ return {
+ success: true,
+ config: toolsConfig,
+ };
+ } catch (error) {
+ console.error('Error getting MCP tools configuration:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ config: {},
+ };
+ }
+ });
+
+ // Handle updating MCP tools configuration with user confirmation
+ ipcMain.handle('mcp-update-tools-config', async (event, toolsConfig: any) => {
+ try {
+ // Show confirmation dialog with detailed changes
+ const userConfirmed = await this.showToolsConfigConfirmationDialog(toolsConfig);
+
+ if (!userConfirmed) {
+ return {
+ success: false,
+ error: 'User cancelled the operation',
+ };
+ }
+
+ this.configManager.setConfig(toolsConfig);
+ return { success: true };
+ } catch (error) {
+ console.error('Error updating MCP tools configuration:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ };
+ }
+ });
+
+ // Handle enabling/disabling specific tools
+ ipcMain.handle('mcp-set-tool-enabled', async (event, { serverName, toolName, enabled }) => {
+ try {
+ this.configManager.setToolEnabled(serverName, toolName, enabled);
+ return { success: true };
+ } catch (error) {
+ console.error('Error setting tool enabled state:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ };
+ }
+ });
+
+ // Handle getting tool statistics
+ ipcMain.handle('mcp-get-tool-stats', async (event, { serverName, toolName }) => {
+ try {
+ const stats = this.configManager.getToolStats(serverName, toolName);
+ return {
+ success: true,
+ stats,
+ };
+ } catch (error) {
+ console.error('Error getting tool statistics:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ stats: null,
+ };
+ }
+ });
}
/**
diff --git a/app/electron/mcp-config.ts b/app/electron/mcp-config.ts
new file mode 100644
index 00000000000..151a9ebeabb
--- /dev/null
+++ b/app/electron/mcp-config.ts
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2025 The Kubernetes Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { app } from 'electron';
+import * as fs from 'fs';
+import * as path from 'path';
+
+export interface MCPToolState {
+ enabled: boolean;
+ lastUsed?: Date;
+ usageCount?: number;
+}
+
+export interface MCPServerToolState {
+ [toolName: string]: MCPToolState;
+}
+
+export interface MCPToolsConfig {
+ [serverName: string]: MCPServerToolState;
+}
+
+export class MCPConfigManager {
+ private configPath: string;
+ private config: MCPToolsConfig = {};
+
+ constructor() {
+ this.configPath = path.join(app.getPath('userData'), 'headlamp-mcp-config.json');
+ this.loadConfig();
+ }
+
+ /**
+ * Load MCP tools configuration from file
+ */
+ private loadConfig(): void {
+ try {
+ if (fs.existsSync(this.configPath)) {
+ const configData = fs.readFileSync(this.configPath, 'utf-8');
+ this.config = JSON.parse(configData);
+ console.log('MCP tools configuration loaded successfully');
+ } else {
+ console.log('MCP tools configuration file does not exist, using default empty config');
+ this.config = {};
+ }
+ } catch (error) {
+ console.error('Error loading MCP tools configuration:', error);
+ this.config = {};
+ }
+ }
+
+ /**
+ * Save MCP tools configuration to file
+ */
+ private saveConfig(): void {
+ try {
+ fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf-8');
+ console.log('MCP tools configuration saved successfully');
+ } catch (error) {
+ console.error('Error saving MCP tools configuration:', error);
+ }
+ }
+
+ /**
+ * Get the enabled state of a specific tool
+ */
+ isToolEnabled(serverName: string, toolName: string): boolean {
+ const serverConfig = this.config[serverName];
+ if (!serverConfig) {
+ // Default to enabled for new tools
+ return true;
+ }
+
+ const toolState = serverConfig[toolName];
+ if (!toolState) {
+ // Default to enabled for new tools
+ return true;
+ }
+
+ return toolState.enabled;
+ }
+
+ /**
+ * Set the enabled state of a specific tool
+ */
+ setToolEnabled(serverName: string, toolName: string, enabled: boolean): void {
+ if (!this.config[serverName]) {
+ this.config[serverName] = {};
+ }
+
+ if (!this.config[serverName][toolName]) {
+ this.config[serverName][toolName] = {
+ enabled: true,
+ usageCount: 0,
+ };
+ }
+
+ this.config[serverName][toolName].enabled = enabled;
+ this.saveConfig();
+ }
+
+ /**
+ * Get all disabled tools for a server
+ */
+ getDisabledTools(serverName: string): string[] {
+ const serverConfig = this.config[serverName];
+ if (!serverConfig) {
+ return [];
+ }
+
+ return Object.entries(serverConfig)
+ .filter(([, toolState]) => !toolState.enabled)
+ .map(([toolName]) => toolName);
+ }
+
+ /**
+ * Get all enabled tools for a server
+ */
+ getEnabledTools(serverName: string): string[] {
+ const serverConfig = this.config[serverName];
+ if (!serverConfig) {
+ return [];
+ }
+
+ return Object.entries(serverConfig)
+ .filter(([, toolState]) => toolState.enabled)
+ .map(([toolName]) => toolName);
+ }
+
+ /**
+ * Update tool usage statistics
+ */
+ recordToolUsage(serverName: string, toolName: string): void {
+ if (!this.config[serverName]) {
+ this.config[serverName] = {};
+ }
+
+ if (!this.config[serverName][toolName]) {
+ this.config[serverName][toolName] = {
+ enabled: true,
+ usageCount: 0,
+ };
+ }
+
+ const toolState = this.config[serverName][toolName];
+ toolState.lastUsed = new Date();
+ toolState.usageCount = (toolState.usageCount || 0) + 1;
+ this.saveConfig();
+ }
+
+ /**
+ * Get the complete configuration
+ */
+ getConfig(): MCPToolsConfig {
+ return { ...this.config };
+ }
+
+ /**
+ * Set the complete configuration
+ */
+ setConfig(newConfig: MCPToolsConfig): void {
+ this.config = { ...newConfig };
+ this.saveConfig();
+ }
+
+ /**
+ * Reset configuration to empty state
+ */
+ resetConfig(): void {
+ this.config = {};
+ this.saveConfig();
+ }
+
+ /**
+ * Initialize default configuration for available tools
+ */
+ initializeToolsConfig(serverName: string, toolNames: string[]): void {
+ if (!this.config[serverName]) {
+ this.config[serverName] = {};
+ }
+
+ const serverConfig = this.config[serverName];
+ let hasChanges = false;
+
+ for (const toolName of toolNames) {
+ if (!serverConfig[toolName]) {
+ serverConfig[toolName] = {
+ enabled: true,
+ usageCount: 0,
+ };
+ hasChanges = true;
+ }
+ }
+
+ if (hasChanges) {
+ this.saveConfig();
+ }
+ }
+
+ /**
+ * Get tool statistics
+ */
+ getToolStats(serverName: string, toolName: string): MCPToolState | null {
+ const serverConfig = this.config[serverName];
+ if (!serverConfig || !serverConfig[toolName]) {
+ return null;
+ }
+
+ return { ...serverConfig[toolName] };
+ }
+}
diff --git a/app/electron/preload.ts b/app/electron/preload.ts
index 072513a1b11..f6207b4bbe3 100644
--- a/app/electron/preload.ts
+++ b/app/electron/preload.ts
@@ -67,5 +67,11 @@ contextBridge.exposeInMainWorld('desktopApi', {
resetClient: () => ipcRenderer.invoke('mcp-reset-client'),
getConfig: () => ipcRenderer.invoke('mcp-get-config'),
updateConfig: (config: any) => ipcRenderer.invoke('mcp-update-config', config),
+ getToolsConfig: () => ipcRenderer.invoke('mcp-get-tools-config'),
+ updateToolsConfig: (config: any) => ipcRenderer.invoke('mcp-update-tools-config', config),
+ setToolEnabled: (serverName: string, toolName: string, enabled: boolean) =>
+ ipcRenderer.invoke('mcp-set-tool-enabled', { serverName, toolName, enabled }),
+ getToolStats: (serverName: string, toolName: string) =>
+ ipcRenderer.invoke('mcp-get-tool-stats', { serverName, toolName }),
},
});
From 53f188fe8330aab675031b70120c8cffe751ef2f Mon Sep 17 00:00:00 2001
From: ashu8912
Date: Sat, 18 Oct 2025 14:24:13 +0530
Subject: [PATCH 06/72] app: Fix initialization and schema config
---
app/electron/main.ts | 6 +
app/electron/mcp-client.ts | 248 ++++++++++++++++++++++++++++---------
app/electron/mcp-config.ts | 54 ++++++--
app/electron/preload.ts | 1 -
4 files changed, 243 insertions(+), 66 deletions(-)
diff --git a/app/electron/main.ts b/app/electron/main.ts
index f7ab6d32561..79b67c16d3c 100644
--- a/app/electron/main.ts
+++ b/app/electron/main.ts
@@ -1134,6 +1134,12 @@ function adjustZoom(delta: number) {
function startElecron() {
console.info('App starting...');
mcpClient = new ElectronMCPClient();
+
+ // Initialize MCP client
+ mcpClient.initialize().catch(error => {
+ console.error('Failed to initialize MCP client on startup:', error);
+ });
+
let appVersion: string;
if (isDev && process.env.HEADLAMP_APP_VERSION) {
appVersion = process.env.HEADLAMP_APP_VERSION;
diff --git a/app/electron/mcp-client.ts b/app/electron/mcp-client.ts
index 74147a70c4c..fdbda60a362 100644
--- a/app/electron/mcp-client.ts
+++ b/app/electron/mcp-client.ts
@@ -60,17 +60,33 @@ class ElectronMCPClient {
*/
private initializeToolsConfiguration(): void {
if (!this.tools || this.tools.length === 0) {
+ console.log('No tools available for configuration initialization');
return;
}
- // Group tools by server name (assuming tool names are prefixed with server name)
- const toolsByServer: Record = {};
+ // Group tools by server name with their schemas
+ const toolsByServer: Record<
+ string,
+ Array<{
+ name: string;
+ inputSchema?: any;
+ description?: string;
+ }>
+ > = {};
for (const tool of this.tools) {
+ console.log('Initializing tools configuration...', tool);
// Extract server name from tool name (format: "serverName__toolName")
const toolName = tool.name;
const parts = toolName.split('__');
+ // Extract schema from the tool (LangChain tools use .schema property)
+ const toolSchema = (tool as any).schema || tool.inputSchema || null;
+ console.log('tool schema is ', toolSchema);
+ console.log(
+ `Processing tool: ${toolName}, has inputSchema: ${toolSchema}, description: "${tool.description}"`
+ );
+
if (parts.length >= 2) {
const serverName = parts[0];
const actualToolName = parts.slice(1).join('__');
@@ -78,19 +94,30 @@ class ElectronMCPClient {
if (!toolsByServer[serverName]) {
toolsByServer[serverName] = [];
}
- toolsByServer[serverName].push(actualToolName);
+ toolsByServer[serverName].push({
+ name: actualToolName,
+ inputSchema: toolSchema,
+ description: tool.description || '',
+ });
} else {
// Fallback for tools without server prefix
if (!toolsByServer['default']) {
toolsByServer['default'] = [];
}
- toolsByServer['default'].push(toolName);
+ toolsByServer['default'].push({
+ name: toolName,
+ inputSchema: toolSchema,
+ description: tool.description || '',
+ });
}
}
+ console.log('Tools grouped by server:', Object.keys(toolsByServer));
+
// Initialize configuration for each server's tools
- for (const [serverName, toolNames] of Object.entries(toolsByServer)) {
- this.configManager.initializeToolsConfig(serverName, toolNames);
+ for (const [serverName, toolsInfo] of Object.entries(toolsByServer)) {
+ console.log(`Initializing ${toolsInfo.length} tools for server: ${serverName}`);
+ this.configManager.initializeToolsConfig(serverName, toolsInfo);
}
}
@@ -129,31 +156,38 @@ class ElectronMCPClient {
}
const currentConfig = this.configManager.getConfig();
- const changes = this.compareToolsConfigs(currentConfig, newConfig);
+ const summary = this.createToolsConfigSummary(currentConfig, newConfig);
- if (changes.length === 0) {
+ if (summary.totalChanges === 0) {
return true; // No changes, allow operation
}
- const changesText = changes.join('\n');
-
const result = await dialog.showMessageBox(this.mainWindow, {
type: 'question',
buttons: ['Apply Changes', 'Cancel'],
defaultId: 1,
title: 'MCP Tools Configuration Changes',
- message: 'The following changes will be applied to your MCP tools configuration:',
- detail: changesText + '\n\nDo you want to apply these changes?',
+ message: `${summary.totalChanges} tool configuration change(s) will be applied:`,
+ detail: summary.summaryText + '\n\nDo you want to apply these changes?',
});
return result.response === 0; // 0 is "Apply Changes"
}
/**
- * Compare two tools configurations and return a list of changes
+ * Create a concise summary of tools configuration changes
*/
- private compareToolsConfigs(currentConfig: any, newConfig: any): string[] {
- const changes: string[] = [];
+ private createToolsConfigSummary(
+ currentConfig: any,
+ newConfig: any
+ ): {
+ totalChanges: number;
+ summaryText: string;
+ } {
+ const enabledTools: string[] = [];
+ const disabledTools: string[] = [];
+ const addedTools: string[] = [];
+ const removedTools: string[] = [];
// Get all server names from both configs
const allServers = new Set([
@@ -174,25 +208,50 @@ class ElectronMCPClient {
for (const toolName of allTools) {
const currentTool = currentServerConfig[toolName];
const newTool = newServerConfig[toolName];
+ const displayName = `${toolName} (${serverName})`;
if (!currentTool && newTool) {
// New tool added
- const status = newTool.enabled ? 'enabled' : 'disabled';
- changes.push(`+ Add tool "${toolName}" on server "${serverName}" (${status})`);
+ addedTools.push(displayName);
+ if (newTool.enabled) {
+ enabledTools.push(displayName);
+ } else {
+ disabledTools.push(displayName);
+ }
} else if (currentTool && !newTool) {
// Tool removed
- changes.push(`- Remove tool "${toolName}" from server "${serverName}"`);
+ removedTools.push(displayName);
} else if (currentTool && newTool) {
// Tool modified
if (currentTool.enabled !== newTool.enabled) {
- const status = newTool.enabled ? 'enabled' : 'disabled';
- changes.push(`~ Change tool "${toolName}" on server "${serverName}" to ${status}`);
+ if (newTool.enabled) {
+ enabledTools.push(displayName);
+ } else {
+ disabledTools.push(displayName);
+ }
}
}
}
}
- return changes;
+ // Build summary text
+ const summaryParts: string[] = [];
+
+ if (enabledTools.length > 0) {
+ summaryParts.push(`✓ ENABLE (${enabledTools.length}): ${enabledTools.join(', ')}`);
+ }
+
+ if (disabledTools.length > 0) {
+ summaryParts.push(`✗ DISABLE (${disabledTools.length}): ${disabledTools.join(', ')}`);
+ }
+
+ const totalChanges =
+ enabledTools.length + disabledTools.length + addedTools.length + removedTools.length;
+
+ return {
+ totalChanges,
+ summaryText: summaryParts.join('\n\n'),
+ };
}
/**
@@ -319,6 +378,90 @@ class ElectronMCPClient {
};
}
+ /**
+ * Validate tool parameters against schema from configuration
+ */
+ private validateToolParameters(
+ serverName: string,
+ toolName: string,
+ args: any
+ ): { valid: boolean; error?: string } {
+ const toolState = this.configManager.getToolStats(serverName, toolName);
+ if (!toolState || !toolState.inputSchema) {
+ // No schema available, assume valid
+ return { valid: true };
+ }
+
+ try {
+ const schema = toolState.inputSchema;
+
+ // Basic validation - check required properties
+ if (schema.required && Array.isArray(schema.required)) {
+ for (const requiredProp of schema.required) {
+ if (args[requiredProp] === undefined || args[requiredProp] === null) {
+ return {
+ valid: false,
+ error: `Required parameter '${requiredProp}' is missing`,
+ };
+ }
+ }
+ }
+
+ // Check property types if schema properties are defined
+ if (schema.properties) {
+ for (const [propName, propSchema] of Object.entries(schema.properties as any)) {
+ if (args[propName] !== undefined) {
+ const propType = (propSchema as any).type;
+ const actualType = typeof args[propName];
+
+ if (propType === 'string' && actualType !== 'string') {
+ return {
+ valid: false,
+ error: `Parameter '${propName}' should be a string, got ${actualType}`,
+ };
+ }
+ if (propType === 'number' && actualType !== 'number') {
+ return {
+ valid: false,
+ error: `Parameter '${propName}' should be a number, got ${actualType}`,
+ };
+ }
+ if (propType === 'boolean' && actualType !== 'boolean') {
+ return {
+ valid: false,
+ error: `Parameter '${propName}' should be a boolean, got ${actualType}`,
+ };
+ }
+ if (propType === 'array' && !Array.isArray(args[propName])) {
+ return {
+ valid: false,
+ error: `Parameter '${propName}' should be an array, got ${actualType}`,
+ };
+ }
+ if (
+ propType === 'object' &&
+ (actualType !== 'object' || Array.isArray(args[propName]) || args[propName] === null)
+ ) {
+ return {
+ valid: false,
+ error: `Parameter '${propName}' should be an object, got ${actualType}`,
+ };
+ }
+ }
+ }
+ }
+
+ return { valid: true };
+ } catch (error) {
+ return {
+ valid: false,
+ error: `Schema validation error: ${
+ error instanceof Error ? error.message : 'Unknown error'
+ }`,
+ };
+ }
+ }
+
/**
* Load MCP server configuration from settings
*/
@@ -390,6 +533,7 @@ class ElectronMCPClient {
}
private async initializeClient(): Promise {
+ console.log('initializeClient called');
if (this.isInitialized) {
return;
}
@@ -398,6 +542,7 @@ class ElectronMCPClient {
return this.initializationPromise;
}
+ console.log('Starting MCP client initialization...');
this.initializationPromise = this.doInitialize();
return this.initializationPromise;
}
@@ -467,7 +612,6 @@ class ElectronMCPClient {
// Get and cache the tools
this.tools = await this.client.getTools();
-
// Initialize configuration for available tools
this.initializeToolsConfiguration();
@@ -483,39 +627,6 @@ class ElectronMCPClient {
}
private setupIpcHandlers(): void {
- // Handle MCP tools request
- ipcMain.handle('mcp-get-tools', async () => {
- try {
- await this.initializeClient();
-
- if (!this.client || this.tools.length === 0) {
- return { success: true, tools: [] };
- }
-
- // Filter tools based on configuration and convert to our format
- const enabledToolsInfo = this.tools
- .filter(tool => {
- const { serverName, toolName } = this.parseToolName(tool.name);
- return this.configManager.isToolEnabled(serverName, toolName);
- })
- .map(tool => ({
- name: tool.name,
- description: tool.description,
- inputSchema: tool.schema,
- }));
-
- console.log('MCP tools retrieved:', enabledToolsInfo.length, 'enabled tools');
- return { success: true, tools: enabledToolsInfo };
- } catch (error) {
- console.error('Error getting MCP tools:', error);
- return {
- success: false,
- error: error instanceof Error ? error.message : 'Unknown error',
- tools: [],
- };
- }
- });
-
// Handle MCP tool execution
ipcMain.handle('mcp-execute-tool', async (event, { toolName, args, toolCallId }) => {
console.log('args in mcp-execute-tool:', args);
@@ -530,8 +641,10 @@ class ElectronMCPClient {
const { serverName, toolName: actualToolName } = this.parseToolName(toolName);
// Check if tool is enabled
- if (!this.configManager.isToolEnabled(serverName, actualToolName)) {
- throw new Error(`Tool ${toolName} is disabled`);
+ const isEnabled = this.configManager.isToolEnabled(serverName, actualToolName);
+
+ if (!isEnabled) {
+ throw new Error(`Tool ${actualToolName} from server ${serverName} is disabled`);
}
// Find the tool by name
@@ -540,6 +653,12 @@ class ElectronMCPClient {
throw new Error(`Tool ${toolName} not found`);
}
+ // Validate parameters against schema from configuration
+ const validation = this.validateToolParameters(serverName, actualToolName, args);
+ if (!validation.valid) {
+ throw new Error(`Parameter validation failed: ${validation.error}`);
+ }
+
console.log(`Executing MCP tool: ${toolName} with args:`, args);
// Execute the tool directly using LangChain's invoke method
@@ -555,7 +674,6 @@ class ElectronMCPClient {
toolCallId,
};
} catch (error) {
- console.error(`Error executing MCP tool ${toolName}:`, error);
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
@@ -706,6 +824,7 @@ class ElectronMCPClient {
// Handle updating MCP tools configuration with user confirmation
ipcMain.handle('mcp-update-tools-config', async (event, toolsConfig: any) => {
+ console.log('Requested MCP tools configuration update:', toolsConfig);
try {
// Show confirmation dialog with detailed changes
const userConfirmed = await this.showToolsConfigConfirmationDialog(toolsConfig);
@@ -761,6 +880,19 @@ class ElectronMCPClient {
});
}
+ /**
+ * Public method to initialize the MCP client
+ * This should be called when the app starts
+ */
+ async initialize(): Promise {
+ try {
+ await this.initializeClient();
+ } catch (error) {
+ console.error('Failed to initialize MCP client on startup:', error);
+ // Don't throw error to prevent app startup failure
+ }
+ }
+
/**
* Cleanup method to be called when the app is shutting down
*/
diff --git a/app/electron/mcp-config.ts b/app/electron/mcp-config.ts
index 151a9ebeabb..bffb5a18386 100644
--- a/app/electron/mcp-config.ts
+++ b/app/electron/mcp-config.ts
@@ -22,6 +22,8 @@ export interface MCPToolState {
enabled: boolean;
lastUsed?: Date;
usageCount?: number;
+ inputSchema?: any; // JSON schema for tool parameters
+ description?: string; // Tool description from MCP server
}
export interface MCPServerToolState {
@@ -49,13 +51,10 @@ export class MCPConfigManager {
if (fs.existsSync(this.configPath)) {
const configData = fs.readFileSync(this.configPath, 'utf-8');
this.config = JSON.parse(configData);
- console.log('MCP tools configuration loaded successfully');
} else {
- console.log('MCP tools configuration file does not exist, using default empty config');
this.config = {};
}
} catch (error) {
- console.error('Error loading MCP tools configuration:', error);
this.config = {};
}
}
@@ -66,7 +65,6 @@ export class MCPConfigManager {
private saveConfig(): void {
try {
fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), 'utf-8');
- console.log('MCP tools configuration saved successfully');
} catch (error) {
console.error('Error saving MCP tools configuration:', error);
}
@@ -183,9 +181,17 @@ export class MCPConfigManager {
}
/**
- * Initialize default configuration for available tools
+ * Initialize default configuration for available tools with schemas
*/
- initializeToolsConfig(serverName: string, toolNames: string[]): void {
+ initializeToolsConfig(
+ serverName: string,
+ toolsInfo: Array<{
+ name: string;
+ inputSchema?: any;
+ description?: string;
+ }>
+ ): void {
+ console.log('MCP config called ', this.config, serverName, toolsInfo);
if (!this.config[serverName]) {
this.config[serverName] = {};
}
@@ -193,18 +199,52 @@ export class MCPConfigManager {
const serverConfig = this.config[serverName];
let hasChanges = false;
- for (const toolName of toolNames) {
+ for (const toolInfo of toolsInfo) {
+ const toolName = toolInfo.name;
+
if (!serverConfig[toolName]) {
+ console.log(`Creating new tool config for: ${toolName}`);
serverConfig[toolName] = {
enabled: true,
usageCount: 0,
+ inputSchema: toolInfo.inputSchema || null,
+ description: toolInfo.description || '',
};
hasChanges = true;
+ } else {
+ console.log(`Updating existing tool config for: ${toolName}`);
+ // Always update schema and description for existing tools
+ let toolChanged = false;
+
+ // Update schema if it's different or missing
+ const currentSchema = JSON.stringify(serverConfig[toolName].inputSchema || null);
+ const newSchema = JSON.stringify(toolInfo.inputSchema || null);
+ if (currentSchema !== newSchema) {
+ console.log(`Updating schema for tool: ${toolName}`);
+ serverConfig[toolName].inputSchema = toolInfo.inputSchema || null;
+ toolChanged = true;
+ }
+
+ // Update description if it's different or missing
+ const currentDescription = serverConfig[toolName].description || '';
+ const newDescription = toolInfo.description || '';
+ if (currentDescription !== newDescription) {
+ console.log(`Updating description for tool: ${toolName}`);
+ serverConfig[toolName].description = newDescription;
+ toolChanged = true;
+ }
+
+ if (toolChanged) {
+ hasChanges = true;
+ }
}
}
if (hasChanges) {
+ console.log(`Saving configuration changes for server: ${serverName}`);
this.saveConfig();
+ } else {
+ console.log(`No changes needed for server: ${serverName}`);
}
}
diff --git a/app/electron/preload.ts b/app/electron/preload.ts
index f6207b4bbe3..0157265b447 100644
--- a/app/electron/preload.ts
+++ b/app/electron/preload.ts
@@ -60,7 +60,6 @@ contextBridge.exposeInMainWorld('desktopApi', {
// MCP client APIs
mcp: {
- getTools: () => ipcRenderer.invoke('mcp-get-tools'),
executeTool: (toolName: string, args: Record, toolCallId?: string) =>
ipcRenderer.invoke('mcp-execute-tool', { toolName, args, toolCallId }),
getStatus: () => ipcRenderer.invoke('mcp-get-status'),
From a72233cfa4d6733bf06deb23263f41d18b374164 Mon Sep 17 00:00:00 2001
From: ashu8912
Date: Sun, 19 Oct 2025 11:51:24 +0530
Subject: [PATCH 07/72] app: Replace mcp config if server config changes
---
app/electron/main.ts | 5 +---
app/electron/mcp-client.ts | 17 ++++++------
app/electron/mcp-config.ts | 56 ++++++++++++++++++++++++++++++++------
3 files changed, 58 insertions(+), 20 deletions(-)
diff --git a/app/electron/main.ts b/app/electron/main.ts
index 79b67c16d3c..9d2086987e4 100644
--- a/app/electron/main.ts
+++ b/app/electron/main.ts
@@ -1474,10 +1474,7 @@ function startElecron() {
if (mainWindow) {
mainWindow.removeAllListeners('close');
}
- // Cleanup MCP client
- if (mcpClient) {
- mcpClient.cleanup().catch(console.error);
- }
+
// Cleanup MCP client
if (mcpClient) {
mcpClient.cleanup().catch(console.error);
diff --git a/app/electron/mcp-client.ts b/app/electron/mcp-client.ts
index fdbda60a362..873d3ab81e9 100644
--- a/app/electron/mcp-client.ts
+++ b/app/electron/mcp-client.ts
@@ -57,10 +57,13 @@ class ElectronMCPClient {
/**
* Initialize tools configuration for all available tools
+ * This completely replaces the existing config with current tools
*/
private initializeToolsConfiguration(): void {
if (!this.tools || this.tools.length === 0) {
console.log('No tools available for configuration initialization');
+ // Clear the config if no tools are available
+ this.configManager.replaceConfig({});
return;
}
@@ -75,16 +78,16 @@ class ElectronMCPClient {
> = {};
for (const tool of this.tools) {
- console.log('Initializing tools configuration...', tool);
// Extract server name from tool name (format: "serverName__toolName")
const toolName = tool.name;
const parts = toolName.split('__');
// Extract schema from the tool (LangChain tools use .schema property)
const toolSchema = (tool as any).schema || tool.inputSchema || null;
- console.log('tool schema is ', toolSchema);
console.log(
- `Processing tool: ${toolName}, has inputSchema: ${toolSchema}, description: "${tool.description}"`
+ `Processing tool: ${toolName}, has inputSchema: ${!!toolSchema}, description: "${
+ tool.description
+ }"`
);
if (parts.length >= 2) {
@@ -114,11 +117,8 @@ class ElectronMCPClient {
console.log('Tools grouped by server:', Object.keys(toolsByServer));
- // Initialize configuration for each server's tools
- for (const [serverName, toolsInfo] of Object.entries(toolsByServer)) {
- console.log(`Initializing ${toolsInfo.length} tools for server: ${serverName}`);
- this.configManager.initializeToolsConfig(serverName, toolsInfo);
- }
+ // Replace the entire configuration with current tools
+ this.configManager.replaceToolsConfig(toolsByServer);
}
/**
@@ -608,6 +608,7 @@ class ElectronMCPClient {
additionalToolNamePrefix: '',
useStandardContentBlocks: true,
mcpServers,
+ defaultToolTimeout: 2 * 60 * 1000, // 2 minutes
});
// Get and cache the tools
diff --git a/app/electron/mcp-config.ts b/app/electron/mcp-config.ts
index bffb5a18386..0bc65234b5d 100644
--- a/app/electron/mcp-config.ts
+++ b/app/electron/mcp-config.ts
@@ -191,7 +191,6 @@ export class MCPConfigManager {
description?: string;
}>
): void {
- console.log('MCP config called ', this.config, serverName, toolsInfo);
if (!this.config[serverName]) {
this.config[serverName] = {};
}
@@ -203,7 +202,6 @@ export class MCPConfigManager {
const toolName = toolInfo.name;
if (!serverConfig[toolName]) {
- console.log(`Creating new tool config for: ${toolName}`);
serverConfig[toolName] = {
enabled: true,
usageCount: 0,
@@ -212,7 +210,6 @@ export class MCPConfigManager {
};
hasChanges = true;
} else {
- console.log(`Updating existing tool config for: ${toolName}`);
// Always update schema and description for existing tools
let toolChanged = false;
@@ -220,7 +217,6 @@ export class MCPConfigManager {
const currentSchema = JSON.stringify(serverConfig[toolName].inputSchema || null);
const newSchema = JSON.stringify(toolInfo.inputSchema || null);
if (currentSchema !== newSchema) {
- console.log(`Updating schema for tool: ${toolName}`);
serverConfig[toolName].inputSchema = toolInfo.inputSchema || null;
toolChanged = true;
}
@@ -229,7 +225,6 @@ export class MCPConfigManager {
const currentDescription = serverConfig[toolName].description || '';
const newDescription = toolInfo.description || '';
if (currentDescription !== newDescription) {
- console.log(`Updating description for tool: ${toolName}`);
serverConfig[toolName].description = newDescription;
toolChanged = true;
}
@@ -241,10 +236,7 @@ export class MCPConfigManager {
}
if (hasChanges) {
- console.log(`Saving configuration changes for server: ${serverName}`);
this.saveConfig();
- } else {
- console.log(`No changes needed for server: ${serverName}`);
}
}
@@ -259,4 +251,52 @@ export class MCPConfigManager {
return { ...serverConfig[toolName] };
}
+
+ /**
+ * Replace the entire tools configuration with a new set of tools
+ * This overwrites all existing tools with only the current ones
+ */
+ replaceToolsConfig(
+ toolsByServer: Record<
+ string,
+ Array<{
+ name: string;
+ inputSchema?: any;
+ description?: string;
+ }>
+ >
+ ): void {
+ // Create a new config object
+ const newConfig: MCPToolsConfig = {};
+
+ for (const [serverName, toolsInfo] of Object.entries(toolsByServer)) {
+ newConfig[serverName] = {};
+
+ for (const toolInfo of toolsInfo) {
+ const toolName = toolInfo.name;
+
+ // Check if this tool existed in the old config to preserve enabled state and usage count
+ const oldToolState = this.config[serverName]?.[toolName];
+
+ newConfig[serverName][toolName] = {
+ enabled: oldToolState?.enabled ?? true, // Preserve enabled state or default to true
+ usageCount: oldToolState?.usageCount ?? 0, // Preserve usage count or default to 0
+ inputSchema: toolInfo.inputSchema || null,
+ description: toolInfo.description || '',
+ };
+ }
+ }
+
+ // Replace the entire config
+ this.config = newConfig;
+ this.saveConfig();
+ }
+
+ /**
+ * Replace the entire configuration with a new config object
+ */
+ replaceConfig(newConfig: MCPToolsConfig): void {
+ this.config = newConfig;
+ this.saveConfig();
+ }
}
From 476f33da804aa2725c8b1794fa4ba33976227225 Mon Sep 17 00:00:00 2001
From: ashu8912
Date: Mon, 27 Oct 2025 13:51:37 +0530
Subject: [PATCH 08/72] app: Handle cluster change
---
app/electron/main.ts | 9 ++++
app/electron/mcp-client.ts | 89 +++++++++++++++++++++++++++++++++++++-
app/electron/preload.ts | 8 ++++
3 files changed, 104 insertions(+), 2 deletions(-)
diff --git a/app/electron/main.ts b/app/electron/main.ts
index 9d2086987e4..dc9de252d9b 100644
--- a/app/electron/main.ts
+++ b/app/electron/main.ts
@@ -1422,6 +1422,15 @@ function startElecron() {
mainWindow?.webContents.send('backend-token', backendToken);
});
+ // Handle cluster change notifications from frontend
+ ipcMain.on('cluster-changed', (event: IpcMainEvent, cluster: string | null) => {
+ if (mcpClient) {
+ mcpClient.handleClusterChange(cluster).catch(error => {
+ console.error('Failed to handle cluster change in MCP client:', error);
+ });
+ }
+ });
+
setupRunCmdHandlers(mainWindow, ipcMain);
new PluginManagerEventListeners().setupEventHandlers();
diff --git a/app/electron/mcp-client.ts b/app/electron/mcp-client.ts
index 873d3ab81e9..a113d1a9f1f 100644
--- a/app/electron/mcp-client.ts
+++ b/app/electron/mcp-client.ts
@@ -41,6 +41,7 @@ class ElectronMCPClient {
private initializationPromise: Promise | null = null;
private configManager: MCPConfigManager;
private mainWindow: BrowserWindow | null = null;
+ private currentCluster: string | null = null;
constructor(mainWindow: BrowserWindow | null = null) {
this.mainWindow = mainWindow;
@@ -483,11 +484,18 @@ class ElectronMCPClient {
/**
* Expand environment variables and resolve paths in arguments
*/
- private expandArgs(args: string[]): string[] {
+ private expandArgs(args: string[], cluster: string | null = null): string[] {
+ const currentCluster = cluster || this.currentCluster || '';
+
return args.map(arg => {
// Replace Windows environment variables like %USERPROFILE%
let expandedArg = arg;
+ // Handle HEADLAMP_CURRENT_CLUSTER placeholder
+ if (expandedArg.includes('HEADLAMP_CURRENT_CLUSTER')) {
+ expandedArg = expandedArg.replace(/HEADLAMP_CURRENT_CLUSTER/g, currentCluster);
+ }
+
// Handle %USERPROFILE%
if (expandedArg.includes('%USERPROFILE%')) {
expandedArg = expandedArg.replace(/%USERPROFILE%/g, os.homedir());
@@ -574,7 +582,7 @@ class ElectronMCPClient {
}
// Expand environment variables and resolve paths in arguments
- const expandedArgs = this.expandArgs(server.args || []);
+ const expandedArgs = this.expandArgs(server.args || [], this.currentCluster);
console.log(`Expanded args for ${server.name}:`, expandedArgs);
// Prepare environment variables
@@ -879,6 +887,83 @@ class ElectronMCPClient {
};
}
});
+
+ // Handle cluster context changes
+ ipcMain.handle('mcp-cluster-change', async (event, { cluster }) => {
+ try {
+ console.log('Received cluster change event:', cluster);
+ await this.handleClusterChange(cluster);
+ return {
+ success: true,
+ };
+ } catch (error) {
+ console.error('Error handling cluster change:', error);
+ return {
+ success: false,
+ error: error instanceof Error ? error.message : 'Unknown error',
+ };
+ }
+ });
+ }
+
+ /**
+ * Check if any server in the config uses HEADLAMP_CURRENT_CLUSTER
+ */
+ private hasClusterDependentServers(mcpConfig: MCPConfig | null): boolean {
+ if (!mcpConfig || !mcpConfig.servers) {
+ return false;
+ }
+
+ return mcpConfig.servers.some(
+ server =>
+ server.enabled &&
+ server.args &&
+ server.args.some(arg => arg.includes('HEADLAMP_CURRENT_CLUSTER'))
+ );
+ }
+
+ /**
+ * Handle cluster context change
+ * This will restart MCP servers if any server uses HEADLAMP_CURRENT_CLUSTER
+ */
+ async handleClusterChange(newCluster: string | null): Promise {
+ // If cluster hasn't actually changed, do nothing
+ if (this.currentCluster === newCluster) {
+ return;
+ }
+
+ const oldCluster = this.currentCluster;
+ this.currentCluster = newCluster;
+
+ // Check if we have any cluster-dependent servers
+ const mcpConfig = this.loadMCPConfig();
+ if (!this.hasClusterDependentServers(mcpConfig)) {
+ console.log('No cluster-dependent MCP servers found, skipping restart');
+ return;
+ }
+
+ try {
+ // Reset the client
+ if (this.client) {
+ if (typeof (this.client as any).close === 'function') {
+ await (this.client as any).close();
+ }
+ }
+
+ this.client = null;
+ this.isInitialized = false;
+ this.initializationPromise = null;
+
+ // Re-initialize with new cluster context
+ await this.initializeClient();
+
+ console.log('MCP client restarted successfully for new cluster:', newCluster);
+ } catch (error) {
+ console.error('Error restarting MCP client for cluster change:', error);
+ // Restore previous cluster on error
+ this.currentCluster = oldCluster;
+ throw error;
+ }
}
/**
diff --git a/app/electron/preload.ts b/app/electron/preload.ts
index 0157265b447..3ab81137370 100644
--- a/app/electron/preload.ts
+++ b/app/electron/preload.ts
@@ -30,6 +30,7 @@ contextBridge.exposeInMainWorld('desktopApi', {
'plugin-manager',
'request-backend-token',
'request-plugin-permission-secrets',
+ 'cluster-changed',
];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
@@ -72,5 +73,12 @@ contextBridge.exposeInMainWorld('desktopApi', {
ipcRenderer.invoke('mcp-set-tool-enabled', { serverName, toolName, enabled }),
getToolStats: (serverName: string, toolName: string) =>
ipcRenderer.invoke('mcp-get-tool-stats', { serverName, toolName }),
+ clusterChange: (cluster: string | null) =>
+ ipcRenderer.invoke('mcp-cluster-change', { cluster }),
+ },
+
+ // Notify cluster change (for MCP server restart)
+ notifyClusterChange: (cluster: string | null) => {
+ ipcRenderer.send('cluster-changed', cluster);
},
});
From 216b803e5549b38cdea8dd42fb30705fc53674f1 Mon Sep 17 00:00:00 2001
From: Joaquim Rocha
Date: Fri, 17 Oct 2025 14:54:05 +0100
Subject: [PATCH 09/72] Add root-level npm
So we can run Headlamp without make, just by using npm.
---
package-lock.json | 377 ++++++++++++++++++++++++++++++++++++++++++++++
package.json | 85 +++++++++++
2 files changed, 462 insertions(+)
create mode 100644 package-lock.json
create mode 100644 package.json
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000000..5ac4ca37c19
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,377 @@
+{
+ "name": "headlamp-root",
+ "version": "0.1.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "headlamp-root",
+ "version": "0.1.0",
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "concurrently": "^8.2.2"
+ },
+ "engines": {
+ "node": ">=20.11.1",
+ "npm": ">=10.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
+ "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chalk/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/concurrently": {
+ "version": "8.2.2",
+ "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.2.2.tgz",
+ "integrity": "sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.2",
+ "date-fns": "^2.30.0",
+ "lodash": "^4.17.21",
+ "rxjs": "^7.8.1",
+ "shell-quote": "^1.8.1",
+ "spawn-command": "0.0.2",
+ "supports-color": "^8.1.1",
+ "tree-kill": "^1.2.2",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "conc": "dist/bin/concurrently.js",
+ "concurrently": "dist/bin/concurrently.js"
+ },
+ "engines": {
+ "node": "^14.13.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
+ }
+ },
+ "node_modules/date-fns": {
+ "version": "2.30.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
+ "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.21.0"
+ },
+ "engines": {
+ "node": ">=0.11"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/date-fns"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/shell-quote": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
+ "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/spawn-command": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz",
+ "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==",
+ "dev": true
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000000..0e659e46390
--- /dev/null
+++ b/package.json
@@ -0,0 +1,85 @@
+{
+ "name": "headlamp-root",
+ "version": "0.1.0",
+ "private": true,
+ "description": "Headlamp - An easy-to-use and extensible Kubernetes web UI",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/kubernetes-sigs/headlamp.git"
+ },
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=20.11.1",
+ "npm": ">=10.0.0"
+ },
+ "scripts": {
+ "install:all": "npm run frontend:install && npm run backend:build && npm run app:install",
+ "install:frontend": "npm run frontend:install",
+ "install:backend": "npm run backend:build",
+ "install:app": "npm run app:install",
+ "build": "npm run backend:build && npm run frontend:build",
+ "dev": "npm run start",
+ "start": "concurrently \"npm run backend:start\" \"npm run frontend:start\" --names \"backend,frontend\" --prefix-colors \"blue,green\"",
+ "test": "npm run backend:test && npm run frontend:test",
+ "lint": "npm run backend:lint && npm run frontend:lint",
+ "lint:fix": "npm run backend:lint:fix && npm run frontend:lint:fix",
+ "clean": "rm -rf frontend/build frontend/node_modules app/node_modules app/dist backend/headlamp-server backend/headlamp-server.exe node_modules",
+ "backend:build": "cd backend && go build -o ./headlamp-server ./cmd",
+ "backend:lint": "npm run backend:install:linter && cd backend && ./tools/golangci-lint run",
+ "backend:lint:fix": "npm run backend:install:linter && cd backend && ./tools/golangci-lint run --fix",
+ "backend:install:linter": "GOBIN=`pwd`/backend/tools go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64",
+ "backend:test": "cd backend && go test -v -p 1 ./...",
+ "backend:coverage": "cd backend && go test -v -p 1 -coverprofile=coverage.out ./... && go tool cover -func=coverage.out",
+ "backend:coverage:html": "cd backend && go test -v -p 1 -coverprofile=coverage.out ./... && go tool cover -html=coverage.out",
+ "backend:format": "cd backend && go fmt ./cmd/ ./pkg/**",
+ "backend:start": "echo 'Warning: Running with Helm and dynamic-clusters endpoints enabled.' && HEADLAMP_BACKEND_TOKEN=headlamp HEADLAMP_CONFIG_ENABLE_HELM=true HEADLAMP_CONFIG_ENABLE_DYNAMIC_CLUSTERS=true ./backend/headlamp-server -dev -proxy-urls https://artifacthub.io/* -listen-addr=localhost",
+ "backend:dev": "echo 'Starting Headlamp backend in dev mode with Air...' && cd backend && air",
+ "backend:start:metrics": "echo 'Running backend with Prometheus metrics enabled' && HEADLAMP_BACKEND_TOKEN=headlamp HEADLAMP_CONFIG_METRICS_ENABLED=true HEADLAMP_CONFIG_ENABLE_HELM=true HEADLAMP_CONFIG_ENABLE_DYNAMIC_CLUSTERS=true ./backend/headlamp-server -dev -proxy-urls https://artifacthub.io/* -listen-addr=localhost",
+ "backend:start:traces": "echo 'Running backend with distributed tracing enabled' && HEADLAMP_BACKEND_TOKEN=headlamp HEADLAMP_CONFIG_TRACING_ENABLED=true HEADLAMP_CONFIG_ENABLE_HELM=true HEADLAMP_CONFIG_ENABLE_DYNAMIC_CLUSTERS=true ./backend/headlamp-server -dev -proxy-urls https://artifacthub.io/* -listen-addr=localhost",
+ "frontend:install": "cd frontend && npm install",
+ "frontend:install:ci": "cd frontend && npm ci",
+ "frontend:build": "cd frontend && npm run build",
+ "frontend:build:storybook": "cd frontend && npm run build-storybook",
+ "frontend:lint": "cd frontend && npm run lint -- --max-warnings 0 && npm run format-check",
+ "frontend:lint:fix": "cd frontend && npm run lint -- --fix && npm run format",
+ "frontend:tsc": "cd frontend && npm run tsc",
+ "frontend:test": "cd frontend && npm test -- --coverage",
+ "frontend:start": "cd frontend && npm start",
+ "frontend:storybook": "cd frontend && npm run storybook",
+ "docs": "cd frontend && npm run build-typedoc",
+ "i18n": "cd frontend && npm run i18n",
+ "i18n:check": "cd frontend && npm run i18n -- --fail-on-update",
+ "app:install": "cd app && npm install",
+ "app:build": "npm run frontend:build && cd app && node ./scripts/setup-plugins.js && npm run build",
+ "app:build:dir": "npm run frontend:build && cd app && node ./scripts/setup-plugins.js && npm run build -- --dir",
+ "app:package": "npm run app:build && cd app && npm run package -- --win --linux --mac",
+ "app:package:win": "npm run app:build && cd app && npm run package -- --win",
+ "app:package:win:msi": "npm run app:build && cd app && npm run package-msi",
+ "app:package:linux": "npm run app:build && cd app && npm run package -- --linux",
+ "app:package:mac": "npm run app:build && cd app && npm run package -- --mac",
+ "app:test": "npm run app:test:unit && npm run app:test:e2e",
+ "app:test:unit": "cd app && npm run test",
+ "app:test:e2e": "cd app/e2e-tests && npm run test",
+ "app:tsc": "cd app && npm run tsc",
+ "app:start": "cd app && node ./scripts/setup-plugins.js && npm run start",
+ "app:start:client": "cd app && npm run dev-only-app",
+ "start:with-app": "concurrently \"npm run backend:start\" \"npm run frontend:start\" \"npm run app:start:client\" --names \"backend,frontend,app\" --prefix-colors \"blue,green,yellow\"",
+ "start:app": "npm run app:start",
+ "start:backend": "npm run backend:build && npm run backend:start",
+ "start:frontend": "npm run frontend:start",
+ "plugins:test": "cd plugins/headlamp-plugin && npm install && ./test-headlamp-plugin.js && ./test-plugins-examples.sh && cd ../pluginctl/src && npm install && node ./plugin-management.e2e.js && cd .. && npx jest src/multi-plugin-management.test.js && npx jest src/plugin-management.test.js && npm run test",
+ "image:build": "sh -c 'docker buildx build --pull --platform=local -t ghcr.io/headlamp-k8s/headlamp:$(git describe --tags --always --dirty) -f Dockerfile .'"
+ },
+ "devDependencies": {
+ "concurrently": "^8.2.2"
+ },
+ "keywords": [
+ "kubernetes",
+ "k8s",
+ "ui",
+ "web",
+ "dashboard",
+ "cluster",
+ "management"
+ ]
+}
From 820a10622cfab12f44a928a21a4e84a938cdc54e Mon Sep 17 00:00:00 2001
From: Joaquim Rocha
Date: Fri, 17 Oct 2025 15:34:35 +0100
Subject: [PATCH 10/72] docs,README.md: Update docs to use npm commands instead
of make
This should make things easier for novice developers.
---
app/e2e-tests/README.md | 6 +--
backend/README.md | 4 +-
docs/contributing.md | 12 +++---
docs/development/architecture.md | 24 ++++++------
docs/development/backend.md | 16 ++++----
docs/development/frontend.md | 10 ++---
docs/development/i18n/contributing.md | 2 +-
docs/development/index.md | 56 +++++++++++++++++----------
docs/installation/base-url.md | 4 +-
e2e-tests/README.md | 2 +-
10 files changed, 75 insertions(+), 61 deletions(-)
diff --git a/app/e2e-tests/README.md b/app/e2e-tests/README.md
index 1fc1da0132c..7cab527a3eb 100644
--- a/app/e2e-tests/README.md
+++ b/app/e2e-tests/README.md
@@ -41,17 +41,17 @@ To run the tests for the web mode, you will need to have the backend running. Fo
`cd headlamp`
- run the following command
- `make backend` followed by `make run-backend`
+ `npm run backend:build` followed by `npm run backend:start`
### Frontend
To run the tests for the web mode, you will need to have the frontend running. Follow the steps below to run the frontend:
- cd into the headlamp directory in a separate terminal
- `cd headlamp/frontend`
+ `cd headlamp`
- run the following command
- `make frontend` followed by `make run-frontend`
+ `npm run frontend:build` followed by `npm run frontend:start`
### Running the tests
diff --git a/backend/README.md b/backend/README.md
index 10aab9e198c..c537e54a90f 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -1,8 +1,8 @@
# Quickstart
```bash
-make backend
-make run-backend
+npm run backend:build
+npm run backend:start
```
See more detailed [Headlamp backend documentation on the web](
diff --git a/docs/contributing.md b/docs/contributing.md
index f2e6c395a7f..d3c345d5eb3 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -55,8 +55,8 @@ Follow these steps when submitting a PR to ensure it meets the project’s stand
Run the following commands from your project directory:
-- `make frontend-test` - Run the test suite
-- `make frontend-lint` - Format your code to match the project
+- `npm run frontend:test` - Run the test suite
+- `npm run frontend:lint` - Format your code to match the project
These steps ensure your code is functional, well-typed, and formatted consistently.
@@ -156,11 +156,11 @@ For linting the `backend` and `frontend`, use the following commands
(respectively):
```bash
-make backend-lint
+npm run backend:lint
```
```bash
-make frontend-lint
+npm run frontend:lint
```
The linters are also run in the CI system, so any PRs you create will be
@@ -194,13 +194,13 @@ an associated story when possible.
For running the frontend tests, use the following command:
```bash
-make frontend-test
+npm run frontend:test
```
The backend uses go's testing and can be run by using the following command:
```bash
-make backend-test
+npm run backend:test
```
Tests will run as part of the CI after a Pull Request is open.
diff --git a/docs/development/architecture.md b/docs/development/architecture.md
index 2e63e6a7c54..3862d3c9c0b 100644
--- a/docs/development/architecture.md
+++ b/docs/development/architecture.md
@@ -128,23 +128,23 @@ The following components are in separate GitHub repos:
- **Plugins**: Extensible modules that add custom functionality to the UI. The Headlamp team maintains their plugins in the [headlamp-k8s/plugins repo](https://github.com/headlamp-k8s/plugins). These include plugins for projects like Flux, Backstage and Inspektor Gadget.
- **Headlamp Website**: Maintained in the [headlamp-k8s/website repo](https://github.com/headlamp-k8s/website). This contains things like the blog and the documentation. The website can be found at https://headlamp.dev/
-### Makefile task entry point
+### npm scripts entry point
-The headlamp/ repo [Makefile](https://github.com/kubernetes-sigs/headlamp/blob/main/Makefile) contains targets for building and testing different components.
+The headlamp/ repo root [package.json](https://github.com/kubernetes-sigs/headlamp/blob/main/package.json) contains scripts for building and testing different components.
Here are some examples:
```shell
-make backend
-make backend-lint
-make backend-test
-make run-backend
-make frontend
-make frontend-lint
-make frontend-test
-make run-frontend
-make app-test
-make run-app
+npm run backend:build
+npm run backend:lint
+npm run backend:test
+npm run backend:start
+npm run frontend:build
+npm run frontend:lint
+npm run frontend:test
+npm run frontend:start
+npm run app:test
+npm run start:app
```
### Frontend
diff --git a/docs/development/backend.md b/docs/development/backend.md
index 0dc214d9375..d4feb0d2387 100644
--- a/docs/development/backend.md
+++ b/docs/development/backend.md
@@ -18,13 +18,13 @@ redirects the requests to the defined proxies.
The backend (Headlamp's server) can be quickly built using:
```bash
-make backend
+npm run backend:build
```
Once built, it can be run in development mode (insecure / don't use in production) using:
```bash
-make run-backend
+npm run backend:start
```
## Lint
@@ -32,13 +32,13 @@ make run-backend
To lint the backend/ code.
```bash
-make backend-lint
+npm run backend:lint
```
This command can fix some lint issues.
```bash
-make backend-lint-fix
+npm run backend:lint:fix
```
## Format
@@ -46,23 +46,23 @@ make backend-lint-fix
To format the backend code.
```bash
-make backend-format
+npm run backend:format
```
## Test
```bash
-make backend-test
+npm run backend:test
```
Test coverage with a html report in the browser.
```bash
-make backend-coverage-html
+npm run backend:coverage:html
```
To just print a simpler coverage report to the console.
```bash
-make backend-coverage
+npm run backend:coverage
```
diff --git a/docs/development/frontend.md b/docs/development/frontend.md
index 190c304d478..6d7b091f52e 100644
--- a/docs/development/frontend.md
+++ b/docs/development/frontend.md
@@ -15,13 +15,13 @@ The frontend is written in Typescript and React, as well as a few other importan
The frontend can be quickly built using:
```bash
-make frontend
+npm run frontend:build
```
Once built, it can be run in development mode (auto-refresh) using:
```bash
-make run-frontend
+npm run frontend:start
```
This command leverages the `create-react-app`'s start script that launches
@@ -35,7 +35,7 @@ for network request, if you need the devtools for react-query, you can simply se
API documentation for TypeScript is done with [typedoc](https://typedoc.org/) and [typedoc-plugin-markdown](https://github.com/tgreyuk/typedoc-plugin-markdown), and is configured in tsconfig.json
```bash
-make docs
+npm run docs
```
The API output markdown is generated in docs/development/api and is not
@@ -49,7 +49,7 @@ Components can be discovered, developed, and tested inside the 'storybook'.
From within the [Headlamp](https://github.com/kubernetes-sigs/headlamp/) repo run:
```bash
-make storybook
+npm run frontend:storybook
```
If you are adding new stories, please wrap your story components with the `TestContext` helper
@@ -75,7 +75,7 @@ Any issues found are reported in the developer console.
To enable the alert message during development, use the following:
```bash
-REACT_APP_SKIP_A11Y=false make run-frontend
+REACT_APP_SKIP_A11Y=false npm run frontend:start
```
This shows an alert when an a11y issue is detected.
diff --git a/docs/development/i18n/contributing.md b/docs/development/i18n/contributing.md
index 0bfa660368f..1c962fe433f 100644
--- a/docs/development/i18n/contributing.md
+++ b/docs/development/i18n/contributing.md
@@ -91,7 +91,7 @@ Here's an example of using date formatting:
Create a folder using the locale code in:
`frontend/src/i18n/locales/`
-Then run `make i18n`. This command parses the translatable strings in
+Then run `npm run i18n`. This command parses the translatable strings in
the project and creates the corresponding catalog files.
Integrated components may need to be adjusted (MaterialUI/Monaco etc).
diff --git a/docs/development/index.md b/docs/development/index.md
index 4daa85bd075..ee060c93be1 100644
--- a/docs/development/index.md
+++ b/docs/development/index.md
@@ -16,46 +16,60 @@ These are the required dependencies to get started. Other dependencies are pulle
- [Node.js](https://nodejs.org/en/download/) Latest LTS (20.11.1 at time of writing). Many of us use [nvm](https://github.com/nvm-sh/nvm) for installing multiple versions of Node.
- [Go](https://go.dev/doc/install), (1.24 at time of writing)
-- [Make](https://www.gnu.org/software/make/) (GNU). Often installed by default. On Windows this can be installed with the "chocolatey" package manager that is installed with node.
- [Kubernetes](https://kubernetes.io/), we suggest [minikube](https://minikube.sigs.k8s.io/docs/) as one good K8s installation for testing locally. Other k8s installations are supported (see [platforms](../platforms.md).
## Build the code
Headlamp is composed of a `backend` and a `frontend`.
-You can build both the `backend` and `frontend` by running.
+You can build both the `backend` and `frontend` by running:
```bash
-make
+npm run build
```
Or individually:
```bash
-make backend
+npm run backend:build
```
and
```bash
-make frontend
+npm run frontend:build
```
## Run the code
-The quickest way to get the `backend` and `frontend` running for development is
-the following (respectively):
+The quickest way to get the `backend` and `frontend` running for development is to run both together:
```bash
-make run-backend
+npm start
+```
+
+Or you can run them individually in separate terminal instances:
+
+```bash
+npm run backend:start
```
and in a different terminal instance:
```bash
-make run-frontend
+npm run frontend:start
+```
+
+## Generate API documentation
+
+To generate the TypeScript API documentation:
+
+```bash
+npm run docs
```
+This generates API documentation in `docs/development/api/` using TypeDoc.
+
## Build the app
You can build the app for Linux, Windows, or Mac.
@@ -66,15 +80,15 @@ and the linux app on a linux box.
Choose the relevant command:
```bash
-make app-linux
+npm run app:package:linux
```
```bash
-make app-mac
+npm run app:package:mac
```
```bash
-make app-win
+npm run app:package:win
```
For Windows, by default it will produce an installer using [NSIS (Nullsoft Scriptable Install System)](https://sourceforge.net/projects/nsis/).
@@ -90,24 +104,24 @@ set PATH=%PATH%;C:\Program Files (x86)\WiX Toolset v3.11\bin
Then run the following command to generate the `.msi` installer:
```bash
-make app-win-msi
+npm run app:package:win:msi
```
See the generated app files in app/dist/ .
### Running the app
-If you already have **BOTH** the `backend` and `frontend` up and running, the quickest way to
+If you already have **BOTH** the `backend` and `frontend` up and running, the quickest way to
get the `app` running for development is the following:
```bash
-make run-only-app
+npm run app:start:client
```
or else you can simply do
```bash
-make run-app
+npm run start:app
```
which runs everything including the `backend`, `frontend` and `app` in parallel.
@@ -137,16 +151,16 @@ source. It will run the `frontend` from a `backend`'s static server, and
options can be appended to the main command as arguments.
```bash
-make image
+npm run image:build
```
### Custom container base images
The Dockerfile takes a build argument for the base image used. You can specify the
-base image used using the IMAGE_BASE environment variable with make.
+base image used using the IMAGE_BASE environment variable.
```bash
-IMAGE_BASE=debian:latest make image
+IMAGE_BASE=debian:latest npm run image:build
```
If no IMAGE_BASE is specified, then a default image is used (see Dockerfile for exact default image used).
@@ -171,7 +185,7 @@ If you want to make a new container image called `headlamp-k8s/headlamp:developm
you can run it like this:
```bash
-$ DOCKER_IMAGE_VERSION=development make image
+$ DOCKER_IMAGE_VERSION=development npm run image:build
...
Successfully tagged headlamp-k8s/headlamp:development
@@ -196,7 +210,7 @@ ones made in the local docker environment.
```bash
eval $(minikube docker-env)
-DOCKER_IMAGE_VERSION=development make image
+DOCKER_IMAGE_VERSION=development npm run image:build
```
#### Create a deployment yaml
diff --git a/docs/installation/base-url.md b/docs/installation/base-url.md
index be9fdf3b992..b84979a48f8 100644
--- a/docs/installation/base-url.md
+++ b/docs/installation/base-url.md
@@ -22,7 +22,7 @@ If in doubt, host Headlamp on a separate origin (domain or port, don't use the `
```bash
./backend/headlamp-server -dev -base-url /headlamp
-PUBLIC_URL="/headlamp" make run-frontend
+PUBLIC_URL="/headlamp" npm run frontend:start
```
Then go to in your browser.
@@ -30,7 +30,7 @@ Then go to in your browser.
### Static build mode
```bash
-cd frontend && npm install && npm run build && cd ..
+npm run frontend:build
./backend/headlamp-server -dev -base-url /headlamp -html-static-dir frontend/build
```
diff --git a/e2e-tests/README.md b/e2e-tests/README.md
index e1273ae33d4..6a6a1ec85ad 100644
--- a/e2e-tests/README.md
+++ b/e2e-tests/README.md
@@ -153,7 +153,7 @@ npx playwright test -g "404 page is present" --headed
- Inside `.github/workflows/build-container.yml` is the source line we need, locate the step for building the image and run in your terminal:
```
- DOCKER_IMAGE_VERSION=latest make image
+ DOCKER_IMAGE_VERSION=latest npm run image:build
```
2. **Tag and push the Docker image to a registry (e.g., ttl.sh):**
From 89f244793834299f094fea9455e8b1c42b72fb73 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Dudfield?=
Date: Wed, 22 Oct 2025 08:55:43 -0300
Subject: [PATCH 11/72] frontend: components: Fix isDrawerMode fetch when state
not there
There are common components that require this state that maybe should
not depend on it being set.
For testing individual components that do not even use the drawer
functionality we make it so these components do not fail when
the state is not set.
---
frontend/src/components/App/Settings/DrawerModeSettings.tsx | 2 +-
frontend/src/components/common/Link.tsx | 2 +-
frontend/src/components/common/Resource/DetailsDrawer.tsx | 2 +-
frontend/src/components/globalSearch/GlobalSearchContent.tsx | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/frontend/src/components/App/Settings/DrawerModeSettings.tsx b/frontend/src/components/App/Settings/DrawerModeSettings.tsx
index df7195fb048..459c909843a 100644
--- a/frontend/src/components/App/Settings/DrawerModeSettings.tsx
+++ b/frontend/src/components/App/Settings/DrawerModeSettings.tsx
@@ -143,7 +143,7 @@ const OptionButton = ({
export default function DrawerModeSettings() {
const dispatch = useDispatch();
- const isDrawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled);
+ const isDrawerEnabled = useTypedSelector(state => state?.drawerMode?.isDetailDrawerEnabled);
return (
diff --git a/frontend/src/components/common/Link.tsx b/frontend/src/components/common/Link.tsx
index ac31abfad71..2136a4127c8 100644
--- a/frontend/src/components/common/Link.tsx
+++ b/frontend/src/components/common/Link.tsx
@@ -142,7 +142,7 @@ function PureLink(
}
export default function Link(props: React.PropsWithChildren) {
- const drawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled);
+ const drawerEnabled = useTypedSelector(state => state?.drawerMode?.isDetailDrawerEnabled);
const { tooltip, ...propsRest } = props as LinkObjectProps;
diff --git a/frontend/src/components/common/Resource/DetailsDrawer.tsx b/frontend/src/components/common/Resource/DetailsDrawer.tsx
index af04f977596..34122e8b21f 100644
--- a/frontend/src/components/common/Resource/DetailsDrawer.tsx
+++ b/frontend/src/components/common/Resource/DetailsDrawer.tsx
@@ -30,7 +30,7 @@ export default function DetailsDrawer() {
const dispatch = useDispatch();
const theme = useTheme();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
- const isDetailDrawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled);
+ const isDetailDrawerEnabled = useTypedSelector(state => state?.drawerMode?.isDetailDrawerEnabled);
function closeDrawer() {
dispatch(setSelectedResource(undefined));
diff --git a/frontend/src/components/globalSearch/GlobalSearchContent.tsx b/frontend/src/components/globalSearch/GlobalSearchContent.tsx
index 12664bf6350..b80750c4d81 100644
--- a/frontend/src/components/globalSearch/GlobalSearchContent.tsx
+++ b/frontend/src/components/globalSearch/GlobalSearchContent.tsx
@@ -172,7 +172,7 @@ export function GlobalSearchContent({
const [query, setQuery] = useState(defaultValue ?? '');
const clusters = useClustersConf() ?? {};
const selectedClusters = useSelectedClusters();
- const drawerEnabled = useTypedSelector(state => state.drawerMode.isDetailDrawerEnabled);
+ const drawerEnabled = useTypedSelector(state => state?.drawerMode?.isDetailDrawerEnabled);
const [recent, bump] = useRecent('search-recent-items');
From 404aabfb03031aca3c76c1388e9f79787aeeedd3 Mon Sep 17 00:00:00 2001
From: Evangelos
Date: Mon, 20 Oct 2025 09:15:22 -0400
Subject: [PATCH 12/72] backend: serviceproxy: Extract tests for TestGet
---
backend/pkg/serviceproxy/connection_test.go | 62 ++++++++++-----------
1 file changed, 31 insertions(+), 31 deletions(-)
diff --git a/backend/pkg/serviceproxy/connection_test.go b/backend/pkg/serviceproxy/connection_test.go
index 3bdb1e6bcb9..53f4cf153b8 100644
--- a/backend/pkg/serviceproxy/connection_test.go
+++ b/backend/pkg/serviceproxy/connection_test.go
@@ -41,38 +41,38 @@ func TestNewConnection(t *testing.T) {
}
}
-func TestGet(t *testing.T) {
- tests := []struct {
- name string
- uri string
- requestURI string
- wantBody []byte
- wantErr bool
- }{
- {
- name: "valid request",
- uri: "http://example.com",
- requestURI: "/test",
- wantBody: []byte("Hello, World!"),
- wantErr: false,
- },
- {
- name: "invalid URI",
- uri: " invalid-uri",
- requestURI: "/test",
- wantBody: nil,
- wantErr: true,
- },
- {
- name: "invalid request URI",
- uri: "http://example.com",
- requestURI: " invalid-request-uri",
- wantBody: nil,
- wantErr: true,
- },
- }
+var getTests = []struct {
+ name string
+ uri string
+ requestURI string
+ wantBody []byte
+ wantErr bool
+}{
+ {
+ name: "valid request",
+ uri: "http://example.com",
+ requestURI: "/test",
+ wantBody: []byte("Hello, World!"),
+ wantErr: false,
+ },
+ {
+ name: "invalid URI",
+ uri: " invalid-uri",
+ requestURI: "/test",
+ wantBody: nil,
+ wantErr: true,
+ },
+ {
+ name: "invalid request URI",
+ uri: "http://example.com",
+ requestURI: " invalid-request-uri",
+ wantBody: nil,
+ wantErr: true,
+ },
+}
- for _, tt := range tests {
+func TestGet(t *testing.T) {
+ for _, tt := range getTests {
t.Run(tt.name, func(t *testing.T) {
conn := &Connection{URI: tt.uri}
From c460e04a9f3baa4fd5d45c870ebcb968c12d5444 Mon Sep 17 00:00:00 2001
From: Evangelos
Date: Mon, 20 Oct 2025 07:46:25 -0400
Subject: [PATCH 13/72] backend: serviceproxy: Restrict requests to relative
paths
This change restricts service proxy requests to relative paths,
preventing uncontrolled data from being used in network requests.
---
backend/pkg/serviceproxy/connection.go | 4 ++++
backend/pkg/serviceproxy/connection_test.go | 7 +++++++
2 files changed, 11 insertions(+)
diff --git a/backend/pkg/serviceproxy/connection.go b/backend/pkg/serviceproxy/connection.go
index 834dbe08c4f..292be596119 100644
--- a/backend/pkg/serviceproxy/connection.go
+++ b/backend/pkg/serviceproxy/connection.go
@@ -35,6 +35,10 @@ func (c *Connection) Get(requestURI string) ([]byte, error) {
return nil, fmt.Errorf("invalid request uri: %w", err)
}
+ if rel.IsAbs() {
+ return nil, fmt.Errorf("request uri must be a relative path")
+ }
+
fullURL := base.ResolveReference(rel)
body, err := HTTPGet(context.Background(), fullURL.String())
diff --git a/backend/pkg/serviceproxy/connection_test.go b/backend/pkg/serviceproxy/connection_test.go
index 53f4cf153b8..71d4490cae6 100644
--- a/backend/pkg/serviceproxy/connection_test.go
+++ b/backend/pkg/serviceproxy/connection_test.go
@@ -69,6 +69,13 @@ var getTests = []struct {
wantBody: nil,
wantErr: true,
},
+ {
+ name: "absolute request URI rejected",
+ uri: "http://example.com",
+ requestURI: "http://malicious.local",
+ wantBody: nil,
+ wantErr: true,
+ },
}
func TestGet(t *testing.T) {
From f3a7dce26ef227a3ae8ca5cecac36557f6de71d0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Dudfield?=
Date: Sun, 19 Oct 2025 01:59:25 -0300
Subject: [PATCH 14/72] headlamp-plugin/config/plugins-tsconfig.json: Enable
checkJS
This makes hovering functions imported from places like
headlamp-plugin/lib to show the function definition and documentation.
For some reason without that it just says "import type" or so.
If you imported from places like lib/plugins/registry where the
declarations actually are it also works. It's just places that
import from somewhere and export.
The docs for checkJs say it enables checking js files, so it might
be related to that, because the compiled files inside of headlamp-plugin
are .js files and declarations.
Docs for checkJs https://www.typescriptlang.org/tsconfig/#checkJs
---
plugins/headlamp-plugin/config/plugins-tsconfig.json | 1 +
1 file changed, 1 insertion(+)
diff --git a/plugins/headlamp-plugin/config/plugins-tsconfig.json b/plugins/headlamp-plugin/config/plugins-tsconfig.json
index 4bb2963a3d4..99ef927f478 100644
--- a/plugins/headlamp-plugin/config/plugins-tsconfig.json
+++ b/plugins/headlamp-plugin/config/plugins-tsconfig.json
@@ -7,6 +7,7 @@
"baseUrl": "../../../../",
"esModuleInterop": true,
"allowJs": true,
+ "checkJs": true,
"types": ["vite/client", "vite-plugin-svgr/client", "vitest/globals", "lodash"],
"paths": {
"@iconify/react": [
From 2dfa9918950976cf3eed682d8510a434afc44c65 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:53:33 -0400
Subject: [PATCH 15/72] frontend: Bump vite to 6.4.1
---
frontend/package-lock.json | 8 ++++----
frontend/package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 4a6e7660c7d..cc0b67a2811 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -84,7 +84,7 @@
"simple-eval": "^2.0.0",
"spacetime": "^7.4.0",
"typescript": "5.6.2",
- "vite": "^6.3.6",
+ "vite": "^6.4.1",
"vite-plugin-node-polyfills": "^0.23.0",
"vite-plugin-static-copy": "^3.1.2",
"vite-plugin-svgr": "^4.3.0"
@@ -15400,9 +15400,9 @@
"dev": true
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
diff --git a/frontend/package.json b/frontend/package.json
index 4581660e9f5..4b17cad2680 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -85,7 +85,7 @@
"simple-eval": "^2.0.0",
"spacetime": "^7.4.0",
"typescript": "5.6.2",
- "vite": "^6.3.6",
+ "vite": "^6.4.1",
"vite-plugin-node-polyfills": "^0.23.0",
"vite-plugin-static-copy": "^3.1.2",
"vite-plugin-svgr": "^4.3.0"
From ae9a8d86fe0b0b20fcf20f3cb5a12f7d6afbddb2 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:54:14 -0400
Subject: [PATCH 16/72] headlamp-plugin: Bump vite to 6.4.1
---
plugins/headlamp-plugin/package-lock.json | 8 ++++----
plugins/headlamp-plugin/package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/plugins/headlamp-plugin/package-lock.json b/plugins/headlamp-plugin/package-lock.json
index fbfc1cfa892..5125f75f8ef 100644
--- a/plugins/headlamp-plugin/package-lock.json
+++ b/plugins/headlamp-plugin/package-lock.json
@@ -105,7 +105,7 @@
"ts-loader": "^9.5.2",
"typescript": "5.6.2",
"validate-npm-package-name": "^3.0.0",
- "vite": "^6.3.6",
+ "vite": "^6.4.1",
"vite-plugin-css-injected-by-js": "^3.5.1",
"vite-plugin-node-polyfills": "^0.23.0",
"vite-plugin-static-copy": "^3.1.2",
@@ -15800,9 +15800,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
diff --git a/plugins/headlamp-plugin/package.json b/plugins/headlamp-plugin/package.json
index 630336ccc4a..c8a0bd7bc5b 100644
--- a/plugins/headlamp-plugin/package.json
+++ b/plugins/headlamp-plugin/package.json
@@ -110,7 +110,7 @@
"ts-loader": "^9.5.2",
"typescript": "5.6.2",
"validate-npm-package-name": "^3.0.0",
- "vite": "^6.3.6",
+ "vite": "^6.4.1",
"vite-plugin-css-injected-by-js": "^3.5.1",
"vite-plugin-node-polyfills": "^0.23.0",
"vite-plugin-static-copy": "^3.1.2",
From 4c75f441476ce54be496e8cb75f8c37a4c19fc00 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 14:02:20 -0400
Subject: [PATCH 17/72] headlamp-plugin/template: Bump vite to 6.4.1
---
plugins/headlamp-plugin/template/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/headlamp-plugin/template/package-lock.json b/plugins/headlamp-plugin/template/package-lock.json
index 7d5816238b7..8d3967c8f8f 100644
--- a/plugins/headlamp-plugin/template/package-lock.json
+++ b/plugins/headlamp-plugin/template/package-lock.json
@@ -17048,9 +17048,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"dependencies": {
"esbuild": "^0.25.0",
From d15a8a05da95411ce9c7bdc1e130e2a955370c5b Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:54:27 -0400
Subject: [PATCH 18/72] plugins/examples/app-menus: Bump vite to 6.4.1
---
plugins/examples/app-menus/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/app-menus/package-lock.json b/plugins/examples/app-menus/package-lock.json
index 7dfb7f112c6..61836b32790 100644
--- a/plugins/examples/app-menus/package-lock.json
+++ b/plugins/examples/app-menus/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From cf29f4858ab3a2e6664cfa9e4279a120cc893d69 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:54:37 -0400
Subject: [PATCH 19/72] plugins/examples/change-logo: Bump vite to 6.4.1
---
plugins/examples/change-logo/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/change-logo/package-lock.json b/plugins/examples/change-logo/package-lock.json
index 2c5004a890e..026ec5186c1 100644
--- a/plugins/examples/change-logo/package-lock.json
+++ b/plugins/examples/change-logo/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 84c866a8369d3bd6a7e95a7f8ce631b7fccb35d8 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:54:47 -0400
Subject: [PATCH 20/72] plugins/examples/cluster-chooser: Bump vite to 6.4.1
---
plugins/examples/cluster-chooser/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/cluster-chooser/package-lock.json b/plugins/examples/cluster-chooser/package-lock.json
index ecee2c86a8d..a557d5b638a 100644
--- a/plugins/examples/cluster-chooser/package-lock.json
+++ b/plugins/examples/cluster-chooser/package-lock.json
@@ -17188,9 +17188,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 0d1207b44c015963e52162c9c1d9060cdb199cb0 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:54:59 -0400
Subject: [PATCH 21/72] plugins/examples/custom-theme: Bump vite to 6.4.1
---
plugins/examples/custom-theme/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/custom-theme/package-lock.json b/plugins/examples/custom-theme/package-lock.json
index a39a143f2eb..d10876ef6d3 100644
--- a/plugins/examples/custom-theme/package-lock.json
+++ b/plugins/examples/custom-theme/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 78a62d6325e4ac3f91377ea16fb12dcd21e164c5 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:55:11 -0400
Subject: [PATCH 22/72] plugins/examples/customizing-map: Bump vite to 6.4.1
---
plugins/examples/customizing-map/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/customizing-map/package-lock.json b/plugins/examples/customizing-map/package-lock.json
index 2b12052024c..6052e21e976 100644
--- a/plugins/examples/customizing-map/package-lock.json
+++ b/plugins/examples/customizing-map/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 8c7537bf395d088e7c1c72afdcb2acc022bf8a33 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:55:19 -0400
Subject: [PATCH 23/72] plugins/examples/details-view: Bump vite to 6.4.1
---
plugins/examples/details-view/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/details-view/package-lock.json b/plugins/examples/details-view/package-lock.json
index cded57417a8..5db41748a29 100644
--- a/plugins/examples/details-view/package-lock.json
+++ b/plugins/examples/details-view/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 44ffbc392f500d0712b091c1594c868e0527e900 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:55:31 -0400
Subject: [PATCH 24/72] plugins/examples/dynamic-clusters: Bump vite to 6.4.1
---
plugins/examples/dynamic-clusters/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/dynamic-clusters/package-lock.json b/plugins/examples/dynamic-clusters/package-lock.json
index 1fe7d7b679f..7da721cfe9d 100644
--- a/plugins/examples/dynamic-clusters/package-lock.json
+++ b/plugins/examples/dynamic-clusters/package-lock.json
@@ -16301,9 +16301,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 729fd37e67679282d8886ffd83335c4b9b007259 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:55:45 -0400
Subject: [PATCH 25/72] plugins/examples/headlamp-events: Bump vite to 6.4.1
---
plugins/examples/headlamp-events/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/headlamp-events/package-lock.json b/plugins/examples/headlamp-events/package-lock.json
index 1864316b9d8..57eda579c82 100644
--- a/plugins/examples/headlamp-events/package-lock.json
+++ b/plugins/examples/headlamp-events/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 5a45f10b7568ace022f6817ff2abcd474d75d3c2 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:55:54 -0400
Subject: [PATCH 26/72] plugins/examples/pod-counter: Bump vite to 6.4.1
---
plugins/examples/pod-counter/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/pod-counter/package-lock.json b/plugins/examples/pod-counter/package-lock.json
index 030aefefd86..e54e0e33fa8 100644
--- a/plugins/examples/pod-counter/package-lock.json
+++ b/plugins/examples/pod-counter/package-lock.json
@@ -17188,9 +17188,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From f56e09d56c769a0bcf916b94db4a7e87533cd119 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:56:05 -0400
Subject: [PATCH 27/72] plugins/examples/projects: Bump vite to 6.4.1
---
plugins/examples/projects/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/projects/package-lock.json b/plugins/examples/projects/package-lock.json
index d5df86ba0f3..262290a4cc6 100644
--- a/plugins/examples/projects/package-lock.json
+++ b/plugins/examples/projects/package-lock.json
@@ -16307,9 +16307,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From a355055961e609ffa8dd7c419960aa1149b00f10 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:56:15 -0400
Subject: [PATCH 28/72] plugins/examples/resource-charts: Bump vite to 6.4.1
---
plugins/examples/resource-charts/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/resource-charts/package-lock.json b/plugins/examples/resource-charts/package-lock.json
index ffa663bc672..99be2585119 100644
--- a/plugins/examples/resource-charts/package-lock.json
+++ b/plugins/examples/resource-charts/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 17fa7ccc6bc5cf024d6d7c2f67e2bc659e88d3ab Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:56:24 -0400
Subject: [PATCH 29/72] plugins/examples/sidebar: Bump vite to 6.4.1
---
plugins/examples/sidebar/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/sidebar/package-lock.json b/plugins/examples/sidebar/package-lock.json
index 152969f206f..fbd857574e7 100644
--- a/plugins/examples/sidebar/package-lock.json
+++ b/plugins/examples/sidebar/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 241f4a7db68668c516142b24201d2e7bcaefe0f8 Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:56:31 -0400
Subject: [PATCH 30/72] plugins/examples/tables: Bump vite to 6.4.1
---
plugins/examples/tables/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/tables/package-lock.json b/plugins/examples/tables/package-lock.json
index ff90f109a64..e69d6be01d8 100644
--- a/plugins/examples/tables/package-lock.json
+++ b/plugins/examples/tables/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 135c069003d6e72a10fb15ce4a764972c0b5e05e Mon Sep 17 00:00:00 2001
From: Evangelos Skopelitis
Date: Tue, 21 Oct 2025 13:56:56 -0400
Subject: [PATCH 31/72] plugins/examples/ui-panels: Bump vite to 6.4.1
---
plugins/examples/ui-panels/package-lock.json | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/plugins/examples/ui-panels/package-lock.json b/plugins/examples/ui-panels/package-lock.json
index 9bd98708dbf..b638418f5a9 100644
--- a/plugins/examples/ui-panels/package-lock.json
+++ b/plugins/examples/ui-panels/package-lock.json
@@ -17187,9 +17187,9 @@
"license": "MIT"
},
"node_modules/vite": {
- "version": "6.3.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz",
- "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==",
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"dev": true,
"license": "MIT",
"dependencies": {
From 59276ace7cd856612ce2490ee466f5a452086c65 Mon Sep 17 00:00:00 2001
From: Evangelos
Date: Mon, 20 Oct 2025 07:29:10 -0400
Subject: [PATCH 32/72] frontend: resourceMap: Display valid dates for events
This change fixes the "Invalid Date" on map events and displays them
properly in the UI.
---
.../resourceMap/KubeObjectGlance/KubeObjectGlance.tsx | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/frontend/src/components/resourceMap/KubeObjectGlance/KubeObjectGlance.tsx b/frontend/src/components/resourceMap/KubeObjectGlance/KubeObjectGlance.tsx
index d48b68ae18e..79a1b6a2761 100644
--- a/frontend/src/components/resourceMap/KubeObjectGlance/KubeObjectGlance.tsx
+++ b/frontend/src/components/resourceMap/KubeObjectGlance/KubeObjectGlance.tsx
@@ -21,7 +21,7 @@ import { useTranslation } from 'react-i18next';
import { KubeObject } from '../../../lib/k8s/cluster';
import Deployment from '../../../lib/k8s/deployment';
import Endpoints from '../../../lib/k8s/endpoints';
-import Event from '../../../lib/k8s/event';
+import Event, { KubeEvent } from '../../../lib/k8s/event';
import HPA from '../../../lib/k8s/hpa';
import Pod from '../../../lib/k8s/pod';
import ReplicaSet from '../../../lib/k8s/replicaSet';
@@ -41,7 +41,9 @@ export const KubeObjectGlance = memo(({ resource }: { resource: KubeObject }) =>
const { t } = useTranslation();
const [events, setEvents] = useState([]);
useEffect(() => {
- Event.objectEvents(resource).then(it => setEvents(it));
+ Event.objectEvents(resource).then(fetchedEvents =>
+ setEvents(fetchedEvents.map((event: KubeEvent) => new Event(event)))
+ );
}, []);
const kind = resource.kind;
From 7db4e559374074167feedea75021813b04bc4e22 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 20 Oct 2025 18:57:58 +0000
Subject: [PATCH 33/72] build(deps): bump playwright and @playwright/test in
/e2e-tests
Bumps [playwright](https://github.com/microsoft/playwright) to 1.56.1 and updates ancestor dependency [@playwright/test](https://github.com/microsoft/playwright). These dependencies need to be updated together.
Updates `playwright` from 1.42.1 to 1.56.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.42.1...v1.56.1)
Updates `@playwright/test` from 1.42.1 to 1.56.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.42.1...v1.56.1)
---
updated-dependencies:
- dependency-name: playwright
dependency-version: 1.56.1
dependency-type: indirect
- dependency-name: "@playwright/test"
dependency-version: 1.56.1
dependency-type: direct:development
...
Signed-off-by: dependabot[bot]
---
e2e-tests/package-lock.json | 50 ++++++++++++++++++-------------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/e2e-tests/package-lock.json b/e2e-tests/package-lock.json
index f1ca54ab23a..dbec72cb2f3 100644
--- a/e2e-tests/package-lock.json
+++ b/e2e-tests/package-lock.json
@@ -30,18 +30,18 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz",
- "integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
+ "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
"dev": true,
"dependencies": {
- "playwright": "1.42.1"
+ "playwright": "1.56.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/@types/node": {
@@ -77,32 +77,32 @@
}
},
"node_modules/playwright": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz",
- "integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
+ "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"dev": true,
"dependencies": {
- "playwright-core": "1.42.1"
+ "playwright-core": "1.56.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz",
- "integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
+ "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/undici-types": {
@@ -130,12 +130,12 @@
}
},
"@playwright/test": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.42.1.tgz",
- "integrity": "sha512-Gq9rmS54mjBL/7/MvBaNOBwbfnh7beHvS6oS4srqXFcQHpQCV1+c8JXWE8VLPyRDhgS3H8x8A7hztqI9VnwrAQ==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
+ "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
"dev": true,
"requires": {
- "playwright": "1.42.1"
+ "playwright": "1.56.1"
}
},
"@types/node": {
@@ -160,19 +160,19 @@
"optional": true
},
"playwright": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.42.1.tgz",
- "integrity": "sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
+ "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"dev": true,
"requires": {
"fsevents": "2.3.2",
- "playwright-core": "1.42.1"
+ "playwright-core": "1.56.1"
}
},
"playwright-core": {
- "version": "1.42.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.42.1.tgz",
- "integrity": "sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA=="
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
+ "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ=="
},
"undici-types": {
"version": "5.26.5",
From 74057052003aa889faddd651f931986862b0c470 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 23 Oct 2025 20:58:38 +0000
Subject: [PATCH 34/72] build(deps): bump playwright and @playwright/test in
/app/e2e-tests
Bumps [playwright](https://github.com/microsoft/playwright) to 1.56.1 and updates ancestor dependency [@playwright/test](https://github.com/microsoft/playwright). These dependencies need to be updated together.
Updates `playwright` from 1.48.1 to 1.56.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.48.1...v1.56.1)
Updates `@playwright/test` from 1.48.1 to 1.56.1
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.48.1...v1.56.1)
---
updated-dependencies:
- dependency-name: playwright
dependency-version: 1.56.1
dependency-type: indirect
- dependency-name: "@playwright/test"
dependency-version: 1.56.1
dependency-type: direct:development
...
Signed-off-by: dependabot[bot]
---
app/e2e-tests/package-lock.json | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/app/e2e-tests/package-lock.json b/app/e2e-tests/package-lock.json
index 8ee2f7b8a9c..2733c2ad3bf 100644
--- a/app/e2e-tests/package-lock.json
+++ b/app/e2e-tests/package-lock.json
@@ -14,13 +14,13 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.48.1",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz",
- "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
+ "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.48.1"
+ "playwright": "1.56.1"
},
"bin": {
"playwright": "cli.js"
@@ -55,13 +55,13 @@
}
},
"node_modules/playwright": {
- "version": "1.48.1",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz",
- "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
+ "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.48.1"
+ "playwright-core": "1.56.1"
},
"bin": {
"playwright": "cli.js"
@@ -74,9 +74,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.48.1",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz",
- "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==",
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
+ "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
From 5cd99bb0c57aa06e2245639d9b21b44c2bcd52aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Dudfield?=
Date: Fri, 24 Oct 2025 15:02:48 -0300
Subject: [PATCH 35/72] .github/build-container.yml: Cleanup disk space to
avoid running out
Sometimes this job is running out of disk space.
---
.github/workflows/build-container.yml | 37 +++++++++++++++++----------
1 file changed, 24 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/build-container.yml b/.github/workflows/build-container.yml
index 91a386a27ce..0265125c6e5 100644
--- a/.github/workflows/build-container.yml
+++ b/.github/workflows/build-container.yml
@@ -51,20 +51,21 @@ jobs:
- name: Try the cluster!
run: kubectl get pods -A
- name: Restore image-cache Folder
- id: cache-image-restore
+ id: cache-image-restore2
uses: actions/cache/restore@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
with:
path: ~/image-cache
# cache the container image. All the paths this PR depends on except the e2e-tests folder for the key.
key: ${{ runner.os }}-image-${{ hashFiles('backend/pkg/**', 'backend/cmd/**', 'backend/go.*', 'frontend/src/**', 'frontend/package.json', 'frontend/package-lock.json', 'Makefile', '.github/workflows/build-container.yml', 'Dockerfile', 'Dockerfile.plugins') }}
- name: Restore Cached Docker Images
- if: steps.cache-image-restore.outputs.cache-hit == 'true'
+ if: steps.cache-image-restore2.outputs.cache-hit == 'true'
run: |
export SHELL=/bin/bash
- docker load -i ~/image-cache/headlamp-plugins-test.tar
- docker load -i ~/image-cache/headlamp.tar
+ mkdir -p ~/image-cache
+ gzip -dc ~/image-cache/headlamp-plugins-test.tar.gz | docker load
+ gzip -dc ~/image-cache/headlamp.tar.gz | docker load
- name: Make a .plugins folder for testing later
- if: steps.cache-image-restore.outputs.cache-hit != 'true'
+ if: steps.cache-image-restore2.outputs.cache-hit != 'true'
run: |
echo "Extract pod-counter plugin into .plugins folder, which will be copied into image later by 'make image'."
cd plugins/examples/pod-counter
@@ -77,12 +78,12 @@ jobs:
cd ../../
ls -laR .plugins
- name: Remove unnecessary files
- if: steps.cache-image-restore.outputs.cache-hit != 'true'
+ if: steps.cache-image-restore2.outputs.cache-hit != 'true'
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
- name: Build image
- if: steps.cache-image-restore.outputs.cache-hit != 'true'
+ if: steps.cache-image-restore2.outputs.cache-hit != 'true'
run: |
export SHELL=/bin/bash
DOCKER_IMAGE_VERSION=latest make image
@@ -95,7 +96,7 @@ jobs:
kind load docker-image ghcr.io/headlamp-k8s/headlamp-plugins-test:latest --name test
kind load docker-image ghcr.io/headlamp-k8s/headlamp:latest --name test
- name: Test .plugins folder
- if: steps.cache-image-restore.outputs.cache-hit != 'true'
+ if: steps.cache-image-restore2.outputs.cache-hit != 'true'
run: |
export SHELL=/bin/bash
echo "----------------------------"
@@ -186,20 +187,30 @@ jobs:
else
echo "Playwright tests passed successfully"
fi
+ # Clear disk space by removing unnecessary files, apt files and uninstall some playwright dependencies
+ - name: Clear Disk Space
+ if: steps.cache-image-restore2.outputs.cache-hit != 'true'
+ run: |
+ export SHELL=/bin/bash
+ sudo rm -rf /var/lib/apt/lists/*
+ sudo apt-get remove -y libgbm-dev libxcb-dri3-0 libxcb-dri2-0 libxcb-xfixes0 libxcb-shape0 libxcb-shm0 libxcb-render0 libxcb-glx0 || true
+ sudo rm -rf e2e-tests/node_modules/
+ kind delete cluster --name test
+ kind delete cluster --name test2
- name: Save Docker Images to Tar files in image-cache Folder
- if: steps.cache-image-restore.outputs.cache-hit != 'true'
+ if: steps.cache-image-restore2.outputs.cache-hit != 'true'
run: |
export SHELL=/bin/bash
mkdir -p ~/image-cache
- docker save -o ~/image-cache/headlamp-plugins-test.tar ghcr.io/headlamp-k8s/headlamp-plugins-test
- docker save -o ~/image-cache/headlamp.tar ghcr.io/headlamp-k8s/headlamp
+ docker save ghcr.io/headlamp-k8s/headlamp-plugins-test | gzip -9 > ~/image-cache/headlamp-plugins-test.tar.gz
+ docker save ghcr.io/headlamp-k8s/headlamp | gzip -9 > ~/image-cache/headlamp.tar.gz
- name: Cache image-cache Folder
- if: steps.cache-image-restore.outputs.cache-hit != 'true'
+ if: steps.cache-image-restore2.outputs.cache-hit != 'true'
id: cache-image-save
uses: actions/cache/save@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1
with:
path: ~/image-cache
- key: ${{ steps.cache-image-restore.outputs.cache-primary-key }}
+ key: ${{ steps.cache-image-restore2.outputs.cache-primary-key }}
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
if: always()
with:
From d108c1ae241f2e2876d54f9a9f6e5e617565ecb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Dudfield?=
Date: Thu, 23 Oct 2025 09:14:58 -0300
Subject: [PATCH 36/72] headlamp-plugin: Add missing
registerProjectDeleteButton export
This is needed for the type checker.
---
plugins/headlamp-plugin/src/index.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/headlamp-plugin/src/index.ts b/plugins/headlamp-plugin/src/index.ts
index a9ded73edbd..f04e8e56e0c 100644
--- a/plugins/headlamp-plugin/src/index.ts
+++ b/plugins/headlamp-plugin/src/index.ts
@@ -66,6 +66,7 @@ import Registry, {
registerMapSource,
registerOverviewChartsProcessor,
registerPluginSettings,
+ registerProjectDeleteButton,
registerProjectDetailsTab,
registerProjectOverviewSection,
registerResourceTableColumnsProcessor,
@@ -129,6 +130,7 @@ export {
registerProjectDetailsTab,
registerProjectOverviewSection,
registerClusterStatus,
+ registerProjectDeleteButton,
};
export type {
From cc491ede2966f10442b6ebc27df8b2def511aecf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Dudfield?=
Date: Thu, 23 Oct 2025 09:33:05 -0300
Subject: [PATCH 37/72] plugins/examples/projects: Fix for using id instead of
name field
The name attribute does not exist on ProjectDefinition.
---
plugins/examples/projects/src/index.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/examples/projects/src/index.tsx b/plugins/examples/projects/src/index.tsx
index cc56d107ce9..1fea4800ca8 100644
--- a/plugins/examples/projects/src/index.tsx
+++ b/plugins/examples/projects/src/index.tsx
@@ -57,7 +57,7 @@ registerProjectDetailsTab({
id: 'my-tab',
label: 'Metrics',
icon: 'mdi:chart-line',
- component: ({ project }) => Metrics for project {project.name}
,
+ component: ({ project }) => Metrics for project {project.id}
,
});
// Example of overriding a default tab - Replace the Access tab with custom content
@@ -156,7 +156,7 @@ registerProjectDetailsTab({
registerProjectOverviewSection({
id: 'resource-usage',
- component: ({ project }) => Custom resource usage for project {project.name}
,
+ component: ({ project }) => Custom resource usage for project {project.id}
,
});
registerProjectDeleteButton({
From ef1147c5c57be5e2a164bf0f9270fbc767506a58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ren=C3=A9=20Dudfield?=
Date: Thu, 23 Oct 2025 09:25:49 -0300
Subject: [PATCH 38/72] frontend: KubeMetadata: Add version of metadata for
creation
When creating KubeMetadata uid and creationTimestamp fields are optional.
Overload apply type signature to take versions without these fields
as well.
---
frontend/src/lib/k8s/KubeMetadata.ts | 22 ++++++++++++++++++++++
frontend/src/lib/k8s/KubeObject.ts | 11 ++++++++++-
frontend/src/lib/k8s/api/v1/apply.ts | 10 +++++++++-
3 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/frontend/src/lib/k8s/KubeMetadata.ts b/frontend/src/lib/k8s/KubeMetadata.ts
index 0087c20a797..cbe2cdc59bd 100644
--- a/frontend/src/lib/k8s/KubeMetadata.ts
+++ b/frontend/src/lib/k8s/KubeMetadata.ts
@@ -149,3 +149,25 @@ export interface KubeMetadata {
uid: string;
apiVersion?: any;
}
+
+/**
+ * KubeMetadataCreate is a version of KubeMetadata for creating objects where uid, creationTimestamp, etc. are optional
+ */
+export interface KubeMetadataCreate extends Omit {
+ /**
+ * UID is the unique in time and space value for this object. It is typically generated by
+ * the server on successful creation of a resource and is not allowed to change on PUT
+ * operations. Populated by the system. Read-only.
+ *
+ * @see {@link https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids | UIDs docs} for more details.
+ *
+ * This is typically generated by the server on successful creation of a resource.
+ */
+ uid?: string;
+ /**
+ * An RFC 3339 date of the date and time an object was created
+ *
+ * This is optional when creating an object; the server will set it for you.
+ */
+ creationTimestamp?: string;
+}
diff --git a/frontend/src/lib/k8s/KubeObject.ts b/frontend/src/lib/k8s/KubeObject.ts
index 61595f926d0..04f2b1a5c8d 100644
--- a/frontend/src/lib/k8s/KubeObject.ts
+++ b/frontend/src/lib/k8s/KubeObject.ts
@@ -32,7 +32,7 @@ import type { ApiError } from './api/v2/ApiError';
import { useKubeObject } from './api/v2/hooks';
import { makeListRequests, useKubeObjectList } from './api/v2/useKubeObjectList';
import type { KubeEvent } from './event';
-import type { KubeMetadata } from './KubeMetadata';
+import type { KubeMetadata, KubeMetadataCreate } from './KubeMetadata';
function getAllowedNamespaces(cluster: string | null = getCluster()): string[] {
if (!cluster) {
@@ -688,6 +688,15 @@ export interface KubeObjectInterface {
key?: any;
[otherProps: string]: any;
}
+
+/**
+ * KubeObjectInterfaceCreate is a version of KubeObjectInterface for creating objects
+ * where uid, creationTimestamp, etc. are optional
+ */
+export interface KubeObjectInterfaceCreate extends Omit {
+ metadata: KubeMetadataCreate;
+}
+
export interface ApiListOptions extends QueryParameters {
/**
* The clusters to list objects from. By default uses the current clusters being viewed.
diff --git a/frontend/src/lib/k8s/api/v1/apply.ts b/frontend/src/lib/k8s/api/v1/apply.ts
index 63b1e02fae7..b91f3576425 100644
--- a/frontend/src/lib/k8s/api/v1/apply.ts
+++ b/frontend/src/lib/k8s/api/v1/apply.ts
@@ -16,7 +16,7 @@
import _ from 'lodash';
import { getCluster } from '../../../cluster';
-import type { KubeObjectInterface } from '../../KubeObject';
+import type { KubeObjectInterface, KubeObjectInterfaceCreate } from '../../KubeObject';
import type { ApiError } from '../v2/ApiError';
import { getClusterDefaultNamespace } from './clusterApi';
import { resourceDefToApiFactory } from './factories';
@@ -26,11 +26,19 @@ import { resourceDefToApiFactory } from './factories';
*
* Tries to POST, and if there's a conflict it does a PUT to the api endpoint.
*
+ * Overloads:
+ * - When called with a KubeObjectInterfaceCreate body, the parameter type is the create type.
+ * - Otherwise it accepts a full KubeObjectInterface.
+ *
* @param body - The kubernetes object body to apply.
* @param clusterName - The cluster to apply the body to. By default uses the current cluster (URL defined).
*
* @returns The response from the kubernetes API server.
*/
+export async function apply(
+ body: T,
+ clusterName?: string
+): Promise;
export async function apply(
body: T,
clusterName?: string
From 0496d48568f506d69a3b811c86d59ae635d9998a Mon Sep 17 00:00:00 2001
From: Clement Aymard
Date: Fri, 24 Oct 2025 16:23:40 +0200
Subject: [PATCH 39/72] charts: fix loadBalancerSourceRanges formatting
This fixes the loadBalancerSourceRanges format after helm
templating.
---
charts/headlamp/templates/service.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/charts/headlamp/templates/service.yaml b/charts/headlamp/templates/service.yaml
index 1a80c333d1b..16a1dd82ec5 100644
--- a/charts/headlamp/templates/service.yaml
+++ b/charts/headlamp/templates/service.yaml
@@ -18,7 +18,7 @@ spec:
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }}
{{- end }}
{{ if (and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerSourceRanges))) }}
- loadBalancerSourceRanges: {{ .Values.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges: {{ .Values.service.loadBalancerSourceRanges | toYaml | nindent 2 }}
{{ end }}
{{- if (and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP))) }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
From 953ec8763649f3a88ae3aac5f2c5870b9c56b323 Mon Sep 17 00:00:00 2001
From: Harsh
Date: Tue, 21 Oct 2025 14:46:07 +0530
Subject: [PATCH 40/72] frontend: Add storybook stories for Layout component
with various states
---
.../src/components/App/Layout.stories.tsx | 282 ++++++++++++++++++
...odeShellSettings.Default.stories.storyshot | 4 +-
.../Layout.Default.stories.storyshot | 113 +++++++
.../Layout.ErrorState.stories.storyshot | 113 +++++++
.../Layout.MultiCluster.stories.storyshot | 113 +++++++
.../Layout.WithClusterRoute.stories.storyshot | 113 +++++++
frontend/src/storybook.test.tsx | 2 +-
7 files changed, 737 insertions(+), 3 deletions(-)
create mode 100644 frontend/src/components/App/Layout.stories.tsx
create mode 100644 frontend/src/components/App/__snapshots__/Layout.Default.stories.storyshot
create mode 100644 frontend/src/components/App/__snapshots__/Layout.ErrorState.stories.storyshot
create mode 100644 frontend/src/components/App/__snapshots__/Layout.MultiCluster.stories.storyshot
create mode 100644 frontend/src/components/App/__snapshots__/Layout.WithClusterRoute.stories.storyshot
diff --git a/frontend/src/components/App/Layout.stories.tsx b/frontend/src/components/App/Layout.stories.tsx
new file mode 100644
index 00000000000..c453eacb22a
--- /dev/null
+++ b/frontend/src/components/App/Layout.stories.tsx
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2025 The Kubernetes Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Meta, StoryFn } from '@storybook/react';
+import { delay, http, HttpResponse } from 'msw';
+import { Provider } from 'react-redux';
+import { MemoryRouter } from 'react-router-dom';
+import store from '../../redux/stores/store';
+import { TestContext } from '../../test';
+import Layout from './Layout';
+
+export default {
+ title: 'App/Layout',
+ component: Layout,
+ parameters: {
+ layout: 'fullscreen',
+ docs: {
+ description: {
+ component:
+ 'The main layout component for Headlamp. It includes the top bar, sidebar, main content area, and handles cluster configuration and routing. This is the primary layout wrapper for the application.',
+ },
+ },
+ msw: {
+ handlers: [
+ // Mock cluster config
+ http.get('http://localhost:4466/config', () =>
+ HttpResponse.json({
+ clusters: {
+ minikube: {
+ name: 'minikube',
+ meta_data: { namespace: 'default' },
+ },
+ production: {
+ name: 'production',
+ meta_data: { namespace: 'default' },
+ },
+ },
+ })
+ ),
+ // Mock plugins
+ http.get('http://localhost:4466/plugins', () => HttpResponse.json([])),
+ // Mock cluster version
+ http.get('http://localhost:4466/version', () =>
+ HttpResponse.json({
+ major: '1',
+ minor: '28',
+ gitVersion: 'v1.28.0',
+ })
+ ),
+ // Mock events
+ http.get('http://localhost:4466/*/api/v1/events', () =>
+ HttpResponse.json({
+ kind: 'EventList',
+ items: [],
+ })
+ ),
+ // Mock namespaces
+ http.get('http://localhost:4466/*/api/v1/namespaces', () =>
+ HttpResponse.json({
+ kind: 'NamespaceList',
+ items: [
+ {
+ metadata: { name: 'default', uid: '1' },
+ spec: {},
+ status: { phase: 'Active' },
+ },
+ ],
+ })
+ ),
+ // Mock CRDs
+ http.get(
+ 'http://localhost:4466/apis/apiextensions.k8s.io/v1/customresourcedefinitions',
+ () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get(
+ 'http://localhost:4466/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions',
+ () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ ],
+ },
+ },
+ decorators: [
+ Story => (
+
+
+
+
+
+
+
+ ),
+ ],
+} as Meta;
+
+const Template: StoryFn = () => ;
+
+export const Default = Template.bind({});
+Default.parameters = {
+ docs: {
+ description: {
+ story: 'The default layout with sidebar, topbar, and main content area.',
+ },
+ },
+};
+
+export const WithClusterRoute = Template.bind({});
+WithClusterRoute.decorators = [
+ Story => (
+
+
+
+
+
+
+
+ ),
+];
+WithClusterRoute.parameters = {
+ docs: {
+ description: {
+ story: 'Layout when viewing a specific cluster route (e.g., /c/minikube/pods).',
+ },
+ },
+};
+
+export const LoadingState = Template.bind({});
+LoadingState.parameters = {
+ docs: {
+ description: {
+ story: 'Layout showing loading state while fetching cluster configuration.',
+ },
+ },
+ storyshots: {
+ disable: true,
+ },
+ msw: {
+ handlers: [
+ // Delay config response to show loading for 5 seconds
+ http.get('http://localhost:4466/config', async () => {
+ await delay(5000);
+ return HttpResponse.json({
+ clusters: {
+ minikube: {
+ name: 'minikube',
+ meta_data: { namespace: 'default' },
+ },
+ },
+ });
+ }),
+ http.get('http://localhost:4466/plugins', () => HttpResponse.json([])),
+ http.get('http://localhost:4466/apis/apiextensions.k8s.io/v1/customresourcedefinitions', () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get(
+ 'http://localhost:4466/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions',
+ () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ ],
+ },
+};
+
+export const ErrorState = Template.bind({});
+ErrorState.parameters = {
+ docs: {
+ description: {
+ story: 'Layout showing error state when cluster configuration fails to load.',
+ },
+ },
+ msw: {
+ handlers: [
+ http.get('http://localhost:4466/config', () => HttpResponse.error()),
+ http.get('http://localhost:4466/plugins', () => HttpResponse.json([])),
+ http.get('http://localhost:4466/apis/apiextensions.k8s.io/v1/customresourcedefinitions', () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get(
+ 'http://localhost:4466/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions',
+ () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ ],
+ },
+};
+
+export const MultiCluster = Template.bind({});
+MultiCluster.decorators = [
+ Story => (
+
+
+
+
+
+
+
+ ),
+];
+MultiCluster.parameters = {
+ docs: {
+ description: {
+ story: 'Layout when viewing multiple clusters simultaneously.',
+ },
+ },
+ msw: {
+ handlers: [
+ http.get('http://localhost:4466/config', () =>
+ HttpResponse.json({
+ clusters: {
+ minikube: {
+ name: 'minikube',
+ meta_data: { namespace: 'default' },
+ },
+ production: {
+ name: 'production',
+ meta_data: { namespace: 'default' },
+ },
+ staging: {
+ name: 'staging',
+ meta_data: { namespace: 'default' },
+ },
+ },
+ })
+ ),
+ http.get('http://localhost:4466/plugins', () => HttpResponse.json([])),
+ http.get('http://localhost:4466/apis/apiextensions.k8s.io/v1/customresourcedefinitions', () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ http.get(
+ 'http://localhost:4466/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions',
+ () =>
+ HttpResponse.json({
+ kind: 'List',
+ items: [],
+ metadata: {},
+ })
+ ),
+ ],
+ },
+};
diff --git a/frontend/src/components/App/Settings/__snapshots__/NodeShellSettings.Default.stories.storyshot b/frontend/src/components/App/Settings/__snapshots__/NodeShellSettings.Default.stories.storyshot
index 17f9761c20e..2fcc03fe65f 100644
--- a/frontend/src/components/App/Settings/__snapshots__/NodeShellSettings.Default.stories.storyshot
+++ b/frontend/src/components/App/Settings/__snapshots__/NodeShellSettings.Default.stories.storyshot
@@ -81,7 +81,7 @@
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-colorPrimary MuiInputBase-formControl MuiInputBase-sizeSmall MuiInputBase-adornedEnd css-14f1a7d-MuiInputBase-root-MuiOutlinedInput-root"
>
+
+
+
+
+
+
+
+