---
phase: 04-direct-command-mappings
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - cmd_rev_parse.py
  - gitsl.py
  - tests/test_cmd_rev_parse.py
autonomous: true

must_haves:
  truths:
    - "git rev-parse --short HEAD returns 7-char hash"
    - "Output matches git's short hash format (7 hex characters)"
    - "Exit code 0 on success, non-zero in non-repo"
  artifacts:
    - path: "cmd_rev_parse.py"
      provides: "Handler for git rev-parse command"
      exports: ["handle"]
    - path: "tests/test_cmd_rev_parse.py"
      provides: "E2E tests for rev-parse command"
  key_links:
    - from: "gitsl.py"
      to: "cmd_rev_parse.py"
      via: "import and dispatch"
      pattern: "import cmd_rev_parse.*cmd_rev_parse\\.handle"
    - from: "cmd_rev_parse.py"
      to: "sl whereami"
      via: "subprocess.run with capture_output"
      pattern: "subprocess\\.run.*whereami.*capture_output"
---

<objective>
Implement rev-parse --short HEAD handler that translates to sl whereami with output truncation.

Purpose: Fulfill CMD-07 requirement - git rev-parse --short HEAD returns current commit hash.
Output: cmd_rev_parse.py handler with special output processing, updated dispatch, and E2E tests.
</objective>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/04-direct-command-mappings/04-RESEARCH.md

# Existing patterns
@gitsl.py
@common.py
@tests/conftest.py
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create rev-parse handler with output truncation</name>
  <files>cmd_rev_parse.py, gitsl.py</files>
  <action>
Create cmd_rev_parse.py that handles git rev-parse --short HEAD specially:

1. Create cmd_rev_parse.py:
   ```python
   """Handler for 'git rev-parse' command."""

   import subprocess
   import sys
   from common import ParsedCommand


   def handle(parsed: ParsedCommand) -> int:
       """
       Handle 'git rev-parse' command.

       Currently only supports: --short HEAD -> sl whereami (truncated to 7 chars)
       """
       # Check for --short HEAD pattern (either order)
       if "--short" in parsed.args and "HEAD" in parsed.args:
           result = subprocess.run(
               ["sl", "whereami"],
               capture_output=True,
               text=True
           )
           if result.returncode == 0:
               # sl whereami returns 40 chars, git rev-parse --short returns 7
               short_hash = result.stdout.strip()[:7]
               print(short_hash)
           else:
               # Pass through error
               sys.stderr.write(result.stderr)
           return result.returncode

       # Unsupported rev-parse variants
       sys.stderr.write("gitsl: rev-parse currently only supports --short HEAD\n")
       return 1
   ```

2. Update gitsl.py:
   - Add import: import cmd_rev_parse
   - Add dispatch case after init (before fallback):
     - if parsed.command == "rev-parse": return cmd_rev_parse.handle(parsed)

Key differences from passthrough handlers:
- Uses subprocess.run with capture_output=True (NOT run_sl)
- Truncates output to 7 characters
- Only implements --short HEAD pattern
- Returns error for unsupported variants
  </action>
  <verify>
    python -c "import cmd_rev_parse; print('OK')"
    # Debug mode won't work for rev-parse since it's special-cased
    # Manual test if sl available:
    # cd to_a_sl_repo && python gitsl.py rev-parse --short HEAD
  </verify>
  <done>
    - cmd_rev_parse.py exists with output truncation logic
    - gitsl.py imports and dispatches to cmd_rev_parse
    - Unsupported variants return error with helpful message
  </done>
</task>

<task type="auto">
  <name>Task 2: Add E2E tests for rev-parse command</name>
  <files>tests/test_cmd_rev_parse.py, tests/conftest.py</files>
  <action>
Create E2E tests for rev-parse and add sl_repo fixture:

1. Add sl_repo fixture to tests/conftest.py:
   ```python
   @pytest.fixture
   def sl_repo(tmp_path: Path) -> Path:
       """
       Create a temporary Sapling repository.

       Uses sl init to create a proper .hg/ repo.
       Configured with test user for commits.

       Returns:
           Path to the initialized sl repository
       """
       run_command(["sl", "init"], cwd=tmp_path)
       run_command(["sl", "config", "--local", "ui.username", "Test User <test@test.com>"], cwd=tmp_path)
       return tmp_path


   @pytest.fixture
   def sl_repo_with_commit(sl_repo: Path) -> Path:
       """
       Sapling repo with initial commit.

       Creates README.md and commits it.

       Returns:
           Path to the sl repository with one commit
       """
       readme = sl_repo / "README.md"
       readme.write_text("# Test Repository\n")

       run_command(["sl", "add", "README.md"], cwd=sl_repo)
       run_command(["sl", "commit", "-m", "Initial commit"], cwd=sl_repo)

       return sl_repo
   ```

