clauderipple 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +229 -0
- package/LICENSE +674 -0
- package/README.ko.md +328 -0
- package/README.md +372 -0
- package/bin/clauderipple.js +12 -0
- package/dist/app/assets/trayDownTemplate.png +0 -0
- package/dist/app/assets/trayDownTemplate@2x.png +0 -0
- package/dist/app/assets/trayTemplate.png +0 -0
- package/dist/app/assets/trayTemplate@2x.png +0 -0
- package/dist/app/assets/trayWarnTemplate.png +0 -0
- package/dist/app/assets/trayWarnTemplate@2x.png +0 -0
- package/dist/app/assets/trayWin.png +0 -0
- package/dist/app/assets/trayWin@2x.png +0 -0
- package/dist/app/assets/trayWinDown.png +0 -0
- package/dist/app/assets/trayWinDown@2x.png +0 -0
- package/dist/app/assets/trayWinWarn.png +0 -0
- package/dist/app/assets/trayWinWarn@2x.png +0 -0
- package/dist/app/dist/main.js +518 -0
- package/dist/cli/src/browser.js +21 -0
- package/dist/cli/src/bundle.js +51 -0
- package/dist/cli/src/certs.js +33 -0
- package/dist/cli/src/claude-auth.js +112 -0
- package/dist/cli/src/codex.js +172 -0
- package/dist/cli/src/gen-certs.js +7 -0
- package/dist/cli/src/hooks/agent-title.js +160 -0
- package/dist/cli/src/index.js +489 -0
- package/dist/cli/src/launchd.js +183 -0
- package/dist/cli/src/picker.js +166 -0
- package/dist/cli/src/probe.js +55 -0
- package/dist/cli/src/runtime.js +62 -0
- package/dist/cli/src/schtasks.js +134 -0
- package/dist/cli/src/settings.js +142 -0
- package/dist/cli/src/supervisor.js +100 -0
- package/dist/cli/src/tray.js +85 -0
- package/dist/router/src/admin.js +945 -0
- package/dist/router/src/bootstrap.js +80 -0
- package/dist/router/src/certs.js +65 -0
- package/dist/router/src/compat.js +172 -0
- package/dist/router/src/config.js +179 -0
- package/dist/router/src/health.js +45 -0
- package/dist/router/src/identity.js +51 -0
- package/dist/router/src/index.js +144 -0
- package/dist/router/src/ingress/models.js +29 -0
- package/dist/router/src/ingress/server.js +400 -0
- package/dist/router/src/ingress/translate.js +457 -0
- package/dist/router/src/log.js +81 -0
- package/dist/router/src/picker.js +74 -0
- package/dist/router/src/presets.js +267 -0
- package/dist/router/src/providers/anthropic-observed.js +88 -0
- package/dist/router/src/providers/anthropic-token-file.js +48 -0
- package/dist/router/src/providers/anthropic.js +203 -0
- package/dist/router/src/providers/chatgpt/auth.js +226 -0
- package/dist/router/src/providers/chatgpt/index.js +274 -0
- package/dist/router/src/providers/chatgpt/sse.js +28 -0
- package/dist/router/src/providers/chatgpt/translate.js +393 -0
- package/dist/router/src/providers/claude-oauth.js +252 -0
- package/dist/router/src/providers/openai/index.js +193 -0
- package/dist/router/src/providers/openai/translate.js +504 -0
- package/dist/router/src/proxy.js +724 -0
- package/dist/router/src/redact.js +43 -0
- package/dist/router/src/requestlog.js +346 -0
- package/dist/router/src/routing.js +113 -0
- package/dist/router/src/version.js +8 -0
- package/dist/router/src/x509.js +203 -0
- package/dist/ui/app.js +1228 -0
- package/dist/ui/i18n.js +95 -0
- package/dist/ui/index.html +104 -0
- package/dist/ui/presets-fallback.js +61 -0
- package/dist/ui/style.css +347 -0
- package/docs/ARCHITECTURE.md +441 -0
- package/package.json +66 -0
package/dist/ui/i18n.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const I18N = {
|
|
4
|
+
ko: {
|
|
5
|
+
"brand": "ClaudeRipple",
|
|
6
|
+
"nav.health": "상태", "nav.slots": "모델 매핑", "nav.providers": "프로바이더", "nav.clients": "클라이언트", "nav.logs": "로그", "nav.about": "정보",
|
|
7
|
+
"lang.toggleKo": "한국어", "lang.toggleEn": "English",
|
|
8
|
+
"common.save": "저장", "common.saved": "저장했습니다.", "common.saveFailed": "저장하지 못했습니다.", "common.loadFailed": "불러오지 못했습니다.", "common.actionFailed": "처리하지 못했습니다.", "common.cancel": "취소", "common.edit": "수정", "common.remove": "삭제", "common.show": "보기", "common.hide": "숨기기", "common.advanced": "고급", "common.notAvailable": "—",
|
|
9
|
+
"health.title": "상태", "health.subtitle": "Claude Desktop 연결, 프로바이더, 모델 피커 상태를 5초마다 확인합니다.", "health.desktop": "Claude Desktop 연결", "health.connection": "연결 상태", "health.connected": "연결됨", "health.notConnected": "연결 안 됨", "health.disconnected": "연결 안 됨", "health.connectedHelp": "Claude Desktop의 Code 탭 요청이 ClaudeRipple을 거쳐 나갑니다.", "health.notConnectedHelp": "Claude Desktop이 ClaudeRipple을 거치지 않습니다. 메뉴 막대 앱에서 라우터를 시작하거나 터미널에서 clauderipple install을 실행하세요.", "health.requests": "요청 (라우터 시작 후)", "health.requestCount": "요청 수", "health.requestsFmt": "완료 {completed} · 실패 {failed} · 진행 중 {inFlight}", "health.providers": "프로바이더", "health.noProviders": "연결한 프로바이더가 없습니다. 프로바이더 메뉴에서 추가하세요.", "health.quota": "사용량 {percent}%{reset}", "health.resetsIn": " · {hours}시간 뒤 초기화", "health.details": "자세히", "health.version": "버전", "health.runtime": "라우터 실행 파일 · 시작 시각", "health.routes": "매핑 수", "health.cli": "Claude Code 버전",
|
|
10
|
+
"picker.title": "모델 피커", "picker.statusHelp": "켜면 Claude Desktop의 모델 피커에 프로바이더 모델이 실제 이름으로 나타납니다. 끄면 모델 매핑대로 Claude 이름 뒤에서 답합니다.", "picker.state": "상태", "picker.on": "켜짐", "picker.off": "꺼짐", "picker.turnOn": "피커 켜기", "picker.turnOff": "피커 끄기", "picker.last": "최근에 모델 {count}개를 표시했습니다.", "picker.restartHelp": "켠 뒤 Claude Desktop을 완전히 껐다 다시 여세요.", "picker.confirmOn": "인증서 신뢰를 위해 운영체제가 확인 창을 띄웁니다(macOS는 로그인 암호, Windows는 인증서 확인). ClaudeRipple은 암호를 보지 않습니다. 계속할까요?", "picker.working": "처리 중입니다.", "picker.doneOn": "켜졌습니다. Claude Desktop을 완전히 껐다 다시 여세요.", "picker.doneOff": "꺼졌습니다. Claude Desktop을 완전히 껐다 다시 여세요.",
|
|
11
|
+
"slots.title": "모델 매핑", "slots.subtitle": "Claude 앱에서 고른 모델의 요청을 실제로 어떤 모델이 답할지 정합니다. 바꾸면 자동으로 저장됩니다.", "slots.pickerHelp": "켜면 Claude Desktop의 모델 피커에 프로바이더 모델이 실제 이름으로 나타납니다. 끄면 위의 매핑대로 Claude 이름 뒤에서 답합니다.", "slots.pickerModels": "피커에 넣을 모델", "slots.pickerModelsHelp": "체크한 모델이 Claude Desktop 피커에 나타나고, 고르면 그 모델이 바로 답합니다. 새로 넣은 모델은 새 세션부터 고를 수 있습니다(진행 중인 세션은 시작할 때의 목록을 씁니다).", "slots.add": "+ 매핑 추가", "slots.th.claude": "Claude 앱에서 고른 모델", "slots.th.target": "실제로 답하는 모델", "slots.th.effort": "추론 강도 (effort)", "slots.passthrough": "그대로 Claude가 답함", "slots.noProviderModels": "먼저 프로바이더를 연결하고 쓸 모델을 고르세요.", "slots.noChanges": "바꾸는 매핑이 없습니다. 모든 모델이 Claude 그대로 답합니다.", "slots.duplicate": "같은 Claude 모델을 두 번 매핑할 수 없습니다.", "slots.effortHint": "앱에서 고른 강도가 모델이 지원하지 않으면 가장 가까운 단계로 바꿔 보냅니다. (예: xhigh → high)", "slots.noEffort": "이 모델은 추론 강도를 받지 않습니다",
|
|
12
|
+
"providers.title": "프로바이더", "providers.subtitle": "프로바이더는 모델을 제공하는 서비스입니다(ChatGPT 구독, DeepSeek, Kimi 등). 계정을 연결하고 쓸 모델을 고르면 모델 매핑에서 선택할 수 있습니다.", "providers.anthropic": "Claude (Anthropic)", "providers.anthropicHelp": "Claude 모델을 Codex 등 OpenAI 방식 도구에서 쓰거나, API 키로 직접 씁니다.", "providers.anthropicIngressOnly": "여기서 고른 모델은 Codex 같은 OpenAI 방식 도구에 제공됩니다. Claude 앱과 Claude Code는 이 프로바이더를 거치지 않으므로 모델 매핑에는 나타나지 않습니다.", "providers.anthropicLoginReuse": "로그인 재사용", "providers.anthropicAuthClaudeCode": "Claude Code 로그인 재사용 (자동)", "providers.anthropicAuthApiKey": "API 키", "providers.anthropicCredentialsHelp": "Claude Code 로그인 또는 Anthropic API 키 중 사용할 방식을 고르세요.", "providers.anthropicSourceObserved": "Claude Desktop 세션에서 감지됨", "providers.anthropicSourceClaudeCode": "터미널 claude 로그인", "providers.anthropicSourceTokenFile": "ClaudeRipple 토큰", "providers.anthropicSourceMissing": "없음 — 아래 버튼으로 연결", "providers.anthropicLogin": "Claude 구독 연결…", "providers.anthropicLogout": "연결 해제", "providers.anthropicLoginDone": "Claude 구독을 연결했습니다.", "providers.anthropicSignInBrowser": "브라우저에서 Claude에 로그인하세요. 창이 열리지 않았으면 아래 링크를 여세요.", "providers.anthropicSignInLink": "로그인 페이지 열기", "providers.anthropicSignInPaste": "브라우저에서 로그인한 뒤 표시되는 코드를 여기에 붙여넣으세요.", "providers.anthropicSignInSubmit": "코드 제출", "providers.anthropicSignInManual": "코드 붙여넣기로 다시 시도", "providers.anthropicSignInWaiting": "브라우저 승인을 기다리는 중… (최대 5분)", "providers.anthropicSignInFailed": "로그인에 실패했습니다", "providers.anthropicSignedInActive": "ClaudeRipple 로그인을 씁니다.", "providers.anthropicSignedInStandby": "ClaudeRipple 로그인도 저장돼 있습니다. 위 출처가 사라지면 이것을 씁니다.", "providers.add": "+ 프로바이더 추가", "providers.refresh": "모두 연결 확인", "providers.check": "연결 확인", "providers.checking": "확인 중", "providers.empty": "아직 연결한 프로바이더가 없습니다. 위의 버튼으로 추가하세요.", "providers.modelsCount": "쓰는 모델 {count}개: {names}", "providers.noModels": "고른 모델이 없습니다. 수정에서 골라 주세요.", "providers.removeConfirm": "프로바이더 {name}을(를) 지울까요? 이 프로바이더를 쓰는 모델 매핑도 함께 지워집니다.", "providers.choose": "프로바이더 추가", "providers.chooseHelp": "연결할 서비스를 하나 고르세요.", "providers.chatgpt": "ChatGPT 구독", "providers.chatgptHelp": "ChatGPT Plus/Pro 구독으로 GPT 모델을 씁니다. API 키 없이 로그인만 하면 됩니다.", "providers.presetHelp": "API 키만 붙여 넣으면 됩니다.", "providers.openaiGroup": "OpenAI 호환", "providers.openaiGroupHelp": "요청은 ClaudeRipple이 OpenAI API 형식으로 번역해 보냅니다.", "providers.verified": "공식 문서로 확인됨", "providers.custom": "직접 입력", "providers.customName": "새 프로바이더", "providers.customHelp": "목록에 없는 Anthropic 호환 API를 주소와 키로 직접 연결합니다.", "providers.addTitle": "프로바이더 추가", "providers.edit": "프로바이더 수정", "providers.name": "이름", "providers.nameHelp": "목록과 매핑에서 이 프로바이더를 부르는 이름입니다.", "providers.nameRequired": "이름을 입력하세요.", "providers.apiKey": "API 키", "providers.keyHelp": "프로바이더 사이트에서 발급한 API 키입니다. 이 컴퓨터의 설정 파일에만 저장됩니다.", "providers.keyPlaceholder": "API 키를 붙여 넣으세요", "providers.keySaved": "저장된 키를 그대로 씁니다. 바꾸려면 새 키를 붙여 넣으세요.", "providers.url": "API 주소 (URL)", "providers.urlHelp": "Anthropic 호환 엔드포인트의 기본 주소입니다. 서비스 문서와 다를 때만 바꾸세요.", "providers.openaiUrlHelp": "OpenAI 호환 API의 기본 주소입니다. 요청은 이 주소의 Chat Completions 또는 Responses endpoint로 번역됩니다.", "providers.wire": "API 형식 (wire)", "providers.wireHelp": "대부분 Chat Completions를 씁니다. 공급자가 stateless Responses API를 지원할 때만 Responses를 고르세요.", "providers.urlRequired": "올바른 URL을 입력하세요.", "providers.keyType": "인증 헤더", "providers.keyTypeHelp": "대부분 x-api-key입니다. 서비스 문서가 Authorization: Bearer를 쓰라고 하면 그것을 고르세요.", "providers.extraHeaders": "추가 HTTP 헤더", "providers.extraHeadersHelp": "서비스가 따로 요구하는 헤더만 '이름: 값' 형식으로 한 줄씩.", "providers.models": "쓸 모델", "providers.modelsHelp": "체크한 모델이 모델 매핑의 선택 목록에 나타납니다.", "providers.modelsFound": "프로바이더가 알려 준 모델 목록입니다.", "providers.modelsFallback": "목록을 받아오지 못해 알려진 기본 모델을 보여 줍니다.", "providers.probeOk": "연결됐습니다.", "providers.probeFailed": "연결하지 못했습니다.", "providers.apiSoon": "잠시 후 다시 확인하세요.", "providers.showInPicker": "Claude 앱 피커에도 실제 이름으로 표시", "providers.pickerOffHint": "지금은 피커 모드가 꺼져 있어 체크해도 피커에 나타나지 않습니다. 저장할 때 켤지 물어봅니다.", "providers.pickerOffPrompt": "피커 모드가 꺼져 있어 이 모델들은 아직 Claude Desktop 피커에 나타나지 않습니다. 지금 켤까요? 인증서 신뢰를 위해 운영체제가 확인 창을 띄웁니다.", "providers.credentials": "로그인 방식", "providers.credentialsHelp": "ChatGPT 계정 토큰을 어디서 가져올지 정합니다.", "providers.authAuto": "자동 (직접 로그인이 있으면 그것, 없으면 Codex CLI 것)", "providers.authOwn": "ClaudeRipple에서 직접 로그인", "providers.authBorrow": "Codex CLI 로그인 재사용 (~/.codex/auth.json)", "providers.login": "ChatGPT 로그인 방법", "providers.loginHelp": "메뉴 막대 앱의 'ChatGPT 로그인…' 또는 터미널의 clauderipple login이 브라우저 로그인 창을 엽니다. 토큰은 이 컴퓨터에만 저장됩니다.", "providers.loginHint": "메뉴 막대 앱에서 'ChatGPT 로그인…'을 누르거나 터미널에서 clauderipple login을 실행하세요.", "providers.chatgptLogin": "ChatGPT 로그인", "providers.chatgptLoginWaiting": "브라우저에서 로그인을 마치세요. 완료되면 여기가 갱신됩니다.", "providers.chatgptLoginDone": "ChatGPT 로그인을 완료했습니다.", "providers.effortLevels": "추론 강도: {levels}", "providers.effortNone": "받지 않음", "providers.modelEffort": "강도 조절", "providers.modelNoEffort": "강도 없음", "providers.defaultEffort": "기본 추론 강도 (effort)", "providers.defaultEffortHelp": "매핑이나 앱에서 강도를 따로 정하지 않은 요청에 쓰는 값입니다.", "providers.identity": "모델에게 자기 정체 알리기 (identity)", "providers.append": "시스템 프롬프트 추가 문구", "providers.appendHelp": "모든 요청의 시스템 프롬프트 끝에 붙는 고정 문구입니다. 자주 바꾸면 프롬프트 캐시가 깨져 비용이 늘어납니다.",
|
|
13
|
+
"providerStatus.connected": "연결됨", "providerStatus.keyNeeded": "키 확인 필요", "providerStatus.loginNeeded": "로그인 필요", "providerStatus.disconnected": "연결 안 됨", "providerStatus.checking": "확인 중",
|
|
14
|
+
"clients.title": "클라이언트", "clients.subtitle": "ClaudeRipple을 쓰는 앱을 설정합니다.", "clients.desktop.title": "Claude Desktop", "clients.desktop.help": "모델 피커에 프로바이더 모델을 실제 이름으로 표시할지 정합니다.", "clients.codex.title": "Codex (앱·CLI)", "clients.codex.help": "Codex 설정(~/.codex/config.toml)에 ClaudeRipple 프로바이더를 추가합니다. 터미널은 `codex --profile clauderipple -m <모델>`, Codex 앱은 설정에서 프로바이더 clauderipple을 기본으로 고르면 됩니다.", "clients.codex.note": "ChatGPT 구독 모델은 Codex가 직접 쓰므로 여기서는 Claude와 Anthropic 호환 프로바이더만 보입니다.", "clients.codex.turnOn": "Codex에서 ClaudeRipple 사용", "clients.codex.turnOff": "Codex 연결 해제", "clients.claudeCode.title": "터미널 Claude Code", "clients.claudeCode.help": "터미널 `claude`도 같은 라우터를 씁니다. `/model <이름>`으로 고르세요.",
|
|
15
|
+
"logs.title": "로그", "logs.requests": "요청", "logs.raw": "원본 로그", "logs.lastHour": "최근 1시간", "logs.autoscroll": "자동 스크롤", "logs.polling": "3초마다 갱신", "logs.rawPolling": "3초마다 갱신 · 최근 200줄", "logs.provider": "프로바이더", "logs.all": "전체", "logs.showCountTokens": "토큰 수 계산 표시", "logs.empty": "아직 요청이 없습니다.", "logs.summary.requests": "요청 수", "logs.summary.success": "성공 / 실패", "logs.summary.input": "입력 토큰", "logs.summary.output": "출력 토큰", "logs.summary.duration": "평균 응답 시간", "logs.cacheHit": "캐시 {percent}%", "logs.th.time": "시간", "logs.th.models": "모델", "logs.th.effort": "effort", "logs.th.input": "입력", "logs.th.output": "출력", "logs.th.duration": "소요", "logs.th.status": "상태", "logs.status.ok": "성공", "logs.status.error": "오류", "logs.detail.id": "요청 ID", "logs.detail.kind": "종류", "logs.detail.stop": "종료 사유", "logs.detail.cacheWrite": "캐시 기록", "logs.detail.note": "메모", "logs.none": "없음", "logs.seconds": "{value}초",
|
|
16
|
+
"about.title": "정보", "about.body": "ClaudeRipple은 독립 오픈소스 프로젝트이며 Anthropic·OpenAI와 제휴·보증·후원 관계가 없습니다. Claude와 Claude Code는 Anthropic, PBC의 상표입니다.", "about.license": "라이선스: GPL-3.0",
|
|
17
|
+
"providers.identityHelp": "시스템 프롬프트 맨 앞에 '너는 <모델명>이고 Claude Code를 통해 답한다'를 넣습니다. 끄면 모델이 자신을 Claude라고 착각할 수 있습니다.",
|
|
18
|
+
"picker.models": "피커에 넣은 모델 {count}개: {names}",
|
|
19
|
+
"picker.lastAt": "Claude Desktop이 마지막으로 목록을 받아간 시각: {at}",
|
|
20
|
+
"picker.never": "아직 Claude Desktop이 목록을 받아가지 않았습니다. 앱을 완전히 껐다 다시 여세요.",
|
|
21
|
+
"agentTitle.title": "서브에이전트 이름표",
|
|
22
|
+
"agentTitle.help": "백그라운드 작업 패널의 서브에이전트 제목 앞에 실제 모델과 추론 강도를 붙입니다(예: Terra·high · 리뷰). Claude Code 훅으로 동작하며 새 서브에이전트부터 적용됩니다.",
|
|
23
|
+
"agentTitle.on": "켜짐",
|
|
24
|
+
"agentTitle.off": "꺼짐",
|
|
25
|
+
"agentTitle.turnOn": "이름표 켜기",
|
|
26
|
+
"agentTitle.turnOff": "이름표 끄기",
|
|
27
|
+
"providers.probeNoCredits": "키는 맞습니다. 다만 이 계정에 크레딧(잔액)이 없어 응답은 받지 못합니다. 프로바이더 사이트에서 충전하세요.",
|
|
28
|
+
"providers.probeBadKey": "API 키가 거부됐습니다. 키를 다시 확인하세요.",
|
|
29
|
+
"providers.searchModels": "모델 검색 (이름 또는 id)",
|
|
30
|
+
"providers.modelsSummary": "선택 {selected}개 / 전체 {total}개",
|
|
31
|
+
"providers.modelsHidden": "{hidden}개는 검색으로 찾으세요",
|
|
32
|
+
"providers.modelsFoundMany": "프로바이더가 알려 준 목록입니다. 많으니 검색해서 쓸 것만 체크하세요.",
|
|
33
|
+
"slots.saving": "저장 중…",
|
|
34
|
+
"slots.saved": "저장됨 · 바로 적용됩니다",
|
|
35
|
+
},
|
|
36
|
+
en: {
|
|
37
|
+
"brand": "ClaudeRipple",
|
|
38
|
+
"nav.health": "Status", "nav.slots": "Model mapping", "nav.providers": "Providers", "nav.clients": "Clients", "nav.logs": "Logs", "nav.about": "About",
|
|
39
|
+
"lang.toggleKo": "한국어", "lang.toggleEn": "English",
|
|
40
|
+
"common.save": "Save", "common.saved": "Saved.", "common.saveFailed": "Could not save.", "common.loadFailed": "Could not load.", "common.actionFailed": "Could not complete that action.", "common.cancel": "Cancel", "common.edit": "Edit", "common.remove": "Remove", "common.show": "Show", "common.hide": "Hide", "common.advanced": "Advanced", "common.notAvailable": "—",
|
|
41
|
+
"health.title": "Status", "health.subtitle": "Claude Desktop connection, providers and the model picker, refreshed every 5s.", "health.desktop": "Claude Desktop connection", "health.connection": "Connection", "health.connected": "Connected", "health.notConnected": "Not connected", "health.disconnected": "Not connected", "health.connectedHelp": "Claude Desktop's Code tab requests go through ClaudeRipple.", "health.notConnectedHelp": "Claude Desktop is not going through ClaudeRipple. Start the router from the menu-bar app or run clauderipple install.", "health.requests": "Requests (since router start)", "health.requestCount": "Request count", "health.requestsFmt": "{completed} done · {failed} failed · {inFlight} in progress", "health.providers": "Providers", "health.noProviders": "No providers connected. Add one under Providers.", "health.quota": "{percent}% used{reset}", "health.resetsIn": " · resets in {hours}h", "health.details": "Details", "health.version": "Version", "health.runtime": "Router files · started", "health.routes": "Mappings", "health.cli": "Claude Code version",
|
|
42
|
+
"picker.title": "Model picker", "picker.statusHelp": "On: provider models appear under their real names in the Claude Desktop picker. Off: they answer behind Claude names per the mapping.", "picker.state": "State", "picker.on": "On", "picker.off": "Off", "picker.turnOn": "Turn picker on", "picker.turnOff": "Turn picker off", "picker.last": "Most recently showed {count} models.", "picker.restartHelp": "After turning it on, quit Claude Desktop completely and open it again.", "picker.confirmOn": "Your operating system will ask you to confirm trusting the certificate (macOS asks for your login password, Windows shows a certificate dialog). ClaudeRipple never sees your password. Continue?", "picker.working": "Working.", "picker.doneOn": "Turned on. Quit Claude Desktop completely and open it again.", "picker.doneOff": "Turned off. Quit Claude Desktop completely and open it again.",
|
|
43
|
+
"slots.title": "Model mapping", "slots.subtitle": "Decide which model actually answers when you pick a Claude model in the app. Changes save automatically.", "slots.pickerHelp": "On: provider models appear under their real names in the Claude Desktop picker. Off: they answer behind Claude names per the mapping above.", "slots.pickerModels": "Models to put in the picker", "slots.pickerModelsHelp": "Checked models appear in the Claude Desktop picker; picking one makes it answer directly. Newly added models are selectable from the next session (a running session keeps the list it started with).", "slots.add": "+ Add mapping", "slots.th.claude": "Picked in the Claude app", "slots.th.target": "Actually answered by", "slots.th.effort": "Reasoning effort", "slots.passthrough": "Claude answers as usual", "slots.noProviderModels": "Connect a provider and choose its models first.", "slots.noChanges": "No mappings. Every model answers as Claude.", "slots.duplicate": "A Claude model can be mapped only once.", "slots.effortHint": "If the effort chosen in the app is unsupported by the model, ClaudeRipple sends the nearest level instead. (For example: xhigh → high)", "slots.noEffort": "This model does not take a reasoning effort",
|
|
44
|
+
"providers.title": "Providers", "providers.subtitle": "A provider is a service that serves models (ChatGPT subscription, DeepSeek, Kimi…). Connect an account and choose the models to offer in Model mapping.", "providers.anthropic": "Claude (Anthropic)", "providers.anthropicHelp": "Use Claude models in OpenAI-style tools such as Codex, or directly with an API key.", "providers.anthropicIngressOnly": "The models chosen here are served to OpenAI-style tools such as Codex. The Claude app and Claude Code do not go through this provider, so it does not appear in Model mapping.", "providers.anthropicLoginReuse": "Reuse sign-in", "providers.anthropicAuthClaudeCode": "Reuse Claude Code sign-in (automatic)", "providers.anthropicAuthApiKey": "API key", "providers.anthropicCredentialsHelp": "Choose your Claude Code sign-in or an Anthropic API key.", "providers.anthropicSourceObserved": "Detected from a Claude Desktop session", "providers.anthropicSourceClaudeCode": "Terminal Claude sign-in", "providers.anthropicSourceTokenFile": "ClaudeRipple token", "providers.anthropicSourceMissing": "None — connect below", "providers.anthropicLogin": "Connect Claude subscription…", "providers.anthropicLogout": "Disconnect", "providers.anthropicLoginDone": "Claude subscription connected.", "providers.anthropicSignInBrowser": "Sign in to Claude in your browser. If no window opened, use the link below.", "providers.anthropicSignInLink": "Open the sign-in page", "providers.anthropicSignInPaste": "After signing in, paste the code the page shows here.", "providers.anthropicSignInSubmit": "Submit code", "providers.anthropicSignInManual": "Try again by pasting a code", "providers.anthropicSignInWaiting": "Waiting for the browser… (up to 5 minutes)", "providers.anthropicSignInFailed": "Sign-in failed", "providers.anthropicSignedInActive": "Using the ClaudeRipple sign-in.", "providers.anthropicSignedInStandby": "A ClaudeRipple sign-in is stored too, and takes over if the source above goes away.", "providers.add": "+ Add provider", "providers.refresh": "Test all", "providers.check": "Test connection", "providers.checking": "Checking", "providers.empty": "No providers connected yet. Add one with the button above.", "providers.modelsCount": "{count} models in use: {names}", "providers.noModels": "No models chosen. Pick some under Edit.", "providers.removeConfirm": "Remove provider {name}? Model mappings that use it are removed too.", "providers.choose": "Add provider", "providers.chooseHelp": "Pick the service to connect.", "providers.chatgpt": "ChatGPT subscription", "providers.chatgptHelp": "Use GPT models through a ChatGPT Plus/Pro subscription. Sign-in only, no API key.", "providers.presetHelp": "Paste an API key and you are done.", "providers.openaiGroup": "OpenAI-compatible", "providers.openaiGroupHelp": "ClaudeRipple translates requests into the OpenAI API format.", "providers.verified": "Verified against official docs", "providers.custom": "Enter manually", "providers.customName": "New provider", "providers.customHelp": "Connect any Anthropic-compatible API by URL and key.", "providers.addTitle": "Add provider", "providers.edit": "Edit provider", "providers.name": "Name", "providers.nameHelp": "How this provider is called in lists and mappings.", "providers.nameRequired": "Enter a name.", "providers.apiKey": "API key", "providers.keyHelp": "The API key issued on the provider's site. Stored only in this computer's config file.", "providers.keyPlaceholder": "Paste your API key", "providers.keySaved": "The saved key stays in use. Paste a new key to replace it.", "providers.url": "API base URL", "providers.urlHelp": "Base URL of the Anthropic-compatible endpoint. Change only if the service docs differ.", "providers.openaiUrlHelp": "Base URL of the OpenAI-compatible API. Requests are translated to its Chat Completions or Responses endpoint.", "providers.wire": "API wire format", "providers.wireHelp": "Use Chat Completions for most providers. Select Responses only when the provider supports the stateless Responses API.", "providers.urlRequired": "Enter a valid URL.", "providers.keyType": "Auth header", "providers.keyTypeHelp": "Usually x-api-key. Pick Authorization: Bearer only if the service docs say so.", "providers.extraHeaders": "Extra HTTP headers", "providers.extraHeadersHelp": "Only headers the service requires, one 'name: value' per line.", "providers.models": "Models to use", "providers.modelsHelp": "Checked models appear in the Model mapping list.", "providers.modelsFound": "Model list reported by the provider.", "providers.modelsFallback": "Could not fetch the list; showing known default models.", "providers.probeOk": "Connected.", "providers.probeFailed": "Could not connect.", "providers.apiSoon": "Please try again shortly.", "providers.showInPicker": "Also show by real name in the Claude app picker", "providers.pickerOffHint": "Picker mode is off right now, so ticking this does not show them yet. You will be asked to turn it on when you save.", "providers.pickerOffPrompt": "Picker mode is off, so these models will not appear in the Claude Desktop picker yet. Turn it on now? Your operating system will ask you to confirm trusting the certificate.", "providers.credentials": "Sign-in source", "providers.credentialsHelp": "Where the ChatGPT account token comes from.", "providers.authAuto": "Auto (own sign-in if present, else Codex CLI's)", "providers.authOwn": "Sign in with ClaudeRipple", "providers.authBorrow": "Reuse Codex CLI sign-in (~/.codex/auth.json)", "providers.login": "How to sign in", "providers.loginHelp": "'Sign in to ChatGPT…' in the menu-bar app or clauderipple login in a terminal opens the browser sign-in. Tokens stay on this computer.", "providers.loginHint": "Use 'Sign in to ChatGPT…' in the menu-bar app or run clauderipple login in a terminal.", "providers.chatgptLogin": "Sign in to ChatGPT", "providers.chatgptLoginWaiting": "Finish signing in in your browser. This will update when it is done.", "providers.chatgptLoginDone": "ChatGPT sign-in complete.", "providers.effortLevels": "Reasoning effort: {levels}", "providers.effortNone": "Does not take reasoning effort", "providers.modelEffort": "effort", "providers.modelNoEffort": "no effort", "providers.defaultEffort": "Default reasoning effort", "providers.defaultEffortHelp": "Used when neither the mapping nor the app sets an effort.", "providers.identity": "Tell the model what it is (identity)", "providers.append": "System prompt addendum", "providers.appendHelp": "Fixed text appended to every request's system prompt. Changing it often breaks the prompt cache and raises cost.",
|
|
45
|
+
"providerStatus.connected": "Connected", "providerStatus.keyNeeded": "Key needed", "providerStatus.loginNeeded": "Sign-in needed", "providerStatus.disconnected": "Not connected", "providerStatus.checking": "Checking",
|
|
46
|
+
"clients.title": "Clients", "clients.subtitle": "Set up the apps that use ClaudeRipple.", "clients.desktop.title": "Claude Desktop", "clients.desktop.help": "Choose whether provider models appear by real name in the model picker.", "clients.codex.title": "Codex (app and CLI)", "clients.codex.help": "Adds ClaudeRipple as a provider to Codex's config (~/.codex/config.toml). Terminal: `codex --profile clauderipple -m <model>`; Codex app: make clauderipple the default provider in that config.", "clients.codex.note": "ChatGPT subscription models are used directly by Codex, so only Claude and Anthropic-compatible providers appear here.", "clients.codex.turnOn": "Use ClaudeRipple in Codex", "clients.codex.turnOff": "Disconnect Codex", "clients.claudeCode.title": "Terminal Claude Code", "clients.claudeCode.help": "Terminal `claude` uses the same router. Choose with `/model <name>`.",
|
|
47
|
+
"logs.title": "Logs", "logs.requests": "Requests", "logs.raw": "Raw logs", "logs.lastHour": "Last hour", "logs.autoscroll": "Auto-scroll", "logs.polling": "Updates every 3s", "logs.rawPolling": "Updates every 3s · last 200 lines", "logs.provider": "Provider", "logs.all": "All", "logs.showCountTokens": "Show token counts", "logs.empty": "No requests yet.", "logs.summary.requests": "Requests", "logs.summary.success": "Succeeded / failed", "logs.summary.input": "Input tokens", "logs.summary.output": "Output tokens", "logs.summary.duration": "Average response", "logs.cacheHit": "Cache {percent}%", "logs.th.time": "Time", "logs.th.models": "Model", "logs.th.effort": "effort", "logs.th.input": "Input", "logs.th.output": "Output", "logs.th.duration": "Duration", "logs.th.status": "Status", "logs.status.ok": "ok", "logs.status.error": "error", "logs.detail.id": "Request ID", "logs.detail.kind": "Kind", "logs.detail.stop": "Stop reason", "logs.detail.cacheWrite": "Cache write", "logs.detail.note": "Note", "logs.none": "None", "logs.seconds": "{value}s",
|
|
48
|
+
"about.title": "About", "about.body": "ClaudeRipple is an independent open-source project, not affiliated with Anthropic or OpenAI. Claude and Claude Code are trademarks of Anthropic, PBC.", "about.license": "License: GPL-3.0",
|
|
49
|
+
"providers.identityHelp": "Prepends 'You are <model>, answering through Claude Code' to the system prompt. Off, the model may believe it is Claude.",
|
|
50
|
+
"picker.models": "{count} models in the picker: {names}",
|
|
51
|
+
"picker.lastAt": "Claude Desktop last fetched the list at {at}",
|
|
52
|
+
"picker.never": "Claude Desktop has not fetched the list yet. Quit it completely and open it again.",
|
|
53
|
+
"agentTitle.title": "Subagent name tags",
|
|
54
|
+
"agentTitle.help": "Prefixes subagent titles in the background-task panel with the real model and effort (e.g. Terra·high · Review). Works through a Claude Code hook; applies to new subagents.",
|
|
55
|
+
"agentTitle.on": "On",
|
|
56
|
+
"agentTitle.off": "Off",
|
|
57
|
+
"agentTitle.turnOn": "Turn on",
|
|
58
|
+
"agentTitle.turnOff": "Turn off",
|
|
59
|
+
"providers.probeNoCredits": "The key is valid, but this account has no credits, so no answer came back. Top up on the provider site.",
|
|
60
|
+
"providers.probeBadKey": "The API key was rejected. Check the key.",
|
|
61
|
+
"providers.searchModels": "Search models (name or id)",
|
|
62
|
+
"providers.modelsSummary": "{selected} selected of {total}",
|
|
63
|
+
"providers.modelsHidden": "{hidden} more — search to find them",
|
|
64
|
+
"providers.modelsFoundMany": "List reported by the provider. It is long: search and tick only what you will use.",
|
|
65
|
+
"slots.saving": "Saving…",
|
|
66
|
+
"slots.saved": "Saved · applies immediately",
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// A language the user picked with the toggle wins; then ?lang= (the tray app passes the OS
|
|
71
|
+
// language there, because navigator.language is Chromium's app locale and read "en" on a Korean
|
|
72
|
+
// Windows); then the browser's own language.
|
|
73
|
+
function detectLang() {
|
|
74
|
+
try {
|
|
75
|
+
const stored = localStorage.getItem("clauderipple_lang");
|
|
76
|
+
if (stored === "ko" || stored === "en") return stored;
|
|
77
|
+
} catch { /* storage unavailable */ }
|
|
78
|
+
try {
|
|
79
|
+
const q = new URLSearchParams(location.search).get("lang");
|
|
80
|
+
if (q === "ko" || q === "en") return q;
|
|
81
|
+
} catch { /* no location */ }
|
|
82
|
+
return navigator.language && navigator.language.startsWith("ko") ? "ko" : "en";
|
|
83
|
+
}
|
|
84
|
+
const CURRENT_LANG = detectLang();
|
|
85
|
+
function t(key, vars) {
|
|
86
|
+
const dictionary = I18N[CURRENT_LANG] || I18N.en;
|
|
87
|
+
let text = dictionary[key] !== undefined ? dictionary[key] : (I18N.en[key] !== undefined ? I18N.en[key] : key);
|
|
88
|
+
for (const [name, value] of Object.entries(vars || {})) text = text.split(`{${name}}`).join(String(value));
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
function applyStaticI18n() {
|
|
92
|
+
for (const node of document.querySelectorAll("[data-i18n]")) node.textContent = t(node.getAttribute("data-i18n"));
|
|
93
|
+
document.title = t("brand");
|
|
94
|
+
}
|
|
95
|
+
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", applyStaticI18n); else applyStaticI18n();
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<title>ClaudeRipple</title>
|
|
2
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; connect-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'self'; base-uri 'none'; form-action 'none'" />
|
|
3
|
+
<link rel="stylesheet" href="style.css" />
|
|
4
|
+
|
|
5
|
+
<nav>
|
|
6
|
+
<div class="brand"><svg viewBox="0 0 1024 1024" aria-hidden="true"><circle cx="512" cy="512" r="128" fill="#6a56d6"/><circle cx="512" cy="512" r="245" stroke="#8a78e6" stroke-width="56" fill="none" opacity="0.7"/><path d="M512 108C735.124 108 916 288.876 916 512C916 735.124 735.124 916 512 916C288.876 916 108 735.124 108 512" stroke="#8a78e6" stroke-width="56" stroke-linecap="round" fill="none" opacity="0.35"/></svg><span data-i18n="brand">ClaudeRipple</span></div>
|
|
7
|
+
<button data-view="health" class="nav-btn" data-i18n="nav.health">Status</button>
|
|
8
|
+
<button data-view="slots" class="nav-btn" data-i18n="nav.slots">Model links</button>
|
|
9
|
+
<button data-view="providers" class="nav-btn" data-i18n="nav.providers">Providers</button>
|
|
10
|
+
<button data-view="clients" class="nav-btn" data-i18n="nav.clients">Clients</button>
|
|
11
|
+
<button data-view="logs" class="nav-btn" data-i18n="nav.logs">Logs</button>
|
|
12
|
+
<button data-view="about" class="nav-btn" data-i18n="nav.about">About</button>
|
|
13
|
+
<div class="nav-spacer"></div>
|
|
14
|
+
<button class="lang-toggle" id="lang-toggle" type="button"></button>
|
|
15
|
+
</nav>
|
|
16
|
+
|
|
17
|
+
<main>
|
|
18
|
+
<section id="view-health" class="view">
|
|
19
|
+
<h1 data-i18n="health.title">Status</h1>
|
|
20
|
+
<p class="subtitle" data-i18n="health.subtitle">Check that Claude Desktop and your providers are ready.</p>
|
|
21
|
+
<div class="card"><h2 data-i18n="health.desktop">Claude Desktop connection</h2><div class="rows" id="health-desktop"></div></div>
|
|
22
|
+
<div class="card"><h2 data-i18n="health.providers">Providers</h2><div class="rows" id="health-providers"></div></div>
|
|
23
|
+
<div class="card"><h2 data-i18n="health.requestCount">Request count</h2><div class="rows" id="health-requests"></div></div>
|
|
24
|
+
<details class="details"><summary data-i18n="health.details">Details</summary><div class="rows detail-rows" id="health-details"></div></details>
|
|
25
|
+
</section>
|
|
26
|
+
|
|
27
|
+
<section id="view-slots" class="view">
|
|
28
|
+
<h1 data-i18n="slots.title">Model links</h1>
|
|
29
|
+
<p class="subtitle" data-i18n="slots.subtitle">Choose what each Claude model should actually use.</p>
|
|
30
|
+
<div class="toolbar"><button class="btn secondary" id="slots-add" type="button" data-i18n="slots.add">+ Add link</button><span class="small" id="slots-status"></span></div>
|
|
31
|
+
<p class="small" id="slots-summary"></p>
|
|
32
|
+
<p class="hint" data-i18n="slots.effortHint">If the effort chosen in the app is unsupported by the model, ClaudeRipple sends the nearest level instead. (For example: xhigh → high)</p>
|
|
33
|
+
<div class="card table-card"><table id="slots-table"><thead><tr><th data-i18n="slots.th.claude">When you choose this</th><th data-i18n="slots.th.target">It answers with</th><th data-i18n="slots.th.effort">Thinking depth</th><th></th></tr></thead><tbody></tbody></table></div>
|
|
34
|
+
</section>
|
|
35
|
+
|
|
36
|
+
<section id="view-providers" class="view">
|
|
37
|
+
<h1 data-i18n="providers.title">Providers</h1>
|
|
38
|
+
<p class="subtitle" data-i18n="providers.subtitle">Connect an AI account, then choose the models you will use.</p>
|
|
39
|
+
<div class="toolbar"><button class="btn" id="providers-add" type="button" data-i18n="providers.add">+ Add provider</button><button class="btn secondary" id="providers-refresh" type="button" data-i18n="providers.refresh">Check connections</button></div>
|
|
40
|
+
<div id="providers-list"></div>
|
|
41
|
+
</section>
|
|
42
|
+
|
|
43
|
+
<section id="view-clients" class="view">
|
|
44
|
+
<h1 data-i18n="clients.title">Clients</h1>
|
|
45
|
+
<p class="subtitle" data-i18n="clients.subtitle">Set up the apps that use ClaudeRipple.</p>
|
|
46
|
+
<div class="card">
|
|
47
|
+
<h2 data-i18n="clients.desktop.title">Claude Desktop</h2>
|
|
48
|
+
<p class="hint" data-i18n="clients.desktop.help">Choose whether provider models appear by name in the model picker.</p>
|
|
49
|
+
<div class="rows" id="client-picker-rows"></div>
|
|
50
|
+
<div class="actions"><button class="btn" id="client-picker-toggle" type="button"></button><span class="small" id="client-picker-msg"></span></div>
|
|
51
|
+
<div class="client-models" id="client-picker-models-card" hidden><h3 data-i18n="slots.pickerModels">Models in picker</h3><p class="hint" data-i18n="slots.pickerModelsHelp">Tick only models you want to see in Claude Desktop.</p><div class="model-checklist" id="client-picker-models"></div></div>
|
|
52
|
+
<div class="client-divider"></div>
|
|
53
|
+
<h3 data-i18n="agentTitle.title">Subagent name tags</h3>
|
|
54
|
+
<p class="hint" data-i18n="agentTitle.help"></p>
|
|
55
|
+
<div class="rows" id="client-agent-title-rows"></div>
|
|
56
|
+
<div class="actions"><button class="btn" id="client-agent-title-toggle" type="button"></button></div>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="card">
|
|
59
|
+
<h2 data-i18n="clients.codex.title">Codex CLI</h2>
|
|
60
|
+
<p class="hint" data-i18n="clients.codex.help">Adds ClaudeRipple as a provider to Codex.</p>
|
|
61
|
+
<div class="rows" id="client-codex-rows"></div>
|
|
62
|
+
<div class="actions"><button class="btn" id="client-codex-toggle" type="button"></button><span class="small" id="client-codex-msg"></span></div>
|
|
63
|
+
<p class="hint" data-i18n="clients.codex.note">ChatGPT subscription models are used directly by Codex, so only Claude and Anthropic-compatible providers appear here.</p>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="card">
|
|
66
|
+
<h2 data-i18n="clients.claudeCode.title">Terminal Claude Code</h2>
|
|
67
|
+
<p class="hint" data-i18n="clients.claudeCode.help">Terminal Claude uses the same router. Choose with /model <name>.</p>
|
|
68
|
+
<div class="rows" id="client-claude-code-rows"></div>
|
|
69
|
+
</div>
|
|
70
|
+
</section>
|
|
71
|
+
|
|
72
|
+
<section id="view-logs" class="view">
|
|
73
|
+
<h1 data-i18n="logs.title">Logs</h1>
|
|
74
|
+
<div class="logs-tabs" role="tablist">
|
|
75
|
+
<button class="logs-tab active" id="logs-requests-tab" type="button" role="tab" aria-selected="true" data-i18n="logs.requests">Requests</button>
|
|
76
|
+
<button class="logs-tab" id="logs-raw-tab" type="button" role="tab" aria-selected="false" data-i18n="logs.raw">Raw logs</button>
|
|
77
|
+
</div>
|
|
78
|
+
<div id="logs-requests-panel" role="tabpanel">
|
|
79
|
+
<div class="logs-summary-title"><strong data-i18n="logs.lastHour">Last hour</strong><span class="small" data-i18n="logs.polling">Updates every 3s</span></div>
|
|
80
|
+
<div class="logs-summary" id="logs-summary"></div>
|
|
81
|
+
<div class="toolbar logs-controls">
|
|
82
|
+
<label class="logs-filter"><span data-i18n="logs.provider">Provider</span><select id="logs-provider"><option value="" data-i18n="logs.all">All</option></select></label>
|
|
83
|
+
</div>
|
|
84
|
+
<div class="card table-card logs-table-card"><table id="requests-table"><thead><tr><th data-i18n="logs.th.time">Time</th><th data-i18n="logs.th.models">Called → answered</th><th data-i18n="logs.th.effort">effort</th><th data-i18n="logs.th.input">Input</th><th data-i18n="logs.th.output">Output</th><th data-i18n="logs.th.duration">Duration</th><th data-i18n="logs.th.status">Status</th></tr></thead><tbody></tbody></table></div>
|
|
85
|
+
<div class="empty-card" id="requests-empty" hidden data-i18n="logs.empty">No requests yet.</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div id="logs-raw-panel" role="tabpanel" hidden>
|
|
88
|
+
<div class="toolbar"><label class="check"><input type="checkbox" id="logs-autoscroll" checked /><span data-i18n="logs.autoscroll">Auto-scroll</span></label><span class="small" data-i18n="logs.rawPolling">Updates every 3s · last 200 lines</span></div>
|
|
89
|
+
<pre id="logbox"></pre>
|
|
90
|
+
</div>
|
|
91
|
+
</section>
|
|
92
|
+
|
|
93
|
+
<section id="view-about" class="view">
|
|
94
|
+
<h1 data-i18n="about.title">About</h1>
|
|
95
|
+
<div class="card"><p data-i18n="about.body">ClaudeRipple is an independent open-source project, not affiliated with Anthropic or OpenAI. Claude and Claude Code are trademarks of Anthropic, PBC.</p><p class="small" data-i18n="about.license">License: GPL-3.0</p></div>
|
|
96
|
+
</section>
|
|
97
|
+
</main>
|
|
98
|
+
|
|
99
|
+
<div class="toast" id="toast" role="status"></div>
|
|
100
|
+
<div class="modal-backdrop" id="modal-backdrop" hidden><section class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title"><button class="icon-btn modal-close" id="modal-close" type="button" aria-label="Close">×</button><div id="modal-content"></div></section></div>
|
|
101
|
+
|
|
102
|
+
<script src="i18n.js"></script>
|
|
103
|
+
<script src="presets-fallback.js"></script>
|
|
104
|
+
<script src="app.js"></script>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Used only while the router is starting up or an older router does not yet expose
|
|
4
|
+
// /api/presets and /api/claude-models. The API response replaces these lists.
|
|
5
|
+
const FALLBACK_CLAUDE_MODELS = [
|
|
6
|
+
{ id: "claude-fable-5-1", name: "Fable 5.1" },
|
|
7
|
+
{ id: "claude-opus-5", name: "Opus 5" },
|
|
8
|
+
{ id: "claude-sonnet-5", name: "Sonnet 5" },
|
|
9
|
+
{ id: "claude-haiku-4-5", name: "Haiku 4.5" },
|
|
10
|
+
{ id: "claude-fable-5", name: "Fable 5" },
|
|
11
|
+
{ id: "claude-opus-4-8", name: "Opus 4.8" },
|
|
12
|
+
{ id: "claude-opus-4-7", name: "Opus 4.7" },
|
|
13
|
+
{ id: "claude-opus-4-6", name: "Opus 4.6" },
|
|
14
|
+
{ id: "claude-sonnet-4-6", name: "Sonnet 4.6" },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const CHATGPT_MODELS = [
|
|
18
|
+
{ id: "gpt-5.6-terra", name: "GPT-5.6 Terra" },
|
|
19
|
+
{ id: "gpt-5.6-sol", name: "GPT-5.6 Sol" },
|
|
20
|
+
{ id: "gpt-5.6-luna", name: "GPT-5.6 Luna" },
|
|
21
|
+
{ id: "gpt-6-astra", name: "GPT-6 Astra" },
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const FALLBACK_PRESETS = [
|
|
25
|
+
{
|
|
26
|
+
id: "deepseek",
|
|
27
|
+
name: "DeepSeek",
|
|
28
|
+
vendorUrl: "https://platform.deepseek.com/",
|
|
29
|
+
anthropicBaseUrl: "https://api.deepseek.com/anthropic",
|
|
30
|
+
authHeader: "x-api-key",
|
|
31
|
+
fallbackModels: [
|
|
32
|
+
{ id: "deepseek-chat", name: "DeepSeek V3" },
|
|
33
|
+
{ id: "deepseek-reasoner", name: "DeepSeek R1" },
|
|
34
|
+
],
|
|
35
|
+
supportsEffort: false,
|
|
36
|
+
verified: false,
|
|
37
|
+
docsUrl: "https://api-docs.deepseek.com/",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "moonshot",
|
|
41
|
+
name: "Moonshot AI",
|
|
42
|
+
vendorUrl: "https://platform.moonshot.ai/",
|
|
43
|
+
anthropicBaseUrl: "https://api.moonshot.ai/anthropic",
|
|
44
|
+
authHeader: "x-api-key",
|
|
45
|
+
fallbackModels: [{ id: "kimi-k2", name: "Kimi K2" }],
|
|
46
|
+
supportsEffort: false,
|
|
47
|
+
verified: false,
|
|
48
|
+
docsUrl: "https://platform.moonshot.ai/docs",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "zai",
|
|
52
|
+
name: "Z.AI",
|
|
53
|
+
vendorUrl: "https://www.z.ai/",
|
|
54
|
+
anthropicBaseUrl: "https://open.bigmodel.cn/api/anthropic",
|
|
55
|
+
authHeader: "authorization-bearer",
|
|
56
|
+
fallbackModels: [{ id: "glm-4.7", name: "GLM-4.7" }],
|
|
57
|
+
supportsEffort: false,
|
|
58
|
+
verified: false,
|
|
59
|
+
docsUrl: "https://docs.z.ai/",
|
|
60
|
+
},
|
|
61
|
+
];
|