feat: 添加 Provider Registry、StatusLine、Cache Stats 和其他增强

- providerRegistry: OpenAI 兼容 provider 切换(Cerebras/Groq/DeepSeek/Qwen)
- StatusLine: 增强状态栏(缓存命中率、TTL 倒计时、自定义 shell 命令)
- cacheStats: 缓存命中率和 token 签名追踪
- ultrareviewPreflight: 代码审查预检服务
- SkillsMenu/filterSkills: 技能菜单过滤增强
- MagicDocs/langfuse prompts: 提示词更新
- claude.ts: API 客户端更新

Co-Authored-By: glm-5-turbo <zai-org@claude-code-best.win>
This commit is contained in:
claude-code-best
2026-05-09 23:04:35 +08:00
parent fdddb6dbe8
commit efaf4afd9c
28 changed files with 3613 additions and 219 deletions

View File

@@ -0,0 +1,56 @@
import React, { useCallback, useRef, useState } from 'react';
import { Box, Dialog, Text } from '@anthropic/ink';
import { Select } from '../../components/CustomSelect/select.js';
type Props = {
billingNote: string | null;
onConfirm: (signal: AbortSignal) => Promise<void>;
onCancel: () => void;
};
/**
* Dialog shown when /v1/ultrareview/preflight returns action='confirm'.
* Displays the server-provided billing_note (or a generic fallback) and
* gives the user a Proceed / Cancel choice.
*/
export function UltrareviewPreflightDialog({ billingNote, onConfirm, onCancel }: Props): React.ReactNode {
const [isLaunching, setIsLaunching] = useState(false);
const abortControllerRef = useRef(new AbortController());
const handleSelect = useCallback(
(value: string) => {
if (value === 'proceed') {
setIsLaunching(true);
void onConfirm(abortControllerRef.current.signal).catch(() => setIsLaunching(false));
} else {
onCancel();
}
},
[onConfirm, onCancel],
);
const handleCancel = useCallback(() => {
abortControllerRef.current.abort();
onCancel();
}, [onCancel]);
const options = [
{ label: 'Proceed', value: 'proceed' },
{ label: 'Cancel', value: 'cancel' },
];
const displayNote = billingNote ?? 'This run may incur additional cost.';
return (
<Dialog title="Ultrareview — additional cost" onCancel={handleCancel} color="background">
<Box flexDirection="column" gap={1}>
<Text>{displayNote}</Text>
{isLaunching ? (
<Text color="background">Launching</Text>
) : (
<Select options={options} onChange={handleSelect} onCancel={handleCancel} />
)}
</Box>
</Dialog>
);
}

View File

