feat(targets): support CCS_DROID_ALIASES argv0 mapping

- extend argv[0] target resolution with env-configurable aliases

- normalize alias matching to lowercase with safe-name filtering

- add tests for custom aliases, invalid entries, and case-insensitivity
This commit is contained in:
Tam Nhu Tran committed 2026-02-17 20:53:03 +07:00
1 parent 15d6c06dbc
commit 025218a706
2 files changed
+46 -2

No files matched your search

+22 -2
View File
@@ -18,6 +18,25 @@ import { TargetType } from './target-adapter';
const ARGV0_TARGET_MAP: Record<string, TargetType> = { const ARGV0_TARGET_MAP: Record<string, TargetType> = {
ccsd: 'droid', ccsd: 'droid',
}; };
const ALIAS_NAME_REGEX = /^[a-z0-9._-]+$/;
function buildArgv0TargetMap(): Record<string, TargetType> {
const map: Record<string, TargetType> = { ...ARGV0_TARGET_MAP };
const envAliases = process.env['CCS_DROID_ALIASES'];
if (!envAliases) {
return map;
}
for (const rawAlias of envAliases.split(',')) {
const alias = rawAlias.trim().toLowerCase();
if (!alias || !ALIAS_NAME_REGEX.test(alias)) {
continue;
}
map[alias] = 'droid';
}
return map;
}
/** /**
* Valid target types for --target flag validation. * Valid target types for --target flag validation.
@@ -108,8 +127,9 @@ export function resolveTargetType(
// 3. Check argv[0] (busybox pattern) // 3. Check argv[0] (busybox pattern)
// Strip common wrapper extensions for Windows shims/wrappers // Strip common wrapper extensions for Windows shims/wrappers
const rawBin = path.basename(process.argv[1] || process.argv0 || ''); const rawBin = path.basename(process.argv[1] || process.argv0 || '');
const binName = rawBin.replace(/\.(cmd|bat|ps1|exe)$/i, ''); const binName = rawBin.replace(/\.(cmd|bat|ps1|exe)$/i, '').toLowerCase();
const argv0Target = ARGV0_TARGET_MAP[binName]; const argv0TargetMap = buildArgv0TargetMap();
const argv0Target = argv0TargetMap[binName];
if (argv0Target) { if (argv0Target) {
return argv0Target; return argv0Target;
} }
@@ -6,9 +6,15 @@ import { resolveTargetType, stripTargetFlag } from '../../../src/targets/target-
describe('resolveTargetType', () => { describe('resolveTargetType', () => {
const originalArgv = process.argv; const originalArgv = process.argv;
const originalDroidAliases = process.env.CCS_DROID_ALIASES;
afterEach(() => { afterEach(() => {
process.argv = originalArgv; process.argv = originalArgv;
if (originalDroidAliases === undefined) {
delete process.env.CCS_DROID_ALIASES;
} else {
process.env.CCS_DROID_ALIASES = originalDroidAliases;
}
}); });
it('should return claude as default', () => { it('should return claude as default', () => {
@@ -41,6 +47,24 @@ describe('resolveTargetType', () => {
expect(resolveTargetType([])).toBe('droid'); expect(resolveTargetType([])).toBe('droid');
}); });
it('should detect custom argv[0] aliases from CCS_DROID_ALIASES', () => {
process.env.CCS_DROID_ALIASES = 'droidx,my-droid';
process.argv = ['node', 'my-droid'];
expect(resolveTargetType([])).toBe('droid');
});
it('should ignore invalid custom alias entries', () => {
process.env.CCS_DROID_ALIASES = 'valid_alias,../bad,';
process.argv = ['node', '../bad'];
expect(resolveTargetType([])).toBe('claude');
});
it('should normalize argv[0] and custom aliases case-insensitively', () => {
process.env.CCS_DROID_ALIASES = 'DroidCaps';
process.argv = ['node', 'DROIDCAPS'];
expect(resolveTargetType([])).toBe('droid');
});
it('should strip .cmd extension on Windows argv[0]', () => { it('should strip .cmd extension on Windows argv[0]', () => {
process.argv = ['node', 'ccsd.cmd']; process.argv = ['node', 'ccsd.cmd'];
expect(resolveTargetType([])).toBe('droid'); expect(resolveTargetType([])).toBe('droid');