Communitygithub.com

BlackBeltTechnology/pi-agent-dashboard

实时网页仪表盘,用于监控 pi 编码助手会话。支持多会话视图、实时聊天镜像、集成终端、差异比较器、pi-flows 执行,并通过 mDNS 或 zrok 隧道实现移动优先的远程控制。与 pi 的 TUI 共存,不替代它。

pi-agent-dashboard 是什么?

此技能(ship-it)用于编排 OpenSpec 变更的**实施阶段**,在其 Git 工作树内部运行。它是 `plan-proposal` 的孪生技能(后者在 `develop` 分支上运行规划阶段)。它组合了现有技能——`openspec-apply-change`、Docker 测试框架和 `ship-change`——并弥补了它们之间缺失的连接。该技能支持**无头运行**,其核心决策逻辑位于 `scripts/` 目录下,并使用 Vitest 进行单元测试。主要平台是支持 OpenSpec 变更工作流程的编码助手环境(如 Claude Code)。其工作流程包括:通过 `openspec status` 进行状态检查、执行 `openspec-apply-change`、合并 `origin/develop`、运行 Docker 集成测试、强制执行静态检查(如 knip/约定检查)、进行本地代码审查(由 `@review` 模型完成),最后通过 `ship-change` 完成发布。关键防护措施包括:基于文件系统真实状态的幂等性、禁止弱化测试(`assertNoWeakening`)、审查前强制执行静态检查、无条件的审查回合(硬性上限为两轮),以及在合并或删除工作树前确保提案存档和同步。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add BlackBeltTechnology/pi-agent-dashboard

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

ship-it

编排 OpenSpec 变更的实施阶段,在其 Git 工作树内运行。是 plan-proposal 的孪生技能(后者在 develop 分支上运行规划阶段)。组合现有技能——openspec-apply-change、Docker 测试框架和 ship-change——并弥补它们之间缺失的连接。可无头运行。

flowchart LR
  P["plan-proposal (develop)"] -->|"边界:衍生工作树"| S
  subgraph 工作树 ["实施阶段 — 工作树 (此技能)"]
    S["ship-it"] --> A["apply"] --> M["合并 develop (2.5)"] --> T["docker-harness 测试"] --> E["执行器(4.4)"] --> R["本地审查(4.5)"] --> C["ship-change"]
  end
  S -.->|"反向:遇到设计问题时写入 SHIP_IT_BLOCKED.md"| P

纯决策逻辑位于此技能自己的 scripts/ 目录下,并经过单元测试(.pi/skills/ship-it 是一个 Vitest 项目): scripts/manifest.ts(parseManifest、deferDecision、filesystemRealityCheck), scripts/no-weakening.ts(assertNoWeakening),以及 scripts/review-gate.ts(reviewRoundDecision、resolveReviewer、classifyFindings、REVIEW_TIMEOUT_MS)。

前置条件

  • 在变更的工作树内运行(.worktrees/os-<change>,分支为 os/<change>)。从工作树目录的基名称解析变更名称。
  • docker 可用(用于端到端测试框架);openspec CLI 在工作树内时从父仓库根目录解析(根据 AGENTS.md)。
  • 宣告:“正在发布变更:<change>(工作树实施阶段)。”

流程

1. 通过 openspec status 定位,但以文件系统真实状态为门控(幂等)

读取 openspec status --change <change> --json 仅用于定位。不要依赖 tasks.md 的复选框作为自动化场景完成的证据——手动勾选或部分先前的 - [x] 可能不准确。

解析 test-plan.md(parseManifest)。对于每行 automated 行,解析其折叠的测试文件并运行 filesystemRealityCheck:仅当该场景的测试文件存在且能通过测试框架时才算满足(步骤 3)。任何 automated 行其测试文件缺失 → 未完成 → 编写它(步骤 2),无论复选框状态如何。这使得重新调用真正幂等:初始运行和重新运行都能达到相同的全绿灯最终状态。

