Merge main into codex-edits

Resolve conflict in gate-pre-continuation.md by keeping the codex-edits
tri-state TIMER_SUPPORT model (cron/blocking-sleep/prompt) while folding
in main's 10-minute post-reset buffer for the cron branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
stephenleo
2026-04-19 14:44:41 +08:00
3 changed files with 25 additions and 22 deletions

View File

@@ -1,16 +1,18 @@
#!/bin/bash
# BAD session-state capture — installed to {project-root}/.claude/bad-statusline.sh
# during /bad setup. Configured as the Claude Code statusLine script so it runs
# after every API response and writes the session JSON to a temp file that the
# BAD coordinator reads during Pre-Continuation Checks.
# after every API response and writes the session JSON to .claude/bad-session-state.json
# (next to this script) that the BAD coordinator reads during Pre-Continuation Checks.
#
# To chain with an existing statusline script:
# SESSION_JSON=$(cat)
# echo "$SESSION_JSON" | /path/to/your-existing-script.sh
# echo "$SESSION_JSON" > "${TMPDIR:-/tmp}/bad-session-state.json"
# SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# echo "$SESSION_JSON" > "$SCRIPT_DIR/bad-session-state.json"
SESSION_JSON=$(cat)
echo "$SESSION_JSON" > "${TMPDIR:-/tmp}/bad-session-state.json"
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
echo "$SESSION_JSON" > "$SCRIPT_DIR/bad-session-state.json"
# Output nothing — add your own status text here if desired, e.g.:
# python3 -c "
# import sys, json

View File

@@ -11,7 +11,7 @@ If `NOTIFY_SOURCE` is not `"terminal"` (i.e. a channel like Telegram is configur
Read the current session state using the Bash tool:
```bash
cat "${TMPDIR:-/tmp}/bad-session-state.json" 2>/dev/null || echo "{}"
cat ".claude/bad-session-state.json" 2>/dev/null || echo "{}"
```
Parse the output as JSON. The relevant fields:
@@ -22,7 +22,7 @@ Parse the output as JSON. The relevant fields:
- `rate_limits.seven_day.used_percentage` — 0100 (Claude Code only)
- `rate_limits.seven_day.resets_at` — Unix epoch seconds when the 7-day window resets
**If the file does not exist** — print `"⚠️ Pre-Continuation: session state unavailable (bad-session-state.json missing — check that the session-state hook is installed via /bad setup Step 3). Skipping rate limit checks."` and proceed.
**If the file does not exist** — print `"⚠️ Pre-Continuation: session state unavailable (.claude/bad-session-state.json missing — check that the session-state hook is installed via /bad setup Step 3). Skipping rate limit checks."` and proceed.
**If a specific field is absent** — silently skip only that check. If the file exists but `rate_limits` is entirely absent, print `"⚠️ Pre-Continuation: rate limit data not in session state — skipping usage checks."` once (not on every gate).
@@ -49,12 +49,12 @@ If `rate_limits.five_hour.used_percentage` is present and **> `API_FIVE_HOUR_THR
date -d @{resets_at}
```
2. Print: `"⏸ 5-hour usage limit at {usage}% — auto-pausing until reset at {reset_time}. BAD will resume automatically."`
3. **If `TIMER_SUPPORT=cron`** (or legacy `true`): compute a cron expression from the reset epoch and schedule a resume:
3. **If `TIMER_SUPPORT=cron`** (or legacy `true`): compute a cron expression 10 minutes after the reset epoch (to avoid a false positive if the reset lands slightly late) and schedule a resume:
```bash
# macOS
date -r {resets_at} '+%M %H %d %m *'
date -r $(( {resets_at} + 600 )) '+%M %H %d %m *'
# Linux
date -d @{resets_at} '+%M %H %d %m *'
date -d @$(( {resets_at} + 600 )) '+%M %H %d %m *'
```
Call `CronCreate`:
- `cron`: expression from above
@@ -86,12 +86,12 @@ If `rate_limits.seven_day.used_percentage` is present and **> `API_SEVEN_DAY_THR
date -d @{resets_at}
```
2. Print: `"⏸ 7-day usage limit at {usage}% — auto-pausing until reset at {reset_time}. BAD will resume automatically."`
3. **If `TIMER_SUPPORT=cron`** (or legacy `true`): compute a cron expression from the reset epoch and schedule a resume:
3. **If `TIMER_SUPPORT=cron`** (or legacy `true`): compute a cron expression 10 minutes after the reset epoch (to avoid a false positive if the reset lands slightly late) and schedule a resume:
```bash
# macOS
date -r {resets_at} '+%M %H %d %m *'
date -r $(( {resets_at} + 600 )) '+%M %H %d %m *'
# Linux
date -d @{resets_at} '+%M %H %d %m *'
date -d @$(( {resets_at} + 600 )) '+%M %H %d %m *'
```
Call `CronCreate`:
- `cron`: expression from above

View File

@@ -8,9 +8,7 @@ loses no existing functionality.
## Step 1: Find the Effective Existing Command
Claude Code applies `statusLine` using this precedence (highest to lowest). Scan in order and
stop at the first file that has a `statusLine.command`. Skip any command already equal to
`.claude/bad-statusline.sh` (re-run guard).
Claude Code applies `statusLine` using this precedence (highest to lowest):
| Priority | File | Writable by setup |
|----------|------|-------------------|
@@ -19,11 +17,13 @@ stop at the first file that has a `statusLine.command`. Skip any command already
| 3 | `{project-root}/.claude/settings.json` | No — local.json takes precedence |
| 4 (lowest) | `~/.claude/settings.json` | No — outside project scope |
- If found at priority 1 (managed): set `MANAGED_CONFLICT=true` — go directly to the managed
warning below and stop. Writing to `settings.local.json` would have no effect since managed
settings override all user-writable files.
- If found at priority 24: save the value as `CHAIN_COMMAND`.
- If not found anywhere: `CHAIN_COMMAND` is empty.
Scan priorities 1 → 4 in order. For each file that has a `statusLine.command`:
- **If the command equals `.claude/bad-statusline.sh`**: this is a re-run — skip this entry and **continue to the next lower-priority file**. Do not stop here.
- **If the command is anything else at priority 1 (managed)**: set `MANAGED_CONFLICT=true`, go directly to the managed warning below, and stop.
- **If the command is anything else at priority 24**: set `CHAIN_COMMAND` to that value and stop.
If no non-BAD `statusLine.command` is found anywhere: `CHAIN_COMMAND` is empty.
---
@@ -38,10 +38,11 @@ If `CHAIN_COMMAND` is non-empty, rewrite the script body:
#!/bin/bash
# BAD session-state capture — auto-generated by /bad setup.
# Chains pre-existing statusLine command then writes Claude Code session JSON
# to a temp file for BAD Pre-Continuation Checks.
# to .claude/bad-session-state.json for BAD Pre-Continuation Checks.
SESSION_JSON=$(cat)
echo "$SESSION_JSON" | <CHAIN_COMMAND>
echo "$SESSION_JSON" > "${TMPDIR:-/tmp}/bad-session-state.json"
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
echo "$SESSION_JSON" > "$SCRIPT_DIR/bad-session-state.json"
```
If `CHAIN_COMMAND` is empty, keep the script body as-is.