Skip to content

Instantly share code, notes, and snippets.

@benhook1013
Last active April 30, 2026 08:43
Show Gist options
  • Select an option

  • Save benhook1013/0ddeac5277f5515080ff5756bc9d7849 to your computer and use it in GitHub Desktop.

Select an option

Save benhook1013/0ddeac5277f5515080ff5756bc9d7849 to your computer and use it in GitHub Desktop.
t3-checkpoints local CLI utility and bash completion
#!/usr/bin/env bash
set -euo pipefail
umask 077
CONFIG_FILE="${T3_CHECKPOINTS_CONFIG_FILE:-$HOME/.t3-checkpoints/config.env}"
if [[ ! -f "$CONFIG_FILE" ]]; then
mkdir -p "$(dirname "$CONFIG_FILE")"
cat > "$CONFIG_FILE" <<'EOF'
# t3-checkpoints local config
#
# Uncomment and edit any values you want to override for this machine.
#
# T3_CHECKPOINTS_REPO_DIR="$HOME/src/FireMUD"
# T3_CHECKPOINTS_CODEX_ROOT="$HOME/.codex"
# T3_CHECKPOINTS_T3CODE_DB_PATHS="$HOME/.t3/userdata/state.sqlite:$HOME/.t3/dev/state.sqlite"
# T3_CHECKPOINTS_DEFAULT_KEEP="5"
# T3_CHECKPOINTS_DEFAULT_PRUNE_DAYS="5"
EOF
chmod 600 "$CONFIG_FILE"
fi
# shellcheck disable=SC1090
source "$CONFIG_FILE"
DEFAULT_KEEP="${T3_CHECKPOINTS_DEFAULT_KEEP:-5}"
DEFAULT_PRUNE_DAYS="${T3_CHECKPOINTS_DEFAULT_PRUNE_DAYS:-5}"
MIN_SAFE_KEEP_COMMITS=3
KEEP="$DEFAULT_KEEP"
PRUNE_DAYS="$DEFAULT_PRUNE_DAYS"
APPLY=0
RUN_GC=1
INSPECT_CODEX=1
INSPECT_T3CODE=1
CODEX_ROOT="${T3_CHECKPOINTS_CODEX_ROOT:-$HOME/.codex}"
DEFAULT_T3CODE_DB_PATHS="$HOME/.t3/userdata/state.sqlite:$HOME/.t3/dev/state.sqlite"
T3CODE_DB_PATHS_RAW="${T3_CHECKPOINTS_T3CODE_DB_PATHS:-$DEFAULT_T3CODE_DB_PATHS}"
declare -a T3CODE_DB_PATHS=()
REPO_DIR="${T3_CHECKPOINTS_REPO_DIR:-}"
COMMAND=""
MODE=""
usage() {
cat <<'EOF'
Inspect and optionally prune T3 Code checkpoint refs.
Usage:
t3-checkpoints help
t3-checkpoints plan prune-chat-checkpoints [N] [options]
t3-checkpoints apply prune-chat-checkpoints [N] [options]
t3-checkpoints plan clear-chat-checkpoints [N] [options]
t3-checkpoints apply clear-chat-checkpoints [N] [options]
t3cp ...
Commands:
help
Show this help text.
plan
Report what would be deleted.
apply
Delete refs after reporting the plan.
Modes:
prune-chat-checkpoints [N]
Keep turn 0 plus the latest N-1 non-baseline checkpoint refs per thread.
This preserves the canonical baseline ref used by T3 Code diffs. Trim mode
enforces a minimum of 3 total refs so the previous-turn and latest-turn
diff flow keeps working. Default: 5.
clear-chat-checkpoints [N]
Delete every checkpoint ref for threads whose latest checkpoint is older
than N days. This removes the entire checkpoint history for those chats.
After prune, T3/Codex-style checkpoint diff viewing and checkpoint-based
revert for those chats will no longer work. Default: 5.
Options for plan/apply:
--repo PATH
Operate on the Git repo at PATH.
--no-gc
Skip reflog expiry and git gc after deleting refs. Applies to `apply`.
--codex-root PATH
Inspect Codex state under PATH instead of ~/.codex.
--no-codex-inspect
Skip local Codex-state inspection and classification. Advisory only.
--t3-db PATH
Inspect a specific T3 Code SQLite state database. May be passed multiple
times. Defaults to ~/.t3/userdata/state.sqlite and ~/.t3/dev/state.sqlite.
--no-t3code-inspect
Skip T3 Code state inspection and safety guards. Unsafe for apply.
--help
Show command help.
This utility only considers refs matching:
refs/t3/checkpoints/<thread-id>/turn/<integer>
It never touches normal branches, tags, remotes, or other refs.
When enabled, T3 Code state inspection is treated as authoritative for whether
checkpoint refs are still needed for live or archived threads.
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
validate_positive_integer() {
local value="$1"
[[ "$value" =~ ^[1-9][0-9]*$ ]]
}
format_epoch() {
local epoch="$1"
if [[ -z "$epoch" || "$epoch" == "0" ]]; then
printf 'unknown'
return
fi
date -d "@$epoch" '+%Y-%m-%d %H:%M:%S %z'
}
inspect_codex_state() {
local thread_file="$1"
local output_file="$2"
if ! command -v python3 >/dev/null 2>&1; then
echo "Codex-state inspection unavailable: python3 not found." >&2
return 1
fi
if ! python3 - "$CODEX_ROOT" "$thread_file" >"$output_file" <<'PY'
import base64
import json
import sqlite3
import sys
from pathlib import Path
codex_root = Path(sys.argv[1]).expanduser()
thread_file = Path(sys.argv[2])
thread_ids = [line.strip() for line in thread_file.read_text().splitlines() if line.strip()]
def decode_thread_id(value: str):
padded = value + "=" * ((4 - len(value) % 4) % 4)
try:
decoded = base64.urlsafe_b64decode(padded.encode("ascii"))
except Exception:
return None
if len(decoded) == 16:
try:
import uuid
return str(uuid.UUID(bytes=decoded))
except Exception:
return None
try:
text = decoded.decode("utf-8")
except UnicodeDecodeError:
return None
return text if text and text.isprintable() else None
records = []
db_thread_ids = set()
db_path = codex_root / "state_5.sqlite"
db_status = "missing"
db_error = None
if db_path.exists():
try:
with sqlite3.connect(db_path) as conn:
tables = {row[0] for row in conn.execute("select name from sqlite_master where type = 'table'")}
if "threads" in tables:
columns = {row[1] for row in conn.execute("pragma table_info(threads)")}
if "id" in columns:
db_thread_ids = {
str(row[0]) for row in conn.execute("select id from threads") if row[0] is not None
}
db_status = "threads.id"
else:
db_status = "threads table without id column"
else:
db_status = "threads table missing"
except Exception as exc:
db_status = "error"
db_error = str(exc)
sessions_root = codex_root / "sessions"
session_hits = {thread_id: [] for thread_id in thread_ids}
session_status = "missing"
if sessions_root.exists():
session_status = "scanned"
search_tokens = {}
for thread_id in thread_ids:
tokens = {thread_id}
decoded = decode_thread_id(thread_id)
if decoded:
tokens.add(decoded)
search_tokens[thread_id] = tuple(token for token in tokens if token)
for path in sessions_root.rglob("*"):
if not path.is_file() or path.suffix not in {".json", ".jsonl"}:
continue
try:
text = path.read_text(errors="ignore")
except Exception:
continue
rel = str(path.relative_to(codex_root))
for thread_id, tokens in search_tokens.items():
if session_hits[thread_id]:
continue
if any(token in text for token in tokens):
session_hits[thread_id].append(rel)
for thread_id in thread_ids:
decoded = decode_thread_id(thread_id)
exact_db = thread_id in db_thread_ids
decoded_db = bool(decoded and decoded in db_thread_ids)
session_paths = session_hits.get(thread_id, [])
if exact_db or decoded_db:
classification = "active-candidate"
elif session_paths:
classification = "archived-candidate"
else:
classification = "orphaned-candidate"
details = []
if exact_db:
details.append("exact sqlite thread id match")
if decoded_db:
details.append(f"decoded sqlite thread id match ({decoded})")
elif decoded:
details.append(f"decoded id candidate: {decoded}")
if session_paths:
details.append(f"session metadata hit: {session_paths[0]}")
if not details:
details.append("no sqlite or session metadata match found")
records.append(
{
"threadId": thread_id,
"classification": classification,
"details": "; ".join(details),
}
)
result = {
"codexRoot": str(codex_root),
"dbStatus": db_status,
"dbError": db_error,
"sessionStatus": session_status,
"records": records,
}
print(json.dumps(result))
PY
then
echo "Codex-state inspection failed." >&2
return 1
fi
return 0
}
populate_t3code_db_paths() {
local raw_path path
local old_ifs="$IFS"
IFS=':'
read -r -a raw_paths <<<"$T3CODE_DB_PATHS_RAW"
IFS="$old_ifs"
for raw_path in "${raw_paths[@]}"; do
path="${raw_path/#\~/$HOME}"
[[ -n "$path" ]] || continue
T3CODE_DB_PATHS+=("$path")
done
}
inspect_t3code_state() {
local thread_file="$1"
local output_file="$2"
if ! command -v python3 >/dev/null 2>&1; then
echo "T3 Code state inspection unavailable: python3 not found." >&2
return 1
fi
local joined_paths
joined_paths="$(printf '%s\n' "${T3CODE_DB_PATHS[@]}")"
if ! T3CP_T3CODE_DB_PATHS="$joined_paths" python3 - "$thread_file" "$output_file" <<'PY'
import json
import os
import sqlite3
import sys
from pathlib import Path
thread_file = Path(sys.argv[1])
output_file = Path(sys.argv[2])
db_paths = [line.strip() for line in os.environ.get("T3CP_T3CODE_DB_PATHS", "").splitlines() if line.strip()]
thread_ids = [line.strip() for line in thread_file.read_text().splitlines() if line.strip()]
records = {}
db_reports = []
for thread_id in thread_ids:
records[thread_id] = {
"threadId": thread_id,
"classification": "orphaned-candidate",
"details": [],
"sources": [],
}
def add_detail(thread_id: str, db_path: Path, detail: str):
record = records[thread_id]
record["details"].append(detail)
record["sources"].append(str(db_path))
def ensure_columns(conn, table):
return {row[1] for row in conn.execute(f"pragma table_info({table})")}
for raw_db_path in db_paths:
db_path = Path(raw_db_path).expanduser()
report = {
"path": str(db_path),
"status": "missing",
"error": None,
}
if not db_path.exists():
db_reports.append(report)
continue
try:
with sqlite3.connect(db_path) as conn:
tables = {row[0] for row in conn.execute("select name from sqlite_master where type = 'table'")}
report["status"] = "opened"
thread_columns = ensure_columns(conn, "projection_threads") if "projection_threads" in tables else set()
runtime_columns = ensure_columns(conn, "provider_session_runtime") if "provider_session_runtime" in tables else set()
turn_columns = ensure_columns(conn, "projection_turns") if "projection_turns" in tables else set()
thread_rows = {}
if "projection_threads" in tables and "thread_id" in thread_columns:
for row in conn.execute(
"""
select thread_id, archived_at, deleted_at
from projection_threads
where thread_id in (%s)
"""
% ",".join("?" for _ in thread_ids),
thread_ids,
):
thread_rows[str(row[0])] = {
"archived_at": row[1],
"deleted_at": row[2],
}
runtime_rows = set()
if "provider_session_runtime" in tables and "thread_id" in runtime_columns:
runtime_rows = {
str(row[0])
for row in conn.execute(
"""
select thread_id
from provider_session_runtime
where thread_id in (%s)
"""
% ",".join("?" for _ in thread_ids),
thread_ids,
)
}
checkpoint_counts = {}
if (
"projection_turns" in tables
and "thread_id" in turn_columns
and "checkpoint_turn_count" in turn_columns
):
for row in conn.execute(
"""
select thread_id, count(*)
from projection_turns
where thread_id in (%s)
and checkpoint_turn_count is not null
group by thread_id
"""
% ",".join("?" for _ in thread_ids),
thread_ids,
):
checkpoint_counts[str(row[0])] = int(row[1] or 0)
for thread_id in thread_ids:
thread_row = thread_rows.get(thread_id)
runtime_bound = thread_id in runtime_rows
checkpoint_count = checkpoint_counts.get(thread_id, 0)
if thread_row:
deleted_at = thread_row["deleted_at"]
archived_at = thread_row["archived_at"]
if deleted_at:
add_detail(thread_id, db_path, f"thread deleted in T3 Code state ({deleted_at})")
if records[thread_id]["classification"] == "orphaned-candidate":
records[thread_id]["classification"] = "deleted-candidate"
elif archived_at:
add_detail(thread_id, db_path, f"thread archived in T3 Code state ({archived_at})")
records[thread_id]["classification"] = "archived-candidate"
else:
add_detail(thread_id, db_path, "thread exists in live T3 Code state")
records[thread_id]["classification"] = "live-candidate"
elif runtime_bound:
add_detail(thread_id, db_path, "provider runtime binding still exists in T3 Code state")
if records[thread_id]["classification"] not in ("live-candidate", "archived-candidate"):
records[thread_id]["classification"] = "runtime-bound-candidate"
elif checkpoint_count > 0:
add_detail(thread_id, db_path, f"T3 Code still stores {checkpoint_count} projected checkpoint row(s)")
if records[thread_id]["classification"] == "orphaned-candidate":
records[thread_id]["classification"] = "lingering-state-candidate"
except Exception as exc:
report["status"] = "error"
report["error"] = str(exc)
db_reports.append(report)
for record in records.values():
if not record["details"]:
record["details"].append("no T3 Code state match found")
record["details"] = "; ".join(record["details"])
record["sources"] = sorted(set(record["sources"]))
output_file.write_text(
json.dumps(
{
"dbReports": db_reports,
"existingDbCount": sum(1 for report in db_reports if report["status"] != "missing"),
"openedDbCount": sum(1 for report in db_reports if report["status"] == "opened"),
"allExistingDbPathsOpened": all(
report["status"] == "opened"
for report in db_reports
if report["status"] != "missing"
),
"records": [records[thread_id] for thread_id in thread_ids],
}
)
)
PY
then
echo "T3 Code state inspection failed." >&2
return 1
fi
return 0
}
resolve_repo_dir() {
if [[ -n "$REPO_DIR" ]]; then
[[ -d "$REPO_DIR/.git" || -f "$REPO_DIR/.git" ]] || die "--repo does not point at a Git repository: $REPO_DIR"
printf '%s\n' "$REPO_DIR"
return 0
fi
if git rev-parse --show-toplevel >/dev/null 2>&1; then
git rev-parse --show-toplevel
return 0
fi
die "not inside a Git repository; pass --repo PATH or set T3_CHECKPOINTS_REPO_DIR in $CONFIG_FILE"
}
parse_command_and_options() {
if (($# == 0)); then
usage
exit 0
fi
COMMAND="$1"
shift
case "$COMMAND" in
help|-h|--help)
usage
exit 0
;;
plan)
APPLY=0
;;
apply)
APPLY=1
;;
*)
die "unknown command: $COMMAND"
;;
esac
if (($# > 0)) && [[ "$1" == "help" || "$1" == "--help" || "$1" == "-h" ]]; then
usage
exit 0
fi
(($# > 0)) || die "missing mode for $COMMAND"
MODE="$1"
shift
case "$MODE" in
prune-chat-checkpoints)
if (($# > 0)) && [[ "$1" =~ ^[0-9]+$ ]]; then
KEEP="$1"
shift
fi
;;
clear-chat-checkpoints)
if (($# > 0)) && [[ "$1" =~ ^[0-9]+$ ]]; then
PRUNE_DAYS="$1"
shift
fi
;;
*)
die "unknown mode for $COMMAND: $MODE"
;;
esac
while (($# > 0)); do
case "$1" in
--repo)
(($# >= 2)) || die "--repo requires a value"
REPO_DIR="$2"
shift 2
;;
--no-gc)
RUN_GC=0
shift
;;
--codex-root)
(($# >= 2)) || die "--codex-root requires a value"
CODEX_ROOT="$2"
shift 2
;;
--no-codex-inspect)
INSPECT_CODEX=0
shift
;;
--t3-db)
(($# >= 2)) || die "--t3-db requires a value"
T3CODE_DB_PATHS+=("$2")
shift 2
;;
--no-t3code-inspect)
INSPECT_T3CODE=0
shift
;;
--help|-h)
usage
exit 0
;;
*)
die "unknown option for $COMMAND $MODE: $1"
;;
esac
done
}
run_main() {
validate_positive_integer "$KEEP" || die "prune-chat-checkpoints must be a positive integer"
validate_positive_integer "$PRUNE_DAYS" || die "clear-chat-checkpoints must be a positive integer"
if [[ "$MODE" == "prune-chat-checkpoints" ]] && ((KEEP < MIN_SAFE_KEEP_COMMITS)); then
echo "Requested prune-chat-checkpoints=$KEEP is below the safe minimum; using $MIN_SAFE_KEEP_COMMITS instead." >&2
KEEP="$MIN_SAFE_KEEP_COMMITS"
fi
REPO_DIR="$(resolve_repo_dir)"
populate_t3code_db_paths
declare -A THREAD_ENTRIES=()
declare -A THREAD_LATEST_TS=()
declare -A T3CODE_CLASSIFICATION=()
declare -A T3CODE_DETAILS=()
local threads_found=0
local valid_refs=0
local kept_refs=0
local deleted_refs=0
local protected_refs=0
local protected_threads=0
local ignored_refs=0
local inactive_threads_matched=0
local inactive_refs_matched=0
local now_epoch inactive_cutoff_epoch latest_ts count refs_to_delete latest_ts_human
local thread_id turn_number ref ref_ts latest_existing entry rest
local t3code_existing_db_count=0
local t3code_all_existing_opened=0
now_epoch="$(date +%s)"
inactive_cutoff_epoch=$((now_epoch - PRUNE_DAYS * 86400))
mapfile -t ALL_REFS < <(git -C "$REPO_DIR" for-each-ref --format='%(refname)%09%(creatordate:unix)' refs/t3/checkpoints)
for ref_with_ts in "${ALL_REFS[@]}"; do
ref="${ref_with_ts%%$'\t'*}"
ref_ts="${ref_with_ts#*$'\t'}"
[[ "$ref_ts" =~ ^[0-9]+$ ]] || ref_ts=0
if [[ "$ref" =~ ^refs/t3/checkpoints/([^/]+)/turn/([0-9]+)$ ]]; then
thread_id="${BASH_REMATCH[1]}"
turn_number="${BASH_REMATCH[2]}"
THREAD_ENTRIES["$thread_id"]+="${turn_number}"$'\t'"${ref}"$'\t'"${ref_ts}"$'\n'
latest_existing="${THREAD_LATEST_TS[$thread_id]:-0}"
if ((ref_ts > latest_existing)); then
THREAD_LATEST_TS["$thread_id"]="$ref_ts"
fi
valid_refs=$((valid_refs + 1))
else
ignored_refs=$((ignored_refs + 1))
echo "Ignoring non-checkpoint-shaped ref under refs/t3/checkpoints: $ref" >&2
fi
done
threads_found="${#THREAD_ENTRIES[@]}"
if ((threads_found == 0)); then
echo "No T3 checkpoint refs found matching refs/t3/checkpoints/<thread-id>/turn/<integer>."
echo "Repo: $REPO_DIR"
echo "Threads found: 0"
echo "Refs kept: 0"
echo "Refs would delete: 0"
exit 0
fi
if ((APPLY)); then
echo "Apply mode: $MODE"
else
echo "Report-only mode: $MODE"
fi
echo "Repo: $REPO_DIR"
case "$MODE" in
prune-chat-checkpoints)
echo "Prune-chat-checkpoints cap: preserve turn 0 and keep up to $KEEP total checkpoint ref(s) per thread"
;;
clear-chat-checkpoints)
echo "Clear-chat-checkpoints cutoff: latest checkpoint older than $PRUNE_DAYS day(s)"
echo "Inactive cutoff: $(format_epoch "$inactive_cutoff_epoch")"
;;
esac
THREAD_FILE="$(mktemp)"
INSPECTION_FILE="$(mktemp)"
trap 'rm -f "$THREAD_FILE" "$INSPECTION_FILE"' EXIT
printf '%s\n' "${!THREAD_ENTRIES[@]}" | sort >"$THREAD_FILE"
if ((INSPECT_T3CODE)); then
echo
echo "T3 Code state classification (authoritative safety check):"
if inspect_t3code_state "$THREAD_FILE" "$INSPECTION_FILE"; then
read -r t3code_existing_db_count t3code_all_existing_opened < <(
python3 - "$INSPECTION_FILE" <<'PY'
import json
import sys
payload = json.load(open(sys.argv[1]))
print(
payload.get("existingDbCount", 0),
1 if payload.get("allExistingDbPathsOpened", False) else 0,
)
PY
)
while IFS=$'\t' read -r thread_id classification details; do
[[ -n "$thread_id" ]] || continue
T3CODE_CLASSIFICATION["$thread_id"]="$classification"
T3CODE_DETAILS["$thread_id"]="$details"
done < <(
python3 - "$INSPECTION_FILE" <<'PY'
import json
import sys
from collections import Counter
payload = json.load(open(sys.argv[1]))
counts = Counter(record["classification"] for record in payload["records"])
for report in payload["dbReports"]:
if report["status"] == "missing":
continue
line = f"DB {report['path']}: {report['status']}"
if report.get("error"):
line += f" ({report['error']})"
print(line, file=sys.stderr)
for key in (
"live-candidate",
"archived-candidate",
"runtime-bound-candidate",
"lingering-state-candidate",
"deleted-candidate",
"orphaned-candidate",
):
print(f"{key}: {counts.get(key, 0)}", file=sys.stderr)
for record in payload["records"]:
print(f"{record['threadId']}\t{record['classification']}\t{record['details']}")
PY
) 2> >(sed 's/^/ /' >&2)
for thread_id in "${!T3CODE_CLASSIFICATION[@]}"; do
echo " - $thread_id: ${T3CODE_CLASSIFICATION[$thread_id]} (${T3CODE_DETAILS[$thread_id]})"
done
if ((APPLY)); then
if ((t3code_existing_db_count == 0)); then
die "No existing T3 Code state database could be inspected; refusing apply."
fi
if ((t3code_all_existing_opened == 0)); then
die "Not every existing configured T3 Code database was inspected successfully; refusing apply."
fi
fi
else
if ((APPLY)); then
die "T3 Code state inspection is unavailable; rerun with 'plan' or pass --no-t3code-inspect only if you intentionally want to bypass T3 Code safety guards."
fi
echo " T3 Code state inspection unavailable; continuing with ref-only report."
fi
else
echo
echo "T3 Code state classification skipped because --no-t3code-inspect was provided."
if ((APPLY)); then
echo "Warning: apply mode is running without T3 Code safety guards." >&2
fi
fi
if ((INSPECT_CODEX)); then
echo
echo "Codex-state candidate classification (advisory only):"
if inspect_codex_state "$THREAD_FILE" "$INSPECTION_FILE"; then
python3 - "$INSPECTION_FILE" <<'PY'
import json
import sys
from collections import Counter
payload = json.load(open(sys.argv[1]))
print(f" Codex root: {payload['codexRoot']}")
print(f" SQLite status: {payload['dbStatus']}")
if payload.get("dbError"):
print(f" SQLite error: {payload['dbError']}")
print(f" Session metadata status: {payload['sessionStatus']}")
counts = Counter(record["classification"] for record in payload["records"])
for key in ("active-candidate", "archived-candidate", "orphaned-candidate"):
print(f" {key}: {counts.get(key, 0)}")
for record in payload["records"]:
print(f" - {record['threadId']}: {record['classification']} ({record['details']})")
PY
else
echo " Codex-state inspection unavailable; continuing without advisory Codex metadata."
fi
else
echo
echo "Codex-state candidate classification skipped because --no-codex-inspect was provided."
fi
echo
while IFS= read -r thread_id; do
[[ -n "$thread_id" ]] || continue
mapfile -t sorted_entries < <(
printf '%s' "${THREAD_ENTRIES[$thread_id]}" | awk 'NF' | sort -t $'\t' -k1,1n
)
count="${#sorted_entries[@]}"
if ((count == 0)); then
continue
fi
latest_ts="${THREAD_LATEST_TS[$thread_id]:-0}"
latest_ts_human="$(format_epoch "$latest_ts")"
echo "Thread $thread_id: $count checkpoint ref(s), latest checkpoint $latest_ts_human"
local t3code_classification t3code_details
t3code_classification="${T3CODE_CLASSIFICATION[$thread_id]:-unknown}"
t3code_details="${T3CODE_DETAILS[$thread_id]:-no T3 Code classification available}"
echo " T3 Code state: $t3code_classification ($t3code_details)"
case "$t3code_classification" in
live-candidate|archived-candidate|runtime-bound-candidate|lingering-state-candidate)
protected_threads=$((protected_threads + 1))
protected_refs=$((protected_refs + count))
kept_refs=$((kept_refs + count))
echo " keeping all $count ref(s); protected by T3 Code state"
continue
;;
esac
case "$MODE" in
clear-chat-checkpoints)
if ((latest_ts > 0)) && ((latest_ts < inactive_cutoff_epoch)); then
inactive_threads_matched=$((inactive_threads_matched + 1))
inactive_refs_matched=$((inactive_refs_matched + count))
if ((APPLY)); then
echo " deleting all $count ref(s); thread is inactive past the cutoff"
else
echo " would delete all $count ref(s); thread is inactive past the cutoff"
fi
for entry in "${sorted_entries[@]}"; do
turn_number="${entry%%$'\t'*}"
rest="${entry#*$'\t'}"
ref="${rest%%$'\t'*}"
if ((APPLY)); then
echo " deleting turn $turn_number: $ref"
git -C "$REPO_DIR" update-ref -d "$ref"
else
echo " would delete turn $turn_number: $ref"
fi
deleted_refs=$((deleted_refs + 1))
done
continue
fi
kept_refs=$((kept_refs + count))
echo " keeping all $count ref(s)"
;;
prune-chat-checkpoints)
mapfile -t deletable_entries < <(
printf '%s\n' "${sorted_entries[@]}" | awk -F $'\t' '$1 != "0"'
)
local deletable_count refs_to_delete_effective
deletable_count="${#deletable_entries[@]}"
if ((count <= KEEP)) || ((deletable_count == 0)); then
kept_refs=$((kept_refs + count))
echo " keeping all $count ref(s)"
continue
fi
refs_to_delete=$((count - KEEP))
refs_to_delete_effective=$refs_to_delete
if ((refs_to_delete_effective > deletable_count)); then
refs_to_delete_effective=$deletable_count
fi
kept_refs=$((count - refs_to_delete_effective))
if ((APPLY)); then
echo " deleting $refs_to_delete_effective older ref(s); keeping turn 0 and the newest remaining refs"
else
echo " would delete $refs_to_delete_effective older ref(s); keeping turn 0 and the newest remaining refs"
fi
for ((i = 0; i < refs_to_delete_effective; i++)); do
entry="${deletable_entries[$i]}"
turn_number="${entry%%$'\t'*}"
rest="${entry#*$'\t'}"
ref="${rest%%$'\t'*}"
if ((APPLY)); then
echo " deleting turn $turn_number: $ref"
git -C "$REPO_DIR" update-ref -d "$ref"
else
echo " would delete turn $turn_number: $ref"
fi
deleted_refs=$((deleted_refs + 1))
done
;;
esac
done <"$THREAD_FILE"
echo
echo "Summary:"
echo " Threads found: $threads_found"
echo " Valid checkpoint refs: $valid_refs"
echo " Refs kept: $kept_refs"
if ((APPLY)); then
echo " Refs deleted: $deleted_refs"
else
echo " Refs would delete: $deleted_refs"
fi
if ((ignored_refs > 0)); then
echo " Ignored non-matching refs: $ignored_refs"
fi
echo " Protected threads: $protected_threads"
echo " Protected refs kept due to T3 Code state: $protected_refs"
if [[ "$MODE" == "clear-chat-checkpoints" ]]; then
echo " Inactive threads matched: $inactive_threads_matched"
echo " Refs deleted via inactive-thread mode: $inactive_refs_matched"
echo " Threads remaining after inactive prune: $((threads_found - inactive_threads_matched))"
fi
if ((APPLY == 0)); then
echo "Report-only mode: skipping ref deletion, reflog expiry, and git gc."
exit 0
fi
if ((deleted_refs == 0)); then
echo "No refs deleted; skipping reflog expiry and git gc."
exit 0
fi
if ((RUN_GC == 0)); then
echo "Skipping reflog expiry and git gc because --no-gc was provided."
exit 0
fi
echo "Expiring reflogs and pruning unreachable objects..."
git -C "$REPO_DIR" reflog expire --expire=now --all
git -C "$REPO_DIR" gc --prune=now
echo "Finished pruning T3 checkpoint refs."
}
parse_command_and_options "$@"
run_main
_t3_checkpoints() {
local cur prev
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if (( COMP_CWORD == 1 )); then
COMPREPLY=($(compgen -W "plan apply help" -- "$cur"))
return 0
fi
case "$prev" in
plan|apply)
COMPREPLY=($(compgen -W "prune-chat-checkpoints clear-chat-checkpoints" -- "$cur"))
return 0
;;
prune-chat-checkpoints)
COMPREPLY=($(compgen -W "1 3 5 10 20 --repo --no-gc --codex-root --no-codex-inspect --help" -- "$cur"))
return 0
;;
clear-chat-checkpoints)
COMPREPLY=($(compgen -W "1 3 5 7 14 30 --repo --no-gc --codex-root --no-codex-inspect --help" -- "$cur"))
return 0
;;
--repo|--codex-root)
compopt -o filenames 2>/dev/null
COMPREPLY=($(compgen -d -- "$cur"))
return 0
;;
esac
COMPREPLY=($(compgen -W "--repo --no-gc --codex-root --no-codex-inspect --help" -- "$cur"))
}
complete -F _t3_checkpoints t3-checkpoints t3cp
#!/usr/bin/env bash
set -euo pipefail
exec /home/ben/bin/t3-checkpoints "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment