Skip to content

fix(exec): expand leading ~ in workdir to home directory#94449

Closed
Pandah97 wants to merge 0 commit into
openclaw:mainfrom
Pandah97:fix/issue-94434-exec-workdir-tilde-expansion
Closed

fix(exec): expand leading ~ in workdir to home directory#94449
Pandah97 wants to merge 0 commit into
openclaw:mainfrom
Pandah97:fix/issue-94434-exec-workdir-tilde-expansion

Conversation

@Pandah97

@Pandah97 Pandah97 commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Summary

exec tool does not expand a leading ~ in workdir, then falls back to another directory and still executes the command, causing relative commands to run from the wrong location.

Root cause: resolveExecWorkdir() in src/agents/bash-tools.exec-workdir.ts passed the explicit workdir value directly to the stat check without expanding ~/~/ to the user's home directory.

Fix: Apply expandHomePrefix() only in the local gateway branch of resolveExecWorkdir(), after the host-specific node/sandbox branches have returned. This ensures leading ~ is expanded for local host=gateway execution while node and sandbox workdirs remain untouched.

Fixes #94434. Supersedes sibling PRs #94447, #94450, #94462.

Real behavior proof (required for external PRs)

Behavior addressed: resolveExecWorkdir({host: "gateway", workdir: "~"}) now expands ~ to the home directory before the stat check, instead of treating the tilde as a literal path component.

Real setup tested:

  • Runtime: Linux x86_64 (kernel 4.19.112), Node v24.13.1, OpenClaw commit 73ab101

Exact steps or command run after fix:

node --import tsx -e '
import { resolveExecWorkdir } from "./src/agents/bash-tools.exec-workdir.ts";
import os from "node:os";

// Gateway: existing ~/... path expands to home directory
const r1 = await resolveExecWorkdir({ host: "gateway", workdir: "~" });
console.log("gateway ~ →", r1.kind, r1.hostCwd ?? "");

// Gateway: nonexistent ~/... path returns unavailable
const r2 = await resolveExecWorkdir({ host: "gateway", workdir: "~/nonexistent-tilde-test" });
console.log("gateway ~/nonexistent →", r2.kind);

// Gateway: absolute path works unchanged
const r3 = await resolveExecWorkdir({ host: "gateway", workdir: "/tmp" });
console.log("gateway /tmp →", r3.kind);

// Node: tilde preserved verbatim (regression)
const r4 = await resolveExecWorkdir({ host: "node", workdir: "~/project" });
console.log("node ~/project →", r4.kind, r4.remoteCwd ?? "");

// Node: omitted cwd
const r5 = await resolveExecWorkdir({ host: "node" });
console.log("node omitted →", r5.kind);
'

After-fix evidence:

gateway ~ → local /home/0668001315
gateway ~/nonexistent → unavailable
gateway /tmp → local
node ~/project → node ~/project
node omitted → node

home dir: /home/0668001315

Observed result after the fix:

  • Gateway ~ resolves to local /home/0668001315 — the home directory exists, so tilde expansion succeeds.
  • Gateway ~/nonexistent-tilde-test returns unavailable — tilde was expanded, but the target does not exist.
  • Gateway /tmp works unchanged — non-tilde paths are not affected.
  • Node ~/project preserves the string as-is (remoteCwd: "~/project") — the tilde is NOT expanded for non-gateway hosts.
  • Node with no workdir omits cwd entirely.

Host-scoping proof

To confirm node and sandbox workdirs are not affected by the gateway-local tilde expansion:

Test: resolveExecWorkdir({host: "node", workdir: "~/project"}) returns {kind: "node", remoteCwd: "~/project"} — the value is forwarded verbatim to the remote node host without gateway-local rewriting.

Test file: src/agents/bash-tools.exec-workdir.test.ts includes regression test "preserves leading tilde in node workdirs without local expansion".

Tests and validation

$ pnpm test src/agents/bash-tools.exec-workdir.test.ts
 Test Files  1 passed (1)
      Tests  38 passed (38)

Risk checklist

Did user-visible behavior change? (Yes)

  • exec.workdir with leading ~/~/ now expands to home directory for local gateway execution

Did config, environment, or migration behavior change? (No)

Did security, auth, secrets, network, or tool execution behavior change? (No)

  • Tilde expansion only affects gateway-local paths; uses expandHomePrefix() from the existing home-dir helper

What is the highest-risk area?

  • Edge case where homedir() returns an unexpected path

How is that risk mitigated?

  • If the expanded path does not exist, the existing fallback mechanism still applies
  • The fix is scoped to gateway execution only; node and sandbox workdir behavior is unchanged
  • Regression test proves node ~/... values are forwarded verbatim

Current review state

What is the next action?

  • Maintainer review

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 18, 2026
@vincentkoc vincentkoc self-assigned this Jun 18, 2026
@vincentkoc
vincentkoc force-pushed the fix/issue-94434-exec-workdir-tilde-expansion branch 2 times, most recently from 5bd6724 to 710e0ef Compare June 18, 2026 09:27
@Pandah97

Copy link
Copy Markdown
Contributor Author

