#!/usr/bin/env bash set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$ROOT" ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" mkdir -p out git_branch="" git_head="" git_head_short="" git_modified_count="0" git_untracked_count="0" git_dirty_count="0" if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then git_branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "?")" git_head="$(git rev-parse HEAD 2>/dev/null || echo "")" git_head_short="$(git rev-parse --short HEAD 2>/dev/null || echo "")" porcelain="$(git status --porcelain=v1 2>/dev/null || true)" if [ -n "${porcelain}" ]; then git_dirty_count="$(printf "%s\n" "${porcelain}" | wc -l | awk '{print $1}')" git_untracked_count="$(printf "%s\n" "${porcelain}" | grep -c '^??' || true)" git_modified_count="$(printf "%s\n" "${porcelain}" | grep -vc '^??' || true)" fi fi latest_checkpoint_path="" latest_checkpoint_sha256="" if ls out/checkpoints/iftypeset_checkpoint_*.tar.gz >/dev/null 2>&1; then latest_checkpoint_path="$(ls -1t out/checkpoints/iftypeset_checkpoint_*.tar.gz | head -n 1)" latest_checkpoint_sha256="$(sha256sum "${latest_checkpoint_path}" | awk '{print $1}')" fi export IFTS_STATE_TS="${ts}" export IFTS_STATE_ROOT="${ROOT}" export IFTS_STATE_GIT_BRANCH="${git_branch}" export IFTS_STATE_GIT_HEAD="${git_head}" export IFTS_STATE_GIT_HEAD_SHORT="${git_head_short}" export IFTS_STATE_GIT_DIRTY_COUNT="${git_dirty_count}" export IFTS_STATE_GIT_MODIFIED_COUNT="${git_modified_count}" export IFTS_STATE_GIT_UNTRACKED_COUNT="${git_untracked_count}" export IFTS_STATE_CHECKPOINT_PATH="${latest_checkpoint_path}" export IFTS_STATE_CHECKPOINT_SHA256="${latest_checkpoint_sha256}" python3 - <<'PY' import json import os from pathlib import Path def _read_json(path: str): p = Path(path) if not p.exists(): return None try: return json.loads(p.read_text()) except Exception: return None ts = os.environ.get("IFTS_STATE_TS", "") root = os.environ.get("IFTS_STATE_ROOT", "") git_branch = os.environ.get("IFTS_STATE_GIT_BRANCH", "") git_head = os.environ.get("IFTS_STATE_GIT_HEAD", "") git_head_short = os.environ.get("IFTS_STATE_GIT_HEAD_SHORT", "") dirty_count = int(os.environ.get("IFTS_STATE_GIT_DIRTY_COUNT", "0") or "0") modified_count = int(os.environ.get("IFTS_STATE_GIT_MODIFIED_COUNT", "0") or "0") untracked_count = int(os.environ.get("IFTS_STATE_GIT_UNTRACKED_COUNT", "0") or "0") checkpoint_path = os.environ.get("IFTS_STATE_CHECKPOINT_PATH", "") checkpoint_sha256 = os.environ.get("IFTS_STATE_CHECKPOINT_SHA256", "") coverage = _read_json("out/coverage-report.json") or {} counts = coverage.get("counts", {}) if isinstance(coverage, dict) else {} trust_contract_md = Path("out/trust-contract.md").exists() trust_contract_json = Path("out/trust-contract.json").exists() state = { "generated_at_utc": ts, "repo_root": root, "git": { "branch": git_branch or None, "head": git_head or None, "head_short": git_head_short or None, "dirty_paths_count": dirty_count, "modified_paths_count": modified_count, "untracked_paths_count": untracked_count, }, "latest_checkpoint": { "path": checkpoint_path or None, "sha256": checkpoint_sha256 or None, }, "coverage": { "generated_at_utc": coverage.get("generated_at_utc") if isinstance(coverage, dict) else None, "counts": counts or None, }, "artifacts": { "trust_contract_md": trust_contract_md, "trust_contract_json": trust_contract_json, "coverage_report_json": Path("out/coverage-report.json").exists(), "manual_checklist_md": Path("out/manual-checklist.md").exists(), }, "canonical_docs": [ "README.md", "STATUS.md", "docs/06-project-overview.md", "docs/07-session-resilience.md", "docs/09-project-status.md", "docs/10-project-brief.md", "docs/12-codex-max-workload.md", "docs/13-task-board.md", "docs/17-rendering-pipeline.md", "docs/CHECKPOINTS.md", ], "resume_commands": [ "./scripts/resume.sh", "./scripts/audit.sh", "./scripts/state.sh", "./scripts/ci.sh", "./scripts/checkpoint.sh \"note\"", ], } Path("out/session-state.json").write_text(json.dumps(state, indent=2, sort_keys=True) + "\n") lines = [] lines.append("# Session State (generated)\n") lines.append(f"- generated_at_utc: `{ts}`") lines.append(f"- repo_root: `{root}`") if git_branch and git_head_short: lines.append(f"- git: `{git_branch}` @ `{git_head_short}`") elif git_branch: lines.append(f"- git: `{git_branch}`") else: lines.append("- git: `(not detected)`") lines.append( f"- working_tree: dirty_paths={dirty_count} (modified={modified_count}, untracked={untracked_count})" ) if checkpoint_path: lines.append(f"- latest_checkpoint: `{checkpoint_path}`") lines.append(f"- latest_checkpoint_sha256: `{checkpoint_sha256}`") else: lines.append("- latest_checkpoint: `(none yet)`") total_rules = None try: total_rules = counts.get("total_rules") except Exception: total_rules = None if total_rules is not None: lines.append(f"- rules_total: `{total_rules}`") by_enf = counts.get("by_enforcement") or {} by_cat = counts.get("by_category") or {} if by_enf: lines.append(f"- enforcement_split: `{by_enf}`") if by_cat: lines.append(f"- categories: `{by_cat}`") else: lines.append("- rules_total: `(unknown; run ./scripts/ci.sh)`") lines.append("") lines.append("## Canonical Docs") for d in state["canonical_docs"]: lines.append(f"- `{d}`") lines.append("") lines.append("## Fast Resume") for c in state["resume_commands"]: lines.append(f"- `{c}`") lines.append("") lines.append("## Notes") lines.append( "- If a chat/session resets and things look “rolled back”, check `latest_checkpoint` above and extract it on a new machine." ) lines.append( "- This file is copied into `docs/SESSION_STATE.md` so it is included in checkpoint snapshots (since `out/` is excluded)." ) md = "\n".join(lines) + "\n" Path("out/session-state.md").write_text(md) Path("docs/SESSION_STATE.md").write_text(md) PY echo "wrote: out/session-state.json out/session-state.md docs/SESSION_STATE.md" >&2