关于 codex-session-recovery
codex-session-recovery 是面向开发者的恢复 Skill,用于处理仍保存在本地、却未显示在 Codex Desktop 界面的会话。它检查会话索引、项目映射和工作目录精确匹配情况,并指导先备份再修复和验证。
主要功能
- 01以 dry-run 模式执行恢复检查
- 02查找缺失的会话索引记录
- 03检查项目与侧边栏映射
- 04备份后修复会话元数据
- 05验证恢复结果和工作目录匹配
- 06处理隐藏线程及最近会话数量限制
适用场景
- 01恢复界面中缺失的 Codex 会话
- 02诊断项目根目录与会话路径不匹配
- 03备份后修复侧边栏分配
- 04排查恢复后线程仍不可见的原因
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ huajiexiewenfeng/ codex-session-recovery --skill codex-session-recovery安装后在 Claude Code 中输入/codex-session-recovery确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
scripts/recover_codex_global_state.pyreparent_codex_sessions.pyrestore_codex_project_sessions.pyrun_recovery_after_codex_exit.ps1surface_codex_sidebar_threads.py详细介绍
Codex 会话恢复
使用此技能恢复仍保存在磁盘上、但在 UI 中缺失的本地 Codex Desktop 会话。
常见故障模式:
sessions/**/*.jsonl和state_5.sqlite中仍保留着这些会话。session_index.jsonl可能缺少部分记录。.codex-global-state.json可能缺少项目/侧边栏分配键,例如project-order、thread-workspace-root-hints、thread-project-assignments和sidebar-project-thread-orders。- 运行中的 Codex Desktop 可能会用其内存状态覆盖手动编辑的内容。
安全规则
- 永远不要删除会话文件。
- 写入前务必创建带时间戳的备份。
- 优先根据
session_meta.payload.cwd精确匹配项目根目录。 - 除非用户明确要求扩大匹配范围,否则不要将路径的全文提及视为项目归属依据。
- 如果 Codex Desktop 正在运行,除非用户明确批准在应用运行时写入,否则不要写入全局状态。请说明 Electron 可能会再次覆盖该文件。
- 如果
missing_*计数为零后,UI 仍未显示恢复的会话,不要继续猜测全局状态键。请检查 UI 中显示的项目根目录是否与会话cwd不同。 thread/list.cwd是精确匹配筛选条件,不是前缀筛选条件。cwd为D:\repo\subdir的会话可能不会显示在根目录为D:\repo的 UI 项目下。- Codex Desktop 26.527 版本会根据近期会话缓存构建项目侧边栏,该缓存从
thread/list limit: 50开始。如果新启动的 app-server 使用thread/list --cwd <root>返回了旧会话,但 UI 项目仍显示 "No recent chats",这些会话可能只是排在全局近期会话列表的第一页之外。备份 SQLite、JSONL 运行记录和全局状态后,使用surface_codex_sidebar_threads.py。仅更新 SQLite 时间戳并不持久,因为 app-server 重启时的读取修复可能会根据 JSONL 重新构建这些时间戳。 - 将 Windows 扩展长度路径视为单独的精确匹配风险。
\\?\D:\repo\project和D:\repo\project会规范化为相同的文件系统路径,但 Codex UI 的cwd筛选条件可能不会将它们视为相同字符串。如果修复元数据后历史记录仍不可见,请检查 SQLite 的threads.cwd是否带有\\?\前缀,并使用reparent_codex_sessions.py --old-root <root> --new-root <root> --write将其规范化。 - 当目标目录是 Git 子目录时,请比较
git rev-parse --show-toplevel和session_meta.payload.cwd。如果 Codex 按 Git 根目录对侧边栏进行分组,请仅在备份 SQLite 和 JSONL 文件后,将匹配的会话重新归属到 Git 根目录。
工作流
- 解析
CODEX_HOME。- 如果
$env:CODEX_HOME指向一个实际存在的目录,优先使用它。 - 否则使用
%USERPROFILE%\.codex。
- 如果
- 解析目标项目根目录。
- 使用用户提供的路径。
- 如果用户未提供路径,且当前工作区就是目标项目,则使用当前工作目录。
- 先以试运行模式运行捆绑脚本。
- 阅读报告中的以下字段:
exact_project_sessionsmissing_from_session_indexmissing_global_hintssqlite_exact_ui_cwd_threadssqlite_non_exact_ui_cwd_threadscwd_exact_match_riskcodex_processes_runningcan_write_global_state_safely
- 如果 Codex 正在运行,且需要修复全局状态:
- 在请求用户采取操作之前,先提供简短的分步状态摘要。
- 不要只说“完全退出 Codex”;很多用户不知道如何关闭 Electron、托盘进程和辅助
codex.exe进程。 - 询问用户是否希望 Agent 自动关闭并重启 Codex,然后继续恢复。
- 如果用户同意,使用外部辅助进程,以便在当前 Codex 窗口退出后继续恢复。
- 如果用户拒绝,请其完全退出 Codex Desktop,然后从外部终端运行脚本。
- 如果用户接受覆盖风险,使用
--allow-running-codex运行,但要说明 SQLite 仍可能被锁定,且 Electron 可能覆盖全局状态。
- 运行写入模式。在 Windows 上,优先使用
--normalize-windows-extended-paths,让主脚本也将同一目录中\\?\D:\...格式的 cwd 值重写为完全一致的显示根目录字符串。 - 重新以试运行模式运行,验证:
missing_from_session_index: 0missing_global_hints: 0missing_project_assignments: 0missing_sidebar_order: 0cwd_exact_match_risk: false
- 如果界面仍未显示这些对话:
- 检查
ThreadListParams的app-server架构或生成的 JSON 架构。 - 请记住,
cwd必须完全匹配。 - 检查
state_5.sqlite中的threads.cwd;如果行中使用\\?\D:\...,请在同一根目录下重新挂接,以将其重写为显示根目录字符串。 - 运行
git -C <project-root> rev-parse --show-toplevel。 - 如果 Git 根目录与项目根目录不同,请修复显示根目录,或将会话重新挂接到 Git 根目录。
- 如果
cwd完全匹配,且全新的 app-server 能返回隐藏的对话,请检查全局thread/list排名。Codex Desktop 可能只将最近的 50 个对话加载到项目侧边栏。 - 在这种情况下,运行
surface_codex_sidebar_threads.py,将一组有数量限制、按轮次排列的已恢复项目对话提升到最近对话缓存中。此操作会更新 JSONLtask_complete.completed_at、SQLiteupdated_at/updated_at_ms和全局项目映射,并生成备份和报告。
- 检查
- 如果恢复需要重启,请告知用户接下来会发生什么,并询问是否要自动执行。如果用户同意,运行重启辅助程序;如果不同意,请其重新打开 Codex Desktop 并检查项目列表。
- 启动任何隐藏的外部辅助程序后,在确认其确实已接管之前,不要声称它正在运行:
- 检查项目根目录下是否存在预期的日志文件,或在
C:\tmp下指定-LogPath。 - 如果日志缺失,检查是否有仍在运行的
powershell.exe辅助进程。 - 如果没有日志,且
Codex/codex进程仍在运行,则视为辅助程序启动失败或在记录日志前失败。不要告诉用户恢复正在进行。 - 如果进程检查或停止操作报告
Access is denied,如果 Codex 进程的Path为空或为 null,或者使用-StopCodexFirst后仍有 WindowsApps Codex 进程运行,则改用 UAC 辅助程序路径。
面向用户的提示词模式
如果试运行发现有可恢复的会话,但 Codex 正在运行,请让用户更新简洁且便于执行。建议采用以下格式:
1. 已按 `codex-session-recovery` 流程处理到安全恢复阶段。
2. Dry-run 结果:当前项目 `<project-root>` 找到 `<N>` 条历史 session。
3. `session_index` <缺失情况>,全局侧边栏映射 <缺失情况>,SQLite 的 `cwd` <是否存在 `\\?\` 精确匹配风险>。
4. 日志在这里:`<log-path>`。
现在需要重启 Codex Desktop 才能继续恢复。是否需要我帮你自动关闭并重启 Codex?
如果用户同意,请改用外部助手,而不是让他们手动查找每个 Codex 进程。如果用户不同意,请提供他们关闭 Codex 后可以运行的确切 PowerShell 命令。
自动关闭/重启指南
满足以下所有条件时,使用自动关闭/重启:
- Codex 正在运行,且
can_write_global_state_safely为 false,或 SQLite 报告disk I/O error。 - 用户明确同意让 Agent 关闭/重启 Codex。
- 你可以启动一个外部 PowerShell 进程,该进程在当前 Codex 窗口退出后仍会继续运行。
重要的 Windows 注意事项:
- 不要启动会终止自身进程树的助手。如果使用
taskkill,且恢复 PowerShell 是由 Codex 启动的,请避免使用/T;/T可能会在助手写入元数据前终止它。 - 如果捆绑的
run_recovery_after_codex_exit.ps1足以完成任务,请优先使用它,因为它会等待 Codex 退出,然后运行验证。 - 如果必须创建临时助手,请避免在
.ps1源代码中硬编码非 ASCII 项目路径。使用$PSScriptRoot、(Get-Location).Path,或将路径作为参数传递,以免 Windows PowerShell 5 的编码导致中文路径乱码。 - 如果
Start-Process因重复的Path/PATH环境变量键而失败,请在启动外部进程前移除重复的进程级PATH变量。 - 如果停止 Codex 时出现
Access is denied,请使用Start-Process -Verb RunAs,并告知用户批准 UAC 提示。 - 如果隐藏助手立即返回、未创建日志,或所有 Codex 进程仍在运行,请勿重试相同的隐藏命令。请使用明确指定的
-LogPath,在C:\tmp中重新运行;如果日志仍不存在或显示拒绝访问,请使用 UAC 助手。 - 如果使用明确指定的
C:\tmp日志路径启动的隐藏助手在 2-3 秒后仍未创建日志,且相同的Codex/codex进程仍在运行,应将此情况视为“助手未接管”,而不是“恢复仍在运行”。直接使用 UAC 助手,并说明缺少日志是原因。 - 自动恢复后,重新运行试运行,并确认
missing_*: 0且cwd_exact_match_risk: false,然后再宣布恢复完成。
成功修复全局状态后界面仍为空
如果 missing_from_session_index、missing_global_hints、missing_project_assignments 和 missing_sidebar_order 均为零,但左侧边栏仍未显示历史记录,请不要急着认定恢复成功。请按以下顺序检查:
- 确认 Codex 确实运行了最新的恢复脚本。日志应包含预期的步骤名称。在编辑脚本前启动且正在等待的脚本会继续运行旧的脚本内容。
- 写入前确认没有仍在运行的
Codex或codex进程。运行中的 Electron 可能会用内存中的状态覆盖数据。 - 检查主脚本的 cwd 精确匹配字段:
sqlite_exact_ui_cwd_threads
sqlite_non_exact_ui_cwd_threads
sqlite_extended_path_threads
cwd_exact_match_risk
recommended_cwd_normalization
如果 cwd_exact_match_risk 为 true,即使所有全局状态的 missing_* 计数均为零,Codex 界面仍可能隐藏这些会话。
- 检查 SQLite 中是否存在 Windows 扩展长度路径不匹配:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
& $py -c "import sqlite3; con=sqlite3.connect(r'C:\Users\admin\.codex\state_5.sqlite'); [print(row) for row in con.execute(\"select id,cwd,title from threads where cwd like '%smartghub%' order by created_at desc\")]"
如果 threads.cwd 以 \\?\ 开头,而界面中的项目根目录是普通路径,请使用主恢复脚本规范化同一个项目根目录:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
$root = (Get-Location).Path
& $py "$skill\scripts\restore_codex_project_sessions.py" --project-root $root --write --normalize-windows-extended-paths
- 检查 app-server 契约:
$env:CODEX_HOME = "C:\Users\admin\.codex"
codex app-server generate-json-schema --out .\app-server-schema
Get-Content .\app-server-schema\v2\ThreadListParams.json
cwd 筛选条件表示:仅返回会话 cwd 与其中一个路径完全匹配的线程。
- 比较项目根目录与 Git 根目录:
git -C "D:\workspace\drone\cloudsmartgo\smart-go-web" rev-parse --show-toplevel
在这台机器上,smart-go-web 位于 Git 根目录下:
D:\workspace\drone\cloudsmartgo
如果界面中的项目是 Git 根目录,但线程记录使用的是 D:\workspace\drone\cloudsmartgo\smart-go-web,那么即使全局状态映射看起来正确,边栏仍可能为空。
-
在这种情况下,只重新指定完全匹配的项目会话的父级:
- 备份
state_5.sqlite - 备份每个已更改的
sessions/**/*.jsonl - 更新
threads.cwd - 更新 JSONL 中的
session_meta.payload.cwd和turn_context.payload.cwd条目 - 将
.codex-global-state.json项目映射更新为显示根目录
- 备份
-
如果出现了一个可见的新测试对话,但同一项目中的较早对话没有显示:
- 使用
thread/list和cwd=<project-root>查询新的 app-server。如果新旧会话都已返回,则表示数据已恢复。 - 按
updated_at查询全局thread/list;如果旧会话排在第一页之后(例如排名为 146),说明界面尚未加载该元数据。 - 运行边栏显示脚本。使用有界形式,将每个项目至少几个线程放入最近记录的第一页:
- 使用
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\surface_codex_sidebar_threads.py" --per-project 2 --max-total 50
& $py "$skill\scripts\surface_codex_sidebar_threads.py" --per-project 2 --max-total 50 --write --report-path "C:\tmp\codex-sidebar-surface.json"
-
如果固定/取消固定测试证明界面可以显示已加载的旧线程,但重启后又丢失,请勿将所有会话都提升到最近记录页。提升所有会话可能会让大型项目再次占据前 50 条记录。请使用上面的有界轮询形式(
--per-project 2 --max-total 50),让每个项目都有代表性线程进入最近记录的第一页。 -
仅将全会话形式用作元数据规范化步骤,而不要用作界面加载步骤:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\surface_codex_sidebar_threads.py" --per-project 0 --max-total 0 --write --report-path "C:\tmp\codex-sidebar-surface-all.json"
- 对于已显示 1-2 个对话但需要显示更多历史记录的项目,请运行定向填充。这不会删除或归档其他项目,但较大的值可能会挤掉其他项目在最近 50 条记录中的位置。建议使用 10-15,然后如果其他项目因此隐藏,再次运行有界全局填充:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\surface_codex_sidebar_threads.py" --project-root "D:\workspace\ai-workspace\linux-web-mysql" --per-project 10 --max-total 10
& $py "$skill\scripts\surface_codex_sidebar_threads.py" --project-root "D:\workspace\ai-workspace\linux-web-mysql" --per-project 10 --max-total 10 --write --report-path "C:\tmp\codex-sidebar-surface-linux-web-mysql.json"
- 要显示同一项目的下一批记录,如果用户不接受其他项目可能暂时再次显示为空,请勿将单个项目设为 50。使用
--offset-per-project翻页浏览该项目。例如,显示最新 10 条后,使用以下命令显示第 11-20 条:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\surface_codex_sidebar_threads.py" --project-root "D:\workspace\ai-workspace\linux-web-mysql" --offset-per-project 10 --per-project 10 --max-total 10
& $py "$skill\scripts\surface_codex_sidebar_threads.py" --project-root "D:\workspace\ai-workspace\linux-web-mysql" --offset-per-project 10 --per-project 10 --max-total 10 --write --report-path "C:\tmp\codex-sidebar-surface-linux-web-mysql-page-2.json"
-
--offset-per-project通过更改要提升的批次,绕过固定的第一页缓存。它不会修改 Codex Desktop 内部的thread/list limit: 50。定向翻页后,如果其他项目因此隐藏,请再次运行有界全局填充。 -
写入模式运行后,重启 Codex Desktop,让边栏重建其最近线程缓存。
命令
如果无法使用常规的 python,请使用捆绑的 Python:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\restore_codex_project_sessions.py" --project-root "D:\workspace\drone\cloudsmartgo\smart-go-web"
仅恢复全局状态;当 state_5.sqlite 被锁定或旧脚本的 SQLite 报告路径失败时,此方法很有用:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\recover_codex_global_state.py" --project-root "D:\workspace\drone\cloudsmartgo\smart-go-web" --project-display-root "D:\workspace\drone\cloudsmartgo" --write
如果怀疑根本原因是 app-server 的 thread/list.cwd 精确匹配问题,请重新设置会话的父级:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\reparent_codex_sessions.py" --old-root "D:\workspace\drone\cloudsmartgo\smart-go-web" --new-root "D:\workspace\drone\cloudsmartgo" --write
规范化 Windows \\?\ cwd 前缀,但不更改项目根目录:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
$root = (Get-Location).Path
& $py "$skill\scripts\reparent_codex_sessions.py" --old-root $root --new-root $root --write
写入模式:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\restore_codex_project_sessions.py" --project-root "D:\workspace\drone\cloudsmartgo\smart-go-web" --write
Windows 写入模式,并精确规范化 UI cwd:
$py = "C:\Users\admin\.cache\codex-runtimes\codex-primary-runtime\dependencies\python\python.exe"
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
& $py "$skill\scripts\restore_codex_project_sessions.py" --project-root (Get-Location).Path --write --normalize-windows-extended-paths
如果用户已完全关闭 Codex Desktop,则写入模式是安全的。如果 Codex 仍在运行,且用户明确接受风险:
& $py "$skill\scripts\restore_codex_project_sessions.py" --project-root "D:\workspace\drone\cloudsmartgo\smart-go-web" --write --allow-running-codex
如果 Codex 实例正在运行,导致无法安全写入,请启动捆绑的外部 PowerShell 辅助程序。它默认将当前目录设为 ProjectRoot,等待所有 Codex/codex 进程退出,然后运行恢复操作、规范化同一根目录下的 cwd 值,并验证结果:
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
Start-Process -FilePath powershell.exe -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","$skill\scripts\run_recovery_after_codex_exit.ps1","-ProjectRoot",(Get-Location).Path) -WindowStyle Hidden
如果日志中只有 Waiting for Codex processes to exit...,说明仍有 Codex 进程在运行。请通过以下命令检查:
Get-Process | Where-Object { $_.ProcessName -match '^(Codex|codex)$' }
如果用户明确要求 Agent 关闭 Codex,或者 Codex 不断自动重启,导致辅助程序无法检测到正常退出,请从外部进程使用 -StopCodexFirst 启动辅助程序:
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
Start-Process -FilePath powershell.exe -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","$skill\scripts\run_recovery_after_codex_exit.ps1","-ProjectRoot",(Get-Location).Path,"-StopCodexFirst") -WindowStyle Hidden
如需在恢复写入后也将旧会话显示在侧边栏的最近记录缓存中:
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
Start-Process -FilePath powershell.exe -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","$skill\scripts\run_recovery_after_codex_exit.ps1","-ProjectRoot",(Get-Location).Path,"-StopCodexFirst","-SurfaceSidebar","-SurfacePerProject","2","-SurfaceMaxTotal","50") -WindowStyle Hidden
如需规范化所有已恢复交互会话的元数据,请使用 -SurfacePerProject 0 -SurfaceMaxTotal 0。这可能会更新许多 JSONL rollout 文件,但不能替代有限的首页 UI 水合步骤。运行完所有会话规范化后,请再次运行有限的展示操作,使用 -SurfacePerProject 2 -SurfaceMaxTotal 50。
如果某个特定项目已显示,但需要展示多于最初的 1-2 条对话,可传入一个或多个 -SurfaceProjectRoot 值来定向展示。请将总数控制在较小范围,例如 10,因为将单个项目设为 50 可能会占满最近记录的首页,导致其他项目再次显示为空:
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
Start-Process -FilePath powershell.exe -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","$skill\scripts\run_recovery_after_codex_exit.ps1","-ProjectRoot",(Get-Location).Path,"-StopCodexFirst","-SurfaceSidebar","-SurfaceProjectRoot","D:\workspace\ai-workspace\linux-web-mysql","-SurfacePerProject","10","-SurfaceMaxTotal","10") -WindowStyle Hidden
如需展示下一页,请添加 -SurfaceOffsetPerProject。以下示例展示 linux-web-mysql 的第 11-20 项:
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
Start-Process -FilePath powershell.exe -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","$skill\scripts\run_recovery_after_codex_exit.ps1","-ProjectRoot",(Get-Location).Path,"-StopCodexFirst","-SurfaceSidebar","-SurfaceProjectRoot","D:\workspace\ai-workspace\linux-web-mysql","-SurfaceOffsetPerProject","10","-SurfacePerProject","10","-SurfaceMaxTotal","10") -WindowStyle Hidden
立即验证辅助程序是否已接管:
$root = (Get-Location).Path
$safeName = ($root -replace '^[A-Za-z]:\\?', '' -replace '[\\/:*?"<>| ]+', '-').Trim('-')
$log = Join-Path $root ".codex-session-recovery-$safeName.log"
Start-Sleep -Seconds 2
if (-not (Test-Path -LiteralPath $log)) {
Get-Process powershell -ErrorAction SilentlyContinue | Select-Object Id,StartTime,Path
Get-Process | Where-Object { $_.ProcessName -match '^(Codex|codex)$' } | Select-Object Id,ProcessName,Path
throw "Recovery helper did not create its log; use explicit -LogPath or UAC helper."
}
Get-Content -LiteralPath $log -Tail 20
如果用户同意自动恢复,但常规的 Start-Process 因进程环境中同时包含 Path 和 PATH 而失败,请在启动辅助程序前移除重复的进程级键:
$envs = [System.Environment]::GetEnvironmentVariables("Process")
if ($envs.Contains("Path") -and $envs.Contains("PATH")) {
$pathValue = $envs["Path"]
[System.Environment]::SetEnvironmentVariable("PATH", $null, "Process")
[System.Environment]::SetEnvironmentVariable("Path", $pathValue, "Process")
}
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
Start-Process -FilePath "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList @("-NoProfile","-ExecutionPolicy","Bypass","-File","$skill\scripts\run_recovery_after_codex_exit.ps1","-ProjectRoot",(Get-Location).Path,"-StopCodexFirst") -WindowStyle Hidden
如果 Stop-Process 因 Access is denied 而失败,请请求用户通过 UAC 批准以提升权限运行辅助程序:
$skill = "C:\Users\admin\.codex\skills\codex-session-recovery"
$script = "$skill\scripts\run_recovery_after_codex_exit.ps1"
$root = (Get-Location).Path
$log = "C:\tmp\codex-session-recovery-$((Split-Path -Leaf $root) -replace '[\\/:*?""<>| ]+', '-').log"
$args = "-NoProfile -ExecutionPolicy Bypass -File `"$script`" -ProjectRoot `"$root`" -LogPath `"$log`" -StopCodexFirst"
Start-Process -FilePath "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -ArgumentList $args -Verb RunAs -WindowStyle Normal
创建一次性辅助脚本时,不要在由 Codex 启动的进程中使用 taskkill /T。它可能会在恢复运行前杀死辅助程序。请使用不带 /T 的 taskkill /F /IM Codex.exe 和 taskkill /F /IM codex.exe,然后运行恢复和验证命令。
输出解读
- 在试运行模式下,
write_performed: false是预期结果。 missing_from_session_index: 0表示旧的轻量级索引已修复。missing_global_hints: 0和missing_project_assignments: 0表示侧边栏/项目状态已包含目标映射。cwd_exact_match_risk: false表示 SQLite 中的threads.cwd值与 UI 项目根目录的字符串完全匹配。请将此项视为成功标准之一,而非可选诊断信息。- 如果
codex_processes_running不为空,且写入后全局状态字段仍然缺失,则 Codex 可能从内存中覆盖了文件。请完全关闭 Codex,并在外部运行脚本。 - 如果这些计数均为零,但 UI 仍未显示任何线程,请检查 app-server
thread/list与 UI 项目根目录之间是否存在cwd完全匹配问题。 - 如果
missing_*计数均为零,且全局状态中包含该项目,但 UI 仍为空,请检查state_5.sqlite中的threads.cwd值是否类似\\?\D:\...。由于 UI 筛选可能要求字符串完全匹配,因此需要将其重新挂接到同一根目录。 - 如果日志显示
Done.,但未包含预期的重新挂接步骤,则后台进程是在脚本更新之前启动的。请启动一个新的等待脚本。 - 如果日志在
Stopping Codex processes...后立即停止,请检查辅助程序是否被其自己的关闭命令终止,或是否被权限阻止。请使用上面的自动关闭/重启指南。