2. 如果仍有非手动工作,则运行 apply——注入示例

即使作为执行者,也要坚持知识库优先。 你知道任务所指的文件,因此你的直觉应该是直接对它们使用 grep/cat/Read。文档优先的门控仍然适用:在对符号执行 grep/rg、读取文件以了解其用途或追踪导入之前,首先运行 kb_search / kb agents <path> / kb_neighbors。了解文件不豁免你——先知识库查询符号/文件,然后编辑。

如果仍有非 manual-only 任务(实际代码加上折叠任务所指定的测试文件),则为此变更运行 openspec-apply-change。apply 编写代码并标记任务。

apply 本身不具备“从示例复制”的能力。对于每个折叠的测试任务,解析测试框架示例指针(任务命名的最接近的现有该类规范),并将其路径注入到传递给 apply 的任务上下文中——或者在修复循环中自己编写规范(步骤 4)。禁止使用没有示例的“编写 X.spec.ts”。

2.5. 集成 develop——在测试框架之前合并(主要集成点)

测试框架(步骤 3)是 ship-it 路径上最强的门控,因此集成必须位于其上游:测试框架必须验证合并后的树 T1,而不是合并前的树 T0。合并 origin/develop——远程引用,永远不要使用本地的 develop(在父仓库中检出 → 工作树分支冲突陷阱):

git fetch origin develop
git merge --no-edit origin/develop

幂等:已是最新 → “Already up to date”,无需合并提交,始终安全运行。使用合并,而非变基——步骤 9 最终使用 squash-merge,因此变基的线性历史无关紧要,而其强制推送则是 ship-change 文档中已知的陷阱。

冲突 → 中止并停止。 出现未解决的冲突时,执行 git merge --abort,报告,且不进入测试框架——绝不要在部分合并的树上运行门控。使用 ship-change 现有的配方解决简单冲突(AGENTS.md 保留联合;pnpm-lock.yaml → git checkout --theirs + pnpm install --lockfile-only),然后重新运行合并。无法机械解决的冲突 → 逃生通道(步骤 5)。

3. 测试框架生命周期——委托端口,始终清理

从 docker/test-up.sh 获取测试框架及其端口(首次运行时分配,重新运行时复用——不要添加端口代码)。从 .pi-test-harness.json 读取派生端口(dashboardPort)——永远不要硬编码 :18000。

包裹整个运行过程,确保清理始终执行(无论测试红、中止还是 test-up.sh 部分启动):

cleanup() { docker/test-down.sh || true; }
trap cleanup EXIT
docker/test-up.sh -d --build            # 分配并记录 .pi-test-harness.json
port=$(jq -r '.dashboardPort' .pi-test-harness.json)   # jq 存在于测试框架环境中
# 针对 $port 运行相关测试套件:
PW_E2E_USE_RUNNING=1 npm run test:e2e   # L3;或针对其他级别的 L1/L2 套件

test-down.sh 对于部分创建的 Compose 项目是安全的(compose down -v + 尽力而为的 rm)。每个工作树独立的 Compose 项目可防止一个工作树的泄露阻塞另一个工作树。

4. 红测修复循环——由 ship-it 拥有(apply 无法修复已检查的任务)

apply 将 - [ ] → - [x],并且从不重新访问已检查的任务,因此对红色但已检查的测试重新调用 apply 无效。测试变红时,ship-it 自行驱动修复——编辑代码或测试,重新运行测试框架。绝不对已检查的任务重新调用 apply。

通过产生进展的循环来约束循环,而非固定次数:

  • 改变工作树并使测试框架结果前进的循环算作一次。
  • 对工作树没有产生变化的循环 → 立即停止并升级(步骤 5)。不要空转。
  • 此约束与怀疑审查的 3 轮约束无关(语义不同)。

禁止弱化防护栏(机械执行,每个循环执行): 在接受对测试文件的更改之前,对其差异运行 assertNoWeakening(git diff -- <test-file>)。如果报告 ok:false(添加了 .only/skip,删除了断言,或强→宽松匹配器替换),拒绝更改——你不能通过降低测试标准来达到绿灯。修复代码本身。

