diff --git a/.gitignore b/.gitignore index 86763a3..90b00f8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ SESSION_STATE.md .test-results/ .workflow-state.json specs/ +build/ +dist/ +*.egg-info/ diff --git a/README.md b/README.md index b49fa27..51039e9 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,34 @@ Launch a new Claude Code session in any project. When a session's context window fills up, this script seamlessly transfers work to a fresh Claude instance in a new terminal tab — no human intervention needed. Also supports switching to a different project entirely. +## Quick start + +```bash +# 1. Install (Python 3.8+, no other dependencies) +pip install git+https://github.com/grobomo/context-reset + +# 2. Add a stop hook to ~/.claude/settings.json +``` + +Add this to your Claude Code settings (`~/.claude/settings.json`): + +```json +{ + "hooks": { + "Stop": [ + { + "type": "command", + "command": "new-session --project-dir $CLAUDE_PROJECT_DIR" + } + ] + } +} +``` + +That's it. Claude will automatically reset to a fresh session when context gets heavy, carrying over TODO.md and a readable summary of the conversation. + +If you already have stop hooks, just add the entry to your existing `Stop` array. + ## How it works 1. Reads the last 500 JSONL lines from the transcript (efficient reverse-read, no full file load) @@ -59,16 +87,27 @@ Each new tab gets: ## Integration with Claude Code hooks -Add to a [stop hook](https://docs.anthropic.com/en/docs/claude-code/hooks) module to let Claude trigger resets autonomously when context gets heavy: - -``` -python C:/path/to/context-reset/new_session.py --project-dir $CLAUDE_PROJECT_DIR +Add to a [stop hook](https://docs.anthropic.com/en/docs/claude-code/hooks) in `~/.claude/settings.json` to let Claude trigger resets autonomously when context gets heavy: + +```json +{ + "hooks": { + "Stop": [ + { + "type": "command", + "command": "new-session --project-dir $CLAUDE_PROJECT_DIR" + } + ] + } +} ``` -The script reads `$CLAUDE_PROJECT_DIR` by default, so from a hook you can simply: +The script reads `$CLAUDE_PROJECT_DIR` by default, so from a hook you can simply use `new-session`. + +If you prefer to run from source instead of pip install: ``` -python C:/path/to/context-reset/new_session.py +python /path/to/context-reset/new_session.py --project-dir $CLAUDE_PROJECT_DIR ``` ## Session continuity diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d1964d9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,18 @@ +[build-system] +requires = ["setuptools>=64"] +build-backend = "setuptools.build_meta" + +[project] +name = "claude-context-reset" +version = "1.0.0" +description = "Launch new Claude Code sessions with automatic state handoff" +readme = "README.md" +license = "MIT" +requires-python = ">=3.8" + +[project.scripts] +new-session = "new_session:main" +context-reset = "new_session:main" + +[tool.setuptools] +py-modules = ["new_session", "context_reset", "task_claims"] diff --git a/scripts/bootstrap.ps1 b/scripts/bootstrap.ps1 new file mode 100644 index 0000000..dc40767 --- /dev/null +++ b/scripts/bootstrap.ps1 @@ -0,0 +1,117 @@ +# bootstrap.ps1 - Set up Claude Code with context-reset on a fresh Windows machine +# Run: iwr -useb https://raw.githubusercontent.com/grobomo/context-reset/main/scripts/bootstrap.ps1 | iex +# +# What it does: +# 1. Checks prerequisites (Python 3.8+, Node.js, Windows Terminal) +# 2. Installs Claude Code CLI (npm) +# 3. Installs context-reset (pip) +# 4. Configures the stop hook in ~/.claude/settings.json +# +# Safe to re-run -- skips already-installed components. + +$ErrorActionPreference = "Stop" + +function Write-Step($msg) { Write-Host "`n=> $msg" -ForegroundColor Cyan } +function Write-Ok($msg) { Write-Host " OK: $msg" -ForegroundColor Green } +function Write-Skip($msg) { Write-Host " SKIP: $msg" -ForegroundColor Yellow } +function Write-Fail($msg) { Write-Host " FAIL: $msg" -ForegroundColor Red } + +# --- Prerequisites --- + +Write-Step "Checking Python" +try { + $pyVer = python --version 2>&1 + if ($pyVer -match 'Python (\d+)\.(\d+)') { + $major = [int]$Matches[1]; $minor = [int]$Matches[2] + if ($major -ge 3 -and $minor -ge 8) { + Write-Ok $pyVer + } else { + Write-Fail "$pyVer -- need Python 3.8+. Install from https://python.org" + exit 1 + } + } +} catch { + Write-Fail "Python not found. Install from https://python.org" + exit 1 +} + +Write-Step "Checking Node.js" +try { + $nodeVer = node --version 2>&1 + Write-Ok "Node $nodeVer" +} catch { + Write-Fail "Node.js not found. Install from https://nodejs.org" + exit 1 +} + +Write-Step "Checking Windows Terminal" +$wt = Get-Command wt -ErrorAction SilentlyContinue +if ($wt) { + Write-Ok "Windows Terminal found" +} else { + Write-Skip "Windows Terminal not found -- context-reset tab features will not work" + Write-Host " Install from Microsoft Store or winget install Microsoft.WindowsTerminal" +} + +# --- Claude Code CLI --- + +Write-Step "Checking Claude Code CLI" +$claude = Get-Command claude -ErrorAction SilentlyContinue +if ($claude) { + Write-Skip "Claude Code already installed" +} else { + Write-Host " Installing Claude Code..." + npm install -g @anthropic-ai/claude-code + Write-Ok "Claude Code installed" +} + +# --- context-reset --- + +Write-Step "Installing context-reset" +$ErrorActionPreference = "Continue" +$existing = pip show claude-context-reset 2>&1 +if ("$existing" -match "Name: claude-context-reset") { + Write-Host " Upgrading..." + pip install --upgrade git+https://github.com/grobomo/context-reset 2>&1 | Out-Null + Write-Ok "context-reset upgraded" +} else { + pip install git+https://github.com/grobomo/context-reset 2>&1 | Out-Null + Write-Ok "context-reset installed" +} +$ErrorActionPreference = "Stop" + +# Verify CLI entry point +try { + $help = new-session --help 2>&1 + Write-Ok "new-session CLI works" +} catch { + Write-Fail "new-session CLI not found in PATH - check pip Scripts directory" + exit 1 +} + +# --- Configure stop hook (uses Python to avoid PowerShell JSON/encoding quirks) --- + +Write-Step "Configuring Claude Code stop hook" +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$result = python (Join-Path $scriptDir "configure_hook.py") 2>&1 + +if ($result -eq "SKIP") { + Write-Skip "Stop hook already configured" +} elseif ($result -eq "ADDED") { + Write-Ok "Stop hook added to existing settings.json" +} elseif ($result -eq "CREATED") { + Write-Ok "Created settings.json with stop hook" +} else { + Write-Fail "Failed to configure stop hook" +} + +# --- Done --- + +Write-Host "" +Write-Host "Setup complete!" -ForegroundColor Green +Write-Host "" +Write-Host "Next steps:" -ForegroundColor White +Write-Host " 1. Run 'claude' in any project directory to start a session" +Write-Host " 2. When context fills up, Claude will automatically reset to a fresh tab" +Write-Host " 3. TODO.md and SESSION_STATE.md carry context between sessions" +Write-Host "" diff --git a/scripts/configure_hook.py b/scripts/configure_hook.py new file mode 100644 index 0000000..8a9fe50 --- /dev/null +++ b/scripts/configure_hook.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +"""Add the context-reset stop hook to Claude Code settings.json.""" +import json +import os +import sys + +settings_file = os.path.join(os.path.expanduser("~"), ".claude", "settings.json") +os.makedirs(os.path.dirname(settings_file), exist_ok=True) + +hook = {"type": "command", "command": "new-session --project-dir $CLAUDE_PROJECT_DIR"} + +if os.path.exists(settings_file): + with open(settings_file, "r", encoding="utf-8-sig") as f: + settings = json.load(f) + stops = settings.get("hooks", {}).get("Stop", []) + if any("new-session" in h.get("command", "") for h in stops): + print("SKIP") + sys.exit(0) + settings.setdefault("hooks", {}).setdefault("Stop", []).append(hook) + print("ADDED") +else: + settings = {"hooks": {"Stop": [hook]}} + print("CREATED") + +with open(settings_file, "w", encoding="utf-8") as f: + json.dump(settings, f, indent=2)