fix(host-service): seed folder trust through env wrappers

LA
2h ago
+213-17

What & why

Part of #9309. Split out of #9310 so each PR carries one change (the env editor stays in #9310).

Agents are often launched as env CLAUDE_CONFIG_DIR=… claude … to run on a second Claude account. In that form folder-trust seeding fails without any message, because resolveTrustFamily only reads the first word of the command (env). Every resume of an automation run then shows the "trust this folder" dialog.

resolveTrustFamily sees through env wrappers (host-service seed-agent-trust.ts)

  • A new unwrapEnvCommand skips a leading env (bare or by path, e.g. /usr/bin/env), its -i / -u NAME / --unset=NAME options, and any leading VAR=value tokens. It reads both the command string and args, because the settings parser saves env A=1 claude as command: "env" plus args. A raw command string is tokenized with shell-quote (quoted values; stops at the first shell operator). This adds shell-quote 1.11.0 to host-service, the version already used by desktop; the lockfile change is two lines.
  • resolveTrustTarget applies those inline assignments on top of {...defaultAccountEnv, ...config.env}, the same precedence as at launch. env -i drops the inherited env and -u removes a name from it. So env CLAUDE_CONFIG_DIR=/p claude seeds /p/.claude.json, not the default account's file.

Not in this PR (possible follow-ups):

  • resolveAgentLaunchPresetId in packages/shared still uses first-word detection.
  • ~ in CLAUDE_CONFIG_DIR is not expanded before the trust-file join.

How I tested it

Unit tests (next to the existing ones in seed-agent-trust.test.ts):

  • resolveTrustFamily › sees through env wrappers and inline assignments: env CLAUDE_CONFIG_DIR=/p claude … → claude; /usr/bin/env + args CODEX_HOME=/p A=1 codex → codex; bare CLAUDE_CONFIG_DIR=/p claude → claude; env my-agent → null.
  • seedAgentFolderTrust › seeds the CLAUDE_CONFIG_DIR named by an env wrapper: runs against an in-memory migrated host DB, checks the trust entry lands in the wrapper's profile .claude.json, and that the wrapper wins over a conflicting config.env.
  • seedAgentFolderTrust › reads a quoted CLAUDE_CONFIG_DIR from a raw command string: a path with spaces, followed by && true.
  • resolveTrustTarget › env -i and -u drop the inherited CLAUDE_CONFIG_DIR and › reads env options from a raw command string: also --unset=, --ignore-environment, and -i plus a new assignment. They check resolved paths only and write no files.
  • The first two tests fail on main.

Run on this branch (rebased on current main):

cd packages/host-service
bun test src/trpc/router/workspace-creation/shared/seed-agent-trust.test.ts
# 29 pass, 0 fail
bun run typecheck   # tsc --noEmit, passes

biome check on the changed files is clean.

Checklist

  • PR title follows conventional commits (type(scope): subject)
  • bun run lint and bun run typecheck pass (CI fails on lint warnings too)
  • "Allow edits from maintainers" is checked on fork PRs
  • I have signed the CLA (the bot asks on your first PR)

🤖 Generated with Claude Code


Summary by cubic

Part of #9309. Fixes folder-trust seeding for agents launched through env wrappers, so runs like env CLAUDE_CONFIG_DIR=/p claude ... no longer re-show the "trust this folder" dialog on every resume.

Previously resolveTrustFamily only read the first word of the command (env), so seeding was silently skipped.

  • resolveTrustTarget now unwraps a leading env (bare or by path), its -i/-u/--unset options, and inline VAR=value assignments, applying them on top of the default-account and config env.
  • Adds shell-quote to host-service for tokenizing raw command strings.

Not covered: resolveAgentLaunchPresetId in packages/shared still uses first-word detection, and ~ in CLAUDE_CONFIG_DIR is not expanded before joining the trust-file path.

Summary by CodeRabbit

  • Improvements
    • Workspace setup now recognizes agent providers launched through command wrappers, quoted commands, executable paths, and .exe files.
    • Agent trust settings now account for environment assignments, removed variables, and custom configuration directories when selecting trust targets. This helps trust settings match the agent’s effective launch configuration, including when wrapper options override inherited environment values.