@simonyea/holysheep-cli 2.1.33 → 2.1.35
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.
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
name: CI sanity
|
|
2
|
+
|
|
3
|
+
# [HolySheep fork] Minimal Gitea-side CI for holysheep-cli.
|
|
4
|
+
# Mirrors the sanity check pattern from holysheep-webui.
|
|
5
|
+
# Runs on every push to main, guards against regressions in:
|
|
6
|
+
# - package.json version format
|
|
7
|
+
# - runtime fetcher URL/SHA/VERSION consistency
|
|
8
|
+
# - key source files present (claude-process-proxy, pty-hermes-wrapper, droid)
|
|
9
|
+
# - aionui-wrapper brand strings (must not contain [aionui-wrapper] prefix)
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
pull_request:
|
|
15
|
+
branches: [main]
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
sanity:
|
|
19
|
+
name: Sanity check (version + key files + invariants)
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout (host deploy-cache mode)
|
|
23
|
+
run: |
|
|
24
|
+
set -e
|
|
25
|
+
REPO_DIR="/opt/act_runner/deploy-cache/holysheep-cli"
|
|
26
|
+
BRANCH="${{ github.ref_name }}"
|
|
27
|
+
BRANCH="${BRANCH:-${GITHUB_REF_NAME:-main}}"
|
|
28
|
+
echo "branch: $BRANCH"
|
|
29
|
+
if [ -d "$REPO_DIR/.git" ]; then
|
|
30
|
+
cd "$REPO_DIR"
|
|
31
|
+
git fetch origin "$BRANCH"
|
|
32
|
+
git reset --hard "origin/$BRANCH"
|
|
33
|
+
else
|
|
34
|
+
mkdir -p "$REPO_DIR"
|
|
35
|
+
git clone --depth 1 -b "$BRANCH" \
|
|
36
|
+
http://simon:123123aa@localhost:3000/simon/holysheep-cli.git "$REPO_DIR"
|
|
37
|
+
fi
|
|
38
|
+
cd "$REPO_DIR"
|
|
39
|
+
echo "head: $(git rev-parse --short HEAD)"
|
|
40
|
+
echo "msg: $(git log -1 --pretty=%s)"
|
|
41
|
+
|
|
42
|
+
- name: Version format check
|
|
43
|
+
run: |
|
|
44
|
+
set -e
|
|
45
|
+
cd /opt/act_runner/deploy-cache/holysheep-cli
|
|
46
|
+
VER=$(node -e "console.log(require('./package.json').version)")
|
|
47
|
+
echo "version: $VER"
|
|
48
|
+
if ! echo "$VER" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
|
|
49
|
+
echo "::error::package.json version '$VER' does not match semver"
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
echo " ok: version $VER"
|
|
53
|
+
|
|
54
|
+
- name: Key source files present
|
|
55
|
+
run: |
|
|
56
|
+
set -e
|
|
57
|
+
cd /opt/act_runner/deploy-cache/holysheep-cli
|
|
58
|
+
for f in \
|
|
59
|
+
src/webui/aionui-wrapper.js \
|
|
60
|
+
src/webui/aionui-runtime-fetcher.js \
|
|
61
|
+
src/tools/claude-process-proxy.js \
|
|
62
|
+
src/tools/pty-hermes-wrapper.py \
|
|
63
|
+
src/tools/droid.js \
|
|
64
|
+
src/tools/hermes.js; do
|
|
65
|
+
if [ ! -f "$f" ]; then
|
|
66
|
+
echo "::error::required file missing: $f"
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
echo " ok: $f"
|
|
70
|
+
done
|
|
71
|
+
|
|
72
|
+
- name: Runtime fetcher URL/SHA/VERSION consistency
|
|
73
|
+
run: |
|
|
74
|
+
set -e
|
|
75
|
+
cd /opt/act_runner/deploy-cache/holysheep-cli
|
|
76
|
+
URL=$(grep "DEFAULT_RUNTIME_URL" src/webui/aionui-runtime-fetcher.js | grep -o "holysheep-hs[0-9]*" | head -1)
|
|
77
|
+
VER=$(grep "DEFAULT_RUNTIME_VERSION" src/webui/aionui-runtime-fetcher.js | grep -o "holysheep-hs[0-9]*" | head -1)
|
|
78
|
+
echo "URL tag: $URL"
|
|
79
|
+
echo "VERSION tag: $VER"
|
|
80
|
+
if [ -z "$URL" ] || [ -z "$VER" ]; then
|
|
81
|
+
echo "::error::DEFAULT_RUNTIME_URL or DEFAULT_RUNTIME_VERSION missing hs-tag"
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
if [ "$URL" != "$VER" ]; then
|
|
85
|
+
echo "::error::URL tag ($URL) != VERSION tag ($VER) — run pack-runtime.mjs and update fetcher"
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
88
|
+
echo " ok: URL and VERSION both reference $URL"
|
|
89
|
+
|
|
90
|
+
- name: Invariant grep (brand + proxy)
|
|
91
|
+
run: |
|
|
92
|
+
set -e
|
|
93
|
+
cd /opt/act_runner/deploy-cache/holysheep-cli
|
|
94
|
+
|
|
95
|
+
# Brand: wrapper must NOT use old [aionui-wrapper] prefix
|
|
96
|
+
if grep -q "\[aionui-wrapper\]" src/webui/aionui-wrapper.js; then
|
|
97
|
+
echo "::error::aionui-wrapper.js still contains [aionui-wrapper] log prefix (should be [holysheep-web])"
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
echo " ok: no [aionui-wrapper] prefix"
|
|
101
|
+
|
|
102
|
+
# mode field must be holysheep-webui
|
|
103
|
+
if ! grep -q "holysheep-webui" src/webui/aionui-wrapper.js; then
|
|
104
|
+
echo "::error::aionui-wrapper.js missing mode=holysheep-webui"
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
echo " ok: holysheep-webui mode present"
|
|
108
|
+
|
|
109
|
+
# claude-process-proxy: sanitizeClaudeClientHeaders must exist
|
|
110
|
+
if ! grep -q "sanitizeClaudeClientHeaders" src/tools/claude-process-proxy.js; then
|
|
111
|
+
echo "::error::claude-process-proxy.js missing sanitizeClaudeClientHeaders (UA-rewrite regression)"
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
echo " ok: sanitizeClaudeClientHeaders present"
|
|
115
|
+
|
|
116
|
+
# pty-hermes-wrapper: ICANON must be disabled
|
|
117
|
+
if ! grep -q "ICANON" src/tools/pty-hermes-wrapper.py; then
|
|
118
|
+
echo "::error::pty-hermes-wrapper.py missing ICANON disable (PTY truncation regression)"
|
|
119
|
+
exit 1
|
|
120
|
+
fi
|
|
121
|
+
echo " ok: ICANON disabled in pty-hermes-wrapper.py"
|
|
122
|
+
|
|
123
|
+
echo "all invariants passed"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simonyea/holysheep-cli",
|
|
3
|
-
"version": "2.1.
|
|
4
|
-
"description": "Claude Code/Cursor/Cline API relay for China
|
|
3
|
+
"version": "2.1.35",
|
|
4
|
+
"description": "Claude Code/Cursor/Cline API relay for China — ¥1=$1, WeChat/Alipay payment, no credit card, no VPN. One command setup for all AI coding tools.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node tests/droid.test.js && node tests/workspace-store.test.js && node tests/runtime-stale-upgrade.test.js && node tests/hermes.test.js && node tests/preflight.test.js",
|
|
7
7
|
"prepublishOnly": "node scripts/check-tarball-size.js"
|
|
@@ -229,8 +229,17 @@ function deriveNodeProxyUrl(lease) {
|
|
|
229
229
|
if (process.env.HS_CLAUDE_NODE_PROXY_OVERRIDE) {
|
|
230
230
|
return String(process.env.HS_CLAUDE_NODE_PROXY_OVERRIDE).replace(/\/+$/, '')
|
|
231
231
|
}
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
// [HolySheep fork v2.1.34 / hs23] Distinguish "field present but empty"
|
|
233
|
+
// (sub2api nodes have no process-proxy) from "field absent" (old lease format).
|
|
234
|
+
// Control plane sets nodeProxyUrl:"" for sub2api nodes = no process proxy exists.
|
|
235
|
+
// Return null so callers skip node-proxy and go straight to direct-https.
|
|
236
|
+
// Only fall through to port inference when field is entirely absent (legacy leases).
|
|
237
|
+
if (Object.prototype.hasOwnProperty.call(lease, 'nodeProxyUrl')) {
|
|
238
|
+
if (!lease.nodeProxyUrl) return null // explicit empty = no proxy on this node
|
|
239
|
+
return String(lease.nodeProxyUrl)
|
|
240
|
+
}
|
|
241
|
+
// Legacy fallback: field absent → infer proxy port from nodeBaseUrl
|
|
242
|
+
if (!lease.nodeBaseUrl) return null
|
|
234
243
|
const upstream = new URL(String(lease.nodeBaseUrl))
|
|
235
244
|
const proxyPort = upstream.port === '3101' ? '3129' : upstream.port
|
|
236
245
|
upstream.port = proxyPort || '3129'
|
|
@@ -678,6 +687,16 @@ function createProcessProxyServer({ sessionId, configPath = CONFIG_PATH, allowAn
|
|
|
678
687
|
const config = readConfig(configPath)
|
|
679
688
|
const nodeProxyUrl = deriveNodeProxyUrl(lease)
|
|
680
689
|
|
|
690
|
+
// [HolySheep fork v2.1.34 / hs23] nodeProxyUrl===null means the control
|
|
691
|
+
// plane signalled this node has no process proxy (sub2api nodes).
|
|
692
|
+
// Skip node-proxy entirely and go straight to direct-https. This avoids
|
|
693
|
+
// the ECONNREFUSED → retry × MAX_PROXY_RETRIES delay that was burning
|
|
694
|
+
// ~5 s before falling back.
|
|
695
|
+
if (nodeProxyUrl === null) {
|
|
696
|
+
logProxyTiming('request.direct-noproxy', { sessionId, nodeId: lease.nodeId || '', attempt })
|
|
697
|
+
return forwardDirectHttps({ config, lease, clientReq, clientRes, trace: null })
|
|
698
|
+
}
|
|
699
|
+
|
|
681
700
|
if (isDirect) {
|
|
682
701
|
const crsBase = config.baseUrlAnthropic || 'https://api.holysheep.ai'
|
|
683
702
|
const target = new URL(clientReq.url, crsBase)
|
|
@@ -824,8 +843,23 @@ function createProcessProxyServer({ sessionId, configPath = CONFIG_PATH, allowAn
|
|
|
824
843
|
}
|
|
825
844
|
|
|
826
845
|
const doConnect = async (lease) => {
|
|
846
|
+
const nodeProxyUrl = deriveNodeProxyUrl(lease)
|
|
847
|
+
// [HolySheep fork v2.1.34 / hs23] No process proxy on this node (sub2api).
|
|
848
|
+
// CONNECT tunnels go directly to the target host — no bridge headers needed.
|
|
849
|
+
if (nodeProxyUrl === null) {
|
|
850
|
+
logProxyTiming('connect.direct-noproxy', { sessionId, nodeId: lease.nodeId || '', target })
|
|
851
|
+
const upstreamSocket = await new Promise((resolve, reject) => {
|
|
852
|
+
const sock = net.connect(port, host, () => resolve(sock))
|
|
853
|
+
sock.once('error', reject)
|
|
854
|
+
sock.setTimeout(15000, () => sock.destroy(new Error('CONNECT direct tunnel timeout')))
|
|
855
|
+
})
|
|
856
|
+
clientSocket.write('HTTP/1.1 200 Connection Established\r\n\r\n')
|
|
857
|
+
if (head?.length) upstreamSocket.write(head)
|
|
858
|
+
pipeWithCleanup(clientSocket, upstreamSocket)
|
|
859
|
+
return
|
|
860
|
+
}
|
|
827
861
|
const upstreamSocket = await createConnectTunnel(
|
|
828
|
-
|
|
862
|
+
nodeProxyUrl,
|
|
829
863
|
target,
|
|
830
864
|
buildAuthHeaders(readConfig(configPath), lease)
|
|
831
865
|
)
|
|
@@ -60,10 +60,10 @@ const VENDOR_DIR = path.join(__dirname, 'vendor', 'aionui')
|
|
|
60
60
|
// new CLI release, the next `hs web` invocation on user machines will detect
|
|
61
61
|
// the version drift and upgrade the cache in place.
|
|
62
62
|
const DEFAULT_RUNTIME_URL =
|
|
63
|
-
'https://mail.holysheep.ai/app/cli/aionui-runtime-v1.9.18-holysheep-
|
|
63
|
+
'https://mail.holysheep.ai/app/cli/aionui-runtime-v1.9.18-holysheep-hs24.tar.gz'
|
|
64
64
|
const DEFAULT_RUNTIME_SHA256 =
|
|
65
|
-
'
|
|
66
|
-
const DEFAULT_RUNTIME_VERSION = '1.9.18-holysheep-
|
|
65
|
+
'8b3c4fa1bed93b938193321b1817c6e950cdbbfcef64c73a9283b3bb589a768c'
|
|
66
|
+
const DEFAULT_RUNTIME_VERSION = '1.9.18-holysheep-hs24'
|
|
67
67
|
|
|
68
68
|
function isValidRuntimeDir(dir) {
|
|
69
69
|
if (!dir) return false
|