diff --git a/.mcp.json b/.mcp.json index 5f68642aa1..9a08267772 100644 --- a/.mcp.json +++ b/.mcp.json @@ -3,6 +3,19 @@ "mcp-docs": { "type": "http", "url": "https://modelcontextprotocol.io/mcp" + }, + "sequential-thinking": { + "command": "docker", + "args": [ + "run", + "-i", + "--rm", + "-e", "MAX_THOUGHT_LENGTH=5000", + "-e", "MAX_HISTORY_SIZE=100", + "-e", "ENABLE_METRICS=true", + "-e", "ENABLE_HEALTH_CHECKS=true", + "mcp/sequential-thinking" + ] } } } diff --git a/package-lock.json b/package-lock.json index 46db9cb702..df6aad4923 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,9 +33,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -53,13 +53,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -69,14 +69,14 @@ } }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -89,6 +89,33 @@ "dev": true, "license": "MIT" }, + "node_modules/@conventional-changelog/git-client": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.5.1.tgz", + "integrity": "sha512-lAw7iA5oTPWOLjiweb7DlGEMDEvzqzLLa6aWOly2FSZ64IwLE8T458rC+o+WvI31Doz6joM7X2DoNog7mX8r4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/child-process-utils": "^1.0.0", + "@simple-libs/stream-utils": "^1.1.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.1.0" + }, + "peerDependenciesMeta": { + "conventional-commits-filter": { + "optional": true + }, + "conventional-commits-parser": { + "optional": true + } + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -378,6 +405,23 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -395,6 +439,23 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -412,6 +473,23 @@ "node": ">=12" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -480,1591 +558,6255 @@ "node": ">=12" } }, - "node_modules/@hono/node-server": { - "version": "1.19.9", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", - "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18.14.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "hono": "^4" + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "engines": { + "node": "*" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "@eslint/core": "^0.17.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "ansi-regex": "^6.0.1" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@gerrit0/mini-shiki": { + "version": "1.27.2", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-1.27.2.tgz", + "integrity": "sha512-GeWyHz8ao2gBiUW4OJnQDxXQnFgZQwwQk05t/CVVgNBN7/rK8XZ7xY6YhLVv9tH3VppWWmr9DCl3MwemB/i+Og==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, + "@shikijs/engine-oniguruma": "^1.27.2", + "@shikijs/types": "^1.27.2", + "@shikijs/vscode-textmate": "^10.0.1" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18.14.1" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "hono": "^4" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=8" + "node": ">=18.18.0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=18.18.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6.0.0" + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6.0.0" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "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.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" }, "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" + "@types/node": ">=18" }, "peerDependenciesMeta": { - "@cfworker/json-schema": { + "@types/node": { "optional": true - }, - "zod": { - "optional": false } } }, - "node_modules/@modelcontextprotocol/server-everything": { - "resolved": "src/everything", - "link": true - }, - "node_modules/@modelcontextprotocol/server-filesystem": { - "resolved": "src/filesystem", - "link": true - }, - "node_modules/@modelcontextprotocol/server-memory": { - "resolved": "src/memory", - "link": true - }, - "node_modules/@modelcontextprotocol/server-sequential-thinking": { - "resolved": "src/sequentialthinking", - "link": true - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { - "node": ">=14" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", - "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", - "cpu": [ - "arm" - ], + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", - "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", - "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", - "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "engines": { + "node": ">=18" + } }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", - "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", - "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", - "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", - "cpu": [ - "arm" - ], + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", - "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", - "cpu": [ - "arm" - ], + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", - "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", - "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "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.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/server-everything": { + "resolved": "src/everything", + "link": true + }, + "node_modules/@modelcontextprotocol/server-filesystem": { + "resolved": "src/filesystem", + "link": true + }, + "node_modules/@modelcontextprotocol/server-memory": { + "resolved": "src/memory", + "link": true + }, + "node_modules/@modelcontextprotocol/server-sequential-thinking": { + "resolved": "src/sequentialthinking", + "link": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodeutils/defaults-deep": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@nodeutils/defaults-deep/-/defaults-deep-1.1.0.tgz", + "integrity": "sha512-gG44cwQovaOFdSR02jR9IhVRpnDP64VN6JdjYJTfNz4J4fWn7TQnmrf22nSjRqlwlxPcW8PL/L3KbJg3tdwvpg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lodash": "^4.15.0" + } + }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.6.tgz", + "integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.3", + "@octokit/request": "^10.0.6", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.2.tgz", + "integrity": "sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.3.tgz", + "integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.6", + "@octokit/types": "^16.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz", + "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz", + "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz", + "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz", + "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.7", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.7.tgz", + "integrity": "sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.2", + "@octokit/request-error": "^7.0.2", + "@octokit/types": "^16.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.0.tgz", + "integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^16.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/rest": { + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz", + "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.6", + "@octokit/plugin-paginate-rest": "^14.0.0", + "@octokit/plugin-request-log": "^6.0.0", + "@octokit/plugin-rest-endpoint-methods": "^17.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz", + "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^27.0.0" + } + }, + "node_modules/@phun-ky/typeof": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@phun-ky/typeof/-/typeof-2.0.3.tgz", + "integrity": "sha512-oeQJs1aa8Ghke8JIK9yuq/+KjMiaYeDZ38jx7MhkXncXlUKjqQ3wEm2X3qCKyjo+ZZofZj+WsEEiqkTtRuE2xQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.9.0 || >=22.0.0", + "npm": ">=10.8.2" + }, + "funding": { + "url": "https://github.com/phun-ky/typeof?sponsor=1" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@release-it/conventional-changelog": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/@release-it/conventional-changelog/-/conventional-changelog-10.0.5.tgz", + "integrity": "sha512-Dxul3YlUsDLbIg+aR6T0QR/VyKwuJNR3GZM8mKVEwFO8GpH2H5vgnN7kacEvq/Qk5puDadOVbhbUq/KBjraemQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@conventional-changelog/git-client": "^2.5.1", + "concat-stream": "^2.0.0", + "conventional-changelog": "^7.1.1", + "conventional-changelog-angular": "^8.1.0", + "conventional-changelog-conventionalcommits": "^9.1.0", + "conventional-recommended-bump": "^11.2.0", + "semver": "^7.7.3" + }, + "engines": { + "node": "^20.12.0 || >=22.0.0" + }, + "peerDependencies": { + "release-it": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", + "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", + "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", + "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", + "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", + "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", + "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", + "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", + "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", + "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", + "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", + "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", + "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", + "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", + "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", + "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", + "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", + "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", + "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", + "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", + "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", + "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", + "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.29.2.tgz", + "integrity": "sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "1.29.2", + "@shikijs/vscode-textmate": "^10.0.1" + } + }, + "node_modules/@shikijs/types": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.29.2.tgz", + "integrity": "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.1", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@simple-libs/child-process-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-1.0.1.tgz", + "integrity": "sha512-3nWd8irxvDI6v856wpPCHZ+08iQR0oHTZfzAZmnbsLzf+Sf1odraP6uKOHDZToXq3RPRV/LbqGVlSCogm9cJjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@simple-libs/stream-utils": "^1.1.0", + "@types/node": "^22.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@simple-libs/stream-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-1.1.0.tgz", + "integrity": "sha512-6rsHTjodIn/t90lv5snQjRPVtOosM7Vp0AKdrObymq45ojlgVwnpAqdc+0OBBrpEiy31zZ6/TKeIVqV1HwvnuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "^22.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://ko-fi.com/dangreen" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/diff": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.3.tgz", + "integrity": "sha512-K0Oqlrq3kQMaO2RhfrNQX5trmt+XLyom88zS0u84nnIcLvFnRUMRRHmrGny5GSM+kNO9IZLARsdQHDzkhAgmrQ==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", + "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-path": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz", + "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.55.0.tgz", + "integrity": "sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.55.0", + "@typescript-eslint/types": "^8.55.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.55.0.tgz", + "integrity": "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.55.0.tgz", + "integrity": "sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.9.tgz", + "integrity": "sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^0.2.3", + "debug": "^4.3.7", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.12", + "magicast": "^0.3.5", + "std-env": "^3.8.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "2.1.9", + "vitest": "2.1.9" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "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/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "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==", + "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==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.11.tgz", + "integrity": "sha512-Qya9fkoofMjCBNVdWINMjB5KZvkYfaO9/anwkWnjxibpWUxo5iHl2sOdP7/uAqaRuUYuoo8rDwnbaaKVFxoUvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/basic-ftp": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz", + "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/body-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c12": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.3.tgz", + "integrity": "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^17.2.3", + "exsolve": "^1.0.8", + "giget": "^2.0.0", + "jiti": "^2.6.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.0.0", + "pkg-types": "^2.3.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "*" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "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==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "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", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", + "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "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==", + "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==" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "dev": true, + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/conventional-changelog": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-7.1.1.tgz", + "integrity": "sha512-rlqa8Lgh8YzT3Akruk05DR79j5gN9NCglHtJZwpi6vxVeaoagz+84UAtKQj/sT+RsfGaZkt3cdFCjcN6yjr5sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@conventional-changelog/git-client": "^2.5.1", + "@types/normalize-package-data": "^2.4.4", + "conventional-changelog-preset-loader": "^5.0.0", + "conventional-changelog-writer": "^8.2.0", + "conventional-commits-parser": "^6.2.0", + "fd-package-json": "^2.0.0", + "meow": "^13.0.0", + "normalize-package-data": "^7.0.0" + }, + "bin": { + "conventional-changelog": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-angular": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.1.0.tgz", + "integrity": "sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-9.1.0.tgz", + "integrity": "sha512-MnbEysR8wWa8dAEvbj5xcBgJKQlX/m0lhS8DsyAAWDHdfs2faDJxTgzRYlRYpXSe7UiKrIIlB4TrBKU9q9DgkA==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-preset-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-5.0.0.tgz", + "integrity": "sha512-SetDSntXLk8Jh1NOAl1Gu5uLiCNSYenB5tm0YVeZKePRIgDW9lQImromTwLa3c/Gae298tsgOM+/CYT9XAl0NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.2.0.tgz", + "integrity": "sha512-Y2aW4596l9AEvFJRwFGJGiQjt2sBYTjPD18DdvxX9Vpz0Z7HQ+g1Z+6iYDAm1vR3QOJrDBkRHixHK/+FhkR6Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-filter": "^5.0.0", + "handlebars": "^4.7.7", + "meow": "^13.0.0", + "semver": "^7.5.2" + }, + "bin": { + "conventional-changelog-writer": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-filter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", + "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-parser": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.1.tgz", + "integrity": "sha512-20pyHgnO40rvfI0NGF/xiEoFMkXDtkF8FwHvk5BokoFoCuTQRI8vrNCNFWUOfuolKJMm1tPCHc8GgYEtr1XRNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-recommended-bump": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-11.2.0.tgz", + "integrity": "sha512-lqIdmw330QdMBgfL0e6+6q5OMKyIpy4OZNmepit6FS3GldhkG+70drZjuZ0A5NFpze5j85dlYs3GabQXl6sMHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@conventional-changelog/git-client": "^2.5.1", + "conventional-changelog-preset-loader": "^5.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.1.0", + "meow": "^13.0.0" + }, + "bin": { + "conventional-recommended-bump": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "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/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "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/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "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==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/diff": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", + "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "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==" + }, + "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==" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "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==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "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==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eta": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/eta/-/eta-4.5.0.tgz", + "integrity": "sha512-qifAYjuW5AM1eEEIsFnOwB+TGqu6ynU3OKj9WbUTOtUBHFPZqL03XUW34kbp3zm19Ald+U8dEyRXaVsUck+Y1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/bgub/eta?sponsor=1" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.5.tgz", + "integrity": "sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", + "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.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": "8.2.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", + "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "license": "MIT", + "dependencies": { + "ip-address": "10.0.1" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-content-type-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", + "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-package-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-2.0.0.tgz", + "integrity": "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "walk-up-path": "^4.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "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": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "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.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/giget/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/git-up": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz", + "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-ssh": "^1.4.0", + "parse-url": "^9.2.0" + } + }, + "node_modules/git-url-parse": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz", + "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==", + "dev": true, + "license": "MIT", + "dependencies": { + "git-up": "^8.1.0" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "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/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.11.7", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz", + "integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "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==", + "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-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "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/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "12.11.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.11.1.tgz", + "integrity": "sha512-9VF7mrY+3OmsAfjH3yKz/pLbJ5z22E23hENKw3/LNSaA/sAt3v49bDRY+Ygct1xwuKT+U+cBfTzjCPySna69Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/prompts": "^7.10.1", + "@inquirer/type": "^3.0.10", + "mute-stream": "^2.0.0", + "run-async": "^4.0.6", + "rxjs": "^7.8.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "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==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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-ssh": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", + "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "protocols": "^2.0.1" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/issue-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", + "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/macos-release": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.4.0.tgz", + "integrity": "sha512-wpGPwyg/xrSp4H4Db4xYSeAr6+cFQGHfspHzDUdYxswDnUW0L5Ov63UuJiSr8NMSpyaChO4u1n0MXUvVPtrN6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "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/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "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/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, + "license": "MIT" + }, + "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", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 0.6" + } }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", - "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", - "cpu": [ - "loong64" - ], + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">= 0.4.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", - "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", - "cpu": [ - "ppc64" - ], + "node_modules/new-github-release-url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz", + "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "type-fest": "^2.5.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", - "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", - "cpu": [ - "riscv64" + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-7.0.1.tgz", + "integrity": "sha512-linxNAT6M0ebEYZOx2tO6vBEFsVgnPpv+AVjk0wJHfaUIbq31Jm3T6vvZaarnOeWDh8ShnwXuaAyM7WT3RzErA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.5.tgz", + "integrity": "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.2.0", + "pathe": "^2.0.3", + "tinyexec": "^1.0.2" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nypm/node_modules/citty": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.1.tgz", + "integrity": "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/nypm/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/nypm/node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" ], + "license": "MIT" + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "dev": true, + "license": "MIT" + }, + "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==", + "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", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.0.0.tgz", + "integrity": "sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.2.2", + "string-width": "^8.1.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ora/node_modules/string-width": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.1.tgz", + "integrity": "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/os-name": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-6.1.0.tgz", + "integrity": "sha512-zBd1G8HkewNd2A8oQ8c6BN/f/c9EId7rSUueOLGu28govmUctXmM+3765GwsByv9nYUdrLqHphXlYIc86saYsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "macos-release": "^3.3.0", + "windows-release": "^6.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": ">=4" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", - "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", - "cpu": [ - "riscv64" - ], + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", - "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", - "cpu": [ - "s390x" - ], + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", - "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", - "cpu": [ - "x64" - ], + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", - "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", - "cpu": [ - "x64" - ], + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", - "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", - "cpu": [ - "arm64" - ], + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", - "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", - "cpu": [ - "arm64" - ], + "node_modules/parse-path": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "protocols": "^2.0.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", - "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", - "cpu": [ - "ia32" - ], + "node_modules/parse-url": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz", + "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@types/parse-path": "^7.0.0", + "parse-path": "^7.0.0" + }, + "engines": { + "node": ">=14.13.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", - "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", - "cpu": [ - "x64" - ], + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "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", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">=8" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", - "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", - "cpu": [ - "x64" - ], + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" } }, - "node_modules/@types/diff": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.3.tgz", - "integrity": "sha512-K0Oqlrq3kQMaO2RhfrNQX5trmt+XLyom88zS0u84nnIcLvFnRUMRRHmrGny5GSM+kNO9IZLARsdQHDzkhAgmrQ==", - "dev": true - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, - "node_modules/@types/express": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "^2" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, - "node_modules/@types/express-serve-static-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", - "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "license": "MIT", + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, - "license": "MIT" + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "node_modules/protocols": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", "dev": true, "license": "MIT" }, - "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "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==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/@types/qs": { - "version": "6.9.17", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", - "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "license": "ISC", + "engines": { + "node": ">=12" } }, - "node_modules/@types/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "dev": true, "license": "MIT", "dependencies": { - "@types/http-errors": "*", - "@types/node": "*" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true - }, - "node_modules/@vitest/coverage-v8": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.9.tgz", - "integrity": "sha512-Z2cOr0ksM00MpEfyVE8KXIYPEcBFxdbLSs56L8PO0QQMxt/6bDj45uQfxoc96v05KW3clk7vvgP0qfDit9DmfQ==", + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "dev": true, "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@bcoe/v8-coverage": "^0.2.3", - "debug": "^4.3.7", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^5.0.6", - "istanbul-reports": "^3.1.7", - "magic-string": "^0.30.12", - "magicast": "^0.3.5", - "std-env": "^3.8.0", - "test-exclude": "^7.0.1", - "tinyrainbow": "^1.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "2.1.9", - "vitest": "2.1.9" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } + "engines": { + "node": ">=6" } }, - "node_modules/@vitest/coverage-v8/node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, + "node_modules/qs": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "license": "BSD-3-Clause", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" + "side-channel": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@vitest/coverage-v8/node_modules/test-exclude": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", - "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "license": "ISC", + "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/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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^10.4.1", - "minimatch": "^9.0.4" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=18" + "node": ">= 0.10" } }, - "node_modules/@vitest/expect": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", - "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", - "dev": true, + "node_modules/raw-body/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", "dependencies": { - "@vitest/spy": "2.1.9", - "@vitest/utils": "2.1.9", - "chai": "^5.1.2", - "tinyrainbow": "^1.2.0" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@vitest/mocker": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", - "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", - "dev": true, + "node_modules/raw-body/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", - "dependencies": { - "@vitest/spy": "2.1.9", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.12" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } + "engines": { + "node": ">= 0.8" } }, - "node_modules/@vitest/pretty-format": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", - "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", "dev": true, "license": "MIT", "dependencies": { - "tinyrainbow": "^1.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "defu": "^6.1.4", + "destr": "^2.0.3" } }, - "node_modules/@vitest/runner": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", - "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", - "dev": true, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { - "@vitest/utils": "2.1.9", - "pathe": "^1.1.2" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/@vitest/snapshot": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", - "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "2.1.9", - "magic-string": "^0.30.12", - "pathe": "^1.1.2" + "engines": { + "node": ">= 20.19.0" }, "funding": { - "url": "https://opencollective.com/vitest" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@vitest/spy": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", - "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, - "license": "MIT", "dependencies": { - "tinyspy": "^3.0.2" + "resolve": "^1.1.6" }, - "funding": { - "url": "https://opencollective.com/vitest" + "engines": { + "node": ">= 0.10" } }, - "node_modules/@vitest/utils": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", - "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "node_modules/release-it": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-19.2.4.tgz", + "integrity": "sha512-BwaJwQYUIIAKuDYvpqQTSoy0U7zIy6cHyEjih/aNaFICphGahia4cjDANuFXb7gVZ51hIK9W0io6fjNQWXqICg==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/webpro" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/webpro" + } + ], "license": "MIT", "dependencies": { - "@vitest/pretty-format": "2.1.9", - "loupe": "^3.1.2", - "tinyrainbow": "^1.2.0" + "@nodeutils/defaults-deep": "1.1.0", + "@octokit/rest": "22.0.1", + "@phun-ky/typeof": "2.0.3", + "async-retry": "1.3.3", + "c12": "3.3.3", + "ci-info": "^4.3.1", + "eta": "4.5.0", + "git-url-parse": "16.1.0", + "inquirer": "12.11.1", + "issue-parser": "7.0.1", + "lodash.merge": "4.6.2", + "mime-types": "3.0.2", + "new-github-release-url": "2.0.0", + "open": "10.2.0", + "ora": "9.0.0", + "os-name": "6.1.0", + "proxy-agent": "6.5.0", + "semver": "7.7.3", + "tinyglobby": "0.2.15", + "undici": "6.23.0", + "url-join": "5.0.0", + "wildcard-match": "5.1.4", + "yargs-parser": "21.1.1" }, - "funding": { - "url": "https://opencollective.com/vitest" + "bin": { + "release-it": "bin/release-it.js" + }, + "engines": { + "node": "^20.12.0 || >=22.0.0" } }, - "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" + "node_modules/release-it/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.6" + "node": ">=10" } }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, "dependencies": { - "ajv": "^8.0.0" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "peerDependencies": { - "ajv": "^8.0.0" + "bin": { + "resolve": "bin/resolve" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, - "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==", + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 4" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } }, - "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "node_modules/rollup": { + "version": "4.52.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", + "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "dev": true, "license": "MIT", "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=18" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.5", + "@rollup/rollup-android-arm64": "4.52.5", + "@rollup/rollup-darwin-arm64": "4.52.5", + "@rollup/rollup-darwin-x64": "4.52.5", + "@rollup/rollup-freebsd-arm64": "4.52.5", + "@rollup/rollup-freebsd-x64": "4.52.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", + "@rollup/rollup-linux-arm-musleabihf": "4.52.5", + "@rollup/rollup-linux-arm64-gnu": "4.52.5", + "@rollup/rollup-linux-arm64-musl": "4.52.5", + "@rollup/rollup-linux-loong64-gnu": "4.52.5", + "@rollup/rollup-linux-ppc64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-gnu": "4.52.5", + "@rollup/rollup-linux-riscv64-musl": "4.52.5", + "@rollup/rollup-linux-s390x-gnu": "4.52.5", + "@rollup/rollup-linux-x64-gnu": "4.52.5", + "@rollup/rollup-linux-x64-musl": "4.52.5", + "@rollup/rollup-openharmony-arm64": "4.52.5", + "@rollup/rollup-win32-arm64-msvc": "4.52.5", + "@rollup/rollup-win32-ia32-msvc": "4.52.5", + "@rollup/rollup-win32-x64-gnu": "4.52.5", + "@rollup/rollup-win32-x64-msvc": "4.52.5", + "fsevents": "~2.3.2" } }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "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": { - "balanced-match": "^1.0.0" + "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/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" + "node_modules/router/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/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/call-bind-apply-helpers": { - "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==", + "node_modules/run-async": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", + "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=0.12.0" } }, - "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==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "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", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "queue-microtask": "^1.2.2" } }, - "node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "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": "MIT", + "license": "Apache-2.0", "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, - "engines": { - "node": ">=18" + "tslib": "^2.1.0" } }, - "node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, - "license": "MIT", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">= 16" + "node": ">=10" } }, - "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==", + "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": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "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": ">=12" + "node": ">= 18" } }, - "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==", + "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": { - "color-name": "~1.1.4" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">=7.0.0" + "node": ">= 18" } }, - "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==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "license": "MIT" }, - "node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "shebang-regex": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "engines": { + "node": ">=8" } }, - "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==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "node_modules/shelljs/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=6.6.0" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "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", + "node_modules/shelljs/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", "dependencies": { - "object-assign": "^4", - "vary": "^1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.10" + "node": "*" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", + "node_modules/shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "dev": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" }, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/side-channel": { + "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": { - "ms": "^2.1.3" + "es-errors": "^1.3.0", + "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": ">=6.0" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, + "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": ">=6" - } - }, - "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==", - "engines": { - "node": ">= 0.8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/diff": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", - "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", - "license": "BSD-3-Clause", + "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.3.1" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "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-bind-apply-helpers": "^1.0.1", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "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==" - }, - "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==" - }, - "node_modules/encodeurl": { + "node_modules/siginfo": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" }, - "node_modules/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==", - "license": "MIT", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { - "node": ">= 0.4" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "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==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0" + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 0.4" + "node": ">= 10.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" }, "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "node": ">= 14" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "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==" - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.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": "BSD-3-Clause", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/eventsource": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.5.tgz", - "integrity": "sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw==", - "license": "MIT", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "eventsource-parser": "^3.0.0" - }, - "engines": { - "node": ">=18.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/eventsource-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", - "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=18.0.0" + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", "dev": true, - "license": "Apache-2.0", + "license": "CC0-1.0" + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">=12.0.0" + "node": ">= 0.8" } }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.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" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/express-rate-limit": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.2.1.tgz", - "integrity": "sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==", + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", "dependencies": { - "ip-address": "10.0.1" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" + "safe-buffer": "~5.1.0" } }, - "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==", + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", + "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==", "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" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">=8" } }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "license": "ISC", + "node_modules/string-width-cjs": { + "name": "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==", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "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==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/fs.realpath": { + "node_modules/strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=0.10.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "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": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" + "has-flag": "^4.0.0" }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -2072,1955 +6814,2475 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" }, "engines": { - "node": ">= 0.4" + "node": ">=18" } }, - "node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "license": "ISC", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": ">=12.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "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==", + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^18.0.0 || >=20.0.0" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=14.0.0" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "is-number": "^7.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8.0" } }, - "node_modules/hono": { - "version": "4.11.7", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz", - "integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==", - "license": "MIT", + "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==", "engines": { - "node": ">=16.9.0" + "node": ">=0.6" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "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": "MIT" + "license": "0BSD" }, - "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==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "prelude-ls": "^1.2.1" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8.0" } }, - "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" - }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=0.10.0" + "node": ">=12.20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", + "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": { - "once": "^1.3.0", - "wrappy": "1" + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "license": "MIT" }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "node_modules/typedoc": { + "version": "0.27.9", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.27.9.tgz", + "integrity": "sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@gerrit0/mini-shiki": "^1.24.0", + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "yaml": "^2.6.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, "engines": { - "node": ">= 0.10" + "node": ">= 18" + }, + "peerDependencies": { + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x" } }, - "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "license": "MIT", + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": ">= 12" + "node": ">=14.17" } }, - "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==", - "engines": { - "node": ">= 0.10" - } + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" }, - "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", "dev": true, - "dependencies": { - "hasown": "^2.0.2" + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.8.0" } }, - "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==", + "node_modules/undici": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", + "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18.17" } }, - "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/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, "license": "MIT" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "BSD-3-Clause", + "license": "BSD-2-Clause", "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, - "license": "BSD-3-Clause", + "license": "Apache-2.0", "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.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==", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, - "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, "license": "MIT", "dependencies": { - "immediate": "~3.0.5" + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "node_modules/walk-up-path": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", + "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==", "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" + "license": "ISC", + "engines": { + "node": "20 || >=22" + } }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", - "dev": true, - "license": "MIT", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/magicast": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", - "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.25.4", - "@babel/types": "^7.25.4", - "source-map-js": "^1.2.0" + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "node_modules/wildcard-match": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.4.tgz", + "integrity": "sha512-wldeCaczs8XXq7hj+5d/F38JE2r7EXgb6WQDM84RVwxy81T/sxB5e9+uZLK9Q9oNz1mlvjut+QtvgaOQFPVq/g==", + "dev": true, + "license": "ISC" + }, + "node_modules/windows-release": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-6.1.0.tgz", + "integrity": "sha512-1lOb3qdzw6OFmOzoY0nauhLG72TpWtb5qgYPiSh/62rjc1XidBSDio2qw0pwHh17VINF217ebIkZJdFLZFn9SA==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.5.3" + "execa": "^8.0.1" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" } }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=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==", + "node_modules/wrap-ansi-cjs": { + "name": "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==", "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=18" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "^1.54.0" + "is-wsl": "^3.1.0" }, "engines": { "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" + "bin": { + "yaml": "bin.mjs" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 14.6" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/eemeli" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "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, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "license": "ISC", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=12" } }, - "node_modules/ms": { - "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/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "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": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", - "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", - "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "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==", - "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", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", + "src/aws-kb-retrieval-server": { + "name": "@modelcontextprotocol/server-aws-kb-retrieval", + "version": "0.6.2", + "extraneous": true, + "license": "MIT", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "@aws-sdk/client-bedrock-agent-runtime": "^3.0.0", + "@modelcontextprotocol/sdk": "0.5.0" }, - "engines": { - "node": ">=16 || 14 >=14.18" + "bin": { + "mcp-server-aws-kb-retrieval": "dist/index.js" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "devDependencies": { + "@types/node": "^22", + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", - "dev": true, + "src/brave-search": { + "name": "@modelcontextprotocol/server-brave-search", + "version": "0.6.2", + "extraneous": true, "license": "MIT", - "engines": { - "node": ">= 14.16" + "dependencies": { + "@modelcontextprotocol/sdk": "1.0.1" + }, + "bin": { + "mcp-server-brave-search": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^22", + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "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==", + "src/duckduckgo": { + "name": "@modelcontextprotocol/server-duckduckgo", + "version": "0.2.0", + "extraneous": true, "license": "MIT", - "engines": { - "node": ">=16.20.0" + "dependencies": { + "@modelcontextprotocol/sdk": "0.5.0", + "jsdom": "^24.1.3", + "node-fetch": "^3.3.2" + }, + "bin": { + "mcp-server-duckduckgo": "dist/index.js" + }, + "devDependencies": { + "@types/jsdom": "^21.1.6", + "@types/node": "^22", + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "src/everart": { + "name": "@modelcontextprotocol/server-everart", + "version": "0.6.2", + "extraneous": true, "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "@modelcontextprotocol/sdk": "0.5.0", + "everart": "^1.0.0", + "node-fetch": "^3.3.2", + "open": "^9.1.0" }, - "engines": { - "node": "^10 || ^12 || >=14" + "bin": { + "mcp-server-everart": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^22", + "shx": "^0.3.4", + "typescript": "^5.3.3" } }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" + "src/everything": { + "name": "@modelcontextprotocol/server-everything", + "version": "2.0.0", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "cors": "^2.8.5", + "express": "^5.2.1", + "jszip": "^3.10.1", + "zod": "^3.25.0", + "zod-to-json-schema": "^3.23.5" }, - "engines": { - "node": ">=10.13.0" + "bin": { + "mcp-server-everything": "dist/index.js" }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "devDependencies": { + "@types/cors": "^2.8.19", + "@types/express": "^5.0.6", + "@vitest/coverage-v8": "^2.1.8", + "prettier": "^2.8.8", + "shx": "^0.3.4", + "typescript": "^5.6.2", + "vitest": "^2.1.8" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "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==", + "src/filesystem": { + "name": "@modelcontextprotocol/server-filesystem", + "version": "0.6.3", + "license": "SEE LICENSE IN LICENSE", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "@modelcontextprotocol/sdk": "^1.26.0", + "diff": "^8.0.3", + "glob": "^10.5.0", + "minimatch": "^10.0.1", + "zod-to-json-schema": "^3.23.5" }, - "engines": { - "node": ">= 0.10" + "bin": { + "mcp-server-filesystem": "dist/index.js" + }, + "devDependencies": { + "@types/diff": "^5.0.9", + "@types/minimatch": "^5.1.2", + "@types/node": "^22", + "@vitest/coverage-v8": "^2.1.8", + "shx": "^0.3.4", + "typescript": "^5.8.2", + "vitest": "^2.1.8" } }, - "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", - "license": "BSD-3-Clause", + "src/filesystem/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", "dependencies": { - "side-channel": "^1.1.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=0.6" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "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==", - "engines": { - "node": ">= 0.6" + "src/gdrive": { + "name": "@modelcontextprotocol/server-gdrive", + "version": "0.6.2", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@google-cloud/local-auth": "^3.0.1", + "@modelcontextprotocol/sdk": "1.0.1", + "googleapis": "^144.0.0" + }, + "bin": { + "mcp-server-gdrive": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^22", + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "src/github": { + "name": "@modelcontextprotocol/server-github", + "version": "0.6.2", + "extraneous": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" + "@modelcontextprotocol/sdk": "1.0.1", + "@types/node": "^22", + "@types/node-fetch": "^2.6.12", + "node-fetch": "^3.3.2", + "universal-user-agent": "^7.0.2", + "zod": "^3.22.4", + "zod-to-json-schema": "^3.23.5" + }, + "bin": { + "mcp-server-github": "dist/index.js" + }, + "devDependencies": { + "shx": "^0.3.4", + "typescript": "^5.6.2" + } + }, + "src/gitlab": { + "name": "@modelcontextprotocol/server-gitlab", + "version": "0.6.2", + "extraneous": true, + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "1.0.1", + "@types/node-fetch": "^2.6.12", + "node-fetch": "^3.3.2", + "zod-to-json-schema": "^3.23.5" }, - "engines": { - "node": ">= 0.10" + "bin": { + "mcp-server-gitlab": "dist/index.js" + }, + "devDependencies": { + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/raw-body/node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "src/google-maps": { + "name": "@modelcontextprotocol/server-google-maps", + "version": "0.6.2", + "extraneous": true, "license": "MIT", "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" + "@modelcontextprotocol/sdk": "1.0.1", + "@types/node-fetch": "^2.6.12", + "node-fetch": "^3.3.2" }, - "engines": { - "node": ">= 0.8" + "bin": { + "mcp-server-google-maps": "dist/index.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "devDependencies": { + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/raw-body/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" + "src/memory": { + "name": "@modelcontextprotocol/server-memory", + "version": "0.6.3", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0" + }, + "bin": { + "mcp-server-memory": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^22", + "@vitest/coverage-v8": "^2.1.8", + "shx": "^0.3.4", + "typescript": "^5.6.2", + "vitest": "^2.1.8" } }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "src/postgres": { + "name": "@modelcontextprotocol/server-postgres", + "version": "0.6.2", + "extraneous": true, "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "@modelcontextprotocol/sdk": "1.0.1", + "pg": "^8.13.0" + }, + "bin": { + "mcp-server-postgres": "dist/index.js" + }, + "devDependencies": { + "@types/pg": "^8.11.10", + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/rechoir": { + "src/puppeteer": { + "name": "@modelcontextprotocol/server-puppeteer", "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, + "extraneous": true, + "license": "MIT", "dependencies": { - "resolve": "^1.1.6" + "@modelcontextprotocol/sdk": "1.0.1", + "puppeteer": "^23.4.0" }, - "engines": { - "node": ">= 0.10" - } - }, - "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==", - "engines": { - "node": ">=0.10.0" + "bin": { + "mcp-server-puppeteer": "dist/index.js" + }, + "devDependencies": { + "shx": "^0.3.4", + "typescript": "^5.6.2" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "src/redis": { + "name": "@modelcontextprotocol/server-redis", + "version": "0.1.0", + "extraneous": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "@modelcontextprotocol/sdk": "^1.7.0", + "@types/node": "^22.10.2", + "@types/redis": "^4.0.10", + "redis": "^4.7.0" }, "bin": { - "resolve": "bin/resolve" + "redis": "build/index.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "devDependencies": { + "shx": "^0.3.4", + "typescript": "^5.7.2" } }, - "node_modules/rollup": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", - "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", - "dev": true, - "license": "MIT", + "src/sequentialthinking": { + "name": "@modelcontextprotocol/server-sequential-thinking", + "version": "0.6.3", + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE", "dependencies": { - "@types/estree": "1.0.8" + "@modelcontextprotocol/sdk": "^1.26.0", + "chalk": "^5.0.0" }, "bin": { - "rollup": "dist/bin/rollup" + "mcp-server-sequential-thinking": "dist/index.js" }, + "devDependencies": { + "@eslint/js": "^9.18.0", + "@release-it/conventional-changelog": "^10.0.5", + "@types/node": "^25.2.3", + "@typescript-eslint/eslint-plugin": "^8.0.0", + "@typescript-eslint/parser": "^8.0.0", + "@vitest/coverage-v8": "^4.0.18", + "eslint": "^9.18.0", + "eslint-config-prettier": "^10.0.0", + "husky": "^9.1.7", + "prettier": "^3.4.0", + "release-it": "^19.2.4", + "shx": "^0.4.0", + "typedoc": "^0.27.0", + "typescript": "^5.9.3", + "vitest": "^4.0.18", + "zod": "^4.3.6" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "src/sequentialthinking/node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.5", - "@rollup/rollup-android-arm64": "4.52.5", - "@rollup/rollup-darwin-arm64": "4.52.5", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-freebsd-arm64": "4.52.5", - "@rollup/rollup-freebsd-x64": "4.52.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", - "@rollup/rollup-linux-arm-musleabihf": "4.52.5", - "@rollup/rollup-linux-arm64-gnu": "4.52.5", - "@rollup/rollup-linux-arm64-musl": "4.52.5", - "@rollup/rollup-linux-loong64-gnu": "4.52.5", - "@rollup/rollup-linux-ppc64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-musl": "4.52.5", - "@rollup/rollup-linux-s390x-gnu": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-linux-x64-musl": "4.52.5", - "@rollup/rollup-openharmony-arm64": "4.52.5", - "@rollup/rollup-win32-arm64-msvc": "4.52.5", - "@rollup/rollup-win32-ia32-msvc": "4.52.5", - "@rollup/rollup-win32-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5", - "fsevents": "~2.3.2" + "node": ">=18" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "src/sequentialthinking/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, "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" - }, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">= 18" + "node": ">=18" } }, - "node_modules/router/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==", + "src/sequentialthinking/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "src/sequentialthinking/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "src/sequentialthinking/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], "dev": true, - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "src/sequentialthinking/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, "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" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 18" + "node": ">=18" } }, - "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==", + "src/sequentialthinking/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 18" + "node": ">=18" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "src/sequentialthinking/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "src/sequentialthinking/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "src/sequentialthinking/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=18" } }, - "node_modules/shelljs/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "src/sequentialthinking/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/shelljs/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "src/sequentialthinking/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18" } }, - "node_modules/shelljs/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "src/sequentialthinking/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/shx": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", - "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "src/sequentialthinking/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "minimist": "^1.2.3", - "shelljs": "^0.8.5" - }, - "bin": { - "shx": "lib/cli.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "src/sequentialthinking/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "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==", + "src/sequentialthinking/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "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==", + "src/sequentialthinking/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "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==", + "src/sequentialthinking/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, "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" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "src/sequentialthinking/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "src/sequentialthinking/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "src/sequentialthinking/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "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", + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">= 0.8" + "node": ">=18" } }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "src/sequentialthinking/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "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==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/string-width-cjs": { - "name": "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==", + "src/sequentialthinking/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "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==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "src/sequentialthinking/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "src/sequentialthinking/node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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==", + "src/sequentialthinking/node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "src/sequentialthinking/node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://eslint.org/donate" } }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "src/sequentialthinking/node_modules/@types/node": { + "version": "25.2.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", + "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "src/sequentialthinking/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.55.0.tgz", + "integrity": "sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==", "dev": true, "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.55.0", + "@typescript-eslint/type-utils": "8.55.0", + "@typescript-eslint/utils": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.55.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/tinyrainbow": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", - "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "src/sequentialthinking/node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, "license": "MIT", "engines": { - "node": ">=14.0.0" + "node": ">= 4" } }, - "node_modules/tinyspy": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", - "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "src/sequentialthinking/node_modules/@typescript-eslint/parser": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.55.0.tgz", + "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.55.0", + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/typescript-estree": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0", + "debug": "^4.4.3" + }, "engines": { - "node": ">=14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.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==", + "src/sequentialthinking/node_modules/@typescript-eslint/scope-manager": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.55.0.tgz", + "integrity": "sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0" + }, "engines": { - "node": ">=0.6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "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==", + "src/sequentialthinking/node_modules/@typescript-eslint/type-utils": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.55.0.tgz", + "integrity": "sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==", + "dev": true, "license": "MIT", "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/typescript-estree": "8.55.0", + "@typescript-eslint/utils": "8.55.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { - "node": ">= 0.6" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "src/sequentialthinking/node_modules/@typescript-eslint/types": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.55.0.tgz", + "integrity": "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==", "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "license": "MIT", "engines": { - "node": ">=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "src/sequentialthinking/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.55.0.tgz", + "integrity": "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==", "dev": true, - "license": "MIT" - }, - "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", + "dependencies": { + "@typescript-eslint/project-service": "8.55.0", + "@typescript-eslint/tsconfig-utils": "8.55.0", + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/visitor-keys": "8.55.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, "engines": { - "node": ">= 0.8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "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==", + "src/sequentialthinking/node_modules/@typescript-eslint/utils": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.55.0.tgz", + "integrity": "sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.55.0", + "@typescript-eslint/types": "8.55.0", + "@typescript-eslint/typescript-estree": "8.55.0" + }, "engines": { - "node": ">= 0.8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "src/sequentialthinking/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.55.0.tgz", + "integrity": "sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" + "@typescript-eslint/types": "8.55.0", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "src/sequentialthinking/node_modules/@vitest/coverage-v8": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", + "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.0.18", + "ast-v8-to-istanbul": "^0.3.10", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.1", + "obug": "^2.1.1", + "std-env": "^3.10.0", + "tinyrainbow": "^3.0.3" }, - "optionalDependencies": { - "fsevents": "~2.3.3" + "funding": { + "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "@vitest/browser": "4.0.18", + "vitest": "4.0.18" }, "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { + "@vitest/browser": { "optional": true } } }, - "node_modules/vite-node": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", - "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "src/sequentialthinking/node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", "dev": true, "license": "MIT", "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.7", - "es-module-lexer": "^1.5.4", - "pathe": "^1.1.2", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/vitest": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", - "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "src/sequentialthinking/node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "2.1.9", - "@vitest/mocker": "2.1.9", - "@vitest/pretty-format": "^2.1.9", - "@vitest/runner": "2.1.9", - "@vitest/snapshot": "2.1.9", - "@vitest/spy": "2.1.9", - "@vitest/utils": "2.1.9", - "chai": "^5.1.2", - "debug": "^4.3.7", - "expect-type": "^1.1.0", - "magic-string": "^0.30.12", - "pathe": "^1.1.2", - "std-env": "^3.8.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.1", - "tinypool": "^1.0.1", - "tinyrainbow": "^1.2.0", - "vite": "^5.0.0", - "vite-node": "2.1.9", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "2.1.9", - "@vitest/ui": "2.1.9", - "happy-dom": "*", - "jsdom": "*" + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" }, "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { + "msw": { "optional": true }, - "jsdom": { + "vite": { "optional": true } } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", + "src/sequentialthinking/node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "src/sequentialthinking/node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "src/sequentialthinking/node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "src/sequentialthinking/node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "src/sequentialthinking/node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "src/sequentialthinking/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "src/sequentialthinking/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "src/sequentialthinking/node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "src/sequentialthinking/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", "bin": { - "node-which": "bin/node-which" + "esbuild": "bin/esbuild" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "src/sequentialthinking/node_modules/eslint": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.2", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" }, "bin": { - "why-is-node-running": "cli.js" + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "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==", + "src/sequentialthinking/node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://opencollective.com/eslint" } }, - "node_modules/wrap-ansi-cjs": { - "name": "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==", + "src/sequentialthinking/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "src/sequentialthinking/node_modules/eslint/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.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "src/sequentialthinking/node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=10" + "node": "*" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "src/sequentialthinking/node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", "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" + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": ">=12" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "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==", + "src/sequentialthinking/node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, "engines": { - "node": ">=12" + "node": ">=6" } }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "src/sequentialthinking/node_modules/execa/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" } }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "src/sequentialthinking/node_modules/execa/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" + "bin": { + "semver": "bin/semver" } }, - "src/aws-kb-retrieval-server": { - "name": "@modelcontextprotocol/server-aws-kb-retrieval", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, "license": "MIT", "dependencies": { - "@aws-sdk/client-bedrock-agent-runtime": "^3.0.0", - "@modelcontextprotocol/sdk": "0.5.0" - }, - "bin": { - "mcp-server-aws-kb-retrieval": "dist/index.js" + "flat-cache": "^4.0.0" }, - "devDependencies": { - "@types/node": "^22", - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": ">=16.0.0" } }, - "src/brave-search": { - "name": "@modelcontextprotocol/server-brave-search", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "1.0.1" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, - "bin": { - "mcp-server-brave-search": "dist/index.js" - }, - "devDependencies": { - "@types/node": "^22", - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": ">=16" } }, - "src/duckduckgo": { - "name": "@modelcontextprotocol/server-duckduckgo", - "version": "0.2.0", - "extraneous": true, + "src/sequentialthinking/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "0.5.0", - "jsdom": "^24.1.3", - "node-fetch": "^3.3.2" - }, - "bin": { - "mcp-server-duckduckgo": "dist/index.js" + "pump": "^3.0.0" }, - "devDependencies": { - "@types/jsdom": "^21.1.6", - "@types/node": "^22", - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": ">=6" } }, - "src/everart": { - "name": "@modelcontextprotocol/server-everart", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "0.5.0", - "everart": "^1.0.0", - "node-fetch": "^3.3.2", - "open": "^9.1.0" - }, - "bin": { - "mcp-server-everart": "dist/index.js" + "engines": { + "node": ">=18" }, - "devDependencies": { - "@types/node": "^22", - "shx": "^0.3.4", - "typescript": "^5.3.3" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "src/everything": { - "name": "@modelcontextprotocol/server-everything", - "version": "2.0.0", - "license": "SEE LICENSE IN LICENSE", + "src/sequentialthinking/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "src/sequentialthinking/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, + "license": "MIT" + }, + "src/sequentialthinking/node_modules/magicast": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "cors": "^2.8.5", - "express": "^5.2.1", - "jszip": "^3.10.1", - "zod": "^3.25.0", - "zod-to-json-schema": "^3.23.5" - }, - "bin": { - "mcp-server-everything": "dist/index.js" - }, - "devDependencies": { - "@types/cors": "^2.8.19", - "@types/express": "^5.0.6", - "@vitest/coverage-v8": "^2.1.8", - "prettier": "^2.8.8", - "shx": "^0.3.4", - "typescript": "^5.6.2", - "vitest": "^2.1.8" + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, - "src/filesystem": { - "name": "@modelcontextprotocol/server-filesystem", - "version": "0.6.3", - "license": "SEE LICENSE IN LICENSE", + "src/sequentialthinking/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "diff": "^8.0.3", - "glob": "^10.5.0", - "minimatch": "^10.0.1", - "zod-to-json-schema": "^3.23.5" + "path-key": "^2.0.0" }, - "bin": { - "mcp-server-filesystem": "dist/index.js" + "engines": { + "node": ">=4" + } + }, + "src/sequentialthinking/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "src/sequentialthinking/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "src/sequentialthinking/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, - "devDependencies": { - "@types/diff": "^5.0.9", - "@types/minimatch": "^5.1.2", - "@types/node": "^22", - "@vitest/coverage-v8": "^2.1.8", - "shx": "^0.3.4", - "typescript": "^5.8.2", - "vitest": "^2.1.8" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "src/filesystem/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" + "src/sequentialthinking/node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": "20 || >=22" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "src/gdrive": { - "name": "@modelcontextprotocol/server-gdrive", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, "license": "MIT", "dependencies": { - "@google-cloud/local-auth": "^3.0.1", - "@modelcontextprotocol/sdk": "1.0.1", - "googleapis": "^144.0.0" - }, - "bin": { - "mcp-server-gdrive": "dist/index.js" + "shebang-regex": "^1.0.0" }, - "devDependencies": { - "@types/node": "^22", - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": ">=0.10.0" } }, - "src/github": { - "name": "@modelcontextprotocol/server-github", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "src/sequentialthinking/node_modules/shelljs": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.9.2.tgz", + "integrity": "sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@modelcontextprotocol/sdk": "1.0.1", - "@types/node": "^22", - "@types/node-fetch": "^2.6.12", - "node-fetch": "^3.3.2", - "universal-user-agent": "^7.0.2", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.23.5" + "execa": "^1.0.0", + "fast-glob": "^3.3.2", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" }, "bin": { - "mcp-server-github": "dist/index.js" + "shjs": "bin/shjs" }, - "devDependencies": { - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": ">=18" } }, - "src/gitlab": { - "name": "@modelcontextprotocol/server-gitlab", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/shx": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.4.0.tgz", + "integrity": "sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA==", + "dev": true, "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "1.0.1", - "@types/node-fetch": "^2.6.12", - "node-fetch": "^3.3.2", - "zod-to-json-schema": "^3.23.5" + "minimist": "^1.2.8", + "shelljs": "^0.9.2" }, "bin": { - "mcp-server-gitlab": "dist/index.js" + "shx": "lib/cli.js" }, - "devDependencies": { - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": ">=18" } }, - "src/google-maps": { - "name": "@modelcontextprotocol/server-google-maps", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "src/sequentialthinking/node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "1.0.1", - "@types/node-fetch": "^2.6.12", - "node-fetch": "^3.3.2" - }, - "bin": { - "mcp-server-google-maps": "dist/index.js" - }, - "devDependencies": { - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": ">=18" } }, - "src/memory": { - "name": "@modelcontextprotocol/server-memory", - "version": "0.6.3", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0" - }, - "bin": { - "mcp-server-memory": "dist/index.js" - }, - "devDependencies": { - "@types/node": "^22", - "@vitest/coverage-v8": "^2.1.8", - "shx": "^0.3.4", - "typescript": "^5.6.2", - "vitest": "^2.1.8" + "src/sequentialthinking/node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "src/postgres": { - "name": "@modelcontextprotocol/server-postgres", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "1.0.1", - "pg": "^8.13.0" - }, - "bin": { - "mcp-server-postgres": "dist/index.js" + "engines": { + "node": ">=18.12" }, - "devDependencies": { - "@types/pg": "^8.11.10", - "shx": "^0.3.4", - "typescript": "^5.6.2" + "peerDependencies": { + "typescript": ">=4.8.4" } }, - "src/puppeteer": { - "name": "@modelcontextprotocol/server-puppeteer", - "version": "0.6.2", - "extraneous": true, + "src/sequentialthinking/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "src/sequentialthinking/node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "1.0.1", - "puppeteer": "^23.4.0" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { - "mcp-server-puppeteer": "dist/index.js" + "vite": "bin/vite.js" }, - "devDependencies": { - "shx": "^0.3.4", - "typescript": "^5.6.2" + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "src/redis": { - "name": "@modelcontextprotocol/server-redis", - "version": "0.1.0", - "extraneous": true, + "src/sequentialthinking/node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, "license": "MIT", "dependencies": { - "@modelcontextprotocol/sdk": "^1.7.0", - "@types/node": "^22.10.2", - "@types/redis": "^4.0.10", - "redis": "^4.7.0" + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" }, "bin": { - "redis": "build/index.js" + "vitest": "vitest.mjs" }, - "devDependencies": { - "shx": "^0.3.4", - "typescript": "^5.7.2" + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } } }, - "src/sequentialthinking": { - "name": "@modelcontextprotocol/server-sequential-thinking", - "version": "0.6.2", - "license": "SEE LICENSE IN LICENSE", + "src/sequentialthinking/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", "dependencies": { - "@modelcontextprotocol/sdk": "^1.26.0", - "chalk": "^5.3.0", - "yargs": "^17.7.2" + "isexe": "^2.0.0" }, "bin": { - "mcp-server-sequential-thinking": "dist/index.js" - }, - "devDependencies": { - "@types/node": "^22", - "@types/yargs": "^17.0.32", - "@vitest/coverage-v8": "^2.1.8", - "shx": "^0.3.4", - "typescript": "^5.3.3", - "vitest": "^2.1.8" + "which": "bin/which" + } + }, + "src/sequentialthinking/node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "src/slack": { diff --git a/src/sequentialthinking/.dockerignore b/src/sequentialthinking/.dockerignore new file mode 100644 index 0000000000..c5ae2da65d --- /dev/null +++ b/src/sequentialthinking/.dockerignore @@ -0,0 +1,48 @@ +# Dependencies +node_modules +npm-debug.log* + +# Build outputs +dist +coverage +*.log + +# Test files +__tests__ +*.test.ts +*.spec.ts +vitest.config.ts + +# Development files +.git +.gitignore +.env +.env.* +!.env.example + +# IDE +.vscode +.idea +*.swp +*.swo + +# Documentation +README.md +LICENSE +docs +*.md + +# CI/CD +.github +.gitlab-ci.yml +Jenkinsfile +azure-pipelines.yml + +# Docker +Dockerfile +docker-compose*.yml +.dockerignore + +# Misc +.DS_Store +Thumbs.db diff --git a/src/sequentialthinking/.github/workflows/ci.yml b/src/sequentialthinking/.github/workflows/ci.yml new file mode 100644 index 0000000000..9e3bdd0a25 --- /dev/null +++ b/src/sequentialthinking/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'npm' + - run: npm ci + - run: npm run check + - run: npm run test:all + + docs: + runs-on: ubuntu-latest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'npm' + - run: npm ci + - run: npm run docs + - uses: actions/upload-pages-artifact@v3 + with: + path: docs + - uses: actions/deploy-pages@v4 + with: + artifact_name: docs diff --git a/src/sequentialthinking/.hadolint.json b/src/sequentialthinking/.hadolint.json new file mode 100644 index 0000000000..b19e793e43 --- /dev/null +++ b/src/sequentialthinking/.hadolint.json @@ -0,0 +1,7 @@ +{ + "critical": ["DL3008", "DL3015", "DL3025", "DL3041"], + "major": ["DL3002", "DL3003", "DL3009", "DL3010", "DL3013", "DL3018", "DL3020", "DL3024", "DL3030", "DL3031", "DL3032", "DL3033"], + "minor": ["DL3001", "DL3004", "DL3005", "DL3006", "DL3007", "DL3011", "DL3012", "DL3014", "DL3016", "DL3017", "DL3019", "DL3021", "DL3022", "DL3023", "DL3026", "DL3027", "DL3028", "DL3029", "DL3034", "DL3035", "DL3036", "DL3037", "DL3038", "DL3039", "DL3040", "DL3042", "DL3043", "DL3044", "DL3045", "DL3046", "DL3047"], + "info": ["DL3000", "DL3013"], + "ignored": ["DL4000", "DL4001", "DL4003", "DL4004", "DL4005", "DL4006"] +} diff --git a/src/sequentialthinking/.husky/pre-commit b/src/sequentialthinking/.husky/pre-commit new file mode 100755 index 0000000000..45f5d67e2f --- /dev/null +++ b/src/sequentialthinking/.husky/pre-commit @@ -0,0 +1 @@ +npm run check && npm test diff --git a/src/sequentialthinking/.prettierrc.json b/src/sequentialthinking/.prettierrc.json new file mode 100644 index 0000000000..340079d3fa --- /dev/null +++ b/src/sequentialthinking/.prettierrc.json @@ -0,0 +1,15 @@ +{ + "semi": true, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "bracketSpacing": true, + "arrowParens": "avoid", + "bracketSameLine": true, + "endOfLine": "lf", + "quoteProps": "as-needed", + "jsxSingleQuote": true, + "proseWrap": "preserve" +} \ No newline at end of file diff --git a/src/sequentialthinking/.release-it.json b/src/sequentialthinking/.release-it.json new file mode 100644 index 0000000000..aceffb51dc --- /dev/null +++ b/src/sequentialthinking/.release-it.json @@ -0,0 +1,15 @@ +{ + "plugins": { + "@release-it/conventional-changelog": { + "preset": "angular", + "infile": "CHANGELOG.md" + } + }, + "github": { + "release": true + }, + "npm": { + "publish": false + }, + "ci": false +} diff --git a/src/sequentialthinking/CHANGELOG.md b/src/sequentialthinking/CHANGELOG.md new file mode 100644 index 0000000000..4b6d98f5db --- /dev/null +++ b/src/sequentialthinking/CHANGELOG.md @@ -0,0 +1,224 @@ +# Changelog + +# [0.8.0](https://github.com/vlordier/servers/compare/v0.6.3...v0.8.0) (2026-02-14) + + +### Bug Fixes + +* Sync version script regex pattern ([0938f67](https://github.com/vlordier/servers/commit/0938f67d2dd37e4b6bb3c7da2a73305be37b01be)) + + +### Features + +* Add auto-versioning with standard-version ([d2a1513](https://github.com/vlordier/servers/commit/d2a151353f59b8cccecf470341daf91581f5c6f7)) + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +### 0.6.3 (2026-02-14) + + +### Features + +* Add adaptive metacognition features ([28da4d8](https://github.com/modelcontextprotocol/servers/commit/28da4d8606b0c7c1189989365825855071453b9f)) +* Add AgentRPC to readme ([ad35f20](https://github.com/modelcontextprotocol/servers/commit/ad35f20a531ee8a94524862d422ecba2f27edc49)) +* add async sampling and elicitation tools ([9d863fb](https://github.com/modelcontextprotocol/servers/commit/9d863fb7e66b01dad880838e8c84f5f1c5f4f2fc)) +* Add Atlan MCP ([8345bfd](https://github.com/modelcontextprotocol/servers/commit/8345bfd8e76131e3975d1ad87b81e18bbe39c6b2)) +* Add auto-mode selection and complexity analysis ([68a6599](https://github.com/modelcontextprotocol/servers/commit/68a6599b86ba4d29e0bf8591277d93b9e45087b1)) +* add bambooHR MCP to community servers list ([becca06](https://github.com/modelcontextprotocol/servers/commit/becca06d0f7b313a518ec1a253b7d5794afbb943)) +* add commerce layer mcp local server ([5e14183](https://github.com/modelcontextprotocol/servers/commit/5e141837cec49de128ab8dae72d3dc1c193fc8ef)) +* add commerce layer server ([41640b0](https://github.com/modelcontextprotocol/servers/commit/41640b04b86db8989482706ba507ecd93769db82)) +* add companies house mcp ([#2613](https://github.com/modelcontextprotocol/servers/issues/2613)) ([1445af1](https://github.com/modelcontextprotocol/servers/commit/1445af12f45ae64fdf43509fbbf90ae80b653961)) +* Add comprehensive Zod schemas with validation improvements ([6ec4572](https://github.com/modelcontextprotocol/servers/commit/6ec45728bbaede3c97d27b62cb9c3b2f6af3a2dd)) +* add conductor mcp server ([7e1b629](https://github.com/modelcontextprotocol/servers/commit/7e1b62911149a73329b29d0723bbd87ffd56d022)) +* add daily release check workflow ([6d36b5a](https://github.com/modelcontextprotocol/servers/commit/6d36b5a1ff49b091845ec141048b6f5e45cfdc84)) +* add Data4Library MCP server to the readme ([1aee44a](https://github.com/modelcontextprotocol/servers/commit/1aee44a951da48878cc929a75ee9c1bf6b7a5773)) +* add day of week to time result ([#2580](https://github.com/modelcontextprotocol/servers/issues/2580)) ([60eb7c2](https://github.com/modelcontextprotocol/servers/commit/60eb7c28ad43403f99197d44712bb62aa62937d3)) +* add DBHub - Universal database MCP server ([4549b5e](https://github.com/modelcontextprotocol/servers/commit/4549b5ea70f5773f652f39de322bb165568dc8b3)) +* add deepseek-thinker-mcp ([e792407](https://github.com/modelcontextprotocol/servers/commit/e7924077216785bf54a3372b13b0396e55153aaa)) +* add excludePatterns to search_files for filtering directories ([b2b8f29](https://github.com/modelcontextprotocol/servers/commit/b2b8f298165c61151d7273e7a0f1c6b83a5ec49c)), closes [modelcontextprotocol/servers#251](https://github.com/modelcontextprotocol/servers/issues/251) +* add get_issue endpoint to retrieve single issue details ([6d7a8f2](https://github.com/modelcontextprotocol/servers/commit/6d7a8f2267ba571bb590d1b51add95173e5a659f)) +* Add get_version MCP tool for server version info ([6e233f5](https://github.com/modelcontextprotocol/servers/commit/6e233f5584a8292f9cf26e684d8b5550ae5d608f)) +* Add git branch functionality and unit tests ([1f95231](https://github.com/modelcontextprotocol/servers/commit/1f952310e4d0c1560d1540406b01e1eabeb58de6)) +* Add git branch functionality and unit tests ([e4d8562](https://github.com/modelcontextprotocol/servers/commit/e4d856214bdd72a19d5c4564481c0157ccd5db7d)) +* add GitHub API error handling utilities ([fb421b4](https://github.com/modelcontextprotocol/servers/commit/fb421b4837b87a5edeea993ecd794cb4f3325b82)) +* add GitHub error handling to MCP server ([272e269](https://github.com/modelcontextprotocol/servers/commit/272e26935b7450216069256d0dd6331e1ed3a22f)) +* add Heroku Platform MCP server to Readme ([4825531](https://github.com/modelcontextprotocol/servers/commit/482553150bf6a02347d9cc2acdda8d67f9c3ad3a)) +* add Heurist Mesh Agent MCP server ([458b332](https://github.com/modelcontextprotocol/servers/commit/458b332a1808f484b929e54bd1ad62692bd20f2b)) +* add issue management functionalities for github ([0801583](https://github.com/modelcontextprotocol/servers/commit/08015830a68f4dfa2cc56e40cdd82538ea85322c)) +* add jenkins-mcp-server ([632604e](https://github.com/modelcontextprotocol/servers/commit/632604e6e7f21b98b1504d957dd150ab310b0136)) +* add Langfuse prompt management server to readme ([369cd25](https://github.com/modelcontextprotocol/servers/commit/369cd253c49076a81bbfdbb0470b1590354a5c59)) +* add MCP roots protocol support to everything server ([cf9f66c](https://github.com/modelcontextprotocol/servers/commit/cf9f66c14ebf4e8b99b9647ea11965051dc2b895)), closes [#2552](https://github.com/modelcontextprotocol/servers/issues/2552) +* Add metacognition module with circle detection, confidence scoring, perspective switching, and problem type classification ([7b0abe4](https://github.com/modelcontextprotocol/servers/commit/7b0abe4e419fe999ad024aaee7827ad64e2a6b8d)) +* add needle to mcp ([5e56fef](https://github.com/modelcontextprotocol/servers/commit/5e56fefeb14310c5a208f11473abadd49ac60e65)) +* add Oracle MCP server with Docker support and configuration ([9846ccc](https://github.com/modelcontextprotocol/servers/commit/9846ccc695fc27673844363474ea657d04ee9587)) +* add Postman API official MCP server ([8e167cd](https://github.com/modelcontextprotocol/servers/commit/8e167cd3896b25c5d0037bfe68d9a8cd3e96b72b)) +* Add problem type metadata with phases, anti-patterns, completeness ([31d4e41](https://github.com/modelcontextprotocol/servers/commit/31d4e410bf3e209f47bd88415b0a1f12f15067b7)) +* Add progress overview, critique, and smart thought compression ([c8feee4](https://github.com/modelcontextprotocol/servers/commit/c8feee48682dbfe93d9bfde727a7d0e8fe82aeaf)) +* add prometheus golang MCP implementation ([1d1e5cb](https://github.com/modelcontextprotocol/servers/commit/1d1e5cb89d64e987a6a55bf16238d671f3282157)) +* Add proper enums with descriptions for LLM clarity ([967ace8](https://github.com/modelcontextprotocol/servers/commit/967ace882f864e429c9481d0e7efc5bf30688528)) +* add Qonto MCP server ([7ec182b](https://github.com/modelcontextprotocol/servers/commit/7ec182b89b362e6320a4bf99ac0b68ceec2a8776)) +* add Rube MCP server to the readme ([11d9d6c](https://github.com/modelcontextprotocol/servers/commit/11d9d6caf82c3f64f99c80ae206983697fb29bdb)) +* add search_files handler in CallToolRequestSchema ([15dbacd](https://github.com/modelcontextprotocol/servers/commit/15dbacdcba07c4b5285ac2f366055cf311dee052)) +* add search_files handler with excludePatterns support ([3cf9a06](https://github.com/modelcontextprotocol/servers/commit/3cf9a060cd9a64b1323ab1115d4e930b9644ffc2)) +* add Solana Agent Kit ([961ef3b](https://github.com/modelcontextprotocol/servers/commit/961ef3be6e444b0cbaff93afe1b844a0e377fd92)) +* Add start and start:sse scripts to package.json on everything server ([f2a8028](https://github.com/modelcontextprotocol/servers/commit/f2a802822b8a72e6a5b3bc9e6847a86b91918749)) +* add stats endpoint for SQL object and update README with Docker AI usage ([eccea56](https://github.com/modelcontextprotocol/servers/commit/eccea564ddbae2eb84c8d2ca80508ee96e0f7775)) +* Add TextArt Tools MCP server ([9f31aa9](https://github.com/modelcontextprotocol/servers/commit/9f31aa92b6f4c772a96a4ba26eb30989e1945e7d)) +* add uuv mcp to official server ([#3036](https://github.com/modelcontextprotocol/servers/issues/3036)) ([e194ed4](https://github.com/modelcontextprotocol/servers/commit/e194ed4d26623d076277c75925f593aeafef7e12)) +* add weekly release automation ([26d3dd4](https://github.com/modelcontextprotocol/servers/commit/26d3dd4760063aa5e3e83a8155cac73fbe0d6c47)) +* Added InditexTech MCP Microsoft Teams server ([8a3a5a8](https://github.com/modelcontextprotocol/servers/commit/8a3a5a8318d85077d8fbc68b6c9d7e5d33e685fb)) +* added Lara Translate official mcp server ([c941284](https://github.com/modelcontextprotocol/servers/commit/c941284d52b7415f5c0fbff30b35e711286a5056)) +* Added mcp-pandoc to enable seamless content conversions when using claude ([8562a81](https://github.com/modelcontextprotocol/servers/commit/8562a813c142472ae7801cb6de3817d12b472ba4)) +* Added Withings MCP server for health data analysis ([#3011](https://github.com/modelcontextprotocol/servers/issues/3011)) ([816fbbe](https://github.com/modelcontextprotocol/servers/commit/816fbbe755f134a4018604664a52c3c21f57c373)) +* adding Bitrise's official MCP server ([caccb92](https://github.com/modelcontextprotocol/servers/commit/caccb925e6899577c8e7485d272c1917633e3c98)) +* adding link to Bing Web Search API MCP server in README.md ([5d3a3ca](https://github.com/modelcontextprotocol/servers/commit/5d3a3ca649a37fa56a4da544f655ed0e2596a649)) +* adding PayPal's official MCP server ([b6a0538](https://github.com/modelcontextprotocol/servers/commit/b6a0538c1cfc5bcbb0c8b3950ad1ab701ff420ae)) +* change winston ai pictured ([d88ea94](https://github.com/modelcontextprotocol/servers/commit/d88ea948324896d48e3de9dbc833fe6e383e3a7a)) +* configurable timezone for docker in `time` server ([f3e1469](https://github.com/modelcontextprotocol/servers/commit/f3e14698c94852f4cb464d6859432b8fa2f79779)), closes [#639](https://github.com/modelcontextprotocol/servers/issues/639) +* **directory_tree:** add excludePatterns support & documentation ([#623](https://github.com/modelcontextprotocol/servers/issues/623)) ([d381cf1](https://github.com/modelcontextprotocol/servers/commit/d381cf1ffda963ccd04b9a5a1913595163d8bcf8)) +* **doc:** add community-developed MCP server for Federal Reserve Economic Data ([c7db8ed](https://github.com/modelcontextprotocol/servers/commit/c7db8ed23d4412dbc8aee58f8d7b3b61c4825ffd)) +* enhance GitHub request utilities with error handling ([ff2f2c5](https://github.com/modelcontextprotocol/servers/commit/ff2f2c5347e442fbe6c070b7bd292a170e6a4b3d)) +* enhance pull request operations with validation and error handling ([10bd24d](https://github.com/modelcontextprotocol/servers/commit/10bd24dd02af122965b84d7327495e67e55f14f1)) +* enhance release automation with daily checks ([0989068](https://github.com/modelcontextprotocol/servers/commit/0989068ef1d62f1eb44eb00089001fb3511337ad)) +* enhance release workflow with artifact collection and job output handling ([3d8c33c](https://github.com/modelcontextprotocol/servers/commit/3d8c33cd9ac9b85458cdb58b628a747d7f8a3d31)) +* **everything:** add SEP-1686 Tasks support ([0208e93](https://github.com/modelcontextprotocol/servers/commit/0208e93f8500a9e8e1b641410faefa0899abe324)), closes [#3037](https://github.com/modelcontextprotocol/servers/issues/3037) +* Expand metacognition with patterns, insights, domains, recommendations ([664ddb6](https://github.com/modelcontextprotocol/servers/commit/664ddb6419b5074d6359bc6e0c50c14a231b92f2)) +* Expand problem types and add reasoning styles ([8d5ead1](https://github.com/modelcontextprotocol/servers/commit/8d5ead127c1b59995122a7009ec54681ce290c09)) +* **fetch:** add support for using proxy for requests ([64a6547](https://github.com/modelcontextprotocol/servers/commit/64a654744a414e76fa007063d6ea5425d17d574d)) +* **filesystem:** add symlink resolution and home directory support to roots protocol ([2c922a9](https://github.com/modelcontextprotocol/servers/commit/2c922a93f9ce7c00f36d69140597656bd33e2a1a)) +* **filesystem:** implement MCP roots protocol for dynamic directory management ([f8dd745](https://github.com/modelcontextprotocol/servers/commit/f8dd74576b06b12fecb0342d3a6679b23f75b1a8)) +* **filesystem:** implement MCP roots protocol for dynamic directory management ([b37da40](https://github.com/modelcontextprotocol/servers/commit/b37da4000399d76a836592e18ad5faaa4ba39d62)), closes [#401](https://github.com/modelcontextprotocol/servers/issues/401) +* fix workflow names ([b3f20de](https://github.com/modelcontextprotocol/servers/commit/b3f20decdc453f34c2f0733d60e2fcbed641763e)) +* **git:** add date-based commit log retrieval functions ([#2057](https://github.com/modelcontextprotocol/servers/issues/2057)) ([09adff0](https://github.com/modelcontextprotocol/servers/commit/09adff0b296dae7c93c6e02ac2690a7c2a6ba17e)) +* **git:** add git_diff tool for branch comparison ([ba301c4](https://github.com/modelcontextprotocol/servers/commit/ba301c4a66a35587075aa74c20113dcbe4fe05ed)) +* **github:** Add missing pull request operations to MCP server ([32f49f4](https://github.com/modelcontextprotocol/servers/commit/32f49f44876ea4e8a7550cafad933b68ae7ace4f)) +* **gitlab:** Make owner and fork properties optional ([732c119](https://github.com/modelcontextprotocol/servers/commit/732c119c75f83b3395d39a5d3b711eba42b36c33)) +* **hyprmcp:** add hyprmcp to the servers' list ([a1daff4](https://github.com/modelcontextprotocol/servers/commit/a1daff49febf8872596f7148a6ccaa3b2980dc9e)) +* improve roots messaging to distinguish client support vs configuration ([39c1ca8](https://github.com/modelcontextprotocol/servers/commit/39c1ca8df07fc53ab8bfbf2802f381af7b4bec4e)) +* improvements to release.yml ([fbb0514](https://github.com/modelcontextprotocol/servers/commit/fbb0514749279695d0f0c46e2096e93522a271fc)) +* improvements to release.yml ([bedc115](https://github.com/modelcontextprotocol/servers/commit/bedc11573e6561b7aabf103615abfbaee9728399)) +* MCP server for lark(Feishu) ([e276b45](https://github.com/modelcontextprotocol/servers/commit/e276b45870852994b40c1edc61b79757b2835e68)) +* **mcp_server_git:** Add support for configurable GIT_DIFF_CONTEXT_LINES ([1ac3c1d](https://github.com/modelcontextprotocol/servers/commit/1ac3c1da5987de17dcf5cc84a7c708da0a649156)) +* **memory:** add MEMORY_FILE_PATH environment variable support ([04209ec](https://github.com/modelcontextprotocol/servers/commit/04209ec24813c063775bb4e0e9e51bc265d3bf1c)) +* modify getChannels method to support fetching channels by IDs from env ([3eee3e6](https://github.com/modelcontextprotocol/servers/commit/3eee3e6872578dd67e17da950941ce0267f2fab1)) +* move winston ai integrations to officiel ([fcd467f](https://github.com/modelcontextprotocol/servers/commit/fcd467f6db38a5bc223684500a4b51e7cf04fbe9)) +* needle mcp integration ([ce7ea23](https://github.com/modelcontextprotocol/servers/commit/ce7ea23f739cb27a18dcfbef0c54b4c3051fc447)) +* only run create-tag job when packages are detected ([a156ab6](https://github.com/modelcontextprotocol/servers/commit/a156ab635b4e10e64f6ce273c211b425bc3956e4)) +* **README:** Add Algolia Official MCP ([9ef8018](https://github.com/modelcontextprotocol/servers/commit/9ef8018779e414330a19e72f6718918d06152ee7)) +* **readme:** add documcp to community servers list ([#2614](https://github.com/modelcontextprotocol/servers/issues/2614)) ([c8fe7d9](https://github.com/modelcontextprotocol/servers/commit/c8fe7d995b99fda79131d2d474422f12c1b3aa02)) +* **readme:** add Exa MCP server to the list of official integrations ([174bdfb](https://github.com/modelcontextprotocol/servers/commit/174bdfb7fa04768bb6dc7fb97b17a25b788a0651)) +* **readme:** add Linkup MCP server to the list of offical integrations ([#2575](https://github.com/modelcontextprotocol/servers/issues/2575)) ([2a4b7b0](https://github.com/modelcontextprotocol/servers/commit/2a4b7b0649734b75faf85f11c80277ddc31d2348)) +* **readme:** add Mandoline MCP server to community servers list ([00492a6](https://github.com/modelcontextprotocol/servers/commit/00492a616ece2f021531b4e85c3dfea27bb7bc25)) +* **readme:** add natoma under resources in readme ([e883721](https://github.com/modelcontextprotocol/servers/commit/e883721bea4feccf89446045e75ded90e1b15b51)) +* **readme:** add OMOP MCP to community servers list ([8940b98](https://github.com/modelcontextprotocol/servers/commit/8940b98686df3d57b2348b72698a175c994e5191)) +* **readme:** add Storybook MCP server to community servers list ([ec7eaad](https://github.com/modelcontextprotocol/servers/commit/ec7eaadfcd2dcc078ab502ea4dbce0d20637970c)) +* rechange image url ([52b4ba3](https://github.com/modelcontextprotocol/servers/commit/52b4ba35077e0582a74e69cdcb6c4547fe995368)) +* register search_files tool with excludePatterns support ([a185550](https://github.com/modelcontextprotocol/servers/commit/a1855509d1dbf7f501ec711ceefb09e688179335)) +* remove release check ([85e303a](https://github.com/modelcontextprotocol/servers/commit/85e303aab801f2ec49944f946f6cd634295d9501)) +* rename ([9db47b2](https://github.com/modelcontextprotocol/servers/commit/9db47b20e7a7f39be4d30f27c756a8a0cc433a42)) +* **sequential-thinking:** Add comprehensive linting, type safety, and test coverage ([09cdf1e](https://github.com/modelcontextprotocol/servers/commit/09cdf1e9bdcc1ecec7d04faf643faeeb9211fa8c)) +* **sequential-thinking:** Round 7 — Configurability, Logic Gaps & Robustness Hardening ([aa30704](https://github.com/modelcontextprotocol/servers/commit/aa3070426881b27ca4027ab504a4e8ab3afe31b7)) +* update package versions before creating release tag ([9edf9fc](https://github.com/modelcontextprotocol/servers/commit/9edf9fcaf043a7ef73cb8027742f3814407fe7aa)) +* Upgrade to Zod v4 and Vitest v4 with breaking changes fixes ([b958c28](https://github.com/modelcontextprotocol/servers/commit/b958c2829a73419b2c71ef3cd154b5a22723e1f6)) +* use artifcats to collect mutliple job outputs into one ([111806d](https://github.com/modelcontextprotocol/servers/commit/111806d6ae1cc80655cfef0d37ce5b7e0be35fed)) + + +### Bug Fixes + +* use 'references' instead of 'refs' for pylance even though it's an alias ([abd24f6](https://github.com/modelcontextprotocol/servers/commit/abd24f63f8db83a93a746a8e29eaf6f3d01828a8)) +* `Lisply` logo in README ([b8a9adb](https://github.com/modelcontextprotocol/servers/commit/b8a9adb6745b932e80c7a41e7e2690e1893358cd)) +* add back the __init__.py in mcp_server_tim ([f35f57c](https://github.com/modelcontextprotocol/servers/commit/f35f57c33347465b261997fe6913d8520dcc9625)) +* Add completions capability to Everything server ([b8d19f9](https://github.com/modelcontextprotocol/servers/commit/b8d19f910e676a774cdb8228eb5f37f4217e20da)) +* add contents write permission to update-packages job ([#3138](https://github.com/modelcontextprotocol/servers/issues/3138)) ([bd858d6](https://github.com/modelcontextprotocol/servers/commit/bd858d6745c32e9c6e2a7f45b383a9f4e6600623)) +* add missing allowed tools for Claude workflow ([#3090](https://github.com/modelcontextprotocol/servers/issues/3090)) ([decb360](https://github.com/modelcontextprotocol/servers/commit/decb360cb7f36a4805c2d59abc0edd32247f2cb8)) +* add missing ClientCapabilities import ([c45c0e2](https://github.com/modelcontextprotocol/servers/commit/c45c0e26a045cd69872db5603e07f4fa265fc813)) +* Add missing CreatePullRequestSchema and createPullRequest function ([de256a4](https://github.com/modelcontextprotocol/servers/commit/de256a48b1155ce11d0b3f78c5aebc374ac6996d)) +* add proper TypeScript types to search_files handler ([00a30ac](https://github.com/modelcontextprotocol/servers/commit/00a30ac2bbb8500e756e3b6027dd1b0c898112f6)) +* add server initialization call ([4e31b9d](https://github.com/modelcontextprotocol/servers/commit/4e31b9d66e9cb7fb7ba1cc332ee91c8ec0513df6)) +* Address minor observations from PR review ([e0398a4](https://github.com/modelcontextprotocol/servers/commit/e0398a4d3749071af45112fe6f870d33dcb21927)) +* also change tag name ([7ecbfdf](https://github.com/modelcontextprotocol/servers/commit/7ecbfdfd84a168d76a08dd404e000fbabccba721)) +* Change memory server default filename from memory.json to memory.jsonl ([9d8c2df](https://github.com/modelcontextprotocol/servers/commit/9d8c2dfcaf17d0fd22f8a25e10f8b1f59eee457b)), closes [#2361](https://github.com/modelcontextprotocol/servers/issues/2361) +* Changed structuredContent output to match outputSchema ([#3099](https://github.com/modelcontextprotocol/servers/issues/3099)) ([e6933ca](https://github.com/modelcontextprotocol/servers/commit/e6933ca98bea8120f44c144834cf32164c0ff62e)) +* **ci:** test failures should fail the build ([#3019](https://github.com/modelcontextprotocol/servers/issues/3019)) ([28a3132](https://github.com/modelcontextprotocol/servers/commit/28a313206c7f1350ba946a923044f2f05a5a54f1)), closes [#3014](https://github.com/modelcontextprotocol/servers/issues/3014) +* clarify list_allowed_directories description to mention subdirectory access ([#2571](https://github.com/modelcontextprotocol/servers/issues/2571)) ([7e1d9d9](https://github.com/modelcontextprotocol/servers/commit/7e1d9d9edee441e038698bfa6ac5bbb85b64320c)) +* correct additional typos - 'independant' to 'independent' and 'thier' to 'their' ([4197ef1](https://github.com/modelcontextprotocol/servers/commit/4197ef1cffa8c25dd7b40e6bac28e0f6a5ad87cd)) +* correct tool registration syntax for search_files ([ffd9cb7](https://github.com/modelcontextprotocol/servers/commit/ffd9cb7f53a9e18754fe672e48948ddf4b98568d)) +* correct typo 'telemtry' to 'telemetry' in Comet Opik description ([e1b62ba](https://github.com/modelcontextprotocol/servers/commit/e1b62ba9bd2b4a866307baecbe0c21cd37841cca)) +* **docker:** Correct build process to compile TypeScript ([90597e3](https://github.com/modelcontextprotocol/servers/commit/90597e32ebc9a865b40431cdd24d460520016e61)), closes [#2965](https://github.com/modelcontextprotocol/servers/issues/2965) +* dont specify username ([a5dbc1d](https://github.com/modelcontextprotocol/servers/commit/a5dbc1d3d3ae32cf4eda2972aa6d56105f37d022)) +* enable tools capability in server setup ([773fb8d](https://github.com/modelcontextprotocol/servers/commit/773fb8d205bbcecb9cdd99c9ce95171a6cd9d176)) +* **everything:** implement graceful HTTP elicitation degradation ([5156cff](https://github.com/modelcontextprotocol/servers/commit/5156cff9dcf1a724eed6b102b882ddf2e4d45b4e)) +* **everything:** move task to params.task and remove pollInterval from requests ([1542b65](https://github.com/modelcontextprotocol/servers/commit/1542b65154e5514811aa157ade40c31bf58e19c1)) +* **everything:** send elicitation directly from background task ([c53a0f3](https://github.com/modelcontextprotocol/servers/commit/c53a0f3799c8fe0bb2004d15fbd3214f1f8451e0)) +* exclude test files from filesystem build ([bd39b09](https://github.com/modelcontextprotocol/servers/commit/bd39b09e4c416fe1b284a32737faf448d68aa285)), closes [#2928](https://github.com/modelcontextprotocol/servers/issues/2928) +* **fetch:** fix puppeteer server to allow evaluate async functions ([2b731fb](https://github.com/modelcontextprotocol/servers/commit/2b731fb70f950ad6fa4560653afdc20beeb49789)) +* **fetch:** specify httpx<0.28 to resolve proxy problem ([9a4d513](https://github.com/modelcontextprotocol/servers/commit/9a4d513724b4fbe638ca24f6f86e6fc3ca373e89)) +* **fetch:** update uv.lock to sync with pyproject.toml ([78e0088](https://github.com/modelcontextprotocol/servers/commit/78e0088ebdf0a512afb193c099935d15bc14bf72)), closes [#1852](https://github.com/modelcontextprotocol/servers/issues/1852) +* **filesystem:** address review feedback from [#3016](https://github.com/modelcontextprotocol/servers/issues/3016) ([#3031](https://github.com/modelcontextprotocol/servers/issues/3031)) ([55c3a31](https://github.com/modelcontextprotocol/servers/commit/55c3a31690af5d3dd99924a6f019f8079d1e525d)) +* **filesystem:** convert to modern TypeScript SDK APIs ([#3016](https://github.com/modelcontextprotocol/servers/issues/3016)) ([4dc24cf](https://github.com/modelcontextprotocol/servers/commit/4dc24cf349e69197c2f6a25e76ca2a6c8e30b3b0)) +* **filesystem:** gracefully handle unavailable directories ([2dfa15d](https://github.com/modelcontextprotocol/servers/commit/2dfa15dc6e2dd5997fbe293f11c1d80ea1c73308)), closes [#2815](https://github.com/modelcontextprotocol/servers/issues/2815) +* **filesystem:** return string in structuredContent to match outputSchema ([#3113](https://github.com/modelcontextprotocol/servers/issues/3113)) ([968acc2](https://github.com/modelcontextprotocol/servers/commit/968acc2ec93e9fb7264aede2171394a4715605f1)), closes [#3110](https://github.com/modelcontextprotocol/servers/issues/3110) [#3106](https://github.com/modelcontextprotocol/servers/issues/3106) [#3093](https://github.com/modelcontextprotocol/servers/issues/3093) [#3110](https://github.com/modelcontextprotocol/servers/issues/3110) [#3106](https://github.com/modelcontextprotocol/servers/issues/3106) [#3093](https://github.com/modelcontextprotocol/servers/issues/3093) +* **filesystem:** run npm audit fix to resolve qs vulnerability ([87a996b](https://github.com/modelcontextprotocol/servers/commit/87a996b5480be3cd5ea566d373a9c82b83f5e4d6)) +* **filesystem:** use vi.fn() instead of jest.fn() in test ([dd6594c](https://github.com/modelcontextprotocol/servers/commit/dd6594c083b452671ed1e3899fdae2276e40aaac)) +* fix f-strings ([0ffd701](https://github.com/modelcontextprotocol/servers/commit/0ffd7013db3b19518007a4d25c48dc6add847275)) +* fix links to the docs ([a6dbebb](https://github.com/modelcontextprotocol/servers/commit/a6dbebb6af1109594a02573c0e9acf0bd914fc41)) +* fix mypy warning about representation of bytes ([c53b530](https://github.com/modelcontextprotocol/servers/commit/c53b53030d3e9f5bcf0afcb6d944bf4f7eba3b5a)) +* fix scripts ([9f86ee5](https://github.com/modelcontextprotocol/servers/commit/9f86ee599876c5540444bacd77cdc2ebe7dfb06e)) +* Fix the readme of github server ([fcbf580](https://github.com/modelcontextprotocol/servers/commit/fcbf58069d1251939a49c05597abd6df730dcdbf)) +* **git:** import BadName directly to fix pyright errors ([88320da](https://github.com/modelcontextprotocol/servers/commit/88320daffa627575f3365505f29b56aab05a5cd0)) +* **gitlab:** Invalid arguments error when using v4 API for gitlab.com ([8fe9b47](https://github.com/modelcontextprotocol/servers/commit/8fe9b4768a14dfbd36326fabba3378a3970788d0)) +* Handle null description in GitHub label schema ([6209bed](https://github.com/modelcontextprotocol/servers/commit/6209bed479bde8894d4c431654d8c198dc3931cb)) +* handle URL parameter types correctly in listIssues function ([cfd6136](https://github.com/modelcontextprotocol/servers/commit/cfd613693c9f0072b6ae7b46de1ea67473fcba92)) +* make checkForExistingPullRequest check exact head/base match ([eea524a](https://github.com/modelcontextprotocol/servers/commit/eea524abcf884def276d1b1a28838b62c238b0d0)) +* Match default server version to package.json (0.6.2) ([b6a36a1](https://github.com/modelcontextprotocol/servers/commit/b6a36a1087502a85c48d99a14a05c62c063f2142)) +* mcp_server_git: correct add logic for `["."]` ([#2379](https://github.com/modelcontextprotocol/servers/issues/2379)) ([a67e3b0](https://github.com/modelcontextprotocol/servers/commit/a67e3b0a9205e76389234da69799ed52ac79984a)) +* **memory:** convert to modern TypeScript SDK APIs ([#3015](https://github.com/modelcontextprotocol/servers/issues/3015)) ([b846373](https://github.com/modelcontextprotocol/servers/commit/b84637314f61cd4a244d3e5641207770c8239298)) +* **memory:** revert back instantiation of KnowledgeGraphManager ([5d0bee0](https://github.com/modelcontextprotocol/servers/commit/5d0bee029505c66fd94cb78df5e814f7107b4cce)) +* modify url in readme ([97bda72](https://github.com/modelcontextprotocol/servers/commit/97bda7231e54f7dc8998ad0f3973fd9623d28601)) +* move ActivityPub MCP server to Community Servers section ([0912cd8](https://github.com/modelcontextprotocol/servers/commit/0912cd8100fd4cdf76bf36a906733c82ac2f6e31)) +* move DICOM MCP from official to community servers section ([b893d60](https://github.com/modelcontextprotocol/servers/commit/b893d605efbe25171f0e9c74d46110437dc3f205)), closes [#2562](https://github.com/modelcontextprotocol/servers/issues/2562) +* nango broken logo link ([f94c7db](https://github.com/modelcontextprotocol/servers/commit/f94c7dbd3de5a5c20654e39b0fdfff01a28f65f5)) +* only run scheduled release pipeline on modelcontextprotocol org ([29aba77](https://github.com/modelcontextprotocol/servers/commit/29aba77a930779741d234c0e1d3c1de1c8a267f5)) +* passing body to handleRequest, and optionally adding a response id if it exists ([d1d7944](https://github.com/modelcontextprotocol/servers/commit/d1d79444f7bf791d153a7587dbb6924b5851c49b)) +* preserve WSL paths and improve path normalization logic ([c9b0135](https://github.com/modelcontextprotocol/servers/commit/c9b0135aa5ee8d6f7f1c9f1e943f78ea1f187fc1)) +* properly register search_files tool with schema in server setup ([22a7957](https://github.com/modelcontextprotocol/servers/commit/22a79571d7ae7a9be8368089deb128552eed3858)) +* puppeteer readme launch option json missing comma ([2fa9cb9](https://github.com/modelcontextprotocol/servers/commit/2fa9cb93e33495e4b06ca02e1cf1db64da69fc3b)) +* pyproject ([8e86d49](https://github.com/modelcontextprotocol/servers/commit/8e86d493469612d7a5d96eab53cd8c136d8d6715)) +* release ([01b5cd5](https://github.com/modelcontextprotocol/servers/commit/01b5cd554c78c7b3d6bdedfe1544da3a796a39c6)) +* remove duplicated project_id from schema ([f221e95](https://github.com/modelcontextprotocol/servers/commit/f221e958d3773204a483e509095255f234d33ed9)) +* remove incorrect resources claim from filesystem server README ([54f9c69](https://github.com/modelcontextprotocol/servers/commit/54f9c6968ef70a062c09f5805a89c91731b839e6)), closes [#399](https://github.com/modelcontextprotocol/servers/issues/399) +* remove roots from server capabilities - it's a client capability ([f51757e](https://github.com/modelcontextprotocol/servers/commit/f51757eedbb1f6193b1e1b74cfec10c5e62015af)) +* replace deprecated pydantic function ([1e7d4bc](https://github.com/modelcontextprotocol/servers/commit/1e7d4bc2544b875547f21f8442fa87dd3705376d)) +* resolve brace-expansion ReDoS vulnerability (CVE-2025-5889) ([#2752](https://github.com/modelcontextprotocol/servers/issues/2752)) ([402f0ed](https://github.com/modelcontextprotocol/servers/commit/402f0ed43ea8f5133258ebf3fa5495f1d96ea91a)), closes [#2700](https://github.com/modelcontextprotocol/servers/issues/2700) +* resolve relative paths against allowed directories instead of process.cwd() ([29c9f8c](https://github.com/modelcontextprotocol/servers/commit/29c9f8c58ea94dd67d55d5e80e06f67096e56c02)), closes [#2526](https://github.com/modelcontextprotocol/servers/issues/2526) +* resolve typescript errors and add buildUrl utility ([3e1b3ca](https://github.com/modelcontextprotocol/servers/commit/3e1b3caaec9c7525ef2641ebc29bb57447d0b787)) +* resolve ZoneInfo error by using IANA-compliant local timezone ([cd88954](https://github.com/modelcontextprotocol/servers/commit/cd88954e18f164bf6e5730ce142df8f012c7c2a6)) +* restore original environment variable name for GitHub token ([339a7b6](https://github.com/modelcontextprotocol/servers/commit/339a7b67088dab021467c36110740db8eb349173)) +* restore proper runServer function closure ([e921c27](https://github.com/modelcontextprotocol/servers/commit/e921c2725cd8103987f34da69f3c4b42a3fd0005)) +* **sequential-thinking:** convert to modern TypeScript SDK APIs ([#3014](https://github.com/modelcontextprotocol/servers/issues/3014)) ([88a2ac4](https://github.com/modelcontextprotocol/servers/commit/88a2ac436091b1d03f5b506bb6736f893b4d75e4)) +* **sequential-thinking:** Fix a typo for `nextThoughtNeeded` ([#3010](https://github.com/modelcontextprotocol/servers/issues/3010)) ([902eed6](https://github.com/modelcontextprotocol/servers/commit/902eed6fbf8ee18c1190ffe957941d4de84b6e84)), closes [#3004](https://github.com/modelcontextprotocol/servers/issues/3004) +* **sequential-thinking:** Keep case of json params and description same ([6dda92b](https://github.com/modelcontextprotocol/servers/commit/6dda92b77b8bd1b87543fee29eaa0d79a5261f29)) +* server url ([e92350c](https://github.com/modelcontextprotocol/servers/commit/e92350c8eb5f3484c15e846efefbd3df9e91fda0)) +* **server.py:** remove unused import 'os' ([ba54c9d](https://github.com/modelcontextprotocol/servers/commit/ba54c9d374d96e6c8fdf823f339d3f78dd745ed8)) +* simplify output schemas for text-only tools and add structuredContent ([3f2ddb0](https://github.com/modelcontextprotocol/servers/commit/3f2ddb047950d5a0d159a56b9e7941db92b14067)) +* simplify server setup and rely on handlers for tool registration ([2c1bb44](https://github.com/modelcontextprotocol/servers/commit/2c1bb4426c5a86c976bd0aa977ddb1a58d63fbf4)) +* some wording ([49bc91a](https://github.com/modelcontextprotocol/servers/commit/49bc91aa314e656fa13fac06e666a71a294e1615)) +* **time:** Fix `McpError` constructor usage in time server ([9c9813d](https://github.com/modelcontextprotocol/servers/commit/9c9813d9dc0b85d5daffce953501bc083e49c779)), closes [#3220](https://github.com/modelcontextprotocol/servers/issues/3220) [#3220](https://github.com/modelcontextprotocol/servers/issues/3220) +* Update Apify MCP server link and description ([0f4a1c2](https://github.com/modelcontextprotocol/servers/commit/0f4a1c20d9c620a62d5851d70aefacf84e8bb700)) +* Update Dockerfile and tsconfig for standalone build ([6a61477](https://github.com/modelcontextprotocol/servers/commit/6a6147748e21a2e22b4f9c576e57e021d43efa85)) +* Update E2E test to expect security block for javascript: protocol ([38a0ca8](https://github.com/modelcontextprotocol/servers/commit/38a0ca8a7b930562a2a1f41d603febed85588f92)) +* update filesystem readme ([69bba96](https://github.com/modelcontextprotocol/servers/commit/69bba96dab6fa105b5f83ffc997579ecd4e1c8b3)) +* update listIssues and updateIssue function signatures ([506eaba](https://github.com/modelcontextprotocol/servers/commit/506eabab398353a587f28dd5c022810ab3fd53dc)) +* update logo ([868707a](https://github.com/modelcontextprotocol/servers/commit/868707a143e5635b2f2515220c7fd34a781db33b)) +* Update package.json and format scripts ([23586f4](https://github.com/modelcontextprotocol/servers/commit/23586f4b8d2eabe01143e6f1509e574600e0d8e2)) +* update server setup with correct tool registration format ([95e88ae](https://github.com/modelcontextprotocol/servers/commit/95e88aeb75f2095010d50e81103c6f9291b6f665)) +* update temperature argument type from number to string in everything server docs ([#2610](https://github.com/modelcontextprotocol/servers/issues/2610)) ([38de94b](https://github.com/modelcontextprotocol/servers/commit/38de94b7ad248676b5ae76473a47649653aca0b6)), closes [#474](https://github.com/modelcontextprotocol/servers/issues/474) +* Update test expectation for version to 0.6.2 ([41579d5](https://github.com/modelcontextprotocol/servers/commit/41579d5a1dd097c2c4286293ce6052c9ea4c8dfe)) +* Update TextArtTools to be one word ([fa0797d](https://github.com/modelcontextprotocol/servers/commit/fa0797da3a8416272c704cf2532df892d6d81bb6)) +* use --frozen instead of --locked in release workflow ([#3140](https://github.com/modelcontextprotocol/servers/issues/3140)) ([c7d60d6](https://github.com/modelcontextprotocol/servers/commit/c7d60d635abcad61fc0cf0bb3f0ca8d83bcd2eec)) +* use buildUrl utility in commits module ([10f0aec](https://github.com/modelcontextprotocol/servers/commit/10f0aec693273a30c16d4e1c03c61914d759a24b)) +* use buildUrl utility in issues module ([dac0b7c](https://github.com/modelcontextprotocol/servers/commit/dac0b7cc343dcdc1805a892336ecf8824e381ba3)) +* use buildUrl utility in search module ([8016e36](https://github.com/modelcontextprotocol/servers/commit/8016e366cd0fff812f7ae7aa134d314c8aaa5197)) +* use correct tools capability format in server setup ([9049f03](https://github.com/modelcontextprotocol/servers/commit/9049f031ccc57875ec0eacf0c37fd60b47c64893)) +* use default HEAD as ref ([a041933](https://github.com/modelcontextprotocol/servers/commit/a04193380d1ea9c2e6bb72112affd51e1928f249)) +* use named import for minimatch ([b648517](https://github.com/modelcontextprotocol/servers/commit/b64851723bd2bc34c76147d67ca9ae811f7b29e6)) diff --git a/src/sequentialthinking/Dockerfile b/src/sequentialthinking/Dockerfile index f1a88195bc..206f7ab73e 100644 --- a/src/sequentialthinking/Dockerfile +++ b/src/sequentialthinking/Dockerfile @@ -1,24 +1,49 @@ -FROM node:22.12-alpine AS builder +# syntax=docker/dockerfile:1 -COPY src/sequentialthinking /app -COPY tsconfig.json /tsconfig.json +# ============================================================================= +# Stage 1: Builder - Compile TypeScript +# ============================================================================= +FROM node:22-alpine AS builder WORKDIR /app -RUN --mount=type=cache,target=/root/.npm npm install +# Copy package files first for better layer caching +COPY package.json ./ -RUN --mount=type=cache,target=/root/.npm-production npm ci --ignore-scripts --omit-dev +# Install ALL dependencies (including dev for TypeScript) +RUN npm install --ignore-scripts --legacy-peer-deps -FROM node:22-alpine AS release +# Copy source code +COPY . . + +# Build the application +RUN npx tsc && npx shx chmod +x dist/*.js -COPY --from=builder /app/dist /app/dist -COPY --from=builder /app/package.json /app/package.json -COPY --from=builder /app/package-lock.json /app/package-lock.json +# ============================================================================= +# Stage 2: Production - Minimal runtime image +# ============================================================================= +FROM node:22-alpine AS release -ENV NODE_ENV=production +# Security: Run as non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nodejs -u 1001 WORKDIR /app -RUN npm ci --ignore-scripts --omit-dev +# Copy only the built artifacts and needed files +COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist +COPY --from=builder --chown=nodejs:nodejs /app/package.json ./ + +# Install production dependencies only +RUN npm install --ignore-scripts --omit=dev --legacy-peer-deps && \ + npm cache clean --force + +# Switch to non-root user +USER nodejs + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "process.exit(0)" +# Run the application ENTRYPOINT ["node", "dist/index.js"] diff --git a/src/sequentialthinking/README.md b/src/sequentialthinking/README.md index 322ded2726..4a4ee7dad2 100644 --- a/src/sequentialthinking/README.md +++ b/src/sequentialthinking/README.md @@ -1,155 +1,216 @@ # Sequential Thinking MCP Server -An MCP server implementation that provides a tool for dynamic and reflective problem-solving through a structured thinking process. +An MCP server for dynamic, reflective problem-solving through sequential thoughts with MCTS-based tree exploration and metacognitive self-awareness. -## Features +## Overview -- Break down complex problems into manageable steps -- Revise and refine thoughts as understanding deepens -- Branch into alternative paths of reasoning -- Adjust the total number of thoughts dynamically -- Generate and verify solution hypotheses +This server provides structured, step-by-step thinking with support for: +- **Revisions** - Reconsider previous thoughts +- **Branching** - Explore alternative reasoning paths +- **Session tracking** - Maintain context across requests +- **MCTS exploration** - Monte Carlo Tree Search for optimal reasoning paths +- **Thinking modes** - Fast, Expert, and Deep exploration strategies +- **Metacognition** - Self-awareness for confidence, circularity detection, problem classification -## Tool +## Tools -### sequential_thinking +### `sequentialthinking` -Facilitates a detailed, step-by-step thinking process for problem-solving and analysis. +Process a single thought in a sequential chain. -**Inputs:** -- `thought` (string): The current thinking step -- `nextThoughtNeeded` (boolean): Whether another thought step is needed -- `thoughtNumber` (integer): Current thought number -- `totalThoughts` (integer): Estimated total thoughts needed -- `isRevision` (boolean, optional): Whether this revises previous thinking -- `revisesThought` (integer, optional): Which thought is being reconsidered -- `branchFromThought` (integer, optional): Branching point thought number -- `branchId` (string, optional): Branch identifier -- `needsMoreThoughts` (boolean, optional): If more thoughts are needed +**Parameters:** -## Usage +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `thought` | string | yes | The current thinking step | +| `nextThoughtNeeded` | boolean | yes | Whether another thought step is needed | +| `thoughtNumber` | number | yes | Current thought number (1-based) | +| `totalThoughts` | number | yes | Estimated total thoughts needed | +| `isRevision` | boolean | no | Whether this revises previous thinking | +| `revisesThought` | number | no | Which thought number is being reconsidered | +| `branchFromThought` | number | no | Branching point thought number | +| `branchId` | string | no | Branch identifier | +| `needsMoreThoughts` | boolean | no | If more thoughts are needed beyond estimate | +| `sessionId` | string | no | Session identifier for tracking | -The Sequential Thinking tool is designed for: -- Breaking down complex problems into steps -- Planning and design with room for revision -- Analysis that might need course correction -- Problems where the full scope might not be clear initially -- Tasks that need to maintain context over multiple steps -- Situations where irrelevant information needs to be filtered out +**Response fields:** `thoughtNumber`, `totalThoughts`, `nextThoughtNeeded`, `branches`, `thoughtHistoryLength`, `sessionId`, `timestamp` -## Configuration +### `get_thought_history` -### Usage with Claude Desktop +Retrieve the thought history for a session. -Add this to your `claude_desktop_config.json`: +**Parameters:** -#### npx +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `sessionId` | string | yes | Session identifier | +| `branchId` | string | no | Filter by branch | -```json -{ - "mcpServers": { - "sequential-thinking": { - "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-sequential-thinking" - ] - } - } -} -``` +### `set_thinking_mode` -#### docker - -```json -{ - "mcpServers": { - "sequentialthinking": { - "command": "docker", - "args": [ - "run", - "--rm", - "-i", - "mcp/sequentialthinking" - ] - } - } -} -``` +Configure the thinking mode for a session (enables MCTS exploration). -To disable logging of thought information set env var: `DISABLE_THOUGHT_LOGGING` to `true`. -Comment +**Parameters:** -### Usage with VS Code +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `sessionId` | string | yes | Session identifier | +| `mode` | string | yes | Thinking mode: `fast`, `expert`, or `deep` | -For quick installation, click one of the installation buttons below... +### `suggest_next_thought` -[![Install with NPX in VS Code](https://img.shields.io/badge/VS_Code-NPM-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=sequentialthinking&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40modelcontextprotocol%2Fserver-sequential-thinking%22%5D%7D) [![Install with NPX in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-NPM-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=sequentialthinking&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40modelcontextprotocol%2Fserver-sequential-thinking%22%5D%7D&quality=insiders) +Get AI-powered suggestions for the next thought using MCTS. -[![Install with Docker in VS Code](https://img.shields.io/badge/VS_Code-Docker-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=sequentialthinking&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22mcp%2Fsequentialthinking%22%5D%7D) [![Install with Docker in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Docker-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=sequentialthinking&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22mcp%2Fsequentialthinking%22%5D%7D&quality=insiders) +**Parameters:** -For manual installation, you can configure the MCP server using one of these methods: +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `sessionId` | string | yes | Session identifier | +| `strategy` | string | no | Selection strategy: `explore`, `exploit`, or `balanced` | -**Method 1: User Configuration (Recommended)** -Add the configuration to your user-level MCP configuration file. Open the Command Palette (`Ctrl + Shift + P`) and run `MCP: Open User Configuration`. This will open your user `mcp.json` file where you can add the server configuration. +### `evaluate_thought` -**Method 2: Workspace Configuration** -Alternatively, you can add the configuration to a file called `.vscode/mcp.json` in your workspace. This will allow you to share the configuration with others. +Evaluate a thought's quality (0-1 scale) for MCTS backpropagation. -> For more details about MCP configuration in VS Code, see the [official VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/customization/mcp-servers). +**Parameters:** -For NPX installation: +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `sessionId` | string | yes | Session identifier | +| `nodeId` | string | yes | Node ID to evaluate | +| `value` | number | yes | Quality score (0-1) | -```json -{ - "servers": { - "sequential-thinking": { - "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-sequential-thinking" - ] - } - } -} -``` +### `backtrack` -For Docker installation: - -```json -{ - "servers": { - "sequential-thinking": { - "command": "docker", - "args": [ - "run", - "--rm", - "-i", - "mcp/sequentialthinking" - ] - } - } -} -``` +Move the thought tree cursor back to a previous node. -### Usage with Codex CLI +**Parameters:** -Run the following: +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `sessionId` | string | yes | Session identifier | +| `nodeId` | string | yes | Target node ID | -#### npx +### `get_thinking_summary` -```bash -codex mcp add sequential-thinking npx -y @modelcontextprotocol/server-sequential-thinking -``` +Get a comprehensive summary of the thought tree. + +**Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `sessionId` | string | yes | Session identifier | +| `maxDepth` | number | no | Maximum depth to include | + +### `health_check` + +Returns server health status including memory, response time, error rate, storage, and security checks. + +### `metrics` + +Returns request metrics (counts, response times), thought metrics (totals, branches), and system metrics. + +## Thinking Modes + +The server supports three thinking modes for MCTS exploration: -## Building +| Mode | Exploration | Target Depth | Best For | +|------|-------------|--------------|----------| +| `fast` | Low (0.5) | 3-5 | Quick decisions | +| `expert` | Balanced (1.41) | 5-10 | Complex analysis | +| `deep` | High (2.0) | 10-20 | Thorough exploration | -Docker: +### Mode Configuration + +| Parameter | fast | expert | deep | +|-----------|------|--------|------| +| `explorationConstant` | 0.5 | √2 (~1.41) | 2.0 | +| `maxBranchingFactor` | 1 | 3 | 5 | +| `targetDepthMin` | 3 | 5 | 10 | +| `targetDepthMax` | 5 | 10 | 20 | +| `autoEvaluate` | true | false | false | +| `enableBacktracking` | false | true | true | + +## Metacognition + +The server includes self-awareness features that analyze thought patterns: + +### Features + +- **Circularity Detection** - Detects repetitive thinking patterns using Jaccard similarity +- **Confidence Scoring** - Assesses thought confidence based on linguistic markers +- **Problem Type Classification** - Identifies problem type (analysis, design, debugging, planning, optimization, decision, creative) +- **Perspective Switching** - Suggests alternative viewpoints (optimist, pessimist, expert, beginner, skeptic) +- **Reasoning Gap Analysis** - Detects premature conclusions and missing evidence +- **Adaptive Strategy** - Learns from evaluation history to recommend better strategies + +### ModeGuidance Response + +When thinking mode is active, responses include: + +| Field | Type | Description | +|-------|------|-------------| +| `mode` | string | Current thinking mode | +| `currentPhase` | string | Phase: exploring, evaluating, converging, concluded | +| `recommendedAction` | string | Suggested next action | +| `confidenceScore` | number | Thought confidence (0-1) | +| `circularityWarning` | boolean | Whether circular thinking detected | +| `problemType` | string | Classified problem type | +| `strategyGuidance` | string | Problem-type-specific strategy | +| `confidenceTrend` | string | improving, declining, stable, insufficient | +| `reasoningGapWarning` | string | Detected reasoning gaps | +| `reflectionPrompt` | string | Metacognitive reflection question | + +## Configuration + +All configuration is via environment variables with sensible defaults: + +| Variable | Default | Description | +|----------|---------|-------------| +| `SERVER_NAME` | `sequential-thinking-server` | Server name reported in MCP metadata | +| `SERVER_VERSION` | `1.0.0` | Server version reported in MCP metadata | +| `MAX_HISTORY_SIZE` | `1000` | Maximum thoughts stored in circular buffer | +| `MAX_THOUGHT_LENGTH` | `5000` | Maximum character length per thought | +| `MAX_THOUGHTS_PER_MIN` | `60` | Rate limit per minute per session | +| `MAX_THOUGHTS_PER_BRANCH` | `100` | Maximum thoughts stored per branch | +| `MAX_BRANCH_AGE` | `3600000` | Branch expiration time (ms) | +| `CLEANUP_INTERVAL` | `300000` | Periodic cleanup interval (ms) | +| `BLOCKED_PATTERNS` | *(built-in list)* | Comma-separated regex patterns to block | +| `DISABLE_THOUGHT_LOGGING` | `false` | Disable console thought formatting | +| `LOG_LEVEL` | `info` | Logging level (`debug`, `info`, `warn`, `error`) | +| `ENABLE_COLORS` | `true` | Enable colored console output | +| `ENABLE_METRICS` | `true` | Enable metrics collection | +| `ENABLE_HEALTH_CHECKS` | `true` | Enable health check endpoint | +| `HEALTH_MAX_MEMORY` | `90` | Memory usage % threshold for unhealthy status | +| `HEALTH_MAX_STORAGE` | `80` | Storage usage % threshold for unhealthy status | +| `HEALTH_MAX_RESPONSE_TIME` | `200` | Response time (ms) threshold for unhealthy status | +| `HEALTH_ERROR_RATE_DEGRADED` | `2` | Error rate % threshold for degraded status | +| `HEALTH_ERROR_RATE_UNHEALTHY` | `5` | Error rate % threshold for unhealthy status | + +## Development ```bash -docker build -t mcp/sequentialthinking -f src/sequentialthinking/Dockerfile . +npm install +npm run build +npm test ``` +### Scripts + +- `npm run build` — Compile TypeScript +- `npm run watch` — Compile in watch mode +- `npm run test` — Run tests +- `npm run lint` — Run ESLint +- `npm run lint:fix` — Auto-fix lint issues +- `npm run type-check` — TypeScript type checking +- `npm run check` — Run type-check, lint, and format +- `npm run docs` — Generate TypeDoc documentation +- `npm run docker:build` — Build Docker image + +## Documentation + +Generated API documentation is available in the `docs/` folder. Run `npm run docs` to regenerate. + ## License -This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository. +SEE LICENSE IN LICENSE diff --git a/src/sequentialthinking/__tests__/e2e/docker.test.ts b/src/sequentialthinking/__tests__/e2e/docker.test.ts new file mode 100644 index 0000000000..fc724ee643 --- /dev/null +++ b/src/sequentialthinking/__tests__/e2e/docker.test.ts @@ -0,0 +1,547 @@ +import { describe, it, expect, beforeAll, afterAll } from 'vitest'; +import { spawn, ChildProcess } from 'child_process'; + +describe('Docker E2E Tests', () => { + let dockerProcess: ChildProcess | null = null; + const DOCKER_IMAGE = 'mcp/sequential-thinking'; + const TIMEOUT = 30000; + + // Helper to send JSON-RPC message to Docker container + async function sendMessage(message: unknown): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error('Response timeout')); + }, 5000); + + dockerProcess = spawn('docker', [ + 'run', + '--rm', + '-i', + '-e', 'MAX_THOUGHT_LENGTH=5000', + '-e', 'MAX_HISTORY_SIZE=100', + DOCKER_IMAGE, + ]); + + let stdout = ''; + let stderr = ''; + + dockerProcess.stdout?.on('data', (data) => { + stdout += data.toString(); + }); + + dockerProcess.stderr?.on('data', (data) => { + stderr += data.toString(); + }); + + dockerProcess.on('close', (code) => { + clearTimeout(timeout); + + if (code !== 0) { + reject(new Error(`Docker exited with code ${code}. stderr: ${stderr}`)); + return; + } + + // Parse the first JSON line (ignore console logs) + const lines = stdout.split('\n'); + for (const line of lines) { + if (line.trim().startsWith('{')) { + try { + const response = JSON.parse(line); + resolve(response); + return; + } catch (e) { + // Continue to next line + } + } + } + + reject(new Error(`No valid JSON response found. stdout: ${stdout}`)); + }); + + dockerProcess.on('error', (err) => { + clearTimeout(timeout); + reject(err); + }); + + // Send the message + dockerProcess.stdin?.write(JSON.stringify(message) + '\n'); + dockerProcess.stdin?.end(); + }); + } + + beforeAll(async () => { + // Verify Docker image exists + const { execSync } = await import('child_process'); + try { + execSync(`docker image inspect ${DOCKER_IMAGE}`, { stdio: 'ignore' }); + } catch { + throw new Error(`Docker image ${DOCKER_IMAGE} not found. Run: docker build -t ${DOCKER_IMAGE} -f src/sequentialthinking/Dockerfile .`); + } + }, TIMEOUT); + + afterAll(() => { + if (dockerProcess && !dockerProcess.killed) { + dockerProcess.kill(); + } + }); + + describe('MCP Protocol', () => { + it('should respond to initialize request', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 1, + method: 'initialize', + params: { + protocolVersion: '2024-11-05', + capabilities: {}, + clientInfo: { + name: 'test-client', + version: '1.0.0', + }, + }, + }) as any; + + expect(response.jsonrpc).toBe('2.0'); + expect(response.id).toBe(1); + expect(response.result).toBeDefined(); + expect(response.result.protocolVersion).toBe('2024-11-05'); + expect(response.result.serverInfo.name).toBe('sequential-thinking-server'); + expect(response.result.capabilities.tools).toBeDefined(); + }, TIMEOUT); + + it('should list available tools', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 2, + method: 'tools/list', + params: {}, + }) as any; + + expect(response.jsonrpc).toBe('2.0'); + expect(response.id).toBe(2); + expect(response.result).toBeDefined(); + expect(response.result.tools).toBeInstanceOf(Array); + expect(response.result.tools.length).toBeGreaterThan(0); + + const sequentialThinkingTool = response.result.tools.find( + (tool: any) => tool.name === 'sequentialthinking' + ); + expect(sequentialThinkingTool).toBeDefined(); + expect(sequentialThinkingTool.description).toBeDefined(); + expect(sequentialThinkingTool.inputSchema).toBeDefined(); + }, TIMEOUT); + }); + + describe('Sequential Thinking Tool', () => { + it('should process a single thought', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 3, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Test thought for Docker e2e', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }, + }, + }) as any; + + expect(response.jsonrpc).toBe('2.0'); + expect(response.id).toBe(3); + expect(response.result).toBeDefined(); + expect(response.result.content).toBeInstanceOf(Array); + expect(response.result.content.length).toBeGreaterThan(0); + + const textContent = response.result.content.find( + (c: any) => c.type === 'text' + ); + expect(textContent).toBeDefined(); + // Response is JSON structured data + const data = JSON.parse(textContent.text); + expect(data.thoughtNumber).toBe(1); + expect(data.totalThoughts).toBe(1); + expect(data.nextThoughtNeeded).toBe(false); + }, TIMEOUT); + + it('should handle multiple sequential thoughts', async () => { + // First thought + const response1 = await sendMessage({ + jsonrpc: '2.0', + id: 4, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'First thought in sequence', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'docker-e2e-session', + }, + }, + }) as any; + + expect(response1.result.isError).toBeUndefined(); + + // Second thought + const response2 = await sendMessage({ + jsonrpc: '2.0', + id: 5, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Second thought in sequence', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'docker-e2e-session', + }, + }, + }) as any; + + expect(response2.result.isError).toBeUndefined(); + + // Final thought + const response3 = await sendMessage({ + jsonrpc: '2.0', + id: 6, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Final thought in sequence', + thoughtNumber: 3, + totalThoughts: 3, + nextThoughtNeeded: false, + sessionId: 'docker-e2e-session', + }, + }, + }) as any; + + expect(response3.result.isError).toBeUndefined(); + const data3 = JSON.parse(response3.result.content[0].text); + expect(data3.thoughtNumber).toBe(3); + expect(data3.totalThoughts).toBe(3); + expect(data3.nextThoughtNeeded).toBe(false); + }, TIMEOUT); + + it('should reject thoughts exceeding maximum length', async () => { + const longThought = 'x'.repeat(6000); // Exceeds MAX_THOUGHT_LENGTH=5000 + + const response = await sendMessage({ + jsonrpc: '2.0', + id: 7, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: longThought, + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }, + }, + }) as any; + + expect(response.result.isError).toBe(true); + const errorData = JSON.parse(response.result.content[0].text); + expect(errorData.error).toBe('VALIDATION_ERROR'); + expect(errorData.message).toContain('exceeds maximum length'); + }, TIMEOUT); + + it('should handle revision thoughts', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 8, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Revised thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + isRevision: true, + revisesThought: 1, + sessionId: 'revision-session', + }, + }, + }) as any; + + expect(response.result.isError).toBeUndefined(); + const revisionData = JSON.parse(response.result.content[0].text); + expect(revisionData.thoughtNumber).toBe(2); + expect(revisionData.totalThoughts).toBe(3); + }, TIMEOUT); + + it('should handle branch thoughts', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 9, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Branch thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'test-branch', + sessionId: 'branch-session', + }, + }, + }) as any; + + expect(response.result.isError).toBeUndefined(); + const branchData = JSON.parse(response.result.content[0].text); + expect(branchData.thoughtNumber).toBe(2); + expect(branchData.totalThoughts).toBe(3); + expect(branchData.branches).toContain('test-branch'); + }, TIMEOUT); + }); + + describe('Get Thought History Tool', () => { + it('should list get_thought_history in tools', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 20, + method: 'tools/list', + params: {}, + }) as any; + + const historyTool = response.result.tools.find( + (tool: any) => tool.name === 'get_thought_history' + ); + expect(historyTool).toBeDefined(); + expect(historyTool.inputSchema).toBeDefined(); + }, TIMEOUT); + + it('should return empty history for unknown session', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 21, + method: 'tools/call', + params: { + name: 'get_thought_history', + arguments: { + sessionId: 'nonexistent-session', + }, + }, + }) as any; + + expect(response.result.isError).toBeUndefined(); + const data = JSON.parse(response.result.content[0].text); + expect(data.sessionId).toBe('nonexistent-session'); + expect(data.count).toBe(0); + expect(data.thoughts).toEqual([]); + }, TIMEOUT); + }); + + describe('MCTS Tools', () => { + it('should list MCTS tools and set_thinking_mode in tools/list', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 30, + method: 'tools/list', + params: {}, + }) as any; + + const toolNames = response.result.tools.map((t: any) => t.name); + expect(toolNames).toContain('backtrack'); + expect(toolNames).toContain('evaluate_thought'); + expect(toolNames).toContain('suggest_next_thought'); + expect(toolNames).toContain('get_thinking_summary'); + expect(toolNames).toContain('set_thinking_mode'); + }, TIMEOUT); + + it('should return tree error for backtrack with invalid session', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 31, + method: 'tools/call', + params: { + name: 'backtrack', + arguments: { + sessionId: 'nonexistent-session', + nodeId: 'nonexistent-node', + }, + }, + }) as any; + + expect(response.result.isError).toBe(true); + const data = JSON.parse(response.result.content[0].text); + expect(data.error).toBe('TREE_ERROR'); + }, TIMEOUT); + + it('should return tree error for evaluate_thought with invalid session', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 32, + method: 'tools/call', + params: { + name: 'evaluate_thought', + arguments: { + sessionId: 'nonexistent-session', + nodeId: 'nonexistent-node', + value: 0.5, + }, + }, + }) as any; + + expect(response.result.isError).toBe(true); + const data = JSON.parse(response.result.content[0].text); + expect(data.error).toBe('TREE_ERROR'); + }, TIMEOUT); + }); + + describe('Environment Configuration', () => { + it('should respect MAX_THOUGHT_LENGTH environment variable', async () => { + // The container is configured with MAX_THOUGHT_LENGTH=5000 + const response = await sendMessage({ + jsonrpc: '2.0', + id: 10, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'x'.repeat(4999), // Just under limit + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }, + }, + }) as any; + + expect(response.result.isError).toBeUndefined(); + }, TIMEOUT); + }); + + describe('Error Handling', () => { + it('should return error for invalid method', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 11, + method: 'invalid/method', + params: {}, + }) as any; + + expect(response.jsonrpc).toBe('2.0'); + expect(response.id).toBe(11); + expect(response.error).toBeDefined(); + }, TIMEOUT); + + it('should validate required parameters', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 12, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + // Missing required fields + thoughtNumber: 1, + }, + }, + }) as any; + + expect(response.result.isError).toBe(true); + // Error text might be plain text or JSON depending on error type + const errorText = response.result.content[0].text; + expect(errorText).toContain('MCP error'); + }, TIMEOUT); + + it('should sanitize potentially harmful content', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 13, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Visit javascript:alert(1) for more info', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }, + }, + }) as any; + + // javascript: protocol is blocked as security threat + expect(response.result.isError).toBe(true); + }, TIMEOUT); + }); + + describe('Health and Metrics', () => { + it('should respond to health check (if endpoint exists)', async () => { + // Note: This test assumes a health endpoint exists + // If not implemented, this test can be skipped + try { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 14, + method: 'health/check', + params: {}, + }) as any; + + if (response.error?.code === -32601) { + // Method not found is acceptable + console.log('Health endpoint not implemented, skipping'); + } else { + expect(response.result).toBeDefined(); + } + } catch (e) { + // Health endpoint may not be exposed via MCP, that's OK + console.log('Health check not available via MCP'); + } + }, TIMEOUT); + }); + + describe('Session Management', () => { + it('should generate session ID when not provided', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 15, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Thought without session ID', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }, + }, + }) as any; + + expect(response.result.isError).toBeUndefined(); + }, TIMEOUT); + + it('should reject invalid session IDs', async () => { + const response = await sendMessage({ + jsonrpc: '2.0', + id: 16, + method: 'tools/call', + params: { + name: 'sequentialthinking', + arguments: { + thought: 'Test thought', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: '', // Empty session ID + }, + }, + }) as any; + + expect(response.result.isError).toBe(true); + const errorData = JSON.parse(response.result.content[0].text); + // Empty session ID is caught by security validation + expect(errorData.error).toBe('SECURITY_ERROR'); + }, TIMEOUT); + }); +}); diff --git a/src/sequentialthinking/__tests__/helpers/factories.ts b/src/sequentialthinking/__tests__/helpers/factories.ts new file mode 100644 index 0000000000..260dac2494 --- /dev/null +++ b/src/sequentialthinking/__tests__/helpers/factories.ts @@ -0,0 +1,27 @@ +import type { ProcessThoughtRequest } from '../../lib.js'; +import type { ThoughtData } from '../../interfaces.js'; + +export function createTestThought( + overrides?: Partial, +): ProcessThoughtRequest { + return { + thought: 'Test thought content', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + ...overrides, + }; +} + +export function createTestThoughtData( + overrides?: Partial, +): ThoughtData { + return { + thought: 'Test thought', + thoughtNumber: 1, + totalThoughts: 5, + nextThoughtNeeded: true, + sessionId: 'test-session', + ...overrides, + }; +} diff --git a/src/sequentialthinking/__tests__/helpers/mocks.ts b/src/sequentialthinking/__tests__/helpers/mocks.ts new file mode 100644 index 0000000000..c89e55cc7d --- /dev/null +++ b/src/sequentialthinking/__tests__/helpers/mocks.ts @@ -0,0 +1,14 @@ +import { vi } from 'vitest'; + +const identity = (str: string) => str; + +vi.mock('chalk', () => ({ + default: { + yellow: identity, + green: identity, + blue: identity, + gray: identity, + cyan: identity, + red: identity, + }, +})); diff --git a/src/sequentialthinking/__tests__/integration/mcts-server.test.ts b/src/sequentialthinking/__tests__/integration/mcts-server.test.ts new file mode 100644 index 0000000000..c89d1fc44e --- /dev/null +++ b/src/sequentialthinking/__tests__/integration/mcts-server.test.ts @@ -0,0 +1,764 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { SequentialThinkingServer, ProcessThoughtRequest } from '../../lib.js'; + +describe('MCTS Server Integration', () => { + let server: SequentialThinkingServer; + + beforeEach(() => { + process.env.DISABLE_THOUGHT_LOGGING = 'true'; + server = new SequentialThinkingServer(); + }); + + afterEach(() => { + if (server && typeof server.destroy === 'function') { + server.destroy(); + } + }); + + describe('Tree Auto-Building', () => { + it('should include nodeId in processThought response', async () => { + const result = await server.processThought({ + thought: 'First thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'mcts-test-1', + }); + + expect(result.isError).toBeUndefined(); + const data = JSON.parse(result.content[0].text); + expect(data.nodeId).toBeDefined(); + expect(data.parentNodeId).toBeNull(); // First node has no parent + expect(data.treeStats).toBeDefined(); + expect(data.treeStats.totalNodes).toBe(1); + }); + + it('should build parent-child relationships', async () => { + const r1 = await server.processThought({ + thought: 'Root thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'mcts-test-2', + }); + + const r2 = await server.processThought({ + thought: 'Child thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'mcts-test-2', + }); + + const d1 = JSON.parse(r1.content[0].text); + const d2 = JSON.parse(r2.content[0].text); + + expect(d2.parentNodeId).toBe(d1.nodeId); + expect(d2.treeStats.totalNodes).toBe(2); + }); + + it('should handle branching in tree', async () => { + await server.processThought({ + thought: 'Root', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'mcts-branch', + }); + + await server.processThought({ + thought: 'Main path', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'mcts-branch', + }); + + const branchResult = await server.processThought({ + thought: 'Alternative path', + thoughtNumber: 3, + totalThoughts: 3, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'alt', + sessionId: 'mcts-branch', + }); + + const data = JSON.parse(branchResult.content[0].text); + expect(data.treeStats.totalNodes).toBe(3); + }); + }); + + describe('Backtrack Tool', () => { + it('should backtrack to a previous node', async () => { + const r1 = await server.processThought({ + thought: 'Root thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'bt-test', + }); + const d1 = JSON.parse(r1.content[0].text); + + await server.processThought({ + thought: 'Second thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'bt-test', + }); + + const btResult = await server.backtrack('bt-test', d1.nodeId); + expect(btResult.isError).toBeUndefined(); + + const btData = JSON.parse(btResult.content[0].text); + expect(btData.node.nodeId).toBe(d1.nodeId); + expect(btData.children).toHaveLength(1); + expect(btData.treeStats.totalNodes).toBe(2); + }); + + it('should return error for invalid session', async () => { + const result = await server.backtrack('nonexistent', 'node-1'); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('TREE_ERROR'); + }); + }); + + describe('Evaluate Tool', () => { + it('should evaluate a thought node', async () => { + const r1 = await server.processThought({ + thought: 'Evaluate me', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + sessionId: 'eval-test', + }); + const d1 = JSON.parse(r1.content[0].text); + + const evalResult = await server.evaluateThought('eval-test', d1.nodeId, 0.85); + expect(evalResult.isError).toBeUndefined(); + + const evalData = JSON.parse(evalResult.content[0].text); + expect(evalData.nodeId).toBe(d1.nodeId); + expect(evalData.newVisitCount).toBe(1); + expect(evalData.newAverageValue).toBeCloseTo(0.85); + expect(evalData.nodesUpdated).toBe(1); + }); + + it('should reject value out of range', async () => { + const r1 = await server.processThought({ + thought: 'Test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: 'eval-range-test', + }); + const d1 = JSON.parse(r1.content[0].text); + + const result = await server.evaluateThought('eval-range-test', d1.nodeId, 1.5); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + + it('should reject negative value', async () => { + const result = await server.evaluateThought('eval-range-test', 'node-1', -0.1); + expect(result.isError).toBe(true); + }); + }); + + describe('Suggest Tool', () => { + it('should suggest next thought to explore', async () => { + await server.processThought({ + thought: 'Root', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'suggest-test', + }); + + await server.processThought({ + thought: 'Child', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'suggest-test', + }); + + const result = await server.suggestNextThought('suggest-test', 'balanced'); + expect(result.isError).toBeUndefined(); + + const data = JSON.parse(result.content[0].text); + expect(data.suggestion).not.toBeNull(); + expect(data.suggestion.nodeId).toBeDefined(); + expect(data.suggestion.ucb1Score).toBeDefined(); + expect(data.treeStats).toBeDefined(); + }); + + it('should return null suggestion when all terminal', async () => { + await server.processThought({ + thought: 'Final', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: 'terminal-test', + }); + + const result = await server.suggestNextThought('terminal-test'); + expect(result.isError).toBeUndefined(); + + const data = JSON.parse(result.content[0].text); + expect(data.suggestion).toBeNull(); + }); + + it('should return error for invalid session', async () => { + const result = await server.suggestNextThought('nonexistent'); + expect(result.isError).toBe(true); + }); + }); + + describe('Summary Tool', () => { + it('should return thinking summary with best path', async () => { + const r1 = await server.processThought({ + thought: 'Start here', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'summary-test', + }); + const d1 = JSON.parse(r1.content[0].text); + + const r2 = await server.processThought({ + thought: 'Good path', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: false, + sessionId: 'summary-test', + }); + const d2 = JSON.parse(r2.content[0].text); + + // Evaluate the good path + await server.evaluateThought('summary-test', d2.nodeId, 0.9); + + const result = await server.getThinkingSummary('summary-test'); + expect(result.isError).toBeUndefined(); + + const data = JSON.parse(result.content[0].text); + expect(data.bestPath).toBeDefined(); + expect(data.bestPath.length).toBeGreaterThanOrEqual(1); + expect(data.treeStructure).not.toBeNull(); + expect(data.treeStats.totalNodes).toBe(2); + }); + + it('should return error for invalid session', async () => { + const result = await server.getThinkingSummary('nonexistent'); + expect(result.isError).toBe(true); + }); + }); + + describe('End-to-End MCTS Cycle', () => { + it('should complete a full MCTS exploration cycle', async () => { + const sessionId = 'e2e-mcts'; + + // Step 1: Submit initial thoughts + const t1 = await server.processThought({ + thought: 'Problem: Find the optimal sorting algorithm', + thoughtNumber: 1, + totalThoughts: 5, + nextThoughtNeeded: true, + sessionId, + }); + const d1 = JSON.parse(t1.content[0].text); + + const t2 = await server.processThought({ + thought: 'Approach 1: QuickSort — average O(n log n)', + thoughtNumber: 2, + totalThoughts: 5, + nextThoughtNeeded: true, + sessionId, + }); + const d2 = JSON.parse(t2.content[0].text); + + // Step 2: Evaluate the first approach + await server.evaluateThought(sessionId, d2.nodeId, 0.7); + + // Step 3: Backtrack to root and try alternative + await server.backtrack(sessionId, d1.nodeId); + + const t3 = await server.processThought({ + thought: 'Approach 2: MergeSort — guaranteed O(n log n)', + thoughtNumber: 3, + totalThoughts: 5, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'mergesort', + sessionId, + }); + const d3 = JSON.parse(t3.content[0].text); + + // Step 4: Evaluate the second approach higher + await server.evaluateThought(sessionId, d3.nodeId, 0.9); + + // Step 5: Get suggestion — should favor under-explored areas + const suggestion = await server.suggestNextThought(sessionId, 'balanced'); + const suggestData = JSON.parse(suggestion.content[0].text); + expect(suggestData.suggestion).not.toBeNull(); + + // Step 6: Verify best path follows higher-rated approach + const summary = await server.getThinkingSummary(sessionId); + const summaryData = JSON.parse(summary.content[0].text); + + expect(summaryData.bestPath.length).toBeGreaterThanOrEqual(2); + expect(summaryData.treeStats.totalNodes).toBe(3); + + // The best path should include the root and the mergesort branch (higher value) + const bestPathThoughts = summaryData.bestPath.map((n: any) => n.thought); + expect(bestPathThoughts[0]).toContain('sorting'); + expect(bestPathThoughts[1]).toContain('MergeSort'); + }); + }); + + describe('set_thinking_mode Tool', () => { + it('should set thinking mode and return config', async () => { + const result = await server.setThinkingMode('mode-test-1', 'fast'); + expect(result.isError).toBeUndefined(); + + const data = JSON.parse(result.content[0].text); + expect(data.sessionId).toBe('mode-test-1'); + expect(data.mode).toBe('fast'); + expect(data.config).toBeDefined(); + expect(data.config.explorationConstant).toBe(0.5); + expect(data.config.suggestStrategy).toBe('exploit'); + expect(data.config.maxBranchingFactor).toBe(1); + expect(data.config.autoEvaluate).toBe(true); + expect(data.config.enableBacktracking).toBe(false); + }); + + it('should reject invalid mode', async () => { + const result = await server.setThinkingMode('mode-test-2', 'invalid'); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + }); + + describe('Fast Mode E2E', () => { + it('should include modeGuidance and auto-evaluate', async () => { + const sessionId = 'fast-e2e'; + await server.setThinkingMode(sessionId, 'fast'); + + // Submit 3 thoughts + for (let i = 1; i <= 3; i++) { + const result = await server.processThought({ + thought: `Fast thought ${i}`, + thoughtNumber: i, + totalThoughts: 5, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + expect(data.modeGuidance).toBeDefined(); + expect(data.modeGuidance.mode).toBe('fast'); + + // Auto-eval: node should be evaluated (unexploredCount decreasing) + expect(data.treeStats.unexploredCount).toBe(0); + } + }); + + it('should recommend conclude at target depth', async () => { + const sessionId = 'fast-conclude'; + await server.setThinkingMode(sessionId, 'fast'); + + // Submit 6 thoughts (depth reaches 5 = targetDepthMax) + let lastGuidance: any; + for (let i = 1; i <= 6; i++) { + const result = await server.processThought({ + thought: `Thought ${i}`, + thoughtNumber: i, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + lastGuidance = data.modeGuidance; + } + + expect(lastGuidance.recommendedAction).toBe('conclude'); + expect(lastGuidance.currentPhase).toBe('concluded'); + }); + }); + + describe('Expert Mode E2E', () => { + it('should provide branching suggestions', async () => { + const sessionId = 'expert-e2e'; + await server.setThinkingMode(sessionId, 'expert'); + + // Submit 3 thoughts (depth = 2, triggers branching) + let lastGuidance: any; + for (let i = 1; i <= 3; i++) { + const result = await server.processThought({ + thought: `Expert thought ${i}`, + thoughtNumber: i, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + lastGuidance = data.modeGuidance; + } + + expect(lastGuidance.recommendedAction).toBe('branch'); + expect(lastGuidance.branchingSuggestion).not.toBeNull(); + expect(lastGuidance.branchingSuggestion.shouldBranch).toBe(true); + }); + + it('should converge with enough high evaluations', async () => { + const sessionId = 'expert-converge'; + await server.setThinkingMode(sessionId, 'expert'); + + // Build some thoughts + const nodeIds: string[] = []; + for (let i = 1; i <= 4; i++) { + const result = await server.processThought({ + thought: `Convergence thought ${i}`, + thoughtNumber: i, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + nodeIds.push(data.nodeId); + } + + // Evaluate leaf with high values 3 times + const leafNodeId = nodeIds[nodeIds.length - 1]; + for (let i = 0; i < 3; i++) { + await server.evaluateThought(sessionId, leafNodeId, 0.9); + } + + // Submit another thought to get updated guidance + const result = await server.processThought({ + thought: 'Check convergence', + thoughtNumber: 5, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + + expect(data.modeGuidance.convergenceStatus).not.toBeNull(); + // With high evals on the path, should converge + expect(data.modeGuidance.convergenceStatus.score).toBeGreaterThan(0); + }); + }); + + describe('Deep Mode E2E', () => { + it('should provide explore-heavy guidance', async () => { + const sessionId = 'deep-e2e'; + await server.setThinkingMode(sessionId, 'deep'); + + const result = await server.processThought({ + thought: 'Deep exploration start', + thoughtNumber: 1, + totalThoughts: 20, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + + expect(data.modeGuidance).toBeDefined(); + expect(data.modeGuidance.mode).toBe('deep'); + // Deep mode should recommend branching aggressively + expect(data.modeGuidance.recommendedAction).toBe('branch'); + expect(data.modeGuidance.branchingSuggestion).not.toBeNull(); + expect(data.modeGuidance.targetTotalThoughts).toBe(20); + }); + }); + + describe('thinkingMode parameter on sequentialthinking', () => { + it('should auto-set mode when thinkingMode provided on first thought', async () => { + const result = await server.processThought({ + thought: 'Inline mode test', + thoughtNumber: 1, + totalThoughts: 5, + nextThoughtNeeded: true, + sessionId: 'inline-mode', + thinkingMode: 'fast', + } as any); + + const data = JSON.parse(result.content[0].text); + expect(data.modeGuidance).toBeDefined(); + expect(data.modeGuidance.mode).toBe('fast'); + }); + }); + + describe('thoughtPrompt in responses', () => { + it('should include thoughtPrompt in processThought response when mode is set', async () => { + const sessionId = 'tp-present'; + await server.setThinkingMode(sessionId, 'fast'); + + const result = await server.processThought({ + thought: 'First thought', + thoughtNumber: 1, + totalThoughts: 5, + nextThoughtNeeded: true, + sessionId, + }); + + const data = JSON.parse(result.content[0].text); + expect(data.modeGuidance).toBeDefined(); + expect(data.modeGuidance.thoughtPrompt).toBeDefined(); + expect(typeof data.modeGuidance.thoughtPrompt).toBe('string'); + expect(data.modeGuidance.thoughtPrompt.length).toBeGreaterThan(0); + }); + + it('should change thoughtPrompt as depth/phase progresses (continue -> conclude in fast mode)', async () => { + const sessionId = 'tp-progress'; + await server.setThinkingMode(sessionId, 'fast'); + + // Submit first thought — should be "continue" + const r1 = await server.processThought({ + thought: 'Step one', + thoughtNumber: 1, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + const d1 = JSON.parse(r1.content[0].text); + expect(d1.modeGuidance.recommendedAction).toBe('continue'); + const promptContinue = d1.modeGuidance.thoughtPrompt; + + // Submit enough thoughts to reach targetDepthMax (5) for fast mode + for (let i = 2; i <= 6; i++) { + await server.processThought({ + thought: `Step ${i}`, + thoughtNumber: i, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + } + + // The 6th thought brings depth to 5 — should conclude + const rLast = await server.processThought({ + thought: 'Final step', + thoughtNumber: 7, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + const dLast = JSON.parse(rLast.content[0].text); + expect(dLast.modeGuidance.recommendedAction).toBe('conclude'); + const promptConclude = dLast.modeGuidance.thoughtPrompt; + + // The two prompts should be different + expect(promptContinue).not.toBe(promptConclude); + expect(promptConclude).toContain('Synthesize'); + }); + }); + + describe('progressOverview and critique in modeGuidance', () => { + it('should include progressOverview and critique fields in modeGuidance response', async () => { + const sessionId = 'guidance-fields'; + await server.setThinkingMode(sessionId, 'expert'); + + const result = await server.processThought({ + thought: 'First thought', + thoughtNumber: 1, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + + const data = JSON.parse(result.content[0].text); + expect(data.modeGuidance).toBeDefined(); + expect('progressOverview' in data.modeGuidance).toBe(true); + expect('critique' in data.modeGuidance).toBe(true); + }); + + it('fast mode: critique always null, progressOverview appears at interval 3', async () => { + const sessionId = 'fast-guidance'; + await server.setThinkingMode(sessionId, 'fast'); + + // Submit 3 thoughts (interval = 3) + let lastData: any; + for (let i = 1; i <= 3; i++) { + const result = await server.processThought({ + thought: `Fast thought ${i}`, + thoughtNumber: i, + totalThoughts: 5, + nextThoughtNeeded: true, + sessionId, + }); + lastData = JSON.parse(result.content[0].text); + // Critique always null for fast mode + expect(lastData.modeGuidance.critique).toBeNull(); + } + + // At 3 nodes, progressOverview should be non-null + expect(lastData.modeGuidance.progressOverview).not.toBeNull(); + expect(lastData.modeGuidance.progressOverview).toContain('PROGRESS'); + }); + + it('expert mode: both fields populate with sufficient data', async () => { + const sessionId = 'expert-guidance'; + await server.setThinkingMode(sessionId, 'expert'); + + // Submit 4 thoughts (expert interval = 4, critique needs bestPath >= 2) + for (let i = 1; i <= 4; i++) { + await server.processThought({ + thought: `Expert thought ${i}`, + thoughtNumber: i, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + } + + // 4 nodes = interval for expert, bestPath >= 2 with enableCritique + // Need to check the last response + const result = await server.processThought({ + thought: 'Expert thought 5', + thoughtNumber: 5, + totalThoughts: 10, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + + // critique should be non-null (expert mode, bestPath >= 2) + expect(data.modeGuidance.critique).not.toBeNull(); + expect(data.modeGuidance.critique).toContain('CRITIQUE'); + }); + }); + + describe('MCTS Metrics Instrumentation', () => { + it('should increment totalRequests and successfulRequests on successful ops', async () => { + const sessionId = 'metrics-success'; + await server.processThought({ + thought: 'Setup', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId, + }); + + const metricsBefore = server.getMetrics() as Record; + const totalBefore = metricsBefore.requests.totalRequests; + const successBefore = metricsBefore.requests.successfulRequests; + + await server.setThinkingMode(sessionId, 'fast'); + await server.suggestNextThought(sessionId); + + const metricsAfter = server.getMetrics() as Record; + expect(metricsAfter.requests.totalRequests).toBe(totalBefore + 2); + expect(metricsAfter.requests.successfulRequests).toBe(successBefore + 2); + }); + + it('should increment failedRequests on tree errors inside withMetrics', async () => { + const metricsBefore = server.getMetrics() as Record; + const failedBefore = metricsBefore.requests.failedRequests; + + // backtrack on nonexistent session: validateSessionId passes, tree error inside withMetrics + await server.backtrack('valid-but-no-tree', 'node-1'); + + const metricsAfter = server.getMetrics() as Record; + expect(metricsAfter.requests.failedRequests).toBe(failedBefore + 1); + }); + }); + + describe('Session Validation for MCTS Operations', () => { + it('should reject empty sessionId on backtrack', async () => { + const result = await server.backtrack('', 'node-1'); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + + it('should reject oversized sessionId on evaluateThought', async () => { + const result = await server.evaluateThought('a'.repeat(101), 'node-1', 0.5); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('SECURITY_ERROR'); + }); + + it('should reject empty sessionId on suggestNextThought', async () => { + const result = await server.suggestNextThought(''); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + + it('should reject empty sessionId on getThinkingSummary', async () => { + const result = await server.getThinkingSummary(''); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + + it('should reject empty sessionId on setThinkingMode', async () => { + const result = await server.setThinkingMode('', 'fast'); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + + it('should accept valid sessionId on all operations', async () => { + const sessionId = 'valid-session'; + // Set up a tree with a thought first + const t1 = await server.processThought({ + thought: 'Setup thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId, + }); + const d1 = JSON.parse(t1.content[0].text); + + // All should succeed (not return validation/security errors) + const btResult = await server.backtrack(sessionId, d1.nodeId); + expect(btResult.isError).toBeUndefined(); + + const evalResult = await server.evaluateThought(sessionId, d1.nodeId, 0.5); + expect(evalResult.isError).toBeUndefined(); + + const suggestResult = await server.suggestNextThought(sessionId); + expect(suggestResult.isError).toBeUndefined(); + + const summaryResult = await server.getThinkingSummary(sessionId); + expect(summaryResult.isError).toBeUndefined(); + + const modeResult = await server.setThinkingMode(sessionId, 'fast'); + expect(modeResult.isError).toBeUndefined(); + }); + }); + + describe('Backward Compatibility', () => { + it('should not break existing processThought response structure', async () => { + const result = await server.processThought({ + thought: 'Backward compat test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: 'compat-test', + }); + + expect(result.isError).toBeUndefined(); + const data = JSON.parse(result.content[0].text); + + // Existing fields still present + expect(data.thoughtNumber).toBe(1); + expect(data.totalThoughts).toBe(1); + expect(data.nextThoughtNeeded).toBe(false); + expect(data.sessionId).toBe('compat-test'); + expect(typeof data.timestamp).toBe('number'); + expect(typeof data.thoughtHistoryLength).toBe('number'); + expect(Array.isArray(data.branches)).toBe(true); + + // New MCTS fields are additive + expect(data.nodeId).toBeDefined(); + expect(data.treeStats).toBeDefined(); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/integration/performance.test.ts b/src/sequentialthinking/__tests__/integration/performance.test.ts new file mode 100644 index 0000000000..9f7645ccb7 --- /dev/null +++ b/src/sequentialthinking/__tests__/integration/performance.test.ts @@ -0,0 +1,164 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { SequentialThinkingServer } from '../../lib.js'; + +describe('SequentialThinkingServer - Performance Tests', () => { + let server: SequentialThinkingServer; + + beforeEach(() => { + process.env.DISABLE_THOUGHT_LOGGING = 'true'; + server = new SequentialThinkingServer(); + }); + + afterEach(() => { + if (server && typeof server.destroy === 'function') { + server.destroy(); + } + }); + + describe('Memory Efficiency', () => { + it('should handle large thoughts efficiently', async () => { + const largeThought = 'a'.repeat(4000); // Within default 5000 limit + + const startTime = Date.now(); + + for (let i = 0; i < 100; i++) { + await server.processThought({ + thought: largeThought, + thoughtNumber: i + 1, + totalThoughts: 100, + nextThoughtNeeded: i < 99, + }); + } + + const duration = Date.now() - startTime; + + // Should process 100 large thoughts quickly (100ms per thought reasonable) + expect(duration).toBeLessThan(1000); + + const history = server.getThoughtHistory(); + expect(history.length).toBe(100); + }); + + it('should maintain performance with history at capacity', async () => { + // Fill history with many thoughts + for (let i = 0; i < 200; i++) { + await server.processThought({ + thought: `Thought ${i}`, + thoughtNumber: i + 1, + totalThoughts: 200, + nextThoughtNeeded: true, + }); + } + + const startTime = Date.now(); + + for (let i = 0; i < 50; i++) { + await server.processThought({ + thought: `Capacity test ${i}`, + thoughtNumber: i + 1, + totalThoughts: 50, + nextThoughtNeeded: true, + }); + } + + const duration = Date.now() - startTime; + + // Should still be performant at capacity + expect(duration).toBeLessThan(500); + }); + }); + + describe('Concurrent Operations', () => { + it('should handle concurrent processing without conflicts', async () => { + const concurrentRequests = 20; + const promises = Array.from({ length: concurrentRequests }, (_, i) => + server.processThought({ + thought: `Concurrent ${i}`, + thoughtNumber: i + 1, + totalThoughts: concurrentRequests, + nextThoughtNeeded: i < concurrentRequests - 1, + }), + ); + + const startTime = Date.now(); + const results = await Promise.all(promises); + const duration = Date.now() - startTime; + + expect(results.every(r => !r.isError)).toBe(true); + expect(duration).toBeLessThan(500); + + const history = server.getThoughtHistory(); + expect(history).toHaveLength(concurrentRequests); + }); + + it('should maintain consistency under high load', async () => { + const batchSize = 50; + const batches = 3; + + for (let batch = 0; batch < batches; batch++) { + const promises = Array.from({ length: batchSize }, (_, i) => + server.processThought({ + thought: `Batch ${batch}-${i}`, + thoughtNumber: i + 1, + totalThoughts: batchSize, + nextThoughtNeeded: i < batchSize - 1, + }), + ); + + await Promise.all(promises); + } + + const history = server.getThoughtHistory(); + expect(history.length).toBe(batches * batchSize); + }); + }); + + describe('Memory Management', () => { + it('should not leak memory during extended operation', async () => { + const initialMemory = process.memoryUsage().heapUsed; + + for (let i = 0; i < 500; i++) { + await server.processThought({ + thought: `Memory test ${i}`, + thoughtNumber: i % 100 + 1, + totalThoughts: 100, + nextThoughtNeeded: true, + }); + } + + const finalMemory = process.memoryUsage().heapUsed; + const memoryIncrease = finalMemory - initialMemory; + + // Memory increase should be reasonable (less than 50MB for 500 operations) + expect(memoryIncrease).toBeLessThan(50 * 1024 * 1024); + }); + }); + + describe('Response Time Consistency', () => { + it('should maintain consistent response times', async () => { + const responseTimes: number[] = []; + + for (let i = 0; i < 100; i++) { + const startTime = Date.now(); + + await server.processThought({ + thought: `Timing test ${i}`, + thoughtNumber: i + 1, + totalThoughts: 100, + nextThoughtNeeded: i < 99, + }); + + const responseTime = Date.now() - startTime; + responseTimes.push(responseTime); + } + + const avgResponseTime = + responseTimes.reduce((sum, time) => sum + time, 0) / + responseTimes.length; + const maxResponseTime = Math.max(...responseTimes); + + expect(avgResponseTime).toBeLessThan(50); + expect(maxResponseTime).toBeLessThan(200); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/integration/server.test.ts b/src/sequentialthinking/__tests__/integration/server.test.ts new file mode 100644 index 0000000000..86599e5dbd --- /dev/null +++ b/src/sequentialthinking/__tests__/integration/server.test.ts @@ -0,0 +1,1307 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { SequentialThinkingServer, ProcessThoughtRequest } from '../../lib.js'; + +describe('SequentialThinkingServer', () => { + let server: SequentialThinkingServer; + + beforeEach(() => { + process.env.DISABLE_THOUGHT_LOGGING = 'true'; + server = new SequentialThinkingServer(); + }); + + afterEach(() => { + if (server && typeof server.destroy === 'function') { + server.destroy(); + } + }); + + describe('Basic Functionality', () => { + it('should process a valid thought successfully', async () => { + const input: ProcessThoughtRequest = { + thought: 'This is my first thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }; + + const result = await server.processThought(input); + + expect(result.isError).toBeUndefined(); + expect(result.content).toHaveLength(1); + + const data = JSON.parse(result.content[0].text); + expect(data.thoughtNumber).toBe(1); + expect(data.totalThoughts).toBe(3); + expect(data.nextThoughtNeeded).toBe(true); + expect(data.thoughtHistoryLength).toBe(1); + expect(typeof data.sessionId).toBe('string'); + expect(data.sessionId.length).toBeGreaterThan(0); + expect(typeof data.timestamp).toBe('number'); + expect(data.timestamp).toBeGreaterThan(0); + }); + + it('should accept thought with optional fields', async () => { + const input: ProcessThoughtRequest = { + thought: 'Revising my earlier idea', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + isRevision: true, + revisesThought: 1, + }; + + const result = await server.processThought(input); + expect(result.isError).toBeUndefined(); + + const data = JSON.parse(result.content[0].text); + expect(data.thoughtNumber).toBe(2); + expect(data.thoughtHistoryLength).toBe(1); + }); + + it('should track multiple thoughts in history', async () => { + await server.processThought({ + thought: 'First thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + await server.processThought({ + thought: 'Second thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + const result = await server.processThought({ + thought: 'Final thought', + thoughtNumber: 3, + totalThoughts: 3, + nextThoughtNeeded: false, + }); + + const data = JSON.parse(result.content[0].text); + expect(data.thoughtHistoryLength).toBe(3); + expect(data.nextThoughtNeeded).toBe(false); + }); + + it('should auto-adjust totalThoughts if thoughtNumber exceeds it', async () => { + const result = await server.processThought({ + thought: 'Thought 5', + thoughtNumber: 5, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + const data = JSON.parse(result.content[0].text); + expect(data.totalThoughts).toBe(5); + }); + }); + + describe('Input Validation', () => { + it('should reject empty thought', async () => { + const result = await server.processThought({ + thought: '', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + } as ProcessThoughtRequest); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + expect(data.message).toContain('Thought is required'); + }); + + it('should reject invalid thoughtNumber', async () => { + const result = await server.processThought({ + thought: 'Valid thought', + thoughtNumber: 0, + totalThoughts: 3, + nextThoughtNeeded: true, + } as ProcessThoughtRequest); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + expect(data.message).toContain('thoughtNumber must be a positive integer'); + }); + + it('should reject invalid totalThoughts', async () => { + const result = await server.processThought({ + thought: 'Valid thought', + thoughtNumber: 1, + totalThoughts: -1, + nextThoughtNeeded: true, + } as ProcessThoughtRequest); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + expect(data.message).toContain('totalThoughts must be a positive integer'); + }); + + it('should reject invalid nextThoughtNeeded', async () => { + const result = await server.processThought({ + thought: 'Valid thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: 'true' as any, + } as ProcessThoughtRequest); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + expect(data.message).toContain('nextThoughtNeeded'); + }); + + it('should handle malformed input gracefully', async () => { + const result = await server.processThought({ + thought: null, + thoughtNumber: 'invalid', + totalThoughts: 'invalid', + nextThoughtNeeded: 'invalid', + } as any); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBeDefined(); + expect(data.timestamp).toBeDefined(); + }); + }); + + describe('Business Logic', () => { + it('should reject revision without revisesThought', async () => { + const result = await server.processThought({ + thought: 'This is a revision', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + isRevision: true, + }); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('BUSINESS_LOGIC_ERROR'); + expect(data.message).toContain('isRevision requires revisesThought'); + }); + + it('should reject branch without branchId', async () => { + const result = await server.processThought({ + thought: 'This is a branch', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + branchFromThought: 1, + }); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('BUSINESS_LOGIC_ERROR'); + expect(data.message).toContain('branchFromThought requires branchId'); + }); + + it('should accept valid revision', async () => { + const result = await server.processThought({ + thought: 'This is a valid revision', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + isRevision: true, + revisesThought: 1, + }); + + expect(result.isError).toBeUndefined(); + }); + + it('should accept valid branch', async () => { + const result = await server.processThought({ + thought: 'This is a valid branch', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'branch-1', + }); + + expect(result.isError).toBeUndefined(); + }); + }); + + describe('Security', () => { + it('should reject overly long thoughts', async () => { + const result = await server.processThought({ + thought: 'a'.repeat(6000), + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + expect(data.message).toContain('exceeds maximum length'); + }); + + it('should reject blocked patterns before sanitization', async () => { + // javascript: is a blocked pattern and should be rejected on raw input + const result = await server.processThought({ + thought: 'Visit javascript: void(0) for info', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('SECURITY_ERROR'); + }); + + it('should sanitize and accept normal content', async () => { + const result = await server.processThought({ + thought: 'Normal text with some test content', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + + expect(result.isError).toBeUndefined(); + }); + + it('should sanitize content that passes validation before storage', async () => { + const sessionId = 'sanitize-storage-test'; + // onclick=handler is not in blocked patterns but is stripped by sanitizeContent + const result = await server.processThought({ + thought: 'Click handler onclick=doSomething for the button', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId, + }); + + expect(result.isError).toBeUndefined(); + // Verify the stored thought was sanitized (onclick= removed) + const history = server.getFilteredHistory({ sessionId }); + expect(history).toHaveLength(1); + expect(history[0].thought).not.toContain('onclick='); + }); + }); + + describe('Session Management', () => { + it('should generate and track session IDs', async () => { + const result1 = await server.processThought({ + thought: 'First thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + const result2 = await server.processThought({ + thought: 'Second thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: false, + }); + + const parsed1 = JSON.parse(result1.content[0].text); + const parsed2 = JSON.parse(result2.content[0].text); + + expect(typeof parsed1.sessionId).toBe('string'); + expect(parsed1.sessionId.length).toBeGreaterThan(0); + expect(typeof parsed2.sessionId).toBe('string'); + expect(parsed2.sessionId.length).toBeGreaterThan(0); + // Auto-generated session IDs differ between calls (no session persistence) + expect(parsed1.sessionId).not.toBe(parsed2.sessionId); + }); + + it('should accept provided session ID', async () => { + const sessionId = 'test-session-123'; + const result = await server.processThought({ + thought: 'Thought with session', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId, + }); + const data = JSON.parse(result.content[0].text); + expect(data.sessionId).toBe(sessionId); + }); + + it('should reject invalid session ID', async () => { + const result = await server.processThought({ + thought: 'Thought with invalid session', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: '', + }); + + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.message).toContain('Invalid session ID'); + }); + }); + + describe('Branching', () => { + it('should track multiple branches correctly', async () => { + await server.processThought({ + thought: 'Main thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + await server.processThought({ + thought: 'Branch A thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'branch-a', + }); + const result = await server.processThought({ + thought: 'Branch B thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: false, + branchFromThought: 1, + branchId: 'branch-b', + }); + + const data = JSON.parse(result.content[0].text); + expect(data.branches).toContain('branch-a'); + expect(data.branches).toContain('branch-b'); + expect(data.branches.length).toBe(2); + expect(data.thoughtHistoryLength).toBe(3); + }); + + it('should allow multiple thoughts in same branch', async () => { + await server.processThought({ + thought: 'Branch thought 1', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'branch-a', + }); + const result = await server.processThought({ + thought: 'Branch thought 2', + thoughtNumber: 2, + totalThoughts: 2, + nextThoughtNeeded: false, + branchFromThought: 1, + branchId: 'branch-a', + }); + + const data = JSON.parse(result.content[0].text); + expect(data.branches).toContain('branch-a'); + expect(data.branches.length).toBe(1); + }); + }); + + describe('Response Format', () => { + it('should return correct response structure on success', async () => { + const result = await server.processThought({ + thought: 'Test thought', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + + expect(result).toHaveProperty('content'); + expect(Array.isArray(result.content)).toBe(true); + expect(result.content.length).toBe(1); + expect(result.content[0]).toHaveProperty('type', 'text'); + expect(result.content[0]).toHaveProperty('text'); + }); + + it('should return valid JSON in response', async () => { + const result = await server.processThought({ + thought: 'Test thought', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + + expect(() => JSON.parse(result.content[0].text)).not.toThrow(); + }); + }); + + describe('Edge Cases', () => { + it('should handle thought strings within limits', async () => { + const result = await server.processThought({ + thought: 'a'.repeat(4000), + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should handle thoughtNumber = 1, totalThoughts = 1', async () => { + const result = await server.processThought({ + thought: 'Only thought', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBeUndefined(); + + const data = JSON.parse(result.content[0].text); + expect(data.thoughtNumber).toBe(1); + expect(data.totalThoughts).toBe(1); + expect(data.nextThoughtNeeded).toBe(false); + }); + + it('should handle nextThoughtNeeded = false', async () => { + const result = await server.processThought({ + thought: 'Final thought', + thoughtNumber: 3, + totalThoughts: 3, + nextThoughtNeeded: false, + }); + const data = JSON.parse(result.content[0].text); + expect(data.nextThoughtNeeded).toBe(false); + }); + }); + + describe('Logging', () => { + let serverWithLogging: SequentialThinkingServer; + + beforeEach(() => { + delete process.env.DISABLE_THOUGHT_LOGGING; + serverWithLogging = new SequentialThinkingServer(); + }); + + afterEach(() => { + process.env.DISABLE_THOUGHT_LOGGING = 'true'; + if (serverWithLogging && typeof serverWithLogging.destroy === 'function') { + serverWithLogging.destroy(); + } + }); + + it('should format and log regular thoughts', async () => { + const result = await serverWithLogging.processThought({ + thought: 'Test thought with logging', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should format and log revision thoughts', async () => { + const result = await serverWithLogging.processThought({ + thought: 'Revised thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + isRevision: true, + revisesThought: 1, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should format and log branch thoughts', async () => { + const result = await serverWithLogging.processThought({ + thought: 'Branch thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: false, + branchFromThought: 1, + branchId: 'branch-a', + }); + expect(result.isError).toBeUndefined(); + }); + }); + + describe('Health & Metrics', () => { + it('should return health status with all checks', async () => { + await server.processThought({ + thought: 'Health check test thought', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: false, + }); + + const health = await server.getHealthStatus(); + + expect(health).toHaveProperty('status'); + expect(health).toHaveProperty('checks'); + expect(health).toHaveProperty('summary'); + expect(health).toHaveProperty('uptime'); + expect(health).toHaveProperty('timestamp'); + expect(['healthy', 'unhealthy', 'degraded']).toContain(health.status); + + const checks = health.checks as Record; + expect(checks).toHaveProperty('memory'); + expect(checks).toHaveProperty('responseTime'); + expect(checks).toHaveProperty('errorRate'); + expect(checks).toHaveProperty('storage'); + expect(checks).toHaveProperty('security'); + }); + + it('should return metrics structure', () => { + const metrics = server.getMetrics() as Record; + + expect(metrics).toHaveProperty('requests'); + expect(metrics).toHaveProperty('thoughts'); + expect(metrics).toHaveProperty('system'); + expect(metrics.requests).toHaveProperty('totalRequests'); + expect(metrics.requests).toHaveProperty('successfulRequests'); + expect(metrics.requests).toHaveProperty('failedRequests'); + }); + + it('should track metrics across operations', async () => { + await server.processThought({ + thought: 'Valid thought 1', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + await server.processThought({ + thought: 'Valid thought 2', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + // Send one invalid request + await server.processThought({ + thought: '', + thoughtNumber: 3, + totalThoughts: 3, + nextThoughtNeeded: false, + } as any); + + const metrics = server.getMetrics() as Record; + + // Validation errors happen before processWithServices, so only 2 successful recorded + expect(metrics.requests.totalRequests).toBe(2); + expect(metrics.requests.successfulRequests).toBe(2); + expect(metrics.thoughts.totalThoughts).toBe(2); + }); + }); + + describe('End-to-End Workflows', () => { + it('should handle complete thinking session', async () => { + const sessionId = 'integration-test-session'; + + const thought1 = await server.processThought({ + thought: 'I need to solve a complex problem step by step', + thoughtNumber: 1, + totalThoughts: 4, + nextThoughtNeeded: true, + sessionId, + }); + expect(thought1.isError).toBeUndefined(); + const parsed1 = JSON.parse(thought1.content[0].text); + expect(parsed1.thoughtNumber).toBe(1); + expect(parsed1.thoughtHistoryLength).toBe(1); + + const thought2 = await server.processThought({ + thought: 'First, I should understand the problem requirements', + thoughtNumber: 2, + totalThoughts: 4, + nextThoughtNeeded: true, + sessionId, + }); + expect(thought2.isError).toBeUndefined(); + + const thought3 = await server.processThought({ + thought: 'Alternative approach: Consider using a different algorithm', + thoughtNumber: 3, + totalThoughts: 4, + nextThoughtNeeded: true, + branchFromThought: 2, + branchId: 'alternative-approach', + sessionId, + }); + const parsed3 = JSON.parse(thought3.content[0].text); + expect(parsed3.branches).toContain('alternative-approach'); + + const thought4 = await server.processThought({ + thought: 'Revising approach 1: The original method is actually better', + thoughtNumber: 4, + totalThoughts: 4, + nextThoughtNeeded: false, + isRevision: true, + revisesThought: 2, + sessionId, + }); + const parsed4 = JSON.parse(thought4.content[0].text); + expect(parsed4.nextThoughtNeeded).toBe(false); + + const history = server.getThoughtHistory(); + expect(history).toHaveLength(4); + + const branches = server.getBranches(); + expect(branches).toContain('alternative-approach'); + }); + + it('should handle and recover from invalid input', async () => { + const invalidResult = await server.processThought({ + thought: '', + thoughtNumber: -1, + totalThoughts: -1, + nextThoughtNeeded: 'invalid' as any, + } as any); + expect(invalidResult.isError).toBe(true); + + const validResult = await server.processThought({ + thought: 'Now this is valid', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + sessionId: 'error-recovery-test', + }); + expect(validResult.isError).toBeUndefined(); + + const parsed = JSON.parse(validResult.content[0].text); + expect(parsed.thoughtNumber).toBe(1); + expect(parsed.sessionId).toBe('error-recovery-test'); + }); + + it('should handle large number of thoughts without memory issues', async () => { + const sessionId = 'memory-test'; + const initialMemory = process.memoryUsage().heapUsed; + + for (let i = 0; i < 200; i++) { + await server.processThought({ + thought: `Memory test thought ${i} with some content to make it realistic`, + thoughtNumber: i + 1, + totalThoughts: 250, + nextThoughtNeeded: i < 199, + sessionId, + }); + } + + const finalMemory = process.memoryUsage().heapUsed; + const memoryIncrease = finalMemory - initialMemory; + + expect(memoryIncrease).toBeLessThan(50 * 1024 * 1024); + + const history = server.getThoughtHistory(); + expect(history.length).toBeLessThanOrEqual(1000); + }); + }); + + describe('Configuration', () => { + it('should respect environment configuration', async () => { + const original = process.env.MAX_THOUGHT_LENGTH; + process.env.MAX_THOUGHT_LENGTH = '500'; + + try { + const configuredServer = new SequentialThinkingServer(); + + const result = await configuredServer.processThought({ + thought: 'a'.repeat(501), + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: false, + }); + + expect(result.isError).toBe(true); + expect(result.content[0].text).toContain('exceeds maximum length'); + + configuredServer.destroy(); + } finally { + if (original === undefined) { + delete process.env.MAX_THOUGHT_LENGTH; + } else { + process.env.MAX_THOUGHT_LENGTH = original; + } + } + }); + }); + + describe('Lifecycle', () => { + it('should clean up resources properly on shutdown', async () => { + await server.processThought({ + thought: 'Shutdown test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + + expect(() => { + server.destroy(); + }).not.toThrow(); + }); + + it('should provide legacy compatibility methods', () => { + const history = server.getThoughtHistory(); + expect(Array.isArray(history)).toBe(true); + + const branches = server.getBranches(); + expect(Array.isArray(branches)).toBe(true); + }); + }); + + describe('Boundary Tests', () => { + it('should accept thought at exactly 5000 chars', async () => { + const result = await server.processThought({ + thought: 'a'.repeat(5000), + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should reject thought at 5001 chars', async () => { + const result = await server.processThought({ + thought: 'a'.repeat(5001), + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + + it('should accept session ID at 100 chars', async () => { + const result = await server.processThought({ + thought: 'Boundary test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: 'a'.repeat(100), + }); + expect(result.isError).toBeUndefined(); + }); + + it('should reject session ID at 101 chars', async () => { + const result = await server.processThought({ + thought: 'Boundary test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: 'a'.repeat(101), + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.message).toContain('Invalid session ID'); + }); + }); + + describe('Health Status Error Fallback', () => { + it('should return unhealthy fallback after destroy', async () => { + server.destroy(); + const health = await server.getHealthStatus(); + expect(health.status).toBe('unhealthy'); + expect(health.checks.memory.status).toBe('unhealthy'); + expect(health.checks.responseTime.status).toBe('unhealthy'); + expect(health.checks.errorRate.status).toBe('unhealthy'); + expect(health.checks.storage.status).toBe('unhealthy'); + expect(health.checks.security.status).toBe('unhealthy'); + }); + }); + + describe('Legacy Methods After Destroy', () => { + it('should return empty array from getThoughtHistory after destroy and log a warning', () => { + server.destroy(); + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + const result = server.getThoughtHistory(); + expect(result).toEqual([]); + expect(errorSpy).toHaveBeenCalled(); + const loggedMessage = errorSpy.mock.calls.find( + call => typeof call[0] === 'string' && call[0].includes('Warning'), + ); + expect(loggedMessage).toBeDefined(); + }); + + it('should return empty array from getBranches after destroy and log a warning', () => { + server.destroy(); + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + const result = server.getBranches(); + expect(result).toEqual([]); + expect(errorSpy).toHaveBeenCalled(); + const loggedMessage = errorSpy.mock.calls.find( + call => typeof call[0] === 'string' && call[0].includes('Warning'), + ); + expect(loggedMessage).toBeDefined(); + }); + }); + + describe('processThought after destroy', () => { + it('should return well-formed error response after destroy', async () => { + server.destroy(); + const result = await server.processThought({ + thought: 'After destroy', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBe(true); + expect(result.content).toHaveLength(1); + // Should be parseable JSON + expect(() => JSON.parse(result.content[0].text)).not.toThrow(); + }); + }); + + describe('Enriched Response Context', () => { + it('should include revisionContext when revising an existing thought', async () => { + const sessionId = 'revision-context-test'; + await server.processThought({ + thought: 'Original idea about sorting', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId, + }); + + const result = await server.processThought({ + thought: 'Actually, merge sort is better', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + isRevision: true, + revisesThought: 1, + sessionId, + }); + + const data = JSON.parse(result.content[0].text); + expect(data.revisionContext).toBeDefined(); + expect(data.revisionContext.originalThoughtNumber).toBe(1); + expect(data.revisionContext.originalThought).toContain('sorting'); + }); + + it('should not include revisionContext for non-revision thoughts', async () => { + const result = await server.processThought({ + thought: 'Regular thought', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + }); + + const data = JSON.parse(result.content[0].text); + expect(data.revisionContext).toBeUndefined(); + }); + + it('should include branchContext when branch has prior thoughts', async () => { + const sessionId = 'branch-context-test'; + await server.processThought({ + thought: 'First branch thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'ctx-branch', + sessionId, + }); + + const result = await server.processThought({ + thought: 'Second branch thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'ctx-branch', + sessionId, + }); + + const data = JSON.parse(result.content[0].text); + expect(data.branchContext).toBeDefined(); + expect(data.branchContext.branchId).toBe('ctx-branch'); + expect(data.branchContext.existingThoughts.length).toBeGreaterThanOrEqual(1); + expect(data.branchContext.existingThoughts[0].thought).toContain('First branch'); + }); + + it('should not include branchContext for first thought in a branch', async () => { + const result = await server.processThought({ + thought: 'First and only branch thought', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'solo-branch', + }); + + const data = JSON.parse(result.content[0].text); + expect(data.branchContext).toBeUndefined(); + }); + }); + + describe('getFilteredHistory', () => { + it('should return thoughts for a specific session', async () => { + const sessionId = 'filter-test'; + await server.processThought({ + thought: 'Thought A', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + sessionId, + }); + await server.processThought({ + thought: 'Thought B', + thoughtNumber: 2, + totalThoughts: 2, + nextThoughtNeeded: false, + sessionId, + }); + // Different session + await server.processThought({ + thought: 'Other session', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: 'other-session', + }); + + const history = server.getFilteredHistory({ sessionId }); + expect(history).toHaveLength(2); + expect(history.every((t) => t.sessionId === sessionId)).toBe(true); + }); + + it('should filter by branchId', async () => { + const sessionId = 'branch-filter-test'; + await server.processThought({ + thought: 'Branch thought', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + branchFromThought: 1, + branchId: 'filter-branch', + sessionId, + }); + await server.processThought({ + thought: 'Main thought', + thoughtNumber: 2, + totalThoughts: 2, + nextThoughtNeeded: false, + sessionId, + }); + + const branchHistory = server.getFilteredHistory({ sessionId, branchId: 'filter-branch' }); + expect(branchHistory).toHaveLength(1); + expect(branchHistory[0].thought).toContain('Branch thought'); + }); + + it('should respect limit parameter', async () => { + const sessionId = 'limit-test'; + for (let i = 1; i <= 5; i++) { + await server.processThought({ + thought: `Thought ${i}`, + thoughtNumber: i, + totalThoughts: 5, + nextThoughtNeeded: i < 5, + sessionId, + }); + } + + const limited = server.getFilteredHistory({ sessionId, limit: 2 }); + expect(limited).toHaveLength(2); + // Should return the most recent + expect(limited[0].thoughtNumber).toBe(4); + expect(limited[1].thoughtNumber).toBe(5); + }); + + it('should return empty array for unknown session', () => { + const history = server.getFilteredHistory({ sessionId: 'nonexistent' }); + expect(history).toEqual([]); + }); + }); + + describe('Whitespace-only thought rejection', () => { + it('should reject whitespace-only thought', async () => { + const result = await server.processThought({ + thought: ' \t\n ', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + }); + + describe('Boundary and Limit Tests', () => { + it('should handle thought at max length boundary', async () => { + const maxLengthThought = 'a'.repeat(5000); + const result = await server.processThought({ + thought: maxLengthThought, + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should reject thought exceeding max length', async () => { + const overMaxLengthThought = 'a'.repeat(5001); + const result = await server.processThought({ + thought: overMaxLengthThought, + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + }); + + it('should handle sessionId at max length', async () => { + const maxSessionId = 'a'.repeat(100); + const result = await server.processThought({ + thought: 'Test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: maxSessionId, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should reject sessionId exceeding max length', async () => { + const overMaxSessionId = 'a'.repeat(101); + const result = await server.processThought({ + thought: 'Test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: overMaxSessionId, + }); + expect(result.isError).toBe(true); + }); + + it('should handle thoughtNumber at minimum valid value', async () => { + const result = await server.processThought({ + thought: 'Test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should reject thoughtNumber below minimum', async () => { + const result = await server.processThought({ + thought: 'Test', + thoughtNumber: 0, + totalThoughts: 1, + nextThoughtNeeded: true, + }); + expect(result.isError).toBe(true); + }); + + it('should handle totalThoughts matching thoughtNumber', async () => { + const result = await server.processThought({ + thought: 'Test', + thoughtNumber: 5, + totalThoughts: 5, + nextThoughtNeeded: false, + }); + expect(result.isError).toBeUndefined(); + }); + + it('should auto-adjust totalThoughts when less than thoughtNumber', async () => { + const result = await server.processThought({ + thought: 'Test', + thoughtNumber: 10, + totalThoughts: 5, + nextThoughtNeeded: true, + }); + // System auto-adjusts totalThoughts to match thoughtNumber + expect(result.isError).toBeUndefined(); + }); + }); + + describe('Non-integer validation', () => { + it('should reject non-integer thoughtNumber', async () => { + const result = await server.processThought({ + thought: 'Valid thought', + thoughtNumber: 1.5, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + expect(data.message).toContain('positive integer'); + }); + + it('should reject non-integer totalThoughts', async () => { + const result = await server.processThought({ + thought: 'Valid thought', + thoughtNumber: 1, + totalThoughts: 2.5, + nextThoughtNeeded: true, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('VALIDATION_ERROR'); + expect(data.message).toContain('positive integer'); + }); + }); + + describe('Regex-Based Blocked Pattern Matching', () => { + it('should reject blocked input before sanitization', async () => { + // eval( is a blocked pattern and should be rejected on raw input + const result = await server.processThought({ + thought: 'use eval(code) here', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('SECURITY_ERROR'); + }); + + it('should block document.cookie via regex', async () => { + const result = await server.processThought({ + thought: 'steal document.cookie from user', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('SECURITY_ERROR'); + }); + + it('should block file.exe via regex', async () => { + const result = await server.processThought({ + thought: 'download malware.exe from site', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(result.isError).toBe(true); + const data = JSON.parse(result.content[0].text); + expect(data.error).toBe('SECURITY_ERROR'); + }); + }); + + describe('Session Isolation', () => { + it('should keep sessions completely separate', async () => { + const sessionA = 'isolation-session-a'; + const sessionB = 'isolation-session-b'; + + await server.processThought({ + thought: 'Thought from session A - unique identifier A123', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + sessionId: sessionA, + }); + + await server.processThought({ + thought: 'Thought from session B - unique identifier B456', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + sessionId: sessionB, + }); + + const historyA = server.getFilteredHistory({ sessionId: sessionA }); + const historyB = server.getFilteredHistory({ sessionId: sessionB }); + + expect(historyA).toHaveLength(1); + expect(historyB).toHaveLength(1); + expect(historyA[0].thought).toContain('A123'); + expect(historyB[0].thought).toContain('B456'); + expect(historyA[0].thought).not.toContain('B456'); + expect(historyB[0].thought).not.toContain('A123'); + }); + + it('should maintain separate branch state per session', async () => { + const sessionA = 'branch-isolation-a'; + const sessionB = 'branch-isolation-b'; + + await server.processThought({ + thought: 'Root thought A', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: sessionA, + }); + + await server.processThought({ + thought: 'Root thought B', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: sessionB, + }); + + await server.processThought({ + thought: 'Branch thought from A', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: sessionA, + branchFromThought: 1, + branchId: 'branch-a', + }); + + const historyA = server.getFilteredHistory({ sessionId: sessionA }); + const historyB = server.getFilteredHistory({ sessionId: sessionB }); + + expect(historyA.filter(t => t.branchId)).toHaveLength(1); + expect(historyB.filter(t => t.branchId)).toHaveLength(0); + }); + + it('should handle rapid concurrent sessions independently', async () => { + const sessions = ['concurrent-1', 'concurrent-2', 'concurrent-3']; + + const promises = sessions.map(async (sessionId, idx) => { + for (let i = 1; i <= 5; i++) { + await server.processThought({ + thought: `Session ${idx} thought ${i}`, + thoughtNumber: i, + totalThoughts: 5, + nextThoughtNeeded: i < 5, + sessionId, + }); + } + }); + + await Promise.all(promises); + + for (const sessionId of sessions) { + const history = server.getFilteredHistory({ sessionId }); + expect(history).toHaveLength(5); + history.forEach((thought) => { + expect(thought.sessionId).toBe(sessionId); + }); + } + }); + + it('should isolate MCTS tree state between sessions', async () => { + const sessionA = 'mcts-isolation-a'; + const sessionB = 'mcts-isolation-b'; + + await server.processThought({ + thought: 'Initial thought A', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: sessionA, + }); + + await server.evaluateThought(sessionA, 'node_1_1', 0.9); + + await server.processThought({ + thought: 'Another thought A', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: sessionA, + }); + + await server.processThought({ + thought: 'Initial thought B', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: sessionB, + }); + + const summaryA = await server.getThinkingSummary(sessionA); + const summaryB = await server.getThinkingSummary(sessionB); + + const dataA = JSON.parse(summaryA.content[0].text); + const dataB = JSON.parse(summaryB.content[0].text); + + expect(dataA.treeStats.totalNodes).toBeGreaterThan(dataB.treeStats.totalNodes); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/integration/snapshot.test.ts b/src/sequentialthinking/__tests__/integration/snapshot.test.ts new file mode 100644 index 0000000000..84c12c09d0 --- /dev/null +++ b/src/sequentialthinking/__tests__/integration/snapshot.test.ts @@ -0,0 +1,192 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { SequentialThinkingServer } from '../../lib.js'; + +describe('SequentialThinkingServer - Snapshot Tests', () => { + let server: SequentialThinkingServer; + + beforeEach(() => { + process.env.DISABLE_THOUGHT_LOGGING = 'true'; + server = new SequentialThinkingServer(); + }); + + afterEach(() => { + if (server && typeof server.destroy === 'function') { + server.destroy(); + } + }); + + it('should produce consistent thought history format', async () => { + await server.processThought({ + thought: 'First thought about testing', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'snapshot-test-1', + }); + + await server.processThought({ + thought: 'Second thought with more detail', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId: 'snapshot-test-1', + }); + + await server.processThought({ + thought: 'Final thought with conclusion', + thoughtNumber: 3, + totalThoughts: 3, + nextThoughtNeeded: false, + sessionId: 'snapshot-test-1', + }); + + const history = server.getThoughtHistory(); + expect(history).toHaveLength(3); + expect(history[0].thought).toBe('First thought about testing'); + expect(history[1].thought).toBe('Second thought with more detail'); + expect(history[2].thought).toBe('Final thought with conclusion'); + expect(history[2].nextThoughtNeeded).toBe(false); + }); + + it('should produce consistent health check format', async () => { + const health = await server.getHealthStatus(); + expect(health).toHaveProperty('status'); + expect(health).toHaveProperty('summary'); + expect(health).toHaveProperty('timestamp'); + expect(['healthy', 'degraded', 'unhealthy']).toContain(health.status); + }); + + it('should produce consistent metrics format', async () => { + await server.processThought({ + thought: 'Test thought for metrics', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + sessionId: 'metrics-snapshot', + }); + + const metrics = await server.getMetrics(); + expect(metrics).toHaveProperty('requests'); + expect(metrics).toHaveProperty('thoughts'); + expect(metrics).toHaveProperty('system'); + expect(metrics.thoughts).toHaveProperty('totalThoughts'); + }); + + it('should produce consistent thinking summary format', async () => { + const sessionId = 'summary-snapshot'; + + await server.processThought({ + thought: 'Root thought A', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + sessionId, + }); + + await server.processThought({ + thought: 'Child thought B', + thoughtNumber: 2, + totalThoughts: 2, + nextThoughtNeeded: false, + sessionId, + }); + + const summary = await server.getThinkingSummary(sessionId); + const data = JSON.parse(summary.content[0].text); + + expect(data).toHaveProperty('bestPath'); + expect(data).toHaveProperty('treeStructure'); + expect(data).toHaveProperty('treeStats'); + expect(data.treeStats).toHaveProperty('totalNodes'); + expect(data.treeStats).toHaveProperty('maxDepth'); + }); + + it('should maintain consistent response structure for revisions', async () => { + const sessionId = 'revision-snapshot'; + + await server.processThought({ + thought: 'Original thought', + thoughtNumber: 1, + totalThoughts: 2, + nextThoughtNeeded: true, + sessionId, + }); + + await server.processThought({ + thought: 'Revised thought with improvements', + thoughtNumber: 2, + totalThoughts: 2, + nextThoughtNeeded: false, + sessionId, + isRevision: true, + revisesThought: 1, + }); + + const history = server.getFilteredHistory({ sessionId }); + const revised = history.find(t => t.isRevision); + expect(revised).toBeDefined(); + expect(revised?.revisesThought).toBe(1); + }); + + it('should maintain consistent branch structure', async () => { + const sessionId = 'branch-snapshot'; + + await server.processThought({ + thought: 'Main branch thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId, + }); + + await server.processThought({ + thought: 'Branched alternative thought', + thoughtNumber: 2, + totalThoughts: 3, + nextThoughtNeeded: true, + sessionId, + branchFromThought: 1, + branchId: 'branch-alt', + }); + + const history = server.getFilteredHistory({ sessionId }); + const branchThought = history.find(t => t.branchId === 'branch-alt'); + expect(branchThought).toBeDefined(); + expect(branchThought?.branchFromThought).toBe(1); + }); + + it('should preserve session data across multiple operations', async () => { + const sessionId = 'persistence-snapshot'; + + for (let i = 1; i <= 5; i++) { + await server.processThought({ + thought: `Thought ${i}`, + thoughtNumber: i, + totalThoughts: 5, + nextThoughtNeeded: i < 5, + sessionId, + }); + } + + const history = server.getFilteredHistory({ sessionId, limit: 10 }); + expect(history).toHaveLength(5); + expect(history.map(t => t.thoughtNumber)).toEqual([1, 2, 3, 4, 5]); + }); + + it('should handle filtered history consistently', async () => { + const sessionA = 'filter-snap-a'; + const sessionB = 'filter-snap-b'; + + await server.processThought({ thought: 'A1', thoughtNumber: 1, totalThoughts: 2, nextThoughtNeeded: true, sessionId: sessionA }); + await server.processThought({ thought: 'A2', thoughtNumber: 2, totalThoughts: 2, nextThoughtNeeded: false, sessionId: sessionA }); + await server.processThought({ thought: 'B1', thoughtNumber: 1, totalThoughts: 1, nextThoughtNeeded: false, sessionId: sessionB }); + + const historyA = server.getFilteredHistory({ sessionId: sessionA }); + const historyB = server.getFilteredHistory({ sessionId: sessionB }); + + expect(historyA).toHaveLength(2); + expect(historyB).toHaveLength(1); + expect(historyA[0].sessionId).toBe(sessionA); + expect(historyB[0].sessionId).toBe(sessionB); + }); +}); diff --git a/src/sequentialthinking/__tests__/lib.test.ts b/src/sequentialthinking/__tests__/lib.test.ts deleted file mode 100644 index 2114c5ec18..0000000000 --- a/src/sequentialthinking/__tests__/lib.test.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { SequentialThinkingServer, ThoughtData } from '../lib.js'; - -// Mock chalk to avoid ESM issues -vi.mock('chalk', () => { - const chalkMock = { - yellow: (str: string) => str, - green: (str: string) => str, - blue: (str: string) => str, - }; - return { - default: chalkMock, - }; -}); - -describe('SequentialThinkingServer', () => { - let server: SequentialThinkingServer; - - beforeEach(() => { - // Disable thought logging for tests - process.env.DISABLE_THOUGHT_LOGGING = 'true'; - server = new SequentialThinkingServer(); - }); - - // Note: Input validation tests removed - validation now happens at the tool - // registration layer via Zod schemas before processThought is called - - describe('processThought - valid inputs', () => { - it('should accept valid basic thought', () => { - const input = { - thought: 'This is my first thought', - thoughtNumber: 1, - totalThoughts: 3, - nextThoughtNeeded: true - }; - - const result = server.processThought(input); - expect(result.isError).toBeUndefined(); - - const data = JSON.parse(result.content[0].text); - expect(data.thoughtNumber).toBe(1); - expect(data.totalThoughts).toBe(3); - expect(data.nextThoughtNeeded).toBe(true); - expect(data.thoughtHistoryLength).toBe(1); - }); - - it('should accept thought with optional fields', () => { - const input = { - thought: 'Revising my earlier idea', - thoughtNumber: 2, - totalThoughts: 3, - nextThoughtNeeded: true, - isRevision: true, - revisesThought: 1, - needsMoreThoughts: false - }; - - const result = server.processThought(input); - expect(result.isError).toBeUndefined(); - - const data = JSON.parse(result.content[0].text); - expect(data.thoughtNumber).toBe(2); - expect(data.thoughtHistoryLength).toBe(1); - }); - - it('should track multiple thoughts in history', () => { - const input1 = { - thought: 'First thought', - thoughtNumber: 1, - totalThoughts: 3, - nextThoughtNeeded: true - }; - - const input2 = { - thought: 'Second thought', - thoughtNumber: 2, - totalThoughts: 3, - nextThoughtNeeded: true - }; - - const input3 = { - thought: 'Final thought', - thoughtNumber: 3, - totalThoughts: 3, - nextThoughtNeeded: false - }; - - server.processThought(input1); - server.processThought(input2); - const result = server.processThought(input3); - - const data = JSON.parse(result.content[0].text); - expect(data.thoughtHistoryLength).toBe(3); - expect(data.nextThoughtNeeded).toBe(false); - }); - - it('should auto-adjust totalThoughts if thoughtNumber exceeds it', () => { - const input = { - thought: 'Thought 5', - thoughtNumber: 5, - totalThoughts: 3, - nextThoughtNeeded: true - }; - - const result = server.processThought(input); - const data = JSON.parse(result.content[0].text); - - expect(data.totalThoughts).toBe(5); - }); - }); - - describe('processThought - branching', () => { - it('should track branches correctly', () => { - const input1 = { - thought: 'Main thought', - thoughtNumber: 1, - totalThoughts: 3, - nextThoughtNeeded: true - }; - - const input2 = { - thought: 'Branch A thought', - thoughtNumber: 2, - totalThoughts: 3, - nextThoughtNeeded: true, - branchFromThought: 1, - branchId: 'branch-a' - }; - - const input3 = { - thought: 'Branch B thought', - thoughtNumber: 2, - totalThoughts: 3, - nextThoughtNeeded: false, - branchFromThought: 1, - branchId: 'branch-b' - }; - - server.processThought(input1); - server.processThought(input2); - const result = server.processThought(input3); - - const data = JSON.parse(result.content[0].text); - expect(data.branches).toContain('branch-a'); - expect(data.branches).toContain('branch-b'); - expect(data.branches.length).toBe(2); - expect(data.thoughtHistoryLength).toBe(3); - }); - - it('should allow multiple thoughts in same branch', () => { - const input1 = { - thought: 'Branch thought 1', - thoughtNumber: 1, - totalThoughts: 2, - nextThoughtNeeded: true, - branchFromThought: 1, - branchId: 'branch-a' - }; - - const input2 = { - thought: 'Branch thought 2', - thoughtNumber: 2, - totalThoughts: 2, - nextThoughtNeeded: false, - branchFromThought: 1, - branchId: 'branch-a' - }; - - server.processThought(input1); - const result = server.processThought(input2); - - const data = JSON.parse(result.content[0].text); - expect(data.branches).toContain('branch-a'); - expect(data.branches.length).toBe(1); - }); - }); - - describe('processThought - edge cases', () => { - it('should handle very long thought strings', () => { - const input = { - thought: 'a'.repeat(10000), - thoughtNumber: 1, - totalThoughts: 1, - nextThoughtNeeded: false - }; - - const result = server.processThought(input); - expect(result.isError).toBeUndefined(); - }); - - it('should handle thoughtNumber = 1, totalThoughts = 1', () => { - const input = { - thought: 'Only thought', - thoughtNumber: 1, - totalThoughts: 1, - nextThoughtNeeded: false - }; - - const result = server.processThought(input); - expect(result.isError).toBeUndefined(); - - const data = JSON.parse(result.content[0].text); - expect(data.thoughtNumber).toBe(1); - expect(data.totalThoughts).toBe(1); - }); - - it('should handle nextThoughtNeeded = false', () => { - const input = { - thought: 'Final thought', - thoughtNumber: 3, - totalThoughts: 3, - nextThoughtNeeded: false - }; - - const result = server.processThought(input); - const data = JSON.parse(result.content[0].text); - - expect(data.nextThoughtNeeded).toBe(false); - }); - }); - - describe('processThought - response format', () => { - it('should return correct response structure on success', () => { - const input = { - thought: 'Test thought', - thoughtNumber: 1, - totalThoughts: 1, - nextThoughtNeeded: false - }; - - const result = server.processThought(input); - - expect(result).toHaveProperty('content'); - expect(Array.isArray(result.content)).toBe(true); - expect(result.content.length).toBe(1); - expect(result.content[0]).toHaveProperty('type', 'text'); - expect(result.content[0]).toHaveProperty('text'); - }); - - it('should return valid JSON in response', () => { - const input = { - thought: 'Test thought', - thoughtNumber: 1, - totalThoughts: 1, - nextThoughtNeeded: false - }; - - const result = server.processThought(input); - - expect(() => JSON.parse(result.content[0].text)).not.toThrow(); - }); - }); - - describe('processThought - with logging enabled', () => { - let serverWithLogging: SequentialThinkingServer; - - beforeEach(() => { - // Enable thought logging for these tests - delete process.env.DISABLE_THOUGHT_LOGGING; - serverWithLogging = new SequentialThinkingServer(); - }); - - afterEach(() => { - // Reset to disabled for other tests - process.env.DISABLE_THOUGHT_LOGGING = 'true'; - }); - - it('should format and log regular thoughts', () => { - const input = { - thought: 'Test thought with logging', - thoughtNumber: 1, - totalThoughts: 3, - nextThoughtNeeded: true - }; - - const result = serverWithLogging.processThought(input); - expect(result.isError).toBeUndefined(); - }); - - it('should format and log revision thoughts', () => { - const input = { - thought: 'Revised thought', - thoughtNumber: 2, - totalThoughts: 3, - nextThoughtNeeded: true, - isRevision: true, - revisesThought: 1 - }; - - const result = serverWithLogging.processThought(input); - expect(result.isError).toBeUndefined(); - }); - - it('should format and log branch thoughts', () => { - const input = { - thought: 'Branch thought', - thoughtNumber: 2, - totalThoughts: 3, - nextThoughtNeeded: false, - branchFromThought: 1, - branchId: 'branch-a' - }; - - const result = serverWithLogging.processThought(input); - expect(result.isError).toBeUndefined(); - }); - }); -}); diff --git a/src/sequentialthinking/__tests__/unit/branch-tracking.test.ts b/src/sequentialthinking/__tests__/unit/branch-tracking.test.ts new file mode 100644 index 0000000000..3e0da025a0 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/branch-tracking.test.ts @@ -0,0 +1,158 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { BasicMetricsCollector } from '../../metrics.js'; +import { BoundedThoughtManager } from '../../state-manager.js'; +import { SessionTracker } from '../../session-tracker.js'; +import { createTestThought as makeThought } from '../helpers/factories.js'; + +describe('Branch Tracking Consistency', () => { + let metrics: BasicMetricsCollector; + let storage: BoundedThoughtManager; + let sessionTracker: SessionTracker; + + beforeEach(() => { + sessionTracker = new SessionTracker(0); + storage = new BoundedThoughtManager({ + maxHistorySize: 100, + maxBranchAge: 3600000, + + maxThoughtsPerBranch: 50, + cleanupInterval: 0, + }, sessionTracker); + metrics = new BasicMetricsCollector(sessionTracker, storage); + }); + + afterEach(() => { + storage.destroy(); + sessionTracker.destroy(); + }); + + it('should reflect actual branch count from storage', () => { + // Add thoughts to different branches + storage.addThought(makeThought({ branchId: 'branch-a' })); + metrics.recordThoughtProcessed(makeThought({ branchId: 'branch-a' })); + + storage.addThought(makeThought({ branchId: 'branch-b' })); + metrics.recordThoughtProcessed(makeThought({ branchId: 'branch-b' })); + + storage.addThought(makeThought({ branchId: 'branch-c' })); + metrics.recordThoughtProcessed(makeThought({ branchId: 'branch-c' })); + + // Metrics should show 3 branches + const m = metrics.getMetrics(); + expect(m.thoughts.branchCount).toBe(3); + + // Verify storage agrees + expect(storage.getBranches()).toHaveLength(3); + }); + + it('should update when branches expire in storage', () => { + vi.useFakeTimers(); + try { + // Create storage with short branch expiry + const shortStorage = new BoundedThoughtManager({ + maxHistorySize: 100, + maxBranchAge: 1000, // 1 second + + maxThoughtsPerBranch: 50, + cleanupInterval: 0, + }, sessionTracker); + + const shortMetrics = new BasicMetricsCollector(sessionTracker, shortStorage); + + // Add branch + shortStorage.addThought(makeThought({ branchId: 'expiring-branch' })); + shortMetrics.recordThoughtProcessed(makeThought({ branchId: 'expiring-branch' })); + + expect(shortMetrics.getMetrics().thoughts.branchCount).toBe(1); + + // Advance time past expiry + vi.advanceTimersByTime(2000); + + // Trigger cleanup + shortStorage.cleanup(); + + // Record a new thought to trigger metrics update + shortMetrics.recordThoughtProcessed(makeThought()); + + // Branch should be gone from both storage and metrics + expect(shortStorage.getBranches()).toHaveLength(0); + expect(shortMetrics.getMetrics().thoughts.branchCount).toBe(0); + + shortStorage.destroy(); + } finally { + vi.useRealTimers(); + } + }); + + it('should handle duplicate branch IDs correctly', () => { + // Add multiple thoughts to same branch + storage.addThought(makeThought({ branchId: 'duplicate-branch', thoughtNumber: 1 })); + metrics.recordThoughtProcessed(makeThought({ branchId: 'duplicate-branch', thoughtNumber: 1 })); + + storage.addThought(makeThought({ branchId: 'duplicate-branch', thoughtNumber: 2 })); + metrics.recordThoughtProcessed(makeThought({ branchId: 'duplicate-branch', thoughtNumber: 2 })); + + storage.addThought(makeThought({ branchId: 'duplicate-branch', thoughtNumber: 3 })); + metrics.recordThoughtProcessed(makeThought({ branchId: 'duplicate-branch', thoughtNumber: 3 })); + + // Should only count as 1 branch + expect(metrics.getMetrics().thoughts.branchCount).toBe(1); + expect(storage.getBranches()).toHaveLength(1); + }); + + it('should handle mixed branch and non-branch thoughts', () => { + // Add non-branch thought + storage.addThought(makeThought({ thoughtNumber: 1 })); + metrics.recordThoughtProcessed(makeThought({ thoughtNumber: 1 })); + + // Branch count should be 0 + expect(metrics.getMetrics().thoughts.branchCount).toBe(0); + + // Add branch thought + storage.addThought(makeThought({ branchId: 'new-branch', thoughtNumber: 2 })); + metrics.recordThoughtProcessed(makeThought({ branchId: 'new-branch', thoughtNumber: 2 })); + + // Branch count should be 1 + expect(metrics.getMetrics().thoughts.branchCount).toBe(1); + + // Add more non-branch thoughts + storage.addThought(makeThought({ thoughtNumber: 3 })); + metrics.recordThoughtProcessed(makeThought({ thoughtNumber: 3 })); + + // Branch count should still be 1 + expect(metrics.getMetrics().thoughts.branchCount).toBe(1); + }); + + it('should maintain consistency after storage clear', () => { + // Add several branches + for (let i = 0; i < 5; i++) { + storage.addThought(makeThought({ branchId: `branch-${i}` })); + metrics.recordThoughtProcessed(makeThought({ branchId: `branch-${i}` })); + } + + expect(metrics.getMetrics().thoughts.branchCount).toBe(5); + + // Clear storage + storage.clearHistory(); + + // Record a new thought to trigger metrics refresh + metrics.recordThoughtProcessed(makeThought()); + + // Metrics should reflect empty storage + expect(metrics.getMetrics().thoughts.branchCount).toBe(0); + expect(storage.getBranches()).toHaveLength(0); + }); + + it('should handle rapid branch creation correctly', () => { + // Create many branches rapidly + const branchCount = 100; + for (let i = 0; i < branchCount; i++) { + storage.addThought(makeThought({ branchId: `rapid-${i}` })); + metrics.recordThoughtProcessed(makeThought({ branchId: `rapid-${i}` })); + } + + // Should count all branches + expect(metrics.getMetrics().thoughts.branchCount).toBe(branchCount); + expect(storage.getBranches()).toHaveLength(branchCount); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/circular-buffer.test.ts b/src/sequentialthinking/__tests__/unit/circular-buffer.test.ts new file mode 100644 index 0000000000..11584b1082 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/circular-buffer.test.ts @@ -0,0 +1,174 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { CircularBuffer } from '../../circular-buffer.js'; + +describe('CircularBuffer', () => { + let buffer: CircularBuffer; + + beforeEach(() => { + buffer = new CircularBuffer(3); + }); + + describe('Basic Operations', () => { + it('should initialize with correct capacity', () => { + expect(buffer.currentSize).toBe(0); + }); + + it('should add items correctly', () => { + buffer.add('item1'); + expect(buffer.currentSize).toBe(1); + + buffer.add('item2'); + expect(buffer.currentSize).toBe(2); + + buffer.add('item3'); + expect(buffer.currentSize).toBe(3); + }); + + it('should overwrite old items when full', () => { + buffer.add('item1'); + buffer.add('item2'); + buffer.add('item3'); + buffer.add('item4'); // Should overwrite item1 + + expect(buffer.currentSize).toBe(3); + + const items = buffer.getAll(); + expect(items).toEqual(['item2', 'item3', 'item4']); + }); + }); + + describe('Retrieval Operations', () => { + beforeEach(() => { + buffer.add('first'); + buffer.add('second'); + buffer.add('third'); + }); + + it('should retrieve all items', () => { + const items = buffer.getAll(); + expect(items).toEqual(['first', 'second', 'third']); + }); + + it('should retrieve limited number of items', () => { + const items = buffer.getAll(2); + expect(items).toEqual(['second', 'third']); // Most recent 2 + }); + + }); + + describe('Edge Cases', () => { + it('should handle empty buffer', () => { + expect(buffer.getAll()).toEqual([]); + }); + + it('should handle limit larger than size', () => { + buffer.add('item1'); + buffer.add('item2'); + + const items = buffer.getAll(10); + expect(items).toEqual(['item1', 'item2']); + }); + + it('should clear buffer correctly', () => { + buffer.add('item1'); + buffer.add('item2'); + + expect(buffer.currentSize).toBe(2); + + buffer.clear(); + + expect(buffer.currentSize).toBe(0); + expect(buffer.getAll()).toEqual([]); + }); + }); + + describe('Wrap-around Behavior', () => { + it('should handle multiple wrap-arounds correctly', () => { + const items = ['a', 'b', 'c', 'd', 'e', 'f', 'g']; + + items.forEach(item => buffer.add(item)); + + // Buffer size should be 3 (capacity) + expect(buffer.currentSize).toBe(3); + + // Should contain last 3 items + const result = buffer.getAll(); + expect(result).toEqual(['e', 'f', 'g']); + }); + + it('should maintain order after wrap-around', () => { + buffer.add('1'); + buffer.add('2'); + buffer.add('3'); + buffer.add('4'); + buffer.add('5'); + + const items = buffer.getAll(); + expect(items).toEqual(['3', '4', '5']); + }); + }); + + describe('Capacity Edge Cases', () => { + it('should handle capacity of 1', () => { + const buf = new CircularBuffer(1); + + buf.add('first'); + expect(buf.currentSize).toBe(1); + expect(buf.getAll()).toEqual(['first']); + + buf.add('second'); + expect(buf.currentSize).toBe(1); + expect(buf.getAll()).toEqual(['second']); + }); + + it('should handle large capacity', () => { + const buf = new CircularBuffer(10000); + + for (let i = 0; i < 100; i++) { + buf.add(i); + } + + expect(buf.currentSize).toBe(100); + }); + }); + + describe('Performance', () => { + it('should handle large number of operations efficiently', () => { + const start = Date.now(); + + // Add many items + for (let i = 0; i < 10000; i++) { + buffer.add(`item-${i}`); + } + + const duration = Date.now() - start; + + // Should be very fast + expect(duration).toBeLessThan(100); // Less than 100ms + expect(buffer.currentSize).toBe(3); // Still at capacity + }); + }); + + describe('getAll(0) returns empty', () => { + it('should return empty array when limit is 0', () => { + buffer.add('item1'); + buffer.add('item2'); + buffer.add('item3'); + expect(buffer.getAll(0)).toEqual([]); + }); + }); + + describe('Constructor validation', () => { + it('should throw on capacity 0', () => { + expect(() => new CircularBuffer(0)).toThrow('capacity must be a positive integer'); + }); + + it('should throw on negative capacity', () => { + expect(() => new CircularBuffer(-1)).toThrow('capacity must be a positive integer'); + }); + + it('should throw on non-integer capacity', () => { + expect(() => new CircularBuffer(1.5)).toThrow('capacity must be a positive integer'); + }); + }); +}); \ No newline at end of file diff --git a/src/sequentialthinking/__tests__/unit/config.test.ts b/src/sequentialthinking/__tests__/unit/config.test.ts new file mode 100644 index 0000000000..83e6d3058f --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/config.test.ts @@ -0,0 +1,257 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { ConfigManager } from '../../config.js'; + +describe('ConfigManager', () => { + const savedEnv: Record = {}; + + beforeEach(() => { + // Save env vars we'll modify + for (const key of [ + 'MAX_HISTORY_SIZE', 'MAX_THOUGHT_LENGTH', 'MAX_THOUGHTS_PER_MIN', + 'SERVER_NAME', 'SERVER_VERSION', 'BLOCKED_PATTERNS', + 'LOG_LEVEL', 'ENABLE_COLORS', 'ENABLE_METRICS', 'ENABLE_HEALTH_CHECKS', + 'MAX_BRANCH_AGE', 'MAX_THOUGHTS_PER_BRANCH', 'CLEANUP_INTERVAL', + 'DISABLE_THOUGHT_LOGGING', + 'HEALTH_MAX_MEMORY', 'HEALTH_MAX_STORAGE', 'HEALTH_MAX_RESPONSE_TIME', + 'HEALTH_ERROR_RATE_DEGRADED', 'HEALTH_ERROR_RATE_UNHEALTHY', + ]) { + savedEnv[key] = process.env[key]; + } + }); + + afterEach(() => { + // Restore env vars + for (const [key, value] of Object.entries(savedEnv)) { + if (value === undefined) { + delete process.env[key]; + } else { + process.env[key] = value; + } + } + }); + + describe('load()', () => { + it('should return default config when no env vars set', () => { + // Clear env vars + delete process.env.MAX_HISTORY_SIZE; + delete process.env.SERVER_NAME; + delete process.env.DISABLE_THOUGHT_LOGGING; + + const config = ConfigManager.load(); + + expect(config.server.name).toBe('sequential-thinking-server'); + expect(config.server.version).toBe('0.6.2'); + expect(config.state.maxHistorySize).toBe(1000); + expect(config.state.maxThoughtLength).toBe(5000); + expect(config.state.maxBranchAge).toBe(3600000); + expect(config.state.maxThoughtsPerBranch).toBe(100); + expect(config.state.cleanupInterval).toBe(300000); + expect(config.security.maxThoughtsPerMinute).toBe(60); + expect(config.logging.level).toBe('info'); + expect(config.logging.enableColors).toBe(true); + expect(config.logging.enableThoughtLogging).toBe(true); + expect(config.monitoring.enableMetrics).toBe(true); + expect(config.monitoring.enableHealthChecks).toBe(true); + expect(config.monitoring.healthThresholds.maxMemoryPercent).toBe(90); + expect(config.monitoring.healthThresholds.maxStoragePercent).toBe(80); + expect(config.monitoring.healthThresholds.maxResponseTimeMs).toBe(200); + expect(config.monitoring.healthThresholds.errorRateDegraded).toBe(2); + expect(config.monitoring.healthThresholds.errorRateUnhealthy).toBe(5); + }); + + it('should respect env var overrides', () => { + process.env.MAX_HISTORY_SIZE = '500'; + process.env.SERVER_NAME = 'custom-server'; + + const config = ConfigManager.load(); + + expect(config.state.maxHistorySize).toBe(500); + expect(config.server.name).toBe('custom-server'); + }); + + it('should use defaults for NaN env values', () => { + process.env.MAX_HISTORY_SIZE = 'not-a-number'; + + const config = ConfigManager.load(); + + expect(config.state.maxHistorySize).toBe(1000); + }); + + it('should use defaults for undefined env values', () => { + delete process.env.MAX_HISTORY_SIZE; + + const config = ConfigManager.load(); + + expect(config.state.maxHistorySize).toBe(1000); + }); + }); + + describe('enableThoughtLogging', () => { + it('should default to true when DISABLE_THOUGHT_LOGGING is not set', () => { + delete process.env.DISABLE_THOUGHT_LOGGING; + const config = ConfigManager.load(); + expect(config.logging.enableThoughtLogging).toBe(true); + }); + + it('should be false when DISABLE_THOUGHT_LOGGING is true', () => { + process.env.DISABLE_THOUGHT_LOGGING = 'true'; + const config = ConfigManager.load(); + expect(config.logging.enableThoughtLogging).toBe(false); + }); + + it('should remain true for non-true values of DISABLE_THOUGHT_LOGGING', () => { + process.env.DISABLE_THOUGHT_LOGGING = 'false'; + const config = ConfigManager.load(); + expect(config.logging.enableThoughtLogging).toBe(true); + }); + }); + + describe('health threshold env vars', () => { + it('should load custom health thresholds from env', () => { + process.env.HEALTH_MAX_MEMORY = '70'; + process.env.HEALTH_MAX_STORAGE = '60'; + process.env.HEALTH_MAX_RESPONSE_TIME = '100'; + process.env.HEALTH_ERROR_RATE_DEGRADED = '1'; + process.env.HEALTH_ERROR_RATE_UNHEALTHY = '3'; + + const config = ConfigManager.load(); + + expect(config.monitoring.healthThresholds.maxMemoryPercent).toBe(70); + expect(config.monitoring.healthThresholds.maxStoragePercent).toBe(60); + expect(config.monitoring.healthThresholds.maxResponseTimeMs).toBe(100); + expect(config.monitoring.healthThresholds.errorRateDegraded).toBe(1); + expect(config.monitoring.healthThresholds.errorRateUnhealthy).toBe(3); + }); + }); + + describe('validate()', () => { + it('should accept valid config', () => { + const config = ConfigManager.load(); + expect(() => ConfigManager.validate(config)).not.toThrow(); + }); + + it('should reject maxHistorySize = 0', () => { + const config = ConfigManager.load(); + config.state.maxHistorySize = 0; + expect(() => ConfigManager.validate(config)).toThrow('MAX_HISTORY_SIZE must be between 1 and 10000'); + }); + + it('should reject maxHistorySize = 10001', () => { + const config = ConfigManager.load(); + config.state.maxHistorySize = 10001; + expect(() => ConfigManager.validate(config)).toThrow('MAX_HISTORY_SIZE must be between 1 and 10000'); + }); + + it('should reject maxThoughtLength = -1', () => { + const config = ConfigManager.load(); + config.state.maxThoughtLength = -1; + expect(() => ConfigManager.validate(config)).toThrow('maxThoughtLength must be between 1 and 100000'); + }); + + it('should reject maxThoughtLength = 100001', () => { + const config = ConfigManager.load(); + config.state.maxThoughtLength = 100001; + expect(() => ConfigManager.validate(config)).toThrow('maxThoughtLength must be between 1 and 100000'); + }); + + it('should accept maxThoughtLength = 1', () => { + const config = ConfigManager.load(); + config.state.maxThoughtLength = 1; + expect(() => ConfigManager.validate(config)).not.toThrow(); + }); + + it('should accept maxThoughtLength = 100000', () => { + const config = ConfigManager.load(); + config.state.maxThoughtLength = 100000; + expect(() => ConfigManager.validate(config)).not.toThrow(); + }); + + it('should reject maxThoughtsPerMinute out of range', () => { + const config = ConfigManager.load(); + config.security.maxThoughtsPerMinute = 0; + expect(() => ConfigManager.validate(config)).toThrow('maxThoughtsPerMinute must be between 1 and 1000'); + }); + + it('should reject negative maxBranchAge', () => { + const config = ConfigManager.load(); + config.state.maxBranchAge = -1; + expect(() => ConfigManager.validate(config)).toThrow('maxBranchAge must be >= 0'); + }); + + it('should reject maxThoughtsPerBranch out of range', () => { + const config = ConfigManager.load(); + config.state.maxThoughtsPerBranch = 0; + expect(() => ConfigManager.validate(config)).toThrow('maxThoughtsPerBranch must be between 1 and 10000'); + }); + + it('should reject maxThoughtsPerBranch exceeding 10000', () => { + const config = ConfigManager.load(); + config.state.maxThoughtsPerBranch = 10001; + expect(() => ConfigManager.validate(config)).toThrow('maxThoughtsPerBranch must be between 1 and 10000'); + }); + + it('should reject negative cleanupInterval', () => { + const config = ConfigManager.load(); + config.state.cleanupInterval = -1; + expect(() => ConfigManager.validate(config)).toThrow('cleanupInterval must be >= 0'); + }); + }); + + describe('getEnvironmentInfo()', () => { + it('should return correct shape', () => { + const info = ConfigManager.getEnvironmentInfo(); + + expect(typeof info.nodeVersion).toBe('string'); + expect(typeof info.platform).toBe('string'); + expect(typeof info.arch).toBe('string'); + expect(typeof info.pid).toBe('number'); + expect(info.memoryUsage).toHaveProperty('heapUsed'); + expect(typeof info.uptime).toBe('number'); + }); + }); + + describe('loadBlockedPatterns()', () => { + it('should load defaults when BLOCKED_PATTERNS is not set', () => { + delete process.env.BLOCKED_PATTERNS; + + const config = ConfigManager.load(); + + expect(config.security.blockedPatterns.length).toBeGreaterThan(0); + expect(config.security.blockedPatterns[0]).toBeInstanceOf(RegExp); + }); + + it('should parse BLOCKED_PATTERNS env var', () => { + process.env.BLOCKED_PATTERNS = 'foo,bar'; + + const config = ConfigManager.load(); + + expect(config.security.blockedPatterns).toHaveLength(2); + expect(config.security.blockedPatterns[0].test('foo')).toBe(true); + }); + + it('should fall back to defaults on invalid regex', () => { + process.env.BLOCKED_PATTERNS = '(invalid['; + + const config = ConfigManager.load(); + + // Should fall back to defaults + expect(config.security.blockedPatterns.length).toBeGreaterThan(0); + }); + }); + + describe('LOG_LEVEL validation', () => { + it('should fall back to info for invalid LOG_LEVEL', () => { + process.env.LOG_LEVEL = 'verbose'; + const config = ConfigManager.load(); + expect(config.logging.level).toBe('info'); + }); + + it('should accept valid LOG_LEVEL values', () => { + for (const level of ['debug', 'info', 'warn', 'error']) { + process.env.LOG_LEVEL = level; + const config = ConfigManager.load(); + expect(config.logging.level).toBe(level); + } + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/container.test.ts b/src/sequentialthinking/__tests__/unit/container.test.ts new file mode 100644 index 0000000000..467baf967d --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/container.test.ts @@ -0,0 +1,107 @@ +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { SimpleContainer, SequentialThinkingApp } from '../../container.js'; + +describe('SimpleContainer', () => { + it('should register and retrieve a service', () => { + const container = new SimpleContainer(); + container.register('greeting', () => 'hello'); + expect(container.get('greeting')).toBe('hello'); + }); + + it('should return cached instance on second get', () => { + const container = new SimpleContainer(); + let callCount = 0; + container.register('counter', () => ++callCount); + expect(container.get('counter')).toBe(1); + expect(container.get('counter')).toBe(1); // Same instance + }); + + it('should throw for unregistered service', () => { + const container = new SimpleContainer(); + expect(() => container.get('nonexistent')).toThrow("Service 'nonexistent' not registered"); + }); + + it('should call destroy on services that have it', () => { + const container = new SimpleContainer(); + const destroyFn = vi.fn(); + container.register('svc', () => ({ destroy: destroyFn })); + container.get('svc'); // Instantiate + container.destroy(); + expect(destroyFn).toHaveBeenCalledTimes(1); + }); + + it('should handle destroy throwing without crashing', () => { + const container = new SimpleContainer(); + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + container.register('bad', () => ({ + destroy: () => { throw new Error('boom'); }, + })); + container.get('bad'); + expect(() => container.destroy()).not.toThrow(); + expect(errorSpy).toHaveBeenCalled(); + }); + + it('should clear cached instance on re-register', () => { + const container = new SimpleContainer(); + container.register('svc', () => 'v1'); + expect(container.get('svc')).toBe('v1'); + container.register('svc', () => 'v2'); + expect(container.get('svc')).toBe('v2'); + }); + + it('should not call factory until first get (lazy instantiation)', () => { + const container = new SimpleContainer(); + const factory = vi.fn(() => 'lazy-value'); + container.register('lazy', factory); + expect(factory).not.toHaveBeenCalled(); + const value = container.get('lazy'); + expect(factory).toHaveBeenCalledTimes(1); + expect(value).toBe('lazy-value'); + }); + + describe('double-destroy safety', () => { + it('should not throw on double destroy', () => { + const container = new SimpleContainer(); + const destroyFn = vi.fn(); + container.register('svc', () => ({ destroy: destroyFn })); + container.get('svc'); // Instantiate + + container.destroy(); + container.destroy(); // Second call should be no-op + + expect(destroyFn).toHaveBeenCalledTimes(1); + }); + }); +}); + +describe('SequentialThinkingApp', () => { + let app: SequentialThinkingApp; + + afterEach(() => { + app?.destroy(); + }); + + it('should create app with default config', () => { + app = new SequentialThinkingApp(); + expect(app.getContainer()).toBeDefined(); + }); + + it('should resolve registered services', () => { + app = new SequentialThinkingApp(); + const container = app.getContainer(); + expect(() => container.get('config')).not.toThrow(); + expect(() => container.get('logger')).not.toThrow(); + expect(() => container.get('formatter')).not.toThrow(); + expect(() => container.get('storage')).not.toThrow(); + expect(() => container.get('security')).not.toThrow(); + expect(() => container.get('metrics')).not.toThrow(); + expect(() => container.get('healthChecker')).not.toThrow(); + }); + + it('should destroy without errors', () => { + app = new SequentialThinkingApp(); + // Force instantiation + app.getContainer().get('storage'); + expect(() => app.destroy()).not.toThrow(); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/formatter.test.ts b/src/sequentialthinking/__tests__/unit/formatter.test.ts new file mode 100644 index 0000000000..ef9d7131cf --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/formatter.test.ts @@ -0,0 +1,62 @@ +import { describe, it, expect } from 'vitest'; +import { ConsoleThoughtFormatter } from '../../formatter.js'; +import { createTestThought as makeThought } from '../helpers/factories.js'; + +describe('ConsoleThoughtFormatter', () => { + describe('format (non-color mode)', () => { + const formatter = new ConsoleThoughtFormatter(false); + + it('should produce box-drawing border', () => { + const output = formatter.format(makeThought()); + expect(output).toContain('┌'); + expect(output).toContain('┘'); + expect(output).toContain('─'); + }); + + it('should contain header and body', () => { + const output = formatter.format(makeThought({ thought: 'My analysis' })); + expect(output).toContain('[Thought] 1/3'); + expect(output).toContain('My analysis'); + }); + + it('should have border width matching content', () => { + const thought = makeThought({ thought: 'Short' }); + const output = formatter.format(thought); + const lines = output.split('\n'); + // All border lines should have the same length + const borderLines = lines.filter(l => l.startsWith('┌') || l.startsWith('└') || l.startsWith('├')); + const lengths = borderLines.map(l => l.length); + expect(new Set(lengths).size).toBe(1); + }); + }); + + describe('multiline body', () => { + const formatter = new ConsoleThoughtFormatter(false); + + it('should not throw on multiline thought body', () => { + const output = formatter.format(makeThought({ thought: 'Line one\nLine two' })); + expect(output).toContain('Line one'); + expect(output).toContain('Line two'); + }); + }); + + describe('undefined optional fields', () => { + const formatter = new ConsoleThoughtFormatter(false); + + it('should show fallback for undefined revisesThought', () => { + const output = formatter.format( + makeThought({ isRevision: true, revisesThought: undefined }), + ); + expect(output).toContain('?'); + expect(output).not.toContain('undefined'); + }); + + it('should show fallback for undefined branchId', () => { + const output = formatter.format( + makeThought({ branchFromThought: 1, branchId: undefined }), + ); + expect(output).toContain('unknown'); + expect(output).not.toContain('undefined'); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/health-checker.test.ts b/src/sequentialthinking/__tests__/unit/health-checker.test.ts new file mode 100644 index 0000000000..43963162f0 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/health-checker.test.ts @@ -0,0 +1,248 @@ +import { describe, it, expect } from 'vitest'; +import { ComprehensiveHealthChecker } from '../../health-checker.js'; +import type { MetricsCollector, ThoughtStorage, SecurityService, StorageStats, RequestMetrics, ThoughtMetrics, SystemMetrics } from '../../interfaces.js'; + +function makeMockMetrics(overrides?: Partial): MetricsCollector { + return { + recordRequest: () => {}, + recordThoughtProcessed: () => {}, + destroy: () => {}, + getMetrics: () => ({ + requests: { + totalRequests: 10, + successfulRequests: 10, + failedRequests: 0, + averageResponseTime: 50, + lastRequestTime: new Date(), + requestsPerMinute: 5, + ...overrides, + }, + thoughts: { + totalThoughts: 0, + averageThoughtLength: 0, + thoughtsPerMinute: 0, + revisionCount: 0, + branchCount: 0, + activeSessions: 0, + }, + system: { + memoryUsage: process.memoryUsage(), + cpuUsage: process.cpuUsage(), + uptime: process.uptime(), + timestamp: new Date(), + }, + }), + }; +} + +function makeMockStorage(overrides?: Partial): ThoughtStorage { + return { + addThought: () => {}, + getHistory: () => [], + getBranches: () => [], + destroy: () => {}, + getStats: () => ({ + historySize: 10, + historyCapacity: 100, + branchCount: 0, + sessionCount: 0, + ...overrides, + }), + }; +} + +function makeMockSecurity(): SecurityService { + return { + validateThought: () => {}, + sanitizeContent: (c: string) => c, + getSecurityStatus: () => ({ status: 'healthy', activeSessions: 0, blockedPatterns: 5 }), + generateSessionId: () => 'test-id', + validateSession: () => true, + }; +} + +describe('ComprehensiveHealthChecker', () => { + it('should return healthy when all checks pass', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.status).toBe('healthy'); + expect(health.checks.memory.status).toBe('healthy'); + expect(health.checks.storage.status).toBe('healthy'); + expect(health.checks.security.status).toBe('healthy'); + }); + + it('should return degraded on elevated storage usage (>64% of capacity)', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage({ historySize: 70, historyCapacity: 100 }), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks.storage.status).toBe('degraded'); + }); + + it('should handle division-by-zero guard (capacity = 0)', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage({ historySize: 0, historyCapacity: 0 }), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + // Should not produce NaN/Infinity — should be healthy with 0% + expect(health.checks.storage.status).toBe('healthy'); + expect(health.checks.storage.message).toContain('0'); + }); + + it('should use fallback on rejected check', async () => { + const brokenSecurity: SecurityService = { + validateThought: () => {}, + sanitizeContent: (c: string) => c, + getSecurityStatus: () => { throw new Error('boom'); }, + generateSessionId: () => 'x', + validateSession: () => true, + }; + + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage(), + brokenSecurity, + ); + const health = await checker.checkHealth(); + // Security check should be unhealthy but others should be fine + expect(health.checks.security.status).toBe('unhealthy'); + expect(health.checks.memory.status).toBe('healthy'); + }); + + it('should return degraded on elevated response time (>80% of max)', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics({ averageResponseTime: 170 }), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks.responseTime.status).toBe('degraded'); + }); + + it('should include all 5 check fields', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks).toHaveProperty('memory'); + expect(health.checks).toHaveProperty('responseTime'); + expect(health.checks).toHaveProperty('errorRate'); + expect(health.checks).toHaveProperty('storage'); + expect(health.checks).toHaveProperty('security'); + }); + + it('should include summary, uptime, and timestamp', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(typeof health.summary).toBe('string'); + expect(typeof health.uptime).toBe('number'); + expect(health.timestamp).toBeInstanceOf(Date); + }); + + it('should return degraded on elevated error rate (>2%)', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics({ totalRequests: 100, failedRequests: 3, successfulRequests: 97 }), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks.errorRate.status).toBe('degraded'); + }); + + it('should return unhealthy on high error rate (>5%)', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics({ totalRequests: 100, failedRequests: 6, successfulRequests: 94 }), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks.errorRate.status).toBe('unhealthy'); + }); + + it('should return unhealthy on response time exceeding max', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics({ averageResponseTime: 250 }), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks.responseTime.status).toBe('unhealthy'); + }); + + it('should return unhealthy on storage usage exceeding max', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage({ historySize: 90, historyCapacity: 100 }), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks.storage.status).toBe('unhealthy'); + }); + + describe('custom thresholds', () => { + it('should use custom maxStoragePercent threshold', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics(), + makeMockStorage({ historySize: 55, historyCapacity: 100 }), + makeMockSecurity(), + { maxMemoryPercent: 90, maxStoragePercent: 50, maxResponseTimeMs: 200, errorRateDegraded: 2, errorRateUnhealthy: 5 }, + ); + const health = await checker.checkHealth(); + // 55% > 50% maxStoragePercent → unhealthy + expect(health.checks.storage.status).toBe('unhealthy'); + }); + + it('should use custom maxResponseTimeMs threshold', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics({ averageResponseTime: 60 }), + makeMockStorage(), + makeMockSecurity(), + { maxMemoryPercent: 90, maxStoragePercent: 80, maxResponseTimeMs: 50, errorRateDegraded: 2, errorRateUnhealthy: 5 }, + ); + const health = await checker.checkHealth(); + // 60 > 50 → unhealthy + expect(health.checks.responseTime.status).toBe('unhealthy'); + }); + + it('should use custom error rate thresholds', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics({ totalRequests: 100, failedRequests: 2, successfulRequests: 98 }), + makeMockStorage(), + makeMockSecurity(), + { maxMemoryPercent: 90, maxStoragePercent: 80, maxResponseTimeMs: 200, errorRateDegraded: 1, errorRateUnhealthy: 3 }, + ); + const health = await checker.checkHealth(); + // 2% > 1% degraded threshold → degraded + expect(health.checks.errorRate.status).toBe('degraded'); + }); + }); + + describe('error rate clamping', () => { + it('should clamp error rate to 100% when failedRequests > totalRequests', async () => { + const checker = new ComprehensiveHealthChecker( + makeMockMetrics({ totalRequests: 100, failedRequests: 200, successfulRequests: 0 }), + makeMockStorage(), + makeMockSecurity(), + ); + const health = await checker.checkHealth(); + expect(health.checks.errorRate.status).toBe('unhealthy'); + // Error rate should be clamped to 100, not 200 + const details = health.checks.errorRate.details as { errorRate: number }; + expect(details.errorRate).toBe(100); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/logger.test.ts b/src/sequentialthinking/__tests__/unit/logger.test.ts new file mode 100644 index 0000000000..9724aaa085 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/logger.test.ts @@ -0,0 +1,206 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { StructuredLogger } from '../../logger.js'; + +describe('StructuredLogger', () => { + let errorSpy: ReturnType; + + beforeEach(() => { + errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + }); + + describe('log level filtering', () => { + it('should suppress debug messages at info level', () => { + const logger = new StructuredLogger({ level: 'info', enableColors: false, enableThoughtLogging: true }); + logger.debug('should not appear'); + expect(errorSpy).not.toHaveBeenCalled(); + }); + + it('should output info messages at info level', () => { + const logger = new StructuredLogger({ level: 'info', enableColors: false, enableThoughtLogging: true }); + logger.info('visible'); + expect(errorSpy).toHaveBeenCalledTimes(1); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.level).toBe('info'); + expect(entry.message).toBe('visible'); + }); + + it('should output debug messages at debug level', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.debug('debug msg'); + expect(errorSpy).toHaveBeenCalledTimes(1); + }); + + it('should suppress info messages at warn level', () => { + const logger = new StructuredLogger({ level: 'warn', enableColors: false, enableThoughtLogging: true }); + logger.info('should not appear'); + expect(errorSpy).not.toHaveBeenCalled(); + }); + + it('should output error messages at error level', () => { + const logger = new StructuredLogger({ level: 'error', enableColors: false, enableThoughtLogging: true }); + logger.error('err'); + expect(errorSpy).toHaveBeenCalledTimes(1); + }); + }); + + describe('sensitive field redaction', () => { + it('should redact password fields', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.info('test', { password: 'secret123' }); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.meta.password).toBe('[REDACTED]'); + }); + + it('should redact nested sensitive fields', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.info('test', { user: { token: 'abc', name: 'Alice' } }); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.meta.user.token).toBe('[REDACTED]'); + expect(entry.meta.user.name).toBe('Alice'); + }); + + it('should redact auth-related fields', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.info('test', { authorization: 'Bearer xyz' }); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.meta.authorization).toBe('[REDACTED]'); + }); + }); + + describe('word-boundary-aware sensitive field matching', () => { + const sensitiveCases = [ + { field: 'authorization', value: 'Bearer xyz', shouldRedact: true }, + { field: 'password', value: 'secret', shouldRedact: true }, + { field: 'mySecretKey', value: 'value', shouldRedact: true }, + { field: 'api_key', value: 'abc123', shouldRedact: true }, + { field: 'authoritativeSource', value: 'docs.example.com', shouldRedact: false }, + { field: 'keyboard', value: 'mechanical', shouldRedact: false }, + { field: 'monkey', value: 'see monkey do', shouldRedact: false }, + ]; + + it.each(sensitiveCases)('should redact $field: $shouldRedact ? "REDACTED" : "original"', ({ field, value, shouldRedact }) => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.info('test', { [field]: value }); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.meta[field]).toBe(shouldRedact ? '[REDACTED]' : value); + }); + }); + + describe('depth limit on sanitize', () => { + it('should return [Object] for deeply nested objects', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + + // Build an object nested 15 levels deep + let deep: Record = { value: 'leaf' }; + for (let i = 0; i < 15; i++) { + deep = { nested: deep }; + } + + logger.info('test', deep as Record); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + + // Walk down until we find '[Object]' + let current: unknown = entry.meta; + let depth = 0; + while (typeof current === 'object' && current !== null && depth < 20) { + current = (current as Record).nested; + depth++; + } + expect(current).toBe('[Object]'); + expect(depth).toBeLessThan(15); + }); + }); + + describe('circular reference handling', () => { + it('should handle circular references without crashing', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + const obj: Record = { name: 'root' }; + obj.self = obj; + + logger.info('test', obj); + expect(errorSpy).toHaveBeenCalledTimes(1); + const output = errorSpy.mock.calls[0][0] as string; + expect(output).toContain('[Circular]'); + }); + + it('should handle nested circular references', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + const a: Record = { name: 'a' }; + const b: Record = { name: 'b', ref: a }; + a.ref = b; + + logger.info('test', a); + expect(errorSpy).toHaveBeenCalledTimes(1); + const output = errorSpy.mock.calls[0][0] as string; + expect(output).toContain('[Circular]'); + }); + }); + + describe('logThought', () => { + it('should produce debug entry with thought metadata', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.logThought('session-1', { + thought: 'test thought', + thoughtNumber: 1, + totalThoughts: 3, + nextThoughtNeeded: true, + }); + expect(errorSpy).toHaveBeenCalledTimes(1); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.level).toBe('debug'); + expect(entry.message).toBe('Thought processed'); + expect(entry.meta.sessionId).toBe('session-1'); + expect(entry.meta.thoughtNumber).toBe(1); + }); + + it('should not log thought at info level', () => { + const logger = new StructuredLogger({ level: 'info', enableColors: false, enableThoughtLogging: true }); + logger.logThought('session-1', { + thought: 'test', + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: false, + }); + expect(errorSpy).not.toHaveBeenCalled(); + }); + }); + + describe('error logging', () => { + it('should log Error instances with stack info', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.error('fail', new Error('boom')); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.meta.error.name).toBe('Error'); + expect(entry.meta.error.message).toBe('boom'); + expect(entry.meta.error.stack).toBeDefined(); + }); + + it('should log non-Error values as meta', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.error('fail', 'string error'); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.meta.error).toBe('string error'); + }); + + it('should log error without error argument', () => { + const logger = new StructuredLogger({ level: 'debug', enableColors: false, enableThoughtLogging: true }); + logger.error('something went wrong'); + expect(errorSpy).toHaveBeenCalledTimes(1); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.level).toBe('error'); + expect(entry.message).toBe('something went wrong'); + expect(entry.meta).toBeUndefined(); + }); + }); + + describe('warn logging', () => { + it('should output warn messages at warn level', () => { + const logger = new StructuredLogger({ level: 'warn', enableColors: false, enableThoughtLogging: true }); + logger.warn('caution'); + expect(errorSpy).toHaveBeenCalledTimes(1); + const entry = JSON.parse(errorSpy.mock.calls[0][0] as string); + expect(entry.level).toBe('warn'); + expect(entry.message).toBe('caution'); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/mcts.test.ts b/src/sequentialthinking/__tests__/unit/mcts.test.ts new file mode 100644 index 0000000000..8082c140a1 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/mcts.test.ts @@ -0,0 +1,294 @@ +import { describe, it, expect } from 'vitest'; +import { MCTSEngine } from '../../mcts.js'; +import { ThoughtTree } from '../../thought-tree.js'; +import { createTestThoughtData as makeThought } from '../helpers/factories.js'; + +describe('MCTSEngine', () => { + const engine = new MCTSEngine(); + + describe('computeUCB1', () => { + it('should return Infinity for unvisited nodes', () => { + const result = engine.computeUCB1(0, 0, 10, Math.SQRT2); + expect(result).toBe(Infinity); + }); + + it('should compute exploitation + exploration', () => { + // nodeVisits=4, nodeValue=2.0, parentVisits=10, C=sqrt(2) + const result = engine.computeUCB1(4, 2.0, 10, Math.SQRT2); + const exploitation = 2.0 / 4; // 0.5 + const exploration = Math.SQRT2 * Math.sqrt(Math.log(10) / 4); + expect(result).toBeCloseTo(exploitation + exploration, 10); + }); + + it('should increase with higher exploitation value', () => { + const low = engine.computeUCB1(4, 1.0, 10, Math.SQRT2); + const high = engine.computeUCB1(4, 3.0, 10, Math.SQRT2); + expect(high).toBeGreaterThan(low); + }); + + it('should increase with lower visit count (more exploration bonus)', () => { + const moreVisits = engine.computeUCB1(10, 5.0, 20, Math.SQRT2); + const fewerVisits = engine.computeUCB1(2, 1.0, 20, Math.SQRT2); + expect(fewerVisits).toBeGreaterThan(moreVisits); + }); + }); + + describe('backpropagate', () => { + it('should update visit count and value along path to root', () => { + const tree = new ThoughtTree('session-1', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + const child = tree.addThought(makeThought({ thoughtNumber: 2 })); + const grandchild = tree.addThought(makeThought({ thoughtNumber: 3 })); + + const updated = engine.backpropagate(tree, grandchild.nodeId, 0.8); + + expect(updated).toBe(3); + expect(grandchild.visitCount).toBe(1); + expect(grandchild.totalValue).toBeCloseTo(0.8); + expect(child.visitCount).toBe(1); + expect(child.totalValue).toBeCloseTo(0.8); + expect(root.visitCount).toBe(1); + expect(root.totalValue).toBeCloseTo(0.8); + }); + + it('should accumulate with multiple evaluations', () => { + const tree = new ThoughtTree('session-1', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + const child = tree.addThought(makeThought({ thoughtNumber: 2 })); + + engine.backpropagate(tree, child.nodeId, 0.6); + engine.backpropagate(tree, child.nodeId, 0.9); + + expect(child.visitCount).toBe(2); + expect(child.totalValue).toBeCloseTo(1.5); + expect(root.visitCount).toBe(2); + expect(root.totalValue).toBeCloseTo(1.5); + }); + + it('should handle root node evaluation', () => { + const tree = new ThoughtTree('session-1', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + + const updated = engine.backpropagate(tree, root.nodeId, 0.5); + expect(updated).toBe(1); + expect(root.visitCount).toBe(1); + expect(root.totalValue).toBeCloseTo(0.5); + }); + }); + + describe('suggestNext', () => { + it('should suggest unexplored nodes first', () => { + const tree = new ThoughtTree('session-1', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + tree.addThought(makeThought({ thoughtNumber: 2 })); + + // Evaluate root but not child + engine.backpropagate(tree, root.nodeId, 0.5); + + const result = engine.suggestNext(tree, 'balanced'); + expect(result.suggestion).not.toBeNull(); + // The unvisited node (child, thought 2) should have Infinity UCB1 + expect(result.suggestion!.ucb1Score).toBe(Infinity); + }); + + it('should return null suggestion when all nodes are terminal', () => { + const tree = new ThoughtTree('session-1', 500); + tree.addThought(makeThought({ thoughtNumber: 1, nextThoughtNeeded: false })); + + const result = engine.suggestNext(tree, 'balanced'); + expect(result.suggestion).toBeNull(); + expect(result.alternatives).toHaveLength(0); + }); + + it('should return alternatives', () => { + const tree = new ThoughtTree('session-1', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + + tree.setCursor(root.nodeId); + tree.addThought(makeThought({ thoughtNumber: 2 })); + + tree.setCursor(root.nodeId); + tree.addThought(makeThought({ thoughtNumber: 3 })); + + const result = engine.suggestNext(tree, 'balanced'); + expect(result.suggestion).not.toBeNull(); + expect(result.alternatives.length).toBeGreaterThan(0); + }); + + it('should respond to different strategies', () => { + const tree = new ThoughtTree('session-1', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + tree.addThought(makeThought({ thoughtNumber: 2 })); + tree.setCursor(root.nodeId); + tree.addThought(makeThought({ thoughtNumber: 3 })); + + // Evaluate to create some variation + engine.backpropagate(tree, root.nodeId, 0.5); + + // All strategies should work without error + const explore = engine.suggestNext(tree, 'explore'); + const exploit = engine.suggestNext(tree, 'exploit'); + const balanced = engine.suggestNext(tree, 'balanced'); + + expect(explore.suggestion).not.toBeNull(); + expect(exploit.suggestion).not.toBeNull(); + expect(balanced.suggestion).not.toBeNull(); + }); + }); + + describe('extractBestPath', () => { + it('should extract path following highest average value', () => { + const tree = new ThoughtTree('session-1', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + const goodChild = tree.addThought(makeThought({ thoughtNumber: 2 })); + + tree.setCursor(root.nodeId); + const badChild = tree.addThought(makeThought({ thoughtNumber: 3 })); + + // Make goodChild better + engine.backpropagate(tree, goodChild.nodeId, 0.9); + engine.backpropagate(tree, badChild.nodeId, 0.1); + + const path = engine.extractBestPath(tree); + expect(path).toHaveLength(2); + expect(path[0].nodeId).toBe(root.nodeId); + expect(path[1].nodeId).toBe(goodChild.nodeId); + }); + + it('should return empty for empty tree', () => { + const tree = new ThoughtTree('session-1', 500); + const path = engine.extractBestPath(tree); + expect(path).toHaveLength(0); + }); + + it('should return single node for root-only tree', () => { + const tree = new ThoughtTree('session-1', 500); + tree.addThought(makeThought({ thoughtNumber: 1 })); + + const path = engine.extractBestPath(tree); + expect(path).toHaveLength(1); + }); + }); + + describe('getTreeStats', () => { + it('should compute stats for empty tree', () => { + const tree = new ThoughtTree('session-1', 500); + const stats = engine.getTreeStats(tree); + + expect(stats.totalNodes).toBe(0); + expect(stats.maxDepth).toBe(0); + expect(stats.unexploredCount).toBe(0); + expect(stats.averageValue).toBe(0); + expect(stats.terminalCount).toBe(0); + }); + + it('should compute stats for populated tree', () => { + const tree = new ThoughtTree('session-1', 500); + tree.addThought(makeThought({ thoughtNumber: 1 })); + tree.addThought(makeThought({ thoughtNumber: 2 })); + tree.addThought(makeThought({ thoughtNumber: 3, nextThoughtNeeded: false })); + + const stats = engine.getTreeStats(tree); + expect(stats.totalNodes).toBe(3); + expect(stats.maxDepth).toBe(2); + expect(stats.unexploredCount).toBe(3); // None evaluated yet + expect(stats.terminalCount).toBe(1); + }); + + it('should track unexplored vs explored correctly', () => { + const tree = new ThoughtTree('session-1', 500); + tree.addThought(makeThought({ thoughtNumber: 1 })); + const child = tree.addThought(makeThought({ thoughtNumber: 2 })); + + engine.backpropagate(tree, child.nodeId, 0.7); + + const stats = engine.getTreeStats(tree); + expect(stats.unexploredCount).toBe(0); // Both visited via backprop + expect(stats.averageValue).toBeCloseTo(0.7); + }); + }); + + describe('toNodeInfo', () => { + it('should convert ThoughtNode to TreeNodeInfo', () => { + const tree = new ThoughtTree('session-1', 500); + const node = tree.addThought(makeThought({ thoughtNumber: 1, thought: 'Hello world' })); + + const info = engine.toNodeInfo(node); + expect(info.nodeId).toBe(node.nodeId); + expect(info.thoughtNumber).toBe(1); + expect(info.thought).toBe('Hello world'); + expect(info.depth).toBe(0); + expect(info.visitCount).toBe(0); + expect(info.averageValue).toBe(0); + expect(info.childCount).toBe(0); + expect(info.isTerminal).toBe(false); + }); + }); + + describe('Edge Cases', () => { + it('should handle empty tree selection', () => { + const tree = new ThoughtTree('session-empty', 500); + const result = engine.suggestNext(tree, 'balanced'); + expect(result.suggestion).toBeNull(); + }); + + it('should handle deep tree (10+ levels)', () => { + const tree = new ThoughtTree('session-deep', 500); + let cursor = tree.addThought(makeThought({ thoughtNumber: 1 })); + + for (let i = 2; i <= 15; i++) { + tree.setCursor(cursor.nodeId); + cursor = tree.addThought(makeThought({ thoughtNumber: i })); + } + + const stats = engine.getTreeStats(tree); + expect(stats.totalNodes).toBe(15); + expect(stats.maxDepth).toBe(14); + + const path = engine.extractBestPath(tree); + expect(path).toHaveLength(15); + }); + + it('should handle zero value evaluations', () => { + const tree = new ThoughtTree('session-zero', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + const child = tree.addThought(makeThought({ thoughtNumber: 2 })); + + engine.backpropagate(tree, child.nodeId, 0); + + const stats = engine.getTreeStats(tree); + expect(stats.averageValue).toBe(0); + }); + + it('should handle many sibling nodes', () => { + const tree = new ThoughtTree('session-siblings', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + + // Add multiple children to root by creating branches + for (let i = 2; i <= 5; i++) { + tree.setCursor(root.nodeId); + tree.addThought(makeThought({ thoughtNumber: i, branchFromThought: 1, branchId: `branch-${i}` })); + } + + const stats = engine.getTreeStats(tree); + expect(stats.totalNodes).toBe(5); + + // Should have multiple branches + const result = engine.suggestNext(tree, 'balanced'); + expect(result.suggestion).not.toBeNull(); + }); + + it('should handle rapid evaluation cycles', () => { + const tree = new ThoughtTree('session-rapid', 500); + const root = tree.addThought(makeThought({ thoughtNumber: 1 })); + + // Evaluate same node multiple times rapidly + for (let i = 0; i < 100; i++) { + engine.backpropagate(tree, root.nodeId, Math.random()); + } + + expect(root.visitCount).toBe(100); + expect(root.totalValue).toBeGreaterThan(0); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/metacognition.test.ts b/src/sequentialthinking/__tests__/unit/metacognition.test.ts new file mode 100644 index 0000000000..937b5802fb --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/metacognition.test.ts @@ -0,0 +1,514 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { metacognition } from '../../metacognition.js'; + +describe('Metacognition', () => { + describe('generateReflectionPrompt', () => { + it('should return null for exploring phase', () => { + const result = metacognition.generateReflectionPrompt('exploring', 'stable', false, 0.5); + expect(result).toBeNull(); + }); + + it('should return prompt when circularity detected in converging phase', () => { + const result = metacognition.generateReflectionPrompt('converging', 'stable', true, 0.5); + expect(result).not.toBeNull(); + expect(result).toContain('loop'); + }); + + it('should return prompt when confidence declining in converging phase', () => { + const result = metacognition.generateReflectionPrompt('converging', 'declining', false, 0.5); + expect(result).not.toBeNull(); + expect(result).toContain('declining'); + }); + + it('should return prompt when high confidence in converging phase', () => { + const result = metacognition.generateReflectionPrompt('converging', 'improving', false, 0.85); + expect(result).not.toBeNull(); + expect(result).toContain('missing'); + }); + + it('should return multiple prompts for concluded phase', () => { + const result = metacognition.generateReflectionPrompt('concluded', 'stable', false, 0.7); + expect(result).not.toBeNull(); + expect(result === 'What is the single strongest counterargument to your conclusion?' || result === 'If you were wrong, what would prove it?').toBe(true); + }); + + it('should not prompt for evaluating phase even with issues', () => { + const result = metacognition.generateReflectionPrompt('evaluating', 'declining', true, 0.3); + expect(result).toBeNull(); + }); + }); + + describe('recordEvaluation and getAdaptiveStrategy', () => { + const TEST_PROBLEM_TYPE = 'test-problem-adaptation'; + + beforeEach(() => { + metacognition.recordEvaluation(TEST_PROBLEM_TYPE, 'branch', 'skeptic', 0.9); + metacognition.recordEvaluation(TEST_PROBLEM_TYPE, 'branch', 'skeptic', 0.7); + metacognition.recordEvaluation(TEST_PROBLEM_TYPE, 'branch', 'skeptic', 0.8); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('should return null when insufficient history', () => { + const result = metacognition.getAdaptiveStrategy('completely-unknown-problem-type-xyz'); + expect(result.recommendedStrategy).toBeNull(); + expect(result.recommendedPerspective).toBeNull(); + expect(result.reasoning).toContain('Insufficient'); + }); + + it('should recommend strategy after 3 evaluations', () => { + const result = metacognition.getAdaptiveStrategy(TEST_PROBLEM_TYPE); + expect(result.recommendedStrategy).toBe('branch'); + expect(result.recommendedPerspective).toBe('skeptic'); + expect(result.reasoning).toContain('0.80'); + }); + + it('should track multiple problem types separately', () => { + metacognition.recordEvaluation('other-problem', 'continue', 'optimist', 0.5); + metacognition.recordEvaluation('other-problem', 'continue', 'optimist', 0.6); + metacognition.recordEvaluation('other-problem', 'continue', 'optimist', 0.7); + const result1 = metacognition.getAdaptiveStrategy(TEST_PROBLEM_TYPE); + const result2 = metacognition.getAdaptiveStrategy('other-problem'); + expect(result1.recommendedStrategy).toBe('branch'); + expect(result2.recommendedStrategy).toBe('continue'); + }); + }); + + describe('analyzeReasoningGaps', () => { + it('should detect premature conclusion (only 1 prior thought)', () => { + const thoughts = [ + { thought: 'First thought', thoughtNumber: 1, totalThoughts: 3, nextThoughtNeeded: true }, + { thought: 'Therefore, this is the answer', thoughtNumber: 2, totalThoughts: 3, nextThoughtNeeded: true }, + ]; + const result = metacognition.analyzeReasoningGaps(thoughts); + expect(result.hasGaps).toBe(true); + expect(result.gaps[0].issue).toContain('Premature'); + }); + + it('should detect conclusion lacking evidence markers', () => { + const thoughts = [ + { thought: 'The sky is blue', thoughtNumber: 1, totalThoughts: 4, nextThoughtNeeded: true }, + { thought: 'It is raining', thoughtNumber: 2, totalThoughts: 4, nextThoughtNeeded: true }, + { thought: 'Therefore, the sky is green', thoughtNumber: 3, totalThoughts: 4, nextThoughtNeeded: true }, + ]; + const result = metacognition.analyzeReasoningGaps(thoughts); + expect(result.hasGaps).toBe(true); + expect(result.gaps[0].issue).toContain('evidence'); + }); + + it('should return no gaps for well-reasoned thoughts with evidence markers', () => { + const thoughts = [ + { thought: 'The sky appears blue because of Rayleigh scattering', thoughtNumber: 1, totalThoughts: 3, nextThoughtNeeded: true }, + { thought: 'However, clouds can make it appear gray', thoughtNumber: 2, totalThoughts: 3, nextThoughtNeeded: true }, + { thought: 'Therefore, sky color depends on atmospheric conditions', thoughtNumber: 3, totalThoughts: 3, nextThoughtNeeded: true }, + ]; + const result = metacognition.analyzeReasoningGaps(thoughts); + expect(result.hasGaps).toBe(false); + }); + + it('should detect multiple gap types in same chain', () => { + const thoughts = [ + { thought: 'Test failed', thoughtNumber: 1, totalThoughts: 2, nextThoughtNeeded: true }, + { thought: 'Therefore, the code is correct', thoughtNumber: 2, totalThoughts: 2, nextThoughtNeeded: false }, + ]; + const result = metacognition.analyzeReasoningGaps(thoughts); + expect(result.hasGaps).toBe(true); + expect(result.gaps.length).toBeGreaterThanOrEqual(1); + }); + + it('should handle empty thoughts', () => { + const result = metacognition.analyzeReasoningGaps([]); + expect(result.hasGaps).toBe(false); + expect(result.gaps).toHaveLength(0); + }); + }); + + describe('jaccardSimilarity', () => { + it('should return 0 for disjoint sets', () => { + const setA = new Set(['apple', 'banana']); + const setB = new Set(['cat', 'dog']); + const result = metacognition.jaccardSimilarity(setA, setB); + expect(result).toBe(0); + }); + + it('should return 1 for identical sets', () => { + const setA = new Set(['apple', 'banana']); + const setB = new Set(['banana', 'apple']); + const result = metacognition.jaccardSimilarity(setA, setB); + expect(result).toBe(1); + }); + + it('should return 0.5 for partial overlap', () => { + const setA = new Set(['apple', 'banana', 'cherry']); + const setB = new Set(['banana', 'cherry', 'date']); + const result = metacognition.jaccardSimilarity(setA, setB); + expect(result).toBe(0.5); + }); + }); + + describe('tokenize', () => { + it('should remove stop words', () => { + const result = metacognition.tokenize('The quick brown fox'); + expect(result.has('quick')).toBe(true); + expect(result.has('brown')).toBe(true); + expect(result.has('fox')).toBe(true); + expect(result.has('the')).toBe(false); + }); + + it('should lowercase and remove punctuation', () => { + const result = metacognition.tokenize('Hello, World! TEST.'); + expect(result.has('hello')).toBe(true); + expect(result.has('world')).toBe(true); + expect(result.has('test')).toBe(true); + }); + + it('should filter short words', () => { + const result = metacognition.tokenize('I am ok'); + expect(result.size).toBe(0); + }); + }); + + describe('analyzeComplexity', () => { + it('should return simple for insufficient thoughts', () => { + const thoughts = [{ thought: 'Just one thought', thoughtNumber: 1, totalThoughts: 1, nextThoughtNeeded: true }]; + const result = metacognition.analyzeComplexity(thoughts); + expect(result.complexity).toBe('simple'); + expect(result.recommendedMode).toBe('fast'); + }); + + it('should detect complex technical problems', () => { + const thoughts = [ + { thought: 'I need to design and implement a complex algorithm to optimize the system architecture for performance', thoughtNumber: 1, totalThoughts: 3, nextThoughtNeeded: true }, + { thought: 'The current implementation has O(n^2) complexity, however there are multiple tradeoffs to consider', thoughtNumber: 2, totalThoughts: 3, nextThoughtNeeded: true }, + { thought: 'How can I reduce it to O(n log n) versus using alternative data structures?', thoughtNumber: 3, totalThoughts: 3, nextThoughtNeeded: false }, + ]; + const result = metacognition.analyzeComplexity(thoughts); + expect(['moderate', 'complex']).toContain(result.complexity); + }); + + it('should detect moderate complexity with tradeoffs', () => { + const thoughts = [ + { thought: 'We need to decide between option A or B', thoughtNumber: 1, totalThoughts: 2, nextThoughtNeeded: true }, + { thought: 'Option A is faster but more expensive, however option B has tradeoffs', thoughtNumber: 2, totalThoughts: 2, nextThoughtNeeded: false }, + ]; + const result = metacognition.analyzeComplexity(thoughts); + expect(['moderate', 'complex']).toContain(result.complexity); + }); + + it('should suggest fast for simple questions', () => { + const thoughts = [ + { thought: 'What is 2 + 2?', thoughtNumber: 1, totalThoughts: 2, nextThoughtNeeded: true }, + { thought: 'It is 4', thoughtNumber: 2, totalThoughts: 2, nextThoughtNeeded: false }, + ]; + const result = metacognition.analyzeComplexity(thoughts); + expect(result.complexity).toBe('simple'); + expect(result.recommendedMode).toBe('fast'); + }); + }); + + describe('detectDomain', () => { + const makeThought = (text: string) => ({ + thought: text, + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: true, + }); + + it('should return general domain for empty thoughts', () => { + const result = metacognition.detectDomain([]); + expect(result.domain).toBe('general'); + expect(result.confidence).toBe(0); + }); + + it('should detect reasoning domain', () => { + const thoughts = [ + makeThought('Therefore, the conclusion follows from the premise'), + makeThought('Consequently, we can deduce that this is logically true'), + ]; + const result = metacognition.detectDomain(thoughts); + expect(result.domain).toBe('reasoning'); + expect(result.confidence).toBeGreaterThan(0); + }); + + it('should detect decision domain', () => { + const thoughts = [ + makeThought('I need to choose between option A or B'), + makeThought('The risk tradeoff suggests we should select option C'), + ]; + const result = metacognition.detectDomain(thoughts); + expect(result.domain).toBe('decision'); + }); + + it('should detect learning domain', () => { + const thoughts = [ + makeThought('I want to understand and master this skill'), + makeThought('Through practice and experience I will acquire knowledge'), + ]; + const result = metacognition.detectDomain(thoughts); + expect(result.domain).toBe('learning'); + }); + + it('should detect problem_solving domain', () => { + const thoughts = [ + makeThought('How to solve this problem?'), + makeThought('I need to find a solution and fix this issue'), + ]; + const result = metacognition.detectDomain(thoughts); + expect(result.domain).toBe('problem_solving'); + }); + + it('should detect creativity domain', () => { + const thoughts = [ + makeThought('Let me imagine a novel approach'), + makeThought('I will generate an innovative idea through brainstorming'), + ]; + const result = metacognition.detectDomain(thoughts); + expect(result.domain).toBe('creativity'); + }); + + it('should detect domain when keywords present (even for vague text)', () => { + const thoughts = [ + makeThought('This is just some random text without specific indicators'), + ]; + const result = metacognition.detectDomain(thoughts); + expect(result.confidence).toBeLessThan(0.5); + }); + + it('should increase confidence with more keyword matches', () => { + const single = metacognition.detectDomain([makeThought('Because I reason')]); + const multiple = metacognition.detectDomain([ + makeThought('Because I reason and therefore deduce'), + makeThought('Consequently, thus hence logically'), + ]); + expect(multiple.confidence).toBeGreaterThan(single.confidence); + }); + }); + + describe('detectCognitiveProcess', () => { + const makeThought = (text: string) => ({ + thought: text, + thoughtNumber: 1, + totalThoughts: 1, + nextThoughtNeeded: true, + }); + + it('should return understanding for empty thoughts', () => { + const result = metacognition.detectCognitiveProcess([]); + expect(result.process).toBe('understanding'); + expect(result.confidence).toBe(0); + }); + + it('should detect creating process', () => { + const thoughts = [ + makeThought('I will create a new design and build something innovative'), + ]; + const result = metacognition.detectCognitiveProcess(thoughts); + expect(result.process).toBe('creating'); + }); + + it('should detect deciding process', () => { + const thoughts = [ + makeThought('I need to decide which option to select'), + ]; + const result = metacognition.detectCognitiveProcess(thoughts); + expect(result.process).toBe('deciding'); + }); + + it('should detect explaining process', () => { + const thoughts = [ + makeThought('This happens because of the effect and mechanism'), + ]; + const result = metacognition.detectCognitiveProcess(thoughts); + expect(result.process).toBe('explaining'); + }); + + it('should detect planning process', () => { + const thoughts = [ + makeThought('Next I will do this, then the next step will be'), + ]; + const result = metacognition.detectCognitiveProcess(thoughts); + expect(result.process).toBe('planning'); + }); + + it('should detect predicting process', () => { + const thoughts = [ + makeThought('I expect this will likely happen in the future'), + ]; + const result = metacognition.detectCognitiveProcess(thoughts); + expect(result.process).toBe('predicting'); + }); + + it('should default to understanding for unrecognized', () => { + const thoughts = [makeThought('Some random text xyz')]; + const result = metacognition.detectCognitiveProcess(thoughts); + expect(result.process).toBe('understanding'); + }); + }); + + describe('detectMetaState', () => { + const makeThought = (text: string, num: number) => ({ + thought: text, + thoughtNumber: num, + totalThoughts: num, + nextThoughtNeeded: true, + }); + + it('should return clarity for insufficient thoughts', () => { + const result = metacognition.detectMetaState([makeThought('First', 1)]); + expect(result.state).toBe('clarity'); + expect(result.severity).toBe(0); + }); + + it('should detect stuck or blockage state', () => { + const thoughts = [ + makeThought('I am trying to solve this problem', 1), + makeThought('I am stuck and cannot proceed with this problem', 2), + ]; + const result = metacognition.detectMetaState(thoughts); + expect(['stuck', 'blockage']).toContain(result.state); + expect(result.severity).toBeGreaterThan(0); + }); + + it('should detect blockage', () => { + const thoughts = [ + makeThought('Let me work on this', 1), + makeThought('I am blocked by a barrier and cannot continue', 2), + ]; + const result = metacognition.detectMetaState(thoughts); + expect(result.state).toBe('blockage'); + }); + + it('should detect progress', () => { + const thoughts = [ + makeThought('I started working on this', 1), + makeThought('I am making progress and moving forward', 2), + ]; + const result = metacognition.detectMetaState(thoughts); + expect(result.state).toBe('progress'); + }); + + it('should detect momentum losing', () => { + const thoughts = [ + makeThought('I was making good progress', 1), + makeThought('I am losing momentum and it is getting harder', 2), + ]; + const result = metacognition.detectMetaState(thoughts); + expect(result.state).toBe('momentum_losing'); + }); + + it('should detect scope_narrow (focus keywords present)', () => { + const thoughts = [ + makeThought('Let me focus on the details', 1), + makeThought('But I need to see the big picture overall', 2), + ]; + const result = metacognition.detectMetaState(thoughts); + expect(result.state).toBe('scope_narrow'); + }); + + it('should detect uncertainty through similarity patterns', () => { + const thoughts = [ + makeThought('I think this might be the answer', 1), + makeThought('I think this might be the answer but not sure', 2), + ]; + const result = metacognition.detectMetaState(thoughts); + expect(result.state).toBeDefined(); + }); + }); + + describe('detectInsightType', () => { + const makeThought = (text: string, num: number) => ({ + thought: text, + thoughtNumber: num, + totalThoughts: num, + nextThoughtNeeded: true, + }); + + it('should detect breakthrough insight', () => { + const thoughts = [ + makeThought('I have been analyzing this problem', 1), + makeThought('Suddenly I see the solution clearly now!', 2), + ]; + const result = metacognition.detectInsightType(thoughts); + expect(result.type).toBeDefined(); + }); + + it('should detect connection insight', () => { + const thoughts = [ + makeThought('Problem A is like problem B', 1), + makeThought('They connect through this mechanism', 2), + ]; + const result = metacognition.detectInsightType(thoughts); + expect(result.confidence).toBeGreaterThanOrEqual(0); + }); + + it('should handle empty thoughts', () => { + const result = metacognition.detectInsightType([]); + expect(result.type).toBe('question_reframing'); + }); + }); + + describe('getProblemTypeRecommendations', () => { + it('should recommend related problem types', () => { + const result = metacognition.getProblemTypeRecommendations('analysis'); + expect(result).toHaveProperty('follows'); + expect(result).toHaveProperty('precedes'); + expect(result).toHaveProperty('related'); + expect(Array.isArray(result.follows)).toBe(true); + }); + + it('should handle unknown problem type', () => { + const result = metacognition.getProblemTypeRecommendations('unknown-type-xyz'); + expect(result).toHaveProperty('follows'); + expect(result).toHaveProperty('precedes'); + expect(result).toHaveProperty('related'); + }); + }); + + describe('recordCrossBranchPattern', () => { + const TEST_KEY = 'test-cross-branch-key'; + + it('should record pattern without error', () => { + expect(() => { + metacognition.recordCrossBranchPattern(TEST_KEY, 'problem-type-1', 'solution1', 0.8); + metacognition.recordCrossBranchPattern(TEST_KEY, 'problem-type-2', 'solution2', 0.9); + }).not.toThrow(); + }); + + it('should find recorded patterns', () => { + const patterns = metacognition.findCrossBranchPattern(TEST_KEY); + expect(patterns).toBeDefined(); + }); + }); + + describe('findSimilarPatterns', () => { + it('should find similar patterns', () => { + const result = metacognition.findSimilarPatterns('testing code', []); + expect(result).toBeDefined(); + expect(Array.isArray(result)).toBe(true); + }); + }); + + describe('computeConfidenceTrend', () => { + it('should detect improving trend', () => { + const result = metacognition.computeConfidenceTrend([0.3, 0.5, 0.7, 0.9]); + expect(result).toBe('improving'); + }); + + it('should detect declining trend', () => { + const result = metacognition.computeConfidenceTrend([0.9, 0.7, 0.5, 0.3]); + expect(result).toBe('declining'); + }); + + it('should detect stable trend', () => { + const result = metacognition.computeConfidenceTrend([0.5, 0.5, 0.5, 0.5]); + expect(result).toBe('stable'); + }); + + it('should return insufficient for too few values', () => { + const result = metacognition.computeConfidenceTrend([0.5]); + expect(result).toBe('insufficient'); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/metrics.test.ts b/src/sequentialthinking/__tests__/unit/metrics.test.ts new file mode 100644 index 0000000000..d75a299d46 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/metrics.test.ts @@ -0,0 +1,168 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { BasicMetricsCollector } from '../../metrics.js'; +import { SessionTracker } from '../../session-tracker.js'; +import { BoundedThoughtManager } from '../../state-manager.js'; +import { createTestThought as makeThought } from '../helpers/factories.js'; + +describe('BasicMetricsCollector', () => { + let metrics: BasicMetricsCollector; + let sessionTracker: SessionTracker; + let storage: BoundedThoughtManager; + + beforeEach(() => { + sessionTracker = new SessionTracker(0); + storage = new BoundedThoughtManager({ + maxHistorySize: 100, + maxBranchAge: 3600000, + maxThoughtsPerBranch: 50, + cleanupInterval: 0, + }, sessionTracker); + metrics = new BasicMetricsCollector(sessionTracker, storage); + }); + + afterEach(() => { + storage.destroy(); + sessionTracker.destroy(); + }); + + describe('recordRequest', () => { + it('should increment total and successful on success', () => { + metrics.recordRequest(10, true); + const m = metrics.getMetrics(); + expect(m.requests.totalRequests).toBe(1); + expect(m.requests.successfulRequests).toBe(1); + expect(m.requests.failedRequests).toBe(0); + }); + + it('should increment total and failed on failure', () => { + metrics.recordRequest(10, false); + const m = metrics.getMetrics(); + expect(m.requests.totalRequests).toBe(1); + expect(m.requests.failedRequests).toBe(1); + expect(m.requests.successfulRequests).toBe(0); + }); + + it('should compute average response time', () => { + metrics.recordRequest(10, true); + metrics.recordRequest(20, true); + const m = metrics.getMetrics(); + expect(m.requests.averageResponseTime).toBe(15); + }); + + it('should update lastRequestTime', () => { + metrics.recordRequest(5, true); + const m = metrics.getMetrics(); + expect(m.requests.lastRequestTime).toBeInstanceOf(Date); + }); + }); + + describe('recordThoughtProcessed', () => { + it('should track total thoughts', () => { + metrics.recordThoughtProcessed(makeThought()); + metrics.recordThoughtProcessed(makeThought({ thoughtNumber: 2 })); + expect(metrics.getMetrics().thoughts.totalThoughts).toBe(2); + }); + + it('should track unique branches', () => { + // Branch count is now queried from storage, so add to storage first + const t1 = makeThought({ branchId: 'b1' }); + storage.addThought(t1); + metrics.recordThoughtProcessed(t1); + + const t2 = makeThought({ branchId: 'b1' }); + storage.addThought(t2); + metrics.recordThoughtProcessed(t2); + + const t3 = makeThought({ branchId: 'b2' }); + storage.addThought(t3); + metrics.recordThoughtProcessed(t3); + + expect(metrics.getMetrics().thoughts.branchCount).toBe(2); + }); + + it('should track sessions', () => { + // Record thoughts in tracker first (mimics what happens in real flow) + sessionTracker.recordThought('s1'); + metrics.recordThoughtProcessed(makeThought({ sessionId: 's1' })); + sessionTracker.recordThought('s2'); + metrics.recordThoughtProcessed(makeThought({ sessionId: 's2' })); + expect(metrics.getMetrics().thoughts.activeSessions).toBe(2); + }); + + it('should track revisions', () => { + metrics.recordThoughtProcessed(makeThought({ isRevision: true })); + expect(metrics.getMetrics().thoughts.revisionCount).toBe(1); + }); + + it('should compute average thought length', () => { + metrics.recordThoughtProcessed(makeThought({ thought: 'abcde' })); // 5 + metrics.recordThoughtProcessed(makeThought({ thought: 'abcdefghij' })); // 10 + // average: (5+10)/2 = 7.5, rounded = 8 + expect(metrics.getMetrics().thoughts.averageThoughtLength).toBe(8); + }); + }); + + describe('response time ring buffer', () => { + it('should keep only last 100 response times', () => { + for (let i = 0; i < 110; i++) { + metrics.recordRequest(i, true); + } + // Average should be based on last 100 values (10-109) + const avg = metrics.getMetrics().requests.averageResponseTime; + // Sum of 10..109 = 5950, avg = 59.5 + expect(avg).toBeCloseTo(59.5, 0); + }); + + it('should compute correct average after adding 150 response times', () => { + for (let i = 1; i <= 150; i++) { + metrics.recordRequest(i, true); + } + // Last 100 values are 51..150 + // Sum = (51+150)*100/2 = 10050, avg = 100.5 + const avg = metrics.getMetrics().requests.averageResponseTime; + expect(avg).toBeCloseTo(100.5, 0); + }); + }); + + describe('getMetrics shape', () => { + it('should return correct top-level structure', () => { + const m = metrics.getMetrics(); + expect(m).toHaveProperty('requests'); + expect(m).toHaveProperty('thoughts'); + expect(m).toHaveProperty('system'); + }); + + it('should include system metrics', () => { + const m = metrics.getMetrics(); + expect(m.system.memoryUsage).toHaveProperty('heapUsed'); + expect(m.system.cpuUsage).toHaveProperty('user'); + expect(typeof m.system.uptime).toBe('number'); + expect(m.system.timestamp).toBeInstanceOf(Date); + }); + }); + + describe('destroy', () => { + it('should reset all counters and collections', () => { + metrics.recordRequest(10, true); + metrics.recordRequest(20, false); + metrics.recordThoughtProcessed(makeThought({ sessionId: 's1', branchId: 'b1' })); + metrics.recordThoughtProcessed(makeThought({ sessionId: 's2', isRevision: true })); + + metrics.destroy(); + + const m = metrics.getMetrics(); + expect(m.requests.totalRequests).toBe(0); + expect(m.requests.successfulRequests).toBe(0); + expect(m.requests.failedRequests).toBe(0); + expect(m.requests.averageResponseTime).toBe(0); + expect(m.requests.lastRequestTime).toBeNull(); + expect(m.requests.requestsPerMinute).toBe(0); + expect(m.thoughts.totalThoughts).toBe(0); + expect(m.thoughts.averageThoughtLength).toBe(0); + expect(m.thoughts.thoughtsPerMinute).toBe(0); + expect(m.thoughts.revisionCount).toBe(0); + expect(m.thoughts.branchCount).toBe(0); + expect(m.thoughts.activeSessions).toBe(0); + }); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/race-condition.test.ts b/src/sequentialthinking/__tests__/unit/race-condition.test.ts new file mode 100644 index 0000000000..8ef7887277 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/race-condition.test.ts @@ -0,0 +1,125 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { SecureThoughtSecurity } from '../../security-service.js'; +import { SessionTracker } from '../../session-tracker.js'; +import { SecurityError } from '../../errors.js'; + +describe('Race Condition: Rate Limit Recording', () => { + let sessionTracker: SessionTracker; + let security: SecureThoughtSecurity; + + beforeEach(() => { + sessionTracker = new SessionTracker(0); + security = new SecureThoughtSecurity( + { maxThoughtsPerMinute: 3 }, + sessionTracker, + ); + }); + + afterEach(() => { + sessionTracker.destroy(); + }); + + it('should record thought immediately after successful validation', () => { + // First validation should succeed + security.validateThought('test 1', 'race-session'); + + // Check that it was recorded by verifying the count + const stats = sessionTracker.getActiveSessionCount(); + expect(stats).toBeGreaterThan(0); + }); + + it('should prevent race condition with rapid sequential validations', () => { + // Rapid fire 3 validations - all should succeed + security.validateThought('test 1', 'rapid-session'); + security.validateThought('test 2', 'rapid-session'); + security.validateThought('test 3', 'rapid-session'); + + // 4th should fail because rate limit was recorded after each validation + expect(() => security.validateThought('test 4', 'rapid-session')) + .toThrow(SecurityError); + expect(() => security.validateThought('test 4', 'rapid-session')) + .toThrow('Rate limit exceeded'); + }); + + it('should enforce rate limit correctly even with interleaved sessions', () => { + // Session A: 3 thoughts (at limit) + security.validateThought('a1', 'session-a'); + security.validateThought('a2', 'session-a'); + security.validateThought('a3', 'session-a'); + + // Session B: 2 thoughts (under limit) + security.validateThought('b1', 'session-b'); + security.validateThought('b2', 'session-b'); + + // Session A: should fail (at limit) + expect(() => security.validateThought('a4', 'session-a')) + .toThrow('Rate limit exceeded'); + + // Session B: should succeed (1 more allowed) + expect(() => security.validateThought('b3', 'session-b')) + .not.toThrow(); + + // Session B: should now fail (at limit) + expect(() => security.validateThought('b4', 'session-b')) + .toThrow('Rate limit exceeded'); + }); + + it('should handle validation failure without recording', () => { + // Create security with blocked pattern + const securityWithBlock = new SecureThoughtSecurity( + { + maxThoughtsPerMinute: 5, + blockedPatterns: [/forbidden/i], + }, + sessionTracker, + ); + + // This should fail validation due to blocked pattern + expect(() => securityWithBlock.validateThought('this is forbidden', 'test-session')) + .toThrow(SecurityError); + + // Session should not have any rate limit entries since validation failed + // Try 5 more validations with valid content + for (let i = 0; i < 5; i++) { + securityWithBlock.validateThought(`valid thought ${i}`, 'test-session'); + } + + // 6th should fail due to rate limit (not including the failed validation) + expect(() => securityWithBlock.validateThought('valid thought 6', 'test-session')) + .toThrow('Rate limit exceeded'); + }); + + it('should maintain accurate count even with empty session IDs', () => { + // Empty session ID should not be rate limited or recorded + security.validateThought('test 1', ''); + security.validateThought('test 2', ''); + security.validateThought('test 3', ''); + security.validateThought('test 4', ''); // Should not throw + + // Verify that empty sessions don't pollute the tracker + expect(sessionTracker.getActiveSessionCount()).toBe(0); + }); + + it('should correctly expire old rate limit entries', () => { + // This test verifies that old entries don't prevent new thoughts + const tracker = new SessionTracker(0); + const sec = new SecureThoughtSecurity( + { maxThoughtsPerMinute: 2 }, + tracker, + ); + + // Add 2 thoughts (at limit) + sec.validateThought('old 1', 'expire-session'); + sec.validateThought('old 2', 'expire-session'); + + // Should be at limit + expect(() => sec.validateThought('new 1', 'expire-session')) + .toThrow('Rate limit exceeded'); + + // Wait for rate window to expire (61 seconds) + // Simulate by manually pruning old timestamps + tracker.cleanup(); + + tracker.destroy(); + }); +}); diff --git a/src/sequentialthinking/__tests__/unit/security-service.test.ts b/src/sequentialthinking/__tests__/unit/security-service.test.ts new file mode 100644 index 0000000000..2bcfaa84e0 --- /dev/null +++ b/src/sequentialthinking/__tests__/unit/security-service.test.ts @@ -0,0 +1,222 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { SecureThoughtSecurity } from '../../security-service.js'; +import { SessionTracker } from '../../session-tracker.js'; +import { SecurityError } from '../../errors.js'; + +describe('SecureThoughtSecurity', () => { + let sessionTracker: SessionTracker; + + beforeEach(() => { + sessionTracker = new SessionTracker(0); + }); + + afterEach(() => { + sessionTracker.destroy(); + }); + + describe('sanitizeContent', () => { + let security: SecureThoughtSecurity; + beforeEach(() => { + security = new SecureThoughtSecurity(undefined, sessionTracker); + }); + + const sanitizeCases = [ + { input: 'hello world', expected: 'hello world' }, + { input: 'visit javascript:void(0)', expected: 'visit void(0)' }, + { input: 'call eval(x)', expected: 'call x)' }, + { input: 'new Function(code)', expected: 'new code)' }, + { input: '
', expected: '
' }, + ]; + + it.each(sanitizeCases)('should sanitize: $input', ({ input, expected }) => { + expect(security.sanitizeContent(input)).toBe(expected); + }); + }); + + describe('validateSession', () => { + let security: SecureThoughtSecurity; + beforeEach(() => { + security = new SecureThoughtSecurity(undefined, sessionTracker); + }); + + const sessionCases = [ + { id: 'a'.repeat(100), valid: true }, + { id: 'a'.repeat(101), valid: false }, + { id: '', valid: false }, + { id: 'session-123', valid: true }, + ]; + + it.each(sessionCases)('should $valid ? "accept" : "reject" session ID of length $id.length', ({ id, valid }) => { + expect(security.validateSession(id)).toBe(valid); + }); + }); + + describe('generateSessionId', () => { + let security: SecureThoughtSecurity; + beforeEach(() => { + security = new SecureThoughtSecurity(undefined, sessionTracker); + }); + + it('should return UUID format', () => { + const id = security.generateSessionId(); + expect(id).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/, + ); + }); + + it('should return unique IDs', () => { + const ids = new Set(Array.from({ length: 10 }, () => security.generateSessionId())); + expect(ids.size).toBe(10); + }); + }); + + describe('validateThought', () => { + it('should block eval( via regex matching', () => { + const security = new SecureThoughtSecurity( + { blockedPatterns: [/eval\s*\(/i] }, + sessionTracker, + ); + expect(() => security.validateThought('call eval(x)', 'sess')).toThrow(SecurityError); + expect(() => security.validateThought('call eval (x)', 'sess')).toThrow(SecurityError); + }); + + it('should block literal patterns like javascript:', () => { + const security = new SecureThoughtSecurity(undefined, sessionTracker); + expect(() => security.validateThought('visit javascript:void(0)', 'sess')).toThrow(SecurityError); + }); + + it('should accept pre-compiled RegExp patterns', () => { + const security = new SecureThoughtSecurity( + { blockedPatterns: [/eval\(/i, /forbidden/i] }, + sessionTracker, + ); + expect(() => security.validateThought('call eval(x)', 'sess')).toThrow(SecurityError); + expect(() => security.validateThought('this is forbidden', 'sess2')).toThrow(SecurityError); + }); + + it('should allow safe content', () => { + const security = new SecureThoughtSecurity(undefined, sessionTracker); + expect(() => security.validateThought('normal analysis text', 'sess')).not.toThrow(); + }); + }); + + describe('repeated regex validation (no lastIndex statefulness)', () => { + it('should block content consistently on repeated calls', () => { + const security = new SecureThoughtSecurity(undefined, sessionTracker); + // Call validateThought 3 times with the same blocked content — all must throw + expect(() => security.validateThought('visit javascript:void(0)', 'sess')).toThrow(SecurityError); + expect(() => security.validateThought('visit javascript:void(0)', 'sess')).toThrow(SecurityError); + expect(() => security.validateThought('visit javascript:void(0)', 'sess')).toThrow(SecurityError); + }); + + it('should block forbidden content consistently on repeated calls', () => { + const security = new SecureThoughtSecurity(undefined, sessionTracker); + expect(() => security.validateThought('this is forbidden content', 'sess2')).toThrow(SecurityError); + expect(() => security.validateThought('this is forbidden content', 'sess2')).toThrow(SecurityError); + expect(() => security.validateThought('this is forbidden content', 'sess2')).toThrow(SecurityError); + }); + }); + + describe('getSecurityStatus', () => { + it('should return status object', () => { + const security = new SecureThoughtSecurity(undefined, sessionTracker); + const status = security.getSecurityStatus(); + expect(status.status).toBe('healthy'); + expect(typeof status.blockedPatterns).toBe('number'); + }); + }); + + + describe('rate limiting', () => { + it('should allow requests within limit', () => { + const tracker = new SessionTracker(0); + const security = new SecureThoughtSecurity( + { maxThoughtsPerMinute: 5 }, + tracker, + ); + // validateThought now records automatically + for (let i = 0; i < 5; i++) { + expect(() => security.validateThought('test thought', 'rate-sess')).not.toThrow(); + } + tracker.destroy(); + }); + + it('should throw SecurityError when rate limit exceeded', () => { + const tracker = new SessionTracker(0); + const security = new SecureThoughtSecurity( + { maxThoughtsPerMinute: 3 }, + tracker, + ); + // Use up the limit - validateThought records automatically + security.validateThought('thought 1', 'rate-sess'); + security.validateThought('thought 2', 'rate-sess'); + security.validateThought('thought 3', 'rate-sess'); + // 4th should exceed + expect(() => security.validateThought('thought 4', 'rate-sess')).toThrow(SecurityError); + expect(() => security.validateThought('thought 4', 'rate-sess')).toThrow('Rate limit exceeded'); + tracker.destroy(); + }); + + it('should not rate-limit different sessions', () => { + const tracker = new SessionTracker(0); + const security = new SecureThoughtSecurity( + { maxThoughtsPerMinute: 2 }, + tracker, + ); + // validateThought records automatically + security.validateThought('thought 1', 'sess-a'); + security.validateThought('thought 2', 'sess-a'); + // sess-a is at limit, but sess-b should still work + expect(() => security.validateThought('thought 1', 'sess-b')).not.toThrow(); + tracker.destroy(); + }); + + it('should not rate-limit when sessionId is empty', () => { + const tracker = new SessionTracker(0); + const security = new SecureThoughtSecurity( + { maxThoughtsPerMinute: 1 }, + tracker, + ); + // Empty sessionId should skip rate limiting entirely + expect(() => security.validateThought('thought 1', '')).not.toThrow(); + expect(() => security.validateThought('thought 2', '')).not.toThrow(); + tracker.destroy(); + }); + }); + + describe('Unicode and Edge Cases', () => { + let security: SecureThoughtSecurity; + beforeEach(() => { + security = new SecureThoughtSecurity(undefined, sessionTracker); + }); + + it('should handle Unicode characters', () => { + const result = security.sanitizeContent('こんにちは世界 🌍 émoji'); + expect(result).toContain('こんにちは世界'); + }); + + it('should handle zero-width characters', () => { + const result = security.sanitizeContent('test\u200B\u200C\u200Dhidden'); + expect(result).toContain('test'); + }); + + it('should handle mixed Unicode and ASCII', () => { + const result = security.sanitizeContent('Hello 世界'); + expect(result).not.toContain('

Sequential Thinking MCP Server - v0.6.2

Sequential Thinking MCP Server

An MCP server for dynamic, reflective problem-solving through sequential thoughts with MCTS-based tree exploration and metacognitive self-awareness.

+

This server provides structured, step-by-step thinking with support for:

+
    +
  • Revisions - Reconsider previous thoughts
  • +
  • Branching - Explore alternative reasoning paths
  • +
  • Session tracking - Maintain context across requests
  • +
  • MCTS exploration - Monte Carlo Tree Search for optimal reasoning paths
  • +
  • Thinking modes - Fast, Expert, and Deep exploration strategies
  • +
  • Metacognition - Self-awareness for confidence, circularity detection, problem classification
  • +
+

Process a single thought in a sequential chain.

+

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequiredDescription
thoughtstringyesThe current thinking step
nextThoughtNeededbooleanyesWhether another thought step is needed
thoughtNumbernumberyesCurrent thought number (1-based)
totalThoughtsnumberyesEstimated total thoughts needed
isRevisionbooleannoWhether this revises previous thinking
revisesThoughtnumbernoWhich thought number is being reconsidered
branchFromThoughtnumbernoBranching point thought number
branchIdstringnoBranch identifier
needsMoreThoughtsbooleannoIf more thoughts are needed beyond estimate
sessionIdstringnoSession identifier for tracking
+

Response fields: thoughtNumber, totalThoughts, nextThoughtNeeded, branches, thoughtHistoryLength, sessionId, timestamp

+

Retrieve the thought history for a session.

+

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequiredDescription
sessionIdstringyesSession identifier
branchIdstringnoFilter by branch
+

Configure the thinking mode for a session (enables MCTS exploration).

+

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequiredDescription
sessionIdstringyesSession identifier
modestringyesThinking mode: fast, expert, or deep
+

Get AI-powered suggestions for the next thought using MCTS.

+

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequiredDescription
sessionIdstringyesSession identifier
strategystringnoSelection strategy: explore, exploit, or balanced
+

Evaluate a thought's quality (0-1 scale) for MCTS backpropagation.

+

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequiredDescription
sessionIdstringyesSession identifier
nodeIdstringyesNode ID to evaluate
valuenumberyesQuality score (0-1)
+

Move the thought tree cursor back to a previous node.

+

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequiredDescription
sessionIdstringyesSession identifier
nodeIdstringyesTarget node ID
+

Get a comprehensive summary of the thought tree.

+

Parameters:

+ + + + + + + + + + + + + + + + + + + + + + + +
ParameterTypeRequiredDescription
sessionIdstringyesSession identifier
maxDepthnumbernoMaximum depth to include
+

Returns server health status including memory, response time, error rate, storage, and security checks.

+

Returns request metrics (counts, response times), thought metrics (totals, branches), and system metrics.

+

The server supports three thinking modes for MCTS exploration:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModeExplorationTarget DepthBest For
fastLow (0.5)3-5Quick decisions
expertBalanced (1.41)5-10Complex analysis
deepHigh (2.0)10-20Thorough exploration
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Parameterfastexpertdeep
explorationConstant0.5√2 (~1.41)2.0
maxBranchingFactor135
targetDepthMin3510
targetDepthMax51020
autoEvaluatetruefalsefalse
enableBacktrackingfalsetruetrue
+

The server includes self-awareness features that analyze thought patterns:

+
    +
  • Circularity Detection - Detects repetitive thinking patterns using Jaccard similarity
  • +
  • Confidence Scoring - Assesses thought confidence based on linguistic markers
  • +
  • Problem Type Classification - Identifies problem type (analysis, design, debugging, planning, optimization, decision, creative)
  • +
  • Perspective Switching - Suggests alternative viewpoints (optimist, pessimist, expert, beginner, skeptic)
  • +
  • Reasoning Gap Analysis - Detects premature conclusions and missing evidence
  • +
  • Adaptive Strategy - Learns from evaluation history to recommend better strategies
  • +
+

When thinking mode is active, responses include:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FieldTypeDescription
modestringCurrent thinking mode
currentPhasestringPhase: exploring, evaluating, converging, concluded
recommendedActionstringSuggested next action
confidenceScorenumberThought confidence (0-1)
circularityWarningbooleanWhether circular thinking detected
problemTypestringClassified problem type
strategyGuidancestringProblem-type-specific strategy
confidenceTrendstringimproving, declining, stable, insufficient
reasoningGapWarningstringDetected reasoning gaps
reflectionPromptstringMetacognitive reflection question
+

All configuration is via environment variables with sensible defaults:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VariableDefaultDescription
SERVER_NAMEsequential-thinking-serverServer name reported in MCP metadata
SERVER_VERSION1.0.0Server version reported in MCP metadata
MAX_HISTORY_SIZE1000Maximum thoughts stored in circular buffer
MAX_THOUGHT_LENGTH5000Maximum character length per thought
MAX_THOUGHTS_PER_MIN60Rate limit per minute per session
MAX_THOUGHTS_PER_BRANCH100Maximum thoughts stored per branch
MAX_BRANCH_AGE3600000Branch expiration time (ms)
CLEANUP_INTERVAL300000Periodic cleanup interval (ms)
BLOCKED_PATTERNS(built-in list)Comma-separated regex patterns to block
DISABLE_THOUGHT_LOGGINGfalseDisable console thought formatting
LOG_LEVELinfoLogging level (debug, info, warn, error)
ENABLE_COLORStrueEnable colored console output
ENABLE_METRICStrueEnable metrics collection
ENABLE_HEALTH_CHECKStrueEnable health check endpoint
HEALTH_MAX_MEMORY90Memory usage % threshold for unhealthy status
HEALTH_MAX_STORAGE80Storage usage % threshold for unhealthy status
HEALTH_MAX_RESPONSE_TIME200Response time (ms) threshold for unhealthy status
HEALTH_ERROR_RATE_DEGRADED2Error rate % threshold for degraded status
HEALTH_ERROR_RATE_UNHEALTHY5Error rate % threshold for unhealthy status
+
npm install
npm run build
npm test +
+ +
    +
  • npm run build — Compile TypeScript
  • +
  • npm run watch — Compile in watch mode
  • +
  • npm run test — Run tests
  • +
  • npm run lint — Run ESLint
  • +
  • npm run lint:fix — Auto-fix lint issues
  • +
  • npm run type-check — TypeScript type checking
  • +
  • npm run check — Run type-check, lint, and format
  • +
  • npm run docs — Generate TypeDoc documentation
  • +
  • npm run docker:build — Build Docker image
  • +
+

Generated API documentation is available at docs/.

+

SEE LICENSE IN LICENSE

+
diff --git a/src/sequentialthinking/docs/modules.html b/src/sequentialthinking/docs/modules.html new file mode 100644 index 0000000000..d029e7287e --- /dev/null +++ b/src/sequentialthinking/docs/modules.html @@ -0,0 +1 @@ +Sequential Thinking MCP Server - v0.6.2

Sequential Thinking MCP Server - v0.6.2

diff --git a/src/sequentialthinking/errors.ts b/src/sequentialthinking/errors.ts new file mode 100644 index 0000000000..82cf6b9ee9 --- /dev/null +++ b/src/sequentialthinking/errors.ts @@ -0,0 +1,59 @@ +type ErrorCategory = + | 'VALIDATION' + | 'SECURITY' + | 'BUSINESS_LOGIC' + | 'SYSTEM'; + +export abstract class SequentialThinkingError extends Error { + abstract readonly code: string; + abstract readonly statusCode: number; + abstract readonly category: ErrorCategory; + readonly timestamp = new Date().toISOString(); + + constructor( + message: string, + public readonly details?: unknown, + ) { + super(message); + this.name = this.constructor.name; + + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } + } + + toJSON(): Record { + return { + error: this.code, + message: this.message, + category: this.category, + statusCode: this.statusCode, + details: this.details, + timestamp: this.timestamp, + }; + } +} + +export class ValidationError extends SequentialThinkingError { + readonly code = 'VALIDATION_ERROR'; + readonly statusCode = 400; + readonly category = 'VALIDATION' as const; +} + +export class SecurityError extends SequentialThinkingError { + readonly code = 'SECURITY_ERROR'; + readonly statusCode = 403; + readonly category = 'SECURITY' as const; +} + +export class BusinessLogicError extends SequentialThinkingError { + readonly code = 'BUSINESS_LOGIC_ERROR'; + readonly statusCode = 422; + readonly category = 'BUSINESS_LOGIC' as const; +} + +export class TreeError extends SequentialThinkingError { + readonly code = 'TREE_ERROR'; + readonly statusCode = 404; + readonly category = 'BUSINESS_LOGIC' as const; +} diff --git a/src/sequentialthinking/eslint.config.mjs b/src/sequentialthinking/eslint.config.mjs new file mode 100644 index 0000000000..e3f911ac4f --- /dev/null +++ b/src/sequentialthinking/eslint.config.mjs @@ -0,0 +1,134 @@ +import eslint from '@eslint/js'; +import tseslint from '@typescript-eslint/eslint-plugin'; +import tsparser from '@typescript-eslint/parser'; +import prettier from 'eslint-config-prettier'; + +export default [ + eslint.configs.recommended, + { + files: ['**/*.ts'], + languageOptions: { + parser: tsparser, + parserOptions: { + ecmaVersion: 2022, + sourceType: 'module', + project: './tsconfig.json', + }, + globals: { + console: 'readonly', + process: 'readonly', + crypto: 'readonly', + setTimeout: 'readonly', + clearTimeout: 'readonly', + setInterval: 'readonly', + clearInterval: 'readonly', + Buffer: 'readonly', + globalThis: 'readonly', + NodeJS: 'readonly', + }, + }, + plugins: { + '@typescript-eslint': tseslint, + }, + rules: { + // TypeScript - stricter + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unused-vars': ['error', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }], + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-misused-promises': ['error', { + checksVoidReturn: false, + }], + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/consistent-type-definitions': 'error', + '@typescript-eslint/no-inferrable-types': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'off', + '@typescript-eslint/prefer-optional-chain': 'off', + + // Security - strict + 'no-eval': 'error', + 'no-implied-eval': 'error', + 'no-new-func': 'error', + 'no-script-url': 'error', + 'no-alert': 'error', + 'no-proto': 'error', + 'no-new-wrappers': 'error', + + // Code Quality - strict + 'prefer-const': 'error', + 'no-var': 'error', + 'no-unused-vars': 'off', + 'no-undef': 'off', + 'no-console': ['warn', { allow: ['warn', 'error'] }], + 'no-dupe-else-if': 'error', + 'no-unreachable': 'error', + 'no-unreachable-loop': 'error', + 'no-useless-escape': 'error', + 'no-empty': 'error', + 'no-empty-function': 'error', + 'no-else-return': 'error', + 'no-unused-expressions': 'error', + 'default-case': 'error', + 'default-case-last': 'error', + 'no-duplicate-imports': 'off', + + // Style - strict + 'semi': ['error', 'always'], + 'quotes': ['error', 'single', { avoidEscape: true }], + 'indent': ['error', 2], + 'object-curly-spacing': ['error', 'always'], + 'comma-dangle': ['error', 'always-multiline'], + 'max-len': ['error', { + code: 100, + ignoreUrls: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + }], + 'comma-style': 'error', + 'block-spacing': 'error', + 'operator-linebreak': ['error', 'before'], + 'prefer-arrow-callback': 'error', + 'arrow-body-style': ['error', 'as-needed', { requireReturnForObjectLiteral: false }], + 'brace-style': ['error', '1tbs'], + 'one-var': ['error', 'never'], + + // Complexity - moderate + 'complexity': ['error', 15], + 'max-depth': ['error', 4], + 'max-nested-callbacks': ['error', 3], + 'max-params': ['error', 5], + 'max-statements': ['error', 25], + + // Best Practices - strict + 'eqeqeq': ['error', 'always', { null: 'ignore' }], + 'no-throw-literal': 'error', + 'no-useless-return': 'error', + 'no-sequences': 'error', + 'radix': 'error', + 'no-return-await': 'error', + 'no-await-in-loop': 'error', + 'no-promise-executor-return': 'error', + 'require-yield': 'error', + + // Prettier + ...prettier.rules, + }, + }, + { + files: ['**/*.test.ts', '**/__tests__/**/*.ts'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + 'max-len': 'off', + 'max-statements': 'off', + 'no-console': 'off', + }, + }, + { + ignores: ['dist/**', 'node_modules/**', 'coverage/**', 'vitest.config.ts'], + }, +]; diff --git a/src/sequentialthinking/formatter.ts b/src/sequentialthinking/formatter.ts new file mode 100644 index 0000000000..fa126ebe2a --- /dev/null +++ b/src/sequentialthinking/formatter.ts @@ -0,0 +1,56 @@ +import type { ThoughtFormatter, ThoughtData } from './interfaces.js'; +import chalk from 'chalk'; + +export class ConsoleThoughtFormatter implements ThoughtFormatter { + constructor(private readonly useColors = true) {} + + private getHeaderParts(thought: ThoughtData): { prefix: string; context: string } { + const { isRevision, revisesThought, branchFromThought, branchId } = thought; + + if (isRevision) { + return { + prefix: '[Revision]', + context: ` (revising thought ${revisesThought ?? '?'})`, + }; + } else if (branchFromThought) { + return { + prefix: '[Branch]', + context: ` (from thought ${branchFromThought}, ID: ${branchId ?? 'unknown'})`, + }; + } + return { prefix: '[Thought]', context: '' }; + } + + format(thought: ThoughtData): string { + const { prefix, context } = this.getHeaderParts(thought); + const suffix = ` ${thought.thoughtNumber}/${thought.totalThoughts}${context}`; + const headerPlain = `${prefix}${suffix}`; + const body = thought.thought; + + const bodyLines = body.split('\n'); + const maxLength = Math.max(headerPlain.length, ...bodyLines.map(l => l.length)); + const border = '─'.repeat(maxLength + 4); + + if (this.useColors) { + let coloredPrefix: string; + if (thought.isRevision) coloredPrefix = chalk.yellow(prefix); + else if (thought.branchFromThought) coloredPrefix = chalk.green(prefix); + else coloredPrefix = chalk.blue(prefix); + const header = `${coloredPrefix}${suffix}`; + const coloredBorder = chalk.gray(border); + + return ` + ${chalk.gray('┌')}${coloredBorder}${chalk.gray('┐')} + ${chalk.gray('│')} ${chalk.cyan(header)} ${chalk.gray('│')} + ${chalk.gray('├')}${coloredBorder}${chalk.gray('┤')} + ${chalk.gray('│')} ${body.padEnd(maxLength)} ${chalk.gray('│')} + ${chalk.gray('└')}${coloredBorder}${chalk.gray('┘')}`.trim(); + } + return ` +┌${border}┐ +│ ${headerPlain} │ +├${border}┤ +│ ${body.padEnd(maxLength)} │ +└${border}┘`.trim(); + } +} diff --git a/src/sequentialthinking/health-checker.ts b/src/sequentialthinking/health-checker.ts new file mode 100644 index 0000000000..599f9e123c --- /dev/null +++ b/src/sequentialthinking/health-checker.ts @@ -0,0 +1,259 @@ +import type { + AppConfig, + HealthChecker, + HealthCheckResult, + HealthStatus, + MetricsCollector, + ThoughtStorage, + SecurityService, +} from './interfaces.js'; + +function createFallbackCheck(): HealthCheckResult { + return { + status: 'unhealthy', + message: 'Check failed', + responseTime: 0, + timestamp: new Date(), + }; +} + +function unwrapSettled( + result: PromiseSettledResult, +): HealthCheckResult { + if (result.status === 'fulfilled') { + return result.value; + } + return createFallbackCheck(); +} + +export class ComprehensiveHealthChecker implements HealthChecker { + private readonly maxMemoryUsage: number; + private readonly maxStorageUsage: number; + private readonly maxResponseTime: number; + private readonly errorRateDegraded: number; + private readonly errorRateUnhealthy: number; + + constructor( + private readonly metrics: MetricsCollector, + private readonly storage: ThoughtStorage, + private readonly security: SecurityService, + thresholds?: AppConfig['monitoring']['healthThresholds'], + ) { + this.maxMemoryUsage = thresholds?.maxMemoryPercent ?? 90; + this.maxStorageUsage = thresholds?.maxStoragePercent ?? 80; + this.maxResponseTime = thresholds?.maxResponseTimeMs ?? 200; + this.errorRateDegraded = thresholds?.errorRateDegraded ?? 2; + this.errorRateUnhealthy = thresholds?.errorRateUnhealthy ?? 5; + } + + async checkHealth(): Promise { + try { + const settled = await Promise.allSettled([ + this.checkMemory(), + this.checkResponseTime(), + this.checkErrorRate(), + this.checkStorage(), + this.checkSecurity(), + ]); + + const [ + memoryResult, + responseTimeResult, + errorRateResult, + storageResult, + securityResult, + ] = settled.map(unwrapSettled); + + const statuses = [ + memoryResult, + responseTimeResult, + errorRateResult, + storageResult, + securityResult, + ].map((r) => r.status); + + const hasUnhealthy = statuses.includes('unhealthy'); + const hasDegraded = statuses.includes('degraded'); + + return { + status: hasUnhealthy + ? ('unhealthy' as const) + : hasDegraded + ? ('degraded' as const) + : ('healthy' as const), + checks: { + memory: memoryResult, + responseTime: responseTimeResult, + errorRate: errorRateResult, + storage: storageResult, + security: securityResult, + }, + summary: `Health check completed at ${new Date().toISOString()}`, + uptime: process.uptime(), + timestamp: new Date(), + }; + } catch { + const fallback = createFallbackCheck(); + return { + status: 'unhealthy', + checks: { + memory: fallback, + responseTime: { ...fallback }, + errorRate: { ...fallback }, + storage: { ...fallback }, + security: { ...fallback }, + }, + summary: 'Health check failed', + uptime: process.uptime(), + timestamp: new Date(), + }; + } + } + + private makeResult( + status: 'healthy' | 'unhealthy' | 'degraded', + message: string, + startTime: number, + details?: unknown, + ): HealthCheckResult { + return { + status, + message, + details, + responseTime: Date.now() - startTime, + timestamp: new Date(), + }; + } + + private evaluateMetric(opts: { + label: string; + value: number; + threshold: number; + degradedThreshold: number; + startTime: number; + details: unknown; + }): HealthCheckResult { + const { label, value, threshold, degradedThreshold } = opts; + const { startTime, details } = opts; + const formatted = `${value.toFixed(1)}%`; + if (value > threshold) { + return this.makeResult( + 'unhealthy', `${label} too high: ${formatted}`, + startTime, details, + ); + } + if (value > degradedThreshold) { + return this.makeResult( + 'degraded', `${label} elevated: ${formatted}`, + startTime, details, + ); + } + return this.makeResult( + 'healthy', `${label} normal: ${formatted}`, + startTime, details, + ); + } + + private async checkMemory(): Promise { + const startTime = Date.now(); + try { + const mem = process.memoryUsage(); + const heapUsedPercent = (mem.heapUsed / mem.heapTotal) * 100; + const details = { + heapUsed: Math.round(heapUsedPercent), + heapTotal: Math.round(mem.heapTotal), + external: Math.round(mem.external), + rss: Math.round(mem.rss), + }; + return this.evaluateMetric({ + label: 'Memory usage', + value: heapUsedPercent, + threshold: this.maxMemoryUsage, + degradedThreshold: this.maxMemoryUsage * 0.8, + startTime, + details, + }); + } catch { + return this.makeResult('unhealthy', 'Memory check failed', startTime); + } + } + + private async checkResponseTime(): Promise { + const startTime = Date.now(); + try { + const { requests } = this.metrics.getMetrics(); + const { averageResponseTime: avg, totalRequests } = requests; + const details = { avgResponseTime: Math.round(avg), requestCount: totalRequests }; + // Response time uses absolute ms values, not percentages — format without % + if (avg > this.maxResponseTime) { + return this.makeResult('unhealthy', `Response time too high: ${avg.toFixed(0)}ms`, startTime, details); + } + if (avg > this.maxResponseTime * 0.8) { + return this.makeResult('degraded', `Response time elevated: ${avg.toFixed(0)}ms`, startTime, details); + } + return this.makeResult('healthy', `Response time normal: ${avg.toFixed(0)}ms`, startTime, details); + } catch { + return this.makeResult('unhealthy', 'Response time check failed', startTime); + } + } + + private async checkErrorRate(): Promise { + const startTime = Date.now(); + try { + const { totalRequests, failedRequests } = + this.metrics.getMetrics().requests; + const errorRate = totalRequests > 0 + ? Math.min((failedRequests / totalRequests) * 100, 100) + : 0; + const details = { totalRequests, failedRequests, errorRate }; + return this.evaluateMetric({ + label: 'Error rate', + value: errorRate, + threshold: this.errorRateUnhealthy, + degradedThreshold: this.errorRateDegraded, + startTime, + details, + }); + } catch { + return this.makeResult( + 'unhealthy', 'Error rate check failed', startTime, + ); + } + } + + private async checkStorage(): Promise { + const startTime = Date.now(); + try { + const stats = this.storage.getStats(); + const usagePercent = stats.historyCapacity > 0 + ? (stats.historySize / stats.historyCapacity) * 100 + : 0; + const details = { + historySize: stats.historySize, + historyCapacity: stats.historyCapacity, + usagePercent: Math.round(usagePercent), + }; + return this.evaluateMetric({ + label: 'Storage usage', + value: usagePercent, + threshold: this.maxStorageUsage, + degradedThreshold: this.maxStorageUsage * 0.8, + startTime, + details, + }); + } catch { + return this.makeResult( + 'unhealthy', 'Storage check failed', startTime, + ); + } + } + + private async checkSecurity(): Promise { + const startTime = Date.now(); + try { + return this.makeResult('healthy', 'Security systems operational', startTime, this.security.getSecurityStatus()); + } catch { + return this.makeResult('unhealthy', 'Security check failed', startTime); + } + } +} diff --git a/src/sequentialthinking/index.ts b/src/sequentialthinking/index.ts index 809086a94c..48713e6e9e 100644 --- a/src/sequentialthinking/index.ts +++ b/src/sequentialthinking/index.ts @@ -1,21 +1,64 @@ #!/usr/bin/env node -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { z } from "zod"; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { z } from 'zod'; +import type { ProcessThoughtRequest } from './lib.js'; import { SequentialThinkingServer } from './lib.js'; +import type { AppConfig } from './interfaces.js'; +import { VALID_THINKING_MODES } from './interfaces.js'; +import { ConfigManager } from './config.js'; + +// Load configuration +let config: AppConfig; +try { + config = ConfigManager.load(); +} catch (error) { + console.error('Failed to load configuration:', error); + process.exit(1); +} const server = new McpServer({ - name: "sequential-thinking-server", - version: "0.2.0", + name: config.server.name, + version: config.server.version, }); const thinkingServer = new SequentialThinkingServer(); +// Shared schema fragments +const sessionIdSchema = z.string().describe('Session identifier'); +const thinkingModeSchema = z.enum(VALID_THINKING_MODES); + +// Shared result wrapper +interface ToolInput { + content: Array<{ type: 'text'; text: string }>; + isError?: boolean; +} + +interface ToolResult { + [key: string]: unknown; + content: Array<{ type: 'text'; text: string }>; + isError?: true; +} + +function wrapToolResult( + result: ToolInput, + treatEmptyAsError = false, +): ToolResult { + if ( + result.isError === true + || (treatEmptyAsError && result.content.length === 0) + ) { + return { content: result.content, isError: true as const }; + } + return { content: result.content }; +} + +// Register the main sequential thinking tool server.registerTool( - "sequentialthinking", + 'sequentialthinking', { - title: "Sequential Thinking", + title: 'Sequential Thinking', description: `A detailed tool for dynamic and reflective problem-solving through thoughts. This tool helps analyze problems through a flexible thinking process that can adapt and evolve. Each thought can build on, question, or revise previous insights as understanding deepens. @@ -39,6 +82,7 @@ Key features: - Verifies the hypothesis based on the Chain of Thought steps - Repeats the process until satisfied - Provides a correct answer +- Enhanced with security controls, rate limiting, and bounded memory management Parameters explained: - thought: Your current thinking step, which can include: @@ -56,8 +100,6 @@ Parameters explained: - revisesThought: If is_revision is true, which thought number is being reconsidered - branchFromThought: If branching, which thought number is the branching point - branchId: Identifier for the current branch (if any) -- needsMoreThoughts: If reaching end but realizing more thoughts needed - You should: 1. Start with an initial estimate of needed thoughts, but be ready to adjust 2. Feel free to question or revise previous thoughts @@ -69,50 +111,295 @@ You should: 8. Verify the hypothesis based on the Chain of Thought steps 9. Repeat the process until satisfied with the solution 10. Provide a single, ideally correct answer as the final output -11. Only set nextThoughtNeeded to false when truly done and a satisfactory answer is reached`, +11. Only set nextThoughtNeeded to false when truly done and a satisfactory answer is reached + +Security Notes: +- All thoughts are validated and sanitized +- Rate limiting is enforced per session +- Maximum thought length and history size are enforced +- Malicious content is automatically filtered`, + inputSchema: { + thought: z.string().describe('Your current thinking step'), + nextThoughtNeeded: z.boolean().describe('Whether another thought step is needed'), + thoughtNumber: z.number().int().min(1).describe('Current thought number (numeric value, e.g., 1, 2, 3)'), + totalThoughts: z.number().int().min(1).describe('Estimated total thoughts needed (numeric value, e.g., 5, 10)'), + isRevision: z.boolean().optional().describe('Whether this revises previous thinking'), + revisesThought: z.number().int().min(1).optional().describe('Which thought is being reconsidered'), + branchFromThought: z.number().int().min(1).optional().describe('Branching point thought number'), + branchId: z.string().optional().describe('Branch identifier'), + sessionId: sessionIdSchema.optional().describe('Session identifier for tracking'), + thinkingMode: thinkingModeSchema.optional().describe('Set thinking mode on first thought: fast (3-5 linear steps), expert (balanced branching), deep (exhaustive exploration)'), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async (args: any) => wrapToolResult( // eslint-disable-line @typescript-eslint/no-explicit-any + await thinkingServer.processThought( + args as ProcessThoughtRequest, + ), + true, + ), +); + +// Register the thought history retrieval tool +server.registerTool( + 'get_thought_history', + { + title: 'Get Thought History', + description: 'Retrieve past thoughts from a session. Use this to review thinking history, examine branch contents, or recall earlier reasoning steps.', + inputSchema: { + sessionId: sessionIdSchema.describe('Session identifier to retrieve thoughts for'), + branchId: z.string().optional().describe('Optional branch identifier to filter thoughts by branch'), + limit: z.number().int().min(1).optional().describe('Maximum number of thoughts to return (most recent first)'), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async (args: any) => { // eslint-disable-line @typescript-eslint/no-explicit-any + const thoughts = thinkingServer.getFilteredHistory({ + sessionId: args.sessionId, + branchId: args.branchId, + limit: args.limit, + }); + + return { + content: [{ + type: 'text' as const, + text: JSON.stringify({ + sessionId: args.sessionId, + branchId: args.branchId ?? null, + count: thoughts.length, + thoughts: thoughts.map((t) => ({ + thoughtNumber: t.thoughtNumber, + totalThoughts: t.totalThoughts, + thought: t.thought, + nextThoughtNeeded: t.nextThoughtNeeded, + isRevision: t.isRevision ?? false, + revisesThought: t.revisesThought ?? null, + branchId: t.branchId ?? null, + branchFromThought: t.branchFromThought ?? null, + timestamp: t.timestamp, + })), + }, null, 2), + }], + }; + }, +); + +// Add health check tool for monitoring +server.registerTool( + 'health_check', + { + title: 'Health Check', + description: 'Check the health and status of the Sequential Thinking server', inputSchema: { - thought: z.string().describe("Your current thinking step"), - nextThoughtNeeded: z.boolean().describe("Whether another thought step is needed"), - thoughtNumber: z.number().int().min(1).describe("Current thought number (numeric value, e.g., 1, 2, 3)"), - totalThoughts: z.number().int().min(1).describe("Estimated total thoughts needed (numeric value, e.g., 5, 10)"), - isRevision: z.boolean().optional().describe("Whether this revises previous thinking"), - revisesThought: z.number().int().min(1).optional().describe("Which thought is being reconsidered"), - branchFromThought: z.number().int().min(1).optional().describe("Branching point thought number"), - branchId: z.string().optional().describe("Branch identifier"), - needsMoreThoughts: z.boolean().optional().describe("If more thoughts are needed") - }, - outputSchema: { - thoughtNumber: z.number(), - totalThoughts: z.number(), - nextThoughtNeeded: z.boolean(), - branches: z.array(z.string()), - thoughtHistoryLength: z.number() - }, + _dummy: z.string().optional(), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async () => { + try { + const healthStatus = await thinkingServer.getHealthStatus(); + return { + content: [{ + type: 'text' as const, + text: JSON.stringify(healthStatus, null, 2), + }], + }; + } catch (error) { + return { + content: [{ + type: 'text' as const, + text: JSON.stringify({ + status: 'unhealthy', + summary: 'Health check failed', + error: error instanceof Error ? error.message : String(error), + timestamp: new Date(), + }, null, 2), + }], + isError: true, + }; + } }, - async (args) => { - const result = thinkingServer.processThought(args); +); - if (result.isError) { - return result; +// Add metrics tool +server.registerTool( + 'metrics', + { + title: 'Get Metrics', + description: 'Get detailed metrics and statistics about the server', + inputSchema: { + _dummy: z.string().optional(), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async () => { + try { + const metrics = await thinkingServer.getMetrics(); + return { + content: [{ + type: 'text' as const, + text: JSON.stringify(metrics, null, 2), + }], + }; + } catch (error) { + return { + content: [{ + type: 'text' as const, + text: JSON.stringify({ + error: 'Failed to retrieve metrics', + message: error instanceof Error ? error.message : String(error), + }, null, 2), + }], + isError: true, + }; } + }, +); + +// Set thinking mode tool +server.registerTool( + 'set_thinking_mode', + { + title: 'Set Thinking Mode', + description: `Set a thinking mode for a session to shape exploration behavior. Modes: +- fast: Linear, exploit-focused. 3-5 steps, no branching, auto-evaluation. +- expert: Balanced exploration with targeted branching, backtracking on low scores, convergence at 0.7. +- deep: Exhaustive exploration. Wide branching (up to 5), aggressive backtracking, convergence at 0.85. + +Once set, each processThought response includes modeGuidance with recommended actions.`, + inputSchema: { + sessionId: sessionIdSchema, + mode: thinkingModeSchema.describe('Thinking mode to activate'), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async (args: any) => wrapToolResult( // eslint-disable-line @typescript-eslint/no-explicit-any + await thinkingServer.setThinkingMode(args.sessionId, args.mode), + ), +); + +// Register MCTS tree exploration tools +server.registerTool( + 'backtrack', + { + title: 'Backtrack', + description: 'Move the thought tree cursor back to a previous node, allowing exploration of alternative paths from that point. Returns the node info, its children, and tree statistics.', + inputSchema: { + sessionId: sessionIdSchema, + nodeId: z.string().describe('The node ID to backtrack to'), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async (args: any) => wrapToolResult( // eslint-disable-line @typescript-eslint/no-explicit-any + await thinkingServer.backtrack(args.sessionId, args.nodeId), + ), +); + +server.registerTool( + 'evaluate_thought', + { + title: 'Evaluate Thought', + description: 'Score a thought node with a value between 0 and 1. The value is backpropagated up the tree to all ancestors, updating their visit counts and total values. This drives the MCTS selection process.', + inputSchema: { + sessionId: sessionIdSchema, + nodeId: z.string().describe('The node ID to evaluate'), + value: z.number().min(0).max(1).describe('Evaluation score between 0 (poor) and 1 (excellent)'), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async (args: any) => wrapToolResult( // eslint-disable-line @typescript-eslint/no-explicit-any + await thinkingServer.evaluateThought( + args.sessionId, args.nodeId, args.value, + ), + ), +); + +server.registerTool( + 'suggest_next_thought', + { + title: 'Suggest Next Thought', + description: 'Use UCB1-based selection to suggest the most promising node to explore next. Strategies: "explore" favors unvisited nodes, "exploit" favors high-value nodes, "balanced" (default) balances both.', + inputSchema: { + sessionId: sessionIdSchema, + strategy: z.enum(['explore', 'exploit', 'balanced']).optional().describe('Selection strategy (default: balanced)'), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async (args: any) => wrapToolResult( // eslint-disable-line @typescript-eslint/no-explicit-any + await thinkingServer.suggestNextThought( + args.sessionId, args.strategy, + ), + ), +); - // Parse the JSON response to get structured content - const parsedContent = JSON.parse(result.content[0].text); +server.registerTool( + 'get_thinking_summary', + { + title: 'Get Thinking Summary', + description: 'Get a comprehensive summary of the thought tree including the best reasoning path (highest average value), full tree structure, and statistics.', + inputSchema: { + sessionId: sessionIdSchema, + maxDepth: z.number().int().min(0).optional().describe('Maximum depth to include in tree structure (omit for full tree)'), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async (args: any) => wrapToolResult( // eslint-disable-line @typescript-eslint/no-explicit-any + await thinkingServer.getThinkingSummary( + args.sessionId, args.maxDepth, + ), + ), +); +// Version tool +server.registerTool( + 'get_version', + { + title: 'Get Server Version', + description: 'Get the version of the Sequential Thinking MCP server along with system information.', + inputSchema: { + _dummy: z.string().optional(), + } as any, // eslint-disable-line @typescript-eslint/no-explicit-any + }, + async () => { + const envInfo = ConfigManager.getEnvironmentInfo(); return { - content: result.content, - structuredContent: parsedContent + content: [{ + type: 'text' as const, + text: JSON.stringify({ + serverVersion: config.server.version, + nodeVersion: envInfo.nodeVersion, + platform: envInfo.platform, + arch: envInfo.arch, + pid: envInfo.pid, + }, null, 2), + }], }; - } + }, ); -async function runServer() { +// Setup graceful shutdown +process.on('SIGINT', () => { + console.error('Received SIGINT, shutting down gracefully...'); + thinkingServer.destroy(); + process.exit(0); +}); + +process.on('SIGTERM', () => { + console.error('Received SIGTERM, shutting down gracefully...'); + thinkingServer.destroy(); + process.exit(0); +}); + +async function runServer(): Promise { const transport = new StdioServerTransport(); await server.connect(transport); - console.error("Sequential Thinking MCP Server running on stdio"); + + const envInfo = ConfigManager.getEnvironmentInfo(); + console.error(`Sequential Thinking MCP Server ${config.server.version} running on stdio`); + console.error(`Node.js ${envInfo.nodeVersion} on ${envInfo.platform}-${envInfo.arch} (PID: ${envInfo.pid})`); + console.error(`Configuration: Max thoughts=${config.state.maxHistorySize}, Rate limit=${config.security.maxThoughtsPerMinute}/min`); + + if (config.monitoring.enableMetrics) { + console.error('Metrics collection enabled'); + } + if (config.monitoring.enableHealthChecks) { + console.error('Health checks enabled'); + } } runServer().catch((error) => { - console.error("Fatal error running server:", error); + console.error('Fatal error running server:', error); + thinkingServer.destroy(); process.exit(1); }); diff --git a/src/sequentialthinking/interfaces.ts b/src/sequentialthinking/interfaces.ts new file mode 100644 index 0000000000..d5d9daa7cf --- /dev/null +++ b/src/sequentialthinking/interfaces.ts @@ -0,0 +1,675 @@ +import { z } from 'zod'; +import type { ThinkingMode, ThinkingModeConfig, ModeGuidance } from './thinking-modes.js'; +import { VALID_THINKING_MODES } from './thinking-modes.js'; +export type { ThinkingMode, ThinkingModeConfig, ModeGuidance }; +export { VALID_THINKING_MODES }; + +const SESSION_ID_MIN_LENGTH = 1; +const SESSION_ID_MAX_LENGTH = 100; +const THOUGHT_NUMBER_MIN = 1; +const MAX_CONSECUTIVE_WHITESPACE = 10; + +const PRE_COMPILED_NORMALIZE_PATTERNS: RegExp[] = [ + /\r\n/g, + /\r/g, + /\t/g, + / {2,}/g, + /\n\n+/g, +]; + +const PRE_COMPILED_VALIDATE_PATTERN = /[ \n]{2,}/g; + +const sanitizeAndNormalizeThought = (val: string): string => { + const normalized = val + .replace(PRE_COMPILED_NORMALIZE_PATTERNS[0], '\n') + .replace(PRE_COMPILED_NORMALIZE_PATTERNS[1], '\n') + .replace(PRE_COMPILED_NORMALIZE_PATTERNS[2], ' ') + .trim() + .replace(PRE_COMPILED_NORMALIZE_PATTERNS[3], ' ') + .replace(PRE_COMPILED_NORMALIZE_PATTERNS[4], '\n'); + return normalized; +}; + +const validateThoughtContent = (val: string): boolean => { + const normalized = sanitizeAndNormalizeThought(val); + if (normalized.length === 0) return false; + const consecutiveWhitespace = normalized.match(PRE_COMPILED_VALIDATE_PATTERN); + if (consecutiveWhitespace?.some((m) => m.length > MAX_CONSECUTIVE_WHITESPACE)) { + return false; + } + return true; +}; + +export const sessionIdSchema = z + .string() + .min(SESSION_ID_MIN_LENGTH, { + message: `Session ID must be at least ${SESSION_ID_MIN_LENGTH} character`, + }) + .max(SESSION_ID_MAX_LENGTH, { + message: `Session ID must be at most ${SESSION_ID_MAX_LENGTH} characters`, + }) + .regex(/^[\p{L}\p{N}_-]+$/u, { + message: 'Session ID must contain only letters, numbers, underscores, and hyphens', + }) + .transform((val) => val.trim().toLowerCase()); + +export const rawSessionIdSchema = z + .string() + .min(SESSION_ID_MIN_LENGTH, { + message: `Session ID must be at least ${SESSION_ID_MIN_LENGTH} character`, + }) + .max(SESSION_ID_MAX_LENGTH, { + message: `Session ID must be at most ${SESSION_ID_MAX_LENGTH} characters`, + }) + .regex(/^[\p{L}\p{N}_-]+$/u, { + message: 'Session ID must contain only letters, numbers, underscores, and hyphens', + }); + +export const thinkingModeSchema = z.enum(VALID_THINKING_MODES) + .describe('Thinking mode: fast=quick decisions (3-5 steps), expert=complex analysis (5-10 steps), deep=thorough exploration (10-20 steps)'); + +export const THOUGHT_CATEGORIES = [ + 'analysis', + 'hypothesis', + 'conclusion', + 'question', + 'reflection', + 'planning', + 'evaluation', +] as const; + +export const THOUGHT_CATEGORY_DESCRIPTIONS: Record = { + analysis: 'Breaking down a problem into components', + hypothesis: 'Forming a testable assumption or theory', + conclusion: 'Drawing a final inference from evidence', + question: 'Asking for clarification or more information', + reflection: 'Thinking about the thinking process itself', + planning: 'Outlining steps to achieve a goal', + evaluation: 'Assessing the merit or quality of something', +}; + +export type ThoughtCategory = (typeof THOUGHT_CATEGORIES)[number]; + +export const thoughtCategorySchema = z.enum(THOUGHT_CATEGORIES) + .describe('Category of thought: analysis|hypothesis|conclusion|question|reflection|planning|evaluation'); + +export const STRATEGY_TYPES = ['explore', 'exploit', 'balanced'] as const; + +export const STRATEGY_DESCRIPTIONS: Record = { + explore: 'Favor unvisited nodes - good for discovery', + exploit: 'Favor high-value nodes - good for optimization', + balanced: 'Balance exploration and exploitation - default', +}; + +export type StrategyType = (typeof STRATEGY_TYPES)[number]; + +export const strategySchema = z.enum(STRATEGY_TYPES) + .describe('MCTS selection strategy: explore=find new paths, exploit=follow best path, balanced=mix both'); + +export const PROBLEM_TYPES = [ + 'analysis', + 'design', + 'debugging', + 'planning', + 'optimization', + 'decision', + 'creative', + 'refactoring', + 'testing', + 'security', + 'performance', + 'integration', + 'migration', + 'documentation', + 'research', + 'review', + 'deployment', + 'troubleshooting', + 'architecture', + 'api_design', + 'data_modeling', + 'ux_design', + 'technical_writing', + 'code_generation', + 'unknown', +] as const; + +export const PROBLEM_TYPE_DESCRIPTIONS: Record = { + analysis: 'Breaking down and understanding a problem', + design: 'Creating a solution or system architecture', + debugging: 'Finding and fixing errors', + planning: 'Mapping out steps to achieve a goal', + optimization: 'Improving efficiency or performance', + decision: 'Choosing between alternatives', + creative: 'Generating novel ideas or solutions', + refactoring: 'Improving existing code structure', + testing: 'Creating or improving test coverage', + security: 'Identifying or fixing security vulnerabilities', + performance: 'Improving speed or resource usage', + integration: 'Connecting systems or components', + migration: 'Moving data or systems to new platforms', + documentation: 'Creating or updating documentation', + research: 'Investigating options or technologies', + review: 'Evaluating code or designs for quality', + deployment: 'Releasing to production environments', + troubleshooting: 'Diagnosing and resolving issues', + architecture: 'Designing system-level structures', + api_design: 'Designing programmatic interfaces', + data_modeling: 'Designing data structures and relationships', + ux_design: 'Designing user experiences', + technical_writing: 'Creating technical content', + code_generation: 'Writing code from specifications', + unknown: 'Unable to classify the problem type', +}; + +export type ProblemType = (typeof PROBLEM_TYPES)[number]; + +export const REASONING_STYLES = ['deductive', 'inductive', 'abductive', 'analogical', 'recursive', 'systems'] as const; + +export const REASONING_STYLE_DESCRIPTIONS: Record = { + deductive: 'Reasoning from general principles to specific conclusions', + inductive: 'Reasoning from specific observations to general rules', + abductive: 'Reasoning to best explanation from incomplete info', + analogical: 'Reasoning from similar known cases', + recursive: 'Breaking problem into self-similar subproblems', + systems: 'Thinking about component interactions and relationships', +}; + +export type ReasoningStyle = (typeof REASONING_STYLES)[number]; + +export const CONFIDENCE_TRENDS = ['improving', 'declining', 'stable', 'insufficient'] as const; + +export const CONFIDENCE_TREND_DESCRIPTIONS: Record = { + improving: 'Confidence is increasing over time', + declining: 'Confidence is decreasing over time', + stable: 'Confidence is consistent', + insufficient: 'Not enough data to determine trend', +}; + +export type ConfidenceTrend = (typeof CONFIDENCE_TRENDS)[number]; + +export const COMPLEXITY_LEVELS = ['simple', 'moderate', 'complex'] as const; + +export const COMPLEXITY_DESCRIPTIONS: Record = { + simple: 'Straightforward, few factors to consider', + moderate: 'Multiple factors with some tradeoffs', + complex: 'Many factors, significant tradeoffs, requires deep analysis', +}; + +export type ComplexityLevel = (typeof COMPLEXITY_LEVELS)[number]; + +export const INSIGHT_TYPES = [ + 'breakthrough', + 'connection', + 'pivot', + 'validation', + 'dead_end', + 'simplification', + 'pattern_recognition', + 'question_reframing', +] as const; + +export const INSIGHT_TYPE_DESCRIPTIONS: Record = { + breakthrough: 'A major realization that changes the approach entirely', + connection: 'Linking two previously unrelated ideas or concepts', + pivot: 'Shifting to a completely different solution direction', + validation: 'Confirming an approach or assumption is correct', + dead_end: 'Recognizing the current path will not succeed', + simplification: 'Finding a simpler solution than originally thought', + pattern_recognition: 'Identifying a familiar pattern in the problem', + question_reframing: 'Asking a better question that leads to progress', +}; + +export type InsightType = (typeof INSIGHT_TYPES)[number]; + +export const DOMAIN_TYPES = [ + 'reasoning', + 'decision', + 'learning', + 'memory', + 'attention', + 'perception', + 'language', + 'emotion', + 'metacognition', + 'creativity', + 'problem_solving', + 'social', + 'general', +] as const; + +export const DOMAIN_DESCRIPTIONS: Record = { + reasoning: 'Logical thinking, deduction, induction, analysis', + decision: 'Making choices under uncertainty', + learning: 'Acquiring knowledge or skills', + memory: 'Encoding, storing, retrieving information', + attention: 'Focus, filtering, managing cognitive load', + perception: 'Interpreting sensory information', + language: 'Communication, comprehension, expression', + emotion: 'Feeling states affecting cognition', + metacognition: 'Thinking about thinking, self-awareness', + creativity: 'Generating novel ideas', + problem_solving: 'Goal-directed thinking', + social: 'Understanding others, collaboration', + general: 'General cognitive task', +}; + +export type DomainType = (typeof DOMAIN_TYPES)[number]; + +export const COGNITIVE_PROCESS_TYPES = [ + 'understanding', + 'creating', + 'deciding', + 'remembering', + 'explaining', + 'predicting', + 'evaluating', + 'planning', + 'communicating', + 'transforming', +] as const; + +export const COGNITIVE_PROCESS_DESCRIPTIONS: Record = { + understanding: 'Making sense of something, grasping meaning', + creating: 'Generating something new, synthesis', + deciding: 'Choosing between alternatives', + remembering: 'Retrieving or storing information', + explaining: 'Cause and effect, making things clear', + predicting: 'Forecasting future outcomes', + evaluating: 'Assessing quality, value, or merit', + planning: 'Mapping out future actions', + communicating: 'Conveying meaning to others', + transforming: 'Changing form, converting, adapting', +}; + +export type CognitiveProcessType = (typeof COGNITIVE_PROCESS_TYPES)[number]; + +export const META_STATES = [ + 'clarity', + 'certainty', + 'progress', + 'blockage', + 'scope_narrow', + 'scope_broad', + 'bias', + 'momentum_gaining', + 'momentum_losing', + 'stuck', +] as const; + +export const META_STATE_DESCRIPTIONS: Record = { + clarity: 'How clear is the current thinking?', + certainty: 'How confident/sure is the thinker?', + progress: 'Is the thinking making forward progress?', + blockage: 'Is the thinker stuck or blocked?', + scope_narrow: 'Thinking is too narrow or focused', + scope_broad: 'Thinking is too broad or scattered', + bias: 'Potential blind spots or biases detected', + momentum_gaining: 'Gaining momentum, productive flow', + momentum_losing: 'Losing momentum, productivity declining', + stuck: 'Completely stuck with no progress', +}; + +export const thoughtTagSchema = z + .string() + .min(1, 'Tag must be non-empty') + .max(50, 'Tag must be at most 50 characters') + .regex(/^[a-z0-9_-]+$/i, { + message: 'Tag must contain only alphanumeric characters, underscores, and hyphens', + }); + +export const thoughtMetadataSchema = z + .object({ + category: thoughtCategorySchema.optional(), + tags: z.array(thoughtTagSchema).max(10, 'Maximum 10 tags allowed').optional(), + priority: z.enum(['low', 'medium', 'high']).optional(), + confidence: z.number().min(0).max(1).optional(), + }) + .strict(); + +export type ThoughtMetadata = z.infer; + +export const thoughtDataSchema = z + .object({ + thought: z + .string() + .min(1, 'Thought is required') + .refine( + validateThoughtContent, + { message: 'Thought content contains invalid patterns (excessive whitespace or repeated characters)' }, + ), + thoughtNumber: z + .number() + .int('thoughtNumber must be a positive integer') + .min(THOUGHT_NUMBER_MIN, 'thoughtNumber must be a positive integer'), + totalThoughts: z + .number() + .int('totalThoughts must be a positive integer') + .min(THOUGHT_NUMBER_MIN, 'totalThoughts must be a positive integer'), + nextThoughtNeeded: z.boolean().describe('must be a boolean'), + isRevision: z.boolean().optional(), + revisesThought: z + .number() + .int('revisesThought must be an integer') + .min(THOUGHT_NUMBER_MIN) + .optional(), + branchFromThought: z + .number() + .int('branchFromThought must be an integer') + .min(THOUGHT_NUMBER_MIN) + .optional(), + branchId: z.string().optional(), + timestamp: z.number().optional(), + sessionId: z.string().optional(), + thinkingMode: thinkingModeSchema.optional(), + metadata: thoughtMetadataSchema.optional(), + schemaVersion: z.string().optional(), + }); + +export type ThoughtData = z.infer; + +export const thoughtDataInputSchema = thoughtDataSchema.partial({ + timestamp: true, + sessionId: true, +}); + +export type ThoughtDataInput = z.infer; + +export const sanitizedThoughtDataSchema = thoughtDataSchema.transform((data) => ({ + ...data, + thought: sanitizeAndNormalizeThought(data.thought), + sessionId: data.sessionId?.trim().toLowerCase(), +})); + +export type SanitizedThoughtData = z.infer; + +export const getThoughtHistorySchema = z.object({ + sessionId: sessionIdSchema, + branchId: z.string().optional(), + limit: z + .number() + .int('limit must be an integer') + .min(1, 'limit must be at least 1') + .optional(), +}); + +export type GetThoughtHistoryInput = z.infer; + +export const setThinkingModeSchema = z.object({ + sessionId: sessionIdSchema, + mode: thinkingModeSchema, +}); + +export type SetThinkingModeInput = z.infer; + +export const nodeIdSchema = z + .string() + .min(1, 'nodeId is required') + .max(100, 'nodeId must be at most 100 characters') + .regex(/^[a-zA-Z0-9_-]+$/, { + message: 'nodeId must be alphanumeric with optional hyphens/underscores', + }); + +export const backtrackSchema = z.object({ + sessionId: rawSessionIdSchema, + nodeId: nodeIdSchema, +}); + +export type BacktrackInput = z.infer; + +export const evaluateThoughtSchema = z.object({ + sessionId: rawSessionIdSchema, + nodeId: nodeIdSchema, + value: z + .number() + .min(0, 'value must be at least 0') + .max(1, 'value must be at most 1'), +}); + +export type EvaluateThoughtInput = z.infer; + +export const suggestNextThoughtSchema = z.object({ + sessionId: rawSessionIdSchema, + strategy: z.enum(['explore', 'exploit', 'balanced']).optional(), +}); + +export type SuggestNextThoughtInput = z.infer; + +export const getThinkingSummarySchema = z.object({ + sessionId: rawSessionIdSchema, + maxDepth: z + .number() + .int('maxDepth must be an integer') + .min(0, 'maxDepth must be at least 0') + .optional(), +}); + +export type GetThinkingSummaryInput = z.infer; + +export interface ThoughtFormatter { + format(thought: ThoughtData): string; +} + +export interface StorageStats { + historySize: number; + historyCapacity: number; + branchCount: number; + sessionCount: number; +} + +export interface ThoughtStorage { + addThought(thought: ThoughtData): void; + getHistory(limit?: number): ThoughtData[]; + getBranches(): string[]; + getBranchThoughts(branchId: string): ThoughtData[]; + getStats(): StorageStats; + destroy(): void; +} + +export interface Logger { + info(message: string, meta?: Record): void; + error(message: string, error?: Error | unknown): void; + debug(message: string, meta?: Record): void; + warn(message: string, meta?: Record): void; + logThought(sessionId: string, thought: ThoughtData): void; +} + +export interface SecurityService { + validateThought( + thought: string, + sessionId: string, + ): void; + sanitizeContent(content: string): string; + getSecurityStatus(): Record; + generateSessionId(): string; + validateSession(sessionId: string): boolean; +} + +export interface RequestMetrics { + totalRequests: number; + successfulRequests: number; + failedRequests: number; + averageResponseTime: number; + lastRequestTime: Date | null; + requestsPerMinute: number; +} + +export interface ThoughtMetrics { + totalThoughts: number; + averageThoughtLength: number; + thoughtsPerMinute: number; + revisionCount: number; + branchCount: number; + activeSessions: number; +} + +export interface SystemMetrics { + memoryUsage: NodeJS.MemoryUsage; + cpuUsage: NodeJS.CpuUsage; + uptime: number; + timestamp: Date; +} + +export interface MetricsCollector { + recordRequest(duration: number, success: boolean): void; + recordThoughtProcessed(thought: ThoughtData): void; + getMetrics(): { requests: RequestMetrics; thoughts: ThoughtMetrics; system: SystemMetrics }; + destroy(): void; +} + +export interface HealthCheckResult { + status: 'healthy' | 'unhealthy' | 'degraded'; + message: string; + details?: unknown; + responseTime: number; + timestamp: Date; +} + +export interface HealthStatus { + status: 'healthy' | 'unhealthy' | 'degraded'; + checks: { + memory: HealthCheckResult; + responseTime: HealthCheckResult; + errorRate: HealthCheckResult; + storage: HealthCheckResult; + security: HealthCheckResult; + }; + summary: string; + uptime: number; + timestamp: Date; +} + +export interface HealthChecker { + checkHealth(): Promise; +} + +export interface ServiceContainer { + register(key: string, factory: () => T): void; + get(key: string): T; + destroy(): void; +} + +export interface MCTSConfig { + maxNodesPerTree: number; + maxTreeAge: number; + explorationConstant: number; + enableAutoTree: boolean; +} + +export interface TreeStats { + totalNodes: number; + maxDepth: number; + unexploredCount: number; + averageValue: number; + terminalCount: number; +} + +export interface TreeNodeInfo { + nodeId: string; + thoughtNumber: number; + thought: string; + depth: number; + visitCount: number; + averageValue: number; + childCount: number; + isTerminal: boolean; +} + +export interface BacktrackResult { + node: TreeNodeInfo; + children: TreeNodeInfo[]; + treeStats: TreeStats; +} + +export interface EvaluateResult { + nodeId: string; + newVisitCount: number; + newAverageValue: number; + nodesUpdated: number; + treeStats: TreeStats; +} + +export interface SuggestResult { + suggestion: { + nodeId: string; + thoughtNumber: number; + thought: string; + ucb1Score: number; + reason: string; + } | null; + alternatives: Array<{ + nodeId: string; + thoughtNumber: number; + ucb1Score: number; + }>; + treeStats: TreeStats; +} + +export interface ThinkingSummary { + bestPath: TreeNodeInfo[]; + treeStructure: unknown; + treeStats: TreeStats; +} + +export interface ThoughtTreeRecordResult { + nodeId: string; + parentNodeId: string | null; + treeStats: TreeStats; + modeGuidance?: ModeGuidance; +} + +export interface ThoughtTreeService { + recordThought(data: ThoughtData): ThoughtTreeRecordResult | null; + backtrack(sessionId: string, nodeId: string): BacktrackResult; + findNodeByThoughtNumber(sessionId: string, thoughtNumber: number): TreeNodeInfo | null; + setMode(sessionId: string, mode: ThinkingMode): ThinkingModeConfig; + getMode(sessionId: string): ThinkingModeConfig | null; + cleanup(): void; + destroy(): void; +} + +export interface MCTSService { + evaluate(sessionId: string, nodeId: string, value: number): EvaluateResult; + suggest(sessionId: string, strategy?: 'explore' | 'exploit' | 'balanced'): SuggestResult; + getSummary(sessionId: string, maxDepth?: number): ThinkingSummary; +} + +export interface AppConfig { + server: { + name: string; + version: string; + }; + state: { + maxHistorySize: number; + maxBranchAge: number; + maxThoughtLength: number; + maxThoughtsPerBranch: number; + cleanupInterval: number; + persistence: { + enabled: boolean; + path: string; + saveInterval: number; + }; + }; + security: { + maxThoughtsPerMinute: number; + blockedPatterns: RegExp[]; + }; + logging: { + level: 'debug' | 'info' | 'warn' | 'error'; + enableColors: boolean; + enableThoughtLogging: boolean; + }; + monitoring: { + enableMetrics: boolean; + enableHealthChecks: boolean; + healthThresholds: { + maxMemoryPercent: number; + maxStoragePercent: number; + maxResponseTimeMs: number; + errorRateDegraded: number; + errorRateUnhealthy: number; + }; + }; + mcts: MCTSConfig; +} diff --git a/src/sequentialthinking/lib.ts b/src/sequentialthinking/lib.ts index 31a1098644..c70625bb40 100644 --- a/src/sequentialthinking/lib.ts +++ b/src/sequentialthinking/lib.ts @@ -1,99 +1,522 @@ -import chalk from 'chalk'; - -export interface ThoughtData { - thought: string; - thoughtNumber: number; - totalThoughts: number; - isRevision?: boolean; - revisesThought?: number; - branchFromThought?: number; - branchId?: string; - needsMoreThoughts?: boolean; - nextThoughtNeeded: boolean; +import type { z } from 'zod'; +import { SequentialThinkingApp } from './container.js'; +import { SequentialThinkingError, ValidationError, SecurityError, BusinessLogicError } from './errors.js'; +import type { ThoughtData, Logger, ThoughtStorage, SecurityService, ThoughtFormatter, MetricsCollector, HealthChecker, HealthStatus, RequestMetrics, ThoughtMetrics, SystemMetrics, AppConfig, ThoughtTreeService, MCTSService, ThinkingMode, ThoughtTreeRecordResult } from './interfaces.js'; +import { VALID_THINKING_MODES, thoughtDataSchema, getThoughtHistorySchema, setThinkingModeSchema, backtrackSchema, evaluateThoughtSchema, suggestNextThoughtSchema, getThinkingSummarySchema } from './interfaces.js'; + +export type ProcessThoughtRequest = ThoughtData; + +export interface ProcessThoughtResponse { + content: Array<{ type: 'text'; text: string }>; + isError?: boolean; + statusCode?: number; +} + +interface ServiceBundle { + logger: Logger; + storage: ThoughtStorage; + security: SecurityService; + formatter: ThoughtFormatter; + metrics: MetricsCollector; + config: AppConfig; + thoughtTreeManager: ThoughtTreeService & MCTSService; } export class SequentialThinkingServer { - private thoughtHistory: ThoughtData[] = []; - private branches: Record = {}; - private disableThoughtLogging: boolean; + private readonly app: SequentialThinkingApp; + private _services: ServiceBundle | null = null; constructor() { - this.disableThoughtLogging = (process.env.DISABLE_THOUGHT_LOGGING || "").toLowerCase() === "true"; + this.app = new SequentialThinkingApp(); + } + + private get services(): ServiceBundle { + if (!this._services) { + const container = this.app.getContainer(); + this._services = { + logger: container.get('logger'), + storage: container.get('storage'), + security: container.get('security'), + formatter: container.get('formatter'), + metrics: container.get('metrics'), + config: container.get('config'), + thoughtTreeManager: container.get('thoughtTreeManager'), + }; + } + return this._services; } - private formatThought(thoughtData: ThoughtData): string { - const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData; + private validateWithZod(schema: z.ZodSchema, data: unknown, errorContext: string): T { + const result = schema.safeParse(data); + if (!result.success) { + const errors = result.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`).join('; '); + throw new ValidationError(`${errorContext}: ${errors}`); + } + return result.data; + } - let prefix = ''; - let context = ''; + private validateInput( + input: ProcessThoughtRequest, + ): ProcessThoughtRequest { + const validated = this.validateWithZod(thoughtDataSchema, input, 'Invalid thought input'); + this.validateBusinessLogic(validated); + this.validateMaxLength(validated); + return validated; + } - if (isRevision) { - prefix = chalk.yellow('🔄 Revision'); - context = ` (revising thought ${revisesThought})`; - } else if (branchFromThought) { - prefix = chalk.green('🌿 Branch'); - context = ` (from thought ${branchFromThought}, ID: ${branchId})`; - } else { - prefix = chalk.blue('💭 Thought'); - context = ''; + private validateMaxLength(input: ProcessThoughtRequest): void { + const maxLength = this.services.config.state.maxThoughtLength; + if (input.thought.length > maxLength) { + throw new ValidationError( + `Thought exceeds maximum length of ${maxLength} characters (actual: ${input.thought.length})`, + ); + } + } + + private validateBusinessLogic(input: ProcessThoughtRequest): void { + if (input.isRevision && !input.revisesThought) { + throw new BusinessLogicError( + 'isRevision requires revisesThought to be specified', + ); + } + if (input.branchFromThought && !input.branchId) { + throw new BusinessLogicError( + 'branchFromThought requires branchId to be specified', + ); } + } - const header = `${prefix} ${thoughtNumber}/${totalThoughts}${context}`; - const border = '─'.repeat(Math.max(header.length, thought.length) + 4); + private buildThoughtData( + input: ProcessThoughtRequest, + sanitizedThought: string, + sessionId: string, + ): ThoughtData { + const thoughtData: ThoughtData = { + ...input, + thought: sanitizedThought, + sessionId, + timestamp: Date.now(), + }; + if (thoughtData.thoughtNumber > thoughtData.totalThoughts) { + thoughtData.totalThoughts = thoughtData.thoughtNumber; + } + return thoughtData; + } - return ` -┌${border}┐ -│ ${header} │ -├${border}┤ -│ ${thought.padEnd(border.length - 2)} │ -└${border}┘`; + private validateSessionId(sessionId: string): void { + if (!sessionId) throw new ValidationError('sessionId is required'); + if (!this.services.security.validateSession(sessionId)) { + throw new SecurityError('Invalid session ID format: must be 1-100 characters'); + } } - public processThought(input: ThoughtData): { content: Array<{ type: "text"; text: string }>; isError?: boolean } { - try { - // Validation happens at the tool registration layer via Zod - // Adjust totalThoughts if thoughtNumber exceeds it - if (input.thoughtNumber > input.totalThoughts) { - input.totalThoughts = input.thoughtNumber; + private static safeStringify(value: unknown): string { + const seen = new WeakSet(); + return JSON.stringify(value, (_key: string, val: unknown) => { + if (typeof val === 'object' && val !== null) { + if (seen.has(val)) return '[Circular]'; + seen.add(val); } + return val; + }, 2); + } - this.thoughtHistory.push(input); + private async withMetrics(fn: () => T | Promise): Promise { + const { metrics } = this.services; + const startTime = Date.now(); + try { + const result = await fn(); + metrics.recordRequest(Date.now() - startTime, true); + return { content: [{ type: 'text', text: SequentialThinkingServer.safeStringify(result) }] }; + } catch (error) { + metrics.recordRequest(Date.now() - startTime, false); + throw error; + } + } - if (input.branchFromThought && input.branchId) { - if (!this.branches[input.branchId]) { - this.branches[input.branchId] = []; - } - this.branches[input.branchId].push(input); + private resolveSession(sessionId: string | undefined): string { + // If user provided a sessionId, validate it first + if (sessionId !== undefined) { + if (!this.services.security.validateSession(sessionId)) { + throw new SecurityError( + `Invalid session ID format: must be 1-100 characters (got ${sessionId.length})`, + ); } + return sessionId; + } + + // No sessionId provided: generate a new one + return this.services.security.generateSessionId(); + } + + private autoSetThinkingMode( + input: ProcessThoughtRequest, + thoughtData: ThoughtData, + sessionId: string, + ): void { + const { thinkingMode: mode } = input; + if (!mode || thoughtData.thoughtNumber !== 1) return; + if ((VALID_THINKING_MODES as readonly string[]).includes(mode)) { + this.services.thoughtTreeManager.setMode( + sessionId, mode as ThinkingMode, + ); + } else { + this.services.logger.warn( + `Invalid thinking mode "${mode}", ignoring. Valid: ${VALID_THINKING_MODES.join(', ')}`, + ); + } + } + + private enrichTreeResult( + responseData: Record, + treeResult: ThoughtTreeRecordResult | null, + ): void { + if (!treeResult) return; + responseData.nodeId = treeResult.nodeId; + responseData.parentNodeId = treeResult.parentNodeId; + responseData.treeStats = treeResult.treeStats; + if (treeResult.modeGuidance) { + responseData.modeGuidance = treeResult.modeGuidance; + } + } + + private enrichRevisionContext( + responseData: Record, + thoughtData: ThoughtData, + sessionId: string, + ): void { + if (!thoughtData.isRevision || !thoughtData.revisesThought) return; + const { thoughtTreeManager, storage } = this.services; + const treeNode = thoughtTreeManager.findNodeByThoughtNumber( + sessionId, thoughtData.revisesThought, + ); + if (treeNode) { + responseData.revisionContext = { + originalThought: treeNode.thought, + originalThoughtNumber: treeNode.thoughtNumber, + }; + return; + } + const history = storage.getHistory(); + const original = history.find( + (t) => + t.thoughtNumber === thoughtData.revisesThought + && t.sessionId === sessionId, + ); + if (original) { + responseData.revisionContext = { + originalThought: original.thought, + originalThoughtNumber: original.thoughtNumber, + }; + } + } + + private enrichBranchContext( + responseData: Record, + thoughtData: ThoughtData, + ): void { + if (!thoughtData.branchId) return; + const branchThoughts = this.services.storage.getBranchThoughts( + thoughtData.branchId, + ); + const prior = branchThoughts + .filter( + (t) => + t !== thoughtData + && t.thoughtNumber !== thoughtData.thoughtNumber, + ) + .map((t) => ({ + thoughtNumber: t.thoughtNumber, thought: t.thought, + })); + if (prior.length > 0) { + responseData.branchContext = { + branchId: thoughtData.branchId, + existingThoughts: prior, + }; + } + } + + private recordToTree( + thoughtData: ThoughtData, + sessionId: string, + ): ThoughtTreeRecordResult | null { + const { thoughtTreeManager, logger } = this.services; + try { + return thoughtTreeManager.recordThought(thoughtData); + } catch (treeError) { + logger.warn( + 'Tree write failed after storage write succeeded', + { error: treeError, sessionId }, + ); + return null; + } + } + + private logThought( + sessionId: string, + thoughtData: ThoughtData, + ): void { + const { config, logger, formatter } = this.services; + if (!config.logging.enableThoughtLogging) return; + logger.logThought(sessionId, thoughtData); + try { + console.error(formatter.format(thoughtData)); + } catch { + console.error( + `[Thought] ${thoughtData.thoughtNumber}/${thoughtData.totalThoughts}`, + ); + } + } + + private async processWithServices( + input: ProcessThoughtRequest, + ): Promise { + const { storage, security, metrics } = this.services; + const startTime = Date.now(); + + try { + const sessionId = this.resolveSession(input.sessionId); + security.validateThought(input.thought, sessionId); + const sanitized = security.sanitizeContent(input.thought); + const thoughtData = this.buildThoughtData( + input, sanitized, sessionId, + ); + + this.autoSetThinkingMode(input, thoughtData, sessionId); + storage.addThought(thoughtData); + const treeResult = this.recordToTree(thoughtData, sessionId); + + const responseData: Record = { + thoughtNumber: thoughtData.thoughtNumber, + totalThoughts: thoughtData.totalThoughts, + nextThoughtNeeded: thoughtData.nextThoughtNeeded, + branches: storage.getBranches(), + thoughtHistoryLength: storage.getStats().historySize, + sessionId, + timestamp: thoughtData.timestamp, + }; - if (!this.disableThoughtLogging) { - const formattedThought = this.formatThought(input); - console.error(formattedThought); + this.enrichTreeResult(responseData, treeResult); + if (!treeResult) { + responseData.warning = 'Tree recording failed; MCTS features unavailable for this thought'; } + this.enrichRevisionContext(responseData, thoughtData, sessionId); + this.enrichBranchContext(responseData, thoughtData); + this.logThought(sessionId, thoughtData); + const duration = Date.now() - startTime; + metrics.recordRequest(duration, true); + metrics.recordThoughtProcessed(thoughtData); return { content: [{ - type: "text" as const, - text: JSON.stringify({ - thoughtNumber: input.thoughtNumber, - totalThoughts: input.totalThoughts, - nextThoughtNeeded: input.nextThoughtNeeded, - branches: Object.keys(this.branches), - thoughtHistoryLength: this.thoughtHistory.length - }, null, 2) - }] + type: 'text' as const, + text: SequentialThinkingServer.safeStringify(responseData), + }], + }; + } catch (error) { + metrics.recordRequest(Date.now() - startTime, false); + throw error; + } + } + + public async processThought(input: ProcessThoughtRequest): Promise { + try { + // Validate input first + this.validateInput(input); + + // Process with services + return await this.processWithServices(input); + + } catch (error) { + return this.handleError(error as Error); + } + } + + // Health check method + public async getHealthStatus(): Promise { + try { + return await this.app.getContainer().get('healthChecker').checkHealth(); + } catch { + return { + status: 'unhealthy', + summary: 'Health check failed', + checks: { + memory: { status: 'unhealthy', message: 'Health check failed', responseTime: 0, timestamp: new Date() }, + responseTime: { status: 'unhealthy', message: 'Health check failed', responseTime: 0, timestamp: new Date() }, + errorRate: { status: 'unhealthy', message: 'Health check failed', responseTime: 0, timestamp: new Date() }, + storage: { status: 'unhealthy', message: 'Health check failed', responseTime: 0, timestamp: new Date() }, + security: { status: 'unhealthy', message: 'Health check failed', responseTime: 0, timestamp: new Date() }, + }, + uptime: process.uptime(), + timestamp: new Date(), }; + } + } + + // Metrics method + public getMetrics(): { + requests: RequestMetrics; + thoughts: ThoughtMetrics; + system: SystemMetrics; + } { + return this.services.metrics.getMetrics(); + } + + // Cleanup method (idempotent — safe to call multiple times) + private destroyed = false; + + public destroy(): void { + if (this.destroyed) return; + this.destroyed = true; + + try { + this.app.destroy(); } catch (error) { + console.error('Error during cleanup:', error); + } + } + + private handleError(error: Error): ProcessThoughtResponse { + if (error instanceof SequentialThinkingError) { return { - content: [{ - type: "text" as const, - text: JSON.stringify({ - error: error instanceof Error ? error.message : String(error), - status: 'failed' - }, null, 2) - }], - isError: true + content: [{ type: 'text', text: JSON.stringify(error.toJSON(), null, 2) }], + isError: true, + statusCode: error.statusCode, }; } + return { + content: [{ type: 'text', text: JSON.stringify({ + error: 'INTERNAL_ERROR', + message: 'An unexpected error occurred', + category: 'SYSTEM', + statusCode: 500, + timestamp: new Date().toISOString(), + }, null, 2) }], + isError: true, + statusCode: 500, + }; + } + + // MCTS tree operations + public async backtrack(sessionId: string, nodeId: string): Promise { + try { + this.validateSessionId(sessionId); + const validated = this.validateWithZod(backtrackSchema, { sessionId, nodeId }, 'Invalid backtrack input'); + return await this.withMetrics(() => this.services.thoughtTreeManager.backtrack(validated.sessionId, validated.nodeId)); + } catch (error) { + return this.handleError(error as Error); + } + } + + public async evaluateThought( + sessionId: string, + nodeId: string, + value: number, + ): Promise { + try { + this.validateSessionId(sessionId); + const validated = this.validateWithZod(evaluateThoughtSchema, { sessionId, nodeId, value }, 'Invalid evaluate thought input'); + return await this.withMetrics(() => this.services.thoughtTreeManager.evaluate( + validated.sessionId, + validated.nodeId, + validated.value, + )); + } catch (error) { + return this.handleError(error as Error); + } + } + + public async suggestNextThought( + sessionId: string, + strategy?: 'explore' | 'exploit' | 'balanced', + ): Promise { + try { + this.validateSessionId(sessionId); + const validated = this.validateWithZod(suggestNextThoughtSchema, { sessionId, strategy }, 'Invalid suggest next thought input'); + return await this.withMetrics(() => this.services.thoughtTreeManager.suggest(validated.sessionId, validated.strategy)); + } catch (error) { + return this.handleError(error as Error); + } + } + + public async getThinkingSummary( + sessionId: string, + maxDepth?: number, + ): Promise { + try { + this.validateSessionId(sessionId); + const validated = this.validateWithZod(getThinkingSummarySchema, { sessionId, maxDepth }, 'Invalid get thinking summary input'); + return await this.withMetrics(() => this.services.thoughtTreeManager.getSummary(validated.sessionId, validated.maxDepth)); + } catch (error) { + return this.handleError(error as Error); + } + } + + // Set thinking mode for a session + public async setThinkingMode(sessionId: string, mode: string): Promise { + try { + this.validateSessionId(sessionId); + const validated = this.validateWithZod(setThinkingModeSchema, { sessionId, mode }, 'Invalid set thinking mode input'); + return await this.withMetrics(() => { + const config = this.services.thoughtTreeManager.setMode( + validated.sessionId, + validated.mode, + ); + return { + sessionId, + mode: config.mode, + config: { + explorationConstant: config.explorationConstant, + suggestStrategy: config.suggestStrategy, + maxBranchingFactor: config.maxBranchingFactor, + targetDepth: `${config.targetDepthMin}-${config.targetDepthMax}`, + autoEvaluate: config.autoEvaluate, + enableBacktracking: config.enableBacktracking, + convergenceThreshold: config.convergenceThreshold, + }, + }; + }); + } catch (error) { + return this.handleError(error as Error); + } + } + + // Filtered history for the get_thought_history tool + public getFilteredHistory(options: { + sessionId: string; + branchId?: string; + limit?: number; + }): ThoughtData[] { + try { + const validated = this.validateWithZod(getThoughtHistorySchema, options, 'Invalid get thought history input'); + const { storage } = this.services; + const source = validated.branchId + ? storage.getBranchThoughts(validated.branchId) + : storage.getHistory(); + const filtered = source.filter((t) => t.sessionId === validated.sessionId); + return validated.limit ? filtered.slice(-validated.limit) : filtered; + } catch (error) { + console.error('Warning: failed to get filtered history:', error); + return []; + } + } + + // Legacy compatibility methods + public getThoughtHistory(limit?: number): ThoughtData[] { + try { + return this.services.storage.getHistory(limit); + } catch (error) { + console.error('Warning: failed to get thought history:', error); + return []; + } + } + + public getBranches(): string[] { + try { + return this.services.storage.getBranches(); + } catch (error) { + console.error('Warning: failed to get branches:', error); + return []; + } } } diff --git a/src/sequentialthinking/logger.ts b/src/sequentialthinking/logger.ts new file mode 100644 index 0000000000..4ad744eb5d --- /dev/null +++ b/src/sequentialthinking/logger.ts @@ -0,0 +1,168 @@ +import type { AppConfig, Logger, ThoughtData } from './interfaces.js'; + +interface LogEntry { + timestamp: string; + level: string; + message: string; + service: string; + meta?: unknown; +} + +export class StructuredLogger implements Logger { + private readonly sensitiveFields = [ + 'password', + 'token', + 'secret', + 'key', + 'auth', + 'authorization', + 'credential', + 'apikey', + 'accesskey', + 'privatekey', + 'sessiontoken', + ]; + + constructor(private readonly config: AppConfig['logging']) {} + + private shouldLog(level: string): boolean { + const levels = ['debug', 'info', 'warn', 'error']; + const currentLevelIndex = levels.indexOf(this.config.level); + const messageLevelIndex = levels.indexOf(level); + return messageLevelIndex >= currentLevelIndex; + } + + private sanitize( + obj: unknown, + depth = 0, + visited: WeakSet = new WeakSet(), + ): unknown { + if (!obj || typeof obj !== 'object') { + return obj; + } + + if (depth > 10) { + return '[Object]'; + } + + if (visited.has(obj)) { + return '[Circular]'; + } + + visited.add(obj); + + if (Array.isArray(obj)) { + return obj.map(item => this.sanitize(item, depth + 1, visited)); + } + + const record = obj as Record; + const sanitized: Record = {}; + for (const [key, value] of Object.entries(record)) { + if (this.isSensitiveField(key)) { + sanitized[key] = '[REDACTED]'; + } else if (typeof value === 'object' && value !== null) { + sanitized[key] = this.sanitize(value, depth + 1, visited); + } else { + sanitized[key] = value; + } + } + + return sanitized; + } + + private isSensitiveField(fieldName: string): boolean { + const segments = this.splitFieldName(fieldName); + return this.sensitiveFields.some(sensitive => + segments.some(segment => segment === sensitive), + ); + } + + private splitFieldName(fieldName: string): string[] { + // Split on common separators: underscore, hyphen, dot + // Then split camelCase segments + return fieldName + .split(/[_\-.]/) + .flatMap(part => part.replace(/([a-z])([A-Z])/g, '$1\0$2').split('\0')) + .map(s => s.toLowerCase()); + } + + private createLogEntry( + level: string, + message: string, + meta?: unknown, + ): LogEntry { + const entry: LogEntry = { + timestamp: new Date().toISOString(), + level, + message, + service: 'sequential-thinking-server', + ...(meta ? { meta: this.sanitize(meta) } : {}), + }; + + return entry; + } + + private output(entry: LogEntry): void { + // All output to stderr — MCP reserves stdout for JSON-RPC protocol + console.error(JSON.stringify(entry)); + } + + info(message: string, meta?: unknown): void { + if (!this.shouldLog('info')) return; + + const entry = this.createLogEntry('info', message, meta); + this.output(entry); + } + + error(message: string, error?: unknown): void { + if (!this.shouldLog('error')) return; + + let meta: Record | undefined; + if (error instanceof Error) { + meta = { + error: { + name: error.name, + message: error.message, + stack: error.stack, + }, + }; + } else if (error) { + meta = { error }; + } + + const entry = this.createLogEntry('error', message, meta); + this.output(entry); + } + + debug(message: string, meta?: unknown): void { + if (!this.shouldLog('debug')) return; + + const entry = this.createLogEntry('debug', message, meta); + this.output(entry); + } + + warn(message: string, meta?: unknown): void { + if (!this.shouldLog('warn')) return; + + const entry = this.createLogEntry('warn', message, meta); + this.output(entry); + } + + // Context-specific logging methods + logThought(sessionId: string, thought: ThoughtData): void { + if (!this.shouldLog('debug')) return; + + const logEntry = { + sessionId, + thoughtNumber: thought.thoughtNumber, + totalThoughts: thought.totalThoughts, + isRevision: thought.isRevision, + branchId: thought.branchId, + thoughtLength: thought.thought.length, + hasContent: !!thought.thought, + }; + + this.debug('Thought processed', logEntry); + } + +} diff --git a/src/sequentialthinking/mcts.ts b/src/sequentialthinking/mcts.ts new file mode 100644 index 0000000000..9bec9a736a --- /dev/null +++ b/src/sequentialthinking/mcts.ts @@ -0,0 +1,172 @@ +import type { ThoughtTree, ThoughtNode } from './thought-tree.js'; +import type { TreeStats, TreeNodeInfo } from './interfaces.js'; + +const STRATEGY_CONSTANTS: Record = { + explore: 2.0, + exploit: 0.5, + balanced: Math.SQRT2, +}; + +export class MCTSEngine { + private readonly defaultC: number; + + constructor(explorationConstant: number = Math.SQRT2) { + this.defaultC = explorationConstant; + } + + computeUCB1( + nodeVisits: number, + nodeValue: number, + parentVisits: number, + explorationC: number, + ): number { + if (nodeVisits === 0) return Infinity; + const exploitation = nodeValue / nodeVisits; + const exploration = explorationC + * Math.sqrt(Math.log(parentVisits) / nodeVisits); + return exploitation + exploration; + } + + backpropagate(tree: ThoughtTree, nodeId: string, value: number): number { + let updated = 0; + const path = tree.getAncestorPath(nodeId); + + for (const node of path) { + node.totalValue += value; + node.visitCount++; + updated++; + } + + return updated; + } + + suggestNext( + tree: ThoughtTree, + strategy: 'explore' | 'exploit' | 'balanced' = 'balanced', + ): { + suggestion: { + nodeId: string; + thoughtNumber: number; + thought: string; + ucb1Score: number; + reason: string; + } | null; + alternatives: Array<{ + nodeId: string; + thoughtNumber: number; + ucb1Score: number; + }>; + } { + const explorationC = STRATEGY_CONSTANTS[strategy] ?? this.defaultC; + const expandable = tree.getExpandableNodes(); + + if (expandable.length === 0) { + return { suggestion: null, alternatives: [] }; + } + + // Compute total visits across tree for parent context + const totalVisits = Math.max(1, expandable.reduce((sum, n) => sum + n.visitCount, 0)); + + const scored = expandable.map(node => ({ + node, + ucb1: this.computeUCB1(node.visitCount, node.totalValue, totalVisits, explorationC), + })); + + // Sort descending by UCB1 score + scored.sort((a, b) => b.ucb1 - a.ucb1); + + const [best] = scored; + const reason = best.node.visitCount === 0 + ? 'Unexplored node — never evaluated' + : `UCB1 score ${best.ucb1.toFixed(4)} (${strategy} strategy)`; + + return { + suggestion: { + nodeId: best.node.nodeId, + thoughtNumber: best.node.thoughtNumber, + thought: best.node.thought, + ucb1Score: best.ucb1, + reason, + }, + alternatives: scored.slice(1, 4).map(s => ({ + nodeId: s.node.nodeId, + thoughtNumber: s.node.thoughtNumber, + ucb1Score: s.ucb1, + })), + }; + } + + extractBestPath(tree: ThoughtTree): TreeNodeInfo[] { + const { root } = tree; + if (!root) return []; + + const path: TreeNodeInfo[] = []; + let current: ThoughtNode | undefined = root; + + while (current) { + path.push(this.toNodeInfo(current)); + + if (current.children.length === 0) break; + + // Follow highest average value child + let bestChild: ThoughtNode | undefined; + let bestAvg = -Infinity; + + for (const childId of current.children) { + const child = tree.getNode(childId); + if (!child) continue; + const avg = child.visitCount > 0 ? child.totalValue / child.visitCount : 0; + if (avg > bestAvg) { + bestAvg = avg; + bestChild = child; + } + } + + current = bestChild; + } + + return path; + } + + getTreeStats(tree: ThoughtTree): TreeStats { + const allNodes = tree.getAllNodes(); + if (allNodes.length === 0) { + return { totalNodes: 0, maxDepth: 0, unexploredCount: 0, averageValue: 0, terminalCount: 0 }; + } + + let maxDepth = 0; + let unexploredCount = 0; + let totalValue = 0; + let totalVisits = 0; + let terminalCount = 0; + + for (const node of allNodes) { + if (node.depth > maxDepth) maxDepth = node.depth; + if (node.visitCount === 0) unexploredCount++; + totalValue += node.totalValue; + totalVisits += node.visitCount; + if (node.isTerminal) terminalCount++; + } + + return { + totalNodes: allNodes.length, + maxDepth, + unexploredCount, + averageValue: totalVisits > 0 ? totalValue / totalVisits : 0, + terminalCount, + }; + } + + toNodeInfo(node: ThoughtNode): TreeNodeInfo { + return { + nodeId: node.nodeId, + thoughtNumber: node.thoughtNumber, + thought: node.thought, + depth: node.depth, + visitCount: node.visitCount, + averageValue: node.visitCount > 0 ? node.totalValue / node.visitCount : 0, + childCount: node.children.length, + isTerminal: node.isTerminal, + }; + } +} diff --git a/src/sequentialthinking/metacognition.ts b/src/sequentialthinking/metacognition.ts new file mode 100644 index 0000000000..a81384ec52 --- /dev/null +++ b/src/sequentialthinking/metacognition.ts @@ -0,0 +1,1217 @@ +/** + * Metacognition module for self-aware problem-solving. + * Provides circularity detection, confidence scoring, perspective switching, + * problem type classification, reasoning gap analysis, and adaptive learning. + */ +import type { ThoughtData } from './interfaces.js'; + +const STOP_WORDS = new Set([ + 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', + 'of', 'with', 'by', 'from', 'is', 'are', 'was', 'were', 'be', 'been', + 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', + 'could', 'should', 'may', 'might', 'must', 'shall', 'can', 'need', + 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we', + 'they', 'what', 'which', 'who', 'whom', 'when', 'where', 'why', 'how', + 'all', 'each', 'every', 'both', 'few', 'more', 'most', 'other', 'some', + 'such', 'no', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', + 'just', 'also', 'now', 'here', 'there', 'then', 'once', 'if', 'about', + 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'up', + 'down', 'out', 'off', 'over', 'under', 'again', 'further', 'am', 'its', +]); + +const PERSPECTIVES = [ + { name: 'optimist', description: 'What are the best possible outcomes and opportunities?', prefix: 'From an optimistic angle:' }, + { name: 'pessimist', description: 'What could go wrong and what are the risks?', prefix: 'From a cautious perspective:' }, + { name: 'expert', description: 'What would a domain expert immediately recognize?', prefix: 'An expert would note:' }, + { name: 'beginner', description: 'What basic questions might someone new ask?', prefix: 'A beginner would ask:' }, + { name: 'skeptic', description: 'What assumptions might be wrong?', prefix: 'Skeptically considering:' }, +]; + +export interface CircularityResult { + isCircular: boolean; + similarity: number; + consecutiveCount: number; + warning: string | null; +} + +export interface ConfidenceResult { + confidence: number; + factors: string[]; + suggestion: string | null; +} + +export interface PerspectiveSuggestion { + perspective: string; + description: string; + prompt: string; +} + +export interface ProblemType { + type: 'analysis' | 'design' | 'debugging' | 'planning' | 'optimization' | 'decision' | 'creative' | 'unknown'; + confidence: number; + indicators: string[]; +} + +export interface PatternMatch { + pattern: string; + similarity: number; + solution: string; +} + +export class Metacognition { + private circularityHistory: Map = new Map(); + + tokenize(text: string): Set { + const words = text + .toLowerCase() + .replace(/[^\w\s]/g, ' ') + .split(/\s+/) + .filter(word => word.length > 2 && !STOP_WORDS.has(word)); + return new Set(words); + } + + jaccardSimilarity(setA: Set, setB: Set): number { + if (setA.size === 0 || setB.size === 0) return 0; + const intersection = new Set([...setA].filter(x => setB.has(x))); + const union = new Set([...setA, ...setB]); + return intersection.size / union.size; + } + + detectCircularity( + thoughts: ThoughtData[], + threshold = 0.6, + minConsecutive = 3, + ): CircularityResult { + if (thoughts.length < minConsecutive) { + return { isCircular: false, similarity: 0, consecutiveCount: 0, warning: null }; + } + + const recentThoughts = thoughts.slice(-minConsecutive * 2); + const tokens = recentThoughts.map(t => this.tokenize(t.thought)); + + let maxConsecutive = 0; + let currentConsecutive = 0; + let maxSimilarity = 0; + + for (let i = 1; i < tokens.length; i++) { + const similarity = this.jaccardSimilarity(tokens[i - 1], tokens[i]); + maxSimilarity = Math.max(maxSimilarity, similarity); + + if (similarity > threshold) { + currentConsecutive++; + maxConsecutive = Math.max(maxConsecutive, currentConsecutive); + } else { + currentConsecutive = 0; + } + } + + const isCircular = maxConsecutive >= minConsecutive; + const warning = isCircular + ? `Circular thinking detected (${maxConsecutive} similar thoughts, ${Math.round(maxSimilarity * 100)}% similarity). Consider pivoting or exploring a different approach.` + : null; + + return { + isCircular, + similarity: maxSimilarity, + consecutiveCount: maxConsecutive, + warning, + }; + } + + assessConfidence(thought: string, context: ThoughtData[], previousConfidence: number | null): ConfidenceResult { + const factors: string[] = []; + let confidence = this.computeBaseConfidence(thought, factors); + + if (previousConfidence !== null && context.length > 0) { + confidence = this.adjustForRepetition(thought, context, previousConfidence, confidence, factors); + } + + confidence = Math.max(0, Math.min(1, confidence)); + + return this.buildConfidenceResult(confidence, factors); + } + + private computeBaseConfidence(thought: string, factors: string[]): number { + let conf = 0.7; + const hasAction = /\b(should|must|need|will|definitely|certainly)\b/i.test(thought); + const hasHedge = /\b(maybe|perhaps|might|could|possibly|probably)\b/i.test(thought); + const hasEvidence = /\b(because|since|evidence|shown|demonstrated|proved)\b/i.test(thought); + const hasQuestion = /\?$/.test(thought.trim()); + const hasUncertainty = /\b(不确定|not sure|don'?t know|unclear)\b/i.test(thought.toLowerCase()); + + if (hasAction) { conf += 0.1; factors.push('assertive language'); } + if (hasHedge) { conf -= 0.15; factors.push('hedging language'); } + if (hasEvidence) { conf += 0.1; factors.push('evidence-based'); } + if (hasQuestion) { conf -= 0.1; factors.push('question form'); } + if (hasUncertainty) { conf -= 0.2; factors.push('explicit uncertainty'); } + + return conf; + } + + private adjustForRepetition( + thought: string, + context: ThoughtData[], + prevConf: number, + conf: number, + factors: string[], + ): number { + const similarity = this.jaccardSimilarity( + this.tokenize(thought), + this.tokenize(context[context.length - 1]?.thought || ''), + ); + if (similarity > 0.7 && prevConf > 0.6) { + conf -= 0.1; + factors.push('repetitive content'); + } + return conf; + } + + private buildConfidenceResult(confidence: number, factors: string[]): ConfidenceResult { + let suggestion: string | null = null; + if (confidence < 0.4) { + suggestion = 'Low confidence detected. Consider gathering more evidence or exploring alternative perspectives.'; + } else if (confidence > 0.8 && factors.length > 2) { + suggestion = 'High confidence. Consider if you might be overconfident - seek counterarguments?'; + } + return { confidence, factors, suggestion }; + } + + suggestPerspective(stuck = false, attemptCount = 0): PerspectiveSuggestion[] { + if (!stuck && attemptCount < 2) { + return []; + } + + const numSuggestions = Math.min(attemptCount + 1, PERSPECTIVES.length); + const shuffled = [...PERSPECTIVES].sort(() => Math.random() - 0.5); + return shuffled.slice(0, numSuggestions).map(p => ({ + perspective: p.name, + description: p.description, + prompt: `${p.prefix} ${p.description}`, + })); + } + + classifyProblemType(thoughts: ThoughtData[]): ProblemType { + if (thoughts.length === 0) { + return { type: 'unknown', confidence: 0, indicators: [] }; + } + + const allText = thoughts.map(t => t.thought.toLowerCase()).join(' '); + + const typeIndicators: Record = { + analysis: ['analyze', 'examine', 'investigate', 'break down', 'understand', 'assess', 'evaluate', 'review', 'explore', 'diagnose'], + design: ['design', 'create', 'build', 'develop', 'architect', 'structure', 'plan', 'construct', 'interface', 'schema'], + debugging: ['bug', 'error', 'fix', 'issue', 'problem', 'wrong', 'broken', 'fail', 'exception', 'crash', 'stack trace'], + planning: ['plan', 'strategy', 'roadmap', 'milestone', 'goal', 'objective', 'future', 'execute', 'timeline', 'deliverable'], + optimization: ['optimize', 'improve', 'better', 'performance', 'efficient', 'faster', 'reduce', 'enhance', 'latency', 'throughput'], + decision: ['choose', 'decision', 'option', 'alternative', 'select', 'pick', 'compare', 'tradeoff', 'pros', 'cons'], + creative: ['creative', 'innovative', 'novel', 'new', 'idea', 'brainstorm', 'imagine', 'invent', 'discover', 'generate'], + refactoring: ['refactor', 'restructure', 'cleanup', 'simplify', 'debt', 'technical debt', 'improve code', 'reorganize'], + testing: ['test', 'coverage', 'unit test', 'integration test', 'test case', 'assertion', 'mock', 'verify', 'spec'], + security: ['security', 'vulnerability', 'attack', 'breach', 'auth', 'authorization', 'authentication', 'encryption', 'permission', 'threat'], + performance: ['performance', 'speed', 'memory', 'cpu', 'bottleneck', 'profiling', 'load', 'scalability', 'cache'], + integration: ['integrate', 'connect', 'api', 'interface', 'bridge', 'compatibility', 'interop', 'dependency'], + migration: ['migrate', 'upgrade', 'convert', 'transform', 'import', 'export', 'backup', 'restore', 'transition'], + documentation: ['document', 'doc', 'readme', 'specification', 'manual', 'guide', 'explain', 'describe'], + research: ['research', 'investigate', 'explore', 'study', 'compare', 'alternatives', 'options', 'feasibility'], + review: ['review', 'audit', 'assess', 'quality', 'best practice', 'standard', 'compliance', 'check'], + deployment: ['deploy', 'release', 'publish', 'environment', 'staging', 'production', 'ci', 'cd', 'pipeline'], + troubleshooting: ['troubleshoot', 'debug', 'solve', 'resolve', 'root cause', 'diagnostic', 'symptom'], + architecture: ['architecture', 'system design', 'microservice', 'monolith', 'distributed', 'component', 'layer', 'pattern'], + api_design: ['api', 'endpoint', 'rest', 'graphql', 'protocol', 'request', 'response', 'payload', 'schema'], + data_modeling: ['database', 'schema', 'entity', 'relationship', 'table', 'model', 'normalization', 'query'], + ux_design: ['user experience', 'ui', 'interface', 'design', 'accessibility', 'usability', 'user flow', 'prototype'], + technical_writing: ['documentation', 'manual', 'guide', 'tutorial', 'spec', 'readme', 'changelog'], + code_generation: ['generate', 'create code', 'scaffold', 'boilerplate', 'template', 'auto-generate', 'write code'], + }; + + const scores: Record = {}; + for (const [type, keywords] of Object.entries(typeIndicators)) { + scores[type] = keywords.filter(kw => allText.includes(kw)).length; + } + + const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]); + const [topType, topScore] = entries[0]; + + const confidence = topScore > 0 ? Math.min(0.9, 0.3 + topScore * 0.15) : 0.1; + const indicators = typeIndicators[topType as keyof typeof typeIndicators] + ?.filter(kw => allText.includes(kw)) || []; + + return { + type: topType as ProblemType['type'], + confidence, + indicators, + }; + } + + getStrategyGuidance(problemType: string): string { + const strategies: Record = { + analysis: 'Break down the problem. What are the key components? What evidence supports each? Consider root causes.', + design: 'Define the architecture. What are the main components? How do they interact? What patterns apply?', + debugging: 'Identify the root cause. What is expected vs actual? What changed? Where does it fail? Check logs and traces.', + planning: 'Define milestones. What are deliverables? What dependencies? What is the timeline? Identify risks.', + optimization: 'Measure first. What is current performance? What are bottlenecks? What has most impact? Profile before optimizing.', + decision: 'Weigh alternatives. What are tradeoffs? What criteria matter most? What are risks of each option?', + creative: 'Explore possibilities. What are 3 different approaches? What would a novice try? An expert?', + refactoring: 'Start small. What code is hardest to change? What has most dependencies? Ensure tests pass after each change.', + testing: 'Write failing test first. What behavior must be preserved? What edge cases matter? Test boundaries.', + security: 'Think like an attacker. What could go wrong? Validate all input. Follow principle of least privilege.', + performance: 'Profile to find hotspots. Measure before and after. Focus on algorithmic improvements first.', + integration: 'Define contracts first. What is the interface? How handle failures? Version your APIs.', + migration: 'Plan for rollback. Migrate incrementally. Keep old and new in sync during transition.', + documentation: 'Explain the why, not just what. Include examples. Keep docs near code.', + research: 'Start with questions. What have others tried? What worked? What are tradeoffs?', + review: 'Focus on logic, not style. Look for edge cases. Verify error handling. Check security.', + deployment: 'Automate everything. Roll back easily. Deploy in small increments. Monitor aggressively.', + troubleshooting: 'Gather evidence first. What changed? When did it break? Reproduce consistently.', + architecture: 'Consider scalability and maintainability. Keep it simple. Define clear boundaries.', + api_design: 'Make it simple and consistent. Version early. Document with examples.', + data_modeling: 'Normalize for consistency. Denormalize for performance. Index wisely.', + ux_design: 'Know your user. Test with real people. Iterate based on feedback.', + technical_writing: 'Know your audience. Use simple words. Show, dont just tell.', + code_generation: 'Provide clear specs. Review generated code. Handle edge cases.', + unknown: 'Clarify the goal. What does success look like? What constraints exist? What have you tried?', + }; + return strategies[problemType] || strategies.unknown; + } + + getCanonicalPatterns(problemType: string): string[] { + const patterns: Record = { + analysis: [ + '1. Define the problem clearly', + '2. Break into components', + '3. Analyze each component', + '4. Synthesize findings', + ], + design: [ + '1. Understand requirements', + '2. Identify components', + '3. Define interfaces', + '4. Choose patterns', + '5. Validate with stakeholders', + ], + debugging: [ + '1. Reproduce the issue', + '2. Gather diagnostic info', + '3. Form hypothesis', + '4. Test hypothesis', + '5. Fix and verify', + ], + planning: [ + '1. Define the goal', + '2. Identify milestones', + '3. Assess dependencies', + '4. Allocate resources', + '5. Define timeline', + ], + optimization: [ + '1. Measure baseline', + '2. Identify bottleneck', + '3. Try simplest fix', + '4. Measure improvement', + '5. Repeat if needed', + ], + decision: [ + '1. Define criteria', + '2. List options', + '3. Evaluate each', + '4. Make decision', + '5. Plan execution', + ], + refactoring: [ + '1. Ensure tests exist', + '2. Make one small change', + '3. Run tests', + '4. Commit if passing', + '5. Repeat', + ], + testing: [ + '1. Identify behaviors', + '2. Write failing test', + '3. Make test pass', + '4. Refactor if needed', + '5. Add edge cases', + ], + security: [ + '1. Identify assets', + '2. Find threats', + '3. Assess risks', + '4. Implement controls', + '5. Test and verify', + ], + performance: [ + '1. Profile baseline', + '2. Find hotspots', + '3. Optimize', + '4. Measure improvement', + '5. Verify no regression', + ], + integration: [ + '1. Define contract', + '2. Implement interface', + '3. Test integration', + '4. Handle errors', + '5. Deploy and monitor', + ], + migration: [ + '1. Audit source', + '2. Plan migration', + '3. Implement', + '4. Validate data', + '5. Switchover', + ], + documentation: [ + '1. Identify audience', + '2. Outline structure', + '3. Write content', + '4. Review and edit', + '5. Publish and maintain', + ], + research: [ + '1. Define question', + '2. Gather sources', + '3. Analyze findings', + '4. Synthesize', + '5. Present conclusions', + ], + review: [ + '1. Understand context', + '2. Read thoroughly', + '3. Note issues', + '4. Categorize priority', + '5. Provide feedback', + ], + deployment: [ + '1. Prepare release', + '2. Deploy to staging', + '3. Run smoke tests', + '4. Deploy to prod', + '5. Monitor health', + ], + troubleshooting: [ + '1. Gather symptoms', + '2. Identify scope', + '3. Form hypothesis', + '4. Test fix', + '5. Document solution', + ], + architecture: [ + '1. Gather requirements', + '2. Design high-level', + '3. Detail components', + '4. Review design', + '5. Document decisions', + ], + api_design: [ + '1. Define use cases', + '2. Design endpoints', + '3. Define schema', + '4. Document', + '5. Version API', + ], + data_modeling: [ + '1. Define entities', + '2. Define relationships', + '3. Normalize schema', + '4. Add indexes', + '5. Document model', + ], + ux_design: [ + '1. Research users', + '2. Define flows', + '3. Create wireframes', + '4. Build prototype', + '5. Test with users', + ], + technical_writing: [ + '1. Know audience', + '2. Outline', + '3. Write draft', + '4. Review', + '5. Publish', + ], + code_generation: [ + '1. Define spec', + '2. Generate code', + '3. Review output', + '4. Refine', + '5. Test', + ], + creative: [ + '1. Explore broadly', + '2. Generate ideas', + '3. Combine concepts', + '4. Evaluate', + '5. Refine solution', + ], + unknown: [ + '1. Clarify goal', + '2. Explore context', + '3. Identify type', + '4. Apply approach', + '5. Validate', + ], + }; + return patterns[problemType] || []; + } + + getProblemTypeMetadata(problemType: string): { + phases: string[]; + successIndicators: string[]; + antiPatterns: string[]; + recommendedMode: 'fast' | 'expert' | 'deep'; + estimatedEffort: 'low' | 'medium' | 'high'; + } { + const metadata: Record = { + analysis: { + phases: ['Define scope', 'Gather information', 'Identify components', 'Analyze relationships', 'Synthesize findings'], + successIndicators: ['Clear breakdown', 'All components identified', 'Relationships understood', 'Root cause found'], + antiPatterns: ['Jumping to conclusions', 'Missing components', 'Ignoring evidence', 'Overcomplicating'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + design: { + phases: ['Requirements', 'Architecture', 'Component design', 'Interface design', 'Review'], + successIndicators: ['Scalable architecture', 'Clear interfaces', 'SOLID principles', 'Documented decisions'], + antiPatterns: ['Over-engineering', 'Premature optimization', 'Tight coupling', 'Missing error handling'], + recommendedMode: 'deep', + estimatedEffort: 'high', + }, + debugging: { + phases: ['Reproduce', 'Gather info', 'Form hypothesis', 'Test hypothesis', 'Fix', 'Verify'], + successIndicators: ['Reproduced consistently', 'Root cause identified', 'Fix works', 'No regression'], + antiPatterns: ['Guessing fix', 'Not reproducing', 'Breaking other things', 'Not verifying'], + recommendedMode: 'fast', + estimatedEffort: 'low', + }, + planning: { + phases: ['Define goal', 'Identify tasks', 'Estimate effort', 'Sequence tasks', 'Define timeline'], + successIndicators: ['Clear milestones', 'Realistic timeline', 'Risks identified', 'Dependencies mapped'], + antiPatterns: ['Unrealistic estimates', 'Missing tasks', 'No buffer', 'Unclear goals'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + optimization: { + phases: ['Measure baseline', 'Identify bottleneck', 'Optimize', 'Measure again', 'Verify'], + successIndicators: ['Measured improvement', 'No regression', 'Maintainable', 'Worth the cost'], + antiPatterns: ['Premature optimization', 'Not measuring', 'Breaking functionality', 'Over-optimizing'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + decision: { + phases: ['Define criteria', 'List options', 'Evaluate', 'Make choice', 'Plan execution'], + successIndicators: ['Clear criteria', 'All options considered', 'Tradeoffs understood', 'Commitment to choice'], + antiPatterns: ['Analysis paralysis', 'Ignoring tradeoffs', 'No clear criteria', 'Reversing frequently'], + recommendedMode: 'fast', + estimatedEffort: 'low', + }, + creative: { + phases: ['Explore', 'Generate ideas', 'Evaluate', 'Select', 'Refine'], + successIndicators: ['Novel solutions', 'Multiple options', 'Feasible approach', 'Stakeholder buy-in'], + antiPatterns: ['Self-censoring', 'First idea is best', 'Ignoring constraints', 'Perfectionism'], + recommendedMode: 'deep', + estimatedEffort: 'high', + }, + refactoring: { + phases: ['Ensure tests', 'Make small change', 'Test', 'Commit', 'Repeat'], + successIndicators: ['Tests pass', 'Cleaner code', 'No regression', 'Intent clearer'], + antiPatterns: ['Big changes', 'No tests', 'Breaking builds', 'Mixing refactor with new features'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + testing: { + phases: ['Identify behaviors', 'Write test', 'Watch fail', 'Make pass', 'Refactor'], + successIndicators: ['Good coverage', 'Meaningful assertions', 'Fast tests', 'Maintainable'], + antiPatterns: ['No failing test first', 'Testing implementation', 'Fragile tests', 'Slow tests'], + recommendedMode: 'fast', + estimatedEffort: 'medium', + }, + security: { + phases: ['Identify assets', 'Find threats', 'Assess risk', 'Implement controls', 'Verify'], + successIndicators: ['No vulnerabilities', 'Defense in depth', 'Compliance', 'Security tested'], + antiPatterns: ['Security after', 'Ignoring threats', 'Single point of failure', 'Hardcoded secrets'], + recommendedMode: 'deep', + estimatedEffort: 'high', + }, + performance: { + phases: ['Profile', 'Identify hotspot', 'Optimize', 'Measure', 'Verify'], + successIndicators: ['Measured gains', 'Scalability improved', 'No regression', 'Worth the complexity'], + antiPatterns: ['Guessing', 'Not profiling', 'Breaking correctness', 'Premature optimization'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + integration: { + phases: ['Define contract', 'Implement', 'Test', 'Deploy', 'Monitor'], + successIndicators: ['Works end-to-end', 'Error handling', 'Documented', 'Monitored'], + antiPatterns: ['No contract', 'Tight coupling', 'Ignoring failures', 'No rollback'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + migration: { + phases: ['Audit source', 'Plan migration', 'Implement', 'Validate', 'Switchover'], + successIndicators: ['Data intact', 'Zero downtime', 'Rollback plan', 'Validated'], + antiPatterns: ['No rollback', 'Data loss', 'Long downtime', 'Not testing'], + recommendedMode: 'deep', + estimatedEffort: 'high', + }, + documentation: { + phases: ['Identify audience', 'Outline', 'Write', 'Review', 'Publish'], + successIndicators: ['Clear', 'Accurate', 'Complete', 'Maintained'], + antiPatterns: ['Outdated', 'Missing', 'Too long', 'Wrong audience'], + recommendedMode: 'fast', + estimatedEffort: 'low', + }, + research: { + phases: ['Define question', 'Gather sources', 'Analyze', 'Synthesize', 'Present'], + successIndicators: ['Clear answer', 'Sources cited', 'Tradeoffs understood', 'Actionable'], + antiPatterns: ['No clear question', 'Single source', 'Ignoring evidence', 'Overcomplicating'], + recommendedMode: 'deep', + estimatedEffort: 'high', + }, + review: { + phases: ['Understand context', 'Read code', 'Note issues', 'Categorize', 'Report'], + successIndicators: ['Constructive', 'Specific', 'Balanced', 'Actionable'], + antiPatterns: ['Personal', 'Vague', 'Nitpicking', 'Ignoring context'], + recommendedMode: 'fast', + estimatedEffort: 'low', + }, + deployment: { + phases: ['Prepare', 'Deploy', 'Verify', 'Monitor', 'Rollback if needed'], + successIndicators: ['Works in prod', 'Rollback ready', 'Monitored', 'No incidents'], + antiPatterns: ['No testing', 'No rollback', 'Not monitoring', 'Big bang'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + troubleshooting: { + phases: ['Gather symptoms', 'Identify cause', 'Fix', 'Verify', 'Prevent'], + successIndicators: ['Root cause fixed', 'No recurrence', 'Documented', 'Automated'], + antiPatterns: ['Treating symptoms', 'Not gathering data', 'Not documenting', 'Quick fix only'], + recommendedMode: 'fast', + estimatedEffort: 'low', + }, + architecture: { + phases: ['Requirements', 'High-level design', 'Detailed design', 'Review', 'Validate'], + successIndicators: ['Scalable', 'Maintainable', 'Secure', 'Documented'], + antiPatterns: ['Over-engineering', 'Single point of failure', 'Tight coupling', 'No consideration for scale'], + recommendedMode: 'deep', + estimatedEffort: 'high', + }, + api_design: { + phases: ['Define use cases', 'Design endpoints', 'Define schema', 'Document', 'Version'], + successIndicators: ['Intuitive', 'Consistent', 'Documented', 'Versioned'], + antiPatterns: ['Breaking changes', 'Inconsistent', 'Poor naming', 'No documentation'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + data_modeling: { + phases: ['Requirements', 'Conceptual model', 'Logical model', 'Physical model', 'Optimize'], + successIndicators: ['Normalized', 'Indexed', 'Documented', 'Performant'], + antiPatterns: ['Denormalized too early', 'Missing relationships', 'No indexes', 'Not documented'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + ux_design: { + phases: ['Research', 'Define user flow', 'Wireframe', 'Prototype', 'Test'], + successIndicators: ['User-friendly', 'Accessible', 'Consistent', 'Tested with users'], + antiPatterns: ['No research', 'Complex', 'Inconsistent', 'Not tested'], + recommendedMode: 'deep', + estimatedEffort: 'high', + }, + technical_writing: { + phases: ['Identify audience', 'Outline', 'Write', 'Review', 'Publish'], + successIndicators: ['Clear', 'Concise', 'Complete', 'Up-to-date'], + antiPatterns: ['Jargon', 'Outdated', 'Incomplete', 'Wrong level'], + recommendedMode: 'fast', + estimatedEffort: 'low', + }, + code_generation: { + phases: ['Define spec', 'Generate', 'Review', 'Refine', 'Test'], + successIndicators: ['Correct', 'Clean', 'Documented', 'Tested'], + antiPatterns: ['No review', 'Not testing', 'Wrong assumptions', 'Not understanding generated code'], + recommendedMode: 'expert', + estimatedEffort: 'medium', + }, + unknown: { + phases: ['Clarify', 'Explore', 'Define', 'Approach', 'Solve'], + successIndicators: ['Clear goal', 'Known approach', 'Progress made', 'Learning documented'], + antiPatterns: ['No clarity', 'Random exploration', 'No progress', 'Not learning'], + recommendedMode: 'fast', + estimatedEffort: 'low', + }, + }; + + return metadata[problemType] || metadata.unknown; + } + + assessCompleteness(thoughts: ThoughtData[], problemType: string): { + completeness: number; + phase: string; + suggestions: string[]; + } { + if (thoughts.length < 2) { + return { completeness: 0.1, phase: 'starting', suggestions: ['Define your goal clearly'] }; + } + + const metadata = this.getProblemTypeMetadata(problemType); + const lastThought = thoughts[thoughts.length - 1]?.thought.toLowerCase() || ''; + const allText = thoughts.map(t => t.thought).join(' ').toLowerCase(); + + const completionMarkers = [ + 'con', 'therefore', 'thusclusion', 'summary', 'final', 'decision made', + 'implemented', 'resolved', 'fixed', 'completed', 'done', 'finished', + 'recommend', 'suggest', 'next step', 'action item', + ]; + const hasConclusion = completionMarkers.some(m => lastThought.includes(m)); + + const questionMarkers = allText.match(/\?/g) || []; + const openQuestions = questionMarkers.length; + + const phaseIndex = Math.min( + Math.floor((thoughts.length / 10) * metadata.phases.length), + metadata.phases.length - 1, + ); + const phase = metadata.phases[phaseIndex] || 'starting'; + + let completeness = Math.min(0.95, thoughts.length / 10); + if (hasConclusion) completeness = Math.min(1.0, completeness + 0.1); + completeness -= openQuestions * 0.05; + + const suggestions: string[] = []; + if (openQuestions > 2) suggestions.push('Answer remaining questions before concluding'); + if (!hasConclusion && thoughts.length > 5) suggestions.push('Consider wrapping up with a conclusion'); + if (thoughts.length < 5) suggestions.push('May need more exploration'); + if (phase === metadata.phases[metadata.phases.length - 1]) { + suggestions.push('You appear to be in the final phase - ready to conclude?'); + } + + return { completeness: Math.max(0, Math.min(1, completeness)), phase, suggestions }; + } + + detectReasoningStyle(thoughts: ThoughtData[]): { style: string; confidence: number } { + if (thoughts.length === 0) { + return { style: 'deductive', confidence: 0 }; + } + + const allText = thoughts.map(t => t.thought.toLowerCase()).join(' '); + + const styleIndicators = { + deductive: ['therefore', 'thus', 'hence', 'consequently', 'it follows', 'must be', 'all', 'every', 'if then'], + inductive: ['suggests', 'appears', 'seems', 'likely', 'probably', 'often', 'sometimes', 'typically', 'in general'], + abductive: ['probably', 'most likely', 'best explanation', 'likely cause', 'makes sense', 'would explain'], + analogical: ['similar to', 'like', 'analogous', 'compared to', 'just as', 'similarly', 'in the same way'], + recursive: ['repeat', 'again', 'iterate', 'loop', 'same problem', 'self-similar', 'fractal'], + systems: ['component', 'interaction', 'feedback', 'loop', 'ecosystem', 'network', 'relationship', 'dependency'], + }; + + const scores: Record = {}; + for (const [style, keywords] of Object.entries(styleIndicators)) { + scores[style] = keywords.filter(kw => allText.includes(kw)).length; + } + + const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]); + const [topStyle, topScore] = entries[0]; + + return { + style: topScore > 0 ? topStyle : 'deductive', + confidence: topScore > 0 ? Math.min(0.9, 0.3 + topScore * 0.2) : 0.3, + }; + } + + computeConfidenceTrend(history: number[]): 'improving' | 'declining' | 'stable' | 'insufficient' { + if (history.length < 3) return 'insufficient'; + const recent = history.slice(-3); + const diff1 = recent[1] - recent[0]; + const diff2 = recent[2] - recent[1]; + const avgDiff = (diff1 + diff2) / 2; + if (avgDiff > 0.1) return 'improving'; + if (avgDiff < -0.1) return 'declining'; + return 'stable'; + } + + getActivePerspectivePrompt(suggestions: PerspectiveSuggestion[]): string | null { + if (suggestions.length === 0) return null; + const primary = suggestions[0]; + return `[${primary.perspective.toUpperCase()} VIEWPOINT] ${primary.description}`; + } + + findSimilarPatterns(currentProblem: string, patternDatabase: PatternMatch[] = []): PatternMatch[] { + if (patternDatabase.length === 0) { + return []; + } + + const currentTokens = this.tokenize(currentProblem); + const scored = patternDatabase.map(pattern => ({ + ...pattern, + similarity: this.jaccardSimilarity(currentTokens, this.tokenize(pattern.pattern)), + })); + + return scored + .filter(p => p.similarity > 0.2) + .sort((a, b) => b.similarity - a.similarity) + .slice(0, 3); + } + + private evaluationHistory: Array<{ + problemType: string; + strategy: string; + perspective: string; + value: number; + }> = []; + + recordEvaluation( + problemType: string, + strategy: string, + perspective: string, + value: number, + ): void { + this.evaluationHistory.push({ problemType, strategy, perspective, value }); + if (this.evaluationHistory.length > 100) { + this.evaluationHistory = this.evaluationHistory.slice(-100); + } + } + + private computeAverageScores( + relevant: Array<{ strategy: string; perspective: string; value: number }>, + ): { strategy: Record; perspective: Record } { + const strategyScores: Record = {}; + const perspectiveScores: Record = {}; + + for (const e of relevant) { + if (!strategyScores[e.strategy]) strategyScores[e.strategy] = { total: 0, count: 0 }; + strategyScores[e.strategy].total += e.value; + strategyScores[e.strategy].count++; + + if (!perspectiveScores[e.perspective]) perspectiveScores[e.perspective] = { total: 0, count: 0 }; + perspectiveScores[e.perspective].total += e.value; + perspectiveScores[e.perspective].count++; + } + + const avg = (s: { total: number; count: number }) => s.total / s.count; + + return { + strategy: Object.fromEntries( + Object.entries(strategyScores).map(([k, v]) => [k, avg(v)]), + ), + perspective: Object.fromEntries( + Object.entries(perspectiveScores).map(([k, v]) => [k, avg(v)]), + ), + }; + } + + getAdaptiveStrategy(problemType: string): { + recommendedStrategy: string | null; + recommendedPerspective: string | null; + reasoning: string; + } { + const relevant = this.evaluationHistory.filter(e => e.problemType === problemType); + if (relevant.length < 3) { + return { recommendedStrategy: null, recommendedPerspective: null, reasoning: 'Insufficient evaluation history.' }; + } + + const scores = this.computeAverageScores(relevant); + const bestStrat = Object.entries(scores.strategy).sort((a, b) => b[1] - a[1])[0]; + const bestPersp = Object.entries(scores.perspective).sort((a, b) => b[1] - a[1])[0]; + + return { + recommendedStrategy: bestStrat?.[0] ?? null, + recommendedPerspective: bestPersp?.[0] ?? null, + reasoning: `From ${relevant.length} evals: "${bestStrat?.[0]}" (${bestStrat?.[1]?.toFixed(2)}), "${bestPersp?.[0]}" (${bestPersp?.[1]?.toFixed(2)}) best.`, + }; + } + + analyzeReasoningGaps(thoughts: ThoughtData[]): { + hasGaps: boolean; + gaps: Array<{ thoughtNumber: number; issue: string }>; + } { + const gaps: Array<{ thoughtNumber: number; issue: string }> = []; + const conclusionIndices: number[] = []; + + for (let i = 0; i < thoughts.length; i++) { + const t = thoughts[i].thought.toLowerCase(); + if (/\b(therefore|thus|so|conclude|conclusion|therefore|hence|accordingly)\b/.test(t)) { + conclusionIndices.push(i); + } + } + + for (const idx of conclusionIndices) { + if (idx < 2) { + gaps.push({ thoughtNumber: thoughts[idx].thoughtNumber, issue: 'Premature conclusion - too few prior thoughts' }); + continue; + } + + const priorThoughts = thoughts.slice(0, idx); + const hasEvidence = priorThoughts.some(t => + /\b(because|since|evidence|shown|demonstrated|proved|however|although|but)\b/.test(t.thought.toLowerCase()), + ); + if (!hasEvidence) { + gaps.push({ thoughtNumber: thoughts[idx].thoughtNumber, issue: 'Conclusion lacks supporting evidence' }); + } + } + + return { hasGaps: gaps.length > 0, gaps }; + } + + generateReflectionPrompt( + phase: 'exploring' | 'evaluating' | 'converging' | 'concluded', + confidenceTrend: string, + circularity: boolean, + confidenceScore: number, + ): string | null { + if (phase !== 'converging' && phase !== 'concluded') return null; + + const prompts: string[] = []; + + if (circularity) { + prompts.push('What assumption is causing you to loop back to the same ideas?'); + } + + if (confidenceTrend === 'declining') { + prompts.push('Your confidence is declining. What evidence contradicts your current path?'); + } + + if (confidenceTrend === 'improving' && confidenceScore > 0.8) { + prompts.push('High confidence detected. What might you be missing? Consider a skeptic\'s view.'); + } + + if (phase === 'concluded') { + prompts.push('What is the single strongest counterargument to your conclusion?'); + prompts.push('If you were wrong, what would prove it?'); + } + + return prompts.length > 0 ? prompts[Math.floor(Math.random() * prompts.length)] : null; + } + + analyzeComplexity(thoughts: ThoughtData[]): { + complexity: 'simple' | 'moderate' | 'complex'; + reasoning: string; + recommendedMode: 'fast' | 'expert' | 'deep'; + } { + if (thoughts.length < 2) { + return { complexity: 'simple', reasoning: 'Insufficient thoughts for analysis', recommendedMode: 'fast' }; + } + + const allText = thoughts.map(t => t.thought).join(' ').toLowerCase(); + const patterns = [ + /\b(code|algorithm|function|implement|optimize|debug|error|bug|system|architecture|api|database)\b/gi, + /\b(analyze|compare|evaluate|assess|determine|calculate|measure|model|simulate)\b/gi, + /\b(plan|strategy|roadmap|approach|method|technique|process|workflow)\b/gi, + /\b(invent|design|create|imagine|explore|discover|innovate|brainstorm)\b/gi, + /\b(decide|choose|select|option|alternative|tradeoff|priority)\b/gi, + ]; + + const totalIndicators = patterns.reduce((sum, p) => sum + (allText.match(p) || []).length, 0); + const hasMultipleCategories = patterns.filter(p => (allText.match(p) || []).length > 0).length; + const hasTradeoffs = /\b(however|but|although|tradeoff|alternative|versus|vs)\b/i.test(allText); + const complexityScore = Math.min(totalIndicators / 10, 3) + hasMultipleCategories * 0.5 + (hasTradeoffs ? 1 : 0); + + const result = complexityScore >= 3 + ? { complexity: 'complex' as const, recommendedMode: 'deep' as const } + : complexityScore >= 1.5 + ? { complexity: 'moderate' as const, recommendedMode: 'expert' as const } + : { complexity: 'simple' as const, recommendedMode: 'fast' as const }; + + return { ...result, reasoning: `Score: ${complexityScore.toFixed(1)}, indicators: ${totalIndicators}` }; + } + + private crossBranchPatterns: Map> = new Map(); + + recordCrossBranchPattern( + problemKey: string, + problemType: string, + solution: string, + score: number, + ): void { + const existing = this.crossBranchPatterns.get(problemKey) || []; + existing.push({ problemType, solution, score }); + if (existing.length > 20) existing.shift(); + this.crossBranchPatterns.set(problemKey, existing); + } + + findCrossBranchPattern(problemKey: string): Array<{ solution: string; avgScore: number }> { + const patterns = this.crossBranchPatterns.get(problemKey); + if (!patterns || patterns.length === 0) return []; + + const bySolution: Record = {}; + for (const p of patterns) { + if (!bySolution[p.solution]) bySolution[p.solution] = { total: 0, count: 0 }; + bySolution[p.solution].total += p.score; + bySolution[p.solution].count++; + } + + return Object.entries(bySolution) + .map(([solution, { total, count }]) => ({ solution, avgScore: total / count })) + .sort((a, b) => b.avgScore - a.avgScore) + .slice(0, 3); + } + + getProblemTypeRecommendations(currentType: string): { + follows: string[]; + precedes: string[]; + related: string[]; + } { + const workflow: Record = { + debugging: { + follows: ['refactoring', 'testing'], + precedes: [], + related: ['troubleshooting', 'performance', 'security'], + }, + refactoring: { + follows: ['testing', 'documentation'], + precedes: ['debugging'], + related: ['optimization', 'code_generation'], + }, + testing: { + follows: ['deployment', 'documentation'], + precedes: ['refactoring', 'debugging'], + related: ['integration', 'code_generation'], + }, + security: { + follows: ['deployment', 'documentation'], + precedes: [], + related: ['review', 'architecture'], + }, + performance: { + follows: ['deployment', 'testing'], + precedes: [], + related: ['optimization', 'architecture'], + }, + architecture: { + follows: ['api_design', 'data_modeling', 'integration'], + precedes: [], + related: ['design', 'devops'], + }, + api_design: { + follows: ['code_generation', 'integration', 'documentation'], + precedes: ['architecture'], + related: ['backend', 'mobile'], + }, + data_modeling: { + follows: ['migration', 'integration'], + precedes: ['architecture'], + related: ['backend', 'data'], + }, + planning: { + follows: ['design', 'architecture', 'deployment'], + precedes: [], + related: ['decision', 'research'], + }, + research: { + follows: ['planning', 'decision', 'design'], + precedes: [], + related: ['analysis', 'architecture'], + }, + migration: { + follows: ['deployment', 'testing'], + precedes: ['data_modeling'], + related: ['integration', 'devops'], + }, + deployment: { + follows: [], + precedes: ['testing', 'security', 'migration'], + related: ['devops', 'monitoring'], + }, + design: { + follows: ['architecture', 'api_design', 'ux_design'], + precedes: ['planning', 'research'], + related: ['creative', 'code_generation'], + }, + documentation: { + follows: [], + precedes: ['testing', 'refactoring', 'deployment'], + related: ['technical_writing', 'code_generation'], + }, + review: { + follows: ['refactoring', 'testing'], + precedes: [], + related: ['security', 'documentation'], + }, + optimization: { + follows: ['testing', 'deployment'], + precedes: ['performance'], + related: ['refactoring', 'architecture'], + }, + decision: { + follows: ['planning', 'design'], + precedes: ['research'], + related: ['planning', 'architecture'], + }, + creative: { + follows: ['design', 'code_generation'], + precedes: [], + related: ['ux_design', 'architecture'], + }, + integration: { + follows: ['deployment', 'testing'], + precedes: ['api_design', 'data_modeling'], + related: ['devops', 'migration'], + }, + troubleshooting: { + follows: ['debugging', 'fixing'], + precedes: [], + related: ['debugging', 'performance'], + }, + unknown: { + follows: ['analysis', 'research'], + precedes: [], + related: [], + }, + }; + + return workflow[currentType] || { follows: [], precedes: [], related: [] }; + } + + detectInsightType(thoughts: ThoughtData[]): { type: string; confidence: number } { + if (thoughts.length < 2) { + return { type: 'question_reframing', confidence: 0.1 }; + } + + const allText = thoughts.map(t => t.thought.toLowerCase()).join(' '); + + const insightIndicators = { + breakthrough: ['completely changed', 'realized', 'suddenly understood', 'the key was', 'game changer', 'paradigm shift'], + connection: ['linked to', 'connected to', 'similar to', 'like', 'relates to', 'brings together'], + pivot: ['instead', 'change direction', 'switch to', 'rather than', 'new approach', 'different strategy'], + validation: ['confirmed', 'verified', 'validated', 'proved correct', 'as expected', 'checked'], + dead_end: ['wont work', 'doesnt work', 'failed', 'stuck', 'no progress', 'not possible', 'impractical'], + simplification: ['simpler', 'easier way', 'overcomplicated', 'actually just', 'in other words'], + pattern_recognition: ['same pattern', 'like before', 'reminds me of', 'similar problem', 'seen this before'], + question_reframing: ['better question', 'reframe', 'what if', 'instead ask', 'wrong question', 'real issue'], + }; + + const scores: Record = {}; + for (const [insight, keywords] of Object.entries(insightIndicators)) { + scores[insight] = keywords.filter(kw => allText.includes(kw)).length; + } + + const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]); + const [topInsight, topScore] = entries[0]; + + return { + type: topScore > 0 ? topInsight : 'question_reframing', + confidence: topScore > 0 ? Math.min(0.9, 0.3 + topScore * 0.2) : 0.2, + }; + } + + detectDomain(thoughts: ThoughtData[]): { domain: string; confidence: number } { + if (thoughts.length === 0) { + return { domain: 'general', confidence: 0 }; + } + + const allText = thoughts.map(t => t.thought.toLowerCase()).join(' '); + + const domainIndicators = { + reasoning: ['therefore', 'thus', 'hence', 'consequently', 'logically', 'implies', 'because', 'reason', 'argue', 'premise', 'conclusion', 'deduce'], + decision: ['choose', 'option', 'alternative', 'decision', 'select', 'pick', 'commit', 'risk', 'benefit', 'tradeoff', 'weigh'], + learning: ['learn', 'understand', 'discover', 'acquire', 'master', 'practice', 'study', 'experience', 'knowledge', 'skill'], + memory: ['remember', 'recall', 'forget', 'remind', 'stored', 'retrieve', 'encode', 'recognize', 'familiar', 'past'], + attention: ['focus', 'concentrate', 'distract', 'attention', 'notice', 'observe', 'aware', 'filter', 'ignore', 'miss'], + perception: ['see', 'perceive', 'observe', 'interpret', 'sense', 'appear', 'seem', 'look', 'sound', 'feel'], + language: ['word', 'sentence', 'describe', 'explain', 'communicate', 'express', 'meaning', 'text', 'write', 'read', 'speak'], + emotion: ['feel', 'emotion', 'happy', 'sad', 'fear', 'anger', 'anxious', 'frustrated', 'excited', 'worried', 'hope'], + metacognition: ['think about', 'meta', 'aware', 'reflect', 'self', 'monitor', 'evaluate', 'understand myself'], + creativity: ['imagine', 'novel', 'creative', 'invent', 'generate', 'idea', 'brainstorm', 'innovate', 'original', 'new approach'], + problem_solving: ['solve', 'problem', 'solution', 'fix', 'resolve', 'approach', 'strategy', 'method', 'way', 'how to'], + social: ['others', 'people', 'team', 'collaborate', 'share', 'communicate', 'together', 'group', 'society', 'relationship'], + }; + + const scores: Record = {}; + for (const [domain, keywords] of Object.entries(domainIndicators)) { + scores[domain] = keywords.filter(kw => allText.includes(kw)).length; + } + + const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]); + const [topDomain, topScore] = entries[0]; + + return { + domain: topScore > 0 ? topDomain : 'general', + confidence: topScore > 0 ? Math.min(0.9, 0.3 + topScore * 0.15) : 0.2, + }; + } + + detectCognitiveProcess(thoughts: ThoughtData[]): { process: string; confidence: number } { + if (thoughts.length === 0) { + return { process: 'understanding', confidence: 0 }; + } + + const allText = thoughts.map(t => t.thought.toLowerCase()).join(' '); + + const processIndicators = { + understanding: ['understand', 'sense', 'grasp', 'comprehend', 'make sense', 'clear', 'meaning', 'interpret'], + creating: ['create', 'generate', 'invent', 'design', 'build', 'make', 'new', 'synthesize', 'produce'], + deciding: ['choose', 'decide', 'select', 'pick', 'option', 'alternative', 'commit', 'choice'], + remembering: ['remember', 'recall', 'memory', 'past', 'before', 'previously', 'familiar', 'stored'], + explaining: ['because', 'explain', 'reason', 'cause', 'effect', 'mechanism', 'how', 'why'], + predicting: ['predict', 'future', 'will', 'expect', 'forecast', 'anticipate', 'likely', 'probably'], + evaluating: ['evaluate', 'assess', 'judge', 'quality', 'worth', 'better', 'best', 'compare', 'value'], + planning: ['plan', 'future', 'will', 'next', 'then', 'step', 'sequence', 'roadmap', 'milestone'], + communicating: ['tell', 'explain', 'share', 'describe', 'say', 'write', 'express', 'communicate'], + transforming: ['change', 'convert', 'transform', 'convert', 'adapt', 'modify', 'convert', 'translate'], + }; + + const scores: Record = {}; + for (const [proc, keywords] of Object.entries(processIndicators)) { + scores[proc] = keywords.filter(kw => allText.includes(kw)).length; + } + + const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]); + const [topProc, topScore] = entries[0]; + + return { + process: topScore > 0 ? topProc : 'understanding', + confidence: topScore > 0 ? Math.min(0.9, 0.3 + topScore * 0.2) : 0.2, + }; + } + + detectMetaState(thoughts: ThoughtData[]): { state: string; severity: number } { + if (thoughts.length < 2) { + return { state: 'clarity', severity: 0 }; + } + + const allText = thoughts.map(t => t.thought.toLowerCase()).join(' '); + const lastThought = thoughts[thoughts.length - 1]?.thought.toLowerCase() || ''; + const prevThought = thoughts[thoughts.length - 2]?.thought.toLowerCase() || ''; + + const similarity = this.jaccardSimilarity( + this.tokenize(lastThought), + this.tokenize(prevThought), + ); + + const metaIndicators = { + clarity: ['clear', 'confused', 'unclear', 'understand', 'confusing', 'vague', 'precise'], + certainty: ['sure', 'certain', 'doubt', 'probably', 'maybe', 'confident', 'unsure'], + progress: ['progress', 'forward', 'advance', 'stuck', '原地踏步', 'no progress', 'moving'], + blockage: ['stuck', 'block', 'cannot', 'blocked', 'stopped', 'halt', 'barrier'], + scope_narrow: ['focus', 'specific', 'narrow', 'detail', 'granular', 'limited'], + scope_broad: ['overall', 'big picture', 'general', 'broad', 'abstract', 'summary'], + bias: ['assume', 'probably', 'likely', 'always', 'never', 'bias', 'blind spot'], + momentum_gaining: ['progress', 'moving forward', 'gaining', 'building', 'more', 'increasing'], + momentum_losing: ['stuck', 'losing', 'less', 'decreasing', 'harder', 'slowing'], + stuck: ['stuck', 'cannot proceed', 'no idea', 'blocked', 'halted', 'dead end'], + }; + + const scores: Record = {}; + for (const [state, keywords] of Object.entries(metaIndicators)) { + scores[state] = keywords.filter(kw => allText.includes(kw)).length; + } + + if (similarity > 0.7) { + scores['stuck'] += 2; + scores['blockage'] += 1; + } + + const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]); + const [topState, topScore] = entries[0]; + + return { + state: topScore > 0 ? topState : 'progress', + severity: Math.min(1, topScore / 3), + }; + } +} + +export const metacognition = new Metacognition(); diff --git a/src/sequentialthinking/metrics.ts b/src/sequentialthinking/metrics.ts new file mode 100644 index 0000000000..c99127dae4 --- /dev/null +++ b/src/sequentialthinking/metrics.ts @@ -0,0 +1,129 @@ +import type { MetricsCollector, ThoughtData, RequestMetrics, ThoughtMetrics, SystemMetrics, ThoughtStorage } from './interfaces.js'; +import { CircularBuffer } from './circular-buffer.js'; +import type { SessionTracker } from './session-tracker.js'; +import { RATE_LIMIT_WINDOW_MS } from './config.js'; + +export class BasicMetricsCollector implements MetricsCollector { + private requestMetrics: RequestMetrics = { + totalRequests: 0, + successfulRequests: 0, + failedRequests: 0, + averageResponseTime: 0, + lastRequestTime: null, + requestsPerMinute: 0, + }; + + private thoughtMetrics: ThoughtMetrics = { + totalThoughts: 0, + averageThoughtLength: 0, + thoughtsPerMinute: 0, + revisionCount: 0, + branchCount: 0, + activeSessions: 0, + }; + + private readonly responseTimes = new CircularBuffer(100); + private readonly requestTimestamps = new CircularBuffer(1000); + private readonly thoughtTimestamps = new CircularBuffer(1000); + private readonly sessionTracker: SessionTracker; + private readonly storage: ThoughtStorage; + + constructor(sessionTracker: SessionTracker, storage: ThoughtStorage) { + this.sessionTracker = sessionTracker; + this.storage = storage; + } + + recordRequest(duration: number, success: boolean): void { + const now = Date.now(); + + this.requestMetrics.totalRequests++; + this.requestMetrics.lastRequestTime = new Date(now); + + if (success) { + this.requestMetrics.successfulRequests++; + } else { + this.requestMetrics.failedRequests++; + } + + // Update response time metrics using circular buffer + this.responseTimes.add(duration); + + const allTimes = this.responseTimes.getAll(); + this.requestMetrics.averageResponseTime = + allTimes.reduce((sum, time) => sum + time, 0) / allTimes.length; + + // Update requests per minute + this.requestTimestamps.add(now); + const cutoff = now - RATE_LIMIT_WINDOW_MS; + this.requestMetrics.requestsPerMinute = + this.requestTimestamps.getAll().filter(ts => ts > cutoff).length; + } + + recordThoughtProcessed(thought: ThoughtData): void { + const now = Date.now(); + + this.thoughtMetrics.totalThoughts++; + this.thoughtTimestamps.add(now); + + // Update average thought length + const prevTotal = + this.thoughtMetrics.averageThoughtLength * + (this.thoughtMetrics.totalThoughts - 1); + const totalLength = prevTotal + thought.thought.length; + this.thoughtMetrics.averageThoughtLength = + Math.round(totalLength / this.thoughtMetrics.totalThoughts); + + // Track revisions + if (thought.isRevision) { + this.thoughtMetrics.revisionCount++; + } + + // Branch count is queried from storage (single source of truth) + this.thoughtMetrics.branchCount = this.storage.getBranches().length; + + // Update thoughts per minute + const cutoff = now - RATE_LIMIT_WINDOW_MS; + this.thoughtMetrics.thoughtsPerMinute = + this.thoughtTimestamps.getAll().filter(ts => ts > cutoff).length; + + // Session tracking now handled by unified SessionTracker + this.thoughtMetrics.activeSessions = + this.sessionTracker.getActiveSessionCount(); + } + + getMetrics(): { + requests: RequestMetrics; + thoughts: ThoughtMetrics; + system: SystemMetrics; + } { + return { + requests: { ...this.requestMetrics }, + thoughts: { ...this.thoughtMetrics }, + system: this.getSystemMetrics(), + }; + } + + private getSystemMetrics(): SystemMetrics { + return { + memoryUsage: process.memoryUsage(), + cpuUsage: process.cpuUsage(), + uptime: process.uptime(), + timestamp: new Date(), + }; + } + + destroy(): void { + this.responseTimes.clear(); + this.requestTimestamps.clear(); + this.thoughtTimestamps.clear(); + this.requestMetrics = { + totalRequests: 0, successfulRequests: 0, failedRequests: 0, + averageResponseTime: 0, lastRequestTime: null, requestsPerMinute: 0, + }; + this.thoughtMetrics = { + totalThoughts: 0, averageThoughtLength: 0, thoughtsPerMinute: 0, + revisionCount: 0, branchCount: 0, activeSessions: 0, + }; + } + +} diff --git a/src/sequentialthinking/package.json b/src/sequentialthinking/package.json index da24ad3e9e..45830623dd 100644 --- a/src/sequentialthinking/package.json +++ b/src/sequentialthinking/package.json @@ -1,6 +1,6 @@ { "name": "@modelcontextprotocol/server-sequential-thinking", - "version": "0.6.2", + "version": "0.8.0", "description": "MCP server for sequential thinking and problem solving", "license": "SEE LICENSE IN LICENSE", "mcpName": "io.github.modelcontextprotocol/server-sequential-thinking", @@ -9,7 +9,8 @@ "bugs": "https://github.com/modelcontextprotocol/servers/issues", "repository": { "type": "git", - "url": "https://github.com/modelcontextprotocol/servers.git" + "url": "https://github.com/modelcontextprotocol/servers.git", + "directory": "src/sequentialthinking" }, "type": "module", "bin": { @@ -20,21 +21,56 @@ ], "scripts": { "build": "tsc && shx chmod +x dist/*.js", - "prepare": "npm run build", + "prepare": "husky", "watch": "tsc --watch", - "test": "vitest run --coverage" + "test": "vitest run", + "test:unit": "vitest run __tests__/unit", + "test:integration": "vitest run __tests__/integration", + "test:e2e": "vitest run __tests__/e2e", + "test:all": "npm run test:unit && npm run test:integration && npm run test:e2e", + "test:coverage": "vitest run --coverage", + "lint": "eslint --config eslint.config.mjs \"*.ts\"", + "lint:fix": "eslint --config eslint.config.mjs \"*.ts\" --fix", + "lint:docker": "hadolint Dockerfile", + "type-check": "tsc --noEmit", + "format": "node -e \"const fs=require('fs');const p=require('path');['.','__tests__'].forEach(d=>{try{fs.readdirSync(d).filter(f=>f.endsWith('.ts')).forEach(f=>{require('child_process').execSync('prettier --write '+p.join(d,f),{stdio:'inherit'})})}catch(e){}})\"", + "format:check": "node -e \"const fs=require('fs');const p=require('path');['.','__tests__'].forEach(d=>{try{fs.readdirSync(d).filter(f=>f.endsWith('.ts')).forEach(f=>{require('child_process').execSync('prettier --check '+p.join(d,f),{stdio:'inherit'})})}catch(e){}})\"", + "check": "npm run type-check && npm run lint", + "check:all": "npm run check && npm run lint:docker && npm run test:all", + "docs": "typedoc", + "update:deps": "npm update --save && npm install", + "clean": "rm -rf dist coverage", + "rebuild": "npm run clean && npm run build", + "docker:build": "docker build -t sequential-thinking .", + "docker:run": "docker run --rm sequential-thinking", + "docker:size": "docker build -t sequential-thinking . && docker images sequential-thinking", + "prepublishOnly": "npm run check && npm run test:all", + "release": "release-it --ci", + "postinstall": "node scripts/sync-version.js" }, "dependencies": { "@modelcontextprotocol/sdk": "^1.26.0", - "chalk": "^5.3.0", - "yargs": "^17.7.2" + "chalk": "^5.0.0" }, "devDependencies": { - "@types/node": "^22", - "@types/yargs": "^17.0.32", - "@vitest/coverage-v8": "^2.1.8", - "shx": "^0.3.4", - "typescript": "^5.3.3", - "vitest": "^2.1.8" + "@eslint/js": "^9.18.0", + "@release-it/conventional-changelog": "^10.0.5", + "@types/node": "^25.2.3", + "@typescript-eslint/eslint-plugin": "^8.0.0", + "@typescript-eslint/parser": "^8.0.0", + "@vitest/coverage-v8": "^4.0.18", + "eslint": "^9.18.0", + "eslint-config-prettier": "^10.0.0", + "husky": "^9.1.7", + "prettier": "^3.4.0", + "release-it": "^19.2.4", + "shx": "^0.4.0", + "typedoc": "^0.27.0", + "typescript": "^5.9.3", + "vitest": "^4.0.18", + "zod": "^4.3.6" + }, + "engines": { + "node": ">=22.0.0" } -} \ No newline at end of file +} diff --git a/src/sequentialthinking/plan.md b/src/sequentialthinking/plan.md new file mode 100644 index 0000000000..1072785360 --- /dev/null +++ b/src/sequentialthinking/plan.md @@ -0,0 +1,252 @@ +# Plan: 5 Robustness Improvements (Round 2) + +## Context + +After a thorough code review of the current state (including the 5 fixes just landed), 5 new concrete robustness issues were identified. Each has a real bug or data-integrity impact. All fixes are backward-compatible, focused, and tested. + +## Implementation Order + +1. **Post-sanitization empty check** (self-contained, lib.ts + security-service.ts) +2. **UCB1 NaN/Infinity guard** (self-contained, mcts.ts) +3. **Config cross-validation** (self-contained, config.ts) +4. **Ordered container destroy** (cross-cutting, container.ts) +5. **Thought reference validation** (lib.ts business-logic layer) + +--- + +## Fix 1: Post-Sanitization Empty Check + +**Problem:** `security-service.ts:72-79` `sanitizeContent()` can strip all content from a thought. For example, `` becomes `""` after sanitization. This empty string passes through `buildThoughtData()` and `storage.addThought()` unchecked, creating an empty thought in history. + +**File:** `lib.ts` — in `processWithServices()`, after the sanitize call (line ~154): + +**Change:** Add a post-sanitization empty check: +```typescript +security.validateThought(input.thought, sessionId); +const sanitized = security.sanitizeContent(input.thought); +if (sanitized.trim().length === 0) { + throw new ValidationError('Thought is empty after content sanitization'); +} +``` + +**Tests in `__tests__/integration/server.test.ts`:** new test in `Security` describe: +- `'should reject thought that becomes empty after sanitization'` — input `` → expect `isError: true`, `VALIDATION_ERROR` +- `'should reject thought that becomes whitespace-only after sanitization'` — input with only sanitizable content + spaces → expect error + +--- + +## Fix 2: UCB1 NaN/Infinity Guard + +**Problem:** `mcts.ts:17-21` — `computeUCB1()` computes `Math.log(parentVisits)`. When `parentVisits` is 0 (possible when `suggestNext()` is called on a tree where all nodes have `visitCount === 0`), `Math.log(0)` returns `-Infinity`, and `Math.sqrt(-Infinity)` returns `NaN`. This NaN propagates into `ucb1Score` in suggestion results, breaking JSON serialization and downstream comparisons. + +Additionally, `suggestNext()` at line 49 computes `totalVisits` via `Math.max(1, ...)`, but this is the *sum* of all expandable nodes' visits — it can still be 0 if all nodes are unexplored (the `Math.max` catches this). However the `computeUCB1` method is a public API that can be called independently. The guard should be in the method itself. + +**File:** `mcts.ts` — in `computeUCB1()`: + +**Change:** +```typescript +computeUCB1(nodeVisits: number, nodeValue: number, parentVisits: number, C: number): number { + if (nodeVisits === 0) return Infinity; + if (parentVisits <= 0) return nodeValue / nodeVisits; // exploitation only, no exploration term + const exploitation = nodeValue / nodeVisits; + const exploration = C * Math.sqrt(Math.log(parentVisits) / nodeVisits); + return exploitation + exploration; +} +``` + +**Tests in `__tests__/unit/mcts.test.ts`:** new tests in appropriate describe: +- `'should return exploitation-only score when parentVisits is 0'` — `computeUCB1(2, 1.0, 0, Math.SQRT2)` → `0.5` (no NaN) +- `'should return Infinity for unvisited node regardless of parentVisits'` — `computeUCB1(0, 0, 0, Math.SQRT2)` → `Infinity` +- `'should not produce NaN for any edge case inputs'` — test several boundary combinations, assert `!Number.isNaN(result)` + +--- + +## Fix 3: Config Cross-Validation + +**Problem:** `config.ts:120-168` validates individual config sections but never checks relationships between them. Three specific gaps: + +1. **`maxThoughtsPerBranch > maxHistorySize`**: Configuration allows branch limit 10000 but history limit 100, meaning branches can never actually reach their limit since history evicts first. Misleading. +2. **Health thresholds unvalidated**: `maxMemoryPercent`, `maxStoragePercent` etc. are never validated — values like 200% or -1 are silently accepted. +3. **`explorationConstant === 0`**: Allowed by current validation (`>= 0`), but this makes the UCB1 exploration term always 0, effectively disabling exploration. Should warn or reject. + +**File:** `config.ts` — in `validate()`: + +**Change:** Add `validateMonitoring()` and `validateCrossConstraints()`: +```typescript +static validate(config: AppConfig): void { + this.validateState(config.state); + this.validateSecurity(config.security); + this.validateMcts(config.mcts); + this.validateMonitoring(config.monitoring); + this.validateCrossConstraints(config); +} + +private static validateMonitoring(monitoring: AppConfig['monitoring']): void { + const t = monitoring.healthThresholds; + if (t.maxMemoryPercent < 1 || t.maxMemoryPercent > 100) { + throw new Error('HEALTH_MAX_MEMORY must be between 1 and 100'); + } + if (t.maxStoragePercent < 1 || t.maxStoragePercent > 100) { + throw new Error('HEALTH_MAX_STORAGE must be between 1 and 100'); + } + if (t.maxResponseTimeMs < 1) { + throw new Error('HEALTH_MAX_RESPONSE_TIME must be >= 1'); + } + if (t.errorRateDegraded < 0 || t.errorRateDegraded > 100) { + throw new Error('HEALTH_ERROR_RATE_DEGRADED must be between 0 and 100'); + } + if (t.errorRateUnhealthy < 0 || t.errorRateUnhealthy > 100) { + throw new Error('HEALTH_ERROR_RATE_UNHEALTHY must be between 0 and 100'); + } + if (t.errorRateDegraded >= t.errorRateUnhealthy) { + throw new Error('HEALTH_ERROR_RATE_DEGRADED must be less than HEALTH_ERROR_RATE_UNHEALTHY'); + } +} + +private static validateCrossConstraints(config: AppConfig): void { + if (config.state.maxThoughtsPerBranch > config.state.maxHistorySize) { + throw new Error( + `maxThoughtsPerBranch (${config.state.maxThoughtsPerBranch}) must not exceed maxHistorySize (${config.state.maxHistorySize})` + ); + } + if (config.mcts.explorationConstant === 0) { + throw new Error('MCTS_EXPLORATION_CONSTANT must be > 0 (zero disables exploration entirely)'); + } +} +``` + +**Tests in `__tests__/unit/config.test.ts`:** new describe blocks: +- `'validateMonitoring'`: reject maxMemoryPercent=0, maxMemoryPercent=101, maxStoragePercent=-1, errorRateDegraded >= errorRateUnhealthy +- `'validateCrossConstraints'`: reject maxThoughtsPerBranch > maxHistorySize, reject explorationConstant=0 +- Positive tests: valid configs pass + +--- + +## Fix 4: Ordered Container Destroy + +**Problem:** `container.ts:52-69` — `SimpleContainer.destroy()` iterates `this.instances` using `Map` iteration order (insertion order). Services are lazily instantiated, so the order depends on which services were first accessed. If `metrics` (which depends on `storage`) was instantiated first, `storage.destroy()` could fire before `metrics.destroy()`, causing `metrics` to reference a destroyed storage. + +**File:** `container.ts` — in `SimpleContainer`: + +**Change:** Add a declared destroy order: +```typescript +export class SimpleContainer implements ServiceContainer { + private readonly services = new Map unknown>(); + private readonly instances = new Map(); + private destroyed = false; + + // Services should be destroyed in reverse-dependency order + private static readonly DESTROY_ORDER = [ + 'healthChecker', // depends on metrics, storage, security + 'metrics', // depends on storage, sessionTracker + 'thoughtTreeManager', // depends on sessionTracker (via eviction) + 'security', // depends on sessionTracker + 'storage', // depends on sessionTracker + 'formatter', // no deps + 'logger', // no deps + 'config', // no deps + 'sessionTracker', // no deps (destroyed separately by app) + ]; + + destroy(): void { + if (this.destroyed) return; + this.destroyed = true; + + // Destroy in declared order first + for (const key of SimpleContainer.DESTROY_ORDER) { + this.destroyInstance(key); + } + // Destroy any remaining instances not in the order list + for (const key of this.instances.keys()) { + this.destroyInstance(key); + } + this.instances.clear(); + this.services.clear(); + } + + private destroyInstance(key: string): void { + const instance = this.instances.get(key); + if (!instance) return; + this.instances.delete(key); + const obj = instance as Record; + if (obj && typeof obj.destroy === 'function') { + try { + (obj.destroy as () => void)(); + } catch (error) { + console.error(`Error destroying service '${key}':`, error); + } + } + } +} +``` + +**Tests in `__tests__/unit/container.test.ts`:** new describe: +- `'should destroy services in dependency order'` — register 3 mock services with destroy() that records call order; verify order matches DESTROY_ORDER +- `'should handle services not in DESTROY_ORDER gracefully'` — register unknown service, verify it still gets destroyed +- `'should not fail if a service throws during ordered destroy'` — one service throws in destroy(), verify others still get destroyed + +--- + +## Fix 5: Thought Reference Validation + +**Problem:** `lib.ts:65-78` — `validateBusinessLogic()` checks that `isRevision` has a `revisesThought` value and `branchFromThought` has a `branchId`. But it never validates that `revisesThought` or `branchFromThought` are *reasonable*. A client can send `revisesThought: 999` when only 2 thoughts have been submitted. The code silently produces a response without `revisionContext` (since no matching thought is found), which is confusing. + +Similarly, `branchFromThought` is not validated against actual thought numbers. + +**File:** `lib.ts` — in `validateBusinessLogic()`: + +**Change:** Add bounds-checking against `thoughtNumber`: +```typescript +private validateBusinessLogic(input: ProcessThoughtRequest): void { + if (input.isRevision && !input.revisesThought) { + throw new BusinessLogicError( + 'isRevision requires revisesThought to be specified', + ); + } + if (input.isRevision && input.revisesThought && input.revisesThought >= input.thoughtNumber) { + throw new BusinessLogicError( + `revisesThought (${input.revisesThought}) must be less than current thoughtNumber (${input.thoughtNumber})`, + ); + } + if (input.branchFromThought && !input.branchId) { + throw new BusinessLogicError( + 'branchFromThought requires branchId to be specified', + ); + } + if (input.branchFromThought && input.branchFromThought >= input.thoughtNumber) { + throw new BusinessLogicError( + `branchFromThought (${input.branchFromThought}) must be less than current thoughtNumber (${input.thoughtNumber})`, + ); + } +} +``` + +**Tests in `__tests__/integration/server.test.ts`:** new describe `'Thought Reference Bounds Validation'`: +- `'should reject revisesThought >= thoughtNumber'` — `revisesThought: 3, thoughtNumber: 2` → `BUSINESS_LOGIC_ERROR` +- `'should reject revisesThought equal to thoughtNumber'` — `revisesThought: 1, thoughtNumber: 1` → `BUSINESS_LOGIC_ERROR` +- `'should reject branchFromThought >= thoughtNumber'` — `branchFromThought: 5, thoughtNumber: 3` → `BUSINESS_LOGIC_ERROR` +- `'should accept valid revisesThought < thoughtNumber'` — `revisesThought: 1, thoughtNumber: 2` → success +- `'should accept valid branchFromThought < thoughtNumber'` — `branchFromThought: 1, thoughtNumber: 2` → success + +--- + +## Files Modified Summary + +| File | Fixes | +|------|-------| +| `lib.ts` | #1, #5 | +| `mcts.ts` | #2 | +| `config.ts` | #3 | +| `container.ts` | #4 | +| `__tests__/integration/server.test.ts` | #1, #5 | +| `__tests__/unit/mcts.test.ts` | #2 | +| `__tests__/unit/config.test.ts` | #3 | +| `__tests__/unit/container.test.ts` | #4 | + +## Verification + +```bash +npx tsc --noEmit # 0 errors +npm run build # clean +npx vitest run # all tests pass +``` diff --git a/src/sequentialthinking/scripts/sync-version.js b/src/sequentialthinking/scripts/sync-version.js new file mode 100644 index 0000000000..8b228eccbf --- /dev/null +++ b/src/sequentialthinking/scripts/sync-version.js @@ -0,0 +1,20 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const rootDir = path.join(__dirname, '..'); +const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8')); +const version = packageJson.version; + +const configPath = path.join(rootDir, 'config.ts'); +let configContent = fs.readFileSync(configPath, 'utf-8'); + +// Update the default version in config.ts +configContent = configContent.replace( + /version: process\.env\.SERVER_VERSION \?\? ['"][^'"]+['"]/, + `version: process.env.SERVER_VERSION ?? '${version}'` +); + +fs.writeFileSync(configPath, configContent); +console.log(`Synced config.ts version to ${version}`); diff --git a/src/sequentialthinking/scripts/sync-version.ts b/src/sequentialthinking/scripts/sync-version.ts new file mode 100644 index 0000000000..0b7721fca6 --- /dev/null +++ b/src/sequentialthinking/scripts/sync-version.ts @@ -0,0 +1,19 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8')); +const version = packageJson.version; + +const configPath = path.join(__dirname, 'config.ts'); +let configContent = fs.readFileSync(configPath, 'utf-8'); + +// Update the default version in config.ts +configContent = configContent.replace( + /version: process\.env\.SERVER_VERSION \?\s*['"][^'"]+['"]/, + `version: process.env.SERVER_VERSION ?? '${version}'` +); + +fs.writeFileSync(configPath, configContent); +console.log(`Updated config.ts with version ${version}`); diff --git a/src/sequentialthinking/security-service.ts b/src/sequentialthinking/security-service.ts new file mode 100644 index 0000000000..5ddc41e076 --- /dev/null +++ b/src/sequentialthinking/security-service.ts @@ -0,0 +1,91 @@ +import type { SecurityService } from './interfaces.js'; +import { SecurityError } from './errors.js'; +import type { SessionTracker } from './session-tracker.js'; + +export interface SecurityServiceConfig { + maxThoughtLength: number; + maxThoughtsPerMinute: number; + blockedPatterns: RegExp[]; +} + +const DEFAULT_CONFIG: SecurityServiceConfig = { + maxThoughtLength: 5000, + maxThoughtsPerMinute: 60, + blockedPatterns: [ + /test-block/i, + /forbidden/i, + /javascript:/i, + /eval\s*\(/i, + /Function\s*\(/i, + ], +}; + +const PRE_COMPILED_SANITIZE_PATTERNS: RegExp[] = [ + /]*>.*?<\/script>/gi, + /javascript:/gi, + /eval\(/gi, + /Function\(/gi, + /on\w+=/gi, +]; + +const SANITIZE_REPLACEMENTS = ['', '', '', '', '']; + +export class SecureThoughtSecurity implements SecurityService { + private readonly config: SecurityServiceConfig; + private readonly sessionTracker: SessionTracker; + + constructor( + config: Partial = {}, + sessionTracker: SessionTracker, + ) { + this.config = { ...DEFAULT_CONFIG, ...config }; + this.sessionTracker = sessionTracker; + } + + validateThought( + thought: string, + sessionId = '', + ): void { + for (const regex of this.config.blockedPatterns) { + if (regex.test(thought)) { + throw new SecurityError( + `Thought contains prohibited content in session ${sessionId}`, + ); + } + } + + if (sessionId) { + const withinLimit = this.sessionTracker.checkAndRecordThought( + sessionId, + this.config.maxThoughtsPerMinute, + ); + if (!withinLimit) { + throw new SecurityError('Rate limit exceeded'); + } + } + } + + sanitizeContent(content: string): string { + let result = content; + for (let i = 0; i < PRE_COMPILED_SANITIZE_PATTERNS.length; i++) { + result = result.replace(PRE_COMPILED_SANITIZE_PATTERNS[i], SANITIZE_REPLACEMENTS[i]); + } + return result; + } + + generateSessionId(): string { + return crypto.randomUUID(); + } + + validateSession(sessionId: string): boolean { + return sessionId.length > 0 && sessionId.length <= 100; + } + + getSecurityStatus(): Record { + return { + status: 'healthy', + activeSessions: this.sessionTracker.getActiveSessionCount(), + blockedPatterns: this.config.blockedPatterns.length, + }; + } +} diff --git a/src/sequentialthinking/session-tracker.ts b/src/sequentialthinking/session-tracker.ts new file mode 100644 index 0000000000..79fa658732 --- /dev/null +++ b/src/sequentialthinking/session-tracker.ts @@ -0,0 +1,199 @@ +import { SESSION_EXPIRY_MS, RATE_LIMIT_WINDOW_MS } from './config.js'; + +interface SessionData { + lastAccess: number; + rateTimestamps: number[]; // For rate limiting (60s window) +} +const MAX_TRACKED_SESSIONS = 10000; + +/** Remove all timestamps before cutoff in O(n) instead of O(n²) shift loop. */ +function pruneTimestamps(timestamps: number[], cutoff: number): void { + const firstValid = timestamps.findIndex(ts => ts >= cutoff); + if (firstValid > 0) { + timestamps.splice(0, firstValid); + } else if (firstValid === -1 && timestamps.length > 0) { + timestamps.length = 0; + } +} + +/** + * Centralized session tracking for state, security, and metrics. + * Replaces three separate Maps with unified expiry logic. + */ +export class SessionTracker { + private readonly sessions = new Map(); + private cleanupTimer: NodeJS.Timeout | null = null; + private readonly evictionCallbacks: Array<(sessionIds: string[]) => void> = []; + private readonly periodicCleanupCallbacks: Array<() => void> = []; + + onEviction(callback: (sessionIds: string[]) => void): void { + this.evictionCallbacks.push(callback); + } + + onPeriodicCleanup(callback: () => void): void { + this.periodicCleanupCallbacks.push(callback); + } + + constructor(cleanupInterval = 60000) { + if (cleanupInterval > 0) { + this.startCleanupTimer(cleanupInterval); + } + } + + /** + * Record a thought for a session. Updates timestamp and count. + */ + recordThought(sessionId: string): void { + const now = Date.now(); + const session = this.sessions.get(sessionId) ?? { + lastAccess: now, + rateTimestamps: [], + }; + + session.lastAccess = now; + session.rateTimestamps.push(now); + + this.sessions.set(sessionId, session); + + // Proactive cleanup when approaching limit + if (this.sessions.size > MAX_TRACKED_SESSIONS * 0.9) { + this.cleanup(); + } + } + + /** + * Atomically check rate limit and record the thought if within limit. + * Closes the race condition between separate check + record calls. + * Returns true if within limit (and thought was recorded), false if exceeded. + */ + checkAndRecordThought(sessionId: string, maxRequests: number): boolean { + const now = Date.now(); + const cutoff = now - RATE_LIMIT_WINDOW_MS; + + const session = this.sessions.get(sessionId) ?? { + lastAccess: now, + rateTimestamps: [], + }; + + pruneTimestamps(session.rateTimestamps, cutoff); + + if (session.rateTimestamps.length >= maxRequests) { + return false; + } + + // Atomically record: update access + push timestamp in one operation + session.lastAccess = now; + session.rateTimestamps.push(now); + this.sessions.set(sessionId, session); + + if (this.sessions.size > MAX_TRACKED_SESSIONS * 0.9) { + this.cleanup(); + } + + return true; + } + + /** + * Get count of active sessions (accessed within expiry window). + */ + getActiveSessionCount(): number { + const now = Date.now(); + const cutoff = now - SESSION_EXPIRY_MS; + let count = 0; + + for (const session of this.sessions.values()) { + if (session.lastAccess >= cutoff) { + count++; + } + } + + return count; + } + + + /** + * Clean up expired sessions (older than 1 hour). + */ + cleanup(): void { + const now = Date.now(); + const cutoff = now - SESSION_EXPIRY_MS; + const rateCutoff = now - RATE_LIMIT_WINDOW_MS; + const evictedIds: string[] = []; + + for (const [id, session] of this.sessions.entries()) { + // Remove sessions with no activity in 1 hour + if (session.lastAccess < cutoff) { + this.sessions.delete(id); + evictedIds.push(id); + continue; + } + + pruneTimestamps(session.rateTimestamps, rateCutoff); + } + + // If still at capacity, remove oldest sessions (FIFO) + if (this.sessions.size >= MAX_TRACKED_SESSIONS) { + const entriesToRemove = this.sessions.size - MAX_TRACKED_SESSIONS + 100; + const sortedSessions = Array.from(this.sessions.entries()) + .sort((a, b) => a[1].lastAccess - b[1].lastAccess) + .slice(0, entriesToRemove); + + for (const [id] of sortedSessions) { + this.sessions.delete(id); + evictedIds.push(id); + } + } + + // Notify subscribers of evicted sessions + if (evictedIds.length > 0) { + for (const callback of this.evictionCallbacks) { + try { + callback(evictedIds); + } catch (error) { + console.error('Eviction callback error:', error); + } + } + } + + // Invoke periodic cleanup subscribers + for (const callback of this.periodicCleanupCallbacks) { + try { + callback(); + } catch (error) { + console.error('Periodic cleanup callback error:', error); + } + } + } + + /** + * Clear all session data. + */ + clear(): void { + this.sessions.clear(); + } + + private startCleanupTimer(interval: number): void { + this.cleanupTimer = setInterval(() => { + try { + this.cleanup(); + } catch (error) { + console.error('Session cleanup error:', error); + } + }, interval); + this.cleanupTimer.unref(); + } + + private stopCleanupTimer(): void { + if (this.cleanupTimer) { + clearInterval(this.cleanupTimer); + this.cleanupTimer = null; + } + } + + destroy(): void { + this.stopCleanupTimer(); + this.clear(); + this.evictionCallbacks.length = 0; + this.periodicCleanupCallbacks.length = 0; + } +} diff --git a/src/sequentialthinking/state-manager.ts b/src/sequentialthinking/state-manager.ts new file mode 100644 index 0000000000..5a514620a7 --- /dev/null +++ b/src/sequentialthinking/state-manager.ts @@ -0,0 +1,153 @@ +import type { ThoughtData, ThoughtStorage } from './interfaces.js'; +import { CircularBuffer } from './circular-buffer.js'; +import type { SessionTracker } from './session-tracker.js'; + +class BranchData { + private thoughts: ThoughtData[] = []; + private lastAccessed: number = Date.now(); + + addThought(thought: ThoughtData): void { + this.thoughts.push(thought); + } + + updateLastAccessed(): void { + this.lastAccessed = Date.now(); + } + + isExpired(maxAge: number): boolean { + return Date.now() - this.lastAccessed > maxAge; + } + + cleanup(maxThoughts: number): void { + if (this.thoughts.length > maxThoughts) { + this.thoughts = this.thoughts.slice(-maxThoughts); + } + } + + getThoughtCount(): number { + return this.thoughts.length; + } + + getThoughts(): ThoughtData[] { + return [...this.thoughts]; + } +} + +interface StateConfig { + maxHistorySize: number; + maxBranchAge: number; + maxThoughtsPerBranch: number; + cleanupInterval: number; +} + +export class BoundedThoughtManager implements ThoughtStorage { + private readonly thoughtHistory: CircularBuffer; + private readonly branches: Map; + private readonly config: StateConfig; + private readonly sessionTracker: SessionTracker; + + constructor(config: StateConfig, sessionTracker: SessionTracker) { + this.config = config; + this.sessionTracker = sessionTracker; + this.thoughtHistory = new CircularBuffer(config.maxHistorySize); + this.branches = new Map(); + sessionTracker.onPeriodicCleanup(() => this.cleanup()); + } + + addThought(thought: ThoughtData): void { + // Length validation happens in lib.ts before reaching here + // Work on a shallow copy to avoid mutating the caller's object + const entry = { ...thought }; + + // Session recording now happens atomically in security validation + // to prevent race conditions + + // Add to main history + this.thoughtHistory.add(entry); + + // Handle branch management + if (entry.branchId) { + const branch = this.getOrCreateBranch(entry.branchId); + branch.addThought(entry); + branch.updateLastAccessed(); + + // Enforce per-branch limits + if (branch.getThoughtCount() > this.config.maxThoughtsPerBranch) { + branch.cleanup(this.config.maxThoughtsPerBranch); + } + } + } + + private getOrCreateBranch(branchId: string): BranchData { + let branch = this.branches.get(branchId); + if (!branch) { + branch = new BranchData(); + this.branches.set(branchId, branch); + } + return branch; + } + + getHistory(limit?: number): ThoughtData[] { + return this.thoughtHistory.getAll(limit); + } + + getBranches(): string[] { + return Array.from(this.branches.keys()); + } + + getBranchThoughts(branchId: string): ThoughtData[] { + const branch = this.branches.get(branchId); + if (!branch) return []; + return branch.getThoughts(); + } + + clearHistory(): void { + this.thoughtHistory.clear(); + this.branches.clear(); + } + + cleanup(): void { + try { + // Clean up expired branches + const expiredBranches: string[] = []; + + for (const [branchId, branch] of this.branches.entries()) { + if (branch.isExpired(this.config.maxBranchAge)) { + expiredBranches.push(branchId); + } else { + // Cleanup old thoughts within active branches + branch.cleanup(this.config.maxThoughtsPerBranch); + } + } + + // Remove expired branches + for (const branchId of expiredBranches) { + this.branches.delete(branchId); + } + + // Session cleanup is now handled by SessionTracker + + } catch (error) { + console.error('Cleanup operation failed', error); + } + } + + getStats(): { + historySize: number; + historyCapacity: number; + branchCount: number; + sessionCount: number; + } { + return { + historySize: this.thoughtHistory.currentSize, + historyCapacity: this.config.maxHistorySize, + branchCount: this.branches.size, + sessionCount: this.sessionTracker.getActiveSessionCount(), + }; + } + + destroy(): void { + this.thoughtHistory.clear(); + this.branches.clear(); + } +} diff --git a/src/sequentialthinking/thinking-modes.ts b/src/sequentialthinking/thinking-modes.ts new file mode 100644 index 0000000000..b477e15e77 --- /dev/null +++ b/src/sequentialthinking/thinking-modes.ts @@ -0,0 +1,840 @@ +import type { ThoughtTree } from './thought-tree.js'; +import type { MCTSEngine } from './mcts.js'; +import type { TreeStats, TreeNodeInfo } from './interfaces.js'; +import { metacognition } from './metacognition.js'; + +export const VALID_THINKING_MODES = ['fast', 'expert', 'deep'] as const; +export type ThinkingMode = (typeof VALID_THINKING_MODES)[number]; + +export interface ThinkingModeConfig { + mode: ThinkingMode; + explorationConstant: number; + suggestStrategy: 'explore' | 'exploit' | 'balanced'; + maxBranchingFactor: number; + targetDepthMin: number; + targetDepthMax: number; + autoEvaluate: boolean; + autoEvalValue: number; + enableBacktracking: boolean; + minEvaluationsBeforeConverge: number; + convergenceThreshold: number; + progressOverviewInterval: number; + maxThoughtDisplayLength: number; + enableCritique: boolean; + backtrackThreshold: number; + branchMinDepth: number; + useMCTSForBranching: boolean; +} + +export interface ModeGuidance { + mode: ThinkingMode; + currentPhase: 'exploring' | 'evaluating' | 'converging' | 'concluded'; + recommendedAction: 'continue' | 'branch' | 'evaluate' | 'backtrack' | 'conclude'; + reasoning: string; + targetTotalThoughts: number; + convergenceStatus: { + isConverged: boolean; + score: number; + bestPathValue: number; + } | null; + branchingSuggestion: { + shouldBranch: boolean; + fromNodeId: string; + reason: string; + } | null; + backtrackSuggestion: { + shouldBacktrack: boolean; + toNodeId: string; + reason: string; + } | null; + thoughtPrompt: string; + progressOverview: string | null; + critique: string | null; + circularityWarning: string | null; + confidenceScore: number | null; + perspectiveSuggestions: Array<{ perspective: string; description: string }>; + problemType: string | null; + strategyGuidance: string | null; + confidenceTrend: 'improving' | 'declining' | 'stable' | 'insufficient' | null; + reasoningGapWarning: string | null; + adaptiveStrategyReasoning: string | null; + reflectionPrompt: string | null; + complexityAnalysis: { + complexity: 'simple' | 'moderate' | 'complex'; + reasoning: string; + recommendedMode: 'fast' | 'expert' | 'deep'; + } | null; +} + +const PRESETS: Record = { + fast: { + mode: 'fast', + explorationConstant: 0.5, + suggestStrategy: 'exploit', + maxBranchingFactor: 1, + targetDepthMin: 3, + targetDepthMax: 5, + autoEvaluate: true, + autoEvalValue: 0.7, + enableBacktracking: false, + minEvaluationsBeforeConverge: 0, + convergenceThreshold: 0, + progressOverviewInterval: 3, + maxThoughtDisplayLength: 150, + enableCritique: false, + backtrackThreshold: 0, + branchMinDepth: Infinity, + useMCTSForBranching: false, + }, + expert: { + mode: 'expert', + explorationConstant: Math.SQRT2, + suggestStrategy: 'balanced', + maxBranchingFactor: 3, + targetDepthMin: 5, + targetDepthMax: 10, + autoEvaluate: false, + autoEvalValue: 0, + enableBacktracking: true, + minEvaluationsBeforeConverge: 3, + convergenceThreshold: 0.7, + progressOverviewInterval: 4, + maxThoughtDisplayLength: 250, + enableCritique: true, + backtrackThreshold: 0.4, + branchMinDepth: 2, + useMCTSForBranching: false, + }, + deep: { + mode: 'deep', + explorationConstant: 2.0, + suggestStrategy: 'explore', + maxBranchingFactor: 5, + targetDepthMin: 10, + targetDepthMax: 20, + autoEvaluate: false, + autoEvalValue: 0, + enableBacktracking: true, + minEvaluationsBeforeConverge: 5, + convergenceThreshold: 0.85, + progressOverviewInterval: 5, + maxThoughtDisplayLength: 300, + enableCritique: true, + backtrackThreshold: 0.5, + branchMinDepth: 0, + useMCTSForBranching: true, + }, +}; + +interface TemplateParams { + thoughtNumber: number; + currentDepth: number; + targetDepthMin: number; + targetDepthMax: number; + totalNodes: number; + unexploredCount: number; + leafCount: number; + terminalCount: number; + progress: string; + cursorValue: string; + bestPathValue: string; + convergenceScore: string; + branchCount: number; + maxBranches: number; + convergenceThreshold: number; + currentThought: string; + parentThought: string; + bestPathSummary: string; + branchFromNodeId: string; + backtrackToNodeId: string; + backtrackDepth: number; +} + +interface BuildTemplateContext { + config: ThinkingModeConfig; + tree: ThoughtTree; + stats: TreeStats; + bestPath: TreeNodeInfo[]; + convergenceStatus: ModeGuidance['convergenceStatus']; + branchingSuggestion: ModeGuidance['branchingSuggestion']; + backtrackSuggestion: ModeGuidance['backtrackSuggestion']; +} + +interface DetermineActionContext { + config: ThinkingModeConfig; + tree: ThoughtTree; + engine: MCTSEngine; + currentPhase: ModeGuidance['currentPhase']; + currentDepth: number; + convergenceStatus: ModeGuidance['convergenceStatus']; +} + +interface ActionResult { + recommendedAction: ModeGuidance['recommendedAction']; + reasoning: string; + branchingSuggestion: ModeGuidance['branchingSuggestion']; + backtrackSuggestion: ModeGuidance['backtrackSuggestion']; +} + +const TEMPLATES: Record = { + fast_continue: 'Step {{thoughtNumber}} of ~{{targetDepthMax}}. Build on: "{{currentThought}}". Next logical step — no alternatives, stay linear.', + fast_conclude: 'Reached target depth ({{currentDepth}}/{{targetDepthMax}}). Synthesize your {{totalNodes}} steps into a direct, concise answer.', + fast_evaluate: 'Assess quality at step {{thoughtNumber}} (depth {{currentDepth}}/{{targetDepthMax}}). Current value: {{cursorValue}}.', + + expert_continue: 'Step {{thoughtNumber}}, depth {{currentDepth}}/{{targetDepthMax}}. {{unexploredCount}} paths unexplored. Building on: "{{currentThought}}". What follows logically?', + expert_branch: 'Decision point at node {{branchFromNodeId}}. {{branchCount}}/{{maxBranches}} perspectives explored. Current path: "{{currentThought}}". Branch with a different angle, method, or assumption.', + expert_evaluate: '{{unexploredCount}} paths need scoring. Use evaluate_thought to rate quality and guide exploration. Best path so far: {{bestPathSummary}}.', + expert_backtrack: 'Path scoring {{cursorValue}} — below threshold. Backtrack to node {{backtrackToNodeId}} (depth {{backtrackDepth}}). What assumption led astray?', + expert_conclude: 'Convergence reached (score {{convergenceScore}}, threshold {{convergenceThreshold}}). Best path: {{bestPathSummary}}. Synthesize the strongest path into a final answer.', + + deep_continue: 'Depth {{currentDepth}}/{{targetDepthMax}}, {{totalNodes}} nodes, {{unexploredCount}} unscored. Building on: "{{currentThought}}". What nuance, edge case, or deeper implication?', + deep_branch: '{{branchCount}}/{{maxBranches}} alternatives explored from node {{branchFromNodeId}}. Branch with a contrarian, lateral, or adversarial perspective on: "{{currentThought}}".', + deep_evaluate: '{{unexploredCount}} paths unscored across {{leafCount}} leaves. Score before convergence check. Best path: {{bestPathSummary}}.', + deep_backtrack: 'Path scoring {{cursorValue}}. Backtrack to node {{backtrackToNodeId}} (depth {{backtrackDepth}}). Find the weakest link in the reasoning and explore the opposite.', + deep_conclude: 'Deep convergence (score {{convergenceScore}}, threshold {{convergenceThreshold}}, {{totalNodes}} nodes). Summarize findings, address counterarguments, and state confidence level.', +}; + +const FALLBACK_TEMPLATE = '{{recommendedAction}} at step {{thoughtNumber}} (depth {{currentDepth}}/{{targetDepthMax}}). {{totalNodes}} nodes explored.'; + +export class ThinkingModeEngine { + getPreset(mode: ThinkingMode): ThinkingModeConfig { + return { ...PRESETS[mode] }; + } + + getAutoEvalValue(config: ThinkingModeConfig): number | null { + return config.autoEvaluate ? config.autoEvalValue : null; + } + + generateGuidance( + config: ThinkingModeConfig, + tree: ThoughtTree, + engine: MCTSEngine, + precomputedStats?: TreeStats, + ): ModeGuidance { + const stats = precomputedStats ?? engine.getTreeStats(tree); + const bestPath = engine.extractBestPath(tree); + const currentDepth = stats.maxDepth; + const totalEvaluated = stats.totalNodes - stats.unexploredCount; + + const convergenceStatus = this.computeConvergenceStatus( + config, bestPath, totalEvaluated, + ); + const currentPhase = this.determinePhase( + config, currentDepth, totalEvaluated, convergenceStatus, + ); + + const actionResult = this.determineAction({ + config, tree, engine, + currentPhase, currentDepth, convergenceStatus, + }); + const { recommendedAction, reasoning } = actionResult; + const { branchingSuggestion, backtrackSuggestion } = actionResult; + + const templateParams = this.buildTemplateParams({ + config, tree, stats, bestPath, + convergenceStatus, branchingSuggestion, backtrackSuggestion, + }); + const template = this.selectTemplate(config.mode, recommendedAction); + const thoughtPrompt = this.renderTemplate( + template, { ...templateParams, recommendedAction }, + ); + + const progressOverview = this.generateProgressOverview( + config, tree, stats, bestPath, + ); + const critique = this.generateCritique(config, tree, bestPath, stats); + + const metacog = this.computeMetacognitionData( + tree, recommendedAction, stats, thoughtPrompt, + ); + + const finalThoughtPrompt = metacog.strategyGuidance + ? `${metacog.enhancedThoughtPrompt}\n\n${metacog.strategyGuidance}` + : metacog.enhancedThoughtPrompt; + + return { + mode: config.mode, + currentPhase, + recommendedAction, + reasoning, + targetTotalThoughts: config.targetDepthMax, + convergenceStatus, + branchingSuggestion, + backtrackSuggestion, + thoughtPrompt: finalThoughtPrompt, + progressOverview, + critique, + circularityWarning: metacog.circularity.warning, + confidenceScore: metacog.confidence.confidence, + perspectiveSuggestions: metacog.perspectiveSuggestions.map(p => ({ + perspective: p.perspective, + description: p.description, + })), + problemType: metacog.problemType.type !== 'unknown' ? metacog.problemType.type : null, + strategyGuidance: metacog.strategyGuidance, + confidenceTrend: metacog.confidenceTrend, + reasoningGapWarning: metacog.reasoningGapWarning, + adaptiveStrategyReasoning: metacog.adaptiveStrategyReasoning, + reflectionPrompt: metacog.reflectionPrompt, + complexityAnalysis: metacog.complexityAnalysis, + }; + } + + private selectTemplate(mode: ThinkingMode, action: ModeGuidance['recommendedAction']): string { + return TEMPLATES[`${mode}_${action}`] ?? FALLBACK_TEMPLATE; + } + + private renderTemplate(template: string, params: Record): string { + return template.replace(/\{\{(\w+)\}\}/g, (_, key) => { + const val = params[key as keyof typeof params]; + return val !== undefined && val !== null ? String(val) : ''; + }); + } + + private computeMetacognitionData( + tree: ThoughtTree, + recommendedAction: ModeGuidance['recommendedAction'], + stats: TreeStats, + thoughtPrompt: string, + ): { + circularity: ReturnType; + confidence: ReturnType; + problemType: ReturnType; + perspectiveSuggestions: ReturnType; + strategyGuidance: string | null; + confidenceTrend: ReturnType | 'insufficient'; + enhancedThoughtPrompt: string; + reasoningGapWarning: string | null; + adaptiveStrategyReasoning: string | null; + reflectionPrompt: string | null; + complexityAnalysis: ReturnType | null; + } { + const thoughtHistory = tree.getAllNodes().map(n => ({ + thought: n.thought, + thoughtNumber: n.thoughtNumber, + totalThoughts: n.thoughtNumber, + nextThoughtNeeded: true, + })); + + const circularity = metacognition.detectCircularity(thoughtHistory); + const confidence = metacognition.assessConfidence( + thoughtHistory[thoughtHistory.length - 1]?.thought || '', + thoughtHistory.slice(0, -1), + null, + ); + const problemType = metacognition.classifyProblemType(thoughtHistory); + + const reasoningGaps = metacognition.analyzeReasoningGaps(thoughtHistory); + const reasoningGapWarning = reasoningGaps.hasGaps + ? `Reasoning gaps detected: ${reasoningGaps.gaps.map(g => g.issue).join('; ')}` + : null; + + const perspectiveSuggestions = metacognition.suggestPerspective( + recommendedAction === 'evaluate', + stats.totalNodes - stats.terminalCount, + ); + + const staticStrategy = problemType.type !== 'unknown' + ? metacognition.getStrategyGuidance(problemType.type) + : null; + + const adaptiveStrategy = problemType.type !== 'unknown' + ? metacognition.getAdaptiveStrategy(problemType.type) + : { recommendedStrategy: null, recommendedPerspective: null, reasoning: '' }; + + const strategyGuidance = adaptiveStrategy.recommendedStrategy + ? `${staticStrategy || ''}\n\n[Adaptive] ${adaptiveStrategy.reasoning}`.trim() + : staticStrategy; + + const allNodes = tree.getAllNodes(); + const confidenceHistory = allNodes + .map(n => n.confidence) + .filter((c): c is number => c !== undefined); + const confidenceTrend = confidenceHistory.length >= 3 + ? metacognition.computeConfidenceTrend(confidenceHistory) + : 'insufficient'; + + const activePerspective = adaptiveStrategy.recommendedPerspective + ? metacognition.getActivePerspectivePrompt([{ ...perspectiveSuggestions[0], perspective: adaptiveStrategy.recommendedPerspective }]) + : metacognition.getActivePerspectivePrompt(perspectiveSuggestions); + const enhancedThoughtPrompt = activePerspective + ? `${thoughtPrompt}\n\n${activePerspective}` + : thoughtPrompt; + + const reflectionPrompt = metacognition.generateReflectionPrompt( + 'exploring', + confidenceTrend, + circularity.isCircular, + confidence.confidence, + ); + + const complexityAnalysis = thoughtHistory.length >= 1 + ? metacognition.analyzeComplexity(thoughtHistory) + : null; + + return { + circularity, + confidence, + problemType, + perspectiveSuggestions, + strategyGuidance, + confidenceTrend, + enhancedThoughtPrompt, + reasoningGapWarning, + adaptiveStrategyReasoning: adaptiveStrategy.reasoning || null, + reflectionPrompt, + complexityAnalysis, + }; + } + + private computeCursorValue( + cursor: ThoughtTree['cursor'], + ): string { + if (!cursor || cursor.visitCount === 0) return 'unscored'; + return (cursor.totalValue / cursor.visitCount).toFixed(2); + } + + private computeBestPathValue( + bestPath: TreeNodeInfo[], + ): string { + if (bestPath.length === 0) return '0.00'; + return bestPath[bestPath.length - 1].averageValue.toFixed(2); + } + + private getParentThought( + tree: ThoughtTree, + maxLen: number, + ): string { + const { cursor } = tree; + if (!cursor?.parentId) return '(root)'; + const parent = tree.getNode(cursor.parentId); + if (!parent) return '(root)'; + return this.compressThought(parent.thought, maxLen); + } + + private computeProgress( + cursorDepth: number, + targetDepthMax: number, + ): string { + if (targetDepthMax <= 0) return '0.00'; + return (cursorDepth / targetDepthMax).toFixed(2); + } + + private getCursorFields( + tree: ThoughtTree, + maxLen: number, + ): Pick< + TemplateParams, + 'thoughtNumber' | 'currentDepth' | 'branchCount' | 'currentThought' + > { + const { cursor } = tree; + if (!cursor) { + return { + thoughtNumber: 0, + currentDepth: 0, + branchCount: 0, + currentThought: '(none)', + }; + } + return { + thoughtNumber: cursor.thoughtNumber, + currentDepth: cursor.depth, + branchCount: cursor.children.length, + currentThought: this.compressThought(cursor.thought, maxLen), + }; + } + + private buildTemplateParams(ctx: BuildTemplateContext): TemplateParams { + const { + config, tree, stats, bestPath, + convergenceStatus, branchingSuggestion, backtrackSuggestion, + } = ctx; + const maxLen = config.maxThoughtDisplayLength; + const cf = this.getCursorFields(tree, maxLen); + + const bestPathSummary = bestPath.length > 0 + ? bestPath.map(n => n.thoughtNumber).join(' -> ') + : '(none)'; + + const backtrackNodeId = backtrackSuggestion?.toNodeId; + const backtrackTarget = backtrackNodeId + ? tree.getNode(backtrackNodeId) : undefined; + + return { + ...cf, + targetDepthMin: config.targetDepthMin, + targetDepthMax: config.targetDepthMax, + totalNodes: stats.totalNodes, + unexploredCount: stats.unexploredCount, + leafCount: tree.getLeafNodes().length, + terminalCount: stats.terminalCount, + progress: this.computeProgress( + cf.currentDepth, config.targetDepthMax, + ), + cursorValue: this.computeCursorValue(tree.cursor), + bestPathValue: this.computeBestPathValue(bestPath), + convergenceScore: convergenceStatus + ? convergenceStatus.score.toFixed(2) + : 'N/A', + maxBranches: config.maxBranchingFactor, + convergenceThreshold: config.convergenceThreshold, + parentThought: this.getParentThought(tree, maxLen), + bestPathSummary, + branchFromNodeId: branchingSuggestion?.fromNodeId ?? '', + backtrackToNodeId: backtrackNodeId ?? '', + backtrackDepth: backtrackTarget?.depth ?? 0, + }; + } + + private computeConvergenceStatus( + config: ThinkingModeConfig, + bestPath: Array<{ visitCount: number; averageValue: number }>, + totalEvaluated: number, + ): ModeGuidance['convergenceStatus'] { + if (config.convergenceThreshold === 0) { + return null; + } + + const bestPathValue = bestPath.length > 0 + ? bestPath[bestPath.length - 1].averageValue + : 0; + + // Average value across visited nodes, penalized by visited ratio. + // Prevents premature convergence when most of the path is unexplored. + const visitedNodes = bestPath.filter(n => n.visitCount > 0); + let score: number; + if (visitedNodes.length === 0 || bestPath.length === 0) { + score = 0; + } else { + const avgValue = visitedNodes.reduce( + (sum, n) => sum + n.averageValue, 0, + ) / visitedNodes.length; + const visitedRatio = visitedNodes.length / bestPath.length; + score = avgValue * visitedRatio; + } + + const isConverged = + totalEvaluated >= config.minEvaluationsBeforeConverge && + score >= config.convergenceThreshold; + + return { isConverged, score, bestPathValue }; + } + + private determinePhase( + config: ThinkingModeConfig, + currentDepth: number, + totalEvaluated: number, + convergenceStatus: ModeGuidance['convergenceStatus'], + ): ModeGuidance['currentPhase'] { + // Already converged → concluded + if (convergenceStatus?.isConverged) { + return 'concluded'; + } + + // Fast mode: conclude when at target depth + if (config.mode === 'fast' && currentDepth >= config.targetDepthMax) { + return 'concluded'; + } + + // Check if enough evaluations for convergence phase + if (config.convergenceThreshold > 0 && totalEvaluated >= config.minEvaluationsBeforeConverge) { + return 'converging'; + } + + // If we have some evaluations, we're evaluating + if (totalEvaluated > 0 && currentDepth >= config.targetDepthMin) { + return 'evaluating'; + } + + return 'exploring'; + } + + private checkBacktrack( + ctx: DetermineActionContext, + ): ActionResult | null { + const { config, tree, engine, currentDepth } = ctx; + const { cursor } = tree; + if (!cursor || !config.enableBacktracking) return null; + if (cursor.visitCount === 0 || config.backtrackThreshold <= 0) { + return null; + } + const cursorAvg = cursor.totalValue / cursor.visitCount; + const eligible = cursor.children.length > 0 || currentDepth > 1; + if (cursorAvg >= config.backtrackThreshold || !eligible) { + return null; + } + const ancestor = this.findBestAncestorForBacktrack( + tree, engine, cursor.nodeId, + ); + if (!ancestor) return null; + return { + recommendedAction: 'backtrack', + reasoning: `Current path scoring ${cursorAvg.toFixed(2)} (threshold ${config.backtrackThreshold}). Backtrack to explore alternatives.`, + branchingSuggestion: null, + backtrackSuggestion: { + shouldBacktrack: true, + toNodeId: ancestor.nodeId, + reason: `Node at depth ${ancestor.depth} has better potential for branching.`, + }, + }; + } + + private checkBranch(ctx: DetermineActionContext): ActionResult | null { + const { config, tree, engine, currentDepth } = ctx; + const { cursor } = tree; + if (!cursor) return null; + const belowCap = cursor.children.length < config.maxBranchingFactor; + if (!belowCap || cursor.isTerminal) return null; + if (currentDepth < config.branchMinDepth) return null; + + let branchFrom = cursor.nodeId; + if (config.useMCTSForBranching) { + const s = engine.suggestNext(tree, config.suggestStrategy); + if (s.suggestion) branchFrom = s.suggestion.nodeId; + } + const remaining = config.maxBranchingFactor - cursor.children.length; + return { + recommendedAction: 'branch', + reasoning: `${config.mode} mode — ${cursor.children.length}/${config.maxBranchingFactor} branches explored. Consider alternative approaches.`, + branchingSuggestion: { + shouldBranch: true, + fromNodeId: branchFrom, + reason: `Node has capacity for ${remaining} more branches.`, + }, + backtrackSuggestion: null, + }; + } + + private determineAction(ctx: DetermineActionContext): ActionResult { + const { config, currentPhase, currentDepth, convergenceStatus } = ctx; + const none = { branchingSuggestion: null, backtrackSuggestion: null }; + + // 1. Concluded check + const concluded = currentPhase === 'concluded' + || (config.convergenceThreshold === 0 + && currentDepth >= config.targetDepthMax); + if (concluded) { + const scoreInfo = convergenceStatus?.score != null + ? ` (score: ${convergenceStatus.score.toFixed(2)}, threshold: ${config.convergenceThreshold})` + : ` (${currentDepth}/${config.targetDepthMax})`; + return { + recommendedAction: 'conclude', + reasoning: `Target reached${scoreInfo}. ${config.mode} mode — conclude.`, + ...none, + }; + } + + // 2. No cursor → continue + if (!ctx.tree.cursor) { + return { + recommendedAction: 'continue', + reasoning: 'No cursor — submit a thought to begin.', + ...none, + }; + } + + // 3. Backtrack check + const backtrack = this.checkBacktrack(ctx); + if (backtrack) return backtrack; + + // 4. Branch check + const branch = this.checkBranch(ctx); + if (branch) return branch; + + // 5. Evaluate unevaluated leaves + const leaves = !config.autoEvaluate + ? ctx.tree.getLeafNodes() : []; + const unevaluated = leaves.filter(l => l.visitCount === 0); + if (unevaluated.length > 0) { + return { + recommendedAction: 'evaluate', + reasoning: `${unevaluated.length} leaf node(s) unevaluated. Score them to guide exploration.`, + ...none, + }; + } + + // 6. Default continue + return { + recommendedAction: 'continue', + reasoning: `${config.mode} mode — continue exploring (depth ${currentDepth}/${config.targetDepthMax}).`, + ...none, + }; + } + + private compressThought(text: string, maxLen: number): string { + if (text.length <= maxLen) return text; + + const sentences = text.split(/(?<=[.!?])\s+/); + + if (sentences.length < 2) { + // Single sentence or no boundaries: word-boundary truncate + const cutoff = maxLen - 3; + const lastSpace = text.lastIndexOf(' ', cutoff); + const breakAt = lastSpace > 0 ? lastSpace : cutoff; + return text.substring(0, breakAt) + '...'; + } + + const [first] = sentences; + const last = sentences[sentences.length - 1]; + const combined = `${first} [...] ${last}`; + if (combined.length <= maxLen) return combined; + + const firstOnly = `${first} [...]`; + if (firstOnly.length <= maxLen) return firstOnly; + + // First sentence alone is too long — word-boundary truncate it + const cutoff = maxLen - 3; + const lastSpace = first.lastIndexOf(' ', cutoff); + const breakAt = lastSpace > 0 ? lastSpace : cutoff; + return first.substring(0, breakAt) + '...'; + } + + private extractFirstSentence(text: string): string { + const match = text.match(/^(.+?[.!?])(?:\s|$)/); + if (match) return match[1]; + // No sentence boundary found — compress to 50 chars + if (text.length <= 50) return text; + const lastSpace = text.lastIndexOf(' ', 47); + const breakAt = lastSpace > 0 ? lastSpace : 47; + return text.substring(0, breakAt) + '...'; + } + + private generateProgressOverview( + config: ThinkingModeConfig, + tree: ThoughtTree, + stats: TreeStats, + bestPath: TreeNodeInfo[], + ): string | null { + const interval = config.progressOverviewInterval; + if (interval <= 0 || stats.totalNodes <= 0 || stats.totalNodes % interval !== 0) { + return null; + } + + const totalEvaluated = stats.totalNodes - stats.unexploredCount; + const leaves = tree.getLeafNodes(); + const leafCount = leaves.length; + + const bestPathSummary = bestPath.length > 0 + ? bestPath.map(n => this.extractFirstSentence(n.thought)).join(' \u2192 ') + : '(none)'; + const bestPathScore = bestPath.length > 0 + ? bestPath[bestPath.length - 1].averageValue.toFixed(2) + : '0.00'; + + // Count single-child non-leaf nodes on best path as "branch points to expand" + let singleChildBranchPoints = 0; + for (const node of bestPath) { + if (node.childCount === 1) { + singleChildBranchPoints++; + } + } + + return `PROGRESS [${stats.totalNodes} thoughts, depth ${stats.maxDepth}/${config.targetDepthMax}]: Evaluated ${totalEvaluated}/${stats.totalNodes} | Leaves ${leafCount} | Terminal ${stats.terminalCount}.\nBest path (score ${bestPathScore}): ${bestPathSummary}.\nGaps: ${stats.unexploredCount} unscored, ${singleChildBranchPoints} single-child branch points to expand.`; + } + + private findWeakestNode( + bestPath: TreeNodeInfo[], + ): { node: TreeNodeInfo; value: number } | null { + let weakest: TreeNodeInfo | null = null; + let weakestValue = Infinity; + for (const node of bestPath) { + if (node.visitCount > 0 && node.averageValue < weakestValue) { + weakestValue = node.averageValue; + weakest = node; + } + } + return weakest ? { node: weakest, value: weakestValue } : null; + } + + private countUnchallenged( + tree: ThoughtTree, + bestPath: TreeNodeInfo[], + ): number { + let count = 0; + for (let i = 1; i < bestPath.length; i++) { + const parentNode = tree.getNode(bestPath[i - 1].nodeId); + if (parentNode?.children.length === 1) { + count++; + } + } + return count; + } + + private computeBranchCoverage( + bestPath: TreeNodeInfo[], + maxBranchingFactor: number, + ): { totalChildren: number; theoreticalMax: number; percent: number } { + let totalChildren = 0; + for (const node of bestPath) { + totalChildren += node.childCount; + } + const theoreticalMax = bestPath.length * maxBranchingFactor; + const percent = theoreticalMax > 0 + ? Math.round((totalChildren / theoreticalMax) * 100) + : 0; + return { totalChildren, theoreticalMax, percent }; + } + + private generateCritique( + config: ThinkingModeConfig, + tree: ThoughtTree, + bestPath: TreeNodeInfo[], + stats: TreeStats, + ): string | null { + if (!config.enableCritique || bestPath.length < 2) { + return null; + } + + const weakest = this.findWeakestNode(bestPath); + const unchallenged = this.countUnchallenged(tree, bestPath); + const coverage = this.computeBranchCoverage( + bestPath, config.maxBranchingFactor, + ); + + const balanceRatio = stats.totalNodes > 0 + ? bestPath.length / stats.totalNodes + : 0; + const balancePercent = Math.round(balanceRatio * 100); + let balanceLabel: string; + if (balanceRatio > 0.8) { + balanceLabel = 'one-sided'; + } else if (balanceRatio > 0.5) { + balanceLabel = 'moderate'; + } else { + balanceLabel = 'well-balanced'; + } + + const weakestInfo = weakest + ? `Weakest: step ${weakest.node.thoughtNumber} (score ${weakest.value.toFixed(2)}) \u2014 "${this.compressThought(weakest.node.thought, 60)}".` + : 'Weakest: N/A (no scored nodes).'; + + const { totalChildren, theoreticalMax, percent } = coverage; + return [ + `CRITIQUE: ${weakestInfo}`, + `Unchallenged: ${unchallenged}/${bestPath.length - 1} steps have no alternatives. Coverage: ${totalChildren}/${theoreticalMax} branches (${percent}%).`, + `Balance: ${balanceLabel} \u2014 ${balancePercent}% of nodes on best path.`, + ].join('\n'); + } + + private findBestAncestorForBacktrack( + tree: ThoughtTree, + engine: MCTSEngine, + nodeId: string, + ): { nodeId: string; depth: number } | null { + const path = tree.getAncestorPath(nodeId); + if (path.length <= 1) return null; + + // Find ancestor with capacity for more children (skip root, skip current) + for (let i = path.length - 2; i >= 0; i--) { + const ancestor = path[i]; + if (ancestor.children.length > 1 || !ancestor.isTerminal) { + return { nodeId: ancestor.nodeId, depth: ancestor.depth }; + } + } + + // Fallback: return root's first child or root + return path.length > 1 + ? { nodeId: path[0].nodeId, depth: path[0].depth } + : null; + } +} diff --git a/src/sequentialthinking/thought-tree-manager.ts b/src/sequentialthinking/thought-tree-manager.ts new file mode 100644 index 0000000000..5ed586a3de --- /dev/null +++ b/src/sequentialthinking/thought-tree-manager.ts @@ -0,0 +1,233 @@ +import type { + ThoughtData, + MCTSConfig, + ThoughtTreeService, + ThoughtTreeRecordResult, + MCTSService, + TreeNodeInfo, + BacktrackResult, + EvaluateResult, + SuggestResult, + ThinkingSummary, +} from './interfaces.js'; +import { ThoughtTree } from './thought-tree.js'; +import { MCTSEngine } from './mcts.js'; +import { TreeError } from './errors.js'; +import { ThinkingModeEngine } from './thinking-modes.js'; +import { metacognition } from './metacognition.js'; +import type { ThinkingMode, ThinkingModeConfig } from './thinking-modes.js'; +import type { SessionTracker } from './session-tracker.js'; + +const MAX_CONCURRENT_TREES = 100; + +export class ThoughtTreeManager implements ThoughtTreeService, MCTSService { + private readonly trees = new Map(); + private readonly engine: MCTSEngine; + private readonly config: MCTSConfig; + private readonly modes = new Map(); + private readonly modeEngine = new ThinkingModeEngine(); + + constructor(config: MCTSConfig, sessionTracker?: SessionTracker) { + this.config = config; + this.engine = new MCTSEngine(config.explorationConstant); + + if (sessionTracker) { + sessionTracker.onEviction((evictedIds) => { + for (const sessionId of evictedIds) { + this.trees.delete(sessionId); + this.modes.delete(sessionId); + } + }); + sessionTracker.onPeriodicCleanup(() => this.cleanup()); + } + } + + recordThought(data: ThoughtData): ThoughtTreeRecordResult | null { + if (!this.config.enableAutoTree) return null; + + const { sessionId } = data; + if (!sessionId) return null; + + const tree = this.getOrCreateTree(sessionId); + const node = tree.addThought(data); + + const allNodes = tree.getAllNodes(); + const thoughtHistory = allNodes.map(n => ({ + thought: n.thought, + thoughtNumber: n.thoughtNumber, + totalThoughts: n.thoughtNumber, + nextThoughtNeeded: true, + })); + const context = thoughtHistory.slice(0, -1); + const prevConfidence = node.confidence ?? null; + const confidenceResult = metacognition.assessConfidence( + data.thought, + context, + prevConfidence, + ); + node.confidence = confidenceResult.confidence; + + // Auto-evaluate in fast mode + const modeConfig = this.modes.get(sessionId); + if (modeConfig) { + const autoVal = this.modeEngine.getAutoEvalValue(modeConfig); + if (autoVal !== null) { + this.engine.backpropagate(tree, node.nodeId, autoVal); + } + } + + const treeStats = this.engine.getTreeStats(tree); + + const result: ThoughtTreeRecordResult = { + nodeId: node.nodeId, + parentNodeId: node.parentId, + treeStats, + }; + + // Generate mode guidance if mode is active (reuse pre-computed stats) + if (modeConfig) { + result.modeGuidance = this.modeEngine.generateGuidance( + modeConfig, tree, this.engine, treeStats, + ); + + if (result.modeGuidance) { + node.strategyUsed = result.modeGuidance.strategyGuidance ?? modeConfig.suggestStrategy; + const primaryPersp = result.modeGuidance.perspectiveSuggestions[0]; + node.perspectiveUsed = primaryPersp?.perspective ?? 'none'; + } + } + + return result; + } + + backtrack(sessionId: string, nodeId: string): BacktrackResult { + const tree = this.getTree(sessionId); + const node = tree.setCursor(nodeId); + const children = tree.getChildren(nodeId); + + return { + node: this.engine.toNodeInfo(node), + children: children.map(c => this.engine.toNodeInfo(c)), + treeStats: this.engine.getTreeStats(tree), + }; + } + + findNodeByThoughtNumber(sessionId: string, thoughtNumber: number): TreeNodeInfo | null { + const tree = this.trees.get(sessionId); + if (!tree) return null; + const node = tree.findNodeByThoughtNumber(thoughtNumber); + return node ? this.engine.toNodeInfo(node) : null; + } + + evaluate(sessionId: string, nodeId: string, value: number): EvaluateResult { + const tree = this.getTree(sessionId); + const node = tree.getNode(nodeId); + if (!node) { + throw new TreeError(`Node not found: ${nodeId}`); + } + + const nodesUpdated = this.engine.backpropagate(tree, nodeId, value); + + const modeConfig = this.modes.get(sessionId); + if (modeConfig) { + const guidance = this.modeEngine.generateGuidance( + modeConfig, tree, this.engine, + ); + metacognition.recordEvaluation( + guidance.problemType ?? 'unknown', + node.strategyUsed ?? modeConfig.suggestStrategy, + node.perspectiveUsed ?? 'none', + value, + ); + } + + return { + nodeId, + newVisitCount: node.visitCount, + newAverageValue: node.visitCount > 0 ? node.totalValue / node.visitCount : 0, + nodesUpdated, + treeStats: this.engine.getTreeStats(tree), + }; + } + + suggest(sessionId: string, strategy: 'explore' | 'exploit' | 'balanced' = 'balanced'): SuggestResult { + const tree = this.getTree(sessionId); + const result = this.engine.suggestNext(tree, strategy); + + return { + suggestion: result.suggestion, + alternatives: result.alternatives, + treeStats: this.engine.getTreeStats(tree), + }; + } + + getSummary(sessionId: string, maxDepth?: number): ThinkingSummary { + const tree = this.getTree(sessionId); + + return { + bestPath: this.engine.extractBestPath(tree), + treeStructure: tree.toJSON(maxDepth), + treeStats: this.engine.getTreeStats(tree), + }; + } + + setMode(sessionId: string, mode: ThinkingMode): ThinkingModeConfig { + const config = this.modeEngine.getPreset(mode); + this.modes.set(sessionId, config); + // Ensure tree exists for this session + this.getOrCreateTree(sessionId); + return config; + } + + getMode(sessionId: string): ThinkingModeConfig | null { + return this.modes.get(sessionId) ?? null; + } + + cleanup(): void { + const now = Date.now(); + + // Remove expired trees and their mode configs + for (const [sessionId, tree] of this.trees.entries()) { + if (now - tree.lastAccessed > this.config.maxTreeAge) { + this.trees.delete(sessionId); + this.modes.delete(sessionId); + } + } + + // Cap at MAX_CONCURRENT_TREES, evict LRU + if (this.trees.size > MAX_CONCURRENT_TREES) { + const sorted = Array.from(this.trees.entries()) + .sort((a, b) => a[1].lastAccessed - b[1].lastAccessed); + + const toRemove = this.trees.size - MAX_CONCURRENT_TREES; + for (let i = 0; i < toRemove; i++) { + this.trees.delete(sorted[i][0]); + this.modes.delete(sorted[i][0]); + } + } + } + + destroy(): void { + this.trees.clear(); + this.modes.clear(); + } + + private getOrCreateTree(sessionId: string): ThoughtTree { + let tree = this.trees.get(sessionId); + if (!tree) { + tree = new ThoughtTree(sessionId, this.config.maxNodesPerTree); + this.trees.set(sessionId, tree); + } + return tree; + } + + private getTree(sessionId: string): ThoughtTree { + const tree = this.trees.get(sessionId); + if (!tree) { + throw new TreeError(`No thought tree found for session: ${sessionId}`); + } + tree.lastAccessed = Date.now(); + return tree; + } + +} diff --git a/src/sequentialthinking/thought-tree.ts b/src/sequentialthinking/thought-tree.ts new file mode 100644 index 0000000000..62e5271c4e --- /dev/null +++ b/src/sequentialthinking/thought-tree.ts @@ -0,0 +1,317 @@ +import type { ThoughtData } from './interfaces.js'; + +export interface ThoughtNode { + nodeId: string; + parentId: string | null; + children: string[]; + depth: number; + visitCount: number; + totalValue: number; + isTerminal: boolean; + thoughtNumber: number; + thought: string; + sessionId: string; + branchId?: string; + isRevision?: boolean; + revisesThought?: number; + branchFromThought?: number; + confidence?: number; + strategyUsed?: string; + perspectiveUsed?: string; +} + +export class ThoughtTree { + private readonly nodes = new Map(); + private readonly thoughtNumberIndex = new Map(); + private rootId: string | null = null; + private cursorId: string | null = null; + private readonly maxNodes: number; + readonly sessionId: string; + lastAccessed: number; + + constructor(sessionId: string, maxNodes: number) { + this.sessionId = sessionId; + this.maxNodes = maxNodes; + this.lastAccessed = Date.now(); + } + + get size(): number { + return this.nodes.size; + } + + get root(): ThoughtNode | undefined { + return this.rootId ? this.nodes.get(this.rootId) : undefined; + } + + get cursor(): ThoughtNode | undefined { + return this.cursorId ? this.nodes.get(this.cursorId) : undefined; + } + + getNode(nodeId: string): ThoughtNode | undefined { + return this.nodes.get(nodeId); + } + + private cursorFallback(): { parentId: string | null; depth: number } { + return { + parentId: this.cursorId, + depth: this.cursor ? this.cursor.depth + 1 : 0, + }; + } + + private resolveBranchParent( + branchFromThought: number, + ): { parentId: string | null; depth: number } { + const branchParent = this.findNodeByThoughtNumber( + branchFromThought, + ); + if (!branchParent) return this.cursorFallback(); + return { + parentId: branchParent.nodeId, + depth: branchParent.depth + 1, + }; + } + + private resolveRevisionParent( + revisesThought: number, + ): { parentId: string | null; depth: number } { + const revisedNode = this.findNodeByThoughtNumber(revisesThought); + if (!revisedNode) return this.cursorFallback(); + if (revisedNode.parentId === null) { + return { + parentId: revisedNode.nodeId, + depth: revisedNode.depth + 1, + }; + } + const { parentId } = revisedNode; + const parent = parentId + ? this.nodes.get(parentId) : undefined; + return { parentId, depth: parent ? parent.depth + 1 : 0 }; + } + + private resolveParent( + data: ThoughtData, + ): { parentId: string | null; depth: number } { + if (this.rootId === null) return { parentId: null, depth: 0 }; + if (data.branchFromThought) { + return this.resolveBranchParent(data.branchFromThought); + } + if (data.isRevision && data.revisesThought) { + return this.resolveRevisionParent(data.revisesThought); + } + return this.cursorFallback(); + } + + private linkToParent(nodeId: string, parentId: string | null): void { + if (parentId === null) return; + const parent = this.nodes.get(parentId); + if (parent) parent.children.push(nodeId); + } + + private indexThoughtNumber( + thoughtNumber: number, + nodeId: string, + ): void { + const existing = this.thoughtNumberIndex.get(thoughtNumber) ?? []; + existing.push(nodeId); + this.thoughtNumberIndex.set(thoughtNumber, existing); + } + + addThought(data: ThoughtData): ThoughtNode { + this.lastAccessed = Date.now(); + const nodeId = this.generateNodeId(); + const { parentId, depth } = this.resolveParent(data); + + const node: ThoughtNode = { + nodeId, + parentId, + children: [], + depth, + visitCount: 0, + totalValue: 0, + isTerminal: !data.nextThoughtNeeded, + thoughtNumber: data.thoughtNumber, + thought: data.thought, + sessionId: data.sessionId ?? this.sessionId, + branchId: data.branchId, + isRevision: data.isRevision, + revisesThought: data.revisesThought, + branchFromThought: data.branchFromThought, + }; + + this.nodes.set(nodeId, node); + this.linkToParent(nodeId, parentId); + this.indexThoughtNumber(data.thoughtNumber, nodeId); + + if (this.rootId === null) this.rootId = nodeId; + this.cursorId = nodeId; + + if (this.nodes.size > this.maxNodes) this.prune(); + + return node; + } + + setCursor(nodeId: string): ThoughtNode { + const node = this.nodes.get(nodeId); + if (!node) { + throw new Error(`Node not found: ${nodeId}`); + } + this.cursorId = nodeId; + this.lastAccessed = Date.now(); + return node; + } + + findNodeByThoughtNumber(thoughtNumber: number): ThoughtNode | undefined { + const nodeIds = this.thoughtNumberIndex.get(thoughtNumber); + if (!nodeIds || nodeIds.length === 0) return undefined; + + if (nodeIds.length === 1) { + return this.nodes.get(nodeIds[0]); + } + + // Multiple nodes with same thoughtNumber: prefer cursor's ancestor + if (this.cursorId) { + const ancestorIds = new Set(this.getAncestorPath(this.cursorId).map(n => n.nodeId)); + for (const id of nodeIds) { + if (ancestorIds.has(id)) { + return this.nodes.get(id); + } + } + } + + // Fallback: return the first one + return this.nodes.get(nodeIds[0]); + } + + getAncestorPath(nodeId: string): ThoughtNode[] { + const path: ThoughtNode[] = []; + let current = this.nodes.get(nodeId); + while (current) { + path.push(current); + if (current.parentId === null) break; + current = this.nodes.get(current.parentId); + } + path.reverse(); + return path; + } + + getChildren(nodeId: string): ThoughtNode[] { + const node = this.nodes.get(nodeId); + if (!node) return []; + return node.children + .map(id => this.nodes.get(id)) + .filter((n): n is ThoughtNode => n !== undefined); + } + + getLeafNodes(): ThoughtNode[] { + const leaves: ThoughtNode[] = []; + for (const node of this.nodes.values()) { + if (node.children.length === 0) { + leaves.push(node); + } + } + return leaves; + } + + getExpandableNodes(): ThoughtNode[] { + const expandable: ThoughtNode[] = []; + for (const node of this.nodes.values()) { + if (!node.isTerminal) { + expandable.push(node); + } + } + return expandable; + } + + getAllNodes(): ThoughtNode[] { + return Array.from(this.nodes.values()); + } + + toJSON(maxDepth?: number): unknown { + if (!this.rootId) return null; + return this.serializeNode(this.rootId, 0, maxDepth); + } + + private serializeNode(nodeId: string, currentDepth: number, maxDepth?: number): unknown { + const node = this.nodes.get(nodeId); + if (!node) return null; + + const result: Record = { + nodeId: node.nodeId, + thoughtNumber: node.thoughtNumber, + thought: node.thought.substring(0, 100) + (node.thought.length > 100 ? '...' : ''), + depth: node.depth, + visitCount: node.visitCount, + averageValue: node.visitCount > 0 ? node.totalValue / node.visitCount : 0, + isTerminal: node.isTerminal, + isCursor: node.nodeId === this.cursorId, + childCount: node.children.length, + }; + + if (maxDepth !== undefined && currentDepth >= maxDepth) { + if (node.children.length > 0) { + result.children = `[${node.children.length} children truncated]`; + } + return result; + } + + if (node.children.length > 0) { + result.children = node.children + .map(id => this.serializeNode(id, currentDepth + 1, maxDepth)) + .filter(n => n !== null); + } + + return result; + } + + prune(): void { + if (this.nodes.size <= this.maxNodes) return; + + // Collect all prunable leaves (not root, not cursor), sorted by value ascending + const prunableLeaves = this.getLeafNodes() + .filter(leaf => leaf.nodeId !== this.rootId && leaf.nodeId !== this.cursorId) + .map(leaf => ({ + leaf, + avgValue: leaf.visitCount > 0 ? leaf.totalValue / leaf.visitCount : 0, + })) + .sort((a, b) => a.avgValue - b.avgValue); + + // Remove worst leaves until under capacity + for (const { leaf } of prunableLeaves) { + if (this.nodes.size <= this.maxNodes) break; + this.removeNode(leaf.nodeId); + } + } + + private removeNode(nodeId: string): void { + const node = this.nodes.get(nodeId); + if (!node) return; + + // Remove from parent's children + if (node.parentId) { + const parent = this.nodes.get(node.parentId); + if (parent) { + parent.children = parent.children.filter(id => id !== nodeId); + } + } + + // Remove from thought number index + const indexIds = this.thoughtNumberIndex.get(node.thoughtNumber); + if (indexIds) { + const filtered = indexIds.filter(id => id !== nodeId); + if (filtered.length === 0) { + this.thoughtNumberIndex.delete(node.thoughtNumber); + } else { + this.thoughtNumberIndex.set(node.thoughtNumber, filtered); + } + } + + this.nodes.delete(nodeId); + } + + private nodeCounter = 0; + + private generateNodeId(): string { + this.nodeCounter++; + return `node_${this.nodeCounter}_${Date.now().toString(36)}`; + } +} diff --git a/src/sequentialthinking/tsconfig.json b/src/sequentialthinking/tsconfig.json index d2d86555b0..68223802c7 100644 --- a/src/sequentialthinking/tsconfig.json +++ b/src/sequentialthinking/tsconfig.json @@ -1,14 +1,27 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "lib": ["ES2022"], "outDir": "./dist", - "rootDir": "." + "rootDir": ".", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "resolveJsonModule": true }, "include": [ "./**/*.ts" ], "exclude": [ "**/*.test.ts", - "vitest.config.ts" + "vitest.config.ts", + "node_modules", + "dist" ] } diff --git a/src/sequentialthinking/typedoc.json b/src/sequentialthinking/typedoc.json new file mode 100644 index 0000000000..7f5a43cd92 --- /dev/null +++ b/src/sequentialthinking/typedoc.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["./index.ts"], + "entryPointStrategy": "expand", + "out": "docs", + "name": "Sequential Thinking MCP Server", + "includeVersion": true, + "readme": "README.md", + "excludePrivate": true, + "excludeProtected": false, + "plugin": [], + "theme": "default", + "navigationLinks": { + "GitHub": "https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking" + } +} diff --git a/src/sequentialthinking/vitest.config.ts b/src/sequentialthinking/vitest.config.ts index d414ec8f52..3e23b3acf0 100644 --- a/src/sequentialthinking/vitest.config.ts +++ b/src/sequentialthinking/vitest.config.ts @@ -4,11 +4,13 @@ export default defineConfig({ test: { globals: true, environment: 'node', - include: ['**/__tests__/**/*.test.ts'], + include: ['**/__tests__/**/**/*.test.ts'], + setupFiles: ['./__tests__/helpers/mocks.ts'], + clearMocks: true, coverage: { provider: 'v8', include: ['**/*.ts'], - exclude: ['**/__tests__/**', '**/dist/**'], + exclude: ['**/__tests__/**', '**/dist/**', '**/index.ts'], }, }, });