Skip to content

RFC: NeoCode 命令行体验 (CLI UX) 重新设计 #549

@pionxe

Description

@pionxe

RFC: NeoCode 命令行体验 (CLI UX) 重新设计

1. 目标问题 (Why)

随着 NeoCode 架构的快速演进,当前 CLI 命令树暴露出以下体验与规范问题:

  1. 概念外泄与认知负担gatewaydaemon 两个底层系统概念直接暴露给普通用户,且 daemon 生命周期管理不直观(如残留旧进程需要手动 kill)。
  2. 缺乏 Provider 管理入口(已解决):自定义大模型通过外挂 providers/ 目录实现,过去用户必须手写 YAML,缩进错误即导致启动崩溃。
  3. 命令无统一规范:部分底层调试命令暴露在外,缺乏清晰的命名约定。
  4. 配置修改门槛高:用户修改超时等简单配置项需要手动编辑 YAML,容易格式错误。

2. 设计原则与命名规范

2.1 命名规范

采用务实混合模式,区分两类命令:

类型 模式 适用场景 示例
动作命令(顶级动词) <verb> <args> 用户最频繁执行的单一动作 neocodeneocode shellneocode use <provider>neocode diag
资源命令(名词组) <noun> <verb> <args> 围绕某一资源的增删改查 neocode provider addneocode model lsneocode daemon status

判断标准:如果该命令 90% 的使用场景就是做一件事,用动作命令;如果一个名词下有多个正交操作,用资源命令。

use 作为顶级动词而非 provider use 的理由:切换 provider 是用户每天可能执行的最频繁操作,额外嵌套一级没有信息增益——用户说"我要用 DeepSeek"自然就是 neocode use deepseek

2.2 配置哲学

  • 简单标量值(超时秒数、开关、路径)通过 CLI 修改,降低出错概率。
  • 复杂嵌套结构(provider 定义、gateway 调优参数、tools 子配置)引导用户编辑 YAML。
  • CLI 不提供 config list——全量查看去配置文件本身即可,CLI 只做单点读写。

3. 完整命令树

标记说明:✅ 已实现 | ⬜ 待实现 | 🔧 待调整

neocode                                    ✅  启动沉浸式 TUI 主页面

# --- 核心交互 ---
neocode shell                              ✅  进入 AI 增强型 PTY 代理终端
neocode shell --init [shell]               ✅  输出 shell integration 初始化脚本
neocode diag                               ✅  向当前 shell 发送一次手动诊断信令
neocode diag auto <on|off|status>          ✅  控制 / 查询自动诊断模式
neocode diag diagnose                      ✅  显式触发一次手动诊断(与 diag 等价,保留作为语义别名)

# --- 提供商选择(高频动作命令) ---
neocode use <provider>                     ✅  全局切换激活的 provider
neocode use <provider> --model <id>        ✅  切换 provider 并同时指定模型

# --- 模型管理 ---
neocode model ls                           ✅  列出当前 provider 的可用模型
neocode model set <model-id>               ✅  在当前 provider 下切换模型

# --- 提供商管理 ---
neocode provider add <name>                ✅  挂载自定义 provider
  --driver, --url, --api-key-env,
  --discovery-endpoint
neocode provider ls                        ✅  列出全部已挂载和内置的 provider
neocode provider rm <name>                 ✅  删除自定义 provider

# --- 配置读写 ---
neocode config get <key>                   ⬜  读取单个配置项的值
neocode config set <key> <value>           ⬜  修改单个标量配置项

# --- 系统服务 ---
neocode gateway                            🔧  启动本地 gateway 进程(保留暴露,供调试)
neocode daemon serve                       ✅  启动 HTTP 唤醒 daemon
neocode daemon install                     ✅  安装 daemon 自启动
neocode daemon uninstall                   ✅  卸载 daemon 自启动
neocode daemon status                      ✅  查询 daemon 运行状态
neocode daemon encode run                  ✅  生成可点击的 /run 唤醒链接
neocode daemon encode review               ✅  生成可点击的 /review 唤醒链接

# --- 版本与升级 ---
neocode version                            ✅  输出版本号
neocode update                             ✅  检查并升级到最新版本

