fix(dashboard): proxy SSH source requests and correct the dev:web README - #5270
huangruiteng merged 2 commits into
Conversation
The workspace calls /api/ssh-source/ensure and /api/ssh-source/goal-lifecycle on the Chat service, but the dev proxy only forwarded /api/chat and /api/actions, so these requests returned a Vite 404 under npm run dev. Signed-off-by: song <liusongstep@gmail.com>
The README said dev:web opens the workspace on the bundled example. The workspace always reads /status.json through the dev proxy, so without loopx serve-status and loopx chat it opens on a status-load error. Say so, and keep the bundled example as what smoke:demo-readiness validates. Signed-off-by: song <liusongstep@gmail.com>
There was a problem hiding this comment.
状态回读补充:该 PR 已于 2026-09-28 17:58:09 UTC 合并,本次评审首次发布于 18:11:38 UTC,属于合并后的代码复核,不能作为事前合并授权。本任务没有执行合并操作。
未发现本次两文件改动引入的阻塞问题,代码结论为 APPROVE。在受测的 exact head 上,下面两项既有验证及严格质量资格仍失败;已合并的状态没有把这些证据改成通过。
动机
本次关闭两个已复现的开发入口缺口:同一个工作区页面通过 Vite 开发服务器运行时,已存在的 SSH 来源请求缺少对应代理,因此在到达 Chat 服务前就返回 HTTP 404;开发说明还错误承诺单独启动网页会自动展示示例。代理修复让现有调用到达原有处理器,文档修正则让首次启动、缺少服务和恢复读取的行为可预期。这是完整的开发入口修复,不以扩大远端生命周期功能作为前置条件。
改动思路
沿用既有 Vite 代理表,将 SSH 来源请求送到本机 Chat 服务;前端继续使用已有类型化客户端,服务端继续负责浏览器来源检查、SSH Host 目录校验、参数验证和远端操作。开发启动脚本仍分别启动状态与 Chat 服务,没有新增业务状态、协议版本或决策源。最强反例是无 Origin 的空请求可以到达处理器,而真正的浏览器调用仍被拦截;本次通过真实 Vite、临时 registry 下的原生 Chat CLI 和浏览器中的实际 SDK 排除了这个反例。隔离仅替换本机测试端口,没有替换处理器或伪造成功响应。
具体改动
完整差异为两个文件,增加十五行、删除十三行。其中四行是开发代理配置,其余是开发说明;没有生成文件、依赖变化或业务实现迁移。
关键代码讲解
- Vite 的 SSH 代理项把接口族转发到既有 Chat 端口,沿用既有的 changeOrigin 设置,浏览器 Origin 检查仍有效。其余五项代理、监听地址、默认端口和 preview 配置均与 base 相同,因此修复落在实际缺失的开发传输边界。
- ensureSshSource由来源添加和选择流程调用。它发送 Host 与本地端口,再读取原有结果;实际浏览器在 base 上收到代理错误,在 head 上成功复用已经响应的状态服务,界面显示来源已连接且为 SSH 只读投影。
- applyRemoteGoalLifecycle继续校验返回的 Goal、Host、操作和投影验证标志。新增代理没有放宽这些校验;未知 Host 和非法操作通过真实处理器返回原有错误,任意新子路由仍返回未知路径。
README 对服务缺失的描述与浏览器实测一致:仅启动 Vite 时明确显示实时状态加载失败;启动隔离的原生状态服务后点击重试,可以恢复 Goal 状态读取。这个恢复检查不声称 Chat 会话或远端 SSH 生命周期也已完成验收。
对主干的风险
主要风险是新增代理可能改写浏览器来源,或者把整个接口前缀当成新的写入权限。实测保留了两条接口的来源拒绝、参数错误和未知路径处理;伪造 Origin 即使同时提交坏 JSON,也先被原有来源检查拒绝。SSH Host 目录、生命周期决策及远端命令仍在原有 owner 内;没有新增泛化状态分类、文本 denylist 或机器义务。生产 dashboard 与当前 Chat 入口资产在 base/head 上逐字节相同,开发配置也没有扩散到安装后的工作区。
| 本地验证 | 结果与边界 |
|---|---|
npm run build;uv run --extra test python scripts/chat_bundle.py verify --source |
base/head 均通过;生产 dashboard 文件和当前 Chat 入口资产一致 |
| 真实 Vite 与原生 Chat CLI 的同一组代理探针 | Node 24.21.0、最低支持版本 22.22.3 各二十八项记录通过;另十二项路由范围与拒绝优先级检查通过 |
| 实际浏览器 SDK、来源添加、服务缺失与重试 | 通过;没有启动新 SSH 隧道或执行远端生命周期写入 |
npm run smoke:status-sources;uv run --extra test python -m pytest -q tests/test_ssh_tunnel_source.py |
来源 smoke 和十项 transport 测试通过;单元测试作为真实 HTTP 证据的补充 |
canary premerge 选出的本地检查 |
十五项仓库检查和三个 diff 检查通过;整体合并资格仍不通过 |
npm run smoke:demo-readiness -- --skip-browser |
base/head 均失败:home-route 仍期待旧的内联 Goal 创建分支 |
node apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-contract.test.mjs |
base/head 均失败:仍期待旧的内联工作区字段;完整 packaged 浏览器 suite 未被记为通过 |
语义与 CI 对齐
两项红检查的完整日志仅归一化 checkout 路径后完全相同,其失败 owner、共享表单和验证代码不在本次差异内;本次请求传输不变量有独立通过的真实路径证据。相关旧断言已有独立修复方向,例如 #5265,但不能继承其尚未集成的测试结论。按当前评审契约,可以批准这个修复并保留独立的合并 HOLD;精确范围质量回执实际为失败,未缩小扫描、放宽预算或跳过检查来转绿。未查询、轮询或等待远端 CI。
我的整体评价
该实现复用了已有 owner,四行配置是当前最小完整修复;未来简化检查没有发现值得在这次添加的代理生成器或兼容层。持续使用方面,来源选择与重复调用不再因开发代理缺失而中断,失败和重试仍由原有状态读取流程处理;用户体验方面,首次启动说明与真实错误、恢复操作一致。剩余限制是两处原有验证失败,以及本次没有资格认定真实远端 SSH 创建或生命周期写入已验证。维护者仍需在相关检查修复或集成后重新验证对应范围;这份事后代码复核不追认合并前的流程或质量资格。本任务没有合并。
English verdict: APPROVE. The exact-head change restores the existing development transport and corrects the startup instructions. Real Vite/native Chat and browser checks pass. Independently reproduced, unchanged baseline validator failures keep the tested head’s strict quality qualification non-passing. This is a post-merge code audit, not prior merge authorization; live remote SSH lifecycle execution is not claimed.
|
框架对齐记录:评审 head 按 CONTRIBUTING 的贡献入口规则,这属于可以直接交付的自包含复现缺陷:原有工作区请求在开发代理处丢失,以及启动说明不符合现有默认行为。不需要为这个修复创建形式上的 roadmap 项。 归属符合 AGENTS 的 Goal、能力放置与有界简化要求:Vite 只补传输,状态与 SSH 操作继续由原有 owner 决策。已检查现有调用、默认路径、浏览器 Origin、来源只读反馈和错误恢复;本次不增加第二状态源或扩大远端权限。未来简化检查结论为无需额外抽象。 按 测试与质量指南,真实调用证据与单元测试分开报告,原有红检查保留为红,未将未验证的远端操作或完整 packaged suite 记为通过。状态回读显示 PR 已于 2026-09-28 17:58:09 UTC 合并,早于这份评审首次发布;代码 APPROVE 是事后复核,不是事前合并授权。受测 exact head 的严格质量资格仍失败,后续检查修复需要独立验证。本任务没有执行合并,也没有声称关闭更广的安装、远端生命周期或持续运行验收。 |
Goal And Delivered Outcome
/api/ssh-source/ensureand/api/ssh-source/goal-lifecycleon the Chat service, butvite.config.tsonly proxied/api/chatand/api/actions, so undernpm run devthese requests hit a Vite 404. (2) The dashboard README saidnpm run dev:webopens the workspace "with the bundled example"; the workspace always requests/status.jsonthrough the proxy (the example mode indashboard-page.tsxis never entered), so a fresh clone following the README lands on a status-load error (HTTP 502).POST /api/ssh-source/ensurethrough the dev server returned 404 from Vite; it now reaches the Chat service (400 host alias is requiredfor an empty body). The README now describes whatdev:webserves and which services it needs.main.Scope And Continuation
npm run smoke:demo-readiness -- --skip-browser, which the README keeps, currently fails onmaininsmoke:home-route(missing explicit Goal form action, after feat(chat): integrate conversational goal drafts into the existing workspace #4376 moved Goal creation intogoal-create-request.ts); unrelated to this change.Validation
real_entrypointpassedloopx chat(isolated synthetic registry):POST /api/ssh-source/ensure→ Chat service400; the same request through a dev server without the entry → Vite404.manualpassednpm run dev:webwithout local services opens on the status-load error the README now describes.integrationfailedmain:npm run smoke:demo-readiness -- --skip-browserfails insmoke:home-routeas noted above.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
N/A
Boundary Checklist
none.Signed-off-bytrailer (git commit -s).Future-facing refactor pass: considered deriving the dev proxy table from the Chat service's route constants; unnecessary for one missing prefix.