fix(sandbox): expand ~ in CLAUDE_CONFIG_DIR + prune .claude from artifacts
shlex.quote() wraps its argument in single quotes, which suppress tilde
expansion. CLAUDE_CONFIG_DIR='~/chat-<id>/.claude' was being handed to
Claude Code as a literal path beginning with `~`, so the CLI treated it
as a relative directory and created `./~/chat-<id>/.claude/` under cwd.
Concrete symptoms:
- Session history JSONLs written to the wrong path, silently defeating
#5 (disk-based session recovery couldn't find them).
- Per-chat config isolation (#9) silently degraded to a shared dir
whose actual location depended on whatever cwd the turn ran in.
- Symlinked skills placed at the correct path were never discovered by
Claude, because CLAUDE_CONFIG_DIR pointed elsewhere.
- `.claude.json` artifacts from the stray tree picked up by the
artifact walker → attempted upload → open-terminal 403 because the
`~` path segment failed its path-sanity check.
Fix by pre-expanding a leading `~/` to `$HOME/` and double-quoting so
$HOME expands at shell parse time. Also prune `.claude/` and any stray
`~` literal directory from the artifact find() so Claude's internal
state never masquerades as a user artifact going forward.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
05d53ade55
commit
e100c801c4
|
|
@ -360,7 +360,18 @@ def _claude_command(prompt: str, cfg: _ClaudeRunConfig) -> str:
|
|||
# the same OWUI user race each other on ~/.claude/. With the proxy
|
||||
# holding credentials, the config dir stores only session history —
|
||||
# safe to shard per chat and discard with the workdir.
|
||||
env_parts.append(f"CLAUDE_CONFIG_DIR={shlex.quote(cfg.workdir + '/.claude')}")
|
||||
#
|
||||
# Leading `~/` must be pre-expanded to `$HOME/` because shlex.quote()
|
||||
# adds single quotes, which suppress tilde expansion by the shell.
|
||||
# Without this, Claude receives a literal `~` as the first path
|
||||
# component and creates `./~/chat-<id>/.claude/` relative to cwd,
|
||||
# silently breaking session isolation, session recovery, and skill
|
||||
# discovery. Double-quoting allows $HOME expansion while still
|
||||
# escaping any other shell specials in the path.
|
||||
config_dir = cfg.workdir + "/.claude"
|
||||
if config_dir.startswith("~/"):
|
||||
config_dir = "$HOME/" + config_dir[2:]
|
||||
env_parts.append(f'CLAUDE_CONFIG_DIR="{config_dir}"')
|
||||
# `claude --dangerously-skip-permissions` still refuses root unless told
|
||||
# it's sandboxed. open-terminal runs processes as the per-user UID so this
|
||||
# rarely matters, but setting it is harmless.
|
||||
|
|
@ -569,8 +580,13 @@ async def _snapshot_workspace(
|
|||
# Use find with -printf to get path + mtime in one call, avoiding N+1
|
||||
# HTTP hits against /files/list for every subdirectory.
|
||||
# workdir unquoted so `~` / `$HOME` expand; see OpenTerminalClient.ensure_dir.
|
||||
# Prune `.claude/` (Claude Code's own config/session storage) and any
|
||||
# stray `~` literal dir from pre-fix chats — neither is user-facing
|
||||
# artifact content, and .claude.json would otherwise get inlined as a
|
||||
# chat attachment.
|
||||
cmd = (
|
||||
f"find {workdir} -type f "
|
||||
f"find {workdir} "
|
||||
rf"\( -name '.claude' -o -name '~' \) -prune -o -type f "
|
||||
rf"\( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' "
|
||||
rf"-o -iname '*.gif' -o -iname '*.svg' -o -iname '*.webp' "
|
||||
rf"-o -iname '*.pdf' -o -iname '*.csv' -o -iname '*.tsv' "
|
||||
|
|
|
|||
Loading…
Reference in New Issue