Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,22 @@
- [x] T004: Tested Notification start hook — DOES NOT WORK. Hook stderr is captured by Claude Code, not passed to terminal. OSC sequence shows as text `]0;context-reset` in output. Removed hook. Tab color is the persistent project identifier; `wt --title` sets initial title before Claude takes over.
- [x] T005: Removed PostToolUse reassertion — would kill Claude's green status icon. Tab color identifies project instead.

## Pre-trust workspace (015)

Skip the "do you trust this folder?" dialog on first launch in new directories.
Claude Code stores trust state in `~/.claude/projects/<slug>/`. Pre-creating that
directory before launching the interactive session bypasses the dialog.

- [x] T001: Add `ensure_workspace_trusted()` to new_session.py — pre-creates projects dir. Also fixed `get_project_logs_dir` slug encoding to match Claude Code (regex `[^a-zA-Z0-9-]` instead of only replacing `\/:.`)
- [ ] T002: Add tests for ensure_workspace_trusted and fixed slug encoding

## Rename: context-reset → new-session (007)

The name "context-reset" confuses Claude into thinking this is only for resetting context in the current project. It's actually for opening a new Claude Code session in ANY project (same or different). Rename to make the purpose clear.

- [ ] T001: Create `new_session.py` (copy of `context_reset.py` with updated docstring/naming)
- [ ] T002: Update stop-message.txt to reference `new_session.py` instead of `context_reset.py`
- [ ] T003: Add explicit "switch project" usage example to stop-message.txt: `python new_session.py --project-dir /path/to/other/project`
- [ ] T004: Update all hook module references (auto-continue.js, load-instructions.js, etc.)
- [ ] T005: Keep `context_reset.py` as backward-compat alias (imports and calls new_session.py)
- [ ] T006: Update README.md and CLAUDE.md with new naming
- [x] T001: Create `new_session.py` (copy of `context_reset.py` with updated docstring/naming)
- [x] T002: Update stop-message.txt to reference `new_session.py` instead of `context_reset.py`
- [x] T003: Add explicit "switch project" usage example to stop-message.txt
- [x] T004: Update all hook module references (auto-continue.js, cwd-drift-detector.js)
- [x] T005: Keep `context_reset.py` as backward-compat alias (re-exports all names from new_session.py)
- [x] T006: Update README.md, CLAUDE.md, and project rules with new naming
30 changes: 21 additions & 9 deletions new_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -952,12 +952,29 @@ def _kill_old_tab_unix(shell_pid):

def get_project_logs_dir(project_dir):
home = os.path.expanduser("~")
slug = os.path.abspath(project_dir).replace("\\", "-").replace("/", "-").replace(":", "-").replace(".", "-")
slug = re.sub(r'[^a-zA-Z0-9-]', '-', os.path.abspath(project_dir))
if slug.startswith("-"):
slug = slug[1:]
return os.path.join(home, ".claude", "projects", slug)


def ensure_workspace_trusted(project_dir):
"""Pre-create the Claude Code projects directory so the trust dialog is skipped.

Claude Code shows "Is this a project you trust?" on first interactive launch
in a new directory. Trust state = existence of ~/.claude/projects/<slug>/.
Pre-creating the directory with a seed JSONL avoids the prompt.
"""
logs_dir = get_project_logs_dir(project_dir)
if os.path.exists(logs_dir):
return # Already trusted
try:
os.makedirs(logs_dir, exist_ok=True)
log(f"Pre-trusted workspace: {logs_dir}")
except Exception as e:
log(f"WARNING: could not pre-trust workspace: {e}")


def get_newest_jsonl(logs_dir):
if not os.path.exists(logs_dir):
return None, 0
Expand Down Expand Up @@ -1103,14 +1120,9 @@ def _remove_lock():
_remove_lock()
return

# NOTE: Claude Code's "Do you trust this folder?" dialog fires on every
# new interactive session. There is NO way to pre-trust a directory —
# no settings.json field, no CLI flag, no env var. claude -p skips it
# only for non-interactive mode. Multiple open feature requests:
# https://github.com/anthropics/claude-code/issues/12737 (trustedDirectories)
# https://github.com/anthropics/claude-code/issues/29285 (permanent trust)
# Until Anthropic adds this, cross-project resets to new dirs require
# the user to press Enter once on the trust dialog.
# Pre-trust the workspace so the interactive session skips the
# "do you trust this folder?" dialog.
ensure_workspace_trusted(launch_dir)

# Phase 1: Launch new tab
before = count_claude_processes()
Expand Down
22 changes: 22 additions & 0 deletions scripts/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,28 @@ def test(name, condition):
test("logs dir is under .claude/projects", ".claude" in logs_dir and "projects" in logs_dir)
test("no colons in slug", ":" not in os.path.basename(logs_dir))

# Encoding: all non-alphanumeric-dash chars become -
with tempfile.TemporaryDirectory() as d:
test_proj = os.path.join(d, "_my.project")
os.makedirs(test_proj)
slug = os.path.basename(context_reset.get_project_logs_dir(test_proj))
test("underscores replaced with -", "_" not in slug)
test("dots replaced with -", "." not in slug)
test("slug preserves hyphens", "my-project" in slug)

# --- ensure_workspace_trusted ---
print("\n=== ensure_workspace_trusted ===")
with tempfile.TemporaryDirectory() as d:
fake_proj = os.path.join(d, "fake-project")
os.makedirs(fake_proj)
logs_dir = context_reset.get_project_logs_dir(fake_proj)
test("dir does not exist before trust", not os.path.exists(logs_dir))
context_reset.ensure_workspace_trusted(fake_proj)
test("dir exists after trust", os.path.exists(logs_dir))
# Second call is a no-op (no error)
context_reset.ensure_workspace_trusted(fake_proj)
test("idempotent (no error on second call)", os.path.exists(logs_dir))

# --- get_newest_jsonl ---
print("\n=== get_newest_jsonl ===")
with tempfile.TemporaryDirectory() as d:
Expand Down
Loading