--- summary: "共享状态压缩加上目标会话 SQLite 检查、导入和恢复" title: "SQLite 维护和会话迁移" read_when: - "您正在压缩或验证 OpenClaw SQLite 数据库" - "您正在导入、验证或恢复旧会话历史记录" --- 显式 SQLite 维护离线运行,网关停止。本页介绍共享状态压缩和目标会话 SQLite 模式。 SQLite 使通过删除而释放的页面可在数据库文件内重用。使用 `auto_vacuum=NONE` 创建的较旧数据库无法通过 OpenClaw 的例行增量回收来释放这些页面。普通的 `VACUUM` 会缩小文件一次,但保持该模式不变。在网关停止的情况下使用下面匹配的 Doctor `compact` 命令:它还启用 `auto_vacuum=INCREMENTAL`,因此日常维护可以回收以后删除的页面。压缩保留保留的数据;它不会更改会话或记录保留设置。 现在,在 Doctor 完成架构修复后,正常更新会对现有共享状态和代理数据库执行一次此转换,而维护仍然拥有已停止的网关。已使用 `FULL` 或 `INCREMENTAL` 的数据库将被保留。转换需要临时磁盘空间,并且会增加大型数据库的维护时间。可用空间不足或无法测量、不安全的文件别名以及活动的 SQLite 读取器会使用匹配的手动命令推迟此可选清理。失败的完整性检查或未经验证的转换会使更新失败,而不是针对不确定的状态重新启动。 自动检查会保守地测量可能的 SQLite 临时卷。未使用的后备卷上的空间过低或无法测量也可能会延迟转换,因为运行时无法可靠地报告 SQLite 选定的临时目录。此延迟不会停止正常更新;检查可用空间后使用报告的离线Doctor命令。 转换后,正常的有界增量回收可以返回稍后删除释放的页面。它不会重新打包部分填充的页面,因此在大型清理操作后显式离线压缩仍然有用。 在 Linux 上,已停止的网关服务在其 systemd cgroup 中仍可以有子进程。医生和更新维护保持阻塞状态,直到这些进程退出。检查服务状态和日志,并让流程所有者在重试之前停止剩余的子进程。即使网关本身作为用户服务运行,根拥有的子进程也可能需要管理员帮助。 ## 共享状态 SQLite 压缩 请参阅 [数据库模式](/reference/database-schemas) 以了解 schema 版本控制、完整性检查和降级恢复。 `openclaw doctor --state-sqlite compact` 是对 `/state/openclaw.sqlite` 共享状态数据库的显式离线维护。它不接受任意数据库路径,不会被正常网关操作调用,并且不是 `openclaw doctor --fix` 的一部分。该命令获取与网关启动相同的状态所有权锁,并通过验证、检查点、`VACUUM` 和最终完整性检查来保持它。当网关或另一个 SQLite 维护命令拥有该锁时,它拒绝运行。当 `OPENCLAW_ALLOW_MULTI_GATEWAY=1` 跳过每个配置的网关单例时,状态锁保持活动状态,因此操作员 shell 不需要继承网关服务的环境来进行维护以检测它。 请先停止 Gateway 并创建已验证的备份: ```bash openclaw gateway stop openclaw backup create --verify openclaw doctor --state-sqlite compact --json openclaw gateway start ``` 该命令: 1. 需要共享状态路径上的常规文件。丢失的数据库报告为 `skipped` 并成功退出。 2. 在 checkpoint 或修改文件之前,验证当前受支持的 schema 版本以及 `schema_meta.role = "global"`。 3. 要求非忙碌状态下的 `wal_checkpoint(TRUNCATE)`。如果 checkpoint 忙碌,请停止任何仍在运行的 OpenClaw 进程后重试。 4. 将 `auto_vacuum` 设为 `INCREMENTAL`,执行完整的 `VACUUM`,然后再次 checkpoint。 5. 运行 `quick_check`、`integrity_check` 和 `foreign_key_check`,然后重新应用仅所有者可访问的数据库及 SQLite sidecar 文件权限。 JSON 输出报告压缩前后的数据库和 WAL 大小、空闲列表页面、页面大小和 `auto_vacuum` 值,以及回收的字节以及 `quick_check` 和 `integrity_check` 结果。 `foreign_key_check` 必须通过才能继续压实;它没有单独的成功领域。 SQLite 将 `auto_vacuum` 报告为 `0`(无)、`1`(完整)和 `2`(增量)。 如果 schema 过旧、比当前运行的 OpenClaw 构建更新,或者属于 agent 数据库,压缩都会在不发生修改的情况下失败。对于较旧的共享状态 schema,请先运行 `openclaw doctor --fix`。对于较新的 schema,请恢复兼容的备份或升级 OpenClaw。 ## Session SQLite 迁移 会话密钥修复遵循完整的转录所有者别名链,包括大型数据库中的长链。它保留终端所有者的会话密钥和保留的记录历史记录;不需要缩短历史记录来限制修复堆栈。 运行时会话行和记录位于 SQLite 中,默认情况下位于 `~/.openclaw/agents//agent/openclaw-agent.sqlite` 中。网关启动使用 Doctor 的专有维护所有者在检查准备情况之前迁移旧会话 JSON/JSONL 文件。运行时读取仅使用当前 SQLite 状态。不可读的旧会话索引及其记录保留在其原始路径中,因此重复启动会拒绝准备并打印活动配置文件的 `doctor --fix` 命令,直到源得到修复。 要从旧的文件支持安装升级历史记录,请停止网关 (`openclaw gateway stop`),备份其状态 (`openclaw backup create --verify`),并运行 `openclaw doctor --fix`,然后使用 `openclaw gateway start` 重新启动它。 Doctor 会迁移每个配置的 `agents.entries..agentDir` 处的现有数据库,包括默认代理树外部的自定义路径和注册表中不存在的数据库。还检查配置的会话存储和保留的旧数据库。如果已配置的数据库在 `--fix` 之后仍需要架构迁移,Doctor 会报告其路径并以非零值退出,而不是打印 `Doctor complete`。 在代理架构迁移之前,Doctor 检查只读子进程中的数据库完整性。长检查每 10 秒打印一条进度线,其中包含数据库大小、已用时间和当前阶段。 Ctrl+C或SIGTERM记录中断,取消检查,等待承认的修复和清理后再退出。中断的检查不会授权下一次架构迁移;重新运行 Doctor 来完成。迁移前备份仍然可用。 `openclaw doctor --session-sqlite ` 提供有针对性的检查、导入、验证和 SQLite 维护。旧版 `sessions.json` 文件是迁移源。热成绩单JSONL文件导入,导入成功后存档;归档层 JSONL 文件仍然支持工件,而不是运行时回退。 较旧的 V2 迁移收据可以记录已完成的索引移动,无需文件标识。 Doctor 将幸存的存档与当前的 `sessions.json` 进行比较:不同的内容导入为新的旧索引。如果存档相同或丢失,Doctor 会导入历史记录,同时保留当前的 ​​SQLite 会话元数据。它不会在旧收据中创建身份字段或删除其存档。目前的索引导入后遵循正常验证和归档。此修复在运行时准备就绪之前(包括升级期间)在 Doctor 中运行。 当插件迁移被推迟时,经过验证的导入收据还会捕获未引用的 JSONL 输入。完成插件迁移后,这些原始文件将具有与索引记录相同的身份和字节检查。转录本的 `.trajectory-path.json` 指针随之移动。如果较早的解决方案存档了抄本,但留下了其收据验证指针,则下一个 `doctor --fix` 也会存档该指针。运行时目标丢失的收据绑定轨迹指针被存档为受保护的诊断;丢失的轨迹伪影将从活动收据中退出。对话记录仍然受到保护。捕获后创建的文件和更改后的原件在结算前会单独进行验证。启动仅检查收据与当前数据库的绑定,而不散列保留的源或搜索其档案。医生拥有该验证。在准入和配置恢复重试之前,会释放并重新获取过期的启动恢复租约。文件时代的会话路径修复会保留这些原始文件,直到其经过验证的导入收据完成存档,即使在清除待处理的插件迁移记录之后也是如此。重试和只读检查会重复使用已验证的收据,包括在 `sessions.json` 之外发现的记录。 Doctor 会针对这些保留的输入报告一个待处理插件警告;它们不会使已完成的核心迁移失败或需要 `doctor --session-sqlite recover`。仅警告结果成功退出。验证存档后,Doctor 会注销延期收据,同时保留存档清单以供恢复。禁用或卸载所属插件也会释放其在下次导入或修复时的未决义务。暂时不可用的已启用插件仍处于待处理状态。以后的显式导入通常可以发现新的遗留转录本。当收据仍然有效时,该收据之外的新文件仍然存在; Doctor 命名完成旧迁移所需的收据、插件和命令并重试导入。该收据之外的有效遗留 JSONL 是等待验证的建议。 `doctor --fix` 和 `--session-sqlite recover` 验证其事件身份和内容是否存在于拥有代理的 SQLite 记录中。较长 SQLite 转录本的前缀或子集被取代,而不是计数不匹配。 Doctor 将原始文件存档并在其现有迁移收据中记录 `superseded by SQLite (N of M events present)`,其中 N 是遗留事件计数,M 是 SQLite 事件计数。缺失后缀事件先经过现有进口商验证;当前会话设置及其活动生成保持不变。原始字节保留在迁移存档中以供恢复。无法验证的已更改、格式错误或冲突的源将保留在原处。调查结果中指出了冲突的身份或缺失的中间事件。将这些事件与已验证的备份进行比较,保留原始事件,并在重新运行恢复之前在指定路径还原更正的 JSONL。健康的代理不会继承另一个代理的失败。当遗留索引和实时记录输入消失时,经过验证的历史档案将保留其现有收据。他们不需要新的遗留索引收据或块会话后插件修复。插件完成后会释放其保留的配置。 如果原始 `sessions.json` 不可用,但已完成的导入收据仍标识当前数据库,则导入会根据收据记录的哈希值重建其源索引。它会在现有收据中记录修复,而无需重新创建 `sessions.json` 或重播会话元数据。哈希匹配源通过导入继续;已更改或无法验证的源仍然受到保护,并按路径列出。保存这些文件以供检查。 会话目录不需要旧版 `sessions.json` 来恢复其历史记录。 Doctor 从经过验证的成绩单标头和 SQLite 中获取会话所有权。对于具有挂起的插件迁移的已配置代理,它会在现有导入收据中记录源索引,而不创建新的 JSON 索引。对于未配置的代理,它会导入有效的对话并将原始历史记录移动到受保护的迁移存档中,记录每个移动。仅轨迹目录也保留在那里,而无需创建空的代理数据库。其他代理的挂起迁移不会阻止此存档。 即使 inode 或修改时间不同,具有记录的 SHA-256 和大小的恢复副本仍然有效。 `--session-sqlite recover` 在现有收据中记录其当前身份,包括不存在失败的迁移清单时。如果数据库文件被替换,恢复首先根据当前 SQLite 数据库验证保留的抄本内容,然后重新绑定收据。当验证失败时,Doctor 会在迁移分类帐中保留绑定到不同数据库的收据,记录其被取代的原因,并通过历史导入程序检查保留的原件。外部收据无法证明或阻止实时数据库。当前会话设置和已知的 archive/deletion 状态仍然具有权威性;与明确代理所有者的未索引对话将作为存档会话恢复。丢失的原件以它们无法恢复到的数据库命名。保留报告的文件并从已验证的备份中恢复不可用的原始文件,然后重新运行 `openclaw doctor --fix`。仅此警告并不能阻止更新程序重新启动网关。 Doctor 还根据记录的源哈希验证仅格式化索引更改,并根据完整存储的历史记录更改转录本。验证内容会刷新收据,而不会覆盖当前会话设置或恢复已删除的历史记录。更改的索引值和其他无法验证的插件输入将移至受保护的迁移存档,并在报告中显示其验证错误和恢复路径。对于更改的索引,Doctor 会将会话密钥和 ID 与当前 SQLite 存储进行比较,并在每个会话警告中命名不同的元数据字段。此比较并不授权重放旧值或接受更改的字节作为原始导入。快照、模型路由和完整性修复使这些历史输入保持不变,包括在插件义务完成后而其源收据仍然存在。对当前 SQLite 商店的修复仍在继续。无索引导入后出现的新索引将保留为冲突输入;它不能继承先前收据的权限。 保留的插件源冲突不会妨碍核心导入完成后网关的准备状态。医生负责维修,网关继续为 SQLite 提供服务。即使保留的输入需要修复,`inspect` 也会报告实际的 SQLite 行计数。恢复报告包括每个剩余的问题代码,并将未解决的问题与已完成的验证区分开来。 对于零字节保留的副本,恢复会列出其 `.jsonl.bak--` 同级副本,并根据存储的会话验证最大的备份。缺失后缀事件使用现有的历史导入器;不会重播当前会话设置和已删除的会话。在 Doctor 归档带有可恢复警告的空原始文件之前,必须覆盖所有候选备份。备份文件保持不变。如果没有备份,带有转录行的已识别存储会话可以确定空源已被取代。如果两个来源都无法证明历史记录,Doctor 会保留该文件并命名准确的记录和数据库路径,以便在重试恢复之前从经过验证的备份中进行恢复。将移动的转录本及其备份保存在报告的原始路径中。 当记录的旧索引及其存档都丢失时,Doctor 会根据当前 SQLite 存储验证剩余的转录本,然后报告存储的转录本完整且旧索引条目仅供参考。它保留这些实时记录和迁移记录,跳过另一次导入,并允许会话后插件修复继续。它不会继续请求导入已验证的历史记录。 Doctor 还发现旧注册表中遗漏了主要对话记录,包括带有时间戳前缀的文件名。它在导入之前验证会话标头、文件身份和逻辑所有者。已知的历史生成仍附加到其现有会话,而不更改其当前生成或设置。仅当其代理所有者明确时,没有注册表所有者的历史记录才会恢复为存档会话。 重新运行导入可以恢复通过早期迁移扫入受保护存档的主要历史记录。医生使用保留的迁移清单和存档的注册表谱系;它不会通过实时 SQLite 状态恢复过时的设置。原件受到保护,并记录已完成的恢复,因此以后的运行不会恢复用户明确删除的历史记录。诊断轨迹包络、​​已删除的工件、不受支持的文件、冲突的身份和不明确的所有权不会转换为对话。延迟的文件仍可用于恢复。 重复导入可能会留下一份主要转录本的多个存档副本。 Doctor 将具有相同验证大小和 SHA-256 的相同原始路径的副本视为一项历史声明。它保留一份经过验证的原件,并通过现有的恢复收据淘汰相同的副本,更新每个保留的清单。即使最近一次失败的运行没有移动任何文件,`--session-sqlite recover` 也会解决这些档案。具有不同字节的副本受到保护并在警告中命名;保留的历史冲突不会阻止更新的会话后插件修复。保留原始清单和迁移清单,同时解决这些冲突,然后重新运行 `openclaw doctor --fix`。 正常 Doctor 输出和 `openclaw update status` 每个会话存储最多显示五个 `historical_transcript_deferred` 示例。较大的组包括总数和遗漏计数;其他警告类型仍然可见。对于每个发现,运行 `openclaw doctor --session-sqlite dry-run --session-sqlite-all-agents --json`。此摘要不会废弃恢复引用或使丢失的档案符合清理条件。保留剩余的原件和迁移清单以供恢复。 ### 更改存档注册表 `historical_transcript_deferred` 可以报告存档会话注册表不再与其迁移收据匹配。收据通过设备、inode、修改时间、大小和SHA-256来标识原始文件;它不是代理或安装ID。历史存档发现、恢复和恢复清理接受卷重新安装后设备编号的更改; inode、修改时间、大小和 SHA-256 必须仍然匹配。复制、替换、触摸或编辑存档可能会使该收据失效。 2026.9.4和2026.9.5中的身份格式相同; 2026.9.5 添加了历史档案发现,用于检查这些较旧的收据。 Doctor 会跳过该商店的历史记录导入并保留原始记录。此警告本身并不表示 SQLite 损坏或需要回滚。如果所有预期对话均可见,则无需执行任何操作。您可以使用 `openclaw doctor --session-sqlite inspect --session-sqlite-all-agents` 检查当前 SQLite 状态。 如果历史记录丢失,请保留指定的存档和 `/session-sqlite-migration-runs/`,进行经过验证的备份,并通过警告和检查输出寻求恢复帮助。将成绩单内容和原始清单保密。 `doctor --fix` 不重置未经验证的指纹;请勿删除或编辑收据以消除警告。导入尝试将跳过的结果记录在其迁移清单中,并保持现有 SQLite 会话完好无损。 ### 导入暂存和验证 公共 Doctor 迁移路径会在私有临时 SQLite 数据库中暂存转录本有效负载并执行分支和提供程序修复,而不是在内存中保留完整的历史记录。它保持原始记录不变,直到通过专有的相同文件系统移动对其进行归档,从而避免了额外的完整 `.pre-doctor` 原始副本和重写的中间文件。 对于大型历史记录,请同时为原始 JSON/JSONL 文件、临时 SQLite 假脱机以及目标数据库和 WAL 规划空间。在系统临时卷和保持 OpenClaw 状态的卷上保留可用空间;生成的 SQLite 数据库可能比原始 JSONL 更大。流式传输减少了整个历史内存压力,但单个记录仍然在内存中解析,并且 SQLite 也使用本机内存。不要单独根据 JSONL 字节数或 JavaScript 堆限制调整主机大小;没有固定磁盘、RAM 或迁移时间保证。 操作完成后,暂存将被删除,并且永远不会用作运行时存储或在中断后恢复;重试使用原始源和提交的会话数据。导入后,Doctor 会检查点并增量清理已经支持自动清理的数据库,在清理之前和之后保留完整的完整性和外键检查。如果数据库已处于增量自动清理模式,没有可用页,并且没有 WAL 进行检查点,则导入完成会对其进行一次验证并保持其内容不变。没有自动清理功能的数据库仍然需要完整的 `VACUUM` 才能启用它。增量清理会释放未使用的页面,但不会重新打包部分填充的页面;显式会话和共享状态 `compact` 模式仍运行完整的 `VACUUM`。 常规 `openclaw doctor` 传递还报告存储的 SQLite 转录本,其初始会话标头从未保留。 `openclaw doctor --fix` 在一个事务中添加当前标头并重建转录索引,同时保留现有事件 ID、父链接、行时间戳和会话列表新近度。无标头遗留或格式错误的转录本仍会被拒绝,直到其所属的迁移可以验证它们为止。 模式: | 模式 | 行为 | | ---------- | ---------------------------------------------------------------------------------------------------------------------- | | `inspect` | 无需导入即可读取 SQLite 计数和任何选定的旧源诊断;不需要遗留文件。 | | `dry-run` | 解析旧版条目和转录 JSONL 文件,统计可导入的行,并报告问题,但不向 SQLite 写入任何行。 | | `import` | 将所选目标的旧版条目和转录事件导入到 SQLite 中。 | | `validate` | 根据 SQLite 验证选定的旧会话身份和转录内容。 | | `compact` | 对所选代理的 SQLite 数据库执行 checkpoint 和 VACUUM,以在大规模删除或归档清理后回收空闲页。 | | `recover` | 恢复失败的迁移运行,解决剩余的活动 JSONL 文件,并报告任何剩余的恢复问题。 | | `restore` | 根据记录的迁移清单从归档的转录工件中恢复数据,但不删除 SQLite 数据。 | 选择器: - Default:配置的默认代理存储; SQLite 检查不需要旧文件。 - `--session-sqlite-agent `:一个已配置的代理,或与 `--session-sqlite-store` 配对时的预期数据库所有者(否则假设为 `main`)。 - `--session-sqlite-all-agents`:已配置代理存储加上已发现的代理存储。 - `--session-sqlite-store `:一个显式 `.sqlite` 数据库或旧版 `sessions.json` 路径。 `dry-run`、`import` 和 `validate` 仅选择现有旧源。显式 `.sqlite` 路径在这些模式下不选择旧目标;它永远不会被解析或归档为 JSON。对于 SQLite 目标,使用 `inspect`、`compact` 或通过 `recover` 进行损坏恢复。从迁移清单中恢复或恢复存档源需要包含它的原始旧选择器或代理存储发现。旧版 `sessions.json` 选择器路径仍受支持,并解析到相应的 SQLite 存储以进行维护。 网关停止并备份其状态后,检查并导入遗留历史记录: ```bash openclaw doctor --session-sqlite inspect --session-sqlite-all-agents openclaw doctor --session-sqlite dry-run --session-sqlite-all-agents --json openclaw doctor --session-sqlite import --session-sqlite-all-agents openclaw doctor --session-sqlite inspect --session-sqlite-all-agents --json ``` `import` 在归档其遗留源之前验证行和转录事件计数。成功导入后,`validate` 可能不会选择任何旧目标;使用 `inspect` 查看当前 SQLite 状态。虽然旧源仍然存在,但当 SQLite 中缺少选定条目、会话 ID 不同、旧转录事件不存在或与 SQLite 冲突时,`validate` 将以非零值退出。其他 SQLite 事件不会导致验证失败。使用`--session-sqlite-store `时,检查报告中是否包含预期的目标计数;不存在的旧源不会为 `dry-run`、`import` 或 `validate` 选择目标。 SQLite先删除数据库内的回收页;他们不一定立即收缩数据库文件。删除或归档大型转录本后,运行 `openclaw doctor --session-sqlite compact --session-sqlite-all-agents` 以检查点 WAL 文件,运行 `VACUUM`,并报告 before/after 数据库和 WAL 大小。压缩需要一个常规文件,其中包含当前代理模式、其持久数据库所有者元数据,并且医生进程中没有打开句柄。破坏性的 `import`、`compact`、`recover` 和 `restore` 模式与网关启动时持有相同的状态所有权锁以进行完整操作; `inspect`、`dry-run` 和 `validate` 保持只读状态,不接受。首先停止网关。破坏性模式会失败,而不是与实时写入竞争或与另一个维护命令竞争。破坏性的 `--session-sqlite-store` 目标必须位于活动状态目录内;在维护另一个安装之前,将 `OPENCLAW_STATE_DIR` 设置为商店所属的状态目录。现有的硬链接目标被拒绝,因为另一个路径可以在锁定状态目录之外共享相同的数据库 inode。相同的所有权检查涵盖 SQLite WAL、共享内存和回滚日志 sidecar。 每次导入都会在将转录工件移入存档之前在 `~/.openclaw/session-sqlite-migration-runs/` 下写入一个清单。恢复引用保留在当前会话目录中,包括使用旧计算机绝对转录路径的备份。重试中断的导入可以使索引和之前存档的转录本保持可恢复状态。如果在移动工件后显式导入失败,请保持网关停止并运行恢复: ```bash openclaw doctor --session-sqlite recover --github-issue ``` 使用 `--yes` 授权在非交互式恢复期间创建问题。如果没有它,重定向输入、`--non-interactive` 和 JSON 输出将跳过提示并记录跳过问题创建的原因。 恢复选择最新失败的迁移清单,仅恢复清单的存档工件,验证受影响的目标,并在当前恢复问题仍然存在时准备经过清理的 `.failure.md` 和 `.failure.json` 报告。报告包括记录的运行 ID、故障时间戳(对于没有时间戳的较旧日志,则为 `not recorded`)、目标以及故障代码和错误。他们将当前的恢复结果与记录的迁移和恢复证据分开。早期故障和现有报告仍可用于诊断。当前问题为零的成功恢复不会准备或打开 GitHub 问题,即使它存档了被取代的 JSONL 文件。重复完成的恢复是一个干净的无操作;被阻止或不受信任的恢复工件仍然需要检查。 JSON 报告保留合并的 `issues` 证据,并为检查的目标添加 `recoveryIssues`。 GitHub 问题正文避免了转录内容、原始环境、秘密和无限制的配置。一旦问题或浏览器切换可能发布了报告,医生就会保留该私人报告工件及其标记收据。当不存在失败的迁移清单时,恢复将使用完整文件集的临时副本检查选定的 SQLite 数据库。 SQLite 可以在 `quick_check`、`integrity_check` 和 `foreign_key_check` 运行之前回滚一次性副本中的有效热日志,而原始取证文件在检查期间保持不变。恢复尝试在架构和所有者验证后修复所需索引中的损坏。架构、所有者和 I/O 错误以及失败或拒绝的索引修复会保留原始数据库并进行诊断。其他已确认的损坏或孤立 sidecar 通过使用一个 `.corrupt-` 后缀重命名整个发现集来保留 DB、WAL、SHM 和回滚日志文件。捕获的重命名失败会在报告失败之前回滚已移动的文件,因此不会静默分割可恢复的文件集。恢复前停止网关;复制或重命名主动更改的 SQLite 文件集是不安全的,并且在不同操作系统中的行为有所不同。对于 `--github-issue --yes`,医生使用 GitHub CLI 在 `openclaw/openclaw` 中创建问题。如果 CLI 不可用或 GitHub 明确拒绝该请求,则当其编码的 URL 保持在安全请求大小范围内时,医生可以在浏览器中打开精确的净化报告。在没有确认的情况下,医生会编写本地支持报告并跳过问题创建,而无需打印或打开预填充的 URL。不明确的提交不会重试。稍后的医生运行会协调保留的标记,而不发送另一个创建请求,因此它无法发布重复的问题。机器可读的输出包括最终的支持问题状态,但不包括私人收据或预填写的 URL。 `restore` 仍然是较低级别的撤消操作。它使用清单 `sourcePath -> archivePath` 记录,仅在原始路径丢失时将存档工件移回原处,报告独立存在的原始工件的冲突,并将 SQLite 数据库保留在适当位置。发布是独占的:验证过程中创建的文件或符号链接不会被替换。恢复会移动原始文件而不复制其内容,并且如果文件系统无法安全地发布存档,则会失败而不消耗存档。可以重试记录的中断发布,包括使用较旧的清单或在删除替换 SQLite 数据库后重试。如果恢复重新创建丢失的会话目录,则在使用存档之前重试重复其父目录持久性检查。当多个清单记录了相同的原始路径时,请在移动其中任何一个之前恢复所有候选者的计划。相同的档案是安全的副本,一个非空的遗留 `sessions.json` 可能会取代旧作者创建的空副本。不同的非空索引、不同的转录存档、无效存档以及在没有记录的先前恢复的情况下丢失的存档会阻止操作,因此恢复无法静默替换或隐藏可恢复的数据。 重新导入未更改的、清单记录的恢复索引会保留当前的 ​​SQLite 会话元数据,同时协调其转录历史记录。它不会将较新的标签、活动时间戳或当前会话指针重置为恢复的值。更改后的恢复收据会保留目标的原始收据并发出警告,而不会停止不相关的 Doctor 或会话后插件修复。不可读的恢复历史记录不再需要空的 SQLite 目标:Doctor 协调每个会话,保留其当前的元数据和生成,验证现有的记录内容,并通过正常的分阶段导入器导入新的历史记录。经过验证的原件与记录的收据一起移至恢复存档。与经过验证的 SQLite 所有者发生冲突或格式错误的历史记录将作为受保护的输入移至该存档,并带有目标警告;它没有经过进口认证或符合清理条件。未经验证的所有权或恢复证据保留原件。保留原件和收据,将指定事件与经过验证的备份进行比较,并在更正存档源并重试 Doctor 之前使用 `--session-sqlite restore`。这些规则在更新期间也适用,并保留现有的 archive/restore 路径进行回滚。当恢复历史记录可读时,具有不同文件标识的新创建的索引仍然是普通导入。保留恢复清单及其原始文件,以便医生可以区分两者。共享索引保留每个代理的 SQLite 目标的收据;仅凭另一位所有者的收据并不能确定所选目标的恢复来源。显式定制商店将其现有的 restore/import 准入保留在状态目录之外;这并不会使他们的文件符合自动恢复清理的条件。 验证迁移和当前历史记录后,使用 `openclaw update cleanup --dry-run` 检查保留的恢复数据,而无需停止网关。仅在停止网关、其他 SQLite 维护以及同一 profile/state 目录的数据库读取器后才能应用 `openclaw update cleanup` 或 `openclaw update cleanup --yes --json`。保持会话列表观察程序停止,直到清理退出:即使是只读连接也可能更改 WAL/SHM sidecar 并使验证无效。这将永久淘汰符合条件的回滚原始版本;它不会删除当前的 SQLite 历史记录或操作员备份。当保留或挂起的工件需要清单时,清单仍然保留,因此可以恢复中断的清理。恢复可区分有意处置、待清理和意外丢失的文件。请参阅 [ 更新清理 ](/cli/update#update-cleanup)。 ### 硬链接遗留工件 当另一个硬链接引用其 inode 时,Doctor 拒绝遗留 `sessions.json` 或转录工件。该诊断命名工件路径、设备、inode 和观察到的链接计数 (`nlink`)。 Doctor 不会扫描其他链接路径。拒绝可以保护快照副本免受通过共享索引节点的更改。 对于在记录其身份进行存档之前被拒绝的旧源,请停止网关并创建经过验证的备份。将内容复制到同一目录中的 **new** 临时常规文件,并保留权限。验证副本是否具有相同的内容且链接计数为 1,然后通过报告的源路径对其进行重命名并重新运行相同的 Doctor 命令。不要就地覆盖源或创建另一个硬链接:用新副本替换其目录条目可以保留快照的内容,而无需查找其其他路径。 如果先前的迁移被中断或报告的路径是存档的恢复工件,请保留文件和清单。首先使用相同的配置文件和旧源选择器运行 `openclaw doctor --session-sqlite recover`。记录的文物取决于其原始身份;用副本替换它们可能会阻止恢复。如果恢复仍然拒绝该工件,请保留该证据作为支持,而不是替换它。 ### 会话 SQLite 迁移后降级 在开始旧版本之前,请先关注 [Downgrade](/install/updating#downgrade)。当编写器停止时,`openclaw doctor --session-sqlite restore --session-sqlite-all-agents` 将清单记录的遗留转录工件恢复到其原始路径。这支持从保留的原件中恢复;它不会反转 SQLite 架构迁移或替换更新前的备份。 在 `openclaw update cleanup` 废弃这些原始文件之前运行恢复。清理后,恢复报告有意处置并且无法重新创建它们。共享状态发现使用私有只读快照(包括自定义存储),因此拒绝的恢复会使共享数据库及其 WAL 保持不变。仅在 SQLite 中创建的会话不会出现在较旧的文件支持运行时中。如果再次升级,请在导入之前使用上面的正常迁移验证序列将恢复的工件与 SQLite 行进行比较。