@nathan33/nao-skill 0.18.4 → 0.18.6
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/comm-templates.md +3 -1
- package/.agents/checklists/pm.md +5 -2
- package/.agents/common/intercom-protocol.md +1 -0
- package/.agents/extensions/nao-role-agents.mjs +207 -0
- package/.agents/prompts/infra-engineer.md +4 -2
- package/.agents/prompts/product-manager.md +5 -3
- package/.agents/scripts/nao-fleet.sh +28 -0
- package/.agents/skills/task-completion.md +49 -0
- package/package.json +4 -1
|
@@ -22,10 +22,11 @@ description: 派发消息与回执模板(按需,派发/回执前读取)
|
|
|
22
22
|
## 回执 done(lite):默认(无阻塞、无风险的常规任务,单行)
|
|
23
23
|
|
|
24
24
|
```text
|
|
25
|
-
[编号] done(lite) | <role> | 清单:未过<项 或 无> | 测试:<命令> exit=<n> <文件数>/<例数>/<红数> | 变更:<f1,f2(>3 个写前 3 + "等 N 个")> | commit=<短 hash 或 —> | 详情:docs/reports/<编号>.md
|
|
25
|
+
[编号] done(lite) | <role> | 清单:未过<项 或 无> | 测试:<命令> exit=<n> <文件数>/<例数>/<红数> | 变更:<f1,f2(>3 个写前 3 + "等 N 个")> | 遗留:<无 | n 项 → 台账|tasks-state|Issue|接受(到期)> | commit=<短 hash 或 —> | 详情:docs/reports/<编号>.md
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
> `commit=`(仅 git 流程任务):work 分支最新提交短 hash,便于 PM 核对归因(commit.md 约定);无 push/纯文档任务写 `commit=—`。
|
|
29
|
+
> `遗留:` 取值枚举 `无 | <n> 项 → <台账|tasks-state|Issue|接受(到期)>`;零遗留写 `无`,禁省略字段(三出口定义见 @.agents/skills/task-completion.md §四)。
|
|
29
30
|
|
|
30
31
|
## 回执 done(full):出现阻塞/风险/需决策,或 PM 指定
|
|
31
32
|
|
|
@@ -36,6 +37,7 @@ description: 派发消息与回执模板(按需,派发/回执前读取)
|
|
|
36
37
|
变更:<文件/模块级>
|
|
37
38
|
测试:<命令 + exit code + 文件数/例数/红数(或错误数)>
|
|
38
39
|
commit:<短 hash 或 —>
|
|
40
|
+
遗留:<无 | n 项 → 台账|tasks-state|Issue|接受(到期)>(每条附出处与 owner;接受类必须带到期日)
|
|
39
41
|
风险/阻塞:<无 或 列出>
|
|
40
42
|
详情:<路径>
|
|
41
43
|
```
|
package/.agents/checklists/pm.md
CHANGED
|
@@ -25,7 +25,7 @@ description: PM 交付核对清单(按需,交付/派发前读取)
|
|
|
25
25
|
|
|
26
26
|
> 写作要求(首屏 TL;DR、每格 ≤3 句、不适用项写法、长度上限 150 行):@.agents/checklists/deliverable-docs.md §三(写 PRD 前读)。
|
|
27
27
|
|
|
28
|
-
## 硬性红线(完整
|
|
28
|
+
## 硬性红线(完整 33 项)
|
|
29
29
|
|
|
30
30
|
- [ ] 无目标指标/假设就进开发?
|
|
31
31
|
- [ ] 边界不清晰(未写不做什么)?
|
|
@@ -59,9 +59,10 @@ description: PM 交付核对清单(按需,交付/派发前读取)
|
|
|
59
59
|
- [ ] 未过验收 / 门禁未绿就打 tag 或 release,或 tag 指向非 main 合并提交?(见 `github-flow.md`)
|
|
60
60
|
- [ ] `git push --force` 到 main/共享分支(未经用户明确授权并指明分支)?
|
|
61
61
|
- [ ] release notes 不可读(纯编号/类名/路径),或未落盘 `docs/releases/`?(规范:@.agents/common/release-notes.md —— 面向用户「本次更新」置顶、内部信息下沉、正文不用表格)
|
|
62
|
+
- [ ] 输出里有 `warn`/`error`/`pending approval`/`N vulnerabilities` 却判完成,或遗留项未走三出口(「先放着」不算出口)?(见 @.agents/skills/task-completion.md)
|
|
62
63
|
- [ ] 降级(无 `gh` / 无远端)未在 `tasks-state` 与回执中标注?
|
|
63
64
|
|
|
64
|
-
## 交付检查清单(完整
|
|
65
|
+
## 交付检查清单(完整 40 项)
|
|
65
66
|
|
|
66
67
|
- [ ] 目标/边界/验收三件事齐备
|
|
67
68
|
- [ ] 证据 + 5 Whys 已产出
|
|
@@ -100,6 +101,8 @@ description: PM 交付核对清单(按需,交付/派发前读取)
|
|
|
100
101
|
- [ ] 合并由 RD 执行(`--squash`);main 上本需求恰好 1 条提交且无 `wip()`;需求分支已删除
|
|
101
102
|
- [ ] 发布(若有):版本号符合 SemVer/项目约定;tag 指向 main 合并提交;release notes 用户可读且落盘 `docs/releases/`(核 @.agents/common/release-notes.md)
|
|
102
103
|
- [ ] `gh` 可用则已用 `gh`,降级已注明;发布后 `tasks-state` 版本/Tag 行已更新
|
|
104
|
+
- [ ] 任务 DoD 四类已随**开工确认卡**逐任务实例化(产物路径 / 可执行验证判据 / 遗留项 / 交接),验收按同一份核
|
|
105
|
+
- [ ] 回执含 `遗留:` 字段且遗留项已**三出口**收口(关闭 / 接受含到期日 / 转办;零遗留显式「无」,可执行项已进 `tasks-state` 待派发队列)
|
|
103
106
|
- [ ] 通过上面全部红线
|
|
104
107
|
|
|
105
108
|
## 会话回收 / 收窗核对(验收通过后 / 手工关窗前)
|
|
@@ -40,6 +40,7 @@ description: pi-intercom 多会话协作协议(常驻引用)
|
|
|
40
40
|
## 会话内子代理(授权与回执归属)
|
|
41
41
|
|
|
42
42
|
- **授权**:角色可在自身 turn 内用 pi-subagents 起**会话内子代理**(scout / researcher / oracle / reviewer / evidence-auditor 等)。默认**只读**;需要写入时须 `worktree: true` 隔离并指定**单一集成者**(父角色),同一 cwd 禁多写。子代理既**不属**舰队会话身份模型 —— 边界与 `status`/`close` 处置**见上文「子代理会话不属舰队会话身份模型」**,此处不重复。
|
|
43
|
+
- **角色口径同源(指针)**:常驻舰队会话 = `nao-fleet.sh` 以 `--append-system-prompt` 注入角色卡;会话内子代理 = 包内扩展(`.agents/extensions/nao-role-agents.mjs`)在 `session_start` 运行时注册 `nao-<role-id>`。两路**同卡同锚**(同一批 `.agents/prompts/*.md` + 同一环境锚点行);细节见该扩展与 `tests/t4/cases/17-role-agents.sh`,此处不复制。
|
|
43
44
|
- **回执归属(硬性)**:子代理的 run 结果**只是证据,不等于回执**;`[编号] done(lite|full)` **只能由父角色**在自行核对后经 intercom `send` 发出(PM 只认父角色 done)。父角色不得把子代理输出直接转贴为回执。
|
|
44
45
|
- **子代理禁令**:子代理**不得以舰队角色名义回执**、**不得发送 `done` 形态消息**、**不得直发 PM**;需决策/阻塞/授权走 `contact_supervisor`(进程内 native 通道,无需 pi-intercom;父侧对应用 `subagent_supervisor`)。
|
|
45
46
|
- **证据格式**:子代理产物须含**命令 + exit code + 例数/文件数(或断言数)+ 路径**,供父角色写入回执「测试」栏;无证据的「完成」不算证据。注入文本见 `@.agents/templates/pi-subagents/intercom-bridge.md`(安装说明见同目录 `README.md`)。
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// .agents/extensions/nao-role-agents.mjs
|
|
2
|
+
// T527 —— 角色→pi-subagents agent 的单一事实(运行时注册扩展 · E-lite)
|
|
3
|
+
//
|
|
4
|
+
// 契约点(外部公开面,升版漂移由 tests/t4/cases/17 探针 fail-loud):
|
|
5
|
+
// 事件名 pi-subagents:runtime-agent-register:v1(docs/extension-api.md §Runtime agent registration)
|
|
6
|
+
//
|
|
7
|
+
// BR1 零副本 :运行时读 .agents/prompts/*.md + .agents/roles.yaml;无生成物、无静态副本。
|
|
8
|
+
// BR2 同卡同锚 :systemPrompt = 卡正文(去 frontmatter)逐字节 + 环境锚点行(与
|
|
9
|
+
// `.agents/scripts/nao-fleet.sh` build_system_prompt 的 printf 段逐字一致;
|
|
10
|
+
// 唯一双写点,由 cases/17 cross-assert 兜住)。
|
|
11
|
+
// BR3 命名纪律 :nao-<role-id>(6 个)· 不设 alias · 不占 subagent- 前缀。
|
|
12
|
+
// BR4 上下文口径:systemPromptMode=replace + inheritProjectContext=true(否则卡内 AGENTS.md 契约静默丢失)。
|
|
13
|
+
// BR5 韧性 :注册/装配失败仅 warn、绝不 throw;session_start 先 dispose 再注册(幂等)。
|
|
14
|
+
// BR6 逃生阀 :NAO_ROLE_AGENTS=off ⇒ 不注册。
|
|
15
|
+
// BR9 分发面 :扩展在**每个 trusted 会话**加载(非仅舰队会话),前提同 pi.skills。
|
|
16
|
+
|
|
17
|
+
import { readFileSync } from "node:fs";
|
|
18
|
+
import { dirname, join, resolve } from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
|
|
21
|
+
export const RUNTIME_AGENT_REGISTER_EVENT = "pi-subagents:runtime-agent-register:v1";
|
|
22
|
+
export const RUNTIME_AGENT_REGISTER_VERSION = 1;
|
|
23
|
+
export const ENV_ANCHOR_HEADING = "## 环境锚点";
|
|
24
|
+
export const ROLE_AGENT_PREFIX = "nao-";
|
|
25
|
+
|
|
26
|
+
// 包根 = <pkg>/.agents/extensions/<this> 向上两级
|
|
27
|
+
const EXT_DIR = dirname(fileURLToPath(import.meta.url));
|
|
28
|
+
const PKG_ROOT = resolve(EXT_DIR, "..", "..");
|
|
29
|
+
|
|
30
|
+
function warn(msg) {
|
|
31
|
+
try {
|
|
32
|
+
console.warn(`[nao-role-agents] ${msg}`);
|
|
33
|
+
} catch {
|
|
34
|
+
/* 日志失败不得影响会话 */
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** root 是否是 nao 机制包根(有 .agents/roles.yaml 才算,防把 shim-only 项目当包根) */
|
|
39
|
+
export function hasRoleMechanism(root) {
|
|
40
|
+
try {
|
|
41
|
+
return readFileSync(join(root, ".agents", "roles.yaml"), "utf8").length > 0;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** 锚点用的 NAO_SKILLS:优先 env;env 指向的不是机制包根则回退扩展自身包根(下游 shim-only 场景) */
|
|
48
|
+
export function resolveSkillsRoot(env = process.env) {
|
|
49
|
+
const fromEnv = env && env.NAO_SKILLS;
|
|
50
|
+
if (fromEnv && hasRoleMechanism(fromEnv)) return resolve(fromEnv);
|
|
51
|
+
return PKG_ROOT;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** 环境锚点行 —— 与 nao-fleet.sh:1068 的 printf 段逐字一致(cases/17 AC3 cross-assert) */
|
|
55
|
+
export function buildAnchorLine(skillsRoot) {
|
|
56
|
+
return `- NAO_SKILLS=${skillsRoot}(nao 机制**包根**;@.agents/... 引用一律以 \`$NAO_SKILLS/.agents/\` 为根解析。注意:项目内 \`.agents/\` 只有 shim,不存机制副本)`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 拆分卡片:frontmatter 文本 + 正文(正文 = 首块 frontmatter 之后,逐字节保留原样) */
|
|
60
|
+
export function splitCard(raw) {
|
|
61
|
+
if (!raw.startsWith("---\n")) return { frontmatter: "", body: raw };
|
|
62
|
+
const end = raw.indexOf("\n---\n", 3);
|
|
63
|
+
if (end < 0) return { frontmatter: "", body: raw };
|
|
64
|
+
return { frontmatter: raw.slice(4, end + 1), body: raw.slice(end + 5) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 卡正文(去 frontmatter + 首尾空白)—— pi-subagents registry 要求
|
|
69
|
+
* `systemPrompt.trim() === systemPrompt`(禁首尾空白,实测 error: "must be a non-empty string
|
|
70
|
+
* without leading or trailing whitespace"),故只归一化首尾空白,内部逐字节保留。
|
|
71
|
+
*/
|
|
72
|
+
export function cardBody(raw) {
|
|
73
|
+
const { body } = splitCard(raw);
|
|
74
|
+
return body.replace(/^\n+/, "").replace(/\s+$/, "");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** 取 frontmatter 单行字段(首个命中) */
|
|
78
|
+
export function frontmatterField(frontmatter, key) {
|
|
79
|
+
for (const line of frontmatter.split("\n")) {
|
|
80
|
+
const m = /^([A-Za-z_][A-Za-z0-9_]*):[ \t]*(.*)$/.exec(line);
|
|
81
|
+
if (m && m[1] === key) return m[2];
|
|
82
|
+
}
|
|
83
|
+
return "";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** 严格子集解析 roles.yaml(角色 id 2 空格 / card 4 空格),保持声明顺序 */
|
|
87
|
+
export function parseRolesYaml(text) {
|
|
88
|
+
const roles = [];
|
|
89
|
+
let cur = null;
|
|
90
|
+
for (const line of text.split("\n")) {
|
|
91
|
+
if (!line.trim() || line.trimStart().startsWith("#")) continue;
|
|
92
|
+
let m = /^ ([a-z0-9][a-z0-9-]*):[ \t]*$/.exec(line);
|
|
93
|
+
if (m) {
|
|
94
|
+
cur = { role: m[1], card: "" };
|
|
95
|
+
roles.push(cur);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
m = /^ card:[ \t]*(\S+)[ \t]*$/.exec(line);
|
|
99
|
+
if (m && cur) cur.card = m[1];
|
|
100
|
+
}
|
|
101
|
+
return roles.filter((r) => r.role && r.card);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 纯装配:读机制文件 → 6 条 agent 定义(不触碰 pi / 事件总线,便于探针逐字节比对)。
|
|
106
|
+
* @returns {{name:string,role:string,card:string,description:string,definition:object}[]}
|
|
107
|
+
*/
|
|
108
|
+
export function buildRoleAgentDefinitions({ root, skillsRoot } = {}) {
|
|
109
|
+
const base = root || PKG_ROOT;
|
|
110
|
+
const anchorRoot = skillsRoot || base;
|
|
111
|
+
const roles = parseRolesYaml(readFileSync(join(base, ".agents", "roles.yaml"), "utf8"));
|
|
112
|
+
const anchorLine = buildAnchorLine(anchorRoot);
|
|
113
|
+
return roles.map(({ role, card }) => {
|
|
114
|
+
const raw = readFileSync(join(base, ".agents", "prompts", card), "utf8");
|
|
115
|
+
const { frontmatter } = splitCard(raw);
|
|
116
|
+
const description = frontmatterField(frontmatter, "description");
|
|
117
|
+
return {
|
|
118
|
+
name: `${ROLE_AGENT_PREFIX}${role}`,
|
|
119
|
+
role,
|
|
120
|
+
card,
|
|
121
|
+
description,
|
|
122
|
+
definition: {
|
|
123
|
+
description,
|
|
124
|
+
// BR2 同卡同锚:cardBody 逐字节 + 与 nao-fleet.sh 逐字一致的锚点段(`\n## 环境锚点\n<行>`)
|
|
125
|
+
systemPrompt: `${cardBody(raw)}\n${ENV_ANCHOR_HEADING}\n${anchorLine}`,
|
|
126
|
+
systemPromptMode: "replace",
|
|
127
|
+
inheritProjectContext: true,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** 经事件总线注册(逐条 try/catch;无 owner 即停)。返回 {registrations, errors},绝不 throw。 */
|
|
134
|
+
export function registerRoleAgents(pi, definitions) {
|
|
135
|
+
const registrations = [];
|
|
136
|
+
const errors = [];
|
|
137
|
+
for (const def of definitions) {
|
|
138
|
+
const request = {
|
|
139
|
+
version: RUNTIME_AGENT_REGISTER_VERSION,
|
|
140
|
+
name: def.name,
|
|
141
|
+
definition: def.definition,
|
|
142
|
+
};
|
|
143
|
+
try {
|
|
144
|
+
pi.events.emit(RUNTIME_AGENT_REGISTER_EVENT, request);
|
|
145
|
+
const result = request.result;
|
|
146
|
+
if (result === undefined) {
|
|
147
|
+
errors.push(`${def.name}: pi-subagents 未安装/未就绪(事件无 owner 响应)`);
|
|
148
|
+
break; // 后续同名合同样无人接管,不刷屏
|
|
149
|
+
}
|
|
150
|
+
if (result.ok === false) throw result.error;
|
|
151
|
+
if (!result.ok || !result.registration || typeof result.registration.dispose !== "function") {
|
|
152
|
+
throw new Error("注册结果格式非法(缺 registration.dispose)");
|
|
153
|
+
}
|
|
154
|
+
registrations.push(result.registration);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
errors.push(`${def.name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { registrations, errors };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** 释放注册(幂等:其 dispose 自身幂等;异常吞掉不 throw) */
|
|
163
|
+
export function disposeRoleAgents(registrations) {
|
|
164
|
+
for (const reg of registrations || []) {
|
|
165
|
+
try {
|
|
166
|
+
reg.dispose();
|
|
167
|
+
} catch {
|
|
168
|
+
/* 清理失败不得影响会话 */
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* pi 扩展工厂(薄 glue):
|
|
175
|
+
* session_start → 先 dispose 再注册(幂等;NAO_ROLE_AGENTS=off 跳过)
|
|
176
|
+
* session_shutdown → dispose
|
|
177
|
+
* 任何失败仅 warn,绝不 throw(最坏 = 无 agent,不伤会话)。
|
|
178
|
+
*/
|
|
179
|
+
export default function naoRoleAgents(pi) {
|
|
180
|
+
let registrations = [];
|
|
181
|
+
const teardown = () => {
|
|
182
|
+
disposeRoleAgents(registrations);
|
|
183
|
+
registrations = [];
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const onSessionStart = () => {
|
|
187
|
+
teardown(); // BR5 幂等:重复 session_start 净 6 条
|
|
188
|
+
if (String(process.env.NAO_ROLE_AGENTS || "").toLowerCase() === "off") return; // BR6
|
|
189
|
+
try {
|
|
190
|
+
const root = resolveSkillsRoot();
|
|
191
|
+
const definitions = buildRoleAgentDefinitions({ root, skillsRoot: root });
|
|
192
|
+
const outcome = registerRoleAgents(pi, definitions);
|
|
193
|
+
registrations = outcome.registrations;
|
|
194
|
+
for (const err of outcome.errors) warn(`注册失败(仅 warn): ${err}`);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
warn(`装配失败(仅 warn): ${error instanceof Error ? error.message : String(error)}`);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
pi.on("session_start", onSessionStart);
|
|
202
|
+
pi.on("session_shutdown", teardown);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
warn(`生命周期挂载失败(仅 warn): ${error instanceof Error ? error.message : String(error)}`);
|
|
205
|
+
}
|
|
206
|
+
return teardown;
|
|
207
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: 工程基座工程师角色 Prompt(短常驻)——CI/构建发布/脚本守卫/依赖安全/仓库治理
|
|
3
3
|
role: rd-infra
|
|
4
|
-
version:
|
|
5
|
-
updated: 2026-10-
|
|
4
|
+
version: 3
|
|
5
|
+
updated: 2026-10-27
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# 工程基座工程师(Infra)
|
|
@@ -36,12 +36,14 @@ updated: 2026-10-13
|
|
|
36
36
|
- [ ] 仓库内引入密钥/机器特定值(token、私钥、绝对家目录路径)?
|
|
37
37
|
- [ ] 无对照就下结论(幂等/提速/体积/宽度/条数须给「改动前 → 改动后」数字)?
|
|
38
38
|
- [ ] 自验自己的守卫(应由 `qa`/`pm` 独立核)?
|
|
39
|
+
- [ ] 维护型动作(依赖/工具/脚本)以 `exit 0` 判完成,`audit`/`install-scripts` 未决策?(见 @.agents/skills/task-completion.md §三)
|
|
39
40
|
|
|
40
41
|
> 完整红线 + 幂等/权限/自证速查 + 交付检查清单:**交付前**读取 @.agents/checklists/rd-infra.md 逐项核对。
|
|
41
42
|
|
|
42
43
|
## 四、关键约定(简)
|
|
43
44
|
|
|
44
45
|
- **幂等与重跑**:脚本/迁移/安装器必须可重入;重复执行不产生重复条目(连跑 2 次自证)。
|
|
46
|
+
- **维护型 DoD(依赖/工具/脚本类)**:命令 `exit 0` **不构成完成**——`npm audit` 与 `install-scripts` 必须各自给出决策(已处置 / 显式接受含到期 / 转台账含 owner),其余 `warn`/`error`/`pending approval`/`N vulnerabilities` 逐条归口,证据落 `docs/reports/<编号>-followups.md`。判据与三出口见 @.agents/skills/task-completion.md §三/§四。
|
|
45
47
|
- **守卫/校验**:新增或改动守卫必须带**失败演练**(破坏 ⇒ 报错 ⇒ 还原复绿),并给精确 rc 与报错项。
|
|
46
48
|
- **CI/权限**:权限最小化;Secret 走仓库变量;日志/回执不输出敏感值,错误体截断。
|
|
47
49
|
- **跨项目**:安装器/脚本在第二个项目或临时目录验证;不假设单仓结构(不写死仓库名/包管理器)。
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: 产品经理角色 Prompt(短常驻)——需求分析/PRD/优先级/验收/多会话调度
|
|
3
3
|
role: pm
|
|
4
|
-
version:
|
|
5
|
-
updated: 2026-10-
|
|
4
|
+
version: 26
|
|
5
|
+
updated: 2026-10-27
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# 产品经理(PM)
|
|
@@ -60,6 +60,7 @@ updated: 2026-10-14
|
|
|
60
60
|
- **架构评审闸门**:PRD 涉及架构/NFR/选型时,开工确认后、派发前 `send` arch-designer 评审。纯 CRUD 跳过。
|
|
61
61
|
- **忙闲闸门**:`list` 见目标在线**且 `idle`** 才派完整任务;忙碌(`thinking`/`tool:*`)→ **不投递任务内容**,记入待排队列(`docs/tasks-state.md`),转 `idle` 再派;**紧急**才抢占(交互会话可 steer 注入并注明 `紧急抢占:…回执须报告挂起任务状态`;非交互会话只能排队)。
|
|
62
62
|
- **终态回执闸门**:每次派发(含架构评审)必须收到 `[编号] done` 回执(两级:默认 `done(lite)`;有阻塞/风险/需决策 `done(full)`,模板见 @.agents/checklists/comm-templates.md);未见回执(含 arch 静默)→ **主动追讨**,必要时上报用户,**不默认成功**。
|
|
63
|
+
- **任务完成闸门(交付 + 维护通用)**:任务单元分**交付型**(Issue 号/批次号)与**维护型**(`M<YYYYMMDD>-<slug>`,外部命令/依赖/环境动作);DoD 四类(产物/验证/遗留项/交接)在**开工确认卡**上逐任务实例化,验收按同一份核;收尾时遗留项必须走**三出口**(关闭 / 接受含到期日 / 转办),零遗留显式写「无」;命中**返工 ≥1 / 漏闸 / 事故 / 同类第二次 / 用户投诉** → L1 完整复盘。协议与判据见 @.agents/skills/task-completion.md。
|
|
63
64
|
- **验收闭环(省 token)**:核对 AC 五覆盖 + 回执「清单」字段(未核对则打回);验收 = 核对回执**全量门禁精确数字** + 读变更文件核对 AC + **异常才复跑/抽查**(**不可改码**、**不重复跑 worker 已跑的门禁**);读码用 `codegraph node --file <f> --offset <n> --limit <m>` 行段,**禁 cat 全文**;**UI 呈现类验收 = 用户验收清单**(QA 产出 → PM 审 → 用户执行回填 → QA 据回填关闭/重开缺陷;清单落 `docs/reports/<编号>-user-acceptance.md`,见 qa 卡)。
|
|
64
65
|
- **合并闸门(PM 控制合并时间点)**:工作期 RD 只在需求分支 `feat/<issue-id>-<slug>`(降级 `nao/<批次-slug>`)提交(`wip(<编号>):` 检查点、路径级暂存、禁 `-A`)。**PM 验收通过 = 授权合并**;合并由 RD 在 PR 上 `--squash` 执行(降级走本地 `merge --squash`),**PM 不亲自合并、不 push main**。验收核对:PR 标题/信息**用户可读** + main 上本需求**恰好 1 条提交且无 `wip()`** + 工作区干净。特例白名单与流水线见 @.agents/skills/github-flow.md。
|
|
65
66
|
- **会话生命周期(PM 专属)**:按批次边界重开(归档完成 / 用户换需求 / `/session` contextTokens 超窗口 40%)+ 落盘接续 + 重开后**回读确认**;细则见 @.agents/skills/pm-operations.md §三。
|
|
@@ -99,9 +100,10 @@ updated: 2026-10-14
|
|
|
99
100
|
- [ ] Issue 与 `docs/` 双源(正文抄进 Issue / 状态只留平台)?(§十三)
|
|
100
101
|
- [ ] `git push --force` 到 main/共享分支(未经用户明确授权并指明分支)?
|
|
101
102
|
- [ ] release notes 不可读(纯编号/类名/路径),或未落盘 `docs/releases/`?
|
|
103
|
+
- [ ] 输出里有 `warn`/`error`/`pending approval`/`N vulnerabilities` 却判完成?(`exit 0` ≠ 完成,见 @.agents/skills/task-completion.md §三)
|
|
102
104
|
- [ ] 降级(无 `gh` / 无远端)未在 `tasks-state` 与回执中标注?
|
|
103
105
|
|
|
104
|
-
> 完整红线(
|
|
106
|
+
> 完整红线(33 项)与交付检查清单(40 项):**交付/派发前**读取 @.agents/checklists/pm.md 逐项核对。
|
|
105
107
|
|
|
106
108
|
## 十一、交付检查清单
|
|
107
109
|
|
|
@@ -1397,6 +1397,34 @@ cmd_check() {
|
|
|
1397
1397
|
shopt -u nullglob
|
|
1398
1398
|
(( orphan )) || echo ' ✓ 无孤儿卡'
|
|
1399
1399
|
|
|
1400
|
+
echo "== pi 扩展声明(T527:声明 + 文件存在,防「声明漏写 ⇒ 静默无 agent」)=="
|
|
1401
|
+
if [[ ! -f "$SKILLS_DIR/package.json" ]]; then
|
|
1402
|
+
# 非包根(legacy 仓内真脚本 / 夹具只有 .agents):无 manifest 可核,跳过不判 FAIL
|
|
1403
|
+
echo ' · package.json 缺失(非包根/legacy:跳过 pi.extensions 校验)'
|
|
1404
|
+
elif ! command -v node >/dev/null 2>&1; then
|
|
1405
|
+
printf ' ✗ node 缺失,无法校验 pi.extensions 声明\n'; rc=1
|
|
1406
|
+
else
|
|
1407
|
+
local ext_list="" ext_bad=0 e
|
|
1408
|
+
if ext_list="$(node -e '
|
|
1409
|
+
const p=require(process.argv[1]); const pi=p.pi||{};
|
|
1410
|
+
const ex=pi.extensions;
|
|
1411
|
+
if(!Array.isArray(ex)||ex.length===0) process.exit(3);
|
|
1412
|
+
process.stdout.write(ex.join("\n"));
|
|
1413
|
+
' "$SKILLS_DIR/package.json" 2>/dev/null)"; then
|
|
1414
|
+
while IFS= read -r e; do
|
|
1415
|
+
[[ -n "$e" ]] || continue
|
|
1416
|
+
if [[ ! -e "$SKILLS_DIR/$e" ]]; then
|
|
1417
|
+
printf ' ✗ pi.extensions 声明条目不存在: %s\n' "$e"; ext_bad=1; rc=1
|
|
1418
|
+
fi
|
|
1419
|
+
done <<< "$ext_list"
|
|
1420
|
+
if (( ext_bad == 0 )); then
|
|
1421
|
+
printf ' ✓ pi.extensions 声明 %d 条且文件存在\n' "$(printf '%s\n' "$ext_list" | grep -c .)"
|
|
1422
|
+
fi
|
|
1423
|
+
else
|
|
1424
|
+
printf ' ✗ pi.extensions 未声明或非法(package.json)\n'; rc=1
|
|
1425
|
+
fi
|
|
1426
|
+
fi
|
|
1427
|
+
|
|
1400
1428
|
echo "== 公共规范 =="
|
|
1401
1429
|
for f in output-format.md intercom-protocol.md; do
|
|
1402
1430
|
if [[ -f "$COMMON_DIR/$f" ]]; then printf ' ✓ %s\n' "$f"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: 任务完成协议(按需,任务收尾/收尾回执前读取)——DoD 四类 · 维护型补充判据 · 遗留项三出口 · 分级复盘
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# 任务完成协议(DoD + 遗留项三出口 + 分级复盘)
|
|
6
|
+
|
|
7
|
+
> 与「派发 → 回执 → 验收 → 合并」**正交**:那条链路管「怎么交付需求」,本文件管「怎么判定一个任务单元真的完成」。
|
|
8
|
+
> 既有闸门**只指针不改写**:终态回执 / 验收闭环 / 合并闸门 @.agents/skills/pm-operations.md §一 · 上线闭环 @.agents/skills/github-flow.md §发布(阶段 7) · 回执模板 @.agents/checklists/comm-templates.md。
|
|
9
|
+
|
|
10
|
+
## 一、任务单元
|
|
11
|
+
|
|
12
|
+
- **交付型**:`T<issue-id>`(有 Issue)或降级批次号(`nao/<批次-slug>`)。
|
|
13
|
+
- **维护型**:`M<YYYYMMDD>-<slug>`(如 `M20261014-pi-ext-update`)——外部命令/依赖/环境动作,通常无 PRD。
|
|
14
|
+
- 两套粒度共存,台账字段一致;一个任务单元 = 一个 DoD 实例 = 一条收尾回执。
|
|
15
|
+
|
|
16
|
+
## 二、DoD 四类骨架(逐任务实例化,不套模板空话)
|
|
17
|
+
|
|
18
|
+
1. **产物**:落盘路径(第三方可独立读到);无产物写「无(理由)」。
|
|
19
|
+
2. **验证**:可执行判据 —— 命令 + exit code + 数字(文件数/例数/红数),或结构断言;禁「看起来没问题」。
|
|
20
|
+
3. **遗留项**:按 §四 三出口,**零遗留也必须显式写「无」**。
|
|
21
|
+
4. **交接**:状态外部化(`docs/tasks-state.md`)+ 会话回收/重开 + 接手者第一动作。
|
|
22
|
+
|
|
23
|
+
实例化时机:**开工确认卡**上逐任务写死(@.agents/skills/pm-operations.md §二),验收时按同一份 DoD 核对。
|
|
24
|
+
|
|
25
|
+
## 三、维护型补充判据(命令 exit 0 ≠ 完成)
|
|
26
|
+
|
|
27
|
+
命令 `exit 0` **不构成**完成。输出中每条 `warn` / `error` / `pending approval` / `N vulnerabilities` 必须归入:
|
|
28
|
+
**已处置**(附命令与结果)|**显式接受**(理由 + 到期日)|**转台账**(含 owner)。
|
|
29
|
+
|
|
30
|
+
- **依赖类必须两项决策**:`npm audit`(逐告警处置/接受)与 `install-scripts`(批准或拒绝 pending script)——**不许留空跳过**。
|
|
31
|
+
- 证据落 `docs/reports/<编号>-followups.md`(一行一条:编号/来源/严重度/出口/到期);可执行项同步进项目 backlog(本仓 = `docs/tasks-state.md` 待派发队列)。
|
|
32
|
+
- 超阈值(安全类 / 到期未决 >30 天)升 Issue。
|
|
33
|
+
- **首个实例**:`docs/reports/M20261014-pi-ext-update-followups.md`(`pi update --extensions` 4 漏洞 + 1 待批脚本,exit 0 但留 3 项遗留)。
|
|
34
|
+
|
|
35
|
+
## 四、遗留项三出口(无第四出口)
|
|
36
|
+
|
|
37
|
+
- **关闭**:已解决(附验证)。
|
|
38
|
+
- **接受**:降级 + 理由 + **到期日**(缺到期日 → 验收打回)。
|
|
39
|
+
- **转办**:进 `docs/tasks-state.md` 待派发队列或 Issue(含 owner)。
|
|
40
|
+
- 「先放着」「后续再看」**不是出口**。
|
|
41
|
+
- 无 `tasks-state` 的下游项目回落到「Issue 或报告末尾遗留段」,不阻塞。
|
|
42
|
+
- 回执形态:`遗留:无 | <n> 项 → <台账|tasks-state|Issue|接受(到期)>`(@.agents/checklists/comm-templates.md)。
|
|
43
|
+
|
|
44
|
+
## 五、分级复盘
|
|
45
|
+
|
|
46
|
+
- **L0 一行(默认)**:四字段 `结论 / 遗留 / 日期 / 编号`,落台账(示例:`docs/reports/M20261014-pi-ext-update-followups.md` §四)。
|
|
47
|
+
- **L1 完整复盘**:`docs/reports/<编号>-retro.md` 四节 —— 发生了什么 / 根因 / 改了哪条机制 / 可验证防线。
|
|
48
|
+
- **L1 触发(五条,命中任一)**:返工 ≥1 次|漏闸|事故(线上 / 共享分支受损或用户可见中断)|同类问题第二次出现|用户投诉。
|
|
49
|
+
- 反面示例:单次文档笔误改回 → L0 一行即可;同批两次因未读对方卡版本导致返工 → 命中「返工 ≥1」+「同类第二次」→ L1。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nathan33/nao-skill",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.6",
|
|
4
4
|
"description": "nao 多角色 AI 开发舰队:角色卡 / 技能 / 协作协议 / 工具链,一键接入项目(pi / Claude / 任意 Agent)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"skills": [
|
|
28
28
|
"./.agents/skills/nao-fleet/SKILL.md",
|
|
29
29
|
"./.agents/skills/frontend-design/SKILL.md"
|
|
30
|
+
],
|
|
31
|
+
"extensions": [
|
|
32
|
+
"./.agents/extensions/nao-role-agents.mjs"
|
|
30
33
|
]
|
|
31
34
|
},
|
|
32
35
|
"author": "Nathan Lee",
|