Skip to main content
Glama
README.md
# Quota-aware Resumer

一个用于 Codex 额度恢复后自动续跑任务的本地控制中心。目前同时提供 **Windows 原生桌面版** 和实验性的 Codex 插件版。

如果你只是想打开一个可点击的程序,不想加载 Widget 或 Skill,建议直接使用 Windows 原生版:它是单文件 WPF 应用,界面操作不调用模型,也不消耗 token。

它用于两类场景:

1. 在五小时额度恢复后,自动回到指定任务继续尚未完成的工作;
2. 在指定日期或工作日的某个时间发送一条极短消息,**尝试**让尚未活跃的五小时窗口从更适合工作的时间开始。

> **非官方项目。** 本仓库与 OpenAI 无隶属或背书关系。额度窗口行为可能随产品更新、账号方案、工作区和服务端策略变化。

## English overview

Quota-aware Resumer now includes a native Windows WPF companion app and an experimental in-chat Codex plugin. The native app reads safe local task metadata and an exact recorded five-hour reset, then uses Windows Task Scheduler and `codex exec resume` to continue a selected task. Opening and configuring the native UI does not call a model. Actual resumed work still consumes Codex quota.

## 推荐:Windows 原生版

原生版不依赖 MCP Widget、浏览器 iframe 或 Skill。它只读取本机的任务索引字段(任务 ID、标题、更新时间)与额度元数据,不读取会话正文。

当前 MVP 支持:

- 显示最近 Codex 任务与五小时额度进度;
- 选择任务并填写恢复指令;
- 在服务端记录的精确重置时间后两分钟创建一次性 Windows 计划任务;
- 后台执行 `codex exec resume --all`,沿用当前 Codex 登录、sandbox 与审批规则;
- 在本机保存计划状态和执行日志。

仓库已包含编译好的 [原生程序](native/bin/QuotaAwareResumer.exe)。也可以自行构建和安装:

```powershell
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\native\build.ps1
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\native\install.ps1
```

安装后可从 Windows 开始菜单打开 **Quota-aware Resumer**。完整说明见 [native/README.md](native/README.md)。原生版已经支持窗口预热开关、指定日期和每周多选;跨多个额度窗口自动循环与唤醒睡眠电脑仍在后续路线图中。

## 它解决什么问题

Codex 的复杂任务可能跨过一个额度窗口。例如,一个重要任务在凌晨额度恢复,但用户不希望守在电脑前重新发送“继续完成”;或者用户上午 10 点开始工作,在中午用完额度后,需要等待到下午才能继续。

Quota-aware Resumer 把这些操作拆成可见、可修改的策略:

- 选择需要守护的 Codex 任务;
- 设置额度恢复后要发送的指令;
- 读取本机记录到的五小时和每周窗口;
- 在重置后通过 Codex 原生 Scheduled Tasks 唤醒原任务;
- 完成后停止,或在下一个额度窗口继续;
- 可选地在工作开始前发送一条最小消息,尝试预热尚未活跃的窗口。

## 功能

| 功能 | 说明 |
| --- | --- |
| Codex 内部 UI | React + MCP Apps Widget,可在对话内显示并请求全屏模式 |
| 任务选择 | 从 Codex 提供的最近任务列表中显式选择,不猜测目标任务 |
| 本地额度读取 | 从最新本地 session JSONL 的 `rate_limits` 元数据提取窗口信息 |
| 可信度门控 | 显示采样年龄与精确/估算状态;非 300 分钟或外推窗口不会被当作可靠五小时重置 |
| 重置后续跑 | 在实际 `resets_at` 后增加安全延迟,再唤醒原任务 |
| 跨窗口继续 | 使用同一条调度继续未完成目标,避免重复创建 |
| 停止条件 | 每轮使用稳定 run key 幂等记账;完成后停止,并在达到最大续跑次数后强制暂停 |
| 漏跑保护 | 逾期调度醒目标记,人工确认后只补跑一次,不自动排空队列 |
| 窗口预热 | 默认关闭;支持指定日期或每周多选星期与具体时间 |
| 本地持久化 | 策略存放在 `$CODEX_HOME/quota-aware-resumer/policies.json` |
| 隐私边界 | 不读取或保存会话正文,只提取额度字段和任务标识 |