@vincentkoc Thanks for the refactor — your version is cleaner than mine. I've reviewed the changes and everything looks good. All CI checks have passed. Is there anything else needed from my side before this gets merged?

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 20, 2026
@clawsweeper

clawsweeper Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed July 2, 2026, 10:11 PM ET / 02:11 UTC.

Summary
The PR expands leading ~ only for gateway-local exec workdirs, updates unavailable-workdir tests, and adjusts two gateway cron test typings.

PR surface: Source +4, Tests +23. Total +27 across 6 files.

Reproducibility: yes. for source-level behavior: current main passes gateway workdir strings directly to the host stat check, so ~/... is treated literally before this PR. I did not run tests because this review is read-only.

Review metrics: 2 noteworthy metrics.

  • Gateway-local workdir semantics: 1 path class changed. Existing ~/... gateway workdirs that currently fail before execution can execute from the OS home path after merge.
  • Shared diagnostic changed: 1 formatter changed. The formatter is used by unavailable workdir failures across gateway, node, and sandbox paths, so host-specific wording must stay accurate.

Root-cause cluster
Relationship: canonical
Canonical: #94449
Summary: This PR is the current open branch for the remaining gateway-local tilde-expansion direction; the original unsafe fallback was fixed by a merged sibling, and older tilde-expansion attempts are closed.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦞 diamond lobster
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Make the unavailable-workdir diagnostic neutral or host-aware across gateway, node, and sandbox failures.
  • Rebase or otherwise refresh the branch so GitHub no longer reports it as conflicting.
  • Get maintainer acceptance for the gateway-local tilde-expansion compatibility change.

Risk before merge

  • [P1] Merging changes existing gateway-local explicit or configured ~/... workdirs from failing before execution on current main to executing from the OS home path when that directory exists.
  • [P1] The shared unavailable-workdir message would show gateway-local tilde guidance for non-tilde gateway, blank/current-cwd, node, and sandbox failures, while dropping the broader guidance that structured workdir fields do not apply other shell expansions.
  • [P1] GitHub currently reports the PR as conflicting with main, so the exact merge result still needs a rebase or refresh before landing.

Maintainer options:

  1. Make the diagnostic neutral before merge (recommended)
    Rebase the branch and change the shared formatter to say that only gateway-local leading ~ is expanded while other shell expansions are not applied, with coverage for non-tilde and non-gateway failures.
  2. Accept gateway-local expansion deliberately
    After the diagnostic is repaired, maintainers can explicitly accept that existing gateway-local ~/... workdirs now resolve to the OS home path when it exists.
  3. Close as covered by fail-fast behavior
    If maintainers do not want local tilde expansion, close this PR because fix(exec): fail invalid explicit workdir before running #94441 already fixed the unsafe fallback part of the original report.

Next step before merge

  • [P2] Needs maintainer acceptance of the compatibility semantics and conflict resolution; the diagnostic repair is narrow, but not enough to make the PR mergeable without human choice.

Security
Cleared: The diff changes local exec workdir resolution and tests only, with no new dependency, workflow, secret, package, download, or supply-chain surface.

Review findings

  • [P2] Keep unavailable-workdir guidance accurate across hosts — src/agents/bash-tools.exec-workdir.ts:331
Review details

Best possible solution:

If maintainers want this follow-on behavior, rebase the branch, keep expansion scoped to gateway-local exec workdirs, and make the shared unavailable-workdir diagnostic accurate for tilde and non-tilde failures across hosts.

Do we have a high-confidence way to reproduce the issue?

Yes for source-level behavior: current main passes gateway workdir strings directly to the host stat check, so ~/... is treated literally before this PR. I did not run tests because this review is read-only.

Is this the best way to solve the issue?

Not yet. The gateway branch is the right layer if maintainers want tilde expansion, but the already-merged fail-fast behavior fixed the unsafe fallback and this PR still needs conflict resolution, diagnostic repair, and compatibility acceptance.

Full review comments:

  • [P2] Keep unavailable-workdir guidance accurate across hosts — src/agents/bash-tools.exec-workdir.ts:331
    This shared formatter is used for every unavailable workdir result, but the new sentence only says leading ~ is expanded for gateway-local execution. For non-tilde gateway failures, blank/current-cwd failures, node failures, and sandbox failures, users lose the existing guidance that structured workdir values are literal path fields and do not get other shell expansion. Please make this sentence neutral or host-aware while preserving the non-tilde/non-gateway guidance.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 3ad465d32b3b.

Label changes

Label changes:

  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (terminal): The PR body includes copied terminal output from a real Linux checkout showing gateway ~ expansion, nonexistent tilde rejection, /tmp unchanged, and node tilde preservation.
  • remove status: 🛠️ actively grinding: Current PR status label is status: ⏳ waiting on author.

Label justifications:

  • P2: This is a normal-priority exec behavior fix with bounded but real impact on agent commands that use structured workdirs.
  • merge-risk: 🚨 compatibility: The PR changes how existing gateway-local ~/... workdir strings are interpreted before command execution.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (terminal): The PR body includes copied terminal output from a real Linux checkout showing gateway ~ expansion, nonexistent tilde rejection, /tmp unchanged, and node tilde preservation.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes copied terminal output from a real Linux checkout showing gateway ~ expansion, nonexistent tilde rejection, /tmp unchanged, and node tilde preservation.
