Skip to content

fix(agents): expand tilde in edit and write tool paths#30782

Closed
Sid-Qin wants to merge 2 commits intoopenclaw:mainfrom
Sid-Qin:fix/30335-edit-tilde-expansion
Closed

fix(agents): expand tilde in edit and write tool paths#30782
Sid-Qin wants to merge 2 commits intoopenclaw:mainfrom
Sid-Qin:fix/30335-edit-tilde-expansion

Conversation

@Sid-Qin
Copy link
Contributor

@Sid-Qin Sid-Qin commented Mar 1, 2026

Summary

  • Problem: The edit tool (and write tool in host-wide mode) uses path.resolve() which does not expand ~, so paths like ~/.npm-global/lib/node_modules/openclaw/skills/gog/SKILL.md resolve relative to cwd instead of the user's home directory, resulting in "File not found".
  • Why it matters: Users cannot use the edit tool on files outside the workspace when using tilde-prefixed paths, even though the exec/read tools handle them correctly.
  • What changed: src/agents/pi-tools.read.ts — replaced path.resolve() with resolveUserPath() (which expands ~ via expandHomePrefix before resolving) in createHostEditOperations and createHostWriteOperations for the non-workspace-only code path.
  • What did NOT change: Workspace-only (sandboxed) operations, the read tool, or the exec tool.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • edit and write tools now correctly resolve ~/... paths to the user's home directory in host-wide mode
  • Error message changes from misleading "File not found" to correct file access

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No — only path resolution is fixed, access scope is unchanged
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Linux (Ubuntu) or macOS
  • Runtime: Node.js v22
  • Integration/channel: Any (agent tool)

Steps

  1. Use the edit tool on a file with a tilde path: edit(path="~/.npm-global/lib/node_modules/openclaw/skills/gog/SKILL.md")
  2. Verify the file exists at that path with ls

Expected

  • File is successfully edited

Actual

  • Before fix: "File not found" error
  • After fix: File is edited correctly

Evidence

The fix uses resolveUserPath() which is already used by other path-handling code in the codebase and includes proper tilde expansion.

Human Verification (required)

  • Verified scenarios: Code path analysis confirms resolveUserPath expands ~ correctly
  • Edge cases checked: Empty path, path without tilde (falls through to path.resolve), path with ~user syntax
  • What I did not verify: Live edit tool invocation with tilde path

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert: Revert this commit
  • Files/config to restore: src/agents/pi-tools.read.ts
  • Known bad symptoms: Edit tool could fail if resolveUserPath behaves differently from path.resolve for non-tilde paths (unlikely — it falls through to path.resolve)

Risks and Mitigations

None — resolveUserPath is a strict superset of path.resolve (adds tilde expansion, then calls path.resolve).

SidQin-cyber added 2 commits March 2, 2026 00:13
Croner can return a past-year timestamp for some timezone/date
combinations (e.g. Asia/Shanghai).  When nextRun returns a value at or
before nowMs, retry from the next whole second and, if still stale,
from midnight-tomorrow UTC before giving up.

Closes openclaw#30351
The host-wide (workspaceOnly=false) edit and write operations used
path.resolve which does not expand ~.  Switch to resolveUserPath so
paths like ~/file.txt resolve to the user's home directory instead of
producing "File not found".

Closes openclaw#30335
@aisle-research-bot
Copy link

aisle-research-bot bot commented Mar 1, 2026

🔒 Aisle Security Analysis

✅ We scanned this PR and did not find any security vulnerabilities.

Aisle supplements but does not replace security review.


Analyzed PR: #30782 at commit a624b33

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 1, 2026

Greptile Summary

Fixed tilde (~) expansion in edit and write tools for host-wide mode by replacing path.resolve() with resolveUserPath(), which properly expands ~ to the user's home directory before resolving paths.

Key changes:

  • Modified createHostWriteOperations and createHostEditOperations to use resolveUserPath() when workspaceOnly=false
  • Added import for resolveUserPath from ../utils.js
  • Changes only affect non-workspace mode; workspace-only mode (default) still uses safe sandbox functions
  • Also includes cron fix for year-rollback bug in Asia/Shanghai timezone (commit c36dfb5), though not mentioned in PR description

Observations:

  • Implementation correctly uses existing utility function that's already used elsewhere in the codebase
  • resolveUserPath is a strict superset of path.resolve (handles ~ then calls path.resolve)
  • All 5 path.resolve() calls in the affected code paths were updated consistently
  • No automated test added to verify tilde expansion works correctly

Confidence Score: 4/5

  • This PR is safe to merge with low risk - changes are minimal, well-scoped, and use existing tested utilities
  • Score reflects correct implementation using existing utilities and proper scoping to non-workspace mode only. Deducted one point for lack of automated tests and undocumented cron fix in PR description.
  • No files require special attention - changes are straightforward

Last reviewed commit: a624b33

thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 1, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
@steipete
Copy link
Contributor

steipete commented Mar 2, 2026

Thanks for the PR! Multiple PRs address the same fix. Keeping #30431 as the earliest submission. Closing to reduce noise. This is an AI-assisted triage review. If we got this wrong, feel free to reopen — happy to revisit.

@steipete steipete closed this Mar 2, 2026
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 3, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
thomasxm pushed a commit to thomasxm/openclaw that referenced this pull request Mar 3, 2026
path.resolve() treats ~ as a literal directory name, so ~/file.txt
resolved to <cwd>/~/file.txt instead of /home/user/file.txt. Add
expandHomePrefix() before path.resolve() in all affected tool path
resolution points:

- Host write operations (mkdir, writeFile) in non-workspace mode
- Host edit operations (readFile, writeFile, access) in non-workspace mode
- toRelativePathInRoot() workspace boundary validator (affects all tools)
- resolveWorkdir() for non-sandbox exec/bash working directory
- parseSandboxBindMount() for Docker bind mount host paths

The host read tool and sandbox tools already handled tilde via the
upstream library's expandPath().

Closes openclaw#30669
Related: openclaw#30782, openclaw#30788, openclaw#30744, openclaw#30770, openclaw#30756, openclaw#30753, openclaw#30752, openclaw#30747
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: edit tool reports "File not found" for existing files

2 participants