## 重要限制

### “窗口预热”是尽力而为,不是重置器

公开的 OpenAI 文档确认 Codex 存在用量限制和计划任务能力,但没有承诺“第一条消息一定把五小时窗口锚定到接下来五小时”。因此:

- 预热只能尝试启动一个尚未活跃的新窗口;
- 如果执行时已经存在活跃窗口,消息会计入当前窗口,不会把窗口移动到设定时间;
- 插件不能强制重置额度、绕过限制或增加套餐额度;
- 实际窗口始终以 Codex 返回并记录到本地的 `resets_at` 为准;
- 服务端策略或本地 session 格式改变后,解析器可能需要更新。

默认预热消息为:

```text
额度窗口预热。请只回复“已预热”,不要读取文件、调用工具或执行其他工作。
```

预热使用独立的轻量任务,避免载入大型工作任务上下文造成额外消耗。

### 调度依赖 Codex 原生能力

MCP 服务不会绕过宿主直接修改 Codex 的调度文件。Widget 保存策略后,会向当前对话发送一条用户可见的请求,由 Codex 创建或更新原生 Scheduled Task。电脑、桌面应用、工作区权限和本地文件可用性仍受 Codex 自身要求约束。

对于本地项目,计划执行时必须保持电脑开机、ChatGPT 桌面应用运行,并确保项目目录仍可访问。电脑睡眠、关机或应用退出可能导致延迟或漏跑;当前官方能力没有给插件一个可靠的“开机后自动补跑”事件,因此控制中心会把已过期策略标成需要处理,并提供一次性的“检查并补跑”,而不是承诺凌晨一定执行。

## v0.4.0 的可靠性改进

- 修正非 300 分钟主窗口仍被标成“五小时窗口”的问题;
- 显示额度采样时间、数据新鲜度和 `exact / estimated`;
- 外推重置时间只作参考,不允许直接启用按额度自动续跑;
- 新安装尚无 session 目录时返回诊断卡片,不再导致 Widget 启动失败;
- 增加幂等运行记录、实际续跑计数和最大次数强制暂停;
- 增加逾期、目标任务缺失、最后错误、暂停和一次性补跑入口;
- 预热关闭先进入“正在暂停”,宿主确认后才显示“已暂停”;
- 修正东八区凌晨使用 UTC 计算“明天”可能错一天的问题。

研究依据与尚未解决的宿主限制见 [用户痛点研究与路线图](docs/user-pain-points-and-roadmap.md)。

## 架构

```mermaid
flowchart LR
    UI[React Control Center] -->|MCP tools/call| MCP[Local MCP server]
    MCP --> META[Local rate-limit metadata]
    MCP --> STORE[Local policy store]
    UI -->|visible user message| CODEX[Codex host]
    CODEX --> SCHED[Native Scheduled Tasks]
    SCHED --> TASK[Selected Codex task]
    TASK -->|complete / next reset| SCHED
```

设计上分为三层:

- **Widget:** 负责选择、编辑和状态展示,不作为关键状态源;
- **本地 MCP 服务:** 负责额度读取、策略校验和本地持久化;
- **Codex 原生调度:** 负责界面关闭后的定时唤醒和后续重排。

## 安装

### 从 GitHub marketplace 添加

要求:已安装支持插件 marketplace 的 Codex CLI / ChatGPT 桌面端。

```bash
codex plugin marketplace add cher9lie/quota-aware-resumer --ref main
```

然后:

1. 重启 ChatGPT 桌面应用;
2. 打开 Plugins Directory;
3. 选择 **Quota-aware Resumer**;
4. 安装并启用插件;
5. 新建一个任务,输入“打开额度续跑控制中心”。

