diff --git a/docs/superpowers/specs/2026-03-22-codex-hud-design.md b/docs/superpowers/specs/2026-03-22-codex-hud-design.md index c7c7e0d..947958a 100644 --- a/docs/superpowers/specs/2026-03-22-codex-hud-design.md +++ b/docs/superpowers/specs/2026-03-22-codex-hud-design.md @@ -140,6 +140,11 @@ type HudState = { toolCounts: Record taskProgress: { done: number; total: number } | null + // from JSONL token_count event (bonus: rate limit data) + rateLimitPrimary: { usedPercent: number; windowMinutes: number; resetsAt: number } | null + rateLimitSecondary: { usedPercent: number; windowMinutes: number; resetsAt: number } | null + planType: string | null // "plus" | "pro" | "team" | ... + // from timer elapsedSec: number @@ -360,6 +365,14 @@ inline 初始化失败 --> 自动降级到 passthrough mode > 这三个 spike 必须在写 implementation plan 之前完成。每个 spike 是独立的小脚本或手工验证,目标是锁定架构假设,不是实现功能。 +**Spike 状态总览(2026-03-22):** + +| Spike | 状态 | 结论 | +|-------|------|------| +| Spike 1: Pane Mode Capability | 待手工验证 | tmux 未安装,需先安装再测 | +| Spike 2: Data Source Stability | **已完成** | SQLite + JSONL 均稳定可依赖,有额外 rate limit 发现 | +| Spike 3: Inline Fallback Safety | 待手工验证 | 需在真实 TTY 中运行测试脚本 | + --- ### Spike 1: Pane Mode Capability @@ -391,6 +404,9 @@ codex - 探测不可靠 → pane mode 进入条件收紧,宁可误降级到 inline 也不误进 pane - kill-pane 不可靠 → pane 生命周期改为"codex 退出时发送信号给 HUD 子进程,HUD 进程自行退出" +**当前状态(2026-03-22):tmux 未安装,待手工验证。** +手工步骤:`brew install tmux` → 在 tmux session 内运行上述验证命令 → 记录结论。 + --- ### Spike 2: Data Source Stability @@ -434,6 +450,54 @@ tail -f ~/.codex/sessions/$(date +%Y/%m/%d)/rollout-*.jsonl | \ --- +### Spike 2 结论(已完成,2026-03-22) + +**SQLite `threads` 表 — 全部字段已验证稳定:** + +| 字段 | 实测值样本 | 结论 | +|------|-----------|------| +| `model` | `gpt-5.4` | 稳定,session 开始时写入 | +| `cwd` | `/Users/manpengan/pro/nas-infra` | 稳定,准确 | +| `git_branch` | `main` / 空字符串(非 git 目录) | 稳定,非 git 目录为空字符串 | +| `tokens_used` | `710865`, `6413335` | 稳定递增,线程累计值 | +| `updated_at` | Unix timestamp(秒) | 每轮对话更新 | + +**JSONL 事件 — 跨 2 个 session 验证,事件名稳定:** + +| event 类型 | payload.type | 关键字段 | HUD 用途 | +|-----------|--------------|----------|----------| +| `session_meta` | — | `cwd`, `cli_version`, `model_provider` | session 初始化 | +| `event_msg` | `task_started` | `turn_id`, `model_context_window: 258400` | turn 开始,context window 大小 | +| `event_msg` | `task_complete` | `turn_id`, `last_agent_message` | turn 结束 | +| `event_msg` | `token_count` | `rate_limits.primary.used_percent`, `secondary.used_percent`, `plan_type` | **rate limit 显示** | +| `event_msg` | `agent_message` | `message`, `phase` | agent 回复内容 | +| `response_item` | `function_call` | `name`(工具名), `call_id` | tool 开始 | +| `response_item` | `function_call_output` | `call_id`(匹配) | tool 结束 | +| `response_item` | `reasoning` | 内部推理 | 可忽略 | +| `turn_context` | — | `cwd`, `timezone`, `approval_policy` | 每轮上下文 | + +**额外发现(超出原预期):** +- `token_count.rate_limits` 直接给出 `primary.used_percent`(5分钟窗口)和 `secondary.used_percent`(周窗口) +- 这是 claude-hud 需要单独调用 OAuth API 才能拿到的数据,Codex 直接写在 JSONL 里 +- `model_context_window: 258400` 给出每个 turn 的 context 窗口大小 + +**结论对 HudState 的影响:** +- `tokensUsedTotal`:来自 SQLite `threads.tokens_used`,可信 +- `rateLimitPrimary` / `rateLimitSecondary`:来自 `token_count` JSONL 事件,可信(**新增字段**) +- `activeTool`:来自 `function_call` / `function_call_output` 配对,可信 +- `taskProgress`:无直接字段,需从 `task_started`/`task_complete` 事件计数推断 +- context window usage:`model_context_window` 大小已知,但当前 turn 的 input token 数暂未找到来源 + +**更新后的 HudState(在 Section 4.2 中同步):** +```typescript +// 新增字段(来自 token_count 事件) +rateLimitPrimary: { usedPercent: number; windowMinutes: number; resetsAt: number } | null +rateLimitSecondary: { usedPercent: number; windowMinutes: number; resetsAt: number } | null +planType: string | null // "plus" | "pro" | ... +``` + +--- + ### Spike 3: Inline Fallback Safety **目标:** 确认 `codex --no-alt-screen` 下能预留底部区域,且 wrapper crash/exit 后不会弄脏终端。 @@ -472,6 +536,36 @@ setTimeout(() => { - scroll region 在任一目标终端不稳定 → inline mode 标记为"实验性",默认不启用,需 `--inline` flag 显式开启 - cleanup 不可靠 → cleanup 逻辑改为双重保险:正常路径 + `process.on('exit')` 兜底 +**当前状态(2026-03-22):需在真实 TTY 中手工验证。** +在真实终端(非 Claude Code 子 shell)中运行: + +```bash +# 保存到 /tmp/spike3.mjs 后执行:node /tmp/spike3.mjs +const rows = process.stdout.rows; +const cols = process.stdout.columns; +if (!rows) { console.error('Not a TTY'); process.exit(1); } +console.log(`Terminal: ${cols}x${rows}`); +process.stdout.write('\x1b[s'); +process.stdout.write(`\x1b[1;${rows - 4}r`); +process.stdout.write(`\x1b[${rows - 3};1H\x1b[2K=== HUD 1: model | cwd | main* | 2m ===`); +process.stdout.write(`\x1b[${rows - 2};1H\x1b[2K=== HUD 2: tokens 12,340 | Write 3s ===`); +process.stdout.write(`\x1b[${rows - 1};1H\x1b[2K=== HUD 3: shell(3) read(7) ===`); +process.stdout.write(`\x1b[${rows};1H\x1b[2K=== HUD 4: task 3/5 ===`); +process.stdout.write('\x1b[u'); +setTimeout(() => { + process.stdout.write('\x1b[r'); + for (let i = rows - 3; i <= rows; i++) + process.stdout.write(`\x1b[${i};1H\x1b[2K`); + process.stdout.write(`\x1b[${rows};1H`); + console.log('\nCLEANUP OK'); +}, 3000); +``` + +通过标准: +- HUD 4 行固定在底部,主区域可自由滚动 +- 3 秒后自动清除,光标恢复,终端无残留 +- 在 macOS Terminal.app / iTerm2 / Ghostty 中各测一次 + --- **三个 spike 全部通过后,才进入 implementation plan。**