@nathan33/nao-skill 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/checklists/deliverable-docs.md +2 -1
- package/.agents/checklists/pm.md +3 -1
- package/.agents/checklists/qa.md +2 -1
- package/.agents/common/intercom-protocol.md +1 -1
- package/.agents/prompts/product-manager.md +4 -2
- package/.agents/prompts/test-engineer.md +3 -2
- package/.agents/scripts/nao-fleet.sh +99 -16
- package/.agents/skills/pm-grill.md +4 -0
- package/.agents/skills/pm-to-spec.md +83 -0
- package/.agents/templates/prd.md.example +65 -0
- package/README.md +1 -1
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ description: 交付文档写作规范(PRD/ADR/报告/调研:简洁、可读
|
|
|
14
14
|
3. **写决策不写过程,写差异不复述**:与代码 / 上游文档重复的内容一律用指针(`路径#小节`)。
|
|
15
15
|
4. **超预算就删,不是加长**:每份文档有长度上限;超了先删「常识 / 过程 / 全量罗列」,仍超才另附文件。
|
|
16
16
|
|
|
17
|
-
- **PRD**:上限 ≤150 行;必须留下 9 模块结论、范围/非范围、AC;禁止
|
|
17
|
+
- **PRD**:上限 ≤150 行;必须留下 9 模块结论、范围/非范围、AC;禁止 抄竞品原文、贴代码;**非范围必带理由**。模板见 `@.agents/templates/prd.md.example`。
|
|
18
18
|
- **ADR**:上限 ≤60 行;必须留下 决策、对照模式、参考来源;禁止 大段代码、教程式背景。
|
|
19
19
|
- **评审报告**:上限 ≤60 行;必须留下 可行性、风险、取舍、待拍板点;禁止 复述 PRD。
|
|
20
20
|
- **测试报告**:上限 ≤80 行;必须留下 范围、结果数字、缺陷、风险、建议;禁止 日志/截图全文。
|
|
@@ -44,6 +44,7 @@ description: 交付文档写作规范(PRD/ADR/报告/调研:简洁、可读
|
|
|
44
44
|
|
|
45
45
|
- 首屏 TL;DR(≤5 行):做什么 · 给谁 · 成功标准 · 不做什么
|
|
46
46
|
- 9 模块:**每模块一小节**,内容用列表承载(**不用表格**);每项 **≤3 句 / ≤60 字**;不适用项写「不适用:<一行理由>」,**不许留空、不许写废话**
|
|
47
|
+
- **非范围必带理由**:每条非范围后跟一行理由(即写「不适用」也要给理由),否则视为未完成
|
|
47
48
|
- AC 逐条 Given/When/Then,一条一行
|
|
48
49
|
- 推演细节(RICE 打分过程、5 Whys 展开、同类产品调研明细)落 `docs/research/` 或附录,**正文只留结论 + 指针**
|
|
49
50
|
- **⛔ PRD 正文不使用表格** ⇒ 改用**有序 / 无序列表 + 加粗字段名**(如 `- **版本**:1.12.3`)。最常被误写成表格的三处:**需求清单(用户故事 / 条目)· 验收标准(AC)· 范围 / 非范围**。
|
package/.agents/checklists/pm.md
CHANGED
|
@@ -61,12 +61,14 @@ description: PM 交付核对清单(按需,交付/派发前读取)
|
|
|
61
61
|
- [ ] release notes 不可读(纯编号/类名/路径),或未落盘 `docs/releases/`?(规范:@.agents/common/release-notes.md —— 面向用户「本次更新」置顶、内部信息下沉、正文不用表格)
|
|
62
62
|
- [ ] 降级(无 `gh` / 无远端)未在 `tasks-state` 与回执中标注?
|
|
63
63
|
|
|
64
|
-
## 交付检查清单(完整
|
|
64
|
+
## 交付检查清单(完整 38 项)
|
|
65
65
|
|
|
66
66
|
- [ ] 目标/边界/验收三件事齐备
|
|
67
67
|
- [ ] 证据 + 5 Whys 已产出
|
|
68
68
|
- [ ] 战略筛子已过,RICE 可追溯
|
|
69
69
|
- [ ] PRD 含 9 模块
|
|
70
|
+
- [ ] 接缝候选已列并经 qa 确认(不适用注明理由)
|
|
71
|
+
- [ ] 路径无关判据已核(@.agents/skills/pm-to-spec.md §六 逐条)
|
|
70
72
|
- [ ] 场景模块含画像+场景卡+关键路径+页面状态清单
|
|
71
73
|
- [ ] AC 五覆盖
|
|
72
74
|
- [ ] 变更记录完整(含 Hotfix)
|
package/.agents/checklists/qa.md
CHANGED
|
@@ -24,12 +24,13 @@ description: 测试工程师交付核对清单(按需,交付前读取)
|
|
|
24
24
|
- [ ] 视觉/UI 呈现类验证启动了浏览器自动化(无头浏览器/截图对比)?(应产出用户验收清单交用户人工,见 skills/test-design.md「视觉/UI 呈现验证」)
|
|
25
25
|
- [ ] 含 UI 呈现的交付未产出用户验收清单(测什么/怎么操作/预期结果/对应 AC)?
|
|
26
26
|
|
|
27
|
-
## 交付检查清单(完整
|
|
27
|
+
## 交付检查清单(完整 18 项)
|
|
28
28
|
|
|
29
29
|
- [ ] 测试计划含范围与风险评估(测什么/不测什么)
|
|
30
30
|
- [ ] 未私自修改现有功能代码
|
|
31
31
|
- [ ] 执行前已列清单并经**用户/PM(开工确认卡)**确认范围
|
|
32
32
|
- [ ] 用例覆盖等价类/边界/主路径/异常,且可追溯 AC
|
|
33
|
+
- [ ] 接缝确认已作为 PRD 阶段输入:PM 列候选 → QA 确认/修正 → 写入 PRD「AC」首行,用例按确认后的接缝组织
|
|
33
34
|
- [ ] 分层测试与 DDD 分层对齐
|
|
34
35
|
- [ ] 缺陷全量入库、信息完整、生命周期闭环
|
|
35
36
|
- [ ] 回归已执行(冒烟 + 受影响),未过未放行
|
|
@@ -29,7 +29,7 @@ description: pi-intercom 多会话协作协议(常驻引用)
|
|
|
29
29
|
|
|
30
30
|
- **判重 / 在线判定**:脚本按 pi 自设的**终端标题**(`π - <会话名> - <仓库名>`)+ `pi-intercom` 名册判在线(**不用 `pgrep --name`**:pi 启动后 argv 被改写为 `pi`,会恒失配);已运行则跳过并 warn。确需重开加 `--force`。
|
|
31
31
|
- **标题被改写时的 pane 定位**(v0.9.4):终端标题可被外部改写(实测变为 `pi:c`),此时 `status`/`close`/`ensure` 按三层后备定位 pane:① 标题契约 → ② pi-intercom 名册 `tmuxPane`(注册时读 `$TMUX_PANE`,与标题改名无关,权威)→ ③ 本仓「未被认领 pi pane」唯一兜底。三层均未命中才认「无法确认」并 exit 非 0(不静默 no-op)。`close` 的在跑 turn 判定叠加名册活动状态(thinking / tool:* 等)与 pane 末 12 行状态行双重信号。
|
|
32
|
-
- **宿主阶梯(tmux 外也看得见)**:`nao-fleet.sh ensure` 按环境选宿主:① `NAO_TERMINAL` 显式(`tmux`/`foot`/`ghostty`/`ptyxis`/`screen`;命令缺失或非法 ⇒ `exit 2`)→ ② `$TMUX`
|
|
32
|
+
- **宿主阶梯(tmux 外也看得见)**:`nao-fleet.sh ensure` 按环境选宿主:① `NAO_TERMINAL` 显式(`tmux`/`foot`/`ghostty`/`ptyxis`/`screen`;命令缺失或非法 ⇒ `exit 2`)→ ② `$TMUX` 内:**派生宿主窗口**(调用者 pane 所在 window)分屏 → ③ tmux 可用且有图形会话:建 `nao-<别名>` 会话并用 `xdg-terminal-exec` 开**可见窗口** attach(默认 socket,句柄模型完整)→ ④ 无 tmux 有图形:`xdg-terminal-exec --app-id=org.nao.<别名> --dir=<repo>` 直接开窗 → ⑤ 无图形:仅显式 `--background` 才建 detached 会话 → ⑥ 否则 `exit 2` + 一行诊断与恢复命令。**失败不假成功**:打印「已拉起」前必先校验宿主句柄。
|
|
33
33
|
- **tmux 布局**:②/③ 的 tmux 宿主三选一(`NAO_TMUX_LAYOUT`):默认 `main-row2`(首 pane 全高占左,后续每角色往右开列、每列上下 2 个);`main-col`(其余在右列竖排);`grid`(等大网格)。**窄列守卫**:`main-row2` 最窄非主 pane < `NAO_TMUX_MIN_PANE_WIDTH`(默认 30)时自动回退 `main-col`,仍不足再退 `grid`(打印带数字的 warn,**不中断拉起**)。
|
|
34
34
|
- **非 tmux 宿主降级边界(D2/D6)**:④ 路径无 tmux pane 句柄,`status` 会明确标注「turn 判定来源 = 名册」(在跑 turn 判定仅供参照),`close` 按窗口 `app-id`(`org.nao.<别名>`)→ pid(校验 `comm=pi`)回收;无 `hyprctl`/`swaymsg`/`xdotool`/`wmctrl` 等 class 探针时,接受启动并打印一行 warn(**无法校验 ≠ 校验失败**)。
|
|
35
35
|
- **模型规则**:用户未指定则**禁止传 `--model`**,也禁止继承 PM 自身模型。
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: 产品经理角色 Prompt(短常驻)——需求分析/PRD/优先级/验收/多会话调度
|
|
3
3
|
role: pm
|
|
4
|
-
version:
|
|
5
|
-
updated: 2026-10-
|
|
4
|
+
version: 24
|
|
5
|
+
updated: 2026-10-14
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# 产品经理(PM)
|
|
@@ -10,6 +10,7 @@ updated: 2026-10-13
|
|
|
10
10
|
> 通用规范见 @.agents/common/output-format.md 与 @.agents/common/intercom-protocol.md(常驻)。
|
|
11
11
|
> 项目上下文:项目根 `AGENTS.md`(项目级属性/约束,PM 维护,pi 自动加载,见 §七)。
|
|
12
12
|
> 按需技能:@.agents/skills/pm-rice.md(优先级)、@.agents/skills/pm-grill.md(澄清)。
|
|
13
|
+
> @.agents/skills/pm-to-spec.md(成熟需求直出 PRD:验证接缝 + 对话综合;判定命中即跳过 grill)。
|
|
13
14
|
> @.agents/skills/pm-routing.md(路由与派单纪律 + 技术调研边界;派发/调研前读取)。
|
|
14
15
|
> @.agents/skills/pm-operations.md(调度细则 / 开工确认卡 / 会话生命周期 / AGENTS.md 治理 / 归档)。
|
|
15
16
|
> @.agents/skills/codegraph.md(验收读码:node --file/--limit 行段读取,禁 cat 全文)。
|
|
@@ -31,6 +32,7 @@ updated: 2026-10-13
|
|
|
31
32
|
|
|
32
33
|
9 模块:**问题证据|目标指标|范围/非范围|用户场景|业务规则|NFRs|AC|上线闭环|变更治理**。
|
|
33
34
|
9 模块是验收闸门不得删;**正文用列表 + 加粗字段名承载,不用表格**(写法规格见 @.agents/checklists/deliverable-docs.md §三)。
|
|
35
|
+
**入口分支**:需求成熟(命中 @.agents/skills/pm-to-spec.md 判定)→ 接缝 + 对话综合直接成稿;不成熟 → 先走 grill 五层追问。
|
|
34
36
|
每模块内容与缺失后果速查(**写前参考,非正文格式**):@.agents/checklists/pm.md(写 PRD 前读取)。
|
|
35
37
|
|
|
36
38
|
## 三、需求工作流(七阶段)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: 测试工程师角色 Prompt(短常驻)——策略/用例/缺陷/质量保障
|
|
3
3
|
role: qa
|
|
4
|
-
version:
|
|
5
|
-
updated: 2026-10-
|
|
4
|
+
version: 14
|
|
5
|
+
updated: 2026-10-14
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# 测试工程师(QA)
|
|
@@ -62,6 +62,7 @@ DDD 分层对齐(简):
|
|
|
62
62
|
- **AC = 测试用例**:Given/When/Then 直接转译;无 AC 需求先补齐再测。
|
|
63
63
|
- **业务规则 → 领域测试**:状态流转、不变量对应 domain 单测;发现规则散落组件/Service 时提示研发收敛。
|
|
64
64
|
- **评审参与**:需求评审确认可测性(数据口径/埋点/边界)。
|
|
65
|
+
- **接缝确认 = QA 在 PRD 阶段的输入**:PM 列验证接缝候选(理想 1 个、优先复用、能高不高低)→ QA 确认或修正(可改为更高/更少)→ PM 写入 PRD「AC」首行;用例按确认后的接缝组织(流程见 @.agents/skills/pm-to-spec.md,用例设计见 @.agents/skills/test-design.md)。
|
|
65
66
|
- **缺陷闭环联动**:指派明确、信息完整,避免"环境问题/数据问题"推诿。缺陷**全量入库**,落点见 @.agents/skills/test-design.md「缺陷管理」(`docs/reports/<编号>-defects.md` 或项目约定缺陷平台)。
|
|
66
67
|
- **PR 验证**:在 PR 评论贴**全量门禁精确数字**(命令 + exit code + 文件数/例数/红数)与预览环境结论;**PM 验收通过前不得以"测试已过"为由催促合并**(合并由 RD 在 PM 授权后执行)。
|
|
67
68
|
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
# NAO_TMUX_LAYOUT=main-row2|main-col|grid tmux 布局(默认 main-row2)
|
|
32
32
|
# NAO_TMUX_MAIN_WIDTH=<10..90> 主 pane 宽度百分比(默认 35;main-row2/main-col 共用)
|
|
33
33
|
# NAO_TMUX_MIN_PANE_WIDTH=<10..80> 最小非主 pane 列宽守卫(默认 30;低于则回退)
|
|
34
|
+
# NAO_TMUX_HOST_WINDOW=<window> 显式指定派生宿主窗口(默认自动:$TMUX_PANE→名册;允许跨 session,建议 @id 形式)
|
|
34
35
|
# NAO_SKILLS=<dir> nao 机制包根目录(默认 <脚本>/../..;项目内 shim 会显式指向包根)
|
|
35
36
|
# NAO_MODEL_WHITELIST=<glob,...> -m 白名单(默认空=不校验,支持 glob)
|
|
36
37
|
# NAO_CLOSE_BUSY_PATTERN=<ERE> close 的在跑 turn 判定正则(默认内置 pi 状态行标记)
|
|
@@ -53,7 +54,9 @@
|
|
|
53
54
|
# → ⑤ 无图形:仅 --background 时 detached tmux/screen → ⑥ 否则 exit 2 + 一行 DEGRADED 诊断
|
|
54
55
|
#
|
|
55
56
|
# tmux 宿主行为
|
|
56
|
-
# - 已在 tmux 内($TMUX
|
|
57
|
+
# - 已在 tmux 内($TMUX 存在):以派生宿主窗口(调用者 pane 所在 window)分屏拉起,不新建窗口;
|
|
58
|
+
# 显式 `-t @<window_id>` 目标(定位链:NAO_TMUX_HOST_WINDOW > $TMUX_PANE > 名册唯一命中;
|
|
59
|
+
# 否则 warn + 跳过该 pane,不落入当前窗口)
|
|
57
60
|
# - 不在 tmux 内:创建 detached 会话 nao-<角色>,需 tmux attach -t nao-<角色>。
|
|
58
61
|
# - main-row2:第 1 个 pane 全高占左,后续每角色往右开列、每列上下 2 个(默认):
|
|
59
62
|
# 1 | 2 | 4
|
|
@@ -86,6 +89,8 @@ TMUX_MAIN_WIDTH="${NAO_TMUX_MAIN_WIDTH:-$TMUX_MAIN_WIDTH_DEFAULT}"
|
|
|
86
89
|
# 最小非主 pane 列宽守卫:默认值与非法值回退共用同一常量(防漂移)
|
|
87
90
|
TMUX_MIN_PANE_WIDTH_DEFAULT=30
|
|
88
91
|
TMUX_MIN_PANE_WIDTH="${NAO_TMUX_MIN_PANE_WIDTH:-$TMUX_MIN_PANE_WIDTH_DEFAULT}"
|
|
92
|
+
# T517:派生宿主窗口 ID(归一化 @<window_id>;空 = 定位失败 ⇒ 该角色 pane warn+skip,禁无 -t 续建)
|
|
93
|
+
HOST_WINDOW=""
|
|
89
94
|
# check 输出契约:默认单行摘要(省 PM 上下文),-v 展开完整报告;失败始终展开
|
|
90
95
|
VERBOSE=false
|
|
91
96
|
# close 的在跑 turn 判定(pi 默认状态行:Working (esc to interrupt) / Thinking... / Retrying / Compacting)
|
|
@@ -295,7 +300,7 @@ resolve_role() {
|
|
|
295
300
|
|
|
296
301
|
# 宿主阶梯(ADR 实施闸门 · T513b/c)——由「枚举模拟器」改为「环境查询 + 显式覆盖」:
|
|
297
302
|
# ① NAO_TERMINAL 显式(档值 ∈ {tmux,foot,ghostty,ptyxis,screen};命令缺失/非法 ⇒ exit 2)
|
|
298
|
-
# ② $TMUX 存在 ⇒
|
|
303
|
+
# ② $TMUX 存在 ⇒ 派生宿主窗口(调用者 pane 所在 window)split-window(显式 -t @<window_id>;单窗口逐值零回归)
|
|
299
304
|
# ③ 非 tmux + tmux 可用 + 图形 ⇒ new-session -d + xdg-terminal-exec 开窗 attach(默认 socket)
|
|
300
305
|
# ④ 无 tmux + 图形 ⇒ xdg-terminal-exec --app-id=org.nao.<角色> --dir=<repo> 直开窗
|
|
301
306
|
# ⑤ 无图形 + 显式 --background ⇒ detached tmux/screen
|
|
@@ -851,37 +856,38 @@ apply_main_col() {
|
|
|
851
856
|
else
|
|
852
857
|
warn "${from} → main-col 右列 ${right_w} < 最小 ${min_w}(${n} pane @ ${win_w} 列)→ 再回退 grid"
|
|
853
858
|
fi
|
|
854
|
-
tmux select-layout tiled >/dev/null 2>&1 || true
|
|
859
|
+
tmux select-layout -t "$HOST_WINDOW" tiled >/dev/null 2>&1 || true
|
|
855
860
|
return 0
|
|
856
861
|
fi
|
|
857
862
|
fi
|
|
858
|
-
tmux set-window-option main-pane-width "${pct}%" >/dev/null 2>&1 || true
|
|
863
|
+
tmux set-window-option -t "$HOST_WINDOW" main-pane-width "${pct}%" >/dev/null 2>&1 || true
|
|
859
864
|
local err
|
|
860
|
-
if ! err=$(tmux select-layout main-vertical 2>&1); then
|
|
861
|
-
warn "main-col(main-vertical)应用失败,回退 grid"
|
|
865
|
+
if ! err=$(tmux select-layout -t "$HOST_WINDOW" main-vertical 2>&1); then
|
|
866
|
+
warn "main-col(main-vertical)应用失败,回退 grid(宿主窗口 $HOST_WINDOW)"
|
|
862
867
|
warn " tmux: ${err:-<no message>}"
|
|
863
|
-
tmux select-layout tiled >/dev/null 2>&1 || true
|
|
868
|
+
tmux select-layout -t "$HOST_WINDOW" tiled >/dev/null 2>&1 || true
|
|
864
869
|
fi
|
|
865
870
|
}
|
|
866
871
|
|
|
867
872
|
apply_tmux_layout() {
|
|
868
873
|
[[ -n "${TMUX:-}" ]] || return 0
|
|
874
|
+
[[ -n "$HOST_WINDOW" ]] || return 0
|
|
869
875
|
if [[ "$TMUX_LAYOUT" == "grid" ]]; then
|
|
870
|
-
tmux select-layout tiled >/dev/null 2>&1 || true
|
|
876
|
+
tmux select-layout -t "$HOST_WINDOW" tiled >/dev/null 2>&1 || true
|
|
871
877
|
return
|
|
872
878
|
fi
|
|
873
879
|
# main-row2
|
|
874
880
|
local win_w win_h
|
|
875
881
|
# D7(T513-S3):display-message 无输出时 `read` 返回 1,set -e 会硬中断整轮 ensure
|
|
876
882
|
# ⇒ 守卫为 true(读不到尺寸即跳过布局,不硬崩)。
|
|
877
|
-
read -r win_w win_h < <(tmux display-message -p '#{window_width} #{window_height}' 2>/dev/null) || true
|
|
883
|
+
read -r win_w win_h < <(tmux display-message -p -t "$HOST_WINDOW" '#{window_width} #{window_height}' 2>/dev/null) || true
|
|
878
884
|
[[ -n "$win_w" && -n "$win_h" ]] || return 0
|
|
879
885
|
|
|
880
886
|
local -a pane_ids=()
|
|
881
887
|
local line
|
|
882
888
|
while IFS= read -r line; do
|
|
883
889
|
[[ -n "$line" ]] && pane_ids+=("$line")
|
|
884
|
-
done < <(tmux list-panes -F '#{pane_id}' 2>/dev/null | sed 's/^%//')
|
|
890
|
+
done < <(tmux list-panes -t "$HOST_WINDOW" -F '#{pane_id}' 2>/dev/null | sed 's/^%//')
|
|
885
891
|
local n=${#pane_ids[@]}
|
|
886
892
|
(( n >= 1 )) || return 0
|
|
887
893
|
|
|
@@ -913,14 +919,85 @@ apply_tmux_layout() {
|
|
|
913
919
|
|
|
914
920
|
local ck; ck="$(_layout_checksum "$full")"
|
|
915
921
|
local err
|
|
916
|
-
if ! err=$(tmux select-layout "${ck},${full}" 2>&1); then
|
|
917
|
-
warn "main-row2 布局应用失败,回退 tiled"
|
|
922
|
+
if ! err=$(tmux select-layout -t "$HOST_WINDOW" "${ck},${full}" 2>&1); then
|
|
923
|
+
warn "main-row2 布局应用失败,回退 tiled(宿主窗口 $HOST_WINDOW)"
|
|
918
924
|
warn " tmux: ${err:-<no message>}"
|
|
919
925
|
warn " layout: $full"
|
|
920
|
-
tmux select-layout tiled >/dev/null 2>&1 || true
|
|
926
|
+
tmux select-layout -t "$HOST_WINDOW" tiled >/dev/null 2>&1 || true
|
|
921
927
|
fi
|
|
922
928
|
}
|
|
923
929
|
|
|
930
|
+
# ---------------------------------------------------------------------------
|
|
931
|
+
# T517 派生宿主窗口解析(ADR 2026-10-13-derived-pane-window-addressing · PRD T517 §五)
|
|
932
|
+
# 入口一次性解析 → 全局 HOST_WINDOW=@<window_id>;空 = 定位失败 ⇒ 解析处 warn 一次(每 run 一次),
|
|
933
|
+
# spawn_tmux 对空值跳过该 pane(D-A:warn + skip,禁无 -t 续建——那是拆用户视图)。定位链:
|
|
934
|
+
# L1 NAO_TMUX_HOST_WINDOW 显式覆盖:display-message 探测归一化;允许跨 session(@id 全局唯一),
|
|
935
|
+
# 非 @id 形式 warn 建议用 @id;解析失败(关窗/垃圾值)⇒ warn + 沿链降级(不 die)
|
|
936
|
+
# L2 $TMUX_PANE → window_id 调用者 pane 所在 window(= 派生宿主;不依赖 client 视图;核心路径)
|
|
937
|
+
# L3 名册唯一命中 仅在本 $TMUX 所属 session 内取候选窗(pane→window 全表一次调用
|
|
938
|
+
# + 名册 cwd=本仓 + 活 pane + 窗口去重唯一);歧义/无命中 ⇒ warn 标来源,不猜
|
|
939
|
+
# L4 skip warn + 不创建(其余角色继续;rc 不劣化)
|
|
940
|
+
# 调用预算:L1/L2 各 ≤1 次 tmux 调用;L3 ≤2 次(session 探测 + list-panes 全表)。
|
|
941
|
+
resolve_host_window() {
|
|
942
|
+
local tgt="" sess_id="" pid wid sid abs rp rw
|
|
943
|
+
# L1 显式覆盖
|
|
944
|
+
if [[ -n "${NAO_TMUX_HOST_WINDOW:-}" ]]; then
|
|
945
|
+
tgt="$(tmux display-message -p -t "$NAO_TMUX_HOST_WINDOW" '#{window_id}' 2>/dev/null || true)"
|
|
946
|
+
if [[ -n "$tgt" ]]; then
|
|
947
|
+
[[ "$NAO_TMUX_HOST_WINDOW" == "@"* ]] || \
|
|
948
|
+
warn "NAO_TMUX_HOST_WINDOW=$NAO_TMUX_HOST_WINDOW 非 @id 形式(裸窗口名跨 session 可能歧义)→ 已归一化 $tgt,建议改用 @id"
|
|
949
|
+
log "宿主窗口 = NAO_TMUX_HOST_WINDOW(显式覆盖)→ $tgt"
|
|
950
|
+
HOST_WINDOW="$tgt"; return 0
|
|
951
|
+
fi
|
|
952
|
+
warn "NAO_TMUX_HOST_WINDOW=$NAO_TMUX_HOST_WINDOW 解析失败(窗口已关或非法)→ 降级 TMUX_PANE/名册"
|
|
953
|
+
fi
|
|
954
|
+
# L2 调用者 pane → window_id(同一次调用顺带取 session_id,供 L3 限定本 session)
|
|
955
|
+
if [[ -n "${TMUX_PANE:-}" ]]; then
|
|
956
|
+
read -r tgt sess_id < <(tmux display-message -p -t "$TMUX_PANE" '#{window_id} #{session_id}' 2>/dev/null || true) || true
|
|
957
|
+
if [[ -n "$tgt" ]]; then
|
|
958
|
+
HOST_WINDOW="$tgt"; return 0
|
|
959
|
+
fi
|
|
960
|
+
warn "TMUX_PANE=$TMUX_PANE 解析不到 window_id(pane 已关?)→ 降级名册推断"
|
|
961
|
+
else
|
|
962
|
+
warn "TMUX 已设但 TMUX_PANE 空(AC5b 场景)→ 跳 L2,降级名册推断"
|
|
963
|
+
fi
|
|
964
|
+
# L3 名册唯一命中(D-B:仅本 $TMUX 所属 session 内取候选窗,不跨 session 推断)
|
|
965
|
+
[[ -n "$sess_id" ]] || sess_id="$(tmux display-message -p '#{session_id}' 2>/dev/null || true)"
|
|
966
|
+
if [[ -z "$sess_id" ]]; then
|
|
967
|
+
warn "无法确定本 \$TMUX 所属 session(无 client/无 pane 句柄)→ 名册推断无从限定,L4 skip"
|
|
968
|
+
return 0
|
|
969
|
+
fi
|
|
970
|
+
local -A win_of=()
|
|
971
|
+
# pane→window 全表(1 次调用;pane 在表中即活,无需单独探测)
|
|
972
|
+
while IFS=$'\t' read -r pid wid sid; do
|
|
973
|
+
[[ "$sid" == "$sess_id" ]] && win_of["$pid"]="$wid"
|
|
974
|
+
done < <(tmux list-panes -a -F "#{pane_id}"$'\t'"#{window_id}"$'\t'"#{session_id}" 2>/dev/null || true)
|
|
975
|
+
abs="$(repo_abspath "$PWD")"; [[ -n "$abs" ]] || return 0
|
|
976
|
+
local -A seen=()
|
|
977
|
+
local -a wins=()
|
|
978
|
+
# 名册 tmuxPane(cwd=本仓)→ 本 session 窗口去重(与 fallback_pane_for 同构的 cwd 过滤)
|
|
979
|
+
while IFS= read -r rp; do
|
|
980
|
+
[[ -n "$rp" ]] || continue
|
|
981
|
+
rw="${win_of[$rp]:-}"
|
|
982
|
+
[[ -n "$rw" ]] && { [[ -z "${seen[$rw]:-}" ]] && { seen["$rw"]=1; wins+=("$rw"); }; }
|
|
983
|
+
done < <(intercom_list_json 2>/dev/null | sed 's/},/}\n/g' | awk -v a="$abs" '
|
|
984
|
+
/"cwd":[[:space:]]*"/ { s=$0; sub(/.*"cwd":[[:space:]]*"/,"",s); sub(/".*/,"",s); cc=s }
|
|
985
|
+
/"tmuxPane":[[:space:]]*"/ { s=$0; sub(/.*"tmuxPane":[[:space:]]*"/,"",s); sub(/".*/,"",s); cp=s
|
|
986
|
+
if (cp != "" && cc == a) print cp }
|
|
987
|
+
' || true) # sed 按对象边界拆行:紧凑/pretty 两种 JSON 布局同语义(逐条目取 cwd+tmuxPane)
|
|
988
|
+
if (( ${#wins[@]} == 1 )); then
|
|
989
|
+
HOST_WINDOW="${wins[0]}"
|
|
990
|
+
warn "名册唯一命中宿主窗口 $HOST_WINDOW(来源:名册 tmuxPane + cwd=本仓 + 仅本 session $sess_id)"
|
|
991
|
+
return 0
|
|
992
|
+
fi
|
|
993
|
+
if (( ${#wins[@]} > 1 )); then
|
|
994
|
+
warn "名册推断歧义:本 session 内候选窗 ${wins[*]}(>1)→ 不猜,L4 skip(可设 NAO_TMUX_HOST_WINDOW 显式指定)"
|
|
995
|
+
else
|
|
996
|
+
warn "名册推断无命中:本 session 内无名册 pane 或 cwd≠本仓 → L4 skip(可设 NAO_TMUX_HOST_WINDOW 显式指定)"
|
|
997
|
+
fi
|
|
998
|
+
return 0 # HOST_WINDOW 保持空 ⇒ spawn_tmux 跳过(D-A:warn + skip,禁无 -t 续建)
|
|
999
|
+
}
|
|
1000
|
+
|
|
924
1001
|
spawn_tmux() {
|
|
925
1002
|
local name="$1" inner="$2"
|
|
926
1003
|
case "$TMUX_LAYOUT" in
|
|
@@ -929,11 +1006,14 @@ spawn_tmux() {
|
|
|
929
1006
|
esac
|
|
930
1007
|
local wrapped="bash -lc $(printf %q "$inner")"
|
|
931
1008
|
if [[ -n "${TMUX:-}" ]]; then
|
|
932
|
-
#
|
|
1009
|
+
# T517:目标显式化——HOST_WINDOW 解析失败时此处已由解析处 warn(每 run 一次),
|
|
1010
|
+
# 跳过该 pane;禁止无 -t 续建(tmux 会落「当前窗口」= 用户视图,即缺陷根因)。
|
|
1011
|
+
[[ -n "$HOST_WINDOW" ]] || return 0
|
|
1012
|
+
# 窄窗口/宿主上限会让 split-window 失败(no space for new pane,含宿主窗已关竞态);
|
|
933
1013
|
# 捕获后 warn 并继续,不因单个 pane 失败中断整轮 ensure。
|
|
934
1014
|
local serr
|
|
935
|
-
if ! serr=$(tmux split-window -h "$wrapped" 2>&1); then
|
|
936
|
-
warn "pane
|
|
1015
|
+
if ! serr=$(tmux split-window -h -t "$HOST_WINDOW" "$wrapped" 2>&1); then
|
|
1016
|
+
warn "pane 创建失败(宿主窗口 $HOST_WINDOW 过窄/已关或已达上限):${serr:-<no message>}"
|
|
937
1017
|
warn " 已跳过该 pane,其余角色继续拉起;可放大窗口后重跑 ensure"
|
|
938
1018
|
return 0
|
|
939
1019
|
fi
|
|
@@ -1688,6 +1768,9 @@ cmd_ensure() {
|
|
|
1688
1768
|
local spec role repo key seen k
|
|
1689
1769
|
local -a cg_done=()
|
|
1690
1770
|
[[ $# -eq 0 ]] && die "ensure 需要至少一个角色,如: nao-fleet.sh ensure arch rd-fe rd-infra"
|
|
1771
|
+
# T517:入口一次性解析派生宿主窗口(仅 $TMUX 分支);定位失败 ⇒ 解析处 warn 一次,各角色 pane 跳过
|
|
1772
|
+
HOST_WINDOW=""
|
|
1773
|
+
if [[ -n "${TMUX:-}" ]] && command -v tmux >/dev/null 2>&1; then resolve_host_window; fi
|
|
1691
1774
|
for spec in "$@"; do
|
|
1692
1775
|
if [[ "$spec" == *"@"* ]]; then
|
|
1693
1776
|
role="${spec%%@*}"; repo="${spec#*@}"
|
|
@@ -6,6 +6,10 @@ description: 按需技能——苏格拉底式澄清(grill-me)
|
|
|
6
6
|
|
|
7
7
|
需求模糊时**必须**触发,逐层追问直至澄清,澄清前不得写 PRD。
|
|
8
8
|
|
|
9
|
+
## 需求成熟度判定:命中则不触发
|
|
10
|
+
|
|
11
|
+
先按 @.agents/skills/pm-to-spec.md §一 判成熟度(① 已有 grill 结论;② 已有原型/设计稿;③ 已有 ADR 或架构评审回执;④ 用户明示「讨论已充分」)。**任一命中 → 不触发本清单**,改走该技能的对话综合流程;一条都不命中才逐层追问。判定与综合入口口径以 `pm-to-spec.md` 为准,本文件不另设标准。
|
|
12
|
+
|
|
9
13
|
## 五层追问
|
|
10
14
|
|
|
11
15
|
1. **目标用户**:谁?画像?规模?
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 按需技能——成熟需求的规格生产方式(验证接缝 + 对话综合,产出仍为 PRD)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# pm-to-spec(成熟需求直出 PRD)
|
|
6
|
+
|
|
7
|
+
> 入口分支:需求**已成熟**(命中 §一 判定)时跳过 grill,走「接缝 → 综合 → 缺口检查 → 出稿」;不成熟仍走 @.agents/skills/pm-grill.md 五层追问。
|
|
8
|
+
> 产出物一律叫 **PRD**(禁 `spec` 作并列术语);格式 = 头部 + TL;DR + 9 模块(见 @.agents/checklists/deliverable-docs.md §三)。
|
|
9
|
+
|
|
10
|
+
## 一、成熟度判定(4 条,任一命中即可走综合)
|
|
11
|
+
|
|
12
|
+
1. **已有 grill 结论**:本需求已跑完五层追问并澄清。
|
|
13
|
+
2. **已有原型 / 设计稿**:用户或 RD 已给出界面 / 交互稿。
|
|
14
|
+
3. **已有 ADR 或架构评审回执**:`docs/adr/` 或 arch 回执已定关键取舍。
|
|
15
|
+
4. **用户明示「讨论已充分」**:用户显式表示可直接成稿。
|
|
16
|
+
|
|
17
|
+
- **一条都不命中 → 仍走 grill**,不得跳过;命中后也只在缺口处定点补产,不重复盘问。
|
|
18
|
+
- 判定结论写入 PRD 头部指针(来源:grill 结论 / 原型 / ADR),供回执核对。
|
|
19
|
+
|
|
20
|
+
## 二、接缝步骤(写 PRD 前先定可测接入点)
|
|
21
|
+
|
|
22
|
+
- **PM 列候选 → QA 确认**:PM 只列 1–3 个候选接入点;最终以 QA 确认为准(QA 可改为更高 / 更少)。
|
|
23
|
+
- **理想 1 个接缝**:接缝越少越好。
|
|
24
|
+
- **优先复用已有接缝**:已有测试 / 调用入口优先于新建。
|
|
25
|
+
- **能高不高低**:能在高层稳定接口测,就不下沉到实现细节。
|
|
26
|
+
- 结论写入 PRD「七、AC」首行:`验证接缝:<接入点>(QA 已确认 YYYY-MM-DD)`;不适用写「不适用:<一行理由>」。
|
|
27
|
+
- **一致性闸门(AC8)**:PRD 接缝与 QA 用例范围不一致 → PM 验收**打回**,对齐后重新验收(不得带不一致合入)。
|
|
28
|
+
|
|
29
|
+
## 三、对话综合流程
|
|
30
|
+
|
|
31
|
+
1. **判成熟度**(§一):不命中 → 回 grill。
|
|
32
|
+
2. **列接缝候选 → 请 QA 确认**(§二)。
|
|
33
|
+
3. **综合上下文成稿**:按 §四 映射把已有讨论填进 9 模块;只综合已知,不重新盘问。
|
|
34
|
+
4. **缺口检查**(§五):缺口未清空不得出稿。
|
|
35
|
+
5. **自核路径无关判据**(§六)→ 落 `docs/prds/` + 更新索引。
|
|
36
|
+
|
|
37
|
+
## 四、上游 7 节 → 9 模块映射(列表,非表格)
|
|
38
|
+
|
|
39
|
+
上游 `to-spec` 模板 7 节按下述归位;**实现决策 / 测试决策不落 PRD 正文**,只留指针:
|
|
40
|
+
|
|
41
|
+
1. **问题证据** ← 上游「问题陈述」。
|
|
42
|
+
2. **目标指标** ← 上游无对应:取 5 Whys + 北极星拆解;无依据即记缺口(§五)。
|
|
43
|
+
3. **范围/非范围** ← 上游「用户故事」+「范围外」(非范围必带理由)。
|
|
44
|
+
4. **用户场景** ← 上游「解决方案」(能力 / 关键路径视角)。
|
|
45
|
+
5. **业务规则** ← 上游「解决方案」+「补充说明」中的状态 / 权限 / 边界 / 不变量。
|
|
46
|
+
6. **NFRs** ← 上游「补充说明」的业务视角基线;无则写「不适用:<理由>」。
|
|
47
|
+
7. **AC** ← 上游「用户故事」逐条转 Given/When/Then;首行为验证接缝(§二)。
|
|
48
|
+
8. **上线闭环** ← 上游「补充说明」(灰度 / 监控 / 回滚);缺则按项目默认并记缺口。
|
|
49
|
+
9. **变更治理** ← 上游「补充说明」(正式流程 + 版本记录)。
|
|
50
|
+
- **上游「实现决策」** → ⛔ 不写正文,指针 `docs/adr/`。
|
|
51
|
+
- **上游「测试决策」** → ⛔ 不写正文,指针 QA 用例范围(`docs/reports/`)。
|
|
52
|
+
|
|
53
|
+
## 五、缺口检查(缺口未清空不得出稿)
|
|
54
|
+
|
|
55
|
+
逐条核对,缺一即列缺口并定点补产(补产靠 grill / 原型 / ADR / 用户拍板):
|
|
56
|
+
|
|
57
|
+
- 目标指标(北极星拆解 + 预期值)
|
|
58
|
+
- NFRs(性能 / 安全 / 兼容性业务基线)
|
|
59
|
+
- 上线闭环(灰度 / 监控 / 回滚)
|
|
60
|
+
- 变更治理(正式流程 + 版本记录)
|
|
61
|
+
|
|
62
|
+
处理顺序:先输出**缺口清单**(编号 + 缺口 + 影响)→ 定点补齐 → 复检清空 → 才可出稿。**不得**带着缺口直接成稿。
|
|
63
|
+
|
|
64
|
+
## 六、路径无关判据清单(AC1,第三方逐条可核)
|
|
65
|
+
|
|
66
|
+
- 头部齐(状态 / 更新 / Owner / 指针)
|
|
67
|
+
- TL;DR ≤5 行(做什么 · 给谁 · 成功标准 · 不做什么)
|
|
68
|
+
- 9 模块无空(不适用项写「不适用:<理由>」)
|
|
69
|
+
- AC 逐条 Given/When/Then + 五覆盖(主路径 / 异常 / 边界 / 负向闭环 / 设计一致性)
|
|
70
|
+
- 非范围含理由
|
|
71
|
+
- 战略筛子 + RICE 结论在
|
|
72
|
+
- 正文无表格
|
|
73
|
+
- ≤150 行
|
|
74
|
+
- 落 `docs/prds/` 且索引更新
|
|
75
|
+
- Issue 只有摘要 + 指针(正文在 `docs/prds/`)
|
|
76
|
+
|
|
77
|
+
> 判据与 @.agents/checklists/deliverable-docs.md §三、@.agents/checklists/pm.md 一致;模板见 @.agents/templates/prd.md.example。
|
|
78
|
+
|
|
79
|
+
## 反模式
|
|
80
|
+
|
|
81
|
+
- 不判成熟度就直接盘问(重复澄清轮次)。
|
|
82
|
+
- 接缝由 PM 单方拍定、未经 QA 确认。
|
|
83
|
+
- 带缺口出稿;写「实现决策 / 测试决策」正文;用 `spec` 作并列术语或替代 PRD 直发 tracker。
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
PRD 骨架 —— 复制为 docs/prds/YYYY-MM-DD-<slug>.md 后逐段填空。
|
|
3
|
+
权威写法:@.agents/checklists/deliverable-docs.md §三;生产方式:@.agents/skills/pm-to-spec.md
|
|
4
|
+
⛔ 自查:正文无表格;每模块 ≤3 句;不适用项写「不适用:<理由>」;AC 一条一行;≤150 行。
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
# PRD:<标题>
|
|
8
|
+
|
|
9
|
+
- 状态:草稿 / 待确认 / 已定稿 · Owner:PM
|
|
10
|
+
- 更新:YYYY-MM-DD
|
|
11
|
+
- 指针:上游 <Issue / 讨论> · 关联 ADR / 调研 `docs/...md`
|
|
12
|
+
- 优先级:<战略筛子结论 / RICE 高|中|低>
|
|
13
|
+
|
|
14
|
+
## TL;DR(≤5 行)
|
|
15
|
+
|
|
16
|
+
- **做什么**:<一句话>
|
|
17
|
+
- **给谁**:<用户 / 角色>
|
|
18
|
+
- **成功标准**:<可核指标>
|
|
19
|
+
- **不做什么**:<边界>
|
|
20
|
+
|
|
21
|
+
## 一、问题证据
|
|
22
|
+
|
|
23
|
+
<数据 / 反馈 + 5 Whys 摘要(展开落 `docs/research/`)>
|
|
24
|
+
|
|
25
|
+
## 二、目标指标
|
|
26
|
+
|
|
27
|
+
<北极星拆解 + 预期提升值>
|
|
28
|
+
|
|
29
|
+
## 三、范围 / 非范围
|
|
30
|
+
|
|
31
|
+
- **范围**:<条目>
|
|
32
|
+
- **非范围**:<条目 + 一行理由>
|
|
33
|
+
|
|
34
|
+
## 四、用户场景
|
|
35
|
+
|
|
36
|
+
<画像 + 场景卡 + 关键路径 + 页面状态清单(加载 / 空 / 错误 / 成功)>
|
|
37
|
+
|
|
38
|
+
## 五、业务规则
|
|
39
|
+
|
|
40
|
+
<状态流转 / 权限 / 边界 / 不变量>
|
|
41
|
+
|
|
42
|
+
## 六、NFRs
|
|
43
|
+
|
|
44
|
+
<性能 / 安全 / 兼容性业务基线;不适用:<理由>>
|
|
45
|
+
|
|
46
|
+
## 七、AC
|
|
47
|
+
|
|
48
|
+
- 验证接缝:<接入点>(QA 已确认 YYYY-MM-DD)
|
|
49
|
+
- AC1(主路径):Given <前置>,When <操作>,Then <预期>
|
|
50
|
+
- AC2(异常):Given <前置>,When <操作>,Then <预期>
|
|
51
|
+
- AC3(边界):Given <前置>,When <操作>,Then <预期>
|
|
52
|
+
- AC4(负向闭环):Given <前置>,When <操作>,Then <预期>
|
|
53
|
+
- AC5(设计一致性):Given <前置>,When <操作>,Then <预期>
|
|
54
|
+
|
|
55
|
+
## 八、上线闭环
|
|
56
|
+
|
|
57
|
+
<灰度 / 监控 / 回滚>
|
|
58
|
+
|
|
59
|
+
## 九、变更治理
|
|
60
|
+
|
|
61
|
+
<正式流程 + 版本记录(Hotfix 24h 补单)>
|
|
62
|
+
|
|
63
|
+
## 附录:战略筛子 / RICE 结论
|
|
64
|
+
|
|
65
|
+
<结论 + 指针;打分过程不展开>
|
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ nao-skills 是一套 **角色卡 + 协作规矩 + 小工具**。装上以后,
|
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
cd 你的项目
|
|
27
|
-
pi install --local npm:@nathan33/nao-skill@0.
|
|
27
|
+
pi install --local npm:@nathan33/nao-skill@0.17.0 # 声明 pin + 把机制包物化到项目内 .pi/npm
|
|
28
28
|
npx @nathan33/nao-skill init # 写入转发 shim + 生成 AGENTS.md
|
|
29
29
|
```
|
|
30
30
|
|