查看已配置来源或拉取更新:

```bash
codex plugin marketplace list
codex plugin marketplace upgrade quota-aware-resumer
```

### 本地开发安装

```bash
git clone https://github.com/cher9lie/quota-aware-resumer.git
cd quota-aware-resumer
npm install
npm run check
npm run build
```

构建产物位于:

- `dist/server.mjs`:自包含的本地 MCP server;
- `dist/control-center.html`:内联 JS/CSS 的 MCP Apps Widget;
- `dist/widget.js`:独立 Widget bundle,主要用于调试。

## 使用

### 打开控制中心

```text
打开额度续跑控制中心
```

Codex 会先取得最近任务列表,再调用 `open_quota_resume_control_center` 渲染 UI。

### 让任务在额度恢复后继续

1. 在“选择要守护的任务”中选择目标;
2. 修改恢复指令;
3. 设置安全延迟和最多续跑窗口数;
4. 选择是否“完成前持续续跑”;
5. 点击“启用额度续跑”;
6. 等待策略状态从“等待创建调度”变成“已启用”。

推荐的恢复指令应包含:

- 先检查目标和最近进度;
- 不重复已完成的步骤;
- 在当前权限范围内继续;
- 验证关键结果;
- 完成后停止调度;
- 再次耗尽时更新同一条调度。

### 设置工作日 07:00 预热

1. 打开“额度窗口预热”开关;
2. 选择“每周重复”;
3. 选择周一至周五;
4. 时间设置为 `07:00`;
5. 保留默认轻量消息,或填写不超过 240 字的消息;
6. 点击“保存并启用预热”。

如果关闭开关并保存,插件只会暂停该策略记录的预热调度,不会影响其他 Scheduled Tasks。

## MCP 工具

| 工具 | 可见性 | 作用 |
| --- | --- | --- |
| `open_quota_resume_control_center` | model | 获取快照并渲染控制中心 |
| `quota_resumer_get_snapshot` | app | 刷新额度和策略状态 |
| `quota_resumer_upsert_policy` | app | 保存或更新续跑策略 |
| `quota_resumer_set_policy_state` | model + app | 同步原生调度状态 |
| `quota_resumer_record_run` | model | 幂等记录每轮结果、递增次数并执行最大次数止损 |
| `quota_resumer_upsert_prewarm` | app | 保存窗口预热策略 |
| `quota_resumer_set_prewarm_state` | model + app | 同步预热调度状态 |

同一任务只维护一条未完成续跑策略,预热也只维护一个策略记录。每次运行使用稳定 `runKey` 去重,避免同一轮被重复计数或重复续排。

## 本地数据与隐私

插件会读取:

- `$CODEX_HOME/sessions/**/rollout-*.jsonl` 中最新的 `token_count.rate_limits`;
- Codex 传给 Widget 的任务 ID、标题、状态和项目标签。

插件不会主动读取或保存:

- 对话正文;
- 未由用户明确填入策略的提示词历史;
- 项目源代码;
- API key、登录 token 或 GitHub 凭据。

策略数据写入:

```text
$CODEX_HOME/quota-aware-resumer/policies.json
```

该文件以明文保存用户明确填写的恢复指令、预热消息、任务 ID/标题和调度状态。不要在恢复指令中放入密钥或机密;删除这个文件可清除插件本地策略,但不会自动删除 Codex 宿主中已经创建的 Scheduled Tasks。

同一 MCP 进程内的写入会串行执行,并采用唯一临时文件 + 原子重命名,降低并发覆盖和进程中断造成文件损坏的概率。

## 开发

要求:

- Node.js 20+
- npm
- PowerShell 7(仅兼容脚本和 Windows 手动排查需要)

常用命令:

```bash
npm install
npm run check
npm run build
npm start
```

测试:

