---
phase: 04-direct-command-mappings
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - cmd_log.py
  - cmd_diff.py
  - cmd_init.py
  - gitsl.py
  - tests/test_cmd_log.py
  - tests/test_cmd_diff.py
  - tests/test_cmd_init.py
autonomous: true

must_haves:
  truths:
    - "git log runs sl log and shows output"
    - "git diff runs sl diff and shows output"
    - "git init runs sl init and creates repo"
  artifacts:
    - path: "cmd_log.py"
      provides: "Handler for git log command"
      exports: ["handle"]
    - path: "cmd_diff.py"
      provides: "Handler for git diff command"
      exports: ["handle"]
    - path: "cmd_init.py"
      provides: "Handler for git init command"
      exports: ["handle"]
    - path: "tests/test_cmd_log.py"
      provides: "E2E tests for log command"
    - path: "tests/test_cmd_diff.py"
      provides: "E2E tests for diff command"
    - path: "tests/test_cmd_init.py"
      provides: "E2E tests for init command"
  key_links:
    - from: "gitsl.py"
      to: "cmd_log.py"
      via: "import and dispatch"
      pattern: "import cmd_log.*cmd_log\\.handle"
    - from: "gitsl.py"
      to: "cmd_diff.py"
      via: "import and dispatch"
      pattern: "import cmd_diff.*cmd_diff\\.handle"
    - from: "gitsl.py"
      to: "cmd_init.py"
      via: "import and dispatch"
      pattern: "import cmd_init.*cmd_init\\.handle"
    - from: "cmd_*.py"
      to: "common.py"
      via: "run_sl() for subprocess execution"
      pattern: "from common import.*run_sl"
---

<objective>
Implement three passthrough command handlers (log, diff, init) following the established cmd_status.py pattern.

Purpose: Fulfill CMD-04, CMD-05, CMD-06 requirements - direct 1:1 git-to-sl command translations.
Output: Three new handler files, updated gitsl.py dispatch, and E2E tests for each command.
</objective>

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

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

<tasks>

<task type="auto">
  <name>Task 1: Create passthrough command handlers</name>
  <files>cmd_log.py, cmd_diff.py, cmd_init.py, gitsl.py</files>
  <action>
Create three handler files following the exact pattern from cmd_status.py:

1. Create cmd_log.py:
   - Docstring: Handler for 'git log' command
   - Import: from common import ParsedCommand, run_sl
   - handle(parsed: ParsedCommand) -> int function
   - Body: return run_sl(["log"] + parsed.args)

2. Create cmd_diff.py:
   - Same pattern, command = "diff"

3. Create cmd_init.py:
   - Same pattern, command = "init"

4. Update gitsl.py:
   - Add imports: import cmd_log, import cmd_diff, import cmd_init
   - Add dispatch cases after the status handler:
     - if parsed.command == "log": return cmd_log.handle(parsed)
     - if parsed.command == "diff": return cmd_diff.handle(parsed)
     - if parsed.command == "init": return cmd_init.handle(parsed)

DO NOT modify common.py or cmd_status.py - they already work correctly.
DO NOT use capture_output - these are passthrough handlers using run_sl().
  </action>
  <verify>
    python -c "import cmd_log; import cmd_diff; import cmd_init; print('OK')"
    GITSL_DEBUG=1 python gitsl.py log 2>&1 | grep -q "Would execute: sl log"
    GITSL_DEBUG=1 python gitsl.py diff 2>&1 | grep -q "Would execute: sl diff"
    GITSL_DEBUG=1 python gitsl.py init 2>&1 | grep -q "Would execute: sl init"
  </verify>
  <done>
    - cmd_log.py, cmd_diff.py, cmd_init.py exist with correct pattern
    - gitsl.py imports all three and dispatches to them
    - Debug mode shows correct sl commands for log, diff, init
  </done>
</task>

<task type="auto">
  <name>Task 2: Add E2E tests for passthrough commands</name>
  <files>tests/test_cmd_log.py, tests/test_cmd_diff.py, tests/test_cmd_init.py</files>
  <action>
Create E2E tests following the pattern from test_execution.py:

1. Create tests/test_cmd_log.py:
   - Import shutil, pytest, Path
   - Import run_gitsl from conftest
   - sl_available check with skipif marker
   - TestLogBasic class:
     - test_log_succeeds_in_repo_with_commit: verify exit_code == 0
     - test_log_shows_output: verify stdout or stderr not empty
   - TestLogExitCodes class:
     - test_log_fails_in_non_repo: verify exit_code != 0 in tmp_path (not a repo)

2. Create tests/test_cmd_diff.py:
   - TestDiffBasic class:
     - test_diff_succeeds_in_repo: verify exit_code == 0 in git_repo
     - test_diff_shows_changes: verify output not empty in git_repo_with_changes
   - TestDiffExitCodes class:
     - test_diff_fails_in_non_repo: verify exit_code != 0 in tmp_path

3. Create tests/test_cmd_init.py:
   - TestInitBasic class:
     - test_init_creates_repo: run gitsl init in empty tmp_path, verify exit_code == 0
     - test_init_creates_hg_directory: verify .hg/ directory exists after init
   - Note: Use tmp_path directly (NOT git_repo fixture) since init creates the repo

All test files must:
- Use sl_available skipif pattern
- Use fixtures from conftest.py
- Follow pytest conventions
  </action>
  <verify>
    pytest tests/test_cmd_log.py tests/test_cmd_diff.py tests/test_cmd_init.py -v
  </verify>
  <done>
    - All tests pass
    - Tests verify exit codes and output for each command
    - Tests properly skip when sl is not installed
  </done>
</task>

</tasks>

<verification>
Run full test suite to ensure nothing is broken:

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

Verify commands work manually (if sl available):

```bash
cd /tmp && mkdir test_gitsl && cd test_gitsl
python /path/to/gitsl.py init
python /path/to/gitsl.py log
python /path/to/gitsl.py diff
```
</verification>

<success_criteria>
- [ ] CMD-04: git log translates to sl log (verified by test)
- [ ] CMD-05: git diff translates to sl diff (verified by test)
- [ ] CMD-06: git init translates to sl init (verified by test)
- [ ] All new tests pass
- [ ] Existing tests still pass
- [ ] No regressions in status command
</success_criteria>

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