Ctrl K
ComunidadGuías…

test/cc-compat.test.js

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { describe, it, beforeEach } from 'node:test';
import assert from 'node:assert/strict';
import {
  detectClaudeCodeClient,
  resolveCcCompat,
  stripCcNamespace,
  isClaudeCode,
  recordSchemaNormalized,
  recordIdentityNeutralized,
  getCcCompatStats,
  resetCcCompatStats,
  CC_CONTENT_MARKERS,
} from '../src/handlers/cc-compat.js';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';

const __root = join(dirname(fileURLToPath(import.meta.url)), '..');

// cc-compat is the standalone, pluggable Claude Code compatibility layer. It
// never changes standard behavior unless a request is explicitly routed through
// /v1/cc/* (endpoint opt-in) or detected as Claude Code with the master toggle
// on. Claude Code defaults to the Anthropic protocol (/v1/messages).

describe('detectClaudeCodeClient', () => {
  it('detects Claude Code by the claude-cli User-Agent', () => {
    assert.equal(detectClaudeCodeClient({ 'user-agent': 'claude-cli/2.1.77 (external, cli)' }), true);
    assert.equal(detectClaudeCodeClient({ 'user-agent': 'claude-code/2.1.77 (cli)' }), true);
    assert.equal(detectClaudeCodeClient({ 'User-Agent': 'CLAUDE-CLI/1.0' }), true);
  });

  it('detects by the gateway session-id header', () => {
    assert.equal(detectClaudeCodeClient({ 'x-claude-code-session-id': 'sess_abc' }), true);
  });

  it('x-app:cli counts ONLY when paired with a claude UA (too broad alone)', () => {
    // Gemini CLI / Codex CLI also send x-app:cli, so it must not fire on its own.
    assert.equal(detectClaudeCodeClient({ 'x-app': 'cli' }), false);
    assert.equal(detectClaudeCodeClient({ 'x-app': 'CLI' }), false);
    // Paired with a claude-mentioning UA it becomes a valid combined signal.
    assert.equal(detectClaudeCodeClient({ 'x-app': 'cli', 'user-agent': 'claude/2.1' }), true);
  });

  it('does not misfire on other clients (incl. Cline, curl, browsers, other CLIs)', () => {
    assert.equal(detectClaudeCodeClient({ 'user-agent': 'Cline/3.2.0' }), false);
    assert.equal(detectClaudeCodeClient({ 'user-agent': 'curl/8.4.0' }), false);
    assert.equal(detectClaudeCodeClient({ 'user-agent': 'Mozilla/5.0' }), false);
    // "claude" alone (e.g. an unrelated UA mentioning it) must not match — we
    // require the claude-cli/ or claude-code/ prefix with a version slash.
    assert.equal(detectClaudeCodeClient({ 'user-agent': 'my-claude-wrapper/1.0' }), false);
    // A different CLI client sending x-app:cli without a claude UA must not match.
    assert.equal(detectClaudeCodeClient({ 'x-app': 'cli', 'user-agent': 'gemini-cli/1.0' }), false);
    assert.equal(detectClaudeCodeClient({ 'x-app': 'web' }), false);
    assert.equal(detectClaudeCodeClient({ 'user-agent': '' }), false);
    assert.equal(detectClaudeCodeClient({}), false);
    assert.equal(detectClaudeCodeClient(null), false);
  });
});

describe('resolveCcCompat', () => {
  it('endpoint path is active even when master toggle is OFF (explicit opt-in namespace)', () => {
    const r = resolveCcCompat({ path: '/v1/cc/messages', headers: {}, masterEnabled: false });
    assert.equal(r.active, true);
    assert.equal(r.source, 'endpoint');
  });

  it('standard path with master OFF and non-CC UA is inactive (byte-identical)', () => {
    const r = resolveCcCompat({ path: '/v1/messages', headers: { 'user-agent': 'curl' }, masterEnabled: false });
    assert.equal(r.active, false);
    assert.equal(r.source, null);
  });

  it('detection path requires master ON', () => {
    const ua = { 'user-agent': 'claude-cli/2.1.77 (external, cli)' };
    const off = resolveCcCompat({ path: '/v1/messages', headers: ua, masterEnabled: false });
    assert.equal(off.active, false);
    const on = resolveCcCompat({ path: '/v1/messages', headers: ua, masterEnabled: true });
    assert.equal(on.active, true);
    assert.equal(on.source, 'detect');
  });

  it('master ON but non-CC client on standard path stays inactive (no blanket change)', () => {
    const r = resolveCcCompat({ path: '/v1/messages', headers: { 'user-agent': 'curl' }, masterEnabled: true });
    assert.equal(r.active, false);
  });

  it('endpoint source takes priority over detect (namespace wins)', () => {
    const r = resolveCcCompat({ path: '/v1/cc/messages', headers: { 'user-agent': 'claude-cli/2.1' }, masterEnabled: true });
    assert.equal(r.source, 'endpoint');
  });
});