4.4. 确定性执行器——廉价、离线,在任何模型调用之前

从工作树根目录运行执行器。每个执行器已经是对应规则的唯一拥有者;此步骤仅调用它们:

node scripts/check-conventions.mjs --base origin/develop
node scripts/dox-byte-gate.mjs
node scripts/i18n-lint.mjs --strict     # --strict,否则无论结果如何都退出 0
node scripts/i18n-parity.mjs
node scripts/knip-config.mjs            # knip.json 仍然根植于每个清单条目
node scripts/knip-ratchet.mjs           # 每类死代码的棘轮机制(约 8 秒)
node scripts/knip-ratchet.mjs --check-baseline-diff origin/develop   # 检查基线是否被提高

knip 对是死代码预言机的预防性一半:夜间作业在合并后运行,只能报告。顺序很重要——knip-config.mjs 优先,因为未根植的图会将活跃文件报告为死代码,而基于该数字的棘轮机制会产生噪音(实测:未根植 723 个发现 / 90 个未使用文件 vs 根植后 437 / 10)。通过删除死代码修复棘轮失败;提高基线会被第三条命令拒绝——该命令必须保持连接,否则“永远不要提高上限”就成了一句空话:普通的棘轮机制在面对提高的数字时会顺利通过。它还会拒绝已删除的类,这是一种更便宜的绕过方式。

它们放在此处,在测试框架之后和审查之前,因为它们是确定性的、离线的且近乎即时:一棵机械性失败的树绝不应耗费模型调用。非零退出状态会路由到步骤 4 的修复循环;步骤 4.5 不会运行。

--base 对于门控是强制性的:没有它,受影响的集合未定义,Discipline-Skills 和 Mermaid 规则会报告但不会门控。受影响的集合合并了已提交的差异和工作树,因此修复循环中尚未提交的修复也会被检查。

这些不会移入 quality:changed。该脚本是开发循环的预言机,没有自动调用者;发布门控就在这里。

4.5. 本地审查检查点——语义部分

在每次调用时运行。没有琐碎情况可以跳过:没有差异大小、路径或更改文件计数条件可以跳过它。

  1. 解决审查者:使用 scripts/review-gate.ts 中的 resolveReviewer。@review 是必需的。未配置 → 硬失败,并提示 update_roles / 仪表盘的 Roles 面板。故意没有回退到会话默认模型:该模型是作者,因此回退会使门控变为自我审查。交互式运行可能会提供引导提示;无头运行会失败。
  2. 将其生成为一个隔离的子代理——一个带有 model: "@review" 的 Agent 调用,携带 review-code 的评分标准。绝不允许上下文内的自我审查,也绝不使用 CodeRabbit CLI(那是 ship-change 的远程门控,在后面且不同)。
  3. 向其提供差异 + 意图:git diff origin/develop...HEAD(三点差异,因此步骤 2.5 的合并不会归于此变更)加上未提交的工作树编辑,再加上 proposal.md 和任务文本。
  4. 限制调用时间为 REVIEW_TIMEOUT_MS(300 秒)。超时既不是通过也不是阻塞性发现——它是检查点失败。
  5. 路由发现:使用 classifyFindings:只有 issue(blocking) 重新进入修复循环。其他所有内容都报告并发布。
  6. 限制循环轮次:使用 reviewRoundDecision:审查、修复、重新审查——绝不允许第三轮。这是一个硬性数字上限,不是步骤 4 的无进展规则,因为审查者每轮都可能发出新的发现,而每次修复都会改变工作树,因此无进展约束永远不会触发。
  7. assertNoWeakening 仍然控制审查修复所做的每个测试编辑。只有通过弱化测试才能满足的发现是不可满足的 → 逃生通道(步骤 5),同时命名发现和防护栏。防护栏绝不会为了达到绿灯而放松。

