Repository navigation
agent: #10 [Agent] Suchen und Ersetzen im Kapitel und im ganzen Projekt - #21
Conversation
…bare Lösung. Lies zuerst den vollständigen Issue-Thread inklusive aller Kommentare, CLAUDE.md und die relevanten Repository-Regeln. Prüfe vorhandene PRs und aktuellen Code, bevor du Änderungen machst. Leite die verbindlichen Akzeptanzkriterien aus dem Issue ab und dokumentiere nicht erfüllbare oder widersprüchliche Kriterien klar. Arbeite testgetrieben: Erzeuge Regressionstests, verifiziere ihr korrektes Fehlschlagen vor dem Fix und führe danach die relevanten Tests sowie die vorgeschriebenen Qualitätsprüfungen aus. Ändere nur, was für das Issue erforderlich ist. Arbeite ausschließlich auf dem ausgecheckten Stand von origin/main: checke keine Branches fremder offener PRs aus, cherry-picke nichts daraus und baue nicht auf ihnen auf. Hängt die Lösung von einem noch offenen PR ab, liefere nur deinen eigenen Anteil und dokumentiere die Abhängigkeit im Handover. Keine Produktionsdeployments, keine Änderungen an Produktionsdaten oder Produktions-Supabase und kein --prod. Merge den PR nicht. Issue: #10 Titel: [Agent] Suchen und Ersetzen im Kapitel und im ganzen Projekt Beschreibung: <!-- hermes-agent-form-v1:start --> ## Ziel und Nutzen Autorin kann im aktuellen Kapitel und im ganzen Projekt (Manuskript, alle Plan-Textfelder, alle Notizen inkl. privater) Text suchen und gezielt ersetzen, mit Schnappschuss-Sicherheitsnetz für Kapitel und App-Undo für Plan und Notizen. ## Ist-Zustand / Problem Nur Schnellsuche (⌘K) für Kapitel, Figuren, Orte, Bereiche und Befehle. Kein Volltext im Manuskript, keine Such-Erweiterung im Editor, keine Such- und Ersetzlogik in core, kein Menüeintrag. ⌘⇧F ist Fokus-Modus, ⌘F in der Recherche belegt. Schnappschüsse gibt es nur für Manuskriptkapitel, kein Undo für Projektdaten. ## Umfang (In Scope) - Suchleiste im Schreiben-Bereich (⌘F): Markierung, vor/zurück, Trefferzahl - Projektsuche (⌥⌘F) mit Ergebnisliste nach Bereich getrennt, Manuskript in Buchreihenfolge - Ersetzen einzeln und Alle ersetzen, im Kapitel und im Projekt, auch in Plan-Textfeldern und Notizen inkl. privater - Optionen Ganzes Wort und Groß-/Kleinschreibung - Schnappschuss je betroffenem Kapitel vor dem Ersetzen - Rückfrage vor Alle ersetzen im Projekt plus App-Undo der ganzen Aktion für Plan und Notizen - Statistik: nur stand nachführen, Zählregel in docs/architektur.md ergänzen - Menüeinträge DE/EN, i18n, Handbuch-Kürzeltabelle - Reine Logik in core/suche/ ## Nicht Teil dieses Issues (Out of Scope) - Reguläre Ausdrücke - Änderungen an der Schnellsuche (⌘K) - Suche in Schnappschüssen und Fassungen - KI-Vorschläge zum Ersetzen - Recherche-Suche (bleibt ⌘F in der Recherche) ## Fachliche und UX-Entscheidungen - Geklärt: Alles in einem Lauf (Leon) - Geklärt: Projektsuche ⌥⌘F, Fokus-Modus bleibt ⌘⇧F (Leon) - Geklärt: Ersetzen auch in Planfeldern und Notizen, alle Textfelder inkl. private (Leon) - Geklärt: Private Notizen erscheinen in Trefferlisten und beim Ersetzen, bleiben lokal (Leon) - Geklärt: Sicherheitsnetz für Plan und Notizen = Rückfrage plus App-Undo der ganzen Aktion (Leon) - Geklärt: Ersetzungstext wörtlich, keine Typografie-Regel (E7) - Geklärt: Ersetzen zählt nicht als geschrieben, nur stand - Geklärt: SchnappschussAnlass additiv erweitern - Geklärt: Textanker werden neu gesucht, sonst verwaist - Geklärt: keine regulären Ausdrücke (vorläufig) - Annahme: Unicode-Wortgrenzen, Groß-/Kleinschreibung ignorieren als Standard, Suche je Absatz - Annahme: App-Undo nur In-Memory für die letzte Aktion ## Prüfbare Akzeptanzkriterien - AC-1: Wenn ich im Bereich „Schreiben“ ⌘F drücke und einen Begriff eingebe, dann sind alle Treffer im aktuellen Kapitel markiert, die Leiste zeigt die Trefferzahl, und Enter springt zum nächsten Treffer. - AC-2: Wenn ich in der Projektsuche (⌥⌘F) einen Begriff suche, dann zeigt die Liste jeden Manuskript-Treffer mit Kapitelnummer, Kapiteltitel und Kontext in Buchreihenfolge. Ein Klick öffnet das Kapitel an dieser Stelle. - AC-3: Mit „Ganzes Wort“ trifft „Ole“ nicht „Oleander“. Mit „Groß- und Kleinschreibung beachten“ trifft „hafen“ nicht „Hafen“. - AC-4: Wenn ich „Alle ersetzen“ im Projekt bestätige, dann liegt vorher für jedes betroffene Kapitel ein neuer Schnappschuss in `.versionen/`. Kapitel ohne Treffer werden nicht neu geschrieben. - AC-5: Nach einem Ersetzen ändert sich der Wert `geschrieben` des Tages in `statistik.json` nicht; nur `stand` folgt. - AC-6: Der Ersetzungstext wird wörtlich eingefügt. Ein `"` darin wird nicht zu „ oder “. - AC-7: Bei leerer Suche oder ohne Treffer sind „Ersetzen“ und „Alle ersetzen“ deaktiviert, und ein leerer Zustand erscheint in DE und EN. - AC-8: Fehlerfall: Schlägt der Schnappschuss eines Kapitels fehl, bleibt dieses Kapitel unverändert, und eine Meldung nennt es. - AC-9: Die Projektsuche findet und ersetzt auch in allen Plan-Textfeldern und allen Notizen (inkl. privater, z. B. `notizen` bei Figur und Ort). Die Treffer sind nach Bereich getrennt aufgeführt. „Alle ersetzen“ in Plan und Notizen fragt vorher nach und lässt sich als ganze Aktion per App-Undo zurücknehmen; beides ist getestet. ## QS und Nachweis - Vitest in core/suche: Wortgrenzen, Case, Kontext, Markdown, mehrere Treffer je Absatz, Plan/Notizen - UI-Tests im Stil von Editor.test.tsx und schreiben.en.test.tsx gegen das Demo-Projekt - Test in src/app/app.test.tsx für ⌥⌘F ohne Kollision - Test, dass core/suche und die Projektsuche keinen Pfad zu core/ki schaffen - Test für App-Undo der ganzen Ersetzen-Aktion in Plan und Notizen - npm test, npm run typecheck, npm run build, npm run sperrliste grün - Rust-Menü: cargo test in der macOS-CI - Manuell auf dem Mac: Menü DE/EN, Kürzel, Alle ersetzen im Demo-Projekt Hafenlichter, Rückkehr über Versionsverlauf ## Offene Fragen – _Automatisch nach dem Formular „Agent-Auftrag“ strukturiert (Hermes-Triage). Die ursprüngliche Beschreibung steht unten unverändert._ <!-- hermes-agent-form-v1:end --> <details><summary>Ursprüngliche Beschreibung</summary> <!-- hermes-original:start --> ### Ziel und Nutzen Als Autorin möchte ich im aktuellen Kapitel und im ganzen Manuskript nach Text suchen und ihn gezielt ersetzen, damit ich etwa einen Figurennamen oder eine Schreibweise sicher im ganzen Buch ändern kann. ### Ist-Zustand / Problem - Es gibt nur die Schnellsuche (⌘K). Sie findet Kapitel, Figuren, Orte, Bereiche und Befehle, aber keinen Text im Manuskript: Trefferarten in `src/app/suche.ts:10`, Funktion `suche` in `src/app/suche.ts:91`. - Das Menü „Bearbeiten“ hat keinen Eintrag „Suchen“ oder „Ersetzen“, nur „Schnellsuche …“ (`src-tauri/src/menue.rs:166-181`). - Der Editor hat keine Such-Erweiterung (`src/features/schreiben/Editor.tsx:307-324`, `useEditor`). Im Repo gibt es keine Such- oder Ersetzen-Logik für Manuskripttext. - Kürzel-Kollision: ⌘⇧F ist schon der Fokus-Modus (`src-tauri/src/menue.rs:207-212`, `src/app/befehle.ts:165`, `src/app/app.test.tsx:13`, `docs/handbuch.md:188`). ⌘F ist in der Recherche schon die Suche (`docs/handbuch.md:146,195`, `src/i18n/de/recherche.ts:28`). ### Umfang (In Scope) - Suchleiste im Bereich „Schreiben“ (⌘F): Treffer im aktuellen Kapitel hervorheben, vor und zurück springen, Trefferzahl anzeigen. - Projektsuche (Kürzel siehe Offen): Ergebnisliste über alle Kapitel in Buchreihenfolge. Je Treffer Kapitelnummer, Kapiteltitel und Kontext. Ein Klick öffnet das Kapitel an der Stelle. - Ersetzen: einzeln und „Alle ersetzen“, im Kapitel und im Projekt. - Optionen „Ganzes Wort“ und „Groß- und Kleinschreibung beachten“. - Vor dem Ersetzen einen Schnappschuss jedes betroffenen Kapitels anlegen (`schnappschuss` aus `core/projekt`, Ablage `.versionen/`, E8). - Ersetzen zählt nicht als geschriebene Wörter. Die Statistik führt nur den `stand` nach. - Menüeinträge in „Bearbeiten“ (DE/EN), Texte in `src/i18n/{de,en}`, Tastenkürzel-Tabelle in `docs/handbuch.md`. - Such- und Ersetzlogik als reine Funktionen in `core/` (z. B. neues Modul `core/suche/`), ohne DOM. ### Nicht Teil dieses Issues (Out of Scope) - Reguläre Ausdrücke (siehe Offen). - Suchen und Ersetzen in Planfeldern, Notizen, Figuren, Orten und Recherche (siehe Offen). - Änderungen an der Schnellsuche (⌘K). - Suche in Schnappschüssen und Fassungen. - Jede Form von KI-Vorschlag zum Ersetzen („Die KI liest mit, schreibt aber nie.“). ### Fachliche und UX-Entscheidungen - Geklärt (Code): Typografie gibt es nur beim Tippen (E7, `docs/architektur.md:17`). Der Ersetzungstext wird wörtlich eingefügt, ohne Typografie-Regel. - Geklärt (Code): Zählregel `docs/architektur.md:85-90`: Import, Wiederherstellen, Änderungen von außen und Rückimport führen nur den `stand` nach. Der Mechanismus existiert: `nurStand` in `bucheAenderung` (`core/statistik/index.ts:123-130`), im Store über `NICHT_ZAEHLEN` und `aussetzen` (`src/state/slices/statistik.ts:74,158-160`). Ersetzen kommt in diese Liste. Die Zählregel in `docs/architektur.md` wird ergänzt. - Geklärt (Code): Schnappschüsse für Manuskriptdateien gibt es (`core/projekt`, `core/versionen`). `SchnappschussAnlass` (`core/versionen/index.ts:7`) darf additiv erweitert werden. - Geklärt (Code): Textanker (E4) werden nach dem Ersetzen neu gesucht. Ist eine Stelle nicht mehr eindeutig, wird sie „verwaist“, nie still falsch. - Annahme: „Ganzes Wort“ nutzt Unicode-Wortgrenzen wie die Namenserkennung (E5). „Ole“ trifft also nicht „Oleander“. - Annahme: Standard ist „Groß- und Kleinschreibung ignorieren“, „Ganzes Wort“ aus. - Annahme: Gesucht wird innerhalb eines Absatzes, nicht über Absatzgrenzen. Markdown-Auszeichnung (`*`, `_`) bleibt beim Ersetzen erhalten. - Annahme: „Alle ersetzen“ im Projekt fragt vorher nach und nennt die Zahl der Treffer und Kapitel. Rückgängig geht über den Versionsverlauf; im offenen Kapitel zusätzlich mit ⌘Z. - Fehlerfall: Lässt sich ein Schnappschuss nicht anlegen, wird dieses Kapitel nicht geändert. Die Meldung nennt das Kapitel. - Leerer Zustand: Keine Eingabe oder keine Treffer zeigt einen Hinweis; Ersetzen ist deaktiviert. - Offen (Leon): Sollen auch Planfelder (Kurzbeschreibung, Szenen) und Notizen ersetzt werden, oder nur der Manuskripttext? - Offen (Leon): Soll es reguläre Ausdrücke geben? - Offen (Leon): Welches Kürzel bekommt die Projektsuche? ⌘⇧F ist der Fokus-Modus. Vorschlag: ⌥⌘F für die Projektsuche, der Fokus-Modus bleibt auf ⌘⇧F. Oder soll der Fokus-Modus umziehen? ### Prüfbare Akzeptanzkriterien AC-1: Wenn ich im Bereich „Schreiben“ ⌘F drücke und einen Begriff eingebe, dann sind alle Treffer im aktuellen Kapitel markiert, die Leiste zeigt die Trefferzahl, und Enter springt zum nächsten Treffer. AC-2: Wenn ich in der Projektsuche einen Begriff suche, dann zeigt die Liste jeden Treffer mit Kapitelnummer, Kapiteltitel und Kontext in Buchreihenfolge. Ein Klick öffnet das Kapitel an dieser Stelle. AC-3: Mit „Ganzes Wort“ trifft „Ole“ nicht „Oleander“. Mit „Groß- und Kleinschreibung beachten“ trifft „hafen“ nicht „Hafen“. AC-4: Wenn ich „Alle ersetzen“ im Projekt bestätige, dann liegt vorher für jedes betroffene Kapitel ein neuer Schnappschuss in `.versionen/`. Kapitel ohne Treffer werden nicht neu geschrieben. AC-5: Nach einem Ersetzen ändert sich der Wert `geschrieben` des Tages in `statistik.json` nicht; nur `stand` folgt. AC-6: Der Ersetzungstext wird wörtlich eingefügt. Ein `"` darin wird nicht zu „ oder “. AC-7: Bei leerer Suche oder ohne Treffer sind „Ersetzen“ und „Alle ersetzen“ deaktiviert, und ein leerer Zustand erscheint in DE und EN. AC-8: Fehlerfall: Schlägt der Schnappschuss eines Kapitels fehl, bleibt dieses Kapitel unverändert, und eine Meldung nennt es. ### QS und Nachweis - Agent: Vitest-Tests für die Such- und Ersetzlogik in `core/` (Wortgrenzen, Groß- und Kleinschreibung, Kontext, Markdown-Auszeichnung, mehrere Treffer je Absatz). UI-Tests im Stil von `src/features/schreiben/Editor.test.tsx` und `schreiben.en.test.tsx` gegen das Demo-Projekt (Markieren, Ersetzen, Schnappschuss, Statistik, Typografie). Test in `src/app/app.test.tsx` für das neue Kürzel ohne Kollision. `npm test`, `npm run typecheck` und `npm run build` grün. Die Menüänderung in Rust prüft `cargo test` in der CI auf macOS; der Agent-Server ist Linux und kann die Mac-App nicht bauen. - Manuell auf dem Mac: Menü „Bearbeiten“ in DE und EN, Kürzel kollidieren nicht mit Fokus-Modus und Recherche-Suche, „Alle ersetzen“ im Demo-Projekt „Hafenlichter“ und Rückkehr über den Versionsverlauf. ### Technischer Kontext und Referenzen - Relevante Dateien: `src/app/suche.ts`, `src/app/befehle.ts`, `src-tauri/src/menue.rs`, `src/features/schreiben/Editor.tsx`, `core/versionen/index.ts`, `core/statistik/index.ts`, `src/state/slices/statistik.ts`, `core/text/` (Klartext, Anker), `docs/handbuch.md`. - Architektur: E4, E5, E7, E8 und Zählregel in `docs/architektur.md`. - Verwandt: Issue zu „Kapitel teilen, zusammenführen und archivieren“ nutzt dieselbe Schnappschuss-Logik. ### Sicherheits- und Liefergrenzen - [X] Das Issue enthält keine Secrets, Tokens, Zugangsdaten oder vertraulichen Manuskript- und Kundendaten. - [X] Der Agent darf Code und Tests ändern sowie einen Draft-PR öffnen, aber nicht selbst mergen, releasen oder deployen. - [X] Änderungen an produktiver Infrastruktur oder veröffentlichten Releases sind nicht Teil dieses Auftrags. _Angelegt von Claude Code im Auftrag von @leonatwork auf Basis einer Code-Analyse (Stand 2026-10-20)._ <!-- hermes-original:end --> </details> Zusätzliche Repo-Regeln: Commits tragen ein DCO-Sign-off (das macht dev-loop automatisch). Auf diesem Server gibt es kein Rust/Tauri: nur TypeScript-Teil (core/, src/) mit npm run build und npm test prüfen, src-tauri nicht bauen. Keine Inhalte aus privaten Manuskripten; Beispiele nur aus fixtures/. Farben nur über Tokens in src/theme/tokens.css, UI nach docs/design/screens, core/ bleibt reines TypeScript, core/ki nutzt nur ProjektLeser. Reviewer verdict: APPROVE after 2 round(s). Generated by dev-loop (not pushed). Signed-off-by: leonatwork <leon.11@live.de>
…stik-Aussetzung und Funktionen-Test gelöst Signed-off-by: leonatwork <leonatwork@users.noreply.github.com>
Signed-off-by: leonatwork <leonatwork@users.noreply.github.com>
…len und App-Test gelöst Signed-off-by: leonatwork <leonatwork@users.noreply.github.com>
| for (const u of [...undo].reverse()) await speichern(feldSetzen(get().daten!, u.feld.pfad, u.vorher), u.feld); | ||
| undo = []; setze({ kannUndo: false }); | ||
| } finally { setze({ laeuft: false }); } | ||
| }, |
There was a problem hiding this comment.
Partial undo becomes unrestorable
Medium Severity
undo writes fields one by one and only clears the in-memory stack after every write succeeds. If a later speichern throws, earlier fields are already back to vorher while the stack still expects every field to equal nachher, so the next undo raises undoKonflikt and cannot finish the rest of the action.
Reviewed by Cursor Bugbot for commit cf29b0a. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1cb8a0c. Configure here.
| editor.view.dispatch(closeHistory(editor.state.tr)); | ||
| geladen.current.doc = editor.state.doc; | ||
| analysieren(); | ||
| return; |
There was a problem hiding this comment.
Replace loses out to dirty editor
High Severity
The new replace handoff via editorErsetzungAbholen runs only after the existing dirty-buffer guard. If the open chapter changes between editorSichern and the store write (snapshot I/O), that guard keeps the local buffer, skips the handoff, and autosave.jetzt() writes the editor back over the replacement already persisted.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 1cb8a0c. Configure here.


