@nathan33/nao-skill 0.17.3 → 0.18.3
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.
|
@@ -26,6 +26,7 @@ description: pi-intercom 多会话协作协议(常驻引用)
|
|
|
26
26
|
拉起:`bash .agents/scripts/nao-fleet.sh ensure <别名>[@<repo>]`
|
|
27
27
|
|
|
28
28
|
- **任务派生**:`ensure --task <编号> <别名>[@<repo>]` 创建 `<角色>-<编号>` 独立会话(如 `rd-be-T1`),并行隔离、互不排队/打断,避免多任务同名冲突;任务闭环即**回收**:`nao-fleet.sh close --task <编号> <别名>`(内置在跑 turn / tasks-state 闸门)。
|
|
29
|
+
- **子代理会话不属舰队会话身份模型**:由 pi-subagents 拉起的子代理会话以 `subagent-<agent>-<id>`(无名时 `subagent-chat-<id>`)进入 intercom 名册,但**不属**舰队会话 —— `status` 只对其汇总计数(不列名、不参与在线/turn 判重),`close subagent-*` 显式拒绝(生命周期归 pi-subagents 的 stop/retention,nao 不接管)。
|
|
29
30
|
|
|
30
31
|
- **判重 / 在线判定**:脚本按 pi 自设的**终端标题**(`π - <会话名> - <仓库名>`)+ `pi-intercom` 名册判在线(**不用 `pgrep --name`**:pi 启动后 argv 被改写为 `pi`,会恒失配);已运行则跳过并 warn。确需重开加 `--force`。
|
|
31
32
|
- **标题被改写时的 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 行状态行双重信号。
|
|
@@ -243,8 +243,14 @@ check_roles_indent() {
|
|
|
243
243
|
check_alias_resolution() {
|
|
244
244
|
local rc=0 ga gr
|
|
245
245
|
local -A owner=()
|
|
246
|
+
# T525 BR6/AC7:`subagent-` 前缀保留给 pi-subagents 子代理会话 —— canonical id 与 alias **都不得占用**
|
|
247
|
+
# (否则 status/close 的排除面会吃掉该角色)。折入本函数(唯一枚举点,避第二处遍历漂移),
|
|
248
|
+
# 与缩进/别名唯一性各自累积 rc。
|
|
246
249
|
while IFS=$'\t' read -r ga gr; do
|
|
247
250
|
[[ -n "$ga" && -n "$gr" ]] || continue
|
|
251
|
+
if [[ "$ga" == subagent-* ]]; then
|
|
252
|
+
printf ' ✗ 角色 id/别名 %s 以 subagent- 开头(该前缀保留给 pi-subagents 子代理会话,nao 不接管)\n' "$ga"; rc=1
|
|
253
|
+
fi
|
|
248
254
|
if [[ -n "${owner[$ga]:-}" && "${owner[$ga]}" != "$gr" ]]; then
|
|
249
255
|
printf ' ✗ 别名 %s 跨角色重名:%s 与 %s\n' "$ga" "${owner[$ga]}" "$gr"; rc=1
|
|
250
256
|
fi
|
|
@@ -261,11 +267,14 @@ check_alias_resolution() {
|
|
|
261
267
|
for (i=1;i<=n;i++){ gsub(/^[[:space:]]+|[[:space:]]+$/, "", a[i]); if(a[i]!="") print a[i] "\t" c }
|
|
262
268
|
}' "$MANIFEST")
|
|
263
269
|
for gr in "${ROLE_ORDER[@]}"; do
|
|
270
|
+
if [[ "$gr" == subagent-* ]]; then
|
|
271
|
+
printf ' ✗ 角色 id/别名 %s 以 subagent- 开头(该前缀保留给 pi-subagents 子代理会话,nao 不接管)\n' "$gr"; rc=1
|
|
272
|
+
fi
|
|
264
273
|
if [[ "${owner[$gr]:-}" != "$gr" ]]; then
|
|
265
274
|
printf ' ✗ 角色 %s 的 canonical id 未登记于 aliases(BR2:canonical 须可解析为自身)\n' "$gr"; rc=1
|
|
266
275
|
fi
|
|
267
276
|
done
|
|
268
|
-
(( rc == 0 )) && printf ' ✓
|
|
277
|
+
(( rc == 0 )) && printf ' ✓ 别名解析守卫:全部别名可解析且无跨角色重名 + 无 subagent- 保留前缀\n'
|
|
269
278
|
return $rc
|
|
270
279
|
}
|
|
271
280
|
|
|
@@ -606,6 +615,17 @@ derived_in_field() { # <name> → 派生名列表(每行一个;空 = 无)
|
|
|
606
615
|
done < <(visible_session_names)
|
|
607
616
|
}
|
|
608
617
|
|
|
618
|
+
# 子代理会话计数(T525):与 derived_in_field 同源(visible_session_names,已去重)中锚首 `subagent-` 者。
|
|
619
|
+
# 子代理(pi-subagents)不属舰队会话身份模型 —— status 只计数不列名;生命周期归 pi-subagents,nao 不回收。
|
|
620
|
+
# BR6 前缀精确:`subagent-*` 不匹配 `subagentfoo` / 裸 `subagent` / `mysubagent-x`。
|
|
621
|
+
subagent_in_field() { # → echo 子代理会话数(0..N)
|
|
622
|
+
local n c=0
|
|
623
|
+
while IFS= read -r n; do
|
|
624
|
+
[[ "$n" == subagent-* ]] && c=$((c + 1))
|
|
625
|
+
done < <(visible_session_names)
|
|
626
|
+
printf '%s\n' "$c"
|
|
627
|
+
}
|
|
628
|
+
|
|
609
629
|
# screen 会话精确令牌(T516 F1/F2 · arch 评审):从 `screen -ls` 取**精确** nao-<名> 会话的 `pid.name` 令牌。
|
|
610
630
|
# 与 running()/close 检测同一锚定(名字后必须是空白或行尾;`\b` 在派生名的 "-" 处仍成立,故不用)。
|
|
611
631
|
# 检测与销毁共用本 helper ⇒ 检测锚与销毁目标不会漂移;**取不到令牌即空,调用方不得 quit**(宁不回收,也不误伤派生)。
|
|
@@ -661,12 +681,27 @@ visible_session_names() {
|
|
|
661
681
|
} | awk -F'\t' 'NF {print $1}' | awk '!seen[$0]++'
|
|
662
682
|
}
|
|
663
683
|
|
|
684
|
+
# 名册「条目感知」pane 认领集(T525 E2):name↔tmuxPane 配对后**过滤** `^subagent-` 条目 ⇒ 每行一个 pane。
|
|
685
|
+
# 兼容紧凑/pretty 两种 JSON:`sed 's/},/}\n/g'` 先按对象边界切行(纯状态机 awk 在紧凑单行名册里会因
|
|
686
|
+
# 贪婪匹配塌缩成末条 ⇒ 假告警);取值法与 intercom_pane_for 的逐条目取法同源。
|
|
687
|
+
# ⚠ 仅用于 unattributed_pi_panes:fallback_pane_for 的 claimed 语义是「该 pane 已被占用」(含子代理),
|
|
688
|
+
# 排除会致兜底**误认领父 pane**(D-A 已裁定,见 PRD §三.4)。
|
|
689
|
+
roster_pane_claims() { # → 被非子代理会话认领的 pane_id(每行一个;rc 恒 0)
|
|
690
|
+
intercom_list_json 2>/dev/null | sed 's/},/}\n/g' | awk '
|
|
691
|
+
/"name":[[:space:]]*"/ { s=$0; sub(/.*"name":[[:space:]]*"/,"",s); sub(/".*/,"",s); n=s }
|
|
692
|
+
/"tmuxPane":[[:space:]]*"/ { s=$0; sub(/.*"tmuxPane":[[:space:]]*"/,"",s); sub(/".*/,"",s); p=s
|
|
693
|
+
if (p != "" && n !~ /^subagent-/) print p }
|
|
694
|
+
' || true
|
|
695
|
+
}
|
|
696
|
+
|
|
664
697
|
# 未能归属到任何会话名的 pi pane(标题不符契约且名册无 tmuxPane 记录):
|
|
665
698
|
# 输出 pane_id<TAB>pane_title;供 status 做「非静默」提示(不假装看不到)。
|
|
699
|
+
# T525 E2:claimed 用 roster_pane_claims(条目感知、排除 `^subagent-`)⇒ 仅被子代理继承 tmuxPane 的孤儿
|
|
700
|
+
# pane 回到「无法归属会话名」告警(BR8 非静默优先)。
|
|
666
701
|
unattributed_pi_panes() {
|
|
667
702
|
command -v tmux >/dev/null 2>&1 || return 0
|
|
668
703
|
local claimed p tt
|
|
669
|
-
claimed="$(
|
|
704
|
+
claimed="$(roster_pane_claims)" || claimed=""
|
|
670
705
|
while IFS=$'\t' read -r p tt; do
|
|
671
706
|
[[ -n "$p" ]] || continue
|
|
672
707
|
grep -qxF "$p" <<< "$claimed" && continue
|
|
@@ -1560,6 +1595,10 @@ cmd_status() {
|
|
|
1560
1595
|
done < <(visible_session_names)
|
|
1561
1596
|
(( found )) || echo ' (无)'
|
|
1562
1597
|
[[ -f "$TASKS_STATE" ]] || echo " ($TASKS_STATE 不存在,残留判定已跳过)"
|
|
1598
|
+
# T525:子代理会话(pi-subagents)不属舰队会话身份模型 —— 派生节后独立一行、只计数不列名、N=0 不打印(BR3/BR6)。
|
|
1599
|
+
local nsub
|
|
1600
|
+
nsub="$(subagent_in_field)"
|
|
1601
|
+
(( nsub > 0 )) && printf ' · 另有 %d 个子代理会话(subagent-*)· 生命周期由 pi-subagents 管理,nao 不回收\n' "$nsub"
|
|
1563
1602
|
# 标题被改写/无名的 pi pane:非静默——显式列出,供人工核对
|
|
1564
1603
|
local -a orph=()
|
|
1565
1604
|
local pn pt
|
|
@@ -1577,6 +1616,12 @@ cmd_status() {
|
|
|
1577
1616
|
cmd_close() {
|
|
1578
1617
|
local force="$1" task="$2" target="${3:-}"
|
|
1579
1618
|
[[ -n "$target" ]] || die "close 需要目标:角色别名或派生会话名(如 rd-be / rd-be-T1 / qa-T1)"
|
|
1619
|
+
# T525 BR1/BR2/BR4:子代理会话显式拒绝 —— 判定**只针对 $target 位置名**(`close --task subagent-x qa`
|
|
1620
|
+
# 是合法派生 qa-subagent-x,不得误杀);锚首 glob(`subagentfoo`/裸 `subagent` 不匹配);`--force` 不旁路;
|
|
1621
|
+
# die 于任何 pane 定位/捕获/kill 之前 ⇒ 父 pane 必存活(父+子共用 tmuxPane 亦然)。
|
|
1622
|
+
if [[ "$target" == subagent-* ]]; then
|
|
1623
|
+
die "拒绝回收 $target:这是 pi-subagents 子代理会话(subagent-*),其生命周期不归 nao 回收(请用 pi-subagents 的 stop / retention 管理)"
|
|
1624
|
+
fi
|
|
1580
1625
|
local name repo cls bus pane pids st tgt a best="" stok
|
|
1581
1626
|
intercom_list_json >/dev/null 2>&1 || true # 预热名册缓存
|
|
1582
1627
|
|
|
@@ -1673,7 +1718,7 @@ cmd_close() {
|
|
|
1673
1718
|
fi
|
|
1674
1719
|
warn "无法确认 $name 在线状态:宿主无 tmux/screen 句柄,且 pi-intercom 名册不可用"
|
|
1675
1720
|
warn " pi 启动后 argv 被改写为 \"pi\",进程扫描不可信 ⇒ 不做静默 no-op(本命令 exit 非 0)"
|
|
1676
|
-
warn " 请用 intercom list
|
|
1721
|
+
warn " 请用 intercom list 人工核对;确认已退出后忽略本提示"
|
|
1677
1722
|
return 1
|
|
1678
1723
|
fi
|
|
1679
1724
|
|
|
@@ -53,6 +53,7 @@ PM 在**立项 / 终签 / 发布**时读取;RD 在**起分支 / 开 PR / 合
|
|
|
53
53
|
|
|
54
54
|
- 版本号:SemVer,PM 按批次范围定(feat→MINOR / fix→PATCH / 破坏性→MAJOR);项目 `AGENTS.md` 有约定则从之。
|
|
55
55
|
- 门禁:AC 全过 + 验收闭环 + main 门禁全绿 + 工作区干净 + PR 已合并。
|
|
56
|
+
- **发布前置(严格闸门)**:若仓库提供 `test:t4:full` 脚本,发布前须先 `npm run test:t4:full` **rc=0**(判据 = **SKIP 计数与 DEGRADE 计数均为 0**,`SKIP`/`DEGRADE` 即 FAIL)。
|
|
56
57
|
- **优先 `gh`**:`gh release create <tag> --title "vX.Y.Z" --notes-file docs/releases/<version>.md`(**标题口径(强约束):@.agents/common/release-notes.md** —— 标题仅裸版本号,描述进正文首段)。
|
|
57
58
|
- 探测:`gh auth status` 按 **exit code** 判定(`keyring` 警告但 exit 0 **仍可用**,可 `gh api user` 复核);**不自动 `gh auth login`**(涉用户凭证)。
|
|
58
59
|
- release notes 落盘 `docs/releases/<version>.md`(**写作规范(强约束):@.agents/common/release-notes.md** —— 面向用户「本次更新」置顶、内部编号 / 文件名 / 属性名一律下沉「技术细节」、正文不用表格;骨架见 @.agents/templates/release-notes.md.example)。
|
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.18.3 # 声明 pin + 把机制包物化到项目内 .pi/npm
|
|
28
28
|
npx @nathan33/nao-skill init # 写入转发 shim + 生成 AGENTS.md
|
|
29
29
|
```
|
|
30
30
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nathan33/nao-skill",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"description": "nao 多角色 AI 开发舰队:角色卡 / 技能 / 协作协议 / 工具链,一键接入项目(pi / Claude / 任意 Agent)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,9 +39,12 @@
|
|
|
39
39
|
"node": ">=18"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
|
-
"test": "
|
|
42
|
+
"test": "npm run test:agents && npm run test:t4",
|
|
43
|
+
"test:agents": "bash .agents/scripts/nao-fleet.sh check && npm run check:agents",
|
|
44
|
+
"test:t4": "bash tests/t4/run.sh",
|
|
45
|
+
"test:t4:full": "T4_ALLOW_MISSING=0 T4_REQUIRE_FULL=1 bash tests/t4/run.sh",
|
|
43
46
|
"check:agents": "tsc -p tsconfig.agents.json",
|
|
44
|
-
"prepack": "npm test"
|
|
47
|
+
"prepack": "npm run test:agents"
|
|
45
48
|
},
|
|
46
49
|
"devDependencies": {
|
|
47
50
|
"@types/node": "^20.19.0",
|