mcpField
C
codex-session-recovery

codex-session-recovery

github.com/huajiexiewenfengAgent 工作流880 次安装22 周前更新
代码仓库

关于 codex-session-recovery

codex-session-recovery 是面向开发者的恢复 Skill,用于处理仍保存在本地、却未显示在 Codex Desktop 界面的会话。它检查会话索引、项目映射和工作目录精确匹配情况,并指导先备份再修复和验证。

主要功能

  1. 01以 dry-run 模式执行恢复检查
  2. 02查找缺失的会话索引记录
  3. 03检查项目与侧边栏映射
  4. 04备份后修复会话元数据
  5. 05验证恢复结果和工作目录匹配
  6. 06处理隐藏线程及最近会话数量限制

适用场景

  1. 01恢复界面中缺失的 Codex 会话
  2. 02诊断项目根目录与会话路径不匹配
  3. 03备份后修复侧边栏分配
  4. 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.py
reparent_codex_sessions.py
restore_codex_project_sessions.py
run_recovery_after_codex_exit.ps1
surface_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 根目录。

工作流

  1. 解析 CODEX_HOME。
    • 如果 $env:CODEX_HOME 指向一个实际存在的目录,优先使用它。
    • 否则使用 %USERPROFILE%\.codex。
  2. 解析目标项目根目录。
    • 使用用户提供的路径。
    • 如果用户未提供路径,且当前工作区就是目标项目,则使用当前工作目录。
  3. 先以试运行模式运行捆绑脚本。
  4. 阅读报告中的以下字段:
    • exact_project_sessions
    • missing_from_session_index
    • missing_global_hints
    • sqlite_exact_ui_cwd_threads
    • sqlite_non_exact_ui_cwd_threads
    • cwd_exact_match_risk
    • codex_processes_running
    • can_write_global_state_safely
  5. 如果 Codex 正在运行,且需要修复全局状态:
    • 在请求用户采取操作之前,先提供简短的分步状态摘要。
    • 不要只说“完全退出 Codex”;很多用户不知道如何关闭 Electron、托盘进程和辅助 codex.exe 进程。
    • 询问用户是否希望 Agent 自动关闭并重启 Codex,然后继续恢复。
    • 如果用户同意,使用外部辅助进程,以便在当前 Codex 窗口退出后继续恢复。
    • 如果用户拒绝,请其完全退出 Codex Desktop,然后从外部终端运行脚本。
    • 如果用户接受覆盖风险,使用 --allow-running-codex 运行,但要说明 SQLite 仍可能被锁定,且 Electron 可能覆盖全局状态。
  6. 运行写入模式。在 Windows 上,优先使用 --normalize-windows-extended-paths,让主脚本也将同一目录中 \\?\D:\... 格式的 cwd 值重写为完全一致的显示根目录字符串。
  7. 重新以试运行模式运行,验证:
    • missing_from_session_index: 0
    • missing_global_hints: 0
    • missing_project_assignments: 0
    • missing_sidebar_order: 0
    • cwd_exact_match_risk: false
  8. 如果界面仍未显示这些对话:
    • 检查 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,将一组有数量限制、按轮次排列的已恢复项目对话提升到最近对话缓存中。此操作会更新 JSONL task_complete.completed_at、SQLite updated_at/updated_at_ms 和全局项目映射,并生成备份和报告。
  9. 如果恢复需要重启,请告知用户接下来会发生什么,并询问是否要自动执行。如果用户同意,运行重启辅助程序;如果不同意,请其重新打开 Codex Desktop 并检查项目列表。
  10. 启动任何隐藏的外部辅助程序后,在确认其确实已接管之前,不要声称它正在运行:
  • 检查项目根目录下是否存在预期的日志文件,或在 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 均为零,但左侧边栏仍未显示历史记录,请不要急着认定恢复成功。请按以下顺序检查:

  1. 确认 Codex 确实运行了最新的恢复脚本。日志应包含预期的步骤名称。在编辑脚本前启动且正在等待的脚本会继续运行旧的脚本内容。
  2. 写入前确认没有仍在运行的 Codex 或 codex 进程。运行中的 Electron 可能会用内存中的状态覆盖数据。
  3. 检查主脚本的 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 界面仍可能隐藏这些会话。

  1. 检查 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
  1. 检查 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 与其中一个路径完全匹配的线程。

  1. 比较项目根目录与 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,那么即使全局状态映射看起来正确,边栏仍可能为空。

  1. 在这种情况下,只重新指定完全匹配的项目会话的父级:

    • 备份 state_5.sqlite
    • 备份每个已更改的 sessions/**/*.jsonl
    • 更新 threads.cwd
    • 更新 JSONL 中的 session_meta.payload.cwd 和 turn_context.payload.cwd 条目
    • 将 .codex-global-state.json 项目映射更新为显示根目录
  2. 如果出现了一个可见的新测试对话,但同一项目中的较早对话没有显示:

    • 使用 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... 后立即停止,请检查辅助程序是否被其自己的关闭命令终止,或是否被权限阻止。请使用上面的自动关闭/重启指南。

评论

支持 Markdown