xiaozhi-client 2.3.0-beta.2 → 2.3.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/WebServer.js +13 -8
- package/dist/backend/WebServer.js.map +1 -1
- package/dist/backend/WebServerLauncher.js +13 -8
- package/dist/backend/WebServerLauncher.js.map +1 -1
- package/dist/backend/package.json +1 -2
- package/dist/frontend/assets/index-COIgGxBW.js +81 -0
- package/dist/frontend/assets/index-COIgGxBW.js.map +1 -0
- package/dist/frontend/assets/index-Cc1OJDGG.css +1 -0
- package/dist/frontend/index.html +2 -2
- package/package.json +7 -8
- package/dist/frontend/assets/index-C3xvW3AQ.js +0 -81
- package/dist/frontend/assets/index-C3xvW3AQ.js.map +0 -1
- package/dist/frontend/assets/index-CLIN00a1.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js","../../apps/backend/WebServer.ts","../../apps/backend/Logger.ts","../../apps/backend/utils/prompt-utils.ts","../../apps/backend/handlers/config.handler.ts","../../apps/backend/handlers/base.handler.ts","../../apps/backend/lib/coze/index.ts","../../apps/backend/lib/coze/config.ts","../../apps/backend/lib/coze/client.ts","../../apps/backend/lib/coze/service.ts","../../apps/backend/handlers/coze.handler.ts","../../apps/backend/constants/api.constants.ts","../../apps/backend/constants/http.constants.ts","../../apps/backend/constants/mcp.constants.ts","../../apps/backend/constants/event.constants.ts","../../apps/backend/constants/timeout.constants.ts","../../apps/backend/constants/cache.constants.ts","../../apps/backend/constants/voices.ts","../../apps/backend/utils/websocket-helper.ts","../../apps/backend/handlers/heartbeat.handler.ts","../../apps/backend/services/event-bus.service.ts","../../apps/backend/handlers/endpoint.handler.ts","../../apps/backend/lib/mcp/manager.ts","../../apps/backend/lib/mcp/types.ts","../../apps/backend/types/mcp.ts","../../apps/backend/types/timeout.ts","../../apps/backend/lib/mcp/custom.ts","../../apps/backend/lib/mcp/log.ts","../../apps/backend/utils/path-utils.ts","../../apps/backend/lib/mcp/message.ts","../../apps/backend/lib/mcp/connection.ts","../../apps/backend/lib/mcp/utils.ts","../../apps/backend/lib/mcp/cache.ts","../../apps/backend/types/hono.context.ts","../../apps/backend/handlers/mcp.handler.ts","../../apps/backend/errors/mcp-errors.ts","../../apps/backend/handlers/mcp-manage.handler.ts","../../apps/backend/handlers/realtime-notification.handler.ts","../../apps/backend/handlers/service.handler.ts","../../apps/backend/handlers/static-file.handler.ts","../../apps/backend/handlers/status.handler.ts","../../apps/backend/types/toolApi.ts","../../apps/backend/utils/toolSorters.ts","../../apps/backend/handlers/mcp-tool.handler.ts","../../apps/backend/handlers/mcp-tool-log.handler.ts","../../apps/backend/lib/npm/manager.ts","../../apps/backend/handlers/update.handler.ts","../../apps/backend/handlers/version.handler.ts","../../apps/backend/handlers/tts.handler.ts","../../apps/backend/handlers/esp32.handler.ts","../../apps/backend/middlewares/logger.middleware.ts","../../apps/backend/middlewares/cors.middleware.ts","../../apps/backend/middlewares/error.middleware.ts","../../apps/backend/middlewares/response-enhancer.middleware.ts","../../apps/backend/errors/mcp-errors.middleware.ts","../../apps/backend/middlewares/mcpServiceManager.middleware.ts","../../apps/backend/middlewares/endpointManager.middleware.ts","../../apps/backend/middlewares/endpoints.middleware.ts","../../apps/backend/services/status.service.ts","../../apps/backend/services/notification.service.ts","../../apps/backend/routes/types.ts","../../apps/backend/routes/RouteManager.ts","../../apps/backend/routes/domains/config.route.ts","../../apps/backend/routes/domains/status.route.ts","../../apps/backend/routes/domains/tools.route.ts","../../apps/backend/routes/domains/mcp.route.ts","../../apps/backend/routes/domains/version.route.ts","../../apps/backend/routes/domains/services.route.ts","../../apps/backend/routes/domains/update.route.ts","../../apps/backend/routes/domains/static.route.ts","../../apps/backend/routes/domains/coze.route.ts","../../apps/backend/routes/domains/tool-logs.route.ts","../../apps/backend/routes/domains/mcpserver.route.ts","../../apps/backend/routes/domains/endpoint.route.ts","../../apps/backend/routes/domains/misc.route.ts","../../apps/backend/routes/domains/tts.route.ts","../../apps/backend/routes/domains/esp32.route.ts"],"sourcesContent":["'use strict'\n\n// Note: this is the semver.org version of the spec that it implements\n// Not necessarily the package version of this code.\nconst SEMVER_SPEC_VERSION = '2.0.0'\n\nconst MAX_LENGTH = 256\nconst MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||\n/* istanbul ignore next */ 9007199254740991\n\n// Max safe segment length for coercion.\nconst MAX_SAFE_COMPONENT_LENGTH = 16\n\n// Max safe length for a build identifier. The max length minus 6 characters for\n// the shortest version with a build 0.0.0+BUILD.\nconst MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6\n\nconst RELEASE_TYPES = [\n 'major',\n 'premajor',\n 'minor',\n 'preminor',\n 'patch',\n 'prepatch',\n 'prerelease',\n]\n\nmodule.exports = {\n MAX_LENGTH,\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_SAFE_INTEGER,\n RELEASE_TYPES,\n SEMVER_SPEC_VERSION,\n FLAG_INCLUDE_PRERELEASE: 0b001,\n FLAG_LOOSE: 0b010,\n}\n","'use strict'\n\nconst debug = (\n typeof process === 'object' &&\n process.env &&\n process.env.NODE_DEBUG &&\n /\\bsemver\\b/i.test(process.env.NODE_DEBUG)\n) ? (...args) => console.error('SEMVER', ...args)\n : () => {}\n\nmodule.exports = debug\n","'use strict'\n\nconst {\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_LENGTH,\n} = require('./constants')\nconst debug = require('./debug')\nexports = module.exports = {}\n\n// The actual regexps go on exports.re\nconst re = exports.re = []\nconst safeRe = exports.safeRe = []\nconst src = exports.src = []\nconst safeSrc = exports.safeSrc = []\nconst t = exports.t = {}\nlet R = 0\n\nconst LETTERDASHNUMBER = '[a-zA-Z0-9-]'\n\n// Replace some greedy regex tokens to prevent regex dos issues. These regex are\n// used internally via the safeRe object since all inputs in this library get\n// normalized first to trim and collapse all extra whitespace. The original\n// regexes are exported for userland consumption and lower level usage. A\n// future breaking change could export the safer regex only with a note that\n// all input should have extra whitespace removed.\nconst safeRegexReplacements = [\n ['\\\\s', 1],\n ['\\\\d', MAX_LENGTH],\n [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],\n]\n\nconst makeSafeRegex = (value) => {\n for (const [token, max] of safeRegexReplacements) {\n value = value\n .split(`${token}*`).join(`${token}{0,${max}}`)\n .split(`${token}+`).join(`${token}{1,${max}}`)\n }\n return value\n}\n\nconst createToken = (name, value, isGlobal) => {\n const safe = makeSafeRegex(value)\n const index = R++\n debug(name, index, value)\n t[name] = index\n src[index] = value\n safeSrc[index] = safe\n re[index] = new RegExp(value, isGlobal ? 'g' : undefined)\n safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)\n}\n\n// The following Regular Expressions can be used for tokenizing,\n// validating, and parsing SemVer version strings.\n\n// ## Numeric Identifier\n// A single `0`, or a non-zero digit followed by zero or more digits.\n\ncreateToken('NUMERICIDENTIFIER', '0|[1-9]\\\\d*')\ncreateToken('NUMERICIDENTIFIERLOOSE', '\\\\d+')\n\n// ## Non-numeric Identifier\n// Zero or more digits, followed by a letter or hyphen, and then zero or\n// more letters, digits, or hyphens.\n\ncreateToken('NONNUMERICIDENTIFIER', `\\\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)\n\n// ## Main Version\n// Three dot-separated numeric identifiers.\n\ncreateToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIER]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIER]})`)\n\ncreateToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIERLOOSE]})`)\n\n// ## Pre-release Version Identifier\n// A numeric identifier, or a non-numeric identifier.\n// Non-numberic identifiers include numberic identifiers but can be longer.\n// Therefore non-numberic identifiers must go first.\n\ncreateToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER]\n}|${src[t.NUMERICIDENTIFIER]})`)\n\ncreateToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER]\n}|${src[t.NUMERICIDENTIFIERLOOSE]})`)\n\n// ## Pre-release Version\n// Hyphen, followed by one or more dot-separated pre-release version\n// identifiers.\n\ncreateToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]\n}(?:\\\\.${src[t.PRERELEASEIDENTIFIER]})*))`)\n\ncreateToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]\n}(?:\\\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)\n\n// ## Build Metadata Identifier\n// Any combination of digits, letters, or hyphens.\n\ncreateToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)\n\n// ## Build Metadata\n// Plus sign, followed by one or more period-separated build metadata\n// identifiers.\n\ncreateToken('BUILD', `(?:\\\\+(${src[t.BUILDIDENTIFIER]\n}(?:\\\\.${src[t.BUILDIDENTIFIER]})*))`)\n\n// ## Full Version String\n// A main version, followed optionally by a pre-release version and\n// build metadata.\n\n// Note that the only major, minor, patch, and pre-release sections of\n// the version string are capturing groups. The build metadata is not a\n// capturing group, because it should not ever be used in version\n// comparison.\n\ncreateToken('FULLPLAIN', `v?${src[t.MAINVERSION]\n}${src[t.PRERELEASE]}?${\n src[t.BUILD]}?`)\n\ncreateToken('FULL', `^${src[t.FULLPLAIN]}$`)\n\n// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.\n// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty\n// common in the npm registry.\ncreateToken('LOOSEPLAIN', `[v=\\\\s]*${src[t.MAINVERSIONLOOSE]\n}${src[t.PRERELEASELOOSE]}?${\n src[t.BUILD]}?`)\n\ncreateToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)\n\ncreateToken('GTLT', '((?:<|>)?=?)')\n\n// Something like \"2.*\" or \"1.2.x\".\n// Note that \"x.x\" is a valid xRange identifer, meaning \"any version\"\n// Only the first item is strictly required.\ncreateToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`)\ncreateToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\\\*`)\n\ncreateToken('XRANGEPLAIN', `[v=\\\\s]*(${src[t.XRANGEIDENTIFIER]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIER]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIER]})` +\n `(?:${src[t.PRERELEASE]})?${\n src[t.BUILD]}?` +\n `)?)?`)\n\ncreateToken('XRANGEPLAINLOOSE', `[v=\\\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:${src[t.PRERELEASELOOSE]})?${\n src[t.BUILD]}?` +\n `)?)?`)\n\ncreateToken('XRANGE', `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAIN]}$`)\ncreateToken('XRANGELOOSE', `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAINLOOSE]}$`)\n\n// Coercion.\n// Extract anything that could conceivably be a part of a valid semver\ncreateToken('COERCEPLAIN', `${'(^|[^\\\\d])' +\n '(\\\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +\n `(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +\n `(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)\ncreateToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\\\d])`)\ncreateToken('COERCEFULL', src[t.COERCEPLAIN] +\n `(?:${src[t.PRERELEASE]})?` +\n `(?:${src[t.BUILD]})?` +\n `(?:$|[^\\\\d])`)\ncreateToken('COERCERTL', src[t.COERCE], true)\ncreateToken('COERCERTLFULL', src[t.COERCEFULL], true)\n\n// Tilde ranges.\n// Meaning is \"reasonably at or greater than\"\ncreateToken('LONETILDE', '(?:~>?)')\n\ncreateToken('TILDETRIM', `(\\\\s*)${src[t.LONETILDE]}\\\\s+`, true)\nexports.tildeTrimReplace = '$1~'\n\ncreateToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)\ncreateToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)\n\n// Caret ranges.\n// Meaning is \"at least and backwards compatible with\"\ncreateToken('LONECARET', '(?:\\\\^)')\n\ncreateToken('CARETTRIM', `(\\\\s*)${src[t.LONECARET]}\\\\s+`, true)\nexports.caretTrimReplace = '$1^'\n\ncreateToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)\ncreateToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)\n\n// A simple gt/lt/eq thing, or just \"\" to indicate \"any version\"\ncreateToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\\\s*(${src[t.LOOSEPLAIN]})$|^$`)\ncreateToken('COMPARATOR', `^${src[t.GTLT]}\\\\s*(${src[t.FULLPLAIN]})$|^$`)\n\n// An expression to strip any whitespace between the gtlt and the thing\n// it modifies, so that `> 1.2.3` ==> `>1.2.3`\ncreateToken('COMPARATORTRIM', `(\\\\s*)${src[t.GTLT]\n}\\\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)\nexports.comparatorTrimReplace = '$1$2$3'\n\n// Something like `1.2.3 - 1.2.4`\n// Note that these all use the loose form, because they'll be\n// checked against either the strict or loose comparator form\n// later.\ncreateToken('HYPHENRANGE', `^\\\\s*(${src[t.XRANGEPLAIN]})` +\n `\\\\s+-\\\\s+` +\n `(${src[t.XRANGEPLAIN]})` +\n `\\\\s*$`)\n\ncreateToken('HYPHENRANGELOOSE', `^\\\\s*(${src[t.XRANGEPLAINLOOSE]})` +\n `\\\\s+-\\\\s+` +\n `(${src[t.XRANGEPLAINLOOSE]})` +\n `\\\\s*$`)\n\n// Star ranges basically just allow anything at all.\ncreateToken('STAR', '(<|>)?=?\\\\s*\\\\*')\n// >=0.0.0 is like a star\ncreateToken('GTE0', '^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$')\ncreateToken('GTE0PRE', '^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$')\n","'use strict'\n\n// parse out just the options we care about\nconst looseOption = Object.freeze({ loose: true })\nconst emptyOpts = Object.freeze({ })\nconst parseOptions = options => {\n if (!options) {\n return emptyOpts\n }\n\n if (typeof options !== 'object') {\n return looseOption\n }\n\n return options\n}\nmodule.exports = parseOptions\n","'use strict'\n\nconst numeric = /^[0-9]+$/\nconst compareIdentifiers = (a, b) => {\n if (typeof a === 'number' && typeof b === 'number') {\n return a === b ? 0 : a < b ? -1 : 1\n }\n\n const anum = numeric.test(a)\n const bnum = numeric.test(b)\n\n if (anum && bnum) {\n a = +a\n b = +b\n }\n\n return a === b ? 0\n : (anum && !bnum) ? -1\n : (bnum && !anum) ? 1\n : a < b ? -1\n : 1\n}\n\nconst rcompareIdentifiers = (a, b) => compareIdentifiers(b, a)\n\nmodule.exports = {\n compareIdentifiers,\n rcompareIdentifiers,\n}\n","'use strict'\n\nconst debug = require('../internal/debug')\nconst { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')\nconst { safeRe: re, t } = require('../internal/re')\n\nconst parseOptions = require('../internal/parse-options')\nconst { compareIdentifiers } = require('../internal/identifiers')\nclass SemVer {\n constructor (version, options) {\n options = parseOptions(options)\n\n if (version instanceof SemVer) {\n if (version.loose === !!options.loose &&\n version.includePrerelease === !!options.includePrerelease) {\n return version\n } else {\n version = version.version\n }\n } else if (typeof version !== 'string') {\n throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof version}\".`)\n }\n\n if (version.length > MAX_LENGTH) {\n throw new TypeError(\n `version is longer than ${MAX_LENGTH} characters`\n )\n }\n\n debug('SemVer', version, options)\n this.options = options\n this.loose = !!options.loose\n // this isn't actually relevant for versions, but keep it so that we\n // don't run into trouble passing this.options around.\n this.includePrerelease = !!options.includePrerelease\n\n const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])\n\n if (!m) {\n throw new TypeError(`Invalid Version: ${version}`)\n }\n\n this.raw = version\n\n // these are actually numbers\n this.major = +m[1]\n this.minor = +m[2]\n this.patch = +m[3]\n\n if (this.major > MAX_SAFE_INTEGER || this.major < 0) {\n throw new TypeError('Invalid major version')\n }\n\n if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {\n throw new TypeError('Invalid minor version')\n }\n\n if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {\n throw new TypeError('Invalid patch version')\n }\n\n // numberify any prerelease numeric ids\n if (!m[4]) {\n this.prerelease = []\n } else {\n this.prerelease = m[4].split('.').map((id) => {\n if (/^[0-9]+$/.test(id)) {\n const num = +id\n if (num >= 0 && num < MAX_SAFE_INTEGER) {\n return num\n }\n }\n return id\n })\n }\n\n this.build = m[5] ? m[5].split('.') : []\n this.format()\n }\n\n format () {\n this.version = `${this.major}.${this.minor}.${this.patch}`\n if (this.prerelease.length) {\n this.version += `-${this.prerelease.join('.')}`\n }\n return this.version\n }\n\n toString () {\n return this.version\n }\n\n compare (other) {\n debug('SemVer.compare', this.version, this.options, other)\n if (!(other instanceof SemVer)) {\n if (typeof other === 'string' && other === this.version) {\n return 0\n }\n other = new SemVer(other, this.options)\n }\n\n if (other.version === this.version) {\n return 0\n }\n\n return this.compareMain(other) || this.comparePre(other)\n }\n\n compareMain (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n if (this.major < other.major) {\n return -1\n }\n if (this.major > other.major) {\n return 1\n }\n if (this.minor < other.minor) {\n return -1\n }\n if (this.minor > other.minor) {\n return 1\n }\n if (this.patch < other.patch) {\n return -1\n }\n if (this.patch > other.patch) {\n return 1\n }\n return 0\n }\n\n comparePre (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n // NOT having a prerelease is > having one\n if (this.prerelease.length && !other.prerelease.length) {\n return -1\n } else if (!this.prerelease.length && other.prerelease.length) {\n return 1\n } else if (!this.prerelease.length && !other.prerelease.length) {\n return 0\n }\n\n let i = 0\n do {\n const a = this.prerelease[i]\n const b = other.prerelease[i]\n debug('prerelease compare', i, a, b)\n if (a === undefined && b === undefined) {\n return 0\n } else if (b === undefined) {\n return 1\n } else if (a === undefined) {\n return -1\n } else if (a === b) {\n continue\n } else {\n return compareIdentifiers(a, b)\n }\n } while (++i)\n }\n\n compareBuild (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n let i = 0\n do {\n const a = this.build[i]\n const b = other.build[i]\n debug('build compare', i, a, b)\n if (a === undefined && b === undefined) {\n return 0\n } else if (b === undefined) {\n return 1\n } else if (a === undefined) {\n return -1\n } else if (a === b) {\n continue\n } else {\n return compareIdentifiers(a, b)\n }\n } while (++i)\n }\n\n // preminor will bump the version up to the next minor release, and immediately\n // down to pre-release. premajor and prepatch work the same way.\n inc (release, identifier, identifierBase) {\n if (release.startsWith('pre')) {\n if (!identifier && identifierBase === false) {\n throw new Error('invalid increment argument: identifier is empty')\n }\n // Avoid an invalid semver results\n if (identifier) {\n const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE])\n if (!match || match[1] !== identifier) {\n throw new Error(`invalid identifier: ${identifier}`)\n }\n }\n }\n\n switch (release) {\n case 'premajor':\n this.prerelease.length = 0\n this.patch = 0\n this.minor = 0\n this.major++\n this.inc('pre', identifier, identifierBase)\n break\n case 'preminor':\n this.prerelease.length = 0\n this.patch = 0\n this.minor++\n this.inc('pre', identifier, identifierBase)\n break\n case 'prepatch':\n // If this is already a prerelease, it will bump to the next version\n // drop any prereleases that might already exist, since they are not\n // relevant at this point.\n this.prerelease.length = 0\n this.inc('patch', identifier, identifierBase)\n this.inc('pre', identifier, identifierBase)\n break\n // If the input is a non-prerelease version, this acts the same as\n // prepatch.\n case 'prerelease':\n if (this.prerelease.length === 0) {\n this.inc('patch', identifier, identifierBase)\n }\n this.inc('pre', identifier, identifierBase)\n break\n case 'release':\n if (this.prerelease.length === 0) {\n throw new Error(`version ${this.raw} is not a prerelease`)\n }\n this.prerelease.length = 0\n break\n\n case 'major':\n // If this is a pre-major version, bump up to the same major version.\n // Otherwise increment major.\n // 1.0.0-5 bumps to 1.0.0\n // 1.1.0 bumps to 2.0.0\n if (\n this.minor !== 0 ||\n this.patch !== 0 ||\n this.prerelease.length === 0\n ) {\n this.major++\n }\n this.minor = 0\n this.patch = 0\n this.prerelease = []\n break\n case 'minor':\n // If this is a pre-minor version, bump up to the same minor version.\n // Otherwise increment minor.\n // 1.2.0-5 bumps to 1.2.0\n // 1.2.1 bumps to 1.3.0\n if (this.patch !== 0 || this.prerelease.length === 0) {\n this.minor++\n }\n this.patch = 0\n this.prerelease = []\n break\n case 'patch':\n // If this is not a pre-release version, it will increment the patch.\n // If it is a pre-release it will bump up to the same patch version.\n // 1.2.0-5 patches to 1.2.0\n // 1.2.0 patches to 1.2.1\n if (this.prerelease.length === 0) {\n this.patch++\n }\n this.prerelease = []\n break\n // This probably shouldn't be used publicly.\n // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.\n case 'pre': {\n const base = Number(identifierBase) ? 1 : 0\n\n if (this.prerelease.length === 0) {\n this.prerelease = [base]\n } else {\n let i = this.prerelease.length\n while (--i >= 0) {\n if (typeof this.prerelease[i] === 'number') {\n this.prerelease[i]++\n i = -2\n }\n }\n if (i === -1) {\n // didn't increment anything\n if (identifier === this.prerelease.join('.') && identifierBase === false) {\n throw new Error('invalid increment argument: identifier already exists')\n }\n this.prerelease.push(base)\n }\n }\n if (identifier) {\n // 1.2.0-beta.1 bumps to 1.2.0-beta.2,\n // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0\n let prerelease = [identifier, base]\n if (identifierBase === false) {\n prerelease = [identifier]\n }\n if (compareIdentifiers(this.prerelease[0], identifier) === 0) {\n if (isNaN(this.prerelease[1])) {\n this.prerelease = prerelease\n }\n } else {\n this.prerelease = prerelease\n }\n }\n break\n }\n default:\n throw new Error(`invalid increment argument: ${release}`)\n }\n this.raw = this.format()\n if (this.build.length) {\n this.raw += `+${this.build.join('.')}`\n }\n return this\n }\n}\n\nmodule.exports = SemVer\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst parse = (version, options, throwErrors = false) => {\n if (version instanceof SemVer) {\n return version\n }\n try {\n return new SemVer(version, options)\n } catch (er) {\n if (!throwErrors) {\n return null\n }\n throw er\n }\n}\n\nmodule.exports = parse\n","'use strict'\n\nconst parse = require('./parse')\nconst valid = (version, options) => {\n const v = parse(version, options)\n return v ? v.version : null\n}\nmodule.exports = valid\n","'use strict'\n\nconst parse = require('./parse')\nconst clean = (version, options) => {\n const s = parse(version.trim().replace(/^[=v]+/, ''), options)\n return s ? s.version : null\n}\nmodule.exports = clean\n","'use strict'\n\nconst SemVer = require('../classes/semver')\n\nconst inc = (version, release, options, identifier, identifierBase) => {\n if (typeof (options) === 'string') {\n identifierBase = identifier\n identifier = options\n options = undefined\n }\n\n try {\n return new SemVer(\n version instanceof SemVer ? version.version : version,\n options\n ).inc(release, identifier, identifierBase).version\n } catch (er) {\n return null\n }\n}\nmodule.exports = inc\n","'use strict'\n\nconst parse = require('./parse.js')\n\nconst diff = (version1, version2) => {\n const v1 = parse(version1, null, true)\n const v2 = parse(version2, null, true)\n const comparison = v1.compare(v2)\n\n if (comparison === 0) {\n return null\n }\n\n const v1Higher = comparison > 0\n const highVersion = v1Higher ? v1 : v2\n const lowVersion = v1Higher ? v2 : v1\n const highHasPre = !!highVersion.prerelease.length\n const lowHasPre = !!lowVersion.prerelease.length\n\n if (lowHasPre && !highHasPre) {\n // Going from prerelease -> no prerelease requires some special casing\n\n // If the low version has only a major, then it will always be a major\n // Some examples:\n // 1.0.0-1 -> 1.0.0\n // 1.0.0-1 -> 1.1.1\n // 1.0.0-1 -> 2.0.0\n if (!lowVersion.patch && !lowVersion.minor) {\n return 'major'\n }\n\n // If the main part has no difference\n if (lowVersion.compareMain(highVersion) === 0) {\n if (lowVersion.minor && !lowVersion.patch) {\n return 'minor'\n }\n return 'patch'\n }\n }\n\n // add the `pre` prefix if we are going to a prerelease version\n const prefix = highHasPre ? 'pre' : ''\n\n if (v1.major !== v2.major) {\n return prefix + 'major'\n }\n\n if (v1.minor !== v2.minor) {\n return prefix + 'minor'\n }\n\n if (v1.patch !== v2.patch) {\n return prefix + 'patch'\n }\n\n // high and low are preleases\n return 'prerelease'\n}\n\nmodule.exports = diff\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst major = (a, loose) => new SemVer(a, loose).major\nmodule.exports = major\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst minor = (a, loose) => new SemVer(a, loose).minor\nmodule.exports = minor\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst patch = (a, loose) => new SemVer(a, loose).patch\nmodule.exports = patch\n","'use strict'\n\nconst parse = require('./parse')\nconst prerelease = (version, options) => {\n const parsed = parse(version, options)\n return (parsed && parsed.prerelease.length) ? parsed.prerelease : null\n}\nmodule.exports = prerelease\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst compare = (a, b, loose) =>\n new SemVer(a, loose).compare(new SemVer(b, loose))\n\nmodule.exports = compare\n","'use strict'\n\nconst compare = require('./compare')\nconst rcompare = (a, b, loose) => compare(b, a, loose)\nmodule.exports = rcompare\n","'use strict'\n\nconst compare = require('./compare')\nconst compareLoose = (a, b) => compare(a, b, true)\nmodule.exports = compareLoose\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst compareBuild = (a, b, loose) => {\n const versionA = new SemVer(a, loose)\n const versionB = new SemVer(b, loose)\n return versionA.compare(versionB) || versionA.compareBuild(versionB)\n}\nmodule.exports = compareBuild\n","'use strict'\n\nconst compareBuild = require('./compare-build')\nconst sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose))\nmodule.exports = sort\n","'use strict'\n\nconst compareBuild = require('./compare-build')\nconst rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose))\nmodule.exports = rsort\n","'use strict'\n\nconst compare = require('./compare')\nconst gt = (a, b, loose) => compare(a, b, loose) > 0\nmodule.exports = gt\n","'use strict'\n\nconst compare = require('./compare')\nconst lt = (a, b, loose) => compare(a, b, loose) < 0\nmodule.exports = lt\n","'use strict'\n\nconst compare = require('./compare')\nconst eq = (a, b, loose) => compare(a, b, loose) === 0\nmodule.exports = eq\n","'use strict'\n\nconst compare = require('./compare')\nconst neq = (a, b, loose) => compare(a, b, loose) !== 0\nmodule.exports = neq\n","'use strict'\n\nconst compare = require('./compare')\nconst gte = (a, b, loose) => compare(a, b, loose) >= 0\nmodule.exports = gte\n","'use strict'\n\nconst compare = require('./compare')\nconst lte = (a, b, loose) => compare(a, b, loose) <= 0\nmodule.exports = lte\n","'use strict'\n\nconst eq = require('./eq')\nconst neq = require('./neq')\nconst gt = require('./gt')\nconst gte = require('./gte')\nconst lt = require('./lt')\nconst lte = require('./lte')\n\nconst cmp = (a, op, b, loose) => {\n switch (op) {\n case '===':\n if (typeof a === 'object') {\n a = a.version\n }\n if (typeof b === 'object') {\n b = b.version\n }\n return a === b\n\n case '!==':\n if (typeof a === 'object') {\n a = a.version\n }\n if (typeof b === 'object') {\n b = b.version\n }\n return a !== b\n\n case '':\n case '=':\n case '==':\n return eq(a, b, loose)\n\n case '!=':\n return neq(a, b, loose)\n\n case '>':\n return gt(a, b, loose)\n\n case '>=':\n return gte(a, b, loose)\n\n case '<':\n return lt(a, b, loose)\n\n case '<=':\n return lte(a, b, loose)\n\n default:\n throw new TypeError(`Invalid operator: ${op}`)\n }\n}\nmodule.exports = cmp\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst parse = require('./parse')\nconst { safeRe: re, t } = require('../internal/re')\n\nconst coerce = (version, options) => {\n if (version instanceof SemVer) {\n return version\n }\n\n if (typeof version === 'number') {\n version = String(version)\n }\n\n if (typeof version !== 'string') {\n return null\n }\n\n options = options || {}\n\n let match = null\n if (!options.rtl) {\n match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE])\n } else {\n // Find the right-most coercible string that does not share\n // a terminus with a more left-ward coercible string.\n // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4'\n // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4'\n //\n // Walk through the string checking with a /g regexp\n // Manually set the index so as to pick up overlapping matches.\n // Stop when we get a match that ends at the string end, since no\n // coercible string can be more right-ward without the same terminus.\n const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL]\n let next\n while ((next = coerceRtlRegex.exec(version)) &&\n (!match || match.index + match[0].length !== version.length)\n ) {\n if (!match ||\n next.index + next[0].length !== match.index + match[0].length) {\n match = next\n }\n coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length\n }\n // leave it in a clean state\n coerceRtlRegex.lastIndex = -1\n }\n\n if (match === null) {\n return null\n }\n\n const major = match[2]\n const minor = match[3] || '0'\n const patch = match[4] || '0'\n const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : ''\n const build = options.includePrerelease && match[6] ? `+${match[6]}` : ''\n\n return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options)\n}\nmodule.exports = coerce\n","'use strict'\n\nclass LRUCache {\n constructor () {\n this.max = 1000\n this.map = new Map()\n }\n\n get (key) {\n const value = this.map.get(key)\n if (value === undefined) {\n return undefined\n } else {\n // Remove the key from the map and add it to the end\n this.map.delete(key)\n this.map.set(key, value)\n return value\n }\n }\n\n delete (key) {\n return this.map.delete(key)\n }\n\n set (key, value) {\n const deleted = this.delete(key)\n\n if (!deleted && value !== undefined) {\n // If cache is full, delete the least recently used item\n if (this.map.size >= this.max) {\n const firstKey = this.map.keys().next().value\n this.delete(firstKey)\n }\n\n this.map.set(key, value)\n }\n\n return this\n }\n}\n\nmodule.exports = LRUCache\n","'use strict'\n\nconst SPACE_CHARACTERS = /\\s+/g\n\n// hoisted class for cyclic dependency\nclass Range {\n constructor (range, options) {\n options = parseOptions(options)\n\n if (range instanceof Range) {\n if (\n range.loose === !!options.loose &&\n range.includePrerelease === !!options.includePrerelease\n ) {\n return range\n } else {\n return new Range(range.raw, options)\n }\n }\n\n if (range instanceof Comparator) {\n // just put it in the set and return\n this.raw = range.value\n this.set = [[range]]\n this.formatted = undefined\n return this\n }\n\n this.options = options\n this.loose = !!options.loose\n this.includePrerelease = !!options.includePrerelease\n\n // First reduce all whitespace as much as possible so we do not have to rely\n // on potentially slow regexes like \\s*. This is then stored and used for\n // future error messages as well.\n this.raw = range.trim().replace(SPACE_CHARACTERS, ' ')\n\n // First, split on ||\n this.set = this.raw\n .split('||')\n // map the range to a 2d array of comparators\n .map(r => this.parseRange(r.trim()))\n // throw out any comparator lists that are empty\n // this generally means that it was not a valid range, which is allowed\n // in loose mode, but will still throw if the WHOLE range is invalid.\n .filter(c => c.length)\n\n if (!this.set.length) {\n throw new TypeError(`Invalid SemVer Range: ${this.raw}`)\n }\n\n // if we have any that are not the null set, throw out null sets.\n if (this.set.length > 1) {\n // keep the first one, in case they're all null sets\n const first = this.set[0]\n this.set = this.set.filter(c => !isNullSet(c[0]))\n if (this.set.length === 0) {\n this.set = [first]\n } else if (this.set.length > 1) {\n // if we have any that are *, then the range is just *\n for (const c of this.set) {\n if (c.length === 1 && isAny(c[0])) {\n this.set = [c]\n break\n }\n }\n }\n }\n\n this.formatted = undefined\n }\n\n get range () {\n if (this.formatted === undefined) {\n this.formatted = ''\n for (let i = 0; i < this.set.length; i++) {\n if (i > 0) {\n this.formatted += '||'\n }\n const comps = this.set[i]\n for (let k = 0; k < comps.length; k++) {\n if (k > 0) {\n this.formatted += ' '\n }\n this.formatted += comps[k].toString().trim()\n }\n }\n }\n return this.formatted\n }\n\n format () {\n return this.range\n }\n\n toString () {\n return this.range\n }\n\n parseRange (range) {\n // memoize range parsing for performance.\n // this is a very hot path, and fully deterministic.\n const memoOpts =\n (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) |\n (this.options.loose && FLAG_LOOSE)\n const memoKey = memoOpts + ':' + range\n const cached = cache.get(memoKey)\n if (cached) {\n return cached\n }\n\n const loose = this.options.loose\n // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`\n const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]\n range = range.replace(hr, hyphenReplace(this.options.includePrerelease))\n debug('hyphen replace', range)\n\n // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`\n range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)\n debug('comparator trim', range)\n\n // `~ 1.2.3` => `~1.2.3`\n range = range.replace(re[t.TILDETRIM], tildeTrimReplace)\n debug('tilde trim', range)\n\n // `^ 1.2.3` => `^1.2.3`\n range = range.replace(re[t.CARETTRIM], caretTrimReplace)\n debug('caret trim', range)\n\n // At this point, the range is completely trimmed and\n // ready to be split into comparators.\n\n let rangeList = range\n .split(' ')\n .map(comp => parseComparator(comp, this.options))\n .join(' ')\n .split(/\\s+/)\n // >=0.0.0 is equivalent to *\n .map(comp => replaceGTE0(comp, this.options))\n\n if (loose) {\n // in loose mode, throw out any that are not valid comparators\n rangeList = rangeList.filter(comp => {\n debug('loose invalid filter', comp, this.options)\n return !!comp.match(re[t.COMPARATORLOOSE])\n })\n }\n debug('range list', rangeList)\n\n // if any comparators are the null set, then replace with JUST null set\n // if more than one comparator, remove any * comparators\n // also, don't include the same comparator more than once\n const rangeMap = new Map()\n const comparators = rangeList.map(comp => new Comparator(comp, this.options))\n for (const comp of comparators) {\n if (isNullSet(comp)) {\n return [comp]\n }\n rangeMap.set(comp.value, comp)\n }\n if (rangeMap.size > 1 && rangeMap.has('')) {\n rangeMap.delete('')\n }\n\n const result = [...rangeMap.values()]\n cache.set(memoKey, result)\n return result\n }\n\n intersects (range, options) {\n if (!(range instanceof Range)) {\n throw new TypeError('a Range is required')\n }\n\n return this.set.some((thisComparators) => {\n return (\n isSatisfiable(thisComparators, options) &&\n range.set.some((rangeComparators) => {\n return (\n isSatisfiable(rangeComparators, options) &&\n thisComparators.every((thisComparator) => {\n return rangeComparators.every((rangeComparator) => {\n return thisComparator.intersects(rangeComparator, options)\n })\n })\n )\n })\n )\n })\n }\n\n // if ANY of the sets match ALL of its comparators, then pass\n test (version) {\n if (!version) {\n return false\n }\n\n if (typeof version === 'string') {\n try {\n version = new SemVer(version, this.options)\n } catch (er) {\n return false\n }\n }\n\n for (let i = 0; i < this.set.length; i++) {\n if (testSet(this.set[i], version, this.options)) {\n return true\n }\n }\n return false\n }\n}\n\nmodule.exports = Range\n\nconst LRU = require('../internal/lrucache')\nconst cache = new LRU()\n\nconst parseOptions = require('../internal/parse-options')\nconst Comparator = require('./comparator')\nconst debug = require('../internal/debug')\nconst SemVer = require('./semver')\nconst {\n safeRe: re,\n t,\n comparatorTrimReplace,\n tildeTrimReplace,\n caretTrimReplace,\n} = require('../internal/re')\nconst { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require('../internal/constants')\n\nconst isNullSet = c => c.value === '<0.0.0-0'\nconst isAny = c => c.value === ''\n\n// take a set of comparators and determine whether there\n// exists a version which can satisfy it\nconst isSatisfiable = (comparators, options) => {\n let result = true\n const remainingComparators = comparators.slice()\n let testComparator = remainingComparators.pop()\n\n while (result && remainingComparators.length) {\n result = remainingComparators.every((otherComparator) => {\n return testComparator.intersects(otherComparator, options)\n })\n\n testComparator = remainingComparators.pop()\n }\n\n return result\n}\n\n// comprised of xranges, tildes, stars, and gtlt's at this point.\n// already replaced the hyphen ranges\n// turn into a set of JUST comparators.\nconst parseComparator = (comp, options) => {\n comp = comp.replace(re[t.BUILD], '')\n debug('comp', comp, options)\n comp = replaceCarets(comp, options)\n debug('caret', comp)\n comp = replaceTildes(comp, options)\n debug('tildes', comp)\n comp = replaceXRanges(comp, options)\n debug('xrange', comp)\n comp = replaceStars(comp, options)\n debug('stars', comp)\n return comp\n}\n\nconst isX = id => !id || id.toLowerCase() === 'x' || id === '*'\n\n// ~, ~> --> * (any, kinda silly)\n// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0\n// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0\n// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0\n// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0\n// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0\n// ~0.0.1 --> >=0.0.1 <0.1.0-0\nconst replaceTildes = (comp, options) => {\n return comp\n .trim()\n .split(/\\s+/)\n .map((c) => replaceTilde(c, options))\n .join(' ')\n}\n\nconst replaceTilde = (comp, options) => {\n const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]\n return comp.replace(r, (_, M, m, p, pr) => {\n debug('tilde', comp, _, M, m, p, pr)\n let ret\n\n if (isX(M)) {\n ret = ''\n } else if (isX(m)) {\n ret = `>=${M}.0.0 <${+M + 1}.0.0-0`\n } else if (isX(p)) {\n // ~1.2 == >=1.2.0 <1.3.0-0\n ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`\n } else if (pr) {\n debug('replaceTilde pr', pr)\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${+m + 1}.0-0`\n } else {\n // ~1.2.3 == >=1.2.3 <1.3.0-0\n ret = `>=${M}.${m}.${p\n } <${M}.${+m + 1}.0-0`\n }\n\n debug('tilde return', ret)\n return ret\n })\n}\n\n// ^ --> * (any, kinda silly)\n// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0\n// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0\n// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0\n// ^1.2.3 --> >=1.2.3 <2.0.0-0\n// ^1.2.0 --> >=1.2.0 <2.0.0-0\n// ^0.0.1 --> >=0.0.1 <0.0.2-0\n// ^0.1.0 --> >=0.1.0 <0.2.0-0\nconst replaceCarets = (comp, options) => {\n return comp\n .trim()\n .split(/\\s+/)\n .map((c) => replaceCaret(c, options))\n .join(' ')\n}\n\nconst replaceCaret = (comp, options) => {\n debug('caret', comp, options)\n const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]\n const z = options.includePrerelease ? '-0' : ''\n return comp.replace(r, (_, M, m, p, pr) => {\n debug('caret', comp, _, M, m, p, pr)\n let ret\n\n if (isX(M)) {\n ret = ''\n } else if (isX(m)) {\n ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`\n } else if (isX(p)) {\n if (M === '0') {\n ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`\n } else {\n ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`\n }\n } else if (pr) {\n debug('replaceCaret pr', pr)\n if (M === '0') {\n if (m === '0') {\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${m}.${+p + 1}-0`\n } else {\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${+m + 1}.0-0`\n }\n } else {\n ret = `>=${M}.${m}.${p}-${pr\n } <${+M + 1}.0.0-0`\n }\n } else {\n debug('no pr')\n if (M === '0') {\n if (m === '0') {\n ret = `>=${M}.${m}.${p\n }${z} <${M}.${m}.${+p + 1}-0`\n } else {\n ret = `>=${M}.${m}.${p\n }${z} <${M}.${+m + 1}.0-0`\n }\n } else {\n ret = `>=${M}.${m}.${p\n } <${+M + 1}.0.0-0`\n }\n }\n\n debug('caret return', ret)\n return ret\n })\n}\n\nconst replaceXRanges = (comp, options) => {\n debug('replaceXRanges', comp, options)\n return comp\n .split(/\\s+/)\n .map((c) => replaceXRange(c, options))\n .join(' ')\n}\n\nconst replaceXRange = (comp, options) => {\n comp = comp.trim()\n const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]\n return comp.replace(r, (ret, gtlt, M, m, p, pr) => {\n debug('xRange', comp, ret, gtlt, M, m, p, pr)\n const xM = isX(M)\n const xm = xM || isX(m)\n const xp = xm || isX(p)\n const anyX = xp\n\n if (gtlt === '=' && anyX) {\n gtlt = ''\n }\n\n // if we're including prereleases in the match, then we need\n // to fix this to -0, the lowest possible prerelease value\n pr = options.includePrerelease ? '-0' : ''\n\n if (xM) {\n if (gtlt === '>' || gtlt === '<') {\n // nothing is allowed\n ret = '<0.0.0-0'\n } else {\n // nothing is forbidden\n ret = '*'\n }\n } else if (gtlt && anyX) {\n // we know patch is an x, because we have any x at all.\n // replace X with 0\n if (xm) {\n m = 0\n }\n p = 0\n\n if (gtlt === '>') {\n // >1 => >=2.0.0\n // >1.2 => >=1.3.0\n gtlt = '>='\n if (xm) {\n M = +M + 1\n m = 0\n p = 0\n } else {\n m = +m + 1\n p = 0\n }\n } else if (gtlt === '<=') {\n // <=0.7.x is actually <0.8.0, since any 0.7.x should\n // pass. Similarly, <=7.x is actually <8.0.0, etc.\n gtlt = '<'\n if (xm) {\n M = +M + 1\n } else {\n m = +m + 1\n }\n }\n\n if (gtlt === '<') {\n pr = '-0'\n }\n\n ret = `${gtlt + M}.${m}.${p}${pr}`\n } else if (xm) {\n ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`\n } else if (xp) {\n ret = `>=${M}.${m}.0${pr\n } <${M}.${+m + 1}.0-0`\n }\n\n debug('xRange return', ret)\n\n return ret\n })\n}\n\n// Because * is AND-ed with everything else in the comparator,\n// and '' means \"any version\", just remove the *s entirely.\nconst replaceStars = (comp, options) => {\n debug('replaceStars', comp, options)\n // Looseness is ignored here. star is always as loose as it gets!\n return comp\n .trim()\n .replace(re[t.STAR], '')\n}\n\nconst replaceGTE0 = (comp, options) => {\n debug('replaceGTE0', comp, options)\n return comp\n .trim()\n .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')\n}\n\n// This function is passed to string.replace(re[t.HYPHENRANGE])\n// M, m, patch, prerelease, build\n// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5\n// 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do\n// 1.2 - 3.4 => >=1.2.0 <3.5.0-0\n// TODO build?\nconst hyphenReplace = incPr => ($0,\n from, fM, fm, fp, fpr, fb,\n to, tM, tm, tp, tpr) => {\n if (isX(fM)) {\n from = ''\n } else if (isX(fm)) {\n from = `>=${fM}.0.0${incPr ? '-0' : ''}`\n } else if (isX(fp)) {\n from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`\n } else if (fpr) {\n from = `>=${from}`\n } else {\n from = `>=${from}${incPr ? '-0' : ''}`\n }\n\n if (isX(tM)) {\n to = ''\n } else if (isX(tm)) {\n to = `<${+tM + 1}.0.0-0`\n } else if (isX(tp)) {\n to = `<${tM}.${+tm + 1}.0-0`\n } else if (tpr) {\n to = `<=${tM}.${tm}.${tp}-${tpr}`\n } else if (incPr) {\n to = `<${tM}.${tm}.${+tp + 1}-0`\n } else {\n to = `<=${to}`\n }\n\n return `${from} ${to}`.trim()\n}\n\nconst testSet = (set, version, options) => {\n for (let i = 0; i < set.length; i++) {\n if (!set[i].test(version)) {\n return false\n }\n }\n\n if (version.prerelease.length && !options.includePrerelease) {\n // Find the set of versions that are allowed to have prereleases\n // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0\n // That should allow `1.2.3-pr.2` to pass.\n // However, `1.2.4-alpha.notready` should NOT be allowed,\n // even though it's within the range set by the comparators.\n for (let i = 0; i < set.length; i++) {\n debug(set[i].semver)\n if (set[i].semver === Comparator.ANY) {\n continue\n }\n\n if (set[i].semver.prerelease.length > 0) {\n const allowed = set[i].semver\n if (allowed.major === version.major &&\n allowed.minor === version.minor &&\n allowed.patch === version.patch) {\n return true\n }\n }\n }\n\n // Version has a -pre, but it's not one of the ones we like.\n return false\n }\n\n return true\n}\n","'use strict'\n\nconst ANY = Symbol('SemVer ANY')\n// hoisted class for cyclic dependency\nclass Comparator {\n static get ANY () {\n return ANY\n }\n\n constructor (comp, options) {\n options = parseOptions(options)\n\n if (comp instanceof Comparator) {\n if (comp.loose === !!options.loose) {\n return comp\n } else {\n comp = comp.value\n }\n }\n\n comp = comp.trim().split(/\\s+/).join(' ')\n debug('comparator', comp, options)\n this.options = options\n this.loose = !!options.loose\n this.parse(comp)\n\n if (this.semver === ANY) {\n this.value = ''\n } else {\n this.value = this.operator + this.semver.version\n }\n\n debug('comp', this)\n }\n\n parse (comp) {\n const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]\n const m = comp.match(r)\n\n if (!m) {\n throw new TypeError(`Invalid comparator: ${comp}`)\n }\n\n this.operator = m[1] !== undefined ? m[1] : ''\n if (this.operator === '=') {\n this.operator = ''\n }\n\n // if it literally is just '>' or '' then allow anything.\n if (!m[2]) {\n this.semver = ANY\n } else {\n this.semver = new SemVer(m[2], this.options.loose)\n }\n }\n\n toString () {\n return this.value\n }\n\n test (version) {\n debug('Comparator.test', version, this.options.loose)\n\n if (this.semver === ANY || version === ANY) {\n return true\n }\n\n if (typeof version === 'string') {\n try {\n version = new SemVer(version, this.options)\n } catch (er) {\n return false\n }\n }\n\n return cmp(version, this.operator, this.semver, this.options)\n }\n\n intersects (comp, options) {\n if (!(comp instanceof Comparator)) {\n throw new TypeError('a Comparator is required')\n }\n\n if (this.operator === '') {\n if (this.value === '') {\n return true\n }\n return new Range(comp.value, options).test(this.value)\n } else if (comp.operator === '') {\n if (comp.value === '') {\n return true\n }\n return new Range(this.value, options).test(comp.semver)\n }\n\n options = parseOptions(options)\n\n // Special cases where nothing can possibly be lower\n if (options.includePrerelease &&\n (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) {\n return false\n }\n if (!options.includePrerelease &&\n (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) {\n return false\n }\n\n // Same direction increasing (> or >=)\n if (this.operator.startsWith('>') && comp.operator.startsWith('>')) {\n return true\n }\n // Same direction decreasing (< or <=)\n if (this.operator.startsWith('<') && comp.operator.startsWith('<')) {\n return true\n }\n // same SemVer and both sides are inclusive (<= or >=)\n if (\n (this.semver.version === comp.semver.version) &&\n this.operator.includes('=') && comp.operator.includes('=')) {\n return true\n }\n // opposite directions less than\n if (cmp(this.semver, '<', comp.semver, options) &&\n this.operator.startsWith('>') && comp.operator.startsWith('<')) {\n return true\n }\n // opposite directions greater than\n if (cmp(this.semver, '>', comp.semver, options) &&\n this.operator.startsWith('<') && comp.operator.startsWith('>')) {\n return true\n }\n return false\n }\n}\n\nmodule.exports = Comparator\n\nconst parseOptions = require('../internal/parse-options')\nconst { safeRe: re, t } = require('../internal/re')\nconst cmp = require('../functions/cmp')\nconst debug = require('../internal/debug')\nconst SemVer = require('./semver')\nconst Range = require('./range')\n","'use strict'\n\nconst Range = require('../classes/range')\nconst satisfies = (version, range, options) => {\n try {\n range = new Range(range, options)\n } catch (er) {\n return false\n }\n return range.test(version)\n}\nmodule.exports = satisfies\n","'use strict'\n\nconst Range = require('../classes/range')\n\n// Mostly just for testing and legacy API reasons\nconst toComparators = (range, options) =>\n new Range(range, options).set\n .map(comp => comp.map(c => c.value).join(' ').trim().split(' '))\n\nmodule.exports = toComparators\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\n\nconst maxSatisfying = (versions, range, options) => {\n let max = null\n let maxSV = null\n let rangeObj = null\n try {\n rangeObj = new Range(range, options)\n } catch (er) {\n return null\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n // satisfies(v, range, options)\n if (!max || maxSV.compare(v) === -1) {\n // compare(max, v, true)\n max = v\n maxSV = new SemVer(max, options)\n }\n }\n })\n return max\n}\nmodule.exports = maxSatisfying\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\nconst minSatisfying = (versions, range, options) => {\n let min = null\n let minSV = null\n let rangeObj = null\n try {\n rangeObj = new Range(range, options)\n } catch (er) {\n return null\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n // satisfies(v, range, options)\n if (!min || minSV.compare(v) === 1) {\n // compare(min, v, true)\n min = v\n minSV = new SemVer(min, options)\n }\n }\n })\n return min\n}\nmodule.exports = minSatisfying\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\nconst gt = require('../functions/gt')\n\nconst minVersion = (range, loose) => {\n range = new Range(range, loose)\n\n let minver = new SemVer('0.0.0')\n if (range.test(minver)) {\n return minver\n }\n\n minver = new SemVer('0.0.0-0')\n if (range.test(minver)) {\n return minver\n }\n\n minver = null\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i]\n\n let setMin = null\n comparators.forEach((comparator) => {\n // Clone to avoid manipulating the comparator's semver object.\n const compver = new SemVer(comparator.semver.version)\n switch (comparator.operator) {\n case '>':\n if (compver.prerelease.length === 0) {\n compver.patch++\n } else {\n compver.prerelease.push(0)\n }\n compver.raw = compver.format()\n /* fallthrough */\n case '':\n case '>=':\n if (!setMin || gt(compver, setMin)) {\n setMin = compver\n }\n break\n case '<':\n case '<=':\n /* Ignore maximum versions */\n break\n /* istanbul ignore next */\n default:\n throw new Error(`Unexpected operation: ${comparator.operator}`)\n }\n })\n if (setMin && (!minver || gt(minver, setMin))) {\n minver = setMin\n }\n }\n\n if (minver && range.test(minver)) {\n return minver\n }\n\n return null\n}\nmodule.exports = minVersion\n","'use strict'\n\nconst Range = require('../classes/range')\nconst validRange = (range, options) => {\n try {\n // Return '*' instead of '' so that truthiness works.\n // This will throw if it's invalid anyway\n return new Range(range, options).range || '*'\n } catch (er) {\n return null\n }\n}\nmodule.exports = validRange\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Comparator = require('../classes/comparator')\nconst { ANY } = Comparator\nconst Range = require('../classes/range')\nconst satisfies = require('../functions/satisfies')\nconst gt = require('../functions/gt')\nconst lt = require('../functions/lt')\nconst lte = require('../functions/lte')\nconst gte = require('../functions/gte')\n\nconst outside = (version, range, hilo, options) => {\n version = new SemVer(version, options)\n range = new Range(range, options)\n\n let gtfn, ltefn, ltfn, comp, ecomp\n switch (hilo) {\n case '>':\n gtfn = gt\n ltefn = lte\n ltfn = lt\n comp = '>'\n ecomp = '>='\n break\n case '<':\n gtfn = lt\n ltefn = gte\n ltfn = gt\n comp = '<'\n ecomp = '<='\n break\n default:\n throw new TypeError('Must provide a hilo val of \"<\" or \">\"')\n }\n\n // If it satisfies the range it is not outside\n if (satisfies(version, range, options)) {\n return false\n }\n\n // From now on, variable terms are as if we're in \"gtr\" mode.\n // but note that everything is flipped for the \"ltr\" function.\n\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i]\n\n let high = null\n let low = null\n\n comparators.forEach((comparator) => {\n if (comparator.semver === ANY) {\n comparator = new Comparator('>=0.0.0')\n }\n high = high || comparator\n low = low || comparator\n if (gtfn(comparator.semver, high.semver, options)) {\n high = comparator\n } else if (ltfn(comparator.semver, low.semver, options)) {\n low = comparator\n }\n })\n\n // If the edge version comparator has a operator then our version\n // isn't outside it\n if (high.operator === comp || high.operator === ecomp) {\n return false\n }\n\n // If the lowest version comparator has an operator and our version\n // is less than it then it isn't higher than the range\n if ((!low.operator || low.operator === comp) &&\n ltefn(version, low.semver)) {\n return false\n } else if (low.operator === ecomp && ltfn(version, low.semver)) {\n return false\n }\n }\n return true\n}\n\nmodule.exports = outside\n","'use strict'\n\n// Determine if version is greater than all the versions possible in the range.\nconst outside = require('./outside')\nconst gtr = (version, range, options) => outside(version, range, '>', options)\nmodule.exports = gtr\n","'use strict'\n\nconst outside = require('./outside')\n// Determine if version is less than all the versions possible in the range\nconst ltr = (version, range, options) => outside(version, range, '<', options)\nmodule.exports = ltr\n","'use strict'\n\nconst Range = require('../classes/range')\nconst intersects = (r1, r2, options) => {\n r1 = new Range(r1, options)\n r2 = new Range(r2, options)\n return r1.intersects(r2, options)\n}\nmodule.exports = intersects\n","'use strict'\n\n// given a set of versions and a range, create a \"simplified\" range\n// that includes the same versions that the original range does\n// If the original range is shorter than the simplified one, return that.\nconst satisfies = require('../functions/satisfies.js')\nconst compare = require('../functions/compare.js')\nmodule.exports = (versions, range, options) => {\n const set = []\n let first = null\n let prev = null\n const v = versions.sort((a, b) => compare(a, b, options))\n for (const version of v) {\n const included = satisfies(version, range, options)\n if (included) {\n prev = version\n if (!first) {\n first = version\n }\n } else {\n if (prev) {\n set.push([first, prev])\n }\n prev = null\n first = null\n }\n }\n if (first) {\n set.push([first, null])\n }\n\n const ranges = []\n for (const [min, max] of set) {\n if (min === max) {\n ranges.push(min)\n } else if (!max && min === v[0]) {\n ranges.push('*')\n } else if (!max) {\n ranges.push(`>=${min}`)\n } else if (min === v[0]) {\n ranges.push(`<=${max}`)\n } else {\n ranges.push(`${min} - ${max}`)\n }\n }\n const simplified = ranges.join(' || ')\n const original = typeof range.raw === 'string' ? range.raw : String(range)\n return simplified.length < original.length ? simplified : range\n}\n","'use strict'\n\nconst Range = require('../classes/range.js')\nconst Comparator = require('../classes/comparator.js')\nconst { ANY } = Comparator\nconst satisfies = require('../functions/satisfies.js')\nconst compare = require('../functions/compare.js')\n\n// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:\n// - Every simple range `r1, r2, ...` is a null set, OR\n// - Every simple range `r1, r2, ...` which is not a null set is a subset of\n// some `R1, R2, ...`\n//\n// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:\n// - If c is only the ANY comparator\n// - If C is only the ANY comparator, return true\n// - Else if in prerelease mode, return false\n// - else replace c with `[>=0.0.0]`\n// - If C is only the ANY comparator\n// - if in prerelease mode, return true\n// - else replace C with `[>=0.0.0]`\n// - Let EQ be the set of = comparators in c\n// - If EQ is more than one, return true (null set)\n// - Let GT be the highest > or >= comparator in c\n// - Let LT be the lowest < or <= comparator in c\n// - If GT and LT, and GT.semver > LT.semver, return true (null set)\n// - If any C is a = range, and GT or LT are set, return false\n// - If EQ\n// - If GT, and EQ does not satisfy GT, return true (null set)\n// - If LT, and EQ does not satisfy LT, return true (null set)\n// - If EQ satisfies every C, return true\n// - Else return false\n// - If GT\n// - If GT.semver is lower than any > or >= comp in C, return false\n// - If GT is >=, and GT.semver does not satisfy every C, return false\n// - If GT.semver has a prerelease, and not in prerelease mode\n// - If no C has a prerelease and the GT.semver tuple, return false\n// - If LT\n// - If LT.semver is greater than any < or <= comp in C, return false\n// - If LT is <=, and LT.semver does not satisfy every C, return false\n// - If GT.semver has a prerelease, and not in prerelease mode\n// - If no C has a prerelease and the LT.semver tuple, return false\n// - Else return true\n\nconst subset = (sub, dom, options = {}) => {\n if (sub === dom) {\n return true\n }\n\n sub = new Range(sub, options)\n dom = new Range(dom, options)\n let sawNonNull = false\n\n OUTER: for (const simpleSub of sub.set) {\n for (const simpleDom of dom.set) {\n const isSub = simpleSubset(simpleSub, simpleDom, options)\n sawNonNull = sawNonNull || isSub !== null\n if (isSub) {\n continue OUTER\n }\n }\n // the null set is a subset of everything, but null simple ranges in\n // a complex range should be ignored. so if we saw a non-null range,\n // then we know this isn't a subset, but if EVERY simple range was null,\n // then it is a subset.\n if (sawNonNull) {\n return false\n }\n }\n return true\n}\n\nconst minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]\nconst minimumVersion = [new Comparator('>=0.0.0')]\n\nconst simpleSubset = (sub, dom, options) => {\n if (sub === dom) {\n return true\n }\n\n if (sub.length === 1 && sub[0].semver === ANY) {\n if (dom.length === 1 && dom[0].semver === ANY) {\n return true\n } else if (options.includePrerelease) {\n sub = minimumVersionWithPreRelease\n } else {\n sub = minimumVersion\n }\n }\n\n if (dom.length === 1 && dom[0].semver === ANY) {\n if (options.includePrerelease) {\n return true\n } else {\n dom = minimumVersion\n }\n }\n\n const eqSet = new Set()\n let gt, lt\n for (const c of sub) {\n if (c.operator === '>' || c.operator === '>=') {\n gt = higherGT(gt, c, options)\n } else if (c.operator === '<' || c.operator === '<=') {\n lt = lowerLT(lt, c, options)\n } else {\n eqSet.add(c.semver)\n }\n }\n\n if (eqSet.size > 1) {\n return null\n }\n\n let gtltComp\n if (gt && lt) {\n gtltComp = compare(gt.semver, lt.semver, options)\n if (gtltComp > 0) {\n return null\n } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) {\n return null\n }\n }\n\n // will iterate one or zero times\n for (const eq of eqSet) {\n if (gt && !satisfies(eq, String(gt), options)) {\n return null\n }\n\n if (lt && !satisfies(eq, String(lt), options)) {\n return null\n }\n\n for (const c of dom) {\n if (!satisfies(eq, String(c), options)) {\n return false\n }\n }\n\n return true\n }\n\n let higher, lower\n let hasDomLT, hasDomGT\n // if the subset has a prerelease, we need a comparator in the superset\n // with the same tuple and a prerelease, or it's not a subset\n let needDomLTPre = lt &&\n !options.includePrerelease &&\n lt.semver.prerelease.length ? lt.semver : false\n let needDomGTPre = gt &&\n !options.includePrerelease &&\n gt.semver.prerelease.length ? gt.semver : false\n // exception: <1.2.3-0 is the same as <1.2.3\n if (needDomLTPre && needDomLTPre.prerelease.length === 1 &&\n lt.operator === '<' && needDomLTPre.prerelease[0] === 0) {\n needDomLTPre = false\n }\n\n for (const c of dom) {\n hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='\n hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='\n if (gt) {\n if (needDomGTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length &&\n c.semver.major === needDomGTPre.major &&\n c.semver.minor === needDomGTPre.minor &&\n c.semver.patch === needDomGTPre.patch) {\n needDomGTPre = false\n }\n }\n if (c.operator === '>' || c.operator === '>=') {\n higher = higherGT(gt, c, options)\n if (higher === c && higher !== gt) {\n return false\n }\n } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {\n return false\n }\n }\n if (lt) {\n if (needDomLTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length &&\n c.semver.major === needDomLTPre.major &&\n c.semver.minor === needDomLTPre.minor &&\n c.semver.patch === needDomLTPre.patch) {\n needDomLTPre = false\n }\n }\n if (c.operator === '<' || c.operator === '<=') {\n lower = lowerLT(lt, c, options)\n if (lower === c && lower !== lt) {\n return false\n }\n } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {\n return false\n }\n }\n if (!c.operator && (lt || gt) && gtltComp !== 0) {\n return false\n }\n }\n\n // if there was a < or >, and nothing in the dom, then must be false\n // UNLESS it was limited by another range in the other direction.\n // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0\n if (gt && hasDomLT && !lt && gtltComp !== 0) {\n return false\n }\n\n if (lt && hasDomGT && !gt && gtltComp !== 0) {\n return false\n }\n\n // we needed a prerelease range in a specific tuple, but didn't get one\n // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,\n // because it includes prereleases in the 1.2.3 tuple\n if (needDomGTPre || needDomLTPre) {\n return false\n }\n\n return true\n}\n\n// >=1.2.3 is lower than >1.2.3\nconst higherGT = (a, b, options) => {\n if (!a) {\n return b\n }\n const comp = compare(a.semver, b.semver, options)\n return comp > 0 ? a\n : comp < 0 ? b\n : b.operator === '>' && a.operator === '>=' ? b\n : a\n}\n\n// <=1.2.3 is higher than <1.2.3\nconst lowerLT = (a, b, options) => {\n if (!a) {\n return b\n }\n const comp = compare(a.semver, b.semver, options)\n return comp < 0 ? a\n : comp > 0 ? b\n : b.operator === '<' && a.operator === '<=' ? b\n : a\n}\n\nmodule.exports = subset\n","'use strict'\n\n// just pre-load all the stuff that index.js lazily exports\nconst internalRe = require('./internal/re')\nconst constants = require('./internal/constants')\nconst SemVer = require('./classes/semver')\nconst identifiers = require('./internal/identifiers')\nconst parse = require('./functions/parse')\nconst valid = require('./functions/valid')\nconst clean = require('./functions/clean')\nconst inc = require('./functions/inc')\nconst diff = require('./functions/diff')\nconst major = require('./functions/major')\nconst minor = require('./functions/minor')\nconst patch = require('./functions/patch')\nconst prerelease = require('./functions/prerelease')\nconst compare = require('./functions/compare')\nconst rcompare = require('./functions/rcompare')\nconst compareLoose = require('./functions/compare-loose')\nconst compareBuild = require('./functions/compare-build')\nconst sort = require('./functions/sort')\nconst rsort = require('./functions/rsort')\nconst gt = require('./functions/gt')\nconst lt = require('./functions/lt')\nconst eq = require('./functions/eq')\nconst neq = require('./functions/neq')\nconst gte = require('./functions/gte')\nconst lte = require('./functions/lte')\nconst cmp = require('./functions/cmp')\nconst coerce = require('./functions/coerce')\nconst Comparator = require('./classes/comparator')\nconst Range = require('./classes/range')\nconst satisfies = require('./functions/satisfies')\nconst toComparators = require('./ranges/to-comparators')\nconst maxSatisfying = require('./ranges/max-satisfying')\nconst minSatisfying = require('./ranges/min-satisfying')\nconst minVersion = require('./ranges/min-version')\nconst validRange = require('./ranges/valid')\nconst outside = require('./ranges/outside')\nconst gtr = require('./ranges/gtr')\nconst ltr = require('./ranges/ltr')\nconst intersects = require('./ranges/intersects')\nconst simplifyRange = require('./ranges/simplify')\nconst subset = require('./ranges/subset')\nmodule.exports = {\n parse,\n valid,\n clean,\n inc,\n diff,\n major,\n minor,\n patch,\n prerelease,\n compare,\n rcompare,\n compareLoose,\n compareBuild,\n sort,\n rsort,\n gt,\n lt,\n eq,\n neq,\n gte,\n lte,\n cmp,\n coerce,\n Comparator,\n Range,\n satisfies,\n toComparators,\n maxSatisfying,\n minSatisfying,\n minVersion,\n validRange,\n outside,\n gtr,\n ltr,\n intersects,\n simplifyRange,\n subset,\n SemVer,\n re: internalRe.re,\n src: internalRe.src,\n tokens: internalRe.t,\n SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,\n RELEASE_TYPES: constants.RELEASE_TYPES,\n compareIdentifiers: identifiers.compareIdentifiers,\n rcompareIdentifiers: identifiers.rcompareIdentifiers,\n}\n","/**\n * Web 服务器\n *\n * 负责:\n * - 启动和管理 HTTP/HTTPS 服务器\n * - 注册和管理路由\n * - 集成中间件(CORS、日志、错误处理等)\n * - 管理 WebSocket 连接\n * - 集成 MCP 服务和端点管理器\n * - 生命周期管理(启动、停止、清理)\n *\n * @example\n * ```typescript\n * import { WebServer } from './WebServer';\n *\n * const server = new WebServer();\n * await server.start();\n * ```\n */\n\nimport { createServer } from \"node:http\";\nimport type { IncomingMessage, Server, ServerResponse } from \"node:http\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n ConfigApiHandler,\n CozeHandler,\n ESP32Handler,\n HeartbeatHandler,\n MCPHandler,\n MCPRouteHandler,\n MCPToolHandler,\n MCPToolLogHandler,\n RealtimeNotificationHandler,\n ServiceApiHandler,\n StaticFileHandler,\n StatusApiHandler,\n TTSApiHandler,\n UpdateApiHandler,\n VersionApiHandler,\n} from \"@/handlers/index.js\";\nimport { MCPServiceManager } from \"@/lib/mcp\";\nimport type { EnhancedToolInfo } from \"@/lib/mcp/types.js\";\nimport { ensureToolJSONSchema } from \"@/lib/mcp/types.js\";\nimport {\n corsMiddleware,\n endpointManagerMiddleware,\n endpointsMiddleware,\n errorHandlerMiddleware,\n loggerMiddleware,\n mcpServiceManagerMiddleware,\n notFoundHandlerMiddleware,\n responseEnhancerMiddleware,\n} from \"@/middlewares/index.js\";\nimport type { EventBus, EventBusEvents } from \"@/services/index.js\";\nimport {\n NotificationService,\n StatusService,\n destroyEventBus,\n getEventBus,\n} from \"@/services/index.js\";\nimport type { AppContext } from \"@/types/index.js\";\nimport { createApp } from \"@/types/index.js\";\nimport type { ServerType } from \"@hono/node-server\";\nimport { serve } from \"@hono/node-server\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { normalizeServiceConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { MCPServerConfig } from \"@xiaozhi-client/config\";\nimport { EndpointManager } from \"@xiaozhi-client/endpoint\";\nimport type { SimpleConnectionStatus } from \"@xiaozhi-client/endpoint\";\nimport {\n ESP32DeviceManager,\n type IESP32ConfigProvider,\n} from \"@xiaozhi-client/esp32\";\nimport type { Hono } from \"hono\";\nimport { WebSocketServer } from \"ws\";\nimport type WebSocket from \"ws\";\n\nimport { HTTP_SERVER_CONFIG } from \"@/constants/index.js\";\nimport { MCPServiceManagerNotInitializedError } from \"@/errors/mcp-errors.middleware.js\";\n// 路由系统导入\nimport {\n type HandlerDependencies,\n RouteManager,\n // 导入所有路由配置\n configRoutes,\n cozeRoutes,\n endpointRoutes,\n esp32Routes,\n mcpRoutes,\n mcpserverRoutes,\n miscRoutes,\n servicesRoutes,\n staticRoutes,\n statusRoutes,\n toolLogsRoutes,\n toolsRoutes,\n ttsRoutes,\n updateRoutes,\n versionRoutes,\n} from \"./routes/index.js\";\n\n// 统一成功响应格式\ninterface ApiSuccessResponse<T = unknown> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n// 小智连接状态响应格式\ninterface XiaozhiConnectionStatusResponse {\n type: \"multi-endpoint\" | \"single-endpoint\" | \"none\";\n connected?: boolean;\n endpoint?: string;\n manager?: {\n connectedConnections: number;\n totalConnections: number;\n healthCheckStats: Record<string, unknown>;\n };\n connections?: SimpleConnectionStatus[];\n}\n\n/**\n * WebServer - 主控制器,协调各个服务和处理器\n */\nexport class WebServer {\n private app: Hono<AppContext>;\n private httpServer: ServerType | null = null;\n private wss: WebSocketServer | null = null;\n private logger: Logger;\n private port: number;\n\n // 事件总线\n private eventBus: EventBus;\n\n // 服务层\n private statusService: StatusService;\n private notificationService: NotificationService;\n private esp32Manager: ESP32DeviceManager;\n\n // HTTP API 处理器\n private configApiHandler: ConfigApiHandler;\n private statusApiHandler: StatusApiHandler;\n private serviceApiHandler: ServiceApiHandler;\n private mcpToolHandler: MCPToolHandler;\n private mcpToolLogHandler: MCPToolLogHandler;\n private versionApiHandler: VersionApiHandler;\n private staticFileHandler: StaticFileHandler;\n private mcpRouteHandler: MCPRouteHandler;\n private mcpHandler?: MCPHandler;\n private updateApiHandler: UpdateApiHandler;\n private cozeHandler: CozeHandler;\n private ttsApiHandler: TTSApiHandler;\n private esp32Handler: ESP32Handler;\n\n // WebSocket 处理器\n private realtimeNotificationHandler: RealtimeNotificationHandler;\n private heartbeatHandler: HeartbeatHandler;\n\n // 心跳监控\n private heartbeatMonitorInterval?: NodeJS.Timeout;\n\n // 路由系统\n private routeManager?: RouteManager;\n\n // 连接管理相关属性\n private endpointManager: EndpointManager | null = null;\n private mcpServiceManager: MCPServiceManager | null = null; // WebServer 直接管理的实例\n\n // 事件监听器清理函数数组\n private eventListenerUnsubscribers: Array<() => void> = [];\n\n constructor(port?: number) {\n // 端口配置\n try {\n this.port =\n port ?? configManager.getWebUIPort() ?? HTTP_SERVER_CONFIG.DEFAULT_PORT;\n } catch (error) {\n // 配置读取失败时使用默认端口\n this.port = port ?? HTTP_SERVER_CONFIG.DEFAULT_PORT;\n }\n this.logger = logger;\n\n // 初始化事件总线\n this.eventBus = getEventBus();\n\n // 初始化服务层\n this.statusService = new StatusService();\n this.notificationService = new NotificationService();\n\n // 创建基于 configManager 的配置提供者\n const esp32ConfigProvider: IESP32ConfigProvider = {\n getASRConfig: () => configManager.getASRConfig(),\n getTTSConfig: () => configManager.getTTSConfig(),\n getLLMConfig: () => configManager.getLLMConfig(),\n isLLMConfigValid: () => configManager.isLLMConfigValid(),\n };\n\n // 创建 ESP32 设备管理器(使用新包)\n this.esp32Manager = new ESP32DeviceManager({\n logger,\n configProvider: esp32ConfigProvider,\n });\n\n // 初始化 HTTP API 处理器\n this.configApiHandler = new ConfigApiHandler();\n this.statusApiHandler = new StatusApiHandler(this.statusService);\n this.serviceApiHandler = new ServiceApiHandler(this.statusService);\n this.mcpToolHandler = new MCPToolHandler();\n this.mcpToolLogHandler = new MCPToolLogHandler();\n this.versionApiHandler = new VersionApiHandler();\n this.staticFileHandler = new StaticFileHandler();\n this.mcpRouteHandler = new MCPRouteHandler();\n this.updateApiHandler = new UpdateApiHandler();\n this.cozeHandler = new CozeHandler();\n this.ttsApiHandler = new TTSApiHandler();\n this.esp32Handler = new ESP32Handler(this.esp32Manager);\n\n // MCPServerApiHandler 将在 start() 方法中初始化,因为它需要 mcpServiceManager\n\n // 初始化 WebSocket 处理器\n this.realtimeNotificationHandler = new RealtimeNotificationHandler(\n this.notificationService,\n this.statusService\n );\n this.heartbeatHandler = new HeartbeatHandler(\n this.statusService,\n this.notificationService\n );\n\n // 初始化 Hono 应用\n this.app = createApp();\n this.setupMiddleware();\n\n // 在所有路由设置完成后,设置 404 处理\n this.app.notFound(notFoundHandlerMiddleware);\n\n // 监听接入点状态变更事件\n this.setupEndpointStatusListener();\n // 监听 MCP 服务添加事件\n this.setupMCPServerAddedListener();\n }\n\n /**\n * 初始化所有连接(配置驱动)\n */\n private async initializeConnections(): Promise<void> {\n try {\n this.logger.debug(\"开始初始化连接...\");\n\n // 2. 初始化 MCP 服务管理器(WebServer 直接管理)\n if (!this.mcpServiceManager) {\n this.logger.debug(\"创建新的 MCPServiceManager 实例\");\n this.mcpServiceManager = new MCPServiceManager();\n // 启动服务管理器,确保它可以正常工作\n await this.mcpServiceManager.start();\n } else {\n this.logger.debug(\"使用现有的 MCPServiceManager 实例,跳过创建\");\n }\n\n // 1. 读取配置\n const config = await this.loadConfiguration();\n\n // 2.1. 初始化 MCP 服务器 API 处理器\n this.mcpHandler = new MCPHandler(this.mcpServiceManager, configManager);\n\n // 3. 从配置加载 MCP 服务\n await this.loadMCPServicesFromConfig(config.mcpServers);\n\n // 4. 获取工具列表\n const rawTools: EnhancedToolInfo[] = this.mcpServiceManager.getAllTools();\n this.logger.debug(`已加载 ${rawTools.length} 个工具`);\n\n // 5. 转换工具格式以符合 MCP SDK 要求\n const tools: Tool[] = rawTools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: ensureToolJSONSchema(tool.inputSchema),\n }));\n\n // 6. 初始化小智接入点连接\n await this.initializeXiaozhiConnection(config.mcpEndpoint);\n\n this.logger.debug(\"所有连接初始化完成\");\n } catch (error) {\n this.logger.error(\"连接初始化失败:\", error);\n // 降级模式:即使配置加载失败,也确保 MCPServiceManager 可用\n if (!this.mcpServiceManager) {\n this.logger.warn(\n \"配置加载失败,正在进入降级模式。在降级模式下:\\n\" +\n \"1. 将创建一个空配置的 MCPServiceManager 实例\\n\" +\n \"2. 不会加载任何 MCP 服务器或端点\\n\" +\n \"3. WebServer 仍然可以启动并提供基础 API 服务\\n\" +\n \"4. 用户需要通过 API 重新配置端点或服务器\\n\" +\n \"5. 建议尽快运行 'xiaozhi init' 初始化配置文件\"\n );\n this.mcpServiceManager = new MCPServiceManager();\n await this.mcpServiceManager.start();\n this.logger.info(\"降级模式已激活,MCPServiceManager 使用空配置启动\");\n }\n }\n }\n\n /**\n * 加载配置文件\n */\n private async loadConfiguration(): Promise<{\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n webUIPort: number;\n }> {\n if (!configManager.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\");\n }\n\n // 在加载配置前,先清理无效的服务器工具配置\n // 确保 mcpServerConfig 与 mcpServers 保持同步\n configManager.cleanupInvalidServerToolsConfig();\n\n const config = configManager.getConfig();\n\n return {\n mcpEndpoint: config.mcpEndpoint,\n mcpServers: config.mcpServers,\n webUIPort: config.webUI?.port ?? HTTP_SERVER_CONFIG.DEFAULT_PORT,\n };\n }\n\n /**\n * 从配置加载 MCP 服务\n */\n private async loadMCPServicesFromConfig(\n mcpServers: Record<string, MCPServerConfig>\n ): Promise<void> {\n if (!this.mcpServiceManager) {\n throw new Error(\"MCPServiceManager 未初始化\");\n }\n\n for (const [name, config] of Object.entries(mcpServers)) {\n this.logger.debug(`添加 MCP 服务配置: ${name}`);\n // 使用配置适配器转换配置格式\n const serviceConfig = normalizeServiceConfig(config);\n this.mcpServiceManager.addServiceConfig(name, serviceConfig);\n }\n\n await this.mcpServiceManager.startAllServices();\n }\n\n /**\n * 初始化小智接入点连接(使用新 API)\n */\n private async initializeXiaozhiConnection(\n mcpEndpoint: string | string[]\n ): Promise<void> {\n // 处理多端点配置\n const endpoints = Array.isArray(mcpEndpoint) ? mcpEndpoint : [mcpEndpoint];\n const validEndpoints = endpoints.filter(\n (ep) => ep && !ep.includes(\"<请填写\")\n );\n\n // 1. 初始化连接管理器(无论是否有有效端点)\n this.logger.debug(\n `初始化小智接入点连接管理器,端点数量: ${validEndpoints.length}`\n );\n\n try {\n // 创建连接管理器实例(总是创建)\n if (!this.endpointManager) {\n this.endpointManager = new EndpointManager({\n defaultReconnectDelay: 2000,\n });\n // ✅ 传入 mcpServiceManager 实例\n this.endpointManager.setMcpManager(this.mcpServiceManager!);\n this.logger.debug(\"✅ 新建连接管理器实例\");\n }\n\n this.logger.debug(\"✅ 连接管理器设置完成\");\n\n // 2. 只有在有有效端点时才创建并添加端点\n if (validEndpoints.length > 0) {\n this.logger.debug(\"有效端点列表:\", validEndpoints);\n\n // 直接使用 URL 字符串添加端点(新 API)\n for (const endpointUrl of validEndpoints) {\n this.endpointManager.addEndpoint(endpointUrl);\n this.logger.debug(`✅ 已添加端点: ${endpointUrl}`);\n }\n\n // 连接所有端点\n await this.endpointManager.connect();\n\n // 设置端点添加事件监听器\n this.endpointManager.on(\n \"endpointAdded\",\n (event: { endpoint: string }) => {\n this.logger.debug(`端点已添加: ${event.endpoint}`);\n }\n );\n\n // 设置端点移除事件监听器\n this.endpointManager.on(\n \"endpointRemoved\",\n (event: { endpoint: string }) => {\n this.logger.debug(`端点已移除: ${event.endpoint}`);\n }\n );\n\n this.logger.debug(\n `小智接入点连接管理器初始化完成,管理 ${validEndpoints.length} 个端点`\n );\n } else {\n this.logger.debug(\"小智接入点连接管理器初始化完成(无端点)\");\n }\n } catch (error) {\n this.logger.error(\"小智接入点连接管理器初始化失败:\", error);\n // 抛出错误,让调用者知道初始化失败\n throw error;\n }\n }\n\n /**\n * 设置连接管理器实例(主要用于测试依赖注入)\n */\n public setXiaozhiConnectionManager(manager: EndpointManager): void {\n this.endpointManager = manager;\n }\n\n /**\n * 获取小智连接管理器实例\n * 提供给中间件使用\n * WebServer 启动后始终返回有效的连接管理器实例\n * @throws {Error} 如果连接管理器未初始化\n */\n public getEndpointManager(): EndpointManager {\n if (!this.endpointManager) {\n throw new Error(\n \"小智连接管理器未初始化,请确保 WebServer 已调用 start() 方法完成初始化\"\n );\n }\n return this.endpointManager;\n }\n\n /**\n * 设置 MCP 服务管理器实例(主要用于测试依赖注入)\n * 警告:如果要替换现有实例,调用者需要负责清理原有实例的资源\n */\n public setMCPServiceManager(manager: MCPServiceManager): void {\n // 如果已有实例且它正在运行,先清理它\n if (this.mcpServiceManager && this.mcpServiceManager !== manager) {\n this.logger.warn(\n \"替换现有的 MCPServiceManager 实例,注意清理原有实例的资源\"\n );\n // 注意:这里不直接调用 stopAllServices,因为调用者可能还在使用它\n // 调用者应该负责清理原有实例\n }\n\n this.mcpServiceManager = manager;\n this.logger.debug(\"MCPServiceManager 实例已更新\");\n }\n\n /**\n * 获取 MCP 服务管理器实例\n * 提供给中间件使用\n * WebServer 启动后始终返回有效的服务管理器实例\n * @throws {MCPServiceManagerNotInitializedError} 如果服务管理器未初始化\n */\n public getMCPServiceManager(): MCPServiceManager {\n if (!this.mcpServiceManager) {\n throw new MCPServiceManagerNotInitializedError(\n \"MCPServiceManager 未初始化,请确保 WebServer 已调用 start() 方法完成初始化\"\n );\n }\n return this.mcpServiceManager;\n }\n\n /**\n * 获取小智连接状态信息\n */\n getEndpointConnectionStatus(): XiaozhiConnectionStatusResponse {\n if (this.endpointManager) {\n const connectionStatuses = this.endpointManager.getConnectionStatus();\n return {\n type: \"multi-endpoint\",\n manager: {\n connectedConnections: connectionStatuses.filter(\n (status: SimpleConnectionStatus) => status.connected\n ).length,\n totalConnections: connectionStatuses.length,\n healthCheckStats: {}, // 简化后不再提供复杂的健康检查统计\n },\n connections: connectionStatuses,\n };\n }\n\n return {\n type: \"none\",\n connected: false,\n };\n }\n\n /**\n * 带重试的连接方法\n */\n private async connectWithRetry<T>(\n connectionFn: () => Promise<T>,\n context: string,\n maxAttempts = 5,\n initialDelay = 1000,\n maxDelay = 30000,\n backoffMultiplier = 2\n ): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n this.logger.info(`${context} - 尝试连接 (${attempt}/${maxAttempts})`);\n return await connectionFn();\n } catch (error) {\n lastError = error as Error;\n this.logger.warn(`${context} - 连接失败:`, error);\n\n if (attempt < maxAttempts) {\n const delay = Math.min(\n initialDelay * backoffMultiplier ** (attempt - 1),\n maxDelay\n );\n this.logger.info(`${context} - ${delay}ms 后重试...`);\n await this.sleep(delay);\n }\n }\n }\n\n throw new Error(\n `${context} - 连接失败,已达到最大重试次数: ${lastError?.message}`\n );\n }\n\n /**\n * 延迟工具方法\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n private setupMiddleware() {\n // Logger 中间件 - 必须在最前面\n this.app?.use(\"*\", loggerMiddleware);\n\n // 响应增强中间件 - 在 logger 之后,其他中间件之前\n // 这样所有路由都可以使用 c.success、c.fail、c.paginate 方法\n this.app?.use(\"*\", responseEnhancerMiddleware);\n\n // 注入 WebServer 实例到上下文\n // 使用类型断言避免循环引用问题\n this.app?.use(\"*\", async (c, next) => {\n c.set(\n \"webServer\",\n this as unknown as import(\"./types/hono.context.js\").IWebServer\n );\n await next();\n });\n\n // MCP Service Manager 中间件 - 必须在 WebServer 注入之后\n this.app?.use(\"*\", mcpServiceManagerMiddleware);\n\n // 小智连接管理器中间件\n this.app?.use(\"*\", endpointManagerMiddleware());\n\n // 小智接入点处理器中间件(在连接管理器中间件之后)\n this.app?.use(\"*\", endpointsMiddleware());\n\n // CORS 中间件\n this.app?.use(\"*\", corsMiddleware);\n\n // 错误处理中间件\n this.app?.onError(errorHandlerMiddleware);\n\n // 注入路由系统依赖\n // 注意:这个中间件必须在路由注册之前设置\n this.app?.use(\"*\", async (c, next) => {\n const dependencies = this.createHandlerDependencies();\n c.set(\"dependencies\", dependencies);\n await next();\n });\n }\n\n /**\n * 创建处理器依赖对象\n * 统一管理依赖对象的创建,避免代码重复\n */\n private createHandlerDependencies(): HandlerDependencies {\n return {\n configApiHandler: this.configApiHandler,\n statusApiHandler: this.statusApiHandler,\n serviceApiHandler: this.serviceApiHandler,\n mcpToolHandler: this.mcpToolHandler,\n mcpToolLogHandler: this.mcpToolLogHandler,\n versionApiHandler: this.versionApiHandler,\n staticFileHandler: this.staticFileHandler,\n mcpRouteHandler: this.mcpRouteHandler,\n mcpHandler: this.mcpHandler,\n updateApiHandler: this.updateApiHandler,\n cozeHandler: this.cozeHandler,\n ttsApiHandler: this.ttsApiHandler,\n esp32Handler: this.esp32Handler,\n // endpointHandler 通过中间件动态注入,不在此初始化\n };\n }\n\n /**\n * 设置路由系统\n */\n private setupRouteSystem(): void {\n // 初始化路由管理器,注入 Logger 实例\n this.routeManager = new RouteManager(this.logger);\n }\n\n /**\n * 从路由配置设置路由\n */\n private setupRoutesFromRegistry(): void {\n if (!this.routeManager || !this.app) {\n throw new Error(\"路由系统未初始化\");\n }\n\n try {\n // 注册所有路由配置 - static 放在最后,作为回退\n this.routeManager.registerRoutes({\n config: configRoutes,\n status: statusRoutes,\n tools: toolsRoutes,\n mcp: mcpRoutes,\n version: versionRoutes,\n services: servicesRoutes,\n update: updateRoutes,\n coze: cozeRoutes,\n \"tool-logs\": toolLogsRoutes,\n mcpserver: mcpserverRoutes,\n endpoint: endpointRoutes,\n misc: miscRoutes,\n tts: ttsRoutes,\n esp32: esp32Routes,\n static: staticRoutes, // 放在最后作为回退\n });\n\n // 应用路由到 Hono 应用\n this.routeManager.applyToApp(this.app);\n\n this.logger.info(\"路由系统注册完成\");\n } catch (error) {\n this.logger.error(\"路由系统注册失败:\", error);\n }\n }\n\n private setupWebSocket() {\n if (!this.wss) return;\n\n this.wss.on(\"connection\", (ws, req) => {\n // 检查是否是ESP32设备连接\n const url = req.url\n ? new URL(req.url, `http://${req.headers.host}`)\n : null;\n const isESP32Device = url?.pathname === \"/ws\";\n\n if (isESP32Device) {\n // 处理ESP32设备连接\n this.handleESP32DeviceConnection(ws, req);\n return;\n }\n\n // 处理Web客户端连接\n this.handleWebClientConnection(ws, req);\n });\n }\n\n /**\n * 处理ESP32设备WebSocket连接\n */\n private handleESP32DeviceConnection(\n ws: WebSocket,\n req: IncomingMessage\n ): void {\n const deviceId = req.headers[\"device-id\"] as string;\n const clientId = req.headers[\"client-id\"] as string;\n const token = req.headers.authorization as string | undefined;\n\n // 提取Bearer token\n const authToken = token?.replace(\"Bearer \", \"\");\n\n this.logger.info(\n `[WS-ESP32] 收到ESP32设备连接请求: deviceId=${deviceId}, clientId=${clientId}, url=${req.url}`\n );\n\n if (!deviceId || !clientId) {\n this.logger.warn(\n `[WS-ESP32] 连接缺少必要的请求头: device-id=\"${deviceId}\", client-id=\"${clientId}\"`\n );\n ws.close(1008, \"Missing required headers\");\n return;\n }\n\n this.logger.info(\n `[WS-ESP32] ESP32设备WebSocket连接: deviceId=${deviceId}, clientId=${clientId}`\n );\n\n // 委托给 ESP32DeviceManager 处理\n this.esp32Manager\n .handleWebSocketConnection(ws, deviceId, clientId, authToken)\n .then(() => {\n this.logger.info(\n `[WS-ESP32] ESP32设备连接处理成功: deviceId=${deviceId}`\n );\n })\n .catch((error) => {\n this.logger.error(\n `[WS-ESP32] ESP32设备连接处理失败: deviceId=${deviceId}`,\n error\n );\n // 只有在 WebSocket 处于可关闭状态时才关闭\n // ws.OPEN = 1, ws.CONNECTING = 0\n if (ws.readyState === 1 || ws.readyState === 0) {\n ws.close(1011, \"Connection handling failed\");\n }\n });\n }\n\n /**\n * 处理Web客户端WebSocket连接\n */\n private handleWebClientConnection(ws: WebSocket, req: IncomingMessage): void {\n // 生成客户端 ID\n const clientId = `client-${Date.now()}-${Math.random()\n .toString(36)\n .substr(2, 9)}`;\n\n this.logger.debug(`WebSocket 客户端已连接: ${clientId}`);\n this.logger.debug(`当前 WebSocket 连接数: ${this.wss?.clients.size || 0}`);\n\n // 注册客户端到通知服务\n this.realtimeNotificationHandler.handleClientConnect(ws, clientId);\n this.heartbeatHandler.handleClientConnect(clientId);\n\n ws.on(\"message\", async (message) => {\n try {\n const data = JSON.parse(message.toString());\n\n // 根据消息类型分发到不同的处理器\n if (data.type === \"clientStatus\") {\n await this.heartbeatHandler.handleClientStatus(ws, data, clientId);\n } else {\n await this.realtimeNotificationHandler.handleMessage(\n ws,\n data,\n clientId\n );\n }\n } catch (error) {\n this.logger.error(\"WebSocket message error:\", error);\n const errorResponse = {\n type: \"error\",\n error: {\n code: \"MESSAGE_PARSE_ERROR\",\n message: error instanceof Error ? error.message : \"消息解析失败\",\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n }\n });\n\n ws.on(\"close\", () => {\n this.logger.debug(`WebSocket 客户端已断开连接: ${clientId}`);\n this.logger.debug(\n `剩余 WebSocket 连接数: ${this.wss?.clients.size || 0}`\n );\n\n // 处理客户端断开连接\n this.realtimeNotificationHandler.handleClientDisconnect(clientId);\n this.heartbeatHandler.handleClientDisconnect(clientId);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 (${clientId}):`, error);\n });\n\n // 发送初始数据\n this.realtimeNotificationHandler.sendInitialData(ws, clientId);\n }\n\n /**\n * 设置接入点状态变更事件监听\n */\n private setupEndpointStatusListener(): void {\n const listener = (eventData: EventBusEvents[\"endpoint:status:changed\"]) => {\n // 向所有连接的 WebSocket 客户端广播接入点状态变更事件\n const message = {\n type: \"endpoint_status_changed\",\n data: {\n endpoint: eventData.endpoint,\n connected: eventData.connected,\n operation: eventData.operation,\n success: eventData.success,\n message: eventData.message,\n timestamp: eventData.timestamp,\n },\n };\n\n this.notificationService.broadcast(\"endpoint_status_changed\", message);\n this.logger.debug(\n `广播接入点状态变更事件: ${eventData.endpoint} - ${eventData.operation}`\n );\n };\n\n this.eventBus.onEvent(\"endpoint:status:changed\", listener);\n\n // 存储清理函数,用于在 destroy 时移除监听器\n this.eventListenerUnsubscribers.push(() => {\n this.eventBus.offEvent(\"endpoint:status:changed\", listener);\n });\n }\n\n /**\n * 设置 MCP 服务添加事件监听\n * 当添加新的 MCP 服务后,自动重连接入点以同步服务列表\n */\n private setupMCPServerAddedListener(): void {\n // 监听单个服务添加事件\n const singleServerListener = async (\n eventData: EventBusEvents[\"mcp:server:added\"]\n ) => {\n this.logger.info(\n `检测到 MCP 服务添加: ${eventData.serverName},工具数量: ${eventData.tools.length}`\n );\n\n if (!this.endpointManager) {\n this.logger.warn(\"EndpointManager 未初始化,跳过重连\");\n return;\n }\n\n try {\n // 获取当前连接的端点数量\n const connectionStatuses = this.endpointManager.getConnectionStatus();\n const connectedEndpointCount = connectionStatuses.filter(\n (status) => status.connected\n ).length;\n\n if (connectedEndpointCount === 0) {\n this.logger.debug(\"当前没有已连接的端点,跳过重连\");\n return;\n }\n\n this.logger.info(`开始重连 ${connectedEndpointCount} 个接入点...`);\n\n // 重连所有端点\n await this.endpointManager.reconnect();\n\n this.logger.info(\"接入点重连成功,新服务工具已同步\");\n\n // 发送重连完成事件\n this.eventBus.emitEvent(\"endpoint:reconnect:completed\", {\n trigger: \"mcp_server_added\",\n serverName: eventData.serverName,\n endpointCount: connectedEndpointCount,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(\"接入点重连失败:\", error);\n\n // 发送重连失败事件\n this.eventBus.emitEvent(\"endpoint:reconnect:failed\", {\n trigger: \"mcp_server_added\",\n serverName: eventData.serverName,\n error: error instanceof Error ? error.message : String(error),\n timestamp: Date.now(),\n });\n }\n };\n\n this.eventBus.onEvent(\"mcp:server:added\", singleServerListener);\n\n // 存储清理函数\n this.eventListenerUnsubscribers.push(() => {\n this.eventBus.offEvent(\"mcp:server:added\", singleServerListener);\n });\n\n // 监听批量服务添加事件\n const batchServerListener = async (\n eventData: EventBusEvents[\"mcp:server:batch_added\"]\n ) => {\n this.logger.info(\n `检测到批量 MCP 服务添加: ${eventData.addedCount} 个成功,${eventData.failedCount} 个失败`\n );\n\n if (!this.endpointManager || eventData.addedCount === 0) {\n return;\n }\n\n try {\n // 获取当前连接的端点数量\n const connectionStatuses = this.endpointManager.getConnectionStatus();\n const connectedEndpointCount = connectionStatuses.filter(\n (status) => status.connected\n ).length;\n\n if (connectedEndpointCount === 0) {\n this.logger.debug(\"当前没有已连接的端点,跳过重连\");\n return;\n }\n\n this.logger.info(`开始重连 ${connectedEndpointCount} 个接入点...`);\n\n // 重连所有端点\n await this.endpointManager.reconnect();\n\n this.logger.info(\"接入点重连成功,批量服务工具已同步\");\n\n // 发送重连完成事件\n this.eventBus.emitEvent(\"endpoint:reconnect:completed\", {\n trigger: \"mcp_server_batch_added\",\n serverName: undefined,\n endpointCount: connectedEndpointCount,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(\"接入点重连失败:\", error);\n\n // 发送重连失败事件\n this.eventBus.emitEvent(\"endpoint:reconnect:failed\", {\n trigger: \"mcp_server_batch_added\",\n serverName: undefined,\n error: error instanceof Error ? error.message : String(error),\n timestamp: Date.now(),\n });\n }\n };\n\n this.eventBus.onEvent(\"mcp:server:batch_added\", batchServerListener);\n\n // 存储清理函数\n this.eventListenerUnsubscribers.push(() => {\n this.eventBus.offEvent(\"mcp:server:batch_added\", batchServerListener);\n });\n }\n\n public async start(): Promise<void> {\n // 检查服务器是否已经启动\n if (this.httpServer) {\n this.logger.warn(\"Web server is already running\");\n return;\n }\n\n // 1. 初始化所有连接(配置驱动)\n // 这必须在启动服务器之前完成,确保 MCPServiceManager 可用\n await this.initializeConnections();\n\n // 2. 设置路由系统(在连接初始化之后)\n this.setupRouteSystem();\n this.setupRoutesFromRegistry();\n\n // 3. 启动 HTTP 服务器\n const server = serve({\n fetch: this.app.fetch,\n port: this.port,\n hostname: HTTP_SERVER_CONFIG.DEFAULT_BIND_ADDRESS, // 绑定到所有网络接口,支持 Docker 部署\n createServer,\n });\n\n // 保存服务器实例\n this.httpServer = server;\n\n // 设置 WebSocket 服务器\n if (!this.httpServer) {\n throw new Error(\"HTTP server 未初始化\");\n }\n this.wss = new WebSocketServer({\n server: this.httpServer as Server<\n typeof IncomingMessage,\n typeof ServerResponse\n >,\n });\n this.setupWebSocket();\n\n // 启动心跳监控\n this.heartbeatMonitorInterval =\n this.heartbeatHandler.startHeartbeatMonitoring();\n\n this.logger.info(\n `Web server listening on http://${HTTP_SERVER_CONFIG.DEFAULT_BIND_ADDRESS}:${this.port}`\n );\n this.logger.info(`Local access: http://localhost:${this.port}`);\n }\n\n public stop(): Promise<void> {\n return new Promise((resolve) => {\n let resolved = false;\n\n const doResolve = () => {\n if (!resolved) {\n resolved = true;\n resolve();\n }\n };\n\n // 清理连接管理器和 MCPServiceManager\n (async () => {\n try {\n if (this.endpointManager) {\n await this.endpointManager.cleanup();\n this.logger.debug(\"连接管理器已清理\");\n }\n } catch (error) {\n this.logger.error(\"连接管理器清理失败:\", error);\n }\n\n try {\n if (this.mcpServiceManager) {\n await this.mcpServiceManager.stopAllServices();\n this.mcpServiceManager = null;\n this.logger.debug(\"MCPServiceManager 已清理\");\n }\n } catch (error) {\n this.logger.error(\"MCPServiceManager 清理失败:\", error);\n }\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 强制断开所有 WebSocket 客户端连接\n if (this.wss) {\n for (const client of this.wss.clients) {\n client.terminate();\n }\n\n // 关闭 WebSocket 服务器\n this.wss.close(() => {\n let forceCloseTimer: NodeJS.Timeout | undefined;\n\n const cleanupAndResolve = () => {\n if (forceCloseTimer) {\n clearTimeout(forceCloseTimer);\n forceCloseTimer = undefined;\n }\n doResolve();\n };\n\n // 强制关闭 HTTP 服务器,不等待现有连接\n if (this.httpServer) {\n this.httpServer.close(() => {\n this.logger.info(\"Web 服务器已停止\");\n cleanupAndResolve();\n });\n\n // 设置超时,如果 2 秒内没有关闭则强制退出\n forceCloseTimer = setTimeout(() => {\n // 超时触发后标记定时器已失效,保持与 cleanupAndResolve 中的语义一致\n forceCloseTimer = undefined;\n this.logger.info(\"Web 服务器已强制停止\");\n doResolve();\n }, 2000);\n } else {\n this.logger.info(\"Web 服务器已停止\");\n cleanupAndResolve();\n }\n });\n } else {\n this.logger.info(\"Web 服务器已停止\");\n doResolve();\n }\n })();\n });\n }\n\n /**\n * 销毁 WebServer 实例,清理所有资源\n */\n public destroy(): void {\n this.logger.debug(\"销毁 WebServer 实例\");\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 移除所有事件监听器,防止内存泄漏\n for (const unsubscribe of this.eventListenerUnsubscribers) {\n unsubscribe();\n }\n this.eventListenerUnsubscribers = [];\n this.logger.debug(\"已移除所有事件总线监听器\");\n\n // 销毁服务层\n this.statusService.destroy();\n this.notificationService.destroy();\n // 异步销毁 ESP32 设备管理器(fire and forget)\n this.esp32Manager.destroy();\n\n // 销毁事件总线\n destroyEventBus();\n\n this.logger.debug(\"WebServer 实例已销毁\");\n }\n}\n","/**\n * 日志系统模块\n *\n * 提供统一的日志记录功能,基于 Pino 日志库实现。\n *\n * ## 主要特性\n *\n * - **多种日志级别**:支持通过日志级别值进行过滤和阈值设置,包括 trace、debug、info、warn、error、fatal\n * - **双重输出**:支持控制台和文件双重输出,控制台输出带彩色格式化\n * - **守护进程模式**:支持守护进程模式(仅文件输出,无控制台输出)\n * - **结构化日志**:支持结构化日志记录,便于日志分析和查询\n * - **自动日志轮转**:自动日志文件轮转和管理,防止日志文件过大\n * - **高性能**:基于 Pino 的高性能异步写入,对应用性能影响极小\n * - **错误堆栈跟踪**:完整的错误堆栈跟踪,便于问题定位\n * - **动态日志级别**:支持动态设置日志级别,无需重启应用\n *\n * ## 日志级别\n *\n * Logger 支持以下日志级别值用于过滤和阈值设置(按严重性递增):\n *\n * - `trace` (10):最详细的日志级别\n * - `debug` (20):调试信息\n * - `info` (30):一般信息 - 提供对应的 `logger.info()` 方法\n * - `warn` (40):警告信息 - 提供对应的 `logger.warn()` 方法\n * - `error` (50):错误信息 - 提供对应的 `logger.error()` 方法\n * - `fatal` (60):致命错误\n *\n * **注意**:当前提供的记录方法包括 `info()`、`success()`、`warn()`、`error()`、`debug()` 和 `log()`。\n * 可以通过 `setGlobalLogLevel()` 设置日志级别阈值来控制输出详细程度。\n *\n * ## 使用示例\n *\n * ### 基本使用\n *\n * ```typescript\n * import { logger } from '@/Logger.js';\n *\n * // 记录信息\n * logger.info('服务启动成功');\n * logger.error('发生错误', error);\n * logger.debug('调试信息', { data: 'value' });\n * ```\n *\n * ### 结构化日志\n *\n * ```typescript\n * // 结构化日志支持\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n * logger.error({ error: err, requestId: 'abc123' }, '请求处理失败');\n * ```\n *\n * ### 创建自定义 Logger 实例\n *\n * ```typescript\n * import { createLogger } from '@/Logger.js';\n *\n * // 创建指定级别的 Logger\n * const customLogger = createLogger('debug');\n * customLogger.debug('这是一条调试日志');\n * ```\n *\n * ### 动态设置日志级别\n *\n * ```typescript\n * import { setGlobalLogLevel } from '@/Logger.js';\n *\n * // 设置全局日志级别\n * setGlobalLogLevel('debug');\n * ```\n *\n * ### 文件日志配置\n *\n * ```typescript\n * import { logger } from '@/Logger.js';\n *\n * // 初始化日志文件\n * logger.initLogFile('/path/to/project');\n *\n * // 配置日志文件管理参数\n * logger.setLogFileOptions(10 * 1024 * 1024, 5); // 10MB,最多5个文件\n * ```\n *\n * ## 与 Pino 的集成\n *\n * 本模块基于 [Pino](https://getpino.io/) 日志库实现,提供了以下增强:\n *\n * - 控制台输出的彩色格式化\n * - 简化的 API 设计\n * - 自动日志文件轮转\n * - 守护进程模式支持\n * - 结构化日志支持\n * - 动态日志级别控制\n *\n * ## 守护进程模式\n *\n * 当环境变量 `XIAOZHI_DAEMON=true` 时,Logger 自动进入守护进程模式:\n *\n * - 仅输出到日志文件,不输出到控制台\n * - 适用于后台服务运行场景\n *\n * **重要提示**:守护进程模式下必须先调用 `logger.initLogFile()` 初始化日志文件路径,\n * 否则日志将被写入 `/dev/null`(等同于被丢弃)。\n *\n * @example\n * ```typescript\n * // 守护进程模式下的正确使用方式\n * import { logger } from '@/Logger.js';\n *\n * // 1. 先初始化日志文件\n * logger.initLogFile('/path/to/project');\n *\n * // 2. 再记录日志\n * logger.info('服务启动成功');\n * ```\n *\n * @module apps/backend/Logger\n *\n * @example\n * ```typescript\n * import { logger } from '@/Logger.js';\n *\n * logger.info('服务启动成功');\n * logger.error('发生错误', error);\n * logger.debug('调试信息', { data: 'value' });\n * ```\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\nimport { z } from \"zod\";\n\nconst LogLevelSchema = z.enum([\n \"fatal\",\n \"error\",\n \"warn\",\n \"info\",\n \"debug\",\n \"trace\",\n]);\ntype Level = z.infer<typeof LogLevelSchema>;\n\n/**\n * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式\n * @param date 要格式化的日期对象\n * @returns 格式化后的日期时间字符串\n */\nfunction formatDateTime(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * 高性能日志记录器,基于 pino 实现\n *\n * 特性:\n * - 支持控制台和文件双重输出\n * - 支持守护进程模式(仅文件输出)\n * - 支持结构化日志记录\n * - 自动日志文件轮转和管理\n * - 高性能异步写入\n * - 完整的错误堆栈跟踪\n */\nexport class Logger {\n private logFilePath: string | null = null;\n private pinoInstance: PinoLogger;\n private isDaemonMode: boolean;\n private logLevel: Level; // 新增:动态日志级别\n private maxLogFileSize = 10 * 1024 * 1024; // 10MB 默认最大文件大小\n private maxLogFiles = 5; // 最多保留5个日志文件\n\n constructor(level: Level = \"info\") {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n\n // 设置并验证日志级别\n this.logLevel = this.validateLogLevel(level);\n\n // 创建 pino 实例\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 验证日志级别\n * @param level 日志级别\n * @returns 验证后的日志级别\n */\n private validateLogLevel(level: string): Level {\n const normalizedLevel = level.toLowerCase();\n const result = LogLevelSchema.safeParse(normalizedLevel);\n\n if (result.success) {\n return result.data;\n }\n\n return \"info\";\n }\n\n private createPinoInstance(): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 只在非守护进程模式下添加\n if (!this.isDaemonMode) {\n // 使用高性能的控制台输出流\n const consoleStream = this.createOptimizedConsoleStream();\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: consoleStream,\n });\n }\n\n // 文件流 - 如果有日志文件路径,使用高性能异步写入\n if (this.logFilePath) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({\n dest: this.logFilePath,\n sync: false, // 异步写入提升性能\n append: true,\n mkdir: true,\n }),\n });\n }\n\n // 如果没有流,创建一个空的流避免错误\n if (streams.length === 0) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({ dest: \"/dev/null\" }),\n });\n }\n\n return pino(\n {\n level: this.logLevel, // 修改:使用动态日志级别\n // 高性能配置\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n // 优化级别格式化\n level: (_label: string, number: number) => ({ level: number }),\n },\n // 禁用不必要的功能以提升性能\n base: null, // 不包含 pid 和 hostname\n serializers: {\n // 优化错误序列化,在测试环境中安全处理\n err: pino.stdSerializers?.err || ((err: any) => err),\n },\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n private createOptimizedConsoleStream() {\n // 预编译级别映射以提升性能\n const levelMap = new Map([\n [20, { name: \"DEBUG\", color: chalk.gray }],\n [30, { name: \"INFO\", color: chalk.blue }],\n [40, { name: \"WARN\", color: chalk.yellow }],\n [50, { name: \"ERROR\", color: chalk.red }],\n [60, { name: \"FATAL\", color: chalk.red }],\n ]);\n\n return {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessageOptimized(logObj, levelMap);\n // 在测试环境中安全地写入\n this.safeWrite(`${message}\\n`);\n } catch (error) {\n // 如果解析失败,直接输出原始内容\n this.safeWrite(chunk);\n }\n },\n };\n }\n\n /**\n * 安全地写入到 stderr,在测试环境中避免错误\n */\n private safeWrite(content: string): void {\n try {\n if (process.stderr && typeof process.stderr.write === \"function\") {\n process.stderr.write(content);\n } else if (console && typeof console.error === \"function\") {\n // 在测试环境中回退到 console.error\n console.error(content.trim());\n }\n } catch (error) {\n // 在极端情况下静默失败,避免测试中断\n }\n }\n\n private formatConsoleMessageOptimized(\n logObj: any,\n levelMap: Map<number, { name: string; color: (text: string) => string }>\n ): string {\n const timestamp = formatDateTime(new Date());\n\n const levelInfo = levelMap.get(logObj.level) || {\n name: \"UNKNOWN\",\n color: (text: string) => text,\n };\n const coloredLevel = levelInfo.color(`[${levelInfo.name}]`);\n\n // 处理结构化日志中的 args,保持兼容性\n let message = logObj.msg;\n if (logObj.args && Array.isArray(logObj.args)) {\n const argsStr = logObj.args\n .map((arg: any) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \");\n message = `${message} ${argsStr}`;\n }\n\n return `[${timestamp}] ${coloredLevel} ${message}`;\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 检查并轮转日志文件\n this.rotateLogFileIfNeeded();\n\n // 确保日志文件存在\n try {\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n } catch (error) {\n // 如果创建日志文件失败,记录警告但继续执行\n // 允许应用在没有文件日志的情况下启动\n console.warn(\n `[Logger] 无法创建日志文件 ${this.logFilePath}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n // 清除日志路径,禁用文件日志\n this.logFilePath = null;\n }\n\n // 重新创建 pino 实例以包含文件流\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n // 在 pino 实现中,文件日志的启用/禁用通过重新创建实例来实现\n // 这里保持方法兼容性,但实际上文件日志在 initLogFile 时就已经启用\n if (enable && this.logFilePath) {\n // 重新创建 pino 实例以确保文件流正确配置\n this.pinoInstance = this.createPinoInstance();\n }\n }\n\n /**\n * 记录信息级别日志\n * @param message 日志消息\n * @param args 额外参数\n * @example\n * logger.info('用户登录', 'userId', 12345);\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n */\n info(message: string, ...args: any[]): void;\n /**\n * 记录结构化信息级别日志\n * @param obj 结构化日志对象\n * @param message 可选的日志消息\n */\n info(obj: object, message?: string): void;\n info(messageOrObj: string | object, ...args: any[]): void {\n this.logInfo(messageOrObj, ...args);\n }\n\n /**\n * 内部方法:记录 info 级别的日志\n * @param messageOrObj 日志消息或对象\n * @param args 额外参数\n * @private\n */\n private logInfo(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n success(message: string, ...args: any[]): void;\n success(obj: object, message?: string): void;\n success(messageOrObj: string | object, ...args: any[]): void {\n // success 映射为 info 级别,保持 API 兼容性\n this.logInfo(messageOrObj, ...args);\n }\n\n warn(message: string, ...args: any[]): void;\n warn(obj: object, message?: string): void;\n warn(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.warn(messageOrObj);\n } else {\n this.pinoInstance.warn({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.warn(messageOrObj, args[0] || \"\");\n }\n }\n\n error(message: string, ...args: any[]): void;\n error(obj: object, message?: string): void;\n error(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.error(messageOrObj);\n } else {\n // 改进错误处理 - 特殊处理 Error 对象\n const errorArgs = args.map((arg) => {\n if (arg instanceof Error) {\n if (this.pinoInstance.level === \"debug\") return arg.message;\n return {\n message: arg.message,\n stack: arg.stack,\n name: arg.name,\n cause: arg.cause,\n };\n }\n return arg;\n });\n this.pinoInstance.error({ args: errorArgs }, messageOrObj);\n }\n } else {\n // 结构化错误日志,自动提取错误信息\n const enhancedObj = this.enhanceErrorObject(messageOrObj);\n this.pinoInstance.error(enhancedObj, args[0] || \"\");\n }\n }\n\n debug(message: string, ...args: any[]): void;\n debug(obj: object, message?: string): void;\n debug(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.debug(messageOrObj);\n } else {\n this.pinoInstance.debug({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.debug(messageOrObj, args[0] || \"\");\n }\n }\n\n log(message: string, ...args: any[]): void;\n log(obj: object, message?: string): void;\n log(messageOrObj: string | object, ...args: any[]): void {\n // log 方法使用 info 级别\n this.logInfo(messageOrObj, ...args);\n }\n\n /**\n * 增强错误对象,提取更多错误信息\n */\n private enhanceErrorObject(obj: any): any {\n const enhanced = { ...obj };\n\n // 遍历对象属性,查找 Error 实例\n for (const [key, value] of Object.entries(enhanced)) {\n if (value instanceof Error) {\n enhanced[key] = {\n message: value.message,\n stack: value.stack,\n name: value.name,\n cause: value.cause,\n };\n }\n }\n\n return enhanced;\n }\n\n /**\n * 检查并轮转日志文件(如果需要)\n */\n private rotateLogFileIfNeeded(): void {\n if (!this.logFilePath || !fs.existsSync(this.logFilePath)) {\n return;\n }\n\n try {\n const stats = fs.statSync(this.logFilePath);\n if (stats.size > this.maxLogFileSize) {\n this.rotateLogFile();\n }\n } catch (error) {\n // 忽略文件状态检查错误\n }\n }\n\n /**\n * 轮转日志文件\n */\n private rotateLogFile(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 移动现有的编号日志文件\n for (let i = this.maxLogFiles - 1; i >= 1; i--) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n const newFile = path.join(logDir, `${logName}.${i + 1}.log`);\n\n if (fs.existsSync(oldFile)) {\n if (i === this.maxLogFiles - 1) {\n // 删除最老的文件\n fs.unlinkSync(oldFile);\n } else {\n fs.renameSync(oldFile, newFile);\n }\n }\n }\n\n // 将当前日志文件重命名为 .1.log\n const firstRotatedFile = path.join(logDir, `${logName}.1.log`);\n fs.renameSync(this.logFilePath, firstRotatedFile);\n } catch (error) {\n // 轮转失败时忽略错误,继续使用当前文件\n }\n }\n\n /**\n * 清理旧的日志文件\n */\n cleanupOldLogs(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 删除超过最大数量的日志文件\n for (let i = this.maxLogFiles + 1; i <= this.maxLogFiles + 10; i++) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n if (fs.existsSync(oldFile)) {\n fs.unlinkSync(oldFile);\n }\n }\n } catch (error) {\n // 忽略清理错误\n }\n }\n\n /**\n * 设置日志文件管理参数\n */\n setLogFileOptions(maxSize: number, maxFiles: number): void {\n this.maxLogFileSize = maxSize;\n this.maxLogFiles = maxFiles;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n // pino 实例会自动处理流的关闭\n // 这里保持方法兼容性\n }\n\n /**\n * 动态设置日志级别\n * @param level 新的日志级别\n * @description 动态更新Logger实例的日志级别\n */\n setLevel(level: Level): void {\n this.logLevel = this.validateLogLevel(level);\n\n // 重新创建pino实例以应用新的日志级别\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 获取当前日志级别\n * @returns 当前日志级别\n */\n getLevel(): Level {\n return this.logLevel;\n }\n}\n\n// 全局Logger实例管理\nlet globalLogger: Logger | null = null;\nlet globalLogLevel: Level = \"info\"; // 全局日志级别\n\n/**\n * 创建Logger实例\n * @param level 日志级别,默认为全局级别\n * @returns Logger实例\n */\nexport function createLogger(level?: Level): Logger {\n return new Logger(level || globalLogLevel);\n}\n\n/**\n * 获取全局Logger实例\n * @returns 全局Logger实例\n */\nexport function getLogger(): Logger {\n if (!globalLogger) {\n globalLogger = new Logger(globalLogLevel); // 使用全局级别\n }\n return globalLogger;\n}\n\n/**\n * 设置全局Logger实例\n * @param logger 新的Logger实例\n */\nexport function setGlobalLogger(logger: Logger): void {\n globalLogger = logger;\n}\n\n/**\n * 设置全局日志级别\n * @param level 新的日志级别\n * @description 更新全局日志级别,并影响现有和未来的Logger实例\n */\nexport function setGlobalLogLevel(level: Level): void {\n globalLogLevel = level;\n\n // 如果已存在全局Logger实例,更新其级别\n if (globalLogger) {\n globalLogger.setLevel(level);\n }\n}\n\n/**\n * 获取当前全局日志级别\n * @returns 当前日志级别\n */\nexport function getGlobalLogLevel(): Level {\n return globalLogLevel;\n}\n\n// 导出默认实例(向后兼容)\nexport const logger = getLogger();\n","/**\n * 提示词解析工具\n *\n * 支持三种格式的提示词配置:\n * 1. 绝对路径:如 `/Users/xxx/prompts/default.md`\n * 2. 相对路径:如 `./prompts/default.md`(相对于配置文件所在目录)\n * 3. 纯字符串:直接作为提示词内容\n */\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { configManager } from \"@xiaozhi-client/config\";\n\n// 默认系统提示词\nconst DEFAULT_SYSTEM_PROMPT =\n \"你是一个友好的语音助手,请用简洁的中文回答用户的问题。\";\n\n/**\n * 判断配置值是否为路径格式\n *\n * 路径格式的判断规则:\n * - 相对路径:以 `./`、`../`、`.\\` 或 `..\\` 开头(支持 Windows 和 Unix 风格)\n * - 绝对路径:使用 path.isAbsolute() 判断\n * - 其他情况:视为纯字符串内容\n *\n * @param config - 提示词配置值\n * @returns 是否为路径格式\n */\nfunction isPromptPath(config: string): boolean {\n // 将路径分隔符统一为正斜杠,便于跨平台判断\n const normalizedConfig = config.replace(/\\\\/g, \"/\");\n\n // 相对路径:以 ./ 或 ../ 开头\n if (normalizedConfig.startsWith(\"./\") || normalizedConfig.startsWith(\"../\")) {\n return true;\n }\n // 绝对路径\n if (isAbsolute(config)) {\n return true;\n }\n return false;\n}\n\n/**\n * 从文件路径读取提示词内容\n *\n * @param promptPath - 提示词文件路径(绝对路径或相对路径)\n * @returns 提示词内容,如果读取失败则返回 null\n */\nfunction resolvePromptFromPath(promptPath: string): string | null {\n try {\n // 将 Windows 风格的反斜杠统一转换为正斜杠,便于跨平台解析\n const normalizedPath = promptPath.replace(/\\\\/g, \"/\");\n\n // 解析路径\n let resolvedPath: string;\n if (isAbsolute(normalizedPath)) {\n // 绝对路径直接使用\n resolvedPath = normalizedPath;\n } else {\n // 相对路径:相对于配置文件所在目录\n const configFilePath = configManager.getConfigPath();\n const configDir = dirname(configFilePath);\n resolvedPath = resolve(configDir, normalizedPath);\n }\n\n // 检查文件是否存在\n if (!existsSync(resolvedPath)) {\n console.warn(\n `[prompt-utils] 提示词文件不存在: ${resolvedPath},将使用默认提示词`\n );\n return null;\n }\n\n // 读取文件内容\n const content = readFileSync(resolvedPath, \"utf-8\").trim();\n\n // 检查文件内容是否为空\n if (!content) {\n console.warn(\n `[prompt-utils] 提示词文件内容为空: ${resolvedPath},将使用默认提示词`\n );\n return null;\n }\n\n console.info(`[prompt-utils] 成功从文件加载提示词: ${resolvedPath}`);\n return content;\n } catch (error) {\n console.error(\n `[prompt-utils] 读取提示词文件失败: ${promptPath}`,\n error instanceof Error ? error.message : String(error)\n );\n return null;\n }\n}\n\n/**\n * 解析提示词配置\n *\n * 处理逻辑:\n * 1. 未配置或空字符串 → 返回默认提示词\n * 2. 是路径格式 → 尝试读取文件内容\n * 3. 不是路径格式 → 直接返回作为纯字符串\n *\n * @param promptConfig - 提示词配置值(可选)\n * @returns 解析后的提示词内容\n */\nexport function resolvePrompt(promptConfig?: string): string {\n // 未配置或空字符串,返回默认提示词\n if (!promptConfig || promptConfig.trim() === \"\") {\n return DEFAULT_SYSTEM_PROMPT;\n }\n\n // 判断是否为路径格式\n if (isPromptPath(promptConfig)) {\n // 尝试从路径读取\n const content = resolvePromptFromPath(promptConfig);\n // 读取失败返回默认提示词\n return content || DEFAULT_SYSTEM_PROMPT;\n }\n\n // 不是路径格式,直接作为纯字符串返回\n return promptConfig;\n}\n\n/**\n * 获取默认系统提示词\n *\n * @returns 默认系统提示词\n */\nexport function getDefaultSystemPrompt(): string {\n return DEFAULT_SYSTEM_PROMPT;\n}\n\n/**\n * 提示词文件信息\n */\nexport interface PromptFileInfo {\n /** 文件名 */\n fileName: string;\n /** 相对路径(相对于配置文件所在目录) */\n relativePath: string;\n}\n\n/**\n * 获取 prompts 目录下的所有 .md 文件列表\n *\n * @returns 提示词文件信息数组\n */\nexport function listPromptFiles(): PromptFileInfo[] {\n try {\n const configFilePath = configManager.getConfigPath();\n const configDir = dirname(configFilePath);\n const promptsDir = resolve(configDir, \"prompts\");\n\n // 检查 prompts 目录是否存在\n if (!existsSync(promptsDir)) {\n return [];\n }\n\n // 读取目录下的所有文件\n const files = readdirSync(promptsDir);\n\n // 过滤出 .md 文件并构建返回结果\n const promptFiles: PromptFileInfo[] = files\n .filter((file: string) => file.endsWith(\".md\"))\n .map((file: string) => ({\n fileName: file,\n relativePath: `./prompts/${file}`,\n }));\n\n return promptFiles;\n } catch (error) {\n console.error(\n \"[prompt-utils] 获取提示词文件列表失败:\",\n error instanceof Error ? error.message : String(error)\n );\n return [];\n }\n}\n\n// ==================== 提示词文件操作相关函数 ====================\n\n/** 最大文件大小限制(100KB) */\nconst MAX_FILE_SIZE = 100 * 1024;\n\n/** 文件名验证正则:允许字母、数字、下划线、中划线、中文 */\nconst FILE_NAME_REGEX = /^[\\u4e00-\\u9fa5a-zA-Z0-9_-]+\\.md$/;\n\n/**\n * 验证提示词文件路径是否安全\n *\n * 安全规则:\n * 1. 必须是相对路径格式(以 ./prompts/ 开头)\n * 2. 路径不能包含 ..(防止路径遍历攻击)\n * 3. 文件名必须符合规范\n *\n * @param relativePath - 相对路径\n * @returns 验证结果,包含是否有效和错误信息\n */\nexport function validatePromptPath(relativePath: string): {\n valid: boolean;\n error?: string;\n} {\n // 将 Windows 风格的反斜杠统一转换为正斜杠,便于跨平台验证\n const normalizedPath = relativePath.replace(/\\\\/g, \"/\");\n\n // 检查路径格式(使用规范化后的路径)\n if (!normalizedPath.startsWith(\"./prompts/\")) {\n return {\n valid: false,\n error: \"路径格式错误,必须以 ./prompts/ 开头\",\n };\n }\n\n // 检查路径遍历攻击(使用规范化后的路径)\n if (normalizedPath.includes(\"..\")) {\n return {\n valid: false,\n error: \"路径不能包含 ..\",\n };\n }\n\n // 提取文件名并验证(使用规范化后的路径)\n const fileName = normalizedPath.replace(\"./prompts/\", \"\");\n if (!FILE_NAME_REGEX.test(fileName)) {\n return {\n valid: false,\n error:\n \"文件名只能包含字母、数字、下划线、中划线、中文,且必须以 .md 结尾\",\n };\n }\n\n return { valid: true };\n}\n\n/**\n * 验证提示词文件名是否合法\n *\n * @param fileName - 文件名\n * @returns 验证结果\n */\nexport function validatePromptFileName(fileName: string): {\n valid: boolean;\n error?: string;\n} {\n if (!FILE_NAME_REGEX.test(fileName)) {\n return {\n valid: false,\n error:\n \"文件名只能包含字母、数字、下划线、中划线、中文,且必须以 .md 结尾\",\n };\n }\n return { valid: true };\n}\n\n/**\n * 获取 prompts 目录的绝对路径\n *\n * @returns prompts 目录的绝对路径\n */\nexport function getPromptsDir(): string {\n const configFilePath = configManager.getConfigPath();\n const configDir = dirname(configFilePath);\n return resolve(configDir, \"prompts\");\n}\n\n/**\n * 将相对路径解析为绝对路径\n *\n * @param relativePath - 相对路径(如 ./prompts/default.md)\n * @returns 绝对路径\n */\nexport function resolvePromptPath(relativePath: string): string {\n const promptsDir = getPromptsDir();\n const fileName = relativePath.replace(\"./prompts/\", \"\");\n return resolve(promptsDir, fileName);\n}\n\n/**\n * 提示词文件内容信息\n */\nexport interface PromptFileContent {\n /** 文件名 */\n fileName: string;\n /** 相对路径(相对于配置文件所在目录) */\n relativePath: string;\n /** 文件内容 */\n content: string;\n}\n\n/**\n * 读取提示词文件内容\n *\n * @param relativePath - 相对路径(如 ./prompts/default.md)\n * @returns 文件内容信息\n * @throws 如果路径无效或文件不存在\n */\nexport function readPromptFile(relativePath: string): PromptFileContent {\n // 验证路径\n const validation = validatePromptPath(relativePath);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 解析绝对路径\n const absolutePath = resolvePromptPath(relativePath);\n\n // 检查文件是否存在\n if (!existsSync(absolutePath)) {\n throw new Error(`文件不存在: ${relativePath}`);\n }\n\n // 检查文件大小\n const stats = statSync(absolutePath);\n if (stats.size > MAX_FILE_SIZE) {\n throw new Error(\"文件大小超过限制(最大 100KB)\");\n }\n\n // 读取文件内容\n const content = readFileSync(absolutePath, \"utf-8\");\n\n return {\n fileName: relativePath.replace(\"./prompts/\", \"\"),\n relativePath,\n content,\n };\n}\n\n/**\n * 更新提示词文件内容\n *\n * @param relativePath - 相对路径(如 ./prompts/default.md)\n * @param content - 新的文件内容\n * @throws 如果路径无效或文件不存在\n */\nexport function updatePromptFile(\n relativePath: string,\n content: string\n): PromptFileContent {\n // 验证路径\n const validation = validatePromptPath(relativePath);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 验证内容大小(按 UTF-8 字节数,与文件大小限制保持一致)\n if (Buffer.byteLength(content, \"utf8\") > MAX_FILE_SIZE) {\n throw new Error(\"内容大小超过限制(最大 100KB)\");\n }\n\n // 解析绝对路径\n const absolutePath = resolvePromptPath(relativePath);\n\n // 检查文件是否存在\n if (!existsSync(absolutePath)) {\n throw new Error(`文件不存在: ${relativePath}`);\n }\n\n // 写入文件\n writeFileSync(absolutePath, content, \"utf-8\");\n\n return {\n fileName: relativePath.replace(\"./prompts/\", \"\"),\n relativePath,\n content,\n };\n}\n\n/**\n * 创建新的提示词文件\n *\n * @param fileName - 文件名(如 custom-prompt.md)\n * @param content - 文件内容\n * @returns 新创建的文件信息\n * @throws 如果文件名无效或文件已存在\n */\nexport function createPromptFile(\n fileName: string,\n content: string\n): PromptFileContent {\n // 验证文件名\n const validation = validatePromptFileName(fileName);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 验证内容大小(按 UTF-8 字节数计算,避免多字节字符导致限制失真)\n const contentSize = Buffer.byteLength(content, \"utf8\");\n if (contentSize > MAX_FILE_SIZE) {\n throw new Error(\"内容大小超过限制(最大 100KB)\");\n }\n\n // 获取 prompts 目录\n const promptsDir = getPromptsDir();\n\n // 确保 prompts 目录存在\n if (!existsSync(promptsDir)) {\n mkdirSync(promptsDir, { recursive: true });\n }\n\n // 构建文件路径\n const absolutePath = resolve(promptsDir, fileName);\n const relativePath = `./prompts/${fileName}`;\n\n // 检查文件是否已存在\n if (existsSync(absolutePath)) {\n throw new Error(`文件已存在: ${fileName}`);\n }\n\n // 写入文件\n writeFileSync(absolutePath, content, \"utf-8\");\n\n return {\n fileName,\n relativePath,\n content,\n };\n}\n\n/**\n * 删除提示词文件\n *\n * @param relativePath - 相对路径(如 ./prompts/old-prompt.md)\n * @throws 如果路径无效或文件不存在\n */\nexport function deletePromptFile(relativePath: string): void {\n // 验证路径\n const validation = validatePromptPath(relativePath);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 解析绝对路径\n const absolutePath = resolvePromptPath(relativePath);\n\n // 检查文件是否存在\n if (!existsSync(absolutePath)) {\n throw new Error(`文件不存在: ${relativePath}`);\n }\n\n // 删除文件\n rmSync(absolutePath);\n}\n","/**\n * 配置 API HTTP 路由处理器\n * 提供配置读取、配置更新等配置相关的 RESTful API 接口\n */\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport {\n createPromptFile,\n deletePromptFile,\n listPromptFiles,\n readPromptFile,\n updatePromptFile,\n} from \"@/utils/prompt-utils.js\";\nimport type { AppConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 配置 API 处理器\n */\nexport class ConfigApiHandler extends BaseHandler {\n constructor() {\n super();\n }\n\n /**\n * 获取配置\n * GET /api/config\n */\n async getConfig(c: Context<AppContext>): Promise<Response> {\n const logger = c.get(\"logger\");\n try {\n logger.debug(\"处理获取配置请求\");\n const config = configManager.getConfig();\n logger.debug(\"获取配置成功\");\n return c.success(config);\n } catch (error) {\n logger.error(\"获取配置失败:\", error);\n return c.fail(\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 更新配置\n * PUT /api/config\n */\n async updateConfig(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理更新配置请求\");\n const newConfig: AppConfig = await c.req.json();\n\n // 使用 configManager 的验证方法\n configManager.validateConfig(newConfig);\n\n // 使用 configManager 的批量更新方法\n configManager.updateConfig(newConfig);\n\n // 更新服务工具配置(单独处理,因为 updateConfig 只更新已存在的配置)\n if (newConfig.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n newConfig.mcpServerConfig\n )) {\n for (const [toolName, toolConfig] of Object.entries(\n toolsConfig.tools\n )) {\n configManager.setToolEnabled(\n serverName,\n toolName,\n toolConfig.enable\n );\n }\n }\n }\n\n c.get(\"logger\").info(\"配置更新成功\");\n return c.success(undefined, \"配置更新成功\");\n } catch (error) {\n c.get(\"logger\").error(\"配置更新失败:\", error);\n return c.fail(\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"配置更新失败\"\n );\n }\n }\n\n /**\n * 获取 MCP 端点\n * GET /api/config/mcp-endpoint\n */\n async getMcpEndpoint(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取 MCP 端点请求\");\n const endpoint = configManager.getMcpEndpoint();\n c.get(\"logger\").debug(\"获取 MCP 端点成功\");\n return c.success({ endpoint });\n } catch (error) {\n c.get(\"logger\").error(\"获取 MCP 端点失败:\", error);\n return c.fail(\n \"MCP_ENDPOINT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取 MCP 端点列表\n * GET /api/config/mcp-endpoints\n */\n async getMcpEndpoints(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取 MCP 端点列表请求\");\n const endpoints = configManager.getMcpEndpoints();\n c.get(\"logger\").debug(\"获取 MCP 端点列表成功\");\n return c.success({ endpoints });\n } catch (error) {\n c.get(\"logger\").error(\"获取 MCP 端点列表失败:\", error);\n return c.fail(\n \"MCP_ENDPOINTS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取 MCP 服务配置\n * GET /api/config/mcp-servers\n */\n async getMcpServers(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取 MCP 服务配置请求\");\n const servers = configManager.getMcpServers();\n c.get(\"logger\").debug(\"获取 MCP 服务配置成功\");\n return c.success({ servers });\n } catch (error) {\n c.get(\"logger\").error(\"获取 MCP 服务配置失败:\", error);\n return c.fail(\n \"MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 服务配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取连接配置\n * GET /api/config/connection\n */\n async getConnectionConfig(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取连接配置请求\");\n const connection = configManager.getConnectionConfig();\n c.get(\"logger\").debug(\"获取连接配置成功\");\n return c.success({ connection });\n } catch (error) {\n c.get(\"logger\").error(\"获取连接配置失败:\", error);\n return c.fail(\n \"CONNECTION_CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取连接配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 重新加载配置\n * POST /api/config/reload\n */\n async reloadConfig(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理重新加载配置请求\");\n configManager.reloadConfig();\n const config = configManager.getConfig();\n c.get(\"logger\").info(\"重新加载配置成功\");\n return c.success(config, \"配置重新加载成功\");\n } catch (error) {\n c.get(\"logger\").error(\"重新加载配置失败:\", error);\n return c.fail(\n \"CONFIG_RELOAD_ERROR\",\n error instanceof Error ? error.message : \"重新加载配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取配置文件路径\n * GET /api/config/path\n */\n async getConfigPath(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取配置文件路径请求\");\n const path = configManager.getConfigPath();\n c.get(\"logger\").debug(\"获取配置文件路径成功\");\n return c.success({ path });\n } catch (error) {\n c.get(\"logger\").error(\"获取配置文件路径失败:\", error);\n return c.fail(\n \"CONFIG_PATH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置文件路径失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 检查配置是否存在\n * GET /api/config/exists\n */\n async checkConfigExists(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理检查配置是否存在请求\");\n const exists = configManager.configExists();\n c.get(\"logger\").debug(`配置存在检查结果: ${exists}`);\n return c.success({ exists });\n } catch (error) {\n c.get(\"logger\").error(\"检查配置是否存在失败:\", error);\n return c.fail(\n \"CONFIG_EXISTS_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查配置是否存在失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取提示词文件列表\n * GET /api/config/prompts\n */\n async getPromptFiles(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取提示词文件列表请求\");\n const prompts = listPromptFiles();\n c.get(\"logger\").debug(\n `获取提示词文件列表成功,共 ${prompts.length} 个文件`\n );\n return c.success({ prompts });\n } catch (error) {\n c.get(\"logger\").error(\"获取提示词文件列表失败:\", error);\n return c.fail(\n \"PROMPT_FILES_READ_ERROR\",\n error instanceof Error ? error.message : \"获取提示词文件列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取提示词文件内容\n * GET /api/config/prompts/content?path=./prompts/default.md\n */\n async getPromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取提示词文件内容请求\");\n const path = c.req.query(\"path\");\n\n if (!path) {\n return c.fail(\"INVALID_REQUEST\", \"缺少 path 参数\", undefined, 400);\n }\n\n const fileContent = readPromptFile(path);\n c.get(\"logger\").debug(`获取提示词文件内容成功: ${path}`);\n return c.success(fileContent);\n } catch (error) {\n c.get(\"logger\").error(\"获取提示词文件内容失败:\", error);\n return c.fail(\n \"PROMPT_FILE_READ_ERROR\",\n error instanceof Error ? error.message : \"获取提示词文件内容失败\",\n undefined,\n 400\n );\n }\n }\n\n /**\n * 更新提示词文件内容\n * PUT /api/config/prompts/content\n */\n async updatePromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理更新提示词文件内容请求\");\n const body = await c.req.json();\n\n // 验证请求体格式\n if (!body || typeof body !== \"object\") {\n return c.fail(\"INVALID_REQUEST\", \"请求体格式错误\", undefined, 400);\n }\n\n const { path, content } = body;\n\n // 验证 path 参数\n if (!path || typeof path !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"path 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n // 验证 content 参数\n if (content === undefined || typeof content !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"content 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n const fileContent = updatePromptFile(path, content);\n c.get(\"logger\").info(`更新提示词文件成功: ${path}`);\n return c.success(fileContent, \"提示词文件更新成功\");\n } catch (error) {\n c.get(\"logger\").error(\"更新提示词文件内容失败:\", error);\n return c.fail(\n \"PROMPT_FILE_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"更新提示词文件内容失败\",\n undefined,\n 400\n );\n }\n }\n\n /**\n * 创建新的提示词文件\n * POST /api/config/prompts/content\n */\n async createPromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理创建提示词文件请求\");\n const body = await c.req.json();\n\n // 验证请求体格式\n if (!body || typeof body !== \"object\") {\n return c.fail(\"INVALID_REQUEST\", \"请求体格式错误\", undefined, 400);\n }\n\n const { fileName, content } = body;\n\n // 验证 fileName 参数\n if (!fileName || typeof fileName !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"fileName 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n // 验证 content 参数\n if (content === undefined || typeof content !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"content 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n const fileContent = createPromptFile(fileName, content);\n c.get(\"logger\").info(`创建提示词文件成功: ${fileName}`);\n return c.success(fileContent, \"提示词文件创建成功\");\n } catch (error) {\n c.get(\"logger\").error(\"创建提示词文件失败:\", error);\n return c.fail(\n \"PROMPT_FILE_CREATE_ERROR\",\n error instanceof Error ? error.message : \"创建提示词文件失败\",\n undefined,\n 400\n );\n }\n }\n\n /**\n * 删除提示词文件\n * DELETE /api/config/prompts/content?path=./prompts/old-prompt.md\n */\n async deletePromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理删除提示词文件请求\");\n const path = c.req.query(\"path\");\n\n if (!path) {\n return c.fail(\"INVALID_REQUEST\", \"缺少 path 参数\", undefined, 400);\n }\n\n deletePromptFile(path);\n c.get(\"logger\").info(`删除提示词文件成功: ${path}`);\n return c.success(undefined, \"提示词文件删除成功\");\n } catch (error) {\n c.get(\"logger\").error(\"删除提示词文件失败:\", error);\n return c.fail(\n \"PROMPT_FILE_DELETE_ERROR\",\n error instanceof Error ? error.message : \"删除提示词文件失败\",\n undefined,\n 400\n );\n }\n }\n}\n","/**\n * 抽象 API Handler 基类\n * 提供便捷的辅助方法\n * logger 通过 c.get(\"logger\") 访问(Hono 推荐做法)\n */\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\n\nexport abstract class BaseHandler {\n /**\n * 统一错误处理方法\n * 记录错误日志并返回格式化的错误响应\n * @param c - Hono context\n * @param error - 错误对象\n * @param operation - 操作描述(用于日志)\n * @param defaultCode - 默认错误码\n * @param defaultMessage - 默认错误消息\n * @param statusCode - HTTP 状态码(默认 500)\n * @returns JSON 错误响应\n */\n protected handleError(\n c: Context<AppContext>,\n error: unknown,\n operation: string,\n defaultCode = \"OPERATION_FAILED\",\n defaultMessage = \"操作失败\",\n statusCode = 500\n ): Response {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const errorCode =\n error instanceof Error && \"code\" in error\n ? String((error as { code: unknown }).code)\n : defaultCode;\n\n c.get(\"logger\").error(`${operation}失败:`, error);\n\n return c.fail(\n errorCode,\n errorMessage || defaultMessage,\n undefined,\n statusCode\n );\n }\n\n /**\n * 解析 JSON 请求体\n * @param c - Hono context\n * @param errorMessage - 自定义错误消息前缀(默认\"请求体格式错误\")\n * @returns 解析后的 JSON 对象\n * @throws 如果请求体不是有效的 JSON\n */\n protected async parseJsonBody<T>(\n c: Context<AppContext>,\n errorMessage = \"请求体格式错误\"\n ): Promise<T> {\n try {\n return await c.req.json();\n } catch (error) {\n // 保留原始错误信息\n const message =\n error instanceof Error\n ? `${errorMessage}: ${error.message}`\n : errorMessage;\n throw new Error(message);\n }\n }\n}\n","/**\n * 扣子(Coze)API 集成模块\n *\n * 提供与扣子平台集成的完整功能,包括:\n * - config: 扣子 API 环境配置(中英文环境)\n * - @coze/api: 扣子官方 SDK 的完整导出\n * - createCozeClient: 创建扣子 API 客户端的工厂函数\n * - CozeApiService: 扣子 API 服务的封装类\n *\n * @example\n * ```typescript\n * import { CozeApiService, createCozeClient, config } from '@/lib/coze';\n *\n * // 使用预配置的服务\n * const service = new CozeApiService('your-token');\n *\n * // 或者创建自定义客户端\n * const client = createCozeClient('your-token', 'zh');\n * ```\n */\nexport { default as config } from \"./config\";\nexport * from \"@coze/api\";\nexport { createCozeClient } from \"./client\";\nexport { CozeApiService } from \"./service\";\n","/**\n * 扣子 API 环境配置\n *\n * 提供扣子 API 的不同环境配置(中文环境和英文环境)\n *\n * @example\n * ```typescript\n * import config from \"@/lib/coze/config\";\n *\n * // 获取中文环境配置(默认)\n * const zhEnv = config.zh;\n * console.log(zhEnv.COZE_BASE_URL); // \"https://api.coze.cn\"\n *\n * // 获取英文环境配置\n * const enEnv = config.en;\n * console.log(enEnv.COZE_BASE_URL); // \"https://api.coze.com\"\n * ```\n *\n * @remarks\n * - 中文环境(zh):适用于中国大陆用户,使用 .cn 域名\n * - 英文环境(en):适用于国际用户,使用 .com 域名\n * - 该配置被 `@/lib/coze/client.ts` 中的 `createCozeClient` 函数使用\n */\nexport default {\n zh: {\n COZE_BASE_URL: \"https://api.coze.cn\",\n COZE_BASE_WS_URL: \"wss://ws.coze.cn\",\n },\n en: {\n COZE_BASE_URL: \"https://api.coze.com\",\n COZE_BASE_WS_URL: \"wss://ws.coze.com\",\n },\n};\n","/**\n * 扣子 API 客户端封装\n * 提供统一的客户端创建和配置\n */\n\nimport { CozeAPI } from \"@/lib/coze\";\nimport config from \"./config\";\n\nexport type Language = \"zh\" | \"en\";\n\n/**\n * 创建 Coze API 客户端\n * @param token - API 访问令牌\n * @param language - API 环境语言,默认为 \"zh\"(中文),可选 \"en\"(英文)\n */\nexport function createCozeClient(\n token: string,\n language: Language = \"zh\"\n): CozeAPI {\n if (!token || typeof token !== \"string\" || token.trim() === \"\") {\n throw new Error(\"扣子 API Token 不能为空\");\n }\n\n const env = config[language] || config.zh;\n\n return new CozeAPI({\n baseURL: env.COZE_BASE_URL,\n token: token.trim(),\n baseWsURL: env.COZE_BASE_WS_URL,\n debug: false,\n });\n}\n","/**\n * 扣子 API 服务类\n * 负责与扣子 API 的交互,包括工作空间和工作流的获取\n */\n\nimport type { RunWorkflowData, WorkSpace } from \"@/lib/coze\";\nimport type {\n CozeWorkflowsData,\n CozeWorkflowsParams,\n CozeWorkflowsResponse,\n} from \"@/types/coze\";\nimport NodeCache from \"node-cache\";\nimport { createCozeClient } from \"./client\";\n\n/**\n * 扣子 API 服务类\n */\nexport class CozeApiService {\n private cache: NodeCache;\n private token: string; // 保留 token 字段用于可能的后续扩展(如 token 刷新)\n private client: ReturnType<typeof createCozeClient>;\n\n constructor(token: string) {\n this.token = token.trim();\n this.client = createCozeClient(this.token);\n\n // 初始化缓存\n this.cache = new NodeCache({\n stdTTL: 5 * 60, // 默认5分钟(工作流缓存使用此默认值)\n });\n }\n\n /**\n * 获取工作空间列表\n */\n async getWorkspaces(): Promise<WorkSpace[]> {\n try {\n const cacheKey = \"workspaces\";\n const cached = this.cache.get<WorkSpace[]>(cacheKey);\n if (cached) return cached;\n\n const { workspaces = [] } = await this.client.workspaces.list();\n\n // 设置缓存,过期时间30分钟\n this.cache.set(cacheKey, workspaces, 30 * 60);\n\n return workspaces;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`获取工作空间列表失败: ${errorMessage}`);\n }\n }\n\n /**\n * 获取工作流列表\n */\n async getWorkflows(params: CozeWorkflowsParams): Promise<CozeWorkflowsData> {\n try {\n const { workspace_id, page_num = 1, page_size = 20 } = params;\n\n if (!workspace_id || typeof workspace_id !== \"string\") {\n throw new Error(\"工作空间ID不能为空\");\n }\n\n const cacheKey = `workflows:${workspace_id}:${page_num}:${page_size}`;\n const cached = this.cache.get<CozeWorkflowsData>(cacheKey);\n if (cached) return cached;\n\n const response = await this.client.get<\n CozeWorkflowsParams,\n CozeWorkflowsResponse\n >(\"/v1/workflows\", {\n workspace_id,\n page_num,\n page_size,\n workflow_mode: \"workflow\",\n });\n\n const result = response.data;\n\n // 设置缓存,使用默认的5分钟过期时间\n this.cache.set(cacheKey, result);\n\n return result;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`获取工作流列表失败: ${errorMessage}`);\n }\n }\n\n /**\n * 运行工作流\n * @param workflowId - 工作流ID\n * @param parameters - 参数\n * @returns 运行工作流数据\n */\n async callWorkflow(\n workflowId: string,\n parameters: Record<string, unknown>\n ): Promise<RunWorkflowData> {\n try {\n return await this.client.workflows.runs.create({\n workflow_id: workflowId,\n parameters,\n });\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`运行工作流失败: ${errorMessage}`);\n }\n }\n\n /**\n * 清除缓存\n * @param pattern 可选的模式字符串,清除所有以该模式开头的缓存键\n */\n clearCache(pattern?: string): void {\n if (!pattern) {\n // 清除所有缓存\n this.cache.flushAll();\n return;\n }\n\n // node-cache 不支持模式匹配,需要手动实现\n // 使用前缀匹配,避免意外匹配\n const keys = this.cache.keys();\n const keysToDelete = keys.filter((key) => key.startsWith(pattern));\n this.cache.del(keysToDelete);\n }\n\n /**\n * 获取缓存统计信息\n */\n getCacheStats(): {\n size: number;\n keys: string[];\n hits: number;\n misses: number;\n hitRate: number;\n ksize: number;\n vsize: number;\n } {\n const stats = this.cache.getStats();\n const keys = this.cache.keys();\n const totalRequests = stats.hits + stats.misses;\n const hitRate = totalRequests > 0 ? stats.hits / totalRequests : 0;\n\n return {\n size: stats.keys,\n keys,\n hits: stats.hits,\n misses: stats.misses,\n hitRate,\n ksize: stats.ksize,\n vsize: stats.vsize,\n };\n }\n}\n","/**\n * 扣子 API HTTP 路由处理器\n * 提供扣子工作空间和工作流相关的 RESTful API 接口\n */\n\nimport { CozeApiService } from \"@/lib/coze\";\nimport type { CozeWorkflowsParams } from \"@/types/coze\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 错误代码类型\n */\ntype CozeErrorCode =\n | \"AUTH_FAILED\"\n | \"RATE_LIMITED\"\n | \"TIMEOUT\"\n | \"API_ERROR\"\n | \"NETWORK_ERROR\";\n\n/**\n * 带 code 属性的错误接口\n */\ninterface ErrorWithCode {\n code: CozeErrorCode;\n message: string;\n statusCode?: number;\n response?: unknown;\n}\n\n/**\n * 类型守卫函数:检查错误是否带有 code 属性\n */\nfunction isErrorWithCode(error: unknown): error is ErrorWithCode {\n if (!(error instanceof Error && \"code\" in error)) {\n return false;\n }\n\n const code = (error as ErrorWithCode).code;\n const validCodes: CozeErrorCode[] = [\n \"AUTH_FAILED\",\n \"RATE_LIMITED\",\n \"TIMEOUT\",\n \"API_ERROR\",\n \"NETWORK_ERROR\",\n ];\n\n return typeof code === \"string\" && validCodes.includes(code as CozeErrorCode);\n}\n\n/**\n * 获取扣子 API 服务实例\n */\nfunction getCozeApiService(): CozeApiService {\n const token = configManager.getCozeToken();\n\n if (!token) {\n throw new Error(\n \"扣子 API Token 未配置,请在配置文件中设置 platforms.coze.token\"\n );\n }\n\n return new CozeApiService(token);\n}\n\n/**\n * 扣子 API 路由处理器类\n */\nexport class CozeHandler extends BaseHandler {\n constructor() {\n super();\n }\n\n /**\n * 处理 Coze API 错误并返回标准化的响应\n * @param c - Hono 上下文对象\n * @param error - 捕获的错误对象\n * @param operationName - 操作名称,用于日志和错误消息\n * @returns 标准化的错误响应\n */\n private handleCozeApiError(\n c: Context<AppContext>,\n error: unknown,\n operationName: string\n ): Response {\n c.get(\"logger\").error(`${operationName}失败:`, error);\n\n // 根据错误类型返回不同的响应\n if (isErrorWithCode(error) && error.code === \"AUTH_FAILED\") {\n return c.fail(\n \"AUTH_FAILED\",\n \"扣子 API 认证失败,请检查 Token 配置\",\n undefined,\n 401\n );\n }\n\n if (isErrorWithCode(error) && error.code === \"RATE_LIMITED\") {\n return c.fail(\"RATE_LIMITED\", \"请求过于频繁,请稍后重试\", undefined, 429);\n }\n\n if (isErrorWithCode(error) && error.code === \"TIMEOUT\") {\n return c.fail(\"TIMEOUT\", \"请求超时,请稍后重试\", undefined, 408);\n }\n\n const details =\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined;\n\n return c.fail(\n \"INTERNAL_ERROR\",\n error instanceof Error ? error.message : `${operationName}失败`,\n details,\n 500\n );\n }\n\n /**\n * 获取工作空间列表\n * GET /api/coze/workspaces\n */\n async getWorkspaces(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取工作空间列表请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n const cozeApiService = getCozeApiService();\n\n c.get(\"logger\").info(\"调用 Coze API 获取工作空间列表\");\n const workspaces = await cozeApiService.getWorkspaces();\n c.get(\"logger\").info(`成功获取 ${workspaces.length} 个工作空间`);\n\n return c.success({ workspaces });\n } catch (error) {\n return this.handleCozeApiError(c, error, \"获取工作空间列表\");\n }\n }\n\n /**\n * 获取工作流列表\n * GET /api/coze/workflows?workspace_id=xxx&page_num=1&page_size=20\n */\n async getWorkflows(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取工作流列表请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n // 解析查询参数\n const workspace_id = c.req.query(\"workspace_id\");\n const page_num = Number.parseInt(c.req.query(\"page_num\") || \"1\", 10);\n const page_size = Number.parseInt(c.req.query(\"page_size\") || \"20\", 10);\n\n // 验证必需参数\n if (!workspace_id) {\n c.get(\"logger\").warn(\"缺少 workspace_id 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少必需参数: workspace_id\",\n undefined,\n 400\n );\n }\n\n // 验证分页参数\n if (page_num < 1 || page_num > 1000) {\n return c.fail(\n \"INVALID_PARAMETER\",\n \"page_num 必须在 1-1000 之间\",\n undefined,\n 400\n );\n }\n\n if (page_size < 1 || page_size > 100) {\n return c.fail(\n \"INVALID_PARAMETER\",\n \"page_size 必须在 1-100 之间\",\n undefined,\n 400\n );\n }\n\n const params: CozeWorkflowsParams = {\n workspace_id,\n page_num,\n page_size,\n };\n\n const cozeApiService = getCozeApiService();\n\n c.get(\"logger\").info(\n `开始获取工作空间 ${workspace_id} 的工作流列表,页码: ${page_num},每页: ${page_size}`\n );\n const result = await cozeApiService.getWorkflows(params);\n c.get(\"logger\").info(\n `成功获取工作空间 ${workspace_id} 的 ${result.items.length} 个工作流`\n );\n\n // 获取已添加的自定义工具列表,检查工作流是否已被添加为工具\n const customMCPTools = configManager.getCustomMCPTools();\n\n // 为每个工作流添加工具状态信息\n const enhancedItems = result.items.map((item) => {\n // 查找对应的自定义工具\n const addedTool = customMCPTools.find(\n (tool) =>\n tool.handler.type === \"proxy\" &&\n tool.handler.platform === \"coze\" &&\n tool.handler.config.workflow_id === item.workflow_id\n );\n\n return {\n ...item,\n isAddedAsTool: !!addedTool,\n toolName: addedTool?.name || null,\n };\n });\n\n c.get(\"logger\").info(\n `工作流工具状态检查完成,共 ${enhancedItems.filter((item) => item.isAddedAsTool).length} 个工作流已添加为工具`\n );\n\n return c.success(\n {\n items: enhancedItems,\n has_more: result.has_more,\n page_num,\n page_size,\n total_count: result.items.length, // 当前页的数量\n },\n `成功获取 ${enhancedItems.length} 个工作流`\n );\n } catch (error) {\n return this.handleCozeApiError(c, error, \"获取工作流列表\");\n }\n }\n\n /**\n * 清除扣子 API 缓存\n * POST /api/coze/cache/clear\n */\n async clearCache(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理清除扣子 API 缓存请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n const pattern = c.req.query(\"pattern\"); // 可选的缓存模式参数\n\n const cozeApiService = getCozeApiService();\n\n const statsBefore = cozeApiService.getCacheStats();\n c.get(\"logger\").info(\n `开始清除缓存${pattern ? ` (模式: ${pattern})` : \"\"}`\n );\n\n cozeApiService.clearCache(pattern);\n\n const statsAfter = cozeApiService.getCacheStats();\n\n c.get(\"logger\").info(\n `缓存清除完成,清除前: ${statsBefore.size} 项,清除后: ${statsAfter.size} 项`\n );\n\n return c.success(\n {\n cleared: statsBefore.size - statsAfter.size,\n remaining: statsAfter.size,\n pattern: pattern || \"all\",\n },\n \"缓存清除成功\"\n );\n } catch (error) {\n c.get(\"logger\").error(\"清除缓存失败:\", error);\n\n const details =\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined;\n\n return c.fail(\n \"INTERNAL_ERROR\",\n error instanceof Error ? error.message : \"清除缓存失败\",\n details,\n 500\n );\n }\n }\n\n /**\n * 获取缓存统计信息\n * GET /api/coze/cache/stats\n */\n async getCacheStats(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取缓存统计信息请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n const cozeApiService = getCozeApiService();\n const stats = cozeApiService.getCacheStats();\n\n return c.success(stats);\n } catch (error) {\n c.get(\"logger\").error(\"获取缓存统计信息失败:\", error);\n\n const details =\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined;\n\n return c.fail(\n \"INTERNAL_ERROR\",\n error instanceof Error ? error.message : \"获取缓存统计信息失败\",\n details,\n 500\n );\n }\n }\n}\n","/**\n * API 相关常量定义\n */\n\n/**\n * 分页相关常量\n */\nexport const PAGINATION_CONSTANTS = {\n /** 默认每页记录数 */\n DEFAULT_LIMIT: 50,\n /** 最大每页记录数 */\n MAX_LIMIT: 200,\n} as const;\n","/**\n * HTTP 协议相关常量定义\n */\n\n/**\n * HTTP Content-Type 常量\n */\nexport const HTTP_CONTENT_TYPES = {\n /** JSON 格式 */\n APPLICATION_JSON: \"application/json\",\n /** HTML 格式 */\n TEXT_HTML: \"text/html\",\n /** 纯文本格式 */\n TEXT_PLAIN: \"text/plain\",\n /** CSS 样式表 */\n TEXT_CSS: \"text/css\",\n /** JavaScript 代码 */\n APPLICATION_JAVASCRIPT: \"application/javascript\",\n /** XML 格式 */\n APPLICATION_XML: \"application/xml\",\n /** PDF 文档 */\n APPLICATION_PDF: \"application/pdf\",\n /** ZIP 压缩包 */\n APPLICATION_ZIP: \"application/zip\",\n /** 八位字节流 */\n APPLICATION_OCTET_STREAM: \"application/octet-stream\",\n} as const;\n\n/**\n * HTTP 请求头常量\n */\nexport const HTTP_HEADERS = {\n /** Content-Type 头 */\n CONTENT_TYPE: \"Content-Type\",\n /** Content-Length 头 */\n CONTENT_LENGTH: \"content-length\",\n /** MCP 协议版本头 */\n MCP_PROTOCOL_VERSION: \"MCP-Protocol-Version\",\n /** 响应时间头 */\n X_RESPONSE_TIME: \"X-Response-Time\",\n} as const;\n\n/**\n * HTTP 状态码常量\n */\nexport const HTTP_STATUS_CODES = {\n /** 成功 */\n OK: 200,\n /** 已创建 */\n CREATED: 201,\n /** 无内容 */\n NO_CONTENT: 204,\n /** 错误的请求 */\n BAD_REQUEST: 400,\n /** 未授权 */\n UNAUTHORIZED: 401,\n /** 禁止访问 */\n FORBIDDEN: 403,\n /** 未找到 */\n NOT_FOUND: 404,\n /** 请求超时 */\n REQUEST_TIMEOUT: 408,\n /** 内部服务器错误 */\n INTERNAL_SERVER_ERROR: 500,\n /** 服务不可用 */\n SERVICE_UNAVAILABLE: 503,\n} as const;\n\n/**\n * HTTP 服务器配置常量\n */\nexport const HTTP_SERVER_CONFIG = {\n /** 默认绑定地址 */\n DEFAULT_BIND_ADDRESS: \"0.0.0.0\",\n /** 默认端口 */\n DEFAULT_PORT: 9999,\n} as const;\n\n/**\n * HTTP 错误消息常量\n */\nexport const HTTP_ERROR_MESSAGES = {\n /** 请求过大错误消息 */\n REQUEST_TOO_LARGE: \"Request too large\",\n /** 消息过大错误消息 */\n MESSAGE_TOO_LARGE: \"Message too large\",\n /** 无效请求错误消息 */\n INVALID_REQUEST: \"Invalid Request\",\n /** Content-Type 必须是 application/json */\n INVALID_CONTENT_TYPE: \"Content-Type must be application/json\",\n /** 解析错误 */\n PARSE_ERROR: \"Parse error\",\n /** 无效的 JSON */\n INVALID_JSON: \"Invalid JSON\",\n /** 内部错误 */\n INTERNAL_ERROR: \"Internal error\",\n} as const;\n","/**\n * MCP 协议相关常量定义\n */\n\n/**\n * JSON-RPC 版本常量\n */\nexport const JSONRPC_VERSION = \"2.0\" as const;\n\n/**\n * MCP 协议版本常量\n */\nexport const MCP_PROTOCOL_VERSIONS = {\n /** 2024-11-05 版本 */\n V2024_11_05: \"2024-11-05\",\n /** 2025-06-18 版本 */\n V2025_06_18: \"2025-06-18\",\n /** 默认版本 */\n DEFAULT: \"2024-11-05\",\n} as const;\n\n/**\n * MCP 支持的协议版本数组\n */\nexport const MCP_SUPPORTED_PROTOCOL_VERSIONS = [\n MCP_PROTOCOL_VERSIONS.V2024_11_05,\n MCP_PROTOCOL_VERSIONS.V2025_06_18,\n] as const;\n\n/**\n * MCP 服务器信息常量\n */\nexport const MCP_SERVER_INFO = {\n /** 服务器名称 */\n NAME: \"xiaozhi-mcp-server\",\n /** 服务器版本 */\n VERSION: \"1.0.0\",\n} as const;\n\n/**\n * MCP 方法名称常量\n */\nexport const MCP_METHODS = {\n /** 初始化 */\n INITIALIZE: \"initialize\",\n /** 已初始化通知 */\n INITIALIZED: \"notifications/initialized\",\n /** 工具列表 */\n TOOLS_LIST: \"tools/list\",\n /** 调用工具 */\n TOOLS_CALL: \"tools/call\",\n /** 资源列表 */\n RESOURCES_LIST: \"resources/list\",\n /** 提示列表 */\n PROMPTS_LIST: \"prompts/list\",\n /** Ping */\n PING: \"ping\",\n} as const;\n\n/**\n * JSON-RPC 错误码常量\n */\nexport const JSONRPC_ERROR_CODES = {\n /** 解析错误 */\n PARSE_ERROR: -32700,\n /** 无效请求 */\n INVALID_REQUEST: -32600,\n /** 方法未找到 */\n METHOD_NOT_FOUND: -32601,\n /** 无效参数 */\n INVALID_PARAMS: -32602,\n /** 内部错误 */\n INTERNAL_ERROR: -32603,\n} as const;\n\n/**\n * JSON-RPC 错误消息常量\n */\nexport const JSONRPC_ERROR_MESSAGES = {\n /** 解析错误消息 */\n PARSE_ERROR: \"Parse error: Invalid JSON\",\n /** 无效请求消息 */\n INVALID_REQUEST: \"Invalid Request: Message does not conform to JSON-RPC 2.0\",\n /** 方法未找到消息 */\n METHOD_NOT_FOUND: \"Method not found\",\n /** 无效参数消息 */\n INVALID_PARAMS: \"Invalid params\",\n /** 内部错误消息 */\n INTERNAL_ERROR: \"Internal error\",\n /** 未找到工具消息 */\n TOOL_NOT_FOUND: \"未找到工具\",\n /** 未知方法消息 */\n UNKNOWN_METHOD: \"未知的方法\",\n} as const;\n\n/**\n * MCP 缓存版本常量\n */\nexport const MCP_CACHE_VERSIONS = {\n /** 缓存文件格式版本 */\n CACHE_VERSION: \"1.0.0\",\n /** 缓存条目版本 */\n CACHE_ENTRY_VERSION: \"1.0.0\",\n} as const;\n\n/**\n * MCP 服务状态类型常量\n */\nexport const MCP_SERVICE_STATUS = {\n /** 已连接 */\n CONNECTED: \"connected\",\n /** 断开连接 */\n DISCONNECTED: \"disconnected\",\n /** 连接中 */\n CONNECTING: \"connecting\",\n /** 错误 */\n ERROR: \"error\",\n} as const;\n","/**\n * 事件名称常量定义\n */\n\n/**\n * MCP 服务相关事件\n */\nexport const MCP_SERVICE_EVENTS = {\n /** 服务已连接 */\n CONNECTED: \"mcp:service:connected\",\n /** 服务已断开连接 */\n DISCONNECTED: \"mcp:service:disconnected\",\n /** 服务连接失败 */\n CONNECTION_FAILED: \"mcp:service:connection:failed\",\n} as const;\n\n/**\n * MCP 服务器相关事件\n */\nexport const MCP_SERVER_EVENTS = {\n /** 服务器已添加 */\n ADDED: \"mcp:server:added\",\n /** 批量添加服务器 */\n BATCH_ADDED: \"mcp:server:batch_added\",\n /** 服务器已移除 */\n REMOVED: \"mcp:server:removed\",\n /** 服务器已启动 */\n STARTED: \"mcp:server:started\",\n /** 服务器已停止 */\n STOPPED: \"mcp:server:stopped\",\n} as const;\n\n/**\n * 接入点相关事件\n */\nexport const ENDPOINT_EVENTS = {\n /** 接入点状态变更 */\n STATUS_CHANGED: \"endpoint:status:changed\",\n /** 接入点已添加 */\n ADDED: \"endpoint:added\",\n /** 接入点已移除 */\n REMOVED: \"endpoint:removed\",\n /** 接入点重连完成 */\n RECONNECT_COMPLETED: \"endpoint:reconnect:completed\",\n /** 接入点重连失败 */\n RECONNECT_FAILED: \"endpoint:reconnect:failed\",\n} as const;\n\n/**\n * 配置相关事件\n */\nexport const CONFIG_EVENTS = {\n /** 配置已更新 */\n UPDATED: \"config:updated\",\n /** 配置错误 */\n ERROR: \"config:error\",\n} as const;\n\n/**\n * 状态相关事件\n */\nexport const STATUS_EVENTS = {\n /** 状态已更新 */\n UPDATED: \"status:updated\",\n /** 心跳超时 */\n HEARTBEAT_TIMEOUT: \"status:heartbeat:timeout\",\n} as const;\n\n/**\n * WebSocket 相关事件\n */\nexport const WEBSOCKET_EVENTS = {\n /** 客户端已连接 */\n CLIENT_CONNECTED: \"websocket:client:connected\",\n /** 客户端已断开 */\n CLIENT_DISCONNECTED: \"websocket:client:disconnected\",\n /** 消息解析错误 */\n MESSAGE_PARSE_ERROR: \"websocket:message:parse_error\",\n} as const;\n\n/**\n * 所有事件名称的联合类型(用于类型检查)\n */\nexport type AllEventNames =\n | (typeof MCP_SERVICE_EVENTS)[keyof typeof MCP_SERVICE_EVENTS]\n | (typeof MCP_SERVER_EVENTS)[keyof typeof MCP_SERVER_EVENTS]\n | (typeof ENDPOINT_EVENTS)[keyof typeof ENDPOINT_EVENTS]\n | (typeof CONFIG_EVENTS)[keyof typeof CONFIG_EVENTS]\n | (typeof STATUS_EVENTS)[keyof typeof STATUS_EVENTS]\n | (typeof WEBSOCKET_EVENTS)[keyof typeof WEBSOCKET_EVENTS];\n","/**\n * 超时和延迟常量定义\n * 所有时间单位均为毫秒(ms)\n */\n\n/**\n * MCP 相关超时常量\n */\nexport const MCP_TIMEOUTS = {\n /** 默认超时时间 */\n DEFAULT: 8000,\n /** 心跳间隔 */\n HEARTBEAT_INTERVAL: 30000,\n /** 心跳超时 */\n HEARTBEAT_TIMEOUT: 35000,\n /** 服务连接超时 */\n CONNECTION_TIMEOUT: 30000,\n} as const;\n\n/**\n * 缓存相关超时常量\n */\nexport const CACHE_TIMEOUTS = {\n /** 缓存 TTL(生存时间) */\n TTL: 300000,\n /** 清理间隔 */\n CLEANUP_INTERVAL: 60000,\n} as const;\n\n/**\n * HTTP 相关超时常量\n */\nexport const HTTP_TIMEOUTS = {\n /** 默认超时 */\n DEFAULT: 30000,\n /** 长运行任务超时 */\n LONG_RUNNING: 60000,\n} as const;\n\n/**\n * 重试相关延迟常量\n */\nexport const RETRY_DELAYS = {\n /** 初始延迟 */\n INITIAL: 1000,\n /** 最大延迟 */\n MAX: 30000,\n /** 重连延迟 */\n RECONNECT: 2000,\n} as const;\n\n/**\n * 心跳监控相关常量\n */\nexport const HEARTBEAT_MONITORING = {\n /** 监控间隔 */\n MONITOR_INTERVAL: 10000,\n /** 超时阈值 */\n TIMEOUT_THRESHOLD: 35000,\n} as const;\n\n/**\n * 重试相关配置常量\n */\nexport const RETRY_CONFIG = {\n /** 最大重试次数 */\n MAX_ATTEMPTS: 5,\n /** 退避乘数 */\n BACKOFF_MULTIPLIER: 2,\n} as const;\n\n/**\n * 服务重启相关延迟常量\n */\nexport const SERVICE_RESTART_DELAYS = {\n /** 重启执行延迟 */\n EXECUTION_DELAY: 500,\n /** 成功状态通知延迟 */\n SUCCESS_NOTIFICATION_DELAY: 5000,\n} as const;\n","/**\n * 缓存相关常量定义\n */\n\n/**\n * 缓存配置常量\n */\nexport const CACHE_CONFIG = {\n /** 最大缓存大小 */\n MAX_SIZE: 1000,\n /** 是否启用一次性缓存 */\n ENABLE_ONE_TIME_CACHE: true,\n} as const;\n\n/**\n * 消息大小限制常量\n */\nexport const MESSAGE_SIZE_LIMITS = {\n /** 默认消息大小限制(1MB) */\n DEFAULT: 1024 * 1024,\n /** 最大消息大小限制(10MB) */\n MAX: 10 * 1024 * 1024,\n} as const;\n\n/**\n * 分页限制常量\n */\nexport const PAGINATION_LIMITS = {\n /** 默认每页记录数 */\n DEFAULT_LIMIT: 50,\n /** 最大每页记录数 */\n MAX_LIMIT: 200,\n} as const;\n\n/**\n * 缓存文件相关常量\n */\nexport const CACHE_FILE_CONFIG = {\n /** 缓存文件名 */\n FILENAME: \"xiaozhi.cache.json\",\n /** 临时文件后缀 */\n TEMP_SUFFIX: \".tmp\",\n} as const;\n\n/**\n * 工具名称分隔符常量\n */\nexport const TOOL_NAME_SEPARATORS = {\n /** 服务名与工具名之间的分隔符 */\n SERVICE_TOOL_SEPARATOR: \"__\",\n} as const;\n\n/**\n * 缓存统计相关常量\n */\nexport const CACHE_STATS = {\n /** 默认缓存命中率 */\n DEFAULT_HIT_RATE: 0,\n /** 最小命中率(百分比) */\n MIN_HIT_RATE: 0,\n /** 最大命中率(百分比) */\n MAX_HIT_RATE: 100,\n} as const;\n","/**\n * TTS 音色数据常量\n * 来源于火山引擎豆包语音合成模型 2.0\n */\n\nimport type { VoiceInfo } from \"@xiaozhi-client/shared-types\";\n\n/**\n * TTS 音色列表\n * 仅包含 2.0 版本的音色(推荐,支持情感变化)\n */\nexport const TTS_VOICES: VoiceInfo[] = [\n // === 通用场景 ===\n {\n name: \"Vivi 2.0\",\n voiceType: \"zh_female_vv_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文、日文、印尼、墨西哥西班牙语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"小何 2.0\",\n voiceType: \"zh_female_xiaohe_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"云舟 2.0\",\n voiceType: \"zh_male_m191_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"小天 2.0\",\n voiceType: \"zh_male_taocheng_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"刘飞 2.0\",\n voiceType: \"zh_male_liufei_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"魅力苏菲 2.0\",\n voiceType: \"zh_male_sophie_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"清新女声 2.0\",\n voiceType: \"zh_female_qingxinnvsheng_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"甜美小源 2.0\",\n voiceType: \"zh_female_tianmeixiaoyuan_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"甜美桃子 2.0\",\n voiceType: \"zh_female_tianmeitaozi_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"爽快思思 2.0\",\n voiceType: \"zh_female_shuangkuaisisi_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"邻家女孩 2.0\",\n voiceType: \"zh_female_linjianvhai_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"少年梓辛/Brayan 2.0\",\n voiceType: \"zh_male_shaonianzixin_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"魅力女友 2.0\",\n voiceType: \"zh_female_meilinvyou_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 角色扮演 ===\n {\n name: \"知性灿灿 2.0\",\n voiceType: \"zh_female_cancan_uranus_bigtts\",\n scene: \"角色扮演\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"撒娇学妹 2.0\",\n voiceType: \"zh_female_sajiaoxuemei_uranus_bigtts\",\n scene: \"角色扮演\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 视频配音 ===\n {\n name: \"佩奇猪 2.0\",\n voiceType: \"zh_female_peiqi_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"猴哥 2.0\",\n voiceType: \"zh_male_sunwukong_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"大壹 2.0\",\n voiceType: \"zh_male_dayi_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"黑猫侦探社咪仔 2.0\",\n voiceType: \"zh_female_mizai_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"鸡汤女 2.0\",\n voiceType: \"zh_female_jitangnv_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"流畅女声 2.0\",\n voiceType: \"zh_female_liuchangnv_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"儒雅逸辰 2.0\",\n voiceType: \"zh_male_ruyayichen_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 教育场景 ===\n {\n name: \"Tina老师 2.0\",\n voiceType: \"zh_female_yingyujiaoxue_uranus_bigtts\",\n scene: \"教育场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 客服场景 ===\n {\n name: \"暖阳女声 2.0\",\n voiceType: \"zh_female_kefunvsheng_uranus_bigtts\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"轻盈朵朵 2.0\",\n voiceType: \"saturn_zh_female_qingyingduoduo_cs_tob\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"指令遵循\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"温婉珊珊 2.0\",\n voiceType: \"saturn_zh_female_wenwanshanshan_cs_tob\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"指令遵循\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"热情艾娜 2.0\",\n voiceType: \"saturn_zh_female_reqingaina_cs_tob\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"指令遵循\"],\n modelVersion: \"2.0\",\n },\n\n // === 有声阅读 ===\n {\n name: \"儿童绘本 2.0\",\n voiceType: \"zh_female_xiaoxue_uranus_bigtts\",\n scene: \"有声阅读\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 多语种 ===\n {\n name: \"Tim\",\n voiceType: \"en_male_tim_uranus_bigtts\",\n scene: \"多语种\",\n language: \"美式英语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"Dacey\",\n voiceType: \"en_female_dacey_uranus_bigtts\",\n scene: \"多语种\",\n language: \"美式英语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"Stokie\",\n voiceType: \"en_female_stokie_uranus_bigtts\",\n scene: \"多语种\",\n language: \"美式英语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n];\n\n/**\n * 获取所有场景列表\n */\nexport function getVoiceScenes(): string[] {\n const scenes = new Set<string>();\n for (const voice of TTS_VOICES) {\n scenes.add(voice.scene);\n }\n return Array.from(scenes);\n}\n\n/**\n * 按场景分组获取音色\n */\nexport function getVoicesByScene(): Map<string, VoiceInfo[]> {\n const result = new Map<string, VoiceInfo[]>();\n for (const voice of TTS_VOICES) {\n const voices = result.get(voice.scene) || [];\n voices.push(voice);\n result.set(voice.scene, voices);\n }\n return result;\n}\n","/**\n * WebSocket 辅助工具模块\n *\n * 提供 WebSocket 相关的工具函数和类型定义:\n * - WebSocketLike: WebSocket 接口定义\n * - sendWebSocketError: 向 WebSocket 客户端发送错误消息\n *\n * @module websocket-helper\n */\n\nimport type { Logger } from \"@/Logger.js\";\n\n/**\n * WebSocket 接口\n * 描述具有 send 方法的 WebSocket 对象\n */\nexport interface WebSocketLike {\n send(data: string): void;\n}\n\n/**\n * 向 WebSocket 客户端发送错误消息\n *\n * @param ws - WebSocket 客户端连接对象\n * @param code - 错误代码\n * @param message - 错误消息\n * @param logger - 日志记录器\n */\nexport function sendWebSocketError(\n ws: WebSocketLike,\n code: string,\n message: string,\n logger: Logger\n): void {\n try {\n const errorResponse = {\n type: \"error\",\n error: {\n code,\n message,\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n } catch (error) {\n logger.error(\"发送错误消息失败:\", error);\n }\n}\n","/**\n * 心跳处理器\n *\n * 负责处理客户端心跳消息,维护客户端连接状态,\n * 并监控 MCP 端点的连接状态。\n */\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { HEARTBEAT_MONITORING } from \"@/constants/index.js\";\nimport type { NotificationService } from \"@/services/notification.service.js\";\nimport type { StatusService } from \"@/services/status.service.js\";\nimport { sendWebSocketError } from \"@/utils/websocket-helper.js\";\nimport { configManager } from \"@xiaozhi-client/config\";\n\n/**\n * 心跳消息接口\n */\ninterface HeartbeatMessage {\n type: \"clientStatus\";\n data: {\n status?: \"connected\" | \"disconnected\";\n mcpEndpoint?: string;\n activeMCPServers?: string[];\n timestamp?: number;\n };\n}\n\n/**\n * 心跳处理器\n */\nexport class HeartbeatHandler {\n private logger: Logger;\n private statusService: StatusService;\n private notificationService: NotificationService;\n\n constructor(\n statusService: StatusService,\n notificationService: NotificationService\n ) {\n this.logger = logger;\n this.statusService = statusService;\n this.notificationService = notificationService;\n }\n\n /**\n * 处理客户端状态更新(心跳)\n */\n async handleClientStatus(\n ws: any,\n message: HeartbeatMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理客户端状态更新: ${clientId}`, message.data);\n\n // 更新客户端信息\n const statusUpdate = {\n ...message.data,\n lastHeartbeat: Date.now(),\n };\n\n this.statusService.updateClientInfo(\n statusUpdate,\n `websocket-${clientId}`\n );\n\n // 发送最新配置给客户端(心跳响应)\n await this.sendLatestConfig(ws, clientId);\n\n this.logger.debug(`客户端状态更新成功: ${clientId}`);\n } catch (error) {\n this.logger.error(`处理客户端状态更新失败: ${clientId}`, error);\n sendWebSocketError(\n ws,\n \"CLIENT_STATUS_ERROR\",\n error instanceof Error ? error.message : \"客户端状态更新失败\",\n this.logger\n );\n }\n }\n\n /**\n * 发送最新配置给客户端\n */\n private async sendLatestConfig(ws: any, clientId: string): Promise<void> {\n try {\n const latestConfig = configManager.getConfig();\n const message = {\n type: \"configUpdate\",\n data: latestConfig,\n timestamp: Date.now(),\n };\n\n ws.send(JSON.stringify(message));\n this.logger.debug(`最新配置已发送给客户端: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送最新配置失败: ${clientId}`, error);\n // 不抛出错误,避免影响心跳处理\n }\n }\n\n /**\n * 检查客户端心跳超时\n */\n checkHeartbeatTimeout(): void {\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n const now = Date.now();\n\n if (\n lastHeartbeat &&\n now - lastHeartbeat > HEARTBEAT_MONITORING.TIMEOUT_THRESHOLD\n ) {\n this.logger.debug(\"客户端心跳超时,标记为断开连接\");\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n \"heartbeat-timeout\"\n );\n }\n }\n\n /**\n * 启动心跳监控\n */\n startHeartbeatMonitoring(): NodeJS.Timeout {\n this.logger.debug(\"启动心跳监控\");\n\n return setInterval(() => {\n this.checkHeartbeatTimeout();\n this.cleanupDisconnectedClients();\n }, HEARTBEAT_MONITORING.MONITOR_INTERVAL);\n }\n\n /**\n * 清理断开连接的客户端\n */\n private cleanupDisconnectedClients(): void {\n try {\n this.notificationService.cleanupDisconnectedClients();\n } catch (error) {\n this.logger.error(\"清理断开连接的客户端失败:\", error);\n }\n }\n\n /**\n * 停止心跳监控\n */\n stopHeartbeatMonitoring(intervalId: NodeJS.Timeout): void {\n this.logger.debug(\"停止心跳监控\");\n clearInterval(intervalId);\n }\n\n /**\n * 获取心跳统计信息\n */\n getHeartbeatStats(): {\n lastHeartbeat?: number;\n isConnected: boolean;\n clientStats: {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n };\n } {\n return {\n lastHeartbeat: this.statusService.getLastHeartbeat(),\n isConnected: this.statusService.isClientConnected(),\n clientStats: this.notificationService.getClientStats(),\n };\n }\n\n /**\n * 处理客户端连接建立\n */\n handleClientConnect(clientId: string): void {\n this.logger.debug(`客户端连接建立: ${clientId}`);\n\n // 更新状态为连接\n this.statusService.updateClientInfo(\n {\n status: \"connected\",\n lastHeartbeat: Date.now(),\n },\n `websocket-connect-${clientId}`\n );\n }\n\n /**\n * 处理客户端连接断开\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.debug(`客户端连接断开: ${clientId}`);\n\n // 更新状态为断开连接\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n `websocket-disconnect-${clientId}`\n );\n }\n\n /**\n * 发送心跳响应\n */\n sendHeartbeatResponse(ws: any, clientId: string): void {\n try {\n const response = {\n type: \"heartbeatResponse\",\n data: {\n timestamp: Date.now(),\n status: \"ok\",\n },\n };\n\n ws.send(JSON.stringify(response));\n this.logger.debug(`心跳响应已发送: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送心跳响应失败: ${clientId}`, error);\n }\n }\n\n /**\n * 验证心跳消息格式\n */\n validateHeartbeatMessage(message: any): message is HeartbeatMessage {\n return (\n message &&\n typeof message === \"object\" &&\n message.type === \"clientStatus\" &&\n message.data &&\n typeof message.data === \"object\"\n );\n }\n}\n","/**\n * 事件总线服务\n * 提供统一的事件发布订阅机制,用于解耦各个模块之间的通信\n * 支持配置更新、状态变更、接入点状态、服务重启、MCP 服务、工具调用等多种事件类型\n *\n * 主要功能:\n * - 事件的发布和订阅\n * - 事件类型的类型安全检查\n * - 统一的事件命名规范\n *\n * @module apps/backend/services/event-bus.service\n */\n\nimport { EventEmitter } from \"node:events\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { ClientInfo } from \"@/services/status.service.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * 事件类型定义\n */\nexport interface EventBusEvents {\n // 配置相关事件\n \"config:updated\": {\n type: string;\n serviceName?: string;\n platformName?: string;\n timestamp: Date;\n };\n \"config:error\": { error: Error; operation: string };\n\n // 状态相关事件\n \"status:updated\": { status: ClientInfo; source: string };\n \"status:error\": { error: Error; operation: string };\n\n // 接入点状态变更事件\n \"endpoint:status:changed\": {\n endpoint: string;\n connected: boolean;\n operation: \"connect\" | \"disconnect\" | \"reconnect\" | \"add\" | \"remove\";\n success: boolean;\n message?: string;\n timestamp: number;\n source: string;\n };\n\n // 接入点重连事件\n \"endpoint:reconnect:completed\": {\n trigger: \"mcp_server_added\" | \"mcp_server_batch_added\" | \"manual\" | \"other\";\n serverName?: string;\n endpointCount: number;\n timestamp: number;\n };\n \"endpoint:reconnect:failed\": {\n trigger: \"mcp_server_added\" | \"mcp_server_batch_added\" | \"manual\" | \"other\";\n serverName?: string;\n error: string;\n timestamp: number;\n };\n\n // 服务相关事件\n \"service:restart:requested\": {\n serviceName: string;\n reason?: string;\n delay: number;\n attempt: number;\n timestamp: number;\n source?: string;\n };\n \"service:restart:started\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:completed\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:execute\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:health:changed\": {\n serviceName: string;\n oldStatus: string;\n newStatus: string;\n timestamp: number;\n };\n\n // WebSocket 相关事件\n \"websocket:client:connected\": { clientId: string; timestamp: number };\n \"websocket:client:disconnected\": { clientId: string; timestamp: number };\n \"websocket:message:received\": { type: string; data: any; clientId: string };\n\n // 通知相关事件\n \"notification:broadcast\": { type: string; data: any; target?: string };\n \"notification:error\": { error: Error; type: string };\n\n // MCP服务相关事件\n \"mcp:service:connected\": {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n };\n \"mcp:service:disconnected\": {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n };\n \"mcp:service:connection:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n };\n \"mcp:server:added\": {\n serverName: string;\n config: any;\n tools: string[];\n timestamp: Date;\n };\n \"mcp:server:removed\": {\n serverName: string;\n affectedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:status_changed\": {\n serverName: string;\n oldStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n newStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n timestamp: Date;\n reason?: string;\n };\n \"mcp:server:connection:attempt\": {\n serverName: string;\n attempt: number;\n maxAttempts: number;\n timestamp: Date;\n };\n \"mcp:server:tools:updated\": {\n serverName: string;\n tools: string[];\n addedTools: string[];\n removedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:batch_added\": {\n totalServers: number;\n addedCount: number;\n failedCount: number;\n successfullyAddedServers: string[];\n results: any[];\n timestamp: Date;\n };\n \"mcp:server:rollback\": {\n serverName: string;\n timestamp: Date;\n };\n\n // 连接相关事件\n \"connection:reconnect:completed\": {\n success: boolean;\n reason: string;\n timestamp: Date;\n };\n\n // NPM 安装相关事件\n \"npm:install:started\": {\n version: string;\n installId: string;\n timestamp: number;\n };\n \"npm:install:log\": {\n version: string;\n installId: string;\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n };\n \"npm:install:completed\": {\n version: string;\n installId: string;\n success: boolean;\n duration: number;\n timestamp: number;\n };\n \"npm:install:failed\": {\n version: string;\n installId: string;\n error: string;\n duration: number;\n timestamp: number;\n };\n\n // 测试相关事件(仅用于测试)\n \"high-frequency\": {\n id: number;\n timestamp: number;\n };\n \"bulk-test\": {\n id: number;\n timestamp: number;\n };\n \"error-test\": {\n error: string;\n timestamp: number;\n };\n \"large-data-test\": {\n data: any;\n timestamp: number;\n };\n \"destroy-test\": {\n message: string;\n timestamp: number;\n };\n \"chain-event-1\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-2\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-3\": {\n value: number;\n timestamp: number;\n };\n \"performance-test\": {\n data: any;\n timestamp: number;\n };\n \"test:performance\": {\n id: number;\n timestamp: number;\n };\n \"chain:start\": {\n value: number;\n timestamp: number;\n };\n \"chain:middle\": {\n value: number;\n timestamp: number;\n };\n \"chain:end\": {\n value: number;\n timestamp: number;\n };\n \"test:error\": {\n error: boolean;\n timestamp: number;\n };\n \"test:remove\": {\n id: number;\n timestamp: number;\n };\n}\n\n/**\n * 事件总线 - 用于模块间的解耦通信\n */\nexport class EventBus extends EventEmitter {\n private logger: Logger;\n private eventStats: Map<string, { count: number; lastEmitted: Date }> =\n new Map();\n private maxListeners: number;\n\n constructor() {\n super();\n this.logger = logger;\n // 测试环境下增加监听器限制,避免 MaxListenersExceededWarning\n const isTest =\n process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\";\n this.maxListeners = isTest ? 200 : 50;\n this.setMaxListeners(this.maxListeners);\n this.setupErrorHandling();\n }\n\n /**\n * 设置错误处理\n */\n private setupErrorHandling(): void {\n this.on(\"error\", (error) => {\n this.logger.error(\"EventBus 内部错误:\", error);\n });\n\n // 监听器数量警告\n this.on(\"newListener\", (eventName) => {\n const listenerCount = this.listenerCount(eventName);\n if (listenerCount > this.maxListeners * 0.8) {\n this.logger.warn(\n `事件 ${eventName} 的监听器数量过多: ${listenerCount}`\n );\n }\n });\n }\n\n /**\n * 发射事件(类型安全)\n */\n emitEvent<K extends keyof EventBusEvents>(\n eventName: K,\n data: EventBusEvents[K]\n ): boolean {\n try {\n this.updateEventStats(eventName as string);\n this.logger.debug(`发射事件: ${eventName}`, data);\n\n // 使用原始emit方法,保持EventEmitter的所有特性\n return super.emit(eventName, data);\n } catch (error) {\n this.logger.error(`发射事件失败: ${eventName}`, error);\n // 将监听器错误发射到error事件\n if (error instanceof Error) {\n this.emit(\"error\", error);\n }\n return false;\n }\n }\n\n /**\n * 监听事件(类型安全)\n */\n onEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加事件监听器: ${eventName}`);\n return this.on(eventName, listener);\n }\n\n /**\n * 一次性监听事件(类型安全)\n */\n onceEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加一次性事件监听器: ${eventName}`);\n\n // 创建包装器来实现一次性监听\n const onceListener = (data: EventBusEvents[K]) => {\n try {\n listener(data);\n } catch (error) {\n // 监听器抛出错误,发射到错误事件\n this.emit(\"error\", error);\n throw error;\n } finally {\n // 在任何情况下都移除监听器\n this.offEvent(eventName, onceListener);\n }\n };\n\n return this.on(eventName, onceListener);\n }\n\n /**\n * 移除事件监听器(类型安全)\n */\n offEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`移除事件监听器: ${eventName}`);\n return this.off(eventName, listener);\n }\n\n /**\n * 更新事件统计\n */\n private updateEventStats(eventName: string): void {\n const stats = this.eventStats.get(eventName) || {\n count: 0,\n lastEmitted: new Date(),\n };\n stats.count++;\n stats.lastEmitted = new Date();\n this.eventStats.set(eventName, stats);\n }\n\n /**\n * 获取事件统计信息\n */\n getEventStats(): Record<string, { count: number; lastEmitted: Date }> {\n const stats: Record<string, { count: number; lastEmitted: Date }> = {};\n for (const [eventName, stat] of this.eventStats) {\n stats[eventName] = { ...stat };\n }\n return stats;\n }\n\n /**\n * 获取监听器统计信息\n */\n getListenerStats(): Record<string, number> {\n const stats: Record<string, number> = {};\n for (const eventName of this.eventNames()) {\n stats[eventName as string] = this.listenerCount(eventName);\n }\n return stats;\n }\n\n /**\n * 清理事件统计\n */\n clearEventStats(): void {\n this.eventStats.clear();\n this.logger.info(\"事件统计已清理\");\n }\n\n /**\n * 获取事件总线状态\n */\n getStatus(): {\n totalEvents: number;\n totalListeners: number;\n eventStats: Record<string, { count: number; lastEmitted: Date }>;\n listenerStats: Record<string, number>;\n } {\n return {\n totalEvents: this.eventStats.size,\n totalListeners: Object.values(this.getListenerStats()).reduce(\n (sum, count) => sum + count,\n 0\n ),\n eventStats: this.getEventStats(),\n listenerStats: this.getListenerStats(),\n };\n }\n\n /**\n * 销毁事件总线\n */\n destroy(): void {\n this.removeAllListeners();\n this.eventStats.clear();\n this.logger.info(\"EventBus 已销毁\");\n }\n}\n\n// 单例实例\nlet eventBusInstance: EventBus | null = null;\n\n/**\n * 获取事件总线单例\n */\nexport function getEventBus(): EventBus {\n if (!eventBusInstance) {\n eventBusInstance = new EventBus();\n }\n return eventBusInstance;\n}\n\n/**\n * 销毁事件总线单例\n */\nexport function destroyEventBus(): void {\n if (eventBusInstance) {\n eventBusInstance.destroy();\n eventBusInstance = null;\n }\n}\n","/**\n * 接入点管理 Handler\n *\n * 负责处理接入点相关的 HTTP 请求,包括:\n * - 接入点连接状态查询\n * - 接入点连接和断开\n * - 接入点状态管理\n * - 接入点重连\n * - 接入点验证\n *\n * @see @xiaozhi-client/endpoint - EndpointManager 实现\n */\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { ConfigManager } from \"@xiaozhi-client/config\";\nimport type {\n ConnectionStatus,\n EndpointManager,\n} from \"@xiaozhi-client/endpoint\";\nimport type { Context } from \"hono\";\n\n/**\n * 验证结果类型定义\n */\ninterface ValidationResult {\n isValid: boolean;\n errors: string[];\n}\n\n/**\n * 端点 API 处理器\n * 支持通过 HTTP API 动态管理端点(添加、删除、连接、断开、查询状态)\n * 端点变更会自动同步到配置文件,确保重启后状态保持一致\n */\nexport class EndpointHandler {\n private logger: Logger;\n private endpointManager: EndpointManager;\n private configManager: ConfigManager;\n private eventBus: EventBus;\n\n constructor(endpointManager: EndpointManager, configManager: ConfigManager) {\n this.logger = logger;\n this.endpointManager = endpointManager;\n this.configManager = configManager;\n this.eventBus = getEventBus();\n }\n\n /**\n * 从请求体中解析端点参数\n * @param c Hono 上下文\n * @param errorErrorCode 错误码,用于区分不同操作的错误\n * @returns 解析结果,成功时包含 endpoint,失败时包含可直接返回的 Response\n */\n private async parseEndpointFromBody(\n c: Context<AppContext>,\n errorErrorCode: string\n ): Promise<\n { ok: true; endpoint: string } | { ok: false; response: Response }\n > {\n let body: { endpoint: string };\n try {\n body = await c.req.json();\n } catch (error) {\n this.logger.error(\"JSON解析失败:\", error);\n return {\n ok: false,\n response: c.fail(\n errorErrorCode,\n \"JSON解析失败\",\n error instanceof Error ? error.message : undefined,\n 500\n ),\n };\n }\n\n const endpoint = body.endpoint;\n\n // 验证端点参数\n if (!endpoint || typeof endpoint !== \"string\") {\n return {\n ok: false,\n response: c.fail(\"INVALID_ENDPOINT\", \"端点参数无效\", undefined, 500),\n };\n }\n\n return { ok: true, endpoint };\n }\n\n /**\n * 验证端点 URL 格式\n * @param endpoint 端点 URL\n * @returns 验证结果\n */\n private validateEndpoint(endpoint: string): ValidationResult {\n const errors: string[] = [];\n\n if (!endpoint || typeof endpoint !== \"string\") {\n errors.push(\"端点必须是非空字符串\");\n return { isValid: false, errors };\n }\n\n try {\n new URL(endpoint);\n } catch {\n errors.push(\"端点 URL 格式无效\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 获取接入点状态\n * POST /api/endpoint/status\n */\n async getEndpointStatus(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_STATUS_READ_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.debug(`处理获取接入点状态请求: ${endpoint}`);\n try {\n // 获取连接状态\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const endpointStatus = connectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n if (!endpointStatus) {\n return c.fail(\"ENDPOINT_NOT_FOUND\", \"端点不存在\", undefined, 500);\n }\n\n this.logger.debug(`获取接入点状态成功: ${endpoint}`);\n return c.success(endpointStatus);\n } catch (error) {\n this.logger.error(\"获取接入点状态失败:\", error);\n return c.fail(\n \"ENDPOINT_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取接入点状态失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 连接指定接入点\n * POST /api/endpoint/connect\n */\n async connectEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_CONNECT_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点连接请求: ${endpoint}`);\n try {\n // 获取端点实例\n const endpointInstance = this.endpointManager.getEndpoint(endpoint);\n\n if (!endpointInstance) {\n return c.fail(\n \"ENDPOINT_NOT_FOUND\",\n \"端点不存在,请先添加接入点\",\n undefined,\n 500\n );\n }\n\n // 执行连接操作\n await this.endpointManager.connect(endpoint);\n\n // 获取连接后的状态\n const updatedConnectionStatus =\n this.endpointManager.getConnectionStatus();\n const endpointStatus = updatedConnectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n if (!endpointStatus) {\n return c.fail(\n \"ENDPOINT_STATUS_NOT_FOUND\",\n \"无法获取端点连接状态\",\n undefined,\n 500\n );\n }\n\n // 发送连接成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: true,\n operation: \"connect\",\n success: true,\n message: \"接入点连接成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点连接成功: ${endpoint}`);\n return c.success(endpointStatus);\n } catch (error) {\n this.logger.error(\"接入点连接失败:\", error);\n return c.fail(\n \"ENDPOINT_CONNECT_ERROR\",\n error instanceof Error ? error.message : \"接入点连接失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 断开指定接入点\n * POST /api/endpoint/disconnect\n */\n async disconnectEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_DISCONNECT_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点断开请求: ${endpoint}`);\n try {\n // 获取端点实例\n const endpointInstance = this.endpointManager.getEndpoint(endpoint);\n\n if (!endpointInstance) {\n return c.fail(\"ENDPOINT_NOT_FOUND\", \"端点不存在\", undefined, 500);\n }\n\n // 执行断开操作\n await this.endpointManager.disconnect(endpoint);\n\n // 获取断开后的状态\n const updatedConnectionStatus =\n this.endpointManager.getConnectionStatus();\n const endpointStatus = updatedConnectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n // 发送断开成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: false,\n operation: \"disconnect\",\n success: true,\n message: \"接入点断开成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点断开成功: ${endpoint}`);\n const fallbackStatus: ConnectionStatus = {\n endpoint,\n connected: false,\n initialized: true,\n };\n return c.success(endpointStatus || fallbackStatus);\n } catch (error) {\n this.logger.error(\"接入点断开失败:\", error);\n return c.fail(\n \"ENDPOINT_DISCONNECT_ERROR\",\n error instanceof Error ? error.message : \"接入点断开失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 添加新接入点\n * POST /api/endpoint/add\n * 流程:验证 URL → 检查存在性 → 创建实例 → 添加到管理器 → 连接 → 更新配置\n */\n async addEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_ADD_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点添加请求: ${endpoint}`);\n\n try {\n // 1. 验证端点 URL 格式\n const validation = this.validateEndpoint(endpoint);\n if (!validation.isValid) {\n return c.fail(\n \"INVALID_ENDPOINT_FORMAT\",\n validation.errors.join(\", \"),\n undefined,\n 500\n );\n }\n\n // 2. 检查端点是否已存在\n const existingEndpoint = this.endpointManager.getEndpoint(endpoint);\n if (existingEndpoint) {\n return c.fail(\"ENDPOINT_ALREADY_EXISTS\", \"端点已存在\", undefined, 500);\n }\n\n // 3. 添加端点到管理器(使用 URL 字符串)\n this.endpointManager.addEndpoint(endpoint);\n this.logger.debug(`端点已添加到管理器: ${endpoint}`);\n\n // 4. 获取新添加的端点实例\n const newEndpoint = this.endpointManager.getEndpoint(endpoint);\n if (!newEndpoint) {\n return c.fail(\n \"ENDPOINT_NOT_FOUND_AFTER_ADD\",\n \"端点添加后未找到\",\n undefined,\n 500\n );\n }\n\n // 5. 连接新端点\n try {\n await this.endpointManager.connect(endpoint);\n this.logger.debug(`端点已连接: ${endpoint}`);\n } catch (connectError) {\n this.logger.warn(\n `端点连接失败,但已添加到管理器: ${endpoint}`,\n connectError\n );\n // 连接失败不中断流程,端点已添加但未连接\n }\n\n // 6. 更新配置文件\n try {\n this.configManager.addMcpEndpoint(endpoint);\n this.logger.debug(`端点已添加到配置文件: ${endpoint}`);\n } catch (configError) {\n this.logger.error(`添加端点到配置文件失败: ${endpoint}`, configError);\n // 配置更新失败,需要回滚:优先尝试断开连接,其次从管理器移除端点\n try {\n await newEndpoint.disconnect();\n this.logger.debug(`回滚时已断开端点连接: ${endpoint}`);\n } catch (disconnectError) {\n // 断开失败只记录警告,不影响后续回滚流程\n this.logger.warn(\n `回滚时断开端点连接失败,将继续从管理器移除端点: ${endpoint}`,\n disconnectError\n );\n }\n // 从管理器移除端点\n await this.endpointManager.removeEndpoint(newEndpoint);\n throw configError;\n }\n\n // 8. 获取连接后的状态\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const endpointStatus = connectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n // 9. 发送事件通知\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: endpointStatus?.connected ?? false,\n operation: \"add\",\n success: true,\n message: \"接入点添加成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点添加成功: ${endpoint}`);\n\n const defaultEndpointStatus = {\n endpoint,\n connected: false,\n initialized: true,\n };\n return c.success(\n endpointStatus || defaultEndpointStatus,\n \"接入点添加成功\"\n );\n } catch (error) {\n this.logger.error(\"添加接入点失败:\", error);\n return c.fail(\n \"ENDPOINT_ADD_ERROR\",\n error instanceof Error ? error.message : \"添加接入点失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 移除接入点\n * POST /api/endpoint/remove\n * 流程:断开连接 → 从管理器移除 → 更新配置文件\n */\n async removeEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_REMOVE_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点移除请求: ${endpoint}`);\n\n try {\n // 检查端点是否存在\n const endpointInstance = this.endpointManager.getEndpoint(endpoint);\n if (!endpointInstance) {\n return c.fail(\"ENDPOINT_NOT_FOUND\", \"端点不存在\", undefined, 500);\n }\n\n // 记录断开前的连接状态\n const wasConnected = endpointInstance.isConnected();\n\n // 先从配置文件移除端点,确保配置与运行时状态保持一致\n try {\n this.configManager.removeMcpEndpoint(endpoint);\n this.logger.debug(`端点已从配置文件中移除: ${endpoint}`);\n } catch (error) {\n this.logger.error(`从配置文件移除端点失败: ${endpoint}`, error);\n // 配置更新失败是致命错误,中断移除操作\n throw error;\n }\n\n // 再从管理器移除端点\n // EndpointManager.removeEndpoint 内部会再次调用 disconnect(幂等操作)\n // 并清理状态和发射 endpointRemoved 事件\n await this.endpointManager.removeEndpoint(endpointInstance);\n this.logger.debug(`端点已从管理器中移除: ${endpoint}`);\n\n // 发送事件通知\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: false,\n operation: \"remove\",\n success: true,\n message: \"接入点移除成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点移除成功: ${endpoint}`);\n\n return c.success(\n {\n endpoint,\n operation: \"removed\",\n wasConnected,\n },\n \"接入点移除成功\"\n );\n } catch (error) {\n this.logger.error(\"移除接入点失败:\", error);\n\n return c.fail(\n \"ENDPOINT_REMOVE_ERROR\",\n error instanceof Error ? error.message : \"移除接入点失败\",\n undefined,\n 500\n );\n }\n }\n}\n","/**\n * MCP 服务管理器\n * 使用 MCPService 实例管理多个 MCP 服务\n * 专注于实例管理、工具聚合和路由调用\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { logger } from \"@/Logger.js\";\nimport { MCPService } from \"@/lib/mcp\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport { ConnectionState } from \"@/lib/mcp/types\";\nimport type {\n CustomMCPTool,\n EnhancedToolInfo,\n InternalMCPServiceConfig,\n MCPServiceConfig,\n ManagerStatus,\n ToolCallResult,\n ToolInfo,\n ToolStatusFilter,\n UnifiedServerConfig,\n UnifiedServerStatus,\n} from \"@/lib/mcp/types\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { MCPMessage } from \"@/types/mcp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { isModelScopeURL } from \"@xiaozhi-client/config\";\nimport type { MCPToolConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport { CustomMCPHandler } from \"./custom.js\";\nimport { ToolCallLogger } from \"./log.js\";\nimport { MCPMessageHandler } from \"./message.js\";\nexport class MCPServiceManager extends EventEmitter {\n private services: Map<string, MCPService> = new Map();\n private configs: Record<string, MCPServiceConfig> = {};\n private tools: Map<string, ToolInfo> = new Map(); // 缓存工具信息,保持向后兼容\n private customMCPHandler: CustomMCPHandler; // CustomMCP 工具处理器\n private cacheManager: MCPCacheManager; // 缓存管理器\n private eventBus = getEventBus(); // 事件总线\n private toolCallLogger: ToolCallLogger; // 工具调用记录器\n private retryTimers: Map<string, NodeJS.Timeout> = new Map(); // 重试定时器\n private failedServices: Set<string> = new Set(); // 失败的服务集合\n\n private messageHandler: MCPMessageHandler;\n\n // 事件监听器引用(用于清理)\n private eventListeners: {\n serviceConnected: (data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }) => void;\n serviceDisconnected: (data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }) => void;\n serviceConnectionFailed: (data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }) => void;\n };\n\n // 新增:服务器状态管理(从 UnifiedMCPServer 移入)\n private isRunning = false;\n private config: UnifiedServerConfig;\n\n /**\n * 创建 MCPServiceManager 实例\n * @param configs 可选的初始服务配置或服务器配置\n */\n constructor(\n configs?: Record<string, MCPServiceConfig> | UnifiedServerConfig\n ) {\n super();\n\n // 处理参数,支持 UnifiedServerConfig 格式\n if (configs && this.isUnifiedServerConfig(configs)) {\n // UnifiedServerConfig 格式\n this.config = {\n name: \"MCPServiceManager\",\n enableLogging: true,\n logLevel: \"info\",\n ...configs,\n };\n this.configs = configs.configs || {};\n } else {\n // 原有的 configs 格式\n this.config = {\n name: \"MCPServiceManager\",\n enableLogging: true,\n logLevel: \"info\",\n };\n this.configs = configs || {};\n }\n\n // 在测试环境中使用临时目录,避免在项目根目录创建缓存文件\n const isTestEnv =\n process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\";\n const cachePath = isTestEnv\n ? `/tmp/xiaozhi-test-${Date.now()}-${Math.random()\n .toString(36)\n .substring(2, 11)}/xiaozhi.cache.json`\n : undefined;\n\n this.cacheManager = new MCPCacheManager(cachePath);\n this.customMCPHandler = new CustomMCPHandler(this.cacheManager, this);\n\n // 初始化工具调用记录器\n const toolCallLogConfig = configManager.getToolCallLogConfig();\n const configDir = configManager.getConfigDir();\n this.toolCallLogger = new ToolCallLogger(toolCallLogConfig, configDir);\n\n // 初始化事件监听器引用\n this.eventListeners = {\n serviceConnected: async (data) => {\n await this.handleServiceConnected(data);\n },\n serviceDisconnected: async (data) => {\n await this.handleServiceDisconnected(data);\n },\n serviceConnectionFailed: async (data) => {\n await this.handleServiceConnectionFailed(data);\n },\n };\n\n // 设置事件监听器\n this.setupEventListeners();\n\n // 初始化消息处理器(确保在其他组件初始化完成后)\n this.messageHandler = new MCPMessageHandler(this);\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听MCP服务连接成功事件\n this.eventBus.onEvent(\n \"mcp:service:connected\",\n this.eventListeners.serviceConnected\n );\n\n // 监听MCP服务断开连接事件\n this.eventBus.onEvent(\n \"mcp:service:disconnected\",\n this.eventListeners.serviceDisconnected\n );\n\n // 监听MCP服务连接失败事件\n this.eventBus.onEvent(\n \"mcp:service:connection:failed\",\n this.eventListeners.serviceConnectionFailed\n );\n }\n\n /**\n * 处理MCP服务连接成功事件\n */\n private async handleServiceConnected(data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }): Promise<void> {\n logger.debug(`服务 ${data.serviceName} 连接成功,开始刷新工具缓存`);\n\n try {\n // 获取最新的工具列表\n const service = this.services.get(data.serviceName);\n if (service) {\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n logger.info(`服务 ${data.serviceName} 工具缓存刷新完成`);\n }\n } catch (error) {\n logger.error(`刷新服务 ${data.serviceName} 工具缓存失败`, { error });\n }\n }\n\n /**\n * 处理MCP服务断开连接事件\n */\n private async handleServiceDisconnected(data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }): Promise<void> {\n logger.info(\n `服务 ${data.serviceName} 断开连接,原因: ${data.reason || \"未知\"}`\n );\n\n try {\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n logger.info(`服务 ${data.serviceName} 断开连接处理完成`);\n } catch (error) {\n logger.error(`服务 ${data.serviceName} 断开连接处理失败`, { error });\n }\n }\n\n /**\n * 处理MCP服务连接失败事件\n */\n private async handleServiceConnectionFailed(data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }): Promise<void> {\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n logger.error(\"刷新CustomMCPHandler失败\", { error });\n }\n }\n\n /**\n * 启动所有 MCP 服务\n */\n async startAllServices(): Promise<void> {\n logger.debug(\"[MCPManager] 正在启动所有 MCP 服务...\");\n\n // 初始化 CustomMCP 处理器\n try {\n this.customMCPHandler.initialize();\n logger.debug(\"[MCPManager] CustomMCP 处理器初始化完成\");\n } catch (error) {\n logger.error(\"[MCPManager] CustomMCP 处理器初始化失败\", { error });\n // CustomMCP 初始化失败不应该阻止标准 MCP 服务启动\n }\n\n const configEntries = Object.entries(this.configs);\n if (configEntries.length === 0) {\n logger.warn(\n \"[MCPManager] 没有配置任何 MCP 服务,请使用 addServiceConfig() 添加服务配置\"\n );\n // 即使没有标准 MCP 服务,也可能有 CustomMCP 工具\n return;\n }\n\n // 记录启动开始\n logger.info(\n `[MCPManager] 开始并行启动 ${configEntries.length} 个 MCP 服务`\n );\n\n // 并行启动所有服务,实现服务隔离\n const startPromises = configEntries.map(async ([serviceName]) => {\n try {\n await this.startService(serviceName);\n return { serviceName, success: true, error: null };\n } catch (error) {\n return {\n serviceName,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n });\n\n // 等待所有服务启动完成\n const results = await Promise.allSettled(startPromises);\n\n // 统计启动结果\n let successCount = 0;\n let failureCount = 0;\n const failedServices: string[] = [];\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n if (result.value.success) {\n successCount++;\n } else {\n failureCount++;\n failedServices.push(result.value.serviceName);\n }\n } else {\n failureCount++;\n }\n }\n\n // 记录启动完成统计\n logger.info(\n `[MCPManager] 服务启动完成 - 成功: ${successCount}, 失败: ${failureCount}`\n );\n\n // 记录失败的服务列表\n if (failedServices.length > 0) {\n logger.warn(\n `[MCPManager] 以下服务启动失败: ${failedServices.join(\", \")}`\n );\n\n // 如果所有服务都失败了,发出警告但系统继续运行以便重试\n if (failureCount === configEntries.length) {\n logger.warn(\n \"[MCPManager] 所有 MCP 服务启动失败,但系统将继续运行以便重试\"\n );\n }\n }\n\n // 启动失败服务重试机制\n if (failedServices.length > 0) {\n this.scheduleFailedServicesRetry(failedServices);\n }\n }\n\n /**\n * 启动单个 MCP 服务\n */\n async startService(serviceName: string): Promise<void> {\n const config = this.configs[serviceName];\n if (!config) {\n throw new Error(`未找到服务配置: ${serviceName}`);\n }\n\n try {\n // 如果服务已存在,先停止它\n if (this.services.has(serviceName)) {\n await this.stopService(serviceName);\n }\n\n // 创建 MCPService 实例(使用 InternalMCPServiceConfig)\n const serviceConfig: InternalMCPServiceConfig = {\n name: serviceName,\n ...config,\n };\n const service = new MCPService(serviceConfig);\n\n // 连接到服务\n await service.connect();\n\n // 存储服务实例\n this.services.set(serviceName, service);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 注意:工具缓存刷新现在通过事件监听器自动处理,不需要在这里手动调用\n // MCPService.connect() 成功后会发射 mcp:service:connected 事件\n // 事件监听器会自动触发工具缓存刷新和CustomMCPHandler刷新\n\n const tools = service.getTools();\n logger.debug(\n `[MCPManager] ${serviceName} 服务启动成功,加载了 ${tools.length} 个工具:`,\n tools.map((t) => t.name).join(\", \")\n );\n } catch (error) {\n logger.error(`[MCPManager] 启动 ${serviceName} 服务失败`, {\n error: (error as Error).message,\n });\n // 清理可能的部分状态\n this.services.delete(serviceName);\n throw error;\n }\n }\n\n /**\n * 停止单个服务\n */\n async stopService(serviceName: string): Promise<void> {\n logger.info(`[MCPManager] 停止 MCP 服务: ${serviceName}`);\n\n const service = this.services.get(serviceName);\n if (!service) {\n logger.warn(`[MCPManager] 服务 ${serviceName} 不存在或未启动`);\n return;\n }\n\n try {\n await service.disconnect();\n this.services.delete(serviceName);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n logger.error(`[MCPManager] 停止 ${serviceName} 服务失败`, {\n error: (error as Error).message,\n });\n throw error;\n }\n }\n\n /**\n * 刷新工具缓存\n */\n private async refreshToolsCache(): Promise<void> {\n this.tools.clear();\n\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n const config = this.configs[serviceName];\n\n // 异步写入缓存(不阻塞主流程)\n if (config) {\n this.cacheManager\n .writeCacheEntry(serviceName, tools, config)\n .then(() => {\n logger.debug(`[MCPManager] 已将 ${serviceName} 工具列表写入缓存`);\n })\n .catch((error) => {\n logger.warn(\n `[MCPManager] 写入缓存失败: ${serviceName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n });\n }\n\n // 原有逻辑保持不变\n for (const tool of tools) {\n const toolKey = `${serviceName}__${tool.name}`;\n this.tools.set(toolKey, {\n serviceName,\n originalName: tool.name,\n tool,\n });\n }\n }\n }\n\n // 同步工具配置到配置文件\n await this.syncToolsConfigToFile();\n }\n\n /**\n * 获取所有可用工具\n * @param status 工具状态过滤:'enabled' 仅返回已启用工具,'disabled' 仅返回未启用工具,'all' 返回所有工具\n * @returns 工具数组,包含工具的启用状态信息\n */\n getAllTools(status: ToolStatusFilter = \"all\"): EnhancedToolInfo[] {\n const allTools: EnhancedToolInfo[] = [];\n\n // 1. 收集所有已连接服务的工具(包含启用状态过滤)\n for (const [serviceName, service] of this.services) {\n try {\n if (service.isConnected()) {\n const serviceTools = service.getTools();\n for (const tool of serviceTools) {\n try {\n // 检查工具启用状态 - 这个调用可能会抛出异常\n const isEnabled = configManager.isToolEnabled(\n serviceName,\n tool.name\n );\n const toolConfig =\n configManager.getMcpServerConfig()[serviceName].tools[\n tool.name\n ];\n\n // 根据 status 参数过滤工具\n if (status === \"enabled\" && !isEnabled) {\n continue; // 跳过未启用的工具\n }\n if (status === \"disabled\" && isEnabled) {\n continue; // 跳过已启用的工具\n }\n\n const toolKey = `${serviceName}__${tool.name}`;\n allTools.push({\n name: toolKey,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName,\n originalName: tool.name,\n enabled: isEnabled,\n usageCount: toolConfig.usageCount ?? 0,\n lastUsedTime: toolConfig.lastUsedTime ?? \"\",\n });\n } catch (toolError) {\n logger.warn(\n `[MCPManager] 检查工具 ${serviceName}.${tool.name} 启用状态失败,跳过该工具`,\n { error: toolError }\n );\n }\n }\n }\n } catch (serviceError) {\n logger.warn(\n `[MCPManager] 获取服务 ${serviceName} 的工具失败,跳过该服务`,\n { error: serviceError }\n );\n }\n }\n\n // 2. 添加CustomMCP工具(默认视为已启用)\n let customTools: Tool[] = [];\n try {\n customTools = this.customMCPHandler.getTools();\n logger.debug(\n `[MCPManager] 成功获取 ${customTools.length} 个 customMCP 工具`\n );\n } catch (error) {\n logger.warn(\n \"[MCPManager] 获取 CustomMCP 工具失败,将只返回标准 MCP 工具\",\n { error }\n );\n // 根据技术方案要求,CustomMCP 工具获取失败时不应该影响标准 MCP 工具的返回\n customTools = [];\n }\n\n // CustomMCP 工具默认视为已启用\n if (status !== \"disabled\") {\n for (const tool of customTools) {\n try {\n allTools.push({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName: this.getServiceNameForTool(tool),\n originalName: tool.name,\n enabled: true, // CustomMCP 工具默认启用\n usageCount: 0,\n lastUsedTime: \"\",\n });\n } catch (toolError) {\n logger.warn(\n `[MCPManager] 处理 CustomMCP 工具 ${tool.name} 失败,跳过该工具`,\n { error: toolError }\n );\n }\n }\n }\n\n logger.debug(\n `[MCPManager] 成功获取 ${allTools.length} 个可用工具(status=${status})`\n );\n return allTools;\n }\n\n /**\n * 根据工具配置确定服务名称\n * @param tool 工具对象\n * @returns 服务名称\n */\n private getServiceNameForTool(tool: CustomMCPTool): string {\n if (tool.handler?.type === \"mcp\") {\n // 如果是从 MCP 同步的工具,返回原始服务名称\n const config = tool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.serviceName || \"customMCP\";\n }\n return \"customMCP\";\n }\n\n /**\n * 根据工具信息获取日志记录用的服务名称\n * @param customTool CustomMCP 工具信息\n * @returns 用于日志记录的服务名称\n */\n private getLogServerName(customTool: CustomMCPTool): string {\n if (!customTool?.handler) {\n return \"custom\";\n }\n\n switch (customTool.handler.type) {\n case \"mcp\": {\n const config = customTool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.serviceName || \"customMCP\";\n }\n case \"coze\":\n return \"coze\";\n case \"dify\":\n return \"dify\";\n case \"n8n\":\n return \"n8n\";\n default:\n return \"custom\";\n }\n }\n\n /**\n * 根据工具信息获取原始工具名称\n * @param toolName 格式化后的工具名称\n * @param customTool CustomMCP 工具信息\n * @param toolInfo 标准工具信息\n * @returns 原始工具名称\n */\n private getOriginalToolName(\n toolName: string,\n customTool: CustomMCPTool | undefined,\n toolInfo?: ToolInfo\n ): string {\n if (customTool) {\n // CustomMCP 工具\n if (customTool.handler?.type === \"mcp\") {\n const config = customTool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.toolName || toolName;\n }\n return toolName;\n }\n\n // 标准 MCP 工具\n return toolInfo?.originalName || toolName;\n }\n\n /**\n * 调用 MCP 工具(支持标准 MCP 工具和 customMCP 工具)\n */\n async callTool(\n toolName: string,\n arguments_: Record<string, unknown>,\n options?: { timeout?: number }\n ): Promise<ToolCallResult> {\n const startTime = Date.now();\n\n // 初始化日志信息\n let logServerName = \"unknown\";\n let originalToolName: string = toolName;\n\n try {\n let result: ToolCallResult;\n\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n\n // 设置日志信息(添加空值检查)\n if (customTool) {\n logServerName = this.getLogServerName(customTool);\n originalToolName = this.getOriginalToolName(toolName, customTool);\n }\n\n if (customTool?.handler?.type === \"mcp\") {\n // 对于 mcp 类型的工具,直接路由到对应的 MCP 服务\n result = await this.callMCPTool(\n toolName,\n customTool.handler.config,\n arguments_\n );\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n true\n );\n } else {\n // 其他类型的 customMCP 工具正常处理,传递options参数\n result = await this.customMCPHandler.callTool(\n toolName,\n arguments_,\n options\n );\n logger.info(`[MCPManager] CustomMCP 工具 ${toolName} 调用成功`);\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, true);\n }\n } else {\n // 如果不是 customMCP 工具,则查找标准 MCP 工具\n const toolInfo = this.tools.get(toolName);\n if (!toolInfo) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 设置日志信息\n logServerName = toolInfo.serviceName;\n originalToolName = toolInfo.originalName;\n\n const service = this.services.get(toolInfo.serviceName);\n if (!service) {\n throw new Error(`服务 ${toolInfo.serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${toolInfo.serviceName} 未连接`);\n }\n\n result = (await service.callTool(\n toolInfo.originalName,\n arguments_ || {}\n )) as ToolCallResult;\n\n logger.debug(\"[MCPManager] 工具调用成功\", {\n toolName: toolName,\n result: result,\n });\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n true\n );\n }\n\n // 记录成功的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: result,\n success: result.isError !== true,\n duration: Date.now() - startTime,\n });\n\n return result as ToolCallResult;\n } catch (error) {\n // 记录失败的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: null,\n success: false,\n duration: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 更新失败统计\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n if (customTool?.handler?.type === \"mcp\") {\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n false\n );\n } else {\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, false);\n logger.error(`[MCPManager] CustomMCP 工具 ${toolName} 调用失败`, {\n error: (error as Error).message,\n });\n }\n } else {\n const toolInfo = this.tools.get(toolName);\n if (toolInfo) {\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n false\n );\n logger.error(`[MCPManager] 工具 ${toolName} 调用失败`, {\n error: (error as Error).message,\n });\n }\n }\n\n throw error;\n }\n }\n\n /**\n * 更新工具调用统计信息的通用方法\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStats(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n const currentTime = new Date().toISOString();\n\n if (isSuccess) {\n // 成功调用:更新使用统计\n await this.updateCustomMCPToolStats(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolStats(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n logger.debug(`[MCPManager] 已更新工具 ${toolName} 的统计信息`);\n } else {\n // 失败调用:只更新最后使用时间\n await this.updateCustomMCPToolLastUsedTime(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolLastUsedTime(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n logger.debug(\"[MCPManager] 已更新工具的失败调用统计信息\", {\n toolName,\n });\n }\n } catch (error) {\n logger.error(\"[MCPManager] 更新工具统计信息失败\", { toolName, error });\n throw error;\n }\n }\n\n /**\n * 统一的统计更新处理方法(带错误处理)\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStatsSafe(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n await this.updateToolStats(\n toolName,\n serviceName,\n originalToolName,\n isSuccess\n );\n } catch (error) {\n const action = isSuccess ? \"统计信息\" : \"失败统计信息\";\n logger.warn(\"[MCPManager] 更新工具统计信息失败\", {\n toolName,\n action,\n error,\n });\n // 统计更新失败不应该影响主流程,所以这里只记录警告\n }\n }\n\n /**\n * 更新 customMCP 工具统计信息\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, true);\n logger.debug(`[MCPManager] 已更新 customMCP 工具 ${toolName} 使用统计`);\n } catch (error) {\n logger.error(`[MCPManager] 更新 customMCP 工具 ${toolName} 统计失败`, {\n error,\n });\n throw error;\n }\n }\n\n /**\n * 更新 customMCP 工具最后使用时间\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolLastUsedTime(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, false); // 只更新时间,不增加计数\n logger.debug(\n `[MCPManager] 已更新 customMCP 工具 ${toolName} 最后使用时间`\n );\n } catch (error) {\n logger.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 最后使用时间失败`,\n { error }\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n true\n );\n logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 统计`\n );\n } catch (error) {\n logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 统计失败`,\n { error }\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具最后使用时间\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolLastUsedTime(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n false\n ); // 只更新时间,不增加计数\n logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间`\n );\n } catch (error) {\n logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间失败`,\n { error }\n );\n throw error;\n }\n }\n\n /**\n * 调用 MCP 工具(用于从 mcpServerConfig 同步的工具)\n * @param toolName 工具名称\n * @param config MCP handler 配置\n * @param arguments_ 工具参数\n */\n private async callMCPTool(\n toolName: string,\n config: { serviceName: string; toolName: string },\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult> {\n const { serviceName, toolName: originalToolName } = config;\n\n logger.debug(\n `[MCPManager] 调用 MCP 同步工具 ${toolName} -> ${serviceName}.${originalToolName}`\n );\n\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`服务 ${serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${serviceName} 未连接`);\n }\n\n try {\n const result = await service.callTool(originalToolName, arguments_ || {});\n logger.debug(`[MCPManager] MCP 同步工具 ${toolName} 调用成功`);\n return result as ToolCallResult;\n } catch (error) {\n logger.error(`[MCPManager] MCP 同步工具 ${toolName} 调用失败`, {\n error: (error as Error).message,\n });\n throw error;\n }\n }\n\n /**\n * 检查是否存在指定工具(包括标准 MCP 工具和 customMCP 工具)\n */\n hasTool(toolName: string): boolean {\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n return true;\n }\n\n // 检查是否是标准 MCP 工具\n return this.tools.has(toolName);\n }\n\n /**\n * 停止所有服务\n */\n async stopAllServices(): Promise<void> {\n logger.info(\"[MCPManager] 正在停止所有 MCP 服务...\");\n\n // 停止所有服务重试\n this.stopAllServiceRetries();\n\n // 停止所有服务实例\n for (const [serviceName, service] of this.services) {\n try {\n await service.disconnect();\n logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n logger.error(`[MCPManager] 停止 ${serviceName} 服务失败`, {\n error: (error as Error).message,\n });\n }\n }\n\n // 清理 CustomMCP 处理器\n try {\n this.customMCPHandler.cleanup();\n logger.info(\"[MCPManager] CustomMCP 处理器已清理\");\n } catch (error) {\n logger.error(\"[MCPManager] CustomMCP 处理器清理失败\", { error });\n }\n\n // 清理统计更新锁\n try {\n configManager.clearAllStatsUpdateLocks();\n logger.info(\"[MCPManager] 统计更新锁已清理\");\n } catch (error) {\n logger.error(\"[MCPManager] 清理统计更新锁失败\", { error });\n }\n\n this.services.clear();\n this.tools.clear();\n\n logger.info(\"[MCPManager] 所有 MCP 服务已停止\");\n }\n\n /**\n * 获取服务器状态(兼容 UnifiedServerStatus 格式)\n */\n getStatus(): UnifiedServerStatus {\n return this.getUnifiedStatus();\n }\n\n /**\n * 获取统计更新监控信息\n */\n getStatsUpdateInfo(): {\n activeLocks: string[];\n totalLocks: number;\n } {\n try {\n const activeLocks = configManager.getStatsUpdateLocks();\n return {\n activeLocks,\n totalLocks: activeLocks.length,\n };\n } catch (error) {\n logger.warn(\"[MCPManager] 获取统计更新监控信息失败\", { error });\n return {\n activeLocks: [],\n totalLocks: 0,\n };\n }\n }\n\n /**\n * 获取指定服务实例\n */\n getService(name: string): MCPService | undefined {\n return this.services.get(name);\n }\n\n /**\n * 获取所有已连接的服务名称\n */\n getConnectedServices(): string[] {\n const connectedServices: string[] = [];\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connectedServices.push(serviceName);\n }\n }\n return connectedServices;\n }\n\n /**\n * 刷新CustomMCPHandler的私有方法\n */\n private async refreshCustomMCPHandler(): Promise<void> {\n try {\n logger.debug(\"重新初始化CustomMCPHandler\");\n this.customMCPHandler.initialize();\n logger.debug(\"CustomMCPHandler重新初始化完成\");\n } catch (error) {\n logger.error(\"CustomMCPHandler重新初始化失败\", { error });\n throw error;\n }\n }\n\n /**\n * 公开的CustomMCPHandler刷新方法,供外部调用\n */\n async refreshCustomMCPHandlerPublic(): Promise<void> {\n return this.refreshCustomMCPHandler();\n }\n\n /**\n * 获取所有服务实例\n */\n getAllServices(): Map<string, MCPService> {\n return new Map(this.services);\n }\n\n /**\n * 获取 CustomMCP 处理器实例\n */\n getCustomMCPHandler(): CustomMCPHandler {\n return this.customMCPHandler;\n }\n\n /**\n * 检查指定的 customMCP 工具是否存在\n * @param toolName 工具名称\n * @returns 如果工具存在返回 true,否则返回 false\n */\n hasCustomMCPTool(toolName: string): boolean {\n try {\n return this.customMCPHandler.hasTool(toolName);\n } catch (error) {\n logger.warn(`[MCPManager] 检查 CustomMCP 工具 ${toolName} 是否存在失败`, {\n error,\n });\n // 异常情况下返回 false,表示工具不存在\n return false;\n }\n }\n\n /**\n * 获取所有 customMCP 工具列表\n * @returns customMCP 工具数组\n */\n getCustomMCPTools(): Tool[] {\n try {\n return this.customMCPHandler.getTools();\n } catch (error) {\n logger.warn(\"[MCPManager] 获取 CustomMCP 工具列表失败,返回空数组\", {\n error,\n });\n // 异常情况下返回空数组,避免影响调用方\n return [];\n }\n }\n\n /**\n * 检查是否为 ModelScope 服务\n * 统一使用 ConfigAdapter 的 isModelScopeURL 函数\n */\n private isModelScopeService(config: MCPServiceConfig): boolean {\n return config.url ? isModelScopeURL(config.url) : false;\n }\n\n /**\n * 处理 ModelScope 服务认证\n * 智能检查现有认证信息,按优先级处理\n */\n private handleModelScopeAuth(\n serviceName: string,\n originalConfig: MCPServiceConfig,\n enhancedConfig: MCPServiceConfig\n ): void {\n // 1. 检查是否已有 Authorization header\n const existingAuthHeader = originalConfig.headers?.Authorization;\n\n if (existingAuthHeader) {\n // 已有认证信息,直接使用\n logger.info(\n `[MCPManager] 服务 ${serviceName} 使用已有的 Authorization header`\n );\n return;\n }\n\n // 2. 检查全局 ModelScope API Key\n const modelScopeApiKey = configManager.getModelScopeApiKey();\n\n if (modelScopeApiKey) {\n // 注入全局 API Key\n enhancedConfig.apiKey = modelScopeApiKey;\n logger.info(`[MCPManager] 为 ${serviceName} 服务添加 ModelScope API Key`);\n return;\n }\n\n // 3. 无法获取认证信息,提供详细错误信息\n const serviceUrl = originalConfig.url || \"未知\";\n\n throw new Error(\n `ModelScope 服务 \"${serviceName}\" 需要认证信息,但未找到有效的认证配置。服务 URL: ${serviceUrl}请选择以下任一方式配置认证:1. 在服务配置中添加 headers.Authorization2. 或者在全局配置中设置 modelscope.apiKey3. 或者设置环境变量 MODELSCOPE_API_TOKEN获取 ModelScope API Key: https://modelscope.cn/my?myInfo=true`\n );\n }\n\n /**\n * 增强服务配置\n * 根据服务类型添加必要的全局配置,智能处理认证信息\n */\n private enhanceServiceConfig(\n serviceName: string,\n config: MCPServiceConfig\n ): MCPServiceConfig {\n const enhancedConfig = { ...config };\n\n try {\n // 处理 ModelScope 服务(智能认证检查)\n if (this.isModelScopeService(config)) {\n this.handleModelScopeAuth(serviceName, config, enhancedConfig);\n }\n\n return enhancedConfig;\n } catch (error) {\n logger.error(`[MCPManager] 配置增强失败: ${serviceName}`, { error });\n throw error;\n }\n }\n\n /**\n * 添加服务配置(重载方法以支持两种调用方式)\n */\n addServiceConfig(name: string, config: MCPServiceConfig): void;\n addServiceConfig(config: InternalMCPServiceConfig): void;\n addServiceConfig(\n nameOrConfig: string | MCPServiceConfig | InternalMCPServiceConfig,\n config?: MCPServiceConfig\n ): void {\n let finalConfig: MCPServiceConfig;\n let serviceName: string;\n\n if (typeof nameOrConfig === \"string\" && config) {\n // 两参数版本\n serviceName = nameOrConfig;\n finalConfig = config;\n } else if (typeof nameOrConfig === \"object\") {\n // 单参数版本(使用 InternalMCPServiceConfig)\n const internalConfig = nameOrConfig as InternalMCPServiceConfig;\n serviceName = internalConfig.name;\n finalConfig = internalConfig;\n } else {\n throw new Error(\"Invalid arguments for addServiceConfig\");\n }\n\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(serviceName, finalConfig);\n\n // 存储增强后的配置\n this.configs[serviceName] = enhancedConfig;\n logger.debug(`[MCPManager] 已添加服务配置: ${serviceName}`);\n }\n\n /**\n * 更新服务配置\n */\n updateServiceConfig(name: string, config: MCPServiceConfig): void {\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(name, config);\n\n // 存储增强后的配置\n this.configs[name] = enhancedConfig;\n logger.debug(`[MCPManager] 已更新并增强服务配置: ${name}`);\n }\n\n /**\n * 移除服务配置\n */\n removeServiceConfig(name: string): void {\n delete this.configs[name];\n logger.debug(`[MCPManager] 已移除服务配置: ${name}`);\n }\n\n /**\n * 同步工具配置到配置文件\n * 实现自动同步 MCP 服务工具配置到 xiaozhi.config.json\n */\n private async syncToolsConfigToFile(): Promise<void> {\n try {\n logger.debug(\"[MCPManager] 开始同步工具配置到配置文件\");\n\n // 获取当前配置文件中的 mcpServerConfig\n const currentServerConfigs = configManager.getMcpServerConfig();\n\n // 遍历所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (!service.isConnected()) {\n continue;\n }\n\n const tools = service.getTools();\n if (tools.length === 0) {\n continue;\n }\n\n // 获取当前服务在配置文件中的工具配置\n const currentToolsConfig =\n currentServerConfigs[serviceName]?.tools || {};\n\n // 构建新的工具配置\n const newToolsConfig: Record<string, MCPToolConfig> = {};\n\n for (const tool of tools) {\n const currentToolConfig = currentToolsConfig[tool.name];\n\n // 如果工具已存在,保留用户设置的 enable 状态,但更新描述\n if (currentToolConfig) {\n newToolsConfig[tool.name] = {\n ...currentToolConfig,\n description:\n tool.description || currentToolConfig.description || \"\",\n };\n } else {\n // 新工具,默认启用\n newToolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: true,\n };\n }\n }\n\n // 检查是否有工具被移除(在配置文件中存在但在当前工具列表中不存在)\n const currentToolNames = tools.map((t) => t.name);\n const configToolNames = Object.keys(currentToolsConfig);\n const removedTools = configToolNames.filter(\n (name) => !currentToolNames.includes(name)\n );\n\n if (removedTools.length > 0) {\n logger.info(\n `[MCPManager] 检测到服务 ${serviceName} 移除了 ${\n removedTools.length\n } 个工具: ${removedTools.join(\", \")}`\n );\n }\n\n // 检查配置是否有变化\n const hasChanges = this.hasToolsConfigChanged(\n currentToolsConfig,\n newToolsConfig\n );\n\n if (hasChanges) {\n // 更新配置文件\n configManager.updateServerToolsConfig(serviceName, newToolsConfig);\n\n const addedTools = Object.keys(newToolsConfig).filter(\n (name) => !currentToolsConfig[name]\n );\n const updatedTools = Object.keys(newToolsConfig).filter((name) => {\n const current = currentToolsConfig[name];\n const updated = newToolsConfig[name];\n return current && current.description !== updated.description;\n });\n\n logger.debug(`[MCPManager] 已同步服务 ${serviceName} 的工具配置:`);\n if (addedTools.length > 0) {\n logger.debug(` - 新增工具: ${addedTools.join(\", \")}`);\n }\n if (updatedTools.length > 0) {\n logger.debug(` - 更新工具: ${updatedTools.join(\", \")}`);\n }\n if (removedTools.length > 0) {\n logger.debug(` - 移除工具: ${removedTools.join(\", \")}`);\n }\n }\n }\n\n logger.debug(\"[MCPManager] 工具配置同步完成\");\n } catch (error) {\n logger.error(\"[MCPManager] 同步工具配置到配置文件失败\", { error });\n // 不抛出错误,避免影响服务正常运行\n }\n }\n\n /**\n * 检查工具配置是否有变化\n */\n private hasToolsConfigChanged(\n currentConfig: Record<string, MCPToolConfig>,\n newConfig: Record<string, MCPToolConfig>\n ): boolean {\n const currentKeys = Object.keys(currentConfig);\n const newKeys = Object.keys(newConfig);\n\n // 检查工具数量是否变化\n if (currentKeys.length !== newKeys.length) {\n return true;\n }\n\n // 检查是否有新增或删除的工具\n const addedTools = newKeys.filter((key) => !currentKeys.includes(key));\n const removedTools = currentKeys.filter((key) => !newKeys.includes(key));\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n return true;\n }\n\n // 检查现有工具的描述是否有变化\n for (const toolName of currentKeys) {\n const currentTool = currentConfig[toolName];\n const newTool = newConfig[toolName];\n\n if (currentTool.description !== newTool.description) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 安排失败服务的重试\n * @param failedServices 失败的服务列表\n */\n private scheduleFailedServicesRetry(failedServices: string[]): void {\n if (failedServices.length === 0) return;\n\n // 记录重试安排\n logger.info(`[MCPManager] 安排 ${failedServices.length} 个失败服务的重试`);\n\n // 初始重试延迟:30秒\n const initialDelay = 30000;\n\n for (const serviceName of failedServices) {\n this.failedServices.add(serviceName);\n this.scheduleServiceRetry(serviceName, initialDelay);\n }\n }\n\n /**\n * 安排单个服务的重试\n * @param serviceName 服务名称\n * @param delay 延迟时间(毫秒)\n */\n private scheduleServiceRetry(serviceName: string, delay: number): void {\n // 清除现有定时器\n const existingTimer = this.retryTimers.get(serviceName);\n if (existingTimer) {\n clearTimeout(existingTimer);\n this.retryTimers.delete(serviceName);\n }\n\n logger.debug(`[MCPManager] 安排服务 ${serviceName} 在 ${delay}ms 后重试`);\n\n const timer = setTimeout(async () => {\n this.retryTimers.delete(serviceName);\n await this.retryFailedService(serviceName);\n }, delay);\n\n this.retryTimers.set(serviceName, timer);\n }\n\n /**\n * 重试失败的服务\n * @param serviceName 服务名称\n */\n private async retryFailedService(serviceName: string): Promise<void> {\n if (!this.failedServices.has(serviceName)) {\n return; // 服务已经成功启动或不再需要重试\n }\n\n try {\n await this.startService(serviceName);\n\n // 重试成功\n this.failedServices.delete(serviceName);\n logger.info(`[MCPManager] 服务 ${serviceName} 重试启动成功`);\n\n // 重新初始化CustomMCPHandler以包含新启动的服务工具\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n logger.error(\"[MCPManager] 刷新CustomMCPHandler失败\", { error });\n }\n } catch (error) {\n logger.error(`[MCPManager] 服务 ${serviceName} 重试启动失败`, {\n error: (error as Error).message,\n });\n\n // 指数退避重试策略:延迟时间翻倍,最大不超过5分钟\n const currentDelay = this.getRetryDelay(serviceName);\n const nextDelay = Math.min(currentDelay * 2, 300000); // 最大5分钟\n\n logger.debug(\n `[MCPManager] 服务 ${serviceName} 下次重试将在 ${nextDelay}ms 后进行`\n );\n\n this.scheduleServiceRetry(serviceName, nextDelay);\n }\n }\n\n /**\n * 获取当前重试延迟时间\n * @param serviceName 服务名称\n * @returns 当前延迟时间\n */\n private getRetryDelay(serviceName: string): number {\n // 这里可以实现更复杂的状态跟踪来计算准确的延迟\n // 简化实现:返回一个基于服务名称的哈希值的初始延迟\n const hash = serviceName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n return 30000 + (hash % 60000); // 30-90秒之间的初始延迟\n }\n\n /**\n * 停止指定服务的重试\n * @param serviceName 服务名称\n */\n public stopServiceRetry(serviceName: string): void {\n const timer = this.retryTimers.get(serviceName);\n if (timer) {\n clearTimeout(timer);\n this.retryTimers.delete(serviceName);\n logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n this.failedServices.delete(serviceName);\n }\n\n /**\n * 停止所有服务的重试\n */\n public stopAllServiceRetries(): void {\n logger.info(\"[MCPManager] 停止所有服务重试\");\n\n for (const [serviceName, timer] of this.retryTimers) {\n clearTimeout(timer);\n logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n\n this.retryTimers.clear();\n this.failedServices.clear();\n }\n\n /**\n * 获取失败服务列表\n * @returns 失败的服务名称数组\n */\n public getFailedServices(): string[] {\n return Array.from(this.failedServices);\n }\n\n /**\n * 检查服务是否失败\n * @param serviceName 服务名称\n * @returns 如果服务失败返回true\n */\n public isServiceFailed(serviceName: string): boolean {\n return this.failedServices.has(serviceName);\n }\n\n /**\n * 获取重试统计信息\n * @returns 重试统计信息\n */\n public getRetryStats(): {\n failedServices: string[];\n activeRetries: string[];\n totalFailed: number;\n totalActiveRetries: number;\n } {\n return {\n failedServices: Array.from(this.failedServices),\n activeRetries: Array.from(this.retryTimers.keys()),\n totalFailed: this.failedServices.size,\n totalActiveRetries: this.retryTimers.size,\n };\n }\n\n /**\n * 获取消息处理器(供外部使用)\n * @returns 消息处理器实例\n */\n public getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 启动管理器\n */\n public async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error(\"服务器已在运行\");\n }\n\n logger.info(\"启动 MCP 服务管理器\");\n\n try {\n await this.startAllServices();\n this.isRunning = true;\n\n logger.info(\"MCP 服务管理器启动成功\");\n this.emit(\"started\");\n } catch (error) {\n logger.error(\"MCP 服务管理器启动失败\", { error });\n throw error;\n }\n }\n\n /**\n * 停止管理器(包含传输和服务)\n */\n public async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n logger.info(\"停止 MCP 服务管理器\");\n\n try {\n await this.stopAllServices();\n this.isRunning = false;\n\n logger.info(\"MCP 服务管理器停止成功\");\n this.emit(\"stopped\");\n } catch (error) {\n logger.error(\"MCP 服务管理器停止失败\", { error });\n throw error;\n }\n }\n\n /**\n * 获取所有连接信息\n * @returns 连接信息列表\n */\n public getAllConnections(): Array<{\n id: string;\n name: string;\n state: ConnectionState;\n }> {\n const connections: Array<{\n id: string;\n name: string;\n state: ConnectionState;\n }> = [];\n\n // 收集服务连接\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connections.push({\n id: `service-${serviceName}`,\n name: serviceName,\n state: ConnectionState.CONNECTED,\n });\n }\n }\n\n return connections;\n }\n\n /**\n * 获取活跃连接数\n * @returns 活跃连接数量\n */\n public getActiveConnectionCount(): number {\n return this.getAllConnections().filter(\n (conn) => conn.state === ConnectionState.CONNECTED\n ).length;\n }\n\n // ===== 从 UnifiedMCPServer 移入的方法 =====\n\n /**\n * 获取服务器状态(从 UnifiedMCPServer 移入)\n */\n getUnifiedStatus(): UnifiedServerStatus {\n const serviceStatus = this.getServiceManagerStatus();\n return {\n isRunning: this.isRunning,\n serviceStatus,\n activeConnections: this.getActiveConnectionCount(),\n config: this.config,\n // 便捷访问属性\n services: serviceStatus.services,\n totalTools: serviceStatus.totalTools,\n availableTools: serviceStatus.availableTools,\n };\n }\n\n /**\n * 获取管理器状态(原有的 getStatus 方法重命名)\n */\n getServiceManagerStatus(): ManagerStatus {\n // 计算总工具数量(包括 customMCP 工具,添加异常处理)\n let customMCPToolCount = 0;\n let customToolNames: string[] = [];\n\n try {\n customMCPToolCount = this.customMCPHandler.getToolCount();\n customToolNames = this.customMCPHandler.getToolNames();\n logger.debug(\n `[MCPManager] 成功获取 customMCP 状态: ${customMCPToolCount} 个工具`\n );\n } catch (error) {\n logger.warn(\n \"[MCPManager] 获取 CustomMCP 状态失败,将只包含标准 MCP 工具\",\n { error }\n );\n // 异常情况下,customMCP 工具数量为0,不影响标准 MCP 工具\n customMCPToolCount = 0;\n customToolNames = [];\n }\n\n const totalTools = this.tools.size + customMCPToolCount;\n\n // 获取所有可用工具名称\n const standardToolNames = Array.from(this.tools.keys());\n const availableTools = [...standardToolNames, ...customToolNames];\n\n const status: ManagerStatus = {\n services: {},\n totalTools,\n availableTools,\n };\n\n // 添加标准 MCP 服务状态\n for (const [serviceName, service] of this.services) {\n const serviceStatus = service.getStatus();\n status.services[serviceName] = {\n connected: serviceStatus.connected,\n clientName: `xiaozhi-${serviceName}-client`,\n };\n }\n\n // 添加 CustomMCP 服务状态\n if (customMCPToolCount > 0) {\n status.services.customMCP = {\n connected: true, // CustomMCP 工具总是可用的\n clientName: \"xiaozhi-customMCP-handler\",\n };\n }\n\n return status;\n }\n\n /**\n * 检查服务器是否正在运行(从 UnifiedMCPServer 移入)\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n\n /**\n * 类型守卫:检查是否为 UnifiedServerConfig\n */\n private isUnifiedServerConfig(\n configs: unknown\n ): configs is UnifiedServerConfig {\n return (\n configs !== null && typeof configs === \"object\" && \"configs\" in configs\n );\n }\n\n /**\n * 消息路由核心功能(从 UnifiedMCPServer 移入)\n */\n async routeMessage(message: MCPMessage): Promise<MCPMessage | null> {\n const response = await this.messageHandler.handleMessage(message);\n // 如果响应是 null,直接返回\n if (response === null) {\n return null;\n }\n // 将 MCPResponse 转换为 MCPMessage 格式\n return {\n jsonrpc: \"2.0\",\n method: \"response\", // 标识这是一个响应消息\n params: response,\n id: response.id, // 使用响应中的ID\n };\n }\n\n // ===== 向后兼容方法 =====\n\n /**\n * 初始化方法(向后兼容,实际调用 start)\n *\n * 注意:此方法仅为向后兼容而保留\n * 实际功能:调用 start() 方法并设置 isRunning 状态\n * 建议新代码直接使用 start() 方法\n */\n async initialize(): Promise<void> {\n // 为了向后兼容,初始化时调用 start\n // 会设置 isRunning 状态为 true\n await this.start();\n }\n\n /**\n * 获取工具注册表(向后兼容,返回自身)\n */\n getToolRegistry(): MCPServiceManager {\n return this;\n }\n\n /**\n * 获取连接管理器(向后兼容,返回自身)\n */\n getConnectionManager(): MCPServiceManager {\n return this;\n }\n\n /**\n * 清理资源(实现 IMCPServiceManager 接口)\n *\n * 注意:此方法会停止所有 MCP 服务\n */\n async cleanup(): Promise<void> {\n await this.stopAllServices();\n\n // 清理事件监听器,防止内存泄漏\n this.eventBus.offEvent(\n \"mcp:service:connected\",\n this.eventListeners.serviceConnected\n );\n this.eventBus.offEvent(\n \"mcp:service:disconnected\",\n this.eventListeners.serviceDisconnected\n );\n this.eventBus.offEvent(\n \"mcp:service:connection:failed\",\n this.eventListeners.serviceConnectionFailed\n );\n }\n}\n","/**\n * MCP 核心库类型定义\n * 统一管理所有 MCP 相关的类型定义,避免重复定义和导入路径混乱\n */\n\nimport type { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\n\n// =========================\n// 1. 基础传输类型\n// =========================\n\n/**\n * MCP 传输层联合类型定义\n * 支持 STDIO、SSE、StreamableHTTP 三种传输协议\n */\nexport type MCPServerTransport =\n | StdioClientTransport\n | SSEClientTransport\n | StreamableHTTPClientTransport;\n\n/**\n * 通信方式枚举\n * 定义 MCP 支持的传输类型\n */\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n HTTP = \"http\",\n}\n\n// =========================\n// 2. 配置接口类型\n// =========================\n\n/**\n * ModelScope SSE 自定义选项接口\n * 专门用于 ModelScope 相关的 SSE 配置\n */\nexport interface ModelScopeSSEOptions {\n eventSourceInit?: {\n fetch?: (\n url: string | URL | Request,\n init?: RequestInit\n ) => Promise<Response>;\n };\n requestInit?: RequestInit;\n}\n\n/**\n * MCP 服务配置接口\n * 包含所有 MCP 服务的配置选项\n *\n * 注意:符合 @modelcontextprotocol 官方标准,不包含 name 字段\n * name 应该作为服务标识符独立管理,不是配置的一部分\n */\nexport interface MCPServiceConfig {\n type?: MCPTransportType; // 现在是可选的,支持自动推断\n // stdio 配置\n command?: string;\n args?: string[];\n env?: Record<string, string>; // 环境变量配置\n // 网络配置\n url?: string;\n // 认证配置\n apiKey?: string;\n headers?: Record<string, string>;\n customSSEOptions?: ModelScopeSSEOptions;\n}\n\n/**\n * 内部使用的 MCP 服务配置接口(包含 name 字段)\n * 用于 MCPService 类等内部函数,保持向后兼容\n */\nexport interface InternalMCPServiceConfig extends MCPServiceConfig {\n name: string;\n}\n\n// =========================\n// 3. 状态枚举类型\n// =========================\n\n/**\n * 连接状态枚举\n * 合并了 connection.ts 和 TransportAdapter.ts 中的定义\n */\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n ERROR = \"error\", // 从 TransportAdapter.ts 合并的额外状态\n}\n\n/**\n * MCP 服务状态接口\n * 描述 MCP 服务的运行时状态信息\n */\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n connectionState: ConnectionState;\n}\n\n// =========================\n// 4. 工具调用相关类型\n// =========================\n\n/**\n * 工具调用结果接口\n * 使用简化的类型定义,保持向后兼容性\n * 注意:这与 @xiaozhi-client/mcp-core 中的 ToolCallResult 类型不同\n */\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n [key: string]: unknown; // 支持其他未知字段,与 endpoint 包保持兼容\n}\n\n/**\n * JSON Schema 类型定义\n * 兼容 MCP SDK 的 JSON Schema 格式,同时支持更宽松的对象格式以保持向后兼容\n */\nexport type JSONSchema =\n | (Record<string, unknown> & {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n })\n | Record<string, unknown>; // 允许更宽松的格式以保持向后兼容\n\n/**\n * 类型守卫:检查对象是否为有效的 MCP Tool JSON Schema\n */\nexport function isValidToolJSONSchema(obj: unknown): obj is {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"type\" in obj &&\n (obj as { type?: unknown }).type === \"object\"\n );\n}\n\n/**\n * 确保对象符合 MCP Tool JSON Schema 格式\n * 如果不符合,会返回一个默认的空对象 schema\n */\nexport function ensureToolJSONSchema(schema: JSONSchema): {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n if (isValidToolJSONSchema(schema)) {\n return schema as {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n };\n }\n\n // 如果不符合标准格式,返回默认的空对象 schema\n return {\n type: \"object\",\n properties: {} as Record<string, object>,\n required: [],\n additionalProperties: true,\n };\n}\n\n/**\n * CustomMCP 工具类型定义\n * 统一了 manager.ts 和 configManager.ts 中的定义\n */\nexport interface CustomMCPTool {\n name: string;\n description?: string;\n inputSchema: JSONSchema;\n handler?: {\n type: string;\n config?: Record<string, unknown>;\n };\n}\n\n/**\n * 工具信息接口\n * 用于缓存工具映射关系,保持向后兼容性\n */\nexport interface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// =========================\n// 5. 增强工具信息类型\n// =========================\n\n/**\n * 工具状态过滤选项\n * 用于 getAllTools() 方法过滤不同状态的工具\n */\nexport type ToolStatusFilter = \"enabled\" | \"disabled\" | \"all\";\n\n/**\n * 增强的工具信息接口\n * 扩展自 ToolInfo 概念,包含工具的启用状态和使用统计信息\n *\n * @remarks\n * 此接口用于 MCPServiceManager.getAllTools() 方法的返回值,\n * 提供比基础 ToolInfo 更丰富的工具元数据信息。\n *\n * @example\n * ```typescript\n * const tools: EnhancedToolInfo[] = manager.getAllTools('enabled');\n * tools.forEach(tool => {\n * console.log(`工具: ${tool.name}`);\n * console.log(`状态: ${tool.enabled ? '已启用' : '已禁用'}`);\n * console.log(`使用次数: ${tool.usageCount}`);\n * });\n * ```\n */\nexport interface EnhancedToolInfo {\n /** 工具唯一标识符,格式为 \"{serviceName}__{originalName}\" */\n name: string;\n\n /** 工具描述信息 */\n description: string;\n\n /** 工具输入参数的 JSON Schema 定义 */\n inputSchema: JSONSchema;\n\n /** 工具所属的 MCP 服务名称 */\n serviceName: string;\n\n /** 工具在 MCP 服务中的原始名称 */\n originalName: string;\n\n /** 工具是否启用 (true=已启用,false=已禁用) */\n enabled: boolean;\n\n /** 工具使用次数统计 */\n usageCount: number;\n\n /** 工具最后使用时间 (ISO 8601 格式字符串) */\n lastUsedTime: string;\n}\n\n// =========================\n// 6. 服务器配置类型\n// =========================\n\n/**\n * 统一服务器配置接口\n * 从 UnifiedMCPServer 移入,用于统一服务器配置管理\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n configs?: Record<string, MCPServiceConfig>; // MCPService 配置\n}\n\n/**\n * 统一服务器状态接口\n * 从 UnifiedMCPServer 移入,用于统一服务器状态管理\n */\nexport interface UnifiedServerStatus {\n isRunning: boolean;\n serviceStatus: ManagerStatus;\n activeConnections: number;\n config: UnifiedServerConfig;\n // 添加对 serviceStatus 的便捷访问属性\n services?: Record<string, MCPServiceConnectionStatus>;\n totalTools?: number;\n availableTools?: string[];\n}\n\n// =========================\n// 6. 管理器相关类型\n// =========================\n\n/**\n * MCP 服务连接状态接口\n * 重命名原 ServiceStatus 为 MCPServiceConnectionStatus 避免与 CLI 的 ServiceStatus 冲突\n */\nexport interface MCPServiceConnectionStatus {\n connected: boolean;\n clientName: string;\n}\n\n/**\n * 管理器状态接口\n * 描述 MCP 服务管理器的整体状态\n */\nexport interface ManagerStatus {\n services: Record<string, MCPServiceConnectionStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// =========================\n// 7. 参数校验相关类型\n// =========================\n\n/**\n * 工具调用参数接口\n * 定义标准工具调用参数结构\n */\nexport interface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 验证后的工具调用参数\n * 参数校验通过后的标准化参数结构\n */\nexport interface ValidatedToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 工具调用验证选项\n * 提供灵活的参数校验配置\n */\nexport interface ToolCallValidationOptions {\n /** 是否验证工具名称,默认为 true */\n validateName?: boolean;\n /** 是否验证参数格式,默认为 true */\n validateArguments?: boolean;\n /** 是否允许空参数,默认为 true */\n allowEmptyArguments?: boolean;\n /** 自定义验证函数 */\n customValidator?: (params: ToolCallParams) => string | null;\n}\n\n/**\n * 工具调用错误码枚举\n * 统一的工具调用错误码定义\n */\nexport enum ToolCallErrorCode {\n /** 无效参数 */\n INVALID_PARAMS = -32602,\n /** 工具不存在 */\n TOOL_NOT_FOUND = -32601,\n /** 服务不可用 */\n SERVICE_UNAVAILABLE = -32001,\n /** 调用超时 */\n TIMEOUT = -32002,\n /** 工具执行错误 */\n TOOL_EXECUTION_ERROR = -32000,\n}\n\n/**\n * 工具调用错误类\n * 统一的工具调用错误处理\n */\nexport class ToolCallError extends Error {\n constructor(\n public code: ToolCallErrorCode,\n message: string,\n public data?: unknown\n ) {\n super(message);\n this.name = \"ToolCallError\";\n }\n}\n\n// =========================\n// 向后兼容性别名\n// =========================\n\n/**\n * 向后兼容:ServiceStatus 别名\n * 为了与现有代码保持兼容,暂时保留此别名\n * @deprecated 请使用 MCPServiceConnectionStatus\n */\nexport type ServiceStatus = MCPServiceConnectionStatus;\n","/**\n * MCP 相关类型定义\n *\n * 定义了与 MCP(Model Context Protocol)相关的所有类型,包括:\n * - 工具调用结果和响应格式\n * - JSON-RPC 2.0 消息和错误类型\n * - MCP 工具缓存相关类型和工具函数\n * - 超时处理和任务状态管理\n *\n * @module types/mcp\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { MCPToolsCache } from \"@/lib/mcp\";\nimport type { TimeoutResponse } from \"./timeout.js\";\n\n// 工具调用结果接口(与 MCPServiceManager 保持一致)\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n [key: string]: unknown; // 支持其他未知字段,与 lib/mcp/types 保持兼容\n}\n\n// MCP 消息接口 - 定义 JSON-RPC 2.0 标准消息格式\nexport interface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: unknown;\n id: string | number;\n}\n\n// MCP 响应接口 - 定义 JSON-RPC 2.0 标准响应格式\nexport interface MCPResponse {\n jsonrpc: \"2.0\";\n id: string | number;\n result?: unknown;\n error?: MCPError;\n}\n\n// MCP 错误接口 - 定义 JSON-RPC 2.0 标准错误格式\nexport interface MCPError {\n code: number;\n message: string;\n data?: unknown;\n}\n\n/**\n * 扩展的 MCP 工具缓存接口\n * 增加对 CustomMCP 执行结果的支持\n */\nexport interface ExtendedMCPToolsCache extends MCPToolsCache {\n customMCPResults?: Record<string, EnhancedToolResultCache>; // 增强的工具执行结果缓存\n}\n\n/**\n * 增强的工具执行结果缓存\n * 用于存储 CustomMCP 工具的执行结果和状态\n */\nexport interface EnhancedToolResultCache {\n result: ToolCallResult;\n timestamp: string; // ISO 8601 格式时间戳\n ttl: number; // 过期时间(毫秒)\n status: TaskStatus; // 任务状态\n consumed: boolean; // 是否已被消费(一次性缓存机制)\n taskId?: string; // 任务ID,用于查询\n retryCount: number; // 重试次数\n}\n\n/**\n * 任务状态类型\n */\nexport type TaskStatus =\n | \"pending\"\n | \"completed\"\n | \"failed\"\n | \"consumed\"\n | \"deleted\";\n\n/**\n * 缓存状态转换接口\n */\nexport interface CacheStateTransition {\n from: TaskStatus;\n to: TaskStatus;\n reason: string;\n timestamp: string;\n}\n\n/**\n * 工具调用选项\n */\nexport interface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n retries?: number; // 重试次数\n retryDelay?: number; // 重试延迟(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 缓存配置选项\n */\nexport interface CacheConfig {\n ttl?: number; // 缓存过期时间(毫秒),默认5分钟\n cleanupInterval?: number; // 清理间隔(毫秒),默认1分钟\n maxCacheSize?: number; // 最大缓存条目数\n enableOneTimeCache?: boolean; // 是否启用一次性缓存\n}\n\n/**\n * 超时配置选项\n */\nexport interface TimeoutConfig {\n timeout?: number; // 超时时间(毫秒),默认8秒\n enableFriendlyTimeout?: boolean; // 是否启用友好超时响应\n backgroundProcessing?: boolean; // 是否启用后台处理\n}\n\n/**\n * 任务信息接口\n */\nexport interface TaskInfo {\n taskId: string;\n toolName: string;\n arguments: Record<string, unknown>;\n status: TaskStatus;\n startTime: string;\n endTime?: string;\n error?: string;\n result?: ToolCallResult;\n}\n\n/**\n * 缓存统计信息\n */\nexport interface CacheStatistics {\n totalEntries: number;\n pendingTasks: number;\n completedTasks: number;\n failedTasks: number;\n consumedEntries: number;\n cacheHitRate: number;\n lastCleanupTime: string;\n memoryUsage: number;\n}\n\n/**\n * 工具调用结果联合类型\n * 包含正常结果和超时响应\n */\nexport type ToolCallResponse = ToolCallResult | TimeoutResponse;\n\n/**\n * 验证是否为工具调用结果\n */\nexport function isToolCallResult(\n response: unknown\n): response is ToolCallResult {\n return (\n !!response &&\n typeof response === \"object\" &&\n response !== null &&\n \"content\" in response &&\n Array.isArray((response as ToolCallResult).content) &&\n (response as ToolCallResult).content.length > 0 &&\n (response as ToolCallResult).content[0]?.type === \"text\" &&\n typeof (response as ToolCallResult).content[0]?.text === \"string\"\n );\n}\n\n/**\n * 验证是否为增强的工具结果缓存\n */\nexport function isEnhancedToolResultCache(\n cache: unknown\n): cache is EnhancedToolResultCache {\n const cacheObj = cache as EnhancedToolResultCache;\n return (\n !!cache &&\n typeof cache === \"object\" &&\n cache !== null &&\n typeof cacheObj.timestamp === \"string\" &&\n typeof cacheObj.ttl === \"number\" &&\n typeof cacheObj.status === \"string\" &&\n [\"completed\", \"pending\", \"failed\", \"consumed\"].includes(cacheObj.status) &&\n typeof cacheObj.consumed === \"boolean\" &&\n typeof cacheObj.retryCount === \"number\"\n );\n}\n\n/**\n * 验证是否为扩展的 MCP 工具缓存\n */\nexport function isExtendedMCPToolsCache(\n cache: unknown\n): cache is ExtendedMCPToolsCache {\n const cacheObj = cache as ExtendedMCPToolsCache;\n return (\n !!cache &&\n typeof cache === \"object\" &&\n cache !== null &&\n typeof cacheObj.version === \"string\" &&\n typeof cacheObj.mcpServers === \"object\" &&\n cacheObj.mcpServers !== null &&\n typeof cacheObj.metadata === \"object\" &&\n cacheObj.metadata !== null\n );\n}\n\n/**\n * 生成缓存键的工具函数\n */\nexport function generateCacheKey(\n toolName: string,\n arguments_: Record<string, unknown>\n): string {\n const argsHash = createHash(\"md5\")\n .update(JSON.stringify(arguments_ || {}))\n .digest(\"hex\");\n return `${toolName}_${argsHash}`;\n}\n\n/**\n * 格式化时间戳的工具函数\n */\nexport function formatTimestamp(timestamp: number | Date = Date.now()): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * 检查缓存是否过期\n */\nexport function isCacheExpired(timestamp: string, ttl: number): boolean {\n const cachedTime = new Date(timestamp).getTime();\n const now = Date.now();\n return now - cachedTime > ttl;\n}\n\n/**\n * 检查是否应该清理缓存条目\n */\nexport function shouldCleanupCache(cache: EnhancedToolResultCache): boolean {\n const now = Date.now();\n const cachedTime = new Date(cache.timestamp).getTime();\n\n // 已消费且超过清理时间(1分钟)\n if (cache.consumed && now - cachedTime > DEFAULT_CONFIG.CLEANUP_INTERVAL) {\n return true;\n }\n\n // 已过期\n if (now - cachedTime > cache.ttl) {\n return true;\n }\n\n // 失败的任务立即清理\n if (cache.status === \"failed\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * 默认配置常量\n */\nexport const DEFAULT_CONFIG = {\n TIMEOUT: 8000, // 8秒超时\n CACHE_TTL: 300000, // 5分钟缓存\n CLEANUP_INTERVAL: 60000, // 1分钟清理间隔\n MAX_CACHE_SIZE: 1000, // 最大缓存条目数\n ENABLE_ONE_TIME_CACHE: true, // 启用一次性缓存\n} as const;\n","/**\n * 超时错误类型\n */\nexport class TimeoutError extends Error {\n public override readonly name = \"TimeoutError\" as const;\n\n constructor(message: string) {\n super(message);\n this.name = \"TimeoutError\";\n Error.captureStackTrace(this, TimeoutError);\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n stack: this.stack,\n };\n }\n}\n\n/**\n * 超时响应接口\n */\nexport interface TimeoutResponse {\n content: Array<{\n type: \"text\";\n text: string;\n }>;\n isError: boolean;\n taskId: string;\n status: \"timeout\";\n message: string;\n nextAction: string;\n [key: string]: unknown; // 支持其他未知字段,与 ToolCallResult 保持兼容\n}\n\n/**\n * 创建超时响应的工具函数\n */\nexport function createTimeoutResponse(\n taskId: string,\n toolName?: string\n): TimeoutResponse {\n const toolSpecificMessage = toolName\n ? getToolSpecificTimeoutMessage(toolName, taskId)\n : getDefaultTimeoutMessage(taskId);\n\n return {\n content: [\n {\n type: \"text\",\n text: toolSpecificMessage,\n },\n ],\n isError: false,\n taskId,\n status: \"timeout\",\n message: \"工具调用超时,正在后台处理中\",\n nextAction: \"请稍后重试或等待任务完成\",\n };\n}\n\n/**\n * 获取工具特定的超时提示信息\n */\nfunction getToolSpecificTimeoutMessage(\n toolName: string,\n taskId: string\n): string {\n const toolMessages: Record<string, string> = {\n coze_workflow: `⏱️ 扣子工作流执行超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 工具类型: 扣子工作流\n- 状态: 处理中\n- 建议: 请等待30-60秒后重试查询\n\n🔄 后续操作:\n1. 使用相同参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 复杂工作流可能需要更长时间处理`,\n\n default: getDefaultTimeoutMessage(taskId),\n };\n\n return toolMessages[toolName] || toolMessages.default;\n}\n\n/**\n * 获取默认超时提示信息\n */\nfunction getDefaultTimeoutMessage(taskId: string): string {\n return `⏱️ 工具调用超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 状态: 处理中\n- 建议: 请等待30秒后重试查询\n\n🔄 后续操作:\n1. 使用相同的参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 如果长时间未完成,请联系管理员`;\n}\n\n/**\n * 验证是否为超时响应\n */\nexport function isTimeoutResponse(response: any): response is TimeoutResponse {\n return !!(\n response &&\n response.status === \"timeout\" &&\n typeof response.taskId === \"string\" &&\n Array.isArray(response.content) &&\n response.content.length > 0 &&\n response.content[0].type === \"text\"\n );\n}\n\n/**\n * 验证是否为超时错误\n */\nexport function isTimeoutError(error: any): error is TimeoutError {\n return !!(\n error &&\n error.name === \"TimeoutError\" &&\n error instanceof TimeoutError\n );\n}\n","#!/usr/bin/env node\n/**\n * 自定义 MCP 工具处理器模块\n *\n * 本模块提供了处理自定义 MCP 工具的核心功能,特别是针对 Coze 工作流工具。\n * 主要功能包括:\n * - CustomMCPHandler:简化的自定义 MCP 工具处理器\n * - 支持代理处理器配置(ProxyHandlerConfig)\n * - 工具调用超时处理\n * - 工具调用缓存机制\n * - 与 Coze API 服务集成\n *\n * @module custom\n *\n * @example\n * ```typescript\n * import { CustomMCPHandler } from '@/lib/mcp/custom.js';\n *\n * const handler = new CustomMCPHandler(mcpServiceManager);\n * const result = await handler.callTool(toolName, arguments, options);\n * ```\n */\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { CozeApiService } from \"@/lib/coze\";\nimport type { RunWorkflowData } from \"@/lib/coze\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport { ensureToolJSONSchema } from \"@/lib/mcp/types.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type {\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n ToolCallResponse,\n ToolCallResult,\n} from \"@/types/mcp.js\";\nimport {\n DEFAULT_CONFIG,\n generateCacheKey,\n isCacheExpired,\n shouldCleanupCache,\n} from \"@/types/mcp.js\";\nimport { TimeoutError, createTimeoutResponse } from \"@/types/timeout.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type {\n CustomMCPTool,\n HandlerConfig,\n ProxyHandlerConfig,\n} from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\n\n// 工具调用参数类型\ntype ToolArguments = Record<string, unknown>;\n\n// 类型守卫函数:检查是否为代理处理器\nfunction isProxyHandler(handler: HandlerConfig): handler is ProxyHandlerConfig {\n return handler.type === \"proxy\";\n}\n\n// 扩展的工具调用选项\ninterface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 简化版的 CustomMCPHandler\n * 专门用于处理 Coze 工作流工具,保持超时友好响应机制\n */\nexport class CustomMCPHandler {\n private logger: Logger;\n private tools: Map<string, CustomMCPTool> = new Map();\n private cacheManager: MCPCacheManager;\n private mcpServiceManager?: MCPServiceManager;\n private readonly TIMEOUT = DEFAULT_CONFIG.TIMEOUT; // 统一8秒超时\n private readonly CACHE_TTL = DEFAULT_CONFIG.CACHE_TTL; // 5分钟缓存过期\n private configUpdateListener: ((data: unknown) => void) | null = null; // 配置更新监听器引用\n\n constructor(\n cacheManager?: MCPCacheManager,\n mcpServiceManager?: MCPServiceManager\n ) {\n this.logger = logger;\n this.cacheManager = cacheManager || new MCPCacheManager();\n this.mcpServiceManager = mcpServiceManager;\n\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 获取 CozeApiService 实例\n */\n private getCozeApiService(): CozeApiService {\n const token = configManager.getConfig().platforms?.coze?.token;\n\n if (!token) {\n throw new Error(\"Coze Token 配置不存在\");\n }\n\n return new CozeApiService(token);\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n const eventBus = getEventBus();\n\n // 监听配置更新事件\n this.configUpdateListener = async (data) => {\n if (\n data &&\n typeof data === \"object\" &&\n \"type\" in data &&\n data.type === \"customMCP\"\n ) {\n this.logger.info(\"[CustomMCP] 检测到配置更新,重新初始化...\");\n try {\n this.reinitialize();\n } catch (error) {\n this.logger.error(\"[CustomMCP] 配置更新处理失败:\", error);\n }\n }\n };\n\n eventBus.onEvent(\"config:updated\", this.configUpdateListener);\n }\n\n /**\n * 初始化 CustomMCP 处理器\n * 加载配置中的 customMCP 工具\n * @param tools 可选的工具数组,如果提供则使用该数组,否则从配置管理器获取\n */\n public initialize(tools?: CustomMCPTool[]): void {\n this.logger.debug(\"[CustomMCP] 初始化 CustomMCP 处理器...\");\n\n try {\n const customTools = tools || configManager.getCustomMCPTools();\n\n // 清空现有工具\n this.tools.clear();\n\n // 只加载 coze 代理工具\n for (const tool of customTools) {\n if (isProxyHandler(tool.handler) && tool.handler.platform === \"coze\") {\n this.tools.set(tool.name, tool);\n this.logger.debug(\n `[CustomMCP] 已加载 Coze 工具: ${tool.name} (workflow_id: ${tool.handler.config.workflow_id})`\n );\n }\n }\n\n this.logger.debug(\n `[CustomMCP] 初始化完成,共加载 ${this.tools.size} 个 Coze 工具`\n );\n } catch (error) {\n this.logger.error(\"[CustomMCP] 初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取所有工具(标准 MCP 格式)\n */\n public getTools(): Tool[] {\n return Array.from(this.tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: ensureToolJSONSchema(tool.inputSchema),\n }));\n }\n\n /**\n * 检查是否存在指定工具\n */\n public hasTool(toolName: string): boolean {\n return this.tools.has(toolName);\n }\n\n /**\n * 获取工具数量\n */\n public getToolCount(): number {\n return this.tools.size;\n }\n\n /**\n * 获取所有工具名称\n */\n public getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * 获取工具详细信息(用于调试)\n */\n public getToolInfo(toolName: string): CustomMCPTool | undefined {\n return this.tools.get(toolName);\n }\n\n /**\n * 重新初始化 CustomMCP 处理器\n * 重新加载配置中的 customMCP 工具\n */\n public reinitialize(): void {\n this.logger.debug(\"[CustomMCP] 重新初始化 CustomMCP 处理器...\");\n this.initialize();\n }\n\n /**\n * 调用工具(支持超时友好响应和缓存管理)\n */\n public async callTool(\n toolName: string,\n arguments_: ToolArguments,\n options?: ToolCallOptions\n ): Promise<ToolCallResponse> {\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 首先检查是否有已完成的任务结果(一次性缓存)\n const completedResult = await this.getCompletedResult(toolName, arguments_);\n if (completedResult) {\n this.logger.debug(`[CustomMCP] 返回已完成的任务结果: ${toolName}`);\n // 立即清理已消费的缓存\n await this.clearConsumedCache(toolName, arguments_);\n return completedResult;\n }\n\n try {\n const timeout = options?.timeout || this.TIMEOUT;\n const result = await Promise.race([\n this.callCozeWorkflow(tool, arguments_),\n this.createTimeoutPromise(toolName, timeout),\n ]);\n\n // 缓存结果(标记为未消费)\n await this.cacheResult(toolName, arguments_, result);\n\n return result;\n } catch (error) {\n // 如果是超时错误,返回友好提示\n if (error instanceof TimeoutError) {\n const taskId = await this.generateTaskId(toolName, arguments_);\n this.logger.info(\n `[CustomMCP] 工具超时,返回友好提示: ${toolName}, taskId: ${taskId}`\n );\n return createTimeoutResponse(taskId, toolName);\n }\n\n throw error;\n }\n }\n\n /**\n * 创建超时 Promise\n */\n private async createTimeoutPromise(\n toolName: string,\n timeout: number\n ): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new TimeoutError(`工具调用超时: ${toolName}`));\n }, timeout);\n });\n }\n\n /**\n * 获取已完成的任务结果(一次性缓存)\n */\n private async getCompletedResult(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<ToolCallResult | null> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cached = cache.customMCPResults[cacheKey];\n\n // 只返回已完成且未消费的结果\n if (cached.status === \"completed\" && !cached.consumed) {\n // 检查是否过期\n if (!isCacheExpired(cached.timestamp, cached.ttl)) {\n return cached.result;\n }\n }\n\n return null;\n } catch (error) {\n this.logger.warn(`[CustomMCP] 获取缓存失败: ${error}`);\n return null;\n }\n }\n\n /**\n * 处理工作流响应\n */\n private processWorkflowResponse(\n toolName: string,\n workflowData: RunWorkflowData\n ): ToolCallResult {\n try {\n // 根据 RunWorkflowData 的实际结构进行处理\n // 假设 workflowData 有 data 字段或其他响应数据字段\n const responseData = workflowData.data || workflowData;\n\n if (typeof responseData === \"string\") {\n return {\n content: [\n {\n type: \"text\",\n text: responseData,\n },\n ],\n isError: false,\n };\n }\n\n // 如果是对象,转换为 JSON 字符串\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(responseData, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 处理工作流响应失败: ${toolName}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `处理响应失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 调用 Coze 工作流\n */\n private async callCozeWorkflow(\n tool: CustomMCPTool,\n arguments_: ToolArguments\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ProxyHandlerConfig;\n const config = handler.config;\n\n this.logger.info(`[CustomMCP] 调用 Coze 工作流: ${tool.name}`, {\n workflow_id: config.workflow_id,\n });\n\n try {\n // 使用 CozeApiService\n const cozeApiService = this.getCozeApiService();\n\n // 检查 workflow_id 是否存在\n if (!config.workflow_id) {\n throw new Error(\"工作流ID未配置\");\n }\n\n // 调用 callWorkflow 方法\n const workflowResult = await cozeApiService.callWorkflow(\n config.workflow_id,\n arguments_\n );\n\n this.logger.info(`[CustomMCP] Coze 工作流调用成功: ${tool.name}`);\n\n // 转换响应格式为 ToolCallResult\n return this.processWorkflowResponse(tool.name, workflowResult);\n } catch (error) {\n this.logger.error(`[CustomMCP] Coze 工作流调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Coze 工作流调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 清理已消费的缓存\n */\n private async clearConsumedCache(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (cache.customMCPResults?.[cacheKey]) {\n // 标记为已消费\n cache.customMCPResults[cacheKey].consumed = true;\n\n // 如果已消费且已过期,直接删除\n const cached = cache.customMCPResults[cacheKey];\n if (shouldCleanupCache(cached)) {\n delete cache.customMCPResults[cacheKey];\n }\n\n // 保存缓存更改\n await this.saveCache(cache);\n this.logger.debug(`[CustomMCP] 清理已消费缓存: ${cacheKey}`);\n }\n } catch (error) {\n this.logger.warn(`[CustomMCP] 清理缓存失败: ${error}`);\n }\n }\n\n /**\n * 生成任务ID\n */\n private async generateTaskId(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<string> {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 生成缓存键\n */\n private generateCacheKey(\n toolName: string,\n arguments_: ToolArguments\n ): string {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 加载扩展缓存\n */\n private async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cacheData = await this.cacheManager.loadExistingCache();\n return cacheData as ExtendedMCPToolsCache;\n } catch (error) {\n return {\n version: \"1.0.0\",\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: new Date().toISOString(),\n totalWrites: 0,\n createdAt: new Date().toISOString(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 更新缓存结果\n */\n private async updateCacheWithResult(\n cacheKey: string,\n cacheData: EnhancedToolResultCache\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheData;\n\n // 使用 MCPCacheManager 的保存方法\n await this.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 更新缓存失败: ${error}`);\n }\n }\n\n /**\n * 缓存结果\n */\n private async cacheResult(\n toolName: string,\n arguments_: ToolArguments,\n result: ToolCallResult\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cacheData: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl: this.CACHE_TTL,\n status: \"completed\",\n consumed: false, // 初始状态为未消费\n retryCount: 0,\n };\n\n await this.updateCacheWithResult(cacheKey, cacheData);\n this.logger.debug(`[CustomMCP] 缓存工具结果: ${toolName}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 缓存结果失败: ${error}`);\n }\n }\n\n /**\n * 保存缓存\n */\n private async saveCache(cache: ExtendedMCPToolsCache): Promise<void> {\n try {\n await this.cacheManager.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 保存缓存失败: ${error}`);\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.logger.info(\"[CustomMCP] 清理 CustomMCP 处理器资源\");\n\n // 移除事件监听器\n if (this.configUpdateListener) {\n const eventBus = getEventBus();\n eventBus.offEvent(\"config:updated\", this.configUpdateListener);\n this.configUpdateListener = null;\n }\n\n this.tools.clear();\n this.cacheManager.cleanup();\n }\n}\n","/**\n * MCP 工具调用日志模块\n * 提供工具调用的写入和查询功能\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { logger } from \"@/Logger.js\";\nimport { PathUtils } from \"@/utils/path-utils.js\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\n\n// ==================== 类型定义 ====================\n\n/**\n * Pino 日志对象类型(内部使用)\n * 用于 formatConsoleMessage 方法的参数类型\n */\ninterface PinoLogObject {\n toolName?: string;\n success?: boolean;\n duration?: number;\n [key: string]: unknown;\n}\n\n/**\n * 工具调用记录接口\n */\nexport interface ToolCallRecord {\n toolName: string; // 工具名称\n originalToolName?: string; // 原始工具名称(未格式化的)\n serverName?: string; // 服务器名称(coze、dify、n8n、custom等)\n arguments?: Record<string, unknown>; // 调用参数\n result?: unknown; // 响应结果\n success: boolean; // 是否成功\n duration?: number; // 调用耗时(毫秒)\n error?: string; // 错误信息(如果有)\n timestamp?: number; // 时间戳(毫秒)\n}\n\n/**\n * 工具调用日志配置接口\n */\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n/**\n * 查询参数接口\n */\nexport interface ToolCallQuery {\n limit?: number;\n offset?: number;\n toolName?: string;\n serverName?: string;\n success?: boolean;\n startDate?: string;\n endDate?: string;\n}\n\n// ==================== ToolCallLogger 类(写入功能)====================\n\n/**\n * MCP 工具调用记录器\n * 提供工具调用的 JSONL 格式记录功能\n */\nexport class ToolCallLogger {\n private pinoLogger: PinoLogger;\n private maxRecords: number;\n private logFilePath: string;\n\n constructor(config: ToolCallLogConfig, configDir: string) {\n this.maxRecords = config?.maxRecords ?? 100;\n\n // 确定日志文件路径 - 使用更健壮的路径处理\n if (config?.logFilePath) {\n this.logFilePath = path.resolve(path.normalize(config.logFilePath));\n } else {\n // 使用 PathUtils 的跨平台临时目录处理\n const baseDir = configDir || PathUtils.getTempDir();\n this.logFilePath = path.join(path.normalize(baseDir), \"tool-calls.jsonl\");\n }\n\n // 创建 Pino 实例\n this.pinoLogger = this.createPinoLogger(this.logFilePath);\n\n logger.info(\"ToolCallLogger 初始化\", {\n maxRecords: this.maxRecords,\n path: this.logFilePath,\n });\n }\n\n /**\n * 创建 Pino Logger 实例\n */\n private createPinoLogger(logFilePath: string): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 使用彩色输出\n streams.push({\n level: \"info\",\n stream: {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessage(logObj);\n console.log(\"[工具调用]\", { message });\n } catch {\n console.log(\"[工具调用]\", { chunk: chunk.trim() });\n }\n },\n },\n });\n\n // 文件流 - JSONL 格式,带错误处理\n try {\n streams.push({\n level: \"info\",\n stream: pino.destination({\n dest: logFilePath,\n sync: true, // 同步写入确保测试可靠性\n append: true,\n mkdir: true,\n }),\n });\n } catch (error) {\n // 如果文件路径无效,记录错误但不抛出异常\n logger.error(\"无法创建工具调用日志文件\", { error });\n }\n\n return pino(\n {\n level: \"info\",\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n level: (_label: string, number: number) => ({ level: number }),\n },\n base: null, // 不包含 pid 和 hostname\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n /**\n * 格式化控制台消息\n */\n private formatConsoleMessage(logObj: PinoLogObject): string {\n const toolName = logObj.toolName || \"未知工具\";\n const success = logObj.success !== false;\n const duration = logObj.duration ? ` (${logObj.duration}ms)` : \"\";\n const status = success ? \"✅\" : \"❌\";\n\n return `${status} ${toolName}${duration}`;\n }\n\n /**\n * 清理旧的日志记录,确保不超过最大记录数量\n */\n private async cleanupOldRecords(): Promise<void> {\n try {\n // 检查日志文件是否存在\n if (!fs.existsSync(this.logFilePath)) {\n return;\n }\n\n // 读取文件内容\n const content = fs.readFileSync(this.logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n // 如果记录数量未超过限制,直接返回\n if (lines.length <= this.maxRecords) {\n return;\n }\n\n // 计算需要删除的记录数量\n const recordsToRemove = lines.length - this.maxRecords + 1; // +1 为即将写入的新记录预留空间\n\n // 删除最旧的记录(从文件开头删除)\n const linesToKeep = lines.slice(recordsToRemove);\n\n // 重新写入文件\n const newContent =\n linesToKeep.join(\"\\n\") + (linesToKeep.length > 0 ? \"\\n\" : \"\");\n fs.writeFileSync(this.logFilePath, newContent, \"utf8\");\n\n logger.info(\"已清理旧的工具调用记录\", {\n recordsToRemove,\n maxRecords: this.maxRecords,\n });\n } catch (error) {\n logger.error(\"清理旧工具调用记录失败\", { error });\n }\n }\n\n /**\n * 记录工具调用\n */\n async recordToolCall(record: ToolCallRecord): Promise<void> {\n try {\n // 在写入新记录前,先清理旧记录以确保不超过最大记录数量\n await this.cleanupOldRecords();\n\n // 使用 Pino 记录日志,自动处理并发和文件写入\n this.pinoLogger.info(record, record.toolName);\n } catch (error) {\n // 记录失败不应该影响主流程,只记录错误日志\n logger.error(\"记录工具调用失败\", { error });\n }\n }\n\n /**\n * 获取日志文件路径\n */\n getLogFilePath(): string {\n return this.logFilePath;\n }\n\n /**\n * 获取最大记录数量\n */\n getMaxRecords(): number {\n return this.maxRecords;\n }\n}\n\n// ==================== ToolCallLogService 类(查询功能)====================\n\n/**\n * 工具调用日志服务类\n * 负责读取和查询工具调用日志\n */\nexport class ToolCallLogService {\n private configDir: string;\n\n constructor(configDir?: string) {\n this.configDir = configDir || PathUtils.getConfigDir();\n }\n\n /**\n * 获取工具调用日志文件路径\n */\n private getLogFilePath(): string {\n const toolCallLogger = new ToolCallLogger({}, this.configDir);\n return toolCallLogger.getLogFilePath();\n }\n\n /**\n * 检查日志文件是否存在\n */\n private checkLogFile(): void {\n const logFilePath = this.getLogFilePath();\n if (!fs.existsSync(logFilePath)) {\n throw new Error(\"工具调用日志文件不存在\");\n }\n }\n\n /**\n * 读取并解析工具调用日志\n */\n private parseLogFile(): ToolCallRecord[] {\n const logFilePath = this.getLogFilePath();\n\n try {\n const content = fs.readFileSync(logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n const records: ToolCallRecord[] = [];\n\n for (const line of lines) {\n try {\n const record = JSON.parse(line);\n // 添加时间戳字段(如果 pino 添加了时间信息)\n if (record.time) {\n record.timestamp = new Date(record.time).getTime();\n }\n // 如果没有时间戳,记录警告信息提示数据质量问题\n if (!record.timestamp) {\n logger.warn(\"日志记录缺少时间戳\", { line });\n }\n records.push(record);\n } catch {\n logger.warn(\"跳过无效的日志行\", { line });\n }\n }\n\n // 按时间戳倒序排列(最新的在前)\n records.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));\n\n return records;\n } catch (error) {\n logger.error(\"读取日志文件失败\", { error });\n throw new Error(\"无法读取工具调用日志文件\");\n }\n }\n\n /**\n * 过滤工具调用记录\n */\n private filterRecords(\n records: ToolCallRecord[],\n query: ToolCallQuery\n ): ToolCallRecord[] {\n let filtered = [...records];\n\n // 按工具名称过滤\n if (query.toolName) {\n filtered = filtered.filter((record) =>\n record.toolName\n .toLowerCase()\n .includes(query.toolName?.toLowerCase() ?? \"\")\n );\n }\n\n // 按服务器名称过滤\n if (query.serverName) {\n filtered = filtered.filter((record) =>\n record.serverName\n ?.toLowerCase()\n .includes(query.serverName?.toLowerCase() ?? \"\")\n );\n }\n\n // 按成功状态过滤\n if (query.success !== undefined) {\n filtered = filtered.filter((record) => record.success === query.success);\n }\n\n // 按时间范围过滤\n if (query.startDate || query.endDate) {\n const startTime = query.startDate\n ? new Date(query.startDate).getTime()\n : 0;\n const endTime = query.endDate\n ? new Date(query.endDate).getTime()\n : Date.now();\n\n filtered = filtered.filter((record) => {\n const recordTime = record.timestamp || 0;\n return recordTime >= startTime && recordTime <= endTime;\n });\n }\n\n return filtered;\n }\n\n /**\n * 获取工具调用日志\n */\n async getToolCallLogs(query: ToolCallQuery = {}): Promise<{\n records: ToolCallRecord[];\n total: number;\n hasMore: boolean;\n }> {\n this.checkLogFile();\n\n const records = this.parseLogFile();\n const filtered = this.filterRecords(records, query);\n const total = filtered.length;\n\n // 分页处理\n const limit = Math.min(\n query.limit || 50,\n 1000 // 最大限制 1000\n );\n const offset = query.offset || 0;\n const paginated = filtered.slice(offset, offset + limit);\n const hasMore = offset + limit < total;\n\n logger.info(\"返回工具调用日志\", {\n count: paginated.length,\n total,\n });\n\n return {\n records: paginated,\n total,\n hasMore,\n };\n }\n}\n","/**\n * 路径处理工具\n */\n\nimport { tmpdir } from \"node:os\";\n\n/**\n * 路径工具类\n */\nexport class PathUtils {\n /**\n * 获取配置目录路径\n */\n static getConfigDir(): string {\n return process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n }\n\n /**\n * 获取临时目录路径\n */\n static getTempDir(): string {\n return process.env.TMPDIR || process.env.TEMP || tmpdir();\n }\n}\n","/**\n * 统一的 MCP 消息处理器\n * 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call、resources/list、prompts/list 等\n * 这是阶段一重构的核心组件,用于消除双层代理架构\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n JSONRPC_VERSION,\n MCP_METHODS,\n MCP_PROTOCOL_VERSIONS,\n MCP_SERVER_INFO,\n MCP_SUPPORTED_PROTOCOL_VERSIONS,\n} from \"@/constants/index.js\";\nimport type { EnhancedToolInfo, MCPServiceManager } from \"@/lib/mcp\";\nimport { validateToolCallParams } from \"@/lib/mcp\";\nimport type { MCPMessage, MCPResponse } from \"@/types/mcp.js\";\nimport type {\n ClientCapabilities,\n InitializedNotification,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\n// 初始化参数接口\ninterface InitializeParams {\n protocolVersion: string;\n capabilities: ClientCapabilities;\n clientInfo: {\n name: string;\n version: string;\n };\n}\n\n// 工具调用参数接口\ninterface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n// MCP 资源接口\ninterface MCPResource {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n}\n\n// MCP 提示接口\ninterface MCPPrompt {\n name: string;\n description?: string;\n arguments?: Array<{\n name: string;\n description?: string;\n required?: boolean;\n }>;\n}\n\nexport class MCPMessageHandler {\n private logger: Logger;\n private serviceManager: MCPServiceManager;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n /**\n * 处理 MCP 消息的统一入口\n * @param message MCP 消息\n * @returns MCP 响应(对于通知消息返回 null)\n */\n async handleMessage(message: MCPMessage): Promise<MCPResponse | null> {\n this.logger.debug(`处理 MCP 消息: ${message.method}`, message);\n\n try {\n // 检查是否为通知消息(没有 id 字段)\n const isNotification = message.id === undefined;\n\n switch (message.method) {\n case MCP_METHODS.INITIALIZE:\n return await this.handleInitialize(\n message.params as InitializeParams,\n message.id\n );\n case MCP_METHODS.INITIALIZED:\n return await this.handleInitializedNotification(\n message.params as InitializedNotification[\"params\"]\n );\n case MCP_METHODS.TOOLS_LIST:\n return await this.handleToolsList(message.id);\n case MCP_METHODS.TOOLS_CALL:\n return await this.handleToolCall(\n message.params as ToolCallParams,\n message.id\n );\n case MCP_METHODS.RESOURCES_LIST:\n return await this.handleResourcesList(message.id);\n case MCP_METHODS.PROMPTS_LIST:\n return await this.handlePromptsList(message.id);\n case MCP_METHODS.PING:\n return await this.handlePing(message.id);\n default:\n if (isNotification) {\n // 对于未知的通知消息,记录警告但不抛出错误\n this.logger.warn(`收到未知的通知消息: ${message.method}`, message);\n return null;\n }\n throw new Error(`未知的方法: ${message.method}`);\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n // 通知消息不需要错误响应\n if (message.id === undefined) {\n return null;\n }\n return this.createErrorResponse(error as Error, message.id);\n }\n }\n\n /**\n * 处理 initialize 请求\n * @param params 初始化参数\n * @param id 消息ID\n * @returns 初始化响应\n */\n private async handleInitialize(\n params: InitializeParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 initialize 请求\", params);\n\n // 支持多个协议版本,优先使用客户端请求的版本\n const clientVersion = params.protocolVersion;\n const responseVersion = MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(\n clientVersion as (typeof MCP_SUPPORTED_PROTOCOL_VERSIONS)[number]\n )\n ? clientVersion\n : MCP_PROTOCOL_VERSIONS.DEFAULT;\n\n this.logger.debug(\n `协议版本协商: 客户端=${clientVersion}, 服务器响应=${responseVersion}`\n );\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n serverInfo: {\n name: MCP_SERVER_INFO.NAME,\n version: MCP_SERVER_INFO.VERSION,\n },\n capabilities: {\n tools: {},\n logging: {},\n },\n protocolVersion: responseVersion,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 notifications/initialized 通知\n * @param params 通知参数\n * @returns null(通知消息不需要响应)\n */\n private async handleInitializedNotification(\n params?: InitializedNotification[\"params\"]\n ): Promise<null> {\n this.logger.debug(\"收到 initialized 通知,客户端初始化完成\", params);\n\n // 可以在这里执行一些初始化完成后的逻辑\n // 例如:记录客户端连接状态、触发事件等\n\n return null;\n }\n\n /**\n * 处理 tools/list 请求\n * @param id 消息ID\n * @returns 工具列表响应\n */\n private async handleToolsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 tools/list 请求\");\n\n try {\n const tools: EnhancedToolInfo[] = this.serviceManager.getAllTools();\n\n // 转换为 MCP 标准格式\n const mcpTools = tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n tools: mcpTools,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(\"获取工具列表失败\", error);\n throw error;\n }\n }\n\n /**\n * 处理 tools/call 请求\n * @param params 工具调用参数\n * @param id 消息ID\n * @returns 工具调用响应\n */\n private async handleToolCall(\n params: ToolCallParams,\n id?: string | number\n ): Promise<MCPResponse> {\n try {\n // 参数校验\n const validatedParams = validateToolCallParams(params);\n\n const result = await this.serviceManager.callTool(\n validatedParams.name,\n validatedParams.arguments || {}\n );\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n content: result.content,\n isError: result.isError || false,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(`工具调用失败: ${params.name}`, error);\n throw error;\n }\n }\n\n /**\n * 处理 ping 请求\n * @param id 消息ID\n * @returns ping 响应\n */\n private async handlePing(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 ping 请求\");\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n status: \"ok\",\n timestamp: new Date().toISOString(),\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 resources/list 请求\n * @param id 消息ID\n * @returns 资源列表响应\n */\n private async handleResourcesList(\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 resources/list 请求\");\n\n // 目前返回空的资源列表\n // 如果将来需要提供资源功能,可以在这里扩展\n const resources: MCPResource[] = [];\n\n this.logger.debug(`返回 ${resources.length} 个资源`);\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n resources: resources,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 prompts/list 请求\n * @param id 消息ID\n * @returns 提示列表响应\n */\n private async handlePromptsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 prompts/list 请求\");\n\n // 目前返回空的提示列表\n // 如果将来需要提供提示模板功能,可以在这里扩展\n const prompts: MCPPrompt[] = [];\n\n this.logger.debug(`返回 ${prompts.length} 个提示模板`);\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n prompts: prompts,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 创建错误响应\n * @param error 错误对象\n * @param id 消息ID\n * @returns 错误响应\n */\n private createErrorResponse(error: Error, id?: string | number): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: JSONRPC_VERSION,\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 获取服务管理器实例\n * @returns MCPServiceManager 实例\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n}\n","/**\n * 向后兼容的 MCPService 类\n * 包装 @xiaozhi-client/mcp-core 的 MCPConnection,使用 EventBus 发射事件\n */\n\nimport { MCP_SERVICE_EVENTS } from \"@/constants/index.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { MCPConnection } from \"@xiaozhi-client/mcp-core\";\nimport type { InternalMCPServiceConfig } from \"./types.js\";\n\n/**\n * MCP 服务类(向后兼容包装器)\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPService {\n private connection: MCPConnection;\n private eventBus = getEventBus();\n\n constructor(config: InternalMCPServiceConfig) {\n // 从配置中解构 name,其余作为连接配置\n const {\n name,\n ...connectionConfig\n }: { name: string } & Omit<InternalMCPServiceConfig, \"name\"> = config;\n\n // 创建回调适配器,将 mcp-core 的回调转换为 EventBus 事件\n const callbacks = {\n onConnected: (data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }) => {\n this.eventBus.emitEvent(MCP_SERVICE_EVENTS.CONNECTED, data);\n },\n onDisconnected: (data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }) => {\n this.eventBus.emitEvent(MCP_SERVICE_EVENTS.DISCONNECTED, data);\n },\n onConnectionFailed: (data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }) => {\n this.eventBus.emitEvent(MCP_SERVICE_EVENTS.CONNECTION_FAILED, data);\n },\n };\n\n // 适配新 API:将 name 从 config 中分离\n this.connection = new MCPConnection(name, connectionConfig, callbacks);\n }\n\n /**\n * 连接到 MCP 服务\n */\n async connect(): Promise<void> {\n return this.connection.connect();\n }\n\n /**\n * 断开连接\n */\n async disconnect(): Promise<void> {\n return this.connection.disconnect();\n }\n\n /**\n * 调用工具\n */\n async callTool(name: string, arguments_: Record<string, unknown>) {\n return this.connection.callTool(name, arguments_);\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return this.connection.getTools();\n }\n\n /**\n * 获取服务配置\n */\n getConfig() {\n return this.connection.getConfig();\n }\n\n /**\n * 获取服务状态\n */\n getStatus() {\n return this.connection.getStatus();\n }\n\n /**\n * 检查是否已连接\n */\n isConnected() {\n return this.connection.isConnected();\n }\n}\n","/**\n * MCP 工具函数模块\n *\n * 提供 MCP 服务配置和工具调用的工具函数:\n * - 传输类型推断(基于 URL 或配置)\n * - 工具调用参数验证\n */\n\nimport { TypeFieldNormalizer } from \"@xiaozhi-client/mcp-core\";\nimport { MCPTransportType, ToolCallError, ToolCallErrorCode } from \"./types.js\";\nimport type {\n MCPServiceConfig,\n ToolCallParams,\n ToolCallValidationOptions,\n ValidatedToolCallParams,\n} from \"./types.js\";\n\n/**\n * 根据 URL 路径推断传输类型\n * 基于路径末尾推断,支持包含多个 / 的复杂路径\n *\n * @param url - 要推断的 URL\n * @param options - 可选配置项\n * @returns 推断出的传输类型\n */\nexport function inferTransportTypeFromUrl(\n url: string,\n options?: {\n serviceName?: string;\n }\n): MCPTransportType {\n try {\n const parsedUrl = new URL(url);\n const pathname = parsedUrl.pathname;\n\n // 检查路径末尾\n if (pathname.endsWith(\"/sse\")) {\n return MCPTransportType.SSE;\n }\n if (pathname.endsWith(\"/mcp\")) {\n return MCPTransportType.HTTP;\n }\n\n // 默认类型 - 使用 console 输出\n if (options?.serviceName) {\n console.info(\n `[MCP-${options.serviceName}] URL 路径 ${pathname} 不匹配特定规则,默认推断为 http 类型`\n );\n }\n return MCPTransportType.HTTP;\n } catch (error) {\n if (options?.serviceName) {\n console.warn(\n `[MCP-${options.serviceName}] URL 解析失败,默认推断为 http 类型`,\n error\n );\n }\n return MCPTransportType.HTTP;\n }\n}\n\n/**\n * 完整的配置类型推断(包括 command 字段)\n *\n * @param config - MCP 服务配置\n * @param serviceName - 服务名称(用于错误信息)\n * @returns 完整的配置对象,包含推断出的类型\n */\nexport function inferTransportTypeFromConfig(\n config: MCPServiceConfig,\n serviceName: string\n): MCPServiceConfig {\n // 如果已显式指定类型,先标准化然后返回\n if (config.type) {\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(config);\n return normalizedConfig as MCPServiceConfig;\n }\n\n // 基于 command 字段推断\n if (config.command) {\n return {\n ...config,\n type: MCPTransportType.STDIO,\n };\n }\n\n // 基于 URL 字段推断(排除 null 和 undefined)\n if (config.url !== undefined && config.url !== null) {\n const inferredType = inferTransportTypeFromUrl(config.url, {\n serviceName,\n });\n return {\n ...config,\n type: inferredType,\n };\n }\n\n throw new Error(\n `无法为服务 ${serviceName} 推断传输类型。请显式指定 type 字段,或提供 command/url 配置`\n );\n}\n\n// =========================\n// 参数校验工具函数\n// =========================\n\n/**\n * 验证工具调用参数\n * 对传入的参数进行完整性和格式验证\n *\n * @param params 待验证的参数\n * @param options 验证选项\n * @returns 验证后的参数\n * @throws ToolCallError 验证失败时抛出\n */\nexport function validateToolCallParams(\n params: unknown,\n options?: ToolCallValidationOptions\n): ValidatedToolCallParams {\n const opts = {\n validateName: true,\n validateArguments: true,\n allowEmptyArguments: true,\n ...options,\n };\n\n // 1. 验证参数必须是对象\n if (!params || typeof params !== \"object\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求参数必须是对象\"\n );\n }\n\n const paramsObj = params as Record<string, unknown>;\n\n // 2. 验证工具名称\n if (opts.validateName) {\n if (!paramsObj.name || typeof paramsObj.name !== \"string\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具名称必须是非空字符串\"\n );\n }\n }\n\n // 3. 验证工具参数格式\n if (\n opts.validateArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n if (\n typeof paramsObj.arguments !== \"object\" ||\n Array.isArray(paramsObj.arguments)\n ) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数必须是对象\"\n );\n }\n }\n\n // 4. 验证是否允许空参数\n if (\n !opts.allowEmptyArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n const argsObj = paramsObj.arguments as Record<string, unknown>;\n if (Object.keys(argsObj).length === 0) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数不能为空\"\n );\n }\n }\n\n // 5. 执行自定义验证\n if (opts.customValidator) {\n const error = opts.customValidator(paramsObj as unknown as ToolCallParams);\n if (error) {\n throw new ToolCallError(ToolCallErrorCode.INVALID_PARAMS, error);\n }\n }\n\n return {\n name: paramsObj.name as string,\n arguments: paramsObj.arguments as Record<string, unknown>,\n };\n}\n","/**\n * MCP 缓存管理器\n * 负责 MCP 服务工具列表的缓存写入功能\n * 专注于缓存文件管理和数据写入的基础设施\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n CACHE_FILE_CONFIG,\n CACHE_TIMEOUTS,\n MCP_CACHE_VERSIONS,\n TOOL_NAME_SEPARATORS,\n} from \"@/constants/index.js\";\nimport type { MCPServiceConfig } from \"@/lib/mcp/types\";\nimport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n ToolCallResult,\n} from \"@/types/index.js\";\nimport { generateCacheKey, shouldCleanupCache } from \"@/types/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport dayjs from \"dayjs\";\n\n// 缓存条目接口\nexport interface MCPToolsCacheEntry {\n tools: Tool[]; // 工具列表\n lastUpdated: string; // 最后更新时间 (YYYY-MM-DD HH:mm:ss)\n serverConfig: MCPServiceConfig; // 服务配置快照\n configHash: string; // 配置哈希值,用于快速变更检测\n version: string; // 缓存条目版本\n}\n\n// 缓存文件接口\nexport interface MCPToolsCache {\n version: string; // 缓存文件格式版本 \"1.0.0\"\n mcpServers: Record<string, MCPToolsCacheEntry>;\n metadata: {\n lastGlobalUpdate: string; // 全局最后更新时间 (YYYY-MM-DD HH:mm:ss)\n totalWrites: number; // 总写入次数\n createdAt: string; // 缓存文件创建时间 (YYYY-MM-DD HH:mm:ss)\n };\n}\n\n// 缓存统计接口\nexport interface CacheStats {\n totalWrites: number;\n lastUpdate: string;\n serverCount: number;\n cacheFileSize: number;\n}\n\n// 重新导出相关类型\nexport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n} from \"@/types/index.js\";\n\nexport class MCPCacheManager {\n private cachePath: string;\n private logger: Logger;\n private readonly CACHE_VERSION = MCP_CACHE_VERSIONS.CACHE_VERSION;\n private readonly CACHE_ENTRY_VERSION = MCP_CACHE_VERSIONS.CACHE_ENTRY_VERSION;\n private cleanupInterval?: NodeJS.Timeout;\n private readonly CLEANUP_INTERVAL = CACHE_TIMEOUTS.CLEANUP_INTERVAL;\n\n constructor(customCachePath?: string) {\n this.logger = logger;\n this.cachePath = customCachePath || this.getCacheFilePath();\n this.startCleanupTimer();\n }\n\n /**\n * 格式化时间戳为 YYYY-MM-DD HH:mm:ss 格式\n */\n private formatTimestamp(): string {\n return dayjs().format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n /**\n * 获取缓存文件路径\n * 与 xiaozhi.config.json 同级目录\n */\n private getCacheFilePath(): string {\n try {\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, CACHE_FILE_CONFIG.FILENAME);\n } catch (error) {\n // 在某些测试环境中 process.cwd() 可能不可用,使用默认路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || \"/tmp\";\n return resolve(configDir, CACHE_FILE_CONFIG.FILENAME);\n }\n }\n\n /**\n * 确保缓存文件存在,如不存在则创建\n */\n async ensureCacheFile(): Promise<void> {\n try {\n if (!existsSync(this.cachePath)) {\n // 确保缓存文件的目录存在\n const cacheDir = dirname(this.cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n this.logger.debug(`[CacheManager] 已创建缓存目录: ${cacheDir}`);\n }\n\n this.logger.debug(\"[CacheManager] 缓存文件不存在,创建初始缓存文件\");\n const initialCache = await this.createInitialCache();\n await this.saveCache(initialCache);\n this.logger.info(`[CacheManager] 已创建缓存文件: ${this.cachePath}`);\n }\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 创建缓存文件失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 不抛出异常,确保不影响主流程\n }\n }\n\n /**\n * 创建初始缓存结构\n */\n private async createInitialCache(): Promise<MCPToolsCache> {\n const now = this.formatTimestamp();\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: now,\n totalWrites: 0,\n createdAt: now,\n },\n };\n }\n\n /**\n * 写入缓存条目\n * @param serverName 服务名称\n * @param tools 工具列表\n * @param config 服务配置\n */\n async writeCacheEntry(\n serverName: string,\n tools: Tool[],\n config: MCPServiceConfig\n ): Promise<void> {\n try {\n this.logger.debug(`[CacheManager] 开始写入缓存: ${serverName}`);\n\n // 确保缓存文件存在\n await this.ensureCacheFile();\n\n // 加载现有缓存\n const cache = await this.loadExistingCache();\n\n // 生成配置哈希\n const configHash = this.generateConfigHash(config);\n\n // 创建缓存条目\n const cacheEntry: MCPToolsCacheEntry = {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n })),\n lastUpdated: this.formatTimestamp(),\n serverConfig: { ...config }, // 深拷贝配置\n configHash,\n version: this.CACHE_ENTRY_VERSION,\n };\n\n // 更新缓存\n cache.mcpServers[serverName] = cacheEntry;\n cache.metadata.lastGlobalUpdate = this.formatTimestamp();\n cache.metadata.totalWrites += 1;\n\n // 保存缓存\n await this.saveCache(cache);\n\n this.logger.debug(\n `[CacheManager] 缓存写入成功: ${serverName}, 工具数量: ${tools.length}`\n );\n } catch (error) {\n // 记录错误但不抛出异常,确保不影响主流程\n this.logger.warn(\n `[CacheManager] 缓存写入失败: ${serverName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 加载现有缓存\n */\n public async loadExistingCache(): Promise<MCPToolsCache> {\n try {\n if (!existsSync(this.cachePath)) {\n return await this.createInitialCache();\n }\n\n const cacheData = readFileSync(this.cachePath, \"utf8\");\n const cache: unknown = JSON.parse(cacheData);\n\n // 验证缓存结构\n if (!this.validateCacheStructure(cache)) {\n this.logger.warn(\"[CacheManager] 缓存文件结构无效,重新创建\");\n return await this.createInitialCache();\n }\n\n return cache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载缓存失败,创建新缓存: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return await this.createInitialCache();\n }\n }\n\n /**\n * 保存缓存到文件(原子写入)\n */\n public async saveCache(cache: MCPToolsCache): Promise<void> {\n const cacheContent = JSON.stringify(cache, null, 2);\n await this.atomicWrite(this.cachePath, cacheContent);\n }\n\n /**\n * 原子写入文件\n * 使用临时文件确保写入操作的原子性\n */\n private async atomicWrite(filePath: string, data: string): Promise<void> {\n const tempPath = `${filePath}.tmp`;\n try {\n // 写入临时文件\n writeFileSync(tempPath, data, \"utf8\");\n // 原子性重命名\n renameSync(tempPath, filePath);\n } catch (error) {\n // 清理临时文件\n try {\n if (existsSync(tempPath)) {\n writeFileSync(tempPath, \"\", \"utf8\"); // 清空后删除\n }\n } catch {\n // 忽略清理错误\n }\n throw error;\n }\n }\n\n /**\n * 生成配置哈希\n * 用于快速检测配置变更\n */\n private generateConfigHash(config: MCPServiceConfig): string {\n try {\n return createHash(\"sha256\").update(JSON.stringify(config)).digest(\"hex\");\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 生成配置哈希失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return \"\";\n }\n }\n\n /**\n * 验证缓存数据结构\n * 使用类型谓词确保类型安全\n */\n private validateCacheStructure(cache: unknown): cache is MCPToolsCache {\n try {\n if (!cache || typeof cache !== \"object\") {\n return false;\n }\n\n const cacheObj = cache as Record<string, unknown>;\n const metadata = cacheObj.metadata as Record<string, unknown>;\n\n return (\n typeof cacheObj.version === \"string\" &&\n typeof cacheObj.mcpServers === \"object\" &&\n cacheObj.mcpServers !== null &&\n cacheObj.metadata !== null &&\n cacheObj.metadata !== undefined &&\n typeof metadata === \"object\" &&\n metadata !== null &&\n typeof metadata.lastGlobalUpdate === \"string\" &&\n typeof metadata.totalWrites === \"number\" &&\n typeof metadata.createdAt === \"string\"\n );\n } catch {\n return false;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n async getStats(): Promise<CacheStats | null> {\n try {\n const cache = await this.loadExistingCache();\n const stats: CacheStats = {\n totalWrites: cache.metadata.totalWrites,\n lastUpdate: cache.metadata.lastGlobalUpdate,\n serverCount: Object.keys(cache.mcpServers).length,\n cacheFileSize: existsSync(this.cachePath)\n ? readFileSync(this.cachePath, \"utf8\").length\n : 0,\n };\n return stats;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 获取缓存文件路径(用于测试和调试)\n */\n getFilePath(): string {\n return this.cachePath;\n }\n\n /**\n * 获取所有缓存中的工具\n * 返回所有服务中的所有工具列表\n */\n async getAllCachedTools(): Promise<Tool[]> {\n try {\n const cache = await this.loadExistingCache();\n const allTools: Tool[] = [];\n\n // 遍历所有服务,收集所有工具\n for (const [serverName, cacheEntry] of Object.entries(cache.mcpServers)) {\n for (const tool of cacheEntry.tools) {\n // 为每个工具添加服务名称信息\n allTools.push({\n ...tool,\n name: `${serverName}${TOOL_NAME_SEPARATORS.SERVICE_TOOL_SEPARATOR}${tool.name}`, // 格式: serviceName__toolName\n });\n }\n }\n\n this.logger.debug(\n `[CacheManager] 获取到所有缓存工具,共 ${allTools.length} 个`\n );\n return allTools;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取所有缓存工具失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return [];\n }\n }\n\n // ==================== CustomMCP 结果缓存管理方法 ====================\n\n /**\n * 写入 CustomMCP 工具执行结果缓存\n */\n async writeCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>,\n result: ToolCallResult,\n status: TaskStatus = \"completed\",\n taskId?: string,\n ttl = 300000\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n // 创建缓存条目\n const cacheEntry: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl,\n status,\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n // 确保customMCPResults存在\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheEntry;\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 写入CustomMCP结果缓存: ${toolName}, 状态: ${status}`\n );\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 写入CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 读取 CustomMCP 工具执行结果缓存\n */\n async readCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<EnhancedToolResultCache | null> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n\n // 检查是否过期\n const now = Date.now();\n const cachedTime = new Date(cacheEntry.timestamp).getTime();\n if (now - cachedTime > cacheEntry.ttl) {\n this.logger.debug(`[CacheManager] 缓存已过期: ${toolName}`);\n return null;\n }\n\n return cacheEntry;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 读取CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 更新 CustomMCP 缓存状态\n */\n async updateCustomMCPStatus(\n toolName: string,\n arguments_: Record<string, unknown>,\n newStatus: TaskStatus,\n result?: ToolCallResult,\n error?: string\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n const oldStatus = cacheEntry.status;\n\n // 更新状态\n cacheEntry.status = newStatus;\n cacheEntry.timestamp = new Date().toISOString();\n\n // 更新结果或错误信息\n if (result) {\n cacheEntry.result = result;\n }\n\n if (error && newStatus === \"failed\") {\n cacheEntry.result = {\n content: [{ type: \"text\", text: `任务失败: ${error}` }],\n };\n cacheEntry.consumed = true; // 失败的任务自动标记为已消费\n }\n\n // 特殊状态处理\n if (newStatus === \"completed\") {\n cacheEntry.consumed = false; // 完成的任务初始状态为未消费\n }\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 更新缓存状态: ${toolName} ${oldStatus} -> ${newStatus}`\n );\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 更新CustomMCP缓存状态失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 标记 CustomMCP 缓存为已消费\n */\n async markCustomMCPAsConsumed(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry.consumed) {\n return true;\n }\n\n cacheEntry.consumed = true;\n cacheEntry.timestamp = new Date().toISOString();\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 标记缓存为已消费: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 标记CustomMCP缓存为已消费失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 删除 CustomMCP 缓存条目\n */\n async deleteCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n delete cache.customMCPResults[cacheKey];\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 删除缓存条目: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 删除CustomMCP缓存条目失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 批量清理 CustomMCP 缓存\n */\n async cleanupCustomMCPResults(): Promise<{ cleaned: number; total: number }> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (shouldCleanupCache(cacheEntry)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n }\n }\n\n if (cleanedCount > 0) {\n await this.saveExtendedCache(cache);\n this.logger.info(\n `[CacheManager] 清理CustomMCP缓存: ${cleanedCount}/${entries.length}`\n );\n }\n\n return { cleaned: cleanedCount, total: entries.length };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 清理CustomMCP缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return { cleaned: 0, total: 0 };\n }\n }\n\n /**\n * 获取 CustomMCP 缓存统计信息\n */\n async getCustomMCPStatistics(): Promise<CacheStatistics> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n\n const entries = Object.values(cache.customMCPResults);\n const totalEntries = entries.length;\n const pendingTasks = entries.filter((e) => e.status === \"pending\").length;\n const completedTasks = entries.filter(\n (e) => e.status === \"completed\"\n ).length;\n const failedTasks = entries.filter((e) => e.status === \"failed\").length;\n const consumedEntries = entries.filter((e) => e.consumed).length;\n\n // 计算缓存命中率\n const cacheHitRate =\n completedTasks > 0 ? (consumedEntries / completedTasks) * 100 : 0;\n\n // 估算内存使用\n const memoryUsage = JSON.stringify(cache.customMCPResults).length;\n\n return {\n totalEntries,\n pendingTasks,\n completedTasks,\n failedTasks,\n consumedEntries,\n cacheHitRate,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage,\n };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取CustomMCP缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n }\n\n /**\n * 加载扩展缓存(包含 CustomMCP 结果)\n */\n async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cache = await this.loadExistingCache();\n return cache as ExtendedMCPToolsCache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载扩展缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: this.formatTimestamp(),\n totalWrites: 0,\n createdAt: this.formatTimestamp(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 保存扩展缓存(包含 CustomMCP 结果)\n */\n async saveExtendedCache(cache: ExtendedMCPToolsCache): Promise<void> {\n await this.saveCache(cache);\n }\n\n /**\n * 启动清理定时器\n */\n private startCleanupTimer(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanupCustomMCPResults().catch((error) => {\n this.logger.warn(`[CacheManager] 自动清理失败: ${error}`);\n });\n }, this.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CacheManager] 启动清理定时器,间隔: ${this.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 停止清理定时器\n */\n public stopCleanupTimer(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n this.logger.debug(\"[CacheManager] 停止清理定时器\");\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.stopCleanupTimer();\n this.logger.debug(\"[CacheManager] 清理资源完成\");\n }\n}\n","/**\n * Hono Context 类型扩展\n * 为 Hono Context 添加项目特定的变量类型定义\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport type { EndpointHandler } from \"@/handlers/index.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { HandlerDependencies } from \"@/routes/types.js\";\nimport type { EndpointManager } from \"@xiaozhi-client/endpoint\";\nimport type { Context } from \"hono\";\nimport { Hono } from \"hono\";\n\n// 导出 API 响应类型供其他模块使用\nexport type {\n ApiErrorResponse,\n ApiPaginatedResponse,\n ApiSuccessResponse,\n PaginationInfo,\n ApiResponse,\n} from \"./api.response.js\";\n\n/**\n * WebServer 实例类型定义\n * 避免与 WebServer 实现类的循环引用\n * 使用类型断言的方式来定义接口\n */\nexport interface IWebServer {\n /**\n * 获取小智连接管理器实例\n * 在 endpointManagerMiddleware 中使用\n * WebServer 启动后始终返回有效的连接管理器实例\n * 如果在启动前调用,会抛出错误\n */\n getEndpointManager(): EndpointManager;\n\n /**\n * 获取 MCP 服务管理器实例\n * 在 mcpServiceManagerMiddleware 中使用\n * WebServer 启动后始终返回有效的服务管理器实例\n * 如果在启动前调用,会抛出错误\n */\n getMCPServiceManager(): MCPServiceManager;\n}\n\n/**\n * 扩展 Hono Context 的 Variables 类型\n * 定义了项目中所有通过中间件注入的变量\n */\nexport type AppContextVariables = {\n /**\n * Logger 实例\n * 由 loggerMiddleware 注入\n */\n logger: Logger;\n\n /**\n * MCP 服务管理器实例\n * 由 mcpServiceManagerMiddleware 注入\n */\n mcpServiceManager?: MCPServiceManager;\n\n /**\n * 路由处理器依赖\n * 由 RouteManager 注入\n */\n dependencies?: HandlerDependencies;\n\n /**\n * WebServer 实例引用\n * 用于获取运行时依赖\n */\n webServer?: IWebServer;\n\n /**\n * 小智连接管理器实例\n * 由 endpointManagerMiddleware 注入\n * WebServer 启动后始终可用的连接管理器实例\n * 可能为 null(初始化失败时)\n */\n endpointManager: EndpointManager | null;\n\n /**\n * 端点处理器实例\n * 由 endpointsMiddleware 注入\n */\n endpointHandler?: EndpointHandler | null;\n};\n\n/**\n * 扩展的 Hono Context 类型\n * 包含项目中所有自定义变量\n */\nexport type AppContext = {\n Variables: AppContextVariables;\n};\n\n/**\n * 创建类型化的 Hono 实例\n * 使用这个类型来创建新的 Hono 应用,确保 Context 类型安全\n */\nexport const createApp = (): Hono<AppContext> => {\n return new Hono<AppContext>();\n};\n\n/**\n * 从 Context 中获取 MCPServiceManager 的类型安全方法\n */\nexport const getMCPServiceManager = (\n c: Context<AppContext>\n): MCPServiceManager | undefined => {\n return c.get(\"mcpServiceManager\");\n};\n\n/**\n * 要求必须存在 MCPServiceManager 的类型安全方法\n */\nexport const requireMCPServiceManager = (\n c: Context<AppContext>\n): MCPServiceManager => {\n const serviceManager = c.get(\"mcpServiceManager\");\n\n if (!serviceManager) {\n throw new Error(\n \"MCPServiceManager 未初始化,请检查 mcpServiceManagerMiddleware 是否正确配置\"\n );\n }\n\n return serviceManager;\n};\n","/**\n * MCP 路由处理器\n * 处理符合 MCP Streamable HTTP 规范的单一 /mcp 端点\n * 支持 POST 请求(JSON-RPC 消息)\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n HTTP_CONTENT_TYPES,\n HTTP_ERROR_MESSAGES,\n HTTP_HEADERS,\n HTTP_STATUS_CODES,\n JSONRPC_VERSION,\n MCP_PROTOCOL_VERSIONS,\n MCP_SUPPORTED_PROTOCOL_VERSIONS,\n MESSAGE_SIZE_LIMITS,\n} from \"@/constants/index.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport { MCPMessageHandler } from \"@/lib/mcp\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { MCPMessage } from \"@/types/mcp.js\";\nimport type { Context } from \"hono\";\n\n/**\n * MCP 路由处理器配置接口\n */\ninterface MCPRouteHandlerConfig {\n maxMessageSize?: number;\n enableMetrics?: boolean;\n}\n\n/**\n * 连接统计信息\n */\ninterface ConnectionMetrics {\n totalMessages: number;\n errorCount: number;\n averageResponseTime: number;\n}\n\n/**\n * MCP 路由处理器\n * 实现符合 MCP Streamable HTTP 规范的单一端点处理(仅 POST 模式)\n */\nexport class MCPRouteHandler {\n private logger: Logger;\n private mcpMessageHandler: MCPMessageHandler | null = null;\n private config: {\n maxMessageSize: number;\n enableMetrics: boolean;\n };\n private metrics: ConnectionMetrics;\n\n constructor(config: MCPRouteHandlerConfig = {}) {\n this.logger = logger;\n this.config = {\n maxMessageSize: config.maxMessageSize ?? MESSAGE_SIZE_LIMITS.DEFAULT,\n enableMetrics: config.enableMetrics ?? true,\n };\n\n this.metrics = {\n totalMessages: 0,\n errorCount: 0,\n averageResponseTime: 0,\n };\n\n this.logger.debug(\"MCPRouteHandler 初始化完成\", {\n maxMessageSize: this.config.maxMessageSize,\n enableMetrics: this.config.enableMetrics,\n });\n }\n\n /**\n * 获取 MCP 服务管理器实例\n * 优先从 Context 获取,如果不存在则从 WebServer 获取\n */\n private getMCPServiceManager(c: Context): MCPServiceManager {\n // 首先尝试从 Context 获取\n const serviceManager = c.get(\"mcpServiceManager\");\n if (serviceManager) {\n return serviceManager;\n }\n\n // 如果 Context 中没有,则从 WebServer 获取\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new Error(\"WebServer 未在 Context 中找到,请检查中间件配置\");\n }\n\n const mcpServiceManager = webServer.getMCPServiceManager();\n this.logger.debug(\n \"MCPServiceManager 从 WebServer 获取(Context 中未找到)\"\n );\n\n return mcpServiceManager;\n }\n\n /**\n * 初始化 MCP 消息处理器\n */\n private async initializeMessageHandler(c: Context): Promise<void> {\n if (this.mcpMessageHandler) {\n return;\n }\n\n try {\n const serviceManager = this.getMCPServiceManager(c);\n this.mcpMessageHandler = new MCPMessageHandler(serviceManager);\n this.logger.debug(\"MCP 消息处理器初始化成功\");\n } catch (error) {\n this.logger.error(\"MCP 消息处理器初始化失败:\", error);\n this.metrics.errorCount++;\n throw error;\n }\n }\n\n /**\n * 处理 POST 请求(JSON-RPC 消息)\n * 符合 MCP Streamable HTTP 规范\n */\n async handlePost(c: Context<AppContext>): Promise<Response> {\n const startTime = Date.now();\n let messageId: string | number | null = null;\n\n try {\n this.logger.debug(\"处理 MCP POST 请求\");\n\n // 验证请求大小\n const contentLength = c.req.header(HTTP_HEADERS.CONTENT_LENGTH);\n if (\n contentLength &&\n Number.parseInt(contentLength) > this.config.maxMessageSize\n ) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `${HTTP_ERROR_MESSAGES.REQUEST_TOO_LARGE}: Maximum size is ${this.config.maxMessageSize} bytes`\n );\n }\n\n // 验证 Content-Type\n const contentType = c.req.header(HTTP_HEADERS.CONTENT_TYPE);\n if (!contentType?.includes(HTTP_CONTENT_TYPES.APPLICATION_JSON)) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `${HTTP_ERROR_MESSAGES.INVALID_REQUEST}: ${HTTP_ERROR_MESSAGES.INVALID_CONTENT_TYPE}`\n );\n }\n\n // 验证 MCP 协议版本头(可选)\n // 支持多种大小写格式的协议版本头\n const protocolVersion =\n c.req.header(\"mcp-protocol-version\") ||\n c.req.header(HTTP_HEADERS.MCP_PROTOCOL_VERSION) ||\n c.req.header(\"Mcp-Protocol-Version\");\n if (\n protocolVersion &&\n !MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(\n protocolVersion as (typeof MCP_SUPPORTED_PROTOCOL_VERSIONS)[number]\n )\n ) {\n this.logger.warn(\n `不支持的 MCP 协议版本: ${protocolVersion},支持的版本: ${MCP_SUPPORTED_PROTOCOL_VERSIONS.join(\n \", \"\n )}`\n );\n }\n\n // 解析请求体\n let message: MCPMessage;\n try {\n const rawBody = await c.req.text();\n if (rawBody.length > this.config.maxMessageSize) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `Message too large: Maximum size is ${this.config.maxMessageSize} bytes`,\n null\n );\n }\n message = JSON.parse(rawBody);\n messageId = message.id || null;\n } catch (error) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32700,\n HTTP_ERROR_MESSAGES.PARSE_ERROR\n );\n }\n\n // 验证 JSON-RPC 格式\n if (!this.validateMessage(message)) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `${HTTP_ERROR_MESSAGES.INVALID_REQUEST}: Message does not conform to JSON-RPC ${JSONRPC_VERSION}`,\n messageId\n );\n }\n\n // 初始化消息处理器\n await this.initializeMessageHandler(c);\n\n // 处理消息\n if (!this.mcpMessageHandler) {\n throw new Error(\"消息处理器初始化失败\");\n }\n const response = await this.mcpMessageHandler.handleMessage(message);\n\n // 更新统计信息\n this.metrics.totalMessages++;\n const responseTime = Date.now() - startTime;\n this.metrics.averageResponseTime =\n (this.metrics.averageResponseTime * (this.metrics.totalMessages - 1) +\n responseTime) /\n this.metrics.totalMessages;\n\n this.logger.debug(\"MCP POST 请求处理成功\", {\n method: message.method,\n messageId: messageId,\n responseTime: responseTime,\n isNotification: response === null,\n });\n\n // 对于通知消息,返回 204 No Content\n if (response === null) {\n return new Response(null, {\n status: HTTP_STATUS_CODES.NO_CONTENT,\n headers: {\n [HTTP_HEADERS.MCP_PROTOCOL_VERSION]: MCP_PROTOCOL_VERSIONS.DEFAULT,\n [HTTP_HEADERS.X_RESPONSE_TIME]: responseTime.toString(),\n },\n });\n }\n\n // 返回 JSON-RPC 响应\n return c.json(response, HTTP_STATUS_CODES.OK, {\n [HTTP_HEADERS.CONTENT_TYPE]: HTTP_CONTENT_TYPES.APPLICATION_JSON,\n [HTTP_HEADERS.MCP_PROTOCOL_VERSION]: MCP_PROTOCOL_VERSIONS.DEFAULT,\n [HTTP_HEADERS.X_RESPONSE_TIME]: responseTime.toString(),\n });\n } catch (error) {\n this.metrics.errorCount++;\n const responseTime = Date.now() - startTime;\n\n this.logger.error(\"处理 MCP POST 请求时出错:\", {\n error: error instanceof Error ? error.message : String(error),\n messageId: messageId,\n responseTime: responseTime,\n stack: error instanceof Error ? error.stack : undefined,\n });\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return this.createErrorResponse(\n -32603,\n `${HTTP_ERROR_MESSAGES.INTERNAL_ERROR}: ${errorMessage}`,\n messageId\n );\n }\n }\n\n /**\n * 验证 JSON-RPC 消息格式\n */\n private validateMessage(message: unknown): message is MCPMessage {\n if (!message || typeof message !== \"object\") {\n this.logger.debug(\"消息验证失败: 不是对象\");\n return false;\n }\n\n // 类型守卫:确保 message 是对象类型\n const msg = message as Record<string, unknown>;\n\n if (msg.jsonrpc !== JSONRPC_VERSION) {\n this.logger.debug(\"消息验证失败: jsonrpc 版本不正确\", {\n jsonrpc: msg.jsonrpc,\n });\n return false;\n }\n\n if (!msg.method || typeof msg.method !== \"string\") {\n this.logger.debug(\"消息验证失败: method 字段无效\", {\n method: msg.method,\n });\n return false;\n }\n\n // 验证 id 字段(如果存在)\n if (\n msg.id !== undefined &&\n typeof msg.id !== \"string\" &&\n typeof msg.id !== \"number\" &&\n msg.id !== null\n ) {\n this.logger.debug(\"消息验证失败: id 字段类型无效\", { id: msg.id });\n return false;\n }\n\n // 验证 params 字段(如果存在)\n if (msg.params !== undefined && typeof msg.params !== \"object\") {\n this.logger.debug(\"消息验证失败: params 字段类型无效\", {\n params: msg.params,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 创建错误响应\n */\n private createErrorResponse(\n code: number,\n message: string,\n id?: string | number | null\n ): Response {\n // 确保ID不为空,如果为空或未提供则生成默认ID\n const responseId = id ?? `error-${Date.now()}`;\n\n const errorResponse = {\n jsonrpc: JSONRPC_VERSION,\n error: {\n code,\n message,\n },\n id: responseId,\n };\n\n return new Response(JSON.stringify(errorResponse), {\n status: HTTP_STATUS_CODES.BAD_REQUEST,\n headers: {\n [HTTP_HEADERS.CONTENT_TYPE]: HTTP_CONTENT_TYPES.APPLICATION_JSON,\n [HTTP_HEADERS.MCP_PROTOCOL_VERSION]: MCP_PROTOCOL_VERSIONS.DEFAULT,\n },\n });\n }\n\n /**\n * 获取连接状态\n */\n getStatus() {\n return {\n isInitialized: this.mcpMessageHandler !== null,\n metrics: this.config.enableMetrics ? this.metrics : undefined,\n config: {\n maxMessageSize: this.config.maxMessageSize,\n },\n };\n }\n\n /**\n * 销毁处理器,清理所有资源\n */\n destroy(): void {\n this.logger.info(\"正在销毁 MCPRouteHandler\");\n\n // 清理消息处理器\n this.mcpMessageHandler = null;\n\n this.logger.info(\"MCPRouteHandler 销毁完成\");\n }\n}\n","/**\n * MCP服务错误类型定义\n *\n * 本模块提供了统一的错误处理框架,包括:\n * - 标准化的错误代码和分类\n * - 结构化的错误信息\n * - 可扩展的错误处理器\n * - 错误转换和格式化工具\n *\n * @module mcp-errors\n */\n\nimport { ErrorCategory } from \"./error-helper.js\";\n\n// 重新导出 ErrorCategory 以保持向后兼容性\nexport { ErrorCategory };\n\n/**\n * MCP错误代码枚举\n *\n * 定义了所有MCP服务相关的错误代码,用于错误分类和处理。\n * 错误代码按功能区域分组:配置、连接、操作、系统等。\n */\nexport enum MCPErrorCode {\n // 配置错误 - 服务配置相关的问题\n /** 服务已存在,尝试添加重复服务时使用 */\n SERVER_ALREADY_EXISTS = \"SERVER_ALREADY_EXISTS\",\n /** 服务未找到,操作不存在的服务时使用 */\n SERVER_NOT_FOUND = \"SERVER_NOT_FOUND\",\n /** 配置格式无效或内容不正确 */\n INVALID_CONFIG = \"INVALID_CONFIG\",\n /** 服务名称不符合规范 */\n INVALID_SERVICE_NAME = \"INVALID_SERVICE_NAME\",\n\n // 连接错误 - 网络连接和服务通信问题\n /** 无法建立到服务的连接 */\n CONNECTION_FAILED = \"CONNECTION_FAILED\",\n /** 连接超时 */\n CONNECTION_TIMEOUT = \"CONNECTION_TIMEOUT\",\n /** 服务暂时不可用 */\n SERVICE_UNAVAILABLE = \"SERVICE_UNAVAILABLE\",\n\n // 操作错误 - 服务操作过程中的问题\n /** 一般操作失败 */\n OPERATION_FAILED = \"OPERATION_FAILED\",\n /** 服务添加操作失败 */\n ADD_FAILED = \"ADD_FAILED\",\n /** 服务移除操作失败 */\n REMOVE_FAILED = \"REMOVE_FAILED\",\n /** 工具同步操作失败 */\n SYNC_FAILED = \"SYNC_FAILED\",\n\n // 系统错误 - 内部系统问题\n /** 内部系统错误 */\n INTERNAL_ERROR = \"INTERNAL_ERROR\",\n /** 配置更新操作失败 */\n CONFIG_UPDATE_FAILED = \"CONFIG_UPDATE_FAILED\",\n\n // 工具同步错误 - 工具管理相关错误\n /** 工具同步失败 */\n TOOL_SYNC_FAILED = \"TOOL_SYNC_FAILED\",\n /** 工具验证失败 */\n TOOL_VALIDATION_FAILED = \"TOOL_VALIDATION_FAILED\",\n /** 工具未找到 */\n TOOL_NOT_FOUND = \"TOOL_NOT_FOUND\",\n}\n\n/**\n * MCP错误严重级别\n */\nexport enum ErrorSeverity {\n LOW = \"low\", // 轻微错误,不影响主要功能\n MEDIUM = \"medium\", // 中等错误,影响部分功能\n HIGH = \"high\", // 严重错误,影响核心功能\n CRITICAL = \"critical\", // 致命错误,系统无法继续运行\n}\n\n/**\n * 错误详情接口\n */\nexport interface ErrorDetails {\n serverName?: string;\n config?: unknown;\n tools?: string[];\n timestamp: string;\n severity: ErrorSeverity;\n category: ErrorCategory;\n stack?: string;\n context?: Record<string, unknown>;\n operation?: string;\n errors?: string[];\n}\n\n/**\n * 标准化的MCP错误类\n */\nexport class MCPError extends Error {\n public readonly code: MCPErrorCode;\n public readonly severity: ErrorSeverity;\n public readonly category: ErrorCategory;\n public readonly details: ErrorDetails;\n public readonly timestamp: string;\n\n constructor(\n code: MCPErrorCode,\n message: string,\n severity: ErrorSeverity = ErrorSeverity.MEDIUM,\n category: ErrorCategory = ErrorCategory.SYSTEM,\n details: Partial<ErrorDetails> = {}\n ) {\n super(message);\n this.name = \"MCPError\";\n this.code = code;\n this.severity = severity;\n this.category = category;\n this.timestamp = new Date().toISOString();\n\n // 合并详情信息\n this.details = {\n ...details,\n timestamp: this.timestamp,\n severity: this.severity,\n category: this.category,\n stack: this.stack,\n };\n\n // 保持堆栈跟踪\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, MCPError);\n }\n }\n\n /**\n * 转换为JSON格式\n */\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n severity: this.severity,\n category: this.category,\n details: this.details,\n timestamp: this.timestamp,\n };\n }\n\n /**\n * 创建配置错误\n */\n static configError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.MEDIUM,\n ErrorCategory.CONFIGURATION,\n details\n );\n }\n\n /**\n * 创建连接错误\n */\n static connectionError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.HIGH,\n ErrorCategory.CONNECTION,\n details\n );\n }\n\n /**\n * 创建操作错误\n */\n static operationError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.MEDIUM,\n ErrorCategory.OPERATION,\n details\n );\n }\n\n /**\n * 创建系统错误\n */\n static systemError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.HIGH,\n ErrorCategory.SYSTEM,\n details\n );\n }\n\n /**\n * 创建验证错误\n */\n static validationError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.LOW,\n ErrorCategory.VALIDATION,\n details\n );\n }\n\n /**\n * 从普通错误创建MCPError\n */\n static fromError(\n error: Error,\n defaultCode: MCPErrorCode = MCPErrorCode.INTERNAL_ERROR,\n category: ErrorCategory = ErrorCategory.SYSTEM\n ): MCPError {\n return new MCPError(\n defaultCode,\n error.message,\n ErrorSeverity.MEDIUM,\n category,\n {\n stack: error.stack,\n context: { originalError: error.name },\n }\n );\n }\n}\n\n/**\n * 错误处理器接口\n */\nexport interface ErrorHandler {\n canHandle(error: Error): boolean;\n handle(error: Error, context?: Record<string, unknown>): MCPError | null;\n}\n\n/**\n * 默认错误处理器\n */\nexport class DefaultErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return !(error instanceof MCPError);\n }\n\n handle(error: Error, context?: Record<string, unknown>): MCPError {\n return MCPError.fromError(\n error,\n MCPErrorCode.INTERNAL_ERROR,\n ErrorCategory.SYSTEM\n );\n }\n}\n\n/**\n * 配置错误处理器\n */\nexport class ConfigErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return (\n error.message.includes(\"配置\") ||\n error.message.includes(\"config\") ||\n error.message.includes(\"JSON\") ||\n error.message.includes(\"解析\")\n );\n }\n\n handle(error: Error, context?: Record<string, unknown>): MCPError {\n return MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n `配置错误: ${error.message}`,\n { context }\n );\n }\n}\n\n/**\n * 连接错误处理器\n */\nexport class ConnectionErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return (\n error.message.includes(\"连接\") ||\n error.message.includes(\"connection\") ||\n error.message.includes(\"timeout\") ||\n error.message.includes(\"ECONNREFUSED\") ||\n error.message.includes(\"ENOTFOUND\")\n );\n }\n\n handle(error: Error, context?: Record<string, unknown>): MCPError {\n return MCPError.connectionError(\n MCPErrorCode.CONNECTION_FAILED,\n `连接失败: ${error.message}`,\n { context }\n );\n }\n}\n\n/**\n * 错误处理器注册表\n */\nexport class ErrorHandlerRegistry {\n private handlers: ErrorHandler[] = [];\n\n constructor() {\n // 注册默认处理器\n this.registerHandler(new ConfigErrorHandler());\n this.registerHandler(new ConnectionErrorHandler());\n this.registerHandler(new DefaultErrorHandler());\n }\n\n /**\n * 注册错误处理器\n */\n registerHandler(handler: ErrorHandler): void {\n this.handlers.unshift(handler); // 添加到前面,优先处理\n }\n\n /**\n * 处理错误\n */\n handleError(error: Error, context?: Record<string, unknown>): MCPError {\n // 如果已经是MCPError,直接返回\n if (error instanceof MCPError) {\n return error;\n }\n\n // 查找合适的处理器\n for (const handler of this.handlers) {\n if (handler.canHandle(error)) {\n const result = handler.handle(error, context);\n if (result) {\n return result;\n }\n }\n }\n\n // 如果没有处理器能处理,使用默认处理器\n return new DefaultErrorHandler().handle(error, context);\n }\n}\n\n/**\n * 全局错误处理器实例\n */\nexport const globalErrorHandler = new ErrorHandlerRegistry();\n","/**\n * MCP 服务管理 API 处理器\n *\n * 负责处理 MCP 服务的动态管理操作,包括:\n * - 服务的添加和删除(若需更新服务配置,请先删除后重新添加)\n * - 服务的停止和资源清理\n * - 服务状态查询\n * - 服务工具信息查询\n * - 配置验证和持久化\n *\n * 该处理器通过 MCPServiceManager 管理多个 MCP 服务实例,\n * 并通过 EventBus 发布(发射)服务状态变化事件。\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { ErrorCategory, MCPError, MCPErrorCode } from \"@/errors/mcp-errors.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { MCPService } from \"@/lib/mcp\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ConfigManager, MCPServerConfig } from \"@xiaozhi-client/config\";\nimport { normalizeServiceConfig } from \"@xiaozhi-client/config\";\nimport { TypeFieldNormalizer } from \"@xiaozhi-client/mcp-core\";\nimport type { Context } from \"hono\";\n\n/**\n * MCPServiceManager 扩展接口,用于访问私有属性\n * 这个接口定义了我们需要访问但实际上是私有的属性\n */\ninterface MCPServiceManagerAccess {\n services: Map<string, MCPService>;\n}\n\n/**\n * 配置详情接口,包含时间戳\n */\ninterface ConfigDetails {\n serverName?: string;\n config?: MCPServerConfig;\n tools?: string[];\n timestamp?: string;\n [key: string]: unknown; // 允许额外的属性\n}\n\n/**\n * MCP 服务添加请求接口(单服务格式)\n */\nexport interface MCPServerAddRequest {\n name: string;\n config: MCPServerConfig;\n}\n\n/**\n * MCP 服务批量添加请求接口(mcpServers 格式)\n */\nexport interface MCPServerBatchAddRequest {\n mcpServers: Record<string, MCPServerConfig>;\n}\n\n/**\n * MCP 服务添加操作结果\n */\nexport interface MCPServerAddResult {\n name: string;\n success: boolean;\n error?: string;\n config?: MCPServerConfig;\n tools?: string[];\n status?: string;\n}\n\n/**\n * MCP 服务批量添加响应\n */\nexport interface MCPServerBatchAddResponse {\n success: boolean;\n message: string;\n results: MCPServerAddResult[];\n addedCount: number;\n failedCount: number;\n}\n\n/**\n * MCP 服务状态接口\n */\nexport interface MCPServerStatus {\n name: string;\n status: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n connected: boolean;\n tools: string[];\n lastUpdated?: string;\n config: MCPServerConfig;\n}\n\n/**\n * MCP 服务列表响应接口\n */\nexport interface MCPServerListResponse {\n servers: MCPServerStatus[];\n total: number;\n}\n\n/**\n * 统一响应格式接口\n * 从 @middlewares/index.js 导入,保持类型一致性\n */\nexport type {\n ApiErrorResponse,\n ApiSuccessResponse,\n} from \"@/middlewares/index.js\";\n\n/**\n * 配置验证结果接口\n */\nexport interface ValidationResult {\n isValid: boolean;\n errors: string[];\n}\n\n/**\n * MCP 服务 API 处理器\n */\nexport class MCPHandler {\n protected logger: Logger;\n private mcpServiceManager: MCPServiceManager;\n private configManager: ConfigManager;\n private statusCache: Map<string, MCPServerStatus>;\n\n constructor(\n mcpServiceManager: MCPServiceManager,\n configManager: ConfigManager\n ) {\n this.logger = logger;\n this.mcpServiceManager = mcpServiceManager;\n this.configManager = configManager;\n this.statusCache = new Map();\n }\n\n /**\n * 处理错误并返回MCPError\n */\n protected handleError(\n error: unknown,\n operation: string,\n context?: Record<string, unknown>\n ): MCPError {\n if (error instanceof MCPError) {\n this.logger.error(\"MCPError\", { error, operation, context });\n return error;\n }\n\n if (error instanceof Error) {\n let mcpError: MCPError;\n\n // 根据错误消息和操作类型确定错误类型\n if (\n error.message.includes(\"服务不存在\") ||\n error.message.includes(\"not found\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"已存在\") ||\n error.message.includes(\"already exists\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.SERVER_ALREADY_EXISTS,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"配置\") ||\n error.message.includes(\"config\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"连接\") ||\n error.message.includes(\"connection\")\n ) {\n mcpError = MCPError.connectionError(\n MCPErrorCode.CONNECTION_FAILED,\n error.message,\n { operation, context }\n );\n } else {\n mcpError = MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n error.message,\n { operation, context, stack: error.stack }\n );\n }\n\n this.logger.error(\"MCPError\", { error: mcpError, operation, context });\n return mcpError;\n }\n\n // 处理未知错误类型\n const mcpError = MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n String(error),\n { operation, context }\n );\n this.logger.error(\"MCPError\", { error: mcpError, operation, context });\n return mcpError;\n }\n\n /**\n * 添加 MCP 服务\n * POST /api/mcp-servers\n * 支持两种格式:\n * 1. 单服务格式:{ name: string, config: MCPServerConfig }\n * 2. 批量格式:{ mcpServers: Record<string, MCPServerConfig> }\n */\n async addMCPServer(c: Context<AppContext>): Promise<Response> {\n const startTime = Date.now();\n const requestData = await c.req.json();\n\n this.logger.info(\"addMCPServer\", {\n requestData,\n method: \"POST\",\n path: \"/api/mcp-servers\",\n });\n\n try {\n // 检测请求格式\n if (\"mcpServers\" in requestData) {\n // 批量格式\n const batchRequest = requestData as MCPServerBatchAddRequest;\n const result = await this.addMCPServersBatch(batchRequest);\n\n const duration = Date.now() - startTime;\n this.logger.info(\"addMCPServer\", {\n batch: true,\n addedCount: result.addedCount,\n failedCount: result.failedCount,\n duration,\n });\n\n return c.success(result, result.message, 201);\n }\n // 单服务格式\n const singleRequest = requestData as MCPServerAddRequest;\n const { name, config } = singleRequest;\n\n const result = await this.addMCPServerSingle(name, config);\n\n const duration = Date.now() - startTime;\n this.logger.info(\"addMCPServer\", {\n serverName: name,\n toolsCount: result.tools?.length || 0,\n duration,\n status: result.status,\n });\n\n return c.success(result, \"MCP 服务添加成功\", 201);\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServer\", {\n requestData,\n });\n\n // 根据错误类型确定HTTP状态码\n let statusCode = 500;\n if (mcpError.category === ErrorCategory.VALIDATION) {\n statusCode = 400;\n } else if (mcpError.category === ErrorCategory.CONFIGURATION) {\n if (mcpError.code === MCPErrorCode.SERVER_ALREADY_EXISTS) {\n statusCode = 409;\n } else {\n statusCode = 400;\n }\n } else if (mcpError.category === ErrorCategory.CONNECTION) {\n statusCode = 500; // 测试期望连接失败返回500而不是503\n }\n\n return c.fail(\n mcpError.code,\n mcpError.message,\n { error: mcpError.details },\n statusCode\n );\n }\n }\n\n /**\n * 处理单个 MCP 服务添加\n */\n private async addMCPServerSingle(\n name: string,\n config: MCPServerConfig\n ): Promise<MCPServerStatus> {\n this.logger.info(\"addMCPServerSingle\", {\n serverName: name,\n });\n\n // 标准化type字段格式(在try块外声明,确保catch块中可以访问)\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(\n config\n ) as MCPServerConfig;\n\n try {\n // 1. 验证服务名称\n const nameValidation = MCPServerConfigValidator.validateServiceName(name);\n if (!nameValidation.isValid) {\n const validationError = MCPError.validationError(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n { serverName: name, errors: nameValidation.errors }\n );\n this.logger.error(\"addMCPServerSingle\", {\n validationError,\n serverName: name,\n phase: \"name_validation\",\n });\n throw validationError;\n }\n\n // 2. 检查服务是否已存在\n if (\n MCPServerConfigValidator.checkServiceExists(name, this.configManager)\n ) {\n const existsError = MCPError.configError(\n MCPErrorCode.SERVER_ALREADY_EXISTS,\n \"MCP 服务已存在\",\n { serverName: name }\n );\n this.logger.error(\"addMCPServerSingle\", {\n existsError,\n serverName: name,\n phase: \"existence_check\",\n });\n throw existsError;\n }\n\n // 3. 验证服务配置\n const configValidation =\n MCPServerConfigValidator.validateConfig(normalizedConfig);\n if (!configValidation.isValid) {\n const configError = MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n configValidation.errors.join(\", \"),\n {\n serverName: name,\n config: normalizedConfig,\n errors: configValidation.errors,\n }\n );\n this.logger.error(\"addMCPServerSingle\", {\n configError,\n serverName: name,\n phase: \"config_validation\",\n });\n throw configError;\n }\n\n // 5. 添加服务到配置管理器\n this.configManager.updateMcpServer(name, normalizedConfig);\n this.logger.debug(\"服务配置已添加到配置管理器\", { serverName: name });\n\n // 6. 添加服务到 MCPServiceManager 并启动服务\n const mcpServiceConfig = normalizeServiceConfig(normalizedConfig);\n // 使用两参数形式传递 name 和 config\n this.mcpServiceManager.addServiceConfig(name, mcpServiceConfig);\n await this.mcpServiceManager.startService(name);\n this.logger.debug(\"服务已启动\", { serverName: name });\n\n // 6. 获取服务状态和工具列表\n const serviceStatus = this.getServiceStatus(name);\n const tools = this.getServiceTools(name);\n const toolNames = tools.map((tool) => tool.name);\n\n // 7. 发送事件通知\n getEventBus().emitEvent(\"mcp:server:added\", {\n serverName: name,\n config: normalizedConfig,\n tools: toolNames,\n timestamp: new Date(),\n });\n\n return {\n ...serviceStatus,\n tools: toolNames,\n };\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServerSingle\", {\n serverName: name,\n config: normalizedConfig,\n });\n this.logger.error(\"addMCPServerSingle\", {\n mcpError,\n serverName: name,\n });\n throw mcpError;\n }\n }\n\n /**\n * 获取服务状态信息\n */\n private getServiceStatus(serverName: string): MCPServerStatus {\n const config = this.configManager.getConfig();\n const serverConfig = config.mcpServers[serverName];\n\n if (!serverConfig) {\n return {\n name: serverName,\n status: \"disconnected\",\n connected: false,\n tools: [],\n config: {} as MCPServerConfig,\n };\n }\n\n // 尝试从 MCPServiceManager 获取实际状态\n try {\n const managerAccess = this\n .mcpServiceManager as unknown as MCPServiceManagerAccess;\n const service = managerAccess.services.get(serverName);\n\n if (service?.isConnected?.()) {\n const currentTools = service.getTools().map((tool: Tool) => tool.name);\n const status = {\n name: serverName,\n status: \"connected\" as const,\n connected: true,\n tools: currentTools,\n lastUpdated: new Date().toISOString(),\n config: serverConfig,\n };\n\n // 检查状态变化并发出事件\n this.checkAndEmitStatusChange(serverName, status);\n return status;\n }\n } catch (error) {\n this.logger.debug(`获取服务 ${serverName} 状态时出错:`, error);\n }\n\n const status = {\n name: serverName,\n status: \"disconnected\" as const,\n connected: false,\n tools: [],\n config: serverConfig,\n };\n\n // 检查状态变化并发出事件\n this.checkAndEmitStatusChange(serverName, status);\n return status;\n }\n\n /**\n * 检查状态变化并发出事件\n */\n private checkAndEmitStatusChange(\n serverName: string,\n newStatus: MCPServerStatus\n ): void {\n // 获取之前的状态(简单的内存缓存)\n const previousStatus = this.getPreviousStatus(serverName);\n\n if (previousStatus && previousStatus.status !== newStatus.status) {\n this.logger.info(\n `服务 ${serverName} 状态变化: ${previousStatus.status} -> ${newStatus.status}`\n );\n\n // 发射状态变化事件\n getEventBus().emitEvent(\"mcp:server:status_changed\", {\n serverName,\n oldStatus: previousStatus.status,\n newStatus: newStatus.status,\n timestamp: new Date(),\n reason:\n newStatus.status === \"connected\"\n ? \"connection_established\"\n : \"connection_lost\",\n });\n\n // 如果工具列表发生变化,发出工具更新事件\n if (previousStatus.tools !== newStatus.tools) {\n const addedTools = newStatus.tools.filter(\n (tool) => !previousStatus.tools.includes(tool)\n );\n const removedTools = previousStatus.tools.filter(\n (tool) => !newStatus.tools.includes(tool)\n );\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n getEventBus().emitEvent(\"mcp:server:tools:updated\", {\n serverName,\n tools: newStatus.tools,\n addedTools,\n removedTools,\n timestamp: new Date(),\n });\n }\n }\n }\n\n // 更新状态缓存\n this.updateStatusCache(serverName, newStatus);\n }\n\n /**\n * 获取之前的状态(简化实现)\n */\n private getPreviousStatus(serverName: string): MCPServerStatus | null {\n // 这里使用一个简单的Map来缓存状态\n // 在实际生产环境中,可能需要更持久化的缓存方案\n return this.statusCache.get(serverName) || null;\n }\n\n /**\n * 更新状态缓存\n */\n private updateStatusCache(serverName: string, status: MCPServerStatus): void {\n this.statusCache.set(serverName, status);\n }\n\n /**\n * 获取服务工具列表\n */\n private getServiceTools(serverName: string): Tool[] {\n try {\n const managerAccess = this\n .mcpServiceManager as unknown as MCPServiceManagerAccess;\n const service = managerAccess.services.get(serverName);\n\n if (service?.getTools) {\n return service.getTools();\n }\n } catch (error) {\n this.logger.debug(`获取服务 ${serverName} 工具列表时出错:`, error);\n }\n\n return [];\n }\n\n /**\n * 移除 MCP 服务\n * DELETE /api/mcp-servers/:serverName\n */\n async removeMCPServer(c: Context<AppContext>): Promise<Response> {\n try {\n // 1. 从路径参数获取服务名称\n const serverName = c.req.param(\"serverName\");\n\n // 验证参数存在性\n if (!serverName) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n \"服务名称不能为空\",\n {},\n 400\n );\n }\n\n // 2. 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n { serverName },\n 400\n );\n }\n\n // 3. 检查服务是否存在\n if (\n !MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n \"MCP 服务不存在\",\n { serverName },\n 404\n );\n }\n\n // 4. 获取服务当前的工具列表(用于事件通知)\n const currentTools = this.getServiceTools(serverName).map(\n (tool) => tool.name\n );\n\n // 5. 停止服务并清理资源\n try {\n await this.mcpServiceManager.stopService(serverName);\n } catch (error) {\n this.logger.warn(`停止服务 ${serverName} 失败:`, error);\n // 即使停止失败,也继续执行配置移除\n }\n\n // 6. 移除服务配置\n this.mcpServiceManager.removeServiceConfig(serverName);\n this.configManager.removeMcpServer(serverName);\n\n // 7. 发送事件通知\n getEventBus().emitEvent(\"mcp:server:removed\", {\n serverName,\n affectedTools: currentTools,\n timestamp: new Date(),\n });\n\n // 8. 返回成功响应\n return c.success(\n {\n name: serverName,\n operation: \"removed\",\n affectedTools: currentTools,\n },\n \"MCP 服务移除成功\"\n );\n } catch (error) {\n this.logger.error(\"移除 MCP 服务失败:\", error);\n\n // 处理不同类型的错误\n if (error instanceof Error) {\n if (error.message.includes(\"服务不存在\")) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message,\n undefined,\n 404\n );\n }\n\n if (error.message.includes(\"配置更新\")) {\n return c.fail(\n MCPErrorCode.CONFIG_UPDATE_FAILED,\n error.message,\n undefined,\n 500\n );\n }\n }\n\n // 其他未知错误\n return c.fail(\n MCPErrorCode.REMOVE_FAILED,\n \"移除 MCP 服务时发生错误\",\n { error: error instanceof Error ? error.message : String(error) },\n 500\n );\n }\n }\n\n /**\n * 获取 MCP 服务状态\n * GET /api/mcp-servers/:serverName/status\n */\n async getMCPServerStatus(c: Context<AppContext>): Promise<Response> {\n try {\n // 1. 从路径参数获取服务名称\n const serverName = c.req.param(\"serverName\");\n\n // 验证参数存在性\n if (!serverName) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n \"服务名称不能为空\",\n {},\n 400\n );\n }\n\n // 2. 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n { serverName },\n 400\n );\n }\n\n // 3. 检查服务是否存在\n if (\n !MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n \"MCP 服务不存在\",\n { serverName },\n 404\n );\n }\n\n // 4. 获取服务状态\n const serviceStatus = this.getServiceStatus(serverName);\n\n // 5. 返回成功响应\n return c.success(serviceStatus, \"MCP 服务状态获取成功\");\n } catch (error) {\n this.logger.error(\"获取 MCP 服务状态失败:\", error);\n\n // 处理不同类型的错误\n if (error instanceof Error) {\n if (error.message.includes(\"服务不存在\")) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message,\n undefined,\n 404\n );\n }\n }\n\n // 其他未知错误\n return c.fail(\n MCPErrorCode.INTERNAL_ERROR,\n \"获取 MCP 服务状态时发生内部错误\",\n { error: error instanceof Error ? error.message : String(error) },\n 500\n );\n }\n }\n\n /**\n * 列出所有 MCP 服务\n * GET /api/mcp-servers\n */\n async listMCPServers(c: Context<AppContext>): Promise<Response> {\n try {\n // 1. 获取所有配置的 MCP 服务\n const config = this.configManager.getConfig();\n const mcpServers = config.mcpServers || {};\n\n // 2. 构建服务列表\n const servers: MCPServerStatus[] = [];\n\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n const serviceStatus = this.getServiceStatus(serverName);\n servers.push(serviceStatus);\n }\n\n // 3. 构建响应数据\n const listResponse: MCPServerListResponse = {\n servers,\n total: servers.length,\n };\n\n // 4. 返回成功响应\n return c.success(listResponse, \"MCP 服务列表获取成功\");\n } catch (error) {\n this.logger.error(\"列出 MCP 服务失败:\", error);\n\n // 其他未知错误\n return c.fail(\n MCPErrorCode.INTERNAL_ERROR,\n \"列出 MCP 服务时发生内部错误\",\n { error: error instanceof Error ? error.message : String(error) },\n 500\n );\n }\n }\n\n /**\n * 处理批量 MCP 服务添加\n */\n private async addMCPServersBatch(\n batchRequest: MCPServerBatchAddRequest\n ): Promise<MCPServerBatchAddResponse> {\n const { mcpServers } = batchRequest;\n const serverNames = Object.keys(mcpServers);\n\n this.logger.info(\"addMCPServersBatch\", {\n serverCount: serverNames.length,\n serverNames,\n });\n\n if (serverNames.length === 0) {\n throw MCPError.validationError(\n MCPErrorCode.INVALID_CONFIG,\n \"批量添加请求中的服务列表为空\"\n );\n }\n\n const results: MCPServerAddResult[] = [];\n const successfullyAddedServers: string[] = [];\n\n // 第一阶段:验证所有服务配置\n const validationResult = this.validateBatchServers(mcpServers);\n if (!validationResult.isValid) {\n throw MCPError.validationError(\n MCPErrorCode.INVALID_CONFIG,\n validationResult.errors.join(\", \")\n );\n }\n\n try {\n // 第二阶段:逐个添加服务,记录成功和失败\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n // 标准化type字段格式(在try块外声明,确保catch块中可以访问)\n const normalizedServerConfig = TypeFieldNormalizer.normalizeTypeField(\n serverConfig\n ) as MCPServerConfig;\n\n try {\n const result = await this.addMCPServerSingle(\n serverName,\n normalizedServerConfig\n );\n\n results.push({\n name: serverName,\n success: true,\n config: normalizedServerConfig,\n tools: result.tools,\n status: result.status,\n });\n\n successfullyAddedServers.push(serverName);\n\n this.logger.debug(\"批量添加:服务添加成功\", {\n serverName,\n toolsCount: result.tools?.length || 0,\n });\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServersBatch\", {\n serverName,\n serverConfig: normalizedServerConfig,\n });\n\n results.push({\n name: serverName,\n success: false,\n error: mcpError.message,\n config: normalizedServerConfig,\n });\n\n this.logger.warn(\"批量添加:服务添加失败\", {\n serverName,\n error: mcpError.message,\n });\n }\n }\n\n // 第三阶段:统计结果\n const addedCount = successfullyAddedServers.length;\n const failedCount = serverNames.length - addedCount;\n\n // 第四阶段:如果完全失败,抛出异常;部分成功则返回结果\n if (addedCount === 0) {\n throw MCPError.configError(\n MCPErrorCode.ADD_FAILED,\n \"批量添加失败:所有服务都无法添加\"\n );\n }\n\n // 发送批量添加事件\n getEventBus().emitEvent(\"mcp:server:batch_added\", {\n totalServers: serverNames.length,\n addedCount,\n failedCount,\n successfullyAddedServers,\n results,\n timestamp: new Date(),\n });\n\n const response: MCPServerBatchAddResponse = {\n success: addedCount > 0,\n message:\n addedCount === serverNames.length\n ? `批量添加成功:已添加 ${addedCount} 个服务`\n : `批量添加部分成功:成功添加 ${addedCount} 个服务,失败 ${failedCount} 个服务`,\n results,\n addedCount,\n failedCount,\n };\n\n this.logger.info(\"addMCPServersBatch\", {\n totalServers: serverNames.length,\n addedCount,\n failedCount,\n });\n\n return response;\n } catch (error) {\n // 如果发生未处理的错误,尝试回滚已成功添加的服务\n if (successfullyAddedServers.length > 0) {\n await this.rollbackBatchAdd(successfullyAddedServers);\n }\n\n if (error instanceof MCPError) {\n throw error;\n }\n throw MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n `批量添加过程中发生错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 验证批量服务配置\n */\n private validateBatchServers(\n mcpServers: Record<string, MCPServerConfig>\n ): ValidationResult {\n const errors: string[] = [];\n\n if (!mcpServers || typeof mcpServers !== \"object\") {\n errors.push(\"mcpServers 必须是一个对象\");\n return { isValid: false, errors };\n }\n\n const serverNames = Object.keys(mcpServers);\n if (serverNames.length === 0) {\n errors.push(\"mcpServers 对象不能为空\");\n return { isValid: false, errors };\n }\n\n if (serverNames.length > 50) {\n errors.push(\"批量添加的服务数量不能超过 50 个\");\n return { isValid: false, errors };\n }\n\n // 验证每个服务\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n // 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n errors.push(\n `服务 \"${serverName}\" 名称无效: ${nameValidation.errors.join(\", \")}`\n );\n continue;\n }\n\n // 检查是否已存在\n if (\n MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n errors.push(`服务 \"${serverName}\" 已存在`);\n continue;\n }\n\n // 标准化type字段格式\n const normalizedServerConfig = TypeFieldNormalizer.normalizeTypeField(\n serverConfig\n ) as MCPServerConfig;\n\n // 验证配置\n const configValidation = MCPServerConfigValidator.validateConfig(\n normalizedServerConfig\n );\n if (!configValidation.isValid) {\n errors.push(\n `服务 \"${serverName}\" 配置无效: ${configValidation.errors.join(\", \")}`\n );\n }\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 回滚批量添加的服务\n */\n private async rollbackBatchAdd(serverNames: string[]): Promise<void> {\n this.logger.info(\"开始回滚批量添加的服务\", { serverNames });\n\n const rollbackResults: string[] = [];\n const rollbackFailures: string[] = [];\n\n for (const serverName of serverNames) {\n try {\n // 停止服务\n try {\n await this.mcpServiceManager.stopService(serverName);\n } catch (error) {\n this.logger.warn(`回滚时停止服务 ${serverName} 失败:`, error);\n }\n\n // 移除服务配置\n this.mcpServiceManager.removeServiceConfig(serverName);\n this.configManager.removeMcpServer(serverName);\n\n rollbackResults.push(serverName);\n\n // 发送回滚事件\n getEventBus().emitEvent(\"mcp:server:rollback\", {\n serverName,\n timestamp: new Date(),\n });\n } catch (error) {\n const mcpError = this.handleError(error, \"rollbackBatchAdd\", {\n serverName,\n });\n rollbackFailures.push(serverName);\n\n this.logger.error(`回滚服务 ${serverName} 失败:`, mcpError.message);\n }\n }\n\n if (rollbackFailures.length > 0) {\n this.logger.warn(\"批量添加回滚部分失败\", {\n totalServers: serverNames.length,\n rollbackedCount: rollbackResults.length,\n failedCount: rollbackFailures.length,\n failedServers: rollbackFailures,\n });\n } else {\n this.logger.info(\"批量添加回滚成功\", {\n totalServers: serverNames.length,\n rollbackedCount: rollbackResults.length,\n });\n }\n }\n}\n\n/**\n * MCP 服务配置验证工具命名空间\n */\nexport namespace MCPServerConfigValidator {\n /**\n * 验证服务配置\n */\n export function validateConfig(config: MCPServerConfig): ValidationResult {\n const errors: string[] = [];\n\n // 验证配置基本结构\n if (!config || typeof config !== \"object\") {\n errors.push(\"配置必须是一个对象\");\n return { isValid: false, errors };\n }\n\n // 根据类型验证配置\n if (\"command\" in config) {\n // LocalMCPServerConfig\n if (!config.command || typeof config.command !== \"string\") {\n errors.push(\"本地服务必须提供有效的命令\");\n }\n if (config.args && !Array.isArray(config.args)) {\n errors.push(\"参数必须是数组\");\n }\n if (config.env && typeof config.env !== \"object\") {\n errors.push(\"环境变量必须是对象\");\n }\n } else if (\"url\" in config) {\n // SSEMCPServerConfig 或 StreamableHTTPMCPServerConfig\n if (!config.url || typeof config.url !== \"string\") {\n errors.push(\"远程服务必须提供有效的 URL\");\n }\n try {\n new URL(config.url);\n } catch {\n errors.push(\"URL 格式无效\");\n }\n } else {\n errors.push(\"配置必须包含 command 或 url 字段\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 验证服务名称\n */\n export function validateServiceName(name: string): ValidationResult {\n const errors: string[] = [];\n\n if (!name || typeof name !== \"string\") {\n errors.push(\"服务名称必须是非空字符串\");\n return { isValid: false, errors };\n }\n\n if (name.length < 1 || name.length > 50) {\n errors.push(\"服务名称长度必须在 1-50 个字符之间\");\n }\n\n if (!/^[a-zA-Z0-9_-]+$/.test(name)) {\n errors.push(\"服务名称只能包含字母、数字、下划线和连字符\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 检查服务是否已存在\n */\n export function checkServiceExists(\n name: string,\n configManager: ConfigManager\n ): boolean {\n const config = configManager.getConfig();\n return config.mcpServers && name in config.mcpServers;\n }\n}\n","/**\n * 实时通知 HTTP 路由处理器\n * 提供 WebSocket 实时通知相关的消息处理接口,处理配置更新、状态变化和服务重启等实时通知\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type {\n NotificationService,\n WebSocketLike,\n} from \"@/services/notification.service.js\";\nimport type { StatusService } from \"@/services/status.service.js\";\nimport { sendWebSocketError } from \"@/utils/websocket-helper.js\";\nimport type { AppConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\n\n/**\n * WebSocket 消息接口\n */\ninterface WebSocketMessage {\n type: string;\n data?: unknown;\n clientId?: string;\n}\n\n/**\n * 实时通知处理器\n */\nexport class RealtimeNotificationHandler {\n private logger: Logger;\n private notificationService: NotificationService;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(\n notificationService: NotificationService,\n statusService: StatusService\n ) {\n this.logger = logger;\n this.notificationService = notificationService;\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 处理 WebSocket 消息\n * @deprecated 部分消息类型已废弃,建议使用 HTTP API\n */\n async handleMessage(\n ws: WebSocketLike,\n message: WebSocketMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理 WebSocket 消息: ${message.type}`, { clientId });\n\n // 发射消息接收事件\n this.eventBus.emitEvent(\"websocket:message:received\", {\n type: message.type,\n data: message.data,\n clientId,\n });\n\n switch (message.type) {\n case \"getConfig\":\n await this.handleGetConfig(ws, clientId);\n break;\n\n case \"updateConfig\":\n await this.handleUpdateConfig(\n ws,\n message.data as AppConfig,\n clientId\n );\n break;\n\n case \"getStatus\":\n await this.handleGetStatus(ws, clientId);\n break;\n\n case \"restartService\":\n await this.handleRestartService(ws, clientId);\n break;\n\n default:\n this.logger.warn(`未知的 WebSocket 消息类型: ${message.type}`, {\n clientId,\n });\n sendWebSocketError(\n ws,\n \"UNKNOWN_MESSAGE_TYPE\",\n `未知的消息类型: ${message.type}`,\n this.logger\n );\n }\n } catch (error) {\n this.logger.error(`处理 WebSocket 消息失败: ${message.type}`, error);\n sendWebSocketError(\n ws,\n \"MESSAGE_PROCESSING_ERROR\",\n error instanceof Error ? error.message : \"消息处理失败\",\n this.logger\n );\n }\n }\n\n /**\n * 处理获取配置请求\n * @deprecated 使用 GET /api/config 替代\n */\n private async handleGetConfig(\n ws: WebSocketLike,\n clientId: string\n ): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getConfig\", \"GET /api/config\");\n\n try {\n const config = configManager.getConfig();\n this.logger.debug(\"WebSocket: getConfig 请求处理成功\", { clientId });\n ws.send(JSON.stringify({ type: \"config\", data: config }));\n } catch (error) {\n this.logger.error(\"WebSocket: getConfig 请求处理失败\", error);\n sendWebSocketError(\n ws,\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\",\n this.logger\n );\n }\n }\n\n /**\n * 处理更新配置请求\n * @deprecated 使用 PUT /api/config 替代\n */\n private async handleUpdateConfig(\n ws: WebSocketLike,\n configData: AppConfig,\n clientId: string\n ): Promise<void> {\n this.logDeprecationWarning(\"WebSocket updateConfig\", \"PUT /api/config\");\n\n try {\n // 使用 configManager 的验证方法\n configManager.validateConfig(configData);\n\n // 使用 configManager 的批量更新方法\n configManager.updateConfig(configData);\n\n // 更新服务工具配置(单独处理,因为 updateConfig 只更新已存在的配置)\n if (configData.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n configData.mcpServerConfig\n )) {\n for (const [toolName, toolConfig] of Object.entries(\n toolsConfig.tools\n )) {\n configManager.setToolEnabled(\n serverName,\n toolName,\n toolConfig.enable\n );\n }\n }\n }\n\n this.logger.debug(\"WebSocket: 配置更新成功\", { clientId });\n ws.send(JSON.stringify({ type: \"config:updated\", success: true }));\n } catch (error) {\n this.logger.error(\"WebSocket: 配置更新失败\", error);\n sendWebSocketError(\n ws,\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : String(error),\n this.logger\n );\n }\n }\n\n /**\n * 处理获取状态请求\n * @deprecated 使用 GET /api/status 替代\n */\n private async handleGetStatus(\n ws: WebSocketLike,\n clientId: string\n ): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getStatus\", \"GET /api/status\");\n\n try {\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"status\", data: status.client }));\n this.logger.debug(\"WebSocket: getStatus 请求处理成功\", { clientId });\n } catch (error) {\n this.logger.error(\"WebSocket: getStatus 请求处理失败\", error);\n sendWebSocketError(\n ws,\n \"STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取状态失败\",\n this.logger\n );\n }\n }\n\n /**\n * 处理重启服务请求\n * @deprecated 使用 POST /api/services/restart 替代\n */\n private async handleRestartService(\n ws: WebSocketLike,\n clientId: string\n ): Promise<void> {\n this.logDeprecationWarning(\n \"WebSocket restartService\",\n \"POST /api/services/restart\"\n );\n\n try {\n this.logger.info(\"WebSocket: 收到服务重启请求\", { clientId });\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n serviceName: \"unknown\", // 由于是WebSocket触发的,服务名未知\n source: `websocket-${clientId}`,\n delay: 0,\n attempt: 1,\n timestamp: Date.now(),\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n } catch (error) {\n this.logger.error(\"WebSocket: 处理重启请求失败\", error);\n sendWebSocketError(\n ws,\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\",\n this.logger\n );\n }\n }\n\n /**\n * 记录废弃功能使用警告\n */\n private logDeprecationWarning(feature: string, alternative: string): void {\n this.logger.warn(\n `[DEPRECATED] ${feature} 功能已废弃,请使用 ${alternative} 替代`\n );\n }\n\n /**\n * 发送初始数据给新连接的客户端\n */\n async sendInitialData(ws: WebSocketLike, clientId: string): Promise<void> {\n try {\n this.logger.debug(\"发送初始数据给客户端\", { clientId });\n\n // 发送当前配置\n const config = configManager.getConfig();\n ws.send(JSON.stringify({ type: \"configUpdate\", data: config }));\n\n // 发送当前状态\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"statusUpdate\", data: status.client }));\n\n // 如果有重启状态,也发送\n if (status.restart) {\n ws.send(\n JSON.stringify({ type: \"restartStatus\", data: status.restart })\n );\n }\n\n this.logger.debug(\"初始数据发送完成\", { clientId });\n } catch (error) {\n this.logger.error(\"发送初始数据失败:\", error);\n sendWebSocketError(\n ws,\n \"INITIAL_DATA_ERROR\",\n error instanceof Error ? error.message : \"发送初始数据失败\",\n this.logger\n );\n }\n }\n\n /**\n * 处理客户端断开连接\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.debug(`客户端断开连接: ${clientId}`);\n this.notificationService.unregisterClient(clientId);\n }\n\n /**\n * 处理客户端连接\n */\n handleClientConnect(ws: WebSocketLike, clientId: string): void {\n this.logger.debug(`客户端连接: ${clientId}`);\n this.notificationService.registerClient(clientId, ws);\n }\n}\n","/**\n * 服务 API HTTP 路由处理器\n * 提供服务启动、停止、重启等相关的 RESTful API 接口\n */\nimport { spawn } from \"node:child_process\";\nimport type { ChildProcess } from \"node:child_process\";\nimport { logger } from \"@/Logger.js\";\nimport type { Logger } from \"@/Logger.js\";\nimport { SERVICE_RESTART_DELAYS } from \"@/constants/timeout.constants.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { StatusService } from \"@/services/status.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { requireMCPServiceManager } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 服务 API 处理器\n */\nexport class ServiceApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(statusService: StatusService) {\n this.logger = logger;\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 通用的 xiaozhi 进程启动方法\n * @param args 命令行参数(如 [\"start\", \"--daemon\"])\n * @returns 启动的子进程\n */\n private spawnXiaozhiProcess(args: string[]): ChildProcess {\n const child = spawn(\"xiaozhi\", args, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(`MCP 服务命令已发送: xiaozhi ${args.join(\" \")}`);\n\n return child;\n }\n\n /**\n * 重启服务\n * POST /api/services/restart\n */\n async restartService(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理服务重启请求\");\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n serviceName: \"unknown\", // 由于是HTTP API触发的,服务名未知\n source: \"http-api\",\n delay: 0,\n attempt: 1,\n timestamp: Date.now(),\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n\n // 从 Context 获取 MCP 服务管理器\n const mcpServiceManager = requireMCPServiceManager(c);\n\n // 异步执行重启,不阻塞响应\n setTimeout(async () => {\n try {\n await this.executeRestart(mcpServiceManager);\n // 服务重启需要一些时间,延迟发送成功状态\n setTimeout(() => {\n this.statusService.updateRestartStatus(\"completed\");\n }, SERVICE_RESTART_DELAYS.SUCCESS_NOTIFICATION_DELAY);\n } catch (error) {\n c.get(\"logger\").error(\"服务重启失败:\", error);\n this.statusService.updateRestartStatus(\n \"failed\",\n error instanceof Error ? error.message : \"未知错误\"\n );\n }\n }, SERVICE_RESTART_DELAYS.EXECUTION_DELAY);\n\n return c.success(null, \"重启请求已接收\");\n } catch (error) {\n c.get(\"logger\").error(\"处理重启请求失败:\", error);\n return c.fail(\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 执行服务重启\n * @param mcpServiceManager MCP 服务管理器实例\n */\n private async executeRestart(\n mcpServiceManager: MCPServiceManager\n ): Promise<void> {\n this.logger.info(\"正在重启 MCP 服务...\");\n\n try {\n // 获取当前服务状态\n const status = mcpServiceManager.getStatus();\n\n if (!status.isRunning) {\n this.logger.warn(\"MCP 服务未运行,尝试启动服务\");\n\n // 如果服务未运行,尝试启动服务\n this.spawnXiaozhiProcess([\"start\", \"--daemon\"]);\n return;\n }\n\n // 执行重启命令,始终使用 daemon 模式\n this.spawnXiaozhiProcess([\"restart\", \"--daemon\"]);\n } catch (error) {\n this.logger.error(\"重启服务失败:\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务\n * POST /api/services/stop\n */\n async stopService(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理服务停止请求\");\n\n // 执行停止命令\n this.spawnXiaozhiProcess([\"stop\"]);\n\n return c.success(null, \"停止请求已接收\");\n } catch (error) {\n c.get(\"logger\").error(\"处理停止请求失败:\", error);\n return c.fail(\n \"STOP_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理停止请求失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 启动服务\n * POST /api/services/start\n */\n async startService(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理服务启动请求\");\n\n // 执行启动命令\n this.spawnXiaozhiProcess([\"start\", \"--daemon\"]);\n\n return c.success(null, \"启动请求已接收\");\n } catch (error) {\n c.get(\"logger\").error(\"处理启动请求失败:\", error);\n return c.fail(\n \"START_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理启动请求失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取服务状态\n * GET /api/services/status\n */\n async getServiceStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取服务状态请求\");\n\n const mcpServiceManager = requireMCPServiceManager(c);\n const status = mcpServiceManager.getStatus();\n\n c.get(\"logger\").debug(\"获取服务状态成功\");\n return c.success(status);\n } catch (error) {\n c.get(\"logger\").error(\"获取服务状态失败:\", error);\n return c.fail(\n \"SERVICE_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务状态失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取服务健康状态\n * GET /api/services/health\n */\n async getServiceHealth(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取服务健康状态请求\");\n\n // 简单的健康检查\n const health = {\n status: \"healthy\",\n timestamp: Date.now(),\n uptime: process.uptime(),\n memory: process.memoryUsage(),\n version: process.version,\n };\n\n c.get(\"logger\").debug(\"获取服务健康状态成功\");\n return c.success(health);\n } catch (error) {\n c.get(\"logger\").error(\"获取服务健康状态失败:\", error);\n return c.fail(\n \"SERVICE_HEALTH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务健康状态失败\",\n undefined,\n 500\n );\n }\n }\n}\n","/**\n * 静态文件 HTTP 路由处理器\n * 负责处理前端静态资源的请求和响应,支持多种构建路径的自动识别和文件访问\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { HTTP_CONTENT_TYPES, HTTP_STATUS_CODES } from \"@/constants/index.js\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 静态文件处理器\n */\nexport class StaticFileHandler extends BaseHandler {\n private logger: Logger;\n private webPath: string | null = null;\n\n constructor() {\n super();\n this.logger = logger;\n this.initializeWebPath();\n }\n\n /**\n * 初始化 Web 路径\n */\n private initializeWebPath(): void {\n try {\n // 获取当前文件所在目录\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n logger.debug(`当前文件目录: ${__dirname}`);\n\n // 确定web目录路径\n // 支持 Nx 构建的 dist/frontend 目录结构\n const possibleWebPaths = [\n // Nx 构建的主要路径:dist/frontend/\n // 对于 dist/backend/handlers/StaticFileHandler.js -> ../../../frontend\n // 对于 dist/backend/cli.js -> ../../frontend\n // 对于 dist/cli.js -> ../frontend\n join(__dirname, \"..\", \"..\", \"..\", \"frontend\"),\n join(__dirname, \"..\", \"..\", \"frontend\"),\n join(__dirname, \"..\", \"frontend\"),\n\n // 兼容旧构建路径:从 dist 目录向上查找 apps/frontend/dist\n join(__dirname, \"..\", \"..\", \"apps\", \"frontend\", \"dist\"),\n join(__dirname, \"..\", \"apps\", \"frontend\", \"dist\"),\n\n // 备用路径:查找未构建的 apps/frontend 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"apps\", \"frontend\"),\n join(__dirname, \"..\", \"apps\", \"frontend\"),\n\n // 兼容路径:保持对旧 web 目录的支持(向后兼容)\n join(__dirname, \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"web\", \"dist\"),\n\n // 备用兼容路径:查找未构建的 web 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"web\"),\n join(__dirname, \"..\", \"web\"),\n\n // 兜底路径:从源码目录查找(开发模式下的源码执行)\n join(__dirname, \"..\", \"..\", \"..\", \"apps\", \"frontend\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"apps\", \"frontend\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\"),\n ];\n\n // 查找第一个存在的路径\n this.webPath =\n possibleWebPaths.find((p) => {\n const exists = existsSync(p);\n logger.debug(`检查路径 ${p}: ${exists ? \"存在\" : \"不存在\"}`);\n return exists;\n }) || null;\n\n if (this.webPath) {\n logger.debug(`静态文件服务路径: ${this.webPath}`);\n } else {\n logger.warn(\"未找到静态文件目录\");\n logger.debug(\"尝试的路径:\", possibleWebPaths);\n }\n } catch (error) {\n logger.error(\"初始化静态文件路径失败:\", error);\n }\n }\n\n /**\n * 处理静态文件请求\n * GET /*\n */\n async handleStaticFile(c: Context): Promise<Response> {\n const pathname = new URL(c.req.url).pathname;\n\n try {\n c.logger.debug(`处理静态文件请求: ${pathname}`);\n\n if (!this.webPath) {\n return this.createErrorPage(c, \"找不到前端资源文件\");\n }\n\n // 处理路径\n let filePath = pathname;\n if (filePath === \"/\") {\n filePath = \"/index.html\";\n }\n\n // 安全性检查:防止路径遍历\n if (filePath.includes(\"..\")) {\n c.logger.warn(`路径遍历攻击尝试: ${filePath}`);\n return c.text(\"Forbidden\", HTTP_STATUS_CODES.FORBIDDEN);\n }\n\n const fullPath = join(this.webPath, filePath);\n\n // 检查文件是否存在\n if (!existsSync(fullPath)) {\n // 对于 SPA,返回 index.html\n const indexPath = join(this.webPath, \"index.html\");\n if (existsSync(indexPath)) {\n c.logger.debug(`SPA 回退到 index.html: ${pathname}`);\n return this.serveFile(c, indexPath, HTTP_CONTENT_TYPES.TEXT_HTML);\n }\n\n c.logger.debug(`文件不存在: ${fullPath}`);\n return c.text(\"Not Found\", HTTP_STATUS_CODES.NOT_FOUND);\n }\n\n // 确定 Content-Type\n const contentType = this.getContentType(fullPath);\n\n c.logger.debug(`服务静态文件: ${fullPath}, Content-Type: ${contentType}`);\n return this.serveFile(c, fullPath, contentType);\n } catch (error) {\n c.logger.error(`服务静态文件错误 (${pathname}):`, error);\n return c.text(\n \"Internal Server Error\",\n HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * 服务文件\n */\n private async serveFile(\n c: Context,\n filePath: string,\n contentType: string\n ): Promise<Response> {\n try {\n const content = await readFile(filePath);\n\n // 对于文本文件,返回字符串;对于二进制文件,返回 ArrayBuffer\n if (\n contentType.startsWith(\"text/\") ||\n contentType.includes(\"javascript\") ||\n contentType.includes(\"json\")\n ) {\n return c.text(content.toString(), 200, { \"Content-Type\": contentType });\n }\n\n return c.body(new Uint8Array(content), 200, {\n \"Content-Type\": contentType,\n });\n } catch (error) {\n logger.error(`读取文件失败: ${filePath}`, error);\n throw error;\n }\n }\n\n /**\n * 获取文件的 Content-Type\n */\n private getContentType(filePath: string): string {\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n\n const contentTypes: Record<string, string> = {\n html: HTTP_CONTENT_TYPES.TEXT_HTML,\n htm: HTTP_CONTENT_TYPES.TEXT_HTML,\n js: HTTP_CONTENT_TYPES.APPLICATION_JAVASCRIPT,\n mjs: HTTP_CONTENT_TYPES.APPLICATION_JAVASCRIPT,\n css: HTTP_CONTENT_TYPES.TEXT_CSS,\n json: HTTP_CONTENT_TYPES.APPLICATION_JSON,\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n svg: \"image/svg+xml\",\n ico: \"image/x-icon\",\n woff: \"font/woff\",\n woff2: \"font/woff2\",\n ttf: \"font/ttf\",\n eot: \"application/vnd.ms-fontobject\",\n pdf: HTTP_CONTENT_TYPES.APPLICATION_PDF,\n txt: HTTP_CONTENT_TYPES.TEXT_PLAIN,\n xml: HTTP_CONTENT_TYPES.APPLICATION_XML,\n zip: HTTP_CONTENT_TYPES.APPLICATION_ZIP,\n tar: \"application/x-tar\",\n gz: \"application/gzip\",\n };\n\n return (\n contentTypes[ext || \"\"] || HTTP_CONTENT_TYPES.APPLICATION_OCTET_STREAM\n );\n }\n\n /**\n * 创建错误页面\n */\n private createErrorPage(c: Context, message: string): Response {\n const errorHtml = `\n <!DOCTYPE html>\n <html>\n <head>\n <title>小智配置管理</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 800px;\n margin: 50px auto;\n padding: 20px;\n line-height: 1.6;\n color: #333;\n }\n .error {\n color: #e53e3e;\n background: #fed7d7;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #e53e3e;\n }\n .info {\n background: #e6f3ff;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #0066cc;\n margin-top: 20px;\n }\n pre {\n background: #f5f5f5;\n padding: 10px;\n border-radius: 4px;\n overflow-x: auto;\n }\n h1 {\n color: #2d3748;\n margin-bottom: 20px;\n }\n </style>\n </head>\n <body>\n <h1>小智配置管理</h1>\n <div class=\"error\">\n <p><strong>错误:</strong>${message}</p>\n </div>\n <div class=\"info\">\n <p><strong>解决方案:</strong></p>\n <p>请先构建前端项目:</p>\n <pre>cd apps/frontend && pnpm install && pnpm build</pre>\n <p><em>如果上面的路径不存在,可以尝试旧路径:</em></p>\n <pre>cd web && pnpm install && pnpm build</pre>\n <p>然后重新启动服务器。</p>\n </div>\n </body>\n </html>\n `;\n\n return c.html(errorHtml);\n }\n\n /**\n * 检查静态文件目录是否存在\n */\n isWebPathAvailable(): boolean {\n return this.webPath !== null && existsSync(this.webPath);\n }\n\n /**\n * 获取静态文件目录路径\n */\n getWebPath(): string | null {\n return this.webPath;\n }\n\n /**\n * 重新初始化 Web 路径\n */\n reinitializeWebPath(): void {\n this.initializeWebPath();\n }\n}\n","/**\n * 状态 API HTTP 路由处理器\n * 提供客户端状态、服务状态、心跳等状态相关的 RESTful API 接口\n */\nimport type { StatusService } from \"@/services/status.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 状态 API 处理器\n */\nexport class StatusApiHandler extends BaseHandler {\n private statusService: StatusService;\n\n constructor(statusService: StatusService) {\n super();\n this.statusService = statusService;\n }\n\n /**\n * 获取完整状态\n * GET /api/status\n */\n async getStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取状态请求\");\n const status = this.statusService.getFullStatus();\n c.get(\"logger\").debug(\"获取状态成功\");\n return c.success(status);\n } catch (error) {\n return this.handleError(c, error, \"获取状态\", \"STATUS_READ_ERROR\");\n }\n }\n\n /**\n * 获取客户端状态\n * GET /api/status/client\n */\n async getClientStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取客户端状态请求\");\n const clientStatus = this.statusService.getClientStatus();\n c.get(\"logger\").debug(\"获取客户端状态成功\");\n return c.success(clientStatus);\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取客户端状态\",\n \"CLIENT_STATUS_READ_ERROR\"\n );\n }\n }\n\n /**\n * 获取重启状态\n * GET /api/status/restart\n */\n async getRestartStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取重启状态请求\");\n const restartStatus = this.statusService.getRestartStatus();\n c.get(\"logger\").debug(\"获取重启状态成功\");\n return c.success(restartStatus);\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取重启状态\",\n \"RESTART_STATUS_READ_ERROR\"\n );\n }\n }\n\n /**\n * 检查客户端是否连接\n * GET /api/status/connected\n */\n async checkClientConnected(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理检查客户端连接请求\");\n const connected = this.statusService.isClientConnected();\n c.get(\"logger\").debug(`客户端连接状态: ${connected}`);\n return c.success({ connected });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"检查客户端连接\",\n \"CLIENT_CONNECTION_CHECK_ERROR\"\n );\n }\n }\n\n /**\n * 获取最后心跳时间\n * GET /api/status/heartbeat\n */\n async getLastHeartbeat(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取最后心跳时间请求\");\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n c.get(\"logger\").debug(\"获取最后心跳时间成功\");\n return c.success({ lastHeartbeat });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取最后心跳时间\",\n \"HEARTBEAT_READ_ERROR\"\n );\n }\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n * GET /api/status/mcp-servers\n */\n async getActiveMCPServers(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取活跃 MCP 服务器请求\");\n const servers = this.statusService.getActiveMCPServers();\n c.get(\"logger\").debug(\"获取活跃 MCP 服务器成功\");\n return c.success({ servers });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取活跃 MCP 服务器\",\n \"ACTIVE_MCP_SERVERS_READ_ERROR\"\n );\n }\n }\n\n /**\n * 更新客户端状态\n * PUT /api/status/client\n */\n async updateClientStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理更新客户端状态请求\");\n const statusUpdate = await this.parseJsonBody<Record<string, unknown>>(\n c,\n \"请求体必须是有效的状态对象\"\n );\n\n // 验证请求体\n if (!statusUpdate || typeof statusUpdate !== \"object\") {\n return c.fail(\n \"INVALID_REQUEST_BODY\",\n \"请求体必须是有效的状态对象\",\n undefined,\n 400\n );\n }\n\n this.statusService.updateClientInfo(statusUpdate, \"http-api\");\n c.get(\"logger\").info(\"客户端状态更新成功\");\n\n return c.success(undefined, \"客户端状态更新成功\");\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"更新客户端状态\",\n \"CLIENT_STATUS_UPDATE_ERROR\",\n \"更新客户端状态失败\",\n 400\n );\n }\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n * PUT /api/status/mcp-servers\n */\n async setActiveMCPServers(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理设置活跃 MCP 服务器请求\");\n const { servers } = await this.parseJsonBody<{ servers: string[] }>(\n c,\n \"请求体格式错误\"\n );\n\n // 验证请求体\n if (!Array.isArray(servers)) {\n return c.fail(\n \"INVALID_REQUEST_BODY\",\n \"servers 必须是字符串数组\",\n undefined,\n 400\n );\n }\n\n this.statusService.setActiveMCPServers(servers);\n c.get(\"logger\").info(\"活跃 MCP 服务器设置成功\");\n\n return c.success(undefined, \"活跃 MCP 服务器设置成功\");\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"设置活跃 MCP 服务器\",\n \"ACTIVE_MCP_SERVERS_UPDATE_ERROR\",\n \"设置活跃 MCP 服务器失败\",\n 400\n );\n }\n }\n\n /**\n * 重置状态\n * POST /api/status/reset\n */\n async resetStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理重置状态请求\");\n this.statusService.reset();\n c.get(\"logger\").info(\"状态重置成功\");\n return c.success(undefined, \"状态重置成功\");\n } catch (error) {\n return this.handleError(c, error, \"重置状态\", \"STATUS_RESET_ERROR\");\n }\n }\n}\n","/**\n * 工具添加 API 相关类型定义\n * 支持多种工具类型的添加,包括 MCP 工具、Coze 工作流等\n */\n\nimport type { JSONSchema as LibJSONSchema } from \"@/lib/mcp/types.js\";\nimport type { CozeWorkflow, WorkflowParameterConfig } from \"./coze.js\";\n\n/**\n * JSON Schema 类型\n * 重新导出 @/lib/mcp/types.js 中的 JSONSchema\n *\n * 注意:此类型与 @xiaozhi-client/shared-types 中的 JSONSchema 相同\n * TODO:将来应从 shared-types 导入 JSONSchema 以消除重复定义\n */\nexport type JSONSchema = LibJSONSchema;\n\n/**\n * 工具处理器配置相关类型\n *\n * 注意:这些类型与 @xiaozhi-client/shared-types/src/mcp/tool-definition.ts 中定义的类型相同\n * TODO:将 toolApi.ts 的类型迁移为从 shared-types 导入,消除重复定义\n * 目前保持本地定义以避免 TypeScript 子路径解析问题(影响 tts、asr 等其他包)\n *\n * 权威定义位置:packages/shared-types/src/mcp/tool-definition.ts\n */\nexport type ToolHandlerConfig =\n | MCPHandlerConfig\n | ProxyHandlerConfig\n | HttpHandlerConfig\n | FunctionHandlerConfig;\n\n/**\n * MCP 处理器配置\n * 用于标准 MCP 服务中的工具\n */\nexport interface MCPHandlerConfig {\n type: \"mcp\";\n config: {\n serviceName: string;\n toolName: string;\n };\n}\n\n/**\n * 代理处理器配置\n * 用于第三方平台代理(如 Coze、OpenAI 等)\n */\nexport interface ProxyHandlerConfig {\n type: \"proxy\";\n platform: \"coze\" | \"openai\" | \"anthropic\" | \"custom\";\n config: Record<string, unknown>;\n}\n\n/**\n * HTTP 处理器配置\n * 用于 HTTP API 工具\n */\nexport interface HttpHandlerConfig {\n type: \"http\";\n config: {\n url: string;\n method?: string;\n headers?: Record<string, string>;\n };\n}\n\n/**\n * 函数处理器配置\n * 用于自定义函数工具\n */\nexport interface FunctionHandlerConfig {\n type: \"function\";\n config: {\n module: string;\n function: string;\n };\n}\n\n/**\n * CustomMCP 工具基础接口\n *\n * 注意:此类型与 @xiaozhi-client/shared-types 中的 CustomMCPTool 相同\n * TODO:将来应从 shared-types 导入 CustomMCPTool 以消除重复定义\n */\nexport interface CustomMCPToolBase {\n /** 工具唯一标识符 */\n name: string;\n /** 工具描述信息 */\n description: string;\n /** 工具输入参数的 JSON Schema 定义 */\n inputSchema: JSONSchema;\n /** 处理器配置 */\n handler: ToolHandlerConfig;\n}\n\n/**\n * 带统计信息的 CustomMCP 工具\n * 用于 API 响应,使用扁平的统计信息结构\n *\n * 注意:此类型与 @xiaozhi-client/shared-types 中的 CustomMCPToolWithStats 类似\n * 但不包含 `enabled` 字段。如需完整功能,请从 shared-types 导入\n */\nexport interface CustomMCPToolWithStats extends CustomMCPToolBase {\n /** 工具使用次数(扁平结构,与 API 响应格式一致) */\n usageCount?: number;\n /** 最后使用时间(ISO 8601 格式) */\n lastUsedTime?: string;\n}\n\n/**\n * 工具类型枚举\n */\nexport enum ToolType {\n /** MCP 工具(标准 MCP 服务中的工具) */\n MCP = \"mcp\",\n /** Coze 工作流工具 */\n COZE = \"coze\",\n /** HTTP API 工具(预留) */\n HTTP = \"http\",\n /** 自定义函数工具(预留) */\n FUNCTION = \"function\",\n}\n\n/**\n * MCP 工具数据\n * 用于将标准 MCP 服务中的工具添加到 customMCP.tools 配置中\n */\nexport interface MCPToolData {\n /** MCP 服务名称 */\n serviceName: string;\n /** 工具名称 */\n toolName: string;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * Coze 工作流数据\n * 保持与现有格式的兼容性\n */\nexport interface CozeWorkflowData {\n /** Coze 工作流信息 */\n workflow: CozeWorkflow;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n /** 可选的参数配置 */\n parameterConfig?: WorkflowParameterConfig;\n}\n\n/**\n * HTTP API 工具数据(预留)\n */\nexport interface HttpApiToolData {\n /** API 地址 */\n url: string;\n /** HTTP 方法 */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n /** API 描述 */\n description: string;\n /** 请求头 */\n headers?: Record<string, string>;\n /** 请求体模板 */\n bodyTemplate?: string;\n /** 认证配置 */\n auth?: {\n type: \"bearer\" | \"basic\" | \"api_key\";\n token?: string;\n username?: string;\n password?: string;\n apiKey?: string;\n apiKeyHeader?: string;\n };\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * 函数工具数据(预留)\n */\nexport interface FunctionToolData {\n /** 模块路径 */\n module: string;\n /** 函数名 */\n function: string;\n /** 函数描述 */\n description: string;\n /** 函数执行上下文 */\n context?: Record<string, any>;\n /** 超时时间 */\n timeout?: number;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * 添加自定义工具的统一请求接口\n */\nexport interface AddCustomToolRequest {\n /** 工具类型 */\n type: ToolType;\n /** 工具数据(根据类型不同而不同) */\n data: MCPToolData | CozeWorkflowData | HttpApiToolData | FunctionToolData;\n}\n\n/**\n * 工具验证错误类型\n */\nexport enum ToolValidationError {\n /** 无效的工具类型 */\n INVALID_TOOL_TYPE = \"INVALID_TOOL_TYPE\",\n /** 缺少必需字段 */\n MISSING_REQUIRED_FIELD = \"MISSING_REQUIRED_FIELD\",\n /** 工具不存在 */\n TOOL_NOT_FOUND = \"TOOL_NOT_FOUND\",\n /** 服务不存在 */\n SERVICE_NOT_FOUND = \"SERVICE_NOT_FOUND\",\n /** 工具名称冲突 */\n TOOL_NAME_CONFLICT = \"TOOL_NAME_CONFLICT\",\n /** 配置验证失败 */\n CONFIG_VALIDATION_FAILED = \"CONFIG_VALIDATION_FAILED\",\n /** 系统配置错误 */\n SYSTEM_CONFIG_ERROR = \"SYSTEM_CONFIG_ERROR\",\n /** 资源限制超出 */\n RESOURCE_LIMIT_EXCEEDED = \"RESOURCE_LIMIT_EXCEEDED\",\n}\n\n/**\n * 工具验证错误详情\n */\nexport interface ToolValidationErrorDetail {\n /** 错误类型 */\n error: ToolValidationError;\n /** 错误消息 */\n message: string;\n /** 错误详情 */\n details?: any;\n /** 建议的解决方案 */\n suggestions?: string[];\n}\n\n/**\n * 添加工具的响应数据\n */\nexport interface AddToolResponse {\n /** 成功添加的工具 */\n tool: any;\n /** 工具名称 */\n toolName: string;\n /** 工具类型 */\n toolType: ToolType;\n /** 添加时间戳 */\n addedAt: string;\n}\n\n/**\n * 工具元数据信息\n */\nexport interface ToolMetadata {\n /** 工具原始来源 */\n source: {\n type: \"mcp\" | \"coze\" | \"http\" | \"function\";\n serviceName?: string;\n toolName?: string;\n url?: string;\n };\n /** 添加时间 */\n addedAt: string;\n /** 最后更新时间 */\n updatedAt?: string;\n /** 版本信息 */\n version?: string;\n}\n\n/**\n * 工具配置选项\n */\nexport interface ToolConfigOptions {\n /** 是否启用工具(默认 true) */\n enabled?: boolean;\n /** 超时时间(毫秒) */\n timeout?: number;\n /** 重试次数 */\n retryCount?: number;\n /** 重试间隔(毫秒) */\n retryDelay?: number;\n /** 自定义标签 */\n tags?: string[];\n /** 工具分组 */\n group?: string;\n}\n","/**\n * MCP 工具排序工具模块\n * 提供可扩展的排序策略,支持多种排序方式\n */\n\nimport { logger } from \"@/Logger.js\";\nimport type { EnhancedToolInfo } from \"@/lib/mcp\";\n\nexport type ToolSortField = \"name\" | \"enabled\" | \"usageCount\" | \"lastUsedTime\";\n\nexport interface ToolSortConfig {\n field: ToolSortField;\n}\n\n/**\n * 排序函数类型\n */\ntype SortFn = (a: EnhancedToolInfo, b: EnhancedToolInfo) => number;\n\n/**\n * 工具排序策略\n * 新增排序方式只需在此处添加对应的排序函数\n */\nexport const toolSorters: Record<ToolSortField, SortFn> = {\n /**\n * 按名称排序(默认排序)\n * 规则:服务名 a-z → 工具名 a-z\n */\n name: (a, b) => {\n // 先按服务名排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n // 服务名相同时,按工具名排序\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n\n /**\n * 按启用状态排序\n * 规则:已启用在前,已禁用在后;同状态内按名称排序\n */\n enabled: (a, b) => {\n // 先按启用状态排序(已启用在前)\n const enabledCompare = Number(b.enabled) - Number(a.enabled);\n if (enabledCompare !== 0) {\n return enabledCompare;\n }\n // 同状态内按名称排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n\n /**\n * 按使用次数排序\n * 规则:使用次数多的在前;同次数时按名称排序\n */\n usageCount: (a, b) => {\n // 按使用次数降序排序(次数多的在前)\n const countCompare = b.usageCount - a.usageCount;\n if (countCompare !== 0) return countCompare;\n // 使用次数相同时,按服务名和工具名排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n\n /**\n * 按最近使用时间排序\n * 规则:最近使用的在前;未使用时间的工具排在后面\n */\n lastUsedTime: (a, b) => {\n // 未使用时间的工具排在后面\n if (!a.lastUsedTime) return 1;\n if (!b.lastUsedTime) return -1;\n // 按时间降序排序(最近的在前)\n const timeCompare =\n new Date(b.lastUsedTime).getTime() - new Date(a.lastUsedTime).getTime();\n if (timeCompare !== 0) return timeCompare;\n // 时间相同时,按服务名和工具名排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n};\n\n/**\n * 应用排序到工具列表\n */\nexport function sortTools(\n tools: EnhancedToolInfo[],\n config: ToolSortConfig\n): EnhancedToolInfo[] {\n const sorter = toolSorters[config.field];\n if (!sorter) {\n logger.warn(`[sortTools] 未知的排序字段: ${config.field}`);\n return tools;\n }\n\n return [...tools].sort(sorter);\n}\n","/**\n * MCP 工具调用 API 处理器\n * 处理通过 HTTP API 调用 MCP 工具的请求\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { HTTP_TIMEOUTS } from \"@/constants/timeout.constants.js\";\nimport { MCPError, MCPErrorCode } from \"@/errors/mcp-errors.js\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { EnhancedToolInfo } from \"@/lib/mcp/types.js\";\nimport type { CozeWorkflow, WorkflowParameterConfig } from \"@/types/coze.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type {\n AddCustomToolRequest,\n AddToolResponse,\n CozeWorkflowData,\n MCPToolData,\n} from \"@/types/toolApi.js\";\nimport { ToolType } from \"@/types/toolApi.js\";\nimport type { CustomMCPToolWithStats, JSONSchema } from \"@/types/toolApi.js\";\nimport { type ToolSortField, sortTools } from \"@/utils/toolSorters\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { CustomMCPTool, ProxyHandlerConfig } from \"@xiaozhi-client/config\";\nimport Ajv from \"ajv\";\nimport dayjs from \"dayjs\";\nimport type { Context } from \"hono\";\n\n/**\n * 工具调用请求接口\n */\ninterface ToolCallRequest {\n serviceName: string;\n toolName: string;\n args: Record<string, unknown>;\n}\n\n/**\n * 添加自定义工具请求接口(向后兼容)\n * @deprecated 使用新的 AddCustomToolRequest 类型定义\n */\ninterface LegacyAddCustomToolRequest {\n workflow: CozeWorkflow;\n customName?: string;\n customDescription?: string;\n parameterConfig?: WorkflowParameterConfig;\n}\n\n/**\n * MCP 工具调用 API 处理器\n */\nexport class MCPToolHandler {\n // 预编译的正则表达式常量,避免在频繁调用时重复创建\n private static readonly UNDERSCORE_TRIM_REGEX = /^_+|_+$/g;\n private static readonly LETTER_START_REGEX = /^[a-zA-Z]/;\n private static readonly CHINESE_CHAR_REGEX = /[\\u4e00-\\u9fa5]/;\n private static readonly DIGITS_ONLY_REGEX = /^\\d+$/;\n private static readonly ALPHANUMERIC_UNDERSCORE_REGEX = /^[a-zA-Z0-9_-]+$/;\n private static readonly IDENTIFIER_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n private logger: Logger;\n private ajv: Ajv;\n private static readonly TOOL_TYPE_VALUES = Object.values(ToolType);\n\n constructor() {\n this.logger = logger;\n this.ajv = new Ajv({ allErrors: true, verbose: true });\n }\n\n /**\n * 调用 MCP 工具\n * POST /api/tools/call\n */\n async callTool(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理工具调用请求\");\n\n // 解析请求体\n const requestBody: ToolCallRequest = await c.req.json();\n const { serviceName, toolName, args } = requestBody;\n\n // 验证请求参数\n if (!serviceName || !toolName) {\n return c.fail(\n \"INVALID_REQUEST\",\n \"serviceName 和 toolName 是必需的参数\",\n undefined,\n 400\n );\n }\n\n c.get(\"logger\").info(\n `准备调用工具: ${serviceName}/${toolName},参数:`,\n JSON.stringify(args)\n );\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n\n if (!serviceManager) {\n return c.fail(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\",\n undefined,\n 503\n );\n }\n\n // 验证服务和工具是否存在\n await this.validateServiceAndTool(serviceManager, serviceName, toolName);\n\n // 对于 customMCP 工具,进行参数验证\n if (serviceName === \"customMCP\") {\n await this.validateCustomMCPArguments(\n serviceManager,\n toolName,\n args || {}\n );\n }\n\n // 调用工具 - 特殊处理 customMCP 服务\n let result: unknown;\n if (serviceName === \"customMCP\") {\n // 对于 customMCP 服务,直接使用 toolName 调用,传递长运行任务超时\n result = await serviceManager.callTool(toolName, args || {}, {\n timeout: HTTP_TIMEOUTS.LONG_RUNNING,\n });\n } else {\n // 对于标准 MCP 服务,使用 serviceName__toolName 格式,保持8秒超时\n const toolKey = `${serviceName}__${toolName}`;\n result = await serviceManager.callTool(toolKey, args || {});\n }\n\n // c.get(\"logger\").debug(`工具调用成功: ${serviceName}/${toolName}`);\n\n return c.success(result, \"工具调用成功\");\n } catch (error) {\n c.get(\"logger\").error(\"工具调用失败:\", error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n let errorCode = \"TOOL_CALL_ERROR\";\n\n // 根据错误类型设置不同的错误码\n if (errorMessage.includes(\"不存在\")) {\n errorCode = \"SERVICE_OR_TOOL_NOT_FOUND\";\n } else if (\n errorMessage.includes(\"未启动\") ||\n errorMessage.includes(\"未连接\")\n ) {\n errorCode = \"SERVICE_NOT_AVAILABLE\";\n } else if (errorMessage.includes(\"已被禁用\")) {\n errorCode = \"TOOL_DISABLED\";\n } else if (errorMessage.includes(\"参数验证失败\")) {\n errorCode = \"INVALID_ARGUMENTS\";\n } else if (\n errorMessage.includes(\"CustomMCP\") ||\n errorMessage.includes(\"customMCP\")\n ) {\n errorCode = \"CUSTOM_MCP_ERROR\";\n } else if (\n errorMessage.includes(\"工作流调用失败\") ||\n errorMessage.includes(\"API 请求失败\")\n ) {\n errorCode = \"EXTERNAL_API_ERROR\";\n } else if (errorMessage.includes(\"超时\")) {\n errorCode = \"TIMEOUT_ERROR\";\n }\n\n return c.fail(errorCode, errorMessage, undefined, 500);\n }\n }\n\n /**\n * 获取自定义 MCP 工具列表\n * GET /api/tools/custom\n */\n async getCustomTools(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取自定义 MCP 工具列表请求\");\n\n // 检查配置文件是否存在\n if (!configManager.configExists()) {\n return c.fail(\n \"CONFIG_NOT_FOUND\",\n \"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\",\n undefined,\n 404\n );\n }\n\n // 获取自定义 MCP 工具列表\n let customTools: CustomMCPTool[] = [];\n let configPath = \"\";\n\n try {\n customTools = configManager.getCustomMCPTools();\n configPath = configManager.getConfigPath();\n } catch (error) {\n c.get(\"logger\").error(\"读取自定义 MCP 工具配置失败:\", error);\n return c.fail(\n \"CONFIG_PARSE_ERROR\",\n `配置文件解析失败: ${error instanceof Error ? error.message : \"未知错误\"}`,\n undefined,\n 500\n );\n }\n\n // 检查是否配置了自定义 MCP 工具\n if (!customTools || customTools.length === 0) {\n c.get(\"logger\").info(\"未配置自定义 MCP 工具\");\n return c.success(\n {\n tools: [],\n totalTools: 0,\n configPath,\n },\n \"未配置自定义 MCP 工具\"\n );\n }\n\n // 验证工具配置的有效性\n const isValid = configManager.validateCustomMCPTools(customTools);\n if (!isValid) {\n c.get(\"logger\").warn(\"自定义 MCP 工具配置验证失败\");\n return c.fail(\n \"INVALID_TOOL_CONFIG\",\n \"自定义 MCP 工具配置验证失败,请检查配置文件中的工具定义\",\n undefined,\n 400\n );\n }\n\n c.get(\"logger\").info(\n `获取自定义 MCP 工具列表成功,共 ${customTools.length} 个工具`\n );\n\n return c.success(\n {\n tools: customTools,\n totalTools: customTools.length,\n configPath,\n },\n \"获取自定义 MCP 工具列表成功\"\n );\n } catch (error) {\n c.get(\"logger\").error(\"获取自定义 MCP 工具列表失败:\", error);\n\n return c.fail(\n \"GET_CUSTOM_TOOLS_ERROR\",\n error instanceof Error ? error.message : \"获取自定义 MCP 工具列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取可用工具列表\n * GET /api/tools/list?status=enabled|disabled|all&sortBy=name\n *\n * @param status 筛选状态:'enabled'(已启用)、'disabled'(未启用)、'all'(全部,默认)\n * @param sortBy 排序字段:'name'(工具名称,默认)、'enabled'(启用状态)、'usageCount'(使用次数)、'lastUsedTime'(最近使用时间)\n */\n async listTools(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取工具列表请求\");\n\n // 获取筛选参数\n const status =\n (c.req.query(\"status\") as \"enabled\" | \"disabled\" | \"all\") || \"all\";\n\n // 解析排序参数并验证\n const sortByParam = c.req.query(\"sortBy\");\n const validSortFields: ToolSortField[] = [\n \"name\",\n \"enabled\",\n \"usageCount\",\n \"lastUsedTime\",\n ];\n const sortBy = validSortFields.includes(sortByParam as ToolSortField)\n ? (sortByParam as ToolSortField)\n : \"name\";\n\n // 如果提供了无效的排序字段,返回错误\n if (\n sortByParam &&\n !validSortFields.includes(sortByParam as ToolSortField)\n ) {\n return c.fail(\n \"INVALID_SORT_FIELD\",\n `无效的排序字段: ${sortByParam}。支持的排序字段: ${validSortFields.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n if (!serviceManager) {\n return c.fail(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\",\n undefined,\n 503\n );\n }\n\n let rawTools: EnhancedToolInfo[] = serviceManager.getAllTools(status);\n\n // 应用排序\n rawTools = sortTools(rawTools, { field: sortBy });\n\n // 转换为 CustomMCPToolWithStats 格式(使用共享类型)\n const tools: CustomMCPToolWithStats[] = rawTools.map(\n (tool: EnhancedToolInfo) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n handler: {\n type: \"mcp\",\n config: {\n serviceName: tool.serviceName,\n toolName: tool.originalName,\n },\n },\n enabled: tool.enabled,\n usageCount: tool.usageCount,\n lastUsedTime: tool.lastUsedTime,\n })\n );\n\n // 返回对象格式的响应\n const responseData = {\n list: tools,\n total: tools.length,\n };\n\n return c.success(responseData, `获取工具列表成功(${status})`);\n } catch (error) {\n c.get(\"logger\").error(\"获取工具列表失败:\", error);\n\n return c.fail(\"GET_TOOLS_FAILED\", \"获取工具列表失败\", undefined, 500);\n }\n }\n\n /**\n * 验证服务和工具是否存在\n * @private\n */\n private async validateServiceAndTool(\n serviceManager: MCPServiceManager,\n serviceName: string,\n toolName: string\n ): Promise<void> {\n // 特殊处理 customMCP 服务\n if (serviceName === \"customMCP\") {\n // 验证 customMCP 工具是否存在\n if (!serviceManager.hasCustomMCPTool(toolName)) {\n const availableTools = serviceManager\n .getCustomMCPTools()\n .map((tool) => tool.name);\n\n if (availableTools.length === 0) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `customMCP 工具 '${toolName}' 不存在。当前没有配置任何 customMCP 工具。请检查 xiaozhi.config.json 中的 customMCP 配置。`\n );\n }\n\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `customMCP 工具 '${toolName}' 不存在。可用的 customMCP 工具: ${availableTools.join(\", \")}。请使用 'xiaozhi mcp list' 查看所有可用工具。`\n );\n }\n\n // 验证 customMCP 工具配置是否有效\n try {\n const customTools = serviceManager.getCustomMCPTools();\n const targetTool = customTools.find((tool) => tool.name === toolName);\n\n if (targetTool && !targetTool.description) {\n this.logger.warn(`customMCP 工具 '${toolName}' 缺少描述信息`);\n }\n\n if (targetTool && !targetTool.inputSchema) {\n this.logger.warn(`customMCP 工具 '${toolName}' 缺少输入参数定义`);\n }\n } catch (error) {\n this.logger.error(\n `验证 customMCP 工具 '${toolName}' 配置时出错:`,\n error\n );\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `customMCP 工具 '${toolName}' 配置验证失败。请检查配置文件中的工具定义。`\n );\n }\n\n return;\n }\n }\n\n /**\n * 验证 customMCP 工具的参数\n * @private\n */\n private async validateCustomMCPArguments(\n serviceManager: MCPServiceManager,\n toolName: string,\n args: Record<string, unknown>\n ): Promise<void> {\n try {\n // 获取工具的 inputSchema\n const customTools = serviceManager.getCustomMCPTools();\n const targetTool = customTools.find((tool) => tool.name === toolName);\n\n if (!targetTool) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `customMCP 工具 '${toolName}' 不存在`\n );\n }\n\n // 如果工具没有定义 inputSchema,跳过验证\n if (!targetTool.inputSchema) {\n this.logger.warn(\n `customMCP 工具 '${toolName}' 没有定义 inputSchema,跳过参数验证`\n );\n return;\n }\n\n // 使用 AJV 验证参数\n const validate = this.ajv.compile(targetTool.inputSchema);\n const valid = validate(args);\n\n if (!valid) {\n // 构建详细的错误信息\n const errors = validate.errors || [];\n const errorMessages = errors.map((error) => {\n const path = error.instancePath || error.schemaPath || \"\";\n const message = error.message || \"未知错误\";\n\n if (error.keyword === \"required\") {\n const missingProperty = error.params?.missingProperty || \"未知字段\";\n return `缺少必需参数: ${missingProperty}`;\n }\n\n if (error.keyword === \"type\") {\n const expectedType = error.params?.type || \"未知类型\";\n return `参数 ${path} 类型错误,期望: ${expectedType}`;\n }\n\n if (error.keyword === \"enum\") {\n const allowedValues = error.params?.allowedValues || [];\n return `参数 ${path} 值无效,允许的值: ${allowedValues.join(\", \")}`;\n }\n\n return `参数 ${path} ${message}`;\n });\n\n const errorMessage = `参数验证失败: ${errorMessages.join(\"; \")}`;\n this.logger.error(\n `customMCP 工具 '${toolName}' 参数验证失败:`,\n errorMessage\n );\n\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n errorMessage\n );\n }\n\n this.logger.debug(`customMCP 工具 '${toolName}' 参数验证通过`);\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"参数验证失败\")) {\n throw error;\n }\n\n this.logger.error(`验证 customMCP 工具 '${toolName}' 参数时出错:`, error);\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `参数验证过程中发生错误: ${error instanceof Error ? error.message : \"未知错误\"}`\n );\n }\n }\n\n /**\n * 添加自定义 MCP 工具\n * POST /api/tools/custom\n * 支持多种工具类型:MCP 工具、Coze 工作流等\n */\n async addCustomTool(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理添加自定义工具请求\");\n\n const requestBody = await c.req.json();\n\n // 检查是否为新格式的请求\n if (this.isNewFormatRequest(requestBody)) {\n // 新格式:支持多种工具类型\n return await this.handleNewFormatAddTool(\n c,\n requestBody as AddCustomToolRequest\n );\n }\n // 旧格式:向后兼容\n return await this.handleLegacyFormatAddTool(\n c,\n requestBody as LegacyAddCustomToolRequest\n );\n } catch (error) {\n c.get(\"logger\").error(\"添加自定义工具失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { code, message, status } = this.handleAddToolError(error);\n return c.fail(code, message, undefined, status);\n }\n }\n\n /**\n * 判断是否为新格式的请求\n */\n private isNewFormatRequest(body: unknown): body is AddCustomToolRequest {\n return (\n body !== null &&\n typeof body === \"object\" &&\n !Array.isArray(body) &&\n \"type\" in body &&\n \"data\" in body\n );\n }\n\n /**\n * 处理新格式的添加工具请求\n */\n private async handleNewFormatAddTool(\n c: Context<AppContext>,\n request: AddCustomToolRequest\n ): Promise<Response> {\n const { type, data } = request;\n\n c.get(\"logger\").info(`处理新格式工具添加请求,类型: ${type}`);\n\n // 验证工具类型\n if (!MCPToolHandler.TOOL_TYPE_VALUES.includes(type)) {\n return c.fail(\n \"INVALID_TOOL_TYPE\",\n `不支持的工具类型: ${type}。支持的类型: ${MCPToolHandler.TOOL_TYPE_VALUES.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 根据工具类型分发处理\n switch (type) {\n case ToolType.MCP:\n return await this.handleAddMCPTool(c, data as MCPToolData);\n\n case ToolType.COZE:\n return await this.handleAddCozeTool(c, data as CozeWorkflowData);\n\n case ToolType.HTTP:\n case ToolType.FUNCTION: {\n return c.fail(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n `工具类型 ${type} 暂未实现,请使用 MCP 或 Coze 类型`,\n undefined,\n 501\n );\n }\n\n default: {\n return c.fail(\n \"UNKNOWN_TOOL_TYPE\",\n `未知的工具类型: ${type}`,\n undefined,\n 400\n );\n }\n }\n }\n\n /**\n * 处理旧格式的添加工具请求(向后兼容)\n */\n private async handleLegacyFormatAddTool(\n c: Context<AppContext>,\n request: LegacyAddCustomToolRequest\n ): Promise<Response> {\n c.get(\"logger\").info(\"处理旧格式工具添加请求(向后兼容)\");\n\n const { workflow, customName, customDescription, parameterConfig } =\n request;\n\n // 边界条件预检查\n const preCheckResult = this.performPreChecks(\n workflow,\n customName,\n customDescription\n );\n if (preCheckResult) {\n return c.fail(\n preCheckResult.code,\n preCheckResult.message,\n undefined,\n preCheckResult.status\n );\n }\n\n // 转换工作流为工具配置\n const tool = this.convertWorkflowToTool(\n workflow,\n customName,\n customDescription,\n parameterConfig\n );\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n c.get(\"logger\").info(`成功添加自定义工具: ${tool.name}`);\n\n return c.success({ tool }, `工具 \"${tool.name}\" 添加成功`);\n }\n\n /**\n * 处理添加 MCP 工具\n */\n private async handleAddMCPTool(\n c: Context<AppContext>,\n data: MCPToolData\n ): Promise<Response> {\n const { serviceName, toolName, customName, customDescription } = data;\n\n c.get(\"logger\").info(`处理添加 MCP 工具: ${serviceName}/${toolName}`);\n\n // 验证必需字段\n if (!serviceName || !toolName) {\n return c.fail(\n \"MISSING_REQUIRED_FIELD\",\n \"serviceName 和 toolName 是必需字段\",\n undefined,\n 400\n );\n }\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n if (!serviceManager) {\n return c.fail(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\",\n undefined,\n 503\n );\n }\n\n // 验证服务和工具是否存在\n try {\n await this.validateServiceAndTool(serviceManager, serviceName, toolName);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return c.fail(\"SERVICE_OR_TOOL_NOT_FOUND\", errorMessage, undefined, 404);\n }\n\n // 从缓存中获取工具信息\n const cacheManager = new MCPCacheManager();\n const cachedTools = await cacheManager.getAllCachedTools();\n\n // 查找对应的工具\n const fullToolName = `${serviceName}__${toolName}`;\n const cachedTool = cachedTools.find((tool) => tool.name === fullToolName);\n\n if (!cachedTool) {\n return c.fail(\n \"TOOL_NOT_FOUND\",\n `在缓存中未找到工具: ${serviceName}/${toolName}`,\n undefined,\n 404\n );\n }\n\n // 生成工具名称\n const finalToolName = customName || fullToolName;\n\n // 检查工具名称是否已存在\n const existingTools = configManager.getCustomMCPTools();\n const existingNames = new Set(existingTools.map((tool) => tool.name));\n\n if (existingNames.has(finalToolName)) {\n return c.fail(\n \"TOOL_NAME_CONFLICT\",\n `工具名称 \"${finalToolName}\" 已存在,请使用不同的自定义名称`,\n undefined,\n 409\n );\n }\n\n // 创建 CustomMCPTool 配置\n const tool: CustomMCPTool = {\n name: finalToolName,\n description:\n customDescription ||\n cachedTool.description ||\n `MCP 工具: ${serviceName}/${toolName}`,\n inputSchema: cachedTool.inputSchema || {},\n handler: {\n type: \"mcp\",\n config: {\n serviceName,\n toolName,\n },\n },\n stats: {\n usageCount: 0,\n lastUsedTime: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n },\n };\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n // 对于 MCP 工具,需要在 mcpServerConfig 中同步启用\n c.get(\"logger\").info(\n `检测到 MCP 工具添加,同步启用 mcpServerConfig 中的工具: ${serviceName}/${toolName}`\n );\n\n // 获取当前的服务工具配置\n const serverToolsConfig = configManager.getServerToolsConfig(serviceName);\n\n if (serverToolsConfig?.toolName) {\n // 更新配置,启用该工具\n serverToolsConfig[toolName].enable = true;\n\n // 保存更新后的配置\n configManager.updateServerToolsConfig(serviceName, serverToolsConfig);\n\n c.get(\"logger\").info(\n `已同步启用 mcpServerConfig 中的工具: ${serviceName}/${toolName}`\n );\n }\n\n c.get(\"logger\").info(`成功添加 MCP 工具: ${finalToolName}`);\n\n const responseData: AddToolResponse = {\n tool,\n toolName: finalToolName,\n toolType: ToolType.MCP,\n addedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.success(responseData, `MCP 工具 \"${finalToolName}\" 添加成功`);\n }\n\n /**\n * 处理添加 Coze 工具\n */\n private async handleAddCozeTool(\n c: Context<AppContext>,\n data: CozeWorkflowData\n ): Promise<Response> {\n const { workflow, customName, customDescription, parameterConfig } = data;\n\n c.get(\"logger\").info(`处理添加 Coze 工具: ${workflow.workflow_name}`);\n\n // 边界条件预检查\n const preCheckResult = this.performPreChecks(\n workflow,\n customName,\n customDescription\n );\n if (preCheckResult) {\n return c.fail(\n preCheckResult.code,\n preCheckResult.message,\n undefined,\n preCheckResult.status\n );\n }\n\n // 转换工作流为工具配置\n const tool = this.convertWorkflowToTool(\n workflow,\n customName,\n customDescription,\n parameterConfig\n );\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n c.get(\"logger\").info(`成功添加 Coze 工具: ${tool.name}`);\n\n const responseData: AddToolResponse = {\n tool,\n toolName: tool.name,\n toolType: ToolType.COZE,\n addedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.success(responseData, `Coze 工具 \"${tool.name}\" 添加成功`);\n }\n\n /**\n * 更新自定义 MCP 工具配置\n * PUT /api/tools/custom/:toolName\n */\n async updateCustomTool(c: Context<AppContext>): Promise<Response> {\n try {\n const toolName = c.req.param(\"toolName\");\n\n if (!toolName) {\n return c.fail(\"INVALID_REQUEST\", \"工具名称不能为空\", undefined, 400);\n }\n\n c.get(\"logger\").info(`处理更新自定义工具配置请求: ${toolName}`);\n\n const requestBody = await c.req.json();\n\n // 验证请求体\n if (!requestBody || typeof requestBody !== \"object\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"请求体必须是有效对象\",\n undefined,\n 400\n );\n }\n\n // 检查是否为新格式的请求\n if (this.isNewFormatRequest(requestBody)) {\n // 新格式:支持多种工具类型\n return await this.handleNewFormatUpdateTool(\n c,\n toolName,\n requestBody as AddCustomToolRequest\n );\n }\n\n // 旧格式不支持更新操作\n return c.fail(\n \"INVALID_REQUEST\",\n \"更新操作只支持新格式的请求\",\n undefined,\n 400\n );\n } catch (error) {\n c.get(\"logger\").error(\"更新自定义工具配置失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { code, message, status } = this.handleUpdateToolError(error);\n return c.fail(code, message, undefined, status);\n }\n }\n\n /**\n * 处理新格式的更新工具请求\n */\n private async handleNewFormatUpdateTool(\n c: Context<AppContext>,\n toolName: string,\n request: AddCustomToolRequest\n ): Promise<Response> {\n const { type, data } = request;\n\n c.get(\"logger\").info(`处理新格式工具更新请求,类型: ${type}`);\n\n // 验证工具类型\n if (!MCPToolHandler.TOOL_TYPE_VALUES.includes(type)) {\n return c.fail(\n \"INVALID_TOOL_TYPE\",\n `不支持的工具类型: ${type}。支持的类型: ${MCPToolHandler.TOOL_TYPE_VALUES.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 根据工具类型分发处理\n switch (type) {\n case ToolType.COZE:\n return await this.handleUpdateCozeTool(\n c,\n toolName,\n data as CozeWorkflowData\n );\n\n case ToolType.MCP:\n case ToolType.HTTP:\n case ToolType.FUNCTION: {\n return c.fail(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n `工具类型 ${type} 暂不支持更新操作,目前仅支持 Coze 类型`,\n undefined,\n 501\n );\n }\n\n default: {\n return c.fail(\n \"UNKNOWN_TOOL_TYPE\",\n `未知的工具类型: ${type}`,\n undefined,\n 400\n );\n }\n }\n }\n\n /**\n * 处理更新 Coze 工具\n */\n private async handleUpdateCozeTool(\n c: Context<AppContext>,\n toolName: string,\n data: CozeWorkflowData\n ): Promise<Response> {\n const { workflow, customName, customDescription, parameterConfig } = data;\n\n c.get(\"logger\").info(`处理更新 Coze 工具: ${toolName}`);\n\n // 验证工具是否存在\n const existingTools = configManager.getCustomMCPTools();\n const existingTool = existingTools.find((tool) => tool.name === toolName);\n\n if (!existingTool) {\n return c.fail(\n \"TOOL_NOT_FOUND\",\n `工具 \"${toolName}\" 不存在`,\n undefined,\n 404\n );\n }\n\n // 验证是否为 Coze 工具\n if (\n existingTool.handler.type !== \"proxy\" ||\n existingTool.handler.platform !== \"coze\"\n ) {\n return c.fail(\n \"INVALID_TOOL_TYPE\",\n `工具 \"${toolName}\" 不是 Coze 工作流工具,不支持参数配置更新`,\n undefined,\n 400\n );\n }\n\n // 如果前端提供的 workflow 中没有 workflow_id,尝试从现有工具中获取\n if (!workflow.workflow_id && existingTool.handler?.config?.workflow_id) {\n workflow.workflow_id = existingTool.handler.config.workflow_id;\n }\n\n // 如果还没有 workflow_id,尝试从其他字段获取\n if (!workflow.workflow_id && workflow.app_id) {\n // 对于某些场景,app_id 可以作为替代标识\n // 但我们仍然需要 workflow_id 用于 Coze API 调用\n c.get(\"logger\").warn(\n `工作流 ${toolName} 缺少 workflow_id,这可能会影响某些功能`\n );\n }\n\n // 验证工作流数据完整性\n this.validateWorkflowUpdateData(workflow);\n\n // 更新工具的 inputSchema\n const updatedInputSchema = this.generateInputSchema(\n workflow,\n parameterConfig\n );\n\n // 构建更新后的工具配置\n const updatedTool: CustomMCPTool = {\n ...existingTool,\n description: customDescription || existingTool.description,\n inputSchema: updatedInputSchema,\n };\n\n // 更新工具配置\n configManager.updateCustomMCPTool(toolName, updatedTool);\n\n c.get(\"logger\").info(`成功更新 Coze 工具: ${toolName}`);\n\n const responseData = {\n tool: updatedTool,\n toolName: toolName,\n toolType: ToolType.COZE,\n updatedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.success(responseData, `Coze 工具 \"${toolName}\" 配置更新成功`);\n }\n\n /**\n * 处理更新工具时的错误\n */\n private handleUpdateToolError(error: unknown): {\n code: string;\n message: string;\n status: number;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"更新自定义工具配置失败\";\n\n // 工具不存在错误 (404)\n if (errorMessage.includes(\"不存在\") || errorMessage.includes(\"未找到\")) {\n return {\n code: \"TOOL_NOT_FOUND\",\n message: `${errorMessage}。请检查工具名称是否正确`,\n status: 404,\n };\n }\n\n // 工具类型错误 (400)\n if (\n errorMessage.includes(\"工具类型\") ||\n errorMessage.includes(\"INVALID_TOOL_TYPE\")\n ) {\n return {\n code: \"INVALID_TOOL_TYPE\",\n message: errorMessage,\n status: 400,\n };\n }\n\n // 参数错误 (400)\n if (errorMessage.includes(\"不能为空\") || errorMessage.includes(\"无效\")) {\n return {\n code: \"INVALID_REQUEST\",\n message: `${errorMessage}。请提供有效的工具配置数据`,\n status: 400,\n };\n }\n\n // 配置错误 (422)\n if (errorMessage.includes(\"配置\") || errorMessage.includes(\"权限\")) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: `${errorMessage}。请检查配置文件权限和格式是否正确`,\n status: 422,\n };\n }\n\n // 未实现功能错误 (501)\n if (\n errorMessage.includes(\"未实现\") ||\n errorMessage.includes(\"NOT_IMPLEMENTED\")\n ) {\n return {\n code: \"TOOL_TYPE_NOT_IMPLEMENTED\",\n message: errorMessage,\n status: 501,\n };\n }\n\n // 系统错误 (500)\n return {\n code: \"UPDATE_CUSTOM_TOOL_ERROR\",\n message: `更新工具配置失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`,\n status: 500,\n };\n }\n\n /**\n * 删除自定义 MCP 工具\n * DELETE /api/tools/custom/:toolName\n */\n async removeCustomTool(c: Context<AppContext>): Promise<Response> {\n try {\n const toolName = c.req.param(\"toolName\");\n\n if (!toolName) {\n return c.fail(\"INVALID_REQUEST\", \"工具名称不能为空\", undefined, 400);\n }\n\n c.get(\"logger\").info(`处理删除自定义工具请求: ${toolName}`);\n\n // 在删除之前,检查是否为 MCP 工具,如果是则需要在 mcpServerConfig 中同步禁用\n const existingTools = configManager.getCustomMCPTools();\n const toolToDelete = existingTools.find((tool) => tool.name === toolName);\n\n if (toolToDelete && toolToDelete.handler.type === \"mcp\") {\n // 这是 MCP 工具,需要在 mcpServerConfig 中同步禁用\n const mcpConfig = toolToDelete.handler.config;\n if (mcpConfig.serviceName && mcpConfig.toolName) {\n c.get(\"logger\").info(\n `检测到 MCP 工具删除,同步禁用 mcpServerConfig 中的工具: ${mcpConfig.serviceName}/${mcpConfig.toolName}`\n );\n\n // 获取当前的服务工具配置\n const serverToolsConfig = configManager.getServerToolsConfig(\n mcpConfig.serviceName\n );\n\n if (serverToolsConfig?.[mcpConfig.toolName]) {\n // 更新配置,禁用该工具\n serverToolsConfig[mcpConfig.toolName].enable = false;\n\n // 保存更新后的配置\n configManager.updateServerToolsConfig(\n mcpConfig.serviceName,\n serverToolsConfig\n );\n\n c.get(\"logger\").info(\n `已同步禁用 mcpServerConfig 中的工具: ${mcpConfig.serviceName}/${mcpConfig.toolName}`\n );\n }\n }\n }\n\n // 从配置中删除工具\n configManager.removeCustomMCPTool(toolName);\n\n c.get(\"logger\").info(`成功删除自定义工具: ${toolName}`);\n\n return c.success(null, `工具 \"${toolName}\" 删除成功`);\n } catch (error) {\n c.get(\"logger\").error(\"删除自定义工具失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { code, message, status } = this.handleRemoveToolError(error);\n return c.fail(code, message, undefined, status);\n }\n }\n\n /**\n * 将扣子工作流转换为自定义 MCP 工具\n */\n private convertWorkflowToTool(\n workflow: CozeWorkflow,\n customName?: string,\n customDescription?: string,\n parameterConfig?: WorkflowParameterConfig\n ): CustomMCPTool {\n // 验证工作流数据完整性\n this.validateWorkflowData(workflow);\n\n // 生成工具名称(处理冲突)\n const baseName =\n customName || this.sanitizeToolName(workflow.workflow_name);\n const toolName = this.resolveToolNameConflict(baseName);\n\n // 生成工具描述\n const description = this.generateToolDescription(\n workflow,\n customDescription\n );\n\n // 生成输入参数结构\n const inputSchema = this.generateInputSchema(workflow, parameterConfig);\n\n // 配置 HTTP 处理器\n const handler = this.createHttpHandler(workflow);\n\n // 创建工具配置\n const tool: CustomMCPTool = {\n name: toolName,\n description,\n inputSchema,\n handler,\n };\n\n // 验证生成的工具配置\n this.validateGeneratedTool(tool);\n\n return tool;\n }\n\n /**\n * 规范化工具名称\n */\n private sanitizeToolName(name: string): string {\n if (!name || typeof name !== \"string\") {\n return \"coze_workflow_unnamed\";\n }\n\n // 去除首尾空格\n let sanitized = name.trim();\n\n if (!sanitized) {\n return \"coze_workflow_empty\";\n }\n\n // 将中文转换为拼音或英文描述(简化处理)\n sanitized = this.convertChineseToEnglish(sanitized);\n\n // 移除特殊字符,只保留字母、数字和下划线\n sanitized = sanitized.replace(/[^a-zA-Z0-9_]/g, \"_\");\n\n // 移除连续的下划线\n sanitized = sanitized.replace(/_+/g, \"_\");\n\n // 移除开头和结尾的下划线\n sanitized = sanitized.replace(MCPToolHandler.UNDERSCORE_TRIM_REGEX, \"\");\n\n // 确保以字母开头\n if (!MCPToolHandler.LETTER_START_REGEX.test(sanitized)) {\n sanitized = `coze_workflow_${sanitized}`;\n }\n\n // 限制长度(保留足够空间给数字后缀)\n if (sanitized.length > 45) {\n sanitized = sanitized.substring(0, 45);\n }\n\n // 确保不为空\n if (!sanitized) {\n sanitized = \"coze_workflow_tool\";\n }\n\n return sanitized;\n }\n\n /**\n * 简单的中文到英文转换(可以扩展为更复杂的拼音转换)\n */\n private convertChineseToEnglish(text: string): string {\n // 常见中文词汇的映射\n const chineseToEnglishMap: Record<string, string> = {\n 工作流: \"workflow\",\n 测试: \"test\",\n 数据: \"data\",\n 处理: \"process\",\n 分析: \"analysis\",\n 生成: \"generate\",\n 查询: \"query\",\n 搜索: \"search\",\n 转换: \"convert\",\n 计算: \"calculate\",\n 统计: \"statistics\",\n 报告: \"report\",\n 文档: \"document\",\n 图片: \"image\",\n 视频: \"video\",\n 音频: \"audio\",\n 文本: \"text\",\n 翻译: \"translate\",\n 识别: \"recognize\",\n 检测: \"detect\",\n 监控: \"monitor\",\n 管理: \"manage\",\n 配置: \"config\",\n 设置: \"setting\",\n 用户: \"user\",\n 系统: \"system\",\n 服务: \"service\",\n 接口: \"api\",\n 数据库: \"database\",\n 网络: \"network\",\n 安全: \"security\",\n 备份: \"backup\",\n 恢复: \"restore\",\n 同步: \"sync\",\n 导入: \"import\",\n 导出: \"export\",\n 上传: \"upload\",\n 下载: \"download\",\n };\n\n let result = text;\n\n // 替换常见中文词汇\n for (const [chinese, english] of Object.entries(chineseToEnglishMap)) {\n result = result.replace(new RegExp(chinese, \"g\"), english);\n }\n\n // 如果还有中文字符,用拼音前缀替代\n if (MCPToolHandler.CHINESE_CHAR_REGEX.test(result)) {\n result = `chinese_${result}`;\n }\n\n return result;\n }\n\n /**\n * 验证工作流数据完整性\n */\n private validateWorkflowData(workflow: CozeWorkflow): void {\n if (!workflow) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流数据不能为空\"\n );\n }\n\n // 验证必需字段\n this.validateRequiredFields(workflow);\n\n // 验证字段格式\n this.validateFieldFormats(workflow);\n\n // 验证字段长度\n this.validateFieldLengths(workflow);\n\n // 验证业务逻辑\n this.validateBusinessLogic(workflow);\n }\n\n /**\n * 验证工作流更新数据完整性\n * 用于更新场景,只验证关键字段\n */\n private validateWorkflowUpdateData(workflow: Partial<CozeWorkflow>): void {\n if (!workflow) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流数据不能为空\"\n );\n }\n\n // 对于更新操作,我们采用更灵活的验证策略\n // 因为这可能是参数配置更新,而不是工作流本身更新\n\n // 如果提供了 workflow_id,验证其格式\n if (workflow.workflow_id) {\n if (\n typeof workflow.workflow_id !== \"string\" ||\n workflow.workflow_id.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流ID必须是非空字符串\"\n );\n }\n\n // 验证工作流ID格式(数字字符串)\n if (!MCPToolHandler.DIGITS_ONLY_REGEX.test(workflow.workflow_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流ID格式无效,应为数字字符串\"\n );\n }\n }\n\n // 如果存在 workflow_name,验证其格式\n if (workflow.workflow_name) {\n if (\n typeof workflow.workflow_name !== \"string\" ||\n workflow.workflow_name.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流名称必须是非空字符串\"\n );\n }\n\n // 验证工作流名称长度\n if (workflow.workflow_name.length > 100) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流名称过长,不能超过100个字符\"\n );\n }\n }\n\n // 如果存在 app_id,验证其格式\n if (workflow.app_id) {\n if (\n typeof workflow.app_id !== \"string\" ||\n workflow.app_id.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID必须是非空字符串\"\n );\n }\n\n // 验证应用ID格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(workflow.app_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n\n // 验证应用ID长度\n if (workflow.app_id.length > 50) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID过长,不能超过50个字符\"\n );\n }\n }\n\n // 对于参数配置更新,workflow_id 可能不是必需的\n // 因为实际的工作流ID已经存储在工具配置中\n // 我们主要验证存在字段的格式,而不是强制要求所有字段都存在\n }\n\n /**\n * 验证必需字段\n */\n private validateRequiredFields(workflow: CozeWorkflow): void {\n const requiredFields = [\n { field: \"workflow_id\", name: \"工作流ID\" },\n { field: \"workflow_name\", name: \"工作流名称\" },\n { field: \"app_id\", name: \"应用ID\" },\n ];\n\n for (const { field, name } of requiredFields) {\n const value = workflow[field as keyof CozeWorkflow];\n if (!value || typeof value !== \"string\" || value.trim() === \"\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `${name}不能为空且必须是非空字符串`\n );\n }\n }\n }\n\n /**\n * 验证字段格式\n */\n private validateFieldFormats(workflow: CozeWorkflow): void {\n // 验证工作流ID格式(数字字符串)\n if (!MCPToolHandler.DIGITS_ONLY_REGEX.test(workflow.workflow_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流ID格式无效,应为数字字符串\"\n );\n }\n\n // 验证应用ID格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(workflow.app_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n\n // 验证图标URL格式(如果存在)\n if (workflow.icon_url?.trim()) {\n try {\n new URL(workflow.icon_url);\n } catch {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"图标URL格式无效\"\n );\n }\n }\n\n // 验证时间戳格式\n if (\n workflow.created_at &&\n (!Number.isInteger(workflow.created_at) || workflow.created_at <= 0)\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"创建时间格式无效,应为正整数时间戳\"\n );\n }\n\n if (\n workflow.updated_at &&\n (!Number.isInteger(workflow.updated_at) || workflow.updated_at <= 0)\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"更新时间格式无效,应为正整数时间戳\"\n );\n }\n }\n\n /**\n * 验证字段长度\n */\n private validateFieldLengths(workflow: CozeWorkflow): void {\n const lengthLimits = [\n { field: \"workflow_name\", name: \"工作流名称\", max: 100 },\n { field: \"description\", name: \"工作流描述\", max: 500 },\n { field: \"app_id\", name: \"应用ID\", max: 50 },\n ];\n\n for (const { field, name, max } of lengthLimits) {\n const value = workflow[field as keyof CozeWorkflow] as string;\n if (value && value.length > max) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `${name}过长,不能超过${max}个字符`\n );\n }\n }\n }\n\n /**\n * 验证业务逻辑\n */\n private validateBusinessLogic(workflow: CozeWorkflow): void {\n // 验证创建者信息\n if (workflow.creator) {\n if (!workflow.creator.id || typeof workflow.creator.id !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"创建者ID不能为空且必须是字符串\"\n );\n }\n if (!workflow.creator.name || typeof workflow.creator.name !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"创建者名称不能为空且必须是字符串\"\n );\n }\n }\n\n // 验证时间逻辑\n if (\n workflow.created_at &&\n workflow.updated_at &&\n workflow.updated_at < workflow.created_at\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"更新时间不能早于创建时间\"\n );\n }\n\n // 验证工作流名称不能包含敏感词\n const sensitiveWords = [\n \"admin\",\n \"root\",\n \"system\",\n \"config\",\n \"password\",\n \"token\",\n ];\n const lowerName = workflow.workflow_name.toLowerCase();\n for (const word of sensitiveWords) {\n if (lowerName.includes(word)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `工作流名称不能包含敏感词: ${word}`\n );\n }\n }\n }\n\n /**\n * 解决工具名称冲突\n */\n private resolveToolNameConflict(baseName: string): string {\n const existingTools = configManager.getCustomMCPTools();\n const existingNames = new Set(existingTools.map((tool) => tool.name));\n\n let finalName = baseName;\n let counter = 1;\n\n // 如果名称已存在,添加数字后缀\n while (existingNames.has(finalName)) {\n finalName = `${baseName}_${counter}`;\n counter++;\n\n // 防止无限循环\n if (counter > 999) {\n throw MCPError.operationError(\n MCPErrorCode.OPERATION_FAILED,\n `无法为工具生成唯一名称,基础名称: ${baseName}`\n );\n }\n }\n\n return finalName;\n }\n\n /**\n * 生成工具描述\n */\n private generateToolDescription(\n workflow: CozeWorkflow,\n customDescription?: string\n ): string {\n if (customDescription) {\n return customDescription;\n }\n\n if (workflow.description?.trim()) {\n return workflow.description.trim();\n }\n\n // 生成默认描述\n return `扣子工作流工具: ${workflow.workflow_name}`;\n }\n\n /**\n * 创建HTTP处理器配置\n */\n private createHttpHandler(workflow: CozeWorkflow): ProxyHandlerConfig {\n // 验证扣子API配置\n this.validateCozeApiConfig();\n\n return {\n type: \"proxy\",\n platform: \"coze\",\n config: {\n workflow_id: workflow.workflow_id,\n },\n };\n }\n\n /**\n * 验证扣子API配置\n */\n private validateCozeApiConfig(): void {\n // 检查是否配置了扣子token\n const cozeConfig = configManager.getCozePlatformConfig();\n if (!cozeConfig || !cozeConfig.token) {\n throw MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n \"未配置扣子API Token,请先在配置中设置 platforms.coze.token\"\n );\n }\n }\n\n /**\n * 验证生成的工具配置\n */\n private validateGeneratedTool(tool: CustomMCPTool): void {\n // 基础结构验证\n this.validateToolStructure(tool);\n\n // 使用configManager的验证方法\n if (!configManager.validateCustomMCPTools([tool])) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"生成的工具配置验证失败,请检查工具定义\"\n );\n }\n\n // JSON Schema验证\n this.validateJsonSchema(tool.inputSchema);\n\n // HTTP处理器验证\n if (tool.handler) {\n this.validateProxyHandler(tool.handler as ProxyHandlerConfig);\n }\n }\n\n /**\n * 验证工具基础结构\n */\n private validateToolStructure(tool: CustomMCPTool): void {\n if (!tool || typeof tool !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具配置必须是有效对象\"\n );\n }\n\n // 验证必需字段\n const requiredFields = [\"name\", \"description\", \"inputSchema\", \"handler\"];\n for (const field of requiredFields) {\n if (!(field in tool) || tool[field as keyof CustomMCPTool] == null) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `工具配置缺少必需字段: ${field}`\n );\n }\n }\n\n // 验证字段类型\n if (typeof tool.name !== \"string\" || tool.name.trim() === \"\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具名称必须是非空字符串\"\n );\n }\n\n if (\n typeof tool.description !== \"string\" ||\n tool.description.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具描述必须是非空字符串\"\n );\n }\n\n if (typeof tool.inputSchema !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构必须是对象\"\n );\n }\n\n if (typeof tool.handler !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"处理器配置必须是对象\"\n );\n }\n }\n\n /**\n * 验证HTTP处理器配置\n */\n private validateProxyHandler(handler: ProxyHandlerConfig): void {\n if (!handler || typeof handler !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"HTTP处理器配置不能为空\"\n );\n }\n\n // 验证处理器类型\n if (handler.type !== \"proxy\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"处理器类型必须是'proxy'\"\n );\n }\n\n if (handler.platform === \"coze\") {\n if (!handler.config.workflow_id) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"Coze处理器必须包含有效的workflow_id\"\n );\n }\n } else {\n throw MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n \"不支持的工作流平台\"\n );\n }\n }\n\n /**\n * 验证认证配置\n */\n private validateAuthConfig(auth: { type: string; token?: string }): void {\n if (!auth || typeof auth !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"认证配置必须是对象\"\n );\n }\n\n if (!auth.type || typeof auth.type !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"认证类型不能为空\"\n );\n }\n\n const validAuthTypes = [\"bearer\", \"basic\", \"api_key\"];\n if (!validAuthTypes.includes(auth.type)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `认证类型必须是以下之一: ${validAuthTypes.join(\", \")}`\n );\n }\n\n // 验证token格式\n if (auth.type === \"bearer\") {\n if (!auth.token || typeof auth.token !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"Bearer认证必须包含有效的token\"\n );\n }\n\n // 验证token格式(应该是环境变量引用或实际token)\n if (\n !auth.token.startsWith(\"${\") &&\n !MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(auth.token)\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"Bearer token格式无效\"\n );\n }\n }\n }\n\n /**\n * 验证请求体模板\n */\n private validateBodyTemplate(bodyTemplate: string): void {\n if (typeof bodyTemplate !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"请求体模板必须是字符串\"\n );\n }\n\n try {\n JSON.parse(bodyTemplate);\n } catch {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"请求体模板必须是有效的JSON格式\"\n );\n }\n\n // 验证模板变量格式\n const templateVars = bodyTemplate.match(/\\{\\{[^}]+\\}\\}/g);\n if (templateVars) {\n for (const templateVar of templateVars) {\n const varName = templateVar.slice(2, -2).trim();\n if (!varName || !MCPToolHandler.IDENTIFIER_REGEX.test(varName)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `模板变量格式无效: ${templateVar}`\n );\n }\n }\n }\n }\n\n /**\n * 验证JSON Schema格式\n */\n private validateJsonSchema(schema: JSONSchema): void {\n if (!schema || typeof schema !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构必须是有效的对象\"\n );\n }\n\n if (!schema.type || schema.type !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构的type必须是'object'\"\n );\n }\n\n if (!schema.properties || typeof schema.properties !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构必须包含properties字段\"\n );\n }\n\n // 验证required字段\n if (schema.required && !Array.isArray(schema.required)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构的required字段必须是数组\"\n );\n }\n }\n\n /**\n * 生成输入参数结构\n */\n private generateInputSchema(\n workflow: CozeWorkflow,\n parameterConfig?: WorkflowParameterConfig\n ): JSONSchema {\n // 如果提供了参数配置,使用参数配置生成schema\n if (parameterConfig && parameterConfig.parameters.length > 0) {\n return this.generateInputSchemaFromConfig(parameterConfig);\n }\n\n // 否则使用默认的基础参数结构\n const baseSchema = {\n type: \"object\",\n properties: {\n input: {\n type: \"string\",\n description: \"输入内容\",\n },\n },\n required: [\"input\"],\n additionalProperties: false,\n };\n\n return baseSchema;\n }\n\n /**\n * 根据参数配置生成输入参数结构\n */\n private generateInputSchemaFromConfig(\n parameterConfig: WorkflowParameterConfig\n ): JSONSchema {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const param of parameterConfig.parameters) {\n properties[param.fieldName] = {\n type: param.type,\n description: param.description,\n };\n\n if (param.required) {\n required.push(param.fieldName);\n }\n }\n\n return {\n type: \"object\",\n properties,\n required: required.length > 0 ? required : undefined,\n additionalProperties: false,\n };\n }\n\n /**\n * 处理添加工具时的错误\n */\n private handleAddToolError(error: unknown): {\n code: string;\n message: string;\n status: number;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"添加自定义工具失败\";\n\n // 工具类型错误 (400)\n if (\n errorMessage.includes(\"工具类型\") ||\n errorMessage.includes(\"TOOL_TYPE\")\n ) {\n return {\n code: \"INVALID_TOOL_TYPE\",\n message: errorMessage,\n status: 400,\n };\n }\n\n // 缺少必需字段错误 (400)\n if (\n errorMessage.includes(\"必需字段\") ||\n errorMessage.includes(\"MISSING_REQUIRED_FIELD\")\n ) {\n return {\n code: \"MISSING_REQUIRED_FIELD\",\n message: errorMessage,\n status: 400,\n };\n }\n\n // 工具或服务不存在错误 (404)\n if (\n errorMessage.includes(\"不存在\") ||\n errorMessage.includes(\"NOT_FOUND\") ||\n errorMessage.includes(\"未找到\")\n ) {\n return {\n code: \"SERVICE_OR_TOOL_NOT_FOUND\",\n message: errorMessage,\n status: 404,\n };\n }\n\n // 服务未初始化错误 (503)\n if (\n errorMessage.includes(\"未初始化\") ||\n errorMessage.includes(\"SERVICE_NOT_INITIALIZED\")\n ) {\n return {\n code: \"SERVICE_NOT_INITIALIZED\",\n message: errorMessage,\n status: 503,\n };\n }\n\n // 工具名称冲突错误 (409)\n if (\n errorMessage.includes(\"已存在\") ||\n errorMessage.includes(\"冲突\") ||\n errorMessage.includes(\"TOOL_NAME_CONFLICT\")\n ) {\n return {\n code: \"TOOL_NAME_CONFLICT\",\n message: `${errorMessage}。建议:1) 使用自定义名称;2) 删除现有同名工具后重试`,\n status: 409,\n };\n }\n\n // 数据验证错误 (400)\n if (this.isValidationError(errorMessage)) {\n return {\n code: \"VALIDATION_ERROR\",\n message: this.formatValidationError(errorMessage),\n status: 400,\n };\n }\n\n // 配置错误 (422)\n if (\n errorMessage.includes(\"配置\") ||\n errorMessage.includes(\"token\") ||\n errorMessage.includes(\"API\") ||\n errorMessage.includes(\"CONFIGURATION_ERROR\")\n ) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: `${errorMessage}。请检查:1) 相关配置是否正确;2) 网络连接是否正常;3) 配置文件权限是否正确`,\n status: 422,\n };\n }\n\n // 资源限制错误 (429)\n if (\n errorMessage.includes(\"资源限制\") ||\n errorMessage.includes(\"RESOURCE_LIMIT_EXCEEDED\")\n ) {\n return {\n code: \"RESOURCE_LIMIT_EXCEEDED\",\n message: errorMessage,\n status: 429,\n };\n }\n\n // 未实现功能错误 (501)\n if (\n errorMessage.includes(\"未实现\") ||\n errorMessage.includes(\"NOT_IMPLEMENTED\")\n ) {\n return {\n code: \"TOOL_TYPE_NOT_IMPLEMENTED\",\n message: errorMessage,\n status: 501,\n };\n }\n\n // 系统错误 (500)\n return {\n code: \"ADD_CUSTOM_TOOL_ERROR\",\n message: `添加工具失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`,\n status: 500,\n };\n }\n\n /**\n * 处理删除工具时的错误\n */\n private handleRemoveToolError(error: unknown): {\n code: string;\n message: string;\n status: number;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"删除自定义工具失败\";\n\n // 工具不存在错误 (404)\n if (errorMessage.includes(\"不存在\") || errorMessage.includes(\"未找到\")) {\n return {\n code: \"TOOL_NOT_FOUND\",\n message: `${errorMessage}。请检查工具名称是否正确,或刷新页面查看最新的工具列表`,\n status: 404,\n };\n }\n\n // 参数错误 (400)\n if (errorMessage.includes(\"不能为空\") || errorMessage.includes(\"无效\")) {\n return {\n code: \"INVALID_REQUEST\",\n message: `${errorMessage}。请提供有效的工具名称`,\n status: 400,\n };\n }\n\n // 配置错误 (422)\n if (errorMessage.includes(\"配置\") || errorMessage.includes(\"权限\")) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: `${errorMessage}。请检查配置文件权限和格式是否正确`,\n status: 422,\n };\n }\n\n // 系统错误 (500)\n return {\n code: \"REMOVE_CUSTOM_TOOL_ERROR\",\n message: `删除工具失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`,\n status: 500,\n };\n }\n\n /**\n * 判断是否为数据验证错误\n */\n private isValidationError(errorMessage: string): boolean {\n const validationKeywords = [\n \"不能为空\",\n \"必须是\",\n \"格式无效\",\n \"过长\",\n \"过短\",\n \"验证失败\",\n \"无效\",\n \"不符合\",\n \"超过\",\n \"少于\",\n \"敏感词\",\n \"时间\",\n \"URL\",\n ];\n\n return validationKeywords.some((keyword) => errorMessage.includes(keyword));\n }\n\n /**\n * 格式化验证错误信息\n */\n private formatValidationError(errorMessage: string): string {\n // 为常见的验证错误提供更友好的提示\n const errorMappings: Record<string, string> = {\n 工作流ID不能为空: \"请提供有效的工作流ID\",\n 工作流名称不能为空: \"请提供有效的工作流名称\",\n 应用ID不能为空: \"请提供有效的应用ID\",\n 工作流ID格式无效: \"工作流ID应为数字格式,请检查工作流配置\",\n 应用ID格式无效: \"应用ID只能包含字母、数字、下划线和连字符\",\n 工作流名称过长: \"工作流名称不能超过100个字符,请缩短名称\",\n 工作流描述过长: \"工作流描述不能超过500个字符,请缩短描述\",\n 图标URL格式无效: \"请提供有效的图标URL地址\",\n 更新时间不能早于创建时间: \"工作流的时间信息有误,请检查工作流数据\",\n 敏感词: \"工作流名称包含敏感词汇,请修改后重试\",\n };\n\n // 查找匹配的错误映射\n for (const [key, value] of Object.entries(errorMappings)) {\n if (errorMessage.includes(key)) {\n return value;\n }\n }\n\n return errorMessage;\n }\n\n /**\n * 执行边界条件预检查\n */\n private performPreChecks(\n workflow: unknown,\n customName?: string,\n customDescription?: string\n ): { code: string; message: string; status: number } | null {\n // 检查基础参数\n const basicCheckResult = this.checkBasicParameters(\n workflow,\n customName,\n customDescription\n );\n if (basicCheckResult) return basicCheckResult;\n\n // 检查系统状态\n const systemCheckResult = this.checkSystemStatus();\n if (systemCheckResult) return systemCheckResult;\n\n // 检查资源限制\n const resourceCheckResult = this.checkResourceLimits();\n if (resourceCheckResult) return resourceCheckResult;\n\n return null; // 所有检查通过\n }\n\n /**\n * 检查基础参数\n */\n private checkBasicParameters(\n workflow: unknown,\n customName?: string,\n customDescription?: string\n ): { code: string; message: string; status: number } | null {\n // 检查workflow参数\n if (!workflow) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"请求体中缺少 workflow 参数\",\n status: 400,\n };\n }\n\n if (typeof workflow !== \"object\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"workflow 参数必须是对象类型\",\n status: 400,\n };\n }\n\n // 类型守卫:确保 workflow 不是数组\n if (!Array.isArray(workflow)) {\n const workflowObj = workflow as Record<string, unknown>;\n\n // 检查必需字段\n if (\n !workflowObj.workflow_id ||\n typeof workflowObj.workflow_id !== \"string\" ||\n !workflowObj.workflow_id.trim()\n ) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"workflow_id 不能为空且必须是非空字符串\",\n status: 400,\n };\n }\n\n if (\n !workflowObj.workflow_name ||\n typeof workflowObj.workflow_name !== \"string\" ||\n !workflowObj.workflow_name.trim()\n ) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"workflow_name 不能为空且必须是非空字符串\",\n status: 400,\n };\n }\n }\n\n // 检查自定义参数\n if (customName !== undefined) {\n if (typeof customName !== \"string\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customName 必须是字符串类型\",\n status: 400,\n };\n }\n\n if (customName.trim() === \"\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customName 不能为空字符串\",\n status: 400,\n };\n }\n\n if (customName.length > 50) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customName 长度不能超过50个字符\",\n status: 400,\n };\n }\n }\n\n if (customDescription !== undefined) {\n if (typeof customDescription !== \"string\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customDescription 必须是字符串类型\",\n status: 400,\n };\n }\n\n if (customDescription.length > 200) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customDescription 长度不能超过200个字符\",\n status: 400,\n };\n }\n }\n\n return null;\n }\n\n /**\n * 检查系统状态\n */\n private checkSystemStatus(): {\n code: string;\n message: string;\n status: number;\n } | null {\n // 检查扣子API配置\n try {\n const cozeConfig = configManager.getCozePlatformConfig();\n if (!cozeConfig || !cozeConfig.token) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message:\n \"未配置扣子API Token。请在系统设置中配置 platforms.coze.token\",\n status: 422,\n };\n }\n\n // 检查token格式\n if (\n typeof cozeConfig.token !== \"string\" ||\n cozeConfig.token.trim() === \"\"\n ) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: \"扣子API Token格式无效。请检查配置中的 platforms.coze.token\",\n status: 422,\n };\n }\n } catch (error) {\n return {\n code: \"SYSTEM_ERROR\",\n message: \"系统配置检查失败,请稍后重试\",\n status: 500,\n };\n }\n\n return null;\n }\n\n /**\n * 检查资源限制\n */\n private checkResourceLimits(): {\n code: string;\n message: string;\n status: number;\n } | null {\n try {\n // 检查现有工具数量限制\n const existingTools = configManager.getCustomMCPTools();\n const maxTools = 100; // 设置最大工具数量限制\n\n if (existingTools.length >= maxTools) {\n return {\n code: \"RESOURCE_LIMIT_EXCEEDED\",\n message: `已达到最大工具数量限制 (${maxTools})。请删除一些不需要的工具后重试`,\n status: 429,\n };\n }\n\n // 检查配置文件大小(简单估算)\n const configSizeEstimate = JSON.stringify(existingTools).length;\n const maxConfigSize = 1024 * 1024; // 1MB限制\n\n if (configSizeEstimate > maxConfigSize) {\n return {\n code: \"PAYLOAD_TOO_LARGE\",\n message: \"配置文件过大。请删除一些不需要的工具以释放空间\",\n status: 413,\n };\n }\n } catch (error) {\n // 资源检查失败不应阻止操作,只记录警告\n this.logger.warn(\"资源限制检查失败:\", error);\n }\n\n return null;\n }\n\n /**\n * 统一的 MCP 工具管理接口\n * POST /api/tools/mcp/manage\n * 支持 action: enable | disable | status | toggle\n */\n async manageMCPTool(c: Context<AppContext>): Promise<Response> {\n try {\n const requestBody = await c.req.json();\n const { action, serverName, toolName, description } = requestBody;\n\n // 验证 action 参数\n if (!action || typeof action !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"action 参数不能为空且必须是字符串\",\n undefined,\n 400\n );\n }\n\n const validActions = [\"enable\", \"disable\", \"status\", \"toggle\"];\n if (!validActions.includes(action)) {\n return c.fail(\n \"INVALID_ACTION\",\n `无效的 action: ${action}。支持的 action: ${validActions.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 验证服务名和工具名\n this.validateToolIdentifier(serverName, toolName);\n\n // 根据不同的 action 执行相应操作\n switch (action) {\n case \"enable\":\n return this.handleEnableTool(c, serverName, toolName, description);\n case \"disable\":\n return this.handleDisableTool(c, serverName, toolName);\n case \"status\":\n return this.handleGetToolStatus(c, serverName, toolName);\n case \"toggle\":\n return this.handleToggleTool(c, serverName, toolName);\n default: {\n return c.fail(\n \"INVALID_ACTION\",\n `未实现的 action: ${action}`,\n undefined,\n 400\n );\n }\n }\n } catch (error) {\n c.get(\"logger\").error(\"管理 MCP 工具失败:\", error);\n const errorMessage =\n error instanceof Error ? error.message : \"管理 MCP 工具失败\";\n return c.fail(\"TOOL_MANAGE_ERROR\", errorMessage, undefined, 500);\n }\n }\n\n /**\n * 获取服务工具列表\n * POST /api/tools/mcp/list\n */\n async listMCPTools(c: Context<AppContext>): Promise<Response> {\n try {\n const requestBody = await c.req.json();\n const { serverName, includeUsageStats } = requestBody;\n\n // 如果指定了服务名,获取该服务的工具列表\n if (serverName) {\n return this.handleListServerTools(c, serverName, includeUsageStats);\n }\n\n // 否则获取所有服务的工具列表\n return this.handleListAllTools(c, includeUsageStats);\n } catch (error) {\n c.get(\"logger\").error(\"获取工具列表失败:\", error);\n return c.fail(\n \"GET_TOOL_LIST_ERROR\",\n error instanceof Error ? error.message : \"获取工具列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 处理启用工具\n */\n private async handleEnableTool(\n c: Context<AppContext>,\n serverName: string,\n toolName: string,\n description?: string\n ): Promise<Response> {\n // 验证服务存在性\n await this.validateServiceAndToolExistence(serverName, toolName);\n\n // 设置工具为启用状态\n configManager.setToolEnabled(serverName, toolName, true, description);\n\n // 获取更新后的工具配置\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n\n c.get(\"logger\").info(`工具已启用: ${serverName}/${toolName}`);\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: true,\n description: toolConfig?.description || description || \"\",\n },\n `工具 \"${serverName}__${toolName}\" 启用成功`\n );\n }\n\n /**\n * 处理禁用工具\n */\n private async handleDisableTool(\n c: Context<AppContext>,\n serverName: string,\n toolName: string\n ): Promise<Response> {\n // 验证服务存在性\n await this.validateServiceAndToolExistence(serverName, toolName);\n\n // 设置工具为禁用状态\n configManager.setToolEnabled(serverName, toolName, false);\n\n c.get(\"logger\").info(`工具已禁用: ${serverName}/${toolName}`);\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: false,\n },\n `工具 \"${serverName}__${toolName}\" 禁用成功`\n );\n }\n\n /**\n * 处理获取工具状态\n */\n private async handleGetToolStatus(\n c: Context<AppContext>,\n serverName: string,\n toolName: string\n ): Promise<Response> {\n // 获取工具配置\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n\n if (!toolConfig) {\n return c.fail(\n \"TOOL_NOT_FOUND\",\n `工具 \"${serverName}__${toolName}\" 不存在或未配置`,\n undefined,\n 404\n );\n }\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: toolConfig.enable !== false,\n description: toolConfig.description || \"\",\n usageCount: toolConfig.usageCount,\n lastUsedTime: toolConfig.lastUsedTime,\n },\n \"工具状态获取成功\"\n );\n }\n\n /**\n * 处理切换工具状态\n */\n private async handleToggleTool(\n c: Context<AppContext>,\n serverName: string,\n toolName: string\n ): Promise<Response> {\n // 验证服务存在性\n await this.validateServiceAndToolExistence(serverName, toolName);\n\n // 获取当前状态\n const currentEnabled = configManager.isToolEnabled(serverName, toolName);\n\n // 切换状态\n const newEnabled = !currentEnabled;\n configManager.setToolEnabled(serverName, toolName, newEnabled);\n\n c.get(\"logger\").info(\n `工具状态已切换: ${serverName}/${toolName} -> ${newEnabled}`\n );\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: newEnabled,\n },\n `工具 \"${serverName}__${toolName}\" 已${newEnabled ? \"启用\" : \"禁用\"}`\n );\n }\n\n /**\n * 处理获取指定服务的工具列表\n */\n private async handleListServerTools(\n c: Context<AppContext>,\n serverName: string,\n includeUsageStats?: boolean\n ): Promise<Response> {\n // 检查服务是否存在\n const mcpServers = configManager.getMcpServers();\n if (!mcpServers[serverName]) {\n return c.fail(\n \"SERVICE_NOT_FOUND\",\n `MCP 服务 \"${serverName}\" 不存在`,\n undefined,\n 404\n );\n }\n\n // 获取工具配置\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const tools = Object.entries(toolsConfig).map(([toolName, toolConfig]) => {\n const result: Record<string, unknown> = {\n toolName,\n enabled: toolConfig.enable !== false,\n description: toolConfig.description || \"\",\n };\n\n if (includeUsageStats) {\n result.usageCount = toolConfig.usageCount;\n result.lastUsedTime = toolConfig.lastUsedTime;\n }\n\n return result;\n });\n\n const enabledCount = tools.filter((t) => t.enabled).length;\n const disabledCount = tools.length - enabledCount;\n\n return c.success(\n {\n serverName,\n tools,\n total: tools.length,\n enabledCount,\n disabledCount,\n },\n \"获取工具列表成功\"\n );\n }\n\n /**\n * 处理获取所有服务的工具列表\n */\n private async handleListAllTools(\n c: Context<AppContext>,\n includeUsageStats?: boolean\n ): Promise<Response> {\n const mcpServerConfig = configManager.getMcpServerConfig();\n\n // 定义工具信息接口\n interface ToolInfo {\n toolName: string;\n enabled: boolean;\n description: string;\n usageCount?: number;\n lastUsedTime?: string;\n }\n\n // 定义服务器工具信息接口\n interface ServerToolsInfo {\n serverName: string;\n tools: ToolInfo[];\n total: number;\n enabledCount: number;\n disabledCount: number;\n }\n\n // 定义返回结果接口\n interface AllToolsResult {\n servers: ServerToolsInfo[];\n totalTools: number;\n totalEnabled: number;\n totalDisabled: number;\n }\n\n const result: AllToolsResult = {\n servers: [],\n totalTools: 0,\n totalEnabled: 0,\n totalDisabled: 0,\n };\n\n for (const [serverName, serverConfig] of Object.entries(mcpServerConfig)) {\n const tools: ToolInfo[] = Object.entries(serverConfig.tools || {}).map(\n ([toolName, toolConfig]) => {\n const toolInfo: ToolInfo = {\n toolName,\n enabled: toolConfig.enable !== false,\n description: toolConfig.description || \"\",\n };\n\n if (includeUsageStats) {\n toolInfo.usageCount = toolConfig.usageCount;\n toolInfo.lastUsedTime = toolConfig.lastUsedTime;\n }\n\n return toolInfo;\n }\n );\n\n const enabledCount = tools.filter((t) => t.enabled).length;\n\n result.servers.push({\n serverName,\n tools,\n total: tools.length,\n enabledCount,\n disabledCount: tools.length - enabledCount,\n });\n\n result.totalTools += tools.length;\n result.totalEnabled += enabledCount;\n result.totalDisabled += tools.length - enabledCount;\n }\n\n return c.success(result, \"获取所有工具列表成功\");\n }\n\n /**\n * 验证工具标识符\n */\n private validateToolIdentifier(serverName: string, toolName: string): void {\n if (\n !serverName ||\n typeof serverName !== \"string\" ||\n serverName.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"服务名称不能为空\"\n );\n }\n\n if (!toolName || typeof toolName !== \"string\" || toolName.trim() === \"\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具名称不能为空\"\n );\n }\n\n // 验证服务名称格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(serverName)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"服务名称格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n\n // 验证工具名称格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(toolName)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具名称格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n }\n\n /**\n * 验证服务和工具是否存在\n */\n private async validateServiceAndToolExistence(\n serverName: string,\n toolName: string\n ): Promise<void> {\n // 检查服务是否存在\n const mcpServers = configManager.getMcpServers();\n if (!mcpServers[serverName]) {\n throw MCPError.validationError(\n MCPErrorCode.SERVER_NOT_FOUND,\n `MCP 服务 \"${serverName}\" 不存在`\n );\n }\n\n // 检查工具是否在服务中存在\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n if (!toolsConfig[toolName]) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `工具 \"${toolName}\" 在服务 \"${serverName}\" 中不存在或未配置`\n );\n }\n }\n}\n","/**\n * 工具调用日志 API 处理器\n * 负责处理工具调用日志相关的 HTTP API 请求\n */\n\nimport { PAGINATION_CONSTANTS } from \"@/constants/api.constants.js\";\nimport type { ToolCallQuery } from \"@/lib/mcp/log.js\";\nimport { ToolCallLogService } from \"@/lib/mcp/log.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\nimport { z } from \"zod\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 工具调用查询参数 Zod Schema\n */\nconst ToolCallQuerySchema = z\n .object({\n limit: z\n .string()\n .optional()\n .transform((val) => (val ? Number.parseInt(val, 10) : undefined))\n .refine(\n (val) =>\n val === undefined ||\n (val >= 1 && val <= PAGINATION_CONSTANTS.MAX_LIMIT),\n {\n message: `limit 参数必须是 1-${PAGINATION_CONSTANTS.MAX_LIMIT} 之间的数字`,\n }\n ),\n offset: z\n .string()\n .optional()\n .transform((val) => (val ? Number.parseInt(val, 10) : undefined))\n .refine((val) => val === undefined || val >= 0, {\n message: \"offset 参数必须是非负数\",\n }),\n toolName: z.string().optional(),\n serverName: z.string().optional(),\n success: z\n .string()\n .optional()\n .transform((val) => (val ? val.toLowerCase() === \"true\" : undefined)),\n startDate: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true;\n const date = Date.parse(val);\n return !Number.isNaN(date);\n },\n {\n message: \"startDate 参数格式无效\",\n }\n ),\n endDate: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true;\n const date = Date.parse(val);\n return !Number.isNaN(date);\n },\n {\n message: \"endDate 参数格式无效\",\n }\n ),\n })\n .refine(\n (data) => {\n if (!data.startDate || !data.endDate) return true;\n return new Date(data.startDate) <= new Date(data.endDate);\n },\n {\n message: \"startDate 不能晚于 endDate\",\n path: [\"startDate\"],\n }\n );\n\n/**\n * 工具调用日志 API 处理器\n */\nexport class MCPToolLogHandler extends BaseHandler {\n private toolCallLogService: ToolCallLogService;\n\n constructor() {\n super();\n this.toolCallLogService = new ToolCallLogService();\n }\n\n /**\n * 解析和验证查询参数\n */\n private parseAndValidateQueryParams(c: Context<AppContext>): {\n success: boolean;\n data?: ToolCallQuery;\n error?: Array<{ field: string; message: string }>;\n } {\n const query = c.req.query();\n const result = ToolCallQuerySchema.safeParse(query);\n\n if (!result.success) {\n return {\n success: false,\n error: result.error.issues.map((err) => ({\n field: err.path.join(\".\"),\n message: err.message,\n })),\n };\n }\n\n return {\n success: true,\n data: result.data as ToolCallQuery,\n };\n }\n\n /**\n * 获取工具调用日志\n */\n async getToolCallLogs(c: Context<AppContext>): Promise<Response> {\n try {\n const validation = this.parseAndValidateQueryParams(c);\n\n if (!validation.success) {\n return c.fail(\n \"INVALID_QUERY_PARAMETERS\",\n \"查询参数格式错误\",\n validation.error,\n 400\n );\n }\n\n const result = await this.toolCallLogService.getToolCallLogs(\n validation.data!\n );\n\n c.get(\"logger\").debug(\n `API: 返回 ${result.records.length} 条工具调用日志记录`\n );\n return c.success(result);\n } catch (error) {\n c.get(\"logger\").error(\"获取工具调用日志失败:\", error);\n\n const message = error instanceof Error ? error.message : \"未知错误\";\n if (message.includes(\"不存在\")) {\n return c.fail(\"LOG_FILE_NOT_FOUND\", message, undefined, 404);\n }\n if (message.includes(\"无法读取\")) {\n return c.fail(\"LOG_FILE_READ_ERROR\", message, undefined, 500);\n }\n\n return c.fail(\n \"INTERNAL_ERROR\",\n \"获取工具调用日志失败\",\n { details: message },\n 500\n );\n }\n }\n}\n","/**\n * NPM 管理器\n *\n * 提供与 NPM 交互的功能,包括:\n * - 安装指定版本\n * - 获取当前版本\n * - 获取可用版本列表\n * - 检查最新版本\n *\n * @example\n * ```typescript\n * const npmManager = new NPMManager();\n * const versions = await npmManager.getAvailableVersions('stable');\n * await npmManager.installVersion('1.0.0');\n * ```\n */\n\nimport { exec, spawn } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport semver from \"semver\";\n\nconst execAsync = promisify(exec);\n\nexport class NPMManager {\n private eventBus: EventBus;\n\n constructor(eventBus?: EventBus) {\n this.eventBus = eventBus || getEventBus();\n }\n\n /**\n * 安装指定版本 - 这是核心功能\n */\n async installVersion(version: string): Promise<void> {\n const installId = `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const startTime = Date.now();\n\n logger.info(\"开始安装\", { version, installId });\n\n // 发射安装开始事件\n this.eventBus.emitEvent(\"npm:install:started\", {\n version,\n installId,\n timestamp: Date.now(),\n });\n\n const npmProcess = spawn(\"npm\", [\n \"install\",\n \"-g\",\n `xiaozhi-client@${version}`,\n \"--registry=https://registry.npmmirror.com\",\n ]);\n\n /**\n * 清理进程资源\n * 移除事件监听器并关闭流,防止资源泄漏\n */\n const cleanup = () => {\n npmProcess.removeAllListeners(\"error\");\n npmProcess.removeAllListeners(\"close\");\n npmProcess.stdout?.removeAllListeners(\"data\");\n npmProcess.stderr?.removeAllListeners(\"data\");\n npmProcess.stdout?.destroy();\n npmProcess.stderr?.destroy();\n };\n\n return new Promise((resolve, reject) => {\n // 监听进程启动失败事件\n npmProcess.on(\"error\", (error) => {\n const errorMessage = `进程启动失败: ${error.message}`;\n console.log(errorMessage, { error });\n\n // 清理资源\n cleanup();\n\n // 发射安装失败事件\n this.eventBus.emitEvent(\"npm:install:failed\", {\n version,\n installId,\n error: errorMessage,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n });\n\n reject(error);\n });\n\n npmProcess.stdout.on(\"data\", (data) => {\n const message = data.toString();\n\n // 发射日志事件\n this.eventBus.emitEvent(\"npm:install:log\", {\n version,\n installId,\n type: \"stdout\",\n message,\n timestamp: Date.now(),\n });\n });\n\n npmProcess.stderr.on(\"data\", (data) => {\n const message = data.toString();\n\n // 发射日志事件\n this.eventBus.emitEvent(\"npm:install:log\", {\n version,\n installId,\n type: \"stderr\",\n message,\n timestamp: Date.now(),\n });\n });\n\n npmProcess.on(\"close\", (code) => {\n const duration = Date.now() - startTime;\n\n // 清理资源(移除事件监听器并关闭流)\n cleanup();\n\n if (code === 0) {\n // 发射安装完成事件\n this.eventBus.emitEvent(\"npm:install:completed\", {\n version,\n installId,\n success: true,\n duration,\n timestamp: Date.now(),\n });\n\n resolve();\n } else {\n const error = `安装失败,退出码: ${code}`;\n logger.error(\"安装失败\", { code });\n\n // 发射安装失败事件\n this.eventBus.emitEvent(\"npm:install:failed\", {\n version,\n installId,\n error,\n duration,\n timestamp: Date.now(),\n });\n\n reject(new Error(error));\n }\n });\n });\n }\n\n /**\n * 获取当前版本\n */\n async getCurrentVersion(): Promise<string> {\n const { stdout } = await execAsync(\n \"npm list -g xiaozhi-client --depth=0 --json --registry=https://registry.npmmirror.com\"\n );\n const info = JSON.parse(stdout);\n return info.dependencies?.[\"xiaozhi-client\"]?.version || \"unknown\";\n }\n\n /**\n * 版本类型枚举\n */\n static readonly VERSION_TYPES = {\n STABLE: \"stable\",\n RC: \"rc\",\n BETA: \"beta\",\n ALL: \"all\",\n } as const;\n\n /**\n * 获取可用版本列表\n */\n async getAvailableVersions(type = \"stable\"): Promise<string[]> {\n try {\n const { stdout } = await execAsync(\n \"npm view xiaozhi-client versions --json --registry=https://registry.npmmirror.com\"\n );\n\n const versions = JSON.parse(stdout) as string[];\n\n // 使用 semver 验证并过滤有效版本\n let filteredVersions = versions.filter((version) => {\n return version && typeof version === \"string\" && semver.valid(version);\n });\n\n // 根据类型过滤版本\n if (type !== \"all\") {\n filteredVersions = filteredVersions.filter((version) => {\n const prerelease = semver.prerelease(version);\n\n if (type === \"stable\") {\n // 正式版:没有预发布标识符的版本 (x.y.z)\n return prerelease === null;\n }\n\n if (type === \"rc\") {\n // 预览版:预发布标识符以 rc 开头\n return (\n prerelease !== null &&\n prerelease[0]?.toString()?.toLowerCase()?.startsWith(\"rc\") ===\n true\n );\n }\n\n if (type === \"beta\") {\n // 测试版:预发布标识符以 beta 开头\n return (\n prerelease !== null &&\n prerelease[0]?.toString()?.toLowerCase()?.startsWith(\"beta\") ===\n true\n );\n }\n\n return true;\n });\n }\n\n // 进行降序排列(最新的在前)\n return filteredVersions.sort((a, b) => semver.rcompare(a, b));\n } catch (error) {\n logger.error(\"获取版本列表失败\", { error });\n // 如果获取失败,返回一些默认版本\n return [];\n }\n }\n\n /**\n * 检查是否有最新版本\n * 返回当前版本、最新版本以及是否有更新\n */\n async checkForLatestVersion(): Promise<{\n currentVersion: string;\n latestVersion: string | null;\n hasUpdate: boolean;\n error?: string;\n }> {\n try {\n // 获取当前版本\n const currentVersion = await this.getCurrentVersion();\n\n // 如果无法获取当前版本,返回错误\n if (!currentVersion || currentVersion === \"unknown\") {\n return {\n currentVersion: \"unknown\",\n latestVersion: null,\n hasUpdate: false,\n error: \"无法获取当前版本信息\",\n };\n }\n\n // 获取最新的正式版本\n const stableVersions = await this.getAvailableVersions(\"stable\");\n\n if (stableVersions.length === 0) {\n return {\n currentVersion,\n latestVersion: null,\n hasUpdate: false,\n error: \"无法获取可用版本列表\",\n };\n }\n\n // 获取最新的正式版本(第一个元素)\n const latestVersion = stableVersions[0];\n\n // 比较版本\n let hasUpdate = false;\n try {\n // 使用 semver 比较版本\n hasUpdate = semver.gt(latestVersion, currentVersion);\n } catch (error) {\n logger.warn(\"版本比较失败,回退到字符串比较\", { error });\n // 如果比较失败,尝试字符串比较\n hasUpdate = latestVersion !== currentVersion;\n }\n\n logger.debug(\"版本检查完成\", {\n currentVersion,\n latestVersion,\n hasUpdate,\n });\n\n return {\n currentVersion,\n latestVersion,\n hasUpdate,\n };\n } catch (error) {\n logger.error(\"检查最新版本失败\", { error });\n return {\n currentVersion: \"unknown\",\n latestVersion: null,\n hasUpdate: false,\n error:\n error instanceof Error ? error.message : \"检查更新时发生未知错误\",\n };\n }\n }\n}\n","/**\n * 更新 API HTTP 路由处理器\n * 提供版本更新和 NPM 包安装相关的 RESTful API 接口\n */\nimport { NPMManager } from \"@/lib/npm\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\nimport { z } from \"zod\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n// 版本号请求格式验证\nconst UpdateRequestSchema = z.object({\n version: z.string().min(1, \"版本号不能为空\"),\n});\n\n/**\n * 更新 API 处理器\n */\nexport class UpdateApiHandler extends BaseHandler {\n private npmManager: NPMManager;\n private eventBus = getEventBus();\n private activeInstalls: Map<string, boolean> = new Map();\n\n constructor() {\n super();\n this.npmManager = new NPMManager(this.eventBus);\n }\n\n /**\n * 执行版本更新\n * POST /api/update\n * Body: { version: string }\n */\n async performUpdate(c: Context<AppContext>): Promise<Response> {\n try {\n const body = await this.parseJsonBody<{ version: string }>(\n c,\n \"请求体格式错误\"\n );\n\n // 使用 zod 进行参数验证\n const parseResult = UpdateRequestSchema.safeParse(body);\n if (!parseResult.success) {\n return c.fail(\n \"INVALID_VERSION\",\n \"请求参数格式错误\",\n parseResult.error.issues.map((err) => ({\n field: err.path.join(\".\"),\n message: err.message,\n })),\n 400\n );\n }\n\n const { version } = parseResult.data;\n\n // 检查是否有正在进行的安装\n const hasActiveInstall = Array.from(this.activeInstalls.values()).some(\n (v) => v\n );\n if (hasActiveInstall) {\n return c.fail(\n \"INSTALL_IN_PROGRESS\",\n \"已有安装进程正在进行,请等待完成后再试\",\n undefined,\n 409\n );\n }\n\n const logger = c.get(\"logger\");\n // 立即返回响应,安装过程通过 WebSocket 推送\n this.npmManager.installVersion(version).catch((error) => {\n logger.error(\"安装过程失败:\", error);\n });\n\n return c.success(\n {\n version: version,\n message: \"安装已启动,请查看实时日志\",\n },\n \"安装请求已接受\"\n );\n } catch (error) {\n return this.handleError(c, error, \"处理安装请求\", \"REQUEST_FAILED\");\n }\n }\n}\n","/**\n * 版本 API HTTP 路由处理器\n * 提供版本信息查询、可用版本列表获取、版本检查等相关的 RESTful API 接口\n */\nimport { NPMManager } from \"@/lib/npm\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { VersionUtils } from \"@xiaozhi-client/version\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 版本 API 处理器\n */\nexport class VersionApiHandler extends BaseHandler {\n /**\n * 获取版本信息\n * GET /api/version\n */\n async getVersion(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取版本信息请求\");\n\n // 使用 VersionUtils 获取完整版本信息\n const versionInfo = VersionUtils.getVersionInfo();\n\n c.get(\"logger\").debug(\"获取版本信息成功:\", versionInfo);\n\n return c.success(versionInfo);\n } catch (error) {\n return this.handleError(c, error, \"获取版本信息\", \"VERSION_READ_ERROR\");\n }\n }\n\n /**\n * 获取版本号(简化接口)\n * GET /api/version/simple\n */\n async getVersionSimple(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取版本号请求\");\n\n const version = VersionUtils.getVersion();\n c.get(\"logger\").debug(`获取版本号成功: ${version}`);\n\n return c.success({ version });\n } catch (error) {\n return this.handleError(c, error, \"获取版本号\", \"VERSION_READ_ERROR\");\n }\n }\n\n /**\n * 清除版本缓存\n * POST /api/version/cache/clear\n */\n async clearVersionCache(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理清除版本缓存请求\");\n\n VersionUtils.clearCache();\n c.get(\"logger\").info(\"版本缓存已清除\");\n\n return c.success(undefined, \"版本缓存已清除\");\n } catch (error) {\n return this.handleError(c, error, \"清除版本缓存\", \"CACHE_CLEAR_ERROR\");\n }\n }\n\n /**\n * 获取可用版本列表\n * GET /api/version/available?type=stable|rc|beta|all\n */\n async getAvailableVersions(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取可用版本列表请求\");\n\n // 获取查询参数\n const type = (c.req.query(\"type\") as unknown) || \"stable\";\n\n // 验证版本类型参数\n const validTypes = [\"stable\", \"rc\", \"beta\", \"all\"];\n if (!validTypes.includes(type as string)) {\n return c.fail(\n \"INVALID_VERSION_TYPE\",\n `无效的版本类型: ${type}。支持的类型: ${validTypes.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n const npmManager = new NPMManager();\n const versions = await npmManager.getAvailableVersions(type as string);\n\n c.get(\"logger\").debug(\n `获取到 ${versions.length} 个可用版本 (类型: ${type})`\n );\n\n return c.success({\n versions,\n type,\n total: versions.length,\n });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取可用版本列表\",\n \"VERSIONS_FETCH_ERROR\"\n );\n }\n }\n\n /**\n * 检查最新版本\n * GET /api/version/latest\n */\n async checkLatestVersion(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理检查最新版本请求\");\n\n const npmManager = new NPMManager();\n const result = await npmManager.checkForLatestVersion();\n\n c.get(\"logger\").debug(\"版本检查结果:\", result);\n\n if (result.error) {\n // 如果有错误,但仍返回部分信息\n return c.success({\n currentVersion: result.currentVersion,\n latestVersion: result.latestVersion,\n hasUpdate: result.hasUpdate,\n error: result.error,\n });\n }\n\n return c.success({\n currentVersion: result.currentVersion,\n latestVersion: result.latestVersion,\n hasUpdate: result.hasUpdate,\n });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"检查最新版本\",\n \"LATEST_VERSION_CHECK_ERROR\"\n );\n }\n }\n}\n","/**\n * TTS API HTTP 路由处理器\n * 提供语音合成 RESTful API 接口\n */\n\nimport { TTS_VOICES, getVoiceScenes } from \"@/constants/voices.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport { mapClusterToResourceId } from \"@xiaozhi-client/esp32\";\nimport type { VoiceInfo, VoicesResponse } from \"@xiaozhi-client/shared-types\";\nimport type { Context } from \"hono\";\nimport { createTTS } from \"univoice\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 允许的 encoding 值白名单\n */\nconst ALLOWED_ENCODINGS = [\n \"mp3\",\n \"wav\",\n \"ogg\",\n \"flac\",\n \"pcm\",\n \"opus\",\n \"ogg_opus\",\n] as const;\n\ntype AllowedEncoding = (typeof ALLOWED_ENCODINGS)[number];\n\n/**\n * encoding 到 MIME Content-Type 的映射\n * 部分值不对应标准 MIME 类型,需要显式映射\n */\nconst ENCODING_TO_MIME: Record<AllowedEncoding, string> = {\n mp3: \"audio/mpeg\",\n wav: \"audio/wav\",\n ogg: \"audio/ogg\",\n flac: \"audio/flac\",\n pcm: \"audio/pcm\",\n opus: \"audio/opus\",\n ogg_opus: \"audio/ogg\",\n};\n\n/**\n * encoding 到文件扩展名的映射\n */\nconst ENCODING_TO_EXT: Record<AllowedEncoding, string> = {\n mp3: \"mp3\",\n wav: \"wav\",\n ogg: \"ogg\",\n flac: \"flac\",\n pcm: \"pcm\",\n opus: \"opus\",\n ogg_opus: \"ogg\",\n};\n\n/**\n * TTS 合成请求体\n */\ninterface TTSRequestBody {\n /** 要转换的文本 */\n text: string;\n /** 应用 ID(可选,从配置读取) */\n appid?: string;\n /** 访问令牌(可选,从配置读取) */\n accessToken?: string;\n /** 声音类型(可选,从配置读取) */\n voice_type?: string;\n /** 编码格式(可选,默认 wav) */\n encoding?: string;\n /** 集群类型(可选) */\n cluster?: string;\n /** WebSocket 端点(可选) */\n endpoint?: string;\n}\n\n/**\n * TTS API 路由处理器类\n */\nexport class TTSApiHandler extends BaseHandler {\n constructor() {\n super();\n }\n\n /**\n * 语音合成\n * POST /api/tts\n */\n async synthesize(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理语音合成请求\");\n\n // 解析请求参数\n const body = await this.parseJsonBody<TTSRequestBody>(c);\n\n // 验证必需参数\n if (!body.text) {\n c.get(\"logger\").warn(\"缺少 text 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少必需参数: text\",\n undefined,\n 400\n );\n }\n\n // 获取 TTS 配置作为默认值\n const ttsConfig = configManager.getTTSConfig();\n\n // 优先从请求参数读取,否则从配置读取\n const appid = body.appid || ttsConfig.appid;\n const accessToken = body.accessToken || ttsConfig.accessToken;\n const voice_type = body.voice_type || ttsConfig.voice_type;\n const cluster = body.cluster || ttsConfig.cluster;\n const endpoint = body.endpoint || ttsConfig.endpoint;\n const encoding = body.encoding || ttsConfig.encoding || \"wav\";\n\n // 运行时校验 encoding 值\n if (!ALLOWED_ENCODINGS.includes(encoding as AllowedEncoding)) {\n c.get(\"logger\").warn(`不支持的 encoding 参数: ${encoding}`);\n return c.fail(\n \"INVALID_PARAMETER\",\n `不支持的 encoding 参数: ${encoding},允许值: ${ALLOWED_ENCODINGS.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n const safeEncoding = encoding as AllowedEncoding;\n\n // 验证必需的 TTS 参数\n if (!appid) {\n c.get(\"logger\").warn(\"缺少 appid 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少 appid 参数,请提供或配置 tts.appid\",\n undefined,\n 400\n );\n }\n\n if (!accessToken) {\n c.get(\"logger\").warn(\"缺少 accessToken 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少 accessToken 参数,请提供或配置 tts.accessToken\",\n undefined,\n 400\n );\n }\n\n if (!voice_type) {\n c.get(\"logger\").warn(\"缺少 voice_type 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少 voice_type 参数,请提供或配置 tts.voice_type\",\n undefined,\n 400\n );\n }\n\n // 创建 TTS 客户端(使用 univoice SDK)\n const tts = createTTS({\n provider: \"doubao\",\n appId: appid!,\n accessToken: accessToken!,\n voice: voice_type!,\n format: safeEncoding,\n resourceId: mapClusterToResourceId(cluster),\n sampleRate: 24000,\n ...(endpoint && { baseUrl: endpoint }),\n });\n\n c.get(\"logger\").info(\n `开始语音合成: text=${body.text.substring(0, 20)}..., voice_type=${voice_type}`\n );\n\n // 调用 TTS 合成(非流式)\n const response = await tts.synthesize({ text: body.text });\n const audioData = response.audio;\n\n c.get(\"logger\").info(`语音合成成功: audioSize=${audioData.length} bytes`);\n\n // 返回音频数据,使用正确的 MIME 类型和文件扩展名\n return new Response(Buffer.from(audioData), {\n headers: {\n \"Content-Type\": ENCODING_TO_MIME[safeEncoding],\n \"Content-Disposition\": `attachment; filename=\"tts_${Date.now()}.${ENCODING_TO_EXT[safeEncoding]}\"`,\n },\n });\n } catch (error) {\n return this.handleError(c, error, \"语音合成\");\n }\n }\n\n /**\n * 获取可用音色列表\n * GET /api/tts/voices\n */\n async getVoices(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"获取音色列表\");\n\n const voices: VoiceInfo[] = TTS_VOICES;\n const scenes = getVoiceScenes();\n\n const response: VoicesResponse = {\n voices,\n total: voices.length,\n scenes,\n };\n\n return c.success(response);\n } catch (error) {\n return this.handleError(c, error, \"获取音色列表\");\n }\n }\n}\n","/**\n * ESP32 设备处理器\n * 处理 ESP32 设备相关的 HTTP 请求\n *\n * 作为薄适配层,将 Hono 请求委托给 ESP32DeviceManager 处理\n */\n\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type {\n ESP32DeviceManager,\n ESP32DeviceReport,\n} from \"@xiaozhi-client/esp32\";\nimport { ESP32ErrorCode } from \"@xiaozhi-client/esp32\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * ESP32 设备处理器\n * 仅处理硬件 OTA/配置请求\n *\n * 注意:设备采用自动激活模式,无需管理 API\n */\nexport class ESP32Handler extends BaseHandler {\n private esp32Manager: ESP32DeviceManager;\n\n constructor(esp32Manager: ESP32DeviceManager) {\n super();\n this.esp32Manager = esp32Manager;\n }\n\n /**\n * 处理OTA/配置请求\n * POST /\n *\n * 硬件API定义:根路径OTA接口\n *\n * 请求头:\n * - Device-Id: 设备MAC地址\n * - Client-Id: 设备UUID\n *\n * 请求体:\n * ```json\n * {\n * \"application\": {\n * \"version\": \"1.0.0\",\n * \"board\": {\n * \"type\": \"ESP32-S3-BOX\"\n * }\n * }\n * }\n * ```\n */\n async handleOTA(c: Context<AppContext>): Promise<Response> {\n const logger = c.get(\"logger\");\n\n try {\n // 获取设备ID和客户端ID\n const deviceId = c.req.header(\"Device-Id\") || c.req.header(\"device-id\");\n const clientId = c.req.header(\"Client-Id\") || c.req.header(\"client-id\");\n\n if (!deviceId) {\n return c.fail(\n ESP32ErrorCode.MISSING_DEVICE_ID,\n \"缺少 Device-Id 请求头\",\n undefined,\n 400\n );\n }\n\n // Client-Id 强制要求\n if (!clientId) {\n return c.fail(\n ESP32ErrorCode.MISSING_DEVICE_ID,\n \"缺少 Client-Id 请求头\",\n undefined,\n 400\n );\n }\n\n // 解析请求体\n const report: ESP32DeviceReport = await this.parseJsonBody(\n c,\n \"请求体格式错误\"\n );\n\n logger.debug(`收到OTA请求: deviceId=${deviceId}, clientId=${clientId}`);\n\n // 委托给设备管理器处理(支持从请求头获取设备型号,与 xiaozhi-esp32-server 保持一致)\n const response = await this.esp32Manager.handleOTARequest(\n deviceId,\n clientId,\n report,\n // 可选:从请求头获取设备信息(优先级高于 body)\n {\n deviceModel:\n c.req.header(\"device-model\") ||\n c.req.header(\"Device-Model\") ||\n undefined,\n deviceVersion:\n c.req.header(\"device-version\") ||\n c.req.header(\"Device-Version\") ||\n undefined,\n },\n c.req.header(\"host\") // 传递 Host 头用于构建完整 WebSocket URL\n );\n\n logger.debug(\"OTA响应\", { response });\n return c.json(response);\n } catch (error) {\n return this.handleError(c, error, \"处理OTA请求\");\n }\n }\n}\n","/**\n * Logger 中间件\n *\n * 负责将 logger 实例注入到 Hono Context 中,支持两种访问方式:\n * - c.get(\"logger\") - Hono 推荐做法\n * - c.logger - 向后兼容方式\n *\n * @module middlewares/logger.middleware\n */\n\nimport { logger } from \"@/Logger.js\";\nimport type { Logger } from \"@/Logger.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context, Next } from \"hono\";\n\n/**\n * 扩展 Hono Context 接口\n * 添加 logger 属性,允许直接通过 c.logger 访问\n * 保留此扩展以提供向后兼容性\n */\ndeclare module \"hono\" {\n interface Context {\n logger: Logger;\n }\n}\n\n/**\n * Logger 中间件 - 将 logger 实例挂载到 Hono context\n * 支持两种访问方式:\n * 1. c.get(\"logger\") - Hono 推荐做法\n * 2. c.logger - 向后兼容\n */\nexport const loggerMiddleware = async (c: Context<AppContext>, next: Next) => {\n // Hono 推荐做法\n c.set(\"logger\", logger);\n\n // 保留模块扩展以提供向后兼容\n c.logger = logger;\n\n await next();\n};\n","/**\n * CORS 中间件配置\n * 负责配置跨域资源共享策略,支持通过环境变量配置允许的来源列表\n *\n * 支持的环境变量:\n * - ALLOWED_ORIGINS: 允许的来源列表,多个来源用逗号分隔\n * 例如:https://example.com,https://app.example.com\n * 未配置时默认允许所有来源(*),生产环境建议显式配置\n *\n * 支持的 HTTP 方法:\n * - GET\n * - POST\n * - PUT\n * - OPTIONS\n *\n * 支持的请求头:\n * - Content-Type\n *\n * @module middlewares/cors.middleware\n */\n\nimport { cors } from \"hono/cors\";\n\n/**\n * CORS 中间件\n */\nexport const corsMiddleware = cors({\n origin: process.env.ALLOWED_ORIGINS\n ? process.env.ALLOWED_ORIGINS.split(\",\").map((origin) => origin.trim())\n : \"*\",\n allowMethods: [\"GET\", \"POST\", \"PUT\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\"],\n});\n","/**\n * 错误处理中间件和统一响应格式\n *\n * 提供统一的 API 响应格式和错误处理中间件:\n * - ApiErrorResponse: 统一的错误响应格式\n * - ApiSuccessResponse: 统一的成功响应格式\n * - errorHandlerMiddleware: 全局错误处理中间件\n * - notFoundHandlerMiddleware: 404 处理中间件\n *\n * @module middlewares/error.middleware\n */\n\nimport type { Context } from \"hono\";\n\n// 统一错误响应格式\nexport interface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\nexport interface ApiSuccessResponse<T> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 创建统一的错误响应\n * @deprecated 请使用 c.fail() 方法代替\n */\nexport const createErrorResponse = (\n code: string,\n message: string,\n details?: unknown\n): ApiErrorResponse => {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n};\n\n/**\n * 创建统一的成功响应\n * @deprecated 请使用 c.success() 方法代替\n */\nexport const createSuccessResponse = <T>(\n data?: T,\n message?: string\n): ApiSuccessResponse<T> => {\n return {\n success: true,\n data,\n message,\n };\n};\n\n/**\n * 错误处理中间件\n */\nexport const errorHandlerMiddleware = (err: Error, c: Context) => {\n // 使用 Context 上的 logger 属性\n c.logger.error(\"HTTP request error:\", err);\n\n // 在开发环境中打印详细错误信息\n if (process.env.NODE_ENV === \"development\") {\n console.error(\"HTTP Request Error:\", {\n error: err.message,\n stack: err.stack,\n path: c.req.path,\n method: c.req.method,\n });\n }\n\n return c.fail(\n \"INTERNAL_SERVER_ERROR\",\n \"服务器内部错误\",\n process.env.NODE_ENV === \"development\" ? err.stack : undefined,\n 500\n );\n};\n\n/**\n * 404 Not Found 处理中间件\n */\nexport const notFoundHandlerMiddleware = (c: Context) => {\n // 如果是 API 路径,返回 API_NOT_FOUND\n if (c.req.path.startsWith(\"/api/\")) {\n return c.fail(\n \"API_NOT_FOUND\",\n \"请求的资源不存在\",\n {\n path: c.req.path,\n method: c.req.method,\n },\n 404\n );\n }\n\n // 非 API 路径返回通用的 NOT_FOUND\n return c.fail(\n \"NOT_FOUND\",\n \"请求的资源不存在\",\n {\n path: c.req.path,\n method: c.req.method,\n },\n 404\n );\n};\n","/**\n * 响应增强中间件\n * 为 Hono Context 添加便捷的响应方法:c.success、c.fail、c.paginate\n */\n\nimport type { PaginationInfo } from \"@/types/api.response.js\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * 扩展 Hono Context 接口\n * 添加三个新的响应方法\n */\ndeclare module \"hono\" {\n interface Context {\n /**\n * 返回成功响应\n * @param data - 响应数据\n * @param message - 响应消息\n * @param status - HTTP 状态码(默认 200)\n * @returns JSON 响应\n *\n * @example\n * ```typescript\n * // 简单成功响应\n * return c.success({ id: 1, name: \"张三\" });\n *\n * // 带消息的成功响应\n * return c.success({ id: 1 }, \"获取用户成功\");\n *\n * // 自定义状态码\n * return c.success({ id: 1 }, \"创建成功\", 201);\n *\n * // 无数据响应(如删除操作)\n * return c.success(undefined, \"删除成功\");\n * ```\n */\n success<T>(data?: T, message?: string, status?: number): Response;\n\n /**\n * 返回失败响应\n * @param code - 错误码\n * @param message - 错误消息\n * @param details - 错误详情\n * @param status - HTTP 状态码(默认 400)\n * @returns JSON 响应\n *\n * @example\n * ```typescript\n * // 简单错误响应\n * return c.fail(\"USER_NOT_FOUND\", \"用户不存在\");\n *\n * // 404 错误\n * return c.fail(\"NOT_FOUND\", \"资源不存在\", undefined, 404);\n *\n * // 带详情的错误响应\n * return c.fail(\"VALIDATION_ERROR\", \"数据验证失败\", {\n * field: \"email\",\n * message: \"邮箱格式不正确\"\n * });\n *\n * // 服务器错误\n * return c.fail(\"INTERNAL_ERROR\", \"服务器内部错误\", undefined, 500);\n * ```\n */\n fail(\n code: string,\n message: string,\n details?: unknown,\n status?: number\n ): Response;\n\n /**\n * 返回分页响应\n * @param data - 数据列表\n * @param pagination - 分页信息\n * @param message - 响应消息\n * @returns JSON 响应\n *\n * @example\n * ```typescript\n * const data = [{ id: 1 }, { id: 2 }];\n * const pagination = {\n * page: 1,\n * pageSize: 10,\n * total: 100,\n * totalPages: 10,\n * hasNext: true,\n * hasPrev: false\n * };\n * return c.paginate(data, pagination, \"查询成功\");\n * ```\n */\n paginate<T>(\n data: T[],\n pagination: PaginationInfo,\n message?: string\n ): Response;\n }\n}\n\n/**\n * 响应增强中间件\n * 为所有请求添加便捷的响应方法\n */\nexport const responseEnhancerMiddleware: MiddlewareHandler = async (\n c,\n next\n) => {\n // 成功响应方法\n c.success = <T>(data?: T, message?: string, status = 200) => {\n const response: {\n success: true;\n data?: T;\n message?: string;\n } = {\n success: true,\n message,\n };\n\n // 只有当 data 不是 undefined 时才添加 data 字段\n if (data !== undefined) {\n response.data = data;\n }\n\n return c.json(response, status as never);\n };\n\n // 失败响应方法\n c.fail = (code: string, message: string, details?: unknown, status = 400) => {\n const response: {\n success: false;\n error: {\n code: string;\n message: string;\n details?: unknown;\n };\n } = {\n success: false,\n error: {\n code,\n message,\n },\n };\n\n // 只有当 details 不是 undefined 时才添加 details 字段\n if (details !== undefined) {\n response.error.details = details;\n }\n\n return c.json(response, status as never);\n };\n\n // 分页响应方法\n c.paginate = <T>(data: T[], pagination: PaginationInfo, message?: string) => {\n const response: {\n success: true;\n data: T[];\n pagination: PaginationInfo;\n message?: string;\n } = {\n success: true,\n data,\n pagination,\n message,\n };\n\n return c.json(response, 200);\n };\n\n await next();\n};\n","/**\n * MCP 中间件相关的错误定义\n */\n\n/**\n * MCPServiceManager 未初始化错误\n */\nexport class MCPServiceManagerNotInitializedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MCPServiceManagerNotInitializedError\";\n }\n}\n\n/**\n * WebServer 不可用错误\n */\nexport class WebServerNotAvailableError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WebServerNotAvailableError\";\n }\n}\n","/**\n * MCP Service Manager 中间件\n * 将 MCPServiceManager 实例注入到 Hono Context 中\n * 提供统一的依赖注入模式,从 WebServer 获取实例而非 Singleton\n */\n\nimport {\n MCPServiceManagerNotInitializedError,\n WebServerNotAvailableError,\n} from \"@/errors/mcp-errors.middleware.js\";\nimport type { AppContextVariables } from \"@/types/hono.context.js\";\nimport type { Context, Next } from \"hono\";\n\n/**\n * MCP Service Manager 中间件\n *\n * 功能:\n * 1. 从 WebServer 获取 MCPServiceManager 实例\n * 2. 将实例注入到 Hono Context\n * 3. 提供错误处理和日志记录\n * 4. 与 WebServer 生命周期绑定\n * 5. 使用 Hono Context 中的 logger 实现统一的日志配置\n *\n * @param c Hono Context\n * @param next 下一个中间件函数\n */\nexport const mcpServiceManagerMiddleware = async (\n c: Context<{ Variables: AppContextVariables }>,\n next: Next\n): Promise<void> => {\n // 检查是否已经注入,避免重复初始化\n if (!c.get(\"mcpServiceManager\")) {\n try {\n c.logger.debug(\n \"[MCPMiddleware] 正在从 WebServer 获取 MCPServiceManager 实例\"\n );\n\n // 从 WebServer 获取实例\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new WebServerNotAvailableError(\"WebServer 未注入到 Context\");\n }\n\n const serviceManager = webServer.getMCPServiceManager();\n\n // 将实例注入到 Context\n c.set(\"mcpServiceManager\", serviceManager);\n\n c.logger.debug(\n \"[MCPMiddleware] MCPServiceManager 实例已成功注入到 Context\"\n );\n } catch (error) {\n // 根据错误类型进行不同的处理\n if (error instanceof MCPServiceManagerNotInitializedError) {\n // MCPServiceManager 未初始化是临时状态,允许通过\n c.logger.debug(\n \"[MCPMiddleware] MCPServiceManager 尚未初始化,允许通过\"\n );\n // 不设置实例,Handler 中需要处理未初始化的情况\n } else if (error instanceof WebServerNotAvailableError) {\n // WebServer 未注入是配置错误,应该抛出\n c.logger.error(\"[MCPMiddleware] WebServer 配置错误:\", error.message);\n throw error;\n } else {\n // 其他未知错误,记录并抛出\n c.logger.error(\n \"[MCPMiddleware] 获取 MCPServiceManager 时发生未知错误:\",\n error\n );\n throw error;\n }\n }\n }\n\n await next();\n};\n\n/**\n * 类型守卫:检查 Context 中是否存在 MCPServiceManager 实例\n *\n * @param c Hono Context\n * @returns 是否存在 MCPServiceManager 实例\n */\nexport const hasMCPServiceManager = (\n c: Context<{ Variables: AppContextVariables }>\n): boolean => {\n return c.get(\"mcpServiceManager\") !== undefined;\n};\n","/**\n * 小智连接管理器中间件\n * 负责将 endpointManager 注入到请求上下文中\n */\n\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * 小智连接管理器中间件\n * 从 WebServer 实例获取连接管理器并注入到上下文中\n */\nexport const endpointManagerMiddleware = (): MiddlewareHandler<AppContext> => {\n return async (c, next) => {\n // 从 WebServer 实例获取连接管理器\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new Error(\n \"WebServer 实例未注入到上下文中,请确保 webServerMiddleware 已正确配置\"\n );\n }\n\n if (!webServer.getEndpointManager) {\n throw new Error(\"WebServer 实例缺少 getEndpointManager 方法\");\n }\n\n try {\n const connectionManager = webServer.getEndpointManager();\n c.set(\"endpointManager\", connectionManager);\n } catch (error) {\n // 记录错误但不阻断请求\n if (error instanceof Error && error.message.includes(\"未初始化\")) {\n c.logger.warn(\"小智连接管理器未初始化,使用 null 值:\", error.message);\n c.set(\"endpointManager\", null);\n } else {\n throw error;\n }\n }\n\n await next();\n };\n};\n","/**\n * 小智端点处理器中间件\n * 负责创建和管理 EndpointHandler 实例\n */\n\nimport { EndpointHandler } from \"@/handlers/endpoint.handler.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { EndpointManager } from \"@xiaozhi-client/endpoint\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * 小智端点处理器中间件\n * 创建单例的 EndpointHandler 并注入到上下文中\n */\nexport const endpointsMiddleware = (): MiddlewareHandler<AppContext> => {\n // 使用闭包缓存 handler 实例和 manager\n let endpointHandler: EndpointHandler | null = null;\n let lastManager: EndpointManager | null | undefined = undefined;\n\n return async (c, next) => {\n const endpointManager = c.get(\"endpointManager\");\n\n // 如果 manager 发生变化,则重建 handler\n // 注意:使用引用相等检查(!==)确保使用最新的 manager 实例\n // 即使 manager 内容相同,但对象引用不同时也会重建 handler\n // 这是期望的行为,确保 handler 总是使用最新的连接管理\n if (endpointManager !== lastManager) {\n lastManager = endpointManager;\n if (endpointManager) {\n endpointHandler = new EndpointHandler(endpointManager, configManager);\n } else {\n endpointHandler = null;\n }\n }\n\n // 将 handler 注入到上下文中\n c.set(\"endpointHandler\", endpointHandler);\n\n await next();\n };\n};\n","/**\n * 状态服务\n *\n * 统一的状态管理服务,负责管理客户端连接状态、MCP 服务状态等。\n *\n * ## 核心功能\n * - 客户端状态管理:跟踪客户端连接状态、MCP 端点、活跃服务器等\n * - 重启状态管理:管理服务重启流程的状态跟踪\n * - 心跳超时管理:监控客户端心跳,超时自动断开连接\n * - 事件通知:通过 EventBus 发射状态变更事件\n *\n * ## 使用方式\n * ```typescript\n * import { StatusService } from '@/services';\n *\n * const statusService = new StatusService();\n * const status = statusService.getFullStatus();\n * ```\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\n\n/**\n * 客户端信息接口\n */\nexport interface ClientInfo {\n status: \"connected\" | \"disconnected\";\n mcpEndpoint: string;\n activeMCPServers: string[];\n lastHeartbeat?: number;\n}\n\n/**\n * 重启状态接口\n */\nexport interface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n serviceName?: string;\n attempt?: number;\n}\n\n/**\n * 状态服务 - 统一的状态管理服务\n */\nexport class StatusService {\n private logger: Logger;\n private eventBus: EventBus;\n private clientInfo: ClientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n private restartStatus?: RestartStatus;\n private heartbeatTimeout?: NodeJS.Timeout;\n private readonly HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n constructor() {\n this.logger = logger;\n this.eventBus = getEventBus();\n }\n\n /**\n * 获取客户端状态\n */\n getClientStatus(): ClientInfo {\n return { ...this.clientInfo };\n }\n\n /**\n * 更新客户端信息\n */\n updateClientInfo(info: Partial<ClientInfo>, source = \"unknown\"): void {\n try {\n const oldStatus = { ...this.clientInfo };\n this.clientInfo = { ...this.clientInfo, ...info };\n\n if (info.lastHeartbeat) {\n this.clientInfo.lastHeartbeat = Date.now();\n }\n\n // 接收到客户端状态时重置心跳超时\n if (info.status === \"connected\") {\n this.resetHeartbeatTimeout();\n }\n\n this.logger.debug(`客户端状态更新,来源: ${source}`, {\n old: oldStatus,\n new: this.clientInfo,\n });\n\n // 发射状态更新事件\n this.eventBus.emitEvent(\"status:updated\", {\n status: this.clientInfo,\n source,\n });\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateClientInfo\",\n });\n }\n }\n\n /**\n * 获取重启状态\n */\n getRestartStatus(): RestartStatus | undefined {\n return this.restartStatus ? { ...this.restartStatus } : undefined;\n }\n\n /**\n * 更新重启状态\n */\n updateRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string\n ): void {\n try {\n this.restartStatus = {\n status,\n error,\n timestamp: Date.now(),\n };\n\n this.logger.info(`重启状态更新: ${status}`, { error });\n\n // 根据状态发射不同的事件\n switch (status) {\n case \"restarting\":\n this.eventBus.emitEvent(\"service:restart:started\", {\n serviceName: this.restartStatus.serviceName || \"\",\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"completed\":\n this.eventBus.emitEvent(\"service:restart:completed\", {\n serviceName: this.restartStatus.serviceName || \"\",\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"failed\":\n this.eventBus.emitEvent(\"service:restart:failed\", {\n serviceName: this.restartStatus.serviceName || \"\",\n error: new Error(error || \"重启失败\"),\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n }\n } catch (error) {\n this.logger.error(\"更新重启状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateRestartStatus\",\n });\n }\n }\n\n /**\n * 获取完整状态信息\n */\n getFullStatus(): {\n client: ClientInfo;\n restart?: RestartStatus;\n timestamp: number;\n } {\n return {\n client: this.getClientStatus(),\n restart: this.getRestartStatus(),\n timestamp: Date.now(),\n };\n }\n\n /**\n * 重置心跳超时\n */\n private resetHeartbeatTimeout(): void {\n // 清除现有的超时定时器\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n // 设置新的超时定时器\n this.heartbeatTimeout = setTimeout(() => {\n this.logger.debug(\"客户端心跳超时,标记为断开连接\");\n this.updateClientInfo({ status: \"disconnected\" }, \"heartbeat-timeout\");\n }, this.HEARTBEAT_TIMEOUT);\n }\n\n /**\n * 清除心跳超时\n */\n clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = undefined;\n }\n }\n\n /**\n * 检查客户端是否连接\n */\n isClientConnected(): boolean {\n return this.clientInfo.status === \"connected\";\n }\n\n /**\n * 获取最后心跳时间\n */\n getLastHeartbeat(): number | undefined {\n return this.clientInfo.lastHeartbeat;\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n */\n getActiveMCPServers(): string[] {\n return [...this.clientInfo.activeMCPServers];\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n */\n setActiveMCPServers(servers: string[]): void {\n this.updateClientInfo(\n { activeMCPServers: [...servers] },\n \"mcp-servers-update\"\n );\n }\n\n /**\n * 设置 MCP 端点\n */\n setMcpEndpoint(endpoint: string): void {\n this.updateClientInfo({ mcpEndpoint: endpoint }, \"mcp-endpoint-update\");\n }\n\n /**\n * 重置状态\n */\n reset(): void {\n this.logger.info(\"重置状态服务\");\n this.clearHeartbeatTimeout();\n this.clientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n this.restartStatus = undefined;\n }\n\n /**\n * 销毁状态服务\n */\n destroy(): void {\n this.logger.info(\"销毁状态服务\");\n this.clearHeartbeatTimeout();\n this.reset();\n }\n}\n","/**\n * 通知服务\n *\n * 负责管理 WebSocket 客户端连接和消息推送,实现实时通知功能。\n *\n * ## 核心功能\n * - WebSocket 客户端管理:注册、移除、连接状态跟踪\n * - 消息队列:离线消息缓存,重连后自动推送\n * - 事件广播:监听 EventBus 事件并推送给所有连接的客户端\n * - 消息类型:配置更新、状态变更、服务重启、NPM 安装日志等\n *\n * ## 使用方式\n * - 由 WebServer 在初始化阶段创建实例\n * - 当前主要由 WebSocket 相关 handler(如 RealtimeNotificationHandler / HeartbeatHandler)持有并使用\n * - 如需在 HTTP handler 中使用,可通过自定义中间件将其实例注入到 Hono Context\n *\n * ## 注意事项\n * - 消息队列最大容量:100 条/客户端\n * - 客户断开连接时会自动清理资源\n * - 与 EventBus 紧密集成,监听系统事件并广播\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { ClientInfo, RestartStatus } from \"@/services/status.service.js\";\nimport type { AppConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\n\n/**\n * WebSocket 类接口\n * 定义了 WebSocket 实例需要具备的基本属性和方法\n */\nexport interface WebSocketLike {\n readyState: number;\n send(data: string): void;\n}\n\n/**\n * WebSocket 客户端接口\n */\nexport interface WebSocketClient {\n id: string;\n ws: WebSocketLike;\n readyState: number;\n send: (data: string) => void;\n}\n\n/**\n * 通知数据类型\n * 定义了通知消息中可能包含的数据类型\n */\nexport type NotificationData =\n | AppConfig\n | ClientInfo\n | RestartStatus\n | { message: string }\n | { [key: string]: unknown };\n\n/**\n * 通知消息接口\n */\nexport interface NotificationMessage {\n type: string;\n data?: NotificationData;\n timestamp?: number;\n}\n\n/**\n * 通知服务 - 统一的通知管理服务\n */\nexport class NotificationService {\n private logger: Logger;\n private eventBus: EventBus;\n private clients: Map<string, WebSocketClient> = new Map();\n private messageQueue: Map<string, NotificationMessage[]> = new Map();\n private maxQueueSize = 100;\n\n constructor() {\n this.logger = logger;\n this.eventBus = getEventBus();\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", (data) => {\n // 获取最新的配置\n const config = configManager.getConfig();\n this.broadcastConfigUpdate(config);\n });\n\n // 监听状态更新事件\n this.eventBus.onEvent(\"status:updated\", (data) => {\n this.broadcastStatusUpdate(data.status);\n });\n\n // 监听重启状态事件\n this.eventBus.onEvent(\"service:restart:started\", (data) => {\n this.broadcastRestartStatus(\"restarting\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:completed\", (data) => {\n this.broadcastRestartStatus(\"completed\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:failed\", (data) => {\n this.broadcastRestartStatus(\"failed\", data.error.message, data.timestamp);\n });\n\n // 监听 NPM 安装事件\n this.eventBus.onEvent(\"npm:install:started\", (data) => {\n this.broadcast(\"npm:install:started\", data);\n });\n\n this.eventBus.onEvent(\"npm:install:log\", (data) => {\n this.broadcast(\"npm:install:log\", data);\n });\n\n this.eventBus.onEvent(\"npm:install:completed\", (data) => {\n this.broadcast(\"npm:install:completed\", data);\n });\n\n this.eventBus.onEvent(\"npm:install:failed\", (data) => {\n this.broadcast(\"npm:install:failed\", data);\n });\n\n // 监听通知广播事件\n this.eventBus.onEvent(\"notification:broadcast\", (data) => {\n if (data.target) {\n this.sendToClient(data.target, data.type, data.data);\n } else {\n this.broadcast(data.type, data.data);\n }\n });\n }\n\n /**\n * 注册 WebSocket 客户端\n */\n registerClient(clientId: string, ws: WebSocketLike): void {\n try {\n const client: WebSocketClient = {\n id: clientId,\n ws,\n readyState: ws.readyState,\n send: (data: string) => {\n if (ws.readyState === 1) {\n // WebSocket.OPEN\n ws.send(data);\n }\n },\n };\n\n this.clients.set(clientId, client);\n this.logger.debug(`WebSocket 客户端已注册: ${clientId}`);\n this.logger.debug(`当前客户端数量: ${this.clients.size}`);\n\n // 发送排队的消息\n this.sendQueuedMessages(clientId);\n\n // 发射客户端连接事件\n this.eventBus.emitEvent(\"websocket:client:connected\", {\n clientId,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(`注册客户端失败: ${clientId}`, error);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"client:register\",\n });\n }\n }\n\n /**\n * 注销 WebSocket 客户端\n */\n unregisterClient(clientId: string): void {\n try {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.messageQueue.delete(clientId);\n this.logger.debug(`WebSocket 客户端已注销: ${clientId}`);\n this.logger.debug(`剩余客户端数量: ${this.clients.size}`);\n\n // 发射客户端断开事件\n this.eventBus.emitEvent(\"websocket:client:disconnected\", {\n clientId,\n timestamp: Date.now(),\n });\n }\n } catch (error) {\n this.logger.error(`注销客户端失败: ${clientId}`, error);\n }\n }\n\n /**\n * 广播消息给所有客户端\n */\n broadcast(type: string, data?: NotificationData): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n this.logger.debug(`广播消息: ${type}`, { clientCount: this.clients.size });\n\n for (const [clientId, client] of this.clients) {\n this.sendMessageToClient(client, message, clientId);\n }\n }\n\n /**\n * 发送消息给特定客户端\n */\n sendToClient(clientId: string, type: string, data?: NotificationData): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n const client = this.clients.get(clientId);\n if (client) {\n this.sendMessageToClient(client, message, clientId);\n } else {\n // 客户端不在线,将消息加入队列\n this.queueMessage(clientId, message);\n }\n }\n\n /**\n * 发送消息给客户端\n */\n private sendMessageToClient(\n client: WebSocketClient,\n message: NotificationMessage,\n clientId: string\n ): void {\n try {\n if (client.ws.readyState === 1) {\n // WebSocket.OPEN\n const messageStr = JSON.stringify(message);\n client.send(messageStr);\n this.logger.debug(`消息已发送给客户端 ${clientId}: ${message.type}`);\n } else {\n // 连接不可用,将消息加入队列\n this.queueMessage(clientId, message);\n this.logger.warn(`客户端 ${clientId} 连接不可用,消息已加入队列`);\n }\n } catch (error) {\n this.logger.error(`发送消息给客户端 ${clientId} 失败:`, error);\n this.queueMessage(clientId, message);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"message:send\",\n });\n }\n }\n\n /**\n * 将消息加入队列\n */\n private queueMessage(clientId: string, message: NotificationMessage): void {\n if (!this.messageQueue.has(clientId)) {\n this.messageQueue.set(clientId, []);\n }\n\n const queue = this.messageQueue.get(clientId)!;\n queue.push(message);\n\n // 限制队列大小\n if (queue.length > this.maxQueueSize) {\n queue.shift(); // 移除最旧的消息\n this.logger.warn(`客户端 ${clientId} 消息队列已满,移除最旧消息`);\n }\n }\n\n /**\n * 发送排队的消息\n */\n private sendQueuedMessages(clientId: string): void {\n const queue = this.messageQueue.get(clientId);\n if (!queue || queue.length === 0) {\n return;\n }\n\n const client = this.clients.get(clientId);\n if (!client) {\n return;\n }\n\n this.logger.debug(`发送 ${queue.length} 条排队消息给客户端 ${clientId}`);\n\n for (const message of queue) {\n this.sendMessageToClient(client, message, clientId);\n }\n\n // 清空队列\n this.messageQueue.delete(clientId);\n }\n\n /**\n * 广播配置更新\n */\n broadcastConfigUpdate(config: AppConfig): void {\n this.broadcast(\"configUpdate\", config);\n }\n\n /**\n * 广播状态更新\n */\n broadcastStatusUpdate(status: ClientInfo): void {\n this.broadcast(\"statusUpdate\", status);\n }\n\n /**\n * 广播重启状态\n */\n broadcastRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string,\n timestamp?: number\n ): void {\n const restartStatus: RestartStatus = {\n status,\n error,\n timestamp: timestamp || Date.now(),\n };\n\n this.broadcast(\"restartStatus\", restartStatus);\n }\n\n /**\n * 获取客户端统计信息\n */\n getClientStats(): {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n } {\n const connectedClients = Array.from(this.clients.values()).filter(\n (client) => client.ws.readyState === 1\n ).length;\n\n const queuedMessages = Array.from(this.messageQueue.values()).reduce(\n (total, queue) => total + queue.length,\n 0\n );\n\n return {\n totalClients: this.clients.size,\n connectedClients,\n queuedMessages,\n };\n }\n\n /**\n * 清理断开的客户端\n */\n cleanupDisconnectedClients(): void {\n const disconnectedClients: string[] = [];\n\n for (const [clientId, client] of this.clients) {\n if (client.ws.readyState !== 1) {\n // Not WebSocket.OPEN\n disconnectedClients.push(clientId);\n }\n }\n\n for (const clientId of disconnectedClients) {\n this.unregisterClient(clientId);\n }\n\n if (disconnectedClients.length > 0) {\n this.logger.debug(`清理了 ${disconnectedClients.length} 个断开的客户端`);\n }\n }\n\n /**\n * 销毁通知服务\n */\n destroy(): void {\n this.logger.debug(\"销毁通知服务\");\n this.clients.clear();\n this.messageQueue.clear();\n }\n}\n","/**\n * 路由系统相关类型定义\n * 提供类型安全的路由配置和依赖注入\n */\n\nimport type {\n ConfigApiHandler,\n CozeHandler,\n ESP32Handler,\n EndpointHandler,\n MCPHandler,\n MCPRouteHandler,\n MCPToolHandler,\n MCPToolLogHandler,\n ServiceApiHandler,\n StaticFileHandler,\n StatusApiHandler,\n TTSApiHandler,\n UpdateApiHandler,\n VersionApiHandler,\n} from \"@/handlers/index.js\";\nimport type { Context, MiddlewareHandler } from \"hono\";\n\n/**\n * 处理器依赖接口\n * 定义路由系统需要的所有处理器依赖\n */\nexport interface HandlerDependencies {\n /** 配置管理处理器 */\n configApiHandler: ConfigApiHandler;\n /** 状态查询处理器 */\n statusApiHandler: StatusApiHandler;\n /** 服务管理处理器 */\n serviceApiHandler: ServiceApiHandler;\n /** MCP 工具处理器 */\n mcpToolHandler: MCPToolHandler;\n /** 工具调用日志处理器 */\n mcpToolLogHandler: MCPToolLogHandler;\n /** 版本信息处理器 */\n versionApiHandler: VersionApiHandler;\n /** 静态文件处理器 */\n staticFileHandler: StaticFileHandler;\n /** MCP 路由处理器 */\n mcpRouteHandler: MCPRouteHandler;\n /** MCP 服务器管理处理器(可选) */\n mcpHandler?: MCPHandler;\n /** 更新管理处理器 */\n updateApiHandler: UpdateApiHandler;\n /** 扣子 API 处理器 */\n cozeHandler: CozeHandler;\n /** TTS API 处理器 */\n ttsApiHandler: TTSApiHandler;\n /** 小智接入点处理器(通过中间件动态注入) */\n endpointHandler?: EndpointHandler;\n /** ESP32 设备处理器(可选) */\n esp32Handler?: ESP32Handler;\n}\n\n/**\n * 路由注册选项接口\n * 控制路由注册的行为\n *\n * @future-feature 计划在 v2.0.0 中实现,用于提供更灵活的路由注册控制\n * - 支持详细的注册日志,便于调试和监控\n * - 支持注册失败时的异常处理策略配置\n */\nexport interface RouteRegistryOptions {\n /** 是否启用详细的路由注册日志 */\n verboseLogging?: boolean;\n /** 是否在注册失败时抛出异常 */\n throwOnRegistrationError?: boolean;\n}\n\n/**\n * 路由统计信息接口\n * 提供路由系统的运行时统计\n *\n * @future-feature 计划在 v2.0.0 中实现,用于提供路由系统的监控和分析能力\n * - 统计各域的路由数量分布\n * - 分析 HTTP 方法的使用情况\n * - 支持路由性能监控和优化建议\n */\nexport interface RouteStatistics {\n /** 注册的域数量 */\n domainCount: number;\n /** 注册的路由总数 */\n totalRouteCount: number;\n /** 各域的路由数量分布 */\n routeDistribution: Record<string, number>;\n /** 支持的 HTTP 方法统计 */\n methodDistribution: Record<string, number>;\n}\n\n/**\n * HTTP 方法类型\n */\nexport type HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * 路由定义接口\n * 定义单个路由的配置信息\n */\nexport interface RouteDefinition {\n /** HTTP 方法 */\n method: HTTPMethod;\n /** 完整路由路径(相对于应用根路径) */\n path: string;\n /** 处理函数 */\n handler: (c: Context) => Promise<Response | undefined>;\n /** 路由级别的中间件 */\n middleware?: MiddlewareHandler[];\n}\n\n/**\n * 路由组接口\n * 用于需要组级别中间件或元数据的场景\n */\nexport interface RouteGroup {\n /** 路由定义数组 */\n routes: RouteDefinition[];\n /** 可选的组名称(用于日志和调试) */\n name?: string;\n /** 可选的组描述 */\n description?: string;\n /** 组级别的中间件(应用到组内所有路由) */\n middleware?: MiddlewareHandler[];\n}\n\n/**\n * 路由注册联合类型\n * 支持直接注册路由数组或路由组\n */\nexport type RouteRegistry = RouteDefinition[] | RouteGroup;\n\n/**\n * 判断是否为路由组\n */\nexport function isRouteGroup(route: RouteRegistry): route is RouteGroup {\n return Array.isArray((route as RouteGroup).routes);\n}\n\n/**\n * 将路由注册转换为路由数组\n */\nexport function normalizeRoutes(route: RouteRegistry): RouteDefinition[] {\n if (isRouteGroup(route)) {\n const { routes, middleware } = route;\n if (middleware && middleware.length > 0) {\n return routes.map((r) => ({\n ...r,\n middleware: [...middleware, ...(r.middleware || [])],\n }));\n }\n return routes;\n }\n return route;\n}\n\n/**\n * 创建路由处理器辅助函数\n * 自动处理依赖注入,减少样板代码\n *\n * @example\n * ```typescript\n * const h = createHandler(\"versionApiHandler\");\n * export const routes = [\n * {\n * method: \"GET\",\n * path: \"/api/version\",\n * handler: h((handler, c) => handler.getVersion(c)),\n * }\n * ];\n * ```\n */\nexport function createHandler<K extends keyof HandlerDependencies>(\n dependencyKey: K\n): (\n method: (handler: HandlerDependencies[K], c: Context) => Promise<Response>\n) => RouteDefinition[\"handler\"] {\n return (method) => (c: Context) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const handler = dependencies[dependencyKey];\n return method(handler, c);\n };\n}\n","/**\n * 路由管理器\n * 提供直接、高效的路由注册和管理功能\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context, Hono, Next } from \"hono\";\nimport {\n type RouteDefinition,\n type RouteRegistry,\n normalizeRoutes,\n} from \"./types.js\";\n\n/**\n * 路由管理器\n * 直接管理路由配置,提供路由注册和应用功能\n * 通过依赖注入接收 Logger 实例,保持与项目日志系统的一致性\n */\nexport class RouteManager {\n private routes: Map<string, RouteDefinition[]> = new Map();\n\n constructor(private logger: Logger) {}\n\n /**\n * 注册单个路由模块\n */\n registerRoute(name: string, routeRegistry: RouteRegistry): void {\n const routes = normalizeRoutes(routeRegistry);\n if (this.routes.has(name)) {\n this.logger.warn(`路由组 '${name}' 已存在,将被覆盖`);\n }\n this.routes.set(name, routes);\n this.logger.info(`已注册路由组: ${name} (${routes.length} 个路由)`);\n }\n\n /**\n * 批量注册路由模块\n */\n registerRoutes(routeRegistries: Record<string, RouteRegistry>): void {\n this.logger.info(\n `开始批量注册 ${Object.keys(routeRegistries).length} 个路由组...`\n );\n\n for (const [name, routeRegistry] of Object.entries(routeRegistries)) {\n this.registerRoute(name, routeRegistry);\n }\n\n this.logger.info(`批量注册完成,共注册 ${this.routes.size} 个路由组`);\n }\n\n /**\n * 获取所有注册的路由配置\n */\n getAllRoutes(): Map<string, RouteDefinition[]> {\n return new Map(this.routes);\n }\n\n /**\n * 获取指定名称的路由配置\n */\n getRoute(name: string): RouteDefinition[] | undefined {\n return this.routes.get(name);\n }\n\n /**\n * 将路由应用到 Hono 应用实例\n */\n applyToApp(app: Hono<AppContext>): void {\n // 获取所有路由并排序,确保 static 路由最后应用\n const routeEntries = Array.from(this.routes.entries());\n routeEntries.sort(([nameA], [nameB]) => {\n // static 路由永远排在最后\n if (nameA === \"static\") return 1;\n if (nameB === \"static\") return -1;\n return 0;\n });\n\n let totalRouteCount = 0;\n for (const [groupName, routes] of routeEntries) {\n try {\n for (const route of routes) {\n this.applyRouteDefinition(app, route, groupName);\n totalRouteCount++;\n }\n } catch (error) {\n this.logger.error(`✗ 应用路由组失败: ${groupName}`, error);\n }\n }\n\n this.logger.info(`路由应用完成,共 ${totalRouteCount} 个路由`);\n }\n\n /**\n * 应用单个路由定义到 Hono 应用\n */\n private applyRouteDefinition(\n app: Hono<AppContext>,\n route: RouteDefinition,\n groupName: string\n ): void {\n const { method, path, handler, middleware = [] } = route;\n\n // 创建包装的处理器,添加错误处理\n const wrappedHandler = async (c: Context<AppContext>, next: Next) => {\n try {\n return await handler(c);\n } catch (error) {\n this.logger.error(`路由处理错误 [${method} ${path}]:`, error);\n return c.fail(\n \"HANDLER_ERROR\",\n \"处理器执行失败\",\n error instanceof Error ? error.message : String(error),\n 500\n );\n }\n };\n\n // 使用 switch-case 避免 Hono 4.11.4 的类型推断问题\n // 注意:Hono 4.11.4 对展开中间件数组的类型推断更加严格,需要使用类型断言\n switch (method) {\n case \"GET\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.get(path, ...middleware, wrappedHandler);\n } else {\n app.get(path, wrappedHandler);\n }\n break;\n case \"POST\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.post(path, ...middleware, wrappedHandler);\n } else {\n app.post(path, wrappedHandler);\n }\n break;\n case \"PUT\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.put(path, ...middleware, wrappedHandler);\n } else {\n app.put(path, wrappedHandler);\n }\n break;\n case \"DELETE\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.delete(path, ...middleware, wrappedHandler);\n } else {\n app.delete(path, wrappedHandler);\n }\n break;\n case \"PATCH\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.patch(path, ...middleware, wrappedHandler);\n } else {\n app.patch(path, wrappedHandler);\n }\n break;\n default:\n throw new Error(`不支持的 HTTP 方法: ${method}`);\n }\n }\n\n /**\n * 清除所有路由(主要用于测试)\n */\n clear(): void {\n this.routes.clear();\n this.logger.info(\"已清除所有路由配置\");\n }\n\n /**\n * 检查路由是否已注册\n */\n hasRoute(name: string): boolean {\n return this.routes.has(name);\n }\n\n /**\n * 列出所有已注册的路由域名称\n */\n getRouteNames(): string[] {\n return Array.from(this.routes.keys());\n }\n}\n","/**\n * 配置管理路由配置\n * 处理所有配置管理相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"configApiHandler\");\n\n/**\n * 配置管理路由定义\n */\nexport const configRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/config\",\n handler: h((handler, c) => handler.getConfig(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/config\",\n handler: h((handler, c) => handler.updateConfig(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/mcp-endpoint\",\n handler: h((handler, c) => handler.getMcpEndpoint(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/mcp-endpoints\",\n handler: h((handler, c) => handler.getMcpEndpoints(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/mcp-servers\",\n handler: h((handler, c) => handler.getMcpServers(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/connection\",\n handler: h((handler, c) => handler.getConnectionConfig(c)),\n },\n {\n method: \"POST\",\n path: \"/api/config/reload\",\n handler: h((handler, c) => handler.reloadConfig(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/path\",\n handler: h((handler, c) => handler.getConfigPath(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/exists\",\n handler: h((handler, c) => handler.checkConfigExists(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/prompts\",\n handler: h((handler, c) => handler.getPromptFiles(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.getPromptFileContent(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.updatePromptFileContent(c)),\n },\n {\n method: \"POST\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.createPromptFileContent(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.deletePromptFileContent(c)),\n },\n];\n","/**\n * 状态查询路由模块\n * 处理所有状态相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"statusApiHandler\");\n\n/**\n * 状态查询路由定义\n */\nexport const statusRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/status\",\n handler: h((handler, c) => handler.getStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/status/client\",\n handler: h((handler, c) => handler.getClientStatus(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/status/client\",\n handler: h((handler, c) => handler.updateClientStatus(c)),\n },\n {\n method: \"POST\",\n path: \"/api/status/reset\",\n handler: h((handler, c) => handler.resetStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/status/mcp-servers\",\n handler: h((handler, c) => handler.getActiveMCPServers(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/status/mcp-servers\",\n handler: h((handler, c) => handler.setActiveMCPServers(c)),\n },\n];\n","/**\n * 工具调用路由模块\n * 处理所有工具相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"mcpToolHandler\");\n\n/**\n * 工具调用路由定义\n */\nexport const toolsRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/tools/call\",\n handler: h((handler, c) => handler.callTool(c)),\n },\n {\n method: \"GET\",\n path: \"/api/tools/list\",\n handler: h((handler, c) => handler.listTools(c)),\n },\n {\n method: \"GET\",\n path: \"/api/tools/custom\",\n handler: h((handler, c) => handler.getCustomTools(c)),\n },\n {\n method: \"POST\",\n path: \"/api/tools/custom\",\n handler: h((handler, c) => handler.addCustomTool(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/tools/custom/:toolName\",\n handler: h((handler, c) => handler.updateCustomTool(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/tools/custom/:toolName\",\n handler: h((handler, c) => handler.removeCustomTool(c)),\n },\n /**\n * MCP 工具管理路由\n * 用于启用/禁用/查询 MCP 工具的状态\n */\n {\n method: \"POST\",\n path: \"/api/tools/mcp/manage\",\n handler: h((handler, c) => handler.manageMCPTool(c)),\n },\n {\n method: \"POST\",\n path: \"/api/tools/mcp/list\",\n handler: h((handler, c) => handler.listMCPTools(c)),\n },\n];\n","/**\n * MCP 协议路由模块\n * 处理 MCP 协议相关的 API 路由(仅 POST 模式)\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"mcpRouteHandler\");\n\n/**\n * MCP 协议路由定义\n */\nexport const mcpRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/mcp\",\n handler: h((handler, c) => handler.handlePost(c)),\n },\n];\n","/**\n * 版本信息路由模块\n * 处理所有版本相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"versionApiHandler\");\n\n/**\n * 版本信息路由定义\n */\nexport const versionRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/version\",\n handler: h((handler, c) => handler.getVersion(c)),\n },\n {\n method: \"GET\",\n path: \"/api/version/simple\",\n handler: h((handler, c) => handler.getVersionSimple(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/version/cache\",\n handler: h((handler, c) => handler.clearVersionCache(c)),\n },\n {\n method: \"GET\",\n path: \"/api/version/latest\",\n handler: h((handler, c) => handler.checkLatestVersion(c)),\n },\n];\n","/**\n * 服务管理路由配置\n * 处理所有服务管理相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"serviceApiHandler\");\n\nexport const servicesRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/services/restart\",\n handler: h((handler, c) => handler.restartService(c)),\n },\n {\n method: \"POST\",\n path: \"/api/services/stop\",\n handler: h((handler, c) => handler.stopService(c)),\n },\n {\n method: \"POST\",\n path: \"/api/services/start\",\n handler: h((handler, c) => handler.startService(c)),\n },\n {\n method: \"GET\",\n path: \"/api/services/status\",\n handler: h((handler, c) => handler.getServiceStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/services/health\",\n handler: h((handler, c) => handler.getServiceHealth(c)),\n },\n];\n","/**\n * 更新管理路由配置\n * 处理更新相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"updateApiHandler\");\n\nexport const updateRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/update\",\n handler: h((handler, c) => handler.performUpdate(c)),\n },\n];\n","/**\n * 静态文件路由配置\n * 处理静态文件服务相关的路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"staticFileHandler\");\n\nexport const staticRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/*\",\n handler: h(async (handler, c) => {\n // 如果路径以 /api/ 开头,不处理静态文件,直接返回 404\n if (c.req.path.startsWith(\"/api/\")) {\n return c.notFound();\n }\n return await handler.handleStaticFile(c);\n }),\n },\n];\n","/**\n * 扣子 API 路由配置\n * 处理所有扣子相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"cozeHandler\");\n\nexport const cozeRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/coze/workspaces\",\n handler: h((handler, c) => handler.getWorkspaces(c)),\n },\n {\n method: \"GET\",\n path: \"/api/coze/workflows\",\n handler: h((handler, c) => handler.getWorkflows(c)),\n },\n {\n method: \"POST\",\n path: \"/api/coze/cache/clear\",\n handler: h((handler, c) => handler.clearCache(c)),\n },\n {\n method: \"GET\",\n path: \"/api/coze/cache/stats\",\n handler: h((handler, c) => handler.getCacheStats(c)),\n },\n];\n","/**\n * 工具调用日志路由配置\n * 处理工具调用日志相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"mcpToolLogHandler\");\n\nexport const toolLogsRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/tool-calls/logs\",\n handler: h((handler, c) => handler.getToolCallLogs(c)),\n },\n];\n","/**\n * MCP 服务器管理路由配置\n * 处理 MCP 服务器管理相关的 API 路由\n */\n\nimport type { HandlerDependencies, RouteDefinition } from \"@/routes/types.js\";\nimport type { Context } from \"hono\";\n\n/**\n * MCP 服务器处理器包装函数\n * 统一处理 MCP Server API Handler 的初始化检查\n */\nconst withMCPServerHandler = async (\n c: Context,\n handlerFn: (\n handler: NonNullable<HandlerDependencies[\"mcpHandler\"]>\n ) => Promise<Response>\n): Promise<Response> => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const handler = dependencies.mcpHandler;\n\n if (!handler) {\n return c.json({ error: \"MCP Server API Handler not initialized\" }, 503);\n }\n\n return await handlerFn(handler);\n};\n\nexport const mcpserverRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/mcp-servers\",\n handler: (c: Context) => withMCPServerHandler(c, (h) => h.addMCPServer(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/mcp-servers/:serverName\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.removeMCPServer(c)),\n },\n {\n method: \"GET\",\n path: \"/api/mcp-servers/:serverName/status\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.getMCPServerStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/mcp-servers\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.listMCPServers(c)),\n },\n];\n","/**\n * 端点管理路由配置\n * 处理所有端点管理相关的 API 路由\n * 使用中间件动态注入的 endpointHandler\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 端点处理器方法名类型\n */\ntype EndpointHandlerMethod =\n | \"getEndpointStatus\"\n | \"connectEndpoint\"\n | \"disconnectEndpoint\"\n | \"addEndpoint\"\n | \"removeEndpoint\";\n\n/**\n * 端点处理器包装函数\n * 从中间件获取 endpointHandler 并调用相应方法\n */\nconst withEndpointHandler = async (\n c: Context<AppContext>,\n handlerName: EndpointHandlerMethod\n): Promise<Response> => {\n // 从中间件获取 endpointHandler\n const endpointHandler = c.get(\"endpointHandler\");\n\n if (!endpointHandler) {\n return c.fail(\n \"ENDPOINT_HANDLER_NOT_AVAILABLE\",\n \"端点处理器尚未初始化,请稍后再试\",\n undefined,\n 503\n );\n }\n\n // 调用对应的处理方法\n try {\n // 使用类型安全的方式调用方法\n return await endpointHandler[handlerName](c);\n } catch (error) {\n console.error(`端点处理器错误 [${handlerName}]:`, error);\n return c.fail(\n \"ENDPOINT_HANDLER_ERROR\",\n error instanceof Error ? error.message : \"端点处理失败\",\n undefined,\n 500\n );\n }\n};\n\n/**\n * 端点管理路由定义(扁平化版本)\n */\nexport const endpointRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/endpoint/status\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"getEndpointStatus\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/connect\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"connectEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/disconnect\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"disconnectEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/add\",\n handler: (c: Context<AppContext>) => withEndpointHandler(c, \"addEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/remove\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"removeEndpoint\"),\n },\n];\n","/**\n * 通用API路由配置\n * 处理不特定于某个模块的通用 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"serviceApiHandler\");\n\nexport const miscRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/restart\",\n handler: h((handler, c) => handler.restartService(c)),\n },\n];\n","/**\n * TTS API 路由配置\n * 处理所有 TTS 相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"ttsApiHandler\");\n\nexport const ttsRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/tts\",\n handler: h((handler, c) => handler.synthesize(c)),\n },\n {\n method: \"GET\",\n path: \"/api/tts/voices\",\n handler: h((handler, c) => handler.getVoices(c)),\n },\n];\n","/**\n * ESP32设备路由模块\n * 处理ESP32设备相关的API路由\n *\n * 硬件API定义:\n * - POST / # OTA/配置获取(根路径,按硬件定义)\n * - POST /xiaozhi/ota/ # 小智硬件官方OTA路径(兼容)\n * - WebSocket /ws # WebSocket连接\n *\n * 注意:设备采用自动激活模式,无需管理API\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { type HandlerDependencies, createHandler } from \"@/routes/types.js\";\nimport type { Context } from \"hono\";\n\nconst h = createHandler(\"esp32Handler\");\n\n/**\n * 创建 ESP32 路由处理器(带可选检查)\n */\nconst createESP32Handler = (\n method: (\n handler: NonNullable<HandlerDependencies[\"esp32Handler\"]>,\n c: Context\n ) => Promise<Response>\n) => {\n return async (c: Context) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const handler = dependencies.esp32Handler;\n if (!handler) {\n return c.json({ error: \"ESP32 service not available\" }, 503);\n }\n return method(handler, c);\n };\n};\n\n/**\n * ESP32设备路由定义\n */\nexport const esp32Routes: RouteDefinition[] = [\n // ========== 硬件API(按硬件定义的路径) ==========\n\n // 硬件 OTA/配置接口(根路径)\n {\n method: \"POST\",\n path: \"/\",\n handler: createESP32Handler((handler, c) => handler.handleOTA(c)),\n },\n\n // 小智硬件官方 OTA 路径(兼容硬件默认配置)\n {\n method: \"POST\",\n path: \"/xiaozhi/ota/\",\n handler: createESP32Handler((handler, c) => handler.handleOTA(c)),\n },\n\n // WebSocket端点(由WebServer直接处理,这里仅作为占位符)\n {\n method: \"GET\",\n path: \"/ws\",\n handler: createESP32Handler(async (handler, c) => {\n c.get(\"logger\").debug(\"ESP32 WebSocket端点访问\");\n // 返回 426 Upgrade Required,明确提示需要 WebSocket 升级\n return c.text(\"WebSocket Upgrade Required\", 426);\n }),\n },\n];\n"],"mappings":"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","names":["require_constants","__commonJSMin","exports","module","SEMVER_SPEC_VERSION","MAX_SAFE_INTEGER","MAX_SAFE_COMPONENT_LENGTH","MAX_SAFE_BUILD_LENGTH","RELEASE_TYPES","require_debug","__commonJSMin","exports","module","debug","args","require_re","__commonJSMin","exports","module","MAX_SAFE_COMPONENT_LENGTH","MAX_SAFE_BUILD_LENGTH","MAX_LENGTH","debug","re","safeRe","src","safeSrc","t","R","LETTERDASHNUMBER","safeRegexReplacements","makeSafeRegex","__name","value","token","max","createToken","name","isGlobal","safe","index","require_parse_options","__commonJSMin","exports","module","looseOption","emptyOpts","parseOptions","__name","options","require_identifiers","__commonJSMin","exports","module","numeric","compareIdentifiers","__name","a","b","anum","bnum","rcompareIdentifiers","require_semver","__commonJSMin","exports","module","debug","MAX_LENGTH","MAX_SAFE_INTEGER","re","t","parseOptions","compareIdentifiers","SemVer","_SemVer","__name","version","options","m","id","num","other","i","a","b","release","identifier","identifierBase","match","base","prerelease","require_parse","__commonJSMin","exports","module","SemVer","parse","__name","version","options","throwErrors","er","require_valid","__commonJSMin","exports","module","parse","valid","__name","version","options","v","require_clean","__commonJSMin","exports","module","parse","clean","__name","version","options","s","require_inc","__commonJSMin","exports","module","SemVer","inc","__name","version","release","options","identifier","identifierBase","require_diff","__commonJSMin","exports","module","parse","diff","__name","version1","version2","v1","v2","comparison","v1Higher","highVersion","lowVersion","highHasPre","prefix","require_major","__commonJSMin","exports","module","SemVer","major","__name","a","loose","require_minor","__commonJSMin","exports","module","SemVer","minor","__name","a","loose","require_patch","__commonJSMin","exports","module","SemVer","patch","__name","a","loose","require_prerelease","__commonJSMin","exports","module","parse","prerelease","__name","version","options","parsed","require_compare","__commonJSMin","exports","module","SemVer","compare","__name","a","b","loose","require_rcompare","__commonJSMin","exports","module","compare","rcompare","__name","a","b","loose","require_compare_loose","__commonJSMin","exports","module","compare","compareLoose","__name","a","b","require_compare_build","__commonJSMin","exports","module","SemVer","compareBuild","__name","a","b","loose","versionA","versionB","require_sort","__commonJSMin","exports","module","compareBuild","sort","__name","list","loose","a","b","require_rsort","__commonJSMin","exports","module","compareBuild","rsort","__name","list","loose","a","b","require_gt","__commonJSMin","exports","module","compare","gt","__name","a","b","loose","require_lt","__commonJSMin","exports","module","compare","lt","__name","a","b","loose","require_eq","__commonJSMin","exports","module","compare","eq","__name","a","b","loose","require_neq","__commonJSMin","exports","module","compare","neq","__name","a","b","loose","require_gte","__commonJSMin","exports","module","compare","gte","__name","a","b","loose","require_lte","__commonJSMin","exports","module","compare","lte","__name","a","b","loose","require_cmp","__commonJSMin","exports","module","eq","neq","gt","gte","lt","lte","cmp","__name","a","op","b","loose","require_coerce","__commonJSMin","exports","module","SemVer","parse","re","t","coerce","__name","version","options","match","coerceRtlRegex","next","major","minor","patch","prerelease","build","require_lrucache","__commonJSMin","exports","module","LRUCache","__name","key","value","firstKey","require_range","__commonJSMin","exports","module","SPACE_CHARACTERS","Range","_Range","__name","range","options","parseOptions","Comparator","c","first","isNullSet","isAny","i","comps","k","memoKey","FLAG_INCLUDE_PRERELEASE","FLAG_LOOSE","cached","cache","loose","hr","re","t","hyphenReplace","debug","comparatorTrimReplace","tildeTrimReplace","caretTrimReplace","rangeList","comp","parseComparator","replaceGTE0","rangeMap","comparators","result","thisComparators","isSatisfiable","rangeComparators","thisComparator","rangeComparator","version","SemVer","testSet","LRU","remainingComparators","testComparator","otherComparator","replaceCarets","replaceTildes","replaceXRanges","replaceStars","isX","id","replaceTilde","r","_","M","m","p","pr","ret","replaceCaret","z","replaceXRange","gtlt","xM","xm","xp","anyX","incPr","$0","from","fM","fm","fp","fpr","fb","to","tM","tm","tp","tpr","set","allowed","require_comparator","__commonJSMin","exports","module","ANY","Comparator","_Comparator","__name","comp","options","parseOptions","debug","r","re","t","m","SemVer","version","cmp","Range","require_satisfies","__commonJSMin","exports","module","Range","satisfies","__name","version","range","options","require_to_comparators","__commonJSMin","exports","module","Range","toComparators","__name","range","options","comp","c","require_max_satisfying","__commonJSMin","exports","module","SemVer","Range","maxSatisfying","__name","versions","range","options","max","maxSV","rangeObj","v","require_min_satisfying","__commonJSMin","exports","module","SemVer","Range","minSatisfying","__name","versions","range","options","min","minSV","rangeObj","v","require_min_version","__commonJSMin","exports","module","SemVer","Range","gt","minVersion","__name","range","loose","minver","i","comparators","setMin","comparator","compver","require_valid","__commonJSMin","exports","module","Range","validRange","__name","range","options","require_outside","__commonJSMin","exports","module","SemVer","Comparator","ANY","Range","satisfies","gt","lt","lte","gte","outside","__name","version","range","hilo","options","gtfn","ltefn","ltfn","comp","ecomp","i","comparators","high","low","comparator","require_gtr","__commonJSMin","exports","module","outside","gtr","__name","version","range","options","require_ltr","__commonJSMin","exports","module","outside","ltr","__name","version","range","options","require_intersects","__commonJSMin","exports","module","Range","intersects","__name","r1","r2","options","require_simplify","__commonJSMin","exports","module","satisfies","compare","versions","range","options","set","first","prev","v","a","b","version","ranges","min","max","simplified","original","require_subset","__commonJSMin","exports","module","Range","Comparator","ANY","satisfies","compare","subset","__name","sub","dom","options","sawNonNull","OUTER","simpleSub","simpleDom","isSub","simpleSubset","minimumVersionWithPreRelease","minimumVersion","eqSet","gt","lt","c","higherGT","lowerLT","gtltComp","eq","higher","lower","hasDomLT","hasDomGT","needDomLTPre","needDomGTPre","a","b","comp","require_semver","__commonJSMin","exports","module","internalRe","constants","SemVer","identifiers","parse","valid","clean","inc","diff","major","minor","patch","prerelease","compare","rcompare","compareLoose","compareBuild","sort","rsort","gt","lt","eq","neq","gte","lte","cmp","coerce","Comparator","Range","satisfies","toComparators","maxSatisfying","minSatisfying","minVersion","validRange","outside","gtr","ltr","intersects","simplifyRange","subset","createServer","fs","path","chalk","pino","z","LogLevelSchema","z","formatDateTime","date","year","month","day","hours","minutes","seconds","__name","Logger","level","normalizedLevel","result","streams","consoleStream","pino","_label","number","err","levelMap","chalk","chunk","logObj","message","content","timestamp","levelInfo","text","coloredLevel","argsStr","arg","projectDir","enable","messageOrObj","args","errorArgs","enhancedObj","obj","enhanced","key","value","logDir","logName","i","oldFile","newFile","firstRotatedFile","maxSize","maxFiles","globalLogger","globalLogLevel","getLogger","globalLogger","Logger","globalLogLevel","__name","logger","getLogger","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","dirname","isAbsolute","resolve","configManager","listPromptFiles","configFilePath","configManager","configDir","dirname","promptsDir","resolve","existsSync","readdirSync","file","__name","MAX_FILE_SIZE","FILE_NAME_REGEX","validatePromptPath","relativePath","normalizedPath","fileName","validatePromptFileName","getPromptsDir","resolvePromptPath","readPromptFile","validation","absolutePath","statSync","content","readFileSync","updatePromptFile","writeFileSync","createPromptFile","mkdirSync","deletePromptFile","rmSync","configManager","BaseHandler","__name","c","error","operation","defaultCode","defaultMessage","statusCode","errorMessage","errorCode","message","ConfigApiHandler","BaseHandler","__name","c","logger","config","configManager","error","newConfig","serverName","toolsConfig","toolName","toolConfig","endpoint","endpoints","servers","connection","path","exists","prompts","listPromptFiles","fileContent","readPromptFile","body","content","updatePromptFile","fileName","createPromptFile","deletePromptFile","coze_exports","__export","CozeApiService","config_default","createCozeClient","config_default","__reExport","coze_exports","api_star","createCozeClient","token","language","env","config_default","__name","NodeCache","CozeApiService","__name","token","createCozeClient","NodeCache","cacheKey","cached","workspaces","error","errorMessage","params","workspace_id","page_num","page_size","result","workflowId","parameters","pattern","keysToDelete","key","stats","keys","totalRequests","hitRate","configManager","isErrorWithCode","error","code","__name","getCozeApiService","token","configManager","CozeApiService","CozeHandler","BaseHandler","c","operationName","details","cozeApiService","workspaces","workspace_id","page_num","page_size","params","result","customMCPTools","enhancedItems","item","addedTool","tool","pattern","statsBefore","statsAfter","stats","PAGINATION_CONSTANTS","HTTP_CONTENT_TYPES","HTTP_HEADERS","HTTP_STATUS_CODES","HTTP_SERVER_CONFIG","HTTP_ERROR_MESSAGES","MCP_PROTOCOL_VERSIONS","MCP_SUPPORTED_PROTOCOL_VERSIONS","MCP_SERVER_INFO","MCP_METHODS","MCP_CACHE_VERSIONS","MCP_SERVICE_EVENTS","CACHE_TIMEOUTS","HTTP_TIMEOUTS","HEARTBEAT_MONITORING","SERVICE_RESTART_DELAYS","MESSAGE_SIZE_LIMITS","CACHE_FILE_CONFIG","TOOL_NAME_SEPARATORS","TTS_VOICES","getVoiceScenes","scenes","voice","__name","sendWebSocketError","ws","code","message","logger","errorResponse","error","__name","configManager","HeartbeatHandler","__name","statusService","notificationService","logger","ws","message","clientId","statusUpdate","error","sendWebSocketError","configManager","lastHeartbeat","now","HEARTBEAT_MONITORING","intervalId","response","EventEmitter","EventBus","EventEmitter","__name","logger","isTest","error","eventName","listenerCount","data","listener","onceListener","stats","stat","sum","count","eventBusInstance","getEventBus","destroyEventBus","EndpointHandler","__name","endpointManager","configManager","logger","getEventBus","c","errorErrorCode","body","error","endpoint","errors","parseResult","endpointStatus","status","fallbackStatus","validation","newEndpoint","connectError","configError","disconnectError","defaultEndpointStatus","endpointInstance","wasConnected","EventEmitter","isValidToolJSONSchema","obj","__name","ensureToolJSONSchema","schema","ToolCallError","code","message","data","__name","isModelScopeURL","configManager","createHash","generateCacheKey","toolName","arguments_","argsHash","createHash","__name","isCacheExpired","timestamp","ttl","cachedTime","__name","shouldCleanupCache","cache","now","DEFAULT_CONFIG","TimeoutError","_TimeoutError","__name","message","createTimeoutResponse","taskId","toolName","getToolSpecificTimeoutMessage","getDefaultTimeoutMessage","toolMessages","configManager","isProxyHandler","handler","__name","CustomMCPHandler","DEFAULT_CONFIG","cacheManager","mcpServiceManager","logger","MCPCacheManager","token","configManager","CozeApiService","eventBus","getEventBus","data","error","tools","customTools","tool","ensureToolJSONSchema","toolName","arguments_","options","completedResult","timeout","result","TimeoutError","taskId","createTimeoutResponse","_","reject","cacheKey","cache","cached","isCacheExpired","workflowData","responseData","config","cozeApiService","workflowResult","shouldCleanupCache","generateCacheKey","cacheData","fs","path","tmpdir","PathUtils","__name","tmpdir","pino","ToolCallLogger","__name","config","configDir","baseDir","PathUtils","logger","logFilePath","streams","chunk","logObj","message","pino","error","_label","number","toolName","success","duration","lines","line","recordsToRemove","linesToKeep","newContent","record","ToolCallLogService","records","a","b","query","filtered","startTime","endTime","recordTime","total","limit","offset","paginated","hasMore","MCPMessageHandler","__name","serviceManager","logger","message","isNotification","MCP_METHODS","error","params","id","clientVersion","responseVersion","MCP_SUPPORTED_PROTOCOL_VERSIONS","MCP_PROTOCOL_VERSIONS","MCP_SERVER_INFO","mcpTools","tool","validatedParams","validateToolCallParams","result","resources","prompts","errorCode","MCPServiceManager","EventEmitter","__name","getEventBus","configs","cachePath","MCPCacheManager","CustomMCPHandler","toolCallLogConfig","configManager","configDir","ToolCallLogger","data","MCPMessageHandler","logger","error","configEntries","startPromises","serviceName","results","successCount","failureCount","failedServices","result","config","serviceConfig","service","MCPService","tools","t","tool","toolKey","status","allTools","serviceTools","isEnabled","toolConfig","toolError","serviceError","customTools","customTool","toolName","toolInfo","arguments_","options","startTime","logServerName","originalToolName","isSuccess","currentTime","action","activeLocks","name","connectedServices","isModelScopeURL","originalConfig","enhancedConfig","modelScopeApiKey","serviceUrl","nameOrConfig","finalConfig","internalConfig","currentServerConfigs","currentToolsConfig","newToolsConfig","currentToolConfig","currentToolNames","removedTools","addedTools","updatedTools","current","updated","currentConfig","newConfig","currentKeys","newKeys","key","currentTool","newTool","initialDelay","delay","existingTimer","timer","currentDelay","nextDelay","acc","char","connections","conn","serviceStatus","customMCPToolCount","customToolNames","totalTools","availableTools","message","response","MCPConnection","MCPService","__name","getEventBus","config","name","connectionConfig","callbacks","data","MCP_SERVICE_EVENTS","MCPConnection","arguments_","TypeFieldNormalizer","validateToolCallParams","params","options","opts","ToolCallError","paramsObj","argsObj","error","__name","createHash","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","resolve","Hono","createApp","__name","Hono","requireMCPServiceManager","__name","c","serviceManager","dayjs","MCPCacheManager","__name","MCP_CACHE_VERSIONS","CACHE_TIMEOUTS","customCachePath","logger","dayjs","configDir","resolve","CACHE_FILE_CONFIG","existsSync","cacheDir","dirname","mkdirSync","initialCache","error","now","serverName","tools","config","cache","configHash","cacheEntry","tool","cacheData","readFileSync","cacheContent","filePath","data","tempPath","writeFileSync","renameSync","createHash","cacheObj","metadata","allTools","TOOL_NAME_SEPARATORS","toolName","arguments_","result","status","taskId","ttl","cacheKey","generateCacheKey","cachedTime","newStatus","oldStatus","entries","cleanedCount","shouldCleanupCache","totalEntries","pendingTasks","e","completedTasks","failedTasks","consumedEntries","cacheHitRate","memoryUsage","MCPRouteHandler","__name","config","logger","MESSAGE_SIZE_LIMITS","c","serviceManager","webServer","mcpServiceManager","MCPMessageHandler","error","startTime","messageId","contentLength","HTTP_HEADERS","HTTP_ERROR_MESSAGES","HTTP_CONTENT_TYPES","protocolVersion","MCP_SUPPORTED_PROTOCOL_VERSIONS","message","rawBody","response","responseTime","HTTP_STATUS_CODES","MCP_PROTOCOL_VERSIONS","errorMessage","msg","code","id","responseId","errorResponse","MCPError","_MCPError","__name","code","message","severity","category","details","error","defaultCode","DefaultErrorHandler","context","ConfigErrorHandler","ConnectionErrorHandler","ErrorHandlerRegistry","handler","result","globalErrorHandler","normalizeServiceConfig","TypeFieldNormalizer","MCPHandler","__name","mcpServiceManager","configManager","logger","error","operation","context","MCPError","mcpError","c","startTime","requestData","batchRequest","result","duration","singleRequest","name","config","statusCode","normalizedConfig","TypeFieldNormalizer","nameValidation","MCPServerConfigValidator","validationError","existsError","configValidation","configError","mcpServiceConfig","normalizeServiceConfig","serviceStatus","toolNames","tool","getEventBus","serverName","serverConfig","service","currentTools","status","newStatus","previousStatus","addedTools","removedTools","mcpServers","servers","listResponse","serverNames","results","successfullyAddedServers","validationResult","normalizedServerConfig","addedCount","failedCount","response","errors","rollbackResults","rollbackFailures","validateConfig","validateServiceName","checkServiceExists","configManager","RealtimeNotificationHandler","__name","notificationService","statusService","logger","getEventBus","ws","message","clientId","sendWebSocketError","error","config","configManager","configData","serverName","toolsConfig","toolName","toolConfig","status","feature","alternative","spawn","ServiceApiHandler","__name","statusService","logger","getEventBus","args","child","spawn","c","mcpServiceManager","requireMCPServiceManager","SERVICE_RESTART_DELAYS","error","status","health","existsSync","readFile","dirname","join","fileURLToPath","StaticFileHandler","BaseHandler","__name","logger","__dirname","dirname","fileURLToPath","possibleWebPaths","join","p","exists","existsSync","error","c","pathname","filePath","HTTP_STATUS_CODES","fullPath","indexPath","HTTP_CONTENT_TYPES","contentType","content","readFile","ext","message","errorHtml","StatusApiHandler","BaseHandler","__name","statusService","c","status","error","clientStatus","restartStatus","connected","lastHeartbeat","servers","statusUpdate","ToolType","toolSorters","__name","a","b","enabledCompare","countCompare","timeCompare","sortTools","tools","config","sorter","logger","configManager","Ajv","dayjs","MCPToolHandler","_MCPToolHandler","__name","ToolType","logger","Ajv","c","requestBody","serviceName","toolName","args","serviceManager","result","HTTP_TIMEOUTS","toolKey","error","errorMessage","errorCode","configManager","customTools","configPath","status","sortByParam","validSortFields","sortBy","rawTools","sortTools","tools","tool","responseData","availableTools","MCPError","targetTool","validate","path","message","expectedType","allowedValues","code","body","request","type","data","workflow","customName","customDescription","parameterConfig","preCheckResult","cachedTools","MCPCacheManager","fullToolName","cachedTool","finalToolName","existingTools","dayjs","serverToolsConfig","existingTool","updatedInputSchema","updatedTool","toolToDelete","mcpConfig","baseName","description","inputSchema","handler","name","sanitized","text","chineseToEnglishMap","chinese","english","requiredFields","field","value","lengthLimits","max","sensitiveWords","lowerName","word","existingNames","finalName","counter","cozeConfig","auth","validAuthTypes","bodyTemplate","templateVars","templateVar","varName","schema","properties","required","param","keyword","errorMappings","key","basicCheckResult","systemCheckResult","resourceCheckResult","workflowObj","maxTools","configSizeEstimate","maxConfigSize","action","serverName","validActions","includeUsageStats","toolConfig","newEnabled","toolsConfig","enabledCount","t","disabledCount","mcpServerConfig","serverConfig","toolInfo","z","ToolCallQuerySchema","z","val","PAGINATION_CONSTANTS","date","data","MCPToolLogHandler","BaseHandler","__name","ToolCallLogService","c","query","result","err","validation","error","message","exec","spawn","promisify","import_semver","execAsync","promisify","exec","NPMManager","__name","eventBus","getEventBus","version","installId","startTime","logger","npmProcess","spawn","cleanup","resolve","reject","error","errorMessage","data","message","code","duration","stdout","type","filteredVersions","semver","prerelease","a","b","currentVersion","stableVersions","latestVersion","hasUpdate","z","UpdateRequestSchema","z","UpdateApiHandler","BaseHandler","__name","getEventBus","NPMManager","c","body","parseResult","err","version","v","logger","error","VersionUtils","VersionApiHandler","BaseHandler","__name","c","versionInfo","VersionUtils","error","version","type","validTypes","versions","NPMManager","result","configManager","mapClusterToResourceId","createTTS","ALLOWED_ENCODINGS","ENCODING_TO_MIME","ENCODING_TO_EXT","TTSApiHandler","BaseHandler","__name","c","body","ttsConfig","configManager","appid","accessToken","voice_type","cluster","endpoint","encoding","safeEncoding","tts","createTTS","mapClusterToResourceId","audioData","error","voices","TTS_VOICES","scenes","getVoiceScenes","response","ESP32ErrorCode","ESP32Handler","BaseHandler","__name","esp32Manager","c","logger","deviceId","clientId","ESP32ErrorCode","report","response","error","loggerMiddleware","__name","c","next","logger","cors","corsMiddleware","origin","errorHandlerMiddleware","__name","err","c","notFoundHandlerMiddleware","responseEnhancerMiddleware","__name","c","next","data","message","status","response","code","details","pagination","MCPServiceManagerNotInitializedError","__name","message","WebServerNotAvailableError","mcpServiceManagerMiddleware","__name","c","next","webServer","WebServerNotAvailableError","serviceManager","error","MCPServiceManagerNotInitializedError","endpointManagerMiddleware","__name","c","next","webServer","connectionManager","error","configManager","endpointsMiddleware","__name","endpointHandler","lastManager","c","next","endpointManager","EndpointHandler","configManager","StatusService","__name","logger","getEventBus","info","source","oldStatus","error","status","servers","endpoint","configManager","NotificationService","__name","logger","getEventBus","data","config","configManager","clientId","ws","client","error","type","message","messageStr","queue","status","timestamp","restartStatus","connectedClients","queuedMessages","total","disconnectedClients","serve","normalizeServiceConfig","configManager","EndpointManager","ESP32DeviceManager","WebSocketServer","isRouteGroup","route","__name","normalizeRoutes","routes","middleware","createHandler","dependencyKey","method","c","handler","RouteManager","logger","__name","name","routeRegistry","routes","normalizeRoutes","routeRegistries","app","routeEntries","nameA","nameB","totalRouteCount","groupName","route","error","method","path","handler","middleware","wrappedHandler","c","next","h","createHandler","configRoutes","handler","c","h","createHandler","statusRoutes","handler","c","h","createHandler","toolsRoutes","handler","c","h","createHandler","mcpRoutes","handler","c","h","createHandler","versionRoutes","handler","c","h","createHandler","servicesRoutes","handler","c","h","createHandler","updateRoutes","handler","c","h","createHandler","staticRoutes","handler","c","h","createHandler","cozeRoutes","handler","c","h","createHandler","toolLogsRoutes","handler","c","withMCPServerHandler","__name","c","handlerFn","handler","mcpserverRoutes","h","withEndpointHandler","__name","c","handlerName","endpointHandler","error","endpointRoutes","h","createHandler","miscRoutes","handler","c","h","createHandler","ttsRoutes","handler","c","h","createHandler","createESP32Handler","__name","method","c","handler","esp32Routes","WebServer","__name","port","configManager","HTTP_SERVER_CONFIG","logger","getEventBus","StatusService","NotificationService","esp32ConfigProvider","ESP32DeviceManager","ConfigApiHandler","StatusApiHandler","ServiceApiHandler","MCPToolHandler","MCPToolLogHandler","VersionApiHandler","StaticFileHandler","MCPRouteHandler","UpdateApiHandler","CozeHandler","TTSApiHandler","ESP32Handler","RealtimeNotificationHandler","HeartbeatHandler","createApp","notFoundHandlerMiddleware","MCPServiceManager","config","MCPHandler","rawTools","tools","tool","ensureToolJSONSchema","error","mcpServers","name","serviceConfig","normalizeServiceConfig","mcpEndpoint","validEndpoints","ep","EndpointManager","endpointUrl","event","manager","MCPServiceManagerNotInitializedError","connectionStatuses","status","connectionFn","context","maxAttempts","initialDelay","maxDelay","backoffMultiplier","lastError","attempt","delay","ms","resolve","loggerMiddleware","responseEnhancerMiddleware","c","next","mcpServiceManagerMiddleware","endpointManagerMiddleware","endpointsMiddleware","corsMiddleware","errorHandlerMiddleware","dependencies","RouteManager","configRoutes","statusRoutes","toolsRoutes","mcpRoutes","versionRoutes","servicesRoutes","updateRoutes","cozeRoutes","toolLogsRoutes","mcpserverRoutes","endpointRoutes","miscRoutes","ttsRoutes","esp32Routes","staticRoutes","ws","req","deviceId","clientId","authToken","message","data","errorResponse","listener","eventData","singleServerListener","connectedEndpointCount","batchServerListener","server","serve","createServer","WebSocketServer","resolved","doResolve","client","forceCloseTimer","cleanupAndResolve","unsubscribe","destroyEventBus"]}
|
|
1
|
+
{"version":3,"sources":["../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js","../../apps/backend/WebServer.ts","../../apps/backend/Logger.ts","../../apps/backend/utils/prompt-utils.ts","../../apps/backend/handlers/config.handler.ts","../../apps/backend/handlers/base.handler.ts","../../apps/backend/lib/coze/index.ts","../../apps/backend/lib/coze/config.ts","../../apps/backend/lib/coze/client.ts","../../apps/backend/lib/coze/service.ts","../../apps/backend/handlers/coze.handler.ts","../../apps/backend/services/event-bus.service.ts","../../apps/backend/handlers/endpoint.handler.ts","../../apps/backend/constants/api.constants.ts","../../apps/backend/constants/http.constants.ts","../../apps/backend/constants/mcp.constants.ts","../../apps/backend/constants/event.constants.ts","../../apps/backend/constants/timeout.constants.ts","../../apps/backend/constants/cache.constants.ts","../../apps/backend/constants/voices.ts","../../apps/backend/lib/mcp/manager.ts","../../apps/backend/lib/mcp/types.ts","../../apps/backend/types/mcp.ts","../../apps/backend/types/timeout.ts","../../apps/backend/lib/mcp/custom.ts","../../apps/backend/lib/mcp/log.ts","../../apps/backend/utils/path-utils.ts","../../apps/backend/lib/mcp/message.ts","../../apps/backend/lib/mcp/connection.ts","../../apps/backend/lib/mcp/utils.ts","../../apps/backend/lib/mcp/cache.ts","../../apps/backend/types/hono.context.ts","../../apps/backend/handlers/mcp.handler.ts","../../apps/backend/errors/mcp-errors.ts","../../apps/backend/handlers/mcp-manage.handler.ts","../../apps/backend/handlers/service.handler.ts","../../apps/backend/handlers/static-file.handler.ts","../../apps/backend/handlers/status.handler.ts","../../apps/backend/types/toolApi.ts","../../apps/backend/utils/toolSorters.ts","../../apps/backend/handlers/mcp-tool.handler.ts","../../apps/backend/handlers/mcp-tool-log.handler.ts","../../apps/backend/lib/npm/manager.ts","../../apps/backend/lib/npm/install-log-stream.ts","../../apps/backend/handlers/update.handler.ts","../../apps/backend/handlers/version.handler.ts","../../apps/backend/handlers/tts.handler.ts","../../apps/backend/handlers/esp32.handler.ts","../../apps/backend/middlewares/logger.middleware.ts","../../apps/backend/middlewares/cors.middleware.ts","../../apps/backend/middlewares/error.middleware.ts","../../apps/backend/middlewares/response-enhancer.middleware.ts","../../apps/backend/errors/mcp-errors.middleware.ts","../../apps/backend/middlewares/mcpServiceManager.middleware.ts","../../apps/backend/middlewares/endpointManager.middleware.ts","../../apps/backend/middlewares/endpoints.middleware.ts","../../apps/backend/services/status.service.ts","../../apps/backend/routes/types.ts","../../apps/backend/routes/RouteManager.ts","../../apps/backend/routes/domains/config.route.ts","../../apps/backend/routes/domains/status.route.ts","../../apps/backend/routes/domains/tools.route.ts","../../apps/backend/routes/domains/mcp.route.ts","../../apps/backend/routes/domains/version.route.ts","../../apps/backend/routes/domains/services.route.ts","../../apps/backend/routes/domains/update.route.ts","../../apps/backend/routes/domains/static.route.ts","../../apps/backend/routes/domains/coze.route.ts","../../apps/backend/routes/domains/tool-logs.route.ts","../../apps/backend/routes/domains/mcpserver.route.ts","../../apps/backend/routes/domains/endpoint.route.ts","../../apps/backend/routes/domains/misc.route.ts","../../apps/backend/routes/domains/tts.route.ts","../../apps/backend/routes/domains/esp32.route.ts"],"sourcesContent":["'use strict'\n\n// Note: this is the semver.org version of the spec that it implements\n// Not necessarily the package version of this code.\nconst SEMVER_SPEC_VERSION = '2.0.0'\n\nconst MAX_LENGTH = 256\nconst MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||\n/* istanbul ignore next */ 9007199254740991\n\n// Max safe segment length for coercion.\nconst MAX_SAFE_COMPONENT_LENGTH = 16\n\n// Max safe length for a build identifier. The max length minus 6 characters for\n// the shortest version with a build 0.0.0+BUILD.\nconst MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6\n\nconst RELEASE_TYPES = [\n 'major',\n 'premajor',\n 'minor',\n 'preminor',\n 'patch',\n 'prepatch',\n 'prerelease',\n]\n\nmodule.exports = {\n MAX_LENGTH,\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_SAFE_INTEGER,\n RELEASE_TYPES,\n SEMVER_SPEC_VERSION,\n FLAG_INCLUDE_PRERELEASE: 0b001,\n FLAG_LOOSE: 0b010,\n}\n","'use strict'\n\nconst debug = (\n typeof process === 'object' &&\n process.env &&\n process.env.NODE_DEBUG &&\n /\\bsemver\\b/i.test(process.env.NODE_DEBUG)\n) ? (...args) => console.error('SEMVER', ...args)\n : () => {}\n\nmodule.exports = debug\n","'use strict'\n\nconst {\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_LENGTH,\n} = require('./constants')\nconst debug = require('./debug')\nexports = module.exports = {}\n\n// The actual regexps go on exports.re\nconst re = exports.re = []\nconst safeRe = exports.safeRe = []\nconst src = exports.src = []\nconst safeSrc = exports.safeSrc = []\nconst t = exports.t = {}\nlet R = 0\n\nconst LETTERDASHNUMBER = '[a-zA-Z0-9-]'\n\n// Replace some greedy regex tokens to prevent regex dos issues. These regex are\n// used internally via the safeRe object since all inputs in this library get\n// normalized first to trim and collapse all extra whitespace. The original\n// regexes are exported for userland consumption and lower level usage. A\n// future breaking change could export the safer regex only with a note that\n// all input should have extra whitespace removed.\nconst safeRegexReplacements = [\n ['\\\\s', 1],\n ['\\\\d', MAX_LENGTH],\n [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],\n]\n\nconst makeSafeRegex = (value) => {\n for (const [token, max] of safeRegexReplacements) {\n value = value\n .split(`${token}*`).join(`${token}{0,${max}}`)\n .split(`${token}+`).join(`${token}{1,${max}}`)\n }\n return value\n}\n\nconst createToken = (name, value, isGlobal) => {\n const safe = makeSafeRegex(value)\n const index = R++\n debug(name, index, value)\n t[name] = index\n src[index] = value\n safeSrc[index] = safe\n re[index] = new RegExp(value, isGlobal ? 'g' : undefined)\n safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)\n}\n\n// The following Regular Expressions can be used for tokenizing,\n// validating, and parsing SemVer version strings.\n\n// ## Numeric Identifier\n// A single `0`, or a non-zero digit followed by zero or more digits.\n\ncreateToken('NUMERICIDENTIFIER', '0|[1-9]\\\\d*')\ncreateToken('NUMERICIDENTIFIERLOOSE', '\\\\d+')\n\n// ## Non-numeric Identifier\n// Zero or more digits, followed by a letter or hyphen, and then zero or\n// more letters, digits, or hyphens.\n\ncreateToken('NONNUMERICIDENTIFIER', `\\\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)\n\n// ## Main Version\n// Three dot-separated numeric identifiers.\n\ncreateToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIER]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIER]})`)\n\ncreateToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIERLOOSE]})`)\n\n// ## Pre-release Version Identifier\n// A numeric identifier, or a non-numeric identifier.\n// Non-numberic identifiers include numberic identifiers but can be longer.\n// Therefore non-numberic identifiers must go first.\n\ncreateToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER]\n}|${src[t.NUMERICIDENTIFIER]})`)\n\ncreateToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER]\n}|${src[t.NUMERICIDENTIFIERLOOSE]})`)\n\n// ## Pre-release Version\n// Hyphen, followed by one or more dot-separated pre-release version\n// identifiers.\n\ncreateToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]\n}(?:\\\\.${src[t.PRERELEASEIDENTIFIER]})*))`)\n\ncreateToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]\n}(?:\\\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)\n\n// ## Build Metadata Identifier\n// Any combination of digits, letters, or hyphens.\n\ncreateToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)\n\n// ## Build Metadata\n// Plus sign, followed by one or more period-separated build metadata\n// identifiers.\n\ncreateToken('BUILD', `(?:\\\\+(${src[t.BUILDIDENTIFIER]\n}(?:\\\\.${src[t.BUILDIDENTIFIER]})*))`)\n\n// ## Full Version String\n// A main version, followed optionally by a pre-release version and\n// build metadata.\n\n// Note that the only major, minor, patch, and pre-release sections of\n// the version string are capturing groups. The build metadata is not a\n// capturing group, because it should not ever be used in version\n// comparison.\n\ncreateToken('FULLPLAIN', `v?${src[t.MAINVERSION]\n}${src[t.PRERELEASE]}?${\n src[t.BUILD]}?`)\n\ncreateToken('FULL', `^${src[t.FULLPLAIN]}$`)\n\n// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.\n// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty\n// common in the npm registry.\ncreateToken('LOOSEPLAIN', `[v=\\\\s]*${src[t.MAINVERSIONLOOSE]\n}${src[t.PRERELEASELOOSE]}?${\n src[t.BUILD]}?`)\n\ncreateToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)\n\ncreateToken('GTLT', '((?:<|>)?=?)')\n\n// Something like \"2.*\" or \"1.2.x\".\n// Note that \"x.x\" is a valid xRange identifer, meaning \"any version\"\n// Only the first item is strictly required.\ncreateToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`)\ncreateToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\\\*`)\n\ncreateToken('XRANGEPLAIN', `[v=\\\\s]*(${src[t.XRANGEIDENTIFIER]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIER]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIER]})` +\n `(?:${src[t.PRERELEASE]})?${\n src[t.BUILD]}?` +\n `)?)?`)\n\ncreateToken('XRANGEPLAINLOOSE', `[v=\\\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:${src[t.PRERELEASELOOSE]})?${\n src[t.BUILD]}?` +\n `)?)?`)\n\ncreateToken('XRANGE', `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAIN]}$`)\ncreateToken('XRANGELOOSE', `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAINLOOSE]}$`)\n\n// Coercion.\n// Extract anything that could conceivably be a part of a valid semver\ncreateToken('COERCEPLAIN', `${'(^|[^\\\\d])' +\n '(\\\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +\n `(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +\n `(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)\ncreateToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\\\d])`)\ncreateToken('COERCEFULL', src[t.COERCEPLAIN] +\n `(?:${src[t.PRERELEASE]})?` +\n `(?:${src[t.BUILD]})?` +\n `(?:$|[^\\\\d])`)\ncreateToken('COERCERTL', src[t.COERCE], true)\ncreateToken('COERCERTLFULL', src[t.COERCEFULL], true)\n\n// Tilde ranges.\n// Meaning is \"reasonably at or greater than\"\ncreateToken('LONETILDE', '(?:~>?)')\n\ncreateToken('TILDETRIM', `(\\\\s*)${src[t.LONETILDE]}\\\\s+`, true)\nexports.tildeTrimReplace = '$1~'\n\ncreateToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)\ncreateToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)\n\n// Caret ranges.\n// Meaning is \"at least and backwards compatible with\"\ncreateToken('LONECARET', '(?:\\\\^)')\n\ncreateToken('CARETTRIM', `(\\\\s*)${src[t.LONECARET]}\\\\s+`, true)\nexports.caretTrimReplace = '$1^'\n\ncreateToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)\ncreateToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)\n\n// A simple gt/lt/eq thing, or just \"\" to indicate \"any version\"\ncreateToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\\\s*(${src[t.LOOSEPLAIN]})$|^$`)\ncreateToken('COMPARATOR', `^${src[t.GTLT]}\\\\s*(${src[t.FULLPLAIN]})$|^$`)\n\n// An expression to strip any whitespace between the gtlt and the thing\n// it modifies, so that `> 1.2.3` ==> `>1.2.3`\ncreateToken('COMPARATORTRIM', `(\\\\s*)${src[t.GTLT]\n}\\\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)\nexports.comparatorTrimReplace = '$1$2$3'\n\n// Something like `1.2.3 - 1.2.4`\n// Note that these all use the loose form, because they'll be\n// checked against either the strict or loose comparator form\n// later.\ncreateToken('HYPHENRANGE', `^\\\\s*(${src[t.XRANGEPLAIN]})` +\n `\\\\s+-\\\\s+` +\n `(${src[t.XRANGEPLAIN]})` +\n `\\\\s*$`)\n\ncreateToken('HYPHENRANGELOOSE', `^\\\\s*(${src[t.XRANGEPLAINLOOSE]})` +\n `\\\\s+-\\\\s+` +\n `(${src[t.XRANGEPLAINLOOSE]})` +\n `\\\\s*$`)\n\n// Star ranges basically just allow anything at all.\ncreateToken('STAR', '(<|>)?=?\\\\s*\\\\*')\n// >=0.0.0 is like a star\ncreateToken('GTE0', '^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$')\ncreateToken('GTE0PRE', '^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$')\n","'use strict'\n\n// parse out just the options we care about\nconst looseOption = Object.freeze({ loose: true })\nconst emptyOpts = Object.freeze({ })\nconst parseOptions = options => {\n if (!options) {\n return emptyOpts\n }\n\n if (typeof options !== 'object') {\n return looseOption\n }\n\n return options\n}\nmodule.exports = parseOptions\n","'use strict'\n\nconst numeric = /^[0-9]+$/\nconst compareIdentifiers = (a, b) => {\n if (typeof a === 'number' && typeof b === 'number') {\n return a === b ? 0 : a < b ? -1 : 1\n }\n\n const anum = numeric.test(a)\n const bnum = numeric.test(b)\n\n if (anum && bnum) {\n a = +a\n b = +b\n }\n\n return a === b ? 0\n : (anum && !bnum) ? -1\n : (bnum && !anum) ? 1\n : a < b ? -1\n : 1\n}\n\nconst rcompareIdentifiers = (a, b) => compareIdentifiers(b, a)\n\nmodule.exports = {\n compareIdentifiers,\n rcompareIdentifiers,\n}\n","'use strict'\n\nconst debug = require('../internal/debug')\nconst { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')\nconst { safeRe: re, t } = require('../internal/re')\n\nconst parseOptions = require('../internal/parse-options')\nconst { compareIdentifiers } = require('../internal/identifiers')\nclass SemVer {\n constructor (version, options) {\n options = parseOptions(options)\n\n if (version instanceof SemVer) {\n if (version.loose === !!options.loose &&\n version.includePrerelease === !!options.includePrerelease) {\n return version\n } else {\n version = version.version\n }\n } else if (typeof version !== 'string') {\n throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof version}\".`)\n }\n\n if (version.length > MAX_LENGTH) {\n throw new TypeError(\n `version is longer than ${MAX_LENGTH} characters`\n )\n }\n\n debug('SemVer', version, options)\n this.options = options\n this.loose = !!options.loose\n // this isn't actually relevant for versions, but keep it so that we\n // don't run into trouble passing this.options around.\n this.includePrerelease = !!options.includePrerelease\n\n const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])\n\n if (!m) {\n throw new TypeError(`Invalid Version: ${version}`)\n }\n\n this.raw = version\n\n // these are actually numbers\n this.major = +m[1]\n this.minor = +m[2]\n this.patch = +m[3]\n\n if (this.major > MAX_SAFE_INTEGER || this.major < 0) {\n throw new TypeError('Invalid major version')\n }\n\n if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {\n throw new TypeError('Invalid minor version')\n }\n\n if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {\n throw new TypeError('Invalid patch version')\n }\n\n // numberify any prerelease numeric ids\n if (!m[4]) {\n this.prerelease = []\n } else {\n this.prerelease = m[4].split('.').map((id) => {\n if (/^[0-9]+$/.test(id)) {\n const num = +id\n if (num >= 0 && num < MAX_SAFE_INTEGER) {\n return num\n }\n }\n return id\n })\n }\n\n this.build = m[5] ? m[5].split('.') : []\n this.format()\n }\n\n format () {\n this.version = `${this.major}.${this.minor}.${this.patch}`\n if (this.prerelease.length) {\n this.version += `-${this.prerelease.join('.')}`\n }\n return this.version\n }\n\n toString () {\n return this.version\n }\n\n compare (other) {\n debug('SemVer.compare', this.version, this.options, other)\n if (!(other instanceof SemVer)) {\n if (typeof other === 'string' && other === this.version) {\n return 0\n }\n other = new SemVer(other, this.options)\n }\n\n if (other.version === this.version) {\n return 0\n }\n\n return this.compareMain(other) || this.comparePre(other)\n }\n\n compareMain (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n if (this.major < other.major) {\n return -1\n }\n if (this.major > other.major) {\n return 1\n }\n if (this.minor < other.minor) {\n return -1\n }\n if (this.minor > other.minor) {\n return 1\n }\n if (this.patch < other.patch) {\n return -1\n }\n if (this.patch > other.patch) {\n return 1\n }\n return 0\n }\n\n comparePre (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n // NOT having a prerelease is > having one\n if (this.prerelease.length && !other.prerelease.length) {\n return -1\n } else if (!this.prerelease.length && other.prerelease.length) {\n return 1\n } else if (!this.prerelease.length && !other.prerelease.length) {\n return 0\n }\n\n let i = 0\n do {\n const a = this.prerelease[i]\n const b = other.prerelease[i]\n debug('prerelease compare', i, a, b)\n if (a === undefined && b === undefined) {\n return 0\n } else if (b === undefined) {\n return 1\n } else if (a === undefined) {\n return -1\n } else if (a === b) {\n continue\n } else {\n return compareIdentifiers(a, b)\n }\n } while (++i)\n }\n\n compareBuild (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n let i = 0\n do {\n const a = this.build[i]\n const b = other.build[i]\n debug('build compare', i, a, b)\n if (a === undefined && b === undefined) {\n return 0\n } else if (b === undefined) {\n return 1\n } else if (a === undefined) {\n return -1\n } else if (a === b) {\n continue\n } else {\n return compareIdentifiers(a, b)\n }\n } while (++i)\n }\n\n // preminor will bump the version up to the next minor release, and immediately\n // down to pre-release. premajor and prepatch work the same way.\n inc (release, identifier, identifierBase) {\n if (release.startsWith('pre')) {\n if (!identifier && identifierBase === false) {\n throw new Error('invalid increment argument: identifier is empty')\n }\n // Avoid an invalid semver results\n if (identifier) {\n const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE])\n if (!match || match[1] !== identifier) {\n throw new Error(`invalid identifier: ${identifier}`)\n }\n }\n }\n\n switch (release) {\n case 'premajor':\n this.prerelease.length = 0\n this.patch = 0\n this.minor = 0\n this.major++\n this.inc('pre', identifier, identifierBase)\n break\n case 'preminor':\n this.prerelease.length = 0\n this.patch = 0\n this.minor++\n this.inc('pre', identifier, identifierBase)\n break\n case 'prepatch':\n // If this is already a prerelease, it will bump to the next version\n // drop any prereleases that might already exist, since they are not\n // relevant at this point.\n this.prerelease.length = 0\n this.inc('patch', identifier, identifierBase)\n this.inc('pre', identifier, identifierBase)\n break\n // If the input is a non-prerelease version, this acts the same as\n // prepatch.\n case 'prerelease':\n if (this.prerelease.length === 0) {\n this.inc('patch', identifier, identifierBase)\n }\n this.inc('pre', identifier, identifierBase)\n break\n case 'release':\n if (this.prerelease.length === 0) {\n throw new Error(`version ${this.raw} is not a prerelease`)\n }\n this.prerelease.length = 0\n break\n\n case 'major':\n // If this is a pre-major version, bump up to the same major version.\n // Otherwise increment major.\n // 1.0.0-5 bumps to 1.0.0\n // 1.1.0 bumps to 2.0.0\n if (\n this.minor !== 0 ||\n this.patch !== 0 ||\n this.prerelease.length === 0\n ) {\n this.major++\n }\n this.minor = 0\n this.patch = 0\n this.prerelease = []\n break\n case 'minor':\n // If this is a pre-minor version, bump up to the same minor version.\n // Otherwise increment minor.\n // 1.2.0-5 bumps to 1.2.0\n // 1.2.1 bumps to 1.3.0\n if (this.patch !== 0 || this.prerelease.length === 0) {\n this.minor++\n }\n this.patch = 0\n this.prerelease = []\n break\n case 'patch':\n // If this is not a pre-release version, it will increment the patch.\n // If it is a pre-release it will bump up to the same patch version.\n // 1.2.0-5 patches to 1.2.0\n // 1.2.0 patches to 1.2.1\n if (this.prerelease.length === 0) {\n this.patch++\n }\n this.prerelease = []\n break\n // This probably shouldn't be used publicly.\n // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.\n case 'pre': {\n const base = Number(identifierBase) ? 1 : 0\n\n if (this.prerelease.length === 0) {\n this.prerelease = [base]\n } else {\n let i = this.prerelease.length\n while (--i >= 0) {\n if (typeof this.prerelease[i] === 'number') {\n this.prerelease[i]++\n i = -2\n }\n }\n if (i === -1) {\n // didn't increment anything\n if (identifier === this.prerelease.join('.') && identifierBase === false) {\n throw new Error('invalid increment argument: identifier already exists')\n }\n this.prerelease.push(base)\n }\n }\n if (identifier) {\n // 1.2.0-beta.1 bumps to 1.2.0-beta.2,\n // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0\n let prerelease = [identifier, base]\n if (identifierBase === false) {\n prerelease = [identifier]\n }\n if (compareIdentifiers(this.prerelease[0], identifier) === 0) {\n if (isNaN(this.prerelease[1])) {\n this.prerelease = prerelease\n }\n } else {\n this.prerelease = prerelease\n }\n }\n break\n }\n default:\n throw new Error(`invalid increment argument: ${release}`)\n }\n this.raw = this.format()\n if (this.build.length) {\n this.raw += `+${this.build.join('.')}`\n }\n return this\n }\n}\n\nmodule.exports = SemVer\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst parse = (version, options, throwErrors = false) => {\n if (version instanceof SemVer) {\n return version\n }\n try {\n return new SemVer(version, options)\n } catch (er) {\n if (!throwErrors) {\n return null\n }\n throw er\n }\n}\n\nmodule.exports = parse\n","'use strict'\n\nconst parse = require('./parse')\nconst valid = (version, options) => {\n const v = parse(version, options)\n return v ? v.version : null\n}\nmodule.exports = valid\n","'use strict'\n\nconst parse = require('./parse')\nconst clean = (version, options) => {\n const s = parse(version.trim().replace(/^[=v]+/, ''), options)\n return s ? s.version : null\n}\nmodule.exports = clean\n","'use strict'\n\nconst SemVer = require('../classes/semver')\n\nconst inc = (version, release, options, identifier, identifierBase) => {\n if (typeof (options) === 'string') {\n identifierBase = identifier\n identifier = options\n options = undefined\n }\n\n try {\n return new SemVer(\n version instanceof SemVer ? version.version : version,\n options\n ).inc(release, identifier, identifierBase).version\n } catch (er) {\n return null\n }\n}\nmodule.exports = inc\n","'use strict'\n\nconst parse = require('./parse.js')\n\nconst diff = (version1, version2) => {\n const v1 = parse(version1, null, true)\n const v2 = parse(version2, null, true)\n const comparison = v1.compare(v2)\n\n if (comparison === 0) {\n return null\n }\n\n const v1Higher = comparison > 0\n const highVersion = v1Higher ? v1 : v2\n const lowVersion = v1Higher ? v2 : v1\n const highHasPre = !!highVersion.prerelease.length\n const lowHasPre = !!lowVersion.prerelease.length\n\n if (lowHasPre && !highHasPre) {\n // Going from prerelease -> no prerelease requires some special casing\n\n // If the low version has only a major, then it will always be a major\n // Some examples:\n // 1.0.0-1 -> 1.0.0\n // 1.0.0-1 -> 1.1.1\n // 1.0.0-1 -> 2.0.0\n if (!lowVersion.patch && !lowVersion.minor) {\n return 'major'\n }\n\n // If the main part has no difference\n if (lowVersion.compareMain(highVersion) === 0) {\n if (lowVersion.minor && !lowVersion.patch) {\n return 'minor'\n }\n return 'patch'\n }\n }\n\n // add the `pre` prefix if we are going to a prerelease version\n const prefix = highHasPre ? 'pre' : ''\n\n if (v1.major !== v2.major) {\n return prefix + 'major'\n }\n\n if (v1.minor !== v2.minor) {\n return prefix + 'minor'\n }\n\n if (v1.patch !== v2.patch) {\n return prefix + 'patch'\n }\n\n // high and low are preleases\n return 'prerelease'\n}\n\nmodule.exports = diff\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst major = (a, loose) => new SemVer(a, loose).major\nmodule.exports = major\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst minor = (a, loose) => new SemVer(a, loose).minor\nmodule.exports = minor\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst patch = (a, loose) => new SemVer(a, loose).patch\nmodule.exports = patch\n","'use strict'\n\nconst parse = require('./parse')\nconst prerelease = (version, options) => {\n const parsed = parse(version, options)\n return (parsed && parsed.prerelease.length) ? parsed.prerelease : null\n}\nmodule.exports = prerelease\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst compare = (a, b, loose) =>\n new SemVer(a, loose).compare(new SemVer(b, loose))\n\nmodule.exports = compare\n","'use strict'\n\nconst compare = require('./compare')\nconst rcompare = (a, b, loose) => compare(b, a, loose)\nmodule.exports = rcompare\n","'use strict'\n\nconst compare = require('./compare')\nconst compareLoose = (a, b) => compare(a, b, true)\nmodule.exports = compareLoose\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst compareBuild = (a, b, loose) => {\n const versionA = new SemVer(a, loose)\n const versionB = new SemVer(b, loose)\n return versionA.compare(versionB) || versionA.compareBuild(versionB)\n}\nmodule.exports = compareBuild\n","'use strict'\n\nconst compareBuild = require('./compare-build')\nconst sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose))\nmodule.exports = sort\n","'use strict'\n\nconst compareBuild = require('./compare-build')\nconst rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose))\nmodule.exports = rsort\n","'use strict'\n\nconst compare = require('./compare')\nconst gt = (a, b, loose) => compare(a, b, loose) > 0\nmodule.exports = gt\n","'use strict'\n\nconst compare = require('./compare')\nconst lt = (a, b, loose) => compare(a, b, loose) < 0\nmodule.exports = lt\n","'use strict'\n\nconst compare = require('./compare')\nconst eq = (a, b, loose) => compare(a, b, loose) === 0\nmodule.exports = eq\n","'use strict'\n\nconst compare = require('./compare')\nconst neq = (a, b, loose) => compare(a, b, loose) !== 0\nmodule.exports = neq\n","'use strict'\n\nconst compare = require('./compare')\nconst gte = (a, b, loose) => compare(a, b, loose) >= 0\nmodule.exports = gte\n","'use strict'\n\nconst compare = require('./compare')\nconst lte = (a, b, loose) => compare(a, b, loose) <= 0\nmodule.exports = lte\n","'use strict'\n\nconst eq = require('./eq')\nconst neq = require('./neq')\nconst gt = require('./gt')\nconst gte = require('./gte')\nconst lt = require('./lt')\nconst lte = require('./lte')\n\nconst cmp = (a, op, b, loose) => {\n switch (op) {\n case '===':\n if (typeof a === 'object') {\n a = a.version\n }\n if (typeof b === 'object') {\n b = b.version\n }\n return a === b\n\n case '!==':\n if (typeof a === 'object') {\n a = a.version\n }\n if (typeof b === 'object') {\n b = b.version\n }\n return a !== b\n\n case '':\n case '=':\n case '==':\n return eq(a, b, loose)\n\n case '!=':\n return neq(a, b, loose)\n\n case '>':\n return gt(a, b, loose)\n\n case '>=':\n return gte(a, b, loose)\n\n case '<':\n return lt(a, b, loose)\n\n case '<=':\n return lte(a, b, loose)\n\n default:\n throw new TypeError(`Invalid operator: ${op}`)\n }\n}\nmodule.exports = cmp\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst parse = require('./parse')\nconst { safeRe: re, t } = require('../internal/re')\n\nconst coerce = (version, options) => {\n if (version instanceof SemVer) {\n return version\n }\n\n if (typeof version === 'number') {\n version = String(version)\n }\n\n if (typeof version !== 'string') {\n return null\n }\n\n options = options || {}\n\n let match = null\n if (!options.rtl) {\n match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE])\n } else {\n // Find the right-most coercible string that does not share\n // a terminus with a more left-ward coercible string.\n // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4'\n // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4'\n //\n // Walk through the string checking with a /g regexp\n // Manually set the index so as to pick up overlapping matches.\n // Stop when we get a match that ends at the string end, since no\n // coercible string can be more right-ward without the same terminus.\n const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL]\n let next\n while ((next = coerceRtlRegex.exec(version)) &&\n (!match || match.index + match[0].length !== version.length)\n ) {\n if (!match ||\n next.index + next[0].length !== match.index + match[0].length) {\n match = next\n }\n coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length\n }\n // leave it in a clean state\n coerceRtlRegex.lastIndex = -1\n }\n\n if (match === null) {\n return null\n }\n\n const major = match[2]\n const minor = match[3] || '0'\n const patch = match[4] || '0'\n const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : ''\n const build = options.includePrerelease && match[6] ? `+${match[6]}` : ''\n\n return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options)\n}\nmodule.exports = coerce\n","'use strict'\n\nclass LRUCache {\n constructor () {\n this.max = 1000\n this.map = new Map()\n }\n\n get (key) {\n const value = this.map.get(key)\n if (value === undefined) {\n return undefined\n } else {\n // Remove the key from the map and add it to the end\n this.map.delete(key)\n this.map.set(key, value)\n return value\n }\n }\n\n delete (key) {\n return this.map.delete(key)\n }\n\n set (key, value) {\n const deleted = this.delete(key)\n\n if (!deleted && value !== undefined) {\n // If cache is full, delete the least recently used item\n if (this.map.size >= this.max) {\n const firstKey = this.map.keys().next().value\n this.delete(firstKey)\n }\n\n this.map.set(key, value)\n }\n\n return this\n }\n}\n\nmodule.exports = LRUCache\n","'use strict'\n\nconst SPACE_CHARACTERS = /\\s+/g\n\n// hoisted class for cyclic dependency\nclass Range {\n constructor (range, options) {\n options = parseOptions(options)\n\n if (range instanceof Range) {\n if (\n range.loose === !!options.loose &&\n range.includePrerelease === !!options.includePrerelease\n ) {\n return range\n } else {\n return new Range(range.raw, options)\n }\n }\n\n if (range instanceof Comparator) {\n // just put it in the set and return\n this.raw = range.value\n this.set = [[range]]\n this.formatted = undefined\n return this\n }\n\n this.options = options\n this.loose = !!options.loose\n this.includePrerelease = !!options.includePrerelease\n\n // First reduce all whitespace as much as possible so we do not have to rely\n // on potentially slow regexes like \\s*. This is then stored and used for\n // future error messages as well.\n this.raw = range.trim().replace(SPACE_CHARACTERS, ' ')\n\n // First, split on ||\n this.set = this.raw\n .split('||')\n // map the range to a 2d array of comparators\n .map(r => this.parseRange(r.trim()))\n // throw out any comparator lists that are empty\n // this generally means that it was not a valid range, which is allowed\n // in loose mode, but will still throw if the WHOLE range is invalid.\n .filter(c => c.length)\n\n if (!this.set.length) {\n throw new TypeError(`Invalid SemVer Range: ${this.raw}`)\n }\n\n // if we have any that are not the null set, throw out null sets.\n if (this.set.length > 1) {\n // keep the first one, in case they're all null sets\n const first = this.set[0]\n this.set = this.set.filter(c => !isNullSet(c[0]))\n if (this.set.length === 0) {\n this.set = [first]\n } else if (this.set.length > 1) {\n // if we have any that are *, then the range is just *\n for (const c of this.set) {\n if (c.length === 1 && isAny(c[0])) {\n this.set = [c]\n break\n }\n }\n }\n }\n\n this.formatted = undefined\n }\n\n get range () {\n if (this.formatted === undefined) {\n this.formatted = ''\n for (let i = 0; i < this.set.length; i++) {\n if (i > 0) {\n this.formatted += '||'\n }\n const comps = this.set[i]\n for (let k = 0; k < comps.length; k++) {\n if (k > 0) {\n this.formatted += ' '\n }\n this.formatted += comps[k].toString().trim()\n }\n }\n }\n return this.formatted\n }\n\n format () {\n return this.range\n }\n\n toString () {\n return this.range\n }\n\n parseRange (range) {\n // memoize range parsing for performance.\n // this is a very hot path, and fully deterministic.\n const memoOpts =\n (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) |\n (this.options.loose && FLAG_LOOSE)\n const memoKey = memoOpts + ':' + range\n const cached = cache.get(memoKey)\n if (cached) {\n return cached\n }\n\n const loose = this.options.loose\n // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`\n const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]\n range = range.replace(hr, hyphenReplace(this.options.includePrerelease))\n debug('hyphen replace', range)\n\n // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`\n range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)\n debug('comparator trim', range)\n\n // `~ 1.2.3` => `~1.2.3`\n range = range.replace(re[t.TILDETRIM], tildeTrimReplace)\n debug('tilde trim', range)\n\n // `^ 1.2.3` => `^1.2.3`\n range = range.replace(re[t.CARETTRIM], caretTrimReplace)\n debug('caret trim', range)\n\n // At this point, the range is completely trimmed and\n // ready to be split into comparators.\n\n let rangeList = range\n .split(' ')\n .map(comp => parseComparator(comp, this.options))\n .join(' ')\n .split(/\\s+/)\n // >=0.0.0 is equivalent to *\n .map(comp => replaceGTE0(comp, this.options))\n\n if (loose) {\n // in loose mode, throw out any that are not valid comparators\n rangeList = rangeList.filter(comp => {\n debug('loose invalid filter', comp, this.options)\n return !!comp.match(re[t.COMPARATORLOOSE])\n })\n }\n debug('range list', rangeList)\n\n // if any comparators are the null set, then replace with JUST null set\n // if more than one comparator, remove any * comparators\n // also, don't include the same comparator more than once\n const rangeMap = new Map()\n const comparators = rangeList.map(comp => new Comparator(comp, this.options))\n for (const comp of comparators) {\n if (isNullSet(comp)) {\n return [comp]\n }\n rangeMap.set(comp.value, comp)\n }\n if (rangeMap.size > 1 && rangeMap.has('')) {\n rangeMap.delete('')\n }\n\n const result = [...rangeMap.values()]\n cache.set(memoKey, result)\n return result\n }\n\n intersects (range, options) {\n if (!(range instanceof Range)) {\n throw new TypeError('a Range is required')\n }\n\n return this.set.some((thisComparators) => {\n return (\n isSatisfiable(thisComparators, options) &&\n range.set.some((rangeComparators) => {\n return (\n isSatisfiable(rangeComparators, options) &&\n thisComparators.every((thisComparator) => {\n return rangeComparators.every((rangeComparator) => {\n return thisComparator.intersects(rangeComparator, options)\n })\n })\n )\n })\n )\n })\n }\n\n // if ANY of the sets match ALL of its comparators, then pass\n test (version) {\n if (!version) {\n return false\n }\n\n if (typeof version === 'string') {\n try {\n version = new SemVer(version, this.options)\n } catch (er) {\n return false\n }\n }\n\n for (let i = 0; i < this.set.length; i++) {\n if (testSet(this.set[i], version, this.options)) {\n return true\n }\n }\n return false\n }\n}\n\nmodule.exports = Range\n\nconst LRU = require('../internal/lrucache')\nconst cache = new LRU()\n\nconst parseOptions = require('../internal/parse-options')\nconst Comparator = require('./comparator')\nconst debug = require('../internal/debug')\nconst SemVer = require('./semver')\nconst {\n safeRe: re,\n t,\n comparatorTrimReplace,\n tildeTrimReplace,\n caretTrimReplace,\n} = require('../internal/re')\nconst { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require('../internal/constants')\n\nconst isNullSet = c => c.value === '<0.0.0-0'\nconst isAny = c => c.value === ''\n\n// take a set of comparators and determine whether there\n// exists a version which can satisfy it\nconst isSatisfiable = (comparators, options) => {\n let result = true\n const remainingComparators = comparators.slice()\n let testComparator = remainingComparators.pop()\n\n while (result && remainingComparators.length) {\n result = remainingComparators.every((otherComparator) => {\n return testComparator.intersects(otherComparator, options)\n })\n\n testComparator = remainingComparators.pop()\n }\n\n return result\n}\n\n// comprised of xranges, tildes, stars, and gtlt's at this point.\n// already replaced the hyphen ranges\n// turn into a set of JUST comparators.\nconst parseComparator = (comp, options) => {\n comp = comp.replace(re[t.BUILD], '')\n debug('comp', comp, options)\n comp = replaceCarets(comp, options)\n debug('caret', comp)\n comp = replaceTildes(comp, options)\n debug('tildes', comp)\n comp = replaceXRanges(comp, options)\n debug('xrange', comp)\n comp = replaceStars(comp, options)\n debug('stars', comp)\n return comp\n}\n\nconst isX = id => !id || id.toLowerCase() === 'x' || id === '*'\n\n// ~, ~> --> * (any, kinda silly)\n// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0\n// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0\n// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0\n// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0\n// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0\n// ~0.0.1 --> >=0.0.1 <0.1.0-0\nconst replaceTildes = (comp, options) => {\n return comp\n .trim()\n .split(/\\s+/)\n .map((c) => replaceTilde(c, options))\n .join(' ')\n}\n\nconst replaceTilde = (comp, options) => {\n const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]\n return comp.replace(r, (_, M, m, p, pr) => {\n debug('tilde', comp, _, M, m, p, pr)\n let ret\n\n if (isX(M)) {\n ret = ''\n } else if (isX(m)) {\n ret = `>=${M}.0.0 <${+M + 1}.0.0-0`\n } else if (isX(p)) {\n // ~1.2 == >=1.2.0 <1.3.0-0\n ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`\n } else if (pr) {\n debug('replaceTilde pr', pr)\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${+m + 1}.0-0`\n } else {\n // ~1.2.3 == >=1.2.3 <1.3.0-0\n ret = `>=${M}.${m}.${p\n } <${M}.${+m + 1}.0-0`\n }\n\n debug('tilde return', ret)\n return ret\n })\n}\n\n// ^ --> * (any, kinda silly)\n// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0\n// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0\n// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0\n// ^1.2.3 --> >=1.2.3 <2.0.0-0\n// ^1.2.0 --> >=1.2.0 <2.0.0-0\n// ^0.0.1 --> >=0.0.1 <0.0.2-0\n// ^0.1.0 --> >=0.1.0 <0.2.0-0\nconst replaceCarets = (comp, options) => {\n return comp\n .trim()\n .split(/\\s+/)\n .map((c) => replaceCaret(c, options))\n .join(' ')\n}\n\nconst replaceCaret = (comp, options) => {\n debug('caret', comp, options)\n const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]\n const z = options.includePrerelease ? '-0' : ''\n return comp.replace(r, (_, M, m, p, pr) => {\n debug('caret', comp, _, M, m, p, pr)\n let ret\n\n if (isX(M)) {\n ret = ''\n } else if (isX(m)) {\n ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`\n } else if (isX(p)) {\n if (M === '0') {\n ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`\n } else {\n ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`\n }\n } else if (pr) {\n debug('replaceCaret pr', pr)\n if (M === '0') {\n if (m === '0') {\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${m}.${+p + 1}-0`\n } else {\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${+m + 1}.0-0`\n }\n } else {\n ret = `>=${M}.${m}.${p}-${pr\n } <${+M + 1}.0.0-0`\n }\n } else {\n debug('no pr')\n if (M === '0') {\n if (m === '0') {\n ret = `>=${M}.${m}.${p\n }${z} <${M}.${m}.${+p + 1}-0`\n } else {\n ret = `>=${M}.${m}.${p\n }${z} <${M}.${+m + 1}.0-0`\n }\n } else {\n ret = `>=${M}.${m}.${p\n } <${+M + 1}.0.0-0`\n }\n }\n\n debug('caret return', ret)\n return ret\n })\n}\n\nconst replaceXRanges = (comp, options) => {\n debug('replaceXRanges', comp, options)\n return comp\n .split(/\\s+/)\n .map((c) => replaceXRange(c, options))\n .join(' ')\n}\n\nconst replaceXRange = (comp, options) => {\n comp = comp.trim()\n const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]\n return comp.replace(r, (ret, gtlt, M, m, p, pr) => {\n debug('xRange', comp, ret, gtlt, M, m, p, pr)\n const xM = isX(M)\n const xm = xM || isX(m)\n const xp = xm || isX(p)\n const anyX = xp\n\n if (gtlt === '=' && anyX) {\n gtlt = ''\n }\n\n // if we're including prereleases in the match, then we need\n // to fix this to -0, the lowest possible prerelease value\n pr = options.includePrerelease ? '-0' : ''\n\n if (xM) {\n if (gtlt === '>' || gtlt === '<') {\n // nothing is allowed\n ret = '<0.0.0-0'\n } else {\n // nothing is forbidden\n ret = '*'\n }\n } else if (gtlt && anyX) {\n // we know patch is an x, because we have any x at all.\n // replace X with 0\n if (xm) {\n m = 0\n }\n p = 0\n\n if (gtlt === '>') {\n // >1 => >=2.0.0\n // >1.2 => >=1.3.0\n gtlt = '>='\n if (xm) {\n M = +M + 1\n m = 0\n p = 0\n } else {\n m = +m + 1\n p = 0\n }\n } else if (gtlt === '<=') {\n // <=0.7.x is actually <0.8.0, since any 0.7.x should\n // pass. Similarly, <=7.x is actually <8.0.0, etc.\n gtlt = '<'\n if (xm) {\n M = +M + 1\n } else {\n m = +m + 1\n }\n }\n\n if (gtlt === '<') {\n pr = '-0'\n }\n\n ret = `${gtlt + M}.${m}.${p}${pr}`\n } else if (xm) {\n ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`\n } else if (xp) {\n ret = `>=${M}.${m}.0${pr\n } <${M}.${+m + 1}.0-0`\n }\n\n debug('xRange return', ret)\n\n return ret\n })\n}\n\n// Because * is AND-ed with everything else in the comparator,\n// and '' means \"any version\", just remove the *s entirely.\nconst replaceStars = (comp, options) => {\n debug('replaceStars', comp, options)\n // Looseness is ignored here. star is always as loose as it gets!\n return comp\n .trim()\n .replace(re[t.STAR], '')\n}\n\nconst replaceGTE0 = (comp, options) => {\n debug('replaceGTE0', comp, options)\n return comp\n .trim()\n .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')\n}\n\n// This function is passed to string.replace(re[t.HYPHENRANGE])\n// M, m, patch, prerelease, build\n// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5\n// 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do\n// 1.2 - 3.4 => >=1.2.0 <3.5.0-0\n// TODO build?\nconst hyphenReplace = incPr => ($0,\n from, fM, fm, fp, fpr, fb,\n to, tM, tm, tp, tpr) => {\n if (isX(fM)) {\n from = ''\n } else if (isX(fm)) {\n from = `>=${fM}.0.0${incPr ? '-0' : ''}`\n } else if (isX(fp)) {\n from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`\n } else if (fpr) {\n from = `>=${from}`\n } else {\n from = `>=${from}${incPr ? '-0' : ''}`\n }\n\n if (isX(tM)) {\n to = ''\n } else if (isX(tm)) {\n to = `<${+tM + 1}.0.0-0`\n } else if (isX(tp)) {\n to = `<${tM}.${+tm + 1}.0-0`\n } else if (tpr) {\n to = `<=${tM}.${tm}.${tp}-${tpr}`\n } else if (incPr) {\n to = `<${tM}.${tm}.${+tp + 1}-0`\n } else {\n to = `<=${to}`\n }\n\n return `${from} ${to}`.trim()\n}\n\nconst testSet = (set, version, options) => {\n for (let i = 0; i < set.length; i++) {\n if (!set[i].test(version)) {\n return false\n }\n }\n\n if (version.prerelease.length && !options.includePrerelease) {\n // Find the set of versions that are allowed to have prereleases\n // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0\n // That should allow `1.2.3-pr.2` to pass.\n // However, `1.2.4-alpha.notready` should NOT be allowed,\n // even though it's within the range set by the comparators.\n for (let i = 0; i < set.length; i++) {\n debug(set[i].semver)\n if (set[i].semver === Comparator.ANY) {\n continue\n }\n\n if (set[i].semver.prerelease.length > 0) {\n const allowed = set[i].semver\n if (allowed.major === version.major &&\n allowed.minor === version.minor &&\n allowed.patch === version.patch) {\n return true\n }\n }\n }\n\n // Version has a -pre, but it's not one of the ones we like.\n return false\n }\n\n return true\n}\n","'use strict'\n\nconst ANY = Symbol('SemVer ANY')\n// hoisted class for cyclic dependency\nclass Comparator {\n static get ANY () {\n return ANY\n }\n\n constructor (comp, options) {\n options = parseOptions(options)\n\n if (comp instanceof Comparator) {\n if (comp.loose === !!options.loose) {\n return comp\n } else {\n comp = comp.value\n }\n }\n\n comp = comp.trim().split(/\\s+/).join(' ')\n debug('comparator', comp, options)\n this.options = options\n this.loose = !!options.loose\n this.parse(comp)\n\n if (this.semver === ANY) {\n this.value = ''\n } else {\n this.value = this.operator + this.semver.version\n }\n\n debug('comp', this)\n }\n\n parse (comp) {\n const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]\n const m = comp.match(r)\n\n if (!m) {\n throw new TypeError(`Invalid comparator: ${comp}`)\n }\n\n this.operator = m[1] !== undefined ? m[1] : ''\n if (this.operator === '=') {\n this.operator = ''\n }\n\n // if it literally is just '>' or '' then allow anything.\n if (!m[2]) {\n this.semver = ANY\n } else {\n this.semver = new SemVer(m[2], this.options.loose)\n }\n }\n\n toString () {\n return this.value\n }\n\n test (version) {\n debug('Comparator.test', version, this.options.loose)\n\n if (this.semver === ANY || version === ANY) {\n return true\n }\n\n if (typeof version === 'string') {\n try {\n version = new SemVer(version, this.options)\n } catch (er) {\n return false\n }\n }\n\n return cmp(version, this.operator, this.semver, this.options)\n }\n\n intersects (comp, options) {\n if (!(comp instanceof Comparator)) {\n throw new TypeError('a Comparator is required')\n }\n\n if (this.operator === '') {\n if (this.value === '') {\n return true\n }\n return new Range(comp.value, options).test(this.value)\n } else if (comp.operator === '') {\n if (comp.value === '') {\n return true\n }\n return new Range(this.value, options).test(comp.semver)\n }\n\n options = parseOptions(options)\n\n // Special cases where nothing can possibly be lower\n if (options.includePrerelease &&\n (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) {\n return false\n }\n if (!options.includePrerelease &&\n (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) {\n return false\n }\n\n // Same direction increasing (> or >=)\n if (this.operator.startsWith('>') && comp.operator.startsWith('>')) {\n return true\n }\n // Same direction decreasing (< or <=)\n if (this.operator.startsWith('<') && comp.operator.startsWith('<')) {\n return true\n }\n // same SemVer and both sides are inclusive (<= or >=)\n if (\n (this.semver.version === comp.semver.version) &&\n this.operator.includes('=') && comp.operator.includes('=')) {\n return true\n }\n // opposite directions less than\n if (cmp(this.semver, '<', comp.semver, options) &&\n this.operator.startsWith('>') && comp.operator.startsWith('<')) {\n return true\n }\n // opposite directions greater than\n if (cmp(this.semver, '>', comp.semver, options) &&\n this.operator.startsWith('<') && comp.operator.startsWith('>')) {\n return true\n }\n return false\n }\n}\n\nmodule.exports = Comparator\n\nconst parseOptions = require('../internal/parse-options')\nconst { safeRe: re, t } = require('../internal/re')\nconst cmp = require('../functions/cmp')\nconst debug = require('../internal/debug')\nconst SemVer = require('./semver')\nconst Range = require('./range')\n","'use strict'\n\nconst Range = require('../classes/range')\nconst satisfies = (version, range, options) => {\n try {\n range = new Range(range, options)\n } catch (er) {\n return false\n }\n return range.test(version)\n}\nmodule.exports = satisfies\n","'use strict'\n\nconst Range = require('../classes/range')\n\n// Mostly just for testing and legacy API reasons\nconst toComparators = (range, options) =>\n new Range(range, options).set\n .map(comp => comp.map(c => c.value).join(' ').trim().split(' '))\n\nmodule.exports = toComparators\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\n\nconst maxSatisfying = (versions, range, options) => {\n let max = null\n let maxSV = null\n let rangeObj = null\n try {\n rangeObj = new Range(range, options)\n } catch (er) {\n return null\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n // satisfies(v, range, options)\n if (!max || maxSV.compare(v) === -1) {\n // compare(max, v, true)\n max = v\n maxSV = new SemVer(max, options)\n }\n }\n })\n return max\n}\nmodule.exports = maxSatisfying\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\nconst minSatisfying = (versions, range, options) => {\n let min = null\n let minSV = null\n let rangeObj = null\n try {\n rangeObj = new Range(range, options)\n } catch (er) {\n return null\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n // satisfies(v, range, options)\n if (!min || minSV.compare(v) === 1) {\n // compare(min, v, true)\n min = v\n minSV = new SemVer(min, options)\n }\n }\n })\n return min\n}\nmodule.exports = minSatisfying\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\nconst gt = require('../functions/gt')\n\nconst minVersion = (range, loose) => {\n range = new Range(range, loose)\n\n let minver = new SemVer('0.0.0')\n if (range.test(minver)) {\n return minver\n }\n\n minver = new SemVer('0.0.0-0')\n if (range.test(minver)) {\n return minver\n }\n\n minver = null\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i]\n\n let setMin = null\n comparators.forEach((comparator) => {\n // Clone to avoid manipulating the comparator's semver object.\n const compver = new SemVer(comparator.semver.version)\n switch (comparator.operator) {\n case '>':\n if (compver.prerelease.length === 0) {\n compver.patch++\n } else {\n compver.prerelease.push(0)\n }\n compver.raw = compver.format()\n /* fallthrough */\n case '':\n case '>=':\n if (!setMin || gt(compver, setMin)) {\n setMin = compver\n }\n break\n case '<':\n case '<=':\n /* Ignore maximum versions */\n break\n /* istanbul ignore next */\n default:\n throw new Error(`Unexpected operation: ${comparator.operator}`)\n }\n })\n if (setMin && (!minver || gt(minver, setMin))) {\n minver = setMin\n }\n }\n\n if (minver && range.test(minver)) {\n return minver\n }\n\n return null\n}\nmodule.exports = minVersion\n","'use strict'\n\nconst Range = require('../classes/range')\nconst validRange = (range, options) => {\n try {\n // Return '*' instead of '' so that truthiness works.\n // This will throw if it's invalid anyway\n return new Range(range, options).range || '*'\n } catch (er) {\n return null\n }\n}\nmodule.exports = validRange\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Comparator = require('../classes/comparator')\nconst { ANY } = Comparator\nconst Range = require('../classes/range')\nconst satisfies = require('../functions/satisfies')\nconst gt = require('../functions/gt')\nconst lt = require('../functions/lt')\nconst lte = require('../functions/lte')\nconst gte = require('../functions/gte')\n\nconst outside = (version, range, hilo, options) => {\n version = new SemVer(version, options)\n range = new Range(range, options)\n\n let gtfn, ltefn, ltfn, comp, ecomp\n switch (hilo) {\n case '>':\n gtfn = gt\n ltefn = lte\n ltfn = lt\n comp = '>'\n ecomp = '>='\n break\n case '<':\n gtfn = lt\n ltefn = gte\n ltfn = gt\n comp = '<'\n ecomp = '<='\n break\n default:\n throw new TypeError('Must provide a hilo val of \"<\" or \">\"')\n }\n\n // If it satisfies the range it is not outside\n if (satisfies(version, range, options)) {\n return false\n }\n\n // From now on, variable terms are as if we're in \"gtr\" mode.\n // but note that everything is flipped for the \"ltr\" function.\n\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i]\n\n let high = null\n let low = null\n\n comparators.forEach((comparator) => {\n if (comparator.semver === ANY) {\n comparator = new Comparator('>=0.0.0')\n }\n high = high || comparator\n low = low || comparator\n if (gtfn(comparator.semver, high.semver, options)) {\n high = comparator\n } else if (ltfn(comparator.semver, low.semver, options)) {\n low = comparator\n }\n })\n\n // If the edge version comparator has a operator then our version\n // isn't outside it\n if (high.operator === comp || high.operator === ecomp) {\n return false\n }\n\n // If the lowest version comparator has an operator and our version\n // is less than it then it isn't higher than the range\n if ((!low.operator || low.operator === comp) &&\n ltefn(version, low.semver)) {\n return false\n } else if (low.operator === ecomp && ltfn(version, low.semver)) {\n return false\n }\n }\n return true\n}\n\nmodule.exports = outside\n","'use strict'\n\n// Determine if version is greater than all the versions possible in the range.\nconst outside = require('./outside')\nconst gtr = (version, range, options) => outside(version, range, '>', options)\nmodule.exports = gtr\n","'use strict'\n\nconst outside = require('./outside')\n// Determine if version is less than all the versions possible in the range\nconst ltr = (version, range, options) => outside(version, range, '<', options)\nmodule.exports = ltr\n","'use strict'\n\nconst Range = require('../classes/range')\nconst intersects = (r1, r2, options) => {\n r1 = new Range(r1, options)\n r2 = new Range(r2, options)\n return r1.intersects(r2, options)\n}\nmodule.exports = intersects\n","'use strict'\n\n// given a set of versions and a range, create a \"simplified\" range\n// that includes the same versions that the original range does\n// If the original range is shorter than the simplified one, return that.\nconst satisfies = require('../functions/satisfies.js')\nconst compare = require('../functions/compare.js')\nmodule.exports = (versions, range, options) => {\n const set = []\n let first = null\n let prev = null\n const v = versions.sort((a, b) => compare(a, b, options))\n for (const version of v) {\n const included = satisfies(version, range, options)\n if (included) {\n prev = version\n if (!first) {\n first = version\n }\n } else {\n if (prev) {\n set.push([first, prev])\n }\n prev = null\n first = null\n }\n }\n if (first) {\n set.push([first, null])\n }\n\n const ranges = []\n for (const [min, max] of set) {\n if (min === max) {\n ranges.push(min)\n } else if (!max && min === v[0]) {\n ranges.push('*')\n } else if (!max) {\n ranges.push(`>=${min}`)\n } else if (min === v[0]) {\n ranges.push(`<=${max}`)\n } else {\n ranges.push(`${min} - ${max}`)\n }\n }\n const simplified = ranges.join(' || ')\n const original = typeof range.raw === 'string' ? range.raw : String(range)\n return simplified.length < original.length ? simplified : range\n}\n","'use strict'\n\nconst Range = require('../classes/range.js')\nconst Comparator = require('../classes/comparator.js')\nconst { ANY } = Comparator\nconst satisfies = require('../functions/satisfies.js')\nconst compare = require('../functions/compare.js')\n\n// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:\n// - Every simple range `r1, r2, ...` is a null set, OR\n// - Every simple range `r1, r2, ...` which is not a null set is a subset of\n// some `R1, R2, ...`\n//\n// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:\n// - If c is only the ANY comparator\n// - If C is only the ANY comparator, return true\n// - Else if in prerelease mode, return false\n// - else replace c with `[>=0.0.0]`\n// - If C is only the ANY comparator\n// - if in prerelease mode, return true\n// - else replace C with `[>=0.0.0]`\n// - Let EQ be the set of = comparators in c\n// - If EQ is more than one, return true (null set)\n// - Let GT be the highest > or >= comparator in c\n// - Let LT be the lowest < or <= comparator in c\n// - If GT and LT, and GT.semver > LT.semver, return true (null set)\n// - If any C is a = range, and GT or LT are set, return false\n// - If EQ\n// - If GT, and EQ does not satisfy GT, return true (null set)\n// - If LT, and EQ does not satisfy LT, return true (null set)\n// - If EQ satisfies every C, return true\n// - Else return false\n// - If GT\n// - If GT.semver is lower than any > or >= comp in C, return false\n// - If GT is >=, and GT.semver does not satisfy every C, return false\n// - If GT.semver has a prerelease, and not in prerelease mode\n// - If no C has a prerelease and the GT.semver tuple, return false\n// - If LT\n// - If LT.semver is greater than any < or <= comp in C, return false\n// - If LT is <=, and LT.semver does not satisfy every C, return false\n// - If GT.semver has a prerelease, and not in prerelease mode\n// - If no C has a prerelease and the LT.semver tuple, return false\n// - Else return true\n\nconst subset = (sub, dom, options = {}) => {\n if (sub === dom) {\n return true\n }\n\n sub = new Range(sub, options)\n dom = new Range(dom, options)\n let sawNonNull = false\n\n OUTER: for (const simpleSub of sub.set) {\n for (const simpleDom of dom.set) {\n const isSub = simpleSubset(simpleSub, simpleDom, options)\n sawNonNull = sawNonNull || isSub !== null\n if (isSub) {\n continue OUTER\n }\n }\n // the null set is a subset of everything, but null simple ranges in\n // a complex range should be ignored. so if we saw a non-null range,\n // then we know this isn't a subset, but if EVERY simple range was null,\n // then it is a subset.\n if (sawNonNull) {\n return false\n }\n }\n return true\n}\n\nconst minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]\nconst minimumVersion = [new Comparator('>=0.0.0')]\n\nconst simpleSubset = (sub, dom, options) => {\n if (sub === dom) {\n return true\n }\n\n if (sub.length === 1 && sub[0].semver === ANY) {\n if (dom.length === 1 && dom[0].semver === ANY) {\n return true\n } else if (options.includePrerelease) {\n sub = minimumVersionWithPreRelease\n } else {\n sub = minimumVersion\n }\n }\n\n if (dom.length === 1 && dom[0].semver === ANY) {\n if (options.includePrerelease) {\n return true\n } else {\n dom = minimumVersion\n }\n }\n\n const eqSet = new Set()\n let gt, lt\n for (const c of sub) {\n if (c.operator === '>' || c.operator === '>=') {\n gt = higherGT(gt, c, options)\n } else if (c.operator === '<' || c.operator === '<=') {\n lt = lowerLT(lt, c, options)\n } else {\n eqSet.add(c.semver)\n }\n }\n\n if (eqSet.size > 1) {\n return null\n }\n\n let gtltComp\n if (gt && lt) {\n gtltComp = compare(gt.semver, lt.semver, options)\n if (gtltComp > 0) {\n return null\n } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) {\n return null\n }\n }\n\n // will iterate one or zero times\n for (const eq of eqSet) {\n if (gt && !satisfies(eq, String(gt), options)) {\n return null\n }\n\n if (lt && !satisfies(eq, String(lt), options)) {\n return null\n }\n\n for (const c of dom) {\n if (!satisfies(eq, String(c), options)) {\n return false\n }\n }\n\n return true\n }\n\n let higher, lower\n let hasDomLT, hasDomGT\n // if the subset has a prerelease, we need a comparator in the superset\n // with the same tuple and a prerelease, or it's not a subset\n let needDomLTPre = lt &&\n !options.includePrerelease &&\n lt.semver.prerelease.length ? lt.semver : false\n let needDomGTPre = gt &&\n !options.includePrerelease &&\n gt.semver.prerelease.length ? gt.semver : false\n // exception: <1.2.3-0 is the same as <1.2.3\n if (needDomLTPre && needDomLTPre.prerelease.length === 1 &&\n lt.operator === '<' && needDomLTPre.prerelease[0] === 0) {\n needDomLTPre = false\n }\n\n for (const c of dom) {\n hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='\n hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='\n if (gt) {\n if (needDomGTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length &&\n c.semver.major === needDomGTPre.major &&\n c.semver.minor === needDomGTPre.minor &&\n c.semver.patch === needDomGTPre.patch) {\n needDomGTPre = false\n }\n }\n if (c.operator === '>' || c.operator === '>=') {\n higher = higherGT(gt, c, options)\n if (higher === c && higher !== gt) {\n return false\n }\n } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {\n return false\n }\n }\n if (lt) {\n if (needDomLTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length &&\n c.semver.major === needDomLTPre.major &&\n c.semver.minor === needDomLTPre.minor &&\n c.semver.patch === needDomLTPre.patch) {\n needDomLTPre = false\n }\n }\n if (c.operator === '<' || c.operator === '<=') {\n lower = lowerLT(lt, c, options)\n if (lower === c && lower !== lt) {\n return false\n }\n } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {\n return false\n }\n }\n if (!c.operator && (lt || gt) && gtltComp !== 0) {\n return false\n }\n }\n\n // if there was a < or >, and nothing in the dom, then must be false\n // UNLESS it was limited by another range in the other direction.\n // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0\n if (gt && hasDomLT && !lt && gtltComp !== 0) {\n return false\n }\n\n if (lt && hasDomGT && !gt && gtltComp !== 0) {\n return false\n }\n\n // we needed a prerelease range in a specific tuple, but didn't get one\n // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,\n // because it includes prereleases in the 1.2.3 tuple\n if (needDomGTPre || needDomLTPre) {\n return false\n }\n\n return true\n}\n\n// >=1.2.3 is lower than >1.2.3\nconst higherGT = (a, b, options) => {\n if (!a) {\n return b\n }\n const comp = compare(a.semver, b.semver, options)\n return comp > 0 ? a\n : comp < 0 ? b\n : b.operator === '>' && a.operator === '>=' ? b\n : a\n}\n\n// <=1.2.3 is higher than <1.2.3\nconst lowerLT = (a, b, options) => {\n if (!a) {\n return b\n }\n const comp = compare(a.semver, b.semver, options)\n return comp < 0 ? a\n : comp > 0 ? b\n : b.operator === '<' && a.operator === '<=' ? b\n : a\n}\n\nmodule.exports = subset\n","'use strict'\n\n// just pre-load all the stuff that index.js lazily exports\nconst internalRe = require('./internal/re')\nconst constants = require('./internal/constants')\nconst SemVer = require('./classes/semver')\nconst identifiers = require('./internal/identifiers')\nconst parse = require('./functions/parse')\nconst valid = require('./functions/valid')\nconst clean = require('./functions/clean')\nconst inc = require('./functions/inc')\nconst diff = require('./functions/diff')\nconst major = require('./functions/major')\nconst minor = require('./functions/minor')\nconst patch = require('./functions/patch')\nconst prerelease = require('./functions/prerelease')\nconst compare = require('./functions/compare')\nconst rcompare = require('./functions/rcompare')\nconst compareLoose = require('./functions/compare-loose')\nconst compareBuild = require('./functions/compare-build')\nconst sort = require('./functions/sort')\nconst rsort = require('./functions/rsort')\nconst gt = require('./functions/gt')\nconst lt = require('./functions/lt')\nconst eq = require('./functions/eq')\nconst neq = require('./functions/neq')\nconst gte = require('./functions/gte')\nconst lte = require('./functions/lte')\nconst cmp = require('./functions/cmp')\nconst coerce = require('./functions/coerce')\nconst Comparator = require('./classes/comparator')\nconst Range = require('./classes/range')\nconst satisfies = require('./functions/satisfies')\nconst toComparators = require('./ranges/to-comparators')\nconst maxSatisfying = require('./ranges/max-satisfying')\nconst minSatisfying = require('./ranges/min-satisfying')\nconst minVersion = require('./ranges/min-version')\nconst validRange = require('./ranges/valid')\nconst outside = require('./ranges/outside')\nconst gtr = require('./ranges/gtr')\nconst ltr = require('./ranges/ltr')\nconst intersects = require('./ranges/intersects')\nconst simplifyRange = require('./ranges/simplify')\nconst subset = require('./ranges/subset')\nmodule.exports = {\n parse,\n valid,\n clean,\n inc,\n diff,\n major,\n minor,\n patch,\n prerelease,\n compare,\n rcompare,\n compareLoose,\n compareBuild,\n sort,\n rsort,\n gt,\n lt,\n eq,\n neq,\n gte,\n lte,\n cmp,\n coerce,\n Comparator,\n Range,\n satisfies,\n toComparators,\n maxSatisfying,\n minSatisfying,\n minVersion,\n validRange,\n outside,\n gtr,\n ltr,\n intersects,\n simplifyRange,\n subset,\n SemVer,\n re: internalRe.re,\n src: internalRe.src,\n tokens: internalRe.t,\n SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,\n RELEASE_TYPES: constants.RELEASE_TYPES,\n compareIdentifiers: identifiers.compareIdentifiers,\n rcompareIdentifiers: identifiers.rcompareIdentifiers,\n}\n","/**\n * Web 服务器\n *\n * 负责:\n * - 启动和管理 HTTP/HTTPS 服务器\n * - 注册和管理路由\n * - 集成中间件(CORS、日志、错误处理等)\n * - 管理 ESP32 设备 WebSocket 连接\n * - 集成 MCP 服务和端点管理器\n * - 生命周期管理(启动、停止、清理)\n *\n * @example\n * ```typescript\n * import { WebServer } from './WebServer';\n *\n * const server = new WebServer();\n * await server.start();\n * ```\n */\n\nimport { createServer } from \"node:http\";\nimport type { IncomingMessage, Server, ServerResponse } from \"node:http\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n ConfigApiHandler,\n CozeHandler,\n ESP32Handler,\n MCPHandler,\n MCPRouteHandler,\n MCPToolHandler,\n MCPToolLogHandler,\n ServiceApiHandler,\n StaticFileHandler,\n StatusApiHandler,\n TTSApiHandler,\n UpdateApiHandler,\n VersionApiHandler,\n} from \"@/handlers/index.js\";\nimport { MCPServiceManager } from \"@/lib/mcp\";\nimport type { EnhancedToolInfo } from \"@/lib/mcp/types.js\";\nimport { ensureToolJSONSchema } from \"@/lib/mcp/types.js\";\nimport {\n corsMiddleware,\n endpointManagerMiddleware,\n endpointsMiddleware,\n errorHandlerMiddleware,\n loggerMiddleware,\n mcpServiceManagerMiddleware,\n notFoundHandlerMiddleware,\n responseEnhancerMiddleware,\n} from \"@/middlewares/index.js\";\nimport type { EventBus, EventBusEvents } from \"@/services/index.js\";\nimport {\n StatusService,\n destroyEventBus,\n getEventBus,\n} from \"@/services/index.js\";\nimport type { AppContext } from \"@/types/index.js\";\nimport { createApp } from \"@/types/index.js\";\nimport type { ServerType } from \"@hono/node-server\";\nimport { serve } from \"@hono/node-server\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { normalizeServiceConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { MCPServerConfig } from \"@xiaozhi-client/config\";\nimport { EndpointManager } from \"@xiaozhi-client/endpoint\";\nimport type { SimpleConnectionStatus } from \"@xiaozhi-client/endpoint\";\nimport {\n ESP32DeviceManager,\n type IESP32ConfigProvider,\n} from \"@xiaozhi-client/esp32\";\nimport type { Hono } from \"hono\";\nimport { WebSocketServer } from \"ws\";\nimport type WebSocket from \"ws\";\n\nimport { HTTP_SERVER_CONFIG } from \"@/constants/index.js\";\nimport { MCPServiceManagerNotInitializedError } from \"@/errors/mcp-errors.middleware.js\";\n// 路由系统导入\nimport {\n type HandlerDependencies,\n RouteManager,\n // 导入所有路由配置\n configRoutes,\n cozeRoutes,\n endpointRoutes,\n esp32Routes,\n mcpRoutes,\n mcpserverRoutes,\n miscRoutes,\n servicesRoutes,\n staticRoutes,\n statusRoutes,\n toolLogsRoutes,\n toolsRoutes,\n ttsRoutes,\n updateRoutes,\n versionRoutes,\n} from \"./routes/index.js\";\n\n// 统一成功响应格式\ninterface ApiSuccessResponse<T = unknown> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n// 小智连接状态响应格式\ninterface XiaozhiConnectionStatusResponse {\n type: \"multi-endpoint\" | \"single-endpoint\" | \"none\";\n connected?: boolean;\n endpoint?: string;\n manager?: {\n connectedConnections: number;\n totalConnections: number;\n healthCheckStats: Record<string, unknown>;\n };\n connections?: SimpleConnectionStatus[];\n}\n\n/**\n * WebServer - 主控制器,协调各个服务和处理器\n */\nexport class WebServer {\n private app: Hono<AppContext>;\n private httpServer: ServerType | null = null;\n private wss: WebSocketServer | null = null;\n private logger: Logger;\n private port: number;\n\n // 事件总线\n private eventBus: EventBus;\n\n // 服务层\n private statusService: StatusService;\n private esp32Manager: ESP32DeviceManager;\n\n // HTTP API 处理器\n private configApiHandler: ConfigApiHandler;\n private statusApiHandler: StatusApiHandler;\n private serviceApiHandler: ServiceApiHandler;\n private mcpToolHandler: MCPToolHandler;\n private mcpToolLogHandler: MCPToolLogHandler;\n private versionApiHandler: VersionApiHandler;\n private staticFileHandler: StaticFileHandler;\n private mcpRouteHandler: MCPRouteHandler;\n private mcpHandler?: MCPHandler;\n private updateApiHandler: UpdateApiHandler;\n private cozeHandler: CozeHandler;\n private ttsApiHandler: TTSApiHandler;\n private esp32Handler: ESP32Handler;\n\n // 路由系统\n private routeManager?: RouteManager;\n\n // 连接管理相关属性\n private endpointManager: EndpointManager | null = null;\n private mcpServiceManager: MCPServiceManager | null = null; // WebServer 直接管理的实例\n\n // 事件监听器清理函数数组\n private eventListenerUnsubscribers: Array<() => void> = [];\n\n constructor(port?: number) {\n // 端口配置\n try {\n this.port =\n port ?? configManager.getWebUIPort() ?? HTTP_SERVER_CONFIG.DEFAULT_PORT;\n } catch (error) {\n // 配置读取失败时使用默认端口\n this.port = port ?? HTTP_SERVER_CONFIG.DEFAULT_PORT;\n }\n this.logger = logger;\n\n // 初始化事件总线\n this.eventBus = getEventBus();\n\n // 初始化服务层\n this.statusService = new StatusService();\n\n // 创建基于 configManager 的配置提供者\n const esp32ConfigProvider: IESP32ConfigProvider = {\n getASRConfig: () => configManager.getASRConfig(),\n getTTSConfig: () => configManager.getTTSConfig(),\n getLLMConfig: () => configManager.getLLMConfig(),\n isLLMConfigValid: () => configManager.isLLMConfigValid(),\n };\n\n // 创建 ESP32 设备管理器(使用新包)\n this.esp32Manager = new ESP32DeviceManager({\n logger,\n configProvider: esp32ConfigProvider,\n });\n\n // 初始化 HTTP API 处理器\n this.configApiHandler = new ConfigApiHandler();\n this.statusApiHandler = new StatusApiHandler(this.statusService);\n this.serviceApiHandler = new ServiceApiHandler(this.statusService);\n this.mcpToolHandler = new MCPToolHandler();\n this.mcpToolLogHandler = new MCPToolLogHandler();\n this.versionApiHandler = new VersionApiHandler();\n this.staticFileHandler = new StaticFileHandler();\n this.mcpRouteHandler = new MCPRouteHandler();\n this.updateApiHandler = new UpdateApiHandler();\n this.cozeHandler = new CozeHandler();\n this.ttsApiHandler = new TTSApiHandler();\n this.esp32Handler = new ESP32Handler(this.esp32Manager);\n\n // MCPServerApiHandler 将在 start() 方法中初始化,因为它需要 mcpServiceManager\n\n // 初始化 Hono 应用\n this.app = createApp();\n this.setupMiddleware();\n\n // 在所有路由设置完成后,设置 404 处理\n this.app.notFound(notFoundHandlerMiddleware);\n\n // 监听 MCP 服务添加事件\n this.setupMCPServerAddedListener();\n }\n\n /**\n * 初始化所有连接(配置驱动)\n */\n private async initializeConnections(): Promise<void> {\n try {\n this.logger.debug(\"开始初始化连接...\");\n\n // 2. 初始化 MCP 服务管理器(WebServer 直接管理)\n if (!this.mcpServiceManager) {\n this.logger.debug(\"创建新的 MCPServiceManager 实例\");\n this.mcpServiceManager = new MCPServiceManager();\n // 启动服务管理器,确保它可以正常工作\n await this.mcpServiceManager.start();\n } else {\n this.logger.debug(\"使用现有的 MCPServiceManager 实例,跳过创建\");\n }\n\n // 1. 读取配置\n const config = await this.loadConfiguration();\n\n // 2.1. 初始化 MCP 服务器 API 处理器\n this.mcpHandler = new MCPHandler(this.mcpServiceManager, configManager);\n\n // 3. 从配置加载 MCP 服务\n await this.loadMCPServicesFromConfig(config.mcpServers);\n\n // 4. 获取工具列表\n const rawTools: EnhancedToolInfo[] = this.mcpServiceManager.getAllTools();\n this.logger.debug(`已加载 ${rawTools.length} 个工具`);\n\n // 5. 转换工具格式以符合 MCP SDK 要求\n const tools: Tool[] = rawTools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: ensureToolJSONSchema(tool.inputSchema),\n }));\n\n // 6. 初始化小智接入点连接\n await this.initializeXiaozhiConnection(config.mcpEndpoint);\n\n this.logger.debug(\"所有连接初始化完成\");\n } catch (error) {\n this.logger.error(\"连接初始化失败:\", error);\n // 降级模式:即使配置加载失败,也确保 MCPServiceManager 可用\n if (!this.mcpServiceManager) {\n this.logger.warn(\n \"配置加载失败,正在进入降级模式。在降级模式下:\\n\" +\n \"1. 将创建一个空配置的 MCPServiceManager 实例\\n\" +\n \"2. 不会加载任何 MCP 服务器或端点\\n\" +\n \"3. WebServer 仍然可以启动并提供基础 API 服务\\n\" +\n \"4. 用户需要通过 API 重新配置端点或服务器\\n\" +\n \"5. 建议尽快运行 'xiaozhi init' 初始化配置文件\"\n );\n this.mcpServiceManager = new MCPServiceManager();\n await this.mcpServiceManager.start();\n this.logger.info(\"降级模式已激活,MCPServiceManager 使用空配置启动\");\n }\n }\n }\n\n /**\n * 加载配置文件\n */\n private async loadConfiguration(): Promise<{\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n webUIPort: number;\n }> {\n if (!configManager.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\");\n }\n\n // 在加载配置前,先清理无效的服务器工具配置\n // 确保 mcpServerConfig 与 mcpServers 保持同步\n configManager.cleanupInvalidServerToolsConfig();\n\n const config = configManager.getConfig();\n\n return {\n mcpEndpoint: config.mcpEndpoint,\n mcpServers: config.mcpServers,\n webUIPort: config.webUI?.port ?? HTTP_SERVER_CONFIG.DEFAULT_PORT,\n };\n }\n\n /**\n * 从配置加载 MCP 服务\n */\n private async loadMCPServicesFromConfig(\n mcpServers: Record<string, MCPServerConfig>\n ): Promise<void> {\n if (!this.mcpServiceManager) {\n throw new Error(\"MCPServiceManager 未初始化\");\n }\n\n for (const [name, config] of Object.entries(mcpServers)) {\n this.logger.debug(`添加 MCP 服务配置: ${name}`);\n // 使用配置适配器转换配置格式\n const serviceConfig = normalizeServiceConfig(config);\n this.mcpServiceManager.addServiceConfig(name, serviceConfig);\n }\n\n await this.mcpServiceManager.startAllServices();\n }\n\n /**\n * 初始化小智接入点连接(使用新 API)\n */\n private async initializeXiaozhiConnection(\n mcpEndpoint: string | string[]\n ): Promise<void> {\n // 处理多端点配置\n const endpoints = Array.isArray(mcpEndpoint) ? mcpEndpoint : [mcpEndpoint];\n const validEndpoints = endpoints.filter(\n (ep) => ep && !ep.includes(\"<请填写\")\n );\n\n // 1. 初始化连接管理器(无论是否有有效端点)\n this.logger.debug(\n `初始化小智接入点连接管理器,端点数量: ${validEndpoints.length}`\n );\n\n try {\n // 创建连接管理器实例(总是创建)\n if (!this.endpointManager) {\n this.endpointManager = new EndpointManager({\n defaultReconnectDelay: 2000,\n });\n // ✅ 传入 mcpServiceManager 实例\n this.endpointManager.setMcpManager(this.mcpServiceManager!);\n this.logger.debug(\"✅ 新建连接管理器实例\");\n }\n\n this.logger.debug(\"✅ 连接管理器设置完成\");\n\n // 2. 只有在有有效端点时才创建并添加端点\n if (validEndpoints.length > 0) {\n this.logger.debug(\"有效端点列表:\", validEndpoints);\n\n // 直接使用 URL 字符串添加端点(新 API)\n for (const endpointUrl of validEndpoints) {\n this.endpointManager.addEndpoint(endpointUrl);\n this.logger.debug(`✅ 已添加端点: ${endpointUrl}`);\n }\n\n // 连接所有端点\n await this.endpointManager.connect();\n\n // 设置端点添加事件监听器\n this.endpointManager.on(\n \"endpointAdded\",\n (event: { endpoint: string }) => {\n this.logger.debug(`端点已添加: ${event.endpoint}`);\n }\n );\n\n // 设置端点移除事件监听器\n this.endpointManager.on(\n \"endpointRemoved\",\n (event: { endpoint: string }) => {\n this.logger.debug(`端点已移除: ${event.endpoint}`);\n }\n );\n\n this.logger.debug(\n `小智接入点连接管理器初始化完成,管理 ${validEndpoints.length} 个端点`\n );\n } else {\n this.logger.debug(\"小智接入点连接管理器初始化完成(无端点)\");\n }\n } catch (error) {\n this.logger.error(\"小智接入点连接管理器初始化失败:\", error);\n // 抛出错误,让调用者知道初始化失败\n throw error;\n }\n }\n\n /**\n * 设置连接管理器实例(主要用于测试依赖注入)\n */\n public setXiaozhiConnectionManager(manager: EndpointManager): void {\n this.endpointManager = manager;\n }\n\n /**\n * 获取小智连接管理器实例\n * 提供给中间件使用\n * WebServer 启动后始终返回有效的连接管理器实例\n * @throws {Error} 如果连接管理器未初始化\n */\n public getEndpointManager(): EndpointManager {\n if (!this.endpointManager) {\n throw new Error(\n \"小智连接管理器未初始化,请确保 WebServer 已调用 start() 方法完成初始化\"\n );\n }\n return this.endpointManager;\n }\n\n /**\n * 设置 MCP 服务管理器实例(主要用于测试依赖注入)\n * 警告:如果要替换现有实例,调用者需要负责清理原有实例的资源\n */\n public setMCPServiceManager(manager: MCPServiceManager): void {\n // 如果已有实例且它正在运行,先清理它\n if (this.mcpServiceManager && this.mcpServiceManager !== manager) {\n this.logger.warn(\n \"替换现有的 MCPServiceManager 实例,注意清理原有实例的资源\"\n );\n // 注意:这里不直接调用 stopAllServices,因为调用者可能还在使用它\n // 调用者应该负责清理原有实例\n }\n\n this.mcpServiceManager = manager;\n this.logger.debug(\"MCPServiceManager 实例已更新\");\n }\n\n /**\n * 获取 MCP 服务管理器实例\n * 提供给中间件使用\n * WebServer 启动后始终返回有效的服务管理器实例\n * @throws {MCPServiceManagerNotInitializedError} 如果服务管理器未初始化\n */\n public getMCPServiceManager(): MCPServiceManager {\n if (!this.mcpServiceManager) {\n throw new MCPServiceManagerNotInitializedError(\n \"MCPServiceManager 未初始化,请确保 WebServer 已调用 start() 方法完成初始化\"\n );\n }\n return this.mcpServiceManager;\n }\n\n /**\n * 获取小智连接状态信息\n */\n getEndpointConnectionStatus(): XiaozhiConnectionStatusResponse {\n if (this.endpointManager) {\n const connectionStatuses = this.endpointManager.getConnectionStatus();\n return {\n type: \"multi-endpoint\",\n manager: {\n connectedConnections: connectionStatuses.filter(\n (status: SimpleConnectionStatus) => status.connected\n ).length,\n totalConnections: connectionStatuses.length,\n healthCheckStats: {}, // 简化后不再提供复杂的健康检查统计\n },\n connections: connectionStatuses,\n };\n }\n\n return {\n type: \"none\",\n connected: false,\n };\n }\n\n /**\n * 带重试的连接方法\n */\n private async connectWithRetry<T>(\n connectionFn: () => Promise<T>,\n context: string,\n maxAttempts = 5,\n initialDelay = 1000,\n maxDelay = 30000,\n backoffMultiplier = 2\n ): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n this.logger.info(`${context} - 尝试连接 (${attempt}/${maxAttempts})`);\n return await connectionFn();\n } catch (error) {\n lastError = error as Error;\n this.logger.warn(`${context} - 连接失败:`, error);\n\n if (attempt < maxAttempts) {\n const delay = Math.min(\n initialDelay * backoffMultiplier ** (attempt - 1),\n maxDelay\n );\n this.logger.info(`${context} - ${delay}ms 后重试...`);\n await this.sleep(delay);\n }\n }\n }\n\n throw new Error(\n `${context} - 连接失败,已达到最大重试次数: ${lastError?.message}`\n );\n }\n\n /**\n * 延迟工具方法\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n private setupMiddleware() {\n // Logger 中间件 - 必须在最前面\n this.app?.use(\"*\", loggerMiddleware);\n\n // 响应增强中间件 - 在 logger 之后,其他中间件之前\n // 这样所有路由都可以使用 c.success、c.fail、c.paginate 方法\n this.app?.use(\"*\", responseEnhancerMiddleware);\n\n // 注入 WebServer 实例到上下文\n // 使用类型断言避免循环引用问题\n this.app?.use(\"*\", async (c, next) => {\n c.set(\n \"webServer\",\n this as unknown as import(\"./types/hono.context.js\").IWebServer\n );\n await next();\n });\n\n // MCP Service Manager 中间件 - 必须在 WebServer 注入之后\n this.app?.use(\"*\", mcpServiceManagerMiddleware);\n\n // 小智连接管理器中间件\n this.app?.use(\"*\", endpointManagerMiddleware());\n\n // 小智接入点处理器中间件(在连接管理器中间件之后)\n this.app?.use(\"*\", endpointsMiddleware());\n\n // CORS 中间件\n this.app?.use(\"*\", corsMiddleware);\n\n // 错误处理中间件\n this.app?.onError(errorHandlerMiddleware);\n\n // 注入路由系统依赖\n // 注意:这个中间件必须在路由注册之前设置\n this.app?.use(\"*\", async (c, next) => {\n const dependencies = this.createHandlerDependencies();\n c.set(\"dependencies\", dependencies);\n await next();\n });\n }\n\n /**\n * 创建处理器依赖对象\n * 统一管理依赖对象的创建,避免代码重复\n */\n private createHandlerDependencies(): HandlerDependencies {\n return {\n configApiHandler: this.configApiHandler,\n statusApiHandler: this.statusApiHandler,\n serviceApiHandler: this.serviceApiHandler,\n mcpToolHandler: this.mcpToolHandler,\n mcpToolLogHandler: this.mcpToolLogHandler,\n versionApiHandler: this.versionApiHandler,\n staticFileHandler: this.staticFileHandler,\n mcpRouteHandler: this.mcpRouteHandler,\n mcpHandler: this.mcpHandler,\n updateApiHandler: this.updateApiHandler,\n cozeHandler: this.cozeHandler,\n ttsApiHandler: this.ttsApiHandler,\n esp32Handler: this.esp32Handler,\n // endpointHandler 通过中间件动态注入,不在此初始化\n };\n }\n\n /**\n * 设置路由系统\n */\n private setupRouteSystem(): void {\n // 初始化路由管理器,注入 Logger 实例\n this.routeManager = new RouteManager(this.logger);\n }\n\n /**\n * 从路由配置设置路由\n */\n private setupRoutesFromRegistry(): void {\n if (!this.routeManager || !this.app) {\n throw new Error(\"路由系统未初始化\");\n }\n\n try {\n // 注册所有路由配置 - static 放在最后,作为回退\n this.routeManager.registerRoutes({\n config: configRoutes,\n status: statusRoutes,\n tools: toolsRoutes,\n mcp: mcpRoutes,\n version: versionRoutes,\n services: servicesRoutes,\n update: updateRoutes,\n coze: cozeRoutes,\n \"tool-logs\": toolLogsRoutes,\n mcpserver: mcpserverRoutes,\n endpoint: endpointRoutes,\n misc: miscRoutes,\n tts: ttsRoutes,\n esp32: esp32Routes,\n static: staticRoutes, // 放在最后作为回退\n });\n\n // 应用路由到 Hono 应用\n this.routeManager.applyToApp(this.app);\n\n this.logger.info(\"路由系统注册完成\");\n } catch (error) {\n this.logger.error(\"路由系统注册失败:\", error);\n }\n }\n\n private setupWebSocket() {\n if (!this.wss) return;\n\n this.wss.on(\"connection\", (ws, req) => {\n // 检查是否是ESP32设备连接\n const url = req.url\n ? new URL(req.url, `http://${req.headers.host}`)\n : null;\n const isESP32Device = url?.pathname === \"/ws\";\n\n if (isESP32Device) {\n // 处理ESP32设备连接\n this.handleESP32DeviceConnection(ws, req);\n return;\n }\n\n // Web 客户端 WebSocket 已移除,关闭非 ESP32 连接\n this.logger.warn(\"Web 客户端 WebSocket 连接已被弃用,拒绝连接\");\n ws.close(\n 1000,\n \"Web client WebSocket is deprecated. Use HTTP API instead.\"\n );\n });\n }\n\n /**\n * 处理ESP32设备WebSocket连接\n */\n private handleESP32DeviceConnection(\n ws: WebSocket,\n req: IncomingMessage\n ): void {\n const deviceId = req.headers[\"device-id\"] as string;\n const clientId = req.headers[\"client-id\"] as string;\n const token = req.headers.authorization as string | undefined;\n\n // 提取Bearer token\n const authToken = token?.replace(\"Bearer \", \"\");\n\n this.logger.info(\n `[WS-ESP32] 收到ESP32设备连接请求: deviceId=${deviceId}, clientId=${clientId}, url=${req.url}`\n );\n\n if (!deviceId || !clientId) {\n this.logger.warn(\n `[WS-ESP32] 连接缺少必要的请求头: device-id=\"${deviceId}\", client-id=\"${clientId}\"`\n );\n ws.close(1008, \"Missing required headers\");\n return;\n }\n\n this.logger.info(\n `[WS-ESP32] ESP32设备WebSocket连接: deviceId=${deviceId}, clientId=${clientId}`\n );\n\n // 委托给 ESP32DeviceManager 处理\n this.esp32Manager\n .handleWebSocketConnection(ws, deviceId, clientId, authToken)\n .then(() => {\n this.logger.info(\n `[WS-ESP32] ESP32设备连接处理成功: deviceId=${deviceId}`\n );\n })\n .catch((error) => {\n this.logger.error(\n `[WS-ESP32] ESP32设备连接处理失败: deviceId=${deviceId}`,\n error\n );\n // 只有在 WebSocket 处于可关闭状态时才关闭\n // ws.OPEN = 1, ws.CONNECTING = 0\n if (ws.readyState === 1 || ws.readyState === 0) {\n ws.close(1011, \"Connection handling failed\");\n }\n });\n }\n\n /**\n * 设置 MCP 服务添加事件监听\n * 当添加新的 MCP 服务后,自动重连接入点以同步服务列表\n */\n private setupMCPServerAddedListener(): void {\n // 监听单个服务添加事件\n const singleServerListener = async (\n eventData: EventBusEvents[\"mcp:server:added\"]\n ) => {\n this.logger.info(\n `检测到 MCP 服务添加: ${eventData.serverName},工具数量: ${eventData.tools.length}`\n );\n\n if (!this.endpointManager) {\n this.logger.warn(\"EndpointManager 未初始化,跳过重连\");\n return;\n }\n\n try {\n // 获取当前连接的端点数量\n const connectionStatuses = this.endpointManager.getConnectionStatus();\n const connectedEndpointCount = connectionStatuses.filter(\n (status) => status.connected\n ).length;\n\n if (connectedEndpointCount === 0) {\n this.logger.debug(\"当前没有已连接的端点,跳过重连\");\n return;\n }\n\n this.logger.info(`开始重连 ${connectedEndpointCount} 个接入点...`);\n\n // 重连所有端点\n await this.endpointManager.reconnect();\n\n this.logger.info(\"接入点重连成功,新服务工具已同步\");\n\n // 发送重连完成事件\n this.eventBus.emitEvent(\"endpoint:reconnect:completed\", {\n trigger: \"mcp_server_added\",\n serverName: eventData.serverName,\n endpointCount: connectedEndpointCount,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(\"接入点重连失败:\", error);\n\n // 发送重连失败事件\n this.eventBus.emitEvent(\"endpoint:reconnect:failed\", {\n trigger: \"mcp_server_added\",\n serverName: eventData.serverName,\n error: error instanceof Error ? error.message : String(error),\n timestamp: Date.now(),\n });\n }\n };\n\n this.eventBus.onEvent(\"mcp:server:added\", singleServerListener);\n\n // 存储清理函数\n this.eventListenerUnsubscribers.push(() => {\n this.eventBus.offEvent(\"mcp:server:added\", singleServerListener);\n });\n\n // 监听批量服务添加事件\n const batchServerListener = async (\n eventData: EventBusEvents[\"mcp:server:batch_added\"]\n ) => {\n this.logger.info(\n `检测到批量 MCP 服务添加: ${eventData.addedCount} 个成功,${eventData.failedCount} 个失败`\n );\n\n if (!this.endpointManager || eventData.addedCount === 0) {\n return;\n }\n\n try {\n // 获取当前连接的端点数量\n const connectionStatuses = this.endpointManager.getConnectionStatus();\n const connectedEndpointCount = connectionStatuses.filter(\n (status) => status.connected\n ).length;\n\n if (connectedEndpointCount === 0) {\n this.logger.debug(\"当前没有已连接的端点,跳过重连\");\n return;\n }\n\n this.logger.info(`开始重连 ${connectedEndpointCount} 个接入点...`);\n\n // 重连所有端点\n await this.endpointManager.reconnect();\n\n this.logger.info(\"接入点重连成功,批量服务工具已同步\");\n\n // 发送重连完成事件\n this.eventBus.emitEvent(\"endpoint:reconnect:completed\", {\n trigger: \"mcp_server_batch_added\",\n serverName: undefined,\n endpointCount: connectedEndpointCount,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(\"接入点重连失败:\", error);\n\n // 发送重连失败事件\n this.eventBus.emitEvent(\"endpoint:reconnect:failed\", {\n trigger: \"mcp_server_batch_added\",\n serverName: undefined,\n error: error instanceof Error ? error.message : String(error),\n timestamp: Date.now(),\n });\n }\n };\n\n this.eventBus.onEvent(\"mcp:server:batch_added\", batchServerListener);\n\n // 存储清理函数\n this.eventListenerUnsubscribers.push(() => {\n this.eventBus.offEvent(\"mcp:server:batch_added\", batchServerListener);\n });\n }\n\n public async start(): Promise<void> {\n // 检查服务器是否已经启动\n if (this.httpServer) {\n this.logger.warn(\"Web server is already running\");\n return;\n }\n\n // 1. 初始化所有连接(配置驱动)\n // 这必须在启动服务器之前完成,确保 MCPServiceManager 可用\n await this.initializeConnections();\n\n // 2. 设置路由系统(在连接初始化之后)\n this.setupRouteSystem();\n this.setupRoutesFromRegistry();\n\n // 3. 启动 HTTP 服务器\n const server = serve({\n fetch: this.app.fetch,\n port: this.port,\n hostname: HTTP_SERVER_CONFIG.DEFAULT_BIND_ADDRESS, // 绑定到所有网络接口,支持 Docker 部署\n createServer,\n });\n\n // 保存服务器实例\n this.httpServer = server;\n\n // 设置 WebSocket 服务器\n if (!this.httpServer) {\n throw new Error(\"HTTP server 未初始化\");\n }\n this.wss = new WebSocketServer({\n server: this.httpServer as Server<\n typeof IncomingMessage,\n typeof ServerResponse\n >,\n });\n this.setupWebSocket();\n\n this.logger.info(\n `Web server listening on http://${HTTP_SERVER_CONFIG.DEFAULT_BIND_ADDRESS}:${this.port}`\n );\n this.logger.info(`Local access: http://localhost:${this.port}`);\n }\n\n public stop(): Promise<void> {\n return new Promise((resolve) => {\n let resolved = false;\n\n const doResolve = () => {\n if (!resolved) {\n resolved = true;\n resolve();\n }\n };\n\n // 清理连接管理器和 MCPServiceManager\n (async () => {\n try {\n if (this.endpointManager) {\n await this.endpointManager.cleanup();\n this.logger.debug(\"连接管理器已清理\");\n }\n } catch (error) {\n this.logger.error(\"连接管理器清理失败:\", error);\n }\n\n try {\n if (this.mcpServiceManager) {\n await this.mcpServiceManager.stopAllServices();\n this.mcpServiceManager = null;\n this.logger.debug(\"MCPServiceManager 已清理\");\n }\n } catch (error) {\n this.logger.error(\"MCPServiceManager 清理失败:\", error);\n }\n\n // 强制断开所有 WebSocket 客户端连接\n if (this.wss) {\n for (const client of this.wss.clients) {\n client.terminate();\n }\n\n // 关闭 WebSocket 服务器\n this.wss.close(() => {\n let forceCloseTimer: NodeJS.Timeout | undefined;\n\n const cleanupAndResolve = () => {\n if (forceCloseTimer) {\n clearTimeout(forceCloseTimer);\n forceCloseTimer = undefined;\n }\n doResolve();\n };\n\n // 强制关闭 HTTP 服务器,不等待现有连接\n if (this.httpServer) {\n this.httpServer.close(() => {\n this.logger.info(\"Web 服务器已停止\");\n cleanupAndResolve();\n });\n\n // 设置超时,如果 2 秒内没有关闭则强制退出\n forceCloseTimer = setTimeout(() => {\n // 超时触发后标记定时器已失效,保持与 cleanupAndResolve 中的语义一致\n forceCloseTimer = undefined;\n this.logger.info(\"Web 服务器已强制停止\");\n doResolve();\n }, 2000);\n } else {\n this.logger.info(\"Web 服务器已停止\");\n cleanupAndResolve();\n }\n });\n } else {\n this.logger.info(\"Web 服务器已停止\");\n doResolve();\n }\n })();\n });\n }\n\n /**\n * 销毁 WebServer 实例,清理所有资源\n */\n public destroy(): void {\n this.logger.debug(\"销毁 WebServer 实例\");\n\n // 移除所有事件监听器,防止内存泄漏\n for (const unsubscribe of this.eventListenerUnsubscribers) {\n unsubscribe();\n }\n this.eventListenerUnsubscribers = [];\n this.logger.debug(\"已移除所有事件总线监听器\");\n\n // 销毁服务层\n this.statusService.destroy();\n // 异步销毁 ESP32 设备管理器(fire and forget)\n this.esp32Manager.destroy();\n\n // 销毁事件总线\n destroyEventBus();\n\n this.logger.debug(\"WebServer 实例已销毁\");\n }\n}\n","/**\n * 日志系统模块\n *\n * 提供统一的日志记录功能,基于 Pino 日志库实现。\n *\n * ## 主要特性\n *\n * - **多种日志级别**:支持通过日志级别值进行过滤和阈值设置,包括 trace、debug、info、warn、error、fatal\n * - **双重输出**:支持控制台和文件双重输出,控制台输出带彩色格式化\n * - **守护进程模式**:支持守护进程模式(仅文件输出,无控制台输出)\n * - **结构化日志**:支持结构化日志记录,便于日志分析和查询\n * - **自动日志轮转**:自动日志文件轮转和管理,防止日志文件过大\n * - **高性能**:基于 Pino 的高性能异步写入,对应用性能影响极小\n * - **错误堆栈跟踪**:完整的错误堆栈跟踪,便于问题定位\n * - **动态日志级别**:支持动态设置日志级别,无需重启应用\n *\n * ## 日志级别\n *\n * Logger 支持以下日志级别值用于过滤和阈值设置(按严重性递增):\n *\n * - `trace` (10):最详细的日志级别\n * - `debug` (20):调试信息\n * - `info` (30):一般信息 - 提供对应的 `logger.info()` 方法\n * - `warn` (40):警告信息 - 提供对应的 `logger.warn()` 方法\n * - `error` (50):错误信息 - 提供对应的 `logger.error()` 方法\n * - `fatal` (60):致命错误\n *\n * **注意**:当前提供的记录方法包括 `info()`、`success()`、`warn()`、`error()`、`debug()` 和 `log()`。\n * 可以通过 `setGlobalLogLevel()` 设置日志级别阈值来控制输出详细程度。\n *\n * ## 使用示例\n *\n * ### 基本使用\n *\n * ```typescript\n * import { logger } from '@/Logger.js';\n *\n * // 记录信息\n * logger.info('服务启动成功');\n * logger.error('发生错误', error);\n * logger.debug('调试信息', { data: 'value' });\n * ```\n *\n * ### 结构化日志\n *\n * ```typescript\n * // 结构化日志支持\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n * logger.error({ error: err, requestId: 'abc123' }, '请求处理失败');\n * ```\n *\n * ### 创建自定义 Logger 实例\n *\n * ```typescript\n * import { createLogger } from '@/Logger.js';\n *\n * // 创建指定级别的 Logger\n * const customLogger = createLogger('debug');\n * customLogger.debug('这是一条调试日志');\n * ```\n *\n * ### 动态设置日志级别\n *\n * ```typescript\n * import { setGlobalLogLevel } from '@/Logger.js';\n *\n * // 设置全局日志级别\n * setGlobalLogLevel('debug');\n * ```\n *\n * ### 文件日志配置\n *\n * ```typescript\n * import { logger } from '@/Logger.js';\n *\n * // 初始化日志文件\n * logger.initLogFile('/path/to/project');\n *\n * // 配置日志文件管理参数\n * logger.setLogFileOptions(10 * 1024 * 1024, 5); // 10MB,最多5个文件\n * ```\n *\n * ## 与 Pino 的集成\n *\n * 本模块基于 [Pino](https://getpino.io/) 日志库实现,提供了以下增强:\n *\n * - 控制台输出的彩色格式化\n * - 简化的 API 设计\n * - 自动日志文件轮转\n * - 守护进程模式支持\n * - 结构化日志支持\n * - 动态日志级别控制\n *\n * ## 守护进程模式\n *\n * 当环境变量 `XIAOZHI_DAEMON=true` 时,Logger 自动进入守护进程模式:\n *\n * - 仅输出到日志文件,不输出到控制台\n * - 适用于后台服务运行场景\n *\n * **重要提示**:守护进程模式下必须先调用 `logger.initLogFile()` 初始化日志文件路径,\n * 否则日志将被写入 `/dev/null`(等同于被丢弃)。\n *\n * @example\n * ```typescript\n * // 守护进程模式下的正确使用方式\n * import { logger } from '@/Logger.js';\n *\n * // 1. 先初始化日志文件\n * logger.initLogFile('/path/to/project');\n *\n * // 2. 再记录日志\n * logger.info('服务启动成功');\n * ```\n *\n * @module apps/backend/Logger\n *\n * @example\n * ```typescript\n * import { logger } from '@/Logger.js';\n *\n * logger.info('服务启动成功');\n * logger.error('发生错误', error);\n * logger.debug('调试信息', { data: 'value' });\n * ```\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\nimport { z } from \"zod\";\n\nconst LogLevelSchema = z.enum([\n \"fatal\",\n \"error\",\n \"warn\",\n \"info\",\n \"debug\",\n \"trace\",\n]);\ntype Level = z.infer<typeof LogLevelSchema>;\n\n/**\n * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式\n * @param date 要格式化的日期对象\n * @returns 格式化后的日期时间字符串\n */\nfunction formatDateTime(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * 高性能日志记录器,基于 pino 实现\n *\n * 特性:\n * - 支持控制台和文件双重输出\n * - 支持守护进程模式(仅文件输出)\n * - 支持结构化日志记录\n * - 自动日志文件轮转和管理\n * - 高性能异步写入\n * - 完整的错误堆栈跟踪\n */\nexport class Logger {\n private logFilePath: string | null = null;\n private pinoInstance: PinoLogger;\n private isDaemonMode: boolean;\n private logLevel: Level; // 新增:动态日志级别\n private maxLogFileSize = 10 * 1024 * 1024; // 10MB 默认最大文件大小\n private maxLogFiles = 5; // 最多保留5个日志文件\n\n constructor(level: Level = \"info\") {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n\n // 设置并验证日志级别\n this.logLevel = this.validateLogLevel(level);\n\n // 创建 pino 实例\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 验证日志级别\n * @param level 日志级别\n * @returns 验证后的日志级别\n */\n private validateLogLevel(level: string): Level {\n const normalizedLevel = level.toLowerCase();\n const result = LogLevelSchema.safeParse(normalizedLevel);\n\n if (result.success) {\n return result.data;\n }\n\n return \"info\";\n }\n\n private createPinoInstance(): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 只在非守护进程模式下添加\n if (!this.isDaemonMode) {\n // 使用高性能的控制台输出流\n const consoleStream = this.createOptimizedConsoleStream();\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: consoleStream,\n });\n }\n\n // 文件流 - 如果有日志文件路径,使用高性能异步写入\n if (this.logFilePath) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({\n dest: this.logFilePath,\n sync: false, // 异步写入提升性能\n append: true,\n mkdir: true,\n }),\n });\n }\n\n // 如果没有流,创建一个空的流避免错误\n if (streams.length === 0) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({ dest: \"/dev/null\" }),\n });\n }\n\n return pino(\n {\n level: this.logLevel, // 修改:使用动态日志级别\n // 高性能配置\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n // 优化级别格式化\n level: (_label: string, number: number) => ({ level: number }),\n },\n // 禁用不必要的功能以提升性能\n base: null, // 不包含 pid 和 hostname\n serializers: {\n // 优化错误序列化,在测试环境中安全处理\n err: pino.stdSerializers?.err || ((err: any) => err),\n },\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n private createOptimizedConsoleStream() {\n // 预编译级别映射以提升性能\n const levelMap = new Map([\n [20, { name: \"DEBUG\", color: chalk.gray }],\n [30, { name: \"INFO\", color: chalk.blue }],\n [40, { name: \"WARN\", color: chalk.yellow }],\n [50, { name: \"ERROR\", color: chalk.red }],\n [60, { name: \"FATAL\", color: chalk.red }],\n ]);\n\n return {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessageOptimized(logObj, levelMap);\n // 在测试环境中安全地写入\n this.safeWrite(`${message}\\n`);\n } catch (error) {\n // 如果解析失败,直接输出原始内容\n this.safeWrite(chunk);\n }\n },\n };\n }\n\n /**\n * 安全地写入到 stderr,在测试环境中避免错误\n */\n private safeWrite(content: string): void {\n try {\n if (process.stderr && typeof process.stderr.write === \"function\") {\n process.stderr.write(content);\n } else if (console && typeof console.error === \"function\") {\n // 在测试环境中回退到 console.error\n console.error(content.trim());\n }\n } catch (error) {\n // 在极端情况下静默失败,避免测试中断\n }\n }\n\n private formatConsoleMessageOptimized(\n logObj: any,\n levelMap: Map<number, { name: string; color: (text: string) => string }>\n ): string {\n const timestamp = formatDateTime(new Date());\n\n const levelInfo = levelMap.get(logObj.level) || {\n name: \"UNKNOWN\",\n color: (text: string) => text,\n };\n const coloredLevel = levelInfo.color(`[${levelInfo.name}]`);\n\n // 处理结构化日志中的 args,保持兼容性\n let message = logObj.msg;\n if (logObj.args && Array.isArray(logObj.args)) {\n const argsStr = logObj.args\n .map((arg: any) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \");\n message = `${message} ${argsStr}`;\n }\n\n return `[${timestamp}] ${coloredLevel} ${message}`;\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 检查并轮转日志文件\n this.rotateLogFileIfNeeded();\n\n // 确保日志文件存在\n try {\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n } catch (error) {\n // 如果创建日志文件失败,记录警告但继续执行\n // 允许应用在没有文件日志的情况下启动\n console.warn(\n `[Logger] 无法创建日志文件 ${this.logFilePath}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n // 清除日志路径,禁用文件日志\n this.logFilePath = null;\n }\n\n // 重新创建 pino 实例以包含文件流\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n // 在 pino 实现中,文件日志的启用/禁用通过重新创建实例来实现\n // 这里保持方法兼容性,但实际上文件日志在 initLogFile 时就已经启用\n if (enable && this.logFilePath) {\n // 重新创建 pino 实例以确保文件流正确配置\n this.pinoInstance = this.createPinoInstance();\n }\n }\n\n /**\n * 记录信息级别日志\n * @param message 日志消息\n * @param args 额外参数\n * @example\n * logger.info('用户登录', 'userId', 12345);\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n */\n info(message: string, ...args: any[]): void;\n /**\n * 记录结构化信息级别日志\n * @param obj 结构化日志对象\n * @param message 可选的日志消息\n */\n info(obj: object, message?: string): void;\n info(messageOrObj: string | object, ...args: any[]): void {\n this.logInfo(messageOrObj, ...args);\n }\n\n /**\n * 内部方法:记录 info 级别的日志\n * @param messageOrObj 日志消息或对象\n * @param args 额外参数\n * @private\n */\n private logInfo(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n success(message: string, ...args: any[]): void;\n success(obj: object, message?: string): void;\n success(messageOrObj: string | object, ...args: any[]): void {\n // success 映射为 info 级别,保持 API 兼容性\n this.logInfo(messageOrObj, ...args);\n }\n\n warn(message: string, ...args: any[]): void;\n warn(obj: object, message?: string): void;\n warn(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.warn(messageOrObj);\n } else {\n this.pinoInstance.warn({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.warn(messageOrObj, args[0] || \"\");\n }\n }\n\n error(message: string, ...args: any[]): void;\n error(obj: object, message?: string): void;\n error(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.error(messageOrObj);\n } else {\n // 改进错误处理 - 特殊处理 Error 对象\n const errorArgs = args.map((arg) => {\n if (arg instanceof Error) {\n if (this.pinoInstance.level === \"debug\") return arg.message;\n return {\n message: arg.message,\n stack: arg.stack,\n name: arg.name,\n cause: arg.cause,\n };\n }\n return arg;\n });\n this.pinoInstance.error({ args: errorArgs }, messageOrObj);\n }\n } else {\n // 结构化错误日志,自动提取错误信息\n const enhancedObj = this.enhanceErrorObject(messageOrObj);\n this.pinoInstance.error(enhancedObj, args[0] || \"\");\n }\n }\n\n debug(message: string, ...args: any[]): void;\n debug(obj: object, message?: string): void;\n debug(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.debug(messageOrObj);\n } else {\n this.pinoInstance.debug({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.debug(messageOrObj, args[0] || \"\");\n }\n }\n\n log(message: string, ...args: any[]): void;\n log(obj: object, message?: string): void;\n log(messageOrObj: string | object, ...args: any[]): void {\n // log 方法使用 info 级别\n this.logInfo(messageOrObj, ...args);\n }\n\n /**\n * 增强错误对象,提取更多错误信息\n */\n private enhanceErrorObject(obj: any): any {\n const enhanced = { ...obj };\n\n // 遍历对象属性,查找 Error 实例\n for (const [key, value] of Object.entries(enhanced)) {\n if (value instanceof Error) {\n enhanced[key] = {\n message: value.message,\n stack: value.stack,\n name: value.name,\n cause: value.cause,\n };\n }\n }\n\n return enhanced;\n }\n\n /**\n * 检查并轮转日志文件(如果需要)\n */\n private rotateLogFileIfNeeded(): void {\n if (!this.logFilePath || !fs.existsSync(this.logFilePath)) {\n return;\n }\n\n try {\n const stats = fs.statSync(this.logFilePath);\n if (stats.size > this.maxLogFileSize) {\n this.rotateLogFile();\n }\n } catch (error) {\n // 忽略文件状态检查错误\n }\n }\n\n /**\n * 轮转日志文件\n */\n private rotateLogFile(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 移动现有的编号日志文件\n for (let i = this.maxLogFiles - 1; i >= 1; i--) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n const newFile = path.join(logDir, `${logName}.${i + 1}.log`);\n\n if (fs.existsSync(oldFile)) {\n if (i === this.maxLogFiles - 1) {\n // 删除最老的文件\n fs.unlinkSync(oldFile);\n } else {\n fs.renameSync(oldFile, newFile);\n }\n }\n }\n\n // 将当前日志文件重命名为 .1.log\n const firstRotatedFile = path.join(logDir, `${logName}.1.log`);\n fs.renameSync(this.logFilePath, firstRotatedFile);\n } catch (error) {\n // 轮转失败时忽略错误,继续使用当前文件\n }\n }\n\n /**\n * 清理旧的日志文件\n */\n cleanupOldLogs(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 删除超过最大数量的日志文件\n for (let i = this.maxLogFiles + 1; i <= this.maxLogFiles + 10; i++) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n if (fs.existsSync(oldFile)) {\n fs.unlinkSync(oldFile);\n }\n }\n } catch (error) {\n // 忽略清理错误\n }\n }\n\n /**\n * 设置日志文件管理参数\n */\n setLogFileOptions(maxSize: number, maxFiles: number): void {\n this.maxLogFileSize = maxSize;\n this.maxLogFiles = maxFiles;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n // pino 实例会自动处理流的关闭\n // 这里保持方法兼容性\n }\n\n /**\n * 动态设置日志级别\n * @param level 新的日志级别\n * @description 动态更新Logger实例的日志级别\n */\n setLevel(level: Level): void {\n this.logLevel = this.validateLogLevel(level);\n\n // 重新创建pino实例以应用新的日志级别\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 获取当前日志级别\n * @returns 当前日志级别\n */\n getLevel(): Level {\n return this.logLevel;\n }\n}\n\n// 全局Logger实例管理\nlet globalLogger: Logger | null = null;\nlet globalLogLevel: Level = \"info\"; // 全局日志级别\n\n/**\n * 创建Logger实例\n * @param level 日志级别,默认为全局级别\n * @returns Logger实例\n */\nexport function createLogger(level?: Level): Logger {\n return new Logger(level || globalLogLevel);\n}\n\n/**\n * 获取全局Logger实例\n * @returns 全局Logger实例\n */\nexport function getLogger(): Logger {\n if (!globalLogger) {\n globalLogger = new Logger(globalLogLevel); // 使用全局级别\n }\n return globalLogger;\n}\n\n/**\n * 设置全局Logger实例\n * @param logger 新的Logger实例\n */\nexport function setGlobalLogger(logger: Logger): void {\n globalLogger = logger;\n}\n\n/**\n * 设置全局日志级别\n * @param level 新的日志级别\n * @description 更新全局日志级别,并影响现有和未来的Logger实例\n */\nexport function setGlobalLogLevel(level: Level): void {\n globalLogLevel = level;\n\n // 如果已存在全局Logger实例,更新其级别\n if (globalLogger) {\n globalLogger.setLevel(level);\n }\n}\n\n/**\n * 获取当前全局日志级别\n * @returns 当前日志级别\n */\nexport function getGlobalLogLevel(): Level {\n return globalLogLevel;\n}\n\n// 导出默认实例(向后兼容)\nexport const logger = getLogger();\n","/**\n * 提示词解析工具\n *\n * 支持三种格式的提示词配置:\n * 1. 绝对路径:如 `/Users/xxx/prompts/default.md`\n * 2. 相对路径:如 `./prompts/default.md`(相对于配置文件所在目录)\n * 3. 纯字符串:直接作为提示词内容\n */\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { configManager } from \"@xiaozhi-client/config\";\n\n// 默认系统提示词\nconst DEFAULT_SYSTEM_PROMPT =\n \"你是一个友好的语音助手,请用简洁的中文回答用户的问题。\";\n\n/**\n * 判断配置值是否为路径格式\n *\n * 路径格式的判断规则:\n * - 相对路径:以 `./`、`../`、`.\\` 或 `..\\` 开头(支持 Windows 和 Unix 风格)\n * - 绝对路径:使用 path.isAbsolute() 判断\n * - 其他情况:视为纯字符串内容\n *\n * @param config - 提示词配置值\n * @returns 是否为路径格式\n */\nfunction isPromptPath(config: string): boolean {\n // 将路径分隔符统一为正斜杠,便于跨平台判断\n const normalizedConfig = config.replace(/\\\\/g, \"/\");\n\n // 相对路径:以 ./ 或 ../ 开头\n if (normalizedConfig.startsWith(\"./\") || normalizedConfig.startsWith(\"../\")) {\n return true;\n }\n // 绝对路径\n if (isAbsolute(config)) {\n return true;\n }\n return false;\n}\n\n/**\n * 从文件路径读取提示词内容\n *\n * @param promptPath - 提示词文件路径(绝对路径或相对路径)\n * @returns 提示词内容,如果读取失败则返回 null\n */\nfunction resolvePromptFromPath(promptPath: string): string | null {\n try {\n // 将 Windows 风格的反斜杠统一转换为正斜杠,便于跨平台解析\n const normalizedPath = promptPath.replace(/\\\\/g, \"/\");\n\n // 解析路径\n let resolvedPath: string;\n if (isAbsolute(normalizedPath)) {\n // 绝对路径直接使用\n resolvedPath = normalizedPath;\n } else {\n // 相对路径:相对于配置文件所在目录\n const configFilePath = configManager.getConfigPath();\n const configDir = dirname(configFilePath);\n resolvedPath = resolve(configDir, normalizedPath);\n }\n\n // 检查文件是否存在\n if (!existsSync(resolvedPath)) {\n console.warn(\n `[prompt-utils] 提示词文件不存在: ${resolvedPath},将使用默认提示词`\n );\n return null;\n }\n\n // 读取文件内容\n const content = readFileSync(resolvedPath, \"utf-8\").trim();\n\n // 检查文件内容是否为空\n if (!content) {\n console.warn(\n `[prompt-utils] 提示词文件内容为空: ${resolvedPath},将使用默认提示词`\n );\n return null;\n }\n\n console.info(`[prompt-utils] 成功从文件加载提示词: ${resolvedPath}`);\n return content;\n } catch (error) {\n console.error(\n `[prompt-utils] 读取提示词文件失败: ${promptPath}`,\n error instanceof Error ? error.message : String(error)\n );\n return null;\n }\n}\n\n/**\n * 解析提示词配置\n *\n * 处理逻辑:\n * 1. 未配置或空字符串 → 返回默认提示词\n * 2. 是路径格式 → 尝试读取文件内容\n * 3. 不是路径格式 → 直接返回作为纯字符串\n *\n * @param promptConfig - 提示词配置值(可选)\n * @returns 解析后的提示词内容\n */\nexport function resolvePrompt(promptConfig?: string): string {\n // 未配置或空字符串,返回默认提示词\n if (!promptConfig || promptConfig.trim() === \"\") {\n return DEFAULT_SYSTEM_PROMPT;\n }\n\n // 判断是否为路径格式\n if (isPromptPath(promptConfig)) {\n // 尝试从路径读取\n const content = resolvePromptFromPath(promptConfig);\n // 读取失败返回默认提示词\n return content || DEFAULT_SYSTEM_PROMPT;\n }\n\n // 不是路径格式,直接作为纯字符串返回\n return promptConfig;\n}\n\n/**\n * 获取默认系统提示词\n *\n * @returns 默认系统提示词\n */\nexport function getDefaultSystemPrompt(): string {\n return DEFAULT_SYSTEM_PROMPT;\n}\n\n/**\n * 提示词文件信息\n */\nexport interface PromptFileInfo {\n /** 文件名 */\n fileName: string;\n /** 相对路径(相对于配置文件所在目录) */\n relativePath: string;\n}\n\n/**\n * 获取 prompts 目录下的所有 .md 文件列表\n *\n * @returns 提示词文件信息数组\n */\nexport function listPromptFiles(): PromptFileInfo[] {\n try {\n const configFilePath = configManager.getConfigPath();\n const configDir = dirname(configFilePath);\n const promptsDir = resolve(configDir, \"prompts\");\n\n // 检查 prompts 目录是否存在\n if (!existsSync(promptsDir)) {\n return [];\n }\n\n // 读取目录下的所有文件\n const files = readdirSync(promptsDir);\n\n // 过滤出 .md 文件并构建返回结果\n const promptFiles: PromptFileInfo[] = files\n .filter((file: string) => file.endsWith(\".md\"))\n .map((file: string) => ({\n fileName: file,\n relativePath: `./prompts/${file}`,\n }));\n\n return promptFiles;\n } catch (error) {\n console.error(\n \"[prompt-utils] 获取提示词文件列表失败:\",\n error instanceof Error ? error.message : String(error)\n );\n return [];\n }\n}\n\n// ==================== 提示词文件操作相关函数 ====================\n\n/** 最大文件大小限制(100KB) */\nconst MAX_FILE_SIZE = 100 * 1024;\n\n/** 文件名验证正则:允许字母、数字、下划线、中划线、中文 */\nconst FILE_NAME_REGEX = /^[\\u4e00-\\u9fa5a-zA-Z0-9_-]+\\.md$/;\n\n/**\n * 验证提示词文件路径是否安全\n *\n * 安全规则:\n * 1. 必须是相对路径格式(以 ./prompts/ 开头)\n * 2. 路径不能包含 ..(防止路径遍历攻击)\n * 3. 文件名必须符合规范\n *\n * @param relativePath - 相对路径\n * @returns 验证结果,包含是否有效和错误信息\n */\nexport function validatePromptPath(relativePath: string): {\n valid: boolean;\n error?: string;\n} {\n // 将 Windows 风格的反斜杠统一转换为正斜杠,便于跨平台验证\n const normalizedPath = relativePath.replace(/\\\\/g, \"/\");\n\n // 检查路径格式(使用规范化后的路径)\n if (!normalizedPath.startsWith(\"./prompts/\")) {\n return {\n valid: false,\n error: \"路径格式错误,必须以 ./prompts/ 开头\",\n };\n }\n\n // 检查路径遍历攻击(使用规范化后的路径)\n if (normalizedPath.includes(\"..\")) {\n return {\n valid: false,\n error: \"路径不能包含 ..\",\n };\n }\n\n // 提取文件名并验证(使用规范化后的路径)\n const fileName = normalizedPath.replace(\"./prompts/\", \"\");\n if (!FILE_NAME_REGEX.test(fileName)) {\n return {\n valid: false,\n error:\n \"文件名只能包含字母、数字、下划线、中划线、中文,且必须以 .md 结尾\",\n };\n }\n\n return { valid: true };\n}\n\n/**\n * 验证提示词文件名是否合法\n *\n * @param fileName - 文件名\n * @returns 验证结果\n */\nexport function validatePromptFileName(fileName: string): {\n valid: boolean;\n error?: string;\n} {\n if (!FILE_NAME_REGEX.test(fileName)) {\n return {\n valid: false,\n error:\n \"文件名只能包含字母、数字、下划线、中划线、中文,且必须以 .md 结尾\",\n };\n }\n return { valid: true };\n}\n\n/**\n * 获取 prompts 目录的绝对路径\n *\n * @returns prompts 目录的绝对路径\n */\nexport function getPromptsDir(): string {\n const configFilePath = configManager.getConfigPath();\n const configDir = dirname(configFilePath);\n return resolve(configDir, \"prompts\");\n}\n\n/**\n * 将相对路径解析为绝对路径\n *\n * @param relativePath - 相对路径(如 ./prompts/default.md)\n * @returns 绝对路径\n */\nexport function resolvePromptPath(relativePath: string): string {\n const promptsDir = getPromptsDir();\n const fileName = relativePath.replace(\"./prompts/\", \"\");\n return resolve(promptsDir, fileName);\n}\n\n/**\n * 提示词文件内容信息\n */\nexport interface PromptFileContent {\n /** 文件名 */\n fileName: string;\n /** 相对路径(相对于配置文件所在目录) */\n relativePath: string;\n /** 文件内容 */\n content: string;\n}\n\n/**\n * 读取提示词文件内容\n *\n * @param relativePath - 相对路径(如 ./prompts/default.md)\n * @returns 文件内容信息\n * @throws 如果路径无效或文件不存在\n */\nexport function readPromptFile(relativePath: string): PromptFileContent {\n // 验证路径\n const validation = validatePromptPath(relativePath);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 解析绝对路径\n const absolutePath = resolvePromptPath(relativePath);\n\n // 检查文件是否存在\n if (!existsSync(absolutePath)) {\n throw new Error(`文件不存在: ${relativePath}`);\n }\n\n // 检查文件大小\n const stats = statSync(absolutePath);\n if (stats.size > MAX_FILE_SIZE) {\n throw new Error(\"文件大小超过限制(最大 100KB)\");\n }\n\n // 读取文件内容\n const content = readFileSync(absolutePath, \"utf-8\");\n\n return {\n fileName: relativePath.replace(\"./prompts/\", \"\"),\n relativePath,\n content,\n };\n}\n\n/**\n * 更新提示词文件内容\n *\n * @param relativePath - 相对路径(如 ./prompts/default.md)\n * @param content - 新的文件内容\n * @throws 如果路径无效或文件不存在\n */\nexport function updatePromptFile(\n relativePath: string,\n content: string\n): PromptFileContent {\n // 验证路径\n const validation = validatePromptPath(relativePath);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 验证内容大小(按 UTF-8 字节数,与文件大小限制保持一致)\n if (Buffer.byteLength(content, \"utf8\") > MAX_FILE_SIZE) {\n throw new Error(\"内容大小超过限制(最大 100KB)\");\n }\n\n // 解析绝对路径\n const absolutePath = resolvePromptPath(relativePath);\n\n // 检查文件是否存在\n if (!existsSync(absolutePath)) {\n throw new Error(`文件不存在: ${relativePath}`);\n }\n\n // 写入文件\n writeFileSync(absolutePath, content, \"utf-8\");\n\n return {\n fileName: relativePath.replace(\"./prompts/\", \"\"),\n relativePath,\n content,\n };\n}\n\n/**\n * 创建新的提示词文件\n *\n * @param fileName - 文件名(如 custom-prompt.md)\n * @param content - 文件内容\n * @returns 新创建的文件信息\n * @throws 如果文件名无效或文件已存在\n */\nexport function createPromptFile(\n fileName: string,\n content: string\n): PromptFileContent {\n // 验证文件名\n const validation = validatePromptFileName(fileName);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 验证内容大小(按 UTF-8 字节数计算,避免多字节字符导致限制失真)\n const contentSize = Buffer.byteLength(content, \"utf8\");\n if (contentSize > MAX_FILE_SIZE) {\n throw new Error(\"内容大小超过限制(最大 100KB)\");\n }\n\n // 获取 prompts 目录\n const promptsDir = getPromptsDir();\n\n // 确保 prompts 目录存在\n if (!existsSync(promptsDir)) {\n mkdirSync(promptsDir, { recursive: true });\n }\n\n // 构建文件路径\n const absolutePath = resolve(promptsDir, fileName);\n const relativePath = `./prompts/${fileName}`;\n\n // 检查文件是否已存在\n if (existsSync(absolutePath)) {\n throw new Error(`文件已存在: ${fileName}`);\n }\n\n // 写入文件\n writeFileSync(absolutePath, content, \"utf-8\");\n\n return {\n fileName,\n relativePath,\n content,\n };\n}\n\n/**\n * 删除提示词文件\n *\n * @param relativePath - 相对路径(如 ./prompts/old-prompt.md)\n * @throws 如果路径无效或文件不存在\n */\nexport function deletePromptFile(relativePath: string): void {\n // 验证路径\n const validation = validatePromptPath(relativePath);\n if (!validation.valid) {\n throw new Error(validation.error);\n }\n\n // 解析绝对路径\n const absolutePath = resolvePromptPath(relativePath);\n\n // 检查文件是否存在\n if (!existsSync(absolutePath)) {\n throw new Error(`文件不存在: ${relativePath}`);\n }\n\n // 删除文件\n rmSync(absolutePath);\n}\n","/**\n * 配置 API HTTP 路由处理器\n * 提供配置读取、配置更新等配置相关的 RESTful API 接口\n */\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport {\n createPromptFile,\n deletePromptFile,\n listPromptFiles,\n readPromptFile,\n updatePromptFile,\n} from \"@/utils/prompt-utils.js\";\nimport type { AppConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 配置 API 处理器\n */\nexport class ConfigApiHandler extends BaseHandler {\n constructor() {\n super();\n }\n\n /**\n * 获取配置\n * GET /api/config\n */\n async getConfig(c: Context<AppContext>): Promise<Response> {\n const logger = c.get(\"logger\");\n try {\n logger.debug(\"处理获取配置请求\");\n const config = configManager.getConfig();\n logger.debug(\"获取配置成功\");\n return c.success(config);\n } catch (error) {\n logger.error(\"获取配置失败:\", error);\n return c.fail(\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 更新配置\n * PUT /api/config\n */\n async updateConfig(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理更新配置请求\");\n const newConfig: AppConfig = await c.req.json();\n\n // 使用 configManager 的验证方法\n configManager.validateConfig(newConfig);\n\n // 使用 configManager 的批量更新方法\n configManager.updateConfig(newConfig);\n\n // 更新服务工具配置(单独处理,因为 updateConfig 只更新已存在的配置)\n if (newConfig.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n newConfig.mcpServerConfig\n )) {\n for (const [toolName, toolConfig] of Object.entries(\n toolsConfig.tools\n )) {\n configManager.setToolEnabled(\n serverName,\n toolName,\n toolConfig.enable\n );\n }\n }\n }\n\n c.get(\"logger\").info(\"配置更新成功\");\n return c.success(undefined, \"配置更新成功\");\n } catch (error) {\n c.get(\"logger\").error(\"配置更新失败:\", error);\n return c.fail(\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"配置更新失败\"\n );\n }\n }\n\n /**\n * 获取 MCP 端点\n * GET /api/config/mcp-endpoint\n */\n async getMcpEndpoint(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取 MCP 端点请求\");\n const endpoint = configManager.getMcpEndpoint();\n c.get(\"logger\").debug(\"获取 MCP 端点成功\");\n return c.success({ endpoint });\n } catch (error) {\n c.get(\"logger\").error(\"获取 MCP 端点失败:\", error);\n return c.fail(\n \"MCP_ENDPOINT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取 MCP 端点列表\n * GET /api/config/mcp-endpoints\n */\n async getMcpEndpoints(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取 MCP 端点列表请求\");\n const endpoints = configManager.getMcpEndpoints();\n c.get(\"logger\").debug(\"获取 MCP 端点列表成功\");\n return c.success({ endpoints });\n } catch (error) {\n c.get(\"logger\").error(\"获取 MCP 端点列表失败:\", error);\n return c.fail(\n \"MCP_ENDPOINTS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取 MCP 服务配置\n * GET /api/config/mcp-servers\n */\n async getMcpServers(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取 MCP 服务配置请求\");\n const servers = configManager.getMcpServers();\n c.get(\"logger\").debug(\"获取 MCP 服务配置成功\");\n return c.success({ servers });\n } catch (error) {\n c.get(\"logger\").error(\"获取 MCP 服务配置失败:\", error);\n return c.fail(\n \"MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 服务配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取连接配置\n * GET /api/config/connection\n */\n async getConnectionConfig(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取连接配置请求\");\n const connection = configManager.getConnectionConfig();\n c.get(\"logger\").debug(\"获取连接配置成功\");\n return c.success({ connection });\n } catch (error) {\n c.get(\"logger\").error(\"获取连接配置失败:\", error);\n return c.fail(\n \"CONNECTION_CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取连接配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 重新加载配置\n * POST /api/config/reload\n */\n async reloadConfig(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理重新加载配置请求\");\n configManager.reloadConfig();\n const config = configManager.getConfig();\n c.get(\"logger\").info(\"重新加载配置成功\");\n return c.success(config, \"配置重新加载成功\");\n } catch (error) {\n c.get(\"logger\").error(\"重新加载配置失败:\", error);\n return c.fail(\n \"CONFIG_RELOAD_ERROR\",\n error instanceof Error ? error.message : \"重新加载配置失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取配置文件路径\n * GET /api/config/path\n */\n async getConfigPath(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取配置文件路径请求\");\n const path = configManager.getConfigPath();\n c.get(\"logger\").debug(\"获取配置文件路径成功\");\n return c.success({ path });\n } catch (error) {\n c.get(\"logger\").error(\"获取配置文件路径失败:\", error);\n return c.fail(\n \"CONFIG_PATH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置文件路径失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 检查配置是否存在\n * GET /api/config/exists\n */\n async checkConfigExists(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理检查配置是否存在请求\");\n const exists = configManager.configExists();\n c.get(\"logger\").debug(`配置存在检查结果: ${exists}`);\n return c.success({ exists });\n } catch (error) {\n c.get(\"logger\").error(\"检查配置是否存在失败:\", error);\n return c.fail(\n \"CONFIG_EXISTS_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查配置是否存在失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取提示词文件列表\n * GET /api/config/prompts\n */\n async getPromptFiles(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取提示词文件列表请求\");\n const prompts = listPromptFiles();\n c.get(\"logger\").debug(\n `获取提示词文件列表成功,共 ${prompts.length} 个文件`\n );\n return c.success({ prompts });\n } catch (error) {\n c.get(\"logger\").error(\"获取提示词文件列表失败:\", error);\n return c.fail(\n \"PROMPT_FILES_READ_ERROR\",\n error instanceof Error ? error.message : \"获取提示词文件列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取提示词文件内容\n * GET /api/config/prompts/content?path=./prompts/default.md\n */\n async getPromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取提示词文件内容请求\");\n const path = c.req.query(\"path\");\n\n if (!path) {\n return c.fail(\"INVALID_REQUEST\", \"缺少 path 参数\", undefined, 400);\n }\n\n const fileContent = readPromptFile(path);\n c.get(\"logger\").debug(`获取提示词文件内容成功: ${path}`);\n return c.success(fileContent);\n } catch (error) {\n c.get(\"logger\").error(\"获取提示词文件内容失败:\", error);\n return c.fail(\n \"PROMPT_FILE_READ_ERROR\",\n error instanceof Error ? error.message : \"获取提示词文件内容失败\",\n undefined,\n 400\n );\n }\n }\n\n /**\n * 更新提示词文件内容\n * PUT /api/config/prompts/content\n */\n async updatePromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理更新提示词文件内容请求\");\n const body = await c.req.json();\n\n // 验证请求体格式\n if (!body || typeof body !== \"object\") {\n return c.fail(\"INVALID_REQUEST\", \"请求体格式错误\", undefined, 400);\n }\n\n const { path, content } = body;\n\n // 验证 path 参数\n if (!path || typeof path !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"path 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n // 验证 content 参数\n if (content === undefined || typeof content !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"content 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n const fileContent = updatePromptFile(path, content);\n c.get(\"logger\").info(`更新提示词文件成功: ${path}`);\n return c.success(fileContent, \"提示词文件更新成功\");\n } catch (error) {\n c.get(\"logger\").error(\"更新提示词文件内容失败:\", error);\n return c.fail(\n \"PROMPT_FILE_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"更新提示词文件内容失败\",\n undefined,\n 400\n );\n }\n }\n\n /**\n * 创建新的提示词文件\n * POST /api/config/prompts/content\n */\n async createPromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理创建提示词文件请求\");\n const body = await c.req.json();\n\n // 验证请求体格式\n if (!body || typeof body !== \"object\") {\n return c.fail(\"INVALID_REQUEST\", \"请求体格式错误\", undefined, 400);\n }\n\n const { fileName, content } = body;\n\n // 验证 fileName 参数\n if (!fileName || typeof fileName !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"fileName 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n // 验证 content 参数\n if (content === undefined || typeof content !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"content 参数必须是字符串\",\n undefined,\n 400\n );\n }\n\n const fileContent = createPromptFile(fileName, content);\n c.get(\"logger\").info(`创建提示词文件成功: ${fileName}`);\n return c.success(fileContent, \"提示词文件创建成功\");\n } catch (error) {\n c.get(\"logger\").error(\"创建提示词文件失败:\", error);\n return c.fail(\n \"PROMPT_FILE_CREATE_ERROR\",\n error instanceof Error ? error.message : \"创建提示词文件失败\",\n undefined,\n 400\n );\n }\n }\n\n /**\n * 删除提示词文件\n * DELETE /api/config/prompts/content?path=./prompts/old-prompt.md\n */\n async deletePromptFileContent(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理删除提示词文件请求\");\n const path = c.req.query(\"path\");\n\n if (!path) {\n return c.fail(\"INVALID_REQUEST\", \"缺少 path 参数\", undefined, 400);\n }\n\n deletePromptFile(path);\n c.get(\"logger\").info(`删除提示词文件成功: ${path}`);\n return c.success(undefined, \"提示词文件删除成功\");\n } catch (error) {\n c.get(\"logger\").error(\"删除提示词文件失败:\", error);\n return c.fail(\n \"PROMPT_FILE_DELETE_ERROR\",\n error instanceof Error ? error.message : \"删除提示词文件失败\",\n undefined,\n 400\n );\n }\n }\n}\n","/**\n * 抽象 API Handler 基类\n * 提供便捷的辅助方法\n * logger 通过 c.get(\"logger\") 访问(Hono 推荐做法)\n */\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\n\nexport abstract class BaseHandler {\n /**\n * 统一错误处理方法\n * 记录错误日志并返回格式化的错误响应\n * @param c - Hono context\n * @param error - 错误对象\n * @param operation - 操作描述(用于日志)\n * @param defaultCode - 默认错误码\n * @param defaultMessage - 默认错误消息\n * @param statusCode - HTTP 状态码(默认 500)\n * @returns JSON 错误响应\n */\n protected handleError(\n c: Context<AppContext>,\n error: unknown,\n operation: string,\n defaultCode = \"OPERATION_FAILED\",\n defaultMessage = \"操作失败\",\n statusCode = 500\n ): Response {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const errorCode =\n error instanceof Error && \"code\" in error\n ? String((error as { code: unknown }).code)\n : defaultCode;\n\n c.get(\"logger\").error(`${operation}失败:`, error);\n\n return c.fail(\n errorCode,\n errorMessage || defaultMessage,\n undefined,\n statusCode\n );\n }\n\n /**\n * 解析 JSON 请求体\n * @param c - Hono context\n * @param errorMessage - 自定义错误消息前缀(默认\"请求体格式错误\")\n * @returns 解析后的 JSON 对象\n * @throws 如果请求体不是有效的 JSON\n */\n protected async parseJsonBody<T>(\n c: Context<AppContext>,\n errorMessage = \"请求体格式错误\"\n ): Promise<T> {\n try {\n return await c.req.json();\n } catch (error) {\n // 保留原始错误信息\n const message =\n error instanceof Error\n ? `${errorMessage}: ${error.message}`\n : errorMessage;\n throw new Error(message);\n }\n }\n}\n","/**\n * 扣子(Coze)API 集成模块\n *\n * 提供与扣子平台集成的完整功能,包括:\n * - config: 扣子 API 环境配置(中英文环境)\n * - @coze/api: 扣子官方 SDK 的完整导出\n * - createCozeClient: 创建扣子 API 客户端的工厂函数\n * - CozeApiService: 扣子 API 服务的封装类\n *\n * @example\n * ```typescript\n * import { CozeApiService, createCozeClient, config } from '@/lib/coze';\n *\n * // 使用预配置的服务\n * const service = new CozeApiService('your-token');\n *\n * // 或者创建自定义客户端\n * const client = createCozeClient('your-token', 'zh');\n * ```\n */\nexport { default as config } from \"./config\";\nexport * from \"@coze/api\";\nexport { createCozeClient } from \"./client\";\nexport { CozeApiService } from \"./service\";\n","/**\n * 扣子 API 环境配置\n *\n * 提供扣子 API 的不同环境配置(中文环境和英文环境)\n *\n * @example\n * ```typescript\n * import config from \"@/lib/coze/config\";\n *\n * // 获取中文环境配置(默认)\n * const zhEnv = config.zh;\n * console.log(zhEnv.COZE_BASE_URL); // \"https://api.coze.cn\"\n *\n * // 获取英文环境配置\n * const enEnv = config.en;\n * console.log(enEnv.COZE_BASE_URL); // \"https://api.coze.com\"\n * ```\n *\n * @remarks\n * - 中文环境(zh):适用于中国大陆用户,使用 .cn 域名\n * - 英文环境(en):适用于国际用户,使用 .com 域名\n * - 该配置被 `@/lib/coze/client.ts` 中的 `createCozeClient` 函数使用\n */\nexport default {\n zh: {\n COZE_BASE_URL: \"https://api.coze.cn\",\n COZE_BASE_WS_URL: \"wss://ws.coze.cn\",\n },\n en: {\n COZE_BASE_URL: \"https://api.coze.com\",\n COZE_BASE_WS_URL: \"wss://ws.coze.com\",\n },\n};\n","/**\n * 扣子 API 客户端封装\n * 提供统一的客户端创建和配置\n */\n\nimport { CozeAPI } from \"@/lib/coze\";\nimport config from \"./config\";\n\nexport type Language = \"zh\" | \"en\";\n\n/**\n * 创建 Coze API 客户端\n * @param token - API 访问令牌\n * @param language - API 环境语言,默认为 \"zh\"(中文),可选 \"en\"(英文)\n */\nexport function createCozeClient(\n token: string,\n language: Language = \"zh\"\n): CozeAPI {\n if (!token || typeof token !== \"string\" || token.trim() === \"\") {\n throw new Error(\"扣子 API Token 不能为空\");\n }\n\n const env = config[language] || config.zh;\n\n return new CozeAPI({\n baseURL: env.COZE_BASE_URL,\n token: token.trim(),\n baseWsURL: env.COZE_BASE_WS_URL,\n debug: false,\n });\n}\n","/**\n * 扣子 API 服务类\n * 负责与扣子 API 的交互,包括工作空间和工作流的获取\n */\n\nimport type { RunWorkflowData, WorkSpace } from \"@/lib/coze\";\nimport type {\n CozeWorkflowsData,\n CozeWorkflowsParams,\n CozeWorkflowsResponse,\n} from \"@/types/coze\";\nimport NodeCache from \"node-cache\";\nimport { createCozeClient } from \"./client\";\n\n/**\n * 扣子 API 服务类\n */\nexport class CozeApiService {\n private cache: NodeCache;\n private token: string; // 保留 token 字段用于可能的后续扩展(如 token 刷新)\n private client: ReturnType<typeof createCozeClient>;\n\n constructor(token: string) {\n this.token = token.trim();\n this.client = createCozeClient(this.token);\n\n // 初始化缓存\n this.cache = new NodeCache({\n stdTTL: 5 * 60, // 默认5分钟(工作流缓存使用此默认值)\n });\n }\n\n /**\n * 获取工作空间列表\n */\n async getWorkspaces(): Promise<WorkSpace[]> {\n try {\n const cacheKey = \"workspaces\";\n const cached = this.cache.get<WorkSpace[]>(cacheKey);\n if (cached) return cached;\n\n const { workspaces = [] } = await this.client.workspaces.list();\n\n // 设置缓存,过期时间30分钟\n this.cache.set(cacheKey, workspaces, 30 * 60);\n\n return workspaces;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`获取工作空间列表失败: ${errorMessage}`);\n }\n }\n\n /**\n * 获取工作流列表\n */\n async getWorkflows(params: CozeWorkflowsParams): Promise<CozeWorkflowsData> {\n try {\n const { workspace_id, page_num = 1, page_size = 20 } = params;\n\n if (!workspace_id || typeof workspace_id !== \"string\") {\n throw new Error(\"工作空间ID不能为空\");\n }\n\n const cacheKey = `workflows:${workspace_id}:${page_num}:${page_size}`;\n const cached = this.cache.get<CozeWorkflowsData>(cacheKey);\n if (cached) return cached;\n\n const response = await this.client.get<\n CozeWorkflowsParams,\n CozeWorkflowsResponse\n >(\"/v1/workflows\", {\n workspace_id,\n page_num,\n page_size,\n workflow_mode: \"workflow\",\n });\n\n const result = response.data;\n\n // 设置缓存,使用默认的5分钟过期时间\n this.cache.set(cacheKey, result);\n\n return result;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`获取工作流列表失败: ${errorMessage}`);\n }\n }\n\n /**\n * 运行工作流\n * @param workflowId - 工作流ID\n * @param parameters - 参数\n * @returns 运行工作流数据\n */\n async callWorkflow(\n workflowId: string,\n parameters: Record<string, unknown>\n ): Promise<RunWorkflowData> {\n try {\n return await this.client.workflows.runs.create({\n workflow_id: workflowId,\n parameters,\n });\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`运行工作流失败: ${errorMessage}`);\n }\n }\n\n /**\n * 清除缓存\n * @param pattern 可选的模式字符串,清除所有以该模式开头的缓存键\n */\n clearCache(pattern?: string): void {\n if (!pattern) {\n // 清除所有缓存\n this.cache.flushAll();\n return;\n }\n\n // node-cache 不支持模式匹配,需要手动实现\n // 使用前缀匹配,避免意外匹配\n const keys = this.cache.keys();\n const keysToDelete = keys.filter((key) => key.startsWith(pattern));\n this.cache.del(keysToDelete);\n }\n\n /**\n * 获取缓存统计信息\n */\n getCacheStats(): {\n size: number;\n keys: string[];\n hits: number;\n misses: number;\n hitRate: number;\n ksize: number;\n vsize: number;\n } {\n const stats = this.cache.getStats();\n const keys = this.cache.keys();\n const totalRequests = stats.hits + stats.misses;\n const hitRate = totalRequests > 0 ? stats.hits / totalRequests : 0;\n\n return {\n size: stats.keys,\n keys,\n hits: stats.hits,\n misses: stats.misses,\n hitRate,\n ksize: stats.ksize,\n vsize: stats.vsize,\n };\n }\n}\n","/**\n * 扣子 API HTTP 路由处理器\n * 提供扣子工作空间和工作流相关的 RESTful API 接口\n */\n\nimport { CozeApiService } from \"@/lib/coze\";\nimport type { CozeWorkflowsParams } from \"@/types/coze\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 错误代码类型\n */\ntype CozeErrorCode =\n | \"AUTH_FAILED\"\n | \"RATE_LIMITED\"\n | \"TIMEOUT\"\n | \"API_ERROR\"\n | \"NETWORK_ERROR\";\n\n/**\n * 带 code 属性的错误接口\n */\ninterface ErrorWithCode {\n code: CozeErrorCode;\n message: string;\n statusCode?: number;\n response?: unknown;\n}\n\n/**\n * 类型守卫函数:检查错误是否带有 code 属性\n */\nfunction isErrorWithCode(error: unknown): error is ErrorWithCode {\n if (!(error instanceof Error && \"code\" in error)) {\n return false;\n }\n\n const code = (error as ErrorWithCode).code;\n const validCodes: CozeErrorCode[] = [\n \"AUTH_FAILED\",\n \"RATE_LIMITED\",\n \"TIMEOUT\",\n \"API_ERROR\",\n \"NETWORK_ERROR\",\n ];\n\n return typeof code === \"string\" && validCodes.includes(code as CozeErrorCode);\n}\n\n/**\n * 获取扣子 API 服务实例\n */\nfunction getCozeApiService(): CozeApiService {\n const token = configManager.getCozeToken();\n\n if (!token) {\n throw new Error(\n \"扣子 API Token 未配置,请在配置文件中设置 platforms.coze.token\"\n );\n }\n\n return new CozeApiService(token);\n}\n\n/**\n * 扣子 API 路由处理器类\n */\nexport class CozeHandler extends BaseHandler {\n constructor() {\n super();\n }\n\n /**\n * 处理 Coze API 错误并返回标准化的响应\n * @param c - Hono 上下文对象\n * @param error - 捕获的错误对象\n * @param operationName - 操作名称,用于日志和错误消息\n * @returns 标准化的错误响应\n */\n private handleCozeApiError(\n c: Context<AppContext>,\n error: unknown,\n operationName: string\n ): Response {\n c.get(\"logger\").error(`${operationName}失败:`, error);\n\n // 根据错误类型返回不同的响应\n if (isErrorWithCode(error) && error.code === \"AUTH_FAILED\") {\n return c.fail(\n \"AUTH_FAILED\",\n \"扣子 API 认证失败,请检查 Token 配置\",\n undefined,\n 401\n );\n }\n\n if (isErrorWithCode(error) && error.code === \"RATE_LIMITED\") {\n return c.fail(\"RATE_LIMITED\", \"请求过于频繁,请稍后重试\", undefined, 429);\n }\n\n if (isErrorWithCode(error) && error.code === \"TIMEOUT\") {\n return c.fail(\"TIMEOUT\", \"请求超时,请稍后重试\", undefined, 408);\n }\n\n const details =\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined;\n\n return c.fail(\n \"INTERNAL_ERROR\",\n error instanceof Error ? error.message : `${operationName}失败`,\n details,\n 500\n );\n }\n\n /**\n * 获取工作空间列表\n * GET /api/coze/workspaces\n */\n async getWorkspaces(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取工作空间列表请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n const cozeApiService = getCozeApiService();\n\n c.get(\"logger\").info(\"调用 Coze API 获取工作空间列表\");\n const workspaces = await cozeApiService.getWorkspaces();\n c.get(\"logger\").info(`成功获取 ${workspaces.length} 个工作空间`);\n\n return c.success({ workspaces });\n } catch (error) {\n return this.handleCozeApiError(c, error, \"获取工作空间列表\");\n }\n }\n\n /**\n * 获取工作流列表\n * GET /api/coze/workflows?workspace_id=xxx&page_num=1&page_size=20\n */\n async getWorkflows(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取工作流列表请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n // 解析查询参数\n const workspace_id = c.req.query(\"workspace_id\");\n const page_num = Number.parseInt(c.req.query(\"page_num\") || \"1\", 10);\n const page_size = Number.parseInt(c.req.query(\"page_size\") || \"20\", 10);\n\n // 验证必需参数\n if (!workspace_id) {\n c.get(\"logger\").warn(\"缺少 workspace_id 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少必需参数: workspace_id\",\n undefined,\n 400\n );\n }\n\n // 验证分页参数\n if (page_num < 1 || page_num > 1000) {\n return c.fail(\n \"INVALID_PARAMETER\",\n \"page_num 必须在 1-1000 之间\",\n undefined,\n 400\n );\n }\n\n if (page_size < 1 || page_size > 100) {\n return c.fail(\n \"INVALID_PARAMETER\",\n \"page_size 必须在 1-100 之间\",\n undefined,\n 400\n );\n }\n\n const params: CozeWorkflowsParams = {\n workspace_id,\n page_num,\n page_size,\n };\n\n const cozeApiService = getCozeApiService();\n\n c.get(\"logger\").info(\n `开始获取工作空间 ${workspace_id} 的工作流列表,页码: ${page_num},每页: ${page_size}`\n );\n const result = await cozeApiService.getWorkflows(params);\n c.get(\"logger\").info(\n `成功获取工作空间 ${workspace_id} 的 ${result.items.length} 个工作流`\n );\n\n // 获取已添加的自定义工具列表,检查工作流是否已被添加为工具\n const customMCPTools = configManager.getCustomMCPTools();\n\n // 为每个工作流添加工具状态信息\n const enhancedItems = result.items.map((item) => {\n // 查找对应的自定义工具\n const addedTool = customMCPTools.find(\n (tool) =>\n tool.handler.type === \"proxy\" &&\n tool.handler.platform === \"coze\" &&\n tool.handler.config.workflow_id === item.workflow_id\n );\n\n return {\n ...item,\n isAddedAsTool: !!addedTool,\n toolName: addedTool?.name || null,\n };\n });\n\n c.get(\"logger\").info(\n `工作流工具状态检查完成,共 ${enhancedItems.filter((item) => item.isAddedAsTool).length} 个工作流已添加为工具`\n );\n\n return c.success(\n {\n items: enhancedItems,\n has_more: result.has_more,\n page_num,\n page_size,\n total_count: result.items.length, // 当前页的数量\n },\n `成功获取 ${enhancedItems.length} 个工作流`\n );\n } catch (error) {\n return this.handleCozeApiError(c, error, \"获取工作流列表\");\n }\n }\n\n /**\n * 清除扣子 API 缓存\n * POST /api/coze/cache/clear\n */\n async clearCache(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理清除扣子 API 缓存请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n const pattern = c.req.query(\"pattern\"); // 可选的缓存模式参数\n\n const cozeApiService = getCozeApiService();\n\n const statsBefore = cozeApiService.getCacheStats();\n c.get(\"logger\").info(\n `开始清除缓存${pattern ? ` (模式: ${pattern})` : \"\"}`\n );\n\n cozeApiService.clearCache(pattern);\n\n const statsAfter = cozeApiService.getCacheStats();\n\n c.get(\"logger\").info(\n `缓存清除完成,清除前: ${statsBefore.size} 项,清除后: ${statsAfter.size} 项`\n );\n\n return c.success(\n {\n cleared: statsBefore.size - statsAfter.size,\n remaining: statsAfter.size,\n pattern: pattern || \"all\",\n },\n \"缓存清除成功\"\n );\n } catch (error) {\n c.get(\"logger\").error(\"清除缓存失败:\", error);\n\n const details =\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined;\n\n return c.fail(\n \"INTERNAL_ERROR\",\n error instanceof Error ? error.message : \"清除缓存失败\",\n details,\n 500\n );\n }\n }\n\n /**\n * 获取缓存统计信息\n * GET /api/coze/cache/stats\n */\n async getCacheStats(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取缓存统计信息请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n c.get(\"logger\").debug(\"扣子配置无效\");\n return c.fail(\n \"CONFIG_INVALID\",\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n undefined,\n 400\n );\n }\n\n const cozeApiService = getCozeApiService();\n const stats = cozeApiService.getCacheStats();\n\n return c.success(stats);\n } catch (error) {\n c.get(\"logger\").error(\"获取缓存统计信息失败:\", error);\n\n const details =\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined;\n\n return c.fail(\n \"INTERNAL_ERROR\",\n error instanceof Error ? error.message : \"获取缓存统计信息失败\",\n details,\n 500\n );\n }\n }\n}\n","/**\n * 事件总线服务\n * 提供统一的事件发布订阅机制,用于解耦各个模块之间的通信\n * 支持配置更新、状态变更、接入点状态、服务重启、MCP 服务、工具调用等多种事件类型\n *\n * 主要功能:\n * - 事件的发布和订阅\n * - 事件类型的类型安全检查\n * - 统一的事件命名规范\n *\n * @module apps/backend/services/event-bus.service\n */\n\nimport { EventEmitter } from \"node:events\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { ClientInfo } from \"@/services/status.service.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * 事件类型定义\n */\nexport interface EventBusEvents {\n // 配置相关事件\n \"config:updated\": {\n type: string;\n serviceName?: string;\n platformName?: string;\n timestamp: Date;\n };\n \"config:error\": { error: Error; operation: string };\n\n // 状态相关事件\n \"status:updated\": { status: ClientInfo; source: string };\n \"status:error\": { error: Error; operation: string };\n\n // 接入点状态变更事件\n \"endpoint:status:changed\": {\n endpoint: string;\n connected: boolean;\n operation: \"connect\" | \"disconnect\" | \"reconnect\" | \"add\" | \"remove\";\n success: boolean;\n message?: string;\n timestamp: number;\n source: string;\n };\n\n // 接入点重连事件\n \"endpoint:reconnect:completed\": {\n trigger: \"mcp_server_added\" | \"mcp_server_batch_added\" | \"manual\" | \"other\";\n serverName?: string;\n endpointCount: number;\n timestamp: number;\n };\n \"endpoint:reconnect:failed\": {\n trigger: \"mcp_server_added\" | \"mcp_server_batch_added\" | \"manual\" | \"other\";\n serverName?: string;\n error: string;\n timestamp: number;\n };\n\n // 服务相关事件\n \"service:restart:requested\": {\n serviceName: string;\n reason?: string;\n delay: number;\n attempt: number;\n timestamp: number;\n source?: string;\n };\n \"service:restart:started\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:completed\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:execute\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:health:changed\": {\n serviceName: string;\n oldStatus: string;\n newStatus: string;\n timestamp: number;\n };\n\n // WebSocket 相关事件\n \"websocket:client:connected\": { clientId: string; timestamp: number };\n \"websocket:client:disconnected\": { clientId: string; timestamp: number };\n \"websocket:message:received\": { type: string; data: any; clientId: string };\n\n // 通知相关事件\n \"notification:broadcast\": { type: string; data: any; target?: string };\n \"notification:error\": { error: Error; type: string };\n\n // MCP服务相关事件\n \"mcp:service:connected\": {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n };\n \"mcp:service:disconnected\": {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n };\n \"mcp:service:connection:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n };\n \"mcp:server:added\": {\n serverName: string;\n config: any;\n tools: string[];\n timestamp: Date;\n };\n \"mcp:server:removed\": {\n serverName: string;\n affectedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:status_changed\": {\n serverName: string;\n oldStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n newStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n timestamp: Date;\n reason?: string;\n };\n \"mcp:server:connection:attempt\": {\n serverName: string;\n attempt: number;\n maxAttempts: number;\n timestamp: Date;\n };\n \"mcp:server:tools:updated\": {\n serverName: string;\n tools: string[];\n addedTools: string[];\n removedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:batch_added\": {\n totalServers: number;\n addedCount: number;\n failedCount: number;\n successfullyAddedServers: string[];\n results: any[];\n timestamp: Date;\n };\n \"mcp:server:rollback\": {\n serverName: string;\n timestamp: Date;\n };\n\n // 连接相关事件\n \"connection:reconnect:completed\": {\n success: boolean;\n reason: string;\n timestamp: Date;\n };\n\n // NPM 安装相关事件\n \"npm:install:started\": {\n version: string;\n installId: string;\n timestamp: number;\n };\n \"npm:install:log\": {\n version: string;\n installId: string;\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n };\n \"npm:install:completed\": {\n version: string;\n installId: string;\n success: boolean;\n duration: number;\n timestamp: number;\n };\n \"npm:install:failed\": {\n version: string;\n installId: string;\n error: string;\n duration: number;\n timestamp: number;\n };\n\n // 测试相关事件(仅用于测试)\n \"high-frequency\": {\n id: number;\n timestamp: number;\n };\n \"bulk-test\": {\n id: number;\n timestamp: number;\n };\n \"error-test\": {\n error: string;\n timestamp: number;\n };\n \"large-data-test\": {\n data: any;\n timestamp: number;\n };\n \"destroy-test\": {\n message: string;\n timestamp: number;\n };\n \"chain-event-1\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-2\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-3\": {\n value: number;\n timestamp: number;\n };\n \"performance-test\": {\n data: any;\n timestamp: number;\n };\n \"test:performance\": {\n id: number;\n timestamp: number;\n };\n \"chain:start\": {\n value: number;\n timestamp: number;\n };\n \"chain:middle\": {\n value: number;\n timestamp: number;\n };\n \"chain:end\": {\n value: number;\n timestamp: number;\n };\n \"test:error\": {\n error: boolean;\n timestamp: number;\n };\n \"test:remove\": {\n id: number;\n timestamp: number;\n };\n}\n\n/**\n * 事件总线 - 用于模块间的解耦通信\n */\nexport class EventBus extends EventEmitter {\n private logger: Logger;\n private eventStats: Map<string, { count: number; lastEmitted: Date }> =\n new Map();\n private maxListeners: number;\n\n constructor() {\n super();\n this.logger = logger;\n // 测试环境下增加监听器限制,避免 MaxListenersExceededWarning\n const isTest =\n process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\";\n this.maxListeners = isTest ? 200 : 50;\n this.setMaxListeners(this.maxListeners);\n this.setupErrorHandling();\n }\n\n /**\n * 设置错误处理\n */\n private setupErrorHandling(): void {\n this.on(\"error\", (error) => {\n this.logger.error(\"EventBus 内部错误:\", error);\n });\n\n // 监听器数量警告\n this.on(\"newListener\", (eventName) => {\n const listenerCount = this.listenerCount(eventName);\n if (listenerCount > this.maxListeners * 0.8) {\n this.logger.warn(\n `事件 ${eventName} 的监听器数量过多: ${listenerCount}`\n );\n }\n });\n }\n\n /**\n * 发射事件(类型安全)\n */\n emitEvent<K extends keyof EventBusEvents>(\n eventName: K,\n data: EventBusEvents[K]\n ): boolean {\n try {\n this.updateEventStats(eventName as string);\n this.logger.debug(`发射事件: ${eventName}`, data);\n\n // 使用原始emit方法,保持EventEmitter的所有特性\n return super.emit(eventName, data);\n } catch (error) {\n this.logger.error(`发射事件失败: ${eventName}`, error);\n // 将监听器错误发射到error事件\n if (error instanceof Error) {\n this.emit(\"error\", error);\n }\n return false;\n }\n }\n\n /**\n * 监听事件(类型安全)\n */\n onEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加事件监听器: ${eventName}`);\n return this.on(eventName, listener);\n }\n\n /**\n * 一次性监听事件(类型安全)\n */\n onceEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加一次性事件监听器: ${eventName}`);\n\n // 创建包装器来实现一次性监听\n const onceListener = (data: EventBusEvents[K]) => {\n try {\n listener(data);\n } catch (error) {\n // 监听器抛出错误,发射到错误事件\n this.emit(\"error\", error);\n throw error;\n } finally {\n // 在任何情况下都移除监听器\n this.offEvent(eventName, onceListener);\n }\n };\n\n return this.on(eventName, onceListener);\n }\n\n /**\n * 移除事件监听器(类型安全)\n */\n offEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`移除事件监听器: ${eventName}`);\n return this.off(eventName, listener);\n }\n\n /**\n * 更新事件统计\n */\n private updateEventStats(eventName: string): void {\n const stats = this.eventStats.get(eventName) || {\n count: 0,\n lastEmitted: new Date(),\n };\n stats.count++;\n stats.lastEmitted = new Date();\n this.eventStats.set(eventName, stats);\n }\n\n /**\n * 获取事件统计信息\n */\n getEventStats(): Record<string, { count: number; lastEmitted: Date }> {\n const stats: Record<string, { count: number; lastEmitted: Date }> = {};\n for (const [eventName, stat] of this.eventStats) {\n stats[eventName] = { ...stat };\n }\n return stats;\n }\n\n /**\n * 获取监听器统计信息\n */\n getListenerStats(): Record<string, number> {\n const stats: Record<string, number> = {};\n for (const eventName of this.eventNames()) {\n stats[eventName as string] = this.listenerCount(eventName);\n }\n return stats;\n }\n\n /**\n * 清理事件统计\n */\n clearEventStats(): void {\n this.eventStats.clear();\n this.logger.info(\"事件统计已清理\");\n }\n\n /**\n * 获取事件总线状态\n */\n getStatus(): {\n totalEvents: number;\n totalListeners: number;\n eventStats: Record<string, { count: number; lastEmitted: Date }>;\n listenerStats: Record<string, number>;\n } {\n return {\n totalEvents: this.eventStats.size,\n totalListeners: Object.values(this.getListenerStats()).reduce(\n (sum, count) => sum + count,\n 0\n ),\n eventStats: this.getEventStats(),\n listenerStats: this.getListenerStats(),\n };\n }\n\n /**\n * 销毁事件总线\n */\n destroy(): void {\n this.removeAllListeners();\n this.eventStats.clear();\n this.logger.info(\"EventBus 已销毁\");\n }\n}\n\n// 单例实例\nlet eventBusInstance: EventBus | null = null;\n\n/**\n * 获取事件总线单例\n */\nexport function getEventBus(): EventBus {\n if (!eventBusInstance) {\n eventBusInstance = new EventBus();\n }\n return eventBusInstance;\n}\n\n/**\n * 销毁事件总线单例\n */\nexport function destroyEventBus(): void {\n if (eventBusInstance) {\n eventBusInstance.destroy();\n eventBusInstance = null;\n }\n}\n","/**\n * 接入点管理 Handler\n *\n * 负责处理接入点相关的 HTTP 请求,包括:\n * - 接入点连接状态查询\n * - 接入点连接和断开\n * - 接入点状态管理\n * - 接入点重连\n * - 接入点验证\n *\n * @see @xiaozhi-client/endpoint - EndpointManager 实现\n */\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { ConfigManager } from \"@xiaozhi-client/config\";\nimport type {\n ConnectionStatus,\n EndpointManager,\n} from \"@xiaozhi-client/endpoint\";\nimport type { Context } from \"hono\";\n\n/**\n * 验证结果类型定义\n */\ninterface ValidationResult {\n isValid: boolean;\n errors: string[];\n}\n\n/**\n * 端点 API 处理器\n * 支持通过 HTTP API 动态管理端点(添加、删除、连接、断开、查询状态)\n * 端点变更会自动同步到配置文件,确保重启后状态保持一致\n */\nexport class EndpointHandler {\n private logger: Logger;\n private endpointManager: EndpointManager;\n private configManager: ConfigManager;\n private eventBus: EventBus;\n\n constructor(endpointManager: EndpointManager, configManager: ConfigManager) {\n this.logger = logger;\n this.endpointManager = endpointManager;\n this.configManager = configManager;\n this.eventBus = getEventBus();\n }\n\n /**\n * 从请求体中解析端点参数\n * @param c Hono 上下文\n * @param errorErrorCode 错误码,用于区分不同操作的错误\n * @returns 解析结果,成功时包含 endpoint,失败时包含可直接返回的 Response\n */\n private async parseEndpointFromBody(\n c: Context<AppContext>,\n errorErrorCode: string\n ): Promise<\n { ok: true; endpoint: string } | { ok: false; response: Response }\n > {\n let body: { endpoint: string };\n try {\n body = await c.req.json();\n } catch (error) {\n this.logger.error(\"JSON解析失败:\", error);\n return {\n ok: false,\n response: c.fail(\n errorErrorCode,\n \"JSON解析失败\",\n error instanceof Error ? error.message : undefined,\n 500\n ),\n };\n }\n\n const endpoint = body.endpoint;\n\n // 验证端点参数\n if (!endpoint || typeof endpoint !== \"string\") {\n return {\n ok: false,\n response: c.fail(\"INVALID_ENDPOINT\", \"端点参数无效\", undefined, 500),\n };\n }\n\n return { ok: true, endpoint };\n }\n\n /**\n * 验证端点 URL 格式\n * @param endpoint 端点 URL\n * @returns 验证结果\n */\n private validateEndpoint(endpoint: string): ValidationResult {\n const errors: string[] = [];\n\n if (!endpoint || typeof endpoint !== \"string\") {\n errors.push(\"端点必须是非空字符串\");\n return { isValid: false, errors };\n }\n\n try {\n new URL(endpoint);\n } catch {\n errors.push(\"端点 URL 格式无效\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 获取接入点状态\n * POST /api/endpoint/status\n */\n async getEndpointStatus(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_STATUS_READ_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.debug(`处理获取接入点状态请求: ${endpoint}`);\n try {\n // 获取连接状态\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const endpointStatus = connectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n if (!endpointStatus) {\n return c.fail(\"ENDPOINT_NOT_FOUND\", \"端点不存在\", undefined, 500);\n }\n\n this.logger.debug(`获取接入点状态成功: ${endpoint}`);\n return c.success(endpointStatus);\n } catch (error) {\n this.logger.error(\"获取接入点状态失败:\", error);\n return c.fail(\n \"ENDPOINT_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取接入点状态失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 连接指定接入点\n * POST /api/endpoint/connect\n */\n async connectEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_CONNECT_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点连接请求: ${endpoint}`);\n try {\n // 获取端点实例\n const endpointInstance = this.endpointManager.getEndpoint(endpoint);\n\n if (!endpointInstance) {\n return c.fail(\n \"ENDPOINT_NOT_FOUND\",\n \"端点不存在,请先添加接入点\",\n undefined,\n 500\n );\n }\n\n // 执行连接操作\n await this.endpointManager.connect(endpoint);\n\n // 获取连接后的状态\n const updatedConnectionStatus =\n this.endpointManager.getConnectionStatus();\n const endpointStatus = updatedConnectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n if (!endpointStatus) {\n return c.fail(\n \"ENDPOINT_STATUS_NOT_FOUND\",\n \"无法获取端点连接状态\",\n undefined,\n 500\n );\n }\n\n // 发送连接成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: true,\n operation: \"connect\",\n success: true,\n message: \"接入点连接成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点连接成功: ${endpoint}`);\n return c.success(endpointStatus);\n } catch (error) {\n this.logger.error(\"接入点连接失败:\", error);\n return c.fail(\n \"ENDPOINT_CONNECT_ERROR\",\n error instanceof Error ? error.message : \"接入点连接失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 断开指定接入点\n * POST /api/endpoint/disconnect\n */\n async disconnectEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_DISCONNECT_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点断开请求: ${endpoint}`);\n try {\n // 获取端点实例\n const endpointInstance = this.endpointManager.getEndpoint(endpoint);\n\n if (!endpointInstance) {\n return c.fail(\"ENDPOINT_NOT_FOUND\", \"端点不存在\", undefined, 500);\n }\n\n // 执行断开操作\n await this.endpointManager.disconnect(endpoint);\n\n // 获取断开后的状态\n const updatedConnectionStatus =\n this.endpointManager.getConnectionStatus();\n const endpointStatus = updatedConnectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n // 发送断开成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: false,\n operation: \"disconnect\",\n success: true,\n message: \"接入点断开成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点断开成功: ${endpoint}`);\n const fallbackStatus: ConnectionStatus = {\n endpoint,\n connected: false,\n initialized: true,\n };\n return c.success(endpointStatus || fallbackStatus);\n } catch (error) {\n this.logger.error(\"接入点断开失败:\", error);\n return c.fail(\n \"ENDPOINT_DISCONNECT_ERROR\",\n error instanceof Error ? error.message : \"接入点断开失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 添加新接入点\n * POST /api/endpoint/add\n * 流程:验证 URL → 检查存在性 → 创建实例 → 添加到管理器 → 连接 → 更新配置\n */\n async addEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_ADD_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点添加请求: ${endpoint}`);\n\n try {\n // 1. 验证端点 URL 格式\n const validation = this.validateEndpoint(endpoint);\n if (!validation.isValid) {\n return c.fail(\n \"INVALID_ENDPOINT_FORMAT\",\n validation.errors.join(\", \"),\n undefined,\n 500\n );\n }\n\n // 2. 检查端点是否已存在\n const existingEndpoint = this.endpointManager.getEndpoint(endpoint);\n if (existingEndpoint) {\n return c.fail(\"ENDPOINT_ALREADY_EXISTS\", \"端点已存在\", undefined, 500);\n }\n\n // 3. 添加端点到管理器(使用 URL 字符串)\n this.endpointManager.addEndpoint(endpoint);\n this.logger.debug(`端点已添加到管理器: ${endpoint}`);\n\n // 4. 获取新添加的端点实例\n const newEndpoint = this.endpointManager.getEndpoint(endpoint);\n if (!newEndpoint) {\n return c.fail(\n \"ENDPOINT_NOT_FOUND_AFTER_ADD\",\n \"端点添加后未找到\",\n undefined,\n 500\n );\n }\n\n // 5. 连接新端点\n try {\n await this.endpointManager.connect(endpoint);\n this.logger.debug(`端点已连接: ${endpoint}`);\n } catch (connectError) {\n this.logger.warn(\n `端点连接失败,但已添加到管理器: ${endpoint}`,\n connectError\n );\n // 连接失败不中断流程,端点已添加但未连接\n }\n\n // 6. 更新配置文件\n try {\n this.configManager.addMcpEndpoint(endpoint);\n this.logger.debug(`端点已添加到配置文件: ${endpoint}`);\n } catch (configError) {\n this.logger.error(`添加端点到配置文件失败: ${endpoint}`, configError);\n // 配置更新失败,需要回滚:优先尝试断开连接,其次从管理器移除端点\n try {\n await newEndpoint.disconnect();\n this.logger.debug(`回滚时已断开端点连接: ${endpoint}`);\n } catch (disconnectError) {\n // 断开失败只记录警告,不影响后续回滚流程\n this.logger.warn(\n `回滚时断开端点连接失败,将继续从管理器移除端点: ${endpoint}`,\n disconnectError\n );\n }\n // 从管理器移除端点\n await this.endpointManager.removeEndpoint(newEndpoint);\n throw configError;\n }\n\n // 8. 获取连接后的状态\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const endpointStatus = connectionStatus.find(\n (status: ConnectionStatus) => status.endpoint === endpoint\n );\n\n // 9. 发送事件通知\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: endpointStatus?.connected ?? false,\n operation: \"add\",\n success: true,\n message: \"接入点添加成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点添加成功: ${endpoint}`);\n\n const defaultEndpointStatus = {\n endpoint,\n connected: false,\n initialized: true,\n };\n return c.success(\n endpointStatus || defaultEndpointStatus,\n \"接入点添加成功\"\n );\n } catch (error) {\n this.logger.error(\"添加接入点失败:\", error);\n return c.fail(\n \"ENDPOINT_ADD_ERROR\",\n error instanceof Error ? error.message : \"添加接入点失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 移除接入点\n * POST /api/endpoint/remove\n * 流程:断开连接 → 从管理器移除 → 更新配置文件\n */\n async removeEndpoint(c: Context<AppContext>): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_REMOVE_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点移除请求: ${endpoint}`);\n\n try {\n // 检查端点是否存在\n const endpointInstance = this.endpointManager.getEndpoint(endpoint);\n if (!endpointInstance) {\n return c.fail(\"ENDPOINT_NOT_FOUND\", \"端点不存在\", undefined, 500);\n }\n\n // 记录断开前的连接状态\n const wasConnected = endpointInstance.isConnected();\n\n // 先从配置文件移除端点,确保配置与运行时状态保持一致\n try {\n this.configManager.removeMcpEndpoint(endpoint);\n this.logger.debug(`端点已从配置文件中移除: ${endpoint}`);\n } catch (error) {\n this.logger.error(`从配置文件移除端点失败: ${endpoint}`, error);\n // 配置更新失败是致命错误,中断移除操作\n throw error;\n }\n\n // 再从管理器移除端点\n // EndpointManager.removeEndpoint 内部会再次调用 disconnect(幂等操作)\n // 并清理状态和发射 endpointRemoved 事件\n await this.endpointManager.removeEndpoint(endpointInstance);\n this.logger.debug(`端点已从管理器中移除: ${endpoint}`);\n\n // 发送事件通知\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: false,\n operation: \"remove\",\n success: true,\n message: \"接入点移除成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点移除成功: ${endpoint}`);\n\n return c.success(\n {\n endpoint,\n operation: \"removed\",\n wasConnected,\n },\n \"接入点移除成功\"\n );\n } catch (error) {\n this.logger.error(\"移除接入点失败:\", error);\n\n return c.fail(\n \"ENDPOINT_REMOVE_ERROR\",\n error instanceof Error ? error.message : \"移除接入点失败\",\n undefined,\n 500\n );\n }\n }\n}\n","/**\n * API 相关常量定义\n */\n\n/**\n * 分页相关常量\n */\nexport const PAGINATION_CONSTANTS = {\n /** 默认每页记录数 */\n DEFAULT_LIMIT: 50,\n /** 最大每页记录数 */\n MAX_LIMIT: 200,\n} as const;\n","/**\n * HTTP 协议相关常量定义\n */\n\n/**\n * HTTP Content-Type 常量\n */\nexport const HTTP_CONTENT_TYPES = {\n /** JSON 格式 */\n APPLICATION_JSON: \"application/json\",\n /** HTML 格式 */\n TEXT_HTML: \"text/html\",\n /** 纯文本格式 */\n TEXT_PLAIN: \"text/plain\",\n /** CSS 样式表 */\n TEXT_CSS: \"text/css\",\n /** JavaScript 代码 */\n APPLICATION_JAVASCRIPT: \"application/javascript\",\n /** XML 格式 */\n APPLICATION_XML: \"application/xml\",\n /** PDF 文档 */\n APPLICATION_PDF: \"application/pdf\",\n /** ZIP 压缩包 */\n APPLICATION_ZIP: \"application/zip\",\n /** 八位字节流 */\n APPLICATION_OCTET_STREAM: \"application/octet-stream\",\n} as const;\n\n/**\n * HTTP 请求头常量\n */\nexport const HTTP_HEADERS = {\n /** Content-Type 头 */\n CONTENT_TYPE: \"Content-Type\",\n /** Content-Length 头 */\n CONTENT_LENGTH: \"content-length\",\n /** MCP 协议版本头 */\n MCP_PROTOCOL_VERSION: \"MCP-Protocol-Version\",\n /** 响应时间头 */\n X_RESPONSE_TIME: \"X-Response-Time\",\n} as const;\n\n/**\n * HTTP 状态码常量\n */\nexport const HTTP_STATUS_CODES = {\n /** 成功 */\n OK: 200,\n /** 已创建 */\n CREATED: 201,\n /** 无内容 */\n NO_CONTENT: 204,\n /** 错误的请求 */\n BAD_REQUEST: 400,\n /** 未授权 */\n UNAUTHORIZED: 401,\n /** 禁止访问 */\n FORBIDDEN: 403,\n /** 未找到 */\n NOT_FOUND: 404,\n /** 请求超时 */\n REQUEST_TIMEOUT: 408,\n /** 内部服务器错误 */\n INTERNAL_SERVER_ERROR: 500,\n /** 服务不可用 */\n SERVICE_UNAVAILABLE: 503,\n} as const;\n\n/**\n * HTTP 服务器配置常量\n */\nexport const HTTP_SERVER_CONFIG = {\n /** 默认绑定地址 */\n DEFAULT_BIND_ADDRESS: \"0.0.0.0\",\n /** 默认端口 */\n DEFAULT_PORT: 9999,\n} as const;\n\n/**\n * HTTP 错误消息常量\n */\nexport const HTTP_ERROR_MESSAGES = {\n /** 请求过大错误消息 */\n REQUEST_TOO_LARGE: \"Request too large\",\n /** 消息过大错误消息 */\n MESSAGE_TOO_LARGE: \"Message too large\",\n /** 无效请求错误消息 */\n INVALID_REQUEST: \"Invalid Request\",\n /** Content-Type 必须是 application/json */\n INVALID_CONTENT_TYPE: \"Content-Type must be application/json\",\n /** 解析错误 */\n PARSE_ERROR: \"Parse error\",\n /** 无效的 JSON */\n INVALID_JSON: \"Invalid JSON\",\n /** 内部错误 */\n INTERNAL_ERROR: \"Internal error\",\n} as const;\n","/**\n * MCP 协议相关常量定义\n */\n\n/**\n * JSON-RPC 版本常量\n */\nexport const JSONRPC_VERSION = \"2.0\" as const;\n\n/**\n * MCP 协议版本常量\n */\nexport const MCP_PROTOCOL_VERSIONS = {\n /** 2024-11-05 版本 */\n V2024_11_05: \"2024-11-05\",\n /** 2025-06-18 版本 */\n V2025_06_18: \"2025-06-18\",\n /** 默认版本 */\n DEFAULT: \"2024-11-05\",\n} as const;\n\n/**\n * MCP 支持的协议版本数组\n */\nexport const MCP_SUPPORTED_PROTOCOL_VERSIONS = [\n MCP_PROTOCOL_VERSIONS.V2024_11_05,\n MCP_PROTOCOL_VERSIONS.V2025_06_18,\n] as const;\n\n/**\n * MCP 服务器信息常量\n */\nexport const MCP_SERVER_INFO = {\n /** 服务器名称 */\n NAME: \"xiaozhi-mcp-server\",\n /** 服务器版本 */\n VERSION: \"1.0.0\",\n} as const;\n\n/**\n * MCP 方法名称常量\n */\nexport const MCP_METHODS = {\n /** 初始化 */\n INITIALIZE: \"initialize\",\n /** 已初始化通知 */\n INITIALIZED: \"notifications/initialized\",\n /** 工具列表 */\n TOOLS_LIST: \"tools/list\",\n /** 调用工具 */\n TOOLS_CALL: \"tools/call\",\n /** 资源列表 */\n RESOURCES_LIST: \"resources/list\",\n /** 提示列表 */\n PROMPTS_LIST: \"prompts/list\",\n /** Ping */\n PING: \"ping\",\n} as const;\n\n/**\n * JSON-RPC 错误消息常量\n */\nexport const JSONRPC_ERROR_MESSAGES = {\n /** 解析错误消息 */\n PARSE_ERROR: \"Parse error: Invalid JSON\",\n /** 无效请求消息 */\n INVALID_REQUEST: \"Invalid Request: Message does not conform to JSON-RPC 2.0\",\n /** 方法未找到消息 */\n METHOD_NOT_FOUND: \"Method not found\",\n /** 无效参数消息 */\n INVALID_PARAMS: \"Invalid params\",\n /** 内部错误消息 */\n INTERNAL_ERROR: \"Internal error\",\n /** 未找到工具消息 */\n TOOL_NOT_FOUND: \"未找到工具\",\n /** 未知方法消息 */\n UNKNOWN_METHOD: \"未知的方法\",\n} as const;\n\n/**\n * MCP 缓存版本常量\n */\nexport const MCP_CACHE_VERSIONS = {\n /** 缓存文件格式版本 */\n CACHE_VERSION: \"1.0.0\",\n /** 缓存条目版本 */\n CACHE_ENTRY_VERSION: \"1.0.0\",\n} as const;\n","/**\n * 事件名称常量定义\n */\n\n/**\n * MCP 服务相关事件\n */\nexport const MCP_SERVICE_EVENTS = {\n /** 服务已连接 */\n CONNECTED: \"mcp:service:connected\",\n /** 服务已断开连接 */\n DISCONNECTED: \"mcp:service:disconnected\",\n /** 服务连接失败 */\n CONNECTION_FAILED: \"mcp:service:connection:failed\",\n} as const;\n\n/**\n * MCP 服务器相关事件\n */\nexport const MCP_SERVER_EVENTS = {\n /** 服务器已添加 */\n ADDED: \"mcp:server:added\",\n /** 批量添加服务器 */\n BATCH_ADDED: \"mcp:server:batch_added\",\n /** 服务器已移除 */\n REMOVED: \"mcp:server:removed\",\n /** 服务器已启动 */\n STARTED: \"mcp:server:started\",\n /** 服务器已停止 */\n STOPPED: \"mcp:server:stopped\",\n} as const;\n","/**\n * 超时和延迟常量定义\n * 所有时间单位均为毫秒(ms)\n */\n\n/**\n * 缓存相关超时常量\n */\nexport const CACHE_TIMEOUTS = {\n /** 缓存 TTL(生存时间) */\n TTL: 300000,\n /** 清理间隔 */\n CLEANUP_INTERVAL: 60000,\n} as const;\n\n/**\n * HTTP 相关超时常量\n */\nexport const HTTP_TIMEOUTS = {\n /** 默认超时 */\n DEFAULT: 30000,\n /** 长运行任务超时 */\n LONG_RUNNING: 60000,\n} as const;\n\n/**\n * 服务重启相关延迟常量\n */\nexport const SERVICE_RESTART_DELAYS = {\n /** 重启执行延迟 */\n EXECUTION_DELAY: 500,\n /** 成功状态通知延迟 */\n SUCCESS_NOTIFICATION_DELAY: 5000,\n} as const;\n","/**\n * 缓存相关常量定义\n */\n\n/**\n * 消息大小限制常量\n */\nexport const MESSAGE_SIZE_LIMITS = {\n /** 默认消息大小限制(1MB) */\n DEFAULT: 1024 * 1024,\n /** 最大消息大小限制(10MB) */\n MAX: 10 * 1024 * 1024,\n} as const;\n\n/**\n * 缓存文件相关常量\n */\nexport const CACHE_FILE_CONFIG = {\n /** 缓存文件名 */\n FILENAME: \"xiaozhi.cache.json\",\n /** 临时文件后缀 */\n TEMP_SUFFIX: \".tmp\",\n} as const;\n\n/**\n * 工具名称分隔符常量\n */\nexport const TOOL_NAME_SEPARATORS = {\n /** 服务名与工具名之间的分隔符 */\n SERVICE_TOOL_SEPARATOR: \"__\",\n} as const;\n","/**\n * TTS 音色数据常量\n * 来源于火山引擎豆包语音合成模型 2.0\n */\n\nimport type { VoiceInfo } from \"@xiaozhi-client/shared-types\";\n\n/**\n * TTS 音色列表\n * 仅包含 2.0 版本的音色(推荐,支持情感变化)\n */\nexport const TTS_VOICES: VoiceInfo[] = [\n // === 通用场景 ===\n {\n name: \"Vivi 2.0\",\n voiceType: \"zh_female_vv_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文、日文、印尼、墨西哥西班牙语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"小何 2.0\",\n voiceType: \"zh_female_xiaohe_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"云舟 2.0\",\n voiceType: \"zh_male_m191_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"小天 2.0\",\n voiceType: \"zh_male_taocheng_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"刘飞 2.0\",\n voiceType: \"zh_male_liufei_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"魅力苏菲 2.0\",\n voiceType: \"zh_male_sophie_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"清新女声 2.0\",\n voiceType: \"zh_female_qingxinnvsheng_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"甜美小源 2.0\",\n voiceType: \"zh_female_tianmeixiaoyuan_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"甜美桃子 2.0\",\n voiceType: \"zh_female_tianmeitaozi_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"爽快思思 2.0\",\n voiceType: \"zh_female_shuangkuaisisi_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"邻家女孩 2.0\",\n voiceType: \"zh_female_linjianvhai_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"少年梓辛/Brayan 2.0\",\n voiceType: \"zh_male_shaonianzixin_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"魅力女友 2.0\",\n voiceType: \"zh_female_meilinvyou_uranus_bigtts\",\n scene: \"通用场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 角色扮演 ===\n {\n name: \"知性灿灿 2.0\",\n voiceType: \"zh_female_cancan_uranus_bigtts\",\n scene: \"角色扮演\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"撒娇学妹 2.0\",\n voiceType: \"zh_female_sajiaoxuemei_uranus_bigtts\",\n scene: \"角色扮演\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 视频配音 ===\n {\n name: \"佩奇猪 2.0\",\n voiceType: \"zh_female_peiqi_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"猴哥 2.0\",\n voiceType: \"zh_male_sunwukong_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"大壹 2.0\",\n voiceType: \"zh_male_dayi_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"黑猫侦探社咪仔 2.0\",\n voiceType: \"zh_female_mizai_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"鸡汤女 2.0\",\n voiceType: \"zh_female_jitangnv_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"流畅女声 2.0\",\n voiceType: \"zh_female_liuchangnv_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"儒雅逸辰 2.0\",\n voiceType: \"zh_male_ruyayichen_uranus_bigtts\",\n scene: \"视频配音\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 教育场景 ===\n {\n name: \"Tina老师 2.0\",\n voiceType: \"zh_female_yingyujiaoxue_uranus_bigtts\",\n scene: \"教育场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 客服场景 ===\n {\n name: \"暖阳女声 2.0\",\n voiceType: \"zh_female_kefunvsheng_uranus_bigtts\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"轻盈朵朵 2.0\",\n voiceType: \"saturn_zh_female_qingyingduoduo_cs_tob\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"指令遵循\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"温婉珊珊 2.0\",\n voiceType: \"saturn_zh_female_wenwanshanshan_cs_tob\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"指令遵循\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"热情艾娜 2.0\",\n voiceType: \"saturn_zh_female_reqingaina_cs_tob\",\n scene: \"客服场景\",\n language: \"中文\",\n capabilities: [\"指令遵循\"],\n modelVersion: \"2.0\",\n },\n\n // === 有声阅读 ===\n {\n name: \"儿童绘本 2.0\",\n voiceType: \"zh_female_xiaoxue_uranus_bigtts\",\n scene: \"有声阅读\",\n language: \"中文\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n\n // === 多语种 ===\n {\n name: \"Tim\",\n voiceType: \"en_male_tim_uranus_bigtts\",\n scene: \"多语种\",\n language: \"美式英语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"Dacey\",\n voiceType: \"en_female_dacey_uranus_bigtts\",\n scene: \"多语种\",\n language: \"美式英语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n {\n name: \"Stokie\",\n voiceType: \"en_female_stokie_uranus_bigtts\",\n scene: \"多语种\",\n language: \"美式英语\",\n capabilities: [\"情感变化\", \"指令遵循\", \"ASMR\"],\n modelVersion: \"2.0\",\n },\n];\n\n/**\n * 获取所有场景列表\n */\nexport function getVoiceScenes(): string[] {\n const scenes = new Set<string>();\n for (const voice of TTS_VOICES) {\n scenes.add(voice.scene);\n }\n return Array.from(scenes);\n}\n\n/**\n * 按场景分组获取音色\n */\nexport function getVoicesByScene(): Map<string, VoiceInfo[]> {\n const result = new Map<string, VoiceInfo[]>();\n for (const voice of TTS_VOICES) {\n const voices = result.get(voice.scene) || [];\n voices.push(voice);\n result.set(voice.scene, voices);\n }\n return result;\n}\n","/**\n * MCP 服务管理器\n * 使用 MCPService 实例管理多个 MCP 服务\n * 专注于实例管理、工具聚合和路由调用\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { logger } from \"@/Logger.js\";\nimport { MCPService } from \"@/lib/mcp\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport { ConnectionState } from \"@/lib/mcp/types\";\nimport type {\n CustomMCPTool,\n EnhancedToolInfo,\n InternalMCPServiceConfig,\n MCPServiceConfig,\n ManagerStatus,\n ToolCallResult,\n ToolInfo,\n ToolStatusFilter,\n UnifiedServerConfig,\n UnifiedServerStatus,\n} from \"@/lib/mcp/types\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { MCPMessage } from \"@/types/mcp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { isModelScopeURL } from \"@xiaozhi-client/config\";\nimport type { MCPToolConfig } from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport { CustomMCPHandler } from \"./custom.js\";\nimport { ToolCallLogger } from \"./log.js\";\nimport { MCPMessageHandler } from \"./message.js\";\nexport class MCPServiceManager extends EventEmitter {\n private services: Map<string, MCPService> = new Map();\n private configs: Record<string, MCPServiceConfig> = {};\n private tools: Map<string, ToolInfo> = new Map(); // 缓存工具信息,保持向后兼容\n private customMCPHandler: CustomMCPHandler; // CustomMCP 工具处理器\n private cacheManager: MCPCacheManager; // 缓存管理器\n private eventBus = getEventBus(); // 事件总线\n private toolCallLogger: ToolCallLogger; // 工具调用记录器\n private retryTimers: Map<string, NodeJS.Timeout> = new Map(); // 重试定时器\n private failedServices: Set<string> = new Set(); // 失败的服务集合\n\n private messageHandler: MCPMessageHandler;\n\n // 事件监听器引用(用于清理)\n private eventListeners: {\n serviceConnected: (data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }) => void;\n serviceDisconnected: (data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }) => void;\n serviceConnectionFailed: (data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }) => void;\n };\n\n // 新增:服务器状态管理(从 UnifiedMCPServer 移入)\n private isRunning = false;\n private config: UnifiedServerConfig;\n\n /**\n * 创建 MCPServiceManager 实例\n * @param configs 可选的初始服务配置或服务器配置\n */\n constructor(\n configs?: Record<string, MCPServiceConfig> | UnifiedServerConfig\n ) {\n super();\n\n // 处理参数,支持 UnifiedServerConfig 格式\n if (configs && this.isUnifiedServerConfig(configs)) {\n // UnifiedServerConfig 格式\n this.config = {\n name: \"MCPServiceManager\",\n enableLogging: true,\n logLevel: \"info\",\n ...configs,\n };\n this.configs = configs.configs || {};\n } else {\n // 原有的 configs 格式\n this.config = {\n name: \"MCPServiceManager\",\n enableLogging: true,\n logLevel: \"info\",\n };\n this.configs = configs || {};\n }\n\n // 在测试环境中使用临时目录,避免在项目根目录创建缓存文件\n const isTestEnv =\n process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\";\n const cachePath = isTestEnv\n ? `/tmp/xiaozhi-test-${Date.now()}-${Math.random()\n .toString(36)\n .substring(2, 11)}/xiaozhi.cache.json`\n : undefined;\n\n this.cacheManager = new MCPCacheManager(cachePath);\n this.customMCPHandler = new CustomMCPHandler(this.cacheManager, this);\n\n // 初始化工具调用记录器\n const toolCallLogConfig = configManager.getToolCallLogConfig();\n const configDir = configManager.getConfigDir();\n this.toolCallLogger = new ToolCallLogger(toolCallLogConfig, configDir);\n\n // 初始化事件监听器引用\n this.eventListeners = {\n serviceConnected: async (data) => {\n await this.handleServiceConnected(data);\n },\n serviceDisconnected: async (data) => {\n await this.handleServiceDisconnected(data);\n },\n serviceConnectionFailed: async (data) => {\n await this.handleServiceConnectionFailed(data);\n },\n };\n\n // 设置事件监听器\n this.setupEventListeners();\n\n // 初始化消息处理器(确保在其他组件初始化完成后)\n this.messageHandler = new MCPMessageHandler(this);\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听MCP服务连接成功事件\n this.eventBus.onEvent(\n \"mcp:service:connected\",\n this.eventListeners.serviceConnected\n );\n\n // 监听MCP服务断开连接事件\n this.eventBus.onEvent(\n \"mcp:service:disconnected\",\n this.eventListeners.serviceDisconnected\n );\n\n // 监听MCP服务连接失败事件\n this.eventBus.onEvent(\n \"mcp:service:connection:failed\",\n this.eventListeners.serviceConnectionFailed\n );\n }\n\n /**\n * 处理MCP服务连接成功事件\n */\n private async handleServiceConnected(data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }): Promise<void> {\n logger.debug(`服务 ${data.serviceName} 连接成功,开始刷新工具缓存`);\n\n try {\n // 获取最新的工具列表\n const service = this.services.get(data.serviceName);\n if (service) {\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n logger.info(`服务 ${data.serviceName} 工具缓存刷新完成`);\n }\n } catch (error) {\n logger.error(`刷新服务 ${data.serviceName} 工具缓存失败`, { error });\n }\n }\n\n /**\n * 处理MCP服务断开连接事件\n */\n private async handleServiceDisconnected(data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }): Promise<void> {\n logger.info(\n `服务 ${data.serviceName} 断开连接,原因: ${data.reason || \"未知\"}`\n );\n\n try {\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n logger.info(`服务 ${data.serviceName} 断开连接处理完成`);\n } catch (error) {\n logger.error(`服务 ${data.serviceName} 断开连接处理失败`, { error });\n }\n }\n\n /**\n * 处理MCP服务连接失败事件\n */\n private async handleServiceConnectionFailed(data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }): Promise<void> {\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n logger.error(\"刷新CustomMCPHandler失败\", { error });\n }\n }\n\n /**\n * 启动所有 MCP 服务\n */\n async startAllServices(): Promise<void> {\n logger.debug(\"[MCPManager] 正在启动所有 MCP 服务...\");\n\n // 初始化 CustomMCP 处理器\n try {\n this.customMCPHandler.initialize();\n logger.debug(\"[MCPManager] CustomMCP 处理器初始化完成\");\n } catch (error) {\n logger.error(\"[MCPManager] CustomMCP 处理器初始化失败\", { error });\n // CustomMCP 初始化失败不应该阻止标准 MCP 服务启动\n }\n\n const configEntries = Object.entries(this.configs);\n if (configEntries.length === 0) {\n logger.warn(\n \"[MCPManager] 没有配置任何 MCP 服务,请使用 addServiceConfig() 添加服务配置\"\n );\n // 即使没有标准 MCP 服务,也可能有 CustomMCP 工具\n return;\n }\n\n // 记录启动开始\n logger.info(\n `[MCPManager] 开始并行启动 ${configEntries.length} 个 MCP 服务`\n );\n\n // 并行启动所有服务,实现服务隔离\n const startPromises = configEntries.map(async ([serviceName]) => {\n try {\n await this.startService(serviceName);\n return { serviceName, success: true, error: null };\n } catch (error) {\n return {\n serviceName,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n });\n\n // 等待所有服务启动完成\n const results = await Promise.allSettled(startPromises);\n\n // 统计启动结果\n let successCount = 0;\n let failureCount = 0;\n const failedServices: string[] = [];\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n if (result.value.success) {\n successCount++;\n } else {\n failureCount++;\n failedServices.push(result.value.serviceName);\n }\n } else {\n failureCount++;\n }\n }\n\n // 记录启动完成统计\n logger.info(\n `[MCPManager] 服务启动完成 - 成功: ${successCount}, 失败: ${failureCount}`\n );\n\n // 记录失败的服务列表\n if (failedServices.length > 0) {\n logger.warn(\n `[MCPManager] 以下服务启动失败: ${failedServices.join(\", \")}`\n );\n\n // 如果所有服务都失败了,发出警告但系统继续运行以便重试\n if (failureCount === configEntries.length) {\n logger.warn(\n \"[MCPManager] 所有 MCP 服务启动失败,但系统将继续运行以便重试\"\n );\n }\n }\n\n // 启动失败服务重试机制\n if (failedServices.length > 0) {\n this.scheduleFailedServicesRetry(failedServices);\n }\n }\n\n /**\n * 启动单个 MCP 服务\n */\n async startService(serviceName: string): Promise<void> {\n const config = this.configs[serviceName];\n if (!config) {\n throw new Error(`未找到服务配置: ${serviceName}`);\n }\n\n try {\n // 如果服务已存在,先停止它\n if (this.services.has(serviceName)) {\n await this.stopService(serviceName);\n }\n\n // 创建 MCPService 实例(使用 InternalMCPServiceConfig)\n const serviceConfig: InternalMCPServiceConfig = {\n name: serviceName,\n ...config,\n };\n const service = new MCPService(serviceConfig);\n\n // 连接到服务\n await service.connect();\n\n // 存储服务实例\n this.services.set(serviceName, service);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 注意:工具缓存刷新现在通过事件监听器自动处理,不需要在这里手动调用\n // MCPService.connect() 成功后会发射 mcp:service:connected 事件\n // 事件监听器会自动触发工具缓存刷新和CustomMCPHandler刷新\n\n const tools = service.getTools();\n logger.debug(\n `[MCPManager] ${serviceName} 服务启动成功,加载了 ${tools.length} 个工具:`,\n tools.map((t) => t.name).join(\", \")\n );\n } catch (error) {\n logger.error(`[MCPManager] 启动 ${serviceName} 服务失败`, {\n error: (error as Error).message,\n });\n // 清理可能的部分状态\n this.services.delete(serviceName);\n throw error;\n }\n }\n\n /**\n * 停止单个服务\n */\n async stopService(serviceName: string): Promise<void> {\n logger.info(`[MCPManager] 停止 MCP 服务: ${serviceName}`);\n\n const service = this.services.get(serviceName);\n if (!service) {\n logger.warn(`[MCPManager] 服务 ${serviceName} 不存在或未启动`);\n return;\n }\n\n try {\n await service.disconnect();\n this.services.delete(serviceName);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n logger.error(`[MCPManager] 停止 ${serviceName} 服务失败`, {\n error: (error as Error).message,\n });\n throw error;\n }\n }\n\n /**\n * 刷新工具缓存\n */\n private async refreshToolsCache(): Promise<void> {\n this.tools.clear();\n\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n const config = this.configs[serviceName];\n\n // 异步写入缓存(不阻塞主流程)\n if (config) {\n this.cacheManager\n .writeCacheEntry(serviceName, tools, config)\n .then(() => {\n logger.debug(`[MCPManager] 已将 ${serviceName} 工具列表写入缓存`);\n })\n .catch((error) => {\n logger.warn(\n `[MCPManager] 写入缓存失败: ${serviceName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n });\n }\n\n // 原有逻辑保持不变\n for (const tool of tools) {\n const toolKey = `${serviceName}__${tool.name}`;\n this.tools.set(toolKey, {\n serviceName,\n originalName: tool.name,\n tool,\n });\n }\n }\n }\n\n // 同步工具配置到配置文件\n await this.syncToolsConfigToFile();\n }\n\n /**\n * 获取所有可用工具\n * @param status 工具状态过滤:'enabled' 仅返回已启用工具,'disabled' 仅返回未启用工具,'all' 返回所有工具\n * @returns 工具数组,包含工具的启用状态信息\n */\n getAllTools(status: ToolStatusFilter = \"all\"): EnhancedToolInfo[] {\n const allTools: EnhancedToolInfo[] = [];\n\n // 1. 收集所有已连接服务的工具(包含启用状态过滤)\n for (const [serviceName, service] of this.services) {\n try {\n if (service.isConnected()) {\n const serviceTools = service.getTools();\n for (const tool of serviceTools) {\n try {\n // 检查工具启用状态 - 这个调用可能会抛出异常\n const isEnabled = configManager.isToolEnabled(\n serviceName,\n tool.name\n );\n const toolConfig =\n configManager.getMcpServerConfig()[serviceName].tools[\n tool.name\n ];\n\n // 根据 status 参数过滤工具\n if (status === \"enabled\" && !isEnabled) {\n continue; // 跳过未启用的工具\n }\n if (status === \"disabled\" && isEnabled) {\n continue; // 跳过已启用的工具\n }\n\n const toolKey = `${serviceName}__${tool.name}`;\n allTools.push({\n name: toolKey,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName,\n originalName: tool.name,\n enabled: isEnabled,\n usageCount: toolConfig.usageCount ?? 0,\n lastUsedTime: toolConfig.lastUsedTime ?? \"\",\n });\n } catch (toolError) {\n logger.warn(\n `[MCPManager] 检查工具 ${serviceName}.${tool.name} 启用状态失败,跳过该工具`,\n { error: toolError }\n );\n }\n }\n }\n } catch (serviceError) {\n logger.warn(\n `[MCPManager] 获取服务 ${serviceName} 的工具失败,跳过该服务`,\n { error: serviceError }\n );\n }\n }\n\n // 2. 添加CustomMCP工具(默认视为已启用)\n let customTools: Tool[] = [];\n try {\n customTools = this.customMCPHandler.getTools();\n logger.debug(\n `[MCPManager] 成功获取 ${customTools.length} 个 customMCP 工具`\n );\n } catch (error) {\n logger.warn(\n \"[MCPManager] 获取 CustomMCP 工具失败,将只返回标准 MCP 工具\",\n { error }\n );\n // 根据技术方案要求,CustomMCP 工具获取失败时不应该影响标准 MCP 工具的返回\n customTools = [];\n }\n\n // CustomMCP 工具默认视为已启用\n if (status !== \"disabled\") {\n for (const tool of customTools) {\n try {\n allTools.push({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName: this.getServiceNameForTool(tool),\n originalName: tool.name,\n enabled: true, // CustomMCP 工具默认启用\n usageCount: 0,\n lastUsedTime: \"\",\n });\n } catch (toolError) {\n logger.warn(\n `[MCPManager] 处理 CustomMCP 工具 ${tool.name} 失败,跳过该工具`,\n { error: toolError }\n );\n }\n }\n }\n\n logger.debug(\n `[MCPManager] 成功获取 ${allTools.length} 个可用工具(status=${status})`\n );\n return allTools;\n }\n\n /**\n * 根据工具配置确定服务名称\n * @param tool 工具对象\n * @returns 服务名称\n */\n private getServiceNameForTool(tool: CustomMCPTool): string {\n if (tool.handler?.type === \"mcp\") {\n // 如果是从 MCP 同步的工具,返回原始服务名称\n const config = tool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.serviceName || \"customMCP\";\n }\n return \"customMCP\";\n }\n\n /**\n * 根据工具信息获取日志记录用的服务名称\n * @param customTool CustomMCP 工具信息\n * @returns 用于日志记录的服务名称\n */\n private getLogServerName(customTool: CustomMCPTool): string {\n if (!customTool?.handler) {\n return \"custom\";\n }\n\n switch (customTool.handler.type) {\n case \"mcp\": {\n const config = customTool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.serviceName || \"customMCP\";\n }\n case \"coze\":\n return \"coze\";\n case \"dify\":\n return \"dify\";\n case \"n8n\":\n return \"n8n\";\n default:\n return \"custom\";\n }\n }\n\n /**\n * 根据工具信息获取原始工具名称\n * @param toolName 格式化后的工具名称\n * @param customTool CustomMCP 工具信息\n * @param toolInfo 标准工具信息\n * @returns 原始工具名称\n */\n private getOriginalToolName(\n toolName: string,\n customTool: CustomMCPTool | undefined,\n toolInfo?: ToolInfo\n ): string {\n if (customTool) {\n // CustomMCP 工具\n if (customTool.handler?.type === \"mcp\") {\n const config = customTool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.toolName || toolName;\n }\n return toolName;\n }\n\n // 标准 MCP 工具\n return toolInfo?.originalName || toolName;\n }\n\n /**\n * 调用 MCP 工具(支持标准 MCP 工具和 customMCP 工具)\n */\n async callTool(\n toolName: string,\n arguments_: Record<string, unknown>,\n options?: { timeout?: number }\n ): Promise<ToolCallResult> {\n const startTime = Date.now();\n\n // 初始化日志信息\n let logServerName = \"unknown\";\n let originalToolName: string = toolName;\n\n try {\n let result: ToolCallResult;\n\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n\n // 设置日志信息(添加空值检查)\n if (customTool) {\n logServerName = this.getLogServerName(customTool);\n originalToolName = this.getOriginalToolName(toolName, customTool);\n }\n\n if (customTool?.handler?.type === \"mcp\") {\n // 对于 mcp 类型的工具,直接路由到对应的 MCP 服务\n result = await this.callMCPTool(\n toolName,\n customTool.handler.config,\n arguments_\n );\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n true\n );\n } else {\n // 其他类型的 customMCP 工具正常处理,传递options参数\n result = await this.customMCPHandler.callTool(\n toolName,\n arguments_,\n options\n );\n logger.info(`[MCPManager] CustomMCP 工具 ${toolName} 调用成功`);\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, true);\n }\n } else {\n // 如果不是 customMCP 工具,则查找标准 MCP 工具\n const toolInfo = this.tools.get(toolName);\n if (!toolInfo) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 设置日志信息\n logServerName = toolInfo.serviceName;\n originalToolName = toolInfo.originalName;\n\n const service = this.services.get(toolInfo.serviceName);\n if (!service) {\n throw new Error(`服务 ${toolInfo.serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${toolInfo.serviceName} 未连接`);\n }\n\n result = (await service.callTool(\n toolInfo.originalName,\n arguments_ || {}\n )) as ToolCallResult;\n\n logger.debug(\"[MCPManager] 工具调用成功\", {\n toolName: toolName,\n result: result,\n });\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n true\n );\n }\n\n // 记录成功的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: result,\n success: result.isError !== true,\n duration: Date.now() - startTime,\n });\n\n return result as ToolCallResult;\n } catch (error) {\n // 记录失败的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: null,\n success: false,\n duration: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 更新失败统计\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n if (customTool?.handler?.type === \"mcp\") {\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n false\n );\n } else {\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, false);\n logger.error(`[MCPManager] CustomMCP 工具 ${toolName} 调用失败`, {\n error: (error as Error).message,\n });\n }\n } else {\n const toolInfo = this.tools.get(toolName);\n if (toolInfo) {\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n false\n );\n logger.error(`[MCPManager] 工具 ${toolName} 调用失败`, {\n error: (error as Error).message,\n });\n }\n }\n\n throw error;\n }\n }\n\n /**\n * 更新工具调用统计信息的通用方法\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStats(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n const currentTime = new Date().toISOString();\n\n if (isSuccess) {\n // 成功调用:更新使用统计\n await this.updateCustomMCPToolStats(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolStats(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n logger.debug(`[MCPManager] 已更新工具 ${toolName} 的统计信息`);\n } else {\n // 失败调用:只更新最后使用时间\n await this.updateCustomMCPToolLastUsedTime(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolLastUsedTime(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n logger.debug(\"[MCPManager] 已更新工具的失败调用统计信息\", {\n toolName,\n });\n }\n } catch (error) {\n logger.error(\"[MCPManager] 更新工具统计信息失败\", { toolName, error });\n throw error;\n }\n }\n\n /**\n * 统一的统计更新处理方法(带错误处理)\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStatsSafe(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n await this.updateToolStats(\n toolName,\n serviceName,\n originalToolName,\n isSuccess\n );\n } catch (error) {\n const action = isSuccess ? \"统计信息\" : \"失败统计信息\";\n logger.warn(\"[MCPManager] 更新工具统计信息失败\", {\n toolName,\n action,\n error,\n });\n // 统计更新失败不应该影响主流程,所以这里只记录警告\n }\n }\n\n /**\n * 更新 customMCP 工具统计信息\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, true);\n logger.debug(`[MCPManager] 已更新 customMCP 工具 ${toolName} 使用统计`);\n } catch (error) {\n logger.error(`[MCPManager] 更新 customMCP 工具 ${toolName} 统计失败`, {\n error,\n });\n throw error;\n }\n }\n\n /**\n * 更新 customMCP 工具最后使用时间\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolLastUsedTime(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, false); // 只更新时间,不增加计数\n logger.debug(\n `[MCPManager] 已更新 customMCP 工具 ${toolName} 最后使用时间`\n );\n } catch (error) {\n logger.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 最后使用时间失败`,\n { error }\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n true\n );\n logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 统计`\n );\n } catch (error) {\n logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 统计失败`,\n { error }\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具最后使用时间\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolLastUsedTime(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n false\n ); // 只更新时间,不增加计数\n logger.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间`\n );\n } catch (error) {\n logger.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间失败`,\n { error }\n );\n throw error;\n }\n }\n\n /**\n * 调用 MCP 工具(用于从 mcpServerConfig 同步的工具)\n * @param toolName 工具名称\n * @param config MCP handler 配置\n * @param arguments_ 工具参数\n */\n private async callMCPTool(\n toolName: string,\n config: { serviceName: string; toolName: string },\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult> {\n const { serviceName, toolName: originalToolName } = config;\n\n logger.debug(\n `[MCPManager] 调用 MCP 同步工具 ${toolName} -> ${serviceName}.${originalToolName}`\n );\n\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`服务 ${serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${serviceName} 未连接`);\n }\n\n try {\n const result = await service.callTool(originalToolName, arguments_ || {});\n logger.debug(`[MCPManager] MCP 同步工具 ${toolName} 调用成功`);\n return result as ToolCallResult;\n } catch (error) {\n logger.error(`[MCPManager] MCP 同步工具 ${toolName} 调用失败`, {\n error: (error as Error).message,\n });\n throw error;\n }\n }\n\n /**\n * 检查是否存在指定工具(包括标准 MCP 工具和 customMCP 工具)\n */\n hasTool(toolName: string): boolean {\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n return true;\n }\n\n // 检查是否是标准 MCP 工具\n return this.tools.has(toolName);\n }\n\n /**\n * 停止所有服务\n */\n async stopAllServices(): Promise<void> {\n logger.info(\"[MCPManager] 正在停止所有 MCP 服务...\");\n\n // 停止所有服务重试\n this.stopAllServiceRetries();\n\n // 停止所有服务实例\n for (const [serviceName, service] of this.services) {\n try {\n await service.disconnect();\n logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n logger.error(`[MCPManager] 停止 ${serviceName} 服务失败`, {\n error: (error as Error).message,\n });\n }\n }\n\n // 清理 CustomMCP 处理器\n try {\n this.customMCPHandler.cleanup();\n logger.info(\"[MCPManager] CustomMCP 处理器已清理\");\n } catch (error) {\n logger.error(\"[MCPManager] CustomMCP 处理器清理失败\", { error });\n }\n\n // 清理统计更新锁\n try {\n configManager.clearAllStatsUpdateLocks();\n logger.info(\"[MCPManager] 统计更新锁已清理\");\n } catch (error) {\n logger.error(\"[MCPManager] 清理统计更新锁失败\", { error });\n }\n\n this.services.clear();\n this.tools.clear();\n\n logger.info(\"[MCPManager] 所有 MCP 服务已停止\");\n }\n\n /**\n * 获取服务器状态(兼容 UnifiedServerStatus 格式)\n */\n getStatus(): UnifiedServerStatus {\n return this.getUnifiedStatus();\n }\n\n /**\n * 获取统计更新监控信息\n */\n getStatsUpdateInfo(): {\n activeLocks: string[];\n totalLocks: number;\n } {\n try {\n const activeLocks = configManager.getStatsUpdateLocks();\n return {\n activeLocks,\n totalLocks: activeLocks.length,\n };\n } catch (error) {\n logger.warn(\"[MCPManager] 获取统计更新监控信息失败\", { error });\n return {\n activeLocks: [],\n totalLocks: 0,\n };\n }\n }\n\n /**\n * 获取指定服务实例\n */\n getService(name: string): MCPService | undefined {\n return this.services.get(name);\n }\n\n /**\n * 获取所有已连接的服务名称\n */\n getConnectedServices(): string[] {\n const connectedServices: string[] = [];\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connectedServices.push(serviceName);\n }\n }\n return connectedServices;\n }\n\n /**\n * 刷新CustomMCPHandler的私有方法\n */\n private async refreshCustomMCPHandler(): Promise<void> {\n try {\n logger.debug(\"重新初始化CustomMCPHandler\");\n this.customMCPHandler.initialize();\n logger.debug(\"CustomMCPHandler重新初始化完成\");\n } catch (error) {\n logger.error(\"CustomMCPHandler重新初始化失败\", { error });\n throw error;\n }\n }\n\n /**\n * 公开的CustomMCPHandler刷新方法,供外部调用\n */\n async refreshCustomMCPHandlerPublic(): Promise<void> {\n return this.refreshCustomMCPHandler();\n }\n\n /**\n * 获取所有服务实例\n */\n getAllServices(): Map<string, MCPService> {\n return new Map(this.services);\n }\n\n /**\n * 获取 CustomMCP 处理器实例\n */\n getCustomMCPHandler(): CustomMCPHandler {\n return this.customMCPHandler;\n }\n\n /**\n * 检查指定的 customMCP 工具是否存在\n * @param toolName 工具名称\n * @returns 如果工具存在返回 true,否则返回 false\n */\n hasCustomMCPTool(toolName: string): boolean {\n try {\n return this.customMCPHandler.hasTool(toolName);\n } catch (error) {\n logger.warn(`[MCPManager] 检查 CustomMCP 工具 ${toolName} 是否存在失败`, {\n error,\n });\n // 异常情况下返回 false,表示工具不存在\n return false;\n }\n }\n\n /**\n * 获取所有 customMCP 工具列表\n * @returns customMCP 工具数组\n */\n getCustomMCPTools(): Tool[] {\n try {\n return this.customMCPHandler.getTools();\n } catch (error) {\n logger.warn(\"[MCPManager] 获取 CustomMCP 工具列表失败,返回空数组\", {\n error,\n });\n // 异常情况下返回空数组,避免影响调用方\n return [];\n }\n }\n\n /**\n * 检查是否为 ModelScope 服务\n * 统一使用 ConfigAdapter 的 isModelScopeURL 函数\n */\n private isModelScopeService(config: MCPServiceConfig): boolean {\n return config.url ? isModelScopeURL(config.url) : false;\n }\n\n /**\n * 处理 ModelScope 服务认证\n * 智能检查现有认证信息,按优先级处理\n */\n private handleModelScopeAuth(\n serviceName: string,\n originalConfig: MCPServiceConfig,\n enhancedConfig: MCPServiceConfig\n ): void {\n // 1. 检查是否已有 Authorization header\n const existingAuthHeader = originalConfig.headers?.Authorization;\n\n if (existingAuthHeader) {\n // 已有认证信息,直接使用\n logger.info(\n `[MCPManager] 服务 ${serviceName} 使用已有的 Authorization header`\n );\n return;\n }\n\n // 2. 检查全局 ModelScope API Key\n const modelScopeApiKey = configManager.getModelScopeApiKey();\n\n if (modelScopeApiKey) {\n // 注入全局 API Key\n enhancedConfig.apiKey = modelScopeApiKey;\n logger.info(`[MCPManager] 为 ${serviceName} 服务添加 ModelScope API Key`);\n return;\n }\n\n // 3. 无法获取认证信息,提供详细错误信息\n const serviceUrl = originalConfig.url || \"未知\";\n\n throw new Error(\n `ModelScope 服务 \"${serviceName}\" 需要认证信息,但未找到有效的认证配置。服务 URL: ${serviceUrl}请选择以下任一方式配置认证:1. 在服务配置中添加 headers.Authorization2. 或者在全局配置中设置 modelscope.apiKey3. 或者设置环境变量 MODELSCOPE_API_TOKEN获取 ModelScope API Key: https://modelscope.cn/my?myInfo=true`\n );\n }\n\n /**\n * 增强服务配置\n * 根据服务类型添加必要的全局配置,智能处理认证信息\n */\n private enhanceServiceConfig(\n serviceName: string,\n config: MCPServiceConfig\n ): MCPServiceConfig {\n const enhancedConfig = { ...config };\n\n try {\n // 处理 ModelScope 服务(智能认证检查)\n if (this.isModelScopeService(config)) {\n this.handleModelScopeAuth(serviceName, config, enhancedConfig);\n }\n\n return enhancedConfig;\n } catch (error) {\n logger.error(`[MCPManager] 配置增强失败: ${serviceName}`, { error });\n throw error;\n }\n }\n\n /**\n * 添加服务配置(重载方法以支持两种调用方式)\n */\n addServiceConfig(name: string, config: MCPServiceConfig): void;\n addServiceConfig(config: InternalMCPServiceConfig): void;\n addServiceConfig(\n nameOrConfig: string | MCPServiceConfig | InternalMCPServiceConfig,\n config?: MCPServiceConfig\n ): void {\n let finalConfig: MCPServiceConfig;\n let serviceName: string;\n\n if (typeof nameOrConfig === \"string\" && config) {\n // 两参数版本\n serviceName = nameOrConfig;\n finalConfig = config;\n } else if (typeof nameOrConfig === \"object\") {\n // 单参数版本(使用 InternalMCPServiceConfig)\n const internalConfig = nameOrConfig as InternalMCPServiceConfig;\n serviceName = internalConfig.name;\n finalConfig = internalConfig;\n } else {\n throw new Error(\"Invalid arguments for addServiceConfig\");\n }\n\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(serviceName, finalConfig);\n\n // 存储增强后的配置\n this.configs[serviceName] = enhancedConfig;\n logger.debug(`[MCPManager] 已添加服务配置: ${serviceName}`);\n }\n\n /**\n * 更新服务配置\n */\n updateServiceConfig(name: string, config: MCPServiceConfig): void {\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(name, config);\n\n // 存储增强后的配置\n this.configs[name] = enhancedConfig;\n logger.debug(`[MCPManager] 已更新并增强服务配置: ${name}`);\n }\n\n /**\n * 移除服务配置\n */\n removeServiceConfig(name: string): void {\n delete this.configs[name];\n logger.debug(`[MCPManager] 已移除服务配置: ${name}`);\n }\n\n /**\n * 同步工具配置到配置文件\n * 实现自动同步 MCP 服务工具配置到 xiaozhi.config.json\n */\n private async syncToolsConfigToFile(): Promise<void> {\n try {\n logger.debug(\"[MCPManager] 开始同步工具配置到配置文件\");\n\n // 获取当前配置文件中的 mcpServerConfig\n const currentServerConfigs = configManager.getMcpServerConfig();\n\n // 遍历所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (!service.isConnected()) {\n continue;\n }\n\n const tools = service.getTools();\n if (tools.length === 0) {\n continue;\n }\n\n // 获取当前服务在配置文件中的工具配置\n const currentToolsConfig =\n currentServerConfigs[serviceName]?.tools || {};\n\n // 构建新的工具配置\n const newToolsConfig: Record<string, MCPToolConfig> = {};\n\n for (const tool of tools) {\n const currentToolConfig = currentToolsConfig[tool.name];\n\n // 如果工具已存在,保留用户设置的 enable 状态,但更新描述\n if (currentToolConfig) {\n newToolsConfig[tool.name] = {\n ...currentToolConfig,\n description:\n tool.description || currentToolConfig.description || \"\",\n };\n } else {\n // 新工具,默认启用\n newToolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: true,\n };\n }\n }\n\n // 检查是否有工具被移除(在配置文件中存在但在当前工具列表中不存在)\n const currentToolNames = tools.map((t) => t.name);\n const configToolNames = Object.keys(currentToolsConfig);\n const removedTools = configToolNames.filter(\n (name) => !currentToolNames.includes(name)\n );\n\n if (removedTools.length > 0) {\n logger.info(\n `[MCPManager] 检测到服务 ${serviceName} 移除了 ${\n removedTools.length\n } 个工具: ${removedTools.join(\", \")}`\n );\n }\n\n // 检查配置是否有变化\n const hasChanges = this.hasToolsConfigChanged(\n currentToolsConfig,\n newToolsConfig\n );\n\n if (hasChanges) {\n // 更新配置文件\n configManager.updateServerToolsConfig(serviceName, newToolsConfig);\n\n const addedTools = Object.keys(newToolsConfig).filter(\n (name) => !currentToolsConfig[name]\n );\n const updatedTools = Object.keys(newToolsConfig).filter((name) => {\n const current = currentToolsConfig[name];\n const updated = newToolsConfig[name];\n return current && current.description !== updated.description;\n });\n\n logger.debug(`[MCPManager] 已同步服务 ${serviceName} 的工具配置:`);\n if (addedTools.length > 0) {\n logger.debug(` - 新增工具: ${addedTools.join(\", \")}`);\n }\n if (updatedTools.length > 0) {\n logger.debug(` - 更新工具: ${updatedTools.join(\", \")}`);\n }\n if (removedTools.length > 0) {\n logger.debug(` - 移除工具: ${removedTools.join(\", \")}`);\n }\n }\n }\n\n logger.debug(\"[MCPManager] 工具配置同步完成\");\n } catch (error) {\n logger.error(\"[MCPManager] 同步工具配置到配置文件失败\", { error });\n // 不抛出错误,避免影响服务正常运行\n }\n }\n\n /**\n * 检查工具配置是否有变化\n */\n private hasToolsConfigChanged(\n currentConfig: Record<string, MCPToolConfig>,\n newConfig: Record<string, MCPToolConfig>\n ): boolean {\n const currentKeys = Object.keys(currentConfig);\n const newKeys = Object.keys(newConfig);\n\n // 检查工具数量是否变化\n if (currentKeys.length !== newKeys.length) {\n return true;\n }\n\n // 检查是否有新增或删除的工具\n const addedTools = newKeys.filter((key) => !currentKeys.includes(key));\n const removedTools = currentKeys.filter((key) => !newKeys.includes(key));\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n return true;\n }\n\n // 检查现有工具的描述是否有变化\n for (const toolName of currentKeys) {\n const currentTool = currentConfig[toolName];\n const newTool = newConfig[toolName];\n\n if (currentTool.description !== newTool.description) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 安排失败服务的重试\n * @param failedServices 失败的服务列表\n */\n private scheduleFailedServicesRetry(failedServices: string[]): void {\n if (failedServices.length === 0) return;\n\n // 记录重试安排\n logger.info(`[MCPManager] 安排 ${failedServices.length} 个失败服务的重试`);\n\n // 初始重试延迟:30秒\n const initialDelay = 30000;\n\n for (const serviceName of failedServices) {\n this.failedServices.add(serviceName);\n this.scheduleServiceRetry(serviceName, initialDelay);\n }\n }\n\n /**\n * 安排单个服务的重试\n * @param serviceName 服务名称\n * @param delay 延迟时间(毫秒)\n */\n private scheduleServiceRetry(serviceName: string, delay: number): void {\n // 清除现有定时器\n const existingTimer = this.retryTimers.get(serviceName);\n if (existingTimer) {\n clearTimeout(existingTimer);\n this.retryTimers.delete(serviceName);\n }\n\n logger.debug(`[MCPManager] 安排服务 ${serviceName} 在 ${delay}ms 后重试`);\n\n const timer = setTimeout(async () => {\n this.retryTimers.delete(serviceName);\n await this.retryFailedService(serviceName);\n }, delay);\n\n this.retryTimers.set(serviceName, timer);\n }\n\n /**\n * 重试失败的服务\n * @param serviceName 服务名称\n */\n private async retryFailedService(serviceName: string): Promise<void> {\n if (!this.failedServices.has(serviceName)) {\n return; // 服务已经成功启动或不再需要重试\n }\n\n try {\n await this.startService(serviceName);\n\n // 重试成功\n this.failedServices.delete(serviceName);\n logger.info(`[MCPManager] 服务 ${serviceName} 重试启动成功`);\n\n // 重新初始化CustomMCPHandler以包含新启动的服务工具\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n logger.error(\"[MCPManager] 刷新CustomMCPHandler失败\", { error });\n }\n } catch (error) {\n logger.error(`[MCPManager] 服务 ${serviceName} 重试启动失败`, {\n error: (error as Error).message,\n });\n\n // 指数退避重试策略:延迟时间翻倍,最大不超过5分钟\n const currentDelay = this.getRetryDelay(serviceName);\n const nextDelay = Math.min(currentDelay * 2, 300000); // 最大5分钟\n\n logger.debug(\n `[MCPManager] 服务 ${serviceName} 下次重试将在 ${nextDelay}ms 后进行`\n );\n\n this.scheduleServiceRetry(serviceName, nextDelay);\n }\n }\n\n /**\n * 获取当前重试延迟时间\n * @param serviceName 服务名称\n * @returns 当前延迟时间\n */\n private getRetryDelay(serviceName: string): number {\n // 这里可以实现更复杂的状态跟踪来计算准确的延迟\n // 简化实现:返回一个基于服务名称的哈希值的初始延迟\n const hash = serviceName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n return 30000 + (hash % 60000); // 30-90秒之间的初始延迟\n }\n\n /**\n * 停止指定服务的重试\n * @param serviceName 服务名称\n */\n public stopServiceRetry(serviceName: string): void {\n const timer = this.retryTimers.get(serviceName);\n if (timer) {\n clearTimeout(timer);\n this.retryTimers.delete(serviceName);\n logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n this.failedServices.delete(serviceName);\n }\n\n /**\n * 停止所有服务的重试\n */\n public stopAllServiceRetries(): void {\n logger.info(\"[MCPManager] 停止所有服务重试\");\n\n for (const [serviceName, timer] of this.retryTimers) {\n clearTimeout(timer);\n logger.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n\n this.retryTimers.clear();\n this.failedServices.clear();\n }\n\n /**\n * 获取失败服务列表\n * @returns 失败的服务名称数组\n */\n public getFailedServices(): string[] {\n return Array.from(this.failedServices);\n }\n\n /**\n * 检查服务是否失败\n * @param serviceName 服务名称\n * @returns 如果服务失败返回true\n */\n public isServiceFailed(serviceName: string): boolean {\n return this.failedServices.has(serviceName);\n }\n\n /**\n * 获取重试统计信息\n * @returns 重试统计信息\n */\n public getRetryStats(): {\n failedServices: string[];\n activeRetries: string[];\n totalFailed: number;\n totalActiveRetries: number;\n } {\n return {\n failedServices: Array.from(this.failedServices),\n activeRetries: Array.from(this.retryTimers.keys()),\n totalFailed: this.failedServices.size,\n totalActiveRetries: this.retryTimers.size,\n };\n }\n\n /**\n * 获取消息处理器(供外部使用)\n * @returns 消息处理器实例\n */\n public getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 启动管理器\n */\n public async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error(\"服务器已在运行\");\n }\n\n logger.info(\"启动 MCP 服务管理器\");\n\n try {\n await this.startAllServices();\n this.isRunning = true;\n\n logger.info(\"MCP 服务管理器启动成功\");\n this.emit(\"started\");\n } catch (error) {\n logger.error(\"MCP 服务管理器启动失败\", { error });\n throw error;\n }\n }\n\n /**\n * 停止管理器(包含传输和服务)\n */\n public async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n logger.info(\"停止 MCP 服务管理器\");\n\n try {\n await this.stopAllServices();\n this.isRunning = false;\n\n logger.info(\"MCP 服务管理器停止成功\");\n this.emit(\"stopped\");\n } catch (error) {\n logger.error(\"MCP 服务管理器停止失败\", { error });\n throw error;\n }\n }\n\n /**\n * 获取所有连接信息\n * @returns 连接信息列表\n */\n public getAllConnections(): Array<{\n id: string;\n name: string;\n state: ConnectionState;\n }> {\n const connections: Array<{\n id: string;\n name: string;\n state: ConnectionState;\n }> = [];\n\n // 收集服务连接\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connections.push({\n id: `service-${serviceName}`,\n name: serviceName,\n state: ConnectionState.CONNECTED,\n });\n }\n }\n\n return connections;\n }\n\n /**\n * 获取活跃连接数\n * @returns 活跃连接数量\n */\n public getActiveConnectionCount(): number {\n return this.getAllConnections().filter(\n (conn) => conn.state === ConnectionState.CONNECTED\n ).length;\n }\n\n // ===== 从 UnifiedMCPServer 移入的方法 =====\n\n /**\n * 获取服务器状态(从 UnifiedMCPServer 移入)\n */\n getUnifiedStatus(): UnifiedServerStatus {\n const serviceStatus = this.getServiceManagerStatus();\n return {\n isRunning: this.isRunning,\n serviceStatus,\n activeConnections: this.getActiveConnectionCount(),\n config: this.config,\n // 便捷访问属性\n services: serviceStatus.services,\n totalTools: serviceStatus.totalTools,\n availableTools: serviceStatus.availableTools,\n };\n }\n\n /**\n * 获取管理器状态(原有的 getStatus 方法重命名)\n */\n getServiceManagerStatus(): ManagerStatus {\n // 计算总工具数量(包括 customMCP 工具,添加异常处理)\n let customMCPToolCount = 0;\n let customToolNames: string[] = [];\n\n try {\n customMCPToolCount = this.customMCPHandler.getToolCount();\n customToolNames = this.customMCPHandler.getToolNames();\n logger.debug(\n `[MCPManager] 成功获取 customMCP 状态: ${customMCPToolCount} 个工具`\n );\n } catch (error) {\n logger.warn(\n \"[MCPManager] 获取 CustomMCP 状态失败,将只包含标准 MCP 工具\",\n { error }\n );\n // 异常情况下,customMCP 工具数量为0,不影响标准 MCP 工具\n customMCPToolCount = 0;\n customToolNames = [];\n }\n\n const totalTools = this.tools.size + customMCPToolCount;\n\n // 获取所有可用工具名称\n const standardToolNames = Array.from(this.tools.keys());\n const availableTools = [...standardToolNames, ...customToolNames];\n\n const status: ManagerStatus = {\n services: {},\n totalTools,\n availableTools,\n };\n\n // 添加标准 MCP 服务状态\n for (const [serviceName, service] of this.services) {\n const serviceStatus = service.getStatus();\n status.services[serviceName] = {\n connected: serviceStatus.connected,\n clientName: `xiaozhi-${serviceName}-client`,\n };\n }\n\n // 添加 CustomMCP 服务状态\n if (customMCPToolCount > 0) {\n status.services.customMCP = {\n connected: true, // CustomMCP 工具总是可用的\n clientName: \"xiaozhi-customMCP-handler\",\n };\n }\n\n return status;\n }\n\n /**\n * 检查服务器是否正在运行(从 UnifiedMCPServer 移入)\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n\n /**\n * 类型守卫:检查是否为 UnifiedServerConfig\n */\n private isUnifiedServerConfig(\n configs: unknown\n ): configs is UnifiedServerConfig {\n return (\n configs !== null && typeof configs === \"object\" && \"configs\" in configs\n );\n }\n\n /**\n * 消息路由核心功能(从 UnifiedMCPServer 移入)\n */\n async routeMessage(message: MCPMessage): Promise<MCPMessage | null> {\n const response = await this.messageHandler.handleMessage(message);\n // 如果响应是 null,直接返回\n if (response === null) {\n return null;\n }\n // 将 MCPResponse 转换为 MCPMessage 格式\n return {\n jsonrpc: \"2.0\",\n method: \"response\", // 标识这是一个响应消息\n params: response,\n id: response.id, // 使用响应中的ID\n };\n }\n\n // ===== 向后兼容方法 =====\n\n /**\n * 初始化方法(向后兼容,实际调用 start)\n *\n * 注意:此方法仅为向后兼容而保留\n * 实际功能:调用 start() 方法并设置 isRunning 状态\n * 建议新代码直接使用 start() 方法\n */\n async initialize(): Promise<void> {\n // 为了向后兼容,初始化时调用 start\n // 会设置 isRunning 状态为 true\n await this.start();\n }\n\n /**\n * 获取工具注册表(向后兼容,返回自身)\n */\n getToolRegistry(): MCPServiceManager {\n return this;\n }\n\n /**\n * 获取连接管理器(向后兼容,返回自身)\n */\n getConnectionManager(): MCPServiceManager {\n return this;\n }\n\n /**\n * 清理资源(实现 IMCPServiceManager 接口)\n *\n * 注意:此方法会停止所有 MCP 服务\n */\n async cleanup(): Promise<void> {\n await this.stopAllServices();\n\n // 清理事件监听器,防止内存泄漏\n this.eventBus.offEvent(\n \"mcp:service:connected\",\n this.eventListeners.serviceConnected\n );\n this.eventBus.offEvent(\n \"mcp:service:disconnected\",\n this.eventListeners.serviceDisconnected\n );\n this.eventBus.offEvent(\n \"mcp:service:connection:failed\",\n this.eventListeners.serviceConnectionFailed\n );\n }\n}\n","/**\n * MCP 核心库类型定义\n * 统一管理所有 MCP 相关的类型定义,避免重复定义和导入路径混乱\n */\n\nimport type { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\n\n// =========================\n// 1. 基础传输类型\n// =========================\n\n/**\n * MCP 传输层联合类型定义\n * 支持 STDIO、SSE、StreamableHTTP 三种传输协议\n */\nexport type MCPServerTransport =\n | StdioClientTransport\n | SSEClientTransport\n | StreamableHTTPClientTransport;\n\n/**\n * 通信方式枚举\n * 定义 MCP 支持的传输类型\n */\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n HTTP = \"http\",\n}\n\n// =========================\n// 2. 配置接口类型\n// =========================\n\n/**\n * ModelScope SSE 自定义选项接口\n * 专门用于 ModelScope 相关的 SSE 配置\n */\nexport interface ModelScopeSSEOptions {\n eventSourceInit?: {\n fetch?: (\n url: string | URL | Request,\n init?: RequestInit\n ) => Promise<Response>;\n };\n requestInit?: RequestInit;\n}\n\n/**\n * MCP 服务配置接口\n * 包含所有 MCP 服务的配置选项\n *\n * 注意:符合 @modelcontextprotocol 官方标准,不包含 name 字段\n * name 应该作为服务标识符独立管理,不是配置的一部分\n */\nexport interface MCPServiceConfig {\n type?: MCPTransportType; // 现在是可选的,支持自动推断\n // stdio 配置\n command?: string;\n args?: string[];\n env?: Record<string, string>; // 环境变量配置\n // 网络配置\n url?: string;\n // 认证配置\n apiKey?: string;\n headers?: Record<string, string>;\n customSSEOptions?: ModelScopeSSEOptions;\n}\n\n/**\n * 内部使用的 MCP 服务配置接口(包含 name 字段)\n * 用于 MCPService 类等内部函数,保持向后兼容\n */\nexport interface InternalMCPServiceConfig extends MCPServiceConfig {\n name: string;\n}\n\n// =========================\n// 3. 状态枚举类型\n// =========================\n\n/**\n * 连接状态枚举\n * 合并了 connection.ts 和 TransportAdapter.ts 中的定义\n */\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n ERROR = \"error\", // 从 TransportAdapter.ts 合并的额外状态\n}\n\n/**\n * MCP 服务状态接口\n * 描述 MCP 服务的运行时状态信息\n */\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n connectionState: ConnectionState;\n}\n\n// =========================\n// 4. 工具调用相关类型\n// =========================\n\n/**\n * 工具调用结果接口\n * 使用简化的类型定义,保持向后兼容性\n * 注意:这与 @xiaozhi-client/mcp-core 中的 ToolCallResult 类型不同\n */\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n [key: string]: unknown; // 支持其他未知字段,与 endpoint 包保持兼容\n}\n\n/**\n * JSON Schema 类型定义\n * 兼容 MCP SDK 的 JSON Schema 格式,同时支持更宽松的对象格式以保持向后兼容\n */\nexport type JSONSchema =\n | (Record<string, unknown> & {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n })\n | Record<string, unknown>; // 允许更宽松的格式以保持向后兼容\n\n/**\n * 类型守卫:检查对象是否为有效的 MCP Tool JSON Schema\n */\nexport function isValidToolJSONSchema(obj: unknown): obj is {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"type\" in obj &&\n (obj as { type?: unknown }).type === \"object\"\n );\n}\n\n/**\n * 确保对象符合 MCP Tool JSON Schema 格式\n * 如果不符合,会返回一个默认的空对象 schema\n */\nexport function ensureToolJSONSchema(schema: JSONSchema): {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n if (isValidToolJSONSchema(schema)) {\n return schema as {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n };\n }\n\n // 如果不符合标准格式,返回默认的空对象 schema\n return {\n type: \"object\",\n properties: {} as Record<string, object>,\n required: [],\n additionalProperties: true,\n };\n}\n\n/**\n * CustomMCP 工具类型定义\n * 统一了 manager.ts 和 configManager.ts 中的定义\n */\nexport interface CustomMCPTool {\n name: string;\n description?: string;\n inputSchema: JSONSchema;\n handler?: {\n type: string;\n config?: Record<string, unknown>;\n };\n}\n\n/**\n * 工具信息接口\n * 用于缓存工具映射关系,保持向后兼容性\n */\nexport interface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// =========================\n// 5. 增强工具信息类型\n// =========================\n\n/**\n * 工具状态过滤选项\n * 用于 getAllTools() 方法过滤不同状态的工具\n */\nexport type ToolStatusFilter = \"enabled\" | \"disabled\" | \"all\";\n\n/**\n * 增强的工具信息接口\n * 扩展自 ToolInfo 概念,包含工具的启用状态和使用统计信息\n *\n * @remarks\n * 此接口用于 MCPServiceManager.getAllTools() 方法的返回值,\n * 提供比基础 ToolInfo 更丰富的工具元数据信息。\n *\n * @example\n * ```typescript\n * const tools: EnhancedToolInfo[] = manager.getAllTools('enabled');\n * tools.forEach(tool => {\n * console.log(`工具: ${tool.name}`);\n * console.log(`状态: ${tool.enabled ? '已启用' : '已禁用'}`);\n * console.log(`使用次数: ${tool.usageCount}`);\n * });\n * ```\n */\nexport interface EnhancedToolInfo {\n /** 工具唯一标识符,格式为 \"{serviceName}__{originalName}\" */\n name: string;\n\n /** 工具描述信息 */\n description: string;\n\n /** 工具输入参数的 JSON Schema 定义 */\n inputSchema: JSONSchema;\n\n /** 工具所属的 MCP 服务名称 */\n serviceName: string;\n\n /** 工具在 MCP 服务中的原始名称 */\n originalName: string;\n\n /** 工具是否启用 (true=已启用,false=已禁用) */\n enabled: boolean;\n\n /** 工具使用次数统计 */\n usageCount: number;\n\n /** 工具最后使用时间 (ISO 8601 格式字符串) */\n lastUsedTime: string;\n}\n\n// =========================\n// 6. 服务器配置类型\n// =========================\n\n/**\n * 统一服务器配置接口\n * 从 UnifiedMCPServer 移入,用于统一服务器配置管理\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n configs?: Record<string, MCPServiceConfig>; // MCPService 配置\n}\n\n/**\n * 统一服务器状态接口\n * 从 UnifiedMCPServer 移入,用于统一服务器状态管理\n */\nexport interface UnifiedServerStatus {\n isRunning: boolean;\n serviceStatus: ManagerStatus;\n activeConnections: number;\n config: UnifiedServerConfig;\n // 添加对 serviceStatus 的便捷访问属性\n services?: Record<string, MCPServiceConnectionStatus>;\n totalTools?: number;\n availableTools?: string[];\n}\n\n// =========================\n// 6. 管理器相关类型\n// =========================\n\n/**\n * MCP 服务连接状态接口\n * 重命名原 ServiceStatus 为 MCPServiceConnectionStatus 避免与 CLI 的 ServiceStatus 冲突\n */\nexport interface MCPServiceConnectionStatus {\n connected: boolean;\n clientName: string;\n}\n\n/**\n * 管理器状态接口\n * 描述 MCP 服务管理器的整体状态\n */\nexport interface ManagerStatus {\n services: Record<string, MCPServiceConnectionStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// =========================\n// 7. 参数校验相关类型\n// =========================\n\n/**\n * 工具调用参数接口\n * 定义标准工具调用参数结构\n */\nexport interface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 验证后的工具调用参数\n * 参数校验通过后的标准化参数结构\n */\nexport interface ValidatedToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 工具调用验证选项\n * 提供灵活的参数校验配置\n */\nexport interface ToolCallValidationOptions {\n /** 是否验证工具名称,默认为 true */\n validateName?: boolean;\n /** 是否验证参数格式,默认为 true */\n validateArguments?: boolean;\n /** 是否允许空参数,默认为 true */\n allowEmptyArguments?: boolean;\n /** 自定义验证函数 */\n customValidator?: (params: ToolCallParams) => string | null;\n}\n\n/**\n * 工具调用错误码枚举\n * 统一的工具调用错误码定义\n */\nexport enum ToolCallErrorCode {\n /** 无效参数 */\n INVALID_PARAMS = -32602,\n /** 工具不存在 */\n TOOL_NOT_FOUND = -32601,\n /** 服务不可用 */\n SERVICE_UNAVAILABLE = -32001,\n /** 调用超时 */\n TIMEOUT = -32002,\n /** 工具执行错误 */\n TOOL_EXECUTION_ERROR = -32000,\n}\n\n/**\n * 工具调用错误类\n * 统一的工具调用错误处理\n */\nexport class ToolCallError extends Error {\n constructor(\n public code: ToolCallErrorCode,\n message: string,\n public data?: unknown\n ) {\n super(message);\n this.name = \"ToolCallError\";\n }\n}\n\n// =========================\n// 向后兼容性别名\n// =========================\n\n/**\n * 向后兼容:ServiceStatus 别名\n * 为了与现有代码保持兼容,暂时保留此别名\n * @deprecated 请使用 MCPServiceConnectionStatus\n */\nexport type ServiceStatus = MCPServiceConnectionStatus;\n","/**\n * MCP 相关类型定义\n *\n * 定义了与 MCP(Model Context Protocol)相关的所有类型,包括:\n * - 工具调用结果和响应格式\n * - JSON-RPC 2.0 消息和错误类型\n * - MCP 工具缓存相关类型和工具函数\n * - 超时处理和任务状态管理\n *\n * @module types/mcp\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { MCPToolsCache } from \"@/lib/mcp\";\nimport type { TimeoutResponse } from \"./timeout.js\";\n\n// 工具调用结果接口(与 MCPServiceManager 保持一致)\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n [key: string]: unknown; // 支持其他未知字段,与 lib/mcp/types 保持兼容\n}\n\n// MCP 消息接口 - 定义 JSON-RPC 2.0 标准消息格式\nexport interface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: unknown;\n id: string | number;\n}\n\n// MCP 响应接口 - 定义 JSON-RPC 2.0 标准响应格式\nexport interface MCPResponse {\n jsonrpc: \"2.0\";\n id: string | number;\n result?: unknown;\n error?: MCPError;\n}\n\n// MCP 错误接口 - 定义 JSON-RPC 2.0 标准错误格式\nexport interface MCPError {\n code: number;\n message: string;\n data?: unknown;\n}\n\n/**\n * 扩展的 MCP 工具缓存接口\n * 增加对 CustomMCP 执行结果的支持\n */\nexport interface ExtendedMCPToolsCache extends MCPToolsCache {\n customMCPResults?: Record<string, EnhancedToolResultCache>; // 增强的工具执行结果缓存\n}\n\n/**\n * 增强的工具执行结果缓存\n * 用于存储 CustomMCP 工具的执行结果和状态\n */\nexport interface EnhancedToolResultCache {\n result: ToolCallResult;\n timestamp: string; // ISO 8601 格式时间戳\n ttl: number; // 过期时间(毫秒)\n status: TaskStatus; // 任务状态\n consumed: boolean; // 是否已被消费(一次性缓存机制)\n taskId?: string; // 任务ID,用于查询\n retryCount: number; // 重试次数\n}\n\n/**\n * 任务状态类型\n */\nexport type TaskStatus =\n | \"pending\"\n | \"completed\"\n | \"failed\"\n | \"consumed\"\n | \"deleted\";\n\n/**\n * 缓存状态转换接口\n */\nexport interface CacheStateTransition {\n from: TaskStatus;\n to: TaskStatus;\n reason: string;\n timestamp: string;\n}\n\n/**\n * 工具调用选项\n */\nexport interface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n retries?: number; // 重试次数\n retryDelay?: number; // 重试延迟(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 缓存配置选项\n */\nexport interface CacheConfig {\n ttl?: number; // 缓存过期时间(毫秒),默认5分钟\n cleanupInterval?: number; // 清理间隔(毫秒),默认1分钟\n maxCacheSize?: number; // 最大缓存条目数\n enableOneTimeCache?: boolean; // 是否启用一次性缓存\n}\n\n/**\n * 超时配置选项\n */\nexport interface TimeoutConfig {\n timeout?: number; // 超时时间(毫秒),默认8秒\n enableFriendlyTimeout?: boolean; // 是否启用友好超时响应\n backgroundProcessing?: boolean; // 是否启用后台处理\n}\n\n/**\n * 任务信息接口\n */\nexport interface TaskInfo {\n taskId: string;\n toolName: string;\n arguments: Record<string, unknown>;\n status: TaskStatus;\n startTime: string;\n endTime?: string;\n error?: string;\n result?: ToolCallResult;\n}\n\n/**\n * 缓存统计信息\n */\nexport interface CacheStatistics {\n totalEntries: number;\n pendingTasks: number;\n completedTasks: number;\n failedTasks: number;\n consumedEntries: number;\n cacheHitRate: number;\n lastCleanupTime: string;\n memoryUsage: number;\n}\n\n/**\n * 工具调用结果联合类型\n * 包含正常结果和超时响应\n */\nexport type ToolCallResponse = ToolCallResult | TimeoutResponse;\n\n/**\n * 验证是否为工具调用结果\n */\nexport function isToolCallResult(\n response: unknown\n): response is ToolCallResult {\n return (\n !!response &&\n typeof response === \"object\" &&\n response !== null &&\n \"content\" in response &&\n Array.isArray((response as ToolCallResult).content) &&\n (response as ToolCallResult).content.length > 0 &&\n (response as ToolCallResult).content[0]?.type === \"text\" &&\n typeof (response as ToolCallResult).content[0]?.text === \"string\"\n );\n}\n\n/**\n * 验证是否为增强的工具结果缓存\n */\nexport function isEnhancedToolResultCache(\n cache: unknown\n): cache is EnhancedToolResultCache {\n const cacheObj = cache as EnhancedToolResultCache;\n return (\n !!cache &&\n typeof cache === \"object\" &&\n cache !== null &&\n typeof cacheObj.timestamp === \"string\" &&\n typeof cacheObj.ttl === \"number\" &&\n typeof cacheObj.status === \"string\" &&\n [\"completed\", \"pending\", \"failed\", \"consumed\"].includes(cacheObj.status) &&\n typeof cacheObj.consumed === \"boolean\" &&\n typeof cacheObj.retryCount === \"number\"\n );\n}\n\n/**\n * 验证是否为扩展的 MCP 工具缓存\n */\nexport function isExtendedMCPToolsCache(\n cache: unknown\n): cache is ExtendedMCPToolsCache {\n const cacheObj = cache as ExtendedMCPToolsCache;\n return (\n !!cache &&\n typeof cache === \"object\" &&\n cache !== null &&\n typeof cacheObj.version === \"string\" &&\n typeof cacheObj.mcpServers === \"object\" &&\n cacheObj.mcpServers !== null &&\n typeof cacheObj.metadata === \"object\" &&\n cacheObj.metadata !== null\n );\n}\n\n/**\n * 生成缓存键的工具函数\n */\nexport function generateCacheKey(\n toolName: string,\n arguments_: Record<string, unknown>\n): string {\n const argsHash = createHash(\"md5\")\n .update(JSON.stringify(arguments_ || {}))\n .digest(\"hex\");\n return `${toolName}_${argsHash}`;\n}\n\n/**\n * 格式化时间戳的工具函数\n */\nexport function formatTimestamp(timestamp: number | Date = Date.now()): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * 检查缓存是否过期\n */\nexport function isCacheExpired(timestamp: string, ttl: number): boolean {\n const cachedTime = new Date(timestamp).getTime();\n const now = Date.now();\n return now - cachedTime > ttl;\n}\n\n/**\n * 检查是否应该清理缓存条目\n */\nexport function shouldCleanupCache(cache: EnhancedToolResultCache): boolean {\n const now = Date.now();\n const cachedTime = new Date(cache.timestamp).getTime();\n\n // 已消费且超过清理时间(1分钟)\n if (cache.consumed && now - cachedTime > DEFAULT_CONFIG.CLEANUP_INTERVAL) {\n return true;\n }\n\n // 已过期\n if (now - cachedTime > cache.ttl) {\n return true;\n }\n\n // 失败的任务立即清理\n if (cache.status === \"failed\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * 默认配置常量\n */\nexport const DEFAULT_CONFIG = {\n TIMEOUT: 8000, // 8秒超时\n CACHE_TTL: 300000, // 5分钟缓存\n CLEANUP_INTERVAL: 60000, // 1分钟清理间隔\n MAX_CACHE_SIZE: 1000, // 最大缓存条目数\n ENABLE_ONE_TIME_CACHE: true, // 启用一次性缓存\n} as const;\n","/**\n * 超时错误类型\n */\nexport class TimeoutError extends Error {\n public override readonly name = \"TimeoutError\" as const;\n\n constructor(message: string) {\n super(message);\n this.name = \"TimeoutError\";\n Error.captureStackTrace(this, TimeoutError);\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n stack: this.stack,\n };\n }\n}\n\n/**\n * 超时响应接口\n */\nexport interface TimeoutResponse {\n content: Array<{\n type: \"text\";\n text: string;\n }>;\n isError: boolean;\n taskId: string;\n status: \"timeout\";\n message: string;\n nextAction: string;\n [key: string]: unknown; // 支持其他未知字段,与 ToolCallResult 保持兼容\n}\n\n/**\n * 创建超时响应的工具函数\n */\nexport function createTimeoutResponse(\n taskId: string,\n toolName?: string\n): TimeoutResponse {\n const toolSpecificMessage = toolName\n ? getToolSpecificTimeoutMessage(toolName, taskId)\n : getDefaultTimeoutMessage(taskId);\n\n return {\n content: [\n {\n type: \"text\",\n text: toolSpecificMessage,\n },\n ],\n isError: false,\n taskId,\n status: \"timeout\",\n message: \"工具调用超时,正在后台处理中\",\n nextAction: \"请稍后重试或等待任务完成\",\n };\n}\n\n/**\n * 获取工具特定的超时提示信息\n */\nfunction getToolSpecificTimeoutMessage(\n toolName: string,\n taskId: string\n): string {\n const toolMessages: Record<string, string> = {\n coze_workflow: `⏱️ 扣子工作流执行超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 工具类型: 扣子工作流\n- 状态: 处理中\n- 建议: 请等待30-60秒后重试查询\n\n🔄 后续操作:\n1. 使用相同参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 复杂工作流可能需要更长时间处理`,\n\n default: getDefaultTimeoutMessage(taskId),\n };\n\n return toolMessages[toolName] || toolMessages.default;\n}\n\n/**\n * 获取默认超时提示信息\n */\nfunction getDefaultTimeoutMessage(taskId: string): string {\n return `⏱️ 工具调用超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 状态: 处理中\n- 建议: 请等待30秒后重试查询\n\n🔄 后续操作:\n1. 使用相同的参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 如果长时间未完成,请联系管理员`;\n}\n\n/**\n * 验证是否为超时响应\n */\nexport function isTimeoutResponse(response: any): response is TimeoutResponse {\n return !!(\n response &&\n response.status === \"timeout\" &&\n typeof response.taskId === \"string\" &&\n Array.isArray(response.content) &&\n response.content.length > 0 &&\n response.content[0].type === \"text\"\n );\n}\n\n/**\n * 验证是否为超时错误\n */\nexport function isTimeoutError(error: any): error is TimeoutError {\n return !!(\n error &&\n error.name === \"TimeoutError\" &&\n error instanceof TimeoutError\n );\n}\n","#!/usr/bin/env node\n/**\n * 自定义 MCP 工具处理器模块\n *\n * 本模块提供了处理自定义 MCP 工具的核心功能,特别是针对 Coze 工作流工具。\n * 主要功能包括:\n * - CustomMCPHandler:简化的自定义 MCP 工具处理器\n * - 支持代理处理器配置(ProxyHandlerConfig)\n * - 工具调用超时处理\n * - 工具调用缓存机制\n * - 与 Coze API 服务集成\n *\n * @module custom\n *\n * @example\n * ```typescript\n * import { CustomMCPHandler } from '@/lib/mcp/custom.js';\n *\n * const handler = new CustomMCPHandler(mcpServiceManager);\n * const result = await handler.callTool(toolName, arguments, options);\n * ```\n */\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { CozeApiService } from \"@/lib/coze\";\nimport type { RunWorkflowData } from \"@/lib/coze\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport { ensureToolJSONSchema } from \"@/lib/mcp/types.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type {\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n ToolCallResponse,\n ToolCallResult,\n} from \"@/types/mcp.js\";\nimport {\n DEFAULT_CONFIG,\n generateCacheKey,\n isCacheExpired,\n shouldCleanupCache,\n} from \"@/types/mcp.js\";\nimport { TimeoutError, createTimeoutResponse } from \"@/types/timeout.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type {\n CustomMCPTool,\n HandlerConfig,\n ProxyHandlerConfig,\n} from \"@xiaozhi-client/config\";\nimport { configManager } from \"@xiaozhi-client/config\";\n\n// 工具调用参数类型\ntype ToolArguments = Record<string, unknown>;\n\n// 类型守卫函数:检查是否为代理处理器\nfunction isProxyHandler(handler: HandlerConfig): handler is ProxyHandlerConfig {\n return handler.type === \"proxy\";\n}\n\n// 扩展的工具调用选项\ninterface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 简化版的 CustomMCPHandler\n * 专门用于处理 Coze 工作流工具,保持超时友好响应机制\n */\nexport class CustomMCPHandler {\n private logger: Logger;\n private tools: Map<string, CustomMCPTool> = new Map();\n private cacheManager: MCPCacheManager;\n private mcpServiceManager?: MCPServiceManager;\n private readonly TIMEOUT = DEFAULT_CONFIG.TIMEOUT; // 统一8秒超时\n private readonly CACHE_TTL = DEFAULT_CONFIG.CACHE_TTL; // 5分钟缓存过期\n private configUpdateListener: ((data: unknown) => void) | null = null; // 配置更新监听器引用\n\n constructor(\n cacheManager?: MCPCacheManager,\n mcpServiceManager?: MCPServiceManager\n ) {\n this.logger = logger;\n this.cacheManager = cacheManager || new MCPCacheManager();\n this.mcpServiceManager = mcpServiceManager;\n\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 获取 CozeApiService 实例\n */\n private getCozeApiService(): CozeApiService {\n const token = configManager.getConfig().platforms?.coze?.token;\n\n if (!token) {\n throw new Error(\"Coze Token 配置不存在\");\n }\n\n return new CozeApiService(token);\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n const eventBus = getEventBus();\n\n // 监听配置更新事件\n this.configUpdateListener = async (data) => {\n if (\n data &&\n typeof data === \"object\" &&\n \"type\" in data &&\n data.type === \"customMCP\"\n ) {\n this.logger.info(\"[CustomMCP] 检测到配置更新,重新初始化...\");\n try {\n this.reinitialize();\n } catch (error) {\n this.logger.error(\"[CustomMCP] 配置更新处理失败:\", error);\n }\n }\n };\n\n eventBus.onEvent(\"config:updated\", this.configUpdateListener);\n }\n\n /**\n * 初始化 CustomMCP 处理器\n * 加载配置中的 customMCP 工具\n * @param tools 可选的工具数组,如果提供则使用该数组,否则从配置管理器获取\n */\n public initialize(tools?: CustomMCPTool[]): void {\n this.logger.debug(\"[CustomMCP] 初始化 CustomMCP 处理器...\");\n\n try {\n const customTools = tools || configManager.getCustomMCPTools();\n\n // 清空现有工具\n this.tools.clear();\n\n // 只加载 coze 代理工具\n for (const tool of customTools) {\n if (isProxyHandler(tool.handler) && tool.handler.platform === \"coze\") {\n this.tools.set(tool.name, tool);\n this.logger.debug(\n `[CustomMCP] 已加载 Coze 工具: ${tool.name} (workflow_id: ${tool.handler.config.workflow_id})`\n );\n }\n }\n\n this.logger.debug(\n `[CustomMCP] 初始化完成,共加载 ${this.tools.size} 个 Coze 工具`\n );\n } catch (error) {\n this.logger.error(\"[CustomMCP] 初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取所有工具(标准 MCP 格式)\n */\n public getTools(): Tool[] {\n return Array.from(this.tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: ensureToolJSONSchema(tool.inputSchema),\n }));\n }\n\n /**\n * 检查是否存在指定工具\n */\n public hasTool(toolName: string): boolean {\n return this.tools.has(toolName);\n }\n\n /**\n * 获取工具数量\n */\n public getToolCount(): number {\n return this.tools.size;\n }\n\n /**\n * 获取所有工具名称\n */\n public getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * 获取工具详细信息(用于调试)\n */\n public getToolInfo(toolName: string): CustomMCPTool | undefined {\n return this.tools.get(toolName);\n }\n\n /**\n * 重新初始化 CustomMCP 处理器\n * 重新加载配置中的 customMCP 工具\n */\n public reinitialize(): void {\n this.logger.debug(\"[CustomMCP] 重新初始化 CustomMCP 处理器...\");\n this.initialize();\n }\n\n /**\n * 调用工具(支持超时友好响应和缓存管理)\n */\n public async callTool(\n toolName: string,\n arguments_: ToolArguments,\n options?: ToolCallOptions\n ): Promise<ToolCallResponse> {\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 首先检查是否有已完成的任务结果(一次性缓存)\n const completedResult = await this.getCompletedResult(toolName, arguments_);\n if (completedResult) {\n this.logger.debug(`[CustomMCP] 返回已完成的任务结果: ${toolName}`);\n // 立即清理已消费的缓存\n await this.clearConsumedCache(toolName, arguments_);\n return completedResult;\n }\n\n try {\n const timeout = options?.timeout || this.TIMEOUT;\n const result = await Promise.race([\n this.callCozeWorkflow(tool, arguments_),\n this.createTimeoutPromise(toolName, timeout),\n ]);\n\n // 缓存结果(标记为未消费)\n await this.cacheResult(toolName, arguments_, result);\n\n return result;\n } catch (error) {\n // 如果是超时错误,返回友好提示\n if (error instanceof TimeoutError) {\n const taskId = await this.generateTaskId(toolName, arguments_);\n this.logger.info(\n `[CustomMCP] 工具超时,返回友好提示: ${toolName}, taskId: ${taskId}`\n );\n return createTimeoutResponse(taskId, toolName);\n }\n\n throw error;\n }\n }\n\n /**\n * 创建超时 Promise\n */\n private async createTimeoutPromise(\n toolName: string,\n timeout: number\n ): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new TimeoutError(`工具调用超时: ${toolName}`));\n }, timeout);\n });\n }\n\n /**\n * 获取已完成的任务结果(一次性缓存)\n */\n private async getCompletedResult(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<ToolCallResult | null> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cached = cache.customMCPResults[cacheKey];\n\n // 只返回已完成且未消费的结果\n if (cached.status === \"completed\" && !cached.consumed) {\n // 检查是否过期\n if (!isCacheExpired(cached.timestamp, cached.ttl)) {\n return cached.result;\n }\n }\n\n return null;\n } catch (error) {\n this.logger.warn(`[CustomMCP] 获取缓存失败: ${error}`);\n return null;\n }\n }\n\n /**\n * 处理工作流响应\n */\n private processWorkflowResponse(\n toolName: string,\n workflowData: RunWorkflowData\n ): ToolCallResult {\n try {\n // 根据 RunWorkflowData 的实际结构进行处理\n // 假设 workflowData 有 data 字段或其他响应数据字段\n const responseData = workflowData.data || workflowData;\n\n if (typeof responseData === \"string\") {\n return {\n content: [\n {\n type: \"text\",\n text: responseData,\n },\n ],\n isError: false,\n };\n }\n\n // 如果是对象,转换为 JSON 字符串\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(responseData, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 处理工作流响应失败: ${toolName}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `处理响应失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 调用 Coze 工作流\n */\n private async callCozeWorkflow(\n tool: CustomMCPTool,\n arguments_: ToolArguments\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ProxyHandlerConfig;\n const config = handler.config;\n\n this.logger.info(`[CustomMCP] 调用 Coze 工作流: ${tool.name}`, {\n workflow_id: config.workflow_id,\n });\n\n try {\n // 使用 CozeApiService\n const cozeApiService = this.getCozeApiService();\n\n // 检查 workflow_id 是否存在\n if (!config.workflow_id) {\n throw new Error(\"工作流ID未配置\");\n }\n\n // 调用 callWorkflow 方法\n const workflowResult = await cozeApiService.callWorkflow(\n config.workflow_id,\n arguments_\n );\n\n this.logger.info(`[CustomMCP] Coze 工作流调用成功: ${tool.name}`);\n\n // 转换响应格式为 ToolCallResult\n return this.processWorkflowResponse(tool.name, workflowResult);\n } catch (error) {\n this.logger.error(`[CustomMCP] Coze 工作流调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Coze 工作流调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 清理已消费的缓存\n */\n private async clearConsumedCache(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (cache.customMCPResults?.[cacheKey]) {\n // 标记为已消费\n cache.customMCPResults[cacheKey].consumed = true;\n\n // 如果已消费且已过期,直接删除\n const cached = cache.customMCPResults[cacheKey];\n if (shouldCleanupCache(cached)) {\n delete cache.customMCPResults[cacheKey];\n }\n\n // 保存缓存更改\n await this.saveCache(cache);\n this.logger.debug(`[CustomMCP] 清理已消费缓存: ${cacheKey}`);\n }\n } catch (error) {\n this.logger.warn(`[CustomMCP] 清理缓存失败: ${error}`);\n }\n }\n\n /**\n * 生成任务ID\n */\n private async generateTaskId(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<string> {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 生成缓存键\n */\n private generateCacheKey(\n toolName: string,\n arguments_: ToolArguments\n ): string {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 加载扩展缓存\n */\n private async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cacheData = await this.cacheManager.loadExistingCache();\n return cacheData as ExtendedMCPToolsCache;\n } catch (error) {\n return {\n version: \"1.0.0\",\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: new Date().toISOString(),\n totalWrites: 0,\n createdAt: new Date().toISOString(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 更新缓存结果\n */\n private async updateCacheWithResult(\n cacheKey: string,\n cacheData: EnhancedToolResultCache\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheData;\n\n // 使用 MCPCacheManager 的保存方法\n await this.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 更新缓存失败: ${error}`);\n }\n }\n\n /**\n * 缓存结果\n */\n private async cacheResult(\n toolName: string,\n arguments_: ToolArguments,\n result: ToolCallResult\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cacheData: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl: this.CACHE_TTL,\n status: \"completed\",\n consumed: false, // 初始状态为未消费\n retryCount: 0,\n };\n\n await this.updateCacheWithResult(cacheKey, cacheData);\n this.logger.debug(`[CustomMCP] 缓存工具结果: ${toolName}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 缓存结果失败: ${error}`);\n }\n }\n\n /**\n * 保存缓存\n */\n private async saveCache(cache: ExtendedMCPToolsCache): Promise<void> {\n try {\n await this.cacheManager.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 保存缓存失败: ${error}`);\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.logger.info(\"[CustomMCP] 清理 CustomMCP 处理器资源\");\n\n // 移除事件监听器\n if (this.configUpdateListener) {\n const eventBus = getEventBus();\n eventBus.offEvent(\"config:updated\", this.configUpdateListener);\n this.configUpdateListener = null;\n }\n\n this.tools.clear();\n this.cacheManager.cleanup();\n }\n}\n","/**\n * MCP 工具调用日志模块\n * 提供工具调用的写入和查询功能\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { logger } from \"@/Logger.js\";\nimport { PathUtils } from \"@/utils/path-utils.js\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\n\n// ==================== 类型定义 ====================\n\n/**\n * Pino 日志对象类型(内部使用)\n * 用于 formatConsoleMessage 方法的参数类型\n */\ninterface PinoLogObject {\n toolName?: string;\n success?: boolean;\n duration?: number;\n [key: string]: unknown;\n}\n\n/**\n * 工具调用记录接口\n */\nexport interface ToolCallRecord {\n toolName: string; // 工具名称\n originalToolName?: string; // 原始工具名称(未格式化的)\n serverName?: string; // 服务器名称(coze、dify、n8n、custom等)\n arguments?: Record<string, unknown>; // 调用参数\n result?: unknown; // 响应结果\n success: boolean; // 是否成功\n duration?: number; // 调用耗时(毫秒)\n error?: string; // 错误信息(如果有)\n timestamp?: number; // 时间戳(毫秒)\n}\n\n/**\n * 工具调用日志配置接口\n */\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n/**\n * 查询参数接口\n */\nexport interface ToolCallQuery {\n limit?: number;\n offset?: number;\n toolName?: string;\n serverName?: string;\n success?: boolean;\n startDate?: string;\n endDate?: string;\n}\n\n// ==================== ToolCallLogger 类(写入功能)====================\n\n/**\n * MCP 工具调用记录器\n * 提供工具调用的 JSONL 格式记录功能\n */\nexport class ToolCallLogger {\n private pinoLogger: PinoLogger;\n private maxRecords: number;\n private logFilePath: string;\n\n constructor(config: ToolCallLogConfig, configDir: string) {\n this.maxRecords = config?.maxRecords ?? 100;\n\n // 确定日志文件路径 - 使用更健壮的路径处理\n if (config?.logFilePath) {\n this.logFilePath = path.resolve(path.normalize(config.logFilePath));\n } else {\n // 使用 PathUtils 的跨平台临时目录处理\n const baseDir = configDir || PathUtils.getTempDir();\n this.logFilePath = path.join(path.normalize(baseDir), \"tool-calls.jsonl\");\n }\n\n // 创建 Pino 实例\n this.pinoLogger = this.createPinoLogger(this.logFilePath);\n\n logger.info(\"ToolCallLogger 初始化\", {\n maxRecords: this.maxRecords,\n path: this.logFilePath,\n });\n }\n\n /**\n * 创建 Pino Logger 实例\n */\n private createPinoLogger(logFilePath: string): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 使用彩色输出\n streams.push({\n level: \"info\",\n stream: {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessage(logObj);\n console.log(\"[工具调用]\", { message });\n } catch {\n console.log(\"[工具调用]\", { chunk: chunk.trim() });\n }\n },\n },\n });\n\n // 文件流 - JSONL 格式,带错误处理\n try {\n streams.push({\n level: \"info\",\n stream: pino.destination({\n dest: logFilePath,\n sync: true, // 同步写入确保测试可靠性\n append: true,\n mkdir: true,\n }),\n });\n } catch (error) {\n // 如果文件路径无效,记录错误但不抛出异常\n logger.error(\"无法创建工具调用日志文件\", { error });\n }\n\n return pino(\n {\n level: \"info\",\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n level: (_label: string, number: number) => ({ level: number }),\n },\n base: null, // 不包含 pid 和 hostname\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n /**\n * 格式化控制台消息\n */\n private formatConsoleMessage(logObj: PinoLogObject): string {\n const toolName = logObj.toolName || \"未知工具\";\n const success = logObj.success !== false;\n const duration = logObj.duration ? ` (${logObj.duration}ms)` : \"\";\n const status = success ? \"✅\" : \"❌\";\n\n return `${status} ${toolName}${duration}`;\n }\n\n /**\n * 清理旧的日志记录,确保不超过最大记录数量\n */\n private async cleanupOldRecords(): Promise<void> {\n try {\n // 检查日志文件是否存在\n if (!fs.existsSync(this.logFilePath)) {\n return;\n }\n\n // 读取文件内容\n const content = fs.readFileSync(this.logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n // 如果记录数量未超过限制,直接返回\n if (lines.length <= this.maxRecords) {\n return;\n }\n\n // 计算需要删除的记录数量\n const recordsToRemove = lines.length - this.maxRecords + 1; // +1 为即将写入的新记录预留空间\n\n // 删除最旧的记录(从文件开头删除)\n const linesToKeep = lines.slice(recordsToRemove);\n\n // 重新写入文件\n const newContent =\n linesToKeep.join(\"\\n\") + (linesToKeep.length > 0 ? \"\\n\" : \"\");\n fs.writeFileSync(this.logFilePath, newContent, \"utf8\");\n\n logger.info(\"已清理旧的工具调用记录\", {\n recordsToRemove,\n maxRecords: this.maxRecords,\n });\n } catch (error) {\n logger.error(\"清理旧工具调用记录失败\", { error });\n }\n }\n\n /**\n * 记录工具调用\n */\n async recordToolCall(record: ToolCallRecord): Promise<void> {\n try {\n // 在写入新记录前,先清理旧记录以确保不超过最大记录数量\n await this.cleanupOldRecords();\n\n // 使用 Pino 记录日志,自动处理并发和文件写入\n this.pinoLogger.info(record, record.toolName);\n } catch (error) {\n // 记录失败不应该影响主流程,只记录错误日志\n logger.error(\"记录工具调用失败\", { error });\n }\n }\n\n /**\n * 获取日志文件路径\n */\n getLogFilePath(): string {\n return this.logFilePath;\n }\n\n /**\n * 获取最大记录数量\n */\n getMaxRecords(): number {\n return this.maxRecords;\n }\n}\n\n// ==================== ToolCallLogService 类(查询功能)====================\n\n/**\n * 工具调用日志服务类\n * 负责读取和查询工具调用日志\n */\nexport class ToolCallLogService {\n private configDir: string;\n\n constructor(configDir?: string) {\n this.configDir = configDir || PathUtils.getConfigDir();\n }\n\n /**\n * 获取工具调用日志文件路径\n */\n private getLogFilePath(): string {\n const toolCallLogger = new ToolCallLogger({}, this.configDir);\n return toolCallLogger.getLogFilePath();\n }\n\n /**\n * 检查日志文件是否存在\n */\n private checkLogFile(): void {\n const logFilePath = this.getLogFilePath();\n if (!fs.existsSync(logFilePath)) {\n throw new Error(\"工具调用日志文件不存在\");\n }\n }\n\n /**\n * 读取并解析工具调用日志\n */\n private parseLogFile(): ToolCallRecord[] {\n const logFilePath = this.getLogFilePath();\n\n try {\n const content = fs.readFileSync(logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n const records: ToolCallRecord[] = [];\n\n for (const line of lines) {\n try {\n const record = JSON.parse(line);\n // 添加时间戳字段(如果 pino 添加了时间信息)\n if (record.time) {\n record.timestamp = new Date(record.time).getTime();\n }\n // 如果没有时间戳,记录警告信息提示数据质量问题\n if (!record.timestamp) {\n logger.warn(\"日志记录缺少时间戳\", { line });\n }\n records.push(record);\n } catch {\n logger.warn(\"跳过无效的日志行\", { line });\n }\n }\n\n // 按时间戳倒序排列(最新的在前)\n records.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));\n\n return records;\n } catch (error) {\n logger.error(\"读取日志文件失败\", { error });\n throw new Error(\"无法读取工具调用日志文件\");\n }\n }\n\n /**\n * 过滤工具调用记录\n */\n private filterRecords(\n records: ToolCallRecord[],\n query: ToolCallQuery\n ): ToolCallRecord[] {\n let filtered = [...records];\n\n // 按工具名称过滤\n if (query.toolName) {\n filtered = filtered.filter((record) =>\n record.toolName\n .toLowerCase()\n .includes(query.toolName?.toLowerCase() ?? \"\")\n );\n }\n\n // 按服务器名称过滤\n if (query.serverName) {\n filtered = filtered.filter((record) =>\n record.serverName\n ?.toLowerCase()\n .includes(query.serverName?.toLowerCase() ?? \"\")\n );\n }\n\n // 按成功状态过滤\n if (query.success !== undefined) {\n filtered = filtered.filter((record) => record.success === query.success);\n }\n\n // 按时间范围过滤\n if (query.startDate || query.endDate) {\n const startTime = query.startDate\n ? new Date(query.startDate).getTime()\n : 0;\n const endTime = query.endDate\n ? new Date(query.endDate).getTime()\n : Date.now();\n\n filtered = filtered.filter((record) => {\n const recordTime = record.timestamp || 0;\n return recordTime >= startTime && recordTime <= endTime;\n });\n }\n\n return filtered;\n }\n\n /**\n * 获取工具调用日志\n */\n async getToolCallLogs(query: ToolCallQuery = {}): Promise<{\n records: ToolCallRecord[];\n total: number;\n hasMore: boolean;\n }> {\n this.checkLogFile();\n\n const records = this.parseLogFile();\n const filtered = this.filterRecords(records, query);\n const total = filtered.length;\n\n // 分页处理\n const limit = Math.min(\n query.limit || 50,\n 1000 // 最大限制 1000\n );\n const offset = query.offset || 0;\n const paginated = filtered.slice(offset, offset + limit);\n const hasMore = offset + limit < total;\n\n logger.info(\"返回工具调用日志\", {\n count: paginated.length,\n total,\n });\n\n return {\n records: paginated,\n total,\n hasMore,\n };\n }\n}\n","/**\n * 路径处理工具\n */\n\nimport { tmpdir } from \"node:os\";\n\n/**\n * 路径工具类\n */\nexport class PathUtils {\n /**\n * 获取配置目录路径\n */\n static getConfigDir(): string {\n return process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n }\n\n /**\n * 获取临时目录路径\n */\n static getTempDir(): string {\n return process.env.TMPDIR || process.env.TEMP || tmpdir();\n }\n}\n","/**\n * 统一的 MCP 消息处理器\n * 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call、resources/list、prompts/list 等\n * 这是阶段一重构的核心组件,用于消除双层代理架构\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n JSONRPC_VERSION,\n MCP_METHODS,\n MCP_PROTOCOL_VERSIONS,\n MCP_SERVER_INFO,\n MCP_SUPPORTED_PROTOCOL_VERSIONS,\n} from \"@/constants/index.js\";\nimport type { EnhancedToolInfo, MCPServiceManager } from \"@/lib/mcp\";\nimport { validateToolCallParams } from \"@/lib/mcp\";\nimport type { MCPMessage, MCPResponse } from \"@/types/mcp.js\";\nimport type {\n ClientCapabilities,\n InitializedNotification,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\n// 初始化参数接口\ninterface InitializeParams {\n protocolVersion: string;\n capabilities: ClientCapabilities;\n clientInfo: {\n name: string;\n version: string;\n };\n}\n\n// 工具调用参数接口\ninterface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n// MCP 资源接口\ninterface MCPResource {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n}\n\n// MCP 提示接口\ninterface MCPPrompt {\n name: string;\n description?: string;\n arguments?: Array<{\n name: string;\n description?: string;\n required?: boolean;\n }>;\n}\n\nexport class MCPMessageHandler {\n private logger: Logger;\n private serviceManager: MCPServiceManager;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n /**\n * 处理 MCP 消息的统一入口\n * @param message MCP 消息\n * @returns MCP 响应(对于通知消息返回 null)\n */\n async handleMessage(message: MCPMessage): Promise<MCPResponse | null> {\n this.logger.debug(`处理 MCP 消息: ${message.method}`, message);\n\n try {\n // 检查是否为通知消息(没有 id 字段)\n const isNotification = message.id === undefined;\n\n switch (message.method) {\n case MCP_METHODS.INITIALIZE:\n return await this.handleInitialize(\n message.params as InitializeParams,\n message.id\n );\n case MCP_METHODS.INITIALIZED:\n return await this.handleInitializedNotification(\n message.params as InitializedNotification[\"params\"]\n );\n case MCP_METHODS.TOOLS_LIST:\n return await this.handleToolsList(message.id);\n case MCP_METHODS.TOOLS_CALL:\n return await this.handleToolCall(\n message.params as ToolCallParams,\n message.id\n );\n case MCP_METHODS.RESOURCES_LIST:\n return await this.handleResourcesList(message.id);\n case MCP_METHODS.PROMPTS_LIST:\n return await this.handlePromptsList(message.id);\n case MCP_METHODS.PING:\n return await this.handlePing(message.id);\n default:\n if (isNotification) {\n // 对于未知的通知消息,记录警告但不抛出错误\n this.logger.warn(`收到未知的通知消息: ${message.method}`, message);\n return null;\n }\n throw new Error(`未知的方法: ${message.method}`);\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n // 通知消息不需要错误响应\n if (message.id === undefined) {\n return null;\n }\n return this.createErrorResponse(error as Error, message.id);\n }\n }\n\n /**\n * 处理 initialize 请求\n * @param params 初始化参数\n * @param id 消息ID\n * @returns 初始化响应\n */\n private async handleInitialize(\n params: InitializeParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 initialize 请求\", params);\n\n // 支持多个协议版本,优先使用客户端请求的版本\n const clientVersion = params.protocolVersion;\n const responseVersion = MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(\n clientVersion as (typeof MCP_SUPPORTED_PROTOCOL_VERSIONS)[number]\n )\n ? clientVersion\n : MCP_PROTOCOL_VERSIONS.DEFAULT;\n\n this.logger.debug(\n `协议版本协商: 客户端=${clientVersion}, 服务器响应=${responseVersion}`\n );\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n serverInfo: {\n name: MCP_SERVER_INFO.NAME,\n version: MCP_SERVER_INFO.VERSION,\n },\n capabilities: {\n tools: {},\n logging: {},\n },\n protocolVersion: responseVersion,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 notifications/initialized 通知\n * @param params 通知参数\n * @returns null(通知消息不需要响应)\n */\n private async handleInitializedNotification(\n params?: InitializedNotification[\"params\"]\n ): Promise<null> {\n this.logger.debug(\"收到 initialized 通知,客户端初始化完成\", params);\n\n // 可以在这里执行一些初始化完成后的逻辑\n // 例如:记录客户端连接状态、触发事件等\n\n return null;\n }\n\n /**\n * 处理 tools/list 请求\n * @param id 消息ID\n * @returns 工具列表响应\n */\n private async handleToolsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 tools/list 请求\");\n\n try {\n const tools: EnhancedToolInfo[] = this.serviceManager.getAllTools();\n\n // 转换为 MCP 标准格式\n const mcpTools = tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n tools: mcpTools,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(\"获取工具列表失败\", error);\n throw error;\n }\n }\n\n /**\n * 处理 tools/call 请求\n * @param params 工具调用参数\n * @param id 消息ID\n * @returns 工具调用响应\n */\n private async handleToolCall(\n params: ToolCallParams,\n id?: string | number\n ): Promise<MCPResponse> {\n try {\n // 参数校验\n const validatedParams = validateToolCallParams(params);\n\n const result = await this.serviceManager.callTool(\n validatedParams.name,\n validatedParams.arguments || {}\n );\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n content: result.content,\n isError: result.isError || false,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(`工具调用失败: ${params.name}`, error);\n throw error;\n }\n }\n\n /**\n * 处理 ping 请求\n * @param id 消息ID\n * @returns ping 响应\n */\n private async handlePing(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 ping 请求\");\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n status: \"ok\",\n timestamp: new Date().toISOString(),\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 resources/list 请求\n * @param id 消息ID\n * @returns 资源列表响应\n */\n private async handleResourcesList(\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 resources/list 请求\");\n\n // 目前返回空的资源列表\n // 如果将来需要提供资源功能,可以在这里扩展\n const resources: MCPResource[] = [];\n\n this.logger.debug(`返回 ${resources.length} 个资源`);\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n resources: resources,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 prompts/list 请求\n * @param id 消息ID\n * @returns 提示列表响应\n */\n private async handlePromptsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 prompts/list 请求\");\n\n // 目前返回空的提示列表\n // 如果将来需要提供提示模板功能,可以在这里扩展\n const prompts: MCPPrompt[] = [];\n\n this.logger.debug(`返回 ${prompts.length} 个提示模板`);\n\n return {\n jsonrpc: JSONRPC_VERSION,\n result: {\n prompts: prompts,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 创建错误响应\n * @param error 错误对象\n * @param id 消息ID\n * @returns 错误响应\n */\n private createErrorResponse(error: Error, id?: string | number): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: JSONRPC_VERSION,\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 获取服务管理器实例\n * @returns MCPServiceManager 实例\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n}\n","/**\n * 向后兼容的 MCPService 类\n * 包装 @xiaozhi-client/mcp-core 的 MCPConnection,使用 EventBus 发射事件\n */\n\nimport { MCP_SERVICE_EVENTS } from \"@/constants/index.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { MCPConnection } from \"@xiaozhi-client/mcp-core\";\nimport type { InternalMCPServiceConfig } from \"./types.js\";\n\n/**\n * MCP 服务类(向后兼容包装器)\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPService {\n private connection: MCPConnection;\n private eventBus = getEventBus();\n\n constructor(config: InternalMCPServiceConfig) {\n // 从配置中解构 name,其余作为连接配置\n const {\n name,\n ...connectionConfig\n }: { name: string } & Omit<InternalMCPServiceConfig, \"name\"> = config;\n\n // 创建回调适配器,将 mcp-core 的回调转换为 EventBus 事件\n const callbacks = {\n onConnected: (data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }) => {\n this.eventBus.emitEvent(MCP_SERVICE_EVENTS.CONNECTED, data);\n },\n onDisconnected: (data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }) => {\n this.eventBus.emitEvent(MCP_SERVICE_EVENTS.DISCONNECTED, data);\n },\n onConnectionFailed: (data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }) => {\n this.eventBus.emitEvent(MCP_SERVICE_EVENTS.CONNECTION_FAILED, data);\n },\n };\n\n // 适配新 API:将 name 从 config 中分离\n this.connection = new MCPConnection(name, connectionConfig, callbacks);\n }\n\n /**\n * 连接到 MCP 服务\n */\n async connect(): Promise<void> {\n return this.connection.connect();\n }\n\n /**\n * 断开连接\n */\n async disconnect(): Promise<void> {\n return this.connection.disconnect();\n }\n\n /**\n * 调用工具\n */\n async callTool(name: string, arguments_: Record<string, unknown>) {\n return this.connection.callTool(name, arguments_);\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return this.connection.getTools();\n }\n\n /**\n * 获取服务配置\n */\n getConfig() {\n return this.connection.getConfig();\n }\n\n /**\n * 获取服务状态\n */\n getStatus() {\n return this.connection.getStatus();\n }\n\n /**\n * 检查是否已连接\n */\n isConnected() {\n return this.connection.isConnected();\n }\n}\n","/**\n * MCP 工具函数模块\n *\n * 提供 MCP 服务配置和工具调用的工具函数:\n * - 传输类型推断(基于 URL 或配置)\n * - 工具调用参数验证\n */\n\nimport { TypeFieldNormalizer } from \"@xiaozhi-client/mcp-core\";\nimport { MCPTransportType, ToolCallError, ToolCallErrorCode } from \"./types.js\";\nimport type {\n MCPServiceConfig,\n ToolCallParams,\n ToolCallValidationOptions,\n ValidatedToolCallParams,\n} from \"./types.js\";\n\n/**\n * 根据 URL 路径推断传输类型\n * 基于路径末尾推断,支持包含多个 / 的复杂路径\n *\n * @param url - 要推断的 URL\n * @param options - 可选配置项\n * @returns 推断出的传输类型\n */\nexport function inferTransportTypeFromUrl(\n url: string,\n options?: {\n serviceName?: string;\n }\n): MCPTransportType {\n try {\n const parsedUrl = new URL(url);\n const pathname = parsedUrl.pathname;\n\n // 检查路径末尾\n if (pathname.endsWith(\"/sse\")) {\n return MCPTransportType.SSE;\n }\n if (pathname.endsWith(\"/mcp\")) {\n return MCPTransportType.HTTP;\n }\n\n // 默认类型 - 使用 console 输出\n if (options?.serviceName) {\n console.info(\n `[MCP-${options.serviceName}] URL 路径 ${pathname} 不匹配特定规则,默认推断为 http 类型`\n );\n }\n return MCPTransportType.HTTP;\n } catch (error) {\n if (options?.serviceName) {\n console.warn(\n `[MCP-${options.serviceName}] URL 解析失败,默认推断为 http 类型`,\n error\n );\n }\n return MCPTransportType.HTTP;\n }\n}\n\n/**\n * 完整的配置类型推断(包括 command 字段)\n *\n * @param config - MCP 服务配置\n * @param serviceName - 服务名称(用于错误信息)\n * @returns 完整的配置对象,包含推断出的类型\n */\nexport function inferTransportTypeFromConfig(\n config: MCPServiceConfig,\n serviceName: string\n): MCPServiceConfig {\n // 如果已显式指定类型,先标准化然后返回\n if (config.type) {\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(config);\n return normalizedConfig as MCPServiceConfig;\n }\n\n // 基于 command 字段推断\n if (config.command) {\n return {\n ...config,\n type: MCPTransportType.STDIO,\n };\n }\n\n // 基于 URL 字段推断(排除 null 和 undefined)\n if (config.url !== undefined && config.url !== null) {\n const inferredType = inferTransportTypeFromUrl(config.url, {\n serviceName,\n });\n return {\n ...config,\n type: inferredType,\n };\n }\n\n throw new Error(\n `无法为服务 ${serviceName} 推断传输类型。请显式指定 type 字段,或提供 command/url 配置`\n );\n}\n\n// =========================\n// 参数校验工具函数\n// =========================\n\n/**\n * 验证工具调用参数\n * 对传入的参数进行完整性和格式验证\n *\n * @param params 待验证的参数\n * @param options 验证选项\n * @returns 验证后的参数\n * @throws ToolCallError 验证失败时抛出\n */\nexport function validateToolCallParams(\n params: unknown,\n options?: ToolCallValidationOptions\n): ValidatedToolCallParams {\n const opts = {\n validateName: true,\n validateArguments: true,\n allowEmptyArguments: true,\n ...options,\n };\n\n // 1. 验证参数必须是对象\n if (!params || typeof params !== \"object\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求参数必须是对象\"\n );\n }\n\n const paramsObj = params as Record<string, unknown>;\n\n // 2. 验证工具名称\n if (opts.validateName) {\n if (!paramsObj.name || typeof paramsObj.name !== \"string\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具名称必须是非空字符串\"\n );\n }\n }\n\n // 3. 验证工具参数格式\n if (\n opts.validateArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n if (\n typeof paramsObj.arguments !== \"object\" ||\n Array.isArray(paramsObj.arguments)\n ) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数必须是对象\"\n );\n }\n }\n\n // 4. 验证是否允许空参数\n if (\n !opts.allowEmptyArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n const argsObj = paramsObj.arguments as Record<string, unknown>;\n if (Object.keys(argsObj).length === 0) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数不能为空\"\n );\n }\n }\n\n // 5. 执行自定义验证\n if (opts.customValidator) {\n const error = opts.customValidator(paramsObj as unknown as ToolCallParams);\n if (error) {\n throw new ToolCallError(ToolCallErrorCode.INVALID_PARAMS, error);\n }\n }\n\n return {\n name: paramsObj.name as string,\n arguments: paramsObj.arguments as Record<string, unknown>,\n };\n}\n","/**\n * MCP 缓存管理器\n * 负责 MCP 服务工具列表的缓存写入功能\n * 专注于缓存文件管理和数据写入的基础设施\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n CACHE_FILE_CONFIG,\n CACHE_TIMEOUTS,\n MCP_CACHE_VERSIONS,\n TOOL_NAME_SEPARATORS,\n} from \"@/constants/index.js\";\nimport type { MCPServiceConfig } from \"@/lib/mcp/types\";\nimport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n ToolCallResult,\n} from \"@/types/index.js\";\nimport { generateCacheKey, shouldCleanupCache } from \"@/types/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport dayjs from \"dayjs\";\n\n// 缓存条目接口\nexport interface MCPToolsCacheEntry {\n tools: Tool[]; // 工具列表\n lastUpdated: string; // 最后更新时间 (YYYY-MM-DD HH:mm:ss)\n serverConfig: MCPServiceConfig; // 服务配置快照\n configHash: string; // 配置哈希值,用于快速变更检测\n version: string; // 缓存条目版本\n}\n\n// 缓存文件接口\nexport interface MCPToolsCache {\n version: string; // 缓存文件格式版本 \"1.0.0\"\n mcpServers: Record<string, MCPToolsCacheEntry>;\n metadata: {\n lastGlobalUpdate: string; // 全局最后更新时间 (YYYY-MM-DD HH:mm:ss)\n totalWrites: number; // 总写入次数\n createdAt: string; // 缓存文件创建时间 (YYYY-MM-DD HH:mm:ss)\n };\n}\n\n// 缓存统计接口\nexport interface CacheStats {\n totalWrites: number;\n lastUpdate: string;\n serverCount: number;\n cacheFileSize: number;\n}\n\n// 重新导出相关类型\nexport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n} from \"@/types/index.js\";\n\nexport class MCPCacheManager {\n private cachePath: string;\n private logger: Logger;\n private readonly CACHE_VERSION = MCP_CACHE_VERSIONS.CACHE_VERSION;\n private readonly CACHE_ENTRY_VERSION = MCP_CACHE_VERSIONS.CACHE_ENTRY_VERSION;\n private cleanupInterval?: NodeJS.Timeout;\n private readonly CLEANUP_INTERVAL = CACHE_TIMEOUTS.CLEANUP_INTERVAL;\n\n constructor(customCachePath?: string) {\n this.logger = logger;\n this.cachePath = customCachePath || this.getCacheFilePath();\n this.startCleanupTimer();\n }\n\n /**\n * 格式化时间戳为 YYYY-MM-DD HH:mm:ss 格式\n */\n private formatTimestamp(): string {\n return dayjs().format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n /**\n * 获取缓存文件路径\n * 与 xiaozhi.config.json 同级目录\n */\n private getCacheFilePath(): string {\n try {\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, CACHE_FILE_CONFIG.FILENAME);\n } catch (error) {\n // 在某些测试环境中 process.cwd() 可能不可用,使用默认路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || \"/tmp\";\n return resolve(configDir, CACHE_FILE_CONFIG.FILENAME);\n }\n }\n\n /**\n * 确保缓存文件存在,如不存在则创建\n */\n async ensureCacheFile(): Promise<void> {\n try {\n if (!existsSync(this.cachePath)) {\n // 确保缓存文件的目录存在\n const cacheDir = dirname(this.cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n this.logger.debug(`[CacheManager] 已创建缓存目录: ${cacheDir}`);\n }\n\n this.logger.debug(\"[CacheManager] 缓存文件不存在,创建初始缓存文件\");\n const initialCache = await this.createInitialCache();\n await this.saveCache(initialCache);\n this.logger.info(`[CacheManager] 已创建缓存文件: ${this.cachePath}`);\n }\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 创建缓存文件失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 不抛出异常,确保不影响主流程\n }\n }\n\n /**\n * 创建初始缓存结构\n */\n private async createInitialCache(): Promise<MCPToolsCache> {\n const now = this.formatTimestamp();\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: now,\n totalWrites: 0,\n createdAt: now,\n },\n };\n }\n\n /**\n * 写入缓存条目\n * @param serverName 服务名称\n * @param tools 工具列表\n * @param config 服务配置\n */\n async writeCacheEntry(\n serverName: string,\n tools: Tool[],\n config: MCPServiceConfig\n ): Promise<void> {\n try {\n this.logger.debug(`[CacheManager] 开始写入缓存: ${serverName}`);\n\n // 确保缓存文件存在\n await this.ensureCacheFile();\n\n // 加载现有缓存\n const cache = await this.loadExistingCache();\n\n // 生成配置哈希\n const configHash = this.generateConfigHash(config);\n\n // 创建缓存条目\n const cacheEntry: MCPToolsCacheEntry = {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n })),\n lastUpdated: this.formatTimestamp(),\n serverConfig: { ...config }, // 深拷贝配置\n configHash,\n version: this.CACHE_ENTRY_VERSION,\n };\n\n // 更新缓存\n cache.mcpServers[serverName] = cacheEntry;\n cache.metadata.lastGlobalUpdate = this.formatTimestamp();\n cache.metadata.totalWrites += 1;\n\n // 保存缓存\n await this.saveCache(cache);\n\n this.logger.debug(\n `[CacheManager] 缓存写入成功: ${serverName}, 工具数量: ${tools.length}`\n );\n } catch (error) {\n // 记录错误但不抛出异常,确保不影响主流程\n this.logger.warn(\n `[CacheManager] 缓存写入失败: ${serverName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 加载现有缓存\n */\n public async loadExistingCache(): Promise<MCPToolsCache> {\n try {\n if (!existsSync(this.cachePath)) {\n return await this.createInitialCache();\n }\n\n const cacheData = readFileSync(this.cachePath, \"utf8\");\n const cache: unknown = JSON.parse(cacheData);\n\n // 验证缓存结构\n if (!this.validateCacheStructure(cache)) {\n this.logger.warn(\"[CacheManager] 缓存文件结构无效,重新创建\");\n return await this.createInitialCache();\n }\n\n return cache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载缓存失败,创建新缓存: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return await this.createInitialCache();\n }\n }\n\n /**\n * 保存缓存到文件(原子写入)\n */\n public async saveCache(cache: MCPToolsCache): Promise<void> {\n const cacheContent = JSON.stringify(cache, null, 2);\n await this.atomicWrite(this.cachePath, cacheContent);\n }\n\n /**\n * 原子写入文件\n * 使用临时文件确保写入操作的原子性\n */\n private async atomicWrite(filePath: string, data: string): Promise<void> {\n const tempPath = `${filePath}.tmp`;\n try {\n // 写入临时文件\n writeFileSync(tempPath, data, \"utf8\");\n // 原子性重命名\n renameSync(tempPath, filePath);\n } catch (error) {\n // 清理临时文件\n try {\n if (existsSync(tempPath)) {\n writeFileSync(tempPath, \"\", \"utf8\"); // 清空后删除\n }\n } catch {\n // 忽略清理错误\n }\n throw error;\n }\n }\n\n /**\n * 生成配置哈希\n * 用于快速检测配置变更\n */\n private generateConfigHash(config: MCPServiceConfig): string {\n try {\n return createHash(\"sha256\").update(JSON.stringify(config)).digest(\"hex\");\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 生成配置哈希失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return \"\";\n }\n }\n\n /**\n * 验证缓存数据结构\n * 使用类型谓词确保类型安全\n */\n private validateCacheStructure(cache: unknown): cache is MCPToolsCache {\n try {\n if (!cache || typeof cache !== \"object\") {\n return false;\n }\n\n const cacheObj = cache as Record<string, unknown>;\n const metadata = cacheObj.metadata as Record<string, unknown>;\n\n return (\n typeof cacheObj.version === \"string\" &&\n typeof cacheObj.mcpServers === \"object\" &&\n cacheObj.mcpServers !== null &&\n cacheObj.metadata !== null &&\n cacheObj.metadata !== undefined &&\n typeof metadata === \"object\" &&\n metadata !== null &&\n typeof metadata.lastGlobalUpdate === \"string\" &&\n typeof metadata.totalWrites === \"number\" &&\n typeof metadata.createdAt === \"string\"\n );\n } catch {\n return false;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n async getStats(): Promise<CacheStats | null> {\n try {\n const cache = await this.loadExistingCache();\n const stats: CacheStats = {\n totalWrites: cache.metadata.totalWrites,\n lastUpdate: cache.metadata.lastGlobalUpdate,\n serverCount: Object.keys(cache.mcpServers).length,\n cacheFileSize: existsSync(this.cachePath)\n ? readFileSync(this.cachePath, \"utf8\").length\n : 0,\n };\n return stats;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 获取缓存文件路径(用于测试和调试)\n */\n getFilePath(): string {\n return this.cachePath;\n }\n\n /**\n * 获取所有缓存中的工具\n * 返回所有服务中的所有工具列表\n */\n async getAllCachedTools(): Promise<Tool[]> {\n try {\n const cache = await this.loadExistingCache();\n const allTools: Tool[] = [];\n\n // 遍历所有服务,收集所有工具\n for (const [serverName, cacheEntry] of Object.entries(cache.mcpServers)) {\n for (const tool of cacheEntry.tools) {\n // 为每个工具添加服务名称信息\n allTools.push({\n ...tool,\n name: `${serverName}${TOOL_NAME_SEPARATORS.SERVICE_TOOL_SEPARATOR}${tool.name}`, // 格式: serviceName__toolName\n });\n }\n }\n\n this.logger.debug(\n `[CacheManager] 获取到所有缓存工具,共 ${allTools.length} 个`\n );\n return allTools;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取所有缓存工具失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return [];\n }\n }\n\n // ==================== CustomMCP 结果缓存管理方法 ====================\n\n /**\n * 写入 CustomMCP 工具执行结果缓存\n */\n async writeCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>,\n result: ToolCallResult,\n status: TaskStatus = \"completed\",\n taskId?: string,\n ttl = 300000\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n // 创建缓存条目\n const cacheEntry: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl,\n status,\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n // 确保customMCPResults存在\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheEntry;\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 写入CustomMCP结果缓存: ${toolName}, 状态: ${status}`\n );\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 写入CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 读取 CustomMCP 工具执行结果缓存\n */\n async readCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<EnhancedToolResultCache | null> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n\n // 检查是否过期\n const now = Date.now();\n const cachedTime = new Date(cacheEntry.timestamp).getTime();\n if (now - cachedTime > cacheEntry.ttl) {\n this.logger.debug(`[CacheManager] 缓存已过期: ${toolName}`);\n return null;\n }\n\n return cacheEntry;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 读取CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 更新 CustomMCP 缓存状态\n */\n async updateCustomMCPStatus(\n toolName: string,\n arguments_: Record<string, unknown>,\n newStatus: TaskStatus,\n result?: ToolCallResult,\n error?: string\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n const oldStatus = cacheEntry.status;\n\n // 更新状态\n cacheEntry.status = newStatus;\n cacheEntry.timestamp = new Date().toISOString();\n\n // 更新结果或错误信息\n if (result) {\n cacheEntry.result = result;\n }\n\n if (error && newStatus === \"failed\") {\n cacheEntry.result = {\n content: [{ type: \"text\", text: `任务失败: ${error}` }],\n };\n cacheEntry.consumed = true; // 失败的任务自动标记为已消费\n }\n\n // 特殊状态处理\n if (newStatus === \"completed\") {\n cacheEntry.consumed = false; // 完成的任务初始状态为未消费\n }\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 更新缓存状态: ${toolName} ${oldStatus} -> ${newStatus}`\n );\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 更新CustomMCP缓存状态失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 标记 CustomMCP 缓存为已消费\n */\n async markCustomMCPAsConsumed(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry.consumed) {\n return true;\n }\n\n cacheEntry.consumed = true;\n cacheEntry.timestamp = new Date().toISOString();\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 标记缓存为已消费: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 标记CustomMCP缓存为已消费失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 删除 CustomMCP 缓存条目\n */\n async deleteCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n delete cache.customMCPResults[cacheKey];\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 删除缓存条目: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 删除CustomMCP缓存条目失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 批量清理 CustomMCP 缓存\n */\n async cleanupCustomMCPResults(): Promise<{ cleaned: number; total: number }> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (shouldCleanupCache(cacheEntry)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n }\n }\n\n if (cleanedCount > 0) {\n await this.saveExtendedCache(cache);\n this.logger.info(\n `[CacheManager] 清理CustomMCP缓存: ${cleanedCount}/${entries.length}`\n );\n }\n\n return { cleaned: cleanedCount, total: entries.length };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 清理CustomMCP缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return { cleaned: 0, total: 0 };\n }\n }\n\n /**\n * 获取 CustomMCP 缓存统计信息\n */\n async getCustomMCPStatistics(): Promise<CacheStatistics> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n\n const entries = Object.values(cache.customMCPResults);\n const totalEntries = entries.length;\n const pendingTasks = entries.filter((e) => e.status === \"pending\").length;\n const completedTasks = entries.filter(\n (e) => e.status === \"completed\"\n ).length;\n const failedTasks = entries.filter((e) => e.status === \"failed\").length;\n const consumedEntries = entries.filter((e) => e.consumed).length;\n\n // 计算缓存命中率\n const cacheHitRate =\n completedTasks > 0 ? (consumedEntries / completedTasks) * 100 : 0;\n\n // 估算内存使用\n const memoryUsage = JSON.stringify(cache.customMCPResults).length;\n\n return {\n totalEntries,\n pendingTasks,\n completedTasks,\n failedTasks,\n consumedEntries,\n cacheHitRate,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage,\n };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取CustomMCP缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n }\n\n /**\n * 加载扩展缓存(包含 CustomMCP 结果)\n */\n async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cache = await this.loadExistingCache();\n return cache as ExtendedMCPToolsCache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载扩展缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: this.formatTimestamp(),\n totalWrites: 0,\n createdAt: this.formatTimestamp(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 保存扩展缓存(包含 CustomMCP 结果)\n */\n async saveExtendedCache(cache: ExtendedMCPToolsCache): Promise<void> {\n await this.saveCache(cache);\n }\n\n /**\n * 启动清理定时器\n */\n private startCleanupTimer(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanupCustomMCPResults().catch((error) => {\n this.logger.warn(`[CacheManager] 自动清理失败: ${error}`);\n });\n }, this.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CacheManager] 启动清理定时器,间隔: ${this.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 停止清理定时器\n */\n public stopCleanupTimer(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n this.logger.debug(\"[CacheManager] 停止清理定时器\");\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.stopCleanupTimer();\n this.logger.debug(\"[CacheManager] 清理资源完成\");\n }\n}\n","/**\n * Hono Context 类型扩展\n * 为 Hono Context 添加项目特定的变量类型定义\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport type { EndpointHandler } from \"@/handlers/index.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { HandlerDependencies } from \"@/routes/types.js\";\nimport type { EndpointManager } from \"@xiaozhi-client/endpoint\";\nimport type { Context } from \"hono\";\nimport { Hono } from \"hono\";\n\n// 导出 API 响应类型供其他模块使用\nexport type {\n ApiErrorResponse,\n ApiPaginatedResponse,\n ApiSuccessResponse,\n PaginationInfo,\n ApiResponse,\n} from \"./api.response.js\";\n\n/**\n * WebServer 实例类型定义\n * 避免与 WebServer 实现类的循环引用\n * 使用类型断言的方式来定义接口\n */\nexport interface IWebServer {\n /**\n * 获取小智连接管理器实例\n * 在 endpointManagerMiddleware 中使用\n * WebServer 启动后始终返回有效的连接管理器实例\n * 如果在启动前调用,会抛出错误\n */\n getEndpointManager(): EndpointManager;\n\n /**\n * 获取 MCP 服务管理器实例\n * 在 mcpServiceManagerMiddleware 中使用\n * WebServer 启动后始终返回有效的服务管理器实例\n * 如果在启动前调用,会抛出错误\n */\n getMCPServiceManager(): MCPServiceManager;\n}\n\n/**\n * 扩展 Hono Context 的 Variables 类型\n * 定义了项目中所有通过中间件注入的变量\n */\nexport type AppContextVariables = {\n /**\n * Logger 实例\n * 由 loggerMiddleware 注入\n */\n logger: Logger;\n\n /**\n * MCP 服务管理器实例\n * 由 mcpServiceManagerMiddleware 注入\n */\n mcpServiceManager?: MCPServiceManager;\n\n /**\n * 路由处理器依赖\n * 由 RouteManager 注入\n */\n dependencies?: HandlerDependencies;\n\n /**\n * WebServer 实例引用\n * 用于获取运行时依赖\n */\n webServer?: IWebServer;\n\n /**\n * 小智连接管理器实例\n * 由 endpointManagerMiddleware 注入\n * WebServer 启动后始终可用的连接管理器实例\n * 可能为 null(初始化失败时)\n */\n endpointManager: EndpointManager | null;\n\n /**\n * 端点处理器实例\n * 由 endpointsMiddleware 注入\n */\n endpointHandler?: EndpointHandler | null;\n};\n\n/**\n * 扩展的 Hono Context 类型\n * 包含项目中所有自定义变量\n */\nexport type AppContext = {\n Variables: AppContextVariables;\n};\n\n/**\n * 创建类型化的 Hono 实例\n * 使用这个类型来创建新的 Hono 应用,确保 Context 类型安全\n */\nexport const createApp = (): Hono<AppContext> => {\n return new Hono<AppContext>();\n};\n\n/**\n * 从 Context 中获取 MCPServiceManager 的类型安全方法\n */\nexport const getMCPServiceManager = (\n c: Context<AppContext>\n): MCPServiceManager | undefined => {\n return c.get(\"mcpServiceManager\");\n};\n\n/**\n * 要求必须存在 MCPServiceManager 的类型安全方法\n */\nexport const requireMCPServiceManager = (\n c: Context<AppContext>\n): MCPServiceManager => {\n const serviceManager = c.get(\"mcpServiceManager\");\n\n if (!serviceManager) {\n throw new Error(\n \"MCPServiceManager 未初始化,请检查 mcpServiceManagerMiddleware 是否正确配置\"\n );\n }\n\n return serviceManager;\n};\n","/**\n * MCP 路由处理器\n * 处理符合 MCP Streamable HTTP 规范的单一 /mcp 端点\n * 支持 POST 请求(JSON-RPC 消息)\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport {\n HTTP_CONTENT_TYPES,\n HTTP_ERROR_MESSAGES,\n HTTP_HEADERS,\n HTTP_STATUS_CODES,\n JSONRPC_VERSION,\n MCP_PROTOCOL_VERSIONS,\n MCP_SUPPORTED_PROTOCOL_VERSIONS,\n MESSAGE_SIZE_LIMITS,\n} from \"@/constants/index.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport { MCPMessageHandler } from \"@/lib/mcp\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { MCPMessage } from \"@/types/mcp.js\";\nimport type { Context } from \"hono\";\n\n/**\n * MCP 路由处理器配置接口\n */\ninterface MCPRouteHandlerConfig {\n maxMessageSize?: number;\n enableMetrics?: boolean;\n}\n\n/**\n * 连接统计信息\n */\ninterface ConnectionMetrics {\n totalMessages: number;\n errorCount: number;\n averageResponseTime: number;\n}\n\n/**\n * MCP 路由处理器\n * 实现符合 MCP Streamable HTTP 规范的单一端点处理(仅 POST 模式)\n */\nexport class MCPRouteHandler {\n private logger: Logger;\n private mcpMessageHandler: MCPMessageHandler | null = null;\n private config: {\n maxMessageSize: number;\n enableMetrics: boolean;\n };\n private metrics: ConnectionMetrics;\n\n constructor(config: MCPRouteHandlerConfig = {}) {\n this.logger = logger;\n this.config = {\n maxMessageSize: config.maxMessageSize ?? MESSAGE_SIZE_LIMITS.DEFAULT,\n enableMetrics: config.enableMetrics ?? true,\n };\n\n this.metrics = {\n totalMessages: 0,\n errorCount: 0,\n averageResponseTime: 0,\n };\n\n this.logger.debug(\"MCPRouteHandler 初始化完成\", {\n maxMessageSize: this.config.maxMessageSize,\n enableMetrics: this.config.enableMetrics,\n });\n }\n\n /**\n * 获取 MCP 服务管理器实例\n * 优先从 Context 获取,如果不存在则从 WebServer 获取\n */\n private getMCPServiceManager(c: Context): MCPServiceManager {\n // 首先尝试从 Context 获取\n const serviceManager = c.get(\"mcpServiceManager\");\n if (serviceManager) {\n return serviceManager;\n }\n\n // 如果 Context 中没有,则从 WebServer 获取\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new Error(\"WebServer 未在 Context 中找到,请检查中间件配置\");\n }\n\n const mcpServiceManager = webServer.getMCPServiceManager();\n this.logger.debug(\n \"MCPServiceManager 从 WebServer 获取(Context 中未找到)\"\n );\n\n return mcpServiceManager;\n }\n\n /**\n * 初始化 MCP 消息处理器\n */\n private async initializeMessageHandler(c: Context): Promise<void> {\n if (this.mcpMessageHandler) {\n return;\n }\n\n try {\n const serviceManager = this.getMCPServiceManager(c);\n this.mcpMessageHandler = new MCPMessageHandler(serviceManager);\n this.logger.debug(\"MCP 消息处理器初始化成功\");\n } catch (error) {\n this.logger.error(\"MCP 消息处理器初始化失败:\", error);\n this.metrics.errorCount++;\n throw error;\n }\n }\n\n /**\n * 处理 POST 请求(JSON-RPC 消息)\n * 符合 MCP Streamable HTTP 规范\n */\n async handlePost(c: Context<AppContext>): Promise<Response> {\n const startTime = Date.now();\n let messageId: string | number | null = null;\n\n try {\n this.logger.debug(\"处理 MCP POST 请求\");\n\n // 验证请求大小\n const contentLength = c.req.header(HTTP_HEADERS.CONTENT_LENGTH);\n if (\n contentLength &&\n Number.parseInt(contentLength) > this.config.maxMessageSize\n ) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `${HTTP_ERROR_MESSAGES.REQUEST_TOO_LARGE}: Maximum size is ${this.config.maxMessageSize} bytes`\n );\n }\n\n // 验证 Content-Type\n const contentType = c.req.header(HTTP_HEADERS.CONTENT_TYPE);\n if (!contentType?.includes(HTTP_CONTENT_TYPES.APPLICATION_JSON)) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `${HTTP_ERROR_MESSAGES.INVALID_REQUEST}: ${HTTP_ERROR_MESSAGES.INVALID_CONTENT_TYPE}`\n );\n }\n\n // 验证 MCP 协议版本头(可选)\n // 支持多种大小写格式的协议版本头\n const protocolVersion =\n c.req.header(\"mcp-protocol-version\") ||\n c.req.header(HTTP_HEADERS.MCP_PROTOCOL_VERSION) ||\n c.req.header(\"Mcp-Protocol-Version\");\n if (\n protocolVersion &&\n !MCP_SUPPORTED_PROTOCOL_VERSIONS.includes(\n protocolVersion as (typeof MCP_SUPPORTED_PROTOCOL_VERSIONS)[number]\n )\n ) {\n this.logger.warn(\n `不支持的 MCP 协议版本: ${protocolVersion},支持的版本: ${MCP_SUPPORTED_PROTOCOL_VERSIONS.join(\n \", \"\n )}`\n );\n }\n\n // 解析请求体\n let message: MCPMessage;\n try {\n const rawBody = await c.req.text();\n if (rawBody.length > this.config.maxMessageSize) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `Message too large: Maximum size is ${this.config.maxMessageSize} bytes`,\n null\n );\n }\n message = JSON.parse(rawBody);\n messageId = message.id || null;\n } catch (error) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32700,\n HTTP_ERROR_MESSAGES.PARSE_ERROR\n );\n }\n\n // 验证 JSON-RPC 格式\n if (!this.validateMessage(message)) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `${HTTP_ERROR_MESSAGES.INVALID_REQUEST}: Message does not conform to JSON-RPC ${JSONRPC_VERSION}`,\n messageId\n );\n }\n\n // 初始化消息处理器\n await this.initializeMessageHandler(c);\n\n // 处理消息\n if (!this.mcpMessageHandler) {\n throw new Error(\"消息处理器初始化失败\");\n }\n const response = await this.mcpMessageHandler.handleMessage(message);\n\n // 更新统计信息\n this.metrics.totalMessages++;\n const responseTime = Date.now() - startTime;\n this.metrics.averageResponseTime =\n (this.metrics.averageResponseTime * (this.metrics.totalMessages - 1) +\n responseTime) /\n this.metrics.totalMessages;\n\n this.logger.debug(\"MCP POST 请求处理成功\", {\n method: message.method,\n messageId: messageId,\n responseTime: responseTime,\n isNotification: response === null,\n });\n\n // 对于通知消息,返回 204 No Content\n if (response === null) {\n return new Response(null, {\n status: HTTP_STATUS_CODES.NO_CONTENT,\n headers: {\n [HTTP_HEADERS.MCP_PROTOCOL_VERSION]: MCP_PROTOCOL_VERSIONS.DEFAULT,\n [HTTP_HEADERS.X_RESPONSE_TIME]: responseTime.toString(),\n },\n });\n }\n\n // 返回 JSON-RPC 响应\n return c.json(response, HTTP_STATUS_CODES.OK, {\n [HTTP_HEADERS.CONTENT_TYPE]: HTTP_CONTENT_TYPES.APPLICATION_JSON,\n [HTTP_HEADERS.MCP_PROTOCOL_VERSION]: MCP_PROTOCOL_VERSIONS.DEFAULT,\n [HTTP_HEADERS.X_RESPONSE_TIME]: responseTime.toString(),\n });\n } catch (error) {\n this.metrics.errorCount++;\n const responseTime = Date.now() - startTime;\n\n this.logger.error(\"处理 MCP POST 请求时出错:\", {\n error: error instanceof Error ? error.message : String(error),\n messageId: messageId,\n responseTime: responseTime,\n stack: error instanceof Error ? error.stack : undefined,\n });\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return this.createErrorResponse(\n -32603,\n `${HTTP_ERROR_MESSAGES.INTERNAL_ERROR}: ${errorMessage}`,\n messageId\n );\n }\n }\n\n /**\n * 验证 JSON-RPC 消息格式\n */\n private validateMessage(message: unknown): message is MCPMessage {\n if (!message || typeof message !== \"object\") {\n this.logger.debug(\"消息验证失败: 不是对象\");\n return false;\n }\n\n // 类型守卫:确保 message 是对象类型\n const msg = message as Record<string, unknown>;\n\n if (msg.jsonrpc !== JSONRPC_VERSION) {\n this.logger.debug(\"消息验证失败: jsonrpc 版本不正确\", {\n jsonrpc: msg.jsonrpc,\n });\n return false;\n }\n\n if (!msg.method || typeof msg.method !== \"string\") {\n this.logger.debug(\"消息验证失败: method 字段无效\", {\n method: msg.method,\n });\n return false;\n }\n\n // 验证 id 字段(如果存在)\n if (\n msg.id !== undefined &&\n typeof msg.id !== \"string\" &&\n typeof msg.id !== \"number\" &&\n msg.id !== null\n ) {\n this.logger.debug(\"消息验证失败: id 字段类型无效\", { id: msg.id });\n return false;\n }\n\n // 验证 params 字段(如果存在)\n if (msg.params !== undefined && typeof msg.params !== \"object\") {\n this.logger.debug(\"消息验证失败: params 字段类型无效\", {\n params: msg.params,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 创建错误响应\n */\n private createErrorResponse(\n code: number,\n message: string,\n id?: string | number | null\n ): Response {\n // 确保ID不为空,如果为空或未提供则生成默认ID\n const responseId = id ?? `error-${Date.now()}`;\n\n const errorResponse = {\n jsonrpc: JSONRPC_VERSION,\n error: {\n code,\n message,\n },\n id: responseId,\n };\n\n return new Response(JSON.stringify(errorResponse), {\n status: HTTP_STATUS_CODES.BAD_REQUEST,\n headers: {\n [HTTP_HEADERS.CONTENT_TYPE]: HTTP_CONTENT_TYPES.APPLICATION_JSON,\n [HTTP_HEADERS.MCP_PROTOCOL_VERSION]: MCP_PROTOCOL_VERSIONS.DEFAULT,\n },\n });\n }\n\n /**\n * 获取连接状态\n */\n getStatus() {\n return {\n isInitialized: this.mcpMessageHandler !== null,\n metrics: this.config.enableMetrics ? this.metrics : undefined,\n config: {\n maxMessageSize: this.config.maxMessageSize,\n },\n };\n }\n\n /**\n * 销毁处理器,清理所有资源\n */\n destroy(): void {\n this.logger.info(\"正在销毁 MCPRouteHandler\");\n\n // 清理消息处理器\n this.mcpMessageHandler = null;\n\n this.logger.info(\"MCPRouteHandler 销毁完成\");\n }\n}\n","/**\n * MCP服务错误类型定义\n *\n * 本模块提供了统一的错误处理框架,包括:\n * - 标准化的错误代码和分类\n * - 结构化的错误信息\n * - 可扩展的错误处理器\n * - 错误转换和格式化工具\n *\n * @module mcp-errors\n */\n\nimport { ErrorCategory } from \"./error-helper.js\";\n\n// 重新导出 ErrorCategory 以保持向后兼容性\nexport { ErrorCategory };\n\n/**\n * MCP错误代码枚举\n *\n * 定义了所有MCP服务相关的错误代码,用于错误分类和处理。\n * 错误代码按功能区域分组:配置、连接、操作、系统等。\n */\nexport enum MCPErrorCode {\n // 配置错误 - 服务配置相关的问题\n /** 服务已存在,尝试添加重复服务时使用 */\n SERVER_ALREADY_EXISTS = \"SERVER_ALREADY_EXISTS\",\n /** 服务未找到,操作不存在的服务时使用 */\n SERVER_NOT_FOUND = \"SERVER_NOT_FOUND\",\n /** 配置格式无效或内容不正确 */\n INVALID_CONFIG = \"INVALID_CONFIG\",\n /** 服务名称不符合规范 */\n INVALID_SERVICE_NAME = \"INVALID_SERVICE_NAME\",\n\n // 连接错误 - 网络连接和服务通信问题\n /** 无法建立到服务的连接 */\n CONNECTION_FAILED = \"CONNECTION_FAILED\",\n /** 连接超时 */\n CONNECTION_TIMEOUT = \"CONNECTION_TIMEOUT\",\n /** 服务暂时不可用 */\n SERVICE_UNAVAILABLE = \"SERVICE_UNAVAILABLE\",\n\n // 操作错误 - 服务操作过程中的问题\n /** 一般操作失败 */\n OPERATION_FAILED = \"OPERATION_FAILED\",\n /** 服务添加操作失败 */\n ADD_FAILED = \"ADD_FAILED\",\n /** 服务移除操作失败 */\n REMOVE_FAILED = \"REMOVE_FAILED\",\n /** 工具同步操作失败 */\n SYNC_FAILED = \"SYNC_FAILED\",\n\n // 系统错误 - 内部系统问题\n /** 内部系统错误 */\n INTERNAL_ERROR = \"INTERNAL_ERROR\",\n /** 配置更新操作失败 */\n CONFIG_UPDATE_FAILED = \"CONFIG_UPDATE_FAILED\",\n\n // 工具同步错误 - 工具管理相关错误\n /** 工具同步失败 */\n TOOL_SYNC_FAILED = \"TOOL_SYNC_FAILED\",\n /** 工具验证失败 */\n TOOL_VALIDATION_FAILED = \"TOOL_VALIDATION_FAILED\",\n /** 工具未找到 */\n TOOL_NOT_FOUND = \"TOOL_NOT_FOUND\",\n}\n\n/**\n * MCP错误严重级别\n */\nexport enum ErrorSeverity {\n LOW = \"low\", // 轻微错误,不影响主要功能\n MEDIUM = \"medium\", // 中等错误,影响部分功能\n HIGH = \"high\", // 严重错误,影响核心功能\n CRITICAL = \"critical\", // 致命错误,系统无法继续运行\n}\n\n/**\n * 错误详情接口\n */\nexport interface ErrorDetails {\n serverName?: string;\n config?: unknown;\n tools?: string[];\n timestamp: string;\n severity: ErrorSeverity;\n category: ErrorCategory;\n stack?: string;\n context?: Record<string, unknown>;\n operation?: string;\n errors?: string[];\n}\n\n/**\n * 标准化的MCP错误类\n */\nexport class MCPError extends Error {\n public readonly code: MCPErrorCode;\n public readonly severity: ErrorSeverity;\n public readonly category: ErrorCategory;\n public readonly details: ErrorDetails;\n public readonly timestamp: string;\n\n constructor(\n code: MCPErrorCode,\n message: string,\n severity: ErrorSeverity = ErrorSeverity.MEDIUM,\n category: ErrorCategory = ErrorCategory.SYSTEM,\n details: Partial<ErrorDetails> = {}\n ) {\n super(message);\n this.name = \"MCPError\";\n this.code = code;\n this.severity = severity;\n this.category = category;\n this.timestamp = new Date().toISOString();\n\n // 合并详情信息\n this.details = {\n ...details,\n timestamp: this.timestamp,\n severity: this.severity,\n category: this.category,\n stack: this.stack,\n };\n\n // 保持堆栈跟踪\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, MCPError);\n }\n }\n\n /**\n * 转换为JSON格式\n */\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n severity: this.severity,\n category: this.category,\n details: this.details,\n timestamp: this.timestamp,\n };\n }\n\n /**\n * 创建配置错误\n */\n static configError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.MEDIUM,\n ErrorCategory.CONFIGURATION,\n details\n );\n }\n\n /**\n * 创建连接错误\n */\n static connectionError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.HIGH,\n ErrorCategory.CONNECTION,\n details\n );\n }\n\n /**\n * 创建操作错误\n */\n static operationError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.MEDIUM,\n ErrorCategory.OPERATION,\n details\n );\n }\n\n /**\n * 创建系统错误\n */\n static systemError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.HIGH,\n ErrorCategory.SYSTEM,\n details\n );\n }\n\n /**\n * 创建验证错误\n */\n static validationError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.LOW,\n ErrorCategory.VALIDATION,\n details\n );\n }\n\n /**\n * 从普通错误创建MCPError\n */\n static fromError(\n error: Error,\n defaultCode: MCPErrorCode = MCPErrorCode.INTERNAL_ERROR,\n category: ErrorCategory = ErrorCategory.SYSTEM\n ): MCPError {\n return new MCPError(\n defaultCode,\n error.message,\n ErrorSeverity.MEDIUM,\n category,\n {\n stack: error.stack,\n context: { originalError: error.name },\n }\n );\n }\n}\n\n/**\n * 错误处理器接口\n */\nexport interface ErrorHandler {\n canHandle(error: Error): boolean;\n handle(error: Error, context?: Record<string, unknown>): MCPError | null;\n}\n\n/**\n * 默认错误处理器\n */\nexport class DefaultErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return !(error instanceof MCPError);\n }\n\n handle(error: Error, context?: Record<string, unknown>): MCPError {\n return MCPError.fromError(\n error,\n MCPErrorCode.INTERNAL_ERROR,\n ErrorCategory.SYSTEM\n );\n }\n}\n\n/**\n * 配置错误处理器\n */\nexport class ConfigErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return (\n error.message.includes(\"配置\") ||\n error.message.includes(\"config\") ||\n error.message.includes(\"JSON\") ||\n error.message.includes(\"解析\")\n );\n }\n\n handle(error: Error, context?: Record<string, unknown>): MCPError {\n return MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n `配置错误: ${error.message}`,\n { context }\n );\n }\n}\n\n/**\n * 连接错误处理器\n */\nexport class ConnectionErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return (\n error.message.includes(\"连接\") ||\n error.message.includes(\"connection\") ||\n error.message.includes(\"timeout\") ||\n error.message.includes(\"ECONNREFUSED\") ||\n error.message.includes(\"ENOTFOUND\")\n );\n }\n\n handle(error: Error, context?: Record<string, unknown>): MCPError {\n return MCPError.connectionError(\n MCPErrorCode.CONNECTION_FAILED,\n `连接失败: ${error.message}`,\n { context }\n );\n }\n}\n\n/**\n * 错误处理器注册表\n */\nexport class ErrorHandlerRegistry {\n private handlers: ErrorHandler[] = [];\n\n constructor() {\n // 注册默认处理器\n this.registerHandler(new ConfigErrorHandler());\n this.registerHandler(new ConnectionErrorHandler());\n this.registerHandler(new DefaultErrorHandler());\n }\n\n /**\n * 注册错误处理器\n */\n registerHandler(handler: ErrorHandler): void {\n this.handlers.unshift(handler); // 添加到前面,优先处理\n }\n\n /**\n * 处理错误\n */\n handleError(error: Error, context?: Record<string, unknown>): MCPError {\n // 如果已经是MCPError,直接返回\n if (error instanceof MCPError) {\n return error;\n }\n\n // 查找合适的处理器\n for (const handler of this.handlers) {\n if (handler.canHandle(error)) {\n const result = handler.handle(error, context);\n if (result) {\n return result;\n }\n }\n }\n\n // 如果没有处理器能处理,使用默认处理器\n return new DefaultErrorHandler().handle(error, context);\n }\n}\n\n/**\n * 全局错误处理器实例\n */\nexport const globalErrorHandler = new ErrorHandlerRegistry();\n","/**\n * MCP 服务管理 API 处理器\n *\n * 负责处理 MCP 服务的动态管理操作,包括:\n * - 服务的添加和删除(若需更新服务配置,请先删除后重新添加)\n * - 服务的停止和资源清理\n * - 服务状态查询\n * - 服务工具信息查询\n * - 配置验证和持久化\n *\n * 该处理器通过 MCPServiceManager 管理多个 MCP 服务实例,\n * 并通过 EventBus 发布(发射)服务状态变化事件。\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { ErrorCategory, MCPError, MCPErrorCode } from \"@/errors/mcp-errors.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { MCPService } from \"@/lib/mcp\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ConfigManager, MCPServerConfig } from \"@xiaozhi-client/config\";\nimport { normalizeServiceConfig } from \"@xiaozhi-client/config\";\nimport { TypeFieldNormalizer } from \"@xiaozhi-client/mcp-core\";\nimport type { Context } from \"hono\";\n\n/**\n * MCPServiceManager 扩展接口,用于访问私有属性\n * 这个接口定义了我们需要访问但实际上是私有的属性\n */\ninterface MCPServiceManagerAccess {\n services: Map<string, MCPService>;\n}\n\n/**\n * 配置详情接口,包含时间戳\n */\ninterface ConfigDetails {\n serverName?: string;\n config?: MCPServerConfig;\n tools?: string[];\n timestamp?: string;\n [key: string]: unknown; // 允许额外的属性\n}\n\n/**\n * MCP 服务添加请求接口(单服务格式)\n */\nexport interface MCPServerAddRequest {\n name: string;\n config: MCPServerConfig;\n}\n\n/**\n * MCP 服务批量添加请求接口(mcpServers 格式)\n */\nexport interface MCPServerBatchAddRequest {\n mcpServers: Record<string, MCPServerConfig>;\n}\n\n/**\n * MCP 服务添加操作结果\n */\nexport interface MCPServerAddResult {\n name: string;\n success: boolean;\n error?: string;\n config?: MCPServerConfig;\n tools?: string[];\n status?: string;\n}\n\n/**\n * MCP 服务批量添加响应\n */\nexport interface MCPServerBatchAddResponse {\n success: boolean;\n message: string;\n results: MCPServerAddResult[];\n addedCount: number;\n failedCount: number;\n}\n\n/**\n * MCP 服务状态接口\n */\nexport interface MCPServerStatus {\n name: string;\n status: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n connected: boolean;\n tools: string[];\n lastUpdated?: string;\n config: MCPServerConfig;\n}\n\n/**\n * MCP 服务列表响应接口\n */\nexport interface MCPServerListResponse {\n servers: MCPServerStatus[];\n total: number;\n}\n\n/**\n * 统一响应格式接口\n * 从 types/api.response 导入,保持类型一致性\n */\nexport type {\n ApiErrorResponse,\n ApiSuccessResponse,\n} from \"@/types/api.response.js\";\n\n/**\n * 配置验证结果接口\n */\nexport interface ValidationResult {\n isValid: boolean;\n errors: string[];\n}\n\n/**\n * MCP 服务 API 处理器\n */\nexport class MCPHandler {\n protected logger: Logger;\n private mcpServiceManager: MCPServiceManager;\n private configManager: ConfigManager;\n private statusCache: Map<string, MCPServerStatus>;\n\n constructor(\n mcpServiceManager: MCPServiceManager,\n configManager: ConfigManager\n ) {\n this.logger = logger;\n this.mcpServiceManager = mcpServiceManager;\n this.configManager = configManager;\n this.statusCache = new Map();\n }\n\n /**\n * 处理错误并返回MCPError\n */\n protected handleError(\n error: unknown,\n operation: string,\n context?: Record<string, unknown>\n ): MCPError {\n if (error instanceof MCPError) {\n this.logger.error(\"MCPError\", { error, operation, context });\n return error;\n }\n\n if (error instanceof Error) {\n let mcpError: MCPError;\n\n // 根据错误消息和操作类型确定错误类型\n if (\n error.message.includes(\"服务不存在\") ||\n error.message.includes(\"not found\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"已存在\") ||\n error.message.includes(\"already exists\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.SERVER_ALREADY_EXISTS,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"配置\") ||\n error.message.includes(\"config\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"连接\") ||\n error.message.includes(\"connection\")\n ) {\n mcpError = MCPError.connectionError(\n MCPErrorCode.CONNECTION_FAILED,\n error.message,\n { operation, context }\n );\n } else {\n mcpError = MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n error.message,\n { operation, context, stack: error.stack }\n );\n }\n\n this.logger.error(\"MCPError\", { error: mcpError, operation, context });\n return mcpError;\n }\n\n // 处理未知错误类型\n const mcpError = MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n String(error),\n { operation, context }\n );\n this.logger.error(\"MCPError\", { error: mcpError, operation, context });\n return mcpError;\n }\n\n /**\n * 添加 MCP 服务\n * POST /api/mcp-servers\n * 支持两种格式:\n * 1. 单服务格式:{ name: string, config: MCPServerConfig }\n * 2. 批量格式:{ mcpServers: Record<string, MCPServerConfig> }\n */\n async addMCPServer(c: Context<AppContext>): Promise<Response> {\n const startTime = Date.now();\n const requestData = await c.req.json();\n\n this.logger.info(\"addMCPServer\", {\n requestData,\n method: \"POST\",\n path: \"/api/mcp-servers\",\n });\n\n try {\n // 检测请求格式\n if (\"mcpServers\" in requestData) {\n // 批量格式\n const batchRequest = requestData as MCPServerBatchAddRequest;\n const result = await this.addMCPServersBatch(batchRequest);\n\n const duration = Date.now() - startTime;\n this.logger.info(\"addMCPServer\", {\n batch: true,\n addedCount: result.addedCount,\n failedCount: result.failedCount,\n duration,\n });\n\n return c.success(result, result.message, 201);\n }\n // 单服务格式\n const singleRequest = requestData as MCPServerAddRequest;\n const { name, config } = singleRequest;\n\n const result = await this.addMCPServerSingle(name, config);\n\n const duration = Date.now() - startTime;\n this.logger.info(\"addMCPServer\", {\n serverName: name,\n toolsCount: result.tools?.length || 0,\n duration,\n status: result.status,\n });\n\n return c.success(result, \"MCP 服务添加成功\", 201);\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServer\", {\n requestData,\n });\n\n // 根据错误类型确定HTTP状态码\n let statusCode = 500;\n if (mcpError.category === ErrorCategory.VALIDATION) {\n statusCode = 400;\n } else if (mcpError.category === ErrorCategory.CONFIGURATION) {\n if (mcpError.code === MCPErrorCode.SERVER_ALREADY_EXISTS) {\n statusCode = 409;\n } else {\n statusCode = 400;\n }\n } else if (mcpError.category === ErrorCategory.CONNECTION) {\n statusCode = 500; // 测试期望连接失败返回500而不是503\n }\n\n return c.fail(\n mcpError.code,\n mcpError.message,\n { error: mcpError.details },\n statusCode\n );\n }\n }\n\n /**\n * 处理单个 MCP 服务添加\n */\n private async addMCPServerSingle(\n name: string,\n config: MCPServerConfig\n ): Promise<MCPServerStatus> {\n this.logger.info(\"addMCPServerSingle\", {\n serverName: name,\n });\n\n // 标准化type字段格式(在try块外声明,确保catch块中可以访问)\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(\n config\n ) as MCPServerConfig;\n\n try {\n // 1. 验证服务名称\n const nameValidation = MCPServerConfigValidator.validateServiceName(name);\n if (!nameValidation.isValid) {\n const validationError = MCPError.validationError(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n { serverName: name, errors: nameValidation.errors }\n );\n this.logger.error(\"addMCPServerSingle\", {\n validationError,\n serverName: name,\n phase: \"name_validation\",\n });\n throw validationError;\n }\n\n // 2. 检查服务是否已存在\n if (\n MCPServerConfigValidator.checkServiceExists(name, this.configManager)\n ) {\n const existsError = MCPError.configError(\n MCPErrorCode.SERVER_ALREADY_EXISTS,\n \"MCP 服务已存在\",\n { serverName: name }\n );\n this.logger.error(\"addMCPServerSingle\", {\n existsError,\n serverName: name,\n phase: \"existence_check\",\n });\n throw existsError;\n }\n\n // 3. 验证服务配置\n const configValidation =\n MCPServerConfigValidator.validateConfig(normalizedConfig);\n if (!configValidation.isValid) {\n const configError = MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n configValidation.errors.join(\", \"),\n {\n serverName: name,\n config: normalizedConfig,\n errors: configValidation.errors,\n }\n );\n this.logger.error(\"addMCPServerSingle\", {\n configError,\n serverName: name,\n phase: \"config_validation\",\n });\n throw configError;\n }\n\n // 5. 添加服务到配置管理器\n this.configManager.updateMcpServer(name, normalizedConfig);\n this.logger.debug(\"服务配置已添加到配置管理器\", { serverName: name });\n\n // 6. 添加服务到 MCPServiceManager 并启动服务\n const mcpServiceConfig = normalizeServiceConfig(normalizedConfig);\n // 使用两参数形式传递 name 和 config\n this.mcpServiceManager.addServiceConfig(name, mcpServiceConfig);\n await this.mcpServiceManager.startService(name);\n this.logger.debug(\"服务已启动\", { serverName: name });\n\n // 6. 获取服务状态和工具列表\n const serviceStatus = this.getServiceStatus(name);\n const tools = this.getServiceTools(name);\n const toolNames = tools.map((tool) => tool.name);\n\n // 7. 发送事件通知\n getEventBus().emitEvent(\"mcp:server:added\", {\n serverName: name,\n config: normalizedConfig,\n tools: toolNames,\n timestamp: new Date(),\n });\n\n return {\n ...serviceStatus,\n tools: toolNames,\n };\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServerSingle\", {\n serverName: name,\n config: normalizedConfig,\n });\n this.logger.error(\"addMCPServerSingle\", {\n mcpError,\n serverName: name,\n });\n throw mcpError;\n }\n }\n\n /**\n * 获取服务状态信息\n */\n private getServiceStatus(serverName: string): MCPServerStatus {\n const config = this.configManager.getConfig();\n const serverConfig = config.mcpServers[serverName];\n\n if (!serverConfig) {\n return {\n name: serverName,\n status: \"disconnected\",\n connected: false,\n tools: [],\n config: {} as MCPServerConfig,\n };\n }\n\n // 尝试从 MCPServiceManager 获取实际状态\n try {\n const managerAccess = this\n .mcpServiceManager as unknown as MCPServiceManagerAccess;\n const service = managerAccess.services.get(serverName);\n\n if (service?.isConnected?.()) {\n const currentTools = service.getTools().map((tool: Tool) => tool.name);\n const status = {\n name: serverName,\n status: \"connected\" as const,\n connected: true,\n tools: currentTools,\n lastUpdated: new Date().toISOString(),\n config: serverConfig,\n };\n\n // 检查状态变化并发出事件\n this.checkAndEmitStatusChange(serverName, status);\n return status;\n }\n } catch (error) {\n this.logger.debug(`获取服务 ${serverName} 状态时出错:`, error);\n }\n\n const status = {\n name: serverName,\n status: \"disconnected\" as const,\n connected: false,\n tools: [],\n config: serverConfig,\n };\n\n // 检查状态变化并发出事件\n this.checkAndEmitStatusChange(serverName, status);\n return status;\n }\n\n /**\n * 检查状态变化并发出事件\n */\n private checkAndEmitStatusChange(\n serverName: string,\n newStatus: MCPServerStatus\n ): void {\n // 获取之前的状态(简单的内存缓存)\n const previousStatus = this.getPreviousStatus(serverName);\n\n if (previousStatus && previousStatus.status !== newStatus.status) {\n this.logger.info(\n `服务 ${serverName} 状态变化: ${previousStatus.status} -> ${newStatus.status}`\n );\n\n // 发射状态变化事件\n getEventBus().emitEvent(\"mcp:server:status_changed\", {\n serverName,\n oldStatus: previousStatus.status,\n newStatus: newStatus.status,\n timestamp: new Date(),\n reason:\n newStatus.status === \"connected\"\n ? \"connection_established\"\n : \"connection_lost\",\n });\n\n // 如果工具列表发生变化,发出工具更新事件\n if (previousStatus.tools !== newStatus.tools) {\n const addedTools = newStatus.tools.filter(\n (tool) => !previousStatus.tools.includes(tool)\n );\n const removedTools = previousStatus.tools.filter(\n (tool) => !newStatus.tools.includes(tool)\n );\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n getEventBus().emitEvent(\"mcp:server:tools:updated\", {\n serverName,\n tools: newStatus.tools,\n addedTools,\n removedTools,\n timestamp: new Date(),\n });\n }\n }\n }\n\n // 更新状态缓存\n this.updateStatusCache(serverName, newStatus);\n }\n\n /**\n * 获取之前的状态(简化实现)\n */\n private getPreviousStatus(serverName: string): MCPServerStatus | null {\n // 这里使用一个简单的Map来缓存状态\n // 在实际生产环境中,可能需要更持久化的缓存方案\n return this.statusCache.get(serverName) || null;\n }\n\n /**\n * 更新状态缓存\n */\n private updateStatusCache(serverName: string, status: MCPServerStatus): void {\n this.statusCache.set(serverName, status);\n }\n\n /**\n * 获取服务工具列表\n */\n private getServiceTools(serverName: string): Tool[] {\n try {\n const managerAccess = this\n .mcpServiceManager as unknown as MCPServiceManagerAccess;\n const service = managerAccess.services.get(serverName);\n\n if (service?.getTools) {\n return service.getTools();\n }\n } catch (error) {\n this.logger.debug(`获取服务 ${serverName} 工具列表时出错:`, error);\n }\n\n return [];\n }\n\n /**\n * 移除 MCP 服务\n * DELETE /api/mcp-servers/:serverName\n */\n async removeMCPServer(c: Context<AppContext>): Promise<Response> {\n try {\n // 1. 从路径参数获取服务名称\n const serverName = c.req.param(\"serverName\");\n\n // 验证参数存在性\n if (!serverName) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n \"服务名称不能为空\",\n {},\n 400\n );\n }\n\n // 2. 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n { serverName },\n 400\n );\n }\n\n // 3. 检查服务是否存在\n if (\n !MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n \"MCP 服务不存在\",\n { serverName },\n 404\n );\n }\n\n // 4. 获取服务当前的工具列表(用于事件通知)\n const currentTools = this.getServiceTools(serverName).map(\n (tool) => tool.name\n );\n\n // 5. 停止服务并清理资源\n try {\n await this.mcpServiceManager.stopService(serverName);\n } catch (error) {\n this.logger.warn(`停止服务 ${serverName} 失败:`, error);\n // 即使停止失败,也继续执行配置移除\n }\n\n // 6. 移除服务配置\n this.mcpServiceManager.removeServiceConfig(serverName);\n this.configManager.removeMcpServer(serverName);\n\n // 7. 发送事件通知\n getEventBus().emitEvent(\"mcp:server:removed\", {\n serverName,\n affectedTools: currentTools,\n timestamp: new Date(),\n });\n\n // 8. 返回成功响应\n return c.success(\n {\n name: serverName,\n operation: \"removed\",\n affectedTools: currentTools,\n },\n \"MCP 服务移除成功\"\n );\n } catch (error) {\n this.logger.error(\"移除 MCP 服务失败:\", error);\n\n // 处理不同类型的错误\n if (error instanceof Error) {\n if (error.message.includes(\"服务不存在\")) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message,\n undefined,\n 404\n );\n }\n\n if (error.message.includes(\"配置更新\")) {\n return c.fail(\n MCPErrorCode.CONFIG_UPDATE_FAILED,\n error.message,\n undefined,\n 500\n );\n }\n }\n\n // 其他未知错误\n return c.fail(\n MCPErrorCode.REMOVE_FAILED,\n \"移除 MCP 服务时发生错误\",\n { error: error instanceof Error ? error.message : String(error) },\n 500\n );\n }\n }\n\n /**\n * 获取 MCP 服务状态\n * GET /api/mcp-servers/:serverName/status\n */\n async getMCPServerStatus(c: Context<AppContext>): Promise<Response> {\n try {\n // 1. 从路径参数获取服务名称\n const serverName = c.req.param(\"serverName\");\n\n // 验证参数存在性\n if (!serverName) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n \"服务名称不能为空\",\n {},\n 400\n );\n }\n\n // 2. 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n return c.fail(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n { serverName },\n 400\n );\n }\n\n // 3. 检查服务是否存在\n if (\n !MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n \"MCP 服务不存在\",\n { serverName },\n 404\n );\n }\n\n // 4. 获取服务状态\n const serviceStatus = this.getServiceStatus(serverName);\n\n // 5. 返回成功响应\n return c.success(serviceStatus, \"MCP 服务状态获取成功\");\n } catch (error) {\n this.logger.error(\"获取 MCP 服务状态失败:\", error);\n\n // 处理不同类型的错误\n if (error instanceof Error) {\n if (error.message.includes(\"服务不存在\")) {\n return c.fail(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message,\n undefined,\n 404\n );\n }\n }\n\n // 其他未知错误\n return c.fail(\n MCPErrorCode.INTERNAL_ERROR,\n \"获取 MCP 服务状态时发生内部错误\",\n { error: error instanceof Error ? error.message : String(error) },\n 500\n );\n }\n }\n\n /**\n * 列出所有 MCP 服务\n * GET /api/mcp-servers\n */\n async listMCPServers(c: Context<AppContext>): Promise<Response> {\n try {\n // 1. 获取所有配置的 MCP 服务\n const config = this.configManager.getConfig();\n const mcpServers = config.mcpServers || {};\n\n // 2. 构建服务列表\n const servers: MCPServerStatus[] = [];\n\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n const serviceStatus = this.getServiceStatus(serverName);\n servers.push(serviceStatus);\n }\n\n // 3. 构建响应数据\n const listResponse: MCPServerListResponse = {\n servers,\n total: servers.length,\n };\n\n // 4. 返回成功响应\n return c.success(listResponse, \"MCP 服务列表获取成功\");\n } catch (error) {\n this.logger.error(\"列出 MCP 服务失败:\", error);\n\n // 其他未知错误\n return c.fail(\n MCPErrorCode.INTERNAL_ERROR,\n \"列出 MCP 服务时发生内部错误\",\n { error: error instanceof Error ? error.message : String(error) },\n 500\n );\n }\n }\n\n /**\n * 处理批量 MCP 服务添加\n */\n private async addMCPServersBatch(\n batchRequest: MCPServerBatchAddRequest\n ): Promise<MCPServerBatchAddResponse> {\n const { mcpServers } = batchRequest;\n const serverNames = Object.keys(mcpServers);\n\n this.logger.info(\"addMCPServersBatch\", {\n serverCount: serverNames.length,\n serverNames,\n });\n\n if (serverNames.length === 0) {\n throw MCPError.validationError(\n MCPErrorCode.INVALID_CONFIG,\n \"批量添加请求中的服务列表为空\"\n );\n }\n\n const results: MCPServerAddResult[] = [];\n const successfullyAddedServers: string[] = [];\n\n // 第一阶段:验证所有服务配置\n const validationResult = this.validateBatchServers(mcpServers);\n if (!validationResult.isValid) {\n throw MCPError.validationError(\n MCPErrorCode.INVALID_CONFIG,\n validationResult.errors.join(\", \")\n );\n }\n\n try {\n // 第二阶段:逐个添加服务,记录成功和失败\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n // 标准化type字段格式(在try块外声明,确保catch块中可以访问)\n const normalizedServerConfig = TypeFieldNormalizer.normalizeTypeField(\n serverConfig\n ) as MCPServerConfig;\n\n try {\n const result = await this.addMCPServerSingle(\n serverName,\n normalizedServerConfig\n );\n\n results.push({\n name: serverName,\n success: true,\n config: normalizedServerConfig,\n tools: result.tools,\n status: result.status,\n });\n\n successfullyAddedServers.push(serverName);\n\n this.logger.debug(\"批量添加:服务添加成功\", {\n serverName,\n toolsCount: result.tools?.length || 0,\n });\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServersBatch\", {\n serverName,\n serverConfig: normalizedServerConfig,\n });\n\n results.push({\n name: serverName,\n success: false,\n error: mcpError.message,\n config: normalizedServerConfig,\n });\n\n this.logger.warn(\"批量添加:服务添加失败\", {\n serverName,\n error: mcpError.message,\n });\n }\n }\n\n // 第三阶段:统计结果\n const addedCount = successfullyAddedServers.length;\n const failedCount = serverNames.length - addedCount;\n\n // 第四阶段:如果完全失败,抛出异常;部分成功则返回结果\n if (addedCount === 0) {\n throw MCPError.configError(\n MCPErrorCode.ADD_FAILED,\n \"批量添加失败:所有服务都无法添加\"\n );\n }\n\n // 发送批量添加事件\n getEventBus().emitEvent(\"mcp:server:batch_added\", {\n totalServers: serverNames.length,\n addedCount,\n failedCount,\n successfullyAddedServers,\n results,\n timestamp: new Date(),\n });\n\n const response: MCPServerBatchAddResponse = {\n success: addedCount > 0,\n message:\n addedCount === serverNames.length\n ? `批量添加成功:已添加 ${addedCount} 个服务`\n : `批量添加部分成功:成功添加 ${addedCount} 个服务,失败 ${failedCount} 个服务`,\n results,\n addedCount,\n failedCount,\n };\n\n this.logger.info(\"addMCPServersBatch\", {\n totalServers: serverNames.length,\n addedCount,\n failedCount,\n });\n\n return response;\n } catch (error) {\n // 如果发生未处理的错误,尝试回滚已成功添加的服务\n if (successfullyAddedServers.length > 0) {\n await this.rollbackBatchAdd(successfullyAddedServers);\n }\n\n if (error instanceof MCPError) {\n throw error;\n }\n throw MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n `批量添加过程中发生错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 验证批量服务配置\n */\n private validateBatchServers(\n mcpServers: Record<string, MCPServerConfig>\n ): ValidationResult {\n const errors: string[] = [];\n\n if (!mcpServers || typeof mcpServers !== \"object\") {\n errors.push(\"mcpServers 必须是一个对象\");\n return { isValid: false, errors };\n }\n\n const serverNames = Object.keys(mcpServers);\n if (serverNames.length === 0) {\n errors.push(\"mcpServers 对象不能为空\");\n return { isValid: false, errors };\n }\n\n if (serverNames.length > 50) {\n errors.push(\"批量添加的服务数量不能超过 50 个\");\n return { isValid: false, errors };\n }\n\n // 验证每个服务\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n // 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n errors.push(\n `服务 \"${serverName}\" 名称无效: ${nameValidation.errors.join(\", \")}`\n );\n continue;\n }\n\n // 检查是否已存在\n if (\n MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n errors.push(`服务 \"${serverName}\" 已存在`);\n continue;\n }\n\n // 标准化type字段格式\n const normalizedServerConfig = TypeFieldNormalizer.normalizeTypeField(\n serverConfig\n ) as MCPServerConfig;\n\n // 验证配置\n const configValidation = MCPServerConfigValidator.validateConfig(\n normalizedServerConfig\n );\n if (!configValidation.isValid) {\n errors.push(\n `服务 \"${serverName}\" 配置无效: ${configValidation.errors.join(\", \")}`\n );\n }\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 回滚批量添加的服务\n */\n private async rollbackBatchAdd(serverNames: string[]): Promise<void> {\n this.logger.info(\"开始回滚批量添加的服务\", { serverNames });\n\n const rollbackResults: string[] = [];\n const rollbackFailures: string[] = [];\n\n for (const serverName of serverNames) {\n try {\n // 停止服务\n try {\n await this.mcpServiceManager.stopService(serverName);\n } catch (error) {\n this.logger.warn(`回滚时停止服务 ${serverName} 失败:`, error);\n }\n\n // 移除服务配置\n this.mcpServiceManager.removeServiceConfig(serverName);\n this.configManager.removeMcpServer(serverName);\n\n rollbackResults.push(serverName);\n\n // 发送回滚事件\n getEventBus().emitEvent(\"mcp:server:rollback\", {\n serverName,\n timestamp: new Date(),\n });\n } catch (error) {\n const mcpError = this.handleError(error, \"rollbackBatchAdd\", {\n serverName,\n });\n rollbackFailures.push(serverName);\n\n this.logger.error(`回滚服务 ${serverName} 失败:`, mcpError.message);\n }\n }\n\n if (rollbackFailures.length > 0) {\n this.logger.warn(\"批量添加回滚部分失败\", {\n totalServers: serverNames.length,\n rollbackedCount: rollbackResults.length,\n failedCount: rollbackFailures.length,\n failedServers: rollbackFailures,\n });\n } else {\n this.logger.info(\"批量添加回滚成功\", {\n totalServers: serverNames.length,\n rollbackedCount: rollbackResults.length,\n });\n }\n }\n}\n\n/**\n * MCP 服务配置验证工具命名空间\n */\nexport namespace MCPServerConfigValidator {\n /**\n * 验证服务配置\n */\n export function validateConfig(config: MCPServerConfig): ValidationResult {\n const errors: string[] = [];\n\n // 验证配置基本结构\n if (!config || typeof config !== \"object\") {\n errors.push(\"配置必须是一个对象\");\n return { isValid: false, errors };\n }\n\n // 根据类型验证配置\n if (\"command\" in config) {\n // LocalMCPServerConfig\n if (!config.command || typeof config.command !== \"string\") {\n errors.push(\"本地服务必须提供有效的命令\");\n }\n if (config.args && !Array.isArray(config.args)) {\n errors.push(\"参数必须是数组\");\n }\n if (config.env && typeof config.env !== \"object\") {\n errors.push(\"环境变量必须是对象\");\n }\n } else if (\"url\" in config) {\n // SSEMCPServerConfig 或 StreamableHTTPMCPServerConfig\n if (!config.url || typeof config.url !== \"string\") {\n errors.push(\"远程服务必须提供有效的 URL\");\n }\n try {\n new URL(config.url);\n } catch {\n errors.push(\"URL 格式无效\");\n }\n } else {\n errors.push(\"配置必须包含 command 或 url 字段\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 验证服务名称\n */\n export function validateServiceName(name: string): ValidationResult {\n const errors: string[] = [];\n\n if (!name || typeof name !== \"string\") {\n errors.push(\"服务名称必须是非空字符串\");\n return { isValid: false, errors };\n }\n\n if (name.length < 1 || name.length > 50) {\n errors.push(\"服务名称长度必须在 1-50 个字符之间\");\n }\n\n if (!/^[a-zA-Z0-9_-]+$/.test(name)) {\n errors.push(\"服务名称只能包含字母、数字、下划线和连字符\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 检查服务是否已存在\n */\n export function checkServiceExists(\n name: string,\n configManager: ConfigManager\n ): boolean {\n const config = configManager.getConfig();\n return config.mcpServers && name in config.mcpServers;\n }\n}\n","/**\n * 服务 API HTTP 路由处理器\n * 提供服务启动、停止、重启等相关的 RESTful API 接口\n */\nimport { spawn } from \"node:child_process\";\nimport type { ChildProcess } from \"node:child_process\";\nimport { logger } from \"@/Logger.js\";\nimport type { Logger } from \"@/Logger.js\";\nimport { SERVICE_RESTART_DELAYS } from \"@/constants/timeout.constants.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { StatusService } from \"@/services/status.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { requireMCPServiceManager } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 服务 API 处理器\n */\nexport class ServiceApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(statusService: StatusService) {\n this.logger = logger;\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 通用的 xiaozhi 进程启动方法\n * @param args 命令行参数(如 [\"start\", \"--daemon\"])\n * @returns 启动的子进程\n */\n private spawnXiaozhiProcess(args: string[]): ChildProcess {\n const child = spawn(\"xiaozhi\", args, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(`MCP 服务命令已发送: xiaozhi ${args.join(\" \")}`);\n\n return child;\n }\n\n /**\n * 重启服务\n * POST /api/services/restart\n */\n async restartService(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理服务重启请求\");\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n serviceName: \"unknown\", // 由于是HTTP API触发的,服务名未知\n source: \"http-api\",\n delay: 0,\n attempt: 1,\n timestamp: Date.now(),\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n\n // 从 Context 获取 MCP 服务管理器\n const mcpServiceManager = requireMCPServiceManager(c);\n\n // 异步执行重启,不阻塞响应\n setTimeout(async () => {\n try {\n await this.executeRestart(mcpServiceManager);\n // 服务重启需要一些时间,延迟发送成功状态\n setTimeout(() => {\n this.statusService.updateRestartStatus(\"completed\");\n }, SERVICE_RESTART_DELAYS.SUCCESS_NOTIFICATION_DELAY);\n } catch (error) {\n c.get(\"logger\").error(\"服务重启失败:\", error);\n this.statusService.updateRestartStatus(\n \"failed\",\n error instanceof Error ? error.message : \"未知错误\"\n );\n }\n }, SERVICE_RESTART_DELAYS.EXECUTION_DELAY);\n\n return c.success(null, \"重启请求已接收\");\n } catch (error) {\n c.get(\"logger\").error(\"处理重启请求失败:\", error);\n return c.fail(\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 执行服务重启\n * @param mcpServiceManager MCP 服务管理器实例\n */\n private async executeRestart(\n mcpServiceManager: MCPServiceManager\n ): Promise<void> {\n this.logger.info(\"正在重启 MCP 服务...\");\n\n try {\n // 获取当前服务状态\n const status = mcpServiceManager.getStatus();\n\n if (!status.isRunning) {\n this.logger.warn(\"MCP 服务未运行,尝试启动服务\");\n\n // 如果服务未运行,尝试启动服务\n this.spawnXiaozhiProcess([\"start\", \"--daemon\"]);\n return;\n }\n\n // 执行重启命令,始终使用 daemon 模式\n this.spawnXiaozhiProcess([\"restart\", \"--daemon\"]);\n } catch (error) {\n this.logger.error(\"重启服务失败:\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务\n * POST /api/services/stop\n */\n async stopService(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理服务停止请求\");\n\n // 执行停止命令\n this.spawnXiaozhiProcess([\"stop\"]);\n\n return c.success(null, \"停止请求已接收\");\n } catch (error) {\n c.get(\"logger\").error(\"处理停止请求失败:\", error);\n return c.fail(\n \"STOP_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理停止请求失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 启动服务\n * POST /api/services/start\n */\n async startService(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理服务启动请求\");\n\n // 执行启动命令\n this.spawnXiaozhiProcess([\"start\", \"--daemon\"]);\n\n return c.success(null, \"启动请求已接收\");\n } catch (error) {\n c.get(\"logger\").error(\"处理启动请求失败:\", error);\n return c.fail(\n \"START_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理启动请求失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取服务状态\n * GET /api/services/status\n */\n async getServiceStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取服务状态请求\");\n\n const mcpServiceManager = requireMCPServiceManager(c);\n const status = mcpServiceManager.getStatus();\n\n c.get(\"logger\").debug(\"获取服务状态成功\");\n return c.success(status);\n } catch (error) {\n c.get(\"logger\").error(\"获取服务状态失败:\", error);\n return c.fail(\n \"SERVICE_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务状态失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取服务健康状态\n * GET /api/services/health\n */\n async getServiceHealth(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取服务健康状态请求\");\n\n // 简单的健康检查\n const health = {\n status: \"healthy\",\n timestamp: Date.now(),\n uptime: process.uptime(),\n memory: process.memoryUsage(),\n version: process.version,\n };\n\n c.get(\"logger\").debug(\"获取服务健康状态成功\");\n return c.success(health);\n } catch (error) {\n c.get(\"logger\").error(\"获取服务健康状态失败:\", error);\n return c.fail(\n \"SERVICE_HEALTH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务健康状态失败\",\n undefined,\n 500\n );\n }\n }\n}\n","/**\n * 静态文件 HTTP 路由处理器\n * 负责处理前端静态资源的请求和响应,支持多种构建路径的自动识别和文件访问\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { HTTP_CONTENT_TYPES, HTTP_STATUS_CODES } from \"@/constants/index.js\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 静态文件处理器\n */\nexport class StaticFileHandler extends BaseHandler {\n private logger: Logger;\n private webPath: string | null = null;\n\n constructor() {\n super();\n this.logger = logger;\n this.initializeWebPath();\n }\n\n /**\n * 初始化 Web 路径\n */\n private initializeWebPath(): void {\n try {\n // 获取当前文件所在目录\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n logger.debug(`当前文件目录: ${__dirname}`);\n\n // 确定web目录路径\n // 支持 Nx 构建的 dist/frontend 目录结构\n const possibleWebPaths = [\n // Nx 构建的主要路径:dist/frontend/\n // 对于 dist/backend/handlers/StaticFileHandler.js -> ../../../frontend\n // 对于 dist/backend/cli.js -> ../../frontend\n // 对于 dist/cli.js -> ../frontend\n join(__dirname, \"..\", \"..\", \"..\", \"frontend\"),\n join(__dirname, \"..\", \"..\", \"frontend\"),\n join(__dirname, \"..\", \"frontend\"),\n\n // 兼容旧构建路径:从 dist 目录向上查找 apps/frontend/dist\n join(__dirname, \"..\", \"..\", \"apps\", \"frontend\", \"dist\"),\n join(__dirname, \"..\", \"apps\", \"frontend\", \"dist\"),\n\n // 备用路径:查找未构建的 apps/frontend 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"apps\", \"frontend\"),\n join(__dirname, \"..\", \"apps\", \"frontend\"),\n\n // 兼容路径:保持对旧 web 目录的支持(向后兼容)\n join(__dirname, \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"web\", \"dist\"),\n\n // 备用兼容路径:查找未构建的 web 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"web\"),\n join(__dirname, \"..\", \"web\"),\n\n // 兜底路径:从源码目录查找(开发模式下的源码执行)\n join(__dirname, \"..\", \"..\", \"..\", \"apps\", \"frontend\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"apps\", \"frontend\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\"),\n ];\n\n // 查找第一个存在的路径\n this.webPath =\n possibleWebPaths.find((p) => {\n const exists = existsSync(p);\n logger.debug(`检查路径 ${p}: ${exists ? \"存在\" : \"不存在\"}`);\n return exists;\n }) || null;\n\n if (this.webPath) {\n logger.debug(`静态文件服务路径: ${this.webPath}`);\n } else {\n logger.warn(\"未找到静态文件目录\");\n logger.debug(\"尝试的路径:\", possibleWebPaths);\n }\n } catch (error) {\n logger.error(\"初始化静态文件路径失败:\", error);\n }\n }\n\n /**\n * 处理静态文件请求\n * GET /*\n */\n async handleStaticFile(c: Context): Promise<Response> {\n const pathname = new URL(c.req.url).pathname;\n\n try {\n c.logger.debug(`处理静态文件请求: ${pathname}`);\n\n if (!this.webPath) {\n return this.createErrorPage(c, \"找不到前端资源文件\");\n }\n\n // 处理路径\n let filePath = pathname;\n if (filePath === \"/\") {\n filePath = \"/index.html\";\n }\n\n // 安全性检查:防止路径遍历\n if (filePath.includes(\"..\")) {\n c.logger.warn(`路径遍历攻击尝试: ${filePath}`);\n return c.text(\"Forbidden\", HTTP_STATUS_CODES.FORBIDDEN);\n }\n\n const fullPath = join(this.webPath, filePath);\n\n // 检查文件是否存在\n if (!existsSync(fullPath)) {\n // 对于 SPA,返回 index.html\n const indexPath = join(this.webPath, \"index.html\");\n if (existsSync(indexPath)) {\n c.logger.debug(`SPA 回退到 index.html: ${pathname}`);\n return this.serveFile(c, indexPath, HTTP_CONTENT_TYPES.TEXT_HTML);\n }\n\n c.logger.debug(`文件不存在: ${fullPath}`);\n return c.text(\"Not Found\", HTTP_STATUS_CODES.NOT_FOUND);\n }\n\n // 确定 Content-Type\n const contentType = this.getContentType(fullPath);\n\n c.logger.debug(`服务静态文件: ${fullPath}, Content-Type: ${contentType}`);\n return this.serveFile(c, fullPath, contentType);\n } catch (error) {\n c.logger.error(`服务静态文件错误 (${pathname}):`, error);\n return c.text(\n \"Internal Server Error\",\n HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * 服务文件\n */\n private async serveFile(\n c: Context,\n filePath: string,\n contentType: string\n ): Promise<Response> {\n try {\n const content = await readFile(filePath);\n\n // 对于文本文件,返回字符串;对于二进制文件,返回 ArrayBuffer\n if (\n contentType.startsWith(\"text/\") ||\n contentType.includes(\"javascript\") ||\n contentType.includes(\"json\")\n ) {\n return c.text(content.toString(), 200, { \"Content-Type\": contentType });\n }\n\n return c.body(new Uint8Array(content), 200, {\n \"Content-Type\": contentType,\n });\n } catch (error) {\n logger.error(`读取文件失败: ${filePath}`, error);\n throw error;\n }\n }\n\n /**\n * 获取文件的 Content-Type\n */\n private getContentType(filePath: string): string {\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n\n const contentTypes: Record<string, string> = {\n html: HTTP_CONTENT_TYPES.TEXT_HTML,\n htm: HTTP_CONTENT_TYPES.TEXT_HTML,\n js: HTTP_CONTENT_TYPES.APPLICATION_JAVASCRIPT,\n mjs: HTTP_CONTENT_TYPES.APPLICATION_JAVASCRIPT,\n css: HTTP_CONTENT_TYPES.TEXT_CSS,\n json: HTTP_CONTENT_TYPES.APPLICATION_JSON,\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n svg: \"image/svg+xml\",\n ico: \"image/x-icon\",\n woff: \"font/woff\",\n woff2: \"font/woff2\",\n ttf: \"font/ttf\",\n eot: \"application/vnd.ms-fontobject\",\n pdf: HTTP_CONTENT_TYPES.APPLICATION_PDF,\n txt: HTTP_CONTENT_TYPES.TEXT_PLAIN,\n xml: HTTP_CONTENT_TYPES.APPLICATION_XML,\n zip: HTTP_CONTENT_TYPES.APPLICATION_ZIP,\n tar: \"application/x-tar\",\n gz: \"application/gzip\",\n };\n\n return (\n contentTypes[ext || \"\"] || HTTP_CONTENT_TYPES.APPLICATION_OCTET_STREAM\n );\n }\n\n /**\n * 创建错误页面\n */\n private createErrorPage(c: Context, message: string): Response {\n const errorHtml = `\n <!DOCTYPE html>\n <html>\n <head>\n <title>小智配置管理</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 800px;\n margin: 50px auto;\n padding: 20px;\n line-height: 1.6;\n color: #333;\n }\n .error {\n color: #e53e3e;\n background: #fed7d7;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #e53e3e;\n }\n .info {\n background: #e6f3ff;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #0066cc;\n margin-top: 20px;\n }\n pre {\n background: #f5f5f5;\n padding: 10px;\n border-radius: 4px;\n overflow-x: auto;\n }\n h1 {\n color: #2d3748;\n margin-bottom: 20px;\n }\n </style>\n </head>\n <body>\n <h1>小智配置管理</h1>\n <div class=\"error\">\n <p><strong>错误:</strong>${message}</p>\n </div>\n <div class=\"info\">\n <p><strong>解决方案:</strong></p>\n <p>请先构建前端项目:</p>\n <pre>cd apps/frontend && pnpm install && pnpm build</pre>\n <p><em>如果上面的路径不存在,可以尝试旧路径:</em></p>\n <pre>cd web && pnpm install && pnpm build</pre>\n <p>然后重新启动服务器。</p>\n </div>\n </body>\n </html>\n `;\n\n return c.html(errorHtml);\n }\n\n /**\n * 检查静态文件目录是否存在\n */\n isWebPathAvailable(): boolean {\n return this.webPath !== null && existsSync(this.webPath);\n }\n\n /**\n * 获取静态文件目录路径\n */\n getWebPath(): string | null {\n return this.webPath;\n }\n\n /**\n * 重新初始化 Web 路径\n */\n reinitializeWebPath(): void {\n this.initializeWebPath();\n }\n}\n","/**\n * 状态 API HTTP 路由处理器\n * 提供客户端状态、服务状态、心跳等状态相关的 RESTful API 接口\n */\nimport type { StatusService } from \"@/services/status.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 状态 API 处理器\n */\nexport class StatusApiHandler extends BaseHandler {\n private statusService: StatusService;\n\n constructor(statusService: StatusService) {\n super();\n this.statusService = statusService;\n }\n\n /**\n * 获取完整状态\n * GET /api/status\n */\n async getStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取状态请求\");\n const status = this.statusService.getFullStatus();\n c.get(\"logger\").debug(\"获取状态成功\");\n return c.success(status);\n } catch (error) {\n return this.handleError(c, error, \"获取状态\", \"STATUS_READ_ERROR\");\n }\n }\n\n /**\n * 获取客户端状态\n * GET /api/status/client\n */\n async getClientStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取客户端状态请求\");\n const clientStatus = this.statusService.getClientStatus();\n c.get(\"logger\").debug(\"获取客户端状态成功\");\n return c.success(clientStatus);\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取客户端状态\",\n \"CLIENT_STATUS_READ_ERROR\"\n );\n }\n }\n\n /**\n * 获取重启状态\n * GET /api/status/restart\n */\n async getRestartStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取重启状态请求\");\n const restartStatus = this.statusService.getRestartStatus();\n c.get(\"logger\").debug(\"获取重启状态成功\");\n return c.success(restartStatus);\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取重启状态\",\n \"RESTART_STATUS_READ_ERROR\"\n );\n }\n }\n\n /**\n * 检查客户端是否连接\n * GET /api/status/connected\n */\n async checkClientConnected(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理检查客户端连接请求\");\n const connected = this.statusService.isClientConnected();\n c.get(\"logger\").debug(`客户端连接状态: ${connected}`);\n return c.success({ connected });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"检查客户端连接\",\n \"CLIENT_CONNECTION_CHECK_ERROR\"\n );\n }\n }\n\n /**\n * 获取最后心跳时间\n * GET /api/status/heartbeat\n */\n async getLastHeartbeat(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取最后心跳时间请求\");\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n c.get(\"logger\").debug(\"获取最后心跳时间成功\");\n return c.success({ lastHeartbeat });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取最后心跳时间\",\n \"HEARTBEAT_READ_ERROR\"\n );\n }\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n * GET /api/status/mcp-servers\n */\n async getActiveMCPServers(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取活跃 MCP 服务器请求\");\n const servers = this.statusService.getActiveMCPServers();\n c.get(\"logger\").debug(\"获取活跃 MCP 服务器成功\");\n return c.success({ servers });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取活跃 MCP 服务器\",\n \"ACTIVE_MCP_SERVERS_READ_ERROR\"\n );\n }\n }\n\n /**\n * 更新客户端状态\n * PUT /api/status/client\n */\n async updateClientStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理更新客户端状态请求\");\n const statusUpdate = await this.parseJsonBody<Record<string, unknown>>(\n c,\n \"请求体必须是有效的状态对象\"\n );\n\n // 验证请求体\n if (!statusUpdate || typeof statusUpdate !== \"object\") {\n return c.fail(\n \"INVALID_REQUEST_BODY\",\n \"请求体必须是有效的状态对象\",\n undefined,\n 400\n );\n }\n\n this.statusService.updateClientInfo(statusUpdate, \"http-api\");\n c.get(\"logger\").info(\"客户端状态更新成功\");\n\n return c.success(undefined, \"客户端状态更新成功\");\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"更新客户端状态\",\n \"CLIENT_STATUS_UPDATE_ERROR\",\n \"更新客户端状态失败\",\n 400\n );\n }\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n * PUT /api/status/mcp-servers\n */\n async setActiveMCPServers(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理设置活跃 MCP 服务器请求\");\n const { servers } = await this.parseJsonBody<{ servers: string[] }>(\n c,\n \"请求体格式错误\"\n );\n\n // 验证请求体\n if (!Array.isArray(servers)) {\n return c.fail(\n \"INVALID_REQUEST_BODY\",\n \"servers 必须是字符串数组\",\n undefined,\n 400\n );\n }\n\n this.statusService.setActiveMCPServers(servers);\n c.get(\"logger\").info(\"活跃 MCP 服务器设置成功\");\n\n return c.success(undefined, \"活跃 MCP 服务器设置成功\");\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"设置活跃 MCP 服务器\",\n \"ACTIVE_MCP_SERVERS_UPDATE_ERROR\",\n \"设置活跃 MCP 服务器失败\",\n 400\n );\n }\n }\n\n /**\n * 重置状态\n * POST /api/status/reset\n */\n async resetStatus(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理重置状态请求\");\n this.statusService.reset();\n c.get(\"logger\").info(\"状态重置成功\");\n return c.success(undefined, \"状态重置成功\");\n } catch (error) {\n return this.handleError(c, error, \"重置状态\", \"STATUS_RESET_ERROR\");\n }\n }\n}\n","/**\n * 工具添加 API 相关类型定义\n * 支持多种工具类型的添加,包括 MCP 工具、Coze 工作流等\n */\n\nimport type { JSONSchema as LibJSONSchema } from \"@/lib/mcp/types.js\";\nimport type { CozeWorkflow, WorkflowParameterConfig } from \"./coze.js\";\n\n/**\n * JSON Schema 类型\n * 重新导出 @/lib/mcp/types.js 中的 JSONSchema\n *\n * 注意:此类型与 @xiaozhi-client/shared-types 中的 JSONSchema 相同\n * TODO:将来应从 shared-types 导入 JSONSchema 以消除重复定义\n */\nexport type JSONSchema = LibJSONSchema;\n\n/**\n * 工具处理器配置相关类型\n *\n * 注意:这些类型与 @xiaozhi-client/shared-types/src/mcp/tool-definition.ts 中定义的类型相同\n * TODO:将 toolApi.ts 的类型迁移为从 shared-types 导入,消除重复定义\n * 目前保持本地定义以避免 TypeScript 子路径解析问题(影响 tts、asr 等其他包)\n *\n * 权威定义位置:packages/shared-types/src/mcp/tool-definition.ts\n */\nexport type ToolHandlerConfig =\n | MCPHandlerConfig\n | ProxyHandlerConfig\n | HttpHandlerConfig\n | FunctionHandlerConfig;\n\n/**\n * MCP 处理器配置\n * 用于标准 MCP 服务中的工具\n */\nexport interface MCPHandlerConfig {\n type: \"mcp\";\n config: {\n serviceName: string;\n toolName: string;\n };\n}\n\n/**\n * 代理处理器配置\n * 用于第三方平台代理(如 Coze、OpenAI 等)\n */\nexport interface ProxyHandlerConfig {\n type: \"proxy\";\n platform: \"coze\" | \"openai\" | \"anthropic\" | \"custom\";\n config: Record<string, unknown>;\n}\n\n/**\n * HTTP 处理器配置\n * 用于 HTTP API 工具\n */\nexport interface HttpHandlerConfig {\n type: \"http\";\n config: {\n url: string;\n method?: string;\n headers?: Record<string, string>;\n };\n}\n\n/**\n * 函数处理器配置\n * 用于自定义函数工具\n */\nexport interface FunctionHandlerConfig {\n type: \"function\";\n config: {\n module: string;\n function: string;\n };\n}\n\n/**\n * CustomMCP 工具基础接口\n *\n * 注意:此类型与 @xiaozhi-client/shared-types 中的 CustomMCPTool 相同\n * TODO:将来应从 shared-types 导入 CustomMCPTool 以消除重复定义\n */\nexport interface CustomMCPToolBase {\n /** 工具唯一标识符 */\n name: string;\n /** 工具描述信息 */\n description: string;\n /** 工具输入参数的 JSON Schema 定义 */\n inputSchema: JSONSchema;\n /** 处理器配置 */\n handler: ToolHandlerConfig;\n}\n\n/**\n * 带统计信息的 CustomMCP 工具\n * 用于 API 响应,使用扁平的统计信息结构\n *\n * 注意:此类型与 @xiaozhi-client/shared-types 中的 CustomMCPToolWithStats 类似\n * 但不包含 `enabled` 字段。如需完整功能,请从 shared-types 导入\n */\nexport interface CustomMCPToolWithStats extends CustomMCPToolBase {\n /** 工具使用次数(扁平结构,与 API 响应格式一致) */\n usageCount?: number;\n /** 最后使用时间(ISO 8601 格式) */\n lastUsedTime?: string;\n}\n\n/**\n * 工具类型枚举\n */\nexport enum ToolType {\n /** MCP 工具(标准 MCP 服务中的工具) */\n MCP = \"mcp\",\n /** Coze 工作流工具 */\n COZE = \"coze\",\n /** HTTP API 工具(预留) */\n HTTP = \"http\",\n /** 自定义函数工具(预留) */\n FUNCTION = \"function\",\n}\n\n/**\n * MCP 工具数据\n * 用于将标准 MCP 服务中的工具添加到 customMCP.tools 配置中\n */\nexport interface MCPToolData {\n /** MCP 服务名称 */\n serviceName: string;\n /** 工具名称 */\n toolName: string;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * Coze 工作流数据\n * 保持与现有格式的兼容性\n */\nexport interface CozeWorkflowData {\n /** Coze 工作流信息 */\n workflow: CozeWorkflow;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n /** 可选的参数配置 */\n parameterConfig?: WorkflowParameterConfig;\n}\n\n/**\n * HTTP API 工具数据(预留)\n */\nexport interface HttpApiToolData {\n /** API 地址 */\n url: string;\n /** HTTP 方法 */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n /** API 描述 */\n description: string;\n /** 请求头 */\n headers?: Record<string, string>;\n /** 请求体模板 */\n bodyTemplate?: string;\n /** 认证配置 */\n auth?: {\n type: \"bearer\" | \"basic\" | \"api_key\";\n token?: string;\n username?: string;\n password?: string;\n apiKey?: string;\n apiKeyHeader?: string;\n };\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * 函数工具数据(预留)\n */\nexport interface FunctionToolData {\n /** 模块路径 */\n module: string;\n /** 函数名 */\n function: string;\n /** 函数描述 */\n description: string;\n /** 函数执行上下文 */\n context?: Record<string, any>;\n /** 超时时间 */\n timeout?: number;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * 添加自定义工具的统一请求接口\n */\nexport interface AddCustomToolRequest {\n /** 工具类型 */\n type: ToolType;\n /** 工具数据(根据类型不同而不同) */\n data: MCPToolData | CozeWorkflowData | HttpApiToolData | FunctionToolData;\n}\n\n/**\n * 工具验证错误类型\n */\nexport enum ToolValidationError {\n /** 无效的工具类型 */\n INVALID_TOOL_TYPE = \"INVALID_TOOL_TYPE\",\n /** 缺少必需字段 */\n MISSING_REQUIRED_FIELD = \"MISSING_REQUIRED_FIELD\",\n /** 工具不存在 */\n TOOL_NOT_FOUND = \"TOOL_NOT_FOUND\",\n /** 服务不存在 */\n SERVICE_NOT_FOUND = \"SERVICE_NOT_FOUND\",\n /** 工具名称冲突 */\n TOOL_NAME_CONFLICT = \"TOOL_NAME_CONFLICT\",\n /** 配置验证失败 */\n CONFIG_VALIDATION_FAILED = \"CONFIG_VALIDATION_FAILED\",\n /** 系统配置错误 */\n SYSTEM_CONFIG_ERROR = \"SYSTEM_CONFIG_ERROR\",\n /** 资源限制超出 */\n RESOURCE_LIMIT_EXCEEDED = \"RESOURCE_LIMIT_EXCEEDED\",\n}\n\n/**\n * 工具验证错误详情\n */\nexport interface ToolValidationErrorDetail {\n /** 错误类型 */\n error: ToolValidationError;\n /** 错误消息 */\n message: string;\n /** 错误详情 */\n details?: any;\n /** 建议的解决方案 */\n suggestions?: string[];\n}\n\n/**\n * 添加工具的响应数据\n */\nexport interface AddToolResponse {\n /** 成功添加的工具 */\n tool: any;\n /** 工具名称 */\n toolName: string;\n /** 工具类型 */\n toolType: ToolType;\n /** 添加时间戳 */\n addedAt: string;\n}\n\n/**\n * 工具元数据信息\n */\nexport interface ToolMetadata {\n /** 工具原始来源 */\n source: {\n type: \"mcp\" | \"coze\" | \"http\" | \"function\";\n serviceName?: string;\n toolName?: string;\n url?: string;\n };\n /** 添加时间 */\n addedAt: string;\n /** 最后更新时间 */\n updatedAt?: string;\n /** 版本信息 */\n version?: string;\n}\n\n/**\n * 工具配置选项\n */\nexport interface ToolConfigOptions {\n /** 是否启用工具(默认 true) */\n enabled?: boolean;\n /** 超时时间(毫秒) */\n timeout?: number;\n /** 重试次数 */\n retryCount?: number;\n /** 重试间隔(毫秒) */\n retryDelay?: number;\n /** 自定义标签 */\n tags?: string[];\n /** 工具分组 */\n group?: string;\n}\n","/**\n * MCP 工具排序工具模块\n * 提供可扩展的排序策略,支持多种排序方式\n */\n\nimport { logger } from \"@/Logger.js\";\nimport type { EnhancedToolInfo } from \"@/lib/mcp\";\n\nexport type ToolSortField = \"name\" | \"enabled\" | \"usageCount\" | \"lastUsedTime\";\n\nexport interface ToolSortConfig {\n field: ToolSortField;\n}\n\n/**\n * 排序函数类型\n */\ntype SortFn = (a: EnhancedToolInfo, b: EnhancedToolInfo) => number;\n\n/**\n * 工具排序策略\n * 新增排序方式只需在此处添加对应的排序函数\n */\nexport const toolSorters: Record<ToolSortField, SortFn> = {\n /**\n * 按名称排序(默认排序)\n * 规则:服务名 a-z → 工具名 a-z\n */\n name: (a, b) => {\n // 先按服务名排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n // 服务名相同时,按工具名排序\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n\n /**\n * 按启用状态排序\n * 规则:已启用在前,已禁用在后;同状态内按名称排序\n */\n enabled: (a, b) => {\n // 先按启用状态排序(已启用在前)\n const enabledCompare = Number(b.enabled) - Number(a.enabled);\n if (enabledCompare !== 0) {\n return enabledCompare;\n }\n // 同状态内按名称排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n\n /**\n * 按使用次数排序\n * 规则:使用次数多的在前;同次数时按名称排序\n */\n usageCount: (a, b) => {\n // 按使用次数降序排序(次数多的在前)\n const countCompare = b.usageCount - a.usageCount;\n if (countCompare !== 0) return countCompare;\n // 使用次数相同时,按服务名和工具名排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n\n /**\n * 按最近使用时间排序\n * 规则:最近使用的在前;未使用时间的工具排在后面\n */\n lastUsedTime: (a, b) => {\n // 未使用时间的工具排在后面\n if (!a.lastUsedTime) return 1;\n if (!b.lastUsedTime) return -1;\n // 按时间降序排序(最近的在前)\n const timeCompare =\n new Date(b.lastUsedTime).getTime() - new Date(a.lastUsedTime).getTime();\n if (timeCompare !== 0) return timeCompare;\n // 时间相同时,按服务名和工具名排序\n if (a.serviceName !== b.serviceName) {\n return a.serviceName.localeCompare(b.serviceName, \"zh-CN\");\n }\n return a.originalName.localeCompare(b.originalName, \"zh-CN\");\n },\n};\n\n/**\n * 应用排序到工具列表\n */\nexport function sortTools(\n tools: EnhancedToolInfo[],\n config: ToolSortConfig\n): EnhancedToolInfo[] {\n const sorter = toolSorters[config.field];\n if (!sorter) {\n logger.warn(`[sortTools] 未知的排序字段: ${config.field}`);\n return tools;\n }\n\n return [...tools].sort(sorter);\n}\n","/**\n * MCP 工具调用 API 处理器\n * 处理通过 HTTP API 调用 MCP 工具的请求\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport { HTTP_TIMEOUTS } from \"@/constants/timeout.constants.js\";\nimport { MCPError, MCPErrorCode } from \"@/errors/mcp-errors.js\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { EnhancedToolInfo } from \"@/lib/mcp/types.js\";\nimport type { CozeWorkflow, WorkflowParameterConfig } from \"@/types/coze.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type {\n AddCustomToolRequest,\n AddToolResponse,\n CozeWorkflowData,\n MCPToolData,\n} from \"@/types/toolApi.js\";\nimport { ToolType } from \"@/types/toolApi.js\";\nimport type { CustomMCPToolWithStats, JSONSchema } from \"@/types/toolApi.js\";\nimport { type ToolSortField, sortTools } from \"@/utils/toolSorters\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { CustomMCPTool, ProxyHandlerConfig } from \"@xiaozhi-client/config\";\nimport Ajv from \"ajv\";\nimport dayjs from \"dayjs\";\nimport type { Context } from \"hono\";\n\n/**\n * 工具调用请求接口\n */\ninterface ToolCallRequest {\n serviceName: string;\n toolName: string;\n args: Record<string, unknown>;\n}\n\n/**\n * 添加自定义工具请求接口(向后兼容)\n * @deprecated 使用新的 AddCustomToolRequest 类型定义\n */\ninterface LegacyAddCustomToolRequest {\n workflow: CozeWorkflow;\n customName?: string;\n customDescription?: string;\n parameterConfig?: WorkflowParameterConfig;\n}\n\n/**\n * MCP 工具调用 API 处理器\n */\nexport class MCPToolHandler {\n // 预编译的正则表达式常量,避免在频繁调用时重复创建\n private static readonly UNDERSCORE_TRIM_REGEX = /^_+|_+$/g;\n private static readonly LETTER_START_REGEX = /^[a-zA-Z]/;\n private static readonly CHINESE_CHAR_REGEX = /[\\u4e00-\\u9fa5]/;\n private static readonly DIGITS_ONLY_REGEX = /^\\d+$/;\n private static readonly ALPHANUMERIC_UNDERSCORE_REGEX = /^[a-zA-Z0-9_-]+$/;\n private static readonly IDENTIFIER_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\n private logger: Logger;\n private ajv: Ajv;\n private static readonly TOOL_TYPE_VALUES = Object.values(ToolType);\n\n constructor() {\n this.logger = logger;\n this.ajv = new Ajv({ allErrors: true, verbose: true });\n }\n\n /**\n * 调用 MCP 工具\n * POST /api/tools/call\n */\n async callTool(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理工具调用请求\");\n\n // 解析请求体\n const requestBody: ToolCallRequest = await c.req.json();\n const { serviceName, toolName, args } = requestBody;\n\n // 验证请求参数\n if (!serviceName || !toolName) {\n return c.fail(\n \"INVALID_REQUEST\",\n \"serviceName 和 toolName 是必需的参数\",\n undefined,\n 400\n );\n }\n\n c.get(\"logger\").info(\n `准备调用工具: ${serviceName}/${toolName},参数:`,\n JSON.stringify(args)\n );\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n\n if (!serviceManager) {\n return c.fail(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\",\n undefined,\n 503\n );\n }\n\n // 验证服务和工具是否存在\n await this.validateServiceAndTool(serviceManager, serviceName, toolName);\n\n // 对于 customMCP 工具,进行参数验证\n if (serviceName === \"customMCP\") {\n await this.validateCustomMCPArguments(\n serviceManager,\n toolName,\n args || {}\n );\n }\n\n // 调用工具 - 特殊处理 customMCP 服务\n let result: unknown;\n if (serviceName === \"customMCP\") {\n // 对于 customMCP 服务,直接使用 toolName 调用,传递长运行任务超时\n result = await serviceManager.callTool(toolName, args || {}, {\n timeout: HTTP_TIMEOUTS.LONG_RUNNING,\n });\n } else {\n // 对于标准 MCP 服务,使用 serviceName__toolName 格式,保持8秒超时\n const toolKey = `${serviceName}__${toolName}`;\n result = await serviceManager.callTool(toolKey, args || {});\n }\n\n // c.get(\"logger\").debug(`工具调用成功: ${serviceName}/${toolName}`);\n\n return c.success(result, \"工具调用成功\");\n } catch (error) {\n c.get(\"logger\").error(\"工具调用失败:\", error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n let errorCode = \"TOOL_CALL_ERROR\";\n\n // 根据错误类型设置不同的错误码\n if (errorMessage.includes(\"不存在\")) {\n errorCode = \"SERVICE_OR_TOOL_NOT_FOUND\";\n } else if (\n errorMessage.includes(\"未启动\") ||\n errorMessage.includes(\"未连接\")\n ) {\n errorCode = \"SERVICE_NOT_AVAILABLE\";\n } else if (errorMessage.includes(\"已被禁用\")) {\n errorCode = \"TOOL_DISABLED\";\n } else if (errorMessage.includes(\"参数验证失败\")) {\n errorCode = \"INVALID_ARGUMENTS\";\n } else if (\n errorMessage.includes(\"CustomMCP\") ||\n errorMessage.includes(\"customMCP\")\n ) {\n errorCode = \"CUSTOM_MCP_ERROR\";\n } else if (\n errorMessage.includes(\"工作流调用失败\") ||\n errorMessage.includes(\"API 请求失败\")\n ) {\n errorCode = \"EXTERNAL_API_ERROR\";\n } else if (errorMessage.includes(\"超时\")) {\n errorCode = \"TIMEOUT_ERROR\";\n }\n\n return c.fail(errorCode, errorMessage, undefined, 500);\n }\n }\n\n /**\n * 获取自定义 MCP 工具列表\n * GET /api/tools/custom\n */\n async getCustomTools(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理获取自定义 MCP 工具列表请求\");\n\n // 检查配置文件是否存在\n if (!configManager.configExists()) {\n return c.fail(\n \"CONFIG_NOT_FOUND\",\n \"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\",\n undefined,\n 404\n );\n }\n\n // 获取自定义 MCP 工具列表\n let customTools: CustomMCPTool[] = [];\n let configPath = \"\";\n\n try {\n customTools = configManager.getCustomMCPTools();\n configPath = configManager.getConfigPath();\n } catch (error) {\n c.get(\"logger\").error(\"读取自定义 MCP 工具配置失败:\", error);\n return c.fail(\n \"CONFIG_PARSE_ERROR\",\n `配置文件解析失败: ${error instanceof Error ? error.message : \"未知错误\"}`,\n undefined,\n 500\n );\n }\n\n // 检查是否配置了自定义 MCP 工具\n if (!customTools || customTools.length === 0) {\n c.get(\"logger\").info(\"未配置自定义 MCP 工具\");\n return c.success(\n {\n tools: [],\n totalTools: 0,\n configPath,\n },\n \"未配置自定义 MCP 工具\"\n );\n }\n\n // 验证工具配置的有效性\n const isValid = configManager.validateCustomMCPTools(customTools);\n if (!isValid) {\n c.get(\"logger\").warn(\"自定义 MCP 工具配置验证失败\");\n return c.fail(\n \"INVALID_TOOL_CONFIG\",\n \"自定义 MCP 工具配置验证失败,请检查配置文件中的工具定义\",\n undefined,\n 400\n );\n }\n\n c.get(\"logger\").info(\n `获取自定义 MCP 工具列表成功,共 ${customTools.length} 个工具`\n );\n\n return c.success(\n {\n tools: customTools,\n totalTools: customTools.length,\n configPath,\n },\n \"获取自定义 MCP 工具列表成功\"\n );\n } catch (error) {\n c.get(\"logger\").error(\"获取自定义 MCP 工具列表失败:\", error);\n\n return c.fail(\n \"GET_CUSTOM_TOOLS_ERROR\",\n error instanceof Error ? error.message : \"获取自定义 MCP 工具列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 获取可用工具列表\n * GET /api/tools/list?status=enabled|disabled|all&sortBy=name\n *\n * @param status 筛选状态:'enabled'(已启用)、'disabled'(未启用)、'all'(全部,默认)\n * @param sortBy 排序字段:'name'(工具名称,默认)、'enabled'(启用状态)、'usageCount'(使用次数)、'lastUsedTime'(最近使用时间)\n */\n async listTools(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取工具列表请求\");\n\n // 获取筛选参数\n const status =\n (c.req.query(\"status\") as \"enabled\" | \"disabled\" | \"all\") || \"all\";\n\n // 解析排序参数并验证\n const sortByParam = c.req.query(\"sortBy\");\n const validSortFields: ToolSortField[] = [\n \"name\",\n \"enabled\",\n \"usageCount\",\n \"lastUsedTime\",\n ];\n const sortBy = validSortFields.includes(sortByParam as ToolSortField)\n ? (sortByParam as ToolSortField)\n : \"name\";\n\n // 如果提供了无效的排序字段,返回错误\n if (\n sortByParam &&\n !validSortFields.includes(sortByParam as ToolSortField)\n ) {\n return c.fail(\n \"INVALID_SORT_FIELD\",\n `无效的排序字段: ${sortByParam}。支持的排序字段: ${validSortFields.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n if (!serviceManager) {\n return c.fail(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\",\n undefined,\n 503\n );\n }\n\n let rawTools: EnhancedToolInfo[] = serviceManager.getAllTools(status);\n\n // 应用排序\n rawTools = sortTools(rawTools, { field: sortBy });\n\n // 转换为 CustomMCPToolWithStats 格式(使用共享类型)\n const tools: CustomMCPToolWithStats[] = rawTools.map(\n (tool: EnhancedToolInfo) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n handler: {\n type: \"mcp\",\n config: {\n serviceName: tool.serviceName,\n toolName: tool.originalName,\n },\n },\n enabled: tool.enabled,\n usageCount: tool.usageCount,\n lastUsedTime: tool.lastUsedTime,\n })\n );\n\n // 返回对象格式的响应\n const responseData = {\n list: tools,\n total: tools.length,\n };\n\n return c.success(responseData, `获取工具列表成功(${status})`);\n } catch (error) {\n c.get(\"logger\").error(\"获取工具列表失败:\", error);\n\n return c.fail(\"GET_TOOLS_FAILED\", \"获取工具列表失败\", undefined, 500);\n }\n }\n\n /**\n * 验证服务和工具是否存在\n * @private\n */\n private async validateServiceAndTool(\n serviceManager: MCPServiceManager,\n serviceName: string,\n toolName: string\n ): Promise<void> {\n // 特殊处理 customMCP 服务\n if (serviceName === \"customMCP\") {\n // 验证 customMCP 工具是否存在\n if (!serviceManager.hasCustomMCPTool(toolName)) {\n const availableTools = serviceManager\n .getCustomMCPTools()\n .map((tool) => tool.name);\n\n if (availableTools.length === 0) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `customMCP 工具 '${toolName}' 不存在。当前没有配置任何 customMCP 工具。请检查 xiaozhi.config.json 中的 customMCP 配置。`\n );\n }\n\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `customMCP 工具 '${toolName}' 不存在。可用的 customMCP 工具: ${availableTools.join(\", \")}。请使用 'xiaozhi mcp list' 查看所有可用工具。`\n );\n }\n\n // 验证 customMCP 工具配置是否有效\n try {\n const customTools = serviceManager.getCustomMCPTools();\n const targetTool = customTools.find((tool) => tool.name === toolName);\n\n if (targetTool && !targetTool.description) {\n this.logger.warn(`customMCP 工具 '${toolName}' 缺少描述信息`);\n }\n\n if (targetTool && !targetTool.inputSchema) {\n this.logger.warn(`customMCP 工具 '${toolName}' 缺少输入参数定义`);\n }\n } catch (error) {\n this.logger.error(\n `验证 customMCP 工具 '${toolName}' 配置时出错:`,\n error\n );\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `customMCP 工具 '${toolName}' 配置验证失败。请检查配置文件中的工具定义。`\n );\n }\n\n return;\n }\n }\n\n /**\n * 验证 customMCP 工具的参数\n * @private\n */\n private async validateCustomMCPArguments(\n serviceManager: MCPServiceManager,\n toolName: string,\n args: Record<string, unknown>\n ): Promise<void> {\n try {\n // 获取工具的 inputSchema\n const customTools = serviceManager.getCustomMCPTools();\n const targetTool = customTools.find((tool) => tool.name === toolName);\n\n if (!targetTool) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `customMCP 工具 '${toolName}' 不存在`\n );\n }\n\n // 如果工具没有定义 inputSchema,跳过验证\n if (!targetTool.inputSchema) {\n this.logger.warn(\n `customMCP 工具 '${toolName}' 没有定义 inputSchema,跳过参数验证`\n );\n return;\n }\n\n // 使用 AJV 验证参数\n const validate = this.ajv.compile(targetTool.inputSchema);\n const valid = validate(args);\n\n if (!valid) {\n // 构建详细的错误信息\n const errors = validate.errors || [];\n const errorMessages = errors.map((error) => {\n const path = error.instancePath || error.schemaPath || \"\";\n const message = error.message || \"未知错误\";\n\n if (error.keyword === \"required\") {\n const missingProperty = error.params?.missingProperty || \"未知字段\";\n return `缺少必需参数: ${missingProperty}`;\n }\n\n if (error.keyword === \"type\") {\n const expectedType = error.params?.type || \"未知类型\";\n return `参数 ${path} 类型错误,期望: ${expectedType}`;\n }\n\n if (error.keyword === \"enum\") {\n const allowedValues = error.params?.allowedValues || [];\n return `参数 ${path} 值无效,允许的值: ${allowedValues.join(\", \")}`;\n }\n\n return `参数 ${path} ${message}`;\n });\n\n const errorMessage = `参数验证失败: ${errorMessages.join(\"; \")}`;\n this.logger.error(\n `customMCP 工具 '${toolName}' 参数验证失败:`,\n errorMessage\n );\n\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n errorMessage\n );\n }\n\n this.logger.debug(`customMCP 工具 '${toolName}' 参数验证通过`);\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"参数验证失败\")) {\n throw error;\n }\n\n this.logger.error(`验证 customMCP 工具 '${toolName}' 参数时出错:`, error);\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `参数验证过程中发生错误: ${error instanceof Error ? error.message : \"未知错误\"}`\n );\n }\n }\n\n /**\n * 添加自定义 MCP 工具\n * POST /api/tools/custom\n * 支持多种工具类型:MCP 工具、Coze 工作流等\n */\n async addCustomTool(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理添加自定义工具请求\");\n\n const requestBody = await c.req.json();\n\n // 检查是否为新格式的请求\n if (this.isNewFormatRequest(requestBody)) {\n // 新格式:支持多种工具类型\n return await this.handleNewFormatAddTool(\n c,\n requestBody as AddCustomToolRequest\n );\n }\n // 旧格式:向后兼容\n return await this.handleLegacyFormatAddTool(\n c,\n requestBody as LegacyAddCustomToolRequest\n );\n } catch (error) {\n c.get(\"logger\").error(\"添加自定义工具失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { code, message, status } = this.handleAddToolError(error);\n return c.fail(code, message, undefined, status);\n }\n }\n\n /**\n * 判断是否为新格式的请求\n */\n private isNewFormatRequest(body: unknown): body is AddCustomToolRequest {\n return (\n body !== null &&\n typeof body === \"object\" &&\n !Array.isArray(body) &&\n \"type\" in body &&\n \"data\" in body\n );\n }\n\n /**\n * 处理新格式的添加工具请求\n */\n private async handleNewFormatAddTool(\n c: Context<AppContext>,\n request: AddCustomToolRequest\n ): Promise<Response> {\n const { type, data } = request;\n\n c.get(\"logger\").info(`处理新格式工具添加请求,类型: ${type}`);\n\n // 验证工具类型\n if (!MCPToolHandler.TOOL_TYPE_VALUES.includes(type)) {\n return c.fail(\n \"INVALID_TOOL_TYPE\",\n `不支持的工具类型: ${type}。支持的类型: ${MCPToolHandler.TOOL_TYPE_VALUES.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 根据工具类型分发处理\n switch (type) {\n case ToolType.MCP:\n return await this.handleAddMCPTool(c, data as MCPToolData);\n\n case ToolType.COZE:\n return await this.handleAddCozeTool(c, data as CozeWorkflowData);\n\n case ToolType.HTTP:\n case ToolType.FUNCTION: {\n return c.fail(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n `工具类型 ${type} 暂未实现,请使用 MCP 或 Coze 类型`,\n undefined,\n 501\n );\n }\n\n default: {\n return c.fail(\n \"UNKNOWN_TOOL_TYPE\",\n `未知的工具类型: ${type}`,\n undefined,\n 400\n );\n }\n }\n }\n\n /**\n * 处理旧格式的添加工具请求(向后兼容)\n */\n private async handleLegacyFormatAddTool(\n c: Context<AppContext>,\n request: LegacyAddCustomToolRequest\n ): Promise<Response> {\n c.get(\"logger\").info(\"处理旧格式工具添加请求(向后兼容)\");\n\n const { workflow, customName, customDescription, parameterConfig } =\n request;\n\n // 边界条件预检查\n const preCheckResult = this.performPreChecks(\n workflow,\n customName,\n customDescription\n );\n if (preCheckResult) {\n return c.fail(\n preCheckResult.code,\n preCheckResult.message,\n undefined,\n preCheckResult.status\n );\n }\n\n // 转换工作流为工具配置\n const tool = this.convertWorkflowToTool(\n workflow,\n customName,\n customDescription,\n parameterConfig\n );\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n c.get(\"logger\").info(`成功添加自定义工具: ${tool.name}`);\n\n return c.success({ tool }, `工具 \"${tool.name}\" 添加成功`);\n }\n\n /**\n * 处理添加 MCP 工具\n */\n private async handleAddMCPTool(\n c: Context<AppContext>,\n data: MCPToolData\n ): Promise<Response> {\n const { serviceName, toolName, customName, customDescription } = data;\n\n c.get(\"logger\").info(`处理添加 MCP 工具: ${serviceName}/${toolName}`);\n\n // 验证必需字段\n if (!serviceName || !toolName) {\n return c.fail(\n \"MISSING_REQUIRED_FIELD\",\n \"serviceName 和 toolName 是必需字段\",\n undefined,\n 400\n );\n }\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n if (!serviceManager) {\n return c.fail(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\",\n undefined,\n 503\n );\n }\n\n // 验证服务和工具是否存在\n try {\n await this.validateServiceAndTool(serviceManager, serviceName, toolName);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return c.fail(\"SERVICE_OR_TOOL_NOT_FOUND\", errorMessage, undefined, 404);\n }\n\n // 从缓存中获取工具信息\n const cacheManager = new MCPCacheManager();\n const cachedTools = await cacheManager.getAllCachedTools();\n\n // 查找对应的工具\n const fullToolName = `${serviceName}__${toolName}`;\n const cachedTool = cachedTools.find((tool) => tool.name === fullToolName);\n\n if (!cachedTool) {\n return c.fail(\n \"TOOL_NOT_FOUND\",\n `在缓存中未找到工具: ${serviceName}/${toolName}`,\n undefined,\n 404\n );\n }\n\n // 生成工具名称\n const finalToolName = customName || fullToolName;\n\n // 检查工具名称是否已存在\n const existingTools = configManager.getCustomMCPTools();\n const existingNames = new Set(existingTools.map((tool) => tool.name));\n\n if (existingNames.has(finalToolName)) {\n return c.fail(\n \"TOOL_NAME_CONFLICT\",\n `工具名称 \"${finalToolName}\" 已存在,请使用不同的自定义名称`,\n undefined,\n 409\n );\n }\n\n // 创建 CustomMCPTool 配置\n const tool: CustomMCPTool = {\n name: finalToolName,\n description:\n customDescription ||\n cachedTool.description ||\n `MCP 工具: ${serviceName}/${toolName}`,\n inputSchema: cachedTool.inputSchema || {},\n handler: {\n type: \"mcp\",\n config: {\n serviceName,\n toolName,\n },\n },\n stats: {\n usageCount: 0,\n lastUsedTime: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n },\n };\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n // 对于 MCP 工具,需要在 mcpServerConfig 中同步启用\n c.get(\"logger\").info(\n `检测到 MCP 工具添加,同步启用 mcpServerConfig 中的工具: ${serviceName}/${toolName}`\n );\n\n // 获取当前的服务工具配置\n const serverToolsConfig = configManager.getServerToolsConfig(serviceName);\n\n if (serverToolsConfig?.toolName) {\n // 更新配置,启用该工具\n serverToolsConfig[toolName].enable = true;\n\n // 保存更新后的配置\n configManager.updateServerToolsConfig(serviceName, serverToolsConfig);\n\n c.get(\"logger\").info(\n `已同步启用 mcpServerConfig 中的工具: ${serviceName}/${toolName}`\n );\n }\n\n c.get(\"logger\").info(`成功添加 MCP 工具: ${finalToolName}`);\n\n const responseData: AddToolResponse = {\n tool,\n toolName: finalToolName,\n toolType: ToolType.MCP,\n addedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.success(responseData, `MCP 工具 \"${finalToolName}\" 添加成功`);\n }\n\n /**\n * 处理添加 Coze 工具\n */\n private async handleAddCozeTool(\n c: Context<AppContext>,\n data: CozeWorkflowData\n ): Promise<Response> {\n const { workflow, customName, customDescription, parameterConfig } = data;\n\n c.get(\"logger\").info(`处理添加 Coze 工具: ${workflow.workflow_name}`);\n\n // 边界条件预检查\n const preCheckResult = this.performPreChecks(\n workflow,\n customName,\n customDescription\n );\n if (preCheckResult) {\n return c.fail(\n preCheckResult.code,\n preCheckResult.message,\n undefined,\n preCheckResult.status\n );\n }\n\n // 转换工作流为工具配置\n const tool = this.convertWorkflowToTool(\n workflow,\n customName,\n customDescription,\n parameterConfig\n );\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n c.get(\"logger\").info(`成功添加 Coze 工具: ${tool.name}`);\n\n const responseData: AddToolResponse = {\n tool,\n toolName: tool.name,\n toolType: ToolType.COZE,\n addedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.success(responseData, `Coze 工具 \"${tool.name}\" 添加成功`);\n }\n\n /**\n * 更新自定义 MCP 工具配置\n * PUT /api/tools/custom/:toolName\n */\n async updateCustomTool(c: Context<AppContext>): Promise<Response> {\n try {\n const toolName = c.req.param(\"toolName\");\n\n if (!toolName) {\n return c.fail(\"INVALID_REQUEST\", \"工具名称不能为空\", undefined, 400);\n }\n\n c.get(\"logger\").info(`处理更新自定义工具配置请求: ${toolName}`);\n\n const requestBody = await c.req.json();\n\n // 验证请求体\n if (!requestBody || typeof requestBody !== \"object\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"请求体必须是有效对象\",\n undefined,\n 400\n );\n }\n\n // 检查是否为新格式的请求\n if (this.isNewFormatRequest(requestBody)) {\n // 新格式:支持多种工具类型\n return await this.handleNewFormatUpdateTool(\n c,\n toolName,\n requestBody as AddCustomToolRequest\n );\n }\n\n // 旧格式不支持更新操作\n return c.fail(\n \"INVALID_REQUEST\",\n \"更新操作只支持新格式的请求\",\n undefined,\n 400\n );\n } catch (error) {\n c.get(\"logger\").error(\"更新自定义工具配置失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { code, message, status } = this.handleUpdateToolError(error);\n return c.fail(code, message, undefined, status);\n }\n }\n\n /**\n * 处理新格式的更新工具请求\n */\n private async handleNewFormatUpdateTool(\n c: Context<AppContext>,\n toolName: string,\n request: AddCustomToolRequest\n ): Promise<Response> {\n const { type, data } = request;\n\n c.get(\"logger\").info(`处理新格式工具更新请求,类型: ${type}`);\n\n // 验证工具类型\n if (!MCPToolHandler.TOOL_TYPE_VALUES.includes(type)) {\n return c.fail(\n \"INVALID_TOOL_TYPE\",\n `不支持的工具类型: ${type}。支持的类型: ${MCPToolHandler.TOOL_TYPE_VALUES.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 根据工具类型分发处理\n switch (type) {\n case ToolType.COZE:\n return await this.handleUpdateCozeTool(\n c,\n toolName,\n data as CozeWorkflowData\n );\n\n case ToolType.MCP:\n case ToolType.HTTP:\n case ToolType.FUNCTION: {\n return c.fail(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n `工具类型 ${type} 暂不支持更新操作,目前仅支持 Coze 类型`,\n undefined,\n 501\n );\n }\n\n default: {\n return c.fail(\n \"UNKNOWN_TOOL_TYPE\",\n `未知的工具类型: ${type}`,\n undefined,\n 400\n );\n }\n }\n }\n\n /**\n * 处理更新 Coze 工具\n */\n private async handleUpdateCozeTool(\n c: Context<AppContext>,\n toolName: string,\n data: CozeWorkflowData\n ): Promise<Response> {\n const { workflow, customName, customDescription, parameterConfig } = data;\n\n c.get(\"logger\").info(`处理更新 Coze 工具: ${toolName}`);\n\n // 验证工具是否存在\n const existingTools = configManager.getCustomMCPTools();\n const existingTool = existingTools.find((tool) => tool.name === toolName);\n\n if (!existingTool) {\n return c.fail(\n \"TOOL_NOT_FOUND\",\n `工具 \"${toolName}\" 不存在`,\n undefined,\n 404\n );\n }\n\n // 验证是否为 Coze 工具\n if (\n existingTool.handler.type !== \"proxy\" ||\n existingTool.handler.platform !== \"coze\"\n ) {\n return c.fail(\n \"INVALID_TOOL_TYPE\",\n `工具 \"${toolName}\" 不是 Coze 工作流工具,不支持参数配置更新`,\n undefined,\n 400\n );\n }\n\n // 如果前端提供的 workflow 中没有 workflow_id,尝试从现有工具中获取\n if (!workflow.workflow_id && existingTool.handler?.config?.workflow_id) {\n workflow.workflow_id = existingTool.handler.config.workflow_id;\n }\n\n // 如果还没有 workflow_id,尝试从其他字段获取\n if (!workflow.workflow_id && workflow.app_id) {\n // 对于某些场景,app_id 可以作为替代标识\n // 但我们仍然需要 workflow_id 用于 Coze API 调用\n c.get(\"logger\").warn(\n `工作流 ${toolName} 缺少 workflow_id,这可能会影响某些功能`\n );\n }\n\n // 验证工作流数据完整性\n this.validateWorkflowUpdateData(workflow);\n\n // 更新工具的 inputSchema\n const updatedInputSchema = this.generateInputSchema(\n workflow,\n parameterConfig\n );\n\n // 构建更新后的工具配置\n const updatedTool: CustomMCPTool = {\n ...existingTool,\n description: customDescription || existingTool.description,\n inputSchema: updatedInputSchema,\n };\n\n // 更新工具配置\n configManager.updateCustomMCPTool(toolName, updatedTool);\n\n c.get(\"logger\").info(`成功更新 Coze 工具: ${toolName}`);\n\n const responseData = {\n tool: updatedTool,\n toolName: toolName,\n toolType: ToolType.COZE,\n updatedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.success(responseData, `Coze 工具 \"${toolName}\" 配置更新成功`);\n }\n\n /**\n * 处理更新工具时的错误\n */\n private handleUpdateToolError(error: unknown): {\n code: string;\n message: string;\n status: number;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"更新自定义工具配置失败\";\n\n // 工具不存在错误 (404)\n if (errorMessage.includes(\"不存在\") || errorMessage.includes(\"未找到\")) {\n return {\n code: \"TOOL_NOT_FOUND\",\n message: `${errorMessage}。请检查工具名称是否正确`,\n status: 404,\n };\n }\n\n // 工具类型错误 (400)\n if (\n errorMessage.includes(\"工具类型\") ||\n errorMessage.includes(\"INVALID_TOOL_TYPE\")\n ) {\n return {\n code: \"INVALID_TOOL_TYPE\",\n message: errorMessage,\n status: 400,\n };\n }\n\n // 参数错误 (400)\n if (errorMessage.includes(\"不能为空\") || errorMessage.includes(\"无效\")) {\n return {\n code: \"INVALID_REQUEST\",\n message: `${errorMessage}。请提供有效的工具配置数据`,\n status: 400,\n };\n }\n\n // 配置错误 (422)\n if (errorMessage.includes(\"配置\") || errorMessage.includes(\"权限\")) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: `${errorMessage}。请检查配置文件权限和格式是否正确`,\n status: 422,\n };\n }\n\n // 未实现功能错误 (501)\n if (\n errorMessage.includes(\"未实现\") ||\n errorMessage.includes(\"NOT_IMPLEMENTED\")\n ) {\n return {\n code: \"TOOL_TYPE_NOT_IMPLEMENTED\",\n message: errorMessage,\n status: 501,\n };\n }\n\n // 系统错误 (500)\n return {\n code: \"UPDATE_CUSTOM_TOOL_ERROR\",\n message: `更新工具配置失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`,\n status: 500,\n };\n }\n\n /**\n * 删除自定义 MCP 工具\n * DELETE /api/tools/custom/:toolName\n */\n async removeCustomTool(c: Context<AppContext>): Promise<Response> {\n try {\n const toolName = c.req.param(\"toolName\");\n\n if (!toolName) {\n return c.fail(\"INVALID_REQUEST\", \"工具名称不能为空\", undefined, 400);\n }\n\n c.get(\"logger\").info(`处理删除自定义工具请求: ${toolName}`);\n\n // 在删除之前,检查是否为 MCP 工具,如果是则需要在 mcpServerConfig 中同步禁用\n const existingTools = configManager.getCustomMCPTools();\n const toolToDelete = existingTools.find((tool) => tool.name === toolName);\n\n if (toolToDelete && toolToDelete.handler.type === \"mcp\") {\n // 这是 MCP 工具,需要在 mcpServerConfig 中同步禁用\n const mcpConfig = toolToDelete.handler.config;\n if (mcpConfig.serviceName && mcpConfig.toolName) {\n c.get(\"logger\").info(\n `检测到 MCP 工具删除,同步禁用 mcpServerConfig 中的工具: ${mcpConfig.serviceName}/${mcpConfig.toolName}`\n );\n\n // 获取当前的服务工具配置\n const serverToolsConfig = configManager.getServerToolsConfig(\n mcpConfig.serviceName\n );\n\n if (serverToolsConfig?.[mcpConfig.toolName]) {\n // 更新配置,禁用该工具\n serverToolsConfig[mcpConfig.toolName].enable = false;\n\n // 保存更新后的配置\n configManager.updateServerToolsConfig(\n mcpConfig.serviceName,\n serverToolsConfig\n );\n\n c.get(\"logger\").info(\n `已同步禁用 mcpServerConfig 中的工具: ${mcpConfig.serviceName}/${mcpConfig.toolName}`\n );\n }\n }\n }\n\n // 从配置中删除工具\n configManager.removeCustomMCPTool(toolName);\n\n c.get(\"logger\").info(`成功删除自定义工具: ${toolName}`);\n\n return c.success(null, `工具 \"${toolName}\" 删除成功`);\n } catch (error) {\n c.get(\"logger\").error(\"删除自定义工具失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { code, message, status } = this.handleRemoveToolError(error);\n return c.fail(code, message, undefined, status);\n }\n }\n\n /**\n * 将扣子工作流转换为自定义 MCP 工具\n */\n private convertWorkflowToTool(\n workflow: CozeWorkflow,\n customName?: string,\n customDescription?: string,\n parameterConfig?: WorkflowParameterConfig\n ): CustomMCPTool {\n // 验证工作流数据完整性\n this.validateWorkflowData(workflow);\n\n // 生成工具名称(处理冲突)\n const baseName =\n customName || this.sanitizeToolName(workflow.workflow_name);\n const toolName = this.resolveToolNameConflict(baseName);\n\n // 生成工具描述\n const description = this.generateToolDescription(\n workflow,\n customDescription\n );\n\n // 生成输入参数结构\n const inputSchema = this.generateInputSchema(workflow, parameterConfig);\n\n // 配置 HTTP 处理器\n const handler = this.createHttpHandler(workflow);\n\n // 创建工具配置\n const tool: CustomMCPTool = {\n name: toolName,\n description,\n inputSchema,\n handler,\n };\n\n // 验证生成的工具配置\n this.validateGeneratedTool(tool);\n\n return tool;\n }\n\n /**\n * 规范化工具名称\n */\n private sanitizeToolName(name: string): string {\n if (!name || typeof name !== \"string\") {\n return \"coze_workflow_unnamed\";\n }\n\n // 去除首尾空格\n let sanitized = name.trim();\n\n if (!sanitized) {\n return \"coze_workflow_empty\";\n }\n\n // 将中文转换为拼音或英文描述(简化处理)\n sanitized = this.convertChineseToEnglish(sanitized);\n\n // 移除特殊字符,只保留字母、数字和下划线\n sanitized = sanitized.replace(/[^a-zA-Z0-9_]/g, \"_\");\n\n // 移除连续的下划线\n sanitized = sanitized.replace(/_+/g, \"_\");\n\n // 移除开头和结尾的下划线\n sanitized = sanitized.replace(MCPToolHandler.UNDERSCORE_TRIM_REGEX, \"\");\n\n // 确保以字母开头\n if (!MCPToolHandler.LETTER_START_REGEX.test(sanitized)) {\n sanitized = `coze_workflow_${sanitized}`;\n }\n\n // 限制长度(保留足够空间给数字后缀)\n if (sanitized.length > 45) {\n sanitized = sanitized.substring(0, 45);\n }\n\n // 确保不为空\n if (!sanitized) {\n sanitized = \"coze_workflow_tool\";\n }\n\n return sanitized;\n }\n\n /**\n * 简单的中文到英文转换(可以扩展为更复杂的拼音转换)\n */\n private convertChineseToEnglish(text: string): string {\n // 常见中文词汇的映射\n const chineseToEnglishMap: Record<string, string> = {\n 工作流: \"workflow\",\n 测试: \"test\",\n 数据: \"data\",\n 处理: \"process\",\n 分析: \"analysis\",\n 生成: \"generate\",\n 查询: \"query\",\n 搜索: \"search\",\n 转换: \"convert\",\n 计算: \"calculate\",\n 统计: \"statistics\",\n 报告: \"report\",\n 文档: \"document\",\n 图片: \"image\",\n 视频: \"video\",\n 音频: \"audio\",\n 文本: \"text\",\n 翻译: \"translate\",\n 识别: \"recognize\",\n 检测: \"detect\",\n 监控: \"monitor\",\n 管理: \"manage\",\n 配置: \"config\",\n 设置: \"setting\",\n 用户: \"user\",\n 系统: \"system\",\n 服务: \"service\",\n 接口: \"api\",\n 数据库: \"database\",\n 网络: \"network\",\n 安全: \"security\",\n 备份: \"backup\",\n 恢复: \"restore\",\n 同步: \"sync\",\n 导入: \"import\",\n 导出: \"export\",\n 上传: \"upload\",\n 下载: \"download\",\n };\n\n let result = text;\n\n // 替换常见中文词汇\n for (const [chinese, english] of Object.entries(chineseToEnglishMap)) {\n result = result.replace(new RegExp(chinese, \"g\"), english);\n }\n\n // 如果还有中文字符,用拼音前缀替代\n if (MCPToolHandler.CHINESE_CHAR_REGEX.test(result)) {\n result = `chinese_${result}`;\n }\n\n return result;\n }\n\n /**\n * 验证工作流数据完整性\n */\n private validateWorkflowData(workflow: CozeWorkflow): void {\n if (!workflow) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流数据不能为空\"\n );\n }\n\n // 验证必需字段\n this.validateRequiredFields(workflow);\n\n // 验证字段格式\n this.validateFieldFormats(workflow);\n\n // 验证字段长度\n this.validateFieldLengths(workflow);\n\n // 验证业务逻辑\n this.validateBusinessLogic(workflow);\n }\n\n /**\n * 验证工作流更新数据完整性\n * 用于更新场景,只验证关键字段\n */\n private validateWorkflowUpdateData(workflow: Partial<CozeWorkflow>): void {\n if (!workflow) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流数据不能为空\"\n );\n }\n\n // 对于更新操作,我们采用更灵活的验证策略\n // 因为这可能是参数配置更新,而不是工作流本身更新\n\n // 如果提供了 workflow_id,验证其格式\n if (workflow.workflow_id) {\n if (\n typeof workflow.workflow_id !== \"string\" ||\n workflow.workflow_id.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流ID必须是非空字符串\"\n );\n }\n\n // 验证工作流ID格式(数字字符串)\n if (!MCPToolHandler.DIGITS_ONLY_REGEX.test(workflow.workflow_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流ID格式无效,应为数字字符串\"\n );\n }\n }\n\n // 如果存在 workflow_name,验证其格式\n if (workflow.workflow_name) {\n if (\n typeof workflow.workflow_name !== \"string\" ||\n workflow.workflow_name.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流名称必须是非空字符串\"\n );\n }\n\n // 验证工作流名称长度\n if (workflow.workflow_name.length > 100) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流名称过长,不能超过100个字符\"\n );\n }\n }\n\n // 如果存在 app_id,验证其格式\n if (workflow.app_id) {\n if (\n typeof workflow.app_id !== \"string\" ||\n workflow.app_id.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID必须是非空字符串\"\n );\n }\n\n // 验证应用ID格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(workflow.app_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n\n // 验证应用ID长度\n if (workflow.app_id.length > 50) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID过长,不能超过50个字符\"\n );\n }\n }\n\n // 对于参数配置更新,workflow_id 可能不是必需的\n // 因为实际的工作流ID已经存储在工具配置中\n // 我们主要验证存在字段的格式,而不是强制要求所有字段都存在\n }\n\n /**\n * 验证必需字段\n */\n private validateRequiredFields(workflow: CozeWorkflow): void {\n const requiredFields = [\n { field: \"workflow_id\", name: \"工作流ID\" },\n { field: \"workflow_name\", name: \"工作流名称\" },\n { field: \"app_id\", name: \"应用ID\" },\n ];\n\n for (const { field, name } of requiredFields) {\n const value = workflow[field as keyof CozeWorkflow];\n if (!value || typeof value !== \"string\" || value.trim() === \"\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `${name}不能为空且必须是非空字符串`\n );\n }\n }\n }\n\n /**\n * 验证字段格式\n */\n private validateFieldFormats(workflow: CozeWorkflow): void {\n // 验证工作流ID格式(数字字符串)\n if (!MCPToolHandler.DIGITS_ONLY_REGEX.test(workflow.workflow_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工作流ID格式无效,应为数字字符串\"\n );\n }\n\n // 验证应用ID格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(workflow.app_id)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"应用ID格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n\n // 验证图标URL格式(如果存在)\n if (workflow.icon_url?.trim()) {\n try {\n new URL(workflow.icon_url);\n } catch {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"图标URL格式无效\"\n );\n }\n }\n\n // 验证时间戳格式\n if (\n workflow.created_at &&\n (!Number.isInteger(workflow.created_at) || workflow.created_at <= 0)\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"创建时间格式无效,应为正整数时间戳\"\n );\n }\n\n if (\n workflow.updated_at &&\n (!Number.isInteger(workflow.updated_at) || workflow.updated_at <= 0)\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"更新时间格式无效,应为正整数时间戳\"\n );\n }\n }\n\n /**\n * 验证字段长度\n */\n private validateFieldLengths(workflow: CozeWorkflow): void {\n const lengthLimits = [\n { field: \"workflow_name\", name: \"工作流名称\", max: 100 },\n { field: \"description\", name: \"工作流描述\", max: 500 },\n { field: \"app_id\", name: \"应用ID\", max: 50 },\n ];\n\n for (const { field, name, max } of lengthLimits) {\n const value = workflow[field as keyof CozeWorkflow] as string;\n if (value && value.length > max) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `${name}过长,不能超过${max}个字符`\n );\n }\n }\n }\n\n /**\n * 验证业务逻辑\n */\n private validateBusinessLogic(workflow: CozeWorkflow): void {\n // 验证创建者信息\n if (workflow.creator) {\n if (!workflow.creator.id || typeof workflow.creator.id !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"创建者ID不能为空且必须是字符串\"\n );\n }\n if (!workflow.creator.name || typeof workflow.creator.name !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"创建者名称不能为空且必须是字符串\"\n );\n }\n }\n\n // 验证时间逻辑\n if (\n workflow.created_at &&\n workflow.updated_at &&\n workflow.updated_at < workflow.created_at\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"更新时间不能早于创建时间\"\n );\n }\n\n // 验证工作流名称不能包含敏感词\n const sensitiveWords = [\n \"admin\",\n \"root\",\n \"system\",\n \"config\",\n \"password\",\n \"token\",\n ];\n const lowerName = workflow.workflow_name.toLowerCase();\n for (const word of sensitiveWords) {\n if (lowerName.includes(word)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `工作流名称不能包含敏感词: ${word}`\n );\n }\n }\n }\n\n /**\n * 解决工具名称冲突\n */\n private resolveToolNameConflict(baseName: string): string {\n const existingTools = configManager.getCustomMCPTools();\n const existingNames = new Set(existingTools.map((tool) => tool.name));\n\n let finalName = baseName;\n let counter = 1;\n\n // 如果名称已存在,添加数字后缀\n while (existingNames.has(finalName)) {\n finalName = `${baseName}_${counter}`;\n counter++;\n\n // 防止无限循环\n if (counter > 999) {\n throw MCPError.operationError(\n MCPErrorCode.OPERATION_FAILED,\n `无法为工具生成唯一名称,基础名称: ${baseName}`\n );\n }\n }\n\n return finalName;\n }\n\n /**\n * 生成工具描述\n */\n private generateToolDescription(\n workflow: CozeWorkflow,\n customDescription?: string\n ): string {\n if (customDescription) {\n return customDescription;\n }\n\n if (workflow.description?.trim()) {\n return workflow.description.trim();\n }\n\n // 生成默认描述\n return `扣子工作流工具: ${workflow.workflow_name}`;\n }\n\n /**\n * 创建HTTP处理器配置\n */\n private createHttpHandler(workflow: CozeWorkflow): ProxyHandlerConfig {\n // 验证扣子API配置\n this.validateCozeApiConfig();\n\n return {\n type: \"proxy\",\n platform: \"coze\",\n config: {\n workflow_id: workflow.workflow_id,\n },\n };\n }\n\n /**\n * 验证扣子API配置\n */\n private validateCozeApiConfig(): void {\n // 检查是否配置了扣子token\n const cozeConfig = configManager.getCozePlatformConfig();\n if (!cozeConfig || !cozeConfig.token) {\n throw MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n \"未配置扣子API Token,请先在配置中设置 platforms.coze.token\"\n );\n }\n }\n\n /**\n * 验证生成的工具配置\n */\n private validateGeneratedTool(tool: CustomMCPTool): void {\n // 基础结构验证\n this.validateToolStructure(tool);\n\n // 使用configManager的验证方法\n if (!configManager.validateCustomMCPTools([tool])) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"生成的工具配置验证失败,请检查工具定义\"\n );\n }\n\n // JSON Schema验证\n this.validateJsonSchema(tool.inputSchema);\n\n // HTTP处理器验证\n if (tool.handler) {\n this.validateProxyHandler(tool.handler as ProxyHandlerConfig);\n }\n }\n\n /**\n * 验证工具基础结构\n */\n private validateToolStructure(tool: CustomMCPTool): void {\n if (!tool || typeof tool !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具配置必须是有效对象\"\n );\n }\n\n // 验证必需字段\n const requiredFields = [\"name\", \"description\", \"inputSchema\", \"handler\"];\n for (const field of requiredFields) {\n if (!(field in tool) || tool[field as keyof CustomMCPTool] == null) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `工具配置缺少必需字段: ${field}`\n );\n }\n }\n\n // 验证字段类型\n if (typeof tool.name !== \"string\" || tool.name.trim() === \"\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具名称必须是非空字符串\"\n );\n }\n\n if (\n typeof tool.description !== \"string\" ||\n tool.description.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具描述必须是非空字符串\"\n );\n }\n\n if (typeof tool.inputSchema !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构必须是对象\"\n );\n }\n\n if (typeof tool.handler !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"处理器配置必须是对象\"\n );\n }\n }\n\n /**\n * 验证HTTP处理器配置\n */\n private validateProxyHandler(handler: ProxyHandlerConfig): void {\n if (!handler || typeof handler !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"HTTP处理器配置不能为空\"\n );\n }\n\n // 验证处理器类型\n if (handler.type !== \"proxy\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"处理器类型必须是'proxy'\"\n );\n }\n\n if (handler.platform === \"coze\") {\n if (!handler.config.workflow_id) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"Coze处理器必须包含有效的workflow_id\"\n );\n }\n } else {\n throw MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n \"不支持的工作流平台\"\n );\n }\n }\n\n /**\n * 验证认证配置\n */\n private validateAuthConfig(auth: { type: string; token?: string }): void {\n if (!auth || typeof auth !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"认证配置必须是对象\"\n );\n }\n\n if (!auth.type || typeof auth.type !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"认证类型不能为空\"\n );\n }\n\n const validAuthTypes = [\"bearer\", \"basic\", \"api_key\"];\n if (!validAuthTypes.includes(auth.type)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `认证类型必须是以下之一: ${validAuthTypes.join(\", \")}`\n );\n }\n\n // 验证token格式\n if (auth.type === \"bearer\") {\n if (!auth.token || typeof auth.token !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"Bearer认证必须包含有效的token\"\n );\n }\n\n // 验证token格式(应该是环境变量引用或实际token)\n if (\n !auth.token.startsWith(\"${\") &&\n !MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(auth.token)\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"Bearer token格式无效\"\n );\n }\n }\n }\n\n /**\n * 验证请求体模板\n */\n private validateBodyTemplate(bodyTemplate: string): void {\n if (typeof bodyTemplate !== \"string\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"请求体模板必须是字符串\"\n );\n }\n\n try {\n JSON.parse(bodyTemplate);\n } catch {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"请求体模板必须是有效的JSON格式\"\n );\n }\n\n // 验证模板变量格式\n const templateVars = bodyTemplate.match(/\\{\\{[^}]+\\}\\}/g);\n if (templateVars) {\n for (const templateVar of templateVars) {\n const varName = templateVar.slice(2, -2).trim();\n if (!varName || !MCPToolHandler.IDENTIFIER_REGEX.test(varName)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n `模板变量格式无效: ${templateVar}`\n );\n }\n }\n }\n }\n\n /**\n * 验证JSON Schema格式\n */\n private validateJsonSchema(schema: JSONSchema): void {\n if (!schema || typeof schema !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构必须是有效的对象\"\n );\n }\n\n if (!schema.type || schema.type !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构的type必须是'object'\"\n );\n }\n\n if (!schema.properties || typeof schema.properties !== \"object\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构必须包含properties字段\"\n );\n }\n\n // 验证required字段\n if (schema.required && !Array.isArray(schema.required)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"输入参数结构的required字段必须是数组\"\n );\n }\n }\n\n /**\n * 生成输入参数结构\n */\n private generateInputSchema(\n workflow: CozeWorkflow,\n parameterConfig?: WorkflowParameterConfig\n ): JSONSchema {\n // 如果提供了参数配置,使用参数配置生成schema\n if (parameterConfig && parameterConfig.parameters.length > 0) {\n return this.generateInputSchemaFromConfig(parameterConfig);\n }\n\n // 否则使用默认的基础参数结构\n const baseSchema = {\n type: \"object\",\n properties: {\n input: {\n type: \"string\",\n description: \"输入内容\",\n },\n },\n required: [\"input\"],\n additionalProperties: false,\n };\n\n return baseSchema;\n }\n\n /**\n * 根据参数配置生成输入参数结构\n */\n private generateInputSchemaFromConfig(\n parameterConfig: WorkflowParameterConfig\n ): JSONSchema {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const param of parameterConfig.parameters) {\n properties[param.fieldName] = {\n type: param.type,\n description: param.description,\n };\n\n if (param.required) {\n required.push(param.fieldName);\n }\n }\n\n return {\n type: \"object\",\n properties,\n required: required.length > 0 ? required : undefined,\n additionalProperties: false,\n };\n }\n\n /**\n * 处理添加工具时的错误\n */\n private handleAddToolError(error: unknown): {\n code: string;\n message: string;\n status: number;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"添加自定义工具失败\";\n\n // 工具类型错误 (400)\n if (\n errorMessage.includes(\"工具类型\") ||\n errorMessage.includes(\"TOOL_TYPE\")\n ) {\n return {\n code: \"INVALID_TOOL_TYPE\",\n message: errorMessage,\n status: 400,\n };\n }\n\n // 缺少必需字段错误 (400)\n if (\n errorMessage.includes(\"必需字段\") ||\n errorMessage.includes(\"MISSING_REQUIRED_FIELD\")\n ) {\n return {\n code: \"MISSING_REQUIRED_FIELD\",\n message: errorMessage,\n status: 400,\n };\n }\n\n // 工具或服务不存在错误 (404)\n if (\n errorMessage.includes(\"不存在\") ||\n errorMessage.includes(\"NOT_FOUND\") ||\n errorMessage.includes(\"未找到\")\n ) {\n return {\n code: \"SERVICE_OR_TOOL_NOT_FOUND\",\n message: errorMessage,\n status: 404,\n };\n }\n\n // 服务未初始化错误 (503)\n if (\n errorMessage.includes(\"未初始化\") ||\n errorMessage.includes(\"SERVICE_NOT_INITIALIZED\")\n ) {\n return {\n code: \"SERVICE_NOT_INITIALIZED\",\n message: errorMessage,\n status: 503,\n };\n }\n\n // 工具名称冲突错误 (409)\n if (\n errorMessage.includes(\"已存在\") ||\n errorMessage.includes(\"冲突\") ||\n errorMessage.includes(\"TOOL_NAME_CONFLICT\")\n ) {\n return {\n code: \"TOOL_NAME_CONFLICT\",\n message: `${errorMessage}。建议:1) 使用自定义名称;2) 删除现有同名工具后重试`,\n status: 409,\n };\n }\n\n // 数据验证错误 (400)\n if (this.isValidationError(errorMessage)) {\n return {\n code: \"VALIDATION_ERROR\",\n message: this.formatValidationError(errorMessage),\n status: 400,\n };\n }\n\n // 配置错误 (422)\n if (\n errorMessage.includes(\"配置\") ||\n errorMessage.includes(\"token\") ||\n errorMessage.includes(\"API\") ||\n errorMessage.includes(\"CONFIGURATION_ERROR\")\n ) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: `${errorMessage}。请检查:1) 相关配置是否正确;2) 网络连接是否正常;3) 配置文件权限是否正确`,\n status: 422,\n };\n }\n\n // 资源限制错误 (429)\n if (\n errorMessage.includes(\"资源限制\") ||\n errorMessage.includes(\"RESOURCE_LIMIT_EXCEEDED\")\n ) {\n return {\n code: \"RESOURCE_LIMIT_EXCEEDED\",\n message: errorMessage,\n status: 429,\n };\n }\n\n // 未实现功能错误 (501)\n if (\n errorMessage.includes(\"未实现\") ||\n errorMessage.includes(\"NOT_IMPLEMENTED\")\n ) {\n return {\n code: \"TOOL_TYPE_NOT_IMPLEMENTED\",\n message: errorMessage,\n status: 501,\n };\n }\n\n // 系统错误 (500)\n return {\n code: \"ADD_CUSTOM_TOOL_ERROR\",\n message: `添加工具失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`,\n status: 500,\n };\n }\n\n /**\n * 处理删除工具时的错误\n */\n private handleRemoveToolError(error: unknown): {\n code: string;\n message: string;\n status: number;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"删除自定义工具失败\";\n\n // 工具不存在错误 (404)\n if (errorMessage.includes(\"不存在\") || errorMessage.includes(\"未找到\")) {\n return {\n code: \"TOOL_NOT_FOUND\",\n message: `${errorMessage}。请检查工具名称是否正确,或刷新页面查看最新的工具列表`,\n status: 404,\n };\n }\n\n // 参数错误 (400)\n if (errorMessage.includes(\"不能为空\") || errorMessage.includes(\"无效\")) {\n return {\n code: \"INVALID_REQUEST\",\n message: `${errorMessage}。请提供有效的工具名称`,\n status: 400,\n };\n }\n\n // 配置错误 (422)\n if (errorMessage.includes(\"配置\") || errorMessage.includes(\"权限\")) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: `${errorMessage}。请检查配置文件权限和格式是否正确`,\n status: 422,\n };\n }\n\n // 系统错误 (500)\n return {\n code: \"REMOVE_CUSTOM_TOOL_ERROR\",\n message: `删除工具失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`,\n status: 500,\n };\n }\n\n /**\n * 判断是否为数据验证错误\n */\n private isValidationError(errorMessage: string): boolean {\n const validationKeywords = [\n \"不能为空\",\n \"必须是\",\n \"格式无效\",\n \"过长\",\n \"过短\",\n \"验证失败\",\n \"无效\",\n \"不符合\",\n \"超过\",\n \"少于\",\n \"敏感词\",\n \"时间\",\n \"URL\",\n ];\n\n return validationKeywords.some((keyword) => errorMessage.includes(keyword));\n }\n\n /**\n * 格式化验证错误信息\n */\n private formatValidationError(errorMessage: string): string {\n // 为常见的验证错误提供更友好的提示\n const errorMappings: Record<string, string> = {\n 工作流ID不能为空: \"请提供有效的工作流ID\",\n 工作流名称不能为空: \"请提供有效的工作流名称\",\n 应用ID不能为空: \"请提供有效的应用ID\",\n 工作流ID格式无效: \"工作流ID应为数字格式,请检查工作流配置\",\n 应用ID格式无效: \"应用ID只能包含字母、数字、下划线和连字符\",\n 工作流名称过长: \"工作流名称不能超过100个字符,请缩短名称\",\n 工作流描述过长: \"工作流描述不能超过500个字符,请缩短描述\",\n 图标URL格式无效: \"请提供有效的图标URL地址\",\n 更新时间不能早于创建时间: \"工作流的时间信息有误,请检查工作流数据\",\n 敏感词: \"工作流名称包含敏感词汇,请修改后重试\",\n };\n\n // 查找匹配的错误映射\n for (const [key, value] of Object.entries(errorMappings)) {\n if (errorMessage.includes(key)) {\n return value;\n }\n }\n\n return errorMessage;\n }\n\n /**\n * 执行边界条件预检查\n */\n private performPreChecks(\n workflow: unknown,\n customName?: string,\n customDescription?: string\n ): { code: string; message: string; status: number } | null {\n // 检查基础参数\n const basicCheckResult = this.checkBasicParameters(\n workflow,\n customName,\n customDescription\n );\n if (basicCheckResult) return basicCheckResult;\n\n // 检查系统状态\n const systemCheckResult = this.checkSystemStatus();\n if (systemCheckResult) return systemCheckResult;\n\n // 检查资源限制\n const resourceCheckResult = this.checkResourceLimits();\n if (resourceCheckResult) return resourceCheckResult;\n\n return null; // 所有检查通过\n }\n\n /**\n * 检查基础参数\n */\n private checkBasicParameters(\n workflow: unknown,\n customName?: string,\n customDescription?: string\n ): { code: string; message: string; status: number } | null {\n // 检查workflow参数\n if (!workflow) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"请求体中缺少 workflow 参数\",\n status: 400,\n };\n }\n\n if (typeof workflow !== \"object\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"workflow 参数必须是对象类型\",\n status: 400,\n };\n }\n\n // 类型守卫:确保 workflow 不是数组\n if (!Array.isArray(workflow)) {\n const workflowObj = workflow as Record<string, unknown>;\n\n // 检查必需字段\n if (\n !workflowObj.workflow_id ||\n typeof workflowObj.workflow_id !== \"string\" ||\n !workflowObj.workflow_id.trim()\n ) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"workflow_id 不能为空且必须是非空字符串\",\n status: 400,\n };\n }\n\n if (\n !workflowObj.workflow_name ||\n typeof workflowObj.workflow_name !== \"string\" ||\n !workflowObj.workflow_name.trim()\n ) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"workflow_name 不能为空且必须是非空字符串\",\n status: 400,\n };\n }\n }\n\n // 检查自定义参数\n if (customName !== undefined) {\n if (typeof customName !== \"string\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customName 必须是字符串类型\",\n status: 400,\n };\n }\n\n if (customName.trim() === \"\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customName 不能为空字符串\",\n status: 400,\n };\n }\n\n if (customName.length > 50) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customName 长度不能超过50个字符\",\n status: 400,\n };\n }\n }\n\n if (customDescription !== undefined) {\n if (typeof customDescription !== \"string\") {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customDescription 必须是字符串类型\",\n status: 400,\n };\n }\n\n if (customDescription.length > 200) {\n return {\n code: \"INVALID_REQUEST\",\n message: \"customDescription 长度不能超过200个字符\",\n status: 400,\n };\n }\n }\n\n return null;\n }\n\n /**\n * 检查系统状态\n */\n private checkSystemStatus(): {\n code: string;\n message: string;\n status: number;\n } | null {\n // 检查扣子API配置\n try {\n const cozeConfig = configManager.getCozePlatformConfig();\n if (!cozeConfig || !cozeConfig.token) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message:\n \"未配置扣子API Token。请在系统设置中配置 platforms.coze.token\",\n status: 422,\n };\n }\n\n // 检查token格式\n if (\n typeof cozeConfig.token !== \"string\" ||\n cozeConfig.token.trim() === \"\"\n ) {\n return {\n code: \"CONFIGURATION_ERROR\",\n message: \"扣子API Token格式无效。请检查配置中的 platforms.coze.token\",\n status: 422,\n };\n }\n } catch (error) {\n return {\n code: \"SYSTEM_ERROR\",\n message: \"系统配置检查失败,请稍后重试\",\n status: 500,\n };\n }\n\n return null;\n }\n\n /**\n * 检查资源限制\n */\n private checkResourceLimits(): {\n code: string;\n message: string;\n status: number;\n } | null {\n try {\n // 检查现有工具数量限制\n const existingTools = configManager.getCustomMCPTools();\n const maxTools = 100; // 设置最大工具数量限制\n\n if (existingTools.length >= maxTools) {\n return {\n code: \"RESOURCE_LIMIT_EXCEEDED\",\n message: `已达到最大工具数量限制 (${maxTools})。请删除一些不需要的工具后重试`,\n status: 429,\n };\n }\n\n // 检查配置文件大小(简单估算)\n const configSizeEstimate = JSON.stringify(existingTools).length;\n const maxConfigSize = 1024 * 1024; // 1MB限制\n\n if (configSizeEstimate > maxConfigSize) {\n return {\n code: \"PAYLOAD_TOO_LARGE\",\n message: \"配置文件过大。请删除一些不需要的工具以释放空间\",\n status: 413,\n };\n }\n } catch (error) {\n // 资源检查失败不应阻止操作,只记录警告\n this.logger.warn(\"资源限制检查失败:\", error);\n }\n\n return null;\n }\n\n /**\n * 统一的 MCP 工具管理接口\n * POST /api/tools/mcp/manage\n * 支持 action: enable | disable | status | toggle\n */\n async manageMCPTool(c: Context<AppContext>): Promise<Response> {\n try {\n const requestBody = await c.req.json();\n const { action, serverName, toolName, description } = requestBody;\n\n // 验证 action 参数\n if (!action || typeof action !== \"string\") {\n return c.fail(\n \"INVALID_REQUEST\",\n \"action 参数不能为空且必须是字符串\",\n undefined,\n 400\n );\n }\n\n const validActions = [\"enable\", \"disable\", \"status\", \"toggle\"];\n if (!validActions.includes(action)) {\n return c.fail(\n \"INVALID_ACTION\",\n `无效的 action: ${action}。支持的 action: ${validActions.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n // 验证服务名和工具名\n this.validateToolIdentifier(serverName, toolName);\n\n // 根据不同的 action 执行相应操作\n switch (action) {\n case \"enable\":\n return this.handleEnableTool(c, serverName, toolName, description);\n case \"disable\":\n return this.handleDisableTool(c, serverName, toolName);\n case \"status\":\n return this.handleGetToolStatus(c, serverName, toolName);\n case \"toggle\":\n return this.handleToggleTool(c, serverName, toolName);\n default: {\n return c.fail(\n \"INVALID_ACTION\",\n `未实现的 action: ${action}`,\n undefined,\n 400\n );\n }\n }\n } catch (error) {\n c.get(\"logger\").error(\"管理 MCP 工具失败:\", error);\n const errorMessage =\n error instanceof Error ? error.message : \"管理 MCP 工具失败\";\n return c.fail(\"TOOL_MANAGE_ERROR\", errorMessage, undefined, 500);\n }\n }\n\n /**\n * 获取服务工具列表\n * POST /api/tools/mcp/list\n */\n async listMCPTools(c: Context<AppContext>): Promise<Response> {\n try {\n const requestBody = await c.req.json();\n const { serverName, includeUsageStats } = requestBody;\n\n // 如果指定了服务名,获取该服务的工具列表\n if (serverName) {\n return this.handleListServerTools(c, serverName, includeUsageStats);\n }\n\n // 否则获取所有服务的工具列表\n return this.handleListAllTools(c, includeUsageStats);\n } catch (error) {\n c.get(\"logger\").error(\"获取工具列表失败:\", error);\n return c.fail(\n \"GET_TOOL_LIST_ERROR\",\n error instanceof Error ? error.message : \"获取工具列表失败\",\n undefined,\n 500\n );\n }\n }\n\n /**\n * 处理启用工具\n */\n private async handleEnableTool(\n c: Context<AppContext>,\n serverName: string,\n toolName: string,\n description?: string\n ): Promise<Response> {\n // 验证服务存在性\n await this.validateServiceAndToolExistence(serverName, toolName);\n\n // 设置工具为启用状态\n configManager.setToolEnabled(serverName, toolName, true, description);\n\n // 获取更新后的工具配置\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n\n c.get(\"logger\").info(`工具已启用: ${serverName}/${toolName}`);\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: true,\n description: toolConfig?.description || description || \"\",\n },\n `工具 \"${serverName}__${toolName}\" 启用成功`\n );\n }\n\n /**\n * 处理禁用工具\n */\n private async handleDisableTool(\n c: Context<AppContext>,\n serverName: string,\n toolName: string\n ): Promise<Response> {\n // 验证服务存在性\n await this.validateServiceAndToolExistence(serverName, toolName);\n\n // 设置工具为禁用状态\n configManager.setToolEnabled(serverName, toolName, false);\n\n c.get(\"logger\").info(`工具已禁用: ${serverName}/${toolName}`);\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: false,\n },\n `工具 \"${serverName}__${toolName}\" 禁用成功`\n );\n }\n\n /**\n * 处理获取工具状态\n */\n private async handleGetToolStatus(\n c: Context<AppContext>,\n serverName: string,\n toolName: string\n ): Promise<Response> {\n // 获取工具配置\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n\n if (!toolConfig) {\n return c.fail(\n \"TOOL_NOT_FOUND\",\n `工具 \"${serverName}__${toolName}\" 不存在或未配置`,\n undefined,\n 404\n );\n }\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: toolConfig.enable !== false,\n description: toolConfig.description || \"\",\n usageCount: toolConfig.usageCount,\n lastUsedTime: toolConfig.lastUsedTime,\n },\n \"工具状态获取成功\"\n );\n }\n\n /**\n * 处理切换工具状态\n */\n private async handleToggleTool(\n c: Context<AppContext>,\n serverName: string,\n toolName: string\n ): Promise<Response> {\n // 验证服务存在性\n await this.validateServiceAndToolExistence(serverName, toolName);\n\n // 获取当前状态\n const currentEnabled = configManager.isToolEnabled(serverName, toolName);\n\n // 切换状态\n const newEnabled = !currentEnabled;\n configManager.setToolEnabled(serverName, toolName, newEnabled);\n\n c.get(\"logger\").info(\n `工具状态已切换: ${serverName}/${toolName} -> ${newEnabled}`\n );\n\n return c.success(\n {\n serverName,\n toolName,\n enabled: newEnabled,\n },\n `工具 \"${serverName}__${toolName}\" 已${newEnabled ? \"启用\" : \"禁用\"}`\n );\n }\n\n /**\n * 处理获取指定服务的工具列表\n */\n private async handleListServerTools(\n c: Context<AppContext>,\n serverName: string,\n includeUsageStats?: boolean\n ): Promise<Response> {\n // 检查服务是否存在\n const mcpServers = configManager.getMcpServers();\n if (!mcpServers[serverName]) {\n return c.fail(\n \"SERVICE_NOT_FOUND\",\n `MCP 服务 \"${serverName}\" 不存在`,\n undefined,\n 404\n );\n }\n\n // 获取工具配置\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const tools = Object.entries(toolsConfig).map(([toolName, toolConfig]) => {\n const result: Record<string, unknown> = {\n toolName,\n enabled: toolConfig.enable !== false,\n description: toolConfig.description || \"\",\n };\n\n if (includeUsageStats) {\n result.usageCount = toolConfig.usageCount;\n result.lastUsedTime = toolConfig.lastUsedTime;\n }\n\n return result;\n });\n\n const enabledCount = tools.filter((t) => t.enabled).length;\n const disabledCount = tools.length - enabledCount;\n\n return c.success(\n {\n serverName,\n tools,\n total: tools.length,\n enabledCount,\n disabledCount,\n },\n \"获取工具列表成功\"\n );\n }\n\n /**\n * 处理获取所有服务的工具列表\n */\n private async handleListAllTools(\n c: Context<AppContext>,\n includeUsageStats?: boolean\n ): Promise<Response> {\n const mcpServerConfig = configManager.getMcpServerConfig();\n\n // 定义工具信息接口\n interface ToolInfo {\n toolName: string;\n enabled: boolean;\n description: string;\n usageCount?: number;\n lastUsedTime?: string;\n }\n\n // 定义服务器工具信息接口\n interface ServerToolsInfo {\n serverName: string;\n tools: ToolInfo[];\n total: number;\n enabledCount: number;\n disabledCount: number;\n }\n\n // 定义返回结果接口\n interface AllToolsResult {\n servers: ServerToolsInfo[];\n totalTools: number;\n totalEnabled: number;\n totalDisabled: number;\n }\n\n const result: AllToolsResult = {\n servers: [],\n totalTools: 0,\n totalEnabled: 0,\n totalDisabled: 0,\n };\n\n for (const [serverName, serverConfig] of Object.entries(mcpServerConfig)) {\n const tools: ToolInfo[] = Object.entries(serverConfig.tools || {}).map(\n ([toolName, toolConfig]) => {\n const toolInfo: ToolInfo = {\n toolName,\n enabled: toolConfig.enable !== false,\n description: toolConfig.description || \"\",\n };\n\n if (includeUsageStats) {\n toolInfo.usageCount = toolConfig.usageCount;\n toolInfo.lastUsedTime = toolConfig.lastUsedTime;\n }\n\n return toolInfo;\n }\n );\n\n const enabledCount = tools.filter((t) => t.enabled).length;\n\n result.servers.push({\n serverName,\n tools,\n total: tools.length,\n enabledCount,\n disabledCount: tools.length - enabledCount,\n });\n\n result.totalTools += tools.length;\n result.totalEnabled += enabledCount;\n result.totalDisabled += tools.length - enabledCount;\n }\n\n return c.success(result, \"获取所有工具列表成功\");\n }\n\n /**\n * 验证工具标识符\n */\n private validateToolIdentifier(serverName: string, toolName: string): void {\n if (\n !serverName ||\n typeof serverName !== \"string\" ||\n serverName.trim() === \"\"\n ) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"服务名称不能为空\"\n );\n }\n\n if (!toolName || typeof toolName !== \"string\" || toolName.trim() === \"\") {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具名称不能为空\"\n );\n }\n\n // 验证服务名称格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(serverName)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"服务名称格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n\n // 验证工具名称格式\n if (!MCPToolHandler.ALPHANUMERIC_UNDERSCORE_REGEX.test(toolName)) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_VALIDATION_FAILED,\n \"工具名称格式无效,只能包含字母、数字、下划线和连字符\"\n );\n }\n }\n\n /**\n * 验证服务和工具是否存在\n */\n private async validateServiceAndToolExistence(\n serverName: string,\n toolName: string\n ): Promise<void> {\n // 检查服务是否存在\n const mcpServers = configManager.getMcpServers();\n if (!mcpServers[serverName]) {\n throw MCPError.validationError(\n MCPErrorCode.SERVER_NOT_FOUND,\n `MCP 服务 \"${serverName}\" 不存在`\n );\n }\n\n // 检查工具是否在服务中存在\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n if (!toolsConfig[toolName]) {\n throw MCPError.validationError(\n MCPErrorCode.TOOL_NOT_FOUND,\n `工具 \"${toolName}\" 在服务 \"${serverName}\" 中不存在或未配置`\n );\n }\n }\n}\n","/**\n * 工具调用日志 API 处理器\n * 负责处理工具调用日志相关的 HTTP API 请求\n */\n\nimport { PAGINATION_CONSTANTS } from \"@/constants/api.constants.js\";\nimport type { ToolCallQuery } from \"@/lib/mcp/log.js\";\nimport { ToolCallLogService } from \"@/lib/mcp/log.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\nimport { z } from \"zod\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 工具调用查询参数 Zod Schema\n */\nconst ToolCallQuerySchema = z\n .object({\n limit: z\n .string()\n .optional()\n .transform((val) => (val ? Number.parseInt(val, 10) : undefined))\n .refine(\n (val) =>\n val === undefined ||\n (val >= 1 && val <= PAGINATION_CONSTANTS.MAX_LIMIT),\n {\n message: `limit 参数必须是 1-${PAGINATION_CONSTANTS.MAX_LIMIT} 之间的数字`,\n }\n ),\n offset: z\n .string()\n .optional()\n .transform((val) => (val ? Number.parseInt(val, 10) : undefined))\n .refine((val) => val === undefined || val >= 0, {\n message: \"offset 参数必须是非负数\",\n }),\n toolName: z.string().optional(),\n serverName: z.string().optional(),\n success: z\n .string()\n .optional()\n .transform((val) => (val ? val.toLowerCase() === \"true\" : undefined)),\n startDate: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true;\n const date = Date.parse(val);\n return !Number.isNaN(date);\n },\n {\n message: \"startDate 参数格式无效\",\n }\n ),\n endDate: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true;\n const date = Date.parse(val);\n return !Number.isNaN(date);\n },\n {\n message: \"endDate 参数格式无效\",\n }\n ),\n })\n .refine(\n (data) => {\n if (!data.startDate || !data.endDate) return true;\n return new Date(data.startDate) <= new Date(data.endDate);\n },\n {\n message: \"startDate 不能晚于 endDate\",\n path: [\"startDate\"],\n }\n );\n\n/**\n * 工具调用日志 API 处理器\n */\nexport class MCPToolLogHandler extends BaseHandler {\n private toolCallLogService: ToolCallLogService;\n\n constructor() {\n super();\n this.toolCallLogService = new ToolCallLogService();\n }\n\n /**\n * 解析和验证查询参数\n */\n private parseAndValidateQueryParams(c: Context<AppContext>): {\n success: boolean;\n data?: ToolCallQuery;\n error?: Array<{ field: string; message: string }>;\n } {\n const query = c.req.query();\n const result = ToolCallQuerySchema.safeParse(query);\n\n if (!result.success) {\n return {\n success: false,\n error: result.error.issues.map((err) => ({\n field: err.path.join(\".\"),\n message: err.message,\n })),\n };\n }\n\n return {\n success: true,\n data: result.data as ToolCallQuery,\n };\n }\n\n /**\n * 获取工具调用日志\n */\n async getToolCallLogs(c: Context<AppContext>): Promise<Response> {\n try {\n const validation = this.parseAndValidateQueryParams(c);\n\n if (!validation.success) {\n return c.fail(\n \"INVALID_QUERY_PARAMETERS\",\n \"查询参数格式错误\",\n validation.error,\n 400\n );\n }\n\n const result = await this.toolCallLogService.getToolCallLogs(\n validation.data!\n );\n\n c.get(\"logger\").debug(\n `API: 返回 ${result.records.length} 条工具调用日志记录`\n );\n return c.success(result);\n } catch (error) {\n c.get(\"logger\").error(\"获取工具调用日志失败:\", error);\n\n const message = error instanceof Error ? error.message : \"未知错误\";\n if (message.includes(\"不存在\")) {\n return c.fail(\"LOG_FILE_NOT_FOUND\", message, undefined, 404);\n }\n if (message.includes(\"无法读取\")) {\n return c.fail(\"LOG_FILE_READ_ERROR\", message, undefined, 500);\n }\n\n return c.fail(\n \"INTERNAL_ERROR\",\n \"获取工具调用日志失败\",\n { details: message },\n 500\n );\n }\n }\n}\n","/**\n * NPM 管理器\n *\n * 提供与 NPM 交互的功能,包括:\n * - 安装指定版本\n * - 获取当前版本\n * - 获取可用版本列表\n * - 检查最新版本\n *\n * @example\n * ```typescript\n * const npmManager = new NPMManager();\n * const versions = await npmManager.getAvailableVersions('stable');\n * await npmManager.installVersion('1.0.0');\n * ```\n */\n\nimport { exec, spawn } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport semver from \"semver\";\nimport type { InstallLogStream } from \"./install-log-stream.js\";\n\nconst execAsync = promisify(exec);\n\nexport class NPMManager {\n private eventBus: EventBus;\n private logStream?: InstallLogStream;\n\n constructor(eventBus?: EventBus, logStream?: InstallLogStream) {\n this.eventBus = eventBus || getEventBus();\n this.logStream = logStream;\n }\n\n /**\n * 安装指定版本 - 这是核心功能\n *\n * @param version 要安装的版本号\n * @param installId 可选的外部传入的安装 ID(由调用方生成以确保能立即返回给前端)\n * @returns Promise,在安装完成时 resolve(成功)或 reject(失败)\n */\n async installVersion(version: string, installId?: string): Promise<string> {\n const resolvedInstallId =\n installId ??\n `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const startTime = Date.now();\n\n logger.info(\"开始安装\", { version, installId: resolvedInstallId });\n\n // 初始化日志流会话\n this.logStream?.startInstall({\n version,\n installId: resolvedInstallId,\n timestamp: Date.now(),\n });\n\n // 发射安装开始事件(向后兼容 WebSocket)\n this.eventBus.emitEvent(\"npm:install:started\", {\n version,\n installId: resolvedInstallId,\n timestamp: Date.now(),\n });\n\n const npmProcess = spawn(\"npm\", [\n \"install\",\n \"-g\",\n `xiaozhi-client@${version}`,\n \"--registry=https://registry.npmmirror.com\",\n ]);\n\n /**\n * 清理进程资源\n * 移除事件监听器并关闭流,防止资源泄漏\n */\n const cleanup = () => {\n npmProcess.removeAllListeners(\"error\");\n npmProcess.removeAllListeners(\"close\");\n npmProcess.stdout?.removeAllListeners(\"data\");\n npmProcess.stderr?.removeAllListeners(\"data\");\n npmProcess.stdout?.destroy();\n npmProcess.stderr?.destroy();\n };\n\n return new Promise<string>((resolve, reject) => {\n // 监听进程启动失败事件\n npmProcess.on(\"error\", (error) => {\n const errorMessage = `进程启动失败: ${error.message}`;\n console.log(errorMessage, { error });\n\n // 清理资源\n cleanup();\n\n // 写入日志流(SSE)\n this.logStream?.fail({\n version,\n installId: resolvedInstallId,\n error: errorMessage,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n });\n\n // 发射安装失败事件(向后兼容 WebSocket)\n this.eventBus.emitEvent(\"npm:install:failed\", {\n version,\n installId: resolvedInstallId,\n error: errorMessage,\n duration: Date.now() - startTime,\n timestamp: Date.now(),\n });\n\n reject(error);\n });\n\n npmProcess.stdout.on(\"data\", (data) => {\n const message = data.toString();\n const logEntry = {\n type: \"stdout\" as const,\n message,\n timestamp: Date.now(),\n };\n\n // 写入日志流(SSE)\n this.logStream?.pushLog(resolvedInstallId, logEntry);\n\n // 发射日志事件(向后兼容 WebSocket)\n this.eventBus.emitEvent(\"npm:install:log\", {\n version,\n installId: resolvedInstallId,\n ...logEntry,\n });\n });\n\n npmProcess.stderr.on(\"data\", (data) => {\n const message = data.toString();\n const logEntry = {\n type: \"stderr\" as const,\n message,\n timestamp: Date.now(),\n };\n\n // 写入日志流(SSE)\n this.logStream?.pushLog(resolvedInstallId, logEntry);\n\n // 发射日志事件(向后兼容 WebSocket)\n this.eventBus.emitEvent(\"npm:install:log\", {\n version,\n installId: resolvedInstallId,\n ...logEntry,\n });\n });\n\n npmProcess.on(\"close\", (code) => {\n const duration = Date.now() - startTime;\n\n // 清理资源(移除事件监听器并关闭流)\n cleanup();\n\n if (code === 0) {\n // 写入日志流(SSE)\n this.logStream?.complete({\n version,\n installId: resolvedInstallId,\n success: true,\n duration,\n timestamp: Date.now(),\n });\n\n // 发射安装完成事件(向后兼容 WebSocket)\n this.eventBus.emitEvent(\"npm:install:completed\", {\n version,\n installId: resolvedInstallId,\n success: true,\n duration,\n timestamp: Date.now(),\n });\n\n resolve(resolvedInstallId);\n } else {\n const error = `安装失败,退出码: ${code}`;\n logger.error(\"安装失败\", { code });\n\n // 写入日志流(SSE)\n this.logStream?.fail({\n version,\n installId: resolvedInstallId,\n error,\n duration,\n timestamp: Date.now(),\n });\n\n // 发射安装失败事件(向后兼容 WebSocket)\n this.eventBus.emitEvent(\"npm:install:failed\", {\n version,\n installId: resolvedInstallId,\n error,\n duration,\n timestamp: Date.now(),\n });\n\n reject(new Error(error));\n }\n });\n });\n }\n\n /**\n * 获取当前版本\n */\n async getCurrentVersion(): Promise<string> {\n const { stdout } = await execAsync(\n \"npm list -g xiaozhi-client --depth=0 --json --registry=https://registry.npmmirror.com\"\n );\n const info = JSON.parse(stdout);\n return info.dependencies?.[\"xiaozhi-client\"]?.version || \"unknown\";\n }\n\n /**\n * 版本类型枚举\n */\n static readonly VERSION_TYPES = {\n STABLE: \"stable\",\n RC: \"rc\",\n BETA: \"beta\",\n ALL: \"all\",\n } as const;\n\n /**\n * 获取可用版本列表\n */\n async getAvailableVersions(type = \"stable\"): Promise<string[]> {\n try {\n const { stdout } = await execAsync(\n \"npm view xiaozhi-client versions --json --registry=https://registry.npmmirror.com\"\n );\n\n const versions = JSON.parse(stdout) as string[];\n\n // 使用 semver 验证并过滤有效版本\n let filteredVersions = versions.filter((version) => {\n return version && typeof version === \"string\" && semver.valid(version);\n });\n\n // 根据类型过滤版本\n if (type !== \"all\") {\n filteredVersions = filteredVersions.filter((version) => {\n const prerelease = semver.prerelease(version);\n\n if (type === \"stable\") {\n // 正式版:没有预发布标识符的版本 (x.y.z)\n return prerelease === null;\n }\n\n if (type === \"rc\") {\n // 预览版:预发布标识符以 rc 开头\n return (\n prerelease !== null &&\n prerelease[0]?.toString()?.toLowerCase()?.startsWith(\"rc\") ===\n true\n );\n }\n\n if (type === \"beta\") {\n // 测试版:预发布标识符以 beta 开头\n return (\n prerelease !== null &&\n prerelease[0]?.toString()?.toLowerCase()?.startsWith(\"beta\") ===\n true\n );\n }\n\n return true;\n });\n }\n\n // 进行降序排列(最新的在前)\n return filteredVersions.sort((a, b) => semver.rcompare(a, b));\n } catch (error) {\n logger.error(\"获取版本列表失败\", { error });\n // 如果获取失败,返回一些默认版本\n return [];\n }\n }\n\n /**\n * 检查是否有最新版本\n * 返回当前版本、最新版本以及是否有更新\n */\n async checkForLatestVersion(): Promise<{\n currentVersion: string;\n latestVersion: string | null;\n hasUpdate: boolean;\n error?: string;\n }> {\n try {\n // 获取当前版本\n const currentVersion = await this.getCurrentVersion();\n\n // 如果无法获取当前版本,返回错误\n if (!currentVersion || currentVersion === \"unknown\") {\n return {\n currentVersion: \"unknown\",\n latestVersion: null,\n hasUpdate: false,\n error: \"无法获取当前版本信息\",\n };\n }\n\n // 获取最新的正式版本\n const stableVersions = await this.getAvailableVersions(\"stable\");\n\n if (stableVersions.length === 0) {\n return {\n currentVersion,\n latestVersion: null,\n hasUpdate: false,\n error: \"无法获取可用版本列表\",\n };\n }\n\n // 获取最新的正式版本(第一个元素)\n const latestVersion = stableVersions[0];\n\n // 比较版本\n let hasUpdate = false;\n try {\n // 使用 semver 比较版本\n hasUpdate = semver.gt(latestVersion, currentVersion);\n } catch (error) {\n logger.warn(\"版本比较失败,回退到字符串比较\", { error });\n // 如果比较失败,尝试字符串比较\n hasUpdate = latestVersion !== currentVersion;\n }\n\n logger.debug(\"版本检查完成\", {\n currentVersion,\n latestVersion,\n hasUpdate,\n });\n\n return {\n currentVersion,\n latestVersion,\n hasUpdate,\n };\n } catch (error) {\n logger.error(\"检查最新版本失败\", { error });\n return {\n currentVersion: \"unknown\",\n latestVersion: null,\n hasUpdate: false,\n error:\n error instanceof Error ? error.message : \"检查更新时发生未知错误\",\n };\n }\n }\n}\n","/**\n * NPM 安装日志流管理器\n *\n * 管理每个安装任务的日志数据,支持通过 SSE 流式推送给前端。\n * 替代原有的 WebSocket 广播机制。\n *\n * ## 核心功能\n * - 按 installId 隔离各安装任务的日志\n * - 支持实时追加日志条目\n * - 提供 ReadableStream 接口用于 SSE 响应\n * - 自动清理已完成的安装任务数据\n */\n\n/** 单条安装日志 */\nexport interface InstallLogEntry {\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n}\n\n/** 安装开始事件数据 */\nexport interface InstallStartedData {\n version: string;\n installId: string;\n timestamp: number;\n}\n\n/** 安装完成事件数据 */\nexport interface InstallCompletedData {\n version: string;\n installId: string;\n success: boolean;\n duration: number;\n timestamp: number;\n}\n\n/** 安装失败事件数据 */\nexport interface InstallFailedData {\n version: string;\n installId: string;\n error: string;\n duration: number;\n timestamp: number;\n}\n\n/** 安装任务内部状态 */\ninterface InstallSession {\n /** 已收集的日志(用于断线重连的客户端) */\n logs: InstallLogEntry[];\n /** 正在等待的 SSE 流控制器(可能有多个消费者) */\n controllers: Set<ReadableStreamDefaultController>;\n /** 是否已完成(成功或失败) */\n done: boolean;\n /** 完成时的最终事件数据 */\n finalData?: InstallCompletedData | InstallFailedData;\n}\n\n/**\n * NPM 安装日志流管理器\n *\n * 使用方式:\n * 1. NPMManager 调用 startInstall/pushLog/complete/fail 写入数据\n * 2. SSE 端点调用 createSSEStream 获取 ReadableStream 用于响应\n */\nexport class InstallLogStream {\n /** 按 installId 管理的安装会话 */\n private sessions: Map<string, InstallSession> = new Map();\n\n /**\n * 开始一个新的安装会话\n */\n startInstall(data: InstallStartedData): void {\n this.sessions.set(data.installId, {\n logs: [],\n controllers: new Set(),\n done: false,\n });\n }\n\n /**\n * 追加一条安装日志\n */\n pushLog(installId: string, entry: InstallLogEntry): void {\n const session = this.sessions.get(installId);\n if (!session) {\n return;\n }\n\n session.logs.push(entry);\n\n // 向所有活跃的 SSE 消费者推送日志\n const eventData = this.formatSSEEvent(\"log\", {\n installId,\n ...entry,\n });\n this.pushToControllers(session.controllers, eventData);\n }\n\n /**\n * 标记安装完成\n */\n complete(data: InstallCompletedData): void {\n this.finalizeSession(data.installId, data);\n }\n\n /**\n * 标记安装失败\n */\n fail(data: InstallFailedData): void {\n this.finalizeSession(data.installId, data);\n }\n\n /**\n * 创建 SSE ReadableStream\n *\n * 前端通过 GET /api/install/logs?installId=xxx 连接此流。\n * 返回的 ReadableStream 会先发送历史日志(支持断线重连),\n * 然后持续推送新日志直到安装完成。\n */\n createSSEStream(installId: string): ReadableStream<string> | null {\n const session = this.sessions.get(installId);\n if (!session) {\n return null;\n }\n\n let streamController: ReadableStreamDefaultController<string> | null = null;\n\n return new ReadableStream<string>({\n start: (controller) => {\n streamController = controller;\n session.controllers.add(controller);\n\n // 发送 SSE 响应头和初始数据\n controller.enqueue(\": connected\\n\\n\");\n\n // 发送历史日志(支持晚连接的客户端)\n for (const log of session.logs) {\n const eventData = this.formatSSEEvent(\"log\", {\n installId,\n ...log,\n });\n controller.enqueue(eventData);\n }\n\n // 如果已经完成,直接发送最终事件并关闭\n if (session.done && session.finalData) {\n const eventType =\n \"success\" in session.finalData ? \"completed\" : \"failed\";\n const eventData = this.formatSSEEvent(eventType, session.finalData);\n controller.enqueue(eventData);\n controller.close();\n session.controllers.delete(controller);\n streamController = null;\n return;\n }\n },\n cancel: () => {\n if (streamController) {\n session.controllers.delete(streamController);\n streamController = null;\n }\n },\n });\n }\n\n /**\n * 清理指定安装会话的资源\n */\n cleanup(installId: string): void {\n const session = this.sessions.get(installId);\n if (session) {\n // 关闭所有活跃的消费者\n for (const controller of session.controllers) {\n try {\n controller.close();\n } catch {\n // 忽略关闭错误\n }\n }\n session.controllers.clear();\n this.sessions.delete(installId);\n }\n }\n\n /**\n * 清理所有已完成的会话(可定期调用释放内存)\n */\n cleanupCompleted(): void {\n for (const [installId, session] of this.sessions) {\n if (session.done) {\n this.cleanup(installId);\n }\n }\n }\n\n /**\n * 检查安装会话是否存在\n */\n hasSession(installId: string): boolean {\n return this.sessions.has(installId);\n }\n\n // ==================== 私有方法 ====================\n\n /**\n * 终结会话:发送最终事件并关闭所有消费者\n */\n private finalizeSession(\n installId: string,\n data: InstallCompletedData | InstallFailedData\n ): void {\n const session = this.sessions.get(installId);\n if (!session || session.done) {\n return;\n }\n\n session.done = true;\n session.finalData = data;\n\n const eventType = \"success\" in data ? \"completed\" : \"failed\";\n const eventData = this.formatSSEEvent(eventType, data);\n\n // 向所有活跃消费者发送最终事件并关闭\n for (const controller of session.controllers) {\n try {\n controller.enqueue(eventData);\n controller.close();\n } catch {\n // 流可能已被取消\n }\n }\n session.controllers.clear();\n\n // 延迟清理会话数据(给消费者一些时间处理完成事件)\n setTimeout(() => {\n this.cleanup(installId);\n }, 60_000); // 1 分钟后清理\n }\n\n /**\n * 向所有活跃控制器推送 SSE 数据\n */\n private pushToControllers(\n controllers: Set<ReadableStreamDefaultController>,\n data: string\n ): void {\n for (const controller of controllers) {\n try {\n controller.enqueue(data);\n } catch {\n // 流可能已被取消或关闭,从集合中移除\n controllers.delete(controller);\n }\n }\n }\n\n /**\n * 格式化 SSE 事件数据\n *\n * 输出格式:\n * event: <type>\\n\n * data: <json>\\n\\n\n */\n private formatSSEEvent(type: string, data: unknown): string {\n return `event: ${type}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n }\n}\n","/**\n * 更新 API HTTP 路由处理器\n * 提供版本更新和 NPM 包安装相关的 RESTful API 接口\n *\n * 支持两种模式:\n * - POST /api/update:触发安装,返回 installId\n * - GET /api/install/logs?installId=xxx:SSE 日志流式推送\n */\nimport { InstallLogStream, NPMManager } from \"@/lib/npm\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\nimport { z } from \"zod\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n// 版本号请求格式验证\nconst UpdateRequestSchema = z.object({\n version: z.string().min(1, \"版本号不能为空\"),\n});\n\n/**\n * 更新 API 处理器\n */\nexport class UpdateApiHandler extends BaseHandler {\n private npmManager: NPMManager;\n private eventBus = getEventBus();\n private activeInstalls: Map<string, boolean> = new Map();\n private logStream: InstallLogStream;\n\n constructor(logStream?: InstallLogStream) {\n super();\n this.logStream = logStream ?? new InstallLogStream();\n this.npmManager = new NPMManager(this.eventBus, this.logStream);\n }\n\n /**\n * 获取日志流实例(供外部访问)\n */\n getLogStream(): InstallLogStream {\n return this.logStream;\n }\n\n /**\n * 执行版本更新\n * POST /api/update\n * Body: { version: string }\n * Response: { success, data: { version, installId }, message }\n */\n async performUpdate(c: Context<AppContext>): Promise<Response> {\n try {\n const body = await this.parseJsonBody<{ version: string }>(\n c,\n \"请求体格式错误\"\n );\n\n // 使用 zod 进行参数验证\n const parseResult = UpdateRequestSchema.safeParse(body);\n if (!parseResult.success) {\n return c.fail(\n \"INVALID_VERSION\",\n \"请求参数格式错误\",\n parseResult.error.issues.map((err) => ({\n field: err.path.join(\".\"),\n message: err.message,\n })),\n 400\n );\n }\n\n const { version } = parseResult.data;\n\n // 检查是否有正在进行的安装\n const hasActiveInstall = Array.from(this.activeInstalls.values()).some(\n (v) => v\n );\n if (hasActiveInstall) {\n return c.fail(\n \"INSTALL_IN_PROGRESS\",\n \"已有安装进程正在进行,请等待完成后再试\",\n undefined,\n 409\n );\n }\n\n const logger = c.get(\"logger\");\n\n // 生成 installId(在 handler 层生成,确保能立即返回给前端)\n const installId = `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n this.activeInstalls.set(installId, true);\n\n // 异步启动安装(不阻塞响应)\n this.npmManager\n .installVersion(version, installId)\n .then(() => {\n // 安装成功,保持标记 1 分钟供 SSE 消费者连接\n setTimeout(() => {\n this.activeInstalls.delete(installId);\n }, 60_000);\n })\n .catch((error) => {\n logger.error(\"安装过程失败:\", error);\n this.activeInstalls.delete(installId);\n });\n\n return c.success(\n {\n version,\n installId,\n message: \"安装已启动,请通过 SSE 日志流查看进度\",\n },\n \"安装请求已接受\"\n );\n } catch (error) {\n return this.handleError(c, error, \"处理安装请求\", \"REQUEST_FAILED\");\n }\n }\n\n /**\n * SSE 安装日志流端点\n * GET /api/install/logs?installId=xxx\n *\n * 返回 text/event-stream 格式的实时安装日志。\n * 前端使用 EventSource API 订阅此端点。\n */\n async getInstallLogs(c: Context<AppContext>): Promise<Response> {\n const installId = c.req.query(\"installId\");\n\n if (!installId) {\n return c.fail(\n \"MISSING_INSTALL_ID\",\n \"缺少 installId 参数\",\n undefined,\n 400\n );\n }\n\n // 检查安装会话是否存在\n if (!this.logStream.hasSession(installId)) {\n return c.fail(\n \"INSTALL_NOT_FOUND\",\n \"未找到对应的安装任务,请先发起安装请求\",\n undefined,\n 404\n );\n }\n\n // 创建 SSE 流\n const stream = this.logStream.createSSEStream(installId);\n if (!stream) {\n return c.fail(\"STREAM_ERROR\", \"无法创建日志流\", undefined, 500);\n }\n\n // 返回 SSE 响应\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\", // 禁用 Nginx 缓冲\n },\n });\n }\n}\n","/**\n * 版本 API HTTP 路由处理器\n * 提供版本信息查询、可用版本列表获取、版本检查等相关的 RESTful API 接口\n */\nimport { NPMManager } from \"@/lib/npm\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { VersionUtils } from \"@xiaozhi-client/version\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 版本 API 处理器\n */\nexport class VersionApiHandler extends BaseHandler {\n /**\n * 获取版本信息\n * GET /api/version\n */\n async getVersion(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取版本信息请求\");\n\n // 使用 VersionUtils 获取完整版本信息\n const versionInfo = VersionUtils.getVersionInfo();\n\n c.get(\"logger\").debug(\"获取版本信息成功:\", versionInfo);\n\n return c.success(versionInfo);\n } catch (error) {\n return this.handleError(c, error, \"获取版本信息\", \"VERSION_READ_ERROR\");\n }\n }\n\n /**\n * 获取版本号(简化接口)\n * GET /api/version/simple\n */\n async getVersionSimple(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取版本号请求\");\n\n const version = VersionUtils.getVersion();\n c.get(\"logger\").debug(`获取版本号成功: ${version}`);\n\n return c.success({ version });\n } catch (error) {\n return this.handleError(c, error, \"获取版本号\", \"VERSION_READ_ERROR\");\n }\n }\n\n /**\n * 清除版本缓存\n * POST /api/version/cache/clear\n */\n async clearVersionCache(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理清除版本缓存请求\");\n\n VersionUtils.clearCache();\n c.get(\"logger\").info(\"版本缓存已清除\");\n\n return c.success(undefined, \"版本缓存已清除\");\n } catch (error) {\n return this.handleError(c, error, \"清除版本缓存\", \"CACHE_CLEAR_ERROR\");\n }\n }\n\n /**\n * 获取可用版本列表\n * GET /api/version/available?type=stable|rc|beta|all\n */\n async getAvailableVersions(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理获取可用版本列表请求\");\n\n // 获取查询参数\n const type = (c.req.query(\"type\") as unknown) || \"stable\";\n\n // 验证版本类型参数\n const validTypes = [\"stable\", \"rc\", \"beta\", \"all\"];\n if (!validTypes.includes(type as string)) {\n return c.fail(\n \"INVALID_VERSION_TYPE\",\n `无效的版本类型: ${type}。支持的类型: ${validTypes.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n const npmManager = new NPMManager();\n const versions = await npmManager.getAvailableVersions(type as string);\n\n c.get(\"logger\").debug(\n `获取到 ${versions.length} 个可用版本 (类型: ${type})`\n );\n\n return c.success({\n versions,\n type,\n total: versions.length,\n });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"获取可用版本列表\",\n \"VERSIONS_FETCH_ERROR\"\n );\n }\n }\n\n /**\n * 检查最新版本\n * GET /api/version/latest\n */\n async checkLatestVersion(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").debug(\"处理检查最新版本请求\");\n\n const npmManager = new NPMManager();\n const result = await npmManager.checkForLatestVersion();\n\n c.get(\"logger\").debug(\"版本检查结果:\", result);\n\n if (result.error) {\n // 如果有错误,但仍返回部分信息\n return c.success({\n currentVersion: result.currentVersion,\n latestVersion: result.latestVersion,\n hasUpdate: result.hasUpdate,\n error: result.error,\n });\n }\n\n return c.success({\n currentVersion: result.currentVersion,\n latestVersion: result.latestVersion,\n hasUpdate: result.hasUpdate,\n });\n } catch (error) {\n return this.handleError(\n c,\n error,\n \"检查最新版本\",\n \"LATEST_VERSION_CHECK_ERROR\"\n );\n }\n }\n}\n","/**\n * TTS API HTTP 路由处理器\n * 提供语音合成 RESTful API 接口\n */\n\nimport { TTS_VOICES, getVoiceScenes } from \"@/constants/voices.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport { mapClusterToResourceId } from \"@xiaozhi-client/esp32\";\nimport type { VoiceInfo, VoicesResponse } from \"@xiaozhi-client/shared-types\";\nimport type { Context } from \"hono\";\nimport { createTTS } from \"univoice\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * 允许的 encoding 值白名单\n */\nconst ALLOWED_ENCODINGS = [\n \"mp3\",\n \"wav\",\n \"ogg\",\n \"flac\",\n \"pcm\",\n \"opus\",\n \"ogg_opus\",\n] as const;\n\ntype AllowedEncoding = (typeof ALLOWED_ENCODINGS)[number];\n\n/**\n * encoding 到 MIME Content-Type 的映射\n * 部分值不对应标准 MIME 类型,需要显式映射\n */\nconst ENCODING_TO_MIME: Record<AllowedEncoding, string> = {\n mp3: \"audio/mpeg\",\n wav: \"audio/wav\",\n ogg: \"audio/ogg\",\n flac: \"audio/flac\",\n pcm: \"audio/pcm\",\n opus: \"audio/opus\",\n ogg_opus: \"audio/ogg\",\n};\n\n/**\n * encoding 到文件扩展名的映射\n */\nconst ENCODING_TO_EXT: Record<AllowedEncoding, string> = {\n mp3: \"mp3\",\n wav: \"wav\",\n ogg: \"ogg\",\n flac: \"flac\",\n pcm: \"pcm\",\n opus: \"opus\",\n ogg_opus: \"ogg\",\n};\n\n/**\n * TTS 合成请求体\n */\ninterface TTSRequestBody {\n /** 要转换的文本 */\n text: string;\n /** 应用 ID(可选,从配置读取) */\n appid?: string;\n /** 访问令牌(可选,从配置读取) */\n accessToken?: string;\n /** 声音类型(可选,从配置读取) */\n voice_type?: string;\n /** 编码格式(可选,默认 wav) */\n encoding?: string;\n /** 集群类型(可选) */\n cluster?: string;\n /** WebSocket 端点(可选) */\n endpoint?: string;\n}\n\n/**\n * TTS API 路由处理器类\n */\nexport class TTSApiHandler extends BaseHandler {\n constructor() {\n super();\n }\n\n /**\n * 语音合成\n * POST /api/tts\n */\n async synthesize(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"处理语音合成请求\");\n\n // 解析请求参数\n const body = await this.parseJsonBody<TTSRequestBody>(c);\n\n // 验证必需参数\n if (!body.text) {\n c.get(\"logger\").warn(\"缺少 text 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少必需参数: text\",\n undefined,\n 400\n );\n }\n\n // 获取 TTS 配置作为默认值\n const ttsConfig = configManager.getTTSConfig();\n\n // 优先从请求参数读取,否则从配置读取\n const appid = body.appid || ttsConfig.appid;\n const accessToken = body.accessToken || ttsConfig.accessToken;\n const voice_type = body.voice_type || ttsConfig.voice_type;\n const cluster = body.cluster || ttsConfig.cluster;\n const endpoint = body.endpoint || ttsConfig.endpoint;\n const encoding = body.encoding || ttsConfig.encoding || \"wav\";\n\n // 运行时校验 encoding 值\n if (!ALLOWED_ENCODINGS.includes(encoding as AllowedEncoding)) {\n c.get(\"logger\").warn(`不支持的 encoding 参数: ${encoding}`);\n return c.fail(\n \"INVALID_PARAMETER\",\n `不支持的 encoding 参数: ${encoding},允许值: ${ALLOWED_ENCODINGS.join(\", \")}`,\n undefined,\n 400\n );\n }\n\n const safeEncoding = encoding as AllowedEncoding;\n\n // 验证必需的 TTS 参数\n if (!appid) {\n c.get(\"logger\").warn(\"缺少 appid 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少 appid 参数,请提供或配置 tts.appid\",\n undefined,\n 400\n );\n }\n\n if (!accessToken) {\n c.get(\"logger\").warn(\"缺少 accessToken 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少 accessToken 参数,请提供或配置 tts.accessToken\",\n undefined,\n 400\n );\n }\n\n if (!voice_type) {\n c.get(\"logger\").warn(\"缺少 voice_type 参数\");\n return c.fail(\n \"MISSING_PARAMETER\",\n \"缺少 voice_type 参数,请提供或配置 tts.voice_type\",\n undefined,\n 400\n );\n }\n\n // 创建 TTS 客户端(使用 univoice SDK)\n const tts = createTTS({\n provider: \"doubao\",\n appId: appid!,\n accessToken: accessToken!,\n voice: voice_type!,\n format: safeEncoding,\n resourceId: mapClusterToResourceId(cluster),\n sampleRate: 24000,\n ...(endpoint && { baseUrl: endpoint }),\n });\n\n c.get(\"logger\").info(\n `开始语音合成: text=${body.text.substring(0, 20)}..., voice_type=${voice_type}`\n );\n\n // 调用 TTS 合成(非流式)\n const response = await tts.synthesize({ text: body.text });\n const audioData = response.audio;\n\n c.get(\"logger\").info(`语音合成成功: audioSize=${audioData.length} bytes`);\n\n // 返回音频数据,使用正确的 MIME 类型和文件扩展名\n return new Response(Buffer.from(audioData), {\n headers: {\n \"Content-Type\": ENCODING_TO_MIME[safeEncoding],\n \"Content-Disposition\": `attachment; filename=\"tts_${Date.now()}.${ENCODING_TO_EXT[safeEncoding]}\"`,\n },\n });\n } catch (error) {\n return this.handleError(c, error, \"语音合成\");\n }\n }\n\n /**\n * 获取可用音色列表\n * GET /api/tts/voices\n */\n async getVoices(c: Context<AppContext>): Promise<Response> {\n try {\n c.get(\"logger\").info(\"获取音色列表\");\n\n const voices: VoiceInfo[] = TTS_VOICES;\n const scenes = getVoiceScenes();\n\n const response: VoicesResponse = {\n voices,\n total: voices.length,\n scenes,\n };\n\n return c.success(response);\n } catch (error) {\n return this.handleError(c, error, \"获取音色列表\");\n }\n }\n}\n","/**\n * ESP32 设备处理器\n * 处理 ESP32 设备相关的 HTTP 请求\n *\n * 作为薄适配层,将 Hono 请求委托给 ESP32DeviceManager 处理\n */\n\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type {\n ESP32DeviceManager,\n ESP32DeviceReport,\n} from \"@xiaozhi-client/esp32\";\nimport { ESP32ErrorCode } from \"@xiaozhi-client/esp32\";\nimport type { Context } from \"hono\";\nimport { BaseHandler } from \"./base.handler.js\";\n\n/**\n * ESP32 设备处理器\n * 仅处理硬件 OTA/配置请求\n *\n * 注意:设备采用自动激活模式,无需管理 API\n */\nexport class ESP32Handler extends BaseHandler {\n private esp32Manager: ESP32DeviceManager;\n\n constructor(esp32Manager: ESP32DeviceManager) {\n super();\n this.esp32Manager = esp32Manager;\n }\n\n /**\n * 处理OTA/配置请求\n * POST /\n *\n * 硬件API定义:根路径OTA接口\n *\n * 请求头:\n * - Device-Id: 设备MAC地址\n * - Client-Id: 设备UUID\n *\n * 请求体:\n * ```json\n * {\n * \"application\": {\n * \"version\": \"1.0.0\",\n * \"board\": {\n * \"type\": \"ESP32-S3-BOX\"\n * }\n * }\n * }\n * ```\n */\n async handleOTA(c: Context<AppContext>): Promise<Response> {\n const logger = c.get(\"logger\");\n\n try {\n // 获取设备ID和客户端ID\n const deviceId = c.req.header(\"Device-Id\") || c.req.header(\"device-id\");\n const clientId = c.req.header(\"Client-Id\") || c.req.header(\"client-id\");\n\n if (!deviceId) {\n return c.fail(\n ESP32ErrorCode.MISSING_DEVICE_ID,\n \"缺少 Device-Id 请求头\",\n undefined,\n 400\n );\n }\n\n // Client-Id 强制要求\n if (!clientId) {\n return c.fail(\n ESP32ErrorCode.MISSING_DEVICE_ID,\n \"缺少 Client-Id 请求头\",\n undefined,\n 400\n );\n }\n\n // 解析请求体\n const report: ESP32DeviceReport = await this.parseJsonBody(\n c,\n \"请求体格式错误\"\n );\n\n logger.debug(`收到OTA请求: deviceId=${deviceId}, clientId=${clientId}`);\n\n // 委托给设备管理器处理(支持从请求头获取设备型号,与 xiaozhi-esp32-server 保持一致)\n const response = await this.esp32Manager.handleOTARequest(\n deviceId,\n clientId,\n report,\n // 可选:从请求头获取设备信息(优先级高于 body)\n {\n deviceModel:\n c.req.header(\"device-model\") ||\n c.req.header(\"Device-Model\") ||\n undefined,\n deviceVersion:\n c.req.header(\"device-version\") ||\n c.req.header(\"Device-Version\") ||\n undefined,\n },\n c.req.header(\"host\") // 传递 Host 头用于构建完整 WebSocket URL\n );\n\n logger.debug(\"OTA响应\", { response });\n return c.json(response);\n } catch (error) {\n return this.handleError(c, error, \"处理OTA请求\");\n }\n }\n}\n","/**\n * Logger 中间件\n *\n * 负责将 logger 实例注入到 Hono Context 中,支持两种访问方式:\n * - c.get(\"logger\") - Hono 推荐做法\n * - c.logger - 向后兼容方式\n *\n * @module middlewares/logger.middleware\n */\n\nimport { logger } from \"@/Logger.js\";\nimport type { Logger } from \"@/Logger.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context, Next } from \"hono\";\n\n/**\n * 扩展 Hono Context 接口\n * 添加 logger 属性,允许直接通过 c.logger 访问\n * 保留此扩展以提供向后兼容性\n */\ndeclare module \"hono\" {\n interface Context {\n logger: Logger;\n }\n}\n\n/**\n * Logger 中间件 - 将 logger 实例挂载到 Hono context\n * 支持两种访问方式:\n * 1. c.get(\"logger\") - Hono 推荐做法\n * 2. c.logger - 向后兼容\n */\nexport const loggerMiddleware = async (c: Context<AppContext>, next: Next) => {\n // Hono 推荐做法\n c.set(\"logger\", logger);\n\n // 保留模块扩展以提供向后兼容\n c.logger = logger;\n\n await next();\n};\n","/**\n * CORS 中间件配置\n * 负责配置跨域资源共享策略,支持通过环境变量配置允许的来源列表\n *\n * 支持的环境变量:\n * - ALLOWED_ORIGINS: 允许的来源列表,多个来源用逗号分隔\n * 例如:https://example.com,https://app.example.com\n * 未配置时默认允许所有来源(*),生产环境建议显式配置\n *\n * 支持的 HTTP 方法:\n * - GET\n * - POST\n * - PUT\n * - OPTIONS\n *\n * 支持的请求头:\n * - Content-Type\n *\n * @module middlewares/cors.middleware\n */\n\nimport { cors } from \"hono/cors\";\n\n/**\n * CORS 中间件\n */\nexport const corsMiddleware = cors({\n origin: process.env.ALLOWED_ORIGINS\n ? process.env.ALLOWED_ORIGINS.split(\",\").map((origin) => origin.trim())\n : \"*\",\n allowMethods: [\"GET\", \"POST\", \"PUT\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\"],\n});\n","/**\n * 错误处理中间件\n *\n * 提供:\n * - errorHandlerMiddleware: 全局错误处理中间件\n * - notFoundHandlerMiddleware: 404 处理中间件\n *\n * @module middlewares/error.middleware\n */\n\nimport type { Context } from \"hono\";\n\n/**\n * 错误处理中间件\n */\nexport const errorHandlerMiddleware = (err: Error, c: Context) => {\n // 使用 Context 上的 logger 属性\n c.logger.error(\"HTTP request error:\", err);\n\n // 在开发环境中打印详细错误信息\n if (process.env.NODE_ENV === \"development\") {\n console.error(\"HTTP Request Error:\", {\n error: err.message,\n stack: err.stack,\n path: c.req.path,\n method: c.req.method,\n });\n }\n\n return c.fail(\n \"INTERNAL_SERVER_ERROR\",\n \"服务器内部错误\",\n process.env.NODE_ENV === \"development\" ? err.stack : undefined,\n 500\n );\n};\n\n/**\n * 404 Not Found 处理中间件\n */\nexport const notFoundHandlerMiddleware = (c: Context) => {\n // 如果是 API 路径,返回 API_NOT_FOUND\n if (c.req.path.startsWith(\"/api/\")) {\n return c.fail(\n \"API_NOT_FOUND\",\n \"请求的资源不存在\",\n {\n path: c.req.path,\n method: c.req.method,\n },\n 404\n );\n }\n\n // 非 API 路径返回通用的 NOT_FOUND\n return c.fail(\n \"NOT_FOUND\",\n \"请求的资源不存在\",\n {\n path: c.req.path,\n method: c.req.method,\n },\n 404\n );\n};\n","/**\n * 响应增强中间件\n * 为 Hono Context 添加便捷的响应方法:c.success、c.fail、c.paginate\n */\n\nimport type { PaginationInfo } from \"@/types/api.response.js\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * 扩展 Hono Context 接口\n * 添加三个新的响应方法\n */\ndeclare module \"hono\" {\n interface Context {\n /**\n * 返回成功响应\n * @param data - 响应数据\n * @param message - 响应消息\n * @param status - HTTP 状态码(默认 200)\n * @returns JSON 响应\n *\n * @example\n * ```typescript\n * // 简单成功响应\n * return c.success({ id: 1, name: \"张三\" });\n *\n * // 带消息的成功响应\n * return c.success({ id: 1 }, \"获取用户成功\");\n *\n * // 自定义状态码\n * return c.success({ id: 1 }, \"创建成功\", 201);\n *\n * // 无数据响应(如删除操作)\n * return c.success(undefined, \"删除成功\");\n * ```\n */\n success<T>(data?: T, message?: string, status?: number): Response;\n\n /**\n * 返回失败响应\n * @param code - 错误码\n * @param message - 错误消息\n * @param details - 错误详情\n * @param status - HTTP 状态码(默认 400)\n * @returns JSON 响应\n *\n * @example\n * ```typescript\n * // 简单错误响应\n * return c.fail(\"USER_NOT_FOUND\", \"用户不存在\");\n *\n * // 404 错误\n * return c.fail(\"NOT_FOUND\", \"资源不存在\", undefined, 404);\n *\n * // 带详情的错误响应\n * return c.fail(\"VALIDATION_ERROR\", \"数据验证失败\", {\n * field: \"email\",\n * message: \"邮箱格式不正确\"\n * });\n *\n * // 服务器错误\n * return c.fail(\"INTERNAL_ERROR\", \"服务器内部错误\", undefined, 500);\n * ```\n */\n fail(\n code: string,\n message: string,\n details?: unknown,\n status?: number\n ): Response;\n\n /**\n * 返回分页响应\n * @param data - 数据列表\n * @param pagination - 分页信息\n * @param message - 响应消息\n * @returns JSON 响应\n *\n * @example\n * ```typescript\n * const data = [{ id: 1 }, { id: 2 }];\n * const pagination = {\n * page: 1,\n * pageSize: 10,\n * total: 100,\n * totalPages: 10,\n * hasNext: true,\n * hasPrev: false\n * };\n * return c.paginate(data, pagination, \"查询成功\");\n * ```\n */\n paginate<T>(\n data: T[],\n pagination: PaginationInfo,\n message?: string\n ): Response;\n }\n}\n\n/**\n * 响应增强中间件\n * 为所有请求添加便捷的响应方法\n */\nexport const responseEnhancerMiddleware: MiddlewareHandler = async (\n c,\n next\n) => {\n // 成功响应方法\n c.success = <T>(data?: T, message?: string, status = 200) => {\n const response: {\n success: true;\n data?: T;\n message?: string;\n } = {\n success: true,\n message,\n };\n\n // 只有当 data 不是 undefined 时才添加 data 字段\n if (data !== undefined) {\n response.data = data;\n }\n\n return c.json(response, status as never);\n };\n\n // 失败响应方法\n c.fail = (code: string, message: string, details?: unknown, status = 400) => {\n const response: {\n success: false;\n error: {\n code: string;\n message: string;\n details?: unknown;\n };\n } = {\n success: false,\n error: {\n code,\n message,\n },\n };\n\n // 只有当 details 不是 undefined 时才添加 details 字段\n if (details !== undefined) {\n response.error.details = details;\n }\n\n return c.json(response, status as never);\n };\n\n // 分页响应方法\n c.paginate = <T>(data: T[], pagination: PaginationInfo, message?: string) => {\n const response: {\n success: true;\n data: T[];\n pagination: PaginationInfo;\n message?: string;\n } = {\n success: true,\n data,\n pagination,\n message,\n };\n\n return c.json(response, 200);\n };\n\n await next();\n};\n","/**\n * MCP 中间件相关的错误定义\n */\n\n/**\n * MCPServiceManager 未初始化错误\n */\nexport class MCPServiceManagerNotInitializedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MCPServiceManagerNotInitializedError\";\n }\n}\n\n/**\n * WebServer 不可用错误\n */\nexport class WebServerNotAvailableError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WebServerNotAvailableError\";\n }\n}\n","/**\n * MCP Service Manager 中间件\n * 将 MCPServiceManager 实例注入到 Hono Context 中\n * 提供统一的依赖注入模式,从 WebServer 获取实例而非 Singleton\n */\n\nimport {\n MCPServiceManagerNotInitializedError,\n WebServerNotAvailableError,\n} from \"@/errors/mcp-errors.middleware.js\";\nimport type { AppContextVariables } from \"@/types/hono.context.js\";\nimport type { Context, Next } from \"hono\";\n\n/**\n * MCP Service Manager 中间件\n *\n * 功能:\n * 1. 从 WebServer 获取 MCPServiceManager 实例\n * 2. 将实例注入到 Hono Context\n * 3. 提供错误处理和日志记录\n * 4. 与 WebServer 生命周期绑定\n * 5. 使用 Hono Context 中的 logger 实现统一的日志配置\n *\n * @param c Hono Context\n * @param next 下一个中间件函数\n */\nexport const mcpServiceManagerMiddleware = async (\n c: Context<{ Variables: AppContextVariables }>,\n next: Next\n): Promise<void> => {\n // 检查是否已经注入,避免重复初始化\n if (!c.get(\"mcpServiceManager\")) {\n try {\n c.logger.debug(\n \"[MCPMiddleware] 正在从 WebServer 获取 MCPServiceManager 实例\"\n );\n\n // 从 WebServer 获取实例\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new WebServerNotAvailableError(\"WebServer 未注入到 Context\");\n }\n\n const serviceManager = webServer.getMCPServiceManager();\n\n // 将实例注入到 Context\n c.set(\"mcpServiceManager\", serviceManager);\n\n c.logger.debug(\n \"[MCPMiddleware] MCPServiceManager 实例已成功注入到 Context\"\n );\n } catch (error) {\n // 根据错误类型进行不同的处理\n if (error instanceof MCPServiceManagerNotInitializedError) {\n // MCPServiceManager 未初始化是临时状态,允许通过\n c.logger.debug(\n \"[MCPMiddleware] MCPServiceManager 尚未初始化,允许通过\"\n );\n // 不设置实例,Handler 中需要处理未初始化的情况\n } else if (error instanceof WebServerNotAvailableError) {\n // WebServer 未注入是配置错误,应该抛出\n c.logger.error(\"[MCPMiddleware] WebServer 配置错误:\", error.message);\n throw error;\n } else {\n // 其他未知错误,记录并抛出\n c.logger.error(\n \"[MCPMiddleware] 获取 MCPServiceManager 时发生未知错误:\",\n error\n );\n throw error;\n }\n }\n }\n\n await next();\n};\n","/**\n * 小智连接管理器中间件\n * 负责将 endpointManager 注入到请求上下文中\n */\n\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * 小智连接管理器中间件\n * 从 WebServer 实例获取连接管理器并注入到上下文中\n */\nexport const endpointManagerMiddleware = (): MiddlewareHandler<AppContext> => {\n return async (c, next) => {\n // 从 WebServer 实例获取连接管理器\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new Error(\n \"WebServer 实例未注入到上下文中,请确保 webServerMiddleware 已正确配置\"\n );\n }\n\n if (!webServer.getEndpointManager) {\n throw new Error(\"WebServer 实例缺少 getEndpointManager 方法\");\n }\n\n try {\n const connectionManager = webServer.getEndpointManager();\n c.set(\"endpointManager\", connectionManager);\n } catch (error) {\n // 记录错误但不阻断请求\n if (error instanceof Error && error.message.includes(\"未初始化\")) {\n c.logger.warn(\"小智连接管理器未初始化,使用 null 值:\", error.message);\n c.set(\"endpointManager\", null);\n } else {\n throw error;\n }\n }\n\n await next();\n };\n};\n","/**\n * 小智端点处理器中间件\n * 负责创建和管理 EndpointHandler 实例\n */\n\nimport { EndpointHandler } from \"@/handlers/endpoint.handler.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport { configManager } from \"@xiaozhi-client/config\";\nimport type { EndpointManager } from \"@xiaozhi-client/endpoint\";\nimport type { MiddlewareHandler } from \"hono\";\n\n/**\n * 小智端点处理器中间件\n * 创建单例的 EndpointHandler 并注入到上下文中\n */\nexport const endpointsMiddleware = (): MiddlewareHandler<AppContext> => {\n // 使用闭包缓存 handler 实例和 manager\n let endpointHandler: EndpointHandler | null = null;\n let lastManager: EndpointManager | null | undefined = undefined;\n\n return async (c, next) => {\n const endpointManager = c.get(\"endpointManager\");\n\n // 如果 manager 发生变化,则重建 handler\n // 注意:使用引用相等检查(!==)确保使用最新的 manager 实例\n // 即使 manager 内容相同,但对象引用不同时也会重建 handler\n // 这是期望的行为,确保 handler 总是使用最新的连接管理\n if (endpointManager !== lastManager) {\n lastManager = endpointManager;\n if (endpointManager) {\n endpointHandler = new EndpointHandler(endpointManager, configManager);\n } else {\n endpointHandler = null;\n }\n }\n\n // 将 handler 注入到上下文中\n c.set(\"endpointHandler\", endpointHandler);\n\n await next();\n };\n};\n","/**\n * 状态服务\n *\n * 统一的状态管理服务,负责管理客户端连接状态、MCP 服务状态等。\n *\n * ## 核心功能\n * - 客户端状态管理:跟踪客户端连接状态、MCP 端点、活跃服务器等\n * - 重启状态管理:管理服务重启流程的状态跟踪\n * - 心跳超时管理:监控客户端心跳,超时自动断开连接\n * - 事件通知:通过 EventBus 发射状态变更事件\n *\n * ## 使用方式\n * ```typescript\n * import { StatusService } from '@/services';\n *\n * const statusService = new StatusService();\n * const status = statusService.getFullStatus();\n * ```\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport { logger } from \"@/Logger.js\";\nimport type { EventBus } from \"@/services/event-bus.service.js\";\nimport { getEventBus } from \"@/services/event-bus.service.js\";\n\n/**\n * 客户端信息接口\n */\nexport interface ClientInfo {\n status: \"connected\" | \"disconnected\";\n mcpEndpoint: string;\n activeMCPServers: string[];\n lastHeartbeat?: number;\n}\n\n/**\n * 重启状态接口\n */\nexport interface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n serviceName?: string;\n attempt?: number;\n}\n\n/**\n * 状态服务 - 统一的状态管理服务\n */\nexport class StatusService {\n private logger: Logger;\n private eventBus: EventBus;\n private clientInfo: ClientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n private restartStatus?: RestartStatus;\n private heartbeatTimeout?: NodeJS.Timeout;\n private readonly HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n constructor() {\n this.logger = logger;\n this.eventBus = getEventBus();\n }\n\n /**\n * 获取客户端状态\n */\n getClientStatus(): ClientInfo {\n return { ...this.clientInfo };\n }\n\n /**\n * 更新客户端信息\n */\n updateClientInfo(info: Partial<ClientInfo>, source = \"unknown\"): void {\n try {\n const oldStatus = { ...this.clientInfo };\n this.clientInfo = { ...this.clientInfo, ...info };\n\n if (info.lastHeartbeat) {\n this.clientInfo.lastHeartbeat = Date.now();\n }\n\n // 接收到客户端状态时重置心跳超时\n if (info.status === \"connected\") {\n this.resetHeartbeatTimeout();\n }\n\n this.logger.debug(`客户端状态更新,来源: ${source}`, {\n old: oldStatus,\n new: this.clientInfo,\n });\n\n // 发射状态更新事件\n this.eventBus.emitEvent(\"status:updated\", {\n status: this.clientInfo,\n source,\n });\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateClientInfo\",\n });\n }\n }\n\n /**\n * 获取重启状态\n */\n getRestartStatus(): RestartStatus | undefined {\n return this.restartStatus ? { ...this.restartStatus } : undefined;\n }\n\n /**\n * 更新重启状态\n */\n updateRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string\n ): void {\n try {\n this.restartStatus = {\n status,\n error,\n timestamp: Date.now(),\n };\n\n this.logger.info(`重启状态更新: ${status}`, { error });\n\n // 根据状态发射不同的事件\n switch (status) {\n case \"restarting\":\n this.eventBus.emitEvent(\"service:restart:started\", {\n serviceName: this.restartStatus.serviceName || \"\",\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"completed\":\n this.eventBus.emitEvent(\"service:restart:completed\", {\n serviceName: this.restartStatus.serviceName || \"\",\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"failed\":\n this.eventBus.emitEvent(\"service:restart:failed\", {\n serviceName: this.restartStatus.serviceName || \"\",\n error: new Error(error || \"重启失败\"),\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n }\n } catch (error) {\n this.logger.error(\"更新重启状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateRestartStatus\",\n });\n }\n }\n\n /**\n * 获取完整状态信息\n */\n getFullStatus(): {\n client: ClientInfo;\n restart?: RestartStatus;\n timestamp: number;\n } {\n return {\n client: this.getClientStatus(),\n restart: this.getRestartStatus(),\n timestamp: Date.now(),\n };\n }\n\n /**\n * 重置心跳超时\n */\n private resetHeartbeatTimeout(): void {\n // 清除现有的超时定时器\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n // 设置新的超时定时器\n this.heartbeatTimeout = setTimeout(() => {\n this.logger.debug(\"客户端心跳超时,标记为断开连接\");\n this.updateClientInfo({ status: \"disconnected\" }, \"heartbeat-timeout\");\n }, this.HEARTBEAT_TIMEOUT);\n }\n\n /**\n * 清除心跳超时\n */\n clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = undefined;\n }\n }\n\n /**\n * 检查客户端是否连接\n */\n isClientConnected(): boolean {\n return this.clientInfo.status === \"connected\";\n }\n\n /**\n * 获取最后心跳时间\n */\n getLastHeartbeat(): number | undefined {\n return this.clientInfo.lastHeartbeat;\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n */\n getActiveMCPServers(): string[] {\n return [...this.clientInfo.activeMCPServers];\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n */\n setActiveMCPServers(servers: string[]): void {\n this.updateClientInfo(\n { activeMCPServers: [...servers] },\n \"mcp-servers-update\"\n );\n }\n\n /**\n * 设置 MCP 端点\n */\n setMcpEndpoint(endpoint: string): void {\n this.updateClientInfo({ mcpEndpoint: endpoint }, \"mcp-endpoint-update\");\n }\n\n /**\n * 重置状态\n */\n reset(): void {\n this.logger.info(\"重置状态服务\");\n this.clearHeartbeatTimeout();\n this.clientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n this.restartStatus = undefined;\n }\n\n /**\n * 销毁状态服务\n */\n destroy(): void {\n this.logger.info(\"销毁状态服务\");\n this.clearHeartbeatTimeout();\n this.reset();\n }\n}\n","/**\n * 路由系统相关类型定义\n * 提供类型安全的路由配置和依赖注入\n */\n\nimport type {\n ConfigApiHandler,\n CozeHandler,\n ESP32Handler,\n EndpointHandler,\n MCPHandler,\n MCPRouteHandler,\n MCPToolHandler,\n MCPToolLogHandler,\n ServiceApiHandler,\n StaticFileHandler,\n StatusApiHandler,\n TTSApiHandler,\n UpdateApiHandler,\n VersionApiHandler,\n} from \"@/handlers/index.js\";\nimport type { Context, MiddlewareHandler } from \"hono\";\n\n/**\n * 处理器依赖接口\n * 定义路由系统需要的所有处理器依赖\n */\nexport interface HandlerDependencies {\n /** 配置管理处理器 */\n configApiHandler: ConfigApiHandler;\n /** 状态查询处理器 */\n statusApiHandler: StatusApiHandler;\n /** 服务管理处理器 */\n serviceApiHandler: ServiceApiHandler;\n /** MCP 工具处理器 */\n mcpToolHandler: MCPToolHandler;\n /** 工具调用日志处理器 */\n mcpToolLogHandler: MCPToolLogHandler;\n /** 版本信息处理器 */\n versionApiHandler: VersionApiHandler;\n /** 静态文件处理器 */\n staticFileHandler: StaticFileHandler;\n /** MCP 路由处理器 */\n mcpRouteHandler: MCPRouteHandler;\n /** MCP 服务器管理处理器(可选) */\n mcpHandler?: MCPHandler;\n /** 更新管理处理器 */\n updateApiHandler: UpdateApiHandler;\n /** 扣子 API 处理器 */\n cozeHandler: CozeHandler;\n /** TTS API 处理器 */\n ttsApiHandler: TTSApiHandler;\n /** 小智接入点处理器(通过中间件动态注入) */\n endpointHandler?: EndpointHandler;\n /** ESP32 设备处理器(可选) */\n esp32Handler?: ESP32Handler;\n}\n\n/**\n * 路由注册选项接口\n * 控制路由注册的行为\n *\n * @future-feature 计划在 v2.0.0 中实现,用于提供更灵活的路由注册控制\n * - 支持详细的注册日志,便于调试和监控\n * - 支持注册失败时的异常处理策略配置\n */\nexport interface RouteRegistryOptions {\n /** 是否启用详细的路由注册日志 */\n verboseLogging?: boolean;\n /** 是否在注册失败时抛出异常 */\n throwOnRegistrationError?: boolean;\n}\n\n/**\n * 路由统计信息接口\n * 提供路由系统的运行时统计\n *\n * @future-feature 计划在 v2.0.0 中实现,用于提供路由系统的监控和分析能力\n * - 统计各域的路由数量分布\n * - 分析 HTTP 方法的使用情况\n * - 支持路由性能监控和优化建议\n */\nexport interface RouteStatistics {\n /** 注册的域数量 */\n domainCount: number;\n /** 注册的路由总数 */\n totalRouteCount: number;\n /** 各域的路由数量分布 */\n routeDistribution: Record<string, number>;\n /** 支持的 HTTP 方法统计 */\n methodDistribution: Record<string, number>;\n}\n\n/**\n * HTTP 方法类型\n */\nexport type HTTPMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * 路由定义接口\n * 定义单个路由的配置信息\n */\nexport interface RouteDefinition {\n /** HTTP 方法 */\n method: HTTPMethod;\n /** 完整路由路径(相对于应用根路径) */\n path: string;\n /** 处理函数 */\n handler: (c: Context) => Promise<Response | undefined>;\n /** 路由级别的中间件 */\n middleware?: MiddlewareHandler[];\n}\n\n/**\n * 路由组接口\n * 用于需要组级别中间件或元数据的场景\n */\nexport interface RouteGroup {\n /** 路由定义数组 */\n routes: RouteDefinition[];\n /** 可选的组名称(用于日志和调试) */\n name?: string;\n /** 可选的组描述 */\n description?: string;\n /** 组级别的中间件(应用到组内所有路由) */\n middleware?: MiddlewareHandler[];\n}\n\n/**\n * 路由注册联合类型\n * 支持直接注册路由数组或路由组\n */\nexport type RouteRegistry = RouteDefinition[] | RouteGroup;\n\n/**\n * 判断是否为路由组\n */\nexport function isRouteGroup(route: RouteRegistry): route is RouteGroup {\n return Array.isArray((route as RouteGroup).routes);\n}\n\n/**\n * 将路由注册转换为路由数组\n */\nexport function normalizeRoutes(route: RouteRegistry): RouteDefinition[] {\n if (isRouteGroup(route)) {\n const { routes, middleware } = route;\n if (middleware && middleware.length > 0) {\n return routes.map((r) => ({\n ...r,\n middleware: [...middleware, ...(r.middleware || [])],\n }));\n }\n return routes;\n }\n return route;\n}\n\n/**\n * 创建路由处理器辅助函数\n * 自动处理依赖注入,减少样板代码\n *\n * @example\n * ```typescript\n * const h = createHandler(\"versionApiHandler\");\n * export const routes = [\n * {\n * method: \"GET\",\n * path: \"/api/version\",\n * handler: h((handler, c) => handler.getVersion(c)),\n * }\n * ];\n * ```\n */\nexport function createHandler<K extends keyof HandlerDependencies>(\n dependencyKey: K\n): (\n method: (handler: HandlerDependencies[K], c: Context) => Promise<Response>\n) => RouteDefinition[\"handler\"] {\n return (method) => (c: Context) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const handler = dependencies[dependencyKey];\n return method(handler, c);\n };\n}\n","/**\n * 路由管理器\n * 提供直接、高效的路由注册和管理功能\n */\n\nimport type { Logger } from \"@/Logger.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context, Hono, Next } from \"hono\";\nimport {\n type RouteDefinition,\n type RouteRegistry,\n normalizeRoutes,\n} from \"./types.js\";\n\n/**\n * 路由管理器\n * 直接管理路由配置,提供路由注册和应用功能\n * 通过依赖注入接收 Logger 实例,保持与项目日志系统的一致性\n */\nexport class RouteManager {\n private routes: Map<string, RouteDefinition[]> = new Map();\n\n constructor(private logger: Logger) {}\n\n /**\n * 注册单个路由模块\n */\n registerRoute(name: string, routeRegistry: RouteRegistry): void {\n const routes = normalizeRoutes(routeRegistry);\n if (this.routes.has(name)) {\n this.logger.warn(`路由组 '${name}' 已存在,将被覆盖`);\n }\n this.routes.set(name, routes);\n this.logger.info(`已注册路由组: ${name} (${routes.length} 个路由)`);\n }\n\n /**\n * 批量注册路由模块\n */\n registerRoutes(routeRegistries: Record<string, RouteRegistry>): void {\n this.logger.info(\n `开始批量注册 ${Object.keys(routeRegistries).length} 个路由组...`\n );\n\n for (const [name, routeRegistry] of Object.entries(routeRegistries)) {\n this.registerRoute(name, routeRegistry);\n }\n\n this.logger.info(`批量注册完成,共注册 ${this.routes.size} 个路由组`);\n }\n\n /**\n * 获取所有注册的路由配置\n */\n getAllRoutes(): Map<string, RouteDefinition[]> {\n return new Map(this.routes);\n }\n\n /**\n * 获取指定名称的路由配置\n */\n getRoute(name: string): RouteDefinition[] | undefined {\n return this.routes.get(name);\n }\n\n /**\n * 将路由应用到 Hono 应用实例\n */\n applyToApp(app: Hono<AppContext>): void {\n // 获取所有路由并排序,确保 static 路由最后应用\n const routeEntries = Array.from(this.routes.entries());\n routeEntries.sort(([nameA], [nameB]) => {\n // static 路由永远排在最后\n if (nameA === \"static\") return 1;\n if (nameB === \"static\") return -1;\n return 0;\n });\n\n let totalRouteCount = 0;\n for (const [groupName, routes] of routeEntries) {\n try {\n for (const route of routes) {\n this.applyRouteDefinition(app, route, groupName);\n totalRouteCount++;\n }\n } catch (error) {\n this.logger.error(`✗ 应用路由组失败: ${groupName}`, error);\n }\n }\n\n this.logger.info(`路由应用完成,共 ${totalRouteCount} 个路由`);\n }\n\n /**\n * 应用单个路由定义到 Hono 应用\n */\n private applyRouteDefinition(\n app: Hono<AppContext>,\n route: RouteDefinition,\n groupName: string\n ): void {\n const { method, path, handler, middleware = [] } = route;\n\n // 创建包装的处理器,添加错误处理\n const wrappedHandler = async (c: Context<AppContext>, next: Next) => {\n try {\n return await handler(c);\n } catch (error) {\n this.logger.error(`路由处理错误 [${method} ${path}]:`, error);\n return c.fail(\n \"HANDLER_ERROR\",\n \"处理器执行失败\",\n error instanceof Error ? error.message : String(error),\n 500\n );\n }\n };\n\n // 使用 switch-case 避免 Hono 4.11.4 的类型推断问题\n // 注意:Hono 4.11.4 对展开中间件数组的类型推断更加严格,需要使用类型断言\n switch (method) {\n case \"GET\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.get(path, ...middleware, wrappedHandler);\n } else {\n app.get(path, wrappedHandler);\n }\n break;\n case \"POST\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.post(path, ...middleware, wrappedHandler);\n } else {\n app.post(path, wrappedHandler);\n }\n break;\n case \"PUT\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.put(path, ...middleware, wrappedHandler);\n } else {\n app.put(path, wrappedHandler);\n }\n break;\n case \"DELETE\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.delete(path, ...middleware, wrappedHandler);\n } else {\n app.delete(path, wrappedHandler);\n }\n break;\n case \"PATCH\":\n if (middleware.length > 0) {\n // @ts-expect-error Hono 4.11.4 类型系统限制:展开中间件数组时无法正确推断类型\n app.patch(path, ...middleware, wrappedHandler);\n } else {\n app.patch(path, wrappedHandler);\n }\n break;\n default:\n throw new Error(`不支持的 HTTP 方法: ${method}`);\n }\n }\n\n /**\n * 清除所有路由(主要用于测试)\n */\n clear(): void {\n this.routes.clear();\n this.logger.info(\"已清除所有路由配置\");\n }\n\n /**\n * 检查路由是否已注册\n */\n hasRoute(name: string): boolean {\n return this.routes.has(name);\n }\n\n /**\n * 列出所有已注册的路由域名称\n */\n getRouteNames(): string[] {\n return Array.from(this.routes.keys());\n }\n}\n","/**\n * 配置管理路由配置\n * 处理所有配置管理相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"configApiHandler\");\n\n/**\n * 配置管理路由定义\n */\nexport const configRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/config\",\n handler: h((handler, c) => handler.getConfig(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/config\",\n handler: h((handler, c) => handler.updateConfig(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/mcp-endpoint\",\n handler: h((handler, c) => handler.getMcpEndpoint(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/mcp-endpoints\",\n handler: h((handler, c) => handler.getMcpEndpoints(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/mcp-servers\",\n handler: h((handler, c) => handler.getMcpServers(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/connection\",\n handler: h((handler, c) => handler.getConnectionConfig(c)),\n },\n {\n method: \"POST\",\n path: \"/api/config/reload\",\n handler: h((handler, c) => handler.reloadConfig(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/path\",\n handler: h((handler, c) => handler.getConfigPath(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/exists\",\n handler: h((handler, c) => handler.checkConfigExists(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/prompts\",\n handler: h((handler, c) => handler.getPromptFiles(c)),\n },\n {\n method: \"GET\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.getPromptFileContent(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.updatePromptFileContent(c)),\n },\n {\n method: \"POST\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.createPromptFileContent(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/config/prompts/content\",\n handler: h((handler, c) => handler.deletePromptFileContent(c)),\n },\n];\n","/**\n * 状态查询路由模块\n * 处理所有状态相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"statusApiHandler\");\n\n/**\n * 状态查询路由定义\n */\nexport const statusRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/status\",\n handler: h((handler, c) => handler.getStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/status/client\",\n handler: h((handler, c) => handler.getClientStatus(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/status/client\",\n handler: h((handler, c) => handler.updateClientStatus(c)),\n },\n {\n method: \"POST\",\n path: \"/api/status/reset\",\n handler: h((handler, c) => handler.resetStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/status/mcp-servers\",\n handler: h((handler, c) => handler.getActiveMCPServers(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/status/mcp-servers\",\n handler: h((handler, c) => handler.setActiveMCPServers(c)),\n },\n];\n","/**\n * 工具调用路由模块\n * 处理所有工具相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"mcpToolHandler\");\n\n/**\n * 工具调用路由定义\n */\nexport const toolsRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/tools/call\",\n handler: h((handler, c) => handler.callTool(c)),\n },\n {\n method: \"GET\",\n path: \"/api/tools/list\",\n handler: h((handler, c) => handler.listTools(c)),\n },\n {\n method: \"GET\",\n path: \"/api/tools/custom\",\n handler: h((handler, c) => handler.getCustomTools(c)),\n },\n {\n method: \"POST\",\n path: \"/api/tools/custom\",\n handler: h((handler, c) => handler.addCustomTool(c)),\n },\n {\n method: \"PUT\",\n path: \"/api/tools/custom/:toolName\",\n handler: h((handler, c) => handler.updateCustomTool(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/tools/custom/:toolName\",\n handler: h((handler, c) => handler.removeCustomTool(c)),\n },\n /**\n * MCP 工具管理路由\n * 用于启用/禁用/查询 MCP 工具的状态\n */\n {\n method: \"POST\",\n path: \"/api/tools/mcp/manage\",\n handler: h((handler, c) => handler.manageMCPTool(c)),\n },\n {\n method: \"POST\",\n path: \"/api/tools/mcp/list\",\n handler: h((handler, c) => handler.listMCPTools(c)),\n },\n];\n","/**\n * MCP 协议路由模块\n * 处理 MCP 协议相关的 API 路由(仅 POST 模式)\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"mcpRouteHandler\");\n\n/**\n * MCP 协议路由定义\n */\nexport const mcpRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/mcp\",\n handler: h((handler, c) => handler.handlePost(c)),\n },\n];\n","/**\n * 版本信息路由模块\n * 处理所有版本相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"versionApiHandler\");\n\n/**\n * 版本信息路由定义\n */\nexport const versionRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/version\",\n handler: h((handler, c) => handler.getVersion(c)),\n },\n {\n method: \"GET\",\n path: \"/api/version/simple\",\n handler: h((handler, c) => handler.getVersionSimple(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/version/cache\",\n handler: h((handler, c) => handler.clearVersionCache(c)),\n },\n {\n method: \"GET\",\n path: \"/api/version/latest\",\n handler: h((handler, c) => handler.checkLatestVersion(c)),\n },\n];\n","/**\n * 服务管理路由配置\n * 处理所有服务管理相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"serviceApiHandler\");\n\nexport const servicesRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/services/restart\",\n handler: h((handler, c) => handler.restartService(c)),\n },\n {\n method: \"POST\",\n path: \"/api/services/stop\",\n handler: h((handler, c) => handler.stopService(c)),\n },\n {\n method: \"POST\",\n path: \"/api/services/start\",\n handler: h((handler, c) => handler.startService(c)),\n },\n {\n method: \"GET\",\n path: \"/api/services/status\",\n handler: h((handler, c) => handler.getServiceStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/services/health\",\n handler: h((handler, c) => handler.getServiceHealth(c)),\n },\n];\n","/**\n * 更新管理路由配置\n * 处理更新相关的 API 路由\n *\n * 路由:\n * - POST /api/update:触发版本安装\n * - GET /api/install/logs?installId=xxx:SSE 安装日志流\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"updateApiHandler\");\n\nexport const updateRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/update\",\n handler: h((handler, c) => handler.performUpdate(c)),\n },\n {\n method: \"GET\",\n path: \"/api/install/logs\",\n handler: h((handler, c) => handler.getInstallLogs(c)),\n },\n];\n","/**\n * 静态文件路由配置\n * 处理静态文件服务相关的路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"staticFileHandler\");\n\nexport const staticRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/*\",\n handler: h(async (handler, c) => {\n // 如果路径以 /api/ 开头,不处理静态文件,直接返回 404\n if (c.req.path.startsWith(\"/api/\")) {\n return c.notFound();\n }\n return await handler.handleStaticFile(c);\n }),\n },\n];\n","/**\n * 扣子 API 路由配置\n * 处理所有扣子相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"cozeHandler\");\n\nexport const cozeRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/coze/workspaces\",\n handler: h((handler, c) => handler.getWorkspaces(c)),\n },\n {\n method: \"GET\",\n path: \"/api/coze/workflows\",\n handler: h((handler, c) => handler.getWorkflows(c)),\n },\n {\n method: \"POST\",\n path: \"/api/coze/cache/clear\",\n handler: h((handler, c) => handler.clearCache(c)),\n },\n {\n method: \"GET\",\n path: \"/api/coze/cache/stats\",\n handler: h((handler, c) => handler.getCacheStats(c)),\n },\n];\n","/**\n * 工具调用日志路由配置\n * 处理工具调用日志相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"mcpToolLogHandler\");\n\nexport const toolLogsRoutes: RouteDefinition[] = [\n {\n method: \"GET\",\n path: \"/api/tool-calls/logs\",\n handler: h((handler, c) => handler.getToolCallLogs(c)),\n },\n];\n","/**\n * MCP 服务器管理路由配置\n * 处理 MCP 服务器管理相关的 API 路由\n */\n\nimport type { HandlerDependencies, RouteDefinition } from \"@/routes/types.js\";\nimport type { Context } from \"hono\";\n\n/**\n * MCP 服务器处理器包装函数\n * 统一处理 MCP Server API Handler 的初始化检查\n */\nconst withMCPServerHandler = async (\n c: Context,\n handlerFn: (\n handler: NonNullable<HandlerDependencies[\"mcpHandler\"]>\n ) => Promise<Response>\n): Promise<Response> => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const handler = dependencies.mcpHandler;\n\n if (!handler) {\n return c.json({ error: \"MCP Server API Handler not initialized\" }, 503);\n }\n\n return await handlerFn(handler);\n};\n\nexport const mcpserverRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/mcp-servers\",\n handler: (c: Context) => withMCPServerHandler(c, (h) => h.addMCPServer(c)),\n },\n {\n method: \"DELETE\",\n path: \"/api/mcp-servers/:serverName\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.removeMCPServer(c)),\n },\n {\n method: \"GET\",\n path: \"/api/mcp-servers/:serverName/status\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.getMCPServerStatus(c)),\n },\n {\n method: \"GET\",\n path: \"/api/mcp-servers\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.listMCPServers(c)),\n },\n];\n","/**\n * 端点管理路由配置\n * 处理所有端点管理相关的 API 路由\n * 使用中间件动态注入的 endpointHandler\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport type { AppContext } from \"@/types/hono.context.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 端点处理器方法名类型\n */\ntype EndpointHandlerMethod =\n | \"getEndpointStatus\"\n | \"connectEndpoint\"\n | \"disconnectEndpoint\"\n | \"addEndpoint\"\n | \"removeEndpoint\";\n\n/**\n * 端点处理器包装函数\n * 从中间件获取 endpointHandler 并调用相应方法\n */\nconst withEndpointHandler = async (\n c: Context<AppContext>,\n handlerName: EndpointHandlerMethod\n): Promise<Response> => {\n // 从中间件获取 endpointHandler\n const endpointHandler = c.get(\"endpointHandler\");\n\n if (!endpointHandler) {\n return c.fail(\n \"ENDPOINT_HANDLER_NOT_AVAILABLE\",\n \"端点处理器尚未初始化,请稍后再试\",\n undefined,\n 503\n );\n }\n\n // 调用对应的处理方法\n try {\n // 使用类型安全的方式调用方法\n return await endpointHandler[handlerName](c);\n } catch (error) {\n console.error(`端点处理器错误 [${handlerName}]:`, error);\n return c.fail(\n \"ENDPOINT_HANDLER_ERROR\",\n error instanceof Error ? error.message : \"端点处理失败\",\n undefined,\n 500\n );\n }\n};\n\n/**\n * 端点管理路由定义(扁平化版本)\n */\nexport const endpointRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/endpoint/status\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"getEndpointStatus\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/connect\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"connectEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/disconnect\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"disconnectEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/add\",\n handler: (c: Context<AppContext>) => withEndpointHandler(c, \"addEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/api/endpoint/remove\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"removeEndpoint\"),\n },\n];\n","/**\n * 通用API路由配置\n * 处理不特定于某个模块的通用 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"serviceApiHandler\");\n\nexport const miscRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/restart\",\n handler: h((handler, c) => handler.restartService(c)),\n },\n];\n","/**\n * TTS API 路由配置\n * 处理所有 TTS 相关的 API 路由\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { createHandler } from \"@/routes/types.js\";\n\nconst h = createHandler(\"ttsApiHandler\");\n\nexport const ttsRoutes: RouteDefinition[] = [\n {\n method: \"POST\",\n path: \"/api/tts\",\n handler: h((handler, c) => handler.synthesize(c)),\n },\n {\n method: \"GET\",\n path: \"/api/tts/voices\",\n handler: h((handler, c) => handler.getVoices(c)),\n },\n];\n","/**\n * ESP32设备路由模块\n * 处理ESP32设备相关的API路由\n *\n * 硬件API定义:\n * - POST / # OTA/配置获取(根路径,按硬件定义)\n * - POST /xiaozhi/ota/ # 小智硬件官方OTA路径(兼容)\n * - WebSocket /ws # WebSocket连接\n *\n * 注意:设备采用自动激活模式,无需管理API\n */\n\nimport type { RouteDefinition } from \"@/routes/types.js\";\nimport { type HandlerDependencies, createHandler } from \"@/routes/types.js\";\nimport type { Context } from \"hono\";\n\nconst h = createHandler(\"esp32Handler\");\n\n/**\n * 创建 ESP32 路由处理器(带可选检查)\n */\nconst createESP32Handler = (\n method: (\n handler: NonNullable<HandlerDependencies[\"esp32Handler\"]>,\n c: Context\n ) => Promise<Response>\n) => {\n return async (c: Context) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const handler = dependencies.esp32Handler;\n if (!handler) {\n return c.json({ error: \"ESP32 service not available\" }, 503);\n }\n return method(handler, c);\n };\n};\n\n/**\n * ESP32设备路由定义\n */\nexport const esp32Routes: RouteDefinition[] = [\n // ========== 硬件API(按硬件定义的路径) ==========\n\n // 硬件 OTA/配置接口(根路径)\n {\n method: \"POST\",\n path: \"/\",\n handler: createESP32Handler((handler, c) => handler.handleOTA(c)),\n },\n\n // 小智硬件官方 OTA 路径(兼容硬件默认配置)\n {\n method: \"POST\",\n path: \"/xiaozhi/ota/\",\n handler: createESP32Handler((handler, c) => handler.handleOTA(c)),\n },\n\n // WebSocket端点(由WebServer直接处理,这里仅作为占位符)\n {\n method: \"GET\",\n path: \"/ws\",\n handler: createESP32Handler(async (handler, c) => {\n c.get(\"logger\").debug(\"ESP32 WebSocket端点访问\");\n // 返回 426 Upgrade Required,明确提示需要 WebSocket 升级\n return c.text(\"WebSocket Upgrade Required\", 426);\n }),\n },\n];\n"],"mappings":"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","names":["require_constants","__commonJSMin","exports","module","SEMVER_SPEC_VERSION","MAX_SAFE_INTEGER","MAX_SAFE_COMPONENT_LENGTH","MAX_SAFE_BUILD_LENGTH","RELEASE_TYPES","require_debug","__commonJSMin","exports","module","debug","args","require_re","__commonJSMin","exports","module","MAX_SAFE_COMPONENT_LENGTH","MAX_SAFE_BUILD_LENGTH","MAX_LENGTH","debug","re","safeRe","src","safeSrc","t","R","LETTERDASHNUMBER","safeRegexReplacements","makeSafeRegex","__name","value","token","max","createToken","name","isGlobal","safe","index","require_parse_options","__commonJSMin","exports","module","looseOption","emptyOpts","parseOptions","__name","options","require_identifiers","__commonJSMin","exports","module","numeric","compareIdentifiers","__name","a","b","anum","bnum","rcompareIdentifiers","require_semver","__commonJSMin","exports","module","debug","MAX_LENGTH","MAX_SAFE_INTEGER","re","t","parseOptions","compareIdentifiers","SemVer","_SemVer","__name","version","options","m","id","num","other","i","a","b","release","identifier","identifierBase","match","base","prerelease","require_parse","__commonJSMin","exports","module","SemVer","parse","__name","version","options","throwErrors","er","require_valid","__commonJSMin","exports","module","parse","valid","__name","version","options","v","require_clean","__commonJSMin","exports","module","parse","clean","__name","version","options","s","require_inc","__commonJSMin","exports","module","SemVer","inc","__name","version","release","options","identifier","identifierBase","require_diff","__commonJSMin","exports","module","parse","diff","__name","version1","version2","v1","v2","comparison","v1Higher","highVersion","lowVersion","highHasPre","prefix","require_major","__commonJSMin","exports","module","SemVer","major","__name","a","loose","require_minor","__commonJSMin","exports","module","SemVer","minor","__name","a","loose","require_patch","__commonJSMin","exports","module","SemVer","patch","__name","a","loose","require_prerelease","__commonJSMin","exports","module","parse","prerelease","__name","version","options","parsed","require_compare","__commonJSMin","exports","module","SemVer","compare","__name","a","b","loose","require_rcompare","__commonJSMin","exports","module","compare","rcompare","__name","a","b","loose","require_compare_loose","__commonJSMin","exports","module","compare","compareLoose","__name","a","b","require_compare_build","__commonJSMin","exports","module","SemVer","compareBuild","__name","a","b","loose","versionA","versionB","require_sort","__commonJSMin","exports","module","compareBuild","sort","__name","list","loose","a","b","require_rsort","__commonJSMin","exports","module","compareBuild","rsort","__name","list","loose","a","b","require_gt","__commonJSMin","exports","module","compare","gt","__name","a","b","loose","require_lt","__commonJSMin","exports","module","compare","lt","__name","a","b","loose","require_eq","__commonJSMin","exports","module","compare","eq","__name","a","b","loose","require_neq","__commonJSMin","exports","module","compare","neq","__name","a","b","loose","require_gte","__commonJSMin","exports","module","compare","gte","__name","a","b","loose","require_lte","__commonJSMin","exports","module","compare","lte","__name","a","b","loose","require_cmp","__commonJSMin","exports","module","eq","neq","gt","gte","lt","lte","cmp","__name","a","op","b","loose","require_coerce","__commonJSMin","exports","module","SemVer","parse","re","t","coerce","__name","version","options","match","coerceRtlRegex","next","major","minor","patch","prerelease","build","require_lrucache","__commonJSMin","exports","module","LRUCache","__name","key","value","firstKey","require_range","__commonJSMin","exports","module","SPACE_CHARACTERS","Range","_Range","__name","range","options","parseOptions","Comparator","c","first","isNullSet","isAny","i","comps","k","memoKey","FLAG_INCLUDE_PRERELEASE","FLAG_LOOSE","cached","cache","loose","hr","re","t","hyphenReplace","debug","comparatorTrimReplace","tildeTrimReplace","caretTrimReplace","rangeList","comp","parseComparator","replaceGTE0","rangeMap","comparators","result","thisComparators","isSatisfiable","rangeComparators","thisComparator","rangeComparator","version","SemVer","testSet","LRU","remainingComparators","testComparator","otherComparator","replaceCarets","replaceTildes","replaceXRanges","replaceStars","isX","id","replaceTilde","r","_","M","m","p","pr","ret","replaceCaret","z","replaceXRange","gtlt","xM","xm","xp","anyX","incPr","$0","from","fM","fm","fp","fpr","fb","to","tM","tm","tp","tpr","set","allowed","require_comparator","__commonJSMin","exports","module","ANY","Comparator","_Comparator","__name","comp","options","parseOptions","debug","r","re","t","m","SemVer","version","cmp","Range","require_satisfies","__commonJSMin","exports","module","Range","satisfies","__name","version","range","options","require_to_comparators","__commonJSMin","exports","module","Range","toComparators","__name","range","options","comp","c","require_max_satisfying","__commonJSMin","exports","module","SemVer","Range","maxSatisfying","__name","versions","range","options","max","maxSV","rangeObj","v","require_min_satisfying","__commonJSMin","exports","module","SemVer","Range","minSatisfying","__name","versions","range","options","min","minSV","rangeObj","v","require_min_version","__commonJSMin","exports","module","SemVer","Range","gt","minVersion","__name","range","loose","minver","i","comparators","setMin","comparator","compver","require_valid","__commonJSMin","exports","module","Range","validRange","__name","range","options","require_outside","__commonJSMin","exports","module","SemVer","Comparator","ANY","Range","satisfies","gt","lt","lte","gte","outside","__name","version","range","hilo","options","gtfn","ltefn","ltfn","comp","ecomp","i","comparators","high","low","comparator","require_gtr","__commonJSMin","exports","module","outside","gtr","__name","version","range","options","require_ltr","__commonJSMin","exports","module","outside","ltr","__name","version","range","options","require_intersects","__commonJSMin","exports","module","Range","intersects","__name","r1","r2","options","require_simplify","__commonJSMin","exports","module","satisfies","compare","versions","range","options","set","first","prev","v","a","b","version","ranges","min","max","simplified","original","require_subset","__commonJSMin","exports","module","Range","Comparator","ANY","satisfies","compare","subset","__name","sub","dom","options","sawNonNull","OUTER","simpleSub","simpleDom","isSub","simpleSubset","minimumVersionWithPreRelease","minimumVersion","eqSet","gt","lt","c","higherGT","lowerLT","gtltComp","eq","higher","lower","hasDomLT","hasDomGT","needDomLTPre","needDomGTPre","a","b","comp","require_semver","__commonJSMin","exports","module","internalRe","constants","SemVer","identifiers","parse","valid","clean","inc","diff","major","minor","patch","prerelease","compare","rcompare","compareLoose","compareBuild","sort","rsort","gt","lt","eq","neq","gte","lte","cmp","coerce","Comparator","Range","satisfies","toComparators","maxSatisfying","minSatisfying","minVersion","validRange","outside","gtr","ltr","intersects","simplifyRange","subset","createServer","fs","path","chalk","pino","z","LogLevelSchema","z","formatDateTime","date","year","month","day","hours","minutes","seconds","__name","Logger","level","normalizedLevel","result","streams","consoleStream","pino","_label","number","err","levelMap","chalk","chunk","logObj","message","content","timestamp","levelInfo","text","coloredLevel","argsStr","arg","projectDir","enable","messageOrObj","args","errorArgs","enhancedObj","obj","enhanced","key","value","logDir","logName","i","oldFile","newFile","firstRotatedFile","maxSize","maxFiles","globalLogger","globalLogLevel","getLogger","globalLogger","Logger","globalLogLevel","__name","logger","getLogger","existsSync","mkdirSync","readFileSync","readdirSync","rmSync","statSync","writeFileSync","dirname","isAbsolute","resolve","configManager","listPromptFiles","configFilePath","configManager","configDir","dirname","promptsDir","resolve","existsSync","readdirSync","file","__name","MAX_FILE_SIZE","FILE_NAME_REGEX","validatePromptPath","relativePath","normalizedPath","fileName","validatePromptFileName","getPromptsDir","resolvePromptPath","readPromptFile","validation","absolutePath","statSync","content","readFileSync","updatePromptFile","writeFileSync","createPromptFile","mkdirSync","deletePromptFile","rmSync","configManager","BaseHandler","__name","c","error","operation","defaultCode","defaultMessage","statusCode","errorMessage","errorCode","message","ConfigApiHandler","BaseHandler","__name","c","logger","config","configManager","error","newConfig","serverName","toolsConfig","toolName","toolConfig","endpoint","endpoints","servers","connection","path","exists","prompts","listPromptFiles","fileContent","readPromptFile","body","content","updatePromptFile","fileName","createPromptFile","deletePromptFile","coze_exports","__export","CozeApiService","config_default","createCozeClient","config_default","__reExport","coze_exports","api_star","createCozeClient","token","language","env","config_default","__name","NodeCache","CozeApiService","__name","token","createCozeClient","NodeCache","cacheKey","cached","workspaces","error","errorMessage","params","workspace_id","page_num","page_size","result","workflowId","parameters","pattern","keysToDelete","key","stats","keys","totalRequests","hitRate","configManager","isErrorWithCode","error","code","__name","getCozeApiService","token","configManager","CozeApiService","CozeHandler","BaseHandler","c","operationName","details","cozeApiService","workspaces","workspace_id","page_num","page_size","params","result","customMCPTools","enhancedItems","item","addedTool","tool","pattern","statsBefore","statsAfter","stats","EventEmitter","EventBus","EventEmitter","__name","logger","isTest","error","eventName","listenerCount","data","listener","onceListener","stats","stat","sum","count","eventBusInstance","getEventBus","destroyEventBus","EndpointHandler","__name","endpointManager","configManager","logger","getEventBus","c","errorErrorCode","body","error","endpoint","errors","parseResult","endpointStatus","status","fallbackStatus","validation","newEndpoint","connectError","configError","disconnectError","defaultEndpointStatus","endpointInstance","wasConnected","PAGINATION_CONSTANTS","HTTP_CONTENT_TYPES","HTTP_HEADERS","HTTP_STATUS_CODES","HTTP_SERVER_CONFIG","HTTP_ERROR_MESSAGES","MCP_PROTOCOL_VERSIONS","MCP_SUPPORTED_PROTOCOL_VERSIONS","MCP_SERVER_INFO","MCP_METHODS","MCP_CACHE_VERSIONS","MCP_SERVICE_EVENTS","CACHE_TIMEOUTS","HTTP_TIMEOUTS","SERVICE_RESTART_DELAYS","MESSAGE_SIZE_LIMITS","CACHE_FILE_CONFIG","TOOL_NAME_SEPARATORS","TTS_VOICES","getVoiceScenes","scenes","voice","__name","EventEmitter","isValidToolJSONSchema","obj","__name","ensureToolJSONSchema","schema","ToolCallError","code","message","data","__name","isModelScopeURL","configManager","createHash","generateCacheKey","toolName","arguments_","argsHash","createHash","__name","isCacheExpired","timestamp","ttl","cachedTime","__name","shouldCleanupCache","cache","now","DEFAULT_CONFIG","TimeoutError","_TimeoutError","__name","message","createTimeoutResponse","taskId","toolName","getToolSpecificTimeoutMessage","getDefaultTimeoutMessage","toolMessages","configManager","isProxyHandler","handler","__name","CustomMCPHandler","DEFAULT_CONFIG","cacheManager","mcpServiceManager","logger","MCPCacheManager","token","configManager","CozeApiService","eventBus","getEventBus","data","error","tools","customTools","tool","ensureToolJSONSchema","toolName","arguments_","options","completedResult","timeout","result","TimeoutError","taskId","createTimeoutResponse","_","reject","cacheKey","cache","cached","isCacheExpired","workflowData","responseData","config","cozeApiService","workflowResult","shouldCleanupCache","generateCacheKey","cacheData","fs","path","tmpdir","PathUtils","__name","tmpdir","pino","ToolCallLogger","__name","config","configDir","baseDir","PathUtils","logger","logFilePath","streams","chunk","logObj","message","pino","error","_label","number","toolName","success","duration","lines","line","recordsToRemove","linesToKeep","newContent","record","ToolCallLogService","records","a","b","query","filtered","startTime","endTime","recordTime","total","limit","offset","paginated","hasMore","MCPMessageHandler","__name","serviceManager","logger","message","isNotification","MCP_METHODS","error","params","id","clientVersion","responseVersion","MCP_SUPPORTED_PROTOCOL_VERSIONS","MCP_PROTOCOL_VERSIONS","MCP_SERVER_INFO","mcpTools","tool","validatedParams","validateToolCallParams","result","resources","prompts","errorCode","MCPServiceManager","EventEmitter","__name","getEventBus","configs","cachePath","MCPCacheManager","CustomMCPHandler","toolCallLogConfig","configManager","configDir","ToolCallLogger","data","MCPMessageHandler","logger","error","configEntries","startPromises","serviceName","results","successCount","failureCount","failedServices","result","config","serviceConfig","service","MCPService","tools","t","tool","toolKey","status","allTools","serviceTools","isEnabled","toolConfig","toolError","serviceError","customTools","customTool","toolName","toolInfo","arguments_","options","startTime","logServerName","originalToolName","isSuccess","currentTime","action","activeLocks","name","connectedServices","isModelScopeURL","originalConfig","enhancedConfig","modelScopeApiKey","serviceUrl","nameOrConfig","finalConfig","internalConfig","currentServerConfigs","currentToolsConfig","newToolsConfig","currentToolConfig","currentToolNames","removedTools","addedTools","updatedTools","current","updated","currentConfig","newConfig","currentKeys","newKeys","key","currentTool","newTool","initialDelay","delay","existingTimer","timer","currentDelay","nextDelay","acc","char","connections","conn","serviceStatus","customMCPToolCount","customToolNames","totalTools","availableTools","message","response","MCPConnection","MCPService","__name","getEventBus","config","name","connectionConfig","callbacks","data","MCP_SERVICE_EVENTS","MCPConnection","arguments_","TypeFieldNormalizer","validateToolCallParams","params","options","opts","ToolCallError","paramsObj","argsObj","error","__name","createHash","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","resolve","Hono","createApp","__name","Hono","requireMCPServiceManager","__name","c","serviceManager","dayjs","MCPCacheManager","__name","MCP_CACHE_VERSIONS","CACHE_TIMEOUTS","customCachePath","logger","dayjs","configDir","resolve","CACHE_FILE_CONFIG","existsSync","cacheDir","dirname","mkdirSync","initialCache","error","now","serverName","tools","config","cache","configHash","cacheEntry","tool","cacheData","readFileSync","cacheContent","filePath","data","tempPath","writeFileSync","renameSync","createHash","cacheObj","metadata","allTools","TOOL_NAME_SEPARATORS","toolName","arguments_","result","status","taskId","ttl","cacheKey","generateCacheKey","cachedTime","newStatus","oldStatus","entries","cleanedCount","shouldCleanupCache","totalEntries","pendingTasks","e","completedTasks","failedTasks","consumedEntries","cacheHitRate","memoryUsage","MCPRouteHandler","__name","config","logger","MESSAGE_SIZE_LIMITS","c","serviceManager","webServer","mcpServiceManager","MCPMessageHandler","error","startTime","messageId","contentLength","HTTP_HEADERS","HTTP_ERROR_MESSAGES","HTTP_CONTENT_TYPES","protocolVersion","MCP_SUPPORTED_PROTOCOL_VERSIONS","message","rawBody","response","responseTime","HTTP_STATUS_CODES","MCP_PROTOCOL_VERSIONS","errorMessage","msg","code","id","responseId","errorResponse","MCPError","_MCPError","__name","code","message","severity","category","details","error","defaultCode","DefaultErrorHandler","context","ConfigErrorHandler","ConnectionErrorHandler","ErrorHandlerRegistry","handler","result","globalErrorHandler","normalizeServiceConfig","TypeFieldNormalizer","MCPHandler","__name","mcpServiceManager","configManager","logger","error","operation","context","MCPError","mcpError","c","startTime","requestData","batchRequest","result","duration","singleRequest","name","config","statusCode","normalizedConfig","TypeFieldNormalizer","nameValidation","MCPServerConfigValidator","validationError","existsError","configValidation","configError","mcpServiceConfig","normalizeServiceConfig","serviceStatus","toolNames","tool","getEventBus","serverName","serverConfig","service","currentTools","status","newStatus","previousStatus","addedTools","removedTools","mcpServers","servers","listResponse","serverNames","results","successfullyAddedServers","validationResult","normalizedServerConfig","addedCount","failedCount","response","errors","rollbackResults","rollbackFailures","validateConfig","validateServiceName","checkServiceExists","spawn","ServiceApiHandler","__name","statusService","logger","getEventBus","args","child","spawn","c","mcpServiceManager","requireMCPServiceManager","SERVICE_RESTART_DELAYS","error","status","health","existsSync","readFile","dirname","join","fileURLToPath","StaticFileHandler","BaseHandler","__name","logger","__dirname","dirname","fileURLToPath","possibleWebPaths","join","p","exists","existsSync","error","c","pathname","filePath","HTTP_STATUS_CODES","fullPath","indexPath","HTTP_CONTENT_TYPES","contentType","content","readFile","ext","message","errorHtml","StatusApiHandler","BaseHandler","__name","statusService","c","status","error","clientStatus","restartStatus","connected","lastHeartbeat","servers","statusUpdate","ToolType","toolSorters","__name","a","b","enabledCompare","countCompare","timeCompare","sortTools","tools","config","sorter","logger","configManager","Ajv","dayjs","MCPToolHandler","_MCPToolHandler","__name","ToolType","logger","Ajv","c","requestBody","serviceName","toolName","args","serviceManager","result","HTTP_TIMEOUTS","toolKey","error","errorMessage","errorCode","configManager","customTools","configPath","status","sortByParam","validSortFields","sortBy","rawTools","sortTools","tools","tool","responseData","availableTools","MCPError","targetTool","validate","path","message","expectedType","allowedValues","code","body","request","type","data","workflow","customName","customDescription","parameterConfig","preCheckResult","cachedTools","MCPCacheManager","fullToolName","cachedTool","finalToolName","existingTools","dayjs","serverToolsConfig","existingTool","updatedInputSchema","updatedTool","toolToDelete","mcpConfig","baseName","description","inputSchema","handler","name","sanitized","text","chineseToEnglishMap","chinese","english","requiredFields","field","value","lengthLimits","max","sensitiveWords","lowerName","word","existingNames","finalName","counter","cozeConfig","auth","validAuthTypes","bodyTemplate","templateVars","templateVar","varName","schema","properties","required","param","keyword","errorMappings","key","basicCheckResult","systemCheckResult","resourceCheckResult","workflowObj","maxTools","configSizeEstimate","maxConfigSize","action","serverName","validActions","includeUsageStats","toolConfig","newEnabled","toolsConfig","enabledCount","t","disabledCount","mcpServerConfig","serverConfig","toolInfo","z","ToolCallQuerySchema","z","val","PAGINATION_CONSTANTS","date","data","MCPToolLogHandler","BaseHandler","__name","ToolCallLogService","c","query","result","err","validation","error","message","exec","spawn","promisify","import_semver","execAsync","promisify","exec","NPMManager","__name","eventBus","logStream","getEventBus","version","installId","resolvedInstallId","startTime","logger","npmProcess","spawn","cleanup","resolve","reject","error","errorMessage","data","logEntry","code","duration","stdout","type","filteredVersions","semver","prerelease","a","b","currentVersion","stableVersions","latestVersion","hasUpdate","InstallLogStream","__name","data","installId","entry","session","eventData","streamController","controller","log","eventType","controllers","type","z","UpdateRequestSchema","z","UpdateApiHandler","BaseHandler","__name","getEventBus","logStream","InstallLogStream","NPMManager","c","body","parseResult","err","version","v","logger","installId","error","stream","VersionUtils","VersionApiHandler","BaseHandler","__name","c","versionInfo","VersionUtils","error","version","type","validTypes","versions","NPMManager","result","configManager","mapClusterToResourceId","createTTS","ALLOWED_ENCODINGS","ENCODING_TO_MIME","ENCODING_TO_EXT","TTSApiHandler","BaseHandler","__name","c","body","ttsConfig","configManager","appid","accessToken","voice_type","cluster","endpoint","encoding","safeEncoding","tts","createTTS","mapClusterToResourceId","audioData","error","voices","TTS_VOICES","scenes","getVoiceScenes","response","ESP32ErrorCode","ESP32Handler","BaseHandler","__name","esp32Manager","c","logger","deviceId","clientId","ESP32ErrorCode","report","response","error","loggerMiddleware","__name","c","next","logger","cors","corsMiddleware","origin","errorHandlerMiddleware","__name","err","c","notFoundHandlerMiddleware","responseEnhancerMiddleware","__name","c","next","data","message","status","response","code","details","pagination","MCPServiceManagerNotInitializedError","__name","message","WebServerNotAvailableError","mcpServiceManagerMiddleware","__name","c","next","webServer","WebServerNotAvailableError","serviceManager","error","MCPServiceManagerNotInitializedError","endpointManagerMiddleware","__name","c","next","webServer","connectionManager","error","configManager","endpointsMiddleware","__name","endpointHandler","lastManager","c","next","endpointManager","EndpointHandler","configManager","StatusService","__name","logger","getEventBus","info","source","oldStatus","error","status","servers","endpoint","serve","normalizeServiceConfig","configManager","EndpointManager","ESP32DeviceManager","WebSocketServer","isRouteGroup","route","__name","normalizeRoutes","routes","middleware","createHandler","dependencyKey","method","c","handler","RouteManager","logger","__name","name","routeRegistry","routes","normalizeRoutes","routeRegistries","app","routeEntries","nameA","nameB","totalRouteCount","groupName","route","error","method","path","handler","middleware","wrappedHandler","c","next","h","createHandler","configRoutes","handler","c","h","createHandler","statusRoutes","handler","c","h","createHandler","toolsRoutes","handler","c","h","createHandler","mcpRoutes","handler","c","h","createHandler","versionRoutes","handler","c","h","createHandler","servicesRoutes","handler","c","h","createHandler","updateRoutes","handler","c","h","createHandler","staticRoutes","handler","c","h","createHandler","cozeRoutes","handler","c","h","createHandler","toolLogsRoutes","handler","c","withMCPServerHandler","__name","c","handlerFn","handler","mcpserverRoutes","h","withEndpointHandler","__name","c","handlerName","endpointHandler","error","endpointRoutes","h","createHandler","miscRoutes","handler","c","h","createHandler","ttsRoutes","handler","c","h","createHandler","createESP32Handler","__name","method","c","handler","esp32Routes","WebServer","__name","port","configManager","HTTP_SERVER_CONFIG","logger","getEventBus","StatusService","esp32ConfigProvider","ESP32DeviceManager","ConfigApiHandler","StatusApiHandler","ServiceApiHandler","MCPToolHandler","MCPToolLogHandler","VersionApiHandler","StaticFileHandler","MCPRouteHandler","UpdateApiHandler","CozeHandler","TTSApiHandler","ESP32Handler","createApp","notFoundHandlerMiddleware","MCPServiceManager","config","MCPHandler","rawTools","tools","tool","ensureToolJSONSchema","error","mcpServers","name","serviceConfig","normalizeServiceConfig","mcpEndpoint","validEndpoints","ep","EndpointManager","endpointUrl","event","manager","MCPServiceManagerNotInitializedError","connectionStatuses","status","connectionFn","context","maxAttempts","initialDelay","maxDelay","backoffMultiplier","lastError","attempt","delay","ms","resolve","loggerMiddleware","responseEnhancerMiddleware","c","next","mcpServiceManagerMiddleware","endpointManagerMiddleware","endpointsMiddleware","corsMiddleware","errorHandlerMiddleware","dependencies","RouteManager","configRoutes","statusRoutes","toolsRoutes","mcpRoutes","versionRoutes","servicesRoutes","updateRoutes","cozeRoutes","toolLogsRoutes","mcpserverRoutes","endpointRoutes","miscRoutes","ttsRoutes","esp32Routes","staticRoutes","ws","req","deviceId","clientId","authToken","singleServerListener","eventData","connectedEndpointCount","batchServerListener","server","serve","createServer","WebSocketServer","resolved","doResolve","client","forceCloseTimer","cleanupAndResolve","unsubscribe","destroyEventBus"]}
|