---
phase: 27-grep-and-blame-flags
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - cmd_grep.py
  - cmd_blame.py
autonomous: true

must_haves:
  truths:
    - "User can search with git grep flags and get correct results"
    - "User can use git blame flags for enhanced annotation output"
    - "User gets helpful warnings for unsupported flags"
    - "git grep -v correctly inverts match (translated to sl -V)"
    - "git blame -b correctly ignores space changes (translated to sl --ignore-space-change)"
  artifacts:
    - path: "cmd_grep.py"
      provides: "Grep flag extraction and translation"
      min_lines: 80
      exports: ["handle"]
    - path: "cmd_blame.py"
      provides: "Blame flag extraction and translation"
      min_lines: 60
      exports: ["handle"]
  key_links:
    - from: "cmd_grep.py"
      to: "sl grep"
      via: "run_sl call with translated flags"
      pattern: "run_sl.*grep"
    - from: "cmd_blame.py"
      to: "sl annotate"
      via: "run_sl call with translated flags"
      pattern: "run_sl.*annotate"
---

<objective>
Extend cmd_grep.py and cmd_blame.py to support the full range of grep and blame flags specified in requirements GREP-01 through GREP-14 and BLAM-01 through BLAM-07.

Purpose: Enable users to search code and view file history with standard git flags, with proper translation to Sapling equivalents and warnings for unsupported features.

Output: Extended handlers with flag extraction, translation, and warning patterns following established codebase conventions.
</objective>

<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/REQUIREMENTS.md
@.planning/phases/27-grep-and-blame-flags/27-RESEARCH.md
@cmd_diff.py (reference for flag extraction pattern)
@cmd_grep.py (current implementation)
@cmd_blame.py (current implementation)
</context>

<tasks>

<task type="auto">
  <name>Task 1: Extend cmd_grep.py with Flag Support</name>
  <files>cmd_grep.py</files>
  <action>
Extend cmd_grep.py to extract and translate grep flags following the pattern in cmd_diff.py:

**Direct pass-through flags (add to sl_args):**
- GREP-01: `-n`/`--line-number` -> `-n`
- GREP-02: `-i`/`--ignore-case` -> `-i`
- GREP-03: `-l`/`--files-with-matches` -> `-l`
- GREP-05: `-w`/`--word-regexp` -> `-w`
- GREP-14: `-F`/`--fixed-strings` -> `-F`

**Context line flags with value parsing (handle both attached and separate formats):**
- GREP-07: `-A <num>` or `-A<num>` -> `-A <num>`
- GREP-08: `-B <num>` or `-B<num>` -> `-B <num>`
- GREP-09: `-C <num>` or `-C<num>` -> `-C <num>`

**Translation required:**
- GREP-06: `-v`/`--invert-match` -> `-V` (CRITICAL: sl uses uppercase V)
- GREP-13: `-q`/`--quiet` -> `-q` (pass through, works correctly)

**Unsupported flags (print warning to stderr, skip flag):**
- GREP-04: `-c`/`--count` - warn: "not supported by Sapling grep. Consider: sl grep pattern | wc -l"
- GREP-10: `-h` - warn: "suppress filename not supported. Filenames will be shown." (do NOT pass through - would show help)
- GREP-11: `-H` - no-op (already default behavior), skip silently
- GREP-12: `-o`/`--only-matching` - warn: "not supported. Consider: sl grep pattern | grep -o pattern"

**Implementation pattern:**
```python
import sys
from common import ParsedCommand, run_sl

def handle(parsed: ParsedCommand) -> int:
    sl_args = ["grep"]
    remaining_args = []

    i = 0
    while i < len(parsed.args):
        arg = parsed.args[i]

        # Direct pass-through flags
        if arg in ('-n', '--line-number'):
            sl_args.append('-n')
        elif arg in ('-i', '--ignore-case'):
            sl_args.append('-i')
        # ... more flags

        # Translation: git -v -> sl -V
        elif arg in ('-v', '--invert-match'):
            sl_args.append('-V')

        # Value parsing: -A<num> or -A <num>
        elif arg == '-A':
            if i + 1 < len(parsed.args):
                i += 1
                sl_args.extend(['-A', parsed.args[i]])
        elif arg.startswith('-A') and len(arg) > 2:
            sl_args.extend(['-A', arg[2:]])

        # Unsupported: warn and skip
        elif arg in ('-c', '--count'):
            print("Warning: -c/--count not supported by Sapling grep. "
                  "Consider: sl grep <pattern> | wc -l", file=sys.stderr)

        else:
            remaining_args.append(arg)

        i += 1

    sl_args.extend(remaining_args)
    return run_sl(sl_args)
```

Ensure docstring header documents all supported flags (GREP-01 through GREP-14).
  </action>
  <verify>
Run: `python -c "import cmd_grep; print('Import OK')"`
Verify cmd_grep.py has flag extraction loop and handles all 14 GREP requirements.
  </verify>
  <done>
cmd_grep.py extracts and translates all grep flags per requirements:
- Direct pass-through: -n, -i, -l, -w, -F, -q
- Context: -A, -B, -C with value parsing
- Translation: -v -> -V
- Warnings: -c, -h, -o with helpful messages
- No-op: -H (already default)
  </done>
</task>

<task type="auto">
  <name>Task 2: Extend cmd_blame.py with Flag Support</name>
  <files>cmd_blame.py</files>
  <action>
Extend cmd_blame.py to extract and translate blame flags following the same pattern:

