cortico-world-archivist 0.0.0-stage → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/LICENSE +21 -0
- package/README.md +114 -2
- package/describe.json +4 -0
- package/package.json +51 -4
- package/src/backup.js +458 -0
- package/src/config.js +433 -0
- package/src/index.js +17 -0
- package/src/log.js +74 -0
- package/src/restore.js +436 -0
- package/src/world.js +302 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.3.4 — 2026-11-15
|
|
4
|
+
|
|
5
|
+
修两个会真出事的问题,其中一个来自市场维护者 Pal AI Lab 的反馈。
|
|
6
|
+
|
|
7
|
+
**备份不再把自己打进去(市场反馈)**
|
|
8
|
+
|
|
9
|
+
- 存放位置默认改到**部署目录**下的 `archivist/`,不再放在 `data/archivist`。`data/` 会被「扩展数据」整目录扫描,放在里面等于每份新备份都把之前的 zip 一起打包——zip 本身已经压过,再压一次几乎不变小,单份体积就逐次接近翻倍,最后吃掉整个磁盘或让 `Compress-Archive` 失败。
|
|
10
|
+
- 就算用户自己把存放位置指回 `data/` 里,也不会再自我打包:判定按**绝对路径**做,存放位置和它下面的 `before-restore-*` 一律跳过,也不再进恢复前快照、不被恢复覆盖。
|
|
11
|
+
- 老部署的兼容:如果 `<data>/archivist` 里已经有旧包,继续用老位置。突然换地方会让「保留份数」的轮转在新目录里从零开始,旧包再也清不掉。
|
|
12
|
+
|
|
13
|
+
**恢复:说清范围,且真的能回滚(市场反馈)**
|
|
14
|
+
|
|
15
|
+
- 面板与 README 明写恢复的覆盖面:**所有扩展的数据**、**所有 World 的配置**(`config.json` 里每一个 Worlds 段,不只是本扩展)、**全部密钥**(`.env` 与 `providers/` 下所有渠道)。之前只写了「恢复会覆盖现在的数据」,太含糊。
|
|
16
|
+
- **修掉一个回滚缺口**:`before-restore-<时间>/` 原先只快照 `data/` 的顶层文件,但恢复时 `data/` 的子目录是整个覆盖的。也就是说 `data/stroll`、`data/terrarium`、`data/parlor-history` 这些目录被覆盖后**没有副本**。现在子目录、`providers/`、额外路径都进快照。
|
|
17
|
+
- 额外路径恢复回**原位**:备份时在包里记一张 `extra-map.json`(包内名字 → 原始绝对路径),恢复照它放回。之前只知道 basename,所有额外路径都会被倒在部署目录下。老备份没有这张表,退回旧行为并在结果里说明。
|
|
18
|
+
- 重名的额外路径(如两个 `data`)不再互相覆盖,自动加 `-2`、`-3` 后缀。
|
|
19
|
+
|
|
20
|
+
**备份内容更干净**
|
|
21
|
+
|
|
22
|
+
- 任意层级的浏览器 profile 一律跳过:`stroll/douyin-profile` 这类嵌在扩展自己目录里的 profile 原本整包带走(几十 MB 全是可重建的缓存,打包时还容易撞上 `EBUSY`)。`*‑profile` 后缀名一律算。
|
|
23
|
+
- `data/archivist` 加进跳过名单,作为升级路径上的兜底。
|
|
24
|
+
|
|
25
|
+
**其他**
|
|
26
|
+
|
|
27
|
+
- `package.json` 补上 `repository`(市场建议,便于以后联系)。
|
|
28
|
+
- 测试扩到 193 项,新增覆盖:自我打包、`data/` 子目录快照、额外路径往返、重名、跳过判定、Windows 大小写与路径分隔符。
|
|
29
|
+
|
|
30
|
+
## 0.3.3 — 2026-11-05
|
|
31
|
+
|
|
32
|
+
首个公开发布的版本。备份与恢复都在里面。
|
|
33
|
+
|
|
34
|
+
**备份**
|
|
35
|
+
|
|
36
|
+
- 按间隔自动备份(默认 24 小时),启动时若已超期立刻补一次
|
|
37
|
+
- 滚动保留(默认 14 份),超出自动删最老的
|
|
38
|
+
- 五项可勾:工作区全部 / 工作区 git 历史 / 工作区附件(blobs) / 扩展数据 / 配置与密钥
|
|
39
|
+
- 「扩展数据」自动扫描 `data/`,装了什么扩展就备份什么,只跳过可重建的运行态与缓存
|
|
40
|
+
- 额外路径补漏、可选连带扩展包
|
|
41
|
+
- 打包前先复制到临时目录再压缩,避免打到写了一半的文件
|
|
42
|
+
- 每份 zip 带 `MANIFEST.md`,写明内容与手工恢复步骤
|
|
43
|
+
|
|
44
|
+
**恢复**
|
|
45
|
+
|
|
46
|
+
- 解压到临时目录 → 校验 `MANIFEST.md` → 快照当前状态到 `before-restore-<时间>/` → 才覆盖
|
|
47
|
+
- 恢复范围复用备份那份勾选
|
|
48
|
+
- 需要输入确认口令 `RESTORE`(或「恢复」)才会动作,输错则一个文件都不碰
|
|
49
|
+
- 恢复后等 3 秒复查:若有扩展把内存里的旧数据写回磁盘,结果里直接说明「这次恢复对它们无效,请完全退出 Coopanion 后重做」
|
|
50
|
+
- 跨平台:Windows 的 `Compress-Archive` 把条目名写成 `\`,解开后就地修正为目录结构(`..` 一并过滤)
|
|
51
|
+
|
|
52
|
+
**其他**
|
|
53
|
+
|
|
54
|
+
- 零上下文成本:`envPromptVars()` 返回 `null`、`tools()` 返回 `[]`,不占前缀、不进工具表
|
|
55
|
+
- 日志写到 `<存放位置>/archivist.log`(`WorldContext` 没有 `log` 通道,所以自己写)
|
|
56
|
+
- 配置项的源 id 改名后自动迁移,缺的源按默认值补齐
|
|
57
|
+
- 中英双语界面文案
|
|
58
|
+
|
|
59
|
+
## 0.1.0 – 0.3.2
|
|
60
|
+
|
|
61
|
+
未公开的本地迭代版本。0.3.3 之前的编号只在作者本机存在。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 cortico-world-archivist contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,115 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 备份与恢复 / Backup & Restore
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
给 [Coopanion](https://github.com/Pal-AI-Lab) 用的 World 扩展(包名 `cortico-world-archivist`,配置段 `worlds.archivist`):**定期备份 + 一键恢复**。
|
|
4
|
+
|
|
5
|
+
她的长期记忆散在三个地方——`workspace/`(画像、自述、日记、笔记、交接档案)、`data/*.json`(事实库、向量索引、档案、反思、画像卡)、`config.json` + `.env` + `providers/`(配置与密钥)。这个扩展把三处打成一个 zip,滚动保留若干份;要回退时从任意一份放回去。
|
|
6
|
+
|
|
7
|
+
> ⚠️ **这三处说的是「备份打些什么」,不是「恢复碰些什么」。**
|
|
8
|
+
> 恢复的覆盖面大得多,见下面[恢复](#恢复)一节——它会覆盖**所有扩展的数据**、**所有 World 的配置**和**全部密钥**。
|
|
9
|
+
|
|
10
|
+
**零上下文成本**:不进系统前缀(`envPromptVars()` 返回 `null`)、不注册任何工具(`tools()` 返回 `[]`)。它只在后台跑,不吃 token。
|
|
11
|
+
|
|
12
|
+
## 装
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
pnpm add cortico-world-archivist # 或在扩展市场里装
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
装完重启 Coopanion,在「世界」页启用「归档」,再打开它的配置页。
|
|
19
|
+
|
|
20
|
+
## 备份
|
|
21
|
+
|
|
22
|
+
| 配置项 | 说明 |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| 备份间隔 | 多久一次(小时)。进程重启后会检查是否超期,超了就立刻补一次 |
|
|
25
|
+
| 保留份数 | 滚动保留。超过就删最老的 |
|
|
26
|
+
| 存放位置 | zip 放哪。留空 = **部署目录**下的 `archivist/`(在 `data/` 之外,不会被下一次备份打包进去)。**建议放到另一块硬盘或网盘同步目录** |
|
|
27
|
+
| 备份内容 | 五项可勾:工作区全部 / git 历史 / blobs 附件 / 扩展数据 / 配置与密钥 |
|
|
28
|
+
| 连带扩展包 | 把 `extensions/` 也打包。几十 MB,一般不用 |
|
|
29
|
+
| 额外要备份的路径 | 一行一个。给那些把数据放在子目录、或装在别处的扩展补漏 |
|
|
30
|
+
| 立即备份一次 | 拨到开 → 一分钟内开始,做完自动关回去 |
|
|
31
|
+
|
|
32
|
+
**存放位置绝不能落在 `data/` 里。** 「扩展数据」会整目录扫描 `data/`,把备份目录放在那里等于每一份新 zip 都把之前的 zip 一起打包——zip 已经压过,再压一次几乎不变小,单份体积逐次接近翻倍,几天就能吃掉整块盘,或者让 `Compress-Archive` 因为单文件过大而失败。
|
|
33
|
+
|
|
34
|
+
即使你手动把它指回 `data/` 里,扩展也不会自我打包:判定按绝对路径做,存放位置与它下面的 `before-restore-*` 在备份、快照、恢复三处都被排除。老版本升级上来的部署如果 `<data>/archivist` 里已经有旧包,会继续用老位置(否则轮转在新目录里从零开始,旧包再也清不掉)。
|
|
35
|
+
|
|
36
|
+
「扩展数据」是**自动扫描** `data/` 目录的:装了什么扩展就备份什么,不用手动配。只跳过明确可重建的东西(运行态 JSON、缓存、`session-main.jsonl` 这类流水、任意层级的浏览器 profile,以及 `media/`、`figures/`、`emoji/` 这些几十上百 MB 的素材目录)。判定标准写在 `src/config.js` 的 `DATA_SKIP` / `DATA_SKIP_DIRS` / `DATA_SKIP_ANY_DIR` 里,附了每一条的理由。
|
|
37
|
+
|
|
38
|
+
一份真实部署(9 MB 工作区 + 13 MB 记忆数据)打包后约 **15 MB,4~5 秒**。
|
|
39
|
+
|
|
40
|
+
## 恢复
|
|
41
|
+
|
|
42
|
+
> ### ⚠️ 恢复的覆盖面
|
|
43
|
+
>
|
|
44
|
+
> 恢复**不只是把「她的记忆」放回去**。它按备份里的内容原样写回原位,所以实际覆盖的是:
|
|
45
|
+
>
|
|
46
|
+
> | 覆盖什么 | 具体是 |
|
|
47
|
+
> | --- | --- |
|
|
48
|
+
> | **所有扩展的数据** | `data/` 下**每一个**扩展存的东西:记忆库、事实库、向量索引、档案、卡片、表情包索引、词汇本……不只是本扩展或记忆类扩展 |
|
|
49
|
+
> | **所有 World 的配置** | `config.json` 里的**每一个 Worlds 段**(桌面宠物、QQ、语音、社交、做梦、画画……),不只是 `worlds.archivist` |
|
|
50
|
+
> | **全部密钥** | `.env` 与 `providers/` 下所有模型渠道的 Key 和地址 |
|
|
51
|
+
>
|
|
52
|
+
> 备份之后的**新文件不会被删除**(只覆盖、不删除),但**已有文件会被换成备份时的版本**。文件被覆盖前会先存到 `before-restore-<时间>/`,见下面第 3 步。
|
|
53
|
+
|
|
54
|
+
恢复默认**只用于灾难恢复**,所以设了两道闸:
|
|
55
|
+
|
|
56
|
+
1. **确认口令**:必须先输入 `RESTORE`(或「恢复」),否则「立即恢复」开关不动。
|
|
57
|
+
2. **先留存再覆盖**:恢复前把当前状态复制到 `<存放位置>/before-restore-<时间>/`,后悔了还能拿回来。
|
|
58
|
+
|
|
59
|
+
流程是固定的四步,顺序不能颠倒:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
① 解压到临时目录 —— 不碰真实数据
|
|
63
|
+
② 校验 MANIFEST.md —— 不是本扩展的包直接拒绝
|
|
64
|
+
③ 快照当前状态 —— before-restore-<时间>/
|
|
65
|
+
④ 才复制覆盖
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
第 ③ 步快照的范围与第 ④ 步覆盖的范围**一一对应**:`workspace/` 的各个子项、`data/` 的顶层数据文件**和每个会被整包覆盖的子目录**、`config.json` / `.env` / `providers/`、以及额外路径(存在快照的 `extra/` 下,按包内名字对应)。所以任何一个被恢复覆盖的位置都拿得回来。
|
|
69
|
+
|
|
70
|
+
**恢复完必须重启 Coopanion。** 记忆类扩展(如 memory-extra)把数据缓存在内存里、每 2 秒全量 flush 一次,不重启会被旧内存写回去。`workspace/*.md` 是每次现读的,会立刻生效。
|
|
71
|
+
|
|
72
|
+
所以恢复完会再等 3 秒复查一遍:如果 `data/` 里的文件在恢复后立刻被改写(内容变了,不只是时间戳),说明进程正把旧数据写回磁盘,这时结果里会直接说「这次恢复对它们无效,请完全退出 Coopanion 后重新恢复」,而不是留下一个看起来成功的假象。
|
|
73
|
+
|
|
74
|
+
恢复与备份共用「备份内容」那份勾选:备份时打包哪些,恢复时就放回哪些。
|
|
75
|
+
|
|
76
|
+
只覆盖、不删除:备份之后新写出来的文件不会被删掉。
|
|
77
|
+
|
|
78
|
+
跨平台:Windows 的 `Compress-Archive` 会把条目名写成 `data\fact-store.json`(zip 规范要求 `/`)。Windows 自己解压没问题,但拿到 macOS/Linux 上会变成一堆名字里带反斜杠的平铺文件。所以解压后会就地修正这类条目名,`..` 一并过滤掉。
|
|
79
|
+
|
|
80
|
+
### 老配置自动迁移
|
|
81
|
+
|
|
82
|
+
配置里的源 id 改过名(早期版本叫 `memory`,现在是 `data`)。构造时会自动改名、补齐缺的源、删掉多余的键,并写回一次配置——否则面板读到 `undefined` 会把勾选框画成「没勾」,一保存就真的把那一类数据关掉了。迁移只在真的需要时才写盘。
|
|
83
|
+
|
|
84
|
+
## 日志
|
|
85
|
+
|
|
86
|
+
`<存放位置>/archivist.log`,一行一条,带 ISO 时间和级别:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
2026-11-05T10:01:24.742Z INFO 开始备份(启动补备份)
|
|
90
|
+
2026-11-05T10:01:28.733Z INFO 备份完成 E:\Coopanion-Archive\archivist-2026-11-05T18-01-21.zip(15.4 MB,3960 ms)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
和 zip 放在一起,出了问题直接把这个文件发出来就行。超过 512 KB 会截断到后一半(这不是审计日志)。
|
|
94
|
+
|
|
95
|
+
`WorldContext` 没有 `log` 字段(api 6 只给 `cfg` / `botDir` / `dataDir` / `persist` 这些),所以在扩展里写 `ctx.log?.info?.(...)` 是**空转**——这也是为什么它自己写文件,而不是指望框架的日志。
|
|
96
|
+
|
|
97
|
+
## 已知限制
|
|
98
|
+
|
|
99
|
+
- zip 打包和解压调系统能力(Windows 用 `Compress-Archive` / `Expand-Archive`,macOS/Linux 用 `zip` / `unzip`),不引第三方依赖,所以打包时源文件被并发改写可能进包失败——这也是先复制到临时目录再压缩的原因。
|
|
100
|
+
- 恢复 `config.json` 会连 `worlds.archivist` 这一段一起还原,包括当时的「存放位置」。如果你改过存放位置,恢复后它也会变回去。
|
|
101
|
+
- 快照与备份都会跳过浏览器 profile(`*‑profile`),所以这些缓存不在回滚范围内——它们本来也能重建。
|
|
102
|
+
- 恢复**只覆盖、不删除**:备份之后新写出来的文件会留在原地,不会因为你回退到旧备份而消失。
|
|
103
|
+
- 不做增量备份,每次都是全量。这样单份 zip 自包含,恢复时不用找链条。
|
|
104
|
+
|
|
105
|
+
## 开发
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
node --check src/index.js # 语法
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`src/` 四个文件:`index.js`(导出 World 定义)、`world.js`(生命周期、定时器、面板开关兑现)、`config.js`(默认值 + JSON Schema 表单 + 跳过名单)、`backup.js` / `restore.js`(两个执行器)。
|
|
112
|
+
|
|
113
|
+
配置表单走 `webUi().config`(纯 JSON Schema,WebUI 直接渲染),不走 `webUi().panels`——后者需要预先构建 `cortico.webUiClient` 产物。
|
|
114
|
+
|
|
115
|
+
MIT。
|
package/describe.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cortico-world-archivist",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.3.4",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "g_zone"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/z-o-n-e/cortico-world-archivist.git"
|
|
11
|
+
},
|
|
12
|
+
"description": "备份与恢复 —— 定期把她的工作区、记忆数据和配置打包成 zip,滚动保留若干份;需要时一键恢复(恢复前自动留存当前状态)。零上下文成本:不进系统前缀、不占工具表。",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"os": [
|
|
15
|
+
"win32",
|
|
16
|
+
"darwin",
|
|
17
|
+
"linux"
|
|
18
|
+
],
|
|
19
|
+
"main": "./src/index.js",
|
|
20
|
+
"files": [
|
|
21
|
+
"src",
|
|
22
|
+
"describe.json",
|
|
23
|
+
"README.md",
|
|
24
|
+
"CHANGELOG.md"
|
|
25
|
+
],
|
|
26
|
+
"keywords": [
|
|
27
|
+
"cortico-world",
|
|
28
|
+
"cortico",
|
|
29
|
+
"coopanion",
|
|
30
|
+
"backup",
|
|
31
|
+
"restore",
|
|
32
|
+
"archive"
|
|
33
|
+
],
|
|
34
|
+
"cortico": {
|
|
35
|
+
"kind": "world",
|
|
36
|
+
"api": 6,
|
|
37
|
+
"displayName": "备份与恢复",
|
|
38
|
+
"tags": [
|
|
39
|
+
"diagnostics"
|
|
40
|
+
],
|
|
41
|
+
"locales": {
|
|
42
|
+
"zh": {
|
|
43
|
+
"displayName": "备份与恢复",
|
|
44
|
+
"description": "定期把她的一切打包成 zip:工作区(画像/自述/日记/笔记/交接档案)、记忆数据(事实库/向量索引/档案/反思)、配置与密钥。滚动保留若干份,自动清理旧的;需要时从任意一份恢复,恢复前先给当前状态留备份。不占系统前缀,不进工具表。"
|
|
45
|
+
},
|
|
46
|
+
"en": {
|
|
47
|
+
"displayName": "Backup & Restore",
|
|
48
|
+
"description": "Zip everything about her on a schedule: workspace (persona, diary, notes, handoffs), memory data, and config. Rolling retention with automatic cleanup, plus one-click restore that snapshots the current state first. Costs no prefix space and adds no tools."
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"describe": "describe.json"
|
|
52
|
+
}
|
|
53
|
+
}
|