2. Create tests/test_cmd_rev_parse.py:
   ```python
   """E2E tests for git rev-parse command."""

   import shutil
   from pathlib import Path

   import pytest

   from conftest import run_gitsl


   sl_available = shutil.which("sl") is not None
   pytestmark = pytest.mark.skipif(not sl_available, reason="Sapling (sl) not installed")


   class TestRevParseShortHead:
       """CMD-07: git rev-parse --short HEAD translates to sl whereami."""

       def test_rev_parse_returns_7_chars(self, sl_repo_with_commit: Path):
           """Output is exactly 7 characters (short hash)."""
           result = run_gitsl(["rev-parse", "--short", "HEAD"], cwd=sl_repo_with_commit)
           assert result.exit_code == 0
           output = result.stdout.strip()
           assert len(output) == 7, f"Expected 7 chars, got {len(output)}: '{output}'"

       def test_rev_parse_returns_hex_chars(self, sl_repo_with_commit: Path):
           """Output is valid hex characters."""
           result = run_gitsl(["rev-parse", "--short", "HEAD"], cwd=sl_repo_with_commit)
           assert result.exit_code == 0
           output = result.stdout.strip()
           assert all(c in "0123456789abcdef" for c in output), f"Invalid hex: '{output}'"

       def test_rev_parse_head_first_order(self, sl_repo_with_commit: Path):
           """Handles 'HEAD --short' order (alternative to '--short HEAD')."""
           result = run_gitsl(["rev-parse", "HEAD", "--short"], cwd=sl_repo_with_commit)
           # Should also work - both args present
           assert result.exit_code == 0


   class TestRevParseExitCodes:
       """Exit code handling for rev-parse."""

       def test_rev_parse_fails_in_non_repo(self, tmp_path: Path):
           """Returns non-zero in non-repo directory."""
           result = run_gitsl(["rev-parse", "--short", "HEAD"], cwd=tmp_path)
           assert result.exit_code != 0

       def test_unsupported_variant_returns_error(self, sl_repo_with_commit: Path):
           """Unsupported rev-parse variants return error."""
           # Without --short or HEAD, should fail
           result = run_gitsl(["rev-parse", "--verify", "master"], cwd=sl_repo_with_commit)
           assert result.exit_code != 0
           assert "only supports" in result.stderr.lower() or result.exit_code != 0
   ```

Important:
- Use sl_repo_with_commit fixture (needs actual sl repo for whereami to work)
- Test both argument orders (--short HEAD and HEAD --short)
- Verify exact 7-character output length
- Verify hex character validity
  </action>
  <verify>
    pytest tests/test_cmd_rev_parse.py -v
  </verify>
  <done>
    - All rev-parse tests pass
    - Tests verify 7-char hex output
    - Tests verify exit codes
    - sl_repo fixtures available for future use
  </done>
</task>

</tasks>

<verification>
Run full test suite:

```bash
pytest tests/ -v
```

Manual verification if sl available:

```bash
# Create sl repo with commit
cd /tmp && rm -rf test_revparse && mkdir test_revparse && cd test_revparse
sl init
echo "test" > file.txt
sl add file.txt
sl commit -m "test"

# Test rev-parse
python /path/to/gitsl.py rev-parse --short HEAD
# Should output 7-char hex hash

# Compare with sl whereami
sl whereami | cut -c1-7
# Should match
```
</verification>

<success_criteria>
- [ ] CMD-07: git rev-parse --short HEAD returns 7-char hash
- [ ] Output is valid hexadecimal
- [ ] Exit code 0 on success
- [ ] Exit code non-zero in non-repo
- [ ] Unsupported variants return helpful error
- [ ] All new tests pass
- [ ] Existing tests still pass
</success_criteria>

<output>
After completion, create `.planning/phases/04-direct-command-mappings/04-02-SUMMARY.md`
</output>
