mirror of
https://github.com/tiennm99/ccs.git
synced 2026-08-08 22:24:09 +00:00
style: format official channel files
This commit is contained in:
@@ -1,10 +1,7 @@
|
|||||||
import { spawnSync } from 'child_process';
|
import { spawnSync } from 'child_process';
|
||||||
import type { TargetType } from '../targets/target-adapter';
|
import type { TargetType } from '../targets/target-adapter';
|
||||||
import type { ProfileType } from '../types/profile';
|
import type { ProfileType } from '../types/profile';
|
||||||
import type {
|
import type { OfficialChannelId, OfficialChannelsConfig } from '../config/unified-config-types';
|
||||||
OfficialChannelId,
|
|
||||||
OfficialChannelsConfig,
|
|
||||||
} from '../config/unified-config-types';
|
|
||||||
|
|
||||||
export interface OfficialChannelDefinition {
|
export interface OfficialChannelDefinition {
|
||||||
id: OfficialChannelId;
|
id: OfficialChannelId;
|
||||||
@@ -132,7 +129,11 @@ export function buildOfficialChannelsArgs(
|
|||||||
channels: OfficialChannelId[],
|
channels: OfficialChannelId[],
|
||||||
includePermissionBypass: boolean
|
includePermissionBypass: boolean
|
||||||
): string[] {
|
): string[] {
|
||||||
const nextArgs = [...args, '--channels', ...channels.map((channel) => OFFICIAL_CHANNELS[channel].pluginSpec)];
|
const nextArgs = [
|
||||||
|
...args,
|
||||||
|
'--channels',
|
||||||
|
...channels.map((channel) => OFFICIAL_CHANNELS[channel].pluginSpec),
|
||||||
|
];
|
||||||
|
|
||||||
if (includePermissionBypass) {
|
if (includePermissionBypass) {
|
||||||
nextArgs.push('--dangerously-skip-permissions');
|
nextArgs.push('--dangerously-skip-permissions');
|
||||||
@@ -191,9 +192,7 @@ export function resolveOfficialChannelsLaunchPlan(
|
|||||||
const channel = OFFICIAL_CHANNELS[channelId];
|
const channel = OFFICIAL_CHANNELS[channelId];
|
||||||
|
|
||||||
if (channel.requiresMacOS && !isMacOS()) {
|
if (channel.requiresMacOS && !isMacOS()) {
|
||||||
skippedMessages.push(
|
skippedMessages.push(`${channel.displayName} auto-enable skipped because it requires macOS.`);
|
||||||
`${channel.displayName} auto-enable skipped because it requires macOS.`
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +255,9 @@ export function getOfficialChannelSummary(channelId: OfficialChannelId): string
|
|||||||
return 'macOS-only. No bot token required, but Messages permissions are required.';
|
return 'macOS-only. No bot token required, but Messages permissions are required.';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOfficialChannelUnavailableReason(channelId: OfficialChannelId): string | undefined {
|
export function getOfficialChannelUnavailableReason(
|
||||||
|
channelId: OfficialChannelId
|
||||||
|
): string | undefined {
|
||||||
if (channelId === 'imessage' && !isMacOS()) {
|
if (channelId === 'imessage' && !isMacOS()) {
|
||||||
return 'Requires macOS.';
|
return 'Requires macOS.';
|
||||||
}
|
}
|
||||||
@@ -300,7 +301,9 @@ export function isOfficialChannelSelectionValid(selection: string): boolean {
|
|||||||
.map((value) => value.trim().toLowerCase())
|
.map((value) => value.trim().toLowerCase())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
||||||
return parsed.length > 0 && parsed.every((value) => value === 'all' || isOfficialChannelId(value));
|
return (
|
||||||
|
parsed.length > 0 && parsed.every((value) => value === 'all' || isOfficialChannelId(value))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveLegacyDiscordSelection(enabled: boolean | undefined): OfficialChannelId[] {
|
export function resolveLegacyDiscordSelection(enabled: boolean | undefined): OfficialChannelId[] {
|
||||||
@@ -369,7 +372,10 @@ export function getOfficialChannelsDocsSummary(): string {
|
|||||||
return 'Supported official channels are Telegram, Discord, and iMessage.';
|
return 'Supported official channels are Telegram, Discord, and iMessage.';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOfficialChannelSyncFailureMessage(channelId: OfficialChannelId, targetPath: string): string {
|
export function getOfficialChannelSyncFailureMessage(
|
||||||
|
channelId: OfficialChannelId,
|
||||||
|
targetPath: string
|
||||||
|
): string {
|
||||||
return `${getOfficialChannelDisplayName(channelId)} auto-enable skipped: failed to sync channel env to ${targetPath}`;
|
return `${getOfficialChannelDisplayName(channelId)} auto-enable skipped: failed to sync channel env to ${targetPath}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,9 +62,7 @@ function parseTokenAssignment(value: string): {
|
|||||||
} | null {
|
} | null {
|
||||||
const separatorIndex = value.indexOf('=');
|
const separatorIndex = value.indexOf('=');
|
||||||
if (separatorIndex === -1) {
|
if (separatorIndex === -1) {
|
||||||
return value.trim()
|
return value.trim() ? { channelId: 'discord', token: value.trim() } : null;
|
||||||
? { channelId: 'discord', token: value.trim() }
|
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const channelId = value.slice(0, separatorIndex).trim().toLowerCase();
|
const channelId = value.slice(0, separatorIndex).trim().toLowerCase();
|
||||||
@@ -139,14 +137,20 @@ function showHelp(): void {
|
|||||||
console.log(` ${color('--clear', 'command')} Clear all selected channels`);
|
console.log(` ${color('--clear', 'command')} Clear all selected channels`);
|
||||||
console.log(` ${color('--enable', 'command')} Legacy alias: add Discord`);
|
console.log(` ${color('--enable', 'command')} Legacy alias: add Discord`);
|
||||||
console.log(` ${color('--disable', 'command')} Legacy alias: remove Discord`);
|
console.log(` ${color('--disable', 'command')} Legacy alias: remove Discord`);
|
||||||
console.log(` ${color('--unattended', 'command')} Also add --dangerously-skip-permissions`);
|
console.log(
|
||||||
|
` ${color('--unattended', 'command')} Also add --dangerously-skip-permissions`
|
||||||
|
);
|
||||||
console.log(` ${color('--no-unattended', 'command')} Disable unattended runtime flag`);
|
console.log(` ${color('--no-unattended', 'command')} Disable unattended runtime flag`);
|
||||||
console.log(` ${color('--set-token <spec>', 'command')} ${getOfficialChannelTokenHelp()}`);
|
console.log(` ${color('--set-token <spec>', 'command')} ${getOfficialChannelTokenHelp()}`);
|
||||||
console.log(` ${color('--clear-token [channel]', 'command')} ${getOfficialChannelClearTokenHelp()}`);
|
console.log(
|
||||||
|
` ${color('--clear-token [channel]', 'command')} ${getOfficialChannelClearTokenHelp()}`
|
||||||
|
);
|
||||||
console.log(` ${color('--help, -h', 'command')} Show this help`);
|
console.log(` ${color('--help, -h', 'command')} Show this help`);
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log(subheader('Examples:'));
|
console.log(subheader('Examples:'));
|
||||||
console.log(` $ ${color('ccs config channels', 'command')} ${dim('# Show status')}`);
|
console.log(
|
||||||
|
` $ ${color('ccs config channels', 'command')} ${dim('# Show status')}`
|
||||||
|
);
|
||||||
console.log(
|
console.log(
|
||||||
` $ ${color('ccs config channels --set telegram,discord', 'command')} ${dim('# Enable Telegram + Discord')}`
|
` $ ${color('ccs config channels --set telegram,discord', 'command')} ${dim('# Enable Telegram + Discord')}`
|
||||||
);
|
);
|
||||||
@@ -170,13 +174,17 @@ function showStatus(): void {
|
|||||||
console.log('');
|
console.log('');
|
||||||
console.log(header('Official Channels Configuration'));
|
console.log(header('Official Channels Configuration'));
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log(` Channels: ${selected.length > 0 ? ok(getChannelConfigSelectionLabel(selected)) : warn('Disabled')}`);
|
console.log(
|
||||||
|
` Channels: ${selected.length > 0 ? ok(getChannelConfigSelectionLabel(selected)) : warn('Disabled')}`
|
||||||
|
);
|
||||||
console.log(` Unattended: ${config.unattended ? warn('Enabled') : info('Disabled')}`);
|
console.log(` Unattended: ${config.unattended ? warn('Enabled') : info('Disabled')}`);
|
||||||
console.log(` Bun: ${bunReady ? ok('Installed') : warn('Missing')}`);
|
console.log(` Bun: ${bunReady ? ok('Installed') : warn('Missing')}`);
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log(subheader('Applies To:'));
|
console.log(subheader('Applies To:'));
|
||||||
console.log(` ${dim(getOfficialChannelsCompatibilityMessage())}`);
|
console.log(` ${dim(getOfficialChannelsCompatibilityMessage())}`);
|
||||||
console.log(` ${dim(`Supported profiles: ${getOfficialChannelsSupportedProfiles().join(', ')}`)}`);
|
console.log(
|
||||||
|
` ${dim(`Supported profiles: ${getOfficialChannelsSupportedProfiles().join(', ')}`)}`
|
||||||
|
);
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log(subheader('Channels:'));
|
console.log(subheader('Channels:'));
|
||||||
for (const channelId of expandOfficialChannelSelection('all')) {
|
for (const channelId of expandOfficialChannelSelection('all')) {
|
||||||
@@ -195,7 +203,9 @@ function showStatus(): void {
|
|||||||
console.log(` ${enabled ? '[x]' : '[ ]'} ${displayName}: ${status}`);
|
console.log(` ${enabled ? '[x]' : '[ ]'} ${displayName}: ${status}`);
|
||||||
console.log(` ${dim(getOfficialChannelSummary(channelId))}`);
|
console.log(` ${dim(getOfficialChannelSummary(channelId))}`);
|
||||||
if (envKey) {
|
if (envKey) {
|
||||||
console.log(` ${dim(`${envKey}: ${tokenConfigured ? 'configured' : 'not configured'}`)}`);
|
console.log(
|
||||||
|
` ${dim(`${envKey}: ${tokenConfigured ? 'configured' : 'not configured'}`)}`
|
||||||
|
);
|
||||||
console.log(` ${dim(getOfficialChannelEnvPath(channelId))}`);
|
console.log(` ${dim(getOfficialChannelEnvPath(channelId))}`);
|
||||||
}
|
}
|
||||||
console.log(` ${dim(getOfficialChannelReadyMessage(channelId))}`);
|
console.log(` ${dim(getOfficialChannelReadyMessage(channelId))}`);
|
||||||
@@ -242,8 +252,13 @@ export async function handleConfigChannelsCommand(args: string[]): Promise<void>
|
|||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (options.setSelection !== undefined && !isOfficialChannelSelectionValid(options.setSelection)) {
|
if (
|
||||||
console.error(fail(`Invalid --set value: ${options.setSelection} (${getOfficialChannelChoices()} or all)`));
|
options.setSelection !== undefined &&
|
||||||
|
!isOfficialChannelSelectionValid(options.setSelection)
|
||||||
|
) {
|
||||||
|
console.error(
|
||||||
|
fail(`Invalid --set value: ${options.setSelection} (${getOfficialChannelChoices()} or all)`)
|
||||||
|
);
|
||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -261,7 +276,9 @@ export async function handleConfigChannelsCommand(args: string[]): Promise<void>
|
|||||||
}
|
}
|
||||||
if (options.clearTokenInvalid) {
|
if (options.clearTokenInvalid) {
|
||||||
console.error(
|
console.error(
|
||||||
fail(`Invalid --clear-token value: ${options.clearTokenInvalid} (use ${getOfficialChannelChoices()})`)
|
fail(
|
||||||
|
`Invalid --clear-token value: ${options.clearTokenInvalid} (use ${getOfficialChannelChoices()})`
|
||||||
|
)
|
||||||
);
|
);
|
||||||
process.exitCode = 1;
|
process.exitCode = 1;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -471,7 +471,10 @@ Run ${color('ccs config', 'command')} for web dashboard`.trim();
|
|||||||
|
|
||||||
printSubSection('Official Channels (official Claude plugins)', [
|
printSubSection('Official Channels (official Claude plugins)', [
|
||||||
['ccs config channels', 'Show current status'],
|
['ccs config channels', 'Show current status'],
|
||||||
['ccs config channels --set telegram,discord', 'Auto-add selected channels on native Claude sessions'],
|
[
|
||||||
|
'ccs config channels --set telegram,discord',
|
||||||
|
'Auto-add selected channels on native Claude sessions',
|
||||||
|
],
|
||||||
['ccs config channels --set all', 'Enable Telegram, Discord, and iMessage'],
|
['ccs config channels --set all', 'Enable Telegram, Discord, and iMessage'],
|
||||||
['ccs config channels --unattended', 'Also add --dangerously-skip-permissions'],
|
['ccs config channels --unattended', 'Also add --dangerously-skip-permissions'],
|
||||||
['ccs config channels --set-token telegram=<token>', 'Save TELEGRAM_BOT_TOKEN'],
|
['ccs config channels --set-token telegram=<token>', 'Save TELEGRAM_BOT_TOKEN'],
|
||||||
|
|||||||
@@ -305,7 +305,9 @@ function normalizeOfficialChannelsConfig(
|
|||||||
partial: Partial<UnifiedConfig> & { discord_channels?: LegacyDiscordChannelsConfig }
|
partial: Partial<UnifiedConfig> & { discord_channels?: LegacyDiscordChannelsConfig }
|
||||||
): OfficialChannelsConfig {
|
): OfficialChannelsConfig {
|
||||||
const rawSelected = Array.isArray(partial.channels?.selected)
|
const rawSelected = Array.isArray(partial.channels?.selected)
|
||||||
? partial.channels.selected.filter((value): value is OfficialChannelId => isOfficialChannelId(value))
|
? partial.channels.selected.filter((value): value is OfficialChannelId =>
|
||||||
|
isOfficialChannelId(value)
|
||||||
|
)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -806,16 +808,15 @@ function generateYamlWithComments(config: UnifiedConfig): string {
|
|||||||
lines.push('# Runtime-only: CCS injects --channels at launch for compatible Claude sessions.');
|
lines.push('# Runtime-only: CCS injects --channels at launch for compatible Claude sessions.');
|
||||||
lines.push('# Bot tokens live in Claude channel env files, not in config.yaml.');
|
lines.push('# Bot tokens live in Claude channel env files, not in config.yaml.');
|
||||||
lines.push('# Use selected: [telegram, discord, imessage] to choose channels.');
|
lines.push('# Use selected: [telegram, discord, imessage] to choose channels.');
|
||||||
lines.push('# unattended adds --dangerously-skip-permissions only when channel auto-enable is active.');
|
lines.push(
|
||||||
|
'# unattended adds --dangerously-skip-permissions only when channel auto-enable is active.'
|
||||||
|
);
|
||||||
lines.push('# Compatible sessions: native Claude default/account profiles only.');
|
lines.push('# Compatible sessions: native Claude default/account profiles only.');
|
||||||
lines.push('# Configure via: ccs config channels or the Settings > Channels dashboard tab.');
|
lines.push('# Configure via: ccs config channels or the Settings > Channels dashboard tab.');
|
||||||
lines.push('# ----------------------------------------------------------------------------');
|
lines.push('# ----------------------------------------------------------------------------');
|
||||||
lines.push(
|
lines.push(
|
||||||
yaml
|
yaml
|
||||||
.dump(
|
.dump({ channels: config.channels }, { indent: 2, lineWidth: -1, quotingType: '"' })
|
||||||
{ channels: config.channels },
|
|
||||||
{ indent: 2, lineWidth: -1, quotingType: '"' }
|
|
||||||
)
|
|
||||||
.trim()
|
.trim()
|
||||||
);
|
);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ router.put('/', (req: Request, res: Response): void => {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
selected !== undefined &&
|
selected !== undefined &&
|
||||||
(!Array.isArray(selected) || selected.some((value) => typeof value !== 'string' || !isOfficialChannelId(value)))
|
(!Array.isArray(selected) ||
|
||||||
|
selected.some((value) => typeof value !== 'string' || !isOfficialChannelId(value)))
|
||||||
) {
|
) {
|
||||||
res.status(400).json({ error: 'selected must be an array of official channel IDs' });
|
res.status(400).json({ error: 'selected must be an array of official channel IDs' });
|
||||||
return;
|
return;
|
||||||
@@ -84,7 +85,7 @@ router.put('/', (req: Request, res: Response): void => {
|
|||||||
try {
|
try {
|
||||||
const updated = mutateUnifiedConfig((config) => {
|
const updated = mutateUnifiedConfig((config) => {
|
||||||
config.channels = {
|
config.channels = {
|
||||||
selected: selected ? [...new Set(selected)] : config.channels?.selected ?? [],
|
selected: selected ? [...new Set(selected)] : (config.channels?.selected ?? []),
|
||||||
unattended: unattended ?? config.channels?.unattended ?? false,
|
unattended: unattended ?? config.channels?.unattended ?? false,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user