Phase 0–7 of docs/joy-cli-hardening-plan.md: - golden fixtures + contract tests (commands/dashboard keys/whitelist) - command tier metadata; help ≡ manifest (pipeline in core) - _joy.schema_version on dict outputs; dashboard collect package split - work_rebuild → shared rebuild; deprecated markers; journal vm-first compat - web JSONL audit; lazy command import; plugins README
22 KiB
joy-cli 长期硬化完整方案(兼容三员 / 神兽 / joy web)
状态:Phase 0–7 已执行(2026-07-10);持续维护见修订表
日期:2026-07-10
范围:~/Projects/joy-cli主仓;关联linuxjoy文档/生成模板、~/office/*/CLAUDE.md|AGENTS.md、launchdjoy.web/joy.dashboard
原则:不破坏在飞轮上的用法;可删入口只能 deprecated 转发,不能 silent 删;一切破坏性变更必须带契约测试与回归清单
0. 为什么要改(问题浓缩)
| # | 问题 | 风险 |
|---|---|---|
| P1 | 顶级命令 58,agent 发现成本高 | 神兽/三员 prompt 与 help 漂移 |
| P2 | dashboard.py ~3.2k 行 单体 |
改一处牵全身;回归靠人眼 |
| P3 | help / manifest 不同源(已出现 pipeline 漂移) |
AI 发现层不可信 |
| P4 | JSON 无 schema_version | 静默破坏 web/agent 解析 |
| P5 | 权限元数据存在但几乎未启用 | 误用 execute 难追责 |
| P6 | web 白名单含 execute,audit 弱 | 本机决策台误操作成本高 |
| P7 | 测试以 smoke 为主 | 「46 绿」≠ 飞轮语义正确 |
本方案不是功能扩张,是:收口、契约化、可维护、可回归。
1. 在飞轮里的真实调用面(改前必知)
1.1 常驻进程(Mac launchd)
| Label | 命令 | 依赖 |
|---|---|---|
joy.dashboard |
joy dashboard --watch |
写 /tmp/joy-dashboard.json;字段形状是 web 真源 |
joy.web |
joy web |
读 cache + /api/* + 白名单 action;前端 src/joy/web/** |
改
dashboard/web等于改生产观测面。必须 热替换后验 cache keys + HTTP + 前端关键 tab。
1.2 三位管理员(Mac office)
| 角色 | 身份检测 | 文档写明的高频 joy 命令 | 影响敏感度 |
|---|---|---|---|
| konqi 龙奇 | JOY_IDENTITY / cwd office/konqi / 进程启发式 |
joy konqi *、patrol、cluster-health、clone *、board、recall、poke、message、mind、tmux、infra、api、prlctl、work_rebuild、clone_restart、restart clones |
极高 |
| tux 塔司 | office/tux + opencode | joy tux *、patrol、profile、board、recall、poke、message、mind、api probe |
极高 |
| wapuu | office/wapuu | joy intel、db、domain、board、recall、poke、message、mind |
高 |
来源:~/office/{konqi,tux,wapuu}/{AGENTS,CLAUDE}.md。
1.3 神兽(16 joy-clones pi)
启动模板真源:linuxjoy/scripts/mac/joy-clones.sh 写入各 ~/office/<vm>/CLAUDE.md 技术段。
神兽标准工具链(每台 VM 同构):
joy patrol <vm>
joy profile <vm>
joy project <vm>
joy curiosity <vm>
joy work <vm> transcript|inject|alive|idle
joy journal <vm> write|last|doubts
joy board ls|claim|done
joy recall search|add
joy signal stuck|done|help
joy delegate / joy who / joy env / joy inbox
joy budget <vm>
神兽不依赖 joy web;依赖 CLI JSON 形状 + 子命令名。
改名只能:旧命令保留转发;或同步改joy-clones.sh模板并 rebuild 16 路 CLAUDE.md。
1.4 人 / 菲比斯
- 浏览器
http://localhost:8899(joy web) - 偶发 CLI:
joy help、joy dashboard、joy board、joy web
1.5 当前 dashboard JSON 顶层键(兼容红线)
实测 /tmp/joy-dashboard.json 顶层(禁止无版本迁移就删/改名):
audit_ledger, board_tasks, bottleneck, bridge, capabilities, collect_errors,
curiosity, data_assets, dispatch_queue, events, flywheel, health_grid, ideas,
infra, issues, llm_providers, mac_host, meter, monitoring, nats, new_api,
physical_hosts, pi_agents, pipelines, pulse, security, tmux, trends, ts, vms
前端 tabs 与 hero 按这些键投影。拆 dashboard 文件时必须 golden 对比顶层键集合。
2. 影响矩阵(改完会不会影响)
2.1 总原则
| 变更类型 | 对 web | 对三员 | 对神兽 | 策略 |
|---|---|---|---|---|
物理拆分 dashboard.py(行为不变) |
无感 | 无感 | 无感 | 优先做 |
| help/manifest 同源 + 补 pipeline | 无感 | 发现更好 | 发现更好 | 优先做 |
JSON 加 schema_version(附加字段) |
无感* | 无感* | 无感* | 附加不删 |
旧命令 deprecated 转发(stdout 多 deprecated 字段) |
无感 | 兼容 | 兼容 | 允许 |
| 删除顶级命令入口 | 可能破 web action | 会破 AGENTS | 会破 16 CLAUDE | 禁止本阶段 |
| 改子命令语义/字段改名 | 破 tab | 破解析 | 破解析 | 仅 schema_version bump + 双写过渡 |
| 收紧 web control 默认 | 部分按钮需确认/失败 | CLI 不受 | 不受 | 可做,需 UI 文案 |
| 懒加载命令 import | 冷启动变快 | 无感 | 无感 | 可做,manifest 全量仍要加载 |
*若某 agent 用「对象键集合严格相等」解析会炸——实测 joy 侧均按字段读取,附加字段安全。
2.2 明确「不会动」的 ABI(冻结列表)
下列 命令路径 + 关键字段 本阶段冻结;只允许 bugfix 与附加字段:
A. 神兽日用 ABI
| 命令 | 冻结点 |
|---|---|
joy patrol <vm> |
顶层含 session/activity/board/inbox/doubts/llm 类信息(允许附加) |
joy work <vm> {transcript,inject,alive,idle} |
子命令名;inject 字符串参数 |
joy journal <vm> write|last|doubts |
路径与写 journal.jsonl 行为 |
joy board ls|claim|done|create|route |
子命令名;task id 语义 |
joy recall search|add |
子命令存在 |
joy signal / joy inbox / joy budget |
入口存在 |
joy profile / joy project / joy curiosity / joy env / joy who / joy delegate |
入口存在 |
B. 三员日用 ABI
| 角色 | 冻结 |
|---|---|
| konqi | joy konqi *、clone *、tmux、infra、api、poke、mind、restart、work_rebuild、clone_restart、prlctl |
| tux | joy tux *、patrol、profile、board、poke |
| wapuu | joy intel、db、domain、board |
C. joy web / dashboard ABI
| 契约 | 冻结 |
|---|---|
GET /api/dashboard |
返回与 cache 同形;顶层键集合 ⊇ 现状 |
GET /api/dashboard/lite |
保留 |
POST /api/action |
白名单前缀兼容;args 数组形态 |
ACTION_WHITELIST 已有前缀 |
不删;可增不可减(本阶段) |
/tmp/joy-dashboard.json 路径 |
不改 |
launchd 参数 joy dashboard --watch / joy web |
不改 |
D. 身份环境变量
JOY_IDENTITY优先逻辑保留PYTHONPATH=.../joy-cli/srclaunchd 注入保留~/bin/joy→Projects/joy-cli/bin/joy符号链接保留
3. 目标架构(长期)
┌─ 人:joy web :8899 ─────────────────────────────────────┐
│ 读 /api/dashboard(+lite) 写 /api/action(三态+audit) │
└───────────────────────────┬─────────────────────────────┘
│ 同源
┌───────────────────────────▼─────────────────────────────┐
│ joy CLI = 飞轮 agent ABI(稳定) │
│ A 核心运行时 B 领域扩展 C deprecated 转发 │
│ tools --manifest ≡ help 同源 │
└───────────────────────────┬─────────────────────────────┘
│ façade
┌───────────────────────────▼─────────────────────────────┐
│ linuxjoy scripts / Board / NATS / prlctl / SSH │
└─────────────────────────────────────────────────────────┘
CLI 表面分层(元数据,不是删命令)
| tier | 含义 | 示例 |
|---|---|---|
| core | 日常 ABI,help 默认展示 | patrol, health, resources, vm, clone, work, tmux, board, journal, message, recall, data, pipeline, idea, dashboard, web, tools, help |
| extended | 领域/角色扩展 | konqi, tux, mind, intel, budget, profile… |
| deprecated | 仍可用,help 标废,JSON 可带 deprecated |
prlctl, clone_restart, work_rebuild(转发 work rebuild) |
核心数量以 help 展示收口 为主;注册表仍保留全部 58,避免神兽/旧 AGENTS 断裂。
4. 分阶段执行计划(可验收)
Phase 0 — 契约冻结与基线(0.5–1 天)
动作
- 本文件入库(
docs/joy-cli-hardening-plan.md) - 建立 golden 基线(只读采集,不改代码逻辑):
tests/fixtures/dashboard_keys_v1.json:顶层键列表tests/fixtures/command_inventory_v1.json:58 命令名 + requires/envtests/fixtures/web_action_prefixes_v1.json:白名单前缀
- 文档化消费者矩阵(§1)进 README 链
- 工作区未提交改动:先 stash/提交归类,避免硬化过程混入 hardware 等半成品
验收
- golden 文件存在且 CI/本地测试可读
pytest现网 46 绿仍过
影响:无。
Phase 1 — 发现层与元数据同源(0.5–1 天)【低风险 · 先做】
动作
@command增加字段:tier: core|extended|deprecatedschema_version(命令级可选)replaced_by(deprecated 用)
HELP_DATA从 COMMANDS 生成(或生成后 diff 强制一致)- 补齐
pipeline进入 help/core tools --manifest输出含tier、schema_version、identity- 测试:
test_manifest_help_sync.py— 注册集 == help 集;pipeline 在 core
验收
joy help --json含 pipelinejoy tools --manifest | jq '.commands|length'≥ 现网- 无命令从注册表消失
影响:无功能影响;三员/神兽 joy help 更准。
Phase 2 — JSON 契约版本化(1 天)【低风险】
动作
- 统一成功输出包装策略(双轨,兼容优先):
- 对「本已是 dict」的响应:附加
"schema_version": 1(或"_joy": {"schema_version":1}若担心冲突) - 推荐
_joy.schema_version命名空间,避免污染业务字段
- 对「本已是 dict」的响应:附加
- 优先覆盖:
dashboardcache、patrol、board ls、tools --manifest、data *、pipeline *、health - 错误 JSON 保持
{error, code, detail?}不变
验收
- 旧解析(读业务字段)仍通过
- 新测试 assert
_joy.schema_version或顶层附加字段存在 /tmp/joy-dashboard.json仍含全部旧顶层键
影响:web 前端忽略未知字段 → 无感。
Phase 3 — dashboard 物理拆分(1–2 天)【中风险 · 行为冻结】
目标:dashboard.py 从 3k 行降到「编排壳 + collect 模块」,输出字节级语义不变(允许键序/空白差)。
建议目录
src/joy/commands/dashboard.py # CLI 入口 + compose + --watch
src/joy/dashboard/
__init__.py
compose.py # 拼总 dict + 写 cache
schema.py # 顶层键常量 + schema_version
collectors/
mac_host.py
tmux_pi.py
vms_health.py
board_dispatch.py
llm_gateway.py
data_assets.py
pipelines.py
security_infra.py
...
硬规则
- 禁止本阶段改 collector 业务算法(除明确 bug)
- 每拆一块:
pytest+ golden keys + 可选joy dashboard --json | jq 'keys'对比 - 去掉
shell=True时改为 argv 列表,对比 stdout 再合 - launchd
joy.dashboard不改参数;拆完后launchctl kickstart -k gui/$UID/joy.dashboard验证
验收
- 顶层键集合 == golden
pulse/bottleneck/vms/pi_agents/pipelines/data_assets抽样字段类型不变joy.dashboardKeepAlive 稳定 ≥ 2 个 watch 周期- web 总览 / 神兽 / 任务 / 流水线 / 数据 tab 人工点检
影响:若 compose 漏字段 → web 破。用 golden 挡。
Phase 4 — deprecated 转发(不删入口)(0.5–1 天)【中风险 · 兼容】
只做转发,不做删除:
| 旧入口 | 转发到 | 额外 |
|---|---|---|
joy prlctl ... |
joy vm ...(已有) |
确保 help 标废 |
joy clone_restart <vm> |
joy clone restart <vm> |
已有,补测 |
joy work_rebuild <vm> |
joy work <vm> rebuild(新增 sub,旧入口保留) |
双入口 |
(可选)joy uptime / joy disk |
内部调 resources 同数据 |
入口保留 |
禁止本阶段
- 删除
work_rebuild顶级名(konqi CLAUDE 仍写它) - 删除
prlctl/clone_restart
同步文档(非阻断)
- 更新
linuxjoy/docs/tools/joy-cli-reference.md - 更新
office/konqi/CLAUDE.md推荐新写法,旧写法仍可用
验收
- 旧命令 exit 0 行为与新命令一致(同 vm 测)
- 响应可含
"deprecated": "use joy ..."但不影响主字段
影响:三员旧 prompt 继续工作。
Phase 5 — web 可追责与 action 统一(1–2 天)【中风险】
动作
/api/action统一路径:
parse args → tier_for_args → whitelist → (control 门闩) → 调 joy CLI 同进程/子进程 → audit append- audit:
~/logs/joy-web-audit.jsonl或/tmp+NAS 可选;字段:ts, identity, tier, args, rc, ms, err_snip - UI:execute 二次确认文案统一;control 默认关(已有则加固)
- 不删 现有白名单前缀
验收
test_web_action_whitelist扩展:非法前缀 403/拒绝- 合法
patrol devops/idea list/board ls类 observe/register 可用 - audit 文件有追加
- 前端按钮仍能点通 3 个代表动作
影响:人用 web 更安全;CLI 与神兽 不受影响。
Phase 6 — 运行时质量(懒加载 / Env / 清理)(1 天)【低–中】
- 懒加载:
main仅 import 目标 command 模块;tools --manifest/help才全量 import Env支持测试注入(不改 singleton 对外行为)- inventory 失败:stderr 诊断 + 明确 fallback 列表,不 silent
- 删除空目录
commands/、lib/;domains/*.sh→archive/domains/(确认无引用) plugins/写 README:实验命令准入规则
验收
time joy help不劣化;time joy patrol可改善或持平- 全量 pytest 绿
影响:应无感;若懒加载漏注册 → 命令「未知」——用 manifest 测试挡。
Phase 7 — 测试金字塔与发布门禁(贯穿 + 收尾 1 天)
7.1 测试分层
| 层 | 内容 | 门禁 |
|---|---|---|
| L0 静态 | python -m compileall src/joy |
必过 |
| L1 unit | cluster_data, pipeline_registry, action_tiers, env identity | 必过 |
| L2 contract | manifest↔help;dashboard keys golden;web whitelist golden;schema_version | 必过 |
| L3 smoke CLI | 每条 core 命令 --help 或无参不崩;JSON 错误形态 |
必过 |
| L4 integration | board ls / data catalog / pipeline list(NAS 在则跑,不在则 skip) | 尽力 |
| L5 live Mac | dashboard --json keys;curl web lite/dashboard;launchd 状态 | 发布前必做 |
| L6 agent 回归 | 见 §5 检查单 | 发布前必做 |
7.2 发布检查单(Definition of Done)
[ ] pytest 全绿(新增 contract 全过)
[ ] golden:commands 集合未减少
[ ] golden:dashboard 顶层键未减少
[ ] golden:web action 前缀未减少
[ ] joy help 含 pipeline;tools --manifest 与 help 一致
[ ] launchctl print joy.dashboard / joy.web 为 running
[ ] curl -s localhost:8899/ | head 200
[ ] curl -s localhost:8899/api/dashboard/lite 含 pulse/ts
[ ] /tmp/joy-dashboard.json 新鲜(ts 在 2min 内)
[ ] 人工:web 总览、神兽、任务、流水线、数据 tab 无空白/JS 错
[ ] 代表 CLI:
JOY_IDENTITY=konqi joy konqi overview | head
JOY_IDENTITY=tux joy tux pending | head
JOY_IDENTITY=wapuu joy intel brief | head # 或 domains
joy patrol devops | head
joy board ls | head
joy clone status | head
joy work devops alive | head
[ ] 神兽模板:joy-clones.sh 技术段命令仍全部可执行(抽 1 台 devops)
[ ] 未改 JOY_IDENTITY / ~/bin/joy / launchd ProgramArguments
7.3 回滚
| 场景 | 回滚 |
|---|---|
| dashboard 采集坏 | git revert 对应 commit;launchctl kickstart -k gui/$UID/joy.dashboard |
| web 起不来 | 同上 + kickstart joy.web |
| 命令丢失 | 禁止出现;若出现从 git 恢复 commands/*.py |
| 半成品分支 | 功能开关:无(本阶段不做大开关);用 git 回滚 |
5. 消费者回归检查单(详细)
5.1 joy web
| 检查 | 方法 | 期望 |
|---|---|---|
| 服务存活 | launchctl list | rg joy.web |
PID 在 |
| 首页 | 浏览器 :8899 | 总览有 pulse |
| lite API | curl /api/dashboard/lite |
200 + ts |
| 全量 API | curl /api/dashboard | jq 'keys' |
⊇ golden |
| 白名单列表 | curl /api/actions |
前缀齐全 |
| 写操作 | UI:idea list / journal last / patrol 单 VM | 成功或明确错误 JSON |
| 样式/JS | DevTools Console | 无硬错误 |
5.2 三员
| 角色 | 命令烟测 | 权限烟测 |
|---|---|---|
| konqi | JOY_IDENTITY=konqi joy konqi overview |
JOY_IDENTITY=wenpai joy konqi overview → E_PERM |
| tux | JOY_IDENTITY=tux joy tux pending |
非 tux → E_PERM |
| wapuu | JOY_IDENTITY=wapuu joy board ls |
可用 |
| 通信 | joy poke dry 路径(避免真注入可 mock/短消息) |
requires 含三员 |
| 旧名 | joy work_rebuild / joy clone_restart / joy prlctl |
仍可用或明确转发 |
5.3 神兽
| 检查 | 方法 |
|---|---|
| 模板命令可运行 | 对 devops 跑 joy-clones 技术段每一条(read-only 优先) |
| journal 写 | joy journal devops last 1 |
| work 观测 | joy work devops alive / transcript 3 |
| board | joy board ls --vm devops |
| 不依赖 web | 断 web 后 CLI 仍可用(可临时停 joy.web 再启) |
| rebuild 策略 | 默认不 rebuild 16 神兽;仅当改 CLAUDE 模板时才 joy-clones 重生配置 |
5.4 VM 上 joy(若已 deploy)
| 检查 | 方法 |
|---|---|
| 存在 | ssh devops 'joy --version' |
| 基础 | ssh devops 'joy help | head' |
| 与 Mac 差集 | VM 无 prlctl/web/dashboard 属预期(env 限制) |
6. 明确不做(本方案非目标)
- 重写前端框架 / 换 React
- 删减 58→15 的硬删除(只做分层与转发)
- 改 Board/NATS/dispatch 协议
- 改 new-api / auto-pi 路由
- 强制 16 神兽全部 rebuild(除非模板变更)
- 生产防火墙、跨 VM 批量高危 prlctl
- 把 joy web 变成真派活引擎(dispatch 仍是真源)
7. 推荐执行顺序与工期
| 顺序 | Phase | 工期 | 风险 | 可独立合并 |
|---|---|---|---|---|
| 1 | Phase 0 基线 | 0.5d | 低 | ✅ |
| 2 | Phase 1 发现层 | 0.5–1d | 低 | ✅ |
| 3 | Phase 2 schema_version | 1d | 低 | ✅ |
| 4 | Phase 3 dashboard 拆分 | 1–2d | 中 | ✅ 需 L5 验 web |
| 5 | Phase 4 deprecated 转发 | 0.5–1d | 中 | ✅ |
| 6 | Phase 5 web audit | 1–2d | 中 | ✅ |
| 7 | Phase 6 懒加载/清理 | 1d | 低–中 | ✅ |
| 8 | Phase 7 门禁固化 | 1d | 低 | 与上并行 |
合计约 6–10 人日。建议 每 Phase 单独 commit,每 Phase 跑 §7.2 检查单再进下一 Phase。
8. 与既有文档关系
| 文档 | 关系 |
|---|---|
docs/joy-panel-cli-architecture-plan.md |
产品 IA / 核心 15 愿景;本方案是其「兼容优先落地版」 |
linuxjoy/docs/specs/2026-07-07-joy-python-rewrite.md |
Python 重写已完成;本方案是 2.0 后硬化 |
linuxjoy/docs/tools/joy-cli-reference.md |
需在 Phase 4/7 同步(可滞后代码一个 commit) |
office/*/AGENTS.md + joy-clones.sh |
消费者;改模板仅当 ABI 真变 |
9. 决策请求(执行前需菲比斯确认)
| # | 问题 | 建议默认 |
|---|---|---|
| D1 | 是否按 Phase 0→7 全做? | 是,按序 |
| D2 | schema 附加字段用 _joy.schema_version 还是顶层 schema_version? |
_joy 命名空间 更安全 |
| D3 | work_rebuild 是否增加 work rebuild sub 并保留旧入口? |
是 |
| D4 | 本阶段是否允许「仅文档」把 konqi 的 prlctl 写法改成 vm? |
是,但代码转发必须先在 |
| D5 | web execute 是否强制二次确认(已有则加强)? | 是 |
| D6 | 是否在本方案中处理未提交 hardware tab? | 分开 PR,不与硬化混提 |
10. 一句话总结
在不打断 joy web 常驻、三员 AGENTS、神兽 CLAUDE 的前提下,把 joy-cli 从「58 命令功能堆」收成「可版本化、可测试、可转发废弃」的长期 ABI;先契约与拆分,后加固与清理;每一刀都用 golden + 消费者检查单验收。
11. 修订
| 日期 | 变更 |
|---|---|
| 2026-07-10 | 首版完整方案:调用面审计 + 影响矩阵 + Phase 0–7 + 测试门禁 |
12. 执行记录
| 日期 | 内容 |
|---|---|
| 2026-07-10 | Phase 0–7 落地:golden fixtures、tier/help 同源、_joy.schema_version、dashboard 包拆分、deprecated 转发、web JSONL audit、懒加载、contract 测试;pytest 54 绿;launchd web/dashboard 回归 |