Evidence reviewed

PR surface:

Source +4, Tests +23. Total +27 across 6 files.

View PR surface stats
Area Files Added Removed Net
Source 1 7 3 +4
Tests 5 31 8 +23
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 6 38 11 +27

What I checked:

Likely related people:

  • renaudcerrato: Authored the merged fail-fast work in fix(exec): fail invalid explicit workdir before running #94441, which introduced the current resolver/diagnostic surface this PR modifies. (role: canonical fail-fast fix author; confidence: high; commits: 95b97e5b0b5e, c910af35818b, b41511eb888b; files: src/agents/bash-tools.exec-workdir.ts, src/agents/bash-tools.exec-workdir.test.ts, src/agents/bash-tools.exec.ts)
  • jesse-merhi: Authored several follow-up commits in the merged fail-fast branch and posted the squash-merge proof for the landed resolver commit. (role: recent exec workdir contributor and merger; confidence: high; commits: b84d0a0e00be, b050f3d6458d, 95b97e5b0b5e; files: src/agents/bash-tools.exec-workdir.ts, src/agents/bash-tools.exec.ts, src/agents/bash-tools.exec-workdir.test.ts)
  • vincentkoc: The PR timeline shows assignment to this area, and branch/history evidence includes a Vincent Koc commit for OS-home tilde workdir semantics plus repeated recent exec-area touches. (role: recent area contributor and assigned reviewer; confidence: medium; commits: 710e0eff9d98; files: src/agents/bash-tools.exec-workdir.ts, src/agents/bash-tools.exec-workdir.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@Pandah97
Pandah97 force-pushed the fix/issue-94434-exec-workdir-tilde-expansion branch from 710e0ef to 7c1fb87 Compare June 26, 2026 06:43
@Pandah97
Pandah97 requested a review from a team as a code owner June 26, 2026 06:43
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: msteams Channel integration: msteams channel: zalouser Channel integration: zalouser app: ios App: ios gateway Gateway runtime extensions: memory-core Extension: memory-core scripts Repository scripts commands Command implementations extensions: github-copilot extensions: copilot labels Jun 26, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 26, 2026
@Pandah97
Pandah97 force-pushed the fix/issue-94434-exec-workdir-tilde-expansion branch from 710e0ef to a9bb3dc Compare June 26, 2026 07:16
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed merge-risk: 🚨 automation 🚨 May affect CI, automerge, proof capture, label sync, or maintainer automation. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 26, 2026
Pandah97 added a commit to Pandah97/openclaw that referenced this pull request Jul 1, 2026
The previous message claimed "~" is not expanded, but this PR
adds leading tilde expansion for local (gateway) execution.
Update the diagnostic to reflect the new behavior.

Ref. openclaw#94449
Pandah97 added a commit to Pandah97/openclaw that referenced this pull request Jul 1, 2026
…tic message

Updated expect strings in two test files to match the revised
formatUnavailableWorkdirFailure message that correctly describes
tilde expansion behavior for local execution.

Ref. openclaw#94449
@Pandah97
Pandah97 force-pushed the fix/issue-94434-exec-workdir-tilde-expansion branch from 6c15095 to 41565d1 Compare July 1, 2026 06:38
Pandah97 added a commit to Pandah97/openclaw that referenced this pull request Jul 1, 2026
The previous message claimed "~" is not expanded, but this PR
adds leading tilde expansion for local (gateway) execution.
Update the diagnostic to reflect the new behavior.

Ref. openclaw#94449
Pandah97 added a commit to Pandah97/openclaw that referenced this pull request Jul 1, 2026
…tic message

Updated expect strings in two test files to match the revised
formatUnavailableWorkdirFailure message that correctly describes
tilde expansion behavior for local execution.

Ref. openclaw#94449
Pandah97 added a commit to Pandah97/openclaw that referenced this pull request Jul 1, 2026
- Replace String() cast with type assertion to fix no-base-to-string lint
- Add generic type param to vi.fn() calls to fix TS2493 tuple access

Ref. openclaw#94449
@openclaw-barnacle openclaw-barnacle Bot added the gateway Gateway runtime label Jul 1, 2026
@Pandah97

Pandah97 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Changes made:

  • Qualified unavailable-workdir diagnostic as gateway-local: changed from 'Leading "" is expanded to the home directory for local execution' to 'Leading "" is expanded for gateway-local execution'
  • Updated 2 test assertions to match the new wording
  • All 114 tests pass across 4 test files (bash-tools.exec-workdir.test.ts, bash-tools.exec.path.test.ts, bash-tools.exec-foreground-failures.test.ts, bash-tools.exec.resolve-env-hook.test.ts)

This addresses the P2 finding: make unavailable-workdir guidance host-aware. The message now accurately reflects that tilde expansion is a gateway-local feature, which remains true for all callers (gateway, node, sandbox).

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: XS status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: exec workdir with leading ~ falls back and still executes command

2 participants