# Story 1.2: Implement Basic Fetch with Wiki Links (Depth 1)

## Status

Ready for Review

## Story

**As a** user,
**I want** to fetch a markdown file and its wiki-linked documents at depth 1,
**so that** I can copy the compiled content to my clipboard for AI consumption

## Acceptance Criteria

1. CLI accepts file identifier as argument
2. Finds markdown file by title (case-insensitive exact match)
3. Extracts all [[wiki links]] from the content
4. Fetches each linked file (depth 1 only)
5. Compiles content in specified format with source paths
6. Copies final output to system clipboard
7. Shows success message with word count
8. Handles missing files gracefully with warnings

## Tasks / Subtasks

- [x] Implement file resolution logic (AC: 1, 2)
  - [x] Create fetch.py with find_markdown_file() function
  - [x] Implement case-insensitive title matching
  - [x] Search current directory and subdirectories for .md files
  - [x] Return Path object for found file
  - [x] Raise DocumentNotFoundError if not found
- [x] Implement wiki link parser (AC: 3)
  - [x] Create parser.py with extract_wiki_links() function
  - [x] Use regex to find all [[wiki link]] patterns
  - [x] Handle variations: [[Link]], [[Link|Alias]], [[Link#Section]]
  - [x] Return list of link targets (without brackets)
  - [x] Write unit tests for different link formats
- [x] Implement document fetching logic (AC: 4, 8)
  - [x] Create fetch_document() function in fetch.py
  - [x] Read main document content
  - [x] Extract wiki links using parser
  - [x] Fetch each linked document (depth 1)
  - [x] Track visited files to avoid duplicates
  - [x] Handle FileNotFoundError gracefully with warnings
- [x] Implement content compilation (AC: 5)
  - [x] Create compile_content() function
  - [x] Format main document with title and source path
  - [x] Add separator between main and linked documents
  - [x] Format each linked document with title and source
  - [x] Use consistent markdown formatting
- [x] Implement clipboard operations (AC: 6, 7)
  - [x] Create clipboard.py with copy_to_clipboard() function
  - [x] Wrap pyperclip.copy() with error handling
  - [x] Return success/failure status
  - [x] Count words in final output
- [x] Wire up CLI command (AC: 1, 6, 7, 8)
  - [x] Add fetch command to cli.py
  - [x] Accept file argument (required)
  - [x] Add --no-copy flag for stdout output
  - [x] Call fetch_document() with error handling
  - [x] Copy to clipboard or print to stdout
  - [x] Show success message with word count
  - [x] Display warnings for missing linked files
- [x] Add comprehensive tests
  - [x] Test file resolution with various inputs
  - [x] Test wiki link extraction edge cases
  - [x] Test full fetch flow with fixtures
  - [x] Test error handling scenarios

## Dev Notes

### File Structure

Based on [Source: architecture/unified-project-structure.md]:

```
nuu/
├── cli.py       # CLI command definitions
├── fetch.py     # Core fetch logic and file resolution
├── parser.py    # Wiki link extraction utilities
└── clipboard.py # Clipboard operations wrapper
```

### Code Standards

Based on [Source: architecture/coding-standards.md]:

- Use type hints for all functions
- Custom exceptions for domain errors
- Google-style docstrings
- Explicit error messages

### Key Functions

#### fetch.py

```python
def find_markdown_file(identifier: str, vault_path: Path = Path(".")) -> Path:
    """Find a markdown file by title (case-insensitive).

    Args:
        identifier: File title to search for
        vault_path: Root directory to search in

    Returns:
        Path to the found markdown file

    Raises:
        DocumentNotFoundError: If no matching file is found
    """

def fetch_document(file_identifier: str, depth: int = 1) -> str:
    """Fetch a document and its linked content.

    Args:
        file_identifier: Title or path of the document
        depth: Link traversal depth (only 1 supported in MVP)

    Returns:
        Compiled markdown content with all linked documents
    """
```

#### parser.py

```python
def extract_wiki_links(content: str) -> List[str]:
    """Extract wiki-style links from markdown content.

    Handles formats:
    - [[Simple Link]]
    - [[Link|Display Alias]]
    - [[Link#Section]]

    Args:
        content: Markdown content to parse

    Returns:
        List of link targets (without brackets or aliases)
    """
```

### Output Format

Based on [Source: prd-mvp-fetch.md#output-format]:

```markdown
# Main Document Title

[Source: /path/to/file.md]

[Main document content...]

---

## Linked Documents (Depth 1)

### [[Linked Doc 1]]

[Source: /path/to/linked1.md]

[Linked document content...]

### [[Linked Doc 2]]

[Source: /path/to/linked2.md]

[Linked document content...]
```

### Error Handling

- Missing main file: Raise DocumentNotFoundError with helpful message
- Missing linked file: Continue processing, show warning
- Clipboard failure: Fall back to stdout with warning
- Invalid depth: Only support depth=1 in MVP

### CLI Usage Examples

```bash
# Basic usage
nuu fetch "Meeting Notes"

# Output to stdout instead of clipboard
nuu fetch "Project Plan" --no-copy

# File not found
nuu fetch "Nonexistent"
> Error: Document 'Nonexistent' not found in vault

# With missing links
nuu fetch "Main Document"
> Warning: Could not find linked document 'Missing Link'
> ✓ Copied to clipboard (1,234 words)
```

### Testing

Based on [Source: architecture/coding-standards.md#testing-standards]:

- Create test fixtures in `tests/fixtures/` with sample markdown files
- Test both success and error cases
- Mock clipboard operations in tests
- Verify output format matches specification

### Test Fixtures Structure

```
tests/fixtures/
├── simple.md          # No links
├── with_links.md      # Contains [[Link1]] and [[Link2]]
├── link1.md          # Target of wiki link
├── link2.md          # Another target
└── broken_links.md   # Contains links to missing files
```

## Change Log

| Date       | Version | Description            | Author       |
| ---------- | ------- | ---------------------- | ------------ |
| 2025-01-30 | 1.0     | Initial story creation | Scrum Master |
| 2025-01-30 | 1.1     | Completed implementation | Dev Agent (claude-opus-4-20250514) |

## Dev Agent Record

### Agent Model Used

claude-opus-4-20250514

### Debug Log References

No debug log entries required - implementation completed without blockers.

### Completion Notes List

- Successfully implemented all acceptance criteria
- Created modular design with separate files for fetch, parser, and clipboard operations
- Comprehensive test coverage with 58 passing tests
- Handled edge cases including missing files, clipboard failures, and duplicate links
- Preserved original wiki link formatting in output (including aliases)
- All validations pass (linting, type checking, tests)

### File List

- src/core/fetch.py (new, modified)
- tests/test_fetch.py (new, modified)
- src/core/parser.py (new)
- tests/test_parser.py (new)
- src/core/clipboard.py (new)
- tests/test_clipboard.py (new)
- src/core/cli.py (modified)
- tests/test_cli_fetch.py (new)
- tests/test_integration.py (new)
- tests/fixtures/simple.md (new)
- tests/fixtures/with_links.md (new)
- tests/fixtures/link1.md (new)
- tests/fixtures/link2.md (new)
- tests/fixtures/broken_links.md (new)
- tests/fixtures/exists.md (new)

## QA Results

_To be filled by QA agent_