describe('stripCcNamespace', () => {
  it('rewrites /v1/cc/* to canonical /v1/*', () => {
    assert.equal(stripCcNamespace('/v1/cc/messages'), '/v1/messages');
    assert.equal(stripCcNamespace('/v1/cc/messages/count_tokens'), '/v1/messages/count_tokens');
    assert.equal(stripCcNamespace('/v1/cc/chat/completions'), '/v1/chat/completions');
    assert.equal(stripCcNamespace('/v1/cc/models'), '/v1/models');
  });
  it('leaves non-cc paths unchanged', () => {
    assert.equal(stripCcNamespace('/v1/messages'), '/v1/messages');
    assert.equal(stripCcNamespace('/v1/cline/chat/completions'), '/v1/cline/chat/completions');
    assert.equal(stripCcNamespace('/dashboard/api/x'), '/dashboard/api/x');
  });
});

describe('isClaudeCode — single consolidated signal', () => {
  it('matches on body.metadata.user_id CC wire shape — string form (highest confidence)', () => {
    const body = { metadata: { user_id: 'user_deadbeef_account_1111-2222_session_abcd-ef01' } };
    assert.equal(isClaudeCode({ headers: {}, body }), true);
  });

  it('matches on body.metadata.user_id object form { account_uuid, session_id }', () => {
    const body = { metadata: { user_id: { device_id: 'd', account_uuid: 'a', session_id: 's' } } };
    assert.equal(isClaudeCode({ headers: {}, body }), true);
    const camel = { metadata: { user_id: { accountUuid: 'a', sessionId: 's' } } };
    assert.equal(isClaudeCode({ headers: {}, body: camel }), true);
  });

  it('requires BOTH account_ AND session_ in the string form (half-match is not enough)', () => {
    // Guards the AND contract: a bare opaque id with only one segment must not
    // be mistaken for the CC wire shape.
    assert.equal(isClaudeCode({ headers: {}, body: { metadata: { user_id: 'user_x_session_y' } } }), false);
    assert.equal(isClaudeCode({ headers: {}, body: { metadata: { user_id: 'user_x_account_y' } } }), false);
    // Object form missing one field also must not match.
    assert.equal(isClaudeCode({ headers: {}, body: { metadata: { user_id: { session_id: 's' } } } }), false);
  });

  it('matches on headers when no metadata present', () => {
    assert.equal(isClaudeCode({ headers: { 'user-agent': 'claude-cli/2.1.77 (external, cli)' }, body: {} }), true);
  });

  it('matches on system-prompt content fingerprint as a fallback', () => {
    const body = { system: "You are Claude Code, Anthropic's official CLI for Claude." };
    assert.equal(isClaudeCode({ headers: {}, body }), true);
    const arr = { system: [{ type: 'text', text: 'blah cc_version=2.1.77 blah' }] };
    assert.equal(isClaudeCode({ headers: {}, body: arr }), true);
  });

  it('does not match unrelated requests', () => {
    assert.equal(isClaudeCode({ headers: { 'user-agent': 'curl' }, body: { system: 'You are a helpful assistant.' } }), false);
    assert.equal(isClaudeCode({ headers: {}, body: { metadata: { user_id: 'plain-string' } } }), false);
    assert.equal(isClaudeCode({ headers: {}, body: null }), false);
    assert.equal(isClaudeCode({}), false);
  });
});

describe('CC_CONTENT_MARKERS — single source of truth (no drift with client.js)', () => {
  it('client.js imports the shared constant instead of an inline copy', () => {
    // The whole point of this module is to kill the divergent "is this CC?"
    // heuristics. Assert client.js references CC_CONTENT_MARKERS and no longer
    // carries its own inline Anthropic-CLI regex literal.
    const clientSrc = readFileSync(join(__root, 'src/client.js'), 'utf8');
    assert.match(clientSrc, /CC_CONTENT_MARKERS/, 'client.js must import/use the shared marker');
    assert.doesNotMatch(
      clientSrc,
      /\/Anthropic's official CLI for Claude\|Claude Code\|cc_version=/,
      'client.js must not keep its own inline copy of the marker regex',
    );
  });

  it('covers every historical Claude Code marker (case-insensitive)', () => {
    for (const s of [
      "You are Claude Code, Anthropic's official CLI for Claude.",
      'ANTHROPIC\'S OFFICIAL CLI FOR CLAUDE',
      'blah Claude Code blah',
      'cc_version=2.1.77',
      'a content_block here',
      'a tool_use block',
      '<env>cwd: /x</env>',
    ]) {
      assert.ok(CC_CONTENT_MARKERS.test(s), `marker regex should match: ${s}`);
    }
    assert.equal(CC_CONTENT_MARKERS.test('You are a helpful assistant.'), false);
  });
});

describe('cc-compat stats', () => {
  beforeEach(() => resetCcCompatStats());

  it('counts schema normalizations and identity neutralizations independently', () => {
    assert.deepEqual(getCcCompatStats(), {
      schemaNormalized: 0,
      identityNeutralized: 0,
      toolDeferLoadingHonored: 0,
      toolDeferLoadingIgnored: 0,
    });
    recordSchemaNormalized();
    recordSchemaNormalized();
    recordIdentityNeutralized();
    assert.deepEqual(getCcCompatStats(), {
      schemaNormalized: 2,
      identityNeutralized: 1,
      toolDeferLoadingHonored: 0,
      toolDeferLoadingIgnored: 0,
    });
  });
});