Files
oh-my-openagent/.opencode/command/remove-deadcode.md
YeonGyu-Kim a691a3ac0a refactor: migrate delegate_task to task tool with metadata fixes
- Rename delegate_task tool to task across codebase (100 files)
- Update model references: claude-opus-4-6 → 4-5, gpt-5.3-codex → 5.2-codex
- Add tool-metadata-store to restore metadata overwritten by fromPlugin()
- Add session ID polling for BackgroundManager task sessions
- Await async ctx.metadata() calls in tool executors
- Add ses_ prefix guard to getMessageDir for performance
- Harden BackgroundManager with idle deferral and error handling
- Fix duplicate task key in sisyphus-junior test object literals
- Fix unawaited showOutputToUser in ast_grep_replace
- Fix background=true → run_in_background=true in ultrawork prompt
- Fix duplicate task/task references in docs and comments
2026-02-06 21:35:30 +09:00

9.9 KiB

description
description
Remove unused code from this project with ultrawork mode, LSP-verified safety, atomic commits
You are a dead code removal specialist. Execute the FULL dead code removal workflow using ultrawork mode.

Your core weapon: LSP FindReferences. If a symbol has ZERO external references, it's dead. Remove it.

CRITICAL RULES

  1. LSP is law. Never guess. Always verify with LspFindReferences before removing ANYTHING.
  2. One removal = one commit. Every dead code removal gets its own atomic commit.
  3. Test after every removal. Run bun test after each. If it fails, REVERT and skip.
  4. Leaf-first order. Remove deepest unused symbols first, then work up the dependency chain. Removing a leaf may expose new dead code upstream.
  5. Never remove entry points. src/index.ts, src/cli/index.ts, test files, config files, and files in packages/ are off-limits unless explicitly targeted.

STEP 0: REGISTER TODO LIST (MANDATORY FIRST ACTION)

TodoWrite([
  {"id": "scan", "content": "PHASE 1: Scan codebase for dead code candidates using LSP + explore agents", "status": "pending", "priority": "high"},
  {"id": "verify", "content": "PHASE 2: Verify each candidate with LspFindReferences - zero false positives", "status": "pending", "priority": "high"},
  {"id": "plan", "content": "PHASE 3: Plan removal order (leaf-first dependency order)", "status": "pending", "priority": "high"},
  {"id": "remove", "content": "PHASE 4: Remove dead code one-by-one (remove -> test -> commit loop)", "status": "pending", "priority": "high"},
  {"id": "final", "content": "PHASE 5: Final verification - full test suite + build + typecheck", "status": "pending", "priority": "high"}
])

PHASE 1: SCAN FOR DEAD CODE CANDIDATES

Mark scan as in_progress.

1.1: Launch Parallel Explore Agents (ALL BACKGROUND)

Fire ALL simultaneously:

