---
phase: 08-add-u-emulation
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - cmd_add.py
  - tests/test_cmd_add.py
autonomous: true

must_haves:
  truths:
    - "git add -u stages modified tracked files (no action in Sapling - auto-staged)"
    - "git add -u marks deleted tracked files for removal via sl remove --mark"
    - "git add -u does NOT stage untracked files"
    - "git add -u path/ respects pathspec (only affects files under path/)"
  artifacts:
    - path: "cmd_add.py"
      provides: "-u/--update flag handling"
      contains: "handle_update"
    - path: "tests/test_cmd_add.py"
      provides: "E2E tests for -u flag"
      contains: "test_add_u"
  key_links:
    - from: "cmd_add.py"
      to: "sl status -d -n"
      via: "subprocess.run with capture_output"
      pattern: "sl.*status.*-d.*-n"
    - from: "cmd_add.py"
      to: "sl remove --mark"
      via: "subprocess.run for marking deleted files"
      pattern: "sl.*remove.*--mark"
---

<objective>
Implement `git add -u` (update) flag to stage only tracked files

Purpose: Enable git client workflows that use `git add -u` to stage modifications without including untracked files
Output: Updated cmd_add.py with -u/--update handling and E2E tests
</objective>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/08-add-u-emulation/08-RESEARCH.md

@cmd_add.py
@common.py
@tests/test_cmd_add.py
</context>

<tasks>

<task type="auto">
  <name>Task 1: Implement -u/--update flag handling in cmd_add.py</name>
  <files>cmd_add.py</files>
  <action>
Add -u/--update handling to cmd_add.py. The implementation must:

1. Detect -u or --update flag at start of handle() function (before -A/--all check)
2. Create helper function get_deleted_files(pathspec: list) -> list:
   - Run `sl status -d -n` with subprocess.run(capture_output=True, text=True)
   - If pathspec provided, append pathspec args to command
   - Parse stdout.splitlines() to get list of deleted filenames
   - Return empty list if returncode != 0 or no files found

3. Create helper function handle_update(parsed: ParsedCommand) -> int:
   - Extract pathspec from parsed.args (args not matching -u, --update)
   - Call get_deleted_files(pathspec)
   - If no deleted files, return 0 (success - modified files already auto-staged in Sapling)
   - If deleted files exist, run subprocess.run(['sl', 'remove', '--mark'] + deleted_files)
   - Return the exit code from sl remove

4. Update handle() to check for -u/--update BEFORE -A/--all check:
   ```python
   if "-u" in parsed.args or "--update" in parsed.args:
       return handle_update(parsed)
   ```

Key behaviors:
- Modified tracked files: NO ACTION (Sapling auto-stages)
- Deleted tracked files: Run sl remove --mark to mark for removal
- Untracked files: IGNORED (this is the key difference from -A)

Import subprocess at top of file if not already imported.
  </action>
  <verify>
Run: python -c "import cmd_add; print('OK')" (no import errors)
Run: python -m pytest tests/test_cmd_add.py -v (existing tests still pass)
  </verify>
  <done>
cmd_add.py handles -u/--update flag, dispatches to handle_update(), and existing -A/--all behavior unchanged
  </done>
</task>

<task type="auto">
  <name>Task 2: Add E2E tests for git add -u scenarios</name>
  <files>tests/test_cmd_add.py</files>
  <action>
Add E2E tests to test_cmd_add.py for FLAG-03 requirement. Create these test functions:

1. test_add_u_ignores_untracked(sl_repo):
   - Create untracked.txt (not added to repo)
   - Modify existing tracked file (if any) or create+add+commit tracked.txt first
   - Run gitsl add -u
   - Run sl status and verify untracked.txt still shows as ? (untracked)
   - Verify modified tracked file is ready for commit (or no action needed since Sapling auto-stages)

2. test_add_u_marks_deleted_for_removal(sl_repo):
   - Create tracked.txt, add, and commit
   - Delete tracked.txt from disk (os.remove or Path.unlink)
   - Run sl status -d -n to verify it shows as deleted
   - Run gitsl add -u
   - Run sl status and verify tracked.txt now shows as R (removed/staged for deletion)

3. test_add_u_with_pathspec(sl_repo):
   - Create subdir/tracked.txt and root_tracked.txt, add and commit both
   - Delete both files from disk
   - Run gitsl add -u subdir/
   - Verify subdir/tracked.txt is marked R (removed)
   - Verify root_tracked.txt still shows as ! (deleted but not marked for removal)

4. test_add_u_no_deleted_files(sl_repo):
   - Create tracked.txt, add and commit
   - Modify tracked.txt (no deletion)
   - Run gitsl add -u
   - Verify exit code is 0
   - Verify no errors (Sapling auto-stages modifications)

Test patterns:
- Use subprocess.run to invoke gitsl
- Use sl status to verify state changes
- Follow existing test patterns in the file
  </action>
  <verify>
Run: python -m pytest tests/test_cmd_add.py -v -k "add_u" (new tests pass)
Run: python -m pytest tests/ -v (full suite passes)
  </verify>
  <done>
4 new E2E tests for git add -u: ignores untracked, marks deleted, respects pathspec, handles no-op case
  </done>
</task>

</tasks>

<verification>
After both tasks complete:
1. python -m pytest tests/ -v - Full test suite passes
2. Manual verification in test repo:
   - Create repo with tracked and untracked files
   - Delete a tracked file
   - Run gitsl add -u
   - Run sl status - verify deleted marked as R, untracked still as ?
</verification>

<success_criteria>
- FLAG-03 requirement satisfied: git add -u finds modified tracked files and adds them
- git add -u marks deleted tracked files for removal
- git add -u ignores untracked files
- git add -u respects pathspec arguments
- All existing tests continue to pass
- 4 new E2E tests covering -u scenarios
</success_criteria>

<output>
After completion, create `.planning/phases/08-add-u-emulation/08-01-SUMMARY.md`
</output>
