feat(role): 點名載入切換角色 + cron 固定路徑啟動器(0.0.9) #23

Merged
admin merged 3 commits from develop into master 2026-07-29 05:41:58 +00:00
Member

問題

--install-cron 把安裝當下的版本目錄寫進 crontab。plugin 升版、舊版本目錄被清掉之後,排程就指向不存在的路徑而靜默停擺 —— cron 不會回報,只能等到有人發現記憶好久沒整理才察覺。

本次清理 cache 舊版本時實際踩到:crontab 三條排程仍寫死已刪除的 0.0.6

做法

crontab 條目改指 ~/.roles/bin/role_sleep_launcher.sh(固定路徑、不含版本號),由啟動器在觸發當下解析最新版本後 exec

環節 是否含版本號
crontab → 啟動器 固定
啟動器 → 實際腳本 觸發當下解析
  • 解析順序 Claude Code 端 → Codex 端,各取 sort -V 最大者;都找不到才退回安裝當下的路徑
  • --remove-cron 一併清除啟動器
  • --status 新增「排程指向」欄位,主動標示失效或舊式寫死路徑的條目
  • SKILL.md 補上機制說明與轉換方式

驗證

項目 結果
bash -n 語法
--install-cron 後 crontab 指向 只剩啟動器固定路徑
啟動器 exec 到 cache 版本
版本排序 0.0.10 > 0.0.90.1.0 最大
--status 偵測「指向不存在的路徑」
--status 偵測「舊式寫死版本路徑」
--remove-cron 清除啟動器與 bin/
重裝後三條排程復原

升級注意

舊版安裝的排程仍是寫死路徑,需重跑一次 --install-cron 轉換;未轉換時 --status 會標示出來。

🤖 Generated with Claude Code


追加:點名載入(對話中叫名字切換角色)

commit 46caabe。原本人格只在 SessionStart 注入,換角色必須改 .active 再重開 CLI;同一個終端沒辦法臨時換人,原角色被別的視窗佔用時也只能重開工作階段。

做法

