mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 00:22:34 +00:00
fix(config/loader): break runtime cycle from normalizers to channels-runtime
The normalizers extraction in #1168 introduced a circular module-load chain that crashed the built CLI: ccs.js -> errors -> services/logging -> log-config -> config-loader-facade -> unified-config-loader -> loader/normalizers -> channels/official-channels-runtime -> utils/claude-detector -> utils/shell-executor -> utils/websearch-manager -> utils/websearch/hook-env -> utils/websearch/trace -> services/logging (mid-load - createLogger undefined) -> CRASH normalizers only needed three pure helpers from official-channels-runtime (isOfficialChannelId, normalizeOfficialChannelIds, resolveLegacyDiscord Selection) but pulled in the whole file's claude-detector / shell- executor / websearch chain. Fix: extract those three helpers + OFFICIAL_CHANNEL_IDS into a leaf module src/channels/official-channels-ids.ts with no runtime deps. Update normalizers.ts and config-getters.ts to import from the leaf. official-channels-runtime.ts re-exports from the leaf for callers that still want the bundled API. Also revert the over-eager facade-import migration in src/utils/config-manager.ts (it was importing from config-loader-facade which re-exports from itself, creating a direct cycle). Verified: dist/ccs.js boots cleanly (--version returns); test:all 1828/1828 pass; typecheck/lint/format clean. Refs #1135
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Official Channels IDs (leaf module, no runtime dependencies)
|
||||
*
|
||||
* Pure helpers extracted from `official-channels-runtime` so that
|
||||
* config-loader code can use them without transitively pulling in
|
||||
* `claude-detector` / `shell-executor` / `websearch-manager`.
|
||||
*
|
||||
* The full channel definitions (with display names, plugin specs, env keys,
|
||||
* etc.) live in `official-channels-runtime`. This module only owns:
|
||||
* - the canonical ordered list of channel IDs
|
||||
* - the type-narrowing predicate
|
||||
* - the order-preserving normalizer
|
||||
* - the legacy-discord shim
|
||||
*/
|
||||
|
||||
import type { OfficialChannelId } from '../config/unified-config-types';
|
||||
|
||||
/** Canonical, ordered list of official channel IDs. */
|
||||
export const OFFICIAL_CHANNEL_IDS: readonly OfficialChannelId[] = [
|
||||
'telegram',
|
||||
'discord',
|
||||
'imessage',
|
||||
] as const;
|
||||
|
||||
const OFFICIAL_CHANNEL_ID_SET = new Set<string>(OFFICIAL_CHANNEL_IDS);
|
||||
|
||||
export function isOfficialChannelId(value: string): value is OfficialChannelId {
|
||||
return OFFICIAL_CHANNEL_ID_SET.has(value);
|
||||
}
|
||||
|
||||
export function normalizeOfficialChannelIds(values: readonly string[]): OfficialChannelId[] {
|
||||
const seen = new Set<OfficialChannelId>();
|
||||
const normalized: OfficialChannelId[] = [];
|
||||
|
||||
for (const channelId of OFFICIAL_CHANNEL_IDS) {
|
||||
if (!values.includes(channelId) || seen.has(channelId)) {
|
||||
continue;
|
||||
}
|
||||
seen.add(channelId);
|
||||
normalized.push(channelId);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export function resolveLegacyDiscordSelection(enabled: boolean | undefined): OfficialChannelId[] {
|
||||
return enabled ? ['discord'] : [];
|
||||
}
|
||||
@@ -64,7 +64,20 @@ export const OFFICIAL_CHANNELS: Record<OfficialChannelId, OfficialChannelDefinit
|
||||
},
|
||||
};
|
||||
|
||||
export const OFFICIAL_CHANNEL_IDS = Object.keys(OFFICIAL_CHANNELS) as OfficialChannelId[];
|
||||
// Re-export from leaf module so config-loader can use these without pulling
|
||||
// in this file's claude-detector / shell-executor dep chain.
|
||||
import {
|
||||
OFFICIAL_CHANNEL_IDS,
|
||||
isOfficialChannelId,
|
||||
normalizeOfficialChannelIds,
|
||||
resolveLegacyDiscordSelection,
|
||||
} from './official-channels-ids';
|
||||
export {
|
||||
OFFICIAL_CHANNEL_IDS,
|
||||
isOfficialChannelId,
|
||||
normalizeOfficialChannelIds,
|
||||
resolveLegacyDiscordSelection,
|
||||
};
|
||||
export const MINIMUM_OFFICIAL_CHANNELS_CLAUDE_VERSION = '2.1.80';
|
||||
|
||||
export interface OfficialChannelsVersionSummary {
|
||||
@@ -163,26 +176,6 @@ export function isDiscordChannelsSessionSupported(
|
||||
return target === 'claude' && (profileType === 'default' || profileType === 'account');
|
||||
}
|
||||
|
||||
export function isOfficialChannelId(value: string): value is OfficialChannelId {
|
||||
return value in OFFICIAL_CHANNELS;
|
||||
}
|
||||
|
||||
export function normalizeOfficialChannelIds(values: readonly string[]): OfficialChannelId[] {
|
||||
const seen = new Set<OfficialChannelId>();
|
||||
const normalized: OfficialChannelId[] = [];
|
||||
|
||||
for (const channelId of OFFICIAL_CHANNEL_IDS) {
|
||||
if (!values.includes(channelId) || seen.has(channelId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seen.add(channelId);
|
||||
normalized.push(channelId);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export function hasExplicitChannelsFlag(args: string[]): boolean {
|
||||
return args.some((arg) => arg === '--channels' || arg.startsWith('--channels='));
|
||||
}
|
||||
@@ -757,10 +750,6 @@ export function isOfficialChannelSelectionValid(selection: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveLegacyDiscordSelection(enabled: boolean | undefined): OfficialChannelId[] {
|
||||
return enabled ? ['discord'] : [];
|
||||
}
|
||||
|
||||
export function getOfficialChannelsSupportedProfiles(): string[] {
|
||||
return ['default', 'account'];
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import type {
|
||||
} from '../unified-config-types';
|
||||
import { canonicalizeBrowserConfig } from './normalizers';
|
||||
import { canonicalizeImageAnalysisConfig } from '../../utils/hooks/image-analysis-backend-resolver';
|
||||
import { normalizeOfficialChannelIds } from '../../channels/official-channels-runtime';
|
||||
import { normalizeOfficialChannelIds } from '../../channels/official-channels-ids';
|
||||
import { normalizeSearxngBaseUrl } from '../../utils/websearch/types';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
isOfficialChannelId,
|
||||
normalizeOfficialChannelIds,
|
||||
resolveLegacyDiscordSelection,
|
||||
} from '../../channels/official-channels-runtime';
|
||||
} from '../../channels/official-channels-ids';
|
||||
import { getRecommendedBrowserUserDataDir } from '../../utils/browser/browser-settings';
|
||||
import { GO_DURATION_PATTERN, GO_DURATION_SEGMENT } from './io-locks';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { isConfig, isSettings } from '../types';
|
||||
import type { Config, Settings, CLIProxyVariantsConfig, CLIProxyVariantConfig } from '../types';
|
||||
import { expandPath, error } from './helpers';
|
||||
import { info } from './ui';
|
||||
import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../config/config-loader-facade';
|
||||
import { isUnifiedMode, loadOrCreateUnifiedConfig } from '../config/unified-config-loader';
|
||||
|
||||
// TODO: Replace with proper imports after converting these files
|
||||
// const { ErrorManager } = require('./error-manager');
|
||||
|
||||
Reference in New Issue
Block a user