Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,32 @@ Sample output:
2. **Index routing** – `DerivedDataPaths` ensures the path points into `Index.noindex/DataStore/IndexStoreDB` so we can open the index without extra setup.
3. **Output formatting** – Paths are normalized, deduplicated, and printed once for easier scripting.

## Agent Skill (OpenSkills)

This repository includes an OpenSkills-compatible agent skill located in `swiftfindrefs/`.
It teaches AI coding agents to use IndexStore-based reference discovery via `swiftfindrefs`
instead of unreliable text search.

### Install OpenSkills
```bash
npm i -g openskills
```

### Install this skill
```bash
openskills install michaelversus/SwiftFindRefs
```

### Sync into your project
```bash
openskills sync
```

### Example agent prompt
Use the swiftfindrefs skill to find all references to `SelectionViewController` (class) and add
`import UIComponents` only where missing.


## 🧪 Testing
The package uses the Swift Testing framework (`swift test`) with mocks for filesystem and derived-data resolution. Tests cover locator edge cases, path building, and index error handling.

Expand Down
75 changes: 75 additions & 0 deletions swiftfindrefs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
name: swiftfindrefs
description: Use swiftfindrefs (IndexStoreDB) to list every Swift source file referencing a symbol. Mandatory for “find references”, “fix missing imports”, and cross-module refactors. Do not replace with grep/rg or IDE search.
---

# SwiftFindRefs

## Purpose
Use `swiftfindrefs` to locate every Swift source file that references a given symbol by querying Xcode’s IndexStore (DerivedData). This skill exists to prevent incomplete refactors caused by text search or heuristics.

## Rules
- Always run `swiftfindrefs` before editing any files.
- Only edit files returned by `swiftfindrefs`.
- Do not substitute `grep`, `rg`, IDE search, or filesystem heuristics for reference discovery.
- Do not expand the file set manually.
- If IndexStore/DerivedData resolution fails, stop and report the error. Do not guess.

## Preconditions
- macOS with Xcode installed
- Project has been built at least once (DerivedData exists)
- `swiftfindrefs` available in PATH

## Canonical command
Prefer providing `--projectName` and `--symbolType` when possible.

```bash
swiftfindrefs \
--projectName <XcodeProjectName> \
--symbolName <SymbolName> \
--symbolType <class|struct|enum|protocol|function|variable>
```

Optional flags:
- `--derivedDataPath <path>`: explicit DerivedData (or IndexStoreDB) path; skips discovery
- `--verbose`: prints discovery steps, resolved paths, and diagnostics

## Output contract
- One absolute file path per line
- Deduplicated
- Script-friendly (safe to pipe line-by-line)
- Ordering is not semantically meaningful

## Standard workflows

### Workflow A: Find all references
1. Run `swiftfindrefs` for the symbol.
2. Treat the output as the complete reference set.
3. If more detail is needed, open only the returned files.

### Workflow B: Fix missing imports after moving a symbol
Use `swiftfindrefs` to restrict scope, then add imports only where needed.

```bash
swiftfindrefs -p <Project> -n <Symbol> -t <Type> | while read file; do
if ! grep -q "^import <ModuleName>$" "$file"; then
echo "$file"
fi
done
```

Then for each printed file:
- Insert `import <ModuleName>` in the imports block at the top.
- Preserve existing import ordering/grouping.
- Never add duplicate imports.
- Do not reformat unrelated code.

### Workflow C: Audit usage before deleting or renaming a symbol
1. Run `swiftfindrefs` for the symbol.
2. If output is empty, treat the symbol as unused (still validate via build/tests if needed).
3. If non-empty, review the listed files before changing public API.

## References
- CLI details: references/cli.md
- Playbooks: references/workflows.md
- Troubleshooting: references/troubleshooting.md
46 changes: 46 additions & 0 deletions swiftfindrefs/references/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# CLI reference (agent-focused)

## Preconditions
- macOS with Xcode installed
- Project built at least once (DerivedData exists)
- `swiftfindrefs` is available in PATH

## Flags
- `-p, --projectName`
Helps infer the correct DerivedData folder when `--derivedDataPath` is not provided.

- `-d, --derivedDataPath`
Points directly to a DerivedData (or IndexStoreDB) directory and skips discovery.

- `-n, --symbolName` (required)
The symbol to inspect.

- `-t, --symbolType`
Narrows matches to a specific kind (recommended when possible).

- `-v, --verbose`
Prints discovery steps, resolved paths, and diagnostics.

## Recommended invocations

Most common:
```bash
swiftfindrefs -p MyApp -n SelectionViewController -t class
```

Explicit DerivedData / deterministic runs:
```bash
swiftfindrefs -d ~/Library/Developer/Xcode/DerivedData/MyApp-XXXX/ -n SelectionViewController -t class
```

Debug discovery:
```bash
swiftfindrefs -p MyApp -n SelectionViewController -t class -v
```

## Output
- Absolute file paths, one per line
- Deduplicated

## Non-goals
- The tool reports which files reference a symbol, not line or column positions.
18 changes: 18 additions & 0 deletions swiftfindrefs/references/troubleshooting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Troubleshooting

## No results returned
- Build the project in Xcode to regenerate indexing.
- Re-run with verbose logging:
```bash
swiftfindrefs -p <Project> -n <Symbol> -t <Type> -v
```
- If multiple DerivedData folders exist for the same project `swiftfindrefs` will use the most recent one.

## Wrong DerivedData selected
- Prefer explicit `--derivedDataPath` in CI or multi-clone setups.
- Use `--verbose` to confirm path selection.

## Do not fall back to grep
- Text search is not acceptable for reference discovery.
- grep/rg may only be used inside files already returned by `swiftfindrefs`
(for example, to check if an import already exists).
30 changes: 30 additions & 0 deletions swiftfindrefs/references/workflows.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Workflows (deterministic behavior)

## Golden rule
Reference discovery must be IndexStore-based. `swiftfindrefs` output defines scope.

## Playbook: add missing imports after moving a symbol
Inputs:
- Project: `<Project>`
- Symbol: `<Symbol>`
- Type: `<Type>`
- Module to import: `<Module>`

Steps:
1. Run:
```bash
swiftfindrefs -p <Project> -n <Symbol> -t <Type>
```
2. Iterate only over the resulting file list.
3. For each file:
- If `import <Module>` exists: no change.
- Else: add it to the imports block at the top.
4. Keep edits minimal:
- No formatting changes
- No unrelated cleanup
- Preserve existing import ordering/grouping

## Playbook: rename or delete a symbol
1. Run `swiftfindrefs` on the symbol.
2. If output is empty, treat as unused (validate via build/tests).
3. If non-empty, update usages only in returned files.