From f83aa1d5897a159026339441c77ee41a85f7f145 Mon Sep 17 00:00:00 2001 From: Aisland Date: Mon, 17 Aug 2026 20:45:29 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20file=E8=B7=AF=E7=94=B1readFile=E6=94=B9p?= =?UTF-8?q?romise=E7=89=88=20+=20=E7=BB=88=E7=AB=AF=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AF=E8=87=AA=E5=8A=A8=E8=81=9A=E7=84=A6=EF=BC=88=E5=AE=9E?= =?UTF-8?q?=E6=9C=BApwd=E5=B7=B2=E9=AA=8C=E8=AF=81=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=AB=AF=E9=80=9A=EF=BC=89?= 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 | 4 ++-- 02_process/worklogs/2026-08-16_worktable-v2.md | 12 ++++++++++++ 04_test/live-term.cjs | 18 ++++++++++++++++++ 04_test/term-e2e.cjs | 7 +++++++ 5 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 04_test/live-term.cjs diff --git a/01_content/src/client/split.tsx b/01_content/src/client/split.tsx index 6bf3330..4d9013f 100644 --- a/01_content/src/client/split.tsx +++ b/01_content/src/client/split.tsx @@ -982,6 +982,9 @@ function TerminalPane() { return } term.open(el) + const focusTerm = () => { try { term.focus() } catch {} } + focusTerm() + el.addEventListener('pointerdown', focusTerm) const scope = splitEnv?.getScope?.() const proto = location.protocol === 'https:' ? 'wss:' : 'ws:' const url = proto + '//' + location.host + '/api/worktable/term?sessionId=' + encodeURIComponent(scope?.sessionId ?? '') + '&cwd=' + encodeURIComponent(scope?.cwd ?? '') + '&cols=80&rows=24' @@ -992,6 +995,7 @@ function TerminalPane() { setFailed(T('pane.termFail')) return } + ws.onopen = () => { focusTerm() } ws.onmessage = (ev) => { try { term.write(String(ev.data)) } catch {} } ws.onclose = () => { if (!disposed) { try { term.write('\r\n[连接已关闭]') } catch {} } } ws.onerror = () => { if (!disposed) setFailed(T('pane.termFail')) } diff --git a/01_content/src/index.ts b/01_content/src/index.ts index 530d98a..c93dad0 100644 --- a/01_content/src/index.ts +++ b/01_content/src/index.ts @@ -1,7 +1,7 @@ import { Context } from '@deepseek-ai/cordis' import { execFile } from 'node:child_process' -import { readdirSync, readFile, realpathSync } from 'node:fs' -import { readdir } from 'node:fs/promises' +import { readdirSync, realpathSync } from 'node:fs' +import { readdir, readFile } from 'node:fs/promises' import { dirname, resolve as pathResolve, sep } from 'node:path' import { createRequire } from 'node:module' import { homedir } from 'node:os' diff --git a/02_process/worklogs/2026-08-16_worktable-v2.md b/02_process/worklogs/2026-08-16_worktable-v2.md index d7c8056..cf9b4fc 100644 --- a/02_process/worklogs/2026-08-16_worktable-v2.md +++ b/02_process/worklogs/2026-08-16_worktable-v2.md @@ -443,3 +443,15 @@ (better-sidebar 同款生命周期)。 - 验证(04_test/term-e2e.cjs 扩展):fs handler 直调 200 + 真实条目;终端 E2E RESULT: PASS(真实 cmd.exe shell,pwd 回显正常)。**需再重启一次 dsh web 生效。** + +## 补记(浏览器 file 路由 readFile 坑 + 终端实机验证 + 客户端焦点) + +- 用户反馈:① 浏览器打不开(错误 JSON = file 路由抛 + ERR_INVALID_ARG_TYPE cb must be function——readFile 用了 node:fs 回调版, + 与 readdir 同一类坑);② 终端仍无法敲命令。 +- 处理: + ① readFile 改 node:fs/promises(file 路由本地直调 200 + README 内容,已验证); + ② 终端**实机验证**:直接对用户运行中的服务器(20:40:44 启动)跑 ws + pwd → + RESULT: PASS(cmd.exe 真实回显 E:\AI_Workspace)——服务端已通!用户侧「敲不了」 + 定位为客户端焦点问题:TerminalPane 增加 open 后自动 focus + 点击聚焦 + ws.onopen 聚焦; + ③ 客户端焦点修复实时下发(F5 生效);file 路由修复需再重启一次。 diff --git a/04_test/live-term.cjs b/04_test/live-term.cjs new file mode 100644 index 0000000..0f2152b --- /dev/null +++ b/04_test/live-term.cjs @@ -0,0 +1,18 @@ + +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('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)) { + clearTimeout(timer); + console.log('RESULT: PASS pwd 真实回显 OK'); + ws.close(); process.exit(0); + } +}); +ws.on('close', (code) => { console.log('WS_CLOSE code=' + code); clearTimeout(timer); process.exit(0); }); +ws.on('error', (e) => { console.log('WS_ERROR:', String(e)); clearTimeout(timer); process.exit(1); }); diff --git a/04_test/term-e2e.cjs b/04_test/term-e2e.cjs index fcabe37..d50a68e 100644 --- a/04_test/term-e2e.cjs +++ b/04_test/term-e2e.cjs @@ -22,6 +22,13 @@ const WebSocket = require('ws'); const fakeReq = { [Symbol.asyncIterator]() { let done = false; return { next: () => (done ? Promise.resolve({ done: true }) : (done = true, Promise.resolve({ done: false, value: Buffer.from('{"path":"E:/AI_Workspace"}') }))) }; } }; await fsRoute.handler(fakeReq, fakeRes); console.log('fs direct:', captured && captured.status, captured && captured.body ? captured.body.slice(0, 160) : ''); + // file 路由直调(真实 README.md) + const fileRoute = routes.find((r) => r.path === '/api/worktable/file'); + let fc = null; + const fRes = { writeHead: (s) => { fc = { status: s }; }, end: (b) => { fc.body = String(b); } }; + const fReq = { url: '/api/worktable/file?path=' + encodeURIComponent('E:/AI_Workspace/DeepseekHarness/Projects/dsh-worktable/README.md') }; + await fileRoute.handler(fReq, fRes); + console.log('file direct:', fc && fc.status, fc && fc.body ? fc.body.slice(0, 60) : ''); if (upgrades.length === 0) { console.log('RESULT: NO_TERMINAL_ROUTE'); process.exit(1); } const server = http.createServer((req, res) => { res.writeHead(404); res.end(); }); server.on('upgrade', (req, socket, head) => {