Why:
- SDD report files are local coordination artifacts and should not be part of the repository tree.
What:
- Remove the accidentally tracked Task 2 report while leaving ignored local SDD files available for this session.
Why:
The Task 2 refactor split frontmatter before URL rewriting, which left GitHub/Jira/Linear URLs in YAML raw even though document formatting previously handled them.
What:
Add a regression test for frontmatter URL formatting with body-only title/link behavior, factor URL rewriting into a shared helper, and apply it to the original frontmatter slice before body-only formatting.
Why:
- The selection command regressed by inheriting document-level URL formatting from the shared body formatter.
- That changed user-visible output for selected text containing GitHub, Jira, or Linear URLs.
What:
- Added a selection-only formatter that projects link replacement settings and calls `replaceLinks(...)` directly.
- Switched `mofifyLinksSelection()` to the new helper so document formatting stays unchanged.
- Added regression coverage for selection-only behavior and documented the fix in the task report.
Why:
- main.ts mixed Obsidian adapter work with pure transformation sequencing, which made formatting behavior require plugin mocks to test.
- A pure formatting run increases locality for URL formatting, URL title replacement, and link replacement order.
What:
- Add a formatting-run module with document and body formatting entry points.
- Route file and selection formatting through the new module.
- Move pure frontmatter URL-title coverage out of main adapter tests.
Why:
- the AI enhancement command normalized the active note path for ambiguity resolution but then passed the raw .md path into replacement, which could still create self-links when preventSelfLinking was enabled
- the scanner merged block-level protected ranges before appending inline-code ranges, which let mixed ordering move scanning backward into protected callout content
What:
- normalize the AI command file path once and reuse it for both resolveAmbiguities() and replaceLinks()
- sort and merge the final protected range list after adding inline-code ranges
- add focused regressions for the AI self-link path handoff and the inline-code-before-callout scanner case
Why:
AI ambiguity requests were scanned without the current file path, so preventSelfLinking could not filter self-link candidates on the AI path.
What:
- Thread an optional filePath through resolveAmbiguities() and pass it into the shared candidate scanner.
- Pass the active markdown path without .md from the AI command in main.ts.
- Add a regression proving self-link candidates are skipped before AI requests are built when the current file matches.
Why: The scanner was skipping Korean particle hits by candidate length, which let it jump past overlapping follow-on candidates and diverge from replaceLinks cursor behavior.\n\nWhat: Advance the scanner by one codepoint after a Korean particle skip, add regressions for the isolated and overlapping 문서/서는 cases, and record the verification in the Task 1 report.
Why:
- Task 1 still had drift between candidate scanning and Korean replacement special cases.
- The scanner could ask AI about Korean particle forms that replacement intentionally skips.
- The Korean suffix replacement path ignored resolved ambiguities and could apply a different target than the AI chose.
What:
- skip Korean particle trie hits in the Task 1 candidate scanner and ambiguity request path
- reuse a shared resolved-ambiguity link-content helper for the standard and Korean suffix replacement branches
- add Task 1 regressions and append the Task 1 fix report with focused and full verification results
Why:
- Existing wikilinks inside inline code were still being collected as candidate occurrences, which could drive resolveAmbiguities() to prepare AI work for text that replaceLinks() intentionally leaves untouched.
What:
- Added inline-code protected ranges to existing wikilink collection so matches inside backticks are ignored alongside the current block-level exclusions.
- Added regression coverage for scanCandidateOccurrences() and the resolveAmbiguities() request path.
- Appended the focused and full verification results to the task 1 report.
Why:
- Task 1 scanner drifted from replaceLinks in two places that affect AI ambiguity review.
- Trie-hit namespace handling was filtering candidate sets differently from replacement-time behavior.
- Protected-region scanning was still walking fenced code, callouts, and ignored headings that replaceLinks already shields.
What:
- make trie-hit scanning use the original candidate set and first-candidate scoped checks, matching current replaceLinks behavior
- skip fenced code blocks, callouts, and ignored headings before protected-regex scanning while preserving original occurrence offsets
- add regressions for trie-hit namespace semantics and protected-region skipping, plus AI-side coverage and append the fix report
Why:
- Candidate detection was duplicated between link replacement and AI ambiguity resolution, which made matching behavior hard to reason about.
- A single scanner improves locality for namespace, protected-span, case, and CJK matching rules.
What:
- Add a shared candidate scanner module for unlinked text and existing wikilinks.
- Route AI ambiguity request construction through the scanner.
- Keep link rendering behavior unchanged and covered by existing replacement tests.
Why:
- The approved architecture design needs an executable task-by-task plan before implementation begins.
- A committed plan gives subagents a stable requirements source and preserves recovery context across long-running work.
What:
- Add a staged TDD implementation plan for candidate scanning, formatting-run extraction, settings catalog, Markdown segmentation, and URL formatting orchestration.
- Include exact files, interfaces, test commands, verification steps, and commit points for each stage.
Why:
- The architecture deepening work will span multiple core modules, so the design needs to remove vague implementation guidance before planning begins.
- Clearer scope reduces the chance that future agents move the wrong tests or leave settings and Markdown segmentation decisions ambiguous.
What:
- Specify that pure transformation tests should move from main adapter tests into formatting-run tests.
- Define the URL formatting settings projection in concrete terms.
- Make the Markdown segment extraction order explicit for the implementation plan.
Why:
The architecture review identified five related deepening opportunities that should be implemented in a staged, testable sequence rather than as ad hoc refactors.
What:
Document the approved design for candidate scanning, formatting runs, settings catalog, Markdown protected segments, and URL formatting adapters, including scope, non-goals, testing strategy, migration order, risks, and success criteria.
Why:
- Some notes need to keep raw URLs and avoid web title requests even when global URL title replacement is enabled.
- A per-note frontmatter flag gives users local control without disabling other automatic linking behavior.
What:
- Add automatic-linker-disable-url-title frontmatter detection.
- Skip URL title fetching and replacement when the flag is set on a note.
- Document the frontmatter option and add regression coverage for the helper and plugin flow.
- Record this repository's agent version-control instructions in AGENTS.md.
Why:
- Markdown table escaping is link formatting behavior, not plugin orchestration behavior.
- Keeping pipe escaping in main.ts duplicated logic already used by the default link generator and made the Obsidian adapter responsible for markdown rendering details.
What:
- Add a shared escapeLinkForMarkdownTable helper in replace-links.
- Reuse the helper from defaultLinkGenerator and from the Obsidian API link generator path.
- Delegate fallback wikilink rendering in main.ts to defaultLinkGenerator.
- Add direct coverage for table link escaping behavior.
Why:
- Markdown treats an opening fenced code block without a closing fence as code through the end of the document.
- Automatic linking was still processing that content as normal text, which could turn code block contents into wiki links.
What:
- Extract fenced code blocks before heading, callout, table, and link replacement processing.
- Preserve unmatched fenced blocks through EOF and restore them unchanged after replacement.
- Add regression coverage for unclosed code blocks, including when heading protection is enabled.
Why:
- Some users prefer leaving Markdown table rows untouched to avoid table formatting conflicts during automatic linking.
- Issue #35 requested a skip-tables option as an additional escape hatch alongside pipe escaping.
What:
- Add an ignoreMarkdownTables setting with a default value of false.
- Add a settings toggle for ignoring Markdown table rows during automatic linking.
- Skip both plain-text link insertion and existing-link ambiguity replacement inside Markdown table rows when the option is enabled.
- Cover the table-skip behavior with regression tests.
Refs: #35
Why:
- Aliased wiki links generated inside Markdown table cells used a raw pipe separator.
- Markdown table formatters interpret that raw pipe as a column delimiter, which mangles table rows after automatic linking.
What:
- Escape pipe characters in links returned by Obsidian's generateMarkdownLink API when the replacement occurs inside a table.
- Add a regression test covering an existing target file with a frontmatter alias inside a Markdown table cell.
Closes: #35
Why:
- Obsidian plugin metadata validation warns when the manifest description does not end with punctuation.
- Keeping the manifest warning-free makes release checks and plugin review feedback easier to act on.
What:
- Add a trailing period to the plugin description in manifest.json.
Why:
- Obsidian's plugin checks were reporting compatibility and packaging warnings that could break popout-window behavior or leave async failures unhandled.
- The build also depended on a deprecated module listing package and carried inline tests that leaked warning noise into the production bundle.
What:
- add @codemirror/view as a runtime dependency and replace builtin-modules with node:module builtinModules in the esbuild config
- route plugin async startup and save-file hooks through compatibility helpers so delayed work uses window.setTimeout and fire-and-forget promises are explicitly handled
- switch the AI progress notice to activeDocument, await clipboard writes, align extended Obsidian types, rename the settings heading, and remove unused catch bindings
- move trie inline tests into dedicated Vitest files and add coverage for the new compatibility helpers to keep the build warning-free
- Implemented AI-powered link disambiguation using local LLMs (Gemma 4 / LM Studio).
- Refactored Trie and candidate mapping to support multiple link candidates per word.
- Added 'AI Link Enhancer' command with a progress bar UI in Obsidian.
- Enhanced link replacement logic to verify existing links and resolve ambiguities using context.
- Added comprehensive unit tests for AI disambiguation and candidate mapping.
- Updated settings to include AI configuration (endpoint, model, context length).
When ignoreCase is off, text capitalized at the start of a sentence (e.g., "My name")
now matches lowercase candidates (e.g., "my name.md"), producing [[my name|My name]].
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>