claude-cn-flag-check 0.1.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/LICENSE +21 -0
- package/README.md +173 -0
- package/README.zh-CN.md +162 -0
- package/bin/cli.js +362 -0
- package/package.json +44 -0
- package/src/capture.js +204 -0
- package/src/detect.js +233 -0
- package/src/extract.js +155 -0
- package/src/index.js +197 -0
- package/src/resolve.js +146 -0
- package/src/snapshot.js +173 -0
package/src/resolve.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolve what Claude Code will *actually* use for ANTHROPIC_BASE_URL / timezone
|
|
5
|
+
* on this machine, from real config sources — not just the current process's
|
|
6
|
+
* environment (which reflects whatever shell spawned us, and is therefore
|
|
7
|
+
* unreliable). Every source checked is reported as evidence.
|
|
8
|
+
*
|
|
9
|
+
* Sources for env vars, low → high precedence (later overrides earlier):
|
|
10
|
+
* 1. the live process environment (session-dependent — noted as such)
|
|
11
|
+
* 2. user settings ~/.claude/settings.json (env block)
|
|
12
|
+
* 3. project settings <cwd>/.claude/settings.json
|
|
13
|
+
* 4. project-local settings <cwd>/.claude/settings.local.json
|
|
14
|
+
* 5. enterprise managed settings /etc/claude-code/managed-settings.json
|
|
15
|
+
*
|
|
16
|
+
* NB: settings.json `env` overrides an exported shell variable — empirically
|
|
17
|
+
* confirmed on 2.1.170 (a base URL set only in ~/.claude/settings.json is used
|
|
18
|
+
* even when the shell exports a different one). Enterprise managed policy wins.
|
|
19
|
+
*
|
|
20
|
+
* Timezone: an explicit TZ (from the above env sources) wins; otherwise the
|
|
21
|
+
* system zone from /etc/localtime or /etc/timezone (what Intl.DateTimeFormat
|
|
22
|
+
* resolves to at runtime).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const os = require('os');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
|
|
29
|
+
function readJson(p) {
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
32
|
+
} catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isFile(p) {
|
|
38
|
+
try {
|
|
39
|
+
return fs.statSync(p).isFile();
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Ordered low → high precedence (later overrides earlier). */
|
|
46
|
+
function settingsFiles(cwd, home) {
|
|
47
|
+
return [
|
|
48
|
+
{ label: '用户设置 ~/.claude/settings.json', tier: 'user', path: path.join(home, '.claude', 'settings.json') },
|
|
49
|
+
{ label: '项目设置 .claude/settings.json', tier: 'project', path: path.join(cwd, '.claude', 'settings.json') },
|
|
50
|
+
{ label: '项目本地 .claude/settings.local.json', tier: 'local', path: path.join(cwd, '.claude', 'settings.local.json') },
|
|
51
|
+
{ label: '企业管理设置', tier: 'managed', path: '/etc/claude-code/managed-settings.json' },
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a single env var across all sources, collecting evidence.
|
|
57
|
+
* Precedence low → high: process env, then user/project/local/managed settings
|
|
58
|
+
* (settings.json env overrides an exported shell var; managed policy wins).
|
|
59
|
+
* @returns {{value:?string, source:?string, evidence:object[]}}
|
|
60
|
+
*/
|
|
61
|
+
function resolveEnvVar(name, { cwd, home }) {
|
|
62
|
+
const evidence = [];
|
|
63
|
+
let value = null;
|
|
64
|
+
let source = null;
|
|
65
|
+
|
|
66
|
+
// Lowest precedence: the live process environment (session-dependent).
|
|
67
|
+
const pe = process.env[name];
|
|
68
|
+
if (pe) {
|
|
69
|
+
evidence.push({ source: '进程环境变量 process.env', status: 'set', key: name, value: pe, note: '会话相关;会被 settings.json 覆盖' });
|
|
70
|
+
value = pe;
|
|
71
|
+
source = '进程环境变量 process.env';
|
|
72
|
+
} else {
|
|
73
|
+
evidence.push({ source: '进程环境变量 process.env', status: 'absent', key: name });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Settings files override, in ascending precedence.
|
|
77
|
+
for (const f of settingsFiles(cwd, home)) {
|
|
78
|
+
if (!isFile(f.path)) {
|
|
79
|
+
evidence.push({ source: f.label, path: f.path, status: 'missing' });
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const json = readJson(f.path);
|
|
83
|
+
const v = json && json.env && json.env[name];
|
|
84
|
+
if (v) {
|
|
85
|
+
evidence.push({ source: f.label, path: f.path, status: 'set', key: `env.${name}`, value: v });
|
|
86
|
+
value = v;
|
|
87
|
+
source = f.label;
|
|
88
|
+
} else {
|
|
89
|
+
evidence.push({ source: f.label, path: f.path, status: 'absent', key: `env.${name}` });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { value, source, evidence };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** System timezone from the OS, with evidence. */
|
|
97
|
+
function systemTimezone() {
|
|
98
|
+
try {
|
|
99
|
+
const link = fs.readlinkSync('/etc/localtime');
|
|
100
|
+
const m = link.match(/zoneinfo\/(.+)$/);
|
|
101
|
+
if (m) return { value: m[1], source: '/etc/localtime', evidence: { source: '/etc/localtime', status: 'set', value: m[1] } };
|
|
102
|
+
} catch {
|
|
103
|
+
/* not a symlink */
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const t = fs.readFileSync('/etc/timezone', 'utf8').trim();
|
|
107
|
+
if (t) return { value: t, source: '/etc/timezone', evidence: { source: '/etc/timezone', status: 'set', value: t } };
|
|
108
|
+
} catch {
|
|
109
|
+
/* absent */
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const t = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
113
|
+
return { value: t, source: 'Intl.DateTimeFormat', evidence: { source: 'Intl.DateTimeFormat()', status: 'set', value: t } };
|
|
114
|
+
} catch {
|
|
115
|
+
return { value: null, source: null, evidence: { source: '系统时区', status: 'missing' } };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function resolveTimezone(ctx) {
|
|
120
|
+
const tz = resolveEnvVar('TZ', ctx);
|
|
121
|
+
const evidence = [...tz.evidence];
|
|
122
|
+
if (tz.value) {
|
|
123
|
+
return { value: tz.value, source: `${tz.source}(TZ 覆盖)`, evidence };
|
|
124
|
+
}
|
|
125
|
+
const sys = systemTimezone();
|
|
126
|
+
evidence.push(sys.evidence);
|
|
127
|
+
return { value: sys.value, source: sys.source, evidence };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {{cwd?:string, home?:string}=} ctx
|
|
132
|
+
* @returns {{baseUrl, timezone, assumeFirstParty}}
|
|
133
|
+
*/
|
|
134
|
+
function resolveConfig(ctx = {}) {
|
|
135
|
+
const c = { cwd: ctx.cwd || process.cwd(), home: ctx.home || os.homedir() };
|
|
136
|
+
const baseUrl = resolveEnvVar('ANTHROPIC_BASE_URL', c);
|
|
137
|
+
const timezone = resolveTimezone(c);
|
|
138
|
+
const afp = resolveEnvVar('_CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL', c);
|
|
139
|
+
return {
|
|
140
|
+
baseUrl,
|
|
141
|
+
timezone,
|
|
142
|
+
assumeFirstParty: { value: !!afp.value, source: afp.source, evidence: afp.evidence },
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
module.exports = { resolveConfig, resolveEnvVar, resolveTimezone, systemTimezone, settingsFiles };
|
package/src/snapshot.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// AUTO-GENERATED from @anthropic-ai/claude-code 2.1.170 (feature present since 2.1.91).
|
|
2
|
+
// Decoded from the bundle constants `u65` (domains) and `m65` (lab keywords)
|
|
3
|
+
// via base64 -> XOR 91 -> split(","). This is the offline fallback; by default
|
|
4
|
+
// the CLI re-extracts the live lists from your installed binary (see extract.js).
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
sourceVersion: '2.1.170',
|
|
10
|
+
xorKey: 91,
|
|
11
|
+
domains: [
|
|
12
|
+
"cn",
|
|
13
|
+
"sankuai.com",
|
|
14
|
+
"netease.com",
|
|
15
|
+
"163.com",
|
|
16
|
+
"baidu-int.com",
|
|
17
|
+
"baidu.com",
|
|
18
|
+
"alibaba-inc.com",
|
|
19
|
+
"alipay.com",
|
|
20
|
+
"antgroup-inc.cn",
|
|
21
|
+
"kuaishou.com",
|
|
22
|
+
"bytedance.net",
|
|
23
|
+
"xiaohongshu.com",
|
|
24
|
+
"ctripcorp.com",
|
|
25
|
+
"jd.com",
|
|
26
|
+
"jdcloud.com",
|
|
27
|
+
"bilibili.co",
|
|
28
|
+
"iflytek.com",
|
|
29
|
+
"stepfun-inc.com",
|
|
30
|
+
"aliyuncs.com",
|
|
31
|
+
"cn-shanghai.fcapp.run",
|
|
32
|
+
"cn-beijing.fcapp.run",
|
|
33
|
+
"xaminim.com",
|
|
34
|
+
"moonshot.ai",
|
|
35
|
+
"anyrouter.top",
|
|
36
|
+
"packyapi.com",
|
|
37
|
+
"aicodemirror.com",
|
|
38
|
+
"aigocode.com",
|
|
39
|
+
"hongshan.com",
|
|
40
|
+
"iwhalecloud.com",
|
|
41
|
+
"dhcoder.net",
|
|
42
|
+
"lemongpt.top",
|
|
43
|
+
"zhihuiapi.top",
|
|
44
|
+
"intsig.net",
|
|
45
|
+
"high-five-ai.xyz",
|
|
46
|
+
"cloudsway.net",
|
|
47
|
+
"4sapi.com",
|
|
48
|
+
"529961.com",
|
|
49
|
+
"88996.cloud",
|
|
50
|
+
"88code.ai",
|
|
51
|
+
"88code.org",
|
|
52
|
+
"91code.pro",
|
|
53
|
+
"992236.xyz",
|
|
54
|
+
"ai.codeqaq.com",
|
|
55
|
+
"ai.hybgzs.com",
|
|
56
|
+
"ai.kjvhh.com",
|
|
57
|
+
"aicanapi.com",
|
|
58
|
+
"aicoding.sh",
|
|
59
|
+
"aifast.site",
|
|
60
|
+
"aihubmix.com",
|
|
61
|
+
"anmory.com",
|
|
62
|
+
"api.5202030.xyz",
|
|
63
|
+
"api.ablai.top",
|
|
64
|
+
"api.bianxie.ai",
|
|
65
|
+
"api.bltcy.ai",
|
|
66
|
+
"api.cpass.cc",
|
|
67
|
+
"api.dev88.tech",
|
|
68
|
+
"api.dreamger.com",
|
|
69
|
+
"api.expansion.chat",
|
|
70
|
+
"api.gueai.com",
|
|
71
|
+
"api.holdai.top",
|
|
72
|
+
"api.ikuncode.cc",
|
|
73
|
+
"api.lconai.com",
|
|
74
|
+
"api.linkapi.org",
|
|
75
|
+
"api.mkeai.com",
|
|
76
|
+
"api.nekoapi.com",
|
|
77
|
+
"api.oaipro.com",
|
|
78
|
+
"api.ruyun.fun",
|
|
79
|
+
"api.ssopen.top",
|
|
80
|
+
"api.tu-zi.com",
|
|
81
|
+
"api.uglycat.cc",
|
|
82
|
+
"api.v3.cm",
|
|
83
|
+
"api.whatai.cc",
|
|
84
|
+
"api.wpgzs.top",
|
|
85
|
+
"api.xty.app",
|
|
86
|
+
"api.yuegle.com",
|
|
87
|
+
"api.zzyu.me",
|
|
88
|
+
"apimart.ai",
|
|
89
|
+
"apipro.maynor1024.live",
|
|
90
|
+
"apiyi.com",
|
|
91
|
+
"applyj.hiapi.top",
|
|
92
|
+
"augmunt.com",
|
|
93
|
+
"b4u.qzz.io",
|
|
94
|
+
"clauddy.com",
|
|
95
|
+
"claude-code-hub.app",
|
|
96
|
+
"claude-opus.top",
|
|
97
|
+
"claudeide.net",
|
|
98
|
+
"co.yes.vg",
|
|
99
|
+
"code.wenwen-ai.com",
|
|
100
|
+
"code.x-aio.com",
|
|
101
|
+
"codeilab.com",
|
|
102
|
+
"cubence.com",
|
|
103
|
+
"deeprouter.top",
|
|
104
|
+
"dimaray.com",
|
|
105
|
+
"dmxapi.com",
|
|
106
|
+
"docs.aigc2d.com",
|
|
107
|
+
"duckcoding.com",
|
|
108
|
+
"fk.hshwk.org",
|
|
109
|
+
"flapcode.com",
|
|
110
|
+
"foxcode.hshwk.org",
|
|
111
|
+
"foxcode.rjj.cc",
|
|
112
|
+
"fuli.hxi.me",
|
|
113
|
+
"getgoapi.com",
|
|
114
|
+
"gpt.zhizengzeng.com",
|
|
115
|
+
"gptgod.cloud",
|
|
116
|
+
"gptkey.eu.org",
|
|
117
|
+
"gptpay.store",
|
|
118
|
+
"hdgsb.com",
|
|
119
|
+
"henapi.top",
|
|
120
|
+
"instcopilot-api.com",
|
|
121
|
+
"jeniya.top",
|
|
122
|
+
"jiekou.ai",
|
|
123
|
+
"kg-api.cloud",
|
|
124
|
+
"n1n.ai",
|
|
125
|
+
"new-api.u4vr.com",
|
|
126
|
+
"new.xychatai.com",
|
|
127
|
+
"one-api.bltcy.top",
|
|
128
|
+
"one.ocoolai.com",
|
|
129
|
+
"oneapi.paintbot.top",
|
|
130
|
+
"open.xiaojingai.com",
|
|
131
|
+
"openclaude.me",
|
|
132
|
+
"opus.gptuu.com",
|
|
133
|
+
"poloai.top",
|
|
134
|
+
"poloapi.top",
|
|
135
|
+
"privnode.com",
|
|
136
|
+
"proxyai.com",
|
|
137
|
+
"qinzhiai.com",
|
|
138
|
+
"right.codes",
|
|
139
|
+
"runanytime.hxi.me",
|
|
140
|
+
"sssaicode.com",
|
|
141
|
+
"store.zzyus.top",
|
|
142
|
+
"tiantianai.pro",
|
|
143
|
+
"uiuiapi.com",
|
|
144
|
+
"uniapi.ai",
|
|
145
|
+
"vip.undyingapi.com",
|
|
146
|
+
"wolfai.top",
|
|
147
|
+
"wzw.de5.net",
|
|
148
|
+
"wzw.pp.ua",
|
|
149
|
+
"xairouter.com",
|
|
150
|
+
"xaixapi.com",
|
|
151
|
+
"xiaohuapi.site",
|
|
152
|
+
"xiaohumini.site",
|
|
153
|
+
"xy.poloapi.com",
|
|
154
|
+
"yansd666.com",
|
|
155
|
+
"yansd666.top",
|
|
156
|
+
"yunwu.ai",
|
|
157
|
+
"yunwu.zeabur.app",
|
|
158
|
+
"zenmux.ai"
|
|
159
|
+
],
|
|
160
|
+
labKeywords: [
|
|
161
|
+
"deepseek",
|
|
162
|
+
"moonshot",
|
|
163
|
+
"minimax",
|
|
164
|
+
"xaminim",
|
|
165
|
+
"zhipu",
|
|
166
|
+
"bigmodel",
|
|
167
|
+
"baichuan",
|
|
168
|
+
"stepfun",
|
|
169
|
+
"01ai",
|
|
170
|
+
"dashscope",
|
|
171
|
+
"volces"
|
|
172
|
+
],
|
|
173
|
+
};
|