每个 escape 决策都带有 reason;将其写入 SHIP_IT_BLOCKED.md。

5. 边界反向逃生通道

工作树边界不是单向的。在以下任一情况下触发反向路径:

  • apply 报告设计问题(自然语言说明——实施揭示设计有误),或者
  • 步骤 4 的修复循环耗尽(无进展的循环)。

此时,不要无头重写 proposal.md/design.md:

  1. 保持工作树不变(不还原)。
  2. 编写 openspec/changes/<change>/SHIP_IT_BLOCKED.md,命名失败场景/设计差距以及已尝试的方法。
  3. 以非零退出。
  4. 通过仪表盘呈现,以便人工在 develop 上重新进入 plan-proposal / doubt-driven-review。

6. 内联驱动 ship-change,附带清单感知的延迟决策和清理顺序

一旦每个自动化场景都变为绿灯(经测试框架验证),即可发布。内联执行 ship-change 的流程(不作为黑盒子子代理),以便为下面的清理顺序保持步骤级别的控制。

延迟规则(deferDecision,清单感知):

  • test-plan.md 存在 → 剩余的 - [ ] 只有在映射到 manual-only 清单行时才可延迟(行内 (test-plan: manual-only) 或解析为清单的 (test-plan #<id>) 引用)。任何其他剩余的 = 实际工作 = 停止(返回步骤 2 或逃生通道)。
  • test-plan.md 不存在(遗留变更)→ ship-change 的当前关键词延迟规则照常适用。

在破坏性步骤之前的归档+同步门控(至关重要): 在提案未归档且规范未同步时,不要让 ship-change 合并 PR、删除分支或移除工作树。ship-change 步骤 8.5 是那个硬门控——内联驱动 ship-change,在步骤 8.5 处保持,直到变更归档(源目录移至 openspec/changes/archive/,移动已提交)且规范已同步。归档失败/跳过 → 停止(返回步骤 2 或逃生通道),绝不允许进入步骤 9/10。

移除前清理的顺序(至关重要): 测试框架必须在 ship-change 步骤 10 移除工作树之前拆除(test-down.sh,已通过步骤 3 的 trap 连接)。泄漏的容器会使工作树“忙碌”并阻塞移除。先运行测试框架清理,然后让 ship-change 进行归档 → 提交 → PR → CI → CodeRabbit → (归档+同步门控) → squash-merge → 移除工作树。

防护措施

  • 基于文件系统真实状态的幂等性——复选框 - [x] 绝不是证据;测试文件必须存在且能通过测试框架。
  • ship-it 拥有修复循环——绝不对已检查的任务重新调用 apply。
  • 绝不弱化测试以达到绿灯——assertNoWeakening 拒绝它。
  • 执行器(4.4)在审查者(4.5)之前——绝不在机械性失败的树上耗费模型调用。
  • 审查是无条件的——没有琐碎情况可以跳过,并且 @review 是必需的;绝不回退到会话默认模型(那是自我审查)。
  • 两轮审查,硬性上限——审查、修复、重新审查,然后逃生。不是无进展约束:模型总是会取得“进展”。
  • 在测试框架之前合并 develop(步骤 2.5)——强门控验证集成树 T1;合并 origin/develop(远程引用),绝不使用变基。冲突 → 中止并停止,绝不在部分合并的树上进入测试框架。
  • 在提案未归档和同步前,绝不合并/删除分支/移除工作树——在 ship-change 步骤 8.5(归档+同步门控)处保持直到通过;归档失败 → 停止。
  • 始终拆除测试框架(trap/finally),在工作树移除之前。
  • 绝不硬编码 :18000——从 .pi-test-harness.json 读取 dashboardPort。
  • 绝不无头重写规划制品——使用逃生通道。
  • 内联驱动 ship-change——不要将其作为子代理生成(你需要其步骤边界来进行清理顺序)。

组成

…

[因翻译而截断]

相关技能