From 3fe012132e353b9257038b244fa3f550430de272 Mon Sep 17 00:00:00 2001 From: Aisland Date: Mon, 17 Aug 2026 20:48:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=88=E7=AB=AFshell=E6=94=B9PowerShe?= =?UTF-8?q?ll(pwd/ls=E5=8F=AF=E7=94=A8)=20+=20=E6=B5=8F=E8=A7=88=E5=99=A8?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=A1=B5=E6=94=B9example.com(=E5=8F=AF?= =?UTF-8?q?=E5=B5=8C=E5=85=A5)=20+=20marker=E5=9B=9E=E6=98=BE=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01_content/src/client/split.tsx | 4 ++-- 01_content/src/index.ts | 9 ++++++--- 02_process/worklogs/2026-08-16_worktable-v2.md | 12 ++++++++++++ 04_test/live-term.cjs | 6 +++--- 04_test/term-e2e.cjs | 6 +++--- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/01_content/src/client/split.tsx b/01_content/src/client/split.tsx index 4d9013f..18b83ff 100644 --- a/01_content/src/client/split.tsx +++ b/01_content/src/client/split.tsx @@ -741,8 +741,8 @@ function makeDividerHandler(kind: 'left' | 'chat' | 'top' | 'pane' | 'topPane', /** 浏览器内置窗:地址栏 + iframe */ function BrowserPane() { - const [url, setUrl] = useState('https://www.bing.com') - const [src, setSrc] = useState('https://www.bing.com') + const [url, setUrl] = useState('https://example.com') + const [src, setSrc] = useState('https://example.com') const go = () => { const u = url.trim() setSrc(/^(\/|https?:\/\/)/i.test(u) ? u : 'about:blank') diff --git a/01_content/src/index.ts b/01_content/src/index.ts index c93dad0..e81d7d3 100644 --- a/01_content/src/index.ts +++ b/01_content/src/index.ts @@ -134,8 +134,10 @@ function setupTerminal(webServer: any, ctx: any) { if (!WebSocketServer) return const pty = ptyMod.default ?? ptyMod const wss = new WebSocketServer({ noServer: true }) - const spawnShell = (): string => - process.platform === 'win32' ? (process.env.ComSpec || 'cmd.exe') : (process.env.SHELL || '/bin/bash') + const spawnShell = (): { cmd: string; args: string[] } => + process.platform === 'win32' + ? { cmd: 'powershell.exe', args: ['-NoLogo'] } + : { cmd: process.env.SHELL || '/bin/bash', args: [] } const clampDim = (v: number, fallback: number) => Math.min(1024, Math.max(2, Number.isFinite(v) ? v : fallback)) ctx.effect(() => webServer.registerUpgrade({ @@ -148,7 +150,8 @@ function setupTerminal(webServer: any, ctx: any) { const rows = clampDim(Number(u.searchParams.get('rows')), 24) let term: any = null try { - term = pty.spawn(spawnShell(), [], { name: 'xterm-256color', cols, rows, cwd, env: process.env }) + const shell = spawnShell() + term = pty.spawn(shell.cmd, shell.args, { name: 'xterm-256color', cols, rows, cwd, env: process.env }) } catch (err) { try { ws.send('\r\n[worktable] 终端启动失败:' + String(err)) } catch {} try { ws.close() } catch {} diff --git a/02_process/worklogs/2026-08-16_worktable-v2.md b/02_process/worklogs/2026-08-16_worktable-v2.md index cf9b4fc..1e538f3 100644 --- a/02_process/worklogs/2026-08-16_worktable-v2.md +++ b/02_process/worklogs/2026-08-16_worktable-v2.md @@ -455,3 +455,15 @@ RESULT: PASS(cmd.exe 真实回显 E:\AI_Workspace)——服务端已通!用户侧「敲不了」 定位为客户端焦点问题:TerminalPane 增加 open 后自动 focus + 点击聚焦 + ws.onopen 聚焦; ③ 客户端焦点修复实时下发(F5 生效);file 路由修复需再重启一次。 + +## 补记(终端 shell 换 PowerShell + 浏览器默认页 + 标记回显验证) + +- 用户反馈:终端报 'pwd' is not recognized(说明终端已通,但 shell 是 cmd.exe—— + pwd/ls 是 PowerShell/bash 命令);浏览器标签页打不开。 +- 处理:① 服务端 spawnShell Windows 改 powershell.exe -NoLogo(pwd/ls 等可用); + ② 浏览器默认页 bing.com → example.com(bing 带 X-Frame-Options 禁止 iframe 嵌入, + 是「打不开」的另一半原因);③ E2E 改为 marker echo 验证(此前 PASS 被 shell banner + 误判);④ 实机验证:对运行中服务器 echo 回显 OK(输入链路确认通)。 +- 验证:harness(PowerShell 壳)marker 回显 PASS(含 PSReadLine 着色码,确认 PowerShell); + 实机 cmd 壳 marker 回显 PASS;file 路由直调 200。 +- 生效:终端 shell 与 file 路由 = 服务端,**需重启 dsh web**;浏览器默认页 = 客户端,F5 即生效。 diff --git a/04_test/live-term.cjs b/04_test/live-term.cjs index 0f2152b..50025e9 100644 --- a/04_test/live-term.cjs +++ b/04_test/live-term.cjs @@ -3,14 +3,14 @@ const WebSocket = require('ws'); const ws = new WebSocket('ws://127.0.0.1:3080/api/worktable/term?cwd=' + encodeURIComponent('E:/AI_Workspace') + '&cols=80&rows=24'); const received = []; const timer = setTimeout(() => { console.log('RESULT: FAIL 15s 无任何输出'); process.exit(1); }, 15000); -ws.on('open', () => { console.log('WS_OPEN'); setTimeout(() => { console.log('SEND pwd'); ws.send('pwd\r'); }, 1500); }); +ws.on('open', () => { console.log('WS_OPEN'); setTimeout(() => { console.log('SEND echo'); ws.send('echo __WT_LIVE_MARKER__\r'); }, 1500); }); ws.on('message', (d) => { const t = String(d); received.push(t); console.log('FRAME[' + received.length + ']:', JSON.stringify(t.slice(0, 100))); - if (t.includes('E:\\AI_Workspace') || /[A-Za-z]:[\\/]/.test(t)) { + if (t.includes('__WT_LIVE_MARKER__')) { clearTimeout(timer); - console.log('RESULT: PASS pwd 真实回显 OK'); + console.log('RESULT: PASS 实机命令回显 OK'); ws.close(); process.exit(0); } }); diff --git a/04_test/term-e2e.cjs b/04_test/term-e2e.cjs index d50a68e..127a31d 100644 --- a/04_test/term-e2e.cjs +++ b/04_test/term-e2e.cjs @@ -40,12 +40,12 @@ const WebSocket = require('ws'); await new Promise((r) => server.listen(19088, '127.0.0.1', r)); const ws = new WebSocket('ws://127.0.0.1:19088/api/worktable/term?cwd=' + encodeURIComponent(process.cwd()) + '&cols=80&rows=24'); const timer = setTimeout(() => { console.log('RESULT: FAIL 超时'); process.exit(1); }, 10000); - ws.on('open', () => ws.send('pwd\r')); + ws.on('open', () => ws.send('echo __WT_E2E_MARKER__\r')); ws.on('message', (d) => { const t = String(d); - if (t.length > 3 && /[A-Za-z]:[\\\/]/.test(t)) { + if (t.includes('__WT_E2E_MARKER__')) { clearTimeout(timer); - console.log('RESULT: PASS pwd 回显正常: ' + t.slice(0, 90).replace(/\r?\n/g, ' | ')); + console.log('RESULT: PASS 命令回显正常: ' + t.slice(0, 120).replace(/\r?\n/g, ' | ')); ws.close(); server.close(); process.exit(0); } });