feat(architecture): [EPIC-INT-01C] 斩断直连实现纯净架构,引入网关无感自动拉起与高可用加固#391
feat(architecture): [EPIC-INT-01C] 斩断直连实现纯净架构,引入网关无感自动拉起与高可用加固#391phantom5099 merged 13 commits into1024XEngineer:mainfrom
Conversation
作为网关下沉战役的最终决战,本提交彻底移除了客户端 (TUI) 对底层业务引擎 (Runtime) 的物理代码依赖,全面贯彻整洁架构 (Clean Architecture) 与依赖倒置原则。 核心演进: 1. 确立独立契约:在 TUI 服务层定义专属 Runtime Contract 与强类型事件 DTO,TUI 核心逻辑全面倒置依赖该契约。 2. 架构防腐层:在 App 装配层引入 runtime_contract_adapter,将本地 Runtime 映射为 TUI Contract,将耦合脏活隔离在主业务逻辑之外。 3. 路由大一统:默认启动路径全局切换为 Gateway 模式。同时为网关服务端进程保留显式 local 注入,彻底规避 Gateway -> Gateway 的无限自举死锁回环。 4. 架构物理守卫:新增依赖扫描测试 (Builder Test),强制断言 TUI 业务代码中不再包含任何 `internal/runtime` 的 import,用代码捍卫架构红线。 附带修复 (UI 边缘场景): - 修复 `CurrentWorkdir` 初始化分支逻辑异常问题。 - 修复对话历史 (Transcript) 重建时,Tool 边界未正确打断 Assistant 气泡折叠的渲染错位问题。
…自动执行 os.Executable() + exec.Command(exePath, "gateway")。
在引入 Gateway 自动拉起 (Auto-Spawn) 机制后,补齐生产环境必需的系统资源管理与日志治理能力,彻底消除端口死锁与磁盘膨胀风险。 核心改动: 1. 进程同生共死 (Lifecycle Binding):在 GatewayRPCClient 中跟踪 spawnedCmd,在 TUI 触发 Close() 时显式发送 Process.Kill() 并异步 Wait() 回收资源,根除子进程沦为僵尸进程并持续霸占 Named Pipe/端口的问题。 2. 保护崩溃现场 (Log Rotation):在重定向子进程输出前,将现存的 gateway_auto.log 滚动备份为 .bak 文件,并以 O_TRUNC 截断模式开启新日志。确保既不无限膨胀,又完整保留上一次的崩溃现场供排障分析。 3. 消除日志风暴 (Ping Muting):在网关服务端的结构化日志拦截器中,对 method == "gateway.ping" 的高频保活心跳进行 INFO 级别静音(不影响指标采集),大幅提升核心业务日志的信噪比。
本次提交修复了代码审查指出的 3 项高优先级缺陷,解决了导致 CI 崩溃的致命错误,并进一步加固了网关下沉架构的自愈能力与可观测性。 核心改动: 1. 修复 CI 崩溃与文档同步:彻底移除 `root.go` 中重复注册的 `runtime-mode` flag,消除 `panic: flag redefined` 错误。同步刷新 README 与配置文件文档,明确“默认 Gateway + 探测失败自动拉起”的最新架构行为。 2. 完善 Auto-Spawn 持续自愈:修复网关崩溃后只能拉起一次的缺陷。监听子进程的 `Wait()` 退出事件,并在连接强制重置或拉起失败时,准确复位 `autoSpawnAttempt` 标志位,确保客户端拥有长期的无感恢复能力。 3. 保护故障现场观测:优化 `gateway.ping` 的日志静音策略。仅对成功响应(status == ok)的心跳进行静默处理,强制保留失败心跳的错误日志,避免掩盖网络抖动、进程阻塞或鉴权异常等真实故障。 4. 补齐容错与生命周期测试:新增网关断连复位测试、失败心跳穿透静音测试,全量 CI 与覆盖率恢复 100% 绿灯。
|
@xgopilot 请你帮我解决CI构建错误的问题! |
|
已处理并修复本次 CI 构建失败。 处理结果
验证
|
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
@xgopilot 请你将codecov/patch 覆盖率提升至百分之九十五以上! |
处理结果已完成一轮定向补测并推送到当前 PR 分支,目标是提升 提交: 本次改动
验证
说明:最终以 Codecov 在线计算结果为准;若仍有偏差,我会继续按 Codecov 缺口清单补齐。 |
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
|
/review |
|
@xgopilot 批判性review整个PR,分析所有潜在风险点,找出所有漏洞,不许输出正向表扬 |
|
@xgopilot 我们来详细探讨你指出的四个问题的解决方法。
|
|
@xgopilot 我觉得你提出的方案不错,并且也给出了执行顺序(先解决“gateway 模式下仍完整构建本地 runtime/tool manager,导致双运行时并存”,再解决“默认网关模式下,首次启动会在 Auto-Spawn 之前因缺失 token 直接失败”,再解决“关闭任意一个 TUI 实例会杀死它拉起的共享网关,影响其它仍在线会话”,最后解决“Auto-Spawn 日志文件打开流程缺失防链接保护,存在可控路径截断风险”),现请你按照你的方案进行修改! |
|
已按你确认的顺序完成四项修改,并推送到当前 PR 分支 变更摘要
验证
提交
|
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
|
@xgopilot
|
完成情况已按你的要求完成“彻底去直连 + 双装配拆分”并已推送到当前 PR 分支 变更摘要
提交
|
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
|
@xgopilot
|
|
@xgopilot 请你帮我解决冲突! |
处理完成已完成冲突解决并推送到当前 PR 头分支 本次关键结果:
已推送提交:
|
…r and events Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
…ct boundaries Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
|
/review |
| _ = logSink.Close() | ||
| }() | ||
|
|
||
| cmd := exec.Command(executablePath, "gateway") |
There was a problem hiding this comment.
defaultAutoSpawnGateway 启动子进程时固定使用 neocode gateway,但没有把 listenAddress 透传为 --listen。这会导致非默认监听地址场景下自动拉起后的网关仍监听默认地址,客户端继续拨号自定义地址并最终失败。建议把 listenAddress(以及对应 token-file 配置)显式透传到子进程参数。
| Authenticator: authManager, | ||
| ACL: acl, | ||
| Metrics: metrics, | ||
| ConnectionCountChanged: func(active int) { |
There was a problem hiding this comment.
空闲退出控制器当前只观察 IPC 连接数(ConnectionCountChanged 来自 IPC server)。当网关仅有 HTTP/WS/SSE 活跃连接而 IPC 为 0 时,30 秒后仍会触发 cancelRuntime 并退出,可能中断有效会话。建议改为聚合 IPC+HTTP 活跃连接,或在存在网络活连接时抑制 idle shutdown。
|
@xgopilot 解决冲突,按照斩断直连的方案,并提交PR到fork仓库 |
处理结果已按“斩断直连”方案完成冲突处理,并将结果推送到当前 PR 头分支
关键处理
验证
未做事项:未新建额外 PR(本次按要求直接更新了现有 PR 分支)。 |
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: phantom5099 <245659304+phantom5099@users.noreply.github.com>
|
/code 解决编译错误 |
处理结果当前 PR 分支未复现编译错误,已完成以下验证:
说明本次未检测到可修复的编译失败点,因此没有产生代码改动、提交或推送。 请补充当前 CI 的具体报错日志(失败 job 链接、报错文件与行号、Go 版本/OS),我会按日志精确修复。 |
|
@xgopilot 1、解释编译报错原因:gateway-relay: 2026/04/22 05:25:42 connection cid-write-err write failed: io: read/write on closed pipe |
结论你贴出来的不是“编译报错”,是测试失败(
我这次没有做的事
|
|
@xgopilot 请你帮我解决CI构建失败的问题! |
修复结果已修复本次
提交: 验证
未做事项:未改动业务实现逻辑,仅修复不稳定测试断言。 |
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
🎯 目标 (Motivation & Context)
本 PR 是 [EPIC-INT-01] 全链路贯通 的终极收官交付。 此前,TUI 客户端在物理代码上依然强依赖着
internal/runtime,且微服务化导致用户必须手动开启两个终端,体验极速下降。 本 PR 一次性解决了架构纯洁度、开箱即用体验、系统长期稳定性三大核心痛点,让 NeoCode 彻底脱胎换骨为一个“内里是分布式微服务,外表是极简 CLI”的现代化应用。Closes #362
✨ 主要变更 (Key Changes)
🧱 1. 物理级隔离 (Domain Decoupling & Guardrails)
Runtime Contract与事件 DTO,将core/app和state/messages与底层业务引擎彻底剥离。runtime_contract_adapter进行组装,并强制网关服务端注入local模式,破解“网关连网关”的自举死锁。import internal/runtime,CI 将直接红灯阻断。🪄 2. 开箱即用 (Seamless Auto-Spawn)
gateway守护进程,并在 3 秒内进行高频轮询等待 Ready,用户全程只需输入一次neocode。🛡️ 3. 生产级维稳 (SRE & Stability Hardening)
Close()时,精准下发Process.Kill()信号并异步回收,绝不遗留进程霸占底层端口。gateway_auto.log实施滚动备份机制(存留上一份.bak),每次启动执行截断,防止长期运行撑爆磁盘,同时保留异常堆栈。gateway.ping,将其静音,大幅提升核心排障日志的信噪比。🐛 4. 附带缺陷修复 (Bug Fixes)
CurrentWorkdir丢失导致的分支异常。✅ 验收标准 (Acceptance Criteria)
internal/tui彻底干净,守卫测试通过。go run ./cmd/neocode直接进入界面,无明显卡顿,背后的网关已自动就绪。Ctrl+C关闭 TUI,系统任务管理器中无残留的neocode gateway进程,随时可再次顺利拉起。go test ./...所有单元测试(含新增的并发状态与生命周期测试)全量绿灯通过。