把 main(v0.15.0,派工紀律三件 #105)併進來,逐支點名複驗過 hooks.json
## hooks.json:這次 git 自動合成功了,而那正是最危險的情況
`hooks.json` 是 JSON——**合錯了語法照樣合法、閘卻不見了,不會有任何東西喊一聲。**
所以「沒有衝突」不等於「沒掉東西」,一律再做兩件事:
① 逐支點名(指令已寫進 README「裝什麼」那段)→ 82 條,60 支各自幾條全部列出
② 跟**兩個父節點**做集合對照:
merged 82 = main 79 + 我的 3
從 main 掉了:0 條
從我這邊掉了:0 條
兩邊都沒有卻冒出來的:0 條
`#105` 三支與我的兩支同時在,位置也對:
roster-guard.sh PreToolUse Agent / Task
diagnosis-evidence-guard.sh PreToolUse Bash
investigate-first-stamp.sh PostToolUse Agent|Task / SendMessage
overdue-nag-guard.sh SessionStart
wiki-size-guard.sh SessionStart / PreToolUse Write|Edit|MultiEdit
(總管提醒的 `roster-guard` vs `mainline-focus-guard` 那種「同一陣列位置兩邊各一支」
這次沒有再發生衝突,但兩支都在,各 2 條。)
## 三處文字衝突:兩邊都留,數字重數
- plugin.json 版本吃 main 的 **0.15.0**(總管已定版,**我沒有動它**);
描述欄補上 main 新增的「7 位有名字的工人」,三個數字重數
- README.md 吃 main 的新表格結構(多了 agents/commands/skills/scripts 四列),
數字重數;並把累積成**四列**的 `hooks/` 收成一列
- hooks-inventory 標頭被貼成兩份、「一句話結論」被貼成**三份**(數字還互相打架),
各收成一份;版本註記兩邊都留
## 盤點(全部在合併後的樹上實數,不是加減推的)
ls hooks/*.sh | wc -l 58 → 60
grep -c '"command":' hooks/hooks.json 79 → 82
ls agents/*.md | wc -l 7
ls -p scripts | grep -v / | wc -l 48
未掛進 hooks.json 的 .sh 3(與本頁原本寫的一致,重數過)
📌 抓到的漂移(每次併都有一個,這次三個):
① hooks-inventory 的標頭 ×2、一句話結論 ×3
② README 的 `hooks/` 列 ×4,其中兩列是舊數字
③ plugin.json 描述欄寫「49 支腳本」,而用本頁寫死的那道指令實數是 48
## 測試(合併後全部重跑,帶對參數)
hooks/tests 23 支全綠:ask-user-question 14、countdown 20、diagnosis-evidence 26、
dispatch-format 52、factory-idle 33、gate-ok 17、gitea-arm-check 16、
presence-beacon 14、cross-repo 19、main-and-prod-push 10、mainline-focus 24、
mainline-idle 61、milestone-account 22、**overdue-nag 36**、pr-verdict 52、
prod-write 37、reply-identity 11、roster 24、sdd 8、search-is-not-proof 31、
stage-before-prod 16、unpushed-police 10、**wiki-compress 25**
scripts/test-* 13 支全綠。
claude plugin validate . ✔ passed;check-version-consistency ✅ 0.15.0 = v0.15.0。
兩支新 SessionStart hook 併完實跑過,閘判定探針對 v0.15.0 的 prod-write-guard 回 pass。
🔴 跑之前清 `CLAUDE_CODE_CHILD_SESSION`;四支要帶參數
(三支帶 hook 絕對路徑、cross-repo 帶 hook 絕對路徑、gitea-arm-check 帶 repo 根目錄)
——不帶會紅,而那是假紅。
This commit is contained in:
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python3
|
||||
"""roster — 工人名單(inkstone/ISEP#86)
|
||||
|
||||
python3 scripts/roster list 名單:有哪幾個工人、各自管什麼
|
||||
python3 scripts/roster show <名字> 一個工人的全文(它開工時會讀到的東西)
|
||||
python3 scripts/roster names 只印名字,一行一個(給腳本用)
|
||||
python3 scripts/roster which <owner/repo> 這個 repo 該派給誰
|
||||
|
||||
leo(ISEP#86):「身為派工的人,我要工人有名字,我才知道票上這件事到底是誰做的。」
|
||||
|
||||
名單是**資料**(`agents/*.md`),不是程式:加一個工人=加一個檔,不改任何 hook。
|
||||
派工時把名字放進 `Task` 的 `subagent_type`;名字不在名單上,
|
||||
`hooks/roster-guard.sh` 會擋下來並說「沒有這個人」。
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "hooks", "lib"))
|
||||
try:
|
||||
import roster as R
|
||||
except Exception as e: # pragma: no cover
|
||||
print("🔴 讀不到 hooks/lib/roster.py:%s" % e, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def cmd_list():
|
||||
ws = R.load()
|
||||
if not ws:
|
||||
print("🔴 名單是空的(找不到 %s 底下任何工人檔)" % R.roster_dir(), file=sys.stderr)
|
||||
return 1
|
||||
print("工人名單(%d 位) 來源:%s\n" % (len(ws), R.roster_dir()))
|
||||
print(" %-18s %-26s %s" % ("名字", "負責 repo", "它是誰"))
|
||||
print(" " + "─" * 100)
|
||||
for w in ws:
|
||||
print(" " + R.one_liner(w))
|
||||
print("\n派工:把「名字」放進 Task 的 subagent_type;派工單本身仍然只有一行【工單】。")
|
||||
print("看某一位的全文:python3 scripts/roster show <名字>")
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_show(name):
|
||||
w = R.find(name)
|
||||
if not w:
|
||||
print("🚫 名單上沒有「%s」這個人。現有的是:\n %s"
|
||||
% (name, "\n ".join(R.names()) or "(空)"), file=sys.stderr)
|
||||
return 2
|
||||
print("# %s\n" % w["name"])
|
||||
print("負責 repo:%s" % (w["repo"] or "(跨 repo)"))
|
||||
print("一句話 :%s" % w["description"])
|
||||
print("檔案 :%s\n" % w["path"])
|
||||
print(w["body"])
|
||||
return 0
|
||||
|
||||
|
||||
def cmd_which(repo):
|
||||
hits = [w for w in R.load() if w["repo"].lower() == (repo or "").strip().lower()]
|
||||
if not hits:
|
||||
print("🚫 名單上沒有負責「%s」的人。現有的是:" % repo, file=sys.stderr)
|
||||
for w in R.load():
|
||||
print(" " + R.one_liner(w), file=sys.stderr)
|
||||
return 2
|
||||
for w in hits:
|
||||
print(w["name"])
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
argv = sys.argv[1:]
|
||||
if not argv or argv[0] in ("-h", "--help", "help"):
|
||||
print(__doc__)
|
||||
return 0
|
||||
verb, rest = argv[0], argv[1:]
|
||||
if verb == "list":
|
||||
return cmd_list()
|
||||
if verb == "names":
|
||||
for n in R.names():
|
||||
print(n)
|
||||
return 0
|
||||
if verb == "show":
|
||||
if not rest:
|
||||
print("用法:scripts/roster show <名字>", file=sys.stderr)
|
||||
return 1
|
||||
return cmd_show(rest[0])
|
||||
if verb == "which":
|
||||
if not rest:
|
||||
print("用法:scripts/roster which <owner/repo>", file=sys.stderr)
|
||||
return 1
|
||||
return cmd_which(rest[0])
|
||||
print("不認得的動詞「%s」。\n%s" % (verb, __doc__), file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user