Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 12 additions & 72 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -149,24 +149,6 @@ jobs:
else
tar -C "$archive_dir" -czf "dist/$archive_name" "$binary_name" LICENSE README.md README_CN.md config.example.yaml
fi
- name: Create asset checksum
shell: bash
run: |
set -euo pipefail
shopt -s nullglob
archives=(dist/CLIProxyAPI_*.tar.gz dist/CLIProxyAPI_*.zip)
if [[ ${#archives[@]} -ne 1 ]]; then
printf 'expected one archive, found %s\n' "${#archives[@]}" >&2
printf '%s\n' "${archives[@]}" >&2
exit 1
fi
archive="${archives[0]}"
archive_name="$(basename "$archive")"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$archive" | awk -v name="$archive_name" '{print $1 " " name}' > "$archive.sha256"
else
shasum -a 256 "$archive" | awk -v name="$archive_name" '{print $1 " " name}' > "$archive.sha256"
fi
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
Expand All @@ -179,9 +161,9 @@ jobs:
run: |
set -euo pipefail
shopt -s nullglob
assets=(dist/CLIProxyAPI_*.tar.gz dist/CLIProxyAPI_*.zip dist/CLIProxyAPI_*.tar.gz.sha256 dist/CLIProxyAPI_*.zip.sha256)
if [[ ${#assets[@]} -lt 2 ]]; then
printf 'expected archive and checksum assets, found %s\n' "${#assets[@]}" >&2
assets=(dist/CLIProxyAPI_*.tar.gz dist/CLIProxyAPI_*.zip)
if [[ ${#assets[@]} -eq 0 ]]; then
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
printf '%s\n' "${assets[@]}" >&2
exit 1
fi
Expand Down Expand Up @@ -302,20 +284,6 @@ jobs:

cp LICENSE README.md README_CN.md config.example.yaml "$archive_dir/"
tar -C "$archive_dir" -czf "dist/$archive_name" cli-proxy-api LICENSE README.md README_CN.md config.example.yaml
- name: Create asset checksum
shell: bash
run: |
set -euo pipefail
shopt -s nullglob
archives=(dist/CLIProxyAPI_*.tar.gz)
if [[ ${#archives[@]} -ne 1 ]]; then
printf 'expected one archive, found %s\n' "${#archives[@]}" >&2
printf '%s\n' "${archives[@]}" >&2
exit 1
fi
archive="${archives[0]}"
archive_name="$(basename "$archive")"
sha256sum "$archive" | awk -v name="$archive_name" '{print $1 " " name}' > "$archive.sha256"
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
Expand All @@ -328,9 +296,9 @@ jobs:
run: |
set -euo pipefail
shopt -s nullglob
assets=(dist/CLIProxyAPI_*.tar.gz dist/CLIProxyAPI_*.tar.gz.sha256)
if [[ ${#assets[@]} -lt 2 ]]; then
printf 'expected archive and checksum assets, found %s\n' "${#assets[@]}" >&2
assets=(dist/CLIProxyAPI_*.tar.gz)
if [[ ${#assets[@]} -eq 0 ]]; then
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
printf '%s\n' "${assets[@]}" >&2
exit 1
fi
Expand Down Expand Up @@ -438,20 +406,6 @@ jobs:

cp LICENSE README.md README_CN.md config.example.yaml "$archive_dir/"
tar -C "$archive_dir" -czf "dist/$archive_name" cli-proxy-api LICENSE README.md README_CN.md config.example.yaml
- name: Create asset checksum
shell: bash
run: |
set -euo pipefail
shopt -s nullglob
archives=(dist/CLIProxyAPI_*.tar.gz)
if [[ ${#archives[@]} -ne 1 ]]; then
printf 'expected one archive, found %s\n' "${#archives[@]}" >&2
printf '%s\n' "${archives[@]}" >&2
exit 1
fi
archive="${archives[0]}"
archive_name="$(basename "$archive")"
sha256sum "$archive" | awk -v name="$archive_name" '{print $1 " " name}' > "$archive.sha256"
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
Expand All @@ -464,9 +418,9 @@ jobs:
run: |
set -euo pipefail
shopt -s nullglob
assets=(dist/CLIProxyAPI_*.tar.gz dist/CLIProxyAPI_*.tar.gz.sha256)
if [[ ${#assets[@]} -lt 2 ]]; then
printf 'expected archive and checksum assets, found %s\n' "${#assets[@]}" >&2
assets=(dist/CLIProxyAPI_*.tar.gz)
if [[ ${#assets[@]} -eq 0 ]]; then
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
printf '%s\n' "${assets[@]}" >&2
exit 1
fi
Expand Down Expand Up @@ -586,20 +540,6 @@ jobs:
cp "dist/${TARGET}/bin/cli-proxy-api" "$archive_dir/cli-proxy-api"
cp LICENSE README.md README_CN.md config.example.yaml "$archive_dir/"
tar -C "$archive_dir" -czf "dist/$archive_name" cli-proxy-api LICENSE README.md README_CN.md config.example.yaml
- name: Create asset checksum
shell: bash
run: |
set -euo pipefail
shopt -s nullglob
archives=(dist/CLIProxyAPI_*.tar.gz)
if [[ ${#archives[@]} -ne 1 ]]; then
printf 'expected one archive, found %s\n' "${#archives[@]}" >&2
printf '%s\n' "${archives[@]}" >&2
exit 1
fi
archive="${archives[0]}"
archive_name="$(basename "$archive")"
sha256sum "$archive" | awk -v name="$archive_name" '{print $1 " " name}' > "$archive.sha256"
- uses: actions/upload-artifact@v4
with:
name: freebsd-${{ matrix.goarch }}
Expand All @@ -612,9 +552,9 @@ jobs:
run: |
set -euo pipefail
shopt -s nullglob
assets=(dist/CLIProxyAPI_*.tar.gz dist/CLIProxyAPI_*.tar.gz.sha256)
if [[ ${#assets[@]} -lt 2 ]]; then
printf 'expected archive and checksum assets, found %s\n' "${#assets[@]}" >&2
assets=(dist/CLIProxyAPI_*.tar.gz)
if [[ ${#assets[@]} -eq 0 ]]; then
printf 'expected archive assets, found %s\n' "${#assets[@]}" >&2
printf '%s\n' "${assets[@]}" >&2
exit 1
fi
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ VisionCoder is also offering our users a limited-time <a href="https://coder.vis
<td width="180"><a href="https://apikey.fun/register?aff=CLIProxyAPI"><img src="./assets/apikey.png" alt="APIKEY.FUN" width="150"></a></td>
<td>Thanks to APIKEY.FUN for sponsoring this project! APIKEY.FUN is a professional enterprise-grade AI relay platform dedicated to providing stable, efficient, and low-cost AI model API access for enterprises and individual developers. The platform supports popular mainstream models such as Claude, OpenAI, and Gemini, with prices as low as 7% of the official price. Register through this project's <a href="https://apikey.fun/register?aff=CLIProxyAPI">exclusive link</a> to enjoy a special <b>permanent 5% top-up discount</b>.</td>
</tr>
<tr>
<td width="180"><a href="https://runapi.co/register?aff=FivD"><img src="./assets/runapi.png" alt="RunAPI" width="150"></a></td>
<td>RunAPI is an efficient and stable API platform—an alternative to OpenRouter. A single API Key gives you access to 150+ leading models, including OpenAI, Claude, Gemini, DeepSeek, Grok, and more, at prices as low as 10% of the original (up to 90% off), with exceptional stability. It's seamlessly compatible with tools like Claude Code, OpenClaw, and others. RunAPI offers an exclusive perk for CPA users: <a href="https://runapi.co/register?aff=FivD">register</a> and contact an administrator to claim ¥7 in free credit.</td>
</tr>
</tbody>
</table>

Expand Down
4 changes: 4 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ VisionCoder 还为我们的用户提供 <a href="https://coder.visioncoder.cn" t
<td width="180"><a href="https://apikey.fun/register?aff=CLIProxyAPI"><img src="./assets/apikey.png" alt="APIKEY.FUN" width="150"></a></td>
<td>感谢 APIKEY.FUN 赞助本项目!APIKEY.FUN 是一家专业的企业级 AI 中转站,致力于为企业和个人开发者提供稳定、高效、低成本的 AI 模型 API 接入服务。平台支持 Claude、OpenAI、Gemini 等主流热门模型,价格低至官方原价的 7%。通过本项目<a href="https://apikey.fun/register?aff=CLIProxyAPI">专属链接</a>注册,还可享受最高 <b>充值永久 95 折</b> 专属优惠。</td>
</tr>
<tr>
<td width="180"><a href="https://runapi.co/register?aff=FivD"><img src="./assets/runapi.png" alt="RunAPI" width="150"></a></td>
<td>RunAPI 是高效稳定的API OpenRouter平替平台,一个 API Key 即可访问 OpenAI、Claude、Gemini、DeepSeek、Grok 等 150+ 主流模型,低至 1 折,极其稳定,可以无缝兼容 Claude Code、OpenClaw 等工具。RunAPI 为 CPA的用户提供专属福利:<a href="https://runapi.co/register?aff=FivD">注册</a>联系管理员即可领取¥7的免费额度</td>
</tr>
</tbody>
</table>

Expand Down
4 changes: 4 additions & 0 deletions README_JA.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ PackyCodeは当ソフトウェアのユーザーに特別割引を提供して
<td width="180"><a href="https://apikey.fun/register?aff=CLIProxyAPI"><img src="./assets/apikey.png" alt="APIKEY.FUN" width="150"></a></td>
<td>APIKEY.FUNのスポンサーシップに感謝します!APIKEY.FUNはプロフェッショナルなエンタープライズ向けAIリレーサービスで、企業および個人開発者に安定・高効率・低コストなAIモデルAPI接続サービスを提供しています。Claude、OpenAI、Geminiなどの主要人気モデルに対応し、価格は公式価格の7%から利用できます。本プロジェクトの<a href="https://apikey.fun/register?aff=CLIProxyAPI">専用リンク</a>から登録すると、さらに<b>チャージが永続的に5%割引</b>となる特別優待を受けられます。</td>
</tr>
<tr>
<td width="180"><a href="https://runapi.co/register?aff=FivD"><img src="./assets/runapi.png" alt="RunAPI" width="150"></a></td>
<td>RunAPIは高効率で安定したAPIプラットフォームで、OpenRouterの代替として利用できます。1つのAPI KeyでOpenAI、Claude、Gemini、DeepSeek、Grokなど150以上の主要モデルにアクセスでき、価格は公式価格の10%から、非常に安定しており、Claude Code、OpenClawなどのツールとシームレスに互換性があります。RunAPIはCPAユーザー向けに特別特典を提供しています:<a href="https://runapi.co/register?aff=FivD">登録</a>後に管理者へ連絡すると、7元分の無料クレジットを受け取れます。</td>
</tr>
</tbody>
</table>

Expand Down
Binary file added assets/runapi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion internal/safemode/example_api_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func WarningServerURL(cfg *config.Config) string {
func NewExampleAPIKeyWarningHandler(configPath string, keys []string) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL == nil || r.URL.Path != "/" {
if r.URL == nil || (r.URL.Path != "/" && r.URL.Path != "/management.html") {
http.NotFound(w, r)
return
}
Expand Down
10 changes: 10 additions & 0 deletions internal/safemode/example_api_keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ func TestExampleAPIKeyWarningHandler(t *testing.T) {
}
}

req = httptest.NewRequest(http.MethodGet, "/management.html", nil)
w = httptest.NewRecorder()
handler.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("GET /management.html status = %d, want %d", w.Code, http.StatusOK)
}
if body := w.Body.String(); !strings.Contains(body, "Example API key detected") {
t.Fatalf("GET /management.html body missing warning: %s", body)
}

req = httptest.NewRequest(http.MethodHead, "/", nil)
w = httptest.NewRecorder()
handler.ServeHTTP(w, req)
Expand Down
Loading