feat: 恢复 --channels 能力 (#297)

* feat: 恢复  --channels 能力

* docs: 添加 channels 注释
This commit is contained in:
claude-code-best
2026-04-19 10:24:34 +08:00
committed by GitHub
parent c5edee431f
commit 481e2a58a9
10 changed files with 319 additions and 479 deletions

View File

@@ -332,59 +332,25 @@ export async function showSetupScreens(
// dev channels to any --channels list already set in main.tsx. Org policy
// is NOT bypassed — gateChannelServer() still runs; this flag only exists
// to sidestep the --channels approved-server allowlist.
if (feature('KAIROS') || feature('KAIROS_CHANNELS')) {
// gateChannelServer and ChannelsNotice read tengu_harbor after this
// function returns. A cold disk cache (fresh install, or first run after
// the flag was added server-side) defaults to false and silently drops
// channel notifications for the whole session — gh#37026.
// checkGate_CACHED_OR_BLOCKING returns immediately if disk already says
// true; only blocks on a cold/stale-false cache (awaits the same memoized
// initializeGrowthBook promise fired earlier). Also warms the
// isChannelsEnabled() check in the dev-channels dialog below.
if (getAllowedChannels().length > 0 || (devChannels?.length ?? 0) > 0) {
await checkGate_CACHED_OR_BLOCKING('tengu_harbor')
}
if (devChannels && devChannels.length > 0) {
const [{ isChannelsEnabled }, { getClaudeAIOAuthTokens }] =
await Promise.all([
import('./services/mcp/channelAllowlist.js'),
import('./utils/auth.js'),
])
// Skip the dialog when channels are blocked (tengu_harbor off or no
// OAuth) — accepting then immediately seeing "not available" in
// ChannelsNotice is worse than no dialog. Append entries anyway so
// ChannelsNotice renders the blocked branch with the dev entries
// named. dev:true here is for the flag label in ChannelsNotice
// (hasNonDev check); the allowlist bypass it also grants is moot
// since the gate blocks upstream.
if (!isChannelsEnabled() || !getClaudeAIOAuthTokens()?.accessToken) {
setAllowedChannels([
...getAllowedChannels(),
...devChannels.map(c => ({ ...c, dev: true })),
])
setHasDevChannels(true)
} else {
const { DevChannelsDialog } = await import(
'./components/DevChannelsDialog.js'
)
await showSetupDialog(root, done => (
<DevChannelsDialog
channels={devChannels}
onAccept={() => {
// Mark dev entries per-entry so the allowlist bypass doesn't leak
// to --channels entries when both flags are passed.
setAllowedChannels([
...getAllowedChannels(),
...devChannels.map(c => ({ ...c, dev: true })),
])
setHasDevChannels(true)
void done()
}}
/>
))
}
}
if (devChannels && devChannels.length > 0) {
const { DevChannelsDialog } = await import(
'./components/DevChannelsDialog.js'
)
await showSetupDialog(root, done => (
<DevChannelsDialog
channels={devChannels}
onAccept={() => {
// Mark dev entries per-entry so the allowlist bypass doesn't leak
// to --channels entries when both flags are passed.
setAllowedChannels([
...getAllowedChannels(),
...devChannels.map(c => ({ ...c, dev: true })),
])
setHasDevChannels(true)
void done()
}}
/>
))
}
// Show Chrome onboarding for first-time Claude in Chrome users