Feature: Skill File Operation Tools As a developer I want skill-level file operation tools So that agents can safely read, write, edit, and delete files with enhanced safety features like binary detection, atomic writes, and newline normalization # ---- ReadFile ---- Scenario: ReadFile reads text file content Given a skill file ops sandbox directory And a sandbox file "greeting.txt" with content "Hello, World!" When I execute the "skill/file-read" tool with path "greeting.txt" Then the skill tool result should be successful And the skill output "content" should be "Hello, World!" And the skill output "encoding" should be "utf-8" And the skill output "size" should be greater than 0 Scenario: ReadFile with offset and limit Given a skill file ops sandbox directory And a sandbox file "lines.txt" with lines "line1,line2,line3,line4" When I execute the "skill/file-read" tool with path "lines.txt" offset 1 limit 2 Then the skill tool result should be successful And the skill output "content" should contain "line2" And the skill output "content" should contain "line3" And the skill output "content" should not contain "line1" Scenario: ReadFile detects binary files and returns error Given a skill file ops sandbox directory And a binary file "image.png" in the sandbox When I execute the "skill/file-read" tool with path "image.png" Then the skill tool result should not be successful And the skill tool error should mention "Binary file detected" Scenario: ReadFile rejects missing file Given a skill file ops sandbox directory When I execute the "skill/file-read" tool with path "ghost.txt" Then the skill tool result should not be successful And the skill tool error should mention "not found" Scenario: ReadFile enforces content size limit Given a skill file ops sandbox directory And an oversized file "huge.txt" in the sandbox When I execute the "skill/file-read" tool with path "huge.txt" Then the skill tool result should not be successful And the skill tool error should mention "too large" Scenario: ReadFile normalizes UTF-8 encoding Given a skill file ops sandbox directory And a sandbox file "utf8.txt" with content "caf\u00e9" When I execute the "skill/file-read" tool with path "utf8.txt" Then the skill tool result should be successful And the skill output "content" should contain "caf" Scenario: ReadFile rejects non-file path Given a skill file ops sandbox directory And a sandbox subdirectory "mydir" When I execute the "skill/file-read" tool with path "mydir" Then the skill tool result should not be successful And the skill tool error should mention "Not a regular file" # ---- WriteFile ---- Scenario: WriteFile creates a new file atomically Given a skill file ops sandbox directory When I execute the "skill/file-write" tool with path "new.txt" and content "created" Then the skill tool result should be successful And the skill output "created" should be boolean true And the skill output "size" should be greater than 0 And the sandbox file "new.txt" should exist Scenario: WriteFile overwrites an existing file Given a skill file ops sandbox directory And a sandbox file "existing.txt" with content "old" When I execute the "skill/file-write" tool with path "existing.txt" and content "new" Then the skill tool result should be successful And the skill output "created" should be boolean false Scenario: WriteFile creates parent directories Given a skill file ops sandbox directory When I execute the "skill/file-write" tool with path "sub/dir/file.txt" and content "nested" Then the skill tool result should be successful And the sandbox file "sub/dir/file.txt" should exist Scenario: WriteFile with LF newline normalization Given a skill file ops sandbox directory When I write "skill/file-write" with path "lf.txt" content "a\r\nb\r\n" and newline_mode "lf" Then the skill tool result should be successful And the sandbox file "lf.txt" should not contain carriage return Scenario: WriteFile with CRLF newline normalization Given a skill file ops sandbox directory When I write "skill/file-write" with path "crlf.txt" content "a\nb\n" and newline_mode "crlf" Then the skill tool result should be successful And the sandbox file "crlf.txt" should contain carriage return # ---- EditFile ---- Scenario: EditFile with single replacement Given a skill file ops sandbox directory And a sandbox file "edit.txt" with content "foo bar foo" When I execute the "skill/file-edit" tool replacing "foo" with "baz" in "edit.txt" Then the skill tool result should be successful And the skill output "replacements" should equal 1 Scenario: EditFile with replace_all Given a skill file ops sandbox directory And a sandbox file "edit.txt" with content "foo bar foo" When I execute the "skill/file-edit" tool replacing all "foo" with "baz" in "edit.txt" Then the skill tool result should be successful And the skill output "replacements" should equal 2 Scenario: EditFile preserves file permissions Given a skill file ops sandbox directory And a sandbox file "perm.txt" with content "original" and mode 0o755 When I execute the "skill/file-edit" tool replacing "original" with "modified" in "perm.txt" Then the skill tool result should be successful And the sandbox file "perm.txt" should have mode 0o755 Scenario: EditFile with text not found raises error Given a skill file ops sandbox directory And a sandbox file "edit.txt" with content "foo bar" When I execute the "skill/file-edit" tool replacing "notfound" with "x" in "edit.txt" Then the skill tool result should not be successful And the skill tool error should mention "not found" Scenario: EditFile rejects missing file Given a skill file ops sandbox directory When I execute the "skill/file-edit" tool replacing "a" with "b" in "ghost.txt" Then the skill tool result should not be successful And the skill tool error should mention "not found" # ---- DeleteFile ---- Scenario: DeleteFile removes an existing file Given a skill file ops sandbox directory And a sandbox file "doomed.txt" with content "goodbye" When I execute the "skill/file-delete" tool with path "doomed.txt" Then the skill tool result should be successful And the skill output "existed" should be boolean true And the sandbox file "doomed.txt" should not exist Scenario: DeleteFile on nonexistent file reports not existed Given a skill file ops sandbox directory When I execute the "skill/file-delete" tool with path "ghost.txt" Then the skill tool result should be successful And the skill output "existed" should be boolean false Scenario: DeleteFile rejects directory targets Given a skill file ops sandbox directory And a sandbox subdirectory "mydir" When I execute the "skill/file-delete" tool with path "mydir" Then the skill tool result should not be successful And the skill tool error should mention "non-file" # ---- Path Traversal Guards ---- Scenario: Path traversal with dotdot in read is rejected Given a skill file ops sandbox directory When I execute the "skill/file-read" tool with path "../../etc/passwd" Then the skill tool result should not be successful And the skill tool error should mention "traversal" And the skill tool error should mention "../../etc/passwd" Scenario: Path traversal in write is rejected Given a skill file ops sandbox directory When I execute the "skill/file-write" tool with path "../escape.txt" and content "evil" Then the skill tool result should not be successful And the skill tool error should mention "traversal" And the skill tool error should mention "../escape.txt" Scenario: Path traversal in edit is rejected Given a skill file ops sandbox directory And a sandbox file "safe.txt" with content "safe" When I execute the "skill/file-edit" tool replacing "safe" with "x" in "../evil.txt" Then the skill tool result should not be successful And the skill tool error should mention "traversal" Scenario: Path traversal in delete is rejected Given a skill file ops sandbox directory When I execute the "skill/file-delete" tool with path "../../etc/important" Then the skill tool result should not be successful And the skill tool error should mention "traversal" # ---- Read-Only Enforcement ---- Scenario: ReadFile tool has read_only capability Given a skill file tools registry Then the "skill/file-read" tool should have read_only capability Scenario: WriteFile tool has writes capability Given a skill file tools registry Then the "skill/file-write" tool should have writes capability Scenario: EditFile tool has writes capability Given a skill file tools registry Then the "skill/file-edit" tool should have writes capability Scenario: DeleteFile tool has writes capability Given a skill file tools registry Then the "skill/file-delete" tool should have writes capability # ---- Registration ---- Scenario: Register all skill file tools Given a skill file tools registry Then the skill registry should contain 4 tools And the skill registry should contain tool "skill/file-read" And the skill registry should contain tool "skill/file-write" And the skill registry should contain tool "skill/file-edit" And the skill registry should contain tool "skill/file-delete" # ---- Newline normalization helpers ---- Scenario: Newline normalization with invalid mode raises error Given a skill file ops sandbox directory When I write "skill/file-write" with path "bad.txt" content "test" and newline_mode "invalid" Then the skill tool result should not be successful And the skill tool error should mention "Invalid newline mode" # ---- Empty path validation ---- Scenario: Empty path is rejected in read Given a skill file ops sandbox directory When I execute the "skill/file-read" tool with an empty path Then the skill tool result should not be successful And the skill tool error should mention "must not be empty" # ---- Binary detection heuristic ---- Scenario: ReadFile detects ELF binary Given a skill file ops sandbox directory And an ELF binary file "program" in the sandbox When I execute the "skill/file-read" tool with path "program" Then the skill tool result should not be successful And the skill tool error should mention "Binary file detected" Scenario: ReadFile detects high control character content Given a skill file ops sandbox directory And a control-heavy file "binary.dat" in the sandbox When I execute the "skill/file-read" tool with path "binary.dat" Then the skill tool result should not be successful And the skill tool error should mention "Binary file detected" # ---- Coverage: _is_binary OSError, create_dirs, atomic write cleanup ---- Scenario: _is_binary returns false for unreadable path Given a skill file ops sandbox directory When I check _is_binary on a nonexistent path Then _is_binary should return false Scenario: WriteFile creates parent directories with create_dirs Given a skill file ops sandbox directory When I execute write_file with create_dirs to "deep/nested/dir/file.txt" and content "hello dirs" Then the skill tool result should be successful And the written file "deep/nested/dir/file.txt" should contain "hello dirs" Scenario: _is_fd_closed returns false for open descriptor When I check _is_fd_closed with an open file descriptor Then _is_fd_closed should return false Scenario: _is_fd_closed returns true for closed descriptor When I check _is_fd_closed with a closed file descriptor Then _is_fd_closed should return true Scenario: WriteFile atomic write cleanup on os.replace failure Given a skill file ops sandbox directory When I simulate atomic write failure during replace Then the temporary file should be cleaned up And the original exception should propagate Scenario: EditFile atomic write cleanup on os.chmod failure Given a skill file ops sandbox directory And a sandbox file "editable.txt" with content "original content" When I simulate edit atomic write failure during chmod Then the temporary file should be cleaned up after edit And the original edit exception should propagate