// Agent 1: Find all exported symbols
task(subagent_type="explore", run_in_background=true,
  prompt="Find ALL exported functions, classes, types, interfaces, and constants across src/.
  List each with: file path, line number, symbol name, export type (named/default).
  EXCLUDE: src/index.ts root exports, test files.
  Return as structured list.")

// Agent 2: Find potentially unused files
task(subagent_type="explore", run_in_background=true,
  prompt="Find files in src/ that are NOT imported by any other file.
  Check import/require statements across the entire codebase.
  EXCLUDE: index.ts files, test files, entry points, config files, .md files.
  Return list of potentially orphaned files.")

// Agent 3: Find unused imports within files
task(subagent_type="explore", run_in_background=true,
  prompt="Find unused imports across src/**/*.ts files.
  Look for import statements where the imported symbol is never referenced in the file body.
  Return: file path, line number, imported symbol name.")

// Agent 4: Find functions/variables only used in their own declaration
task(subagent_type="explore", run_in_background=true,
  prompt="Find private/non-exported functions, variables, and types in src/**/*.ts that appear
  to have zero usage beyond their declaration. Return: file path, line number, symbol name.")

1.2: Direct AST-Grep Scans (WHILE AGENTS RUN)

// Find unused imports pattern
ast_grep_search(pattern="import { $NAME } from '$PATH'", lang="typescript", paths=["src/"])

// Find empty export objects
ast_grep_search(pattern="export {}", lang="typescript", paths=["src/"])

1.3: Collect All Results

Collect background agent results. Compile into a master candidate list:

## DEAD CODE CANDIDATES

| # | File | Line | Symbol | Type | Confidence |
|---|------|------|--------|------|------------|
| 1 | src/foo.ts | 42 | unusedFunc | function | HIGH |
| 2 | src/bar.ts | 10 | OldType | type | MEDIUM |

Mark scan as completed.


PHASE 2: VERIFY WITH LSP (ZERO FALSE POSITIVES)

Mark verify as in_progress.

For EVERY candidate from Phase 1, run this verification:

2.1: The LSP Verification Protocol

For each candidate symbol:

// Step 1: Find the symbol's exact position
LspDocumentSymbols(filePath)  // Get line/character of the symbol

// Step 2: Find ALL references across the ENTIRE workspace
LspFindReferences(filePath, line, character, includeDeclaration=false)
// includeDeclaration=false → only counts USAGES, not the definition itself

// Step 3: Evaluate
// 0 references → CONFIRMED DEAD CODE
// 1+ references → NOT dead, remove from candidate list

2.2: False Positive Guards

NEVER mark as dead code if:

  • Symbol is in src/index.ts (package entry point)
  • Symbol is in any index.ts that re-exports (barrel file check: look if it's re-exported)
  • Symbol is referenced in test files (tests are valid consumers)
  • Symbol has @public or @api JSDoc tags
  • Symbol is in a file listed in package.json exports
  • Symbol is a hook factory (createXXXHook) registered in src/index.ts
  • Symbol is a tool factory (createXXXTool) registered in tool loading
  • Symbol is an agent definition registered in agentSources
  • File is a command template, skill definition, or MCP config

2.3: Build Confirmed Dead Code List

After verification, produce:

## CONFIRMED DEAD CODE (LSP-verified, 0 external references)

| # | File | Line | Symbol | Type | Safe to Remove |
|---|------|------|--------|------|----------------|
| 1 | src/foo.ts | 42 | unusedFunc | function | YES |

If ZERO confirmed dead code found: Report "No dead code found" and STOP.

Mark verify as completed.


PHASE 3: PLAN REMOVAL ORDER

Mark plan as in_progress.

3.1: Dependency Analysis

For each confirmed dead symbol:

  1. Check if removing it would expose other dead code
  2. Check if other dead symbols depend on this one
  3. Build removal dependency graph

3.2: Order by Leaf-First

Removal Order:
1. [Leaf symbols - no other dead code depends on them]
2. [Intermediate symbols - depended on only by already-removed dead code]
3. [Dead files - entire files with no live exports]

3.3: Register Granular Todos

Create one todo per removal:

TodoWrite([
  {"id": "remove-1", "content": "Remove unusedFunc from src/foo.ts:42", "status": "pending", "priority": "high"},
  {"id": "remove-2", "content": "Remove OldType from src/bar.ts:10", "status": "pending", "priority": "high"},
  // ... one per confirmed dead symbol
])

Mark plan as completed.


PHASE 4: ITERATIVE REMOVAL LOOP

Mark remove as in_progress.

For EACH dead code item, execute this exact loop:

4.1: Pre-Removal Check

// Re-verify it's still dead (previous removals may have changed things)
LspFindReferences(filePath, line, character, includeDeclaration=false)
// If references > 0 now → SKIP (previous removal exposed a new consumer)

4.2: Remove the Dead Code

Use appropriate tool:

For unused imports:

Edit(filePath, oldString="import { deadSymbol } from '...';\n", newString="")
// Or if it's one of many imports, remove just the symbol from the import list

For unused functions/classes/types:

// Read the full symbol extent first
Read(filePath, offset=startLine, limit=endLine-startLine+1)
// Then remove it
Edit(filePath, oldString="[full symbol text]", newString="")

For dead files:

# Only after confirming ZERO imports point to this file
rm "path/to/dead-file.ts"

After removal, also clean up:

  • Remove any imports that were ONLY used by the removed code
  • Remove any now-empty import statements
  • Fix any trailing whitespace / double blank lines left behind

4.3: Post-Removal Verification

// 1. LSP diagnostics on changed file
LspDiagnostics(filePath, severity="error")
// Must be clean (or only pre-existing errors)

// 2. Run tests
bash("bun test")
// Must pass

// 3. Typecheck
bash("bun run typecheck")
// Must pass

4.4: Handle Failures

If ANY verification fails:

  1. REVERT the change immediately (git checkout -- [file])
  2. Mark this removal todo as cancelled with note: "Removal caused [error]. Skipped."
  3. Proceed to next item

4.5: Commit

git add [changed-files]
git commit -m "refactor: remove unused [symbolType] [symbolName] from [filePath]"

Mark this removal todo as completed.

4.6: Re-scan After Removal

After removing a symbol, check if its removal exposed NEW dead code:

  • Were there imports that only existed to serve the removed symbol?
  • Are there other symbols in the same file now unreferenced?

If new dead code is found, add it to the removal queue.

Repeat 4.1-4.6 for every item. Mark remove as completed when done.


PHASE 5: FINAL VERIFICATION

Mark final as in_progress.

5.1: Full Test Suite

bun test

5.2: Full Typecheck

bun run typecheck

5.3: Full Build

bun run build

5.4: Summary Report

## Dead Code Removal Complete

### Removed
| # | Symbol | File | Type | Commit |
|---|--------|------|------|--------|
| 1 | unusedFunc | src/foo.ts | function | abc1234 |

### Skipped (caused failures)
| # | Symbol | File | Reason |
|---|--------|------|--------|
| 1 | riskyFunc | src/bar.ts | Test failure: [details] |

### Verification
- Tests: PASSED (X/Y passing)
- Typecheck: CLEAN
- Build: SUCCESS
- Total dead code removed: N symbols across M files
- Total commits: K atomic commits

Mark final as completed.


SCOPE CONTROL

If $ARGUMENTS is provided, narrow the scan to the specified scope:

  • File path: Only scan that file
  • Directory: Only scan that directory
  • Symbol name: Only check that specific symbol
  • "all" or empty: Full project scan (default)

ABORT CONDITIONS

STOP and report to user if:

  • 3 consecutive removals cause test failures
  • Build breaks and cannot be fixed by reverting
  • More than 50 candidates found (ask user to narrow scope)

LANGUAGE

Use English for commit messages and technical output.

$ARGUMENTS