@@ -0,0 +1,312 @@
/**
* Regression tests for `ultrareviewCommand.call` (src/commands/review/
* ultrareviewCommand.tsx). The previous version of `call` made an axios
* preflight POST and branched on `action: proceed | blocked | confirm`;
* that integration was removed and `call` now branches on `checkOverageGate()`'s
* four `kind` values: `not-enabled`, `low-balance`, `needs-confirm`, `proceed`.
*
* These tests verify each branch:
* - `proceed` → forwards billingNote and args to `launchRemoteReview`,
* calls `onDone(text)`, returns null
* - `not-enabled` → onDone with paywall message + `display: 'system'`,
* returns null, does NOT launch
* - `low-balance` → onDone with balance-too-low message including the
* available amount, returns null, does NOT launch
* - `needs-confirm` → returns the React `UltrareviewOverageDialog` element,
* does NOT call onDone, does NOT launch
* - `proceed` + null launch result → onDone with "failed to launch" message
* - `proceed` + arg pass-through → args (e.g. PR number) reach launchRemoteReview
* verbatim (call doesn't parse them itself)
*/
import { afterAll, beforeEach, describe, expect, mock, test } from 'bun:test';
import { debugMock } from '../../../../tests/mocks/debug.js';
import { logMock } from '../../../../tests/mocks/log.js';
import { setupAxiosMock } from '../../../../tests/mocks/axios.js';
// Pre-import the real react and ink modules so we can delegate after this
// suite. Bun's mock.module is process-global / last-write-wins; without
// delegation the stub createElement / stub ink components leak into other
// test files (e.g. SnapshotUpdateDialog.test.tsx, AgentsPlatformView.test.tsx)
// that need real React.createElement and real Box/Text components.
const _realReactMod = (await import('react')) as Record<string, unknown> & {
default?: Record<string, unknown>;
};
const _realInkMod = (await import('@anthropic/ink')) as Record<string, unknown>;
let _useStubReactForUltrareview = true;
let _useStubInkForUltrareview = true;
afterAll(() => {
_useStubReactForUltrareview = false;
_useStubInkForUltrareview = false;
// The handle reference exists by the time afterAll runs (TDZ resolves via
// closure). Flip useStubs off so the spread-real fall-through kicks in for
// any test file that runs after this one in the same process.
_ultrareviewAxiosHandle.useStubs = false;
});
// Mock dependency chain before any subject import
mock.module('src/utils/debug.ts', debugMock);
mock.module('src/utils/log.ts', logMock);
mock.module('src/services/analytics/index.js', () => ({
logEvent: () => {},
}));
mock.module('src/services/analytics/growthbook.js', () => ({
getFeatureValue_CACHED_MAY_BE_STALE: () => null,
}));
// Mock auth utilities
mock.module('src/utils/auth.js', () => ({
isClaudeAISubscriber: () => true,
isTeamSubscriber: () => false,
isEnterpriseSubscriber: () => false,
}));
// Mock checkOverageGate with a mutable gate result so each test can drive
// the four branches in ultrareviewCommand.call (not-enabled, low-balance,
// needs-confirm, proceed). launchRemoteReview captures args for the
// args-forwarding test, and its return value is mutable too — `null` triggers
// the "failed to launch" onDone branch.
type GateResult =
| { kind: 'proceed'; billingNote: string }
| { kind: 'not-enabled' }
| { kind: 'low-balance'; available: number }
| { kind: 'needs-confirm' };
let _gateResult: GateResult = { kind: 'proceed', billingNote: '' };
let _launchResult: Array<{ type: 'text'; text: string }> | null = [{ type: 'text', text: 'Launched successfully.' }];
const _capturedLaunchArgs: string[] = [];
mock.module('src/commands/review/reviewRemote.js', () => ({
checkOverageGate: async () => _gateResult,
confirmOverage: () => {},
launchRemoteReview: async (args: string) => {
_capturedLaunchArgs.push(args);
return _launchResult;
},
}));
// Mock OAuth config so real fetchUltrareviewPreflight can run
mock.module('src/constants/oauth.js', () => ({
getOauthConfig: () => ({ BASE_API_URL: 'https://api.anthropic.com' }),
}));
// Mock prepareApiRequest so real fetchUltrareviewPreflight skips auth
mock.module('src/utils/teleport/api.js', () => ({
prepareApiRequest: async () => ({
accessToken: 'test-token',
orgUUID: 'org-uuid-test',
}),
getOAuthHeaders: (token: string) => ({
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
'anthropic-version': '2023-06-01',
}),
}));
// Mock axios — per-test responses set via mockAxiosPost.mockImplementationOnce
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const mockAxiosPost = mock(
async (..._args: any[]): Promise<any> => ({
status: 200,
data: { action: 'proceed', billing_note: null },
}),
);
// Spread real axios + flag-gate stubs so the per-test mockAxiosPost stops
// leaking into later test files (mock.module is process-global). Default ON
// for this suite; afterAll above flips _useStubReactForUltrareview, but here
// we tie axios cleanup to the helper's own flag — see suite-level afterAll.
const _ultrareviewAxiosHandle = setupAxiosMock();
_ultrareviewAxiosHandle.useStubs = true;
_ultrareviewAxiosHandle.stubs.post = mockAxiosPost;
_ultrareviewAxiosHandle.stubs.isAxiosError = (e: unknown) =>
typeof e === 'object' && e !== null && (e as { isAxiosError?: boolean }).isAxiosError === true;
// Mock detectCurrentRepositoryWithHost
mock.module('src/utils/detectRepository.js', () => ({
detectCurrentRepositoryWithHost: async () => ({
host: 'github.com',
owner: 'testowner',
name: 'testrepo',
}),
}));
// Minimal mock for React/Ink so we don't need a full renderer.
// Preserve any explicit `children` prop when no varargs children are passed
// — otherwise consumers who pass `children` via the props object (e.g.
// SnapshotUpdateDialog.ts uses `React.createElement(Dialog, { ..., children })`)
// see their array overwritten with `[]`. mock.module is process-global so this
// mock survives into other test files in the same run; afterAll flips the flag
// so we delegate to real React thereafter.
mock.module('react', () => {
const stubCreateElement = (type: unknown, props: unknown, ...children: unknown[]) => {
const propsObj = (props ?? {}) as Record<string, unknown>;
const finalChildren = children.length > 0 ? children : 'children' in propsObj ? propsObj.children : [];
return {
$$typeof: Symbol.for('react.element'),
type,
props: { ...propsObj, children: finalChildren },
};
};
const realCreate = ((_realReactMod.default as Record<string, unknown> | undefined)?.createElement ??
_realReactMod.createElement) as (...args: unknown[]) => unknown;
const createElement = (...args: unknown[]) =>
_useStubReactForUltrareview ? stubCreateElement(args[0], args[1], ...args.slice(2)) : realCreate(...args);
return {
..._realReactMod,
default: {
...((_realReactMod.default as Record<string, unknown> | undefined) ?? {}),
createElement,
},
createElement,
};
});
// Spread real ink + flag-gate the stub components. Without spread, the bare
// { Box: 'Box', Dialog: 'Dialog', Text: 'Text' } leaks into every later test
// file (e.g. AgentsPlatformView.test.tsx) that imports @anthropic/ink — those
// consumers receive strings instead of real components and rendering breaks.
mock.module('@anthropic/ink', () => {
if (_useStubInkForUltrareview) {
return {
..._realInkMod,
Box: 'Box',
Dialog: 'Dialog',
Text: 'Text',
};
}
return _realInkMod;
});
mock.module('src/components/CustomSelect/select.js', () => ({
Select: 'Select',
}));
// UltrareviewOverageDialog and PreflightDialog — return a simple marker
mock.module('src/commands/review/UltrareviewOverageDialog.js', () => ({
UltrareviewOverageDialog: () => ({ type: 'UltrareviewOverageDialog' }),
}));
mock.module('src/commands/review/UltrareviewPreflightDialog.js', () => ({
UltrareviewPreflightDialog: () => ({ type: 'UltrareviewPreflightDialog' }),
}));
import { call } from '../ultrareviewCommand.js';
const makeContext = () =>
({
abortController: { signal: {} },
}) as Parameters<typeof call>[1];
describe('ultrareviewCommand.call: gate branches', () => {
// Reset gate + launch state between tests so a previous test's mutation
// doesn't leak into the next.
beforeEach(() => {
_gateResult = { kind: 'proceed', billingNote: '' };
_launchResult = [{ type: 'text', text: 'Launched successfully.' }];
_capturedLaunchArgs.length = 0;
});
test('proceed gate: forwards billingNote to launchRemoteReview, calls onDone, returns null', async () => {
_gateResult = { kind: 'proceed', billingNote: ' Free review 1 of 5.' };
const messages: string[] = [];
const onDone = (msg: string) => messages.push(msg);
const result = await call(onDone as Parameters<typeof call>[0], makeContext(), '');
expect(result).toBeNull();
expect(messages.length).toBe(1);
expect(messages[0]).toContain('Launched successfully');
// launchRemoteReview was invoked exactly once with the empty args.
expect(_capturedLaunchArgs).toEqual(['']);
});
test('not-enabled gate: onDone with paywall message, returns null', async () => {
_gateResult = { kind: 'not-enabled' };
const messages: string[] = [];
const opts: Array<unknown> = [];
const onDone = (msg: string, opt: unknown) => {
messages.push(msg);
opts.push(opt);
};
const result = await call(onDone as Parameters<typeof call>[0], makeContext(), '');
expect(result).toBeNull();
expect(messages).toHaveLength(1);
expect(messages[0]).toContain('Free ultrareviews used');
expect(messages[0]).toContain('claude.ai/settings/billing');
expect((opts[0] as { display: string }).display).toBe('system');
// launchRemoteReview must NOT be called when paywalled.
expect(_capturedLaunchArgs).toEqual([]);
});
test('low-balance gate: onDone with balance-too-low message including available amount, returns null', async () => {
_gateResult = { kind: 'low-balance', available: 4.5 };
const messages: string[] = [];
const opts: Array<unknown> = [];
const onDone = (msg: string, opt: unknown) => {
messages.push(msg);
opts.push(opt);
};
const result = await call(onDone as Parameters<typeof call>[0], makeContext(), '');
expect(result).toBeNull();
expect(messages).toHaveLength(1);
expect(messages[0]).toContain('Balance too low');
expect(messages[0]).toContain('$4.50');
expect(messages[0]).toContain('claude.ai/settings/billing');
expect((opts[0] as { display: string }).display).toBe('system');
expect(_capturedLaunchArgs).toEqual([]);
});
test('needs-confirm gate: returns UltrareviewOverageDialog React element, does not launch', async () => {
_gateResult = { kind: 'needs-confirm' };
const messages: string[] = [];
const onDone = (msg: string) => messages.push(msg);
const result = await call(onDone as Parameters<typeof call>[0], makeContext(), '');
// Returns a React element rather than null.
expect(result).not.toBeNull();
expect(typeof result).toBe('object');
const element = result as { type: unknown };
expect(element.type).toBeDefined();
// No onDone call until the user interacts with the dialog.
expect(messages).toEqual([]);
expect(_capturedLaunchArgs).toEqual([]);
});
test('proceed gate + launchRemoteReview returns null: onDone with failure message', async () => {
_gateResult = { kind: 'proceed', billingNote: '' };
_launchResult = null; // teleport / non-github failure path
const messages: string[] = [];
const opts: Array<unknown> = [];
const onDone = (msg: string, opt: unknown) => {
messages.push(msg);
opts.push(opt);
};
const result = await call(onDone as Parameters<typeof call>[0], makeContext(), '');
expect(result).toBeNull();
expect(messages).toHaveLength(1);
expect(messages[0]).toContain('Ultrareview failed to launch');
expect((opts[0] as { display: string }).display).toBe('system');
});
test('proceed gate: forwards args (e.g. PR number) verbatim to launchRemoteReview', async () => {
_gateResult = { kind: 'proceed', billingNote: '' };
const messages: string[] = [];
const onDone = (msg: string) => messages.push(msg);
await call(onDone as Parameters<typeof call>[0], makeContext(), '42');
// ultrareviewCommand.call doesn't parse args itself — launchRemoteReview
// is responsible for PR-number detection. So we only assert pass-through.
expect(_capturedLaunchArgs).toEqual(['42']);
});
});