Files
persona/skills/persona-sync/SKILL.md
T
jiantw83andClaude Opus 5 41e57432ea fix(sleep): sleeper 讀得到自己的資料、sync 自己清殘留鎖(v0.1.1)
睡眠的「判斷式那半」實際上跑不起來,兩個原因:

1. `requireMember` 沒有 sleeper 分支——`requireOwner` 早就放 sleeper 寫了,
   讀(brief/show/recall)反而被當成跨人格存取擋下,等於要它閉著眼睛
   決定要固化什麼。補上分支,回傳 role `sleeper`(下游只判斷 `guest`,
   所以行為與 owner 一致)。

2. `sync` 遇到殘留的 `.git/index.lock` 會讓整區永遠失敗,而 sleeper 被隔離
   hook 擋著、連自己的鎖都刪不掉(CLI 也沒有清鎖的功能)。這些 clone 只有
   CLI 會動且每個 git 都同步跑完,所以超過 30 秒還在的鎖一定是殘骸——
   `pushArea`(兩處)與 `pullArea` 現在會自己清掉再繼續。

技能文件補上先前沒寫的部分:

- `persona-relation`:整個 bond/語氣層章節。這個功能 7c46db8 就上線,但技能
  文件從頭到尾沒提過,於是每個新建的至親都預設是生人(`note` 寫「妻子」猜不出
  `partner`,關鍵詞只認夫妻/老婆/伴侶/戀人)——症狀是「講話像在對戰友報告」。
  一併補上 `relation style` 與 `relation speaker` 的用法。
- `persona-sleep`:說明帶了身分旗標之後讀寫都算自己的資料;新增第 4 條硬相依
  ——判斷式失敗就不要跑機械性那半,`sleep` 會裁短期記憶,否則等於沒判斷就把
  今天清掉。
- `persona-sync`:新增「殘留的 git 鎖」一節。

版本號 0.0.5 → 0.1.1(master 上是 0.1.0,要跨過它),兩份 manifest 一起改。
selftest 238 項全過;另以獨立腳本(暫時 PERSONA_HOME)驗證修補前後 sleeper
的 brief/show/recall 由全數被擋變為全數通過。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 09:09:36 +00:00