# --- 数据迁移 ---
neocode migrate context-budget             🔧  迁移 context.auto_compact → context.budget
  --dry-run, --config

4. 分模块设计细节

4.1 neocode config — 新命令 ⬜

适用范围:仅暴露 Config 结构体中的顶层标量字段。嵌套对象(runtimecontexttoolsmemogateway)引导用户编辑 ~/.neocode/config.yaml

支持的可配置 key(对应 Config struct 的 YAML tag):

CLI key YAML 路径 类型 说明
tool_timeout_sec tool_timeout_sec int 工具调用超时秒数
generate_start_timeout_sec generate_start_timeout_sec int 模型生成启动超时秒数
shell shell string 默认 shell 路径
selected_provider selected_provider string 当前激活的 provider(建议用 neocode use 代替)
current_model current_model string 当前激活的 model(建议用 neocode model set 代替)

子命令

neocode config get <key>
    # 读取并输出单个配置值
    # 示例:neocode config get tool_timeout_sec → "120"

neocode config set <key> <value>
    # 修改单个配置值,写入前经过 ValidateSnapshot 校验
    # 示例:neocode config set tool_timeout_sec 60
    # 示例:neocode config set shell /usr/bin/zsh

错误处理

  • 不存在的 key → 提示可用 key 列表
  • 类型不匹配 → 提示期望类型(如 "tool_timeout_sec 需要整数")
  • 校验失败 → 透传 ValidateSnapshot 的错误信息,不写入

实现路径internal/cli/config_commands.go,通过 config.Manager.Update() 执行变更。

4.2 neocode gateway — 调整策略 🔧

当前状态:通过 neocode gateway 暴露,同时有独立二进制 neocode-gateway(通过 NewGatewayStandaloneCommand)。

调整:保留为可见命令,不隐藏。理由:

  • 高级用户和开发者需要显式控制 gateway 参数(--log-level--metrics-enabled--acl-mode 等十余项 flags)
  • neocode-gateway 独立部署场景需要对应的 CLI 文档入口
  • 30 秒空闲自动回收已由 gatewayIdleShutdownController 实现,无需隐藏命令来保证

4.3 neocode migrate — 调整策略 🔧

当前状态neocode migrate context-budget 负责将旧 context.auto_compact schema 迁移到 context.budget,支持 --dry-run 预览和 --config 指定路径。

调整:保留为可见命令,不隐藏。理由:

  • --dry-run 让用户在迁移前预览变更,避免静默修改 config.yaml 导致的意外
  • 迁移失败时备份文件(MigrateContextBudgetConfigFile 自动创建 .bak)需要用户感知
  • 静默迁移失败只会记日志,用户可能长时间不知道 config 未升级

4.4 neocode diag diagnose 去留

neocode diagneocode diag diagnose 功能完全等价(都调用 runDiagDiagnoseCommand)。建议保留两者:diag 是快捷入口,diag diagnose 是显式语义别名。无需调整。


5. 用户场景故事

场景一:配置新的大模型供应商(✅ 已实现)

小明刚下载 NeoCode,想用公司内部署的 DeepSeek 模型。过去他必须手写 ~/.neocode/providers/deepseek/provider.yaml,缩进错误导致启动崩溃。

# 一行命令完成挂载,屏蔽底层 YAML
$ neocode provider add deepseek --driver openaicompat \
    --url "https://api.deepseek.com/v1" \
    --api-key-env DEEPSEEK_KEY

# 输出: ✅ 提供商 deepseek 添加成功,当前模型: deepseek-chat

# 切换为全局使用
$ neocode use deepseek
# 输出: ✅ 已全局切换到供应商: deepseek

场景二:查看和切换模型(✅ 已实现)

小红想看看当前 provider 有哪些可用模型,并切换到 Claude Sonnet。

$ neocode model ls
# 供应商: anthropic
# 当前模型: claude-haiku-4-5-20251001
# 可用模型:
#   claude-haiku-4-5-20251001 (Claude Haiku 4.5)
# * claude-sonnet-4-6 (Claude Sonnet 4.6)
#   claude-opus-4-7 (Claude Opus 4.7)

$ neocode model set claude-sonnet-4-6
# 输出: ✅ 已切换模型: claude-sonnet-4-6

