@@ -12,50 +12,27 @@ import {
1212 getHasDevChannels ,
1313} from '../../bootstrap/state.js'
1414import { Box , Text } from '@anthropic/ink'
15- import { isChannelsEnabled } from '../../services/mcp/channelAllowlist.js'
16- import { getEffectiveChannelAllowlist } from '../../services/mcp/channelNotification.js'
1715import { getMcpConfigsByScope } from '../../services/mcp/config.js'
18- import {
19- getClaudeAIOAuthTokens ,
20- getSubscriptionType ,
21- } from '../../utils/auth.js'
2216import { loadInstalledPluginsV2 } from '../../utils/plugins/installedPluginsManager.js'
23- import { getSettingsForSource } from '../../utils/settings/settings.js'
2417
2518export function ChannelsNotice ( ) : React . ReactNode {
2619 // Snapshot all reads at mount. This notice enters scrollback immediately
2720 // after the logo; any re-render past that point forces a full terminal
28- // reset. getAllowedChannels (bootstrap state), getSettingsForSource
29- // (session cache updated by background polling / /login), and
30- // isChannelsEnabled (GrowthBook 5-min refresh) must be captured once
31- // so a later re-render cannot flip branches.
32- const [ { channels, disabled, noAuth, policyBlocked, list, unmatched } ] =
21+ // reset.
22+ const [ { channels, list, unmatched } ] =
3323 useState ( ( ) => {
3424 const ch = getAllowedChannels ( )
3525 if ( ch . length === 0 )
3626 return {
3727 channels : ch ,
38- disabled : false ,
39- noAuth : false ,
40- policyBlocked : false ,
4128 list : '' ,
4229 unmatched : [ ] as Unmatched [ ] ,
4330 }
4431 const l = ch . map ( formatEntry ) . join ( ', ' )
45- const sub = getSubscriptionType ( )
46- const managed = sub === 'team' || sub === 'enterprise'
47- const policy = getSettingsForSource ( 'policySettings' )
48- const allowlist = getEffectiveChannelAllowlist (
49- sub ,
50- policy ?. allowedChannelPlugins ,
51- )
5232 return {
5333 channels : ch ,
54- disabled : ! isChannelsEnabled ( ) ,
55- noAuth : ! getClaudeAIOAuthTokens ( ) ?. accessToken ,
56- policyBlocked : managed && policy ?. channelsEnabled !== true ,
5734 list : l ,
58- unmatched : findUnmatched ( ch , allowlist ) ,
35+ unmatched : findUnmatched ( ch ) ,
5936 }
6037 } )
6138 if ( channels . length === 0 ) return null
@@ -70,50 +47,6 @@ export function ChannelsNotice(): React.ReactNode {
7047 ? '--dangerously-load-development-channels'
7148 : '--channels'
7249
73- if ( disabled ) {
74- return (
75- < Box paddingLeft = { 2 } flexDirection = "column" >
76- < Text color = "error" >
77- { flag } ignored ({ list } )
78- </ Text >
79- < Text dimColor > Channels are not currently available</ Text >
80- </ Box >
81- )
82- }
83-
84- if ( noAuth ) {
85- return (
86- < Box paddingLeft = { 2 } flexDirection = "column" >
87- < Text color = "error" >
88- { flag } ignored ({ list } )
89- </ Text >
90- < Text dimColor >
91- Channels require claude.ai authentication · run /login, then restart
92- </ Text >
93- </ Box >
94- )
95- }
96-
97- if ( policyBlocked ) {
98- return (
99- < Box paddingLeft = { 2 } flexDirection = "column" >
100- < Text color = "error" >
101- { flag } blocked by org policy ({ list } )
102- </ Text >
103- < Text dimColor > Inbound messages will be silently dropped</ Text >
104- < Text dimColor >
105- Have an administrator set channelsEnabled: true in managed settings to
106- enable
107- </ Text >
108- { unmatched . map ( u => (
109- < Text key = { `${ formatEntry ( u . entry ) } :${ u . why } ` } color = "warning" >
110- { formatEntry ( u . entry ) } · { u . why }
111- </ Text >
112- ) ) }
113- </ Box >
114- )
115- }
116-
11750 // "Listening for" not "active" — at this point we only know the allowlist
11851 // was set. Server connection, capability declaration, and whether the name
11952 // even matches a configured MCP server are all still unknown.
@@ -144,7 +77,6 @@ type Unmatched = { entry: ChannelEntry; why: string }
14477
14578function findUnmatched (
14679 entries : readonly ChannelEntry [ ] ,
147- allowlist : ReturnType < typeof getEffectiveChannelAllowlist > ,
14880) : Unmatched [ ] {
14981 // Server-kind: build one Set from all scopes up front. getMcpConfigsByScope
15082 // is not cached (project scope walks the dir tree); getMcpConfigByName would
@@ -163,46 +95,17 @@ function findUnmatched(
16395 Object . keys ( loadInstalledPluginsV2 ( ) . plugins ) ,
16496 )
16597
166- // Plugin-kind allowlist check: same {marketplace, plugin} test as the
167- // gate at channelNotification.ts. entry.dev bypasses (dev flag opts out
168- // of the allowlist). Org list replaces ledger when set (team/enterprise).
169- // GrowthBook _CACHED_MAY_BE_STALE — cold cache yields [] so every plugin
170- // entry warns; same tradeoff the gate already accepts.
171- const { entries : allowed , source } = allowlist
172-
173- // Independent ifs — a plugin entry that's both uninstalled AND
174- // unlisted shows two lines. Server kind checks config + dev flag.
17598 const out : Unmatched [ ] = [ ]
17699 for ( const entry of entries ) {
177100 if ( entry . kind === 'server' ) {
178101 if ( ! configured . has ( entry . name ) ) {
179102 out . push ( { entry, why : 'no MCP server configured with that name' } )
180103 }
181- if ( ! entry . dev ) {
182- out . push ( {
183- entry,
184- why : 'server: entries need --dangerously-load-development-channels' ,
185- } )
186- }
187104 continue
188105 }
189106 if ( ! installedPluginIds . has ( `${ entry . name } @${ entry . marketplace } ` ) ) {
190107 out . push ( { entry, why : 'plugin not installed' } )
191108 }
192- if (
193- ! entry . dev &&
194- ! allowed . some (
195- e => e . plugin === entry . name && e . marketplace === entry . marketplace ,
196- )
197- ) {
198- out . push ( {
199- entry,
200- why :
201- source === 'org'
202- ? "not on your org's approved channels list"
203- : 'not on the approved channels allowlist' ,
204- } )
205- }
206109 }
207110 return out
208111}
0 commit comments