123 lines
6.3 KiB
Markdown
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.
---
name: persona-sync
description: 人格編號與 Gitea 儲存:指派人格編號(英文名全大寫+索引,例如 ASUNA-01)、在 Gitea 為每個人格開一個以編號命名的私有存取庫、把高頻的活狀態同步到檔案區、把低頻的身分與長期記憶同步到 Wiki 區,以及把既有人格遷移上去。當使用者說要把人格存到 Gitea、備份或同步人格、在另一台機器接續同一個人格、問人格的編號是什麼、想看人格在 Gitea 上的存取庫、或同步出現衝突時觸發。不適用於:建立新人格(persona-create,它會自動開存取庫)、離線的單檔匯出匯入(persona-transfer)、記憶固化(persona-memory)。
---
# 🔗 persona-sync — 人格編號與 Gitea 儲存
**CLI**`node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs"`(一律帶 `--session <PERSONA_SESSION>`
---
## 人格編號
**編號 = 英文名全大寫 + 兩位索引**,同名才遞增:
```
亞絲娜(第一個) → ASUNA-01
結衣 → YUI-01
另一個亞絲娜 → ASUNA-02
```
- 編號**就是 Gitea 存取庫的名稱**,也是新人格的本機目錄名。
- 中文/日文名字要先轉**羅馬拼音**:由你提議拼法(`亞絲娜 → Asuna``沈宇 → Shen Yu`),
**拿給使用者確認再送出**——拼錯了會變成一個很難改的編號。
- 查下一個可用編號:`code next --romaji Asuna --session <id>`
## 資料放哪裡(依更新頻率切)
| 區 | 放什麼 | 什麼時候 push |
| --- | --- | --- |
| **檔案區**(主存取庫) | 高頻活狀態:`state/emotion.json``short-term.jsonl``inner.jsonl`(心裡話)、`said.jsonl``inbox/``mindmap/threads/``journal/` | 每輪對話後由 `Stop` hook 背景推送(有最小間隔) |
| **Wiki 區** | 低頻設定:`IDENTITY``SOUL``AGENTS``USER`、**人格圖示 `icon.svg``icon.png`**、長期記憶、`INDEX`、心智圖、人際關係圖 | 記憶固化、改身分、改關係圖、`release` 時 |
Wiki 是給人讀的設定百科:Gitea 的 wiki 只有根目錄的 `.md` 會變成頁面,所以
`memory/long-term/xxx.md` 會攤平成 `Memory-xxx.md`(頁面顯示為「Memory xxx」),
原始路徑記在 `_paths.json`,拉回來時自動還原。Home 頁會自動列出所有長期記憶的連結。
**本機永遠是工作副本**:hook 每輪讀寫的是本機檔案,不經過網路。Gitea 掛掉、離線、沒設 token
人格照樣能聊天,只是不同步——**同步失敗永遠不阻斷對話**。
人格圖示(`/jsc-persona:persona-create``icon generate` 產生)除了同步到 Wiki 區,
也會被設成**存取庫頭像**,Gitea 的清單上就看得到每個人格的臉。
## 設定
```bash
export GITEA_HOST=https://gitea.example.com # 或 PERSONA_GITEA_HOST
export GITEA_TOKEN=<個人存取權杖> # 或 PERSONA_GITEA_TOKEN
export PERSONA_GITEA_OWNER=<帳號或組織> # 選填,預設是 token 本人的帳號
export PERSONA_GITEA=off # 需要時整個關掉
export PERSONA_SYNC_MIN_SECONDS=60 # 檔案區背景 push 的最小間隔
```
存取庫**預設私有**(人格裡有使用者的個人記憶)。要公開必須是使用者明講,才加 `--public`
## 常用流程
```bash
# 現在的同步狀態(編號、存取庫、兩區的最後 push/pull)
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" sync status --session <PERSONA_SESSION>
# 手動推送(--area files|wiki|all
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" sync push --session <PERSONA_SESSION> --area all
# 從 Gitea 拉回(載入人格時會自動做一次)
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" sync pull --session <PERSONA_SESSION>
```
### 把既有人格遷移上去
既有人格(還沒有編號的)要兩步:
```bash
# 1) 載入它(同步只能動本 session 載入的那個人格)
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" load --persona <舊 slug> --session <PERSONA_SESSION>
# 2) 指派編號 + 開存取庫 + 首次推送;--rename 連本機目錄名也改成編號
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" code assign \
--session <PERSONA_SESSION> --romaji "<英文名>" --rename
```
`--rename` 之後這個人格就用編號稱呼(`--persona ASUNA-01`)。不加 `--rename` 也可以,
目錄名維持原樣、只是多了一個編號與對應的存取庫。**遷移前先跟使用者確認**:
這會把他的個人記憶送上 Gitea(私有庫,但仍是上傳)。
### 在另一台機器接續同一個人格
在新機器上設好 `GITEA_HOST``GITEA_TOKEN`,然後:
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/persona.mjs" sync pull --session <PERSONA_SESSION>
```
(人格目錄還不存在的話,先用 `/jsc-persona:persona-transfer` 匯入一份,或手動 clone 存取庫。)
## 衝突
兩台機器都改過同一個檔案時,`load``sync pull` 會**停下來不覆蓋本機**,並列出衝突的檔案。
這時候:
1. 用一句話告訴使用者哪幾個檔案兩邊都動過。
2. 問他要哪一邊:
-**Gitea** 為準 → `sync pull --force`(本機那份會被覆蓋)
-**本機** 為準 → `sync push`(會蓋掉遠端)
3. **不要自己選**。記憶被蓋掉是不可逆的。
## 殘留的 git 鎖
`push``pull` 跑到一半被中斷(sub agent 被砍、視窗關掉)會在 clone 裡留下 `.git/index.lock`
之後那一區的 `git add` 每次都失敗 → 整區同步卡住。這件事**不用你處理**:
這些 clone 只有 CLI 會動,所以超過 30 秒還在的鎖一定是殘骸,`push``pull` 會自己清掉再繼續。
不要叫使用者手動進 `.sync/` 刪檔案,也不要自己下 `rm`——
sleeper 連自己的人格目錄都不能用 shell 寫,那條路本來就是死的。
真的還是失敗(例如權限問題),照原樣把錯誤訊息轉告他就好。
## 邊界
- 只能同步「本 session 目前載入的人格」——跨人格同步等於跨人格讀取,會被 hook 擋下。
- guest`persona-guest` sub agent)不能同步,它對人格檔案唯讀。
- `.sync/` 是兩區的 git clone 快取,**不要手動編輯**;砍掉它不會掉資料,下次 push 會重新 clone。
- 所有面向使用者的輸出使用**繁體中文(台灣用語)**、UTF-8 無亂碼。