场景三:解决版本更新后的环境冲突(✅ 已实现)

老李更新 NeoCode 后执行 neocode shell,终端疯狂报错 execute_system_tool failed。过去他要用 ps aux | grep neocode 配合 kill -9 手动清理旧 daemon 进程。

# 查看 daemon 状态
$ neocode daemon status
# {"status":"ok","listen_address":"127.0.0.1:18921","running":true,...}

# 卸载旧的 daemon 自启动
$ neocode daemon uninstall
# {"status":"ok"}

# 重新安装并启动
$ neocode daemon install
$ neocode daemon serve

场景四:修改工具超时(⬜ 待实现)

小张的网络环境不稳定,web_fetch 工具经常超时。他不想打开 vim 小心翼翼地改 YAML 缩进。

# 查看当前超时值
$ neocode config get tool_timeout_sec
# 120

# 调整到 180 秒
$ neocode config set tool_timeout_sec 180
# ✅ tool_timeout_sec 已更新为 180

场景五:生成可分享的唤醒链接(✅ 已实现)

运维小王想让 NeoCode review 一个日志文件,但不想教对方怎么进 TUI。他生成一个可点击链接发给同事。

$ neocode daemon encode review --path /var/log/app.log --workdir /home/ops
# http://neocode:18921/review?path=%2Fvar%2Flog%2Fapp.log&workdir=%2Fhome%2Fops

场景六:开发者调试 Gateway(🔧 已实现,保留暴露)

开发者小陈怀疑 gateway 的 IPC 连接数限制导致请求排队。他显式启动 gateway 并开启 metrics。

$ neocode gateway --log-level debug --metrics-enabled --ipc-max-connections 100
# neocode-gateway: starting gateway (log-level=debug)
# neocode-gateway: gateway ipc listen address: /tmp/neocode-gateway-xxx.sock
# neocode-gateway: gateway network listen address: 127.0.0.1:18920

6. 落地清单

# 任务 状态 涉及文件
1 provider add/ls/rm 命令 ✅ 已实现 internal/cli/provider_commands.go
2 use <provider> 命令 ✅ 已实现 internal/cli/use_command.go
3 model ls/set 命令 ✅ 已实现 internal/cli/model_commands.go
4 daemon serve/install/uninstall/status/encode ✅ 已实现 internal/cli/daemon_commands.go
5 shell / shell --init / diag / diag auto ✅ 已实现 internal/cli/shell_diag_commands.go
6 version / update ✅ 已实现 internal/cli/version_command.goupdate_command.go
7 gateway 保留暴露(不隐藏) 🔧 当前已暴露,无需改动 internal/cli/gateway_commands.go
8 migrate 保留可见(不隐藏) 🔧 当前已暴露,无需改动 internal/cli/migrate_command.go
9 config get <key> ⬜ 待实现 新建 internal/cli/config_commands.go
10 config set <key> <value> ⬜ 待实现 同上

7. 验收标准

  1. 现有命令行为不变neocode shell --initneocode diag auto on/off 等已实现命令的回归测试通过。
  2. config get
    • neocode config get tool_timeout_sec 输出当前整数值。
    • neocode config get no_such_key 输出友好错误并列出可用 key。
  3. config set
    • neocode config set tool_timeout_sec 60 写入成功,再次 get 验证。
    • neocode config set tool_timeout_sec abc 被拒绝(类型校验)。
    • 写入后的 config.yaml 保持 YAML 格式和注释不丢失。
  4. Provider 闭环
    • neocode provider addneocode provider lsneocode use <name>neocode model lsneocode provider rm <name> 全链路可跑通。
  5. Daemon 闭环
    • neocode daemon installneocode daemon statusneocode daemon uninstall 链路正常。

8. 风险与回滚

  • 风险config set 修改 config.yaml 时可能破坏 YAML 格式或丢失注释。
  • 缓解策略:通过 config.Manager.Update() 执行写入,该路径已有 ValidateSnapshot 校验保护;写入前创建 .bak 备份(复用现有 migrate 的备份模式)。
  • 回滚:若 config 命令引入问题,用户可直接编辑 YAML 文件作为后备路径。

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions