feat: 人格編號(ASUNA-01)與 Gitea 儲存,依更新頻率分檔案區/Wiki 區
1. 人格編號
- 編號 = 英文名全大寫 + 兩位索引,同名才遞增:ASUNA-01 / YUI-01 / ASUNA-02。
- 編號同時是新人格的本機目錄名與 Gitea 存取庫名稱(`create` 不給
--persona 就用編號當目錄名;既有小寫 slug 仍然合法,不會被鎖在門外)。
- 中文名由 skill 提議羅馬拼音、使用者確認後帶 `--romaji` 進來;
CLI 只吃拉丁字母,避免拼音在程式裡亂猜。
- 新增 `code show|assign|next`;`code assign --rename` 可把既有人格的
目錄名一併改成編號(會轉移鎖與 session 綁定)。
2. Gitea 儲存(scripts/persona-gitea.mjs)
- 每個人格一個私有存取庫,庫名 = 編號。本機仍是工作副本,hook 每輪
讀寫本機檔案,**同步失敗永遠不阻斷對話**。
- 依更新頻率分區:
檔案區(高頻)emotion / short-term / inner / said / inbox /
mindmap threads / journal → 每輪由 Stop hook 背景 push
Wiki 區(低頻)IDENTITY SOUL AGENTS USER / 長期記憶 / INDEX /
心智圖 / 關係圖 → 固化、改身分關係、release 時 push
- Gitea 的 wiki 只有根目錄 .md 會變成頁面(1.27 實測子目錄頁面 404),
所以 Wiki 區攤平成 `Memory-xxx.md`,原始路徑記在 `_paths.json`,
pull 時還原;Home 頁自動列出所有長期記憶連結。
- 新增 `sync status|init|push|pull`;載入時先 pull,兩邊都改過同一個
檔案就停下來不覆蓋本機,交由使用者決定。
- push 遇到 non-fast-forward 會對齊遠端後把工作副本重新疊上去再推。
- 認證走 http.extraHeader(GIT_CONFIG_* 環境變數),token 不寫進
.git/config 也不進 process 參數。
3. 順帶修正
- guard 的 `--persona` 解析原本只吃小寫,大寫編號會漏掉整個跨人格檢查。
- pull 原本會無差別覆蓋本機檔案,本機較新但還沒 push 的內容會被蓋掉;
改成只寫回「遠端真的改過的」與「本機缺少的」。
- `create` 原本吞掉 Gitea 首次推送的結果,失敗是靜默的。
新增 skill:persona-sync(編號、同步、既有人格遷移、衝突處理)。
selftest 116 項全綠(新增 ⑬,含「分區不重不漏」檢查;測試強制 PERSONA_GITEA=off)。
另對真實 Gitea 跑過端對端(建庫→兩區推送→改動→拉回→release),測試用存取庫已刪除。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
---
|
||||
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`、長期記憶、`INDEX`、心智圖、人際關係圖 | 記憶固化、改身分、改關係圖、`release` 時 |
|
||||
|
||||
Wiki 是給人讀的設定百科:Gitea 的 wiki 只有根目錄的 `.md` 會變成頁面,所以
|
||||
`memory/long-term/xxx.md` 會攤平成 `Memory-xxx.md`(頁面顯示為「Memory xxx」),
|
||||
原始路徑記在 `_paths.json`,拉回來時自動還原。Home 頁會自動列出所有長期記憶的連結。
|
||||
|
||||
**本機永遠是工作副本**:hook 每輪讀寫的是本機檔案,不經過網路。Gitea 掛掉、離線、沒設 token,
|
||||
人格照樣能聊天,只是不同步——**同步失敗永遠不阻斷對話**。
|
||||
|
||||
## 設定
|
||||
|
||||
```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. **不要自己選**。記憶被蓋掉是不可逆的。
|
||||
|
||||
## 邊界
|
||||
|
||||
- 只能同步「本 session 目前載入的人格」——跨人格同步等於跨人格讀取,會被 hook 擋下。
|
||||
- guest(`persona-guest` sub agent)不能同步,它對人格檔案唯讀。
|
||||
- `.sync/` 是兩區的 git clone 快取,**不要手動編輯**;砍掉它不會掉資料,下次 push 會重新 clone。
|
||||
- 所有面向使用者的輸出使用**繁體中文(台灣用語)**、UTF-8 無亂碼。
|
||||
Reference in New Issue
Block a user