**Direct pass-through flags:**
- BLAM-01: `-w` -> `-w`/`--ignore-all-space` (ignore whitespace)
- BLAM-07: `-n`/`--show-number` -> `-n` (show line numbers)

**Translation required:**
- BLAM-02: `-b` -> `--ignore-space-change` (CRITICAL: sl -b means "blank SHA1 for boundary" - completely different!)

**Unsupported flags (print warning to stderr, skip flag):**
- BLAM-03: `-L <start>,<end>` - warn: "line range not supported by Sapling annotate. Consider: sl annotate file | sed -n 'start,endp'"
  Handle both `-L10,20` (attached) and `-L 10,20` (separate) formats
- BLAM-04: `-e`/`--show-email` - warn: "show email not supported by Sapling annotate"
- BLAM-05: `-p`/`--porcelain` - warn: "porcelain output not supported by Sapling annotate"
- BLAM-06: `-l` (long hash) - warn: "long revision hash not supported. Use -T template for custom format." (CRITICAL: do NOT pass through - sl -l means "line number at first appearance")

**Implementation pattern:**
```python
import sys
from common import ParsedCommand, run_sl

def handle(parsed: ParsedCommand) -> int:
    sl_args = ["annotate"]
    remaining_args = []

    i = 0
    while i < len(parsed.args):
        arg = parsed.args[i]

        # Direct pass-through
        if arg == '-w':
            sl_args.append('-w')
        elif arg in ('-n', '--show-number'):
            sl_args.append('-n')

        # Translation: git -b (ignore space) -> sl --ignore-space-change
        # CRITICAL: sl -b means "blank SHA1 for boundary" - different meaning!
        elif arg == '-b':
            sl_args.append('--ignore-space-change')

        # Unsupported: -L line range
        elif arg == '-L':
            if i + 1 < len(parsed.args):
                i += 1
                line_range = parsed.args[i]
            else:
                line_range = "?"
            print(f"Warning: -L {line_range} line range not supported by Sapling annotate. "
                  f"Consider: sl annotate <file> | sed -n '{line_range}p'", file=sys.stderr)
        elif arg.startswith('-L'):
            line_range = arg[2:]
            print(f"Warning: -L{line_range} line range not supported by Sapling annotate. "
                  f"Consider: sl annotate <file> | sed -n '{line_range}p'", file=sys.stderr)

        # Unsupported: -l (long hash) - CRITICAL: sl -l has different meaning!
        elif arg == '-l':
            print("Warning: -l (long revision hash) not supported by Sapling annotate. "
                  "Sapling shows short hashes by default.", file=sys.stderr)

        else:
            remaining_args.append(arg)

        i += 1

    sl_args.extend(remaining_args)
    return run_sl(sl_args)
```

Ensure docstring header documents all supported flags (BLAM-01 through BLAM-07).
  </action>
  <verify>
Run: `python -c "import cmd_blame; print('Import OK')"`
Verify cmd_blame.py has flag extraction loop and handles all 7 BLAM requirements.
  </verify>
  <done>
cmd_blame.py extracts and translates all blame flags per requirements:
- Direct pass-through: -w, -n
- Translation: -b -> --ignore-space-change (critical semantic fix)
- Warnings: -L, -e, -p, -l with helpful messages
  </done>
</task>

<task type="auto">
  <name>Task 3: Verify Handler Integration</name>
  <files>cmd_grep.py, cmd_blame.py</files>
  <action>
Run existing tests to ensure handlers still work correctly with the new flag extraction:

1. Run existing grep tests:
   `pytest tests/test_grep.py -v`

2. Run existing blame tests:
   `pytest tests/test_blame.py -v`

3. Verify both handlers import correctly in gitsl.py dispatch:
   `python -c "import gitsl; print('Dispatch OK')"`

4. Quick smoke test of critical translations:
   - Create a test file with content
   - Test: `python gitsl.py grep -v pattern` (should translate to sl grep -V)
   - Test: `python gitsl.py blame -b file` (should translate to sl annotate --ignore-space-change)

If any tests fail, fix the issue before proceeding.
  </action>
  <verify>
`pytest tests/test_grep.py tests/test_blame.py -v` - all tests pass
`python -c "import gitsl"` - no import errors
  </verify>
  <done>
Both handlers work correctly:
- Existing tests pass (backward compatible)
- New flag handling integrates with gitsl.py dispatch
- Critical translations verified working
  </done>
</task>

</tasks>

<verification>
1. cmd_grep.py handles all 14 GREP requirements (GREP-01 through GREP-14)
2. cmd_blame.py handles all 7 BLAM requirements (BLAM-01 through BLAM-07)
3. Both handlers follow established flag extraction pattern from cmd_diff.py
4. Critical translations implemented:
   - git grep -v -> sl grep -V (invert match)
   - git blame -b -> sl annotate --ignore-space-change
5. Unsupported flags print helpful warnings to stderr
6. All existing tests continue to pass
</verification>

<success_criteria>
- [ ] cmd_grep.py extended with flag extraction loop (~80+ lines)
- [ ] cmd_blame.py extended with flag extraction loop (~60+ lines)
- [ ] git grep -v correctly translates to sl grep -V
- [ ] git blame -b correctly translates to sl annotate --ignore-space-change
- [ ] Unsupported flags (-c, -h, -o, -L, -e, -p, -l) print warnings
- [ ] Existing tests pass (pytest tests/test_grep.py tests/test_blame.py)
</success_criteria>

<output>
After completion, create `.planning/phases/27-grep-and-blame-flags/27-01-SUMMARY.md`
</output>
