feat(role): SessionEnd 立即釋放角色鎖,不必等閒置逾時
關掉 CLI 後立刻重開新階段時,角色會被自己上一個階段的殘留鎖擋住: 原本只有「持有者 transcript 閒置超過 30 分鐘」與手動 --unlock 兩條釋放 路徑,而剛關閉的 transcript mtime 還很新,機制無法區分「已關閉」與 「正在別的視窗打字」,因此最久要等 30 分鐘才叫得回角色。 新增 SessionEnd hook(role_unload.sh)作為快速路徑,工作階段正常結束時 立即刪鎖。mtime 閒置逾時後援保留不動 —— SessionEnd 不保證觸發 (kill -9、直接關終端機、WSL 關機、當機都不會跑),少了後援會在異常 結束時把角色鎖死到下次手動解鎖,兩條路徑缺一不可。 只在鎖檔登記的 transcript 等於自己時才釋放:被鎖擋下的第二個階段結束時 同樣會觸發 SessionEnd,若無條件刪鎖會把仍在使用中的第一個階段的鎖一起 刪掉,等於讓單一實例限制形同虛設。無法取得 transcript、sub agent (ROLE_SKIP_INSTANCE_LOCK=1)、限制已停用(ROLE_SINGLE_INSTANCE=0) 一律不動鎖。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+14
-3
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: role
|
||||
description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI 工具以固定角色(name/nature/vibe/簽名 emoji)回覆,並把每輪對話累積成長期記憶:搭配相容的 SessionStart hook 於啟動時依字元預算載入高價值記憶、Stop hook 先本地過濾再輕量記錄對話,睡眠時段(預設 22:00 至隔天 06:00)由排程整理記憶(NREM 鞏固:分類/去噪/去重/合併/優先度;REM 整合:跨記憶連結/抽象化/提取線索;再依 semantic/episodic/procedural/emotional/preference/rule 與 explicit/implicit 標記長期記憶型態,壓縮歸檔並適當遺忘)。提供 --new(新建或更新角色;可只給角色名稱,必要時詢問來源/作品並推斷 name/nature/vibe/emoji 四欄)、--use(以角色 ID 切換啟用角色)、--list(列出角色與 ID)、--export(匯出角色壓縮檔)、--sleep(立即整理)、--status/--diagnose、--install-cron/--remove-cron、--forget-preview、--brief(晨間狀態檢查)、--agent(匯出成 sub agent 供多角色協作)、--migrate(舊格式角色檔拆成身分與人格兩檔)等模式。當使用者說建立角色、新增人格、切換角色、匯出角色、備份角色、讓回覆更有特色、角色記憶、記憶整理、睡覺整理記憶、忘記舊記憶、角色沒有載入、hook 沒載入角色、晨間狀態檢查、早上主動回報狀態,或提到 .roles/.memory/ROLE_NAME/ROLE_ENABLED/ROLE_SLEEP_START/ROLE_MEMORY_HOME/ROLE_LOAD_LIMIT/ROLE_LOAD_INBOX_LIMIT/ROLE_LOAD_DIALOG_TURNS/ROLE_CAPTURE_ENABLED 時觸發。不適用於:工作紀錄寫入 Gitea wiki(用 /jsc-doc:worklog)、專案文件化(用 /jsc-doc:funcs)。
|
||||
description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI 工具以固定角色(name/nature/vibe/簽名 emoji)回覆,並把每輪對話累積成長期記憶:搭配相容的 SessionStart hook 於啟動時依字元預算載入高價值記憶、Stop hook 先本地過濾再輕量記錄對話,睡眠時段(預設 22:00 至隔天 06:00)由排程整理記憶(NREM 鞏固:分類/去噪/去重/合併/優先度;REM 整合:跨記憶連結/抽象化/提取線索;再依 semantic/episodic/procedural/emotional/preference/rule 與 explicit/implicit 標記長期記憶型態,壓縮歸檔並適當遺忘)。提供 --new(新建或更新角色;可只給角色名稱,必要時詢問來源/作品並推斷 name/nature/vibe/emoji 四欄)、--use(以角色 ID 切換啟用角色)、--list(列出角色與 ID)、--export(匯出角色壓縮檔)、--sleep(立即整理)、--status/--diagnose、--install-cron/--remove-cron、--forget-preview、--brief(晨間狀態檢查)、--agent(匯出成 sub agent 供多角色協作)、--migrate(舊格式角色檔拆成身分與人格兩檔)等模式。當使用者說建立角色、新增人格、切換角色、匯出角色、備份角色、讓回覆更有特色、角色記憶、記憶整理、睡覺整理記憶、忘記舊記憶、角色沒有載入、hook 沒載入角色、角色被鎖住、角色鎖沒有自動解除、關掉 CLI 後角色叫不回來、角色說已在另一個工作階段、晨間狀態檢查、早上主動回報狀態,或提到 .roles/.memory/ROLE_NAME/ROLE_ENABLED/ROLE_SLEEP_START/ROLE_MEMORY_HOME/ROLE_LOAD_LIMIT/ROLE_LOAD_INBOX_LIMIT/ROLE_LOAD_DIALOG_TURNS/ROLE_CAPTURE_ENABLED/ROLE_SINGLE_INSTANCE/ROLE_INSTANCE_IDLE_MINUTES 時觸發。不適用於:工作紀錄寫入 Gitea wiki(用 /jsc-doc:worklog)、專案文件化(用 /jsc-doc:funcs)。
|
||||
---
|
||||
|
||||
# role — 角色人格與長期記憶
|
||||
@@ -14,10 +14,12 @@ description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI
|
||||
| `hooks/hooks.json` 的 `Stop` hook | harness 自動 | 每輪結束先記錄最後互動時間 → 用本地規則過濾低價值短回合 → 值得保存時才濃縮成一則輕量 inbox 記憶 → 遮蔽 → 寫入 `inbox/` |
|
||||
| `hooks/hooks.json` 的 `PreCompact` hook | harness 自動 | 對話壓縮**前**強制記錄一次(**跳過長度門檻**):壓縮會讓尚未寫入的內容永久蒸發,此時寧可多記 |
|
||||
| `hooks/hooks.json` 的 `PostCompact` hook | harness 自動 | 壓縮**後**把 harness 產生的摘要存成一則 `daily` 記憶,作為該段落的濃縮備份 |
|
||||
| `hooks/hooks.json` 的 `SessionEnd` hook | harness 自動 | 工作階段結束時釋放本階段持有的角色單一載入鎖,讓關掉 CLI 後可立刻重開叫回同一角色;鎖不屬於自己時不動作 |
|
||||
| cron 排程(本 skill 安裝) | 系統排程 | 睡眠時段每小時檢查一次:**有 AI 在運行就不睡**;另可依 CLI 閒置時間自動小睡整理 |
|
||||
| 本 skill `/jsc-generic:role` | 使用者/助理手動 | `--new`/`--use`/`--list`/`--export`/`--agent`/`--migrate`/`--sleep`/`--brief`/`--status`/`--install-cron`/`--forget-preview` |
|
||||
| `scripts/role/role_load.sh` | SessionStart hook | 角色與記憶載入;參考 OpenClaw 的 SOUL/AGENTS/USER/MEMORY 分層,把人格、操作邊界、使用者記憶分開注入,並提供第一則回覆問候提示(單一實作,避免漂移) |
|
||||
| `scripts/role/role_capture.sh` | Stop hook | 對話 → 記憶(固定欄位格式) |
|
||||
| `scripts/role/role_unload.sh` | SessionEnd hook | 釋放本階段的角色單一載入鎖(比對 transcript 確認鎖屬於自己才釋放) |
|
||||
| `scripts/role/role_sleep.sh` | cron/小睡/補跑/手動 | 睡眠與小睡判斷、記憶整理、角色匯出、sub agent 定義匯出、晨間狀態檢查、排程安裝、狀態輸出 |
|
||||
| `scripts/role/memory.js` | 上述共用 | 記憶檔讀寫、分類、去重合併、優先度、心理學記憶型態與關聯 metadata、壓縮歸檔、遺忘、載入組裝 |
|
||||
| `scripts/role/transcript.js` | 上述共用 | 抽本輪對話片段、抽最近數輪純對話供工作階段交接、機密與個資遮蔽 |
|
||||
@@ -30,6 +32,7 @@ description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `SessionStart` 載入角色 | ✅ | ⚠️ 需該版本支援 SessionStart hook | ❌ | ❌ | ❌ |
|
||||
| `Stop` 記錄記憶 | ✅ | ✅ 需可讀 Codex session JSONL | ❌ | ❌ | ❌ |
|
||||
| `SessionEnd` 釋放角色鎖 | ✅ | ⚠️ 需該版本支援 SessionEnd hook | ❌ | ❌ | ❌ |
|
||||
| cron 睡眠整理 | ✅ 與助理無關(系統排程) | ✅ | ✅ | ✅ | ✅ |
|
||||
| `--new`/`--use`/`--sleep` 等模式 | ✅ | ⚠️ 需 plugin 目錄保留 `scripts/` | ⚠️ 同左 | ❌ 只複製 `skills/`,無腳本 | ⚠️ 同左 |
|
||||
| 濃縮/整理 CLI | `claude -p` | `codex exec` | `agy -p` | `opencode run` | `copilot -p` |
|
||||
@@ -40,7 +43,7 @@ description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI
|
||||
|
||||
| plugin | hooks.json 內容 | 擁有的腳本 |
|
||||
| --- | --- | --- |
|
||||
| `jsc-generic` | `SessionStart`(role_load)+ `Stop`(role_capture) | `scripts/role/` |
|
||||
| `jsc-generic` | `SessionStart`(role_load)+ `Stop`/`PreCompact`/`PostCompact`(role_capture)+ `SessionEnd`(role_unload) | `scripts/role/` |
|
||||
| `jsc-doc` | `Stop`(worklog) | `scripts/worklog/` |
|
||||
| `jsc-code` | 無 `hooks/hooks.json` | 無 hook 腳本 |
|
||||
|
||||
@@ -345,12 +348,20 @@ Stop hook 只做「編碼前處理」,輸出粗分類、summary、tags、prior
|
||||
| --- | --- |
|
||||
| 同一個工作階段重新載入(含 `resume`) | 允許,更新鎖 |
|
||||
| 另一個工作階段仍活躍 | 拒絕載入人格,並在 context 說明解除方式 |
|
||||
| 持有者正常結束工作階段(`SessionEnd`) | **立即釋放**,下一個階段可馬上載入 |
|
||||
| 持有者的 transcript 已刪除 | 自動接手 |
|
||||
| 持有者閒置超過 `ROLE_INSTANCE_IDLE_MINUTES` | 自動接手 |
|
||||
| hook 未提供 transcript 路徑 | **一律放行且不寫鎖** |
|
||||
| `ROLE_SKIP_INSTANCE_LOCK=1` | **一律放行且不寫鎖**(sub agent 等非對話情境) |
|
||||
|
||||
判斷依據是**持有者 transcript 檔的 mtime**,而非 pid —— SessionStart hook 無法可靠取得 CLI 主行程 pid,也沒有保證會觸發的 SessionEnd hook 可用來釋放鎖;活躍的工作階段會持續寫入 transcript,因此「多久沒被寫入」最貼近真實狀態且不需要清理程序。
|
||||
釋放分兩條路,**兩者缺一不可**:
|
||||
|
||||
1. **快速路徑**:`SessionEnd` hook(`role_unload.sh`)刪掉自己的鎖。少了它,關掉 CLI 後立刻重開會被自己上一個階段的殘留鎖擋住,得等閒置逾時。
|
||||
2. **後援**:持有者 transcript 的 mtime 閒置逾時接手。少了它,`kill -9`、直接關掉終端機視窗、WSL 關機、當機這些**不會觸發 `SessionEnd`** 的情況會把角色鎖死到下次手動解鎖。
|
||||
|
||||
`role_unload.sh` 只在**鎖檔登記的 transcript 等於自己**時才釋放:被鎖擋下的第二個階段結束時同樣會觸發 `SessionEnd`,若無條件刪鎖,它會把仍在使用中的第一個階段的鎖一起刪掉,等於讓整個限制形同虛設。
|
||||
|
||||
後援之所以看 transcript mtime 而非 pid:SessionStart hook 無法可靠取得 CLI 主行程 pid;活躍的工作階段會持續寫入 transcript,因此「多久沒被寫入」最貼近真實狀態且不需要清理程序。
|
||||
|
||||
**設計原則是寧可誤放行也不要誤鎖** —— 誤鎖會讓使用者叫不出角色,比偶爾重複載入嚴重得多。因此無法識別工作階段時一律放行。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user