現在的主線是哪一個,變成一個查得到的事實(inkstone/ISEP#82)
14 個 open milestone 同時亮著,其中「Mira 現代化」同名活在 5 個 repo,
所以 SOP 說的「那個 active milestone」在現場沒有指涉對象。
- hooks/lib/mainline.py 主線的唯一存放處(一個檔放得下一條),從不打網路
- scripts/mainline show/list/set/clear/refresh/adopt/has
- hooks/mainline-focus-guard.sh 派了不在主線上的票 ⇒ 攔一次,問補收還是跳線
- hooks/lib/countdown.py ⏱ 那一行的主線改讀「被標定的」,蓋過「期限最近」的猜測
- hooks/countdown-guard.sh 同一個注入點加第二行 🎯(ISEP#63 那半不動)
- 測試 24 條(離線)+ countdown 原有 20 條仍全綠
This commit is contained in:
+46
-6
@@ -27,6 +27,13 @@ leo 2026-08-28 07:40:「今天我整天上課……**下午四點左右**希
|
||||
從快取檔讀,**這支從不打網路**:UserPromptSubmit 走在每一則訊息的關鍵路徑上,
|
||||
在那裡打網路 = 每一句話都先等一次 HTTP。快取由 SessionStart 那支負責更新
|
||||
(`scripts/countdown-milestone-refresh.sh`),拿不到就整段不顯示,不編數字。
|
||||
|
||||
🔴 **來源有兩個,優先序寫死(inkstone/ISEP#82)**:
|
||||
① **被標定的主線**(`hooks/lib/mainline.py`,`scripts/mainline set` 寫的)—— 優先
|
||||
② 期限最近的那一個(`milestone-due` 快取,`countdown-milestone-refresh.sh` 寫的)
|
||||
② 是**猜**出來的(「最近到期的大概就是在做的那個」),而 ISEP#82 的整件事就是
|
||||
「那個 active milestone」在 14 個裡沒有指涉對象。⇒ 一旦有人真的標了主線,
|
||||
就不准再用猜的那個蓋過它。兩個都沒有 ⇒ 整段不顯示。
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
@@ -137,10 +144,40 @@ def deadline(now: datetime) -> datetime:
|
||||
return d
|
||||
|
||||
|
||||
def milestone() -> "tuple[str, datetime] | None":
|
||||
"""主線 milestone 的期限。快取檔一行:`YYYY-MM-DD|<名稱>`。沒有就沒有。"""
|
||||
def _mainline():
|
||||
"""借 `hooks/lib/mainline.py` 讀「被標定的主線」。拿不到就當沒有(fail-open)。
|
||||
|
||||
刻意用檔案路徑載入而不是 `import mainline`:本檔自己也是被
|
||||
`spec_from_file_location` 載進去的,`sys.path` 裡沒有 `hooks/lib`。
|
||||
"""
|
||||
try:
|
||||
import importlib.util
|
||||
p = os.path.join(os.path.dirname(os.path.abspath(__file__)), "mainline.py")
|
||||
spec = importlib.util.spec_from_file_location("isep_mainline", p)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def milestone() -> "tuple[str, datetime | None] | None":
|
||||
"""主線 milestone 的期限。優先讀被標定的主線,其次讀「期限最近」的快取。
|
||||
|
||||
快取檔一行:`YYYY-MM-DD|<名稱>`。兩個都沒有就沒有(回 None,整段不顯示)。
|
||||
期限可能是 None(被標定的主線沒設期限)——那時只說名字,不編一個日期。
|
||||
"""
|
||||
raw = os.environ.get("ISEP_MILESTONE_DUE", "").strip()
|
||||
name = os.environ.get("ISEP_MILESTONE_NAME", "").strip()
|
||||
if not raw:
|
||||
mod = _mainline()
|
||||
if mod is not None:
|
||||
try:
|
||||
seg = mod.countdown_segment()
|
||||
except Exception:
|
||||
seg = None
|
||||
if seg:
|
||||
return seg
|
||||
if not raw:
|
||||
p = os.path.join(state_dir(), "milestone-due")
|
||||
try:
|
||||
@@ -184,11 +221,14 @@ def line(session_id: str, transcript_path: str) -> str:
|
||||
ms = milestone()
|
||||
if ms:
|
||||
name, due = ms
|
||||
gap = due - now
|
||||
if gap.total_seconds() >= 0:
|
||||
parts.append("主線 %s 剩 %s" % (name, human(gap)))
|
||||
if due is None:
|
||||
parts.append("主線 %s(沒設期限)" % name)
|
||||
else:
|
||||
parts.append("🔴 主線 %s 已逾期 %s" % (name, human(gap)))
|
||||
gap = due - now
|
||||
if gap.total_seconds() >= 0:
|
||||
parts.append("主線 %s 剩 %s" % (name, human(gap)))
|
||||
else:
|
||||
parts.append("🔴 主線 %s 已逾期 %s" % (name, human(gap)))
|
||||
|
||||
return "|".join(parts)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user