mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-14 22:17:20 +00:00
fix(profile): close km legacy kimi compatibility gaps
This commit is contained in:
1 parent
cf8070b5f0
commit
0bf00b23d9
9 files changed
+343
-66
No files matched your search
@@ -12,6 +12,16 @@ describe('provider-presets', () => {
|
||||
expect(preset?.id).toBe('km');
|
||||
});
|
||||
|
||||
it('resolves preset id with extra whitespace', () => {
|
||||
const preset = getPresetById(' km ');
|
||||
expect(preset?.id).toBe('km');
|
||||
});
|
||||
|
||||
it('resolves uppercase legacy alias', () => {
|
||||
const preset = getPresetById('KIMI');
|
||||
expect(preset?.id).toBe('km');
|
||||
});
|
||||
|
||||
it('treats legacy kimi alias as a valid preset id', () => {
|
||||
expect(isValidPresetId('kimi')).toBe(true);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { loadMigrationCheckData, migrate } from '../../../src/config/migration-manager';
|
||||
import { saveUnifiedConfig } from '../../../src/config/unified-config-loader';
|
||||
import { createEmptyUnifiedConfig } from '../../../src/config/unified-config-types';
|
||||
|
||||
describe('migration-manager legacy kimi compatibility', () => {
|
||||
let tempHome: string;
|
||||
let ccsDir: string;
|
||||
let originalCcsHome: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-migration-manager-test-'));
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
process.env.CCS_HOME = tempHome;
|
||||
ccsDir = path.join(tempHome, '.ccs');
|
||||
fs.mkdirSync(ccsDir, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalCcsHome !== undefined) {
|
||||
process.env.CCS_HOME = originalCcsHome;
|
||||
} else {
|
||||
delete process.env.CCS_HOME;
|
||||
}
|
||||
|
||||
if (fs.existsSync(tempHome)) {
|
||||
fs.rmSync(tempHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('prefers explicit canonical km profile over legacy kimi when both exist', async () => {
|
||||
const kmSettingsPath = path.join(ccsDir, 'km.settings.json');
|
||||
const kimiSettingsPath = path.join(ccsDir, 'kimi.settings.json');
|
||||
|
||||
fs.writeFileSync(kmSettingsPath, JSON.stringify({ env: { ANTHROPIC_AUTH_TOKEN: 'sk-km' } }));
|
||||
fs.writeFileSync(
|
||||
kimiSettingsPath,
|
||||
JSON.stringify({ env: { ANTHROPIC_AUTH_TOKEN: 'sk-kimi' } })
|
||||
);
|
||||
|
||||
// Intentionally place legacy alias first to verify deterministic behavior.
|
||||
fs.writeFileSync(
|
||||
path.join(ccsDir, 'config.json'),
|
||||
JSON.stringify(
|
||||
{
|
||||
profiles: {
|
||||
kimi: kimiSettingsPath,
|
||||
km: kmSettingsPath,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
const result = await migrate(true);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(
|
||||
result.migratedFiles.some((entry) =>
|
||||
entry.includes(`config.json.profiles.km → config.yaml.profiles.km (settings: ${kmSettingsPath})`)
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
result.migratedFiles.some((entry) =>
|
||||
entry.includes(`(settings: ${kimiSettingsPath})`)
|
||||
)
|
||||
).toBe(false);
|
||||
expect(
|
||||
result.warnings.some((warning) =>
|
||||
warning.includes(
|
||||
'Skipped kimi: canonical profile "km" exists in config.json with different settings'
|
||||
)
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('renames case-variant legacy Kimi profile key to km', async () => {
|
||||
const kimiSettingsPath = path.join(ccsDir, 'kimi.settings.json');
|
||||
fs.writeFileSync(
|
||||
kimiSettingsPath,
|
||||
JSON.stringify({ env: { ANTHROPIC_AUTH_TOKEN: 'sk-kimi-case-variant' } })
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(ccsDir, 'config.json'),
|
||||
JSON.stringify(
|
||||
{
|
||||
profiles: {
|
||||
Kimi: kimiSettingsPath,
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
const result = await migrate(true);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(
|
||||
result.migratedFiles.some((entry) =>
|
||||
entry.includes('config.json.profiles.Kimi → config.yaml.profiles.km')
|
||||
)
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('treats legacy kimi profile as migrated when unified config already has km', () => {
|
||||
const unifiedConfig = createEmptyUnifiedConfig();
|
||||
unifiedConfig.profiles.km = {
|
||||
type: 'api',
|
||||
settings: '~/.ccs/km.settings.json',
|
||||
};
|
||||
saveUnifiedConfig(unifiedConfig);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(ccsDir, 'config.json'),
|
||||
JSON.stringify(
|
||||
{
|
||||
profiles: {
|
||||
kimi: '~/.ccs/kimi.settings.json',
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
const checkData = loadMigrationCheckData();
|
||||
expect(checkData.needsMigration).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
import { getProfileLookupCandidates, isLegacyProfileAlias } from '../../../src/utils/profile-compat';
|
||||
import {
|
||||
getProfileLookupCandidates,
|
||||
isLegacyProfileAlias,
|
||||
resolveAliasToCanonical,
|
||||
} from '../../../src/utils/profile-compat';
|
||||
|
||||
describe('profile-compat', () => {
|
||||
describe('getProfileLookupCandidates', () => {
|
||||
@@ -14,6 +18,15 @@ describe('profile-compat', () => {
|
||||
it('normalizes uppercase input and still resolves aliases', () => {
|
||||
expect(getProfileLookupCandidates('KM')).toEqual(['KM', 'km', 'kimi']);
|
||||
});
|
||||
|
||||
it('handles surrounding whitespace', () => {
|
||||
expect(getProfileLookupCandidates(' km ')).toEqual(['km', 'kimi']);
|
||||
});
|
||||
|
||||
it('returns empty candidates for empty input', () => {
|
||||
expect(getProfileLookupCandidates('')).toEqual([]);
|
||||
expect(getProfileLookupCandidates(' ')).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isLegacyProfileAlias', () => {
|
||||
@@ -30,4 +43,16 @@ describe('profile-compat', () => {
|
||||
expect(isLegacyProfileAlias('glm', 'kimi')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveAliasToCanonical', () => {
|
||||
it('maps legacy kimi alias to canonical km', () => {
|
||||
expect(resolveAliasToCanonical('kimi')).toBe('km');
|
||||
expect(resolveAliasToCanonical('KIMI')).toBe('km');
|
||||
});
|
||||
|
||||
it('keeps canonical and non-aliased names', () => {
|
||||
expect(resolveAliasToCanonical('km')).toBe('km');
|
||||
expect(resolveAliasToCanonical('glm')).toBe('glm');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import { checkSettingsFiles } from '../../../src/web-server/health/config-checks';
|
||||
|
||||
describe('web-server config-checks settings compatibility', () => {
|
||||
let tempHome: string;
|
||||
let ccsDir: string;
|
||||
let originalCcsHome: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-config-checks-test-'));
|
||||
originalCcsHome = process.env.CCS_HOME;
|
||||
process.env.CCS_HOME = tempHome;
|
||||
ccsDir = path.join(tempHome, '.ccs');
|
||||
fs.mkdirSync(ccsDir, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (originalCcsHome !== undefined) {
|
||||
process.env.CCS_HOME = originalCcsHome;
|
||||
} else {
|
||||
delete process.env.CCS_HOME;
|
||||
}
|
||||
|
||||
if (fs.existsSync(tempHome)) {
|
||||
fs.rmSync(tempHome, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('reports km as configured when only legacy kimi.settings.json exists', () => {
|
||||
fs.writeFileSync(
|
||||
path.join(ccsDir, 'kimi.settings.json'),
|
||||
JSON.stringify({
|
||||
env: {
|
||||
ANTHROPIC_AUTH_TOKEN: 'sk-live-kimi-compat',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const checks = checkSettingsFiles(ccsDir);
|
||||
const kmCheck = checks.find((check) => check.id === 'settings-km');
|
||||
|
||||
expect(kmCheck).toBeDefined();
|
||||
expect(kmCheck?.status).toBe('ok');
|
||||
expect(kmCheck?.name).toBe('kimi.settings.json');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user