fix: 合并 main 后的测试回归修复

- index.ts: 移除 #130 遗留的 ctx.on('session/disposed')(fake ctx 无 on,
  且 #130 已按取 HEAD 决策,closeSession 调用方一并移除)
- browser.probe: 405→GET 重试后跳过 embed-signals GET,避免多余第 3 次请求(#69)
- EditorHost: 移植 #228 的 dirty 确认守卫到 HEAD 的 reloadSeq 结构(refreshFile)
- tests: fake ctx 补 get()(#357 ctx.get 回归,free-window/editor-refresh/markdown)
- tests: prefs 期望对象补 browserAllowedLoopback(smoke/plugin-shape/state)
- tests: builtins 浏览器设置行补 browserAllowedLoopback(#69)
- tests: install-powershell BOM 门限仅对实际文档化远程调用的文件生效
- locales: 19 语言补齐 showInFolder / refreshUnsavedConfirm(#94 #215 #228)
This commit is contained in:
HuanLinOTO
2026-08-24 17:54:33 +08:00
parent f4e71c1257
commit 6001f0167c
30 changed files with 77 additions and 19 deletions
+5 -8
View File
@@ -533,8 +533,10 @@ function buildApi(
let response = await fetch(parsed, { method: 'HEAD', redirect: 'follow', signal: controller.signal })
// Some servers answer HEAD with 405/501; retry once as GET (the
// body is discarded — only the headers matter).
let retriedFromHeadRejection = false
if (response.status === 405 || response.status === 501) {
response = await fetch(parsed, { method: 'GET', redirect: 'follow', signal: controller.signal })
retriedFromHeadRejection = true
}
// Some servers (e.g. aliyun consoles) answer HEAD without the
// X-Frame-Options / CSP headers that only their GET response
@@ -542,9 +544,11 @@ function buildApi(
// would wrongly report the site as embeddable and the plain iframe
// would surface the browser's misleading "refused to connect".
// Retry once as GET when both signals are absent (body discarded).
// A 405/501 retry already fetched the GET response, so the signals
// are either there or genuinely absent — another GET adds nothing.
const hasEmbedSignals = response.headers.get('content-security-policy') !== null
|| response.headers.get('x-frame-options') !== null
if (!hasEmbedSignals && response.status !== 405 && response.status !== 501) {
if (!hasEmbedSignals && !retriedFromHeadRejection && response.status !== 405 && response.status !== 501) {
response = await fetch(parsed, { method: 'GET', redirect: 'follow', signal: controller.signal })
}
const csp = response.headers.get('content-security-policy')
@@ -1006,13 +1010,6 @@ export function apply(ctx: Context, config?: SidebarConfig): void {
agentListWss.close()
agentOpenWss.close()
}, 'dsh-better-sidebar: teardown')
// Close all UI terminals of a session when the conversation is deleted —
// terminals follow the session, not the reconnect grace. Agent terminals
// are owned by the agent lifecycle and are not touched here.
ctx.on('session/disposed', (session) => {
try { ptyManager?.closeSession(session?.id) } catch {}
}, { global: true })
}
/** Push queued `sidebar_open` requests for one session to a connected view. */