Zusammenfassung
Autonome Umsetzung von #10: [Agent] Suchen und Ersetzen im Kapitel und im ganzen Projekt
Verifikation
Coder-/Reviewer-Loop:
APPROVEnach 2 Runde(n)Tests und Qualitätsprüfungen: siehe Commit und CI-Checks
Kein automatischer Merge oder Produktionsdeploy
Modell:
azure/gpt-6.1-sol; Decision-1 (active): routegpt-5.3-codex, Risikomedium; QS:npm run build && npm testbestandenArt der Änderung (Triage):
code; Zweitprüfung:azure/gpt-5.3-codexKosten (Listenpreis): 15,4 Mio Tokens · 7,23 €
Hinweise der Qualitätsprüfung
core/suche/index.ts:14copies the pattern fromsrc/features/schreiben/verweise.ts:19. If a new reference type is added later, both places must change. A short note in the comment, or a shared constant incore/text, would prevent them drifting apart. Optional.)Closes #10
Note
Medium Risk
Bulk edits touch persisted manuscript and plan/note data with snapshot gating, but the behavior is heavily tested and scoped to local text fields rather than auth or external services.
Overview
Adds local find/replace for the current chapter and the whole project (Issue #10), with no KI or network use.
Core (
core/suche) introduces literal paragraph-level search (optional whole word / case), project field enumeration with an allowlist (manuscript, plan, notes; skips IDs, anchors, and full[[typ:id|…]]spans), and replace that keeps manuscript Markdown markup while inserting literal replacement text in plan/notes.UI & commands: ⌘F opens in-editor chapter search with highlights and navigation; ⌥⌘F opens a project dialog grouped by manuscript / plan / notes. Native Edit menu entries, DE/EN strings, and Recherche still uses ⌘F for its own filter via a custom event.
Safety & persistence: Each affected chapter gets a mandatory snapshot (
SchnappschussAnlass: ersetzen) before write; failed snapshots leave that chapter untouched. Plan/notes support one in-memory undo for the last replace action; manuscript uses editor undo or version history. Replace updates writing statisticsstandonly, notgeschrieben. An import-boundary test keeps search code off KI/backend paths.Reviewed by Cursor Bugbot for commit 1cb8a0c. Bugbot is set up for automated code reviews on this repo. Configure here.