Skip to content

Inline AI editing (✨ generate / rewrite, streaming, @-context)#252

Open
dep wants to merge 21 commits into
mainfrom
worktree-inline-ai-editing
Open

Inline AI editing (✨ generate / rewrite, streaming, @-context)#252
dep wants to merge 21 commits into
mainfrom
worktree-inline-ai-editing

Conversation

@dep

@dep dep commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the ability to edit the current note with AI, inline in the editor:

  • Active-line ✨ → click to open a prompt bar; AI text streams in at the cursor.
  • Selection ✨ → rewrite selected text as an inline diff (original struck-through in red, new text in green) with Accept / Reject / Retry — the original is never destroyed until you accept.
  • Anthropic API key stored in the macOS Keychain (first Keychain usage in the app), entered in Settings → AI.
  • Per-request model picker in the bar (Haiku 4.5 / Sonnet 4.6 / Opus 4.8); last choice persists as the machine-local default.
  • @note / @[Multi Word Note] autocomplete in the prompt to pull vault notes in as context (reuses the existing command-palette filename scoring; ~100K-char cap).
  • Streaming over direct URLSession SSE to api.anthropic.com/v1/messages (no SDK dependency, mirrors the existing GistPublisher pattern). Stop button / Esc cancels, keeping whatever streamed.

Built spec-first → plan → subagent-driven TDD, one unit per task with two-stage (spec + code-quality) review, plus a holistic final review that caught and fixed two cross-unit seam bugs (spaced-filename @-token mismatch; generate-error retry concatenation).

Architecture (new files)

Unit Responsibility
AIModel The 3-model enum: exact Anthropic API IDs + display names.
KeychainStore SecItem wrapper for the API key.
AIContextResolver @name → note-content resolution, capped, with missing/truncation reporting. Pure.
AIRequestBuilder Builds the /v1/messages body for generate/rewrite. Pure.
AnthropicClient URLSession.bytes SSE → AsyncThrowingStream<String>, typed error mapping, injectable session.
InlineAIController Text-mutation state machine (generate/rewrite/accept/reject) over NSTextStorage.
InlineAIView AISparkleButton (NSControl ✨) + the SwiftUI bar + @-autocomplete.

Plus: SettingsManager/SettingsView (key + default model), and EditorView wiring (✨ positioning, bar presentation, streaming → controller, transient diff coloring, teardown on note switch).

Test Plan

Automated (passing): 48 new unit tests across the 6 logic units + settings persistence. xcodebuild build succeeds; app launches.

Manual QA needed (not exercised by automated tests — requires a real API key):

  • Settings → AI: paste an Anthropic key (persists in Keychain across relaunch); switch the default model (persists).
  • Click into a line → ✨ appears at line end → click → type a prompt → Generate streams text at the cursor.
  • Select a sentence → ✨ appears past the selection → rewrite → original goes red/struck-through, new text streams green → Accept replaces / Reject restores / Retry re-runs.
  • In the prompt, type @ + letters → suggestions appear; pick one → inserts @name (or @[Multi Word] for spaced filenames) → resolves as context.
  • Error paths: no key shows "Add your Anthropic API key in Settings →"; invalid key → "Invalid API key"; network failure surfaces inline with Retry; partial stream kept on Stop/Esc.
  • ✨ tracks the caret while typing in both hide-markdown and raw modes; hides while the bar is open.
  • Switch notes/tabs mid-rewrite → bar tears down, no corruption of the new note; the half-diff is not autosaved mid-decision.

🤖 Generated with Claude Code

dep and others added 20 commits June 9, 2026 06:44
Design for editing the current note via AI: active-line ✨ to generate at
cursor, selection ✨ to rewrite via inline diff, Anthropic key in Keychain,
per-request model picker (Haiku 4.5 / Sonnet 4.6 / Opus 4.8), @-note context
autocomplete, and streamed output over direct URLSession SSE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nine TDD-structured tasks: AIModel, KeychainStore, AIContextResolver,
AIRequestBuilder, AnthropicClient (SSE), InlineAIController, Settings
integration, InlineAIView, and editor wiring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
XcodeGen adds PBXBuildFile/PBXFileReference entries for the 7 new
AI-feature source and test files. Pure additions, no deletions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…us polish

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… diff)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r + Esc to close

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ard rewrite autosave

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…diff

- Retry now discards the prior generation (discardOutput) before re-streaming,
  so it replaces rather than appends (was concatenating onto the last result).
- The bar re-anchors below the streamed text as it grows, flipping to above the
  region when a long diff would push it off-screen — it no longer covers the diff.
- Adds discardOutput() + 5 regression tests for the Retry replace behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
synapse-web Ignored Ignored Jun 9, 2026 9:17pm

Request Review

… first row

- @mentions now resolve folders (concatenates a folder's direct notes) in addition
  to notes; autocomplete lists both with file/folder icons (allFolders wired through
  AIContextResolver + the bar). Fixes directories not appearing for @Weekly etc.
- Prompt field is now multiline (axis: .vertical): Enter submits, Shift+Enter inserts
  a newline; the bar grows to fit and re-anchors.
- The bar has a drag handle and can be repositioned; once moved it stops auto-snapping
  below the streamed text.
- First @-suggestion is now clickable: the invisible Esc handler moved to a non-layout,
  non-hit-testing background, and each row has an explicit contentShape.
- Adds 5 folder-resolution tests (35 resolver+controller tests pass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant