coding-proxy 0.1.0__tar.gz
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.
- coding_proxy-0.1.0/.github/workflows/promote.yml +163 -0
- coding_proxy-0.1.0/.github/workflows/release.yml +151 -0
- coding_proxy-0.1.0/.gitignore +17 -0
- coding_proxy-0.1.0/AGENTS.md +82 -0
- coding_proxy-0.1.0/CHANGELOG.md +34 -0
- coding_proxy-0.1.0/CLAUDE.md +1 -0
- coding_proxy-0.1.0/LICENSE +201 -0
- coding_proxy-0.1.0/PKG-INFO +184 -0
- coding_proxy-0.1.0/README.md +168 -0
- coding_proxy-0.1.0/config.example.yaml +273 -0
- coding_proxy-0.1.0/docs/framework.md +1640 -0
- coding_proxy-0.1.0/docs/user-guide.md +1490 -0
- coding_proxy-0.1.0/docs/zh-CN/README.md +168 -0
- coding_proxy-0.1.0/pyproject.toml +32 -0
- coding_proxy-0.1.0/src/coding/__init__.py +0 -0
- coding_proxy-0.1.0/src/coding/proxy/__init__.py +3 -0
- coding_proxy-0.1.0/src/coding/proxy/__main__.py +5 -0
- coding_proxy-0.1.0/src/coding/proxy/auth/__init__.py +13 -0
- coding_proxy-0.1.0/src/coding/proxy/auth/providers/__init__.py +6 -0
- coding_proxy-0.1.0/src/coding/proxy/auth/providers/base.py +35 -0
- coding_proxy-0.1.0/src/coding/proxy/auth/providers/github.py +133 -0
- coding_proxy-0.1.0/src/coding/proxy/auth/providers/google.py +237 -0
- coding_proxy-0.1.0/src/coding/proxy/auth/runtime.py +122 -0
- coding_proxy-0.1.0/src/coding/proxy/auth/store.py +74 -0
- coding_proxy-0.1.0/src/coding/proxy/cli/__init__.py +151 -0
- coding_proxy-0.1.0/src/coding/proxy/cli/auth_commands.py +224 -0
- coding_proxy-0.1.0/src/coding/proxy/compat/__init__.py +30 -0
- coding_proxy-0.1.0/src/coding/proxy/compat/canonical.py +193 -0
- coding_proxy-0.1.0/src/coding/proxy/compat/session_store.py +137 -0
- coding_proxy-0.1.0/src/coding/proxy/config/__init__.py +6 -0
- coding_proxy-0.1.0/src/coding/proxy/config/auth_schema.py +24 -0
- coding_proxy-0.1.0/src/coding/proxy/config/loader.py +139 -0
- coding_proxy-0.1.0/src/coding/proxy/config/resiliency.py +46 -0
- coding_proxy-0.1.0/src/coding/proxy/config/routing.py +279 -0
- coding_proxy-0.1.0/src/coding/proxy/config/schema.py +280 -0
- coding_proxy-0.1.0/src/coding/proxy/config/server.py +23 -0
- coding_proxy-0.1.0/src/coding/proxy/config/vendors.py +53 -0
- coding_proxy-0.1.0/src/coding/proxy/convert/__init__.py +14 -0
- coding_proxy-0.1.0/src/coding/proxy/convert/anthropic_to_gemini.py +352 -0
- coding_proxy-0.1.0/src/coding/proxy/convert/anthropic_to_openai.py +352 -0
- coding_proxy-0.1.0/src/coding/proxy/convert/gemini_sse_adapter.py +169 -0
- coding_proxy-0.1.0/src/coding/proxy/convert/gemini_to_anthropic.py +98 -0
- coding_proxy-0.1.0/src/coding/proxy/convert/openai_to_anthropic.py +88 -0
- coding_proxy-0.1.0/src/coding/proxy/logging/__init__.py +49 -0
- coding_proxy-0.1.0/src/coding/proxy/logging/db.py +308 -0
- coding_proxy-0.1.0/src/coding/proxy/logging/stats.py +129 -0
- coding_proxy-0.1.0/src/coding/proxy/model/__init__.py +93 -0
- coding_proxy-0.1.0/src/coding/proxy/model/auth.py +32 -0
- coding_proxy-0.1.0/src/coding/proxy/model/compat.py +153 -0
- coding_proxy-0.1.0/src/coding/proxy/model/constants.py +21 -0
- coding_proxy-0.1.0/src/coding/proxy/model/pricing.py +70 -0
- coding_proxy-0.1.0/src/coding/proxy/model/token.py +64 -0
- coding_proxy-0.1.0/src/coding/proxy/model/vendor.py +218 -0
- coding_proxy-0.1.0/src/coding/proxy/pricing.py +100 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/__init__.py +47 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/circuit_breaker.py +152 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/error_classifier.py +67 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/executor.py +453 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/model_mapper.py +90 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/quota_guard.py +169 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/rate_limit.py +159 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/retry.py +82 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/router.py +84 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/session_manager.py +62 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/tier.py +171 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/usage_parser.py +193 -0
- coding_proxy-0.1.0/src/coding/proxy/routing/usage_recorder.py +131 -0
- coding_proxy-0.1.0/src/coding/proxy/server/__init__.py +1 -0
- coding_proxy-0.1.0/src/coding/proxy/server/app.py +142 -0
- coding_proxy-0.1.0/src/coding/proxy/server/factory.py +175 -0
- coding_proxy-0.1.0/src/coding/proxy/server/request_normalizer.py +139 -0
- coding_proxy-0.1.0/src/coding/proxy/server/responses.py +74 -0
- coding_proxy-0.1.0/src/coding/proxy/server/routes.py +264 -0
- coding_proxy-0.1.0/src/coding/proxy/streaming/__init__.py +1 -0
- coding_proxy-0.1.0/src/coding/proxy/streaming/anthropic_compat.py +484 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/__init__.py +29 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/anthropic.py +44 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/antigravity.py +328 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/base.py +353 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/copilot.py +702 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/copilot_models.py +438 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/copilot_token_manager.py +167 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/copilot_urls.py +16 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/mixins.py +71 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/token_manager.py +128 -0
- coding_proxy-0.1.0/src/coding/proxy/vendors/zhipu.py +243 -0
- coding_proxy-0.1.0/tests/__init__.py +0 -0
- coding_proxy-0.1.0/tests/test_antigravity.py +339 -0
- coding_proxy-0.1.0/tests/test_app_routes.py +643 -0
- coding_proxy-0.1.0/tests/test_auto_login.py +454 -0
- coding_proxy-0.1.0/tests/test_circuit_breaker.py +49 -0
- coding_proxy-0.1.0/tests/test_cli_usage.py +110 -0
- coding_proxy-0.1.0/tests/test_compat.py +72 -0
- coding_proxy-0.1.0/tests/test_config_loader.py +512 -0
- coding_proxy-0.1.0/tests/test_convert_request.py +319 -0
- coding_proxy-0.1.0/tests/test_convert_response.py +289 -0
- coding_proxy-0.1.0/tests/test_convert_sse.py +483 -0
- coding_proxy-0.1.0/tests/test_copilot.py +871 -0
- coding_proxy-0.1.0/tests/test_copilot_convert_request.py +419 -0
- coding_proxy-0.1.0/tests/test_copilot_convert_response.py +217 -0
- coding_proxy-0.1.0/tests/test_copilot_models.py +193 -0
- coding_proxy-0.1.0/tests/test_copilot_urls.py +67 -0
- coding_proxy-0.1.0/tests/test_currency.py +200 -0
- coding_proxy-0.1.0/tests/test_error_classifier.py +176 -0
- coding_proxy-0.1.0/tests/test_mixins.py +105 -0
- coding_proxy-0.1.0/tests/test_model_auth.py +97 -0
- coding_proxy-0.1.0/tests/test_model_compat.py +471 -0
- coding_proxy-0.1.0/tests/test_model_constants.py +60 -0
- coding_proxy-0.1.0/tests/test_model_mapper.py +91 -0
- coding_proxy-0.1.0/tests/test_model_pricing.py +79 -0
- coding_proxy-0.1.0/tests/test_model_token.py +155 -0
- coding_proxy-0.1.0/tests/test_model_vendor.py +695 -0
- coding_proxy-0.1.0/tests/test_parse_usage.py +284 -0
- coding_proxy-0.1.0/tests/test_pricing.py +237 -0
- coding_proxy-0.1.0/tests/test_quota_guard.py +144 -0
- coding_proxy-0.1.0/tests/test_rate_limit.py +111 -0
- coding_proxy-0.1.0/tests/test_request_normalizer.py +82 -0
- coding_proxy-0.1.0/tests/test_router_chain.py +1093 -0
- coding_proxy-0.1.0/tests/test_router_executor.py +863 -0
- coding_proxy-0.1.0/tests/test_runtime_reauth.py +194 -0
- coding_proxy-0.1.0/tests/test_schema.py +154 -0
- coding_proxy-0.1.0/tests/test_streaming_anthropic_compat.py +673 -0
- coding_proxy-0.1.0/tests/test_tier.py +317 -0
- coding_proxy-0.1.0/tests/test_tiers_config.py +234 -0
- coding_proxy-0.1.0/tests/test_token_logger.py +442 -0
- coding_proxy-0.1.0/tests/test_token_manager.py +184 -0
- coding_proxy-0.1.0/tests/test_types.py +222 -0
- coding_proxy-0.1.0/tests/test_vendor_streaming.py +394 -0
- coding_proxy-0.1.0/tests/test_vendors.py +442 -0
- coding_proxy-0.1.0/tests/test_zhipu.py +260 -0
- coding_proxy-0.1.0/uv.lock +445 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# coding-proxy: Prerelease → Stable Promotion Workflow
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Trigger: Manual workflow_dispatch with tag_name input
|
|
5
|
+
# Purpose: Promote a validated TestPyPI prerelease to PyPI production
|
|
6
|
+
#
|
|
7
|
+
# Flow:
|
|
8
|
+
# Job 1 (validate): Verify target release exists AND is a prerelease
|
|
9
|
+
# Job 2 (promote): Update GitHub Release metadata + build/publish to PyPI
|
|
10
|
+
#
|
|
11
|
+
# Safety Guarantees:
|
|
12
|
+
# - Refuses to promote non-prerelease releases (idempotency guard)
|
|
13
|
+
# - Uses environment: pypi for deployment approval gate (human gate)
|
|
14
|
+
# - Concurrency group prevents simultaneous promotions of same tag
|
|
15
|
+
# - Rebuilds from git tag for deterministic, reproducible artifacts
|
|
16
|
+
#
|
|
17
|
+
# Paired with: release.yml (initial release creation)
|
|
18
|
+
#
|
|
19
|
+
# Pre-requisites (same auth options as release.yml):
|
|
20
|
+
# Option A — OIDC Trusted Publishing:
|
|
21
|
+
# 1. Create GitHub Environment: "pypi" with required reviewers
|
|
22
|
+
# 2. Configure Trusted Publisher on PyPI admin panel
|
|
23
|
+
# Option B — API Token Fallback:
|
|
24
|
+
# 1. Set repository secret: PYPI_API_TOKEN
|
|
25
|
+
# 2. (Optional) Create "pypi" environment for deployment guards
|
|
26
|
+
#
|
|
27
|
+
# References:
|
|
28
|
+
# [1] https://docs.github.com/en/rest/releases/releases#update-a-release
|
|
29
|
+
# [2] https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
|
|
30
|
+
# =============================================================================
|
|
31
|
+
|
|
32
|
+
name: Promote Prerelease to PyPI
|
|
33
|
+
|
|
34
|
+
on:
|
|
35
|
+
workflow_dispatch:
|
|
36
|
+
inputs:
|
|
37
|
+
tag_name:
|
|
38
|
+
description: '待提升的 prerelease tag(如 v0.2.0a1)'
|
|
39
|
+
required: true
|
|
40
|
+
type: string
|
|
41
|
+
|
|
42
|
+
permissions:
|
|
43
|
+
contents: read
|
|
44
|
+
|
|
45
|
+
concurrency:
|
|
46
|
+
group: promote-${{ inputs.tag_name }}
|
|
47
|
+
cancel-in-progress: false
|
|
48
|
+
|
|
49
|
+
jobs:
|
|
50
|
+
# ===========================================================================
|
|
51
|
+
# Job 1: VALIDATE -- Confirm release exists and is a prerelease
|
|
52
|
+
# ===========================================================================
|
|
53
|
+
validate:
|
|
54
|
+
name: Validate prerelease status
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
timeout-minutes: 5
|
|
57
|
+
|
|
58
|
+
steps:
|
|
59
|
+
- name: Check release exists and is a prerelease
|
|
60
|
+
uses: actions/github-script@v7
|
|
61
|
+
id: check-release
|
|
62
|
+
with:
|
|
63
|
+
script: |
|
|
64
|
+
const tag = context.payload.inputs.tag_name;
|
|
65
|
+
const { owner, repo } = context.repo;
|
|
66
|
+
|
|
67
|
+
const release = await github.rest.releases.getReleaseByTag({
|
|
68
|
+
owner,
|
|
69
|
+
repo,
|
|
70
|
+
tag,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const isPrerelease = release.data.prerelease;
|
|
74
|
+
const releaseId = release.data.id;
|
|
75
|
+
const tagName = release.data.tag_name;
|
|
76
|
+
|
|
77
|
+
if (!isPrerelease) {
|
|
78
|
+
core.setFailed(
|
|
79
|
+
`Release ${tagName} is NOT a prerelease. ` +
|
|
80
|
+
`Only prereleases can be promoted to stable.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
core.setOutput('release_id', releaseId);
|
|
85
|
+
core.setOutput('tag_name', tagName);
|
|
86
|
+
core.info(`✅ Validated: release #${releaseId} (${tagName}) is a prerelease`);
|
|
87
|
+
|
|
88
|
+
# ===========================================================================
|
|
89
|
+
# Job 2: PROMOTE -- Update release + publish to PyPI Production
|
|
90
|
+
# ===========================================================================
|
|
91
|
+
promote:
|
|
92
|
+
name: Promote to PyPI Production
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
needs: validate
|
|
95
|
+
timeout-minutes: 15
|
|
96
|
+
environment:
|
|
97
|
+
name: pypi
|
|
98
|
+
url: https://pypi.org/p/coding-proxy
|
|
99
|
+
permissions:
|
|
100
|
+
contents: write # 更新 Release 元数据所需
|
|
101
|
+
id-token: write # OIDC Trusted Publishing 所需
|
|
102
|
+
|
|
103
|
+
steps:
|
|
104
|
+
# -----------------------------------------------------------------------
|
|
105
|
+
# Step 1: 检出精确的 git tag 用于确定性重建
|
|
106
|
+
# -----------------------------------------------------------------------
|
|
107
|
+
- name: Checkout repository at release tag
|
|
108
|
+
uses: actions/checkout@v4
|
|
109
|
+
with:
|
|
110
|
+
ref: ${{ needs.validate.outputs.tag_name }}
|
|
111
|
+
persist-credentials: false
|
|
112
|
+
|
|
113
|
+
# -----------------------------------------------------------------------
|
|
114
|
+
# Step 2: 更新 GitHub Release: prerelease=false, make_latest=true
|
|
115
|
+
# -----------------------------------------------------------------------
|
|
116
|
+
- name: Promote release to stable
|
|
117
|
+
uses: actions/github-script@v7
|
|
118
|
+
with:
|
|
119
|
+
script: |
|
|
120
|
+
const releaseId = ${{ needs.validate.outputs.release_id }};
|
|
121
|
+
const { owner, repo } = context.repo;
|
|
122
|
+
|
|
123
|
+
await github.rest.releases.update({
|
|
124
|
+
owner,
|
|
125
|
+
repo,
|
|
126
|
+
release_id: releaseId,
|
|
127
|
+
prerelease: false,
|
|
128
|
+
make_latest: true,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
core.notice(
|
|
132
|
+
`✅ Release #${releaseId} promoted to stable (make_latest=true)`
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
# -----------------------------------------------------------------------
|
|
136
|
+
# Step 3: 从 tagged source 构建分发包
|
|
137
|
+
# -----------------------------------------------------------------------
|
|
138
|
+
- name: Set up Python
|
|
139
|
+
uses: actions/setup-python@v5
|
|
140
|
+
with:
|
|
141
|
+
python-version: "3.13"
|
|
142
|
+
|
|
143
|
+
- name: Set up uv
|
|
144
|
+
uses: astral-sh/setup-uv@v4
|
|
145
|
+
with:
|
|
146
|
+
enable-cache: true
|
|
147
|
+
|
|
148
|
+
- name: Install build dependencies
|
|
149
|
+
run: uv pip install --system build twine
|
|
150
|
+
|
|
151
|
+
- name: Build sdist and wheel
|
|
152
|
+
run: python -m build
|
|
153
|
+
|
|
154
|
+
- name: Check package metadata
|
|
155
|
+
run: twine check dist/*
|
|
156
|
+
|
|
157
|
+
# -----------------------------------------------------------------------
|
|
158
|
+
# Step 4: 发布到 PyPI Production
|
|
159
|
+
# -----------------------------------------------------------------------
|
|
160
|
+
- name: Publish to PyPI
|
|
161
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
162
|
+
with:
|
|
163
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# coding-proxy: PyPI Publishing Workflow (Initial Release)
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Trigger: GitHub Release publication event
|
|
5
|
+
# Architecture: Build-Publish Separation (PyPA security best practice)
|
|
6
|
+
# Paired with: promote.yml (prerelease → stable promotion gate)
|
|
7
|
+
# - Job 1 (build): Low privileges, produces sdist+wheel artifacts
|
|
8
|
+
# - Job 2 (publish-testpypi): Publish to TestPyPI (prereleases only)
|
|
9
|
+
# - Job 3 (publish-pypi): Publish to PyPI (stable releases / hotfixes)
|
|
10
|
+
#
|
|
11
|
+
# Routing Logic:
|
|
12
|
+
# - prerelease == true --> TestPyPI (with skip-existing tolerance)
|
|
13
|
+
# --> THEN use promote.yml to promote to PyPI after validation
|
|
14
|
+
# - prerelease == false --> PyPI production (direct stable release, e.g. hotfixes)
|
|
15
|
+
#
|
|
16
|
+
# Promotion Flow (see promote.yml):
|
|
17
|
+
# 1. Create release with prerelease: true --> builds + publishes to TestPyPI
|
|
18
|
+
# 2. Human validates package on TestPyPI
|
|
19
|
+
# 3. Run promote.yml (workflow_dispatch) --> promotes to PyPI production
|
|
20
|
+
#
|
|
21
|
+
# Pre-requisites (choose ONE authentication method):
|
|
22
|
+
#
|
|
23
|
+
# Option A — OIDC Trusted Publishing (recommended, no secrets needed):
|
|
24
|
+
# 1. Create GitHub Environments: "pypi" and "testpypi"
|
|
25
|
+
# 2. Configure Trusted Publishers on PyPI/TestPyPI admin panels
|
|
26
|
+
# 3. (Recommended) Set "Required reviewers" on "pypi" environment
|
|
27
|
+
#
|
|
28
|
+
# Option B — API Token Fallback (simpler initial setup):
|
|
29
|
+
# 1. Set repository secrets: PYPI_API_TOKEN and/or TEST_PYPI_API_TOKEN
|
|
30
|
+
# 2. (Optional) Create "pypi"/"testpypi" environments for deployment guards
|
|
31
|
+
# If environments are not created, remove the `environment:` blocks below.
|
|
32
|
+
#
|
|
33
|
+
# References:
|
|
34
|
+
# [1] https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
|
|
35
|
+
# [2] https://github.com/pypa/gh-action-pypi-publish
|
|
36
|
+
# [3] https://docs.pypi.org/trusted-publishers/using-a-publisher/
|
|
37
|
+
# =============================================================================
|
|
38
|
+
|
|
39
|
+
name: Release / Publish to PyPI
|
|
40
|
+
|
|
41
|
+
on:
|
|
42
|
+
release:
|
|
43
|
+
types: [published]
|
|
44
|
+
|
|
45
|
+
permissions:
|
|
46
|
+
contents: read
|
|
47
|
+
|
|
48
|
+
concurrency:
|
|
49
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
50
|
+
cancel-in-progress: true
|
|
51
|
+
|
|
52
|
+
jobs:
|
|
53
|
+
# ===========================================================================
|
|
54
|
+
# Job 1: BUILD -- Produce distribution artifacts (low privilege isolation)
|
|
55
|
+
# ===========================================================================
|
|
56
|
+
build:
|
|
57
|
+
name: Build distributions
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
timeout-minutes: 10
|
|
60
|
+
|
|
61
|
+
steps:
|
|
62
|
+
- name: Checkout repository
|
|
63
|
+
uses: actions/checkout@v4
|
|
64
|
+
with:
|
|
65
|
+
persist-credentials: false
|
|
66
|
+
|
|
67
|
+
- name: Set up Python
|
|
68
|
+
uses: actions/setup-python@v5
|
|
69
|
+
with:
|
|
70
|
+
python-version: "3.13"
|
|
71
|
+
|
|
72
|
+
- name: Set up uv
|
|
73
|
+
uses: astral-sh/setup-uv@v4
|
|
74
|
+
with:
|
|
75
|
+
enable-cache: true
|
|
76
|
+
|
|
77
|
+
- name: Install build dependencies
|
|
78
|
+
run: uv pip install --system build twine
|
|
79
|
+
|
|
80
|
+
- name: Build sdist and wheel
|
|
81
|
+
run: python -m build
|
|
82
|
+
|
|
83
|
+
- name: Check package metadata
|
|
84
|
+
run: twine check dist/*
|
|
85
|
+
|
|
86
|
+
- name: Upload build artifacts
|
|
87
|
+
uses: actions/upload-artifact@v4
|
|
88
|
+
with:
|
|
89
|
+
name: dist
|
|
90
|
+
path: dist/
|
|
91
|
+
retention-days: 14
|
|
92
|
+
|
|
93
|
+
# ===========================================================================
|
|
94
|
+
# Job 2: PUBLISH TO TESTPYPI -- Prerelease / staging releases only
|
|
95
|
+
# ===========================================================================
|
|
96
|
+
publish-testpypi:
|
|
97
|
+
name: Publish to TestPyPI
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
needs: build
|
|
100
|
+
if: github.event.release.prerelease == true
|
|
101
|
+
timeout-minutes: 10
|
|
102
|
+
environment:
|
|
103
|
+
name: testpypi
|
|
104
|
+
url: https://test.pypi.org/p/coding-proxy
|
|
105
|
+
permissions:
|
|
106
|
+
id-token: write
|
|
107
|
+
contents: read
|
|
108
|
+
|
|
109
|
+
steps:
|
|
110
|
+
- name: Download build artifacts
|
|
111
|
+
uses: actions/download-artifact@v4
|
|
112
|
+
with:
|
|
113
|
+
name: dist
|
|
114
|
+
path: dist/
|
|
115
|
+
|
|
116
|
+
- name: Publish to TestPyPI
|
|
117
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
118
|
+
with:
|
|
119
|
+
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
|
120
|
+
repository-url: https://test.pypi.org/legacy/
|
|
121
|
+
skip-existing: true
|
|
122
|
+
attestations: false # TestPyPI 不支持 attestations,必须显式禁用
|
|
123
|
+
verbose: true # 启用详细日志以获取 400 错误响应体
|
|
124
|
+
|
|
125
|
+
# ===========================================================================
|
|
126
|
+
# Job 3: PUBLISH TO PYPI -- Production releases only
|
|
127
|
+
# ===========================================================================
|
|
128
|
+
publish-pypi:
|
|
129
|
+
name: Publish to PyPI
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
needs: build
|
|
132
|
+
if: github.event.release.prerelease == false
|
|
133
|
+
timeout-minutes: 10
|
|
134
|
+
environment:
|
|
135
|
+
name: pypi
|
|
136
|
+
url: https://pypi.org/p/coding-proxy
|
|
137
|
+
permissions:
|
|
138
|
+
id-token: write
|
|
139
|
+
contents: read
|
|
140
|
+
|
|
141
|
+
steps:
|
|
142
|
+
- name: Download build artifacts
|
|
143
|
+
uses: actions/download-artifact@v4
|
|
144
|
+
with:
|
|
145
|
+
name: dist
|
|
146
|
+
path: dist/
|
|
147
|
+
|
|
148
|
+
- name: Publish to PyPI
|
|
149
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
150
|
+
with:
|
|
151
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Collaboration Protocol (协作协议)
|
|
4
|
+
|
|
5
|
+
本文件旨在规范 AI Agent(Claude Code、Antigravity 等)在本项目中的代码与文档协作行为。
|
|
6
|
+
|
|
7
|
+
- **Core Language**: Output MUST be in **Chinese (Simplified)** unless serving code/technical constraints.
|
|
8
|
+
- **Tone**: Professional, precise, and evidence-based.
|
|
9
|
+
|
|
10
|
+
## Project Positioning (项目定位)
|
|
11
|
+
|
|
12
|
+
参考 README.md
|
|
13
|
+
|
|
14
|
+
## Engineering Code of Conduct (工程行为准则)
|
|
15
|
+
|
|
16
|
+
**Core Philosophy**: **Entropy Reduction (熵减)**. 通过上下文锚定、复用驱动与标准化流水线,对抗软件系统的无序熵增。
|
|
17
|
+
|
|
18
|
+
### 道 (Mindset - 认知心法)
|
|
19
|
+
|
|
20
|
+
- **Context-Driven (上下文驱动)**: 上下文是第一性要素 (Context Quality First)。任何变更需建立在深度理解之上(CDD),拒绝基于关键字匹配的机械式修改。
|
|
21
|
+
- **Minimal Intervention (最小干预)**: 遵循奥卡姆剃刀与 YAGNI 原则,仅实施必要的变更,推崇演进式设计 (Evolutionary Design) 而非过度设计。
|
|
22
|
+
- **Evidence-Based (循证工程)**: 杜绝主观臆断,核心决策需以权威文献(IEEE 格式)为佐证,构建 Feedback Loops 以验证假设。
|
|
23
|
+
- **Systemic Integrity (系统完整性)**: 具备全局视角与二阶思维 (Second-Order Thinking),评估变更对上下游依赖及整个生态(Engine, Adapter, Agent, UI)的“涟漪效应”,优先保障整体稳定性与逻辑自洽。
|
|
24
|
+
|
|
25
|
+
### 法 (Strategy - 架构原则)
|
|
26
|
+
|
|
27
|
+
- **Plan Node Default (默认规划模式)**: 面对任何非琐碎任务(预估步骤 > 3 或涉及架构级决策),**必须**率先进入 Plan 模式。规划产物需明确界定:功能边界、边缘 Case 应对策略、与现有逻辑的交互锚点以及预计改动的爆炸半径。
|
|
28
|
+
- **Subagent Strategy (子代理并发策略)**: 面对高复杂度命题,严禁主 Agent 单点统揽。应贯彻“算力换空间”思路,果断编排 Subagent 进行任务拆解与并行攻坚,主 Agent 的职责需严格收敛于上下文协同与最终成果的组装整合。
|
|
29
|
+
- **Verification Before Done (交付前验证定式)**: 严禁在缺乏确凿运行证据的情况下标记任务为“已完成”。交付阶段**强制要求**提供客观自证材料:Diff 变更分析、测试用例覆盖、实施日志截图及核心链路边缘 Case 验证结果,并时刻以“方案是否能通过 Staff Engineer 严格审查”的视角自检。
|
|
30
|
+
- **Reuse-Driven (复用驱动)**: Composition over Construction。系统变更**必须**主动参考业界经典设计模式与最佳实践。在进入实质性编码前,需率先对相关领域的成熟范式进行深度调研,并结合当前项目上下文输出充分的关联分析与方案梳理。坚决贯彻“拿来主义”,优先通过组合与集成来构建系统,防范闭门造车与重复造轮子。
|
|
31
|
+
- **Boundary Management (边界管理)**: 严控模块/Agent 间的职责边界与契约,确保高内聚低耦合,防范隐式依赖穿透。
|
|
32
|
+
- **Orthogonal Decomposition (正交分解)**: 坚持“正交地提取概念主体”。识别系统中独立变化的维度并进行解耦(如机制与策略分离),确保单一概念主体的变更具备局部性,避免逻辑纠缠。
|
|
33
|
+
- **Feedback Loops (反馈闭环)**:构建“设计-实现-验证”的完整闭环,确保每一项工程行动都能产生可观测的反馈信号(测试、日志、监控),以验证假设并指导迭代。
|
|
34
|
+
- **Evolutionary Design (演进式设计)**: 将系统视为有机体,通过将 AI 错误转化为经验约束 (Negative Prompts) 和持久化知识,实现系统的自我进化与熵减。
|
|
35
|
+
- **Second-Order Thinking (二阶思维)**:不只关注变更的直接结果,更要预测“结果的结果”(如引入缓存导致的陈旧数据、重试机制引发的雪崩),未雨绸缪防范隐性风险。
|
|
36
|
+
- **Single Source of Truth (单一事实源)**:严格维护唯一的权威定义源。引用时**必须**使用轻量级指针 (Link/ID) 而非数据副本 (Copy-Paste),从根源消除断裂 (Split-Brain) 风险。
|
|
37
|
+
- **Proactive Navigation (主动导航)**: 智能体不应止步于被动响应,需即时转化为“领航者”。在交付任务结果的同时,**必须**基于上下文预判并提出**下一步最佳行动建议 (Next Best Action)**。不仅交付“答案”,更要交付“路径”,消除用户决策的认知摩擦,确保持续的熵减动量。
|
|
38
|
+
|
|
39
|
+
### 术 (Tactics - 执行规范)
|
|
40
|
+
|
|
41
|
+
- **Vibe Coding Pipeline**: 遵循 **Specification-Driven (规划驱动)** + **Context-Anchored (上下文锚定)** + **AI-Pair (AI 结对)** 模式,将开发固化为可审计的流水线,避免代码腐化为无法维护的“大泥球 (Big Ball of Mud)”。
|
|
42
|
+
- **Visual Documentation (图文并茂)**: 对于复杂逻辑,优先使用 Mermaid 图表(Sequence/Flowchart/Class)辅助说明,构建“图文并茂”的直观文档。
|
|
43
|
+
- **Direct Hyperlinking (直接跳转)**: 在文档中提及 Repo 内其他资源(文档/代码)时,**必须**构建可跳转的相对路径链接(如 `[Doc Name](./path.md)`),严禁使用“死文本”引用,以降低信息检索熵。
|
|
44
|
+
- **Operational Excellence (卓越运营)**:
|
|
45
|
+
1. **Git Hygiene**: 如非显性要求,严禁调用 git commit;
|
|
46
|
+
2. **Temp Management**: 临时产物(执行计划等)一律收敛至 `.temp/` 并及时清理;
|
|
47
|
+
3. **Link Validity**: 确保所有引用的 URL 可访问且具备明确的上下文价值;
|
|
48
|
+
4. **Git Commit**: 在需要提交变更到 Git 时,一律使用 Shell 调用 Claude Code 的自定义 Slash Command: `/commit` 进行 git commit 操作(若环境中未安装 Claude Code,则直接读取 `~/.claude/commands/commit.md`,按照其中的规则进行 git commit 操作)。不要执行 Rebase。
|
|
49
|
+
- **Package Management Standardization (包管理规范)**:
|
|
50
|
+
1. **Python**: 严禁使用 pip/poetry,**必须**统一使用 `uv` 进行包管理与脚本执行(如 `uv run`);
|
|
51
|
+
2. **JavaScript/TypeScript**: 严禁使用 npm/yarn,**必须**统一使用 `pnpm` 进行包管理与脚本执行。
|
|
52
|
+
- **Database Management**: 谨慎操作,数据迁移、测试等操作严禁将现有数据删除。
|
|
53
|
+
|
|
54
|
+
## Documentation Standards (文档规范)
|
|
55
|
+
|
|
56
|
+
### Mermaid Visualization Norms (Mermaid 可视化规范)
|
|
57
|
+
|
|
58
|
+
- **色彩语义与兼容性**:为图表节点配置具备语义辨识度的色彩,并确保在深色模式(Dark Mode)下具有极高的对比度与清晰度。
|
|
59
|
+
- **逻辑模块化解构**:针对业务跨度较大的架构流程,强制采用 `subgraph` 容器进行层级解构与边界划分,以增强图表的自解说(Self-explaining)能力。
|
|
60
|
+
|
|
61
|
+
### Reference Specifications (IEEE)
|
|
62
|
+
|
|
63
|
+
为保障工程决策的可追溯性与学术严谨性,核心引用需遵循 **IEEE 标准引用格式**。
|
|
64
|
+
|
|
65
|
+
> **模版准则**:[编号] 作者缩写. 姓, "文章标题," _刊名/会议名缩写 (斜体)_, 卷号, 期数, 页码, 年份.
|
|
66
|
+
|
|
67
|
+
```latex
|
|
68
|
+
[1] A. Author, B. Author, and C. Author, "Title of paper," *Abbrev. Title of Journal*, vol. X, no. Y, pp. XX–XX, Year.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**引用实践**
|
|
72
|
+
|
|
73
|
+
- **文内锚定**:采用标准上标链接形式:`描述内容<sup>[[1]](#ref1)</sup>`。
|
|
74
|
+
- **文献索引**:底层采用 HTML 锚点 `id` 实现跳转稳定性。
|
|
75
|
+
|
|
76
|
+
```latex
|
|
77
|
+
<a id="ref1"></a>[1] A. Vaswani et al., "Attention is all you need," Adv. Neural Inf. Process. Syst., vol. 30, pp. 5998–6008, 2017.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Knowledge Map (知识索引)
|
|
81
|
+
|
|
82
|
+
(WIP)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
本文件基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/) 规范维护,版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [v0.1.0] — 2026-04-05
|
|
8
|
+
|
|
9
|
+
### ✨ 亮点特性
|
|
10
|
+
|
|
11
|
+
> **coding-proxy MVP 版本发布!** 一行环境变量,让 Claude Code 拥有永不宕机的多后端智能代理——主服务故障时毫秒级自动切换至备用通道,编码心流零中断。
|
|
12
|
+
|
|
13
|
+
| 特性 | 价值 |
|
|
14
|
+
| :--------------------- | :------------------------------------------------------------------------------------------------------- |
|
|
15
|
+
| **N-tiers 故障转移** | 灵活编排的供应商优先级与降级链路;<br/>默认 Claude → GitHub Copilot → Antigravity → GLM 全链路自动降级; |
|
|
16
|
+
| **智能熔断器** | 状态机防护雪崩,指数退避自动恢复; |
|
|
17
|
+
| **Token 用量成本看板** | SQLite 本地存储,CLI 多维统计(按天/供应商/模型); |
|
|
18
|
+
| **OAuth2 内置集成** | GitHub Device Flow / Google OAuth 开箱即用,令牌自动轮转; |
|
|
19
|
+
| **协议双向转换** | Anthropic ↔ OpenAI/Gemini 双向无缝翻译; |
|
|
20
|
+
| **模型名自助映射** | 自定义模型转发规则,`claude-*` → `glm-*` 一键切; |
|
|
21
|
+
| **零侵入轻量透明代理** | 开箱即用,配置 `ANTHROPIC_BASE_URL` 即接入,FastAPI 异步架构,交互全透明; |
|
|
22
|
+
| **SSE 流式全链路** | 流式请求完整透传,跨协议 SSE 转换零感知; |
|
|
23
|
+
| **双窗口配额守卫** | 5h 滑动窗口 + 周配额双重护盾,超额前主动预警; |
|
|
24
|
+
|
|
25
|
+
### 🔧 更多特性
|
|
26
|
+
|
|
27
|
+
- 模型定价表支持,按供应商/模型细粒度成本追踪;
|
|
28
|
+
- 指数退避重试机制,可配置最大重试次数与退避策略;
|
|
29
|
+
- Vendor 自动兼容性降级决策;
|
|
30
|
+
- 速率限制头解析与智能等待,精确计算恢复时间;
|
|
31
|
+
- Copilot 421 Misdirection 自动重试;
|
|
32
|
+
- 优雅停机与资源清理,进程退出无残留;
|
|
33
|
+
|
|
34
|
+
[0.1.0]: https://github.com/ThreeFish-AI/coding-proxy/releases/tag/v0.1.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AGENTS.md
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|