Files
ISEP/scripts/roster
T
Leo 5ac06abc95 工人有名字+回覆也是派工+未經調查不寫診斷(inkstone/ISEP#86/#87/#88)
三張票同一族(誰在派、派給誰、派的內容住哪裡),做在同一條分支:

#86 工人名單:agents/ 七位有名字的工人+scripts/roster+hooks/roster-guard.sh
    派工用 Task 的 subagent_type 指名,派工單格式一個字都沒改;
    指對名字就把那位的檔案原文注入(你是誰/先讀什麼/你的紅線)。
    【身份】欄同時吃得下工人名字(原本三個角色照舊)。

#87 未經調查不寫診斷:hooks/diagnosis-evidence-guard.sh + investigate-first-stamp.sh
    三個結構訊號(派過人查沒/有沒有走得過去的出處/有沒有份量),
    一個關鍵字比對都沒有;轉述有出處不會被誤擋。

#88 回覆也是派工:不另造閘,把攔截點加掛上去。
    hooks/lib/dispatch_parse.py 的 tool_channel() 一次列全所有通往 subagent 的路
    (SendMessage/雲端 session・trigger/claude -p);擋下來時把那段內容原文印出來。
    subagent 往上回報(to: "main")=交件不是派工,刻意不管。

順手修掉一個真的會咬人的 flake:dispatch-format-guard 原本開四支 python 各讀一個欄位,
機器忙的時候某個欄位會靜靜變空字串(實測連跑 10 次有 1 次「豁免了卻還是被擋」)。
四個欄位改成一次讀完。

版本號待總管定(plugin.json 只更新了描述裡的數字,版本沒動)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZBu4Sa1cGntKFRBYNZ6xs
2026-08-28 01:15:09 +00:00

95 lines
3.3 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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())