@simonyea/holysheep-cli 1.7.44 → 1.7.46
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simonyea/holysheep-cli",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.46",
|
|
4
4
|
"description": "Claude Code/Cursor/Cline API relay for China \u2014 \u00a51=$1, WeChat/Alipay payment, no credit card, no VPN. One command setup for all AI coding tools.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openai-china",
|
package/src/commands/claude.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const path = require('path')
|
|
3
4
|
const { spawn } = require('child_process')
|
|
4
5
|
const {
|
|
5
6
|
BASE_URL_ANTHROPIC,
|
|
@@ -15,6 +16,8 @@ const {
|
|
|
15
16
|
} = require('../tools/claude-process-proxy')
|
|
16
17
|
const claudeCodeTool = require('../tools/claude-code')
|
|
17
18
|
|
|
19
|
+
const INJECT_PATH = path.resolve(__dirname, '../tools/process-proxy-inject.js')
|
|
20
|
+
|
|
18
21
|
function ensureClaudeProxyConfig(apiKey) {
|
|
19
22
|
const config = readConfig()
|
|
20
23
|
const next = claudeCodeTool.buildBridgeConfig(apiKey, BASE_URL_ANTHROPIC, {
|
|
@@ -46,10 +49,13 @@ async function runClaude(args = []) {
|
|
|
46
49
|
...process.env,
|
|
47
50
|
ANTHROPIC_API_KEY: undefined,
|
|
48
51
|
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
49
|
-
ANTHROPIC_BASE_URL:
|
|
52
|
+
ANTHROPIC_BASE_URL: BASE_URL_ANTHROPIC,
|
|
50
53
|
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: '1',
|
|
51
54
|
HOLYSHEEP_CLAUDE_PROCESS_PROXY: '1',
|
|
52
55
|
HOLYSHEEP_CLAUDE_SESSION_ID: sessionId,
|
|
56
|
+
// 进程级代理注入:强制所有 TCP 连接走本地 bridge CONNECT 隧道
|
|
57
|
+
NODE_OPTIONS: `--require ${INJECT_PATH}`,
|
|
58
|
+
HS_PROXY_URL: proxyUrl,
|
|
53
59
|
HTTP_PROXY: undefined,
|
|
54
60
|
HTTPS_PROXY: undefined,
|
|
55
61
|
ALL_PROXY: undefined,
|
|
@@ -152,33 +152,8 @@ function pipeWithCleanup(a, b) {
|
|
|
152
152
|
|
|
153
153
|
function createProcessProxyServer({ sessionId, configPath = CONFIG_PATH }) {
|
|
154
154
|
const server = http.createServer(async (clientReq, clientRes) => {
|
|
155
|
-
const isDirect = !clientReq.url.startsWith('http')
|
|
156
|
-
|
|
157
155
|
const doForward = async (lease) => {
|
|
158
156
|
const config = readConfig(configPath)
|
|
159
|
-
|
|
160
|
-
if (isDirect) {
|
|
161
|
-
const crsBase = config.baseUrlAnthropic || 'https://api.holysheep.ai'
|
|
162
|
-
const target = new URL(clientReq.url, crsBase)
|
|
163
|
-
const fwdHeaders = { ...clientReq.headers, ...buildAuthHeaders(config, lease), 'x-hs-node-proxied': '1', host: target.host }
|
|
164
|
-
const transport = target.protocol === 'https:' ? https : http
|
|
165
|
-
return new Promise((resolve, reject) => {
|
|
166
|
-
const fwd = transport.request({
|
|
167
|
-
hostname: target.hostname,
|
|
168
|
-
port: Number(target.port || (target.protocol === 'https:' ? 443 : 80)),
|
|
169
|
-
method: clientReq.method,
|
|
170
|
-
path: target.pathname + target.search,
|
|
171
|
-
headers: fwdHeaders,
|
|
172
|
-
}, (res) => {
|
|
173
|
-
clientRes.writeHead(res.statusCode || 502, res.headers)
|
|
174
|
-
res.pipe(clientRes)
|
|
175
|
-
resolve()
|
|
176
|
-
})
|
|
177
|
-
fwd.once('error', reject)
|
|
178
|
-
clientReq.pipe(fwd)
|
|
179
|
-
})
|
|
180
|
-
}
|
|
181
|
-
|
|
182
157
|
const nodeProxyUrl = deriveNodeProxyUrl(lease)
|
|
183
158
|
const headers = {
|
|
184
159
|
...buildAuthHeaders(config, lease),
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/**
|
|
3
|
+
* 进程级代理注入 — 通过 NODE_OPTIONS=--require 加载
|
|
4
|
+
* 在 net.createConnection 最底层拦截所有 TCP 连接,强制走 CONNECT 隧道
|
|
5
|
+
* 使得所有出口流量(undici / https / 任意 HTTP 客户端)都通过 node 节点 IP 出去
|
|
6
|
+
*/
|
|
7
|
+
const net = require('net')
|
|
8
|
+
const { URL } = require('url')
|
|
9
|
+
|
|
10
|
+
const raw = process.env.HS_PROXY_URL
|
|
11
|
+
if (!raw) return
|
|
12
|
+
|
|
13
|
+
let parsed
|
|
14
|
+
try {
|
|
15
|
+
parsed = new URL(raw)
|
|
16
|
+
} catch {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const PROXY_HOST = parsed.hostname
|
|
21
|
+
const PROXY_PORT = Number(parsed.port) || 80
|
|
22
|
+
const SKIP = new Set(['127.0.0.1', '::1', 'localhost', '0.0.0.0', PROXY_HOST])
|
|
23
|
+
|
|
24
|
+
const _orig = net.createConnection
|
|
25
|
+
|
|
26
|
+
function proxied(options, cb) {
|
|
27
|
+
const isObj = options !== null && typeof options === 'object'
|
|
28
|
+
const host = isObj
|
|
29
|
+
? String(options.host || options.hostname || 'localhost')
|
|
30
|
+
: String(options || 'localhost')
|
|
31
|
+
const port = isObj
|
|
32
|
+
? Number(options.port || 0)
|
|
33
|
+
: Number(arguments[1] || 0)
|
|
34
|
+
|
|
35
|
+
if (!port || SKIP.has(host)) return _orig.apply(this, arguments)
|
|
36
|
+
|
|
37
|
+
// 建立到本地 bridge CONNECT 代理的 TCP 连接
|
|
38
|
+
const sock = _orig({ host: PROXY_HOST, port: PROXY_PORT })
|
|
39
|
+
const pending = []
|
|
40
|
+
|
|
41
|
+
// 暂时拦截 'connect' 事件,等 CONNECT 隧道建好才放行
|
|
42
|
+
const _on = sock.on.bind(sock)
|
|
43
|
+
const _once = sock.once.bind(sock)
|
|
44
|
+
sock.on = function(event, listener) {
|
|
45
|
+
if (event === 'connect') { pending.push(['on', listener]); return sock }
|
|
46
|
+
return _on(event, listener)
|
|
47
|
+
}
|
|
48
|
+
sock.once = function(event, listener) {
|
|
49
|
+
if (event === 'connect') { pending.push(['once', listener]); return sock }
|
|
50
|
+
return _once(event, listener)
|
|
51
|
+
}
|
|
52
|
+
if (typeof cb === 'function') pending.push(['once', cb])
|
|
53
|
+
|
|
54
|
+
// TCP 到 proxy 建立后,发送 CONNECT 请求
|
|
55
|
+
_once('connect', () => {
|
|
56
|
+
sock.write(`CONNECT ${host}:${port} HTTP/1.1\r\nHost: ${host}:${port}\r\n\r\n`)
|
|
57
|
+
let buf = Buffer.alloc(0)
|
|
58
|
+
_on('data', function onData(chunk) {
|
|
59
|
+
buf = Buffer.concat([buf, chunk])
|
|
60
|
+
const i = buf.indexOf('\r\n\r\n')
|
|
61
|
+
if (i === -1) return
|
|
62
|
+
sock.removeListener('data', onData)
|
|
63
|
+
|
|
64
|
+
const header = buf.slice(0, i).toString()
|
|
65
|
+
if (!header.includes(' 200 ')) {
|
|
66
|
+
sock.destroy(new Error(`CONNECT ${host}:${port} failed: ${header.split('\r\n')[0]}`))
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const rest = buf.slice(i + 4)
|
|
71
|
+
if (rest.length) sock.unshift(rest)
|
|
72
|
+
|
|
73
|
+
// 隧道建好:恢复 on/once,触发所有等待中的 connect 监听器
|
|
74
|
+
sock.on = _on
|
|
75
|
+
sock.once = _once
|
|
76
|
+
for (const [type, listener] of pending) {
|
|
77
|
+
if (type === 'once') sock.once('connect', listener)
|
|
78
|
+
else sock.on('connect', listener)
|
|
79
|
+
}
|
|
80
|
+
pending.length = 0
|
|
81
|
+
sock.emit('connect')
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
return sock
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
net.createConnection = net.connect = proxied
|