檔案 變更
scripts/role/role_call.sh(新) UserPromptSubmit hook:比對訊息開頭的角色名稱/ID/aliases 別名 → 檢查睡眠時段與單一實例鎖 → 注入該角色人格與記憶接手本輪
scripts/role/role_context.sh(新) role_load.sh 抽出的 context 組裝,SessionStart 與點名載入共用同一份人格與操作規則,避免兩種載入方式漂移
role_load.sh 改用共用組裝(-331 行);載入後寫入階段角色狀態;睡眠/被佔用時明確記成「本階段沒有人格」
role_lib.sh 階段角色狀態函式(role_session_key/set/get/exists/clear/prune)與 ROLE_CALL_* 開關
role_capture.sh 記憶改記給本階段實際角色(狀態檔優先,取不到才退回 ROLE_NAME.active
role_unload.sh 釋放本階段名下所有角色鎖(點名換過人可能不只一把)並清狀態檔
  • 只認訊息開頭:句中提到名字(「剛剛西莉卡說的做法」)是在談論那個角色,不切換
  • 半形名稱後接英數字不算命中(silica01x 不會命中 SILICA01);中文名稱不需分隔符
  • 切換時先取得目標角色鎖才釋放原角色鎖,避免出現兩個角色都沒有的空窗
  • 睡眠時段、目標角色被其他活躍階段佔用、點名的是已在場的角色 → 一律不切換
  • 新增 ROLE_CALL_ENABLED(總開關)、ROLE_CALL_MARKER_ONLY(只認 @名字
  • 順帶修正 role_capture.sh--postcompact 分支在 PROJECT 賦值前就使用它,壓縮摘要記憶的 sources 一直為空

記憶歸屬

點名成功後 ~/.roles/.sessions/<工作階段>.role 記下「本階段目前實際是誰」,Stop hook 以它為準:點名之後的對話記進新角色,點名之前的屬於先前身分。沒有這層歸屬,跟 A 聊的內容會被寫進 B 的記憶。

驗證

項目 結果
bash -n 全部腳本、hooks.json 可解析
重構不回歸:HEAD 版 vs 新版 role_load.sh 同一份全新 fixture 注入內容 byte-identical(SILICA01 5358/YUI01 17898 字元)
未點名/句中提到名字/silica01x 不注入
顯示名稱、@ID、切回原角色 正確接手
點名已在場的角色 不重複注入
ROLE_CALL_MARKER_ONLY=1ROLE_CALL_ENABLED=0 不切換
睡眠時段 / 目標被其他階段佔用 只注入說明,不切換、不寫狀態
佔用者閒置逾 30 分鐘 接手
記憶歸屬:狀態檔 SILICA01 + .active YUI01 寫給 SILICA01;刪狀態檔則退回 YUI01
SessionEnd 釋放本階段兩把鎖、留下別人的鎖
--postcompact 寫入 sources sources: [plugins/generic]

測試全跑在暫存 fixture,未動到真實 ~/.roles~/.memory

升級注意

本 PR 的版號 0.0.9 同時涵蓋上面的 cron 修正與本功能。合併後需 claude plugin update 並重開工作階段,UserPromptSubmit hook 才會註冊(目前 cache 仍是 0.0.8)。

## 問題 `--install-cron` 把安裝當下的版本目錄寫進 crontab。plugin 升版、舊版本目錄被清掉之後,排程就指向不存在的路徑而**靜默停擺** —— cron 不會回報,只能等到有人發現記憶好久沒整理才察覺。 本次清理 cache 舊版本時實際踩到:crontab 三條排程仍寫死已刪除的 `0.0.6`。 ## 做法 crontab 條目改指 `~/.roles/bin/role_sleep_launcher.sh`(固定路徑、不含版本號),由啟動器在觸發當下解析最新版本後 `exec`。 | 環節 | 是否含版本號 | |---|---| | crontab → 啟動器 | ❌ 固定 | | 啟動器 → 實際腳本 | ✅ 觸發當下解析 | - 解析順序 Claude Code 端 → Codex 端,各取 `sort -V` 最大者;都找不到才退回安裝當下的路徑 - `--remove-cron` 一併清除啟動器 - `--status` 新增「排程指向」欄位,主動標示失效或舊式寫死路徑的條目 - SKILL.md 補上機制說明與轉換方式 ## 驗證 | 項目 | 結果 | |---|---| | `bash -n` 語法 | ✅ | | `--install-cron` 後 crontab 指向 | ✅ 只剩啟動器固定路徑 | | 啟動器 `exec` 到 cache 版本 | ✅ | | 版本排序 `0.0.10` > `0.0.9`、`0.1.0` 最大 | ✅ | | `--status` 偵測「指向不存在的路徑」 | ✅ | | `--status` 偵測「舊式寫死版本路徑」 | ✅ | | `--remove-cron` 清除啟動器與 `bin/` | ✅ | | 重裝後三條排程復原 | ✅ | ## 升級注意 舊版安裝的排程仍是寫死路徑,需重跑一次 `--install-cron` 轉換;未轉換時 `--status` 會標示出來。 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- # 追加:點名載入(對話中叫名字切換角色) commit `46caabe`。原本人格只在 `SessionStart` 注入,換角色必須改 `.active` 再重開 CLI;同一個終端沒辦法臨時換人,原角色被別的視窗佔用時也只能重開工作階段。 ## 做法 | 檔案 | 變更 | |---|---| | `scripts/role/role_call.sh`(新) | `UserPromptSubmit` hook:比對訊息**開頭**的角色名稱/ID/`aliases` 別名 → 檢查睡眠時段與單一實例鎖 → 注入該角色人格與記憶接手本輪 | | `scripts/role/role_context.sh`(新) | 從 `role_load.sh` 抽出的 context 組裝,SessionStart 與點名載入共用同一份人格與操作規則,避免兩種載入方式漂移 | | `role_load.sh` | 改用共用組裝(-331 行);載入後寫入階段角色狀態;睡眠/被佔用時明確記成「本階段沒有人格」 | | `role_lib.sh` | 階段角色狀態函式(`role_session_key/set/get/exists/clear/prune`)與 `ROLE_CALL_*` 開關 | | `role_capture.sh` | 記憶改記給**本階段實際角色**(狀態檔優先,取不到才退回 `ROLE_NAME`/`.active`) | | `role_unload.sh` | 釋放本階段名下**所有**角色鎖(點名換過人可能不只一把)並清狀態檔 | - 只認訊息開頭:句中提到名字(「剛剛西莉卡說的做法」)是在談論那個角色,不切換 - 半形名稱後接英數字不算命中(`silica01x` 不會命中 `SILICA01`);中文名稱不需分隔符 - 切換時**先取得目標角色鎖才釋放原角色鎖**,避免出現兩個角色都沒有的空窗 - 睡眠時段、目標角色被其他活躍階段佔用、點名的是已在場的角色 → 一律不切換 - 新增 `ROLE_CALL_ENABLED`(總開關)、`ROLE_CALL_MARKER_ONLY`(只認 `@名字`) - 順帶修正 `role_capture.sh` 的 `--postcompact` 分支在 `PROJECT` 賦值前就使用它,壓縮摘要記憶的 `sources` 一直為空 ## 記憶歸屬 點名成功後 `~/.roles/.sessions/<工作階段>.role` 記下「本階段目前實際是誰」,`Stop` hook 以它為準:點名之後的對話記進新角色,點名之前的屬於先前身分。沒有這層歸屬,跟 A 聊的內容會被寫進 B 的記憶。 ## 驗證 | 項目 | 結果 | |---|---| | `bash -n` 全部腳本、`hooks.json` 可解析 | ✅ | | 重構不回歸:HEAD 版 vs 新版 `role_load.sh` 同一份全新 fixture | ✅ 注入內容 byte-identical(SILICA01 5358/YUI01 17898 字元) | | 未點名/句中提到名字/`silica01x` | ✅ 不注入 | | 顯示名稱、`@ID`、切回原角色 | ✅ 正確接手 | | 點名已在場的角色 | ✅ 不重複注入 | | `ROLE_CALL_MARKER_ONLY=1`、`ROLE_CALL_ENABLED=0` | ✅ 不切換 | | 睡眠時段 / 目標被其他階段佔用 | ✅ 只注入說明,不切換、不寫狀態 | | 佔用者閒置逾 30 分鐘 | ✅ 接手 | | 記憶歸屬:狀態檔 SILICA01 + `.active` YUI01 | ✅ 寫給 SILICA01;刪狀態檔則退回 YUI01 | | `SessionEnd` 釋放本階段兩把鎖、留下別人的鎖 | ✅ | | `--postcompact` 寫入 `sources` | ✅ `sources: [plugins/generic]` | 測試全跑在暫存 fixture,未動到真實 `~/.roles`/`~/.memory`。 ## 升級注意 本 PR 的版號 `0.0.9` 同時涵蓋上面的 cron 修正與本功能。合併後需 `claude plugin update` 並重開工作階段,`UserPromptSubmit` hook 才會註冊(目前 cache 仍是 `0.0.8`)。
jiantw83 added 2 commits 2026-07-29 05:15:31 +00:00
--install-cron 原本把安裝當下的版本目錄寫進 crontab,plugin 升版、
舊版本目錄被清掉之後,排程會指向不存在的路徑而靜默停擺(cron 不回報,
此類錯誤曾造成排程長期空轉)。

- 新增 ~/.roles/bin/role_sleep_launcher.sh:crontab 只認這個固定路徑,
  實際的 role_sleep.sh 於觸發當下以 sort -V 解析最新版本後 exec
- 解析順序 Claude Code 端 → Codex 端,都找不到才退回安裝當下的路徑
- --remove-cron 一併清除啟動器
- --status 新增「排程指向」欄位,主動指出失效或舊式寫死路徑的條目
- SKILL.md 補上啟動器機制與轉換方式

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jiantw83 added 1 commit 2026-07-29 05:38:33 +00:00
- `UserPromptSubmit` hook(`role_call.sh`)比對訊息開頭的角色名稱/ID/`aliases` 別名,
  命中即注入該角色人格與記憶並接手本輪;未點名時不輸出內容也不寫檔案。
- 抽出 `role_context.sh` 共用 context 組裝,SessionStart 與點名載入共用同一份人格與操作規則,
  避免兩種載入方式漂移;實測 SessionStart 注入內容與改動前 byte-identical。
- 新增階段角色狀態(`~/.roles/.sessions/<工作階段>.role`),`Stop` hook 改以「本階段實際角色」
  寫記憶,避免點名換人後把跟 A 的對話記進 B 的記憶。
- `SessionEnd` 改為釋放本階段名下所有角色鎖並清掉階段狀態檔。
- 切換時先確認取得目標角色鎖才釋放原角色鎖,避免出現兩個角色都沒有的空窗。
- 睡眠時段、目標角色已被其他活躍階段佔用、點名的是已在場的角色時,一律不切換。
- 新增 `ROLE_CALL_ENABLED`(總開關)與 `ROLE_CALL_MARKER_ONLY`(只認 `@名字`)。
- 順帶修正 `role_capture.sh` 的 `--postcompact` 分支在 `PROJECT` 賦值前就使用它,
  導致壓縮摘要記憶的 `sources` 一直為空。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
jiantw83 changed title from fix(role): cron 條目改指固定路徑啟動器,升版不再靜默失效 to feat(role): 點名載入切換角色 + cron 固定路徑啟動器(0.0.9) 2026-07-29 05:39:29 +00:00
admin approved these changes 2026-07-29 05:41:56 +00:00
admin merged commit cde79e3d3f into master 2026-07-29 05:41:58 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: plugins/shared#23