```bash
node scripts/smoke-test.mjs
node scripts/prewarm-state-test.mjs
node scripts/reliability-state-test.mjs
```

`smoke-test.mjs` 会启动打包后的 MCP server、检查 7 个工具、调用控制中心并读取 Widget resource。`prewarm-state-test.mjs` 使用临时 `CODEX_HOME` 验证预热策略保存与状态同步。`reliability-state-test.mjs` 验证空 session 诊断、run key 去重和最大续跑次数止损;它们都不会修改真实策略。

## 目录结构

```text
quota-aware-resumer/
├─ .codex-plugin/plugin.json
├─ .mcp.json
├─ .agents/plugins/marketplace.json
├─ dist/
│  ├─ server.mjs
│  ├─ control-center.html
│  └─ widget.js
├─ server/
│  ├─ quota.ts
│  ├─ server.ts
│  └─ state.ts
├─ web/
│  ├─ control-center.tsx
│  ├─ control-center.css
│  ├─ prewarm.css
│  └─ reliability.css
├─ skills/quota-aware-resumer/
├─ docs/user-pain-points-and-roadmap.md
├─ scripts/
├─ build.mjs
└─ package.json
```

`dist/` 有意提交到仓库,因为插件的 `.mcp.json` 直接启动 `dist/server.mjs`,安装用户不需要在本机执行 npm 生命周期脚本。

## 参考文档

- [Package your plugin](https://developers.openai.com/plugins/build/plugins)
- [Add UI to your MCP server](https://developers.openai.com/plugins/build/chatgpt-ui)
- [Build an MCP server](https://developers.openai.com/plugins/build/mcp-server)
- [Scheduled tasks](https://learn.chatgpt.com/docs/automations)
- [Codex pricing](https://learn.chatgpt.com/docs/pricing)

## 已知问题

- 本地 session JSONL 不是公开稳定 API;Codex 更新后可能需要调整解析器;
- 预热是否改变窗口起点取决于服务端实际行为;
- 本地电脑睡眠、关机或桌面应用未运行时,Scheduled Task 可能延迟或错过;
- 插件尚不能读取原生 automation 的完整运行历史,也不能在系统唤醒事件上自动补偿;
- 本仓库完成了本地 MCP 协议回路测试,但不同 Codex / ChatGPT 桌面版本的 Widget 宿主行为可能不同;
- 插件不会自动购买 credits、使用 banked reset 或绕过账户限制。

## 贡献

欢迎提交 Issue 或 Pull Request。涉及额度解析变化时,请提供脱敏后的字段结构,不要上传完整 session JSONL、对话正文、访问令牌或项目机密。

提交前请运行:

```bash
npm run check
npm run build
node scripts/smoke-test.mjs
node scripts/prewarm-state-test.mjs
```

## 许可证

本项目采用 [MIT License](LICENSE)。Copyright (c) 2026 cher9lie。

TDQS

B3.4/5.0

Scored across 6 tools

Disambiguation5/5

Each tool maps to a distinct action and resource: display control center, refresh snapshot, upsert policy, sync policy state, upsert prewarm, and sync prewarm state. The policy vs prewarm and upsert vs set distinctions are clear and unlikely to be confused.

Naming Consistency4/5

Five of six tools consistently use the quota_resumer_ prefix with a verb_noun shape. The exception is open_quota_resume_control_center, which drops the prefix and changes 'resumer' to 'resume', creating a minor but noticeable inconsistency.

Tool Count5/5

Six tools is a well-scoped size for this domain, covering control-center interaction, state refresh, policy management, and prewarm management without unnecessary redundancy. Each tool has a clear purpose and earns its place.

Completeness3/5

The set covers core lifecycle operations through upsert and state sync, and the snapshot/control center tools provide visibility. However, there is no explicit delete/remove operation for policies or prewarm settings, and no detailed list/get beyond the aggregate snapshot, leaving cleanup of stale entries as a notable gap.

Maintenance

ActivityMaintained
ResponsivenessNo issues