dsh-crossterm 0.3.35 → 0.3.37
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/lib/bus.js +1 -1
- package/lib/web.js +90 -14
- package/package.json +1 -1
package/lib/bus.js
CHANGED
package/lib/web.js
CHANGED
|
@@ -129,14 +129,34 @@ async function latestVersion() {
|
|
|
129
129
|
throw new Error(last || 'unknown')
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
// 子进程输出解码:中文 Windows 控制台默认 CP936(GBK),直接当 UTF-8 读会变成 ����。
|
|
133
|
+
// 先按整段 UTF-8 严格解码,失败再退回 GBK;顺带清掉 ANSI 控制符与 \r 进度残留。
|
|
134
|
+
function decodeOutput(buffer) {
|
|
135
|
+
if (!buffer || buffer.length === 0) return ''
|
|
136
|
+
let text
|
|
137
|
+
try {
|
|
138
|
+
text = new TextDecoder('utf-8', { fatal: true }).decode(buffer)
|
|
139
|
+
} catch {
|
|
140
|
+
try {
|
|
141
|
+
text = new TextDecoder('gbk').decode(buffer)
|
|
142
|
+
} catch {
|
|
143
|
+
text = buffer.toString('utf8')
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// eslint-disable-next-line no-control-regex
|
|
147
|
+
return text.replace(/\u001b\[[0-9;?]*[A-Za-z]/g, '').replace(/\r/g, '\n')
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function run(cmd, args, cwd, opts) {
|
|
133
151
|
return new Promise((resolve) => {
|
|
134
|
-
|
|
152
|
+
const chunks = []
|
|
153
|
+
let size = 0
|
|
135
154
|
let child
|
|
155
|
+
const shell = opts && typeof opts.shell === 'boolean' ? opts.shell : process.platform === 'win32'
|
|
136
156
|
try {
|
|
137
157
|
child = spawn(cmd, args, {
|
|
138
158
|
cwd,
|
|
139
|
-
shell
|
|
159
|
+
shell,
|
|
140
160
|
windowsHide: true,
|
|
141
161
|
})
|
|
142
162
|
} catch (error) {
|
|
@@ -144,16 +164,67 @@ function run(cmd, args, cwd) {
|
|
|
144
164
|
return
|
|
145
165
|
}
|
|
146
166
|
const push = (chunk) => {
|
|
147
|
-
|
|
148
|
-
|
|
167
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk), 'utf8')
|
|
168
|
+
chunks.push(buf)
|
|
169
|
+
size += buf.length
|
|
170
|
+
// 只留最后 64 KB,免得长日志把内存和卡片撑爆
|
|
171
|
+
while (size > 65536 && chunks.length > 1) size -= chunks.shift().length
|
|
149
172
|
}
|
|
150
173
|
child.stdout && child.stdout.on('data', push)
|
|
151
174
|
child.stderr && child.stderr.on('data', push)
|
|
152
|
-
child.on('error', (error) =>
|
|
153
|
-
|
|
175
|
+
child.on('error', (error) =>
|
|
176
|
+
resolve({ code: -1, out: decodeOutput(Buffer.concat(chunks)) + String((error && error.message) || error) }),
|
|
177
|
+
)
|
|
178
|
+
child.on('close', (code) => resolve({ code, out: decodeOutput(Buffer.concat(chunks)) }))
|
|
154
179
|
})
|
|
155
180
|
}
|
|
156
181
|
|
|
182
|
+
// 更新失败时给人的提示:命令找不到就明说,别把一行乱码甩到卡片上
|
|
183
|
+
function updateErrorText(result) {
|
|
184
|
+
const raw = (result.out || '').trim()
|
|
185
|
+
if (!raw) {
|
|
186
|
+
return `自动更新没跑起来(dsh 退出码 ${result.code}):本机找不到可用的 dsh 命令,请在命令行手动执行 dsh plugin add ${PKG}@latest,然后重启 DSH`
|
|
187
|
+
}
|
|
188
|
+
const tail = raw.slice(-1200)
|
|
189
|
+
if (/not recognized|不是内部或外部命令|无法将.{0,12}项识别|command not found|ENOENT/i.test(raw)) {
|
|
190
|
+
return `${tail}\n\n提示:PATH 里没有 dsh 命令,请在命令行手动执行 dsh plugin add ${PKG}@latest,然后重启 DSH`
|
|
191
|
+
}
|
|
192
|
+
return tail
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// 有些机器没把 `dsh` 命令放进 PATH(桌面版就是),这时退回 DSH 自带运行时里的
|
|
196
|
+
// node + pnpm 直接装:<DSH_HOME>\dsh-runtimes\dsh-primary-runtime\dependencies\{node,pnpm}
|
|
197
|
+
function runtimeTools(cfg) {
|
|
198
|
+
const busDir = (cfg && cfg.busDir) || ''
|
|
199
|
+
const home = busDir ? path.dirname(busDir) : path.join(os.homedir(), '.dsh')
|
|
200
|
+
const deps = path.join(home, 'dsh-runtimes', 'dsh-primary-runtime', 'dependencies')
|
|
201
|
+
return {
|
|
202
|
+
node: path.join(deps, 'node', 'bin', 'node.exe'),
|
|
203
|
+
pnpm: path.join(deps, 'pnpm', 'bin', 'pnpm.cjs'),
|
|
204
|
+
ok:
|
|
205
|
+
fs.existsSync(path.join(deps, 'node', 'bin', 'node.exe')) &&
|
|
206
|
+
fs.existsSync(path.join(deps, 'pnpm', 'bin', 'pnpm.cjs')),
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function looksMissingCommand(result) {
|
|
211
|
+
return /not recognized|不是内部或外部命令|无法将.{0,12}项识别|command not found|ENOENT|is not recognized/i.test(
|
|
212
|
+
result.out || '',
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async function updatePlugin(term, info) {
|
|
217
|
+
const target = `${PKG}@latest`
|
|
218
|
+
const direct = await run('dsh', ['plugin', '--profile', info.name, 'add', target], info.dir)
|
|
219
|
+
if (direct.code === 0) return { ok: true, via: 'dsh', out: direct.out }
|
|
220
|
+
const miss = looksMissingCommand(direct) || direct.out.trim() === ''
|
|
221
|
+
if (!miss) return { ok: false, via: 'dsh', out: direct.out }
|
|
222
|
+
const tools = runtimeTools(term.cfg)
|
|
223
|
+
if (!tools.ok) return { ok: false, via: 'none', out: updateErrorText(direct) }
|
|
224
|
+
const fallback = await run(tools.node, [tools.pnpm, 'add', target], info.dir, { shell: false })
|
|
225
|
+
return { ok: fallback.code === 0, via: 'pnpm', out: fallback.out || updateErrorText(fallback) }
|
|
226
|
+
}
|
|
227
|
+
|
|
157
228
|
function statusOf(term) {
|
|
158
229
|
const cfg = term.cfg || {}
|
|
159
230
|
const info = profileInfo(cfg.busDir)
|
|
@@ -315,15 +386,17 @@ export function registerWeb(ctx, term, log) {
|
|
|
315
386
|
})
|
|
316
387
|
return
|
|
317
388
|
}
|
|
318
|
-
const result = await
|
|
389
|
+
const result = await updatePlugin(term, info)
|
|
319
390
|
json(res, 200, {
|
|
320
|
-
ok: result.
|
|
391
|
+
ok: result.ok,
|
|
321
392
|
mode: 'registry',
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
393
|
+
via: result.via,
|
|
394
|
+
needRestart: result.ok,
|
|
395
|
+
message: result.ok
|
|
396
|
+
? `已更新${result.via === 'pnpm' ? '(用 DSH 自带 pnpm)' : ''},重启 DSH 后生效`
|
|
397
|
+
: result.via === 'none'
|
|
398
|
+
? result.out
|
|
399
|
+
: (result.out || '').slice(-1200) || `更新失败(退出码不明)`,
|
|
327
400
|
})
|
|
328
401
|
},
|
|
329
402
|
}),
|
|
@@ -345,3 +418,6 @@ export function registerWeb(ctx, term, log) {
|
|
|
345
418
|
if (typeof log === 'function') log(`web 路由注册失败:${(error && error.message) || error}`)
|
|
346
419
|
}
|
|
347
420
|
}
|
|
421
|
+
|
|
422
|
+
// 只给探针用:把内部小工具导出来,宿主运行时不依赖这些导出
|
|
423
|
+
export { decodeOutput, runtimeTools, looksMissingCommand, updateErrorText }
|