()
| 1790 | // settings were fetched. Without clearing, getCommands() would rebuild |
| 1791 | // from a stale plugin list. |
| 1792 | async function refreshPluginState(): Promise<void> { |
| 1793 | // refreshActivePlugins handles the full cache sweep (clearAllCaches), |
| 1794 | // reloads all plugin component loaders, writes AppState.plugins + |
| 1795 | // AppState.agentDefinitions, registers hooks, and bumps mcp.pluginReconnectKey. |
| 1796 | const { agentDefinitions: freshAgentDefs } = |
| 1797 | await refreshActivePlugins(setAppState) |
| 1798 | |
| 1799 | // Headless-specific: currentCommands/currentAgents are local mutable refs |
| 1800 | // captured by the query loop (REPL uses AppState instead). getCommands is |
| 1801 | // fresh because refreshActivePlugins cleared its cache. |
| 1802 | currentCommands = await getCommands(cwd()) |
| 1803 | |
| 1804 | // Preserve SDK-provided agents (--agents CLI flag or SDK initialize |
| 1805 | // control_request) — both inject via parseAgentsFromJson with |
| 1806 | // source='flagSettings'. loadMarkdownFilesForSubdir never assigns this |
| 1807 | // source, so it cleanly discriminates "injected, not disk-loadable". |
| 1808 | // |
| 1809 | // The previous filter used a negative set-diff (!freshAgentTypes.has(a)) |
| 1810 | // which also matched plugin agents that were in the poisoned initial |
| 1811 | // currentAgents but correctly excluded from freshAgentDefs after managed |
| 1812 | // settings applied — leaking policy-blocked agents into the init message. |
| 1813 | // See gh-23085: isBridgeEnabled() at Commander-definition time poisoned |
| 1814 | // the settings cache before setEligibility(true) ran. |
| 1815 | const sdkAgents = currentAgents.filter(a => a.source === 'flagSettings') |
| 1816 | currentAgents = [...freshAgentDefs.allAgents, ...sdkAgents] |
| 1817 | } |
| 1818 | |
| 1819 | // Re-diff MCP configs after plugin state changes. Filters to |
| 1820 | // process-transport-supported types and carries SDK-mode servers through |
no test coverage detected