mirror of
https://github.com/tiennm99/ccs.git
synced 2026-08-07 00:23:05 +00:00
feat(channels): auto-enable official Claude channels
This commit is contained in:
@@ -1,7 +1,18 @@
|
||||
import * as fs from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
import { execFileSync, execSync } from 'child_process';
|
||||
import { expandPath } from './helpers';
|
||||
import { ClaudeCliInfo } from '../types';
|
||||
import type { ClaudeCliInfo } from '../types';
|
||||
import { escapeShellArg, stripAnthropicEnv, stripClaudeCodeEnv } from './shell-executor';
|
||||
|
||||
export interface ClaudeAuthStatus {
|
||||
loggedIn: boolean;
|
||||
authMethod?: string | null;
|
||||
apiProvider?: string | null;
|
||||
email?: string | null;
|
||||
orgId?: string | null;
|
||||
orgName?: string | null;
|
||||
subscriptionType?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Windows installation paths for Claude CLI
|
||||
@@ -127,6 +138,120 @@ export function getClaudeCliInfo(): ClaudeCliInfo | null {
|
||||
};
|
||||
}
|
||||
|
||||
function runClaudeCliCommand(args: string[], envOverrides?: NodeJS.ProcessEnv): string | null {
|
||||
const cliInfo = getClaudeCliInfo();
|
||||
if (!cliInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const env = stripClaudeCodeEnv(stripAnthropicEnv({ ...process.env, ...envOverrides }));
|
||||
const { path: claudePath, needsShell } = cliInfo;
|
||||
const isWindows = process.platform === 'win32';
|
||||
const isPowerShellScript = isWindows && /\.ps1$/i.test(claudePath);
|
||||
|
||||
try {
|
||||
if (isPowerShellScript) {
|
||||
return execFileSync(
|
||||
'powershell.exe',
|
||||
['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', claudePath, ...args],
|
||||
{
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
timeout: 5000,
|
||||
env,
|
||||
}
|
||||
).trim();
|
||||
}
|
||||
|
||||
if (needsShell) {
|
||||
return execSync([claudePath, ...args].map(escapeShellArg).join(' '), {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
timeout: 5000,
|
||||
shell: process.env.ComSpec || 'cmd.exe',
|
||||
env,
|
||||
}).trim();
|
||||
}
|
||||
|
||||
return execFileSync(claudePath, args, {
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
timeout: 5000,
|
||||
env,
|
||||
}).trim();
|
||||
} catch (error) {
|
||||
if (typeof error === 'object' && error !== null && 'stdout' in error) {
|
||||
const stdout = (error as { stdout?: string | Buffer | null }).stdout;
|
||||
if (typeof stdout === 'string') {
|
||||
const trimmed = stdout.trim();
|
||||
return trimmed.length > 0 ? trimmed : null;
|
||||
}
|
||||
if (Buffer.isBuffer(stdout)) {
|
||||
const trimmed = stdout.toString('utf8').trim();
|
||||
return trimmed.length > 0 ? trimmed : null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getClaudeCliVersion(): string | null {
|
||||
const output = runClaudeCliCommand(['--version']);
|
||||
const versionMatch = output?.match(/(\d+\.\d+\.\d+)/);
|
||||
return versionMatch ? versionMatch[1] : null;
|
||||
}
|
||||
|
||||
export function compareClaudeCliVersions(left: string, right: string): number {
|
||||
const leftParts = left.split('.').map((value) => Number.parseInt(value, 10) || 0);
|
||||
const rightParts = right.split('.').map((value) => Number.parseInt(value, 10) || 0);
|
||||
const maxLength = Math.max(leftParts.length, rightParts.length);
|
||||
|
||||
for (let index = 0; index < maxLength; index += 1) {
|
||||
const leftValue = leftParts[index] ?? 0;
|
||||
const rightValue = rightParts[index] ?? 0;
|
||||
|
||||
if (leftValue !== rightValue) {
|
||||
return leftValue > rightValue ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function isClaudeCliVersionAtLeast(
|
||||
currentVersion: string | null,
|
||||
minimumVersion: string
|
||||
): boolean {
|
||||
return currentVersion !== null && compareClaudeCliVersions(currentVersion, minimumVersion) >= 0;
|
||||
}
|
||||
|
||||
export function getClaudeAuthStatus(envOverrides?: NodeJS.ProcessEnv): ClaudeAuthStatus | null {
|
||||
const output = runClaudeCliCommand(['auth', 'status'], envOverrides);
|
||||
if (!output) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(output) as Partial<ClaudeAuthStatus>;
|
||||
if (typeof parsed.loggedIn !== 'boolean') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
loggedIn: parsed.loggedIn,
|
||||
authMethod: parsed.authMethod ?? null,
|
||||
apiProvider: parsed.apiProvider ?? null,
|
||||
email: parsed.email ?? null,
|
||||
orgId: parsed.orgId ?? null,
|
||||
orgName: parsed.orgName ?? null,
|
||||
subscriptionType: parsed.subscriptionType ?? null,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Claude not found error
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user