Fix untrusted-workspace wedge: re-seed claude trust at every launch

Phase 4 (1517e4d) deleted the tmux launch path and with it the only
caller of claude_config.ensure_onboarded, so agent working dirs -
every fresh worktree is a brand-new path - were never pre-trusted in
~/.claude.json. Headless 'claude -p' runs then wedge or refuse on the
workspace-trust dialog with nobody at a TTY to accept it.

Spawn and resume now mark onboarding complete and trust the working
dir right before launch, next to the settings/claude_gen
materialization. Resume matters independently: a cross-worker resume
can land in a container whose ~/.claude.json has never seen the dir.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
This commit is contained in:
Claude
2026-08-13 16:58:32 +00:00
parent e007440612
commit a93cd27ead
3 changed files with 54 additions and 0 deletions
+35
View File
@@ -181,3 +181,38 @@ def test_resume_refused_while_run_live(env, fake_launch):
ok, detail = spawn.resume(agent, "answer")
assert ok is False
assert "live run" in detail
def test_spawn_trusts_working_dir_in_claude_json(env, fake_launch):
"""The launch must pre-trust the agent's working dir in ~/.claude.json — an
untrusted workspace wedges a headless run on the trust dialog with nobody at a
TTY (regression: the call was lost when phase 4 deleted the tmux launch path)."""
root = env["tmp"] / "proj"
_write_mise(root, with_test=True)
_register_project(root)
spawn.spawn("proj", "api", task="build the thing")
cfg = json.loads((env["tmp"] / ".claude.json").read_text())
assert cfg["hasCompletedOnboarding"] is True
entry = cfg["projects"][str(root)]
assert entry["hasTrustDialogAccepted"] is True
def test_resume_trusts_working_dir_in_claude_json(env, fake_launch):
"""Cross-worker resume may run in a container that has never seen this working
dir; resume must re-seed trust exactly as spawn does."""
root = env["tmp"] / "proj"
_write_mise(root, with_test=True)
_register_project(root)
spawn.spawn("proj", "api", task="do it")
with get_engine().begin() as conn:
agent = repo.get_agent_by_name(conn, "proj", "api")
repo.finish_run(conn, repo.get_latest_run(conn, agent["id"])["id"], "completed")
(env["tmp"] / ".claude.json").unlink() # a "fresh container": no config at all
ok, _ = spawn.resume(agent, "use Postgres")
assert ok is True
cfg = json.loads((env["tmp"] / ".claude.json").read_text())
assert cfg["projects"][str(root)]["hasTrustDialogAccepted"] is True