@@ -618,6 +618,51 @@ describe('PluginPresenter', () => {
618618 expect ( presenter . __mocks . mcpPresenter . startServer ) . toHaveBeenCalledWith ( 'fixture-tools' )
619619 } )
620620
621+ it ( 'removes persisted plugin state when discovery rejects an installed official plugin' , async ( ) => {
622+ const fixture = await createDirectoryFixture ( )
623+ const workspaceManifestPath = path . join ( fixture . pluginRoot , 'plugin.json' )
624+ const manifest = JSON . parse ( await readFile ( workspaceManifestPath , 'utf8' ) )
625+ manifest . toolPolicies = [
626+ {
627+ serverId : 'fixture-tools' ,
628+ tools : {
629+ fixture_tool : 'ask'
630+ }
631+ }
632+ ]
633+ await writeFile ( workspaceManifestPath , `${ JSON . stringify ( manifest , null , 2 ) } \n` )
634+
635+ const presenter = await createPluginPresenter ( 'darwin' , fixture . appPath )
636+ const { getPluginToolPolicy } = await import ( '@/presenter/pluginPresenter/toolPolicyStore' )
637+
638+ const enabled = await presenter . enablePlugin ( fixture . pluginId )
639+ expect ( enabled . ok ) . toBe ( true )
640+ expect ( getPluginToolPolicy ( 'fixture-tools' , 'fixture_tool' ) ) . toBe ( 'ask' )
641+
642+ const rejectedManifest = {
643+ ...manifest ,
644+ engines : {
645+ ...manifest . engines ,
646+ platforms : [ 'linux' ]
647+ }
648+ }
649+ await writeFile ( workspaceManifestPath , `${ JSON . stringify ( rejectedManifest , null , 2 ) } \n` )
650+ await writeFile (
651+ path . join ( fixture . installedRoot , 'plugin.json' ) ,
652+ `${ JSON . stringify ( rejectedManifest , null , 2 ) } \n`
653+ )
654+
655+ await presenter . initialize ( )
656+
657+ const servers = await presenter . __mocks . configPresenter . getMcpServers ( )
658+
659+ expect ( ( presenter as any ) . store . get ( 'installations' ) ) . toEqual ( [ ] )
660+ expect ( ( presenter as any ) . store . get ( 'resources' ) ) . toEqual ( [ ] )
661+ expect ( ( presenter as any ) . store . get ( 'runtimes' ) ) . toEqual ( [ ] )
662+ expect ( servers [ 'fixture-tools' ] ) . toBeUndefined ( )
663+ expect ( getPluginToolPolicy ( 'fixture-tools' , 'fixture_tool' ) ) . toBeNull ( )
664+ } )
665+
621666 it ( 'loads official packages only from resources roots in packaged mode' , async ( ) => {
622667 const cwdRoot = await mkdtemp ( path . join ( os . tmpdir ( ) , 'deepchat-plugin-cwd-' ) )
623668 tempRoots . push ( cwdRoot )
@@ -885,13 +930,27 @@ describe('PluginPresenter', () => {
885930 }
886931 } )
887932
888- it ( 'keeps the Feishu MCP bootstrap self-contained for installed plugin copies ' , async ( ) => {
933+ it ( 'pins the Feishu MCP bootstrap package and keeps registry selection explicit ' , async ( ) => {
889934 const source = await readFile ( 'plugins/feishu/mcp/serve.mjs' , 'utf8' )
890935
891936 expect ( source ) . not . toContain ( '@modelcontextprotocol/sdk' )
892937 expect ( source ) . toContain ( 'Content-Length:' )
893- expect ( source ) . toContain ( 'npm_config_registry' )
894- expect ( source ) . toContain ( 'registry.npmmirror.com' )
938+ expect ( source ) . toContain ( '@larksuiteoapi/lark-mcp@0.5.1' )
939+ expect ( source ) . toContain ( 'REGISTRY_OVERRIDE' )
940+ expect ( source ) . not . toContain ( 'registry.npmmirror.com' )
941+ } )
942+
943+ it ( 'uses conservative Feishu MCP defaults in the plugin manifest' , async ( ) => {
944+ const manifest = JSON . parse ( await readFile ( 'plugins/feishu/plugin.json' , 'utf8' ) )
945+
946+ expect ( manifest . mcpServers ) . toEqual (
947+ expect . arrayContaining ( [
948+ expect . objectContaining ( {
949+ id : 'feishu-tools' ,
950+ autoApprove : [ ]
951+ } )
952+ ] )
953+ )
895954 } )
896955
897956 it ( 'declares a Feishu plugin skill for MCP tool routing' , async ( ) => {
0 commit comments