@wwkit/opm 1.0.12 → 1.0.14
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": "@wwkit/opm",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.14",
|
|
4
4
|
"author": "bluesliu <langcai163@163.com>",
|
|
5
5
|
"description": "Unified CLI — package management (npm/pip/dnf/apt) + config view + opencode maintenance",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"basic-ftp": "^6.2.1",
|
|
36
36
|
"extract-zip": "^2.0.1",
|
|
37
37
|
"systeminformation": "^5.23.0",
|
|
38
|
-
"@wwkit/shared": "1.0.
|
|
38
|
+
"@wwkit/shared": "1.0.18"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"registry": "https://registry.npmjs.org/",
|
package/src/cli/groups/ping.js
CHANGED
|
@@ -46,6 +46,14 @@ function isUrl(addr) {
|
|
|
46
46
|
return /^https?:\/\//i.test(addr)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// HTTP 状态码 → 可达性判断:2xx/3xx 视为可达,allowlist 中的状态码
|
|
50
|
+
// 虽非成功响应但证明服务器已响应(如 404 表示主机/代理存活)
|
|
51
|
+
const REACHABLE_ALLOWLIST = [404]
|
|
52
|
+
|
|
53
|
+
function httpReachable(httpCode) {
|
|
54
|
+
return (httpCode >= 200 && httpCode < 400) || REACHABLE_ALLOWLIST.includes(httpCode)
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
/**
|
|
50
58
|
* 获取所有含 registry 配置的工具名列表
|
|
51
59
|
* @returns {string[]}
|
|
@@ -82,14 +90,16 @@ function checkByPing(host, count) {
|
|
|
82
90
|
let stderr = ''
|
|
83
91
|
child.stdout.on('data', (d) => { stdout += d })
|
|
84
92
|
child.stderr.on('data', (d) => { stderr += d })
|
|
85
|
-
child.on('close', () => {
|
|
93
|
+
child.on('close', (code) => {
|
|
86
94
|
const raw = stdout + stderr
|
|
87
95
|
let received = 0
|
|
88
96
|
let rttMin = ''
|
|
89
97
|
let rttAvg = ''
|
|
90
98
|
let rttMax = ''
|
|
91
99
|
|
|
100
|
+
// English: "1 packets received" / Chinese: "已接收 = 1"
|
|
92
101
|
const recvMatch = raw.match(/(\d+)\s+packets?\s+received/)
|
|
102
|
+
|| raw.match(/(\d+)\s*已接收/)
|
|
93
103
|
if (recvMatch) received = parseInt(recvMatch[1], 10)
|
|
94
104
|
|
|
95
105
|
if (!isWin) {
|
|
@@ -100,7 +110,10 @@ function checkByPing(host, count) {
|
|
|
100
110
|
rttMax = rttMatch[3]
|
|
101
111
|
}
|
|
102
112
|
} else {
|
|
113
|
+
// English: "Minimum = 28ms, Maximum = 28ms, Average = 28ms"
|
|
114
|
+
// Chinese: "最小 = 28ms,最大 = 28ms,平均 = 28ms"
|
|
103
115
|
const msMatch = raw.match(/Minimum\s*=\s*(\d+)ms.*?Maximum\s*=\s*(\d+)ms.*?Average\s*=\s*(\d+)ms/s)
|
|
116
|
+
|| raw.match(/最小\s*=\s*(\d+)ms.*?最大\s*=\s*(\d+)ms.*?平均\s*=\s*(\d+)ms/s)
|
|
104
117
|
if (msMatch) {
|
|
105
118
|
rttMin = msMatch[1]
|
|
106
119
|
rttAvg = msMatch[3]
|
|
@@ -108,8 +121,12 @@ function checkByPing(host, count) {
|
|
|
108
121
|
}
|
|
109
122
|
}
|
|
110
123
|
|
|
124
|
+
// Use exit code as primary signal (language-independent);
|
|
125
|
+
// regex-based received count as secondary fallback
|
|
126
|
+
const reachable = code === 0 || received > 0
|
|
127
|
+
|
|
111
128
|
resolve({
|
|
112
|
-
reachable
|
|
129
|
+
reachable,
|
|
113
130
|
sent: count,
|
|
114
131
|
received,
|
|
115
132
|
loss: count - received,
|
|
@@ -150,8 +167,7 @@ function checkByCurl(url, proxy) {
|
|
|
150
167
|
const httpCode = parseInt(parts[0], 10) || 0
|
|
151
168
|
const timeTotal = parseFloat(parts[1]) || 0
|
|
152
169
|
const proxyAuthRequired = httpCode === 407
|
|
153
|
-
const
|
|
154
|
-
const reachable = (httpCode >= 200 && httpCode < 400) || allowlist.includes(httpCode)
|
|
170
|
+
const reachable = httpReachable(httpCode)
|
|
155
171
|
const rttMs = reachable ? String(Math.round(timeTotal * 1000)) : ''
|
|
156
172
|
resolve({
|
|
157
173
|
reachable,
|
|
@@ -183,7 +199,7 @@ function checkByCurl(url, proxy) {
|
|
|
183
199
|
*/
|
|
184
200
|
function checkByWget(url, proxy) {
|
|
185
201
|
return new Promise((resolve) => {
|
|
186
|
-
const args = ['-q', '--spider', '--timeout=5']
|
|
202
|
+
const args = ['-q', '--spider', '-S', '--timeout=5']
|
|
187
203
|
if (proxy) {
|
|
188
204
|
args.push('-e', `use_proxy=yes`, '-e', `https_proxy=${proxy}`, '-e', `http_proxy=${proxy}`)
|
|
189
205
|
}
|
|
@@ -194,7 +210,11 @@ function checkByWget(url, proxy) {
|
|
|
194
210
|
child.stdout.on('data', (d) => { stdout += d })
|
|
195
211
|
child.stderr.on('data', (d) => { stderr += d })
|
|
196
212
|
child.on('close', (code) => {
|
|
197
|
-
|
|
213
|
+
// -S 输出响应头,从中提取 HTTP 状态码(wget 退出码无法区分 404/网络错误)
|
|
214
|
+
const httpMatch = stderr.match(/HTTP\/\S+\s+(\d{3})/)
|
|
215
|
+
|| stderr.match(/awaiting response\.\.\.\s*(\d{3})/)
|
|
216
|
+
const httpCode = httpMatch ? parseInt(httpMatch[1], 10) : 0
|
|
217
|
+
const reachable = httpCode ? httpReachable(httpCode) : code === 0
|
|
198
218
|
resolve({
|
|
199
219
|
reachable,
|
|
200
220
|
sent: 1,
|
|
@@ -204,7 +224,7 @@ function checkByWget(url, proxy) {
|
|
|
204
224
|
rttMin: '',
|
|
205
225
|
rttAvg: '',
|
|
206
226
|
rttMax: '',
|
|
207
|
-
raw: stderr.trim() || (reachable ? 'OK' : 'Failed'),
|
|
227
|
+
raw: httpCode ? `HTTP ${httpCode}` : (stderr.trim() || (reachable ? 'OK' : 'Failed')),
|
|
208
228
|
})
|
|
209
229
|
})
|
|
210
230
|
child.on('error', () => {
|
|
@@ -225,6 +245,7 @@ function checkByWget(url, proxy) {
|
|
|
225
245
|
* @returns {Promise<object>}
|
|
226
246
|
*/
|
|
227
247
|
async function checkReachability(address, tool, count, proxy) {
|
|
248
|
+
console.log(` [CHECK] ${tool}` + (proxy ? ` via proxy ${proxy}` : '') + ` → ${address}`)
|
|
228
249
|
if (tool === 'ping') {
|
|
229
250
|
let host = address
|
|
230
251
|
if (isUrl(address)) {
|
|
@@ -442,7 +463,7 @@ Options:
|
|
|
442
463
|
-d, --detail Output full JSON details (default: compact [{tool, address, proxy, reachable}])
|
|
443
464
|
-h, --help Show this help
|
|
444
465
|
|
|
445
|
-
Tool detection:
|
|
466
|
+
Tool detection: curl > wget > ping (auto-detected)
|
|
446
467
|
|
|
447
468
|
Output:
|
|
448
469
|
default (no -d) [{ "tool": "npm", "address": "https://...", "proxy": "", "reachable": true }]
|
|
@@ -39,21 +39,22 @@ function findConfigFile() {
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* 获取 env 变量当前值
|
|
42
|
-
*
|
|
42
|
+
* 优先级:opm config opencode.env > 系统环境变量
|
|
43
|
+
* 用户在配置文件中设置的值优先,无需手动管理环境变量。
|
|
43
44
|
* @returns {Record<string, string>}
|
|
44
45
|
*/
|
|
45
46
|
function getEnvVars() {
|
|
46
47
|
const cfgEnv = (getConfig().opencode?.env) || {}
|
|
47
48
|
const result = {}
|
|
48
49
|
for (const key of ENV_VARS) {
|
|
49
|
-
result[key] =
|
|
50
|
+
result[key] = cfgEnv[key] || process.env[key] || ''
|
|
50
51
|
}
|
|
51
52
|
return result
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* 在指定工作目录启动 opencode TUI
|
|
56
|
-
*
|
|
57
|
+
* 自动注入有值的环境变量(opm config 优先,系统 env 回退)
|
|
57
58
|
* @param {string} workDir - 工作目录
|
|
58
59
|
* @param {string[]} [passThroughArgs=[]] - Extra args passed to opencode
|
|
59
60
|
*/
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* 由 blues-lib 提供的 ww init / ww init -u 全权处理,不再单独安装/检查。
|
|
6
6
|
*
|
|
7
7
|
* install 流程(5 步):
|
|
8
|
-
* 镜像检查(必查 npm/pip
|
|
8
|
+
* 镜像检查(必查 npm/pip + 按需 nvm/node/uv) → ensure node/python → 写 NPM/PIP_REGISTRY/REGISTRY_PROXY → 装 blues-lib → ww init
|
|
9
9
|
* upgrade 流程(4 步):
|
|
10
|
-
* 镜像检查(必查 npm/pip
|
|
10
|
+
* 镜像检查(必查 npm/pip) → 写 NPM/PIP_REGISTRY/REGISTRY_PROXY → pip 升级 blues-lib → ww init -u
|
|
11
11
|
*
|
|
12
12
|
* 命令: version / versions / installed / install / uninstall / upgrade / help
|
|
13
13
|
*/
|
|
@@ -184,8 +184,8 @@ export class WebworkGroup {
|
|
|
184
184
|
console.log(` → python ${env.python.provided} 已满足`)
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
console.log('\n========== 步骤 3/5: 写入 NPM_REGISTRY / PIP_REGISTRY /
|
|
188
|
-
this._writeRegistryEnv()
|
|
187
|
+
console.log('\n========== 步骤 3/5: 写入 NPM_REGISTRY / PIP_REGISTRY / REGISTRY_PROXY ==========')
|
|
188
|
+
this._writeRegistryEnv(proxy)
|
|
189
189
|
|
|
190
190
|
console.log('\n========== 步骤 4/5: 安装 blues-lib ==========')
|
|
191
191
|
const blue = await this._installPipPackage('blues-lib', proxy)
|
|
@@ -196,7 +196,7 @@ export class WebworkGroup {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
console.log('\n========== 步骤 5/5: ww init ==========')
|
|
199
|
-
|
|
199
|
+
this._runWwInit('init')
|
|
200
200
|
|
|
201
201
|
output({ action: 'install', env, ensured, bluesLib: blue, init: 'ww init' })
|
|
202
202
|
}
|
|
@@ -207,32 +207,44 @@ export class WebworkGroup {
|
|
|
207
207
|
console.log('\n========== 步骤 1/4: 镜像可达检查 ==========')
|
|
208
208
|
await this._checkMirrors(proxy, null)
|
|
209
209
|
|
|
210
|
-
console.log('\n========== 步骤 2/4: 写入 NPM_REGISTRY / PIP_REGISTRY /
|
|
211
|
-
this._writeRegistryEnv()
|
|
210
|
+
console.log('\n========== 步骤 2/4: 写入 NPM_REGISTRY / PIP_REGISTRY / REGISTRY_PROXY ==========')
|
|
211
|
+
this._writeRegistryEnv(proxy)
|
|
212
212
|
|
|
213
213
|
console.log('\n========== 步骤 3/4: 升级 blues-lib ==========')
|
|
214
214
|
const blue = await this._upgradePipPackage('blues-lib', proxy)
|
|
215
215
|
console.log(` ✓ blues-lib 升级完成`)
|
|
216
216
|
|
|
217
217
|
console.log('\n========== 步骤 4/4: ww init -u ==========')
|
|
218
|
-
|
|
218
|
+
this._runWwInit('init -u')
|
|
219
219
|
|
|
220
220
|
output({ action: 'upgrade', bluesLib: blue, init: 'ww init -u' })
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
/**
|
|
224
|
-
*
|
|
225
|
-
*
|
|
224
|
+
* 执行 ww init/init -u
|
|
225
|
+
* 镜像与代理配置通过 NPM_REGISTRY/PIP_REGISTRY/REGISTRY_PROXY 环境变量传递(见 _writeRegistryEnv)
|
|
226
|
+
* @param {string} action - 'init' 或 'init -u'
|
|
227
|
+
* @private
|
|
228
|
+
*/
|
|
229
|
+
_runWwInit(action) {
|
|
230
|
+
execSync(`ww ${action}`, { encoding: 'utf8', stdio: 'inherit' })
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 将 NPM_REGISTRY / PIP_REGISTRY / REGISTRY_PROXY 写入 shell profile,并同步到当前会话 env
|
|
235
|
+
* blues-lib 的相关命令依赖镜像,写入后保持与 opm 配置一致;代理同理,ww init 用同一机制读取
|
|
236
|
+
* @param {string} [proxy] - 代理地址(来自 -p/--proxy 或 opm 配置 proxy.active),空则跳过
|
|
226
237
|
*/
|
|
227
|
-
_writeRegistryEnv() {
|
|
238
|
+
_writeRegistryEnv(proxy = '') {
|
|
228
239
|
const entries = [
|
|
229
240
|
['NPM_REGISTRY', getActiveRegistry('npm')],
|
|
230
241
|
['PIP_REGISTRY', getActiveRegistry('pip')],
|
|
231
|
-
['
|
|
242
|
+
['REGISTRY_PROXY', proxy],
|
|
232
243
|
]
|
|
233
244
|
for (const [name, url] of entries) {
|
|
234
245
|
if (!url) continue
|
|
235
246
|
shell.setEnvVar(name, url)
|
|
247
|
+
process.env[name] = url
|
|
236
248
|
console.log(` [OK] ${name}=${url}`)
|
|
237
249
|
}
|
|
238
250
|
}
|
|
@@ -268,8 +280,9 @@ export class WebworkGroup {
|
|
|
268
280
|
|
|
269
281
|
/**
|
|
270
282
|
* 检查镜像可达性(HEAD 请求,不可达则抛错)
|
|
271
|
-
* 必查:npm / pip
|
|
283
|
+
* 必查:npm / pip(blues-lib 依赖,环境必然可用)
|
|
272
284
|
* 条件查:nvm + node(仅 env.node 不满足时)、uv(仅 env.python 不满足时)
|
|
285
|
+
* cft 不查:由 ww init 全权处理插件安装,不再单独检查。
|
|
273
286
|
* @param {string} proxy
|
|
274
287
|
* @param {{ node: { satisfied: boolean }, python: { satisfied: boolean } } | null} env
|
|
275
288
|
* null 表示不做条件检查(upgrade 场景,不装 runtime)
|
|
@@ -277,7 +290,7 @@ export class WebworkGroup {
|
|
|
277
290
|
async _checkMirrors(proxy, env) {
|
|
278
291
|
const tool = shell.getNetProbeTool()
|
|
279
292
|
if (!tool) {
|
|
280
|
-
console.log(' [WARN] No network probe tool (
|
|
293
|
+
console.log(' [WARN] No network probe tool (curl/wget/ping), skipping mirror check')
|
|
281
294
|
return
|
|
282
295
|
}
|
|
283
296
|
|
|
@@ -287,7 +300,6 @@ export class WebworkGroup {
|
|
|
287
300
|
const checks = [
|
|
288
301
|
{ name: 'npm', url: getActiveRegistry('npm') },
|
|
289
302
|
{ name: 'pip', url: getActiveRegistry('pip') },
|
|
290
|
-
{ name: 'cft', url: getActiveRegistry('cft') },
|
|
291
303
|
...(needNode ? [
|
|
292
304
|
{ name: 'nvm', url: getActiveRegistry('nvm') },
|
|
293
305
|
{ name: 'node', url: getActiveRegistry('node') },
|
|
@@ -318,7 +330,10 @@ export class WebworkGroup {
|
|
|
318
330
|
}
|
|
319
331
|
|
|
320
332
|
if (!allOk) {
|
|
321
|
-
|
|
333
|
+
const hint = proxy
|
|
334
|
+
? `Proxy (${proxy}) was used for ${tool}-based checks. Ensure the proxy is working and mirrors are accessible through it.`
|
|
335
|
+
: `No proxy configured. If behind a proxy, set config proxy.active or use -p <url>. Current tool: ${tool}.`
|
|
336
|
+
throw new Error(`Some mirrors unreachable, aborting. ${hint}`)
|
|
322
337
|
}
|
|
323
338
|
}
|
|
324
339
|
|