{"record":{"id":"e5d1e795aafa1ca5","repo":"docmirror/dev-sidecar","slug":"key","errorCode":null,"errorMessage":"插件【${key}】不可用","messagePattern":"插件【(.+?)】不可用","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/expose.js","lineNumber":44,"sourceCode":"  }\n  return api\n}\n\nconst proxy = setupPlugin('proxy', modules.proxy, context, config)\nconst plugin = {}\nfor (const key in modules.plugin) {\n  const target = modules.plugin[key]\n  if (target == null) {\n    // 插件不可用（如 SEA 独立可执行文件中无法携带 free-eye），注册为禁用状态\n    log.warn(`插件【${key}】不可用，已注册为禁用状态`)\n    const stub = {\n      config: { key, enabled: false },\n      status: { enabled: false },\n      plugin: () => ({\n        start: async () => log.warn(`插件【${key}】不可用，无法启动`),\n        stop: async () => {},\n        close: async () => {},\n        run: async () => { throw new Error(`插件【${key}】不可用`) },\n      }),\n    }\n    const stubApi = setupPlugin(`plugin.${key}`, stub, context, config)\n    plugin[key] = stubApi\n    continue\n  }\n  const api = setupPlugin(`plugin.${key}`, target, context, config)\n  plugin[key] = api\n}\nconfig.resetDefault()\nconst server = modules.server\nconst serverStart = server.start\n\nfunction newServerStart ({ mitmproxyPath }) {\n  return serverStart({ mitmproxyPath, plugins: plugin })\n}\nserver.start = newServerStart\nasync function startup ({ mitmproxyPath }) {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/docmirror/dev-sidecar/blob/7710cd56cce760c708f30b01d2d4056eb8c402d5/packages/core/src/expose.js#L26-L62","documentation":"When a bundled plugin module (e.g. free-eye) cannot be loaded — typically because it is missing inside a SEA single-executable build — dev-sidecar registers a disabled stub instead of the real plugin. The stub's `run()` (and every other lifecycle call) throws `插件【key】不可用` to make it explicit that the plugin functionality is not available in this installation. It is a deliberate guard, not an unexpected failure.","triggerScenarios":"Calling `DevSidecar.plugin.<key>.run(...)` (or start/stop on the stub) for a plugin whose module was null at registration time in packages/core/src/expose.js:32-50 — most commonly running the packaged SEA binary where the free-eye plugin assets are not embedded.","commonSituations":"Running the standalone executable instead of the full Node install; a partially broken install where a plugin module fails to require; scripts/automation that unconditionally calls plugin APIs without checking `status.plugin.<key>.enabled`.","solutions":["Check availability before use: read `DevSidecar.status.plugin.<key>.enabled` and skip/stub the call when it is false.","Install/use the full Node-based package (pnpm workspace install) where all plugin modules are present, rather than the SEA binary.","If you own the build, ensure the plugin directory is included in the SEA asset bundle so `modules.plugin[key]` is not null.","Guard your caller with try/catch so the stub throw degrades gracefully instead of crashing the automation."],"exampleFix":"// before\nawait DevSidecar.plugin['free-eye'].run(options)\n// after\nif (DevSidecar.status.plugin['free-eye']?.enabled) {\n  await DevSidecar.plugin['free-eye'].run(options)\n} else {\n  log.warn('free-eye plugin unavailable in this build; skipping')\n}","handlingStrategy":"try-catch","validationCode":"// check plugin availability before calling\nconst enabled = DevSidecar.status?.plugin?.['free-eye']?.enabled\nif (!enabled) throw new SkipError('plugin unavailable in this build')","typeGuard":"function isPluginAvailable (devSidecar, key) {\n  return Boolean(devSidecar?.status?.plugin?.[key]?.enabled) &&\n    typeof devSidecar.plugin?.[key]?.run === 'function'\n}","tryCatchPattern":"try {\n  await DevSidecar.plugin[key].run(options)\n} catch (err) {\n  if (String(err.message).includes('不可用')) {\n    log.warn(`plugin ${key} unavailable; skipping`)\n  } else {\n    throw err\n  }\n}","preventionTips":["Check status.plugin.<key>.enabled before every plugin call","Prefer the full Node install over SEA binaries when plugins are required","Wrap plugin automation in guards that treat unavailable plugins as skippable","Log plugin availability at startup of your integration"],"tags":["plugin","sea-bundle","unavailable-feature"],"backgroundTag":"plugin-unavailable-stub","analyzedSha":"7710cd56cce760c708f30b01d2d4056eb8c402d5","analyzedAt":"2026-08-31T22:07:07.234Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}