Enhance editor features, improve performance, and fix bugs#6
Enhance editor features, improve performance, and fix bugs#6Szowesgad wants to merge 61 commits into
Conversation
…o feat/pensieve-mvp3-machete2
…feat/pensieve-mvp3-machete2
Refactors Makefile help output to use structured `printf` output with ANSI color constants, improving readability and alignment of command descriptions. Authored-By: codex <agents@vetcoders.io> session_id: 019e90db-cdfe-7ad2-ab53-d62bef636222 time: Thu Jun 4 14:08:52 MDT 2026 runtime: iterm2
…b UX Addresses six findings from a ScreenScribe review of the editor. The window toolbar (EditorToolbelt) existed but was never mounted; this attaches it via `.toolbar` on ContentView, restoring the mode picker, block-format strip, and preview controls. The find bar gains a disclosure toggle next to the search field so Find & Replace is reachable inline, not only via the menu shortcut. The document tab strip pins its "+" New File button to the trailing edge instead of letting it scroll away, and a window-scoped scroll-wheel monitor (HorizontalWheelRedirector) maps vertical wheel input onto the strip's horizontal axis for plain-mouse users. Automatic macOS window tabbing is disabled so the only tab surface is the app's own strip, removing the duplicate native tab bar that always showed the same document. A new DocumentSharing helper backs File - Share and a toolbar Share button, sharing the file URL (or buffer text when unsaved). .gitignore now ignores *.log. Verified: swift build (debug+release), swift test 242/242, make lint clean, make release-clean -> notarized + stapled + Gatekeeper-accepted. Authored-By: claude <agents@vetcoders.io> session_id: 9c13d55e-1af1-4dc0-ae3b-382659e4f766 date: 2026-06-04T15:36:27 MDT runtime: claude-code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks .gitignore to stop blanket-ignoring every *.md. Only root-level and docs-direct markdown stay ignored, with README/CHANGELOG/CONTRIBUTING/SECURITY/ CODE_OF_CONDUCT/AGENTS and VERSION whitelisted, and docs/superpowers + docs/ workforce excluded. Design and plan specs under docs/specs/ are now tracked. Adds the per-window-documents + native-window-tabs implementation plan (Stream S0b of the Pensieve mega-meta atlas): state split into a shared WorkspaceStore + per-window DocumentWindowModel, native tabbing, sidebar in every window, removal of the programmatic DocumentTabStrip, with a measurable cut/verifier per step. Authored-By: claude <agents@vetcoders.io> session_id: 314040e7-b4ec-4bf8-afde-46cf128fd083 date: 2026-06-04T18:02:29 MDT runtime: claude-code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d *.md ignore Internal documents (specs, plans, agent prompts) sync between the operator's machines over Tailscale + rsync, NOT through git/GitHub. The broad *.md ignore was a deliberate privacy guard; a narrower rule had let an internal plan doc be tracked. This reinstates the broad *.md ignore (named governance/root files still whitelisted) and untracks the per-window-tabs plan, which stays on disk for rsync but no longer ships to the remote. Reverts the tracking introduced in 2a1ffca (file content remains in history; purge requires a separate force-push rewrite, operator-gated). Authored-By: claude <agents@vetcoders.io> session_id: 314040e7-b4ec-4bf8-afde-46cf128fd083 date: 2026-06-04T18:07:58 MDT runtime: claude-code Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Split workspace and per-window document state so native macOS tabs can host independent documents. Route open-file intents through value-scoped windows, activate existing document tabs, remove the in-app DocumentTabStrip, and keep menu commands focused on the frontmost document window.
Two Pensieve bugfixes (plans 10 + 20), living tree, no push. Plan 10 — floating format bar must NOT steal focus - Replace NSPopover (a separate key window → NSTextView resigns first-responder → user had to press Esc before typing/copying) with an in-window subview accessory (FloatingFormatBarView) that hosts the existing MarkdownFloatingFormatBar (reuse, no second bar). - acceptsFirstResponder=false → the bar never becomes key → text view keeps first-responder → no focus theft, no Esc. - Draggable via a leading grip (mouseDown/Dragged moves the bar, clamped to visibleRect); anchored in text-view coordinates so it scrolls with the text and never floats over a stale spot. Lifecycle parity preserved (show on non-empty selection, hide on empty / apply / Esc). show/hide/apply API names and the EditorView caller unchanged. Plan 20 — P0: workspace index hangs the app (DB off the main thread) Root: @mainactor IndexDatabase ran SQLite on main — open()'s DatabasePool + migrate (incl. FTS5 rebuild) and every sync read/write blocked the run loop; ensureOpen() was sync at the head of the "...InBackground" methods, so even those migrated on first touch on main. - makeDatabasePool (nonisolated static) + openInBackground/ensureOpenInBackground (async, detached executor, coalesced via openTask) move open+migrate off main. - All ...InBackground methods now await ensureOpenInBackground (first-open off main systemically). refreshSearchResultsInBackground moves the post-reindex search read off main. indexedDocumentCountInBackground for the skip-gate. - DocumentStore live background path: open, cold skip-gate count, performColdIndex content-guard, and hot-reopen open all moved off main (precomputed off-main values injected; legacy sync path keeps sync). AppController.start warms the index off main instead of a synchronous open at launch. Verified: swift build (debug+release) green; swift test 242/242, 0 failures; make lint exit 0; git diff --check clean. NOT verified (operator-owned): make ui-smoke (System Events AppleEvent -1712 in headless session; needs signed .app) and the Time-Profiler no-beachball runtime gate. Residual (documented): single-doc autosave index() stays sync on main to preserve the synchronous save-test contract — not the import storm. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a new `make install-app` target that builds the signed app, safely stops any running Pensieve process, replaces `/Applications/Pensieve.app`, and relaunches it. Also updates the project version from `0.2.1` to `0.2.3`.
…in thread (P0 R1) The autosave/save tail ran IndexDatabase.index(document:body:) — ensureOpen + pool.write (ensure-workspace + upsert) + refreshSearchResults (a pool.read) — synchronously ON THE MAIN ACTOR on every persisted edit, a per-save SQLite stall on the run loop. Add an off-main twin indexInBackground(document:body:) mirroring updateSearchIndexInBackground (shared pendingIndexUpdateTask supersede chain, detached .utility pool.write, refreshSearchResultsInBackground hop), and repoint the single production caller (DocumentStore's default index closure) to it so the file write stays synchronous while the FTS update commits in the background. The sync index() is kept for the explicit one-shot/test callers (same sync/background duality as reindex/reindexInBackground); the two ad-hoc single-doc index tests now sync on the awaited background write instead of the sync method. swift test 242/242 green, make lint clean. Authored-By: claude <agents@vetcoders.io> session_id: 52e36949-a5c9-4b44-8951-37cbd6aafce2 date: 2026-06-05T18:00:13 MDT runtime: claude
…store edit toolbar + degut ghosting Three P0 regressions surfaced by a 2026-06-05 ScreenScribe review of the per-window build (a152d00 + 9646193). The per-window state bridge (windowModel/workspaceStore objectWillChange re-broadcast onto AppState) re-renders the whole UI on every keystroke, and the editor's NSScrollView re-scrolled to the caret each time — "the screen goes wild on every letter". updateNSView now pins the clip-view origin across a pure re-render (text unchanged) and the text re-sync path preserves caret + scroll, so the viewport only moves when the user's own typing pushes the caret past the edge. The window-toolbar format strip gated on document != nil, so it vanished while editing any buffer whose DocumentRef was nil (e.g. an opened doc that did not carry a ref) — it now lights up for any hasEditableBuffer, untitled included. The line-number gutter ghosted/doubled because partial ruler redraws left stale numbers at the old scroll offset; contentView now posts bounds changes so every scroll forces a full gutter repaint. Native window tabs / Merge All Windows confirmed working and untouched. Authored-By: claude <agents@vetcoders.io> session_id: 1e9d8b44-cdef-4c26-b152-b3d0e664a6b4 date: 2026-06-05T20:26:55 MDT runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d off the main actor (P0 beachball)
The constant beachball ("the app churns every ~0.5-3s, non-stop") on a 54k-file workspace was
the watcher-refresh path re-enumerating the whole tree ON the main actor. performWatcherRefresh
computed the .md signature off-main, but applyRefresh -> rebuildWorkspace then re-walked all 54k
files + per-file stat synchronously on the main actor on every .md change — and a live workspace
full of agent reports, rsync and .git churns .md constantly, so the rebuild fired in a loop and
pinned the main thread. Now the rebuild enumeration also runs on a detached .utility task: the
.md signature scan is off-main, a non-.md change skips the rebuild entirely on the cheap delta
check, and only a genuine .md change pays for an off-main rebuild scan whose result is handed to
the main actor purely to assign the tree. rebuildWorkspace accepts precomputed scans so the main
actor never enumerates the workspace.
Authored-By: claude <agents@vetcoders.io>
session_id: 286d1e8c-3f76-492f-85d8-3f8a58f2fb80
date: 2026-06-05T20:46:57 MDT
runtime: claude
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Guard DocumentWindowRegistry open and attach ordering while AppKit has an active modal window, then retry on a clean main-queue turn. Keep SwiftUI window accessor repeats idempotent so pending merge targets are only consumed once native tab mutation is safe. Add coverage for the modal-blocked attach path: no merge or order work runs while blocked, duplicate accessor updates coalesce to one retry, and the deferred attach completes once unblocked. Authored-By: codex Session-Id: pending Date: 2026-06-06 Runtime: unknown
…ab attach test testDocumentWindowAttachDefersNativeTabMutationDuringModalRunLoop created an NSWindow via init(contentRect:styleMask:backing:defer:), which defaults to isReleasedWhenClosed = true. The deferred window.close() then released the window once, and ARC released the local reference again at scope exit — a double free that crashed the whole xctest process with SIGSEGV (objc_release EXC_BAD_ACCESS on the main thread), taking the full suite down to a non-result. Setting isReleasedWhenClosed = false lets ARC own the single reference so teardown is balanced. Suite is green again at 243/243 (gate for the off-main index work). Surgical, test-only; production NSWindow lifetime is unchanged. Authored-By: claude <agents@vetcoders.io> session_id: b6ad7720-7637-4dae-ac54-2675e4174309 date: 2026-06-06T04:44:51 MDT runtime: interactive
- Pensieve/Sources/Pensieve/App/DocumentWindowRegistry.swift: decouple window opening from SwiftUI OpenWindowAction for direct deferred-open testing and use NSApplication.shared for optional key/main window lookup in headless or launch-timing paths. - Pensieve/Sources/Pensieve/App/PensieveApp.swift: preserve production openWindow(value:) routing through the registry's document opener closure. - Pensieve/Tests/PensieveTests/PensieveTests.swift: cover modal-time open deferral, retry coalescing, and single resumed document open. Gate: pass Tests: swift test targeted open/attach modal tests; make test; make lint; make release-local; make ui-smoke; scripted About/open-file runtime probe with 12 confirmed modal passes plus 2 no-crash automation-noise attempts Regressions: 0 Round-ID: marb-044111-62487-005
…ction Protect workspace cache and metadata artifacts with complete file protection and lock the contract with regression tests. Authored-By: junie <agents@vetcoders.io> session_id: 8ec86487-629a-4883-bf86-310672271e8c date: 2026-06-06T21:32:08 MDT runtime: interactive Co-authored-by: Junie <junie@jetbrains.com>
Replace blind autosave sleeps with deterministic file-write and waitForPendingReindex-gated search assertions. Authored-By: junie <agents@vetcoders.io> session_id: 7bfa8e36-d960-4bf7-a9a5-65a397ad3d41 date: 2026-06-06T22:01:34 MDT runtime: gpt-5.4 Co-authored-by: Junie <junie@jetbrains.com>
Adds Return-time Markdown continuation behind the Rich Markdown toggle and pins inline highlight rendering with tests. Authored-By: codex <agents@vetcoders.io> session_id: b201a096-5522-4563-b2bb-05b05cbd895e date: 2026-06-07T06:38:33 MDT runtime: codex
Adds the first wikilink/backlink core seam by parsing [[target]] text, rendering safe preview anchors, and covering extraction plus escaping behavior. Authored-By: codex <agents@vetcoders.io> session_id: 1c51fd30-a2ec-4e68-aeec-ef48f46681e1 date: 2026-06-07T06:49:38 MDT runtime: codex
Wire the existing preview viewport bridge to the editor with paragraph-index mapping and tests. Authored-By: codex <agents@vetcoders.io> session_id: c7a5555f-d83d-47d2-8bbf-44652a758430 date: 2026-06-07T06:58:27 MDT runtime: codex
Adds an offline-safe markdown math layer to the existing HTML preview pipeline with tests for inline and display delimiters. Authored-By: codex <agents@vetcoders.io> session_id: c83ccf4e-9aaf-461b-8df4-045715e88099 date: 2026-06-07T07:08:17 MDT runtime: unknown
Focus mode now keeps the insertion line centered during typing and selection changes without adding a parallel editor mode. Authored-By: codex <agents@vetcoders.io> session_id: 77e0ed10-9cdd-45f5-ab93-baf33b1d4131 date: 2026-06-07T07:17:28 MDT runtime: unknown
Adds File menu export paths backed by the existing preview renderer, with standalone HTML coverage and WebKit PDF generation. Authored-By: codex <agents@vetcoders.io> session_id: 3d18a8e2-b50e-439a-abe9-1ae8dcf58373 date: 2026-06-07T07:28:13 MDT runtime: unknown
Pensieve now vendors the generated qube UniFFI bridge and links the debug libqube_ffi dylib through SwiftPM, unblocking the transcription overlay W0 build seam. Authored-By: codex <agents@vetcoders.io> session_id: 1e82d76f-f6b2-4c5e-98a9-bcca2f793aa3 date: 2026-06-07T07:42:42 MDT runtime: codex
…rvice Adds the headless TranscriptionService seam for W1, wires it into the existing app graph, and locks preview/final accumulation with tests. Authored-By: codex <agents@vetcoders.io> session_id: 0f4d69e2-4812-4b18-9a76-4b12ffa719bf date: 2026-06-07T07:53:01 MDT runtime: codex
Adds scoped backlink queries over the existing documents index so wikilinks can resolve incoming references without a parallel parser. Authored-By: codex <agents@vetcoders.io> session_id: 0fd1aa2d-ea85-4f7c-8ed2-5809194a56b6 date: 2026-06-07T08:03:01 MDT runtime: codex
Extend the existing MarkdownFormatter typing pipeline so a single closing equals finishes source-first ==highlight== markup without touching closed spans. Authored-By: codex <agents@vetcoders.io> session_id: 30489637-018d-4550-9112-878978a25f35 date: 2026-06-07T08:08:45 MDT runtime: codex
…edback loop on keystroke The editor↔preview scroll sync (c7ed51f) yanked the editor to the caret on every character in split mode: typing posts the editor viewport, the preview re-renders + emits a viewport change, and handlePreviewViewportChanged scrollRangeToVisible'd the editor back — a loop the operator hit as "every char jumps the whole document". Guard handlePreviewViewportChanged so preview-driven scroll only moves the editor when the editor is NOT first responder; while the user is typing the editor drives and is never scrolled by the sync. User-driven preview scrolling still syncs. Authored-By: claude <agents@vetcoders.io> session_id: b83b0fb9-3bfb-4853-8d5e-1da067c81836 date: 2026-06-07T15:40:52 MDT runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an Application Support recovery store for dirty untitled buffers, restore the latest draft during startup, and delete drafts after Save As or discard. Bound the Open Files working set, add clear/close affordances, pin default scanner noise filtering, and fix the vendored qube_ffi install name so SwiftPM tests load the repo-local dylib instead of a stale external path. Verification: make test (281 tests, 0 failures); make lint; scoped semgrep scan; targeted recovery/working-set/regression tests. Authored-By: codex session_id: pending date: 2026-06-07T23:20:00-06:00 runtime: codex-cli
Cut 42-A3 had default noise filtering but no .gitignore layer, so agent artifacts and project-local ignore rules could still leak into the notes tree/index. Extend the existing WorkspaceScanner path with scan-local GitIgnoreRule handling for anchored, directory, wildcard, nested, and negation rules while preserving the default deny-list and manual exclusions. Verification: targeted Cut 42 cluster passed; make test passed 282 tests; make lint passed. Semgrep 1.164.0 was run and failed on 5 pre-existing blocking findings outside this scoped patch: ATS pinning in plist files and one existing WorkspaceSubstrateTests storage-protection fixture. Authored-By: codex/gpt-5 session_id: pending date: 2026-06-07T23:37:37 MDT runtime: codex
Stop assigning the shared Pensieve document tabbing identifier to standalone document windows during attach. Only opt windows into the shared identifier at the moment an explicit tab merge is performed, so AppKit can honor View > Show/Hide Tab Bar for a single document window.
Add focused coverage for exact [[Target]] backlinks, stale rename and missing-target edge cases, and indexed-row/FTS-backed lookup behavior.\n\nVerification:\n- swift test --package-path Pensieve --filter IndexDatabaseBacklinksTests\n- semgrep scan --config auto Pensieve/Tests/PensieveTests/IndexDatabaseBacklinksTests.swift\n\nFull swift test currently aborts in existing IndexDatabaseV2StatsTests.testColdScanAppendsSessionAndUpsertsStats at a nil unwrap before this change's scope completes.
Cover Swift-side Vista transcription accumulation ordering, preview flush, reset/reuse, and blank buffer edge cases without touching FFI, UI, or release surfaces.
…n subtitle to diagnose the "Pensieve" tab-title bug Two blind code-fixes (06eb730 registry title) passed green tests but the running app still shows "Pensieve" as the tab title for an open document. systematic-debugging Phase 1 was skipped — this adds a TEMP diagnostic subtitle (buf=<hasEditableBuffer> t=[displayTitle]) so one screenshot reveals whether the per-window documentSession is .empty for a shown doc (the real desync) vs a navigationTitle fight. Revert once the title root cause is confirmed. Authored-By: claude <agents@vetcoders.io> session_id: beb173fb-18a3-4e72-9351-b1d2f4e8fcce date: 2026-06-08T18:14:48 MST runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…+ preview for AX-driven verification
Adds setAccessibilityIdentifier("pensieve.editor") to the editor NSTextView and "pensieve.preview"
to the preview WKWebView so the running app can be queried/driven via osascript + AXUIElement
(focus-safe: read state, AXPress, screencapture by window) instead of asking the operator to
screenshot. Complements the existing pensieve.toolbar.modePicker + floating-format identifiers. The
"aria zaczepy" foundation for self-verifying GUI fixes (measure-don't-declare on the live app).
Authored-By: claude <agents@vetcoders.io>
session_id: f4c5519b-17ce-41b2-b155-e271ca814298
date: 2026-06-08T18:37:58 MST
runtime: claude
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AX measurement on the running build 146 confirmed dbg buf=true t=[SKILL] — i.e. hasEditableBuffer is true and the navigationTitle correctly shows the document name; the 'Pensieve' tab title the operator saw was build 134, not 146. The diagnostic served its purpose; restore the clean Edited subtitle. Authored-By: claude <agents@vetcoders.io> session_id: 0c714819-762a-42f3-9039-b2ed8831e2c6 date: 2026-06-08T18:45:37 MST runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…croll-sync crash (P0) Build 146 crashed (EXC_BAD_ACCESS in objc_msgSend) when the editor<->preview scroll sync fired: handlePreviewViewportChanged scrolls the editor -> the clip-view bounds change invokes editorBoundsDidChange SYNCHRONOUSLY -> postEditorViewportIfNeeded -> currentTopVisibleBlockIndex queries NSTextView layout (characterIndexForInsertion) re-entrantly mid-scroll -> dangling-object crash. The bbdb719 first-responder guard did not cover the preview-driven path (editor not first responder). Add an isApplyingPreviewScroll re-entrancy flag set around the programmatic scrollRangeToVisible and checked at the top of editorBoundsDidChange, cleared on the next runloop turn. Breaks the feedback loop that the operator saw as 'scroll skacze w chuj na synchro' and crashed. Runtime-verify: scroll editor + preview in split -> no jump, no crash. Authored-By: claude <agents@vetcoders.io> session_id: 05aa3c16-aa6d-4ec8-831a-f347235e4362 date: 2026-06-08T22:49:31 MST runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Include the target document row in backlink record lookup so heading/title aliases resolve from the indexed database row even when the target body itself has no wikilinks. Add a regression test that mutates the target file after reindex and still expects [[Indexed Target]] backlinks to resolve from the indexed title.
Route the app command surface to NSWindow.toggleTabBar so View > Show/Hide Tab Bar is handled by AppKit instead of being blocked by Pensieve's document-window routing.
Paint a stable startup surface until launch/session state has propagated, then reveal the real content on the next main-loop turn. This avoids the cold-launch blank/transparent flash that reads like a crash even when no DiagnosticReport exists.
Replace force unwraps in IndexDatabaseV2StatsTests with XCTUnwrap messages so missing scan_sessions/workspace_stats rows fail as ordinary XCTest assertions instead of aborting the suite. Keep the production workspace_id path unchanged because current WorkspaceIdentity keying already excludes bookmark data from workspaceID and matches the cold-scan write path.
Clean the startup first-paint view modifier indentation flagged by make lint without rewriting concurrent commits that landed after the launch fix.
Cut 42-A2 only: route file/sidebar opens into an empty current document window instead of creating a throwaway launcher plus replacement document window, no-op already-active document opens, and merge already-open document windows into the current native tab group before focusing them. Adds regression coverage for empty launcher reuse, existing-window merge/reap, and preserves the modal tab mutation guard path from 97f224a. Verification: swift test --filter focused 42-A2/window suite; swift test; make lint; make build-release. UI smoke attempted against dist/Pensieve.app but blocked before workflow verification because System Events reported 0 visible windows for the launched app. Authored-By: codex session_id: pending date: 2026-06-09 runtime: vc-justdo/codex
… scroll-sync (P0 crash, stop the bleed) Builds 146 and 148 crashed (EXC_BAD_ACCESS in objc_msgSend) on the editor<->preview scroll sync: currentTopVisibleBlockIndex() -> characterIndexForInsertion triggers TextKit2 viewport layout (a nested scroll) when called from a bounds-change / text / selection notification, re-entering layout and dereferencing a freed object. Two targeted guards (bbdb719 first-responder, d4aa124 re-entrancy flag) did not hold because the crashing layout query fires from multiple notification paths. Per the operator's lived runtime truth (crash log + 'dalej skacze, ten sam crash'), the sync mechanism is fundamentally fragile. Disable both directions (postEditorViewportIfNeeded no-op; handlePreviewViewportChanged no-op) so no characterIndexForInsertion runs inside a notification. Editor and preview now scroll independently — no jump, no crash. Two-way scroll-sync to be re-implemented off the layout pass (async/coalesced) as a separate cut. swift test green. Authored-By: claude <agents@vetcoders.io> session_id: b1ffd947-61aa-4415-8f62-68612c369517 date: 2026-06-09T01:45:10 MST runtime: claude Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add a non-activating floating NSPanel bound to TranscriptionService.rendered/isRecording/lastStatus/lastError - wire View-menu and toolbar toggles through AppController without touching editor scroll-sync, tabs, or recovery paths - cover panel non-activating/floating/accessibility invariants with AppKit test Verification: swift test; make test; make lint; swift build
Add the Pensieve-side VistaEngineProtocol.complete(prefix:maxTokens:) mirror and a mocked autocomplete engine for the 45-A1 service cut. Wire MarkdownEditorSurface.textDidChange into a cancellable debounced controller without ghost-text rendering or layout queries, and cover typing-pause plus stale-task cancellation.
- keep the AoT tafla panel non-activating by ordering it normally and requiring key only if needed - expose tafla from the Window menu in addition to the existing View menu and toolbar toggle - strengthen tafla panel tests around floating, non-key, non-main, resizable behavior Verification: swift test --filter TranscriptionTaflaPanelTests; swift test; make test; make lint; make ui-smoke; debug Accessibility probe for Tafla main=false focused=false; git diff --check
Add the disabled-by-default AI Autocomplete menu toggle, bind the existing controller into the editor surface, render display-only ghost text in MarkdownTextView, and route Tab/Esc accept/dismiss behavior through normal editor edits. Cover accept, dismiss, invalidate, and stale-anchor suppression in AutocompleteControllerTests. Leave concurrent Transcription/* work unstaged.
- add tafla format/copy/send controls backed by VistaEngine.formatText - route Shift+Return/send into the active Pensieve editor at the caret - add cadence preview promotion to keep continuous speech growing - lock formatter, send, panel focus, and cadence behavior in Swift tests Authored-By: codex <agents@vetcoders.io>
- run autocomplete completion work at user-initiated priority - clear stale autocomplete error state on cancellation - add regression coverage proving a superseded completion task observes cancellation before its stale result can surface Verification: - swift test - make lint - semgrep --config auto --error --timeout 60 Pensieve/Sources/Pensieve/Editor/AutocompleteController.swift Pensieve/Tests/PensieveTests/AutocompleteControllerTests.swift
- keep ghost repositioning async after bounds/layout changes - guard async render against stale invalidation generations - cover edit invalidation and default-off autocomplete setting
Add Polish/Kurier transcription formatting modes, wire Kurier through Vista assistive formatting, and expose independent Tafla send targets for editor insertion vs agent dispatch. Add a mockable Vibecrafted Process launcher that runs from the Pensieve workspace root, updates Tafla dispatch status with parsed run_id/report path metadata, and keeps real dispatch out of tests. Verification: swift test --package-path Pensieve; make test; make lint (exit 0, pre-existing warnings remain in untouched workspace/index test files).
There was a problem hiding this comment.
Code Review
This pull request introduces several significant features to the Pensieve markdown editor, including a voice transcription service with a floating 'Tafla' panel, an autocomplete controller powered by a native Rust FFI bridge, multi-window document routing, document recovery for untitled drafts, and HTML/PDF export capabilities. It also optimizes workspace scanning by honoring .gitignore rules and moves database operations off the main thread. The code review feedback identifies critical issues that need to be addressed, such as hardcoded user home directory paths, potential data races in IndexDatabase requiring synchronization, main-thread blocking during PDF export, a dictionary memory leak in DocumentWindowRegistry, incorrect CRLF line ending handling in .gitignore parsing, and threading issues in AutocompleteController.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| static let executablePath = | ||
| "/Users/maciejgad/.local/share/vibecrafted/tools/vibecrafted-current/scripts/vibecrafted" |
There was a problem hiding this comment.
The executable path is hardcoded to a specific user's home directory (/Users/maciejgad). This will fail on any other machine. Use NSHomeDirectory() to dynamically construct the path relative to the current user's home directory.
static var executablePath: String {
let home = NSHomeDirectory()
return "\(home)/.local/share/vibecrafted/tools/vibecrafted-current/scripts/vibecrafted"
}| agentWorkspaceRoot: URL = URL( | ||
| fileURLWithPath: "/Users/maciejgad/vc-workspace/vetcoders/pensieve"), |
There was a problem hiding this comment.
The workspace root is hardcoded to /Users/maciejgad/.... This should be constructed dynamically using the current user's home directory to ensure portability across different development environments.
| agentWorkspaceRoot: URL = URL( | |
| fileURLWithPath: "/Users/maciejgad/vc-workspace/vetcoders/pensieve"), | |
| agentWorkspaceRoot: URL = FileManager.default.homeDirectoryForCurrentUser | |
| .appendingPathComponent("vc-workspace/vetcoders/pensieve"), |
| /// Coalesces concurrent off-main opens: the first `ensureOpenInBackground` that finds no pool | ||
| /// starts the migration on a detached executor and parks this task; later callers await the SAME | ||
| /// task instead of racing a second `DatabasePool`/migration. Cleared once the open resolves. | ||
| private var openTask: Task<DatabasePool, Error>? |
There was a problem hiding this comment.
Since IndexDatabase is accessed concurrently from multiple background tasks and the main thread, the mutable properties databasePool, databaseURL, and openTask are subject to data races. Introduce an NSRecursiveLock to synchronize access to these properties.
| /// Coalesces concurrent off-main opens: the first `ensureOpenInBackground` that finds no pool | |
| /// starts the migration on a detached executor and parks this task; later callers await the SAME | |
| /// task instead of racing a second `DatabasePool`/migration. Cleared once the open resolves. | |
| private var openTask: Task<DatabasePool, Error>? | |
| /// Coalesces concurrent off-main opens: the first `ensureOpenInBackground` that finds no pool | |
| /// starts the migration on a detached executor and parks this task; later callers await the SAME | |
| /// task instead of racing a second `DatabasePool`/migration. Cleared once the open resolves. | |
| private var openTask: Task<DatabasePool, Error>? | |
| private let lock = NSRecursiveLock() |
| func open(into appState: AppState? = nil) { | ||
| do { | ||
| let url: URL | ||
| if let configuredDatabaseURL { | ||
| url = configuredDatabaseURL | ||
| } else { | ||
| let directory = try applicationSupportDirectory() | ||
| url = directory.appendingPathComponent("index.db", isDirectory: false) | ||
| } | ||
| let url = try resolveDatabaseURL() | ||
| let pool = try Self.makeDatabasePool(at: url) | ||
| databasePool = pool | ||
| databaseURL = url | ||
| } catch { | ||
| reportOpenFailure(error, appState: appState) | ||
| } | ||
| } |
There was a problem hiding this comment.
Synchronize the synchronous open(into:) method using the recursive lock to prevent data races when called concurrently with background open operations.
| func open(into appState: AppState? = nil) { | |
| do { | |
| let url: URL | |
| if let configuredDatabaseURL { | |
| url = configuredDatabaseURL | |
| } else { | |
| let directory = try applicationSupportDirectory() | |
| url = directory.appendingPathComponent("index.db", isDirectory: false) | |
| } | |
| let url = try resolveDatabaseURL() | |
| let pool = try Self.makeDatabasePool(at: url) | |
| databasePool = pool | |
| databaseURL = url | |
| } catch { | |
| reportOpenFailure(error, appState: appState) | |
| } | |
| } | |
| func open(into appState: AppState? = nil) { | |
| lock.lock() | |
| defer { lock.unlock() } | |
| do { | |
| let url = try resolveDatabaseURL() | |
| let pool = try Self.makeDatabasePool(at: url) | |
| databasePool = pool | |
| databaseURL = url | |
| } catch { | |
| reportOpenFailure(error, appState: appState) | |
| } | |
| } |
| private func ensureOpenInBackground(into appState: AppState?) async -> DatabasePool? { | ||
| if let databasePool { return databasePool } | ||
| if let openTask { return try? await openTask.value } | ||
|
|
||
| var migrator = DatabaseMigrator() | ||
| migrator.registerMigration("mvp_workspace_search_fts") { db in | ||
| try db.execute( | ||
| sql: """ | ||
| CREATE VIRTUAL TABLE IF NOT EXISTS workspace_search_documents | ||
| USING fts5( | ||
| path UNINDEXED, | ||
| title, | ||
| display_path, | ||
| body, | ||
| is_ad_hoc UNINDEXED, | ||
| updated_at UNINDEXED, | ||
| tokenize = 'unicode61' | ||
| ) | ||
| """) | ||
| } | ||
| registerIndexV2Migrations(&migrator) | ||
| try migrator.migrate(pool) | ||
| let url: URL | ||
| do { | ||
| url = try resolveDatabaseURL() | ||
| } catch { | ||
| reportOpenFailure(error, appState: appState) | ||
| return nil | ||
| } | ||
|
|
||
| let task = Task<DatabasePool, Error> { | ||
| try await Task.detached(priority: .userInitiated) { | ||
| try Self.makeDatabasePool(at: url) | ||
| }.value | ||
| } | ||
| openTask = task | ||
| defer { openTask = nil } | ||
|
|
||
| do { | ||
| let pool = try await task.value | ||
| databasePool = pool | ||
| databaseURL = url | ||
| return pool | ||
| } catch { | ||
| let message = "Could not open Pensieve index database: \(error.localizedDescription)" | ||
| appState?.lastError = message | ||
| NSLog(message) | ||
| reportOpenFailure(error, appState: appState) | ||
| return nil | ||
| } | ||
| } |
There was a problem hiding this comment.
Implement thread-safe synchronization in ensureOpenInBackground using the recursive lock to safely manage concurrent database pool initialization and avoid data races on databasePool and openTask.
private func ensureOpenInBackground(into appState: AppState?) async -> DatabasePool? {
lock.lock()
if let databasePool {
lock.unlock()
return databasePool
}
if let openTask {
lock.unlock()
return try? await openTask.value
}
let url: URL
do {
url = try resolveDatabaseURL()
} catch {
lock.unlock()
reportOpenFailure(error, appState: appState)
return nil
}
let task = Task<DatabasePool, Error> {
try await Task.detached(priority: .userInitiated) {
try Self.makeDatabasePool(at: url)
}.value
}
openTask = task
lock.unlock()
do {
let pool = try await task.value
lock.lock()
databasePool = pool
databaseURL = url
openTask = nil
lock.unlock()
return pool
} catch {
lock.lock()
openTask = nil
lock.unlock()
reportOpenFailure(error, appState: appState)
return nil
}
}| case .success(let data): | ||
| do { | ||
| try data.write(to: outputURL, options: .atomic) | ||
| finish(.success(())) | ||
| } catch { | ||
| finish(.failure(error)) | ||
| } |
There was a problem hiding this comment.
Writing the PDF data to disk is currently performed synchronously on the main thread (since PDFExportJob is @MainActor). This can block the UI and cause beachballing for larger documents. Perform the write operation asynchronously on a background queue.
case .success(let data):
let url = self.outputURL
DispatchQueue.global(qos: .userInitiated).async {
do {
try data.write(to: url, options: .atomic)
DispatchQueue.main.async {
self.finish(.success(()))
}
} catch {
DispatchQueue.main.async {
self.finish(.failure(error))
}
}
}| private func purgeClosedLauncherWindows() { | ||
| launcherWindows = launcherWindows.filter { $0.value.window != nil } | ||
| contentWindows = contentWindows.filter { $0.value.window != nil } | ||
| if let preferredLauncherID, launcherWindows[preferredLauncherID]?.window == nil { | ||
| self.preferredLauncherID = nil | ||
| } | ||
| } |
There was a problem hiding this comment.
The windowsByDocumentID dictionary holds WeakWindow wrappers. When a window is closed, the weak reference inside WeakWindow becomes nil, but the key (the document URL) remains in the dictionary forever. Filter windowsByDocumentID during the sweep to prevent a memory leak of dictionary entries.
| private func purgeClosedLauncherWindows() { | |
| launcherWindows = launcherWindows.filter { $0.value.window != nil } | |
| contentWindows = contentWindows.filter { $0.value.window != nil } | |
| if let preferredLauncherID, launcherWindows[preferredLauncherID]?.window == nil { | |
| self.preferredLauncherID = nil | |
| } | |
| } | |
| private func purgeClosedLauncherWindows() { | |
| launcherWindows = launcherWindows.filter { $0.value.window != nil } | |
| contentWindows = contentWindows.filter { $0.value.window != nil } | |
| windowsByDocumentID = windowsByDocumentID.filter { $0.value.window != nil } | |
| if let preferredLauncherID, launcherWindows[preferredLauncherID]?.window == nil { | |
| self.preferredLauncherID = nil | |
| } | |
| } |
| init?(line rawLine: String, baseRelativePath: String) { | ||
| var line = rawLine.trimmingCharacters(in: .whitespaces) |
There was a problem hiding this comment.
Trimming only whitespaces (rawLine.trimmingCharacters(in: .whitespaces)) does not remove carriage returns (\r) from files with CRLF line endings (common on Windows or when git autocrlf is enabled). This causes pattern matching to fail. Trim both whitespaces and newlines to handle CRLF line endings correctly.
| init?(line rawLine: String, baseRelativePath: String) { | |
| var line = rawLine.trimmingCharacters(in: .whitespaces) | |
| init?(line rawLine: String, baseRelativePath: String) { | |
| var line = rawLine.trimmingCharacters(in: .whitespacesAndNewlines) |
| import Combine | ||
| import Foundation | ||
|
|
||
| final class AutocompleteController: ObservableObject, @unchecked Sendable { |
There was a problem hiding this comment.
AutocompleteController is an ObservableObject whose @Published properties are updated from asynchronous tasks. To prevent threading issues and SwiftUI runtime warnings, the entire class should be marked with @MainActor.
| final class AutocompleteController: ObservableObject, @unchecked Sendable { | |
| @MainActor | |
| final class AutocompleteController: ObservableObject { |
There was a problem hiding this comment.
Pull request overview
This PR significantly expands Pensieve’s editor/runtime capabilities by adding transcription (“Tafla”) tooling, agent prompt dispatch infrastructure, multi-window/tab routing, richer markdown rendering (wikilinks + math), and build/CI improvements (FFI linking + signed app installation + workflow).
Changes:
- Added transcription accumulation/service + a floating Tafla panel, with routing to editor insertion or agent dispatch.
- Introduced editor enhancements: inline highlight syntax, markdown autoconversion while typing, AI autocomplete plumbing, and scroll/format-bar UX changes.
- Improved preview pipeline and markdown rendering: incremental preview updates, base URL handling, wikilinks, and math nodes + bootstrap scripts.
- Added window/document routing infrastructure (window registry + per-window model/state split) and build/CI updates (FFI embedding/linking, Makefile targets, GitHub Actions).
Reviewed changes
Copilot reviewed 66 out of 69 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| VERSION | Bumps app version to 0.2.7. |
| SECURITY.md | Adds security policy and vulnerability reporting guidance. |
| scripts/build-release.sh | Embeds and re-signs libqube_ffi.dylib inside the app bundle for hardened runtime. |
| Pensieve/Tests/PensieveTests/WorkspaceSubstrateTests.swift | Adds assertions around file protection when writing workspace cache/metadata artifacts. |
| Pensieve/Tests/PensieveTests/TranscriptionTaflaPanelTests.swift | Adds UI configuration tests for the Tafla floating panel. |
| Pensieve/Tests/PensieveTests/TranscriptionAccumulationTests.swift | Adds extensive tests for transcription buffering/formatting and routing to editor/agent. |
| Pensieve/Tests/PensieveTests/SyntaxHighlighterTests.swift | Adds coverage for inline ==highlight== background rendering. |
| Pensieve/Tests/PensieveTests/QubeFfiBridgeSmokeTests.swift | Adds a compile/surface smoke test for the Vista engine bridge. |
| Pensieve/Tests/PensieveTests/PreviewPipelineTests.swift | Extends preview document tests (sourceURL/refreshToken, math bootstrap, body/style extraction). |
| Pensieve/Tests/PensieveTests/MarkdownWikilinksTests.swift | Adds extraction/rendering tests for [[wikilinks]]. |
| Pensieve/Tests/PensieveTests/MarkdownFormatterTests.swift | Adds typing autoconversion + typewriter-scroll tests; updates representable init parameters. |
| Pensieve/Tests/PensieveTests/MarkdownBlockMapperTests.swift | Adds tests for block-index mapping used for scroll sync. |
| Pensieve/Tests/PensieveTests/IndexDatabaseV2StatsTests.swift | Improves unwrap diagnostics and aligns bookmark store setup with throwing APIs. |
| Pensieve/Tests/PensieveTests/IndexDatabaseV2FtsTriggerTests.swift | Switches ad-hoc indexing tests to await background indexing completion. |
| Pensieve/Tests/PensieveTests/IndexDatabaseExternalContentFtsTests.swift | Updates docs + awaits background indexing for deterministic assertions. |
| Pensieve/Tests/PensieveTests/IndexDatabaseBacklinksTests.swift | Adds backlink resolution tests for wikilinks and workspace scoping. |
| Pensieve/Tests/PensieveTests/HTMLEmitterTests.swift | Adds HTML emission tests for inline/display math and coexistence with wikilinks. |
| Pensieve/Tests/PensieveTests/DocumentExportTests.swift | Adds export HTML rendering and file-name defaulting tests. |
| Pensieve/Tests/PensieveTests/AutocompleteControllerTests.swift | Adds debounce/cancellation and surface integration tests for autocomplete. |
| Pensieve/Sources/qube_ffiFFI/module.modulemap | Adds modulemap for the system library target exposing the FFI header. |
| Pensieve/Sources/Pensieve/Workspace/WorkspaceMetadataStore.swift | Writes metadata with file-protection options (with fallback). |
| Pensieve/Sources/Pensieve/Workspace/WorkspaceCacheStore.swift | Writes cache artifacts with file-protection options (with fallback). |
| Pensieve/Sources/Pensieve/Transcription/TranscriptionTaflaPanel.swift | Adds a floating non-activating SwiftUI/AppKit transcription panel. |
| Pensieve/Sources/Pensieve/Transcription/TranscriptionService.swift | Implements transcription accumulation, cadence commits, formatting, and dispatch status. |
| Pensieve/Sources/Pensieve/Storage/RecoveryStore.swift | Adds crash-recovery draft persistence/loading/deletion. |
| Pensieve/Sources/Pensieve/Sidebar/SidebarView.swift | Adds “Clear Open Files” and ad-hoc close action; routes open to new window handler. |
| Pensieve/Sources/Pensieve/Search/WorkspaceSearchResult.swift | Adds a backlink result model for backlink UI/workflows. |
| Pensieve/Sources/Pensieve/Resources/markdown.css | Styles wikilink anchors in the default theme. |
| Pensieve/Sources/Pensieve/Resources/gfm.css | Styles wikilink anchors in the GFM theme. |
| Pensieve/Sources/Pensieve/Preview/PreviewWebView.swift | Adds incremental update path + math styling/bootstrap + accessibility identifier. |
| Pensieve/Sources/Pensieve/Preview/PreviewPipeline.swift | Extends PreviewDocument with body/style/maths/identity fields + base tag insertion. |
| Pensieve/Sources/Pensieve/Markdown/MarkdownWikilinks.swift | Implements wikilink parsing, rendering, and slugging. |
| Pensieve/Sources/Pensieve/Markdown/MarkdownMath.swift | Adds math delimiter parsing and math-node rendering with escaped TeX. |
| Pensieve/Sources/Pensieve/Markdown/HTMLEmitter.swift | Routes text rendering through math/wikilink renderers; avoids nesting in markdown links. |
| Pensieve/Sources/Pensieve/Editor/SyntaxHighlighter.swift | Adds inline ==highlight== regex and attributes. |
| Pensieve/Sources/Pensieve/Editor/MarkdownTextView.swift | Adds autocomplete ghost rendering + in-window draggable formatting bar + insert helper. |
| Pensieve/Sources/Pensieve/Editor/MarkdownFormatter.swift | Adds typing autoconversion logic (lists/quotes + inline highlight closure). |
| Pensieve/Sources/Pensieve/Editor/MarkdownBlockMapper.swift | Adds block start/index mapping for scroll syncing. |
| Pensieve/Sources/Pensieve/Editor/FindBar.swift | Adds a disclosure toggle to show/hide Replace inline. |
| Pensieve/Sources/Pensieve/Editor/EditorView.swift | Threads new editor parameters; pins scroll across SwiftUI updates; adds autocomplete wiring. |
| Pensieve/Sources/Pensieve/Editor/AutocompleteController.swift | Adds debounce/cancellation-based autocomplete controller + mock engine. |
| Pensieve/Sources/Pensieve/App/WorkspaceStore.swift | Extracts workspace state into a shared store with cached lookups + sort persistence. |
| Pensieve/Sources/Pensieve/App/PensieveApp.swift | Migrates to per-document WindowGroup, per-window AppState/controller, and startup presentation. |
| Pensieve/Sources/Pensieve/App/LaunchIntentCoordinator.swift | Adds startup decision callback and improved URL routing for multi-window behavior. |
| Pensieve/Sources/Pensieve/App/EditorToolbelt.swift | Makes toolbar work for any editable buffer; adds Tafla toggle + Share button. |
| Pensieve/Sources/Pensieve/App/DocumentWindowRegistry.swift | Adds window/tab registry to merge/activate windows and close empty launcher windows. |
| Pensieve/Sources/Pensieve/App/DocumentWindowModel.swift | Adds per-window persisted preferences (preview reload, table tidy, AI autocomplete). |
| Pensieve/Sources/Pensieve/App/DocumentSharing.swift | Adds Share-sheet routing for file-backed or unsaved buffers. |
| Pensieve/Sources/Pensieve/App/DocumentSession.swift | Adds recovery ID support for untitled buffers and restoration API. |
| Pensieve/Sources/Pensieve/App/DocumentExport.swift | Adds HTML/PDF export flows and filename sanitization. |
| Pensieve/Sources/Pensieve/App/ContentView.swift | Removes custom tab strip; uses toolbar toolbelt and relies on native window tabs. |
| Pensieve/Sources/Pensieve/App/Commands.swift | Refactors commands to focused objects; adds share/export, Tafla toggle, AI autocomplete toggle, tab bar toggle. |
| Pensieve/Sources/Pensieve/App/AppState.swift | Refactors into WorkspaceStore + DocumentWindowModel bridge and adds DocumentRef: Codable. |
| Pensieve/Sources/Pensieve/App/AppController.swift | Adds transcription + agent dispatch integration; multi-window open routing; open-files management; background DB warmup. |
| Pensieve/Sources/Pensieve/App/AgentPromptDispatcher.swift | Adds agent dispatch metadata parsing + launcher protocol + Process-based launcher implementation. |
| Pensieve/scripts/build-ffi.sh | Adds helper script to rebuild/sync UniFFI Swift bridge and the dylib into the repo. |
| Pensieve/Package.swift | Adds system library target and linker flags/rpath for qube_ffi dylib integration. |
| Makefile | Adds install-app target, improves clean robustness, excludes generated file from formatting/lint. |
| docs/index.html | Adds a static project landing page for docs hosting. |
| docs/.nojekyll | Disables Jekyll processing for docs hosting. |
| .gitignore | Updates ignore rules (logs, markdown governance allowlist, tmp/dist/docs exclusions). |
| .github/workflows/ci.yml | Adds GitHub Actions workflow running make test on macOS. |
| .claude/settings.local.json | Removes local Claude permissions file from the repo. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| init( | ||
| engine: VistaEngineProtocol? = nil, | ||
| engineFactory: @escaping EngineFactory = { MockVistaAutocompleteEngine() }, | ||
| debounceNanoseconds: UInt64 = AutocompleteController.defaultDebounceNanoseconds, | ||
| maxTokens: UInt32 = 32 |
| agentPromptLauncher: AgentPromptLaunching = VibecraftedAgentPromptLauncher(), | ||
| agentWorkspaceRoot: URL = URL( | ||
| fileURLWithPath: "/Users/maciejgad/vc-workspace/vetcoders/pensieve"), | ||
| importsFoldersInBackground: Bool = false, |
| final class VibecraftedAgentPromptLauncher: AgentPromptLaunching, @unchecked Sendable { | ||
| static let executablePath = | ||
| "/Users/maciejgad/.local/share/vibecrafted/tools/vibecrafted-current/scripts/vibecrafted" | ||
|
|
| linkerSettings: [ | ||
| .unsafeFlags([ | ||
| "-L", qubeFFILibraryPath, | ||
| "-lqube_ffi", | ||
| "-Xlinker", "-rpath", | ||
| "-Xlinker", qubeFFILibraryPath | ||
| ]) | ||
| ] |
| @printf "$(C_CYAN)[install]$(C_RESET) swapping /Applications/Pensieve.app\n" | ||
| @rm -rf "/Applications/Pensieve.app" | ||
| @ditto "$(APP_BUNDLE)" "/Applications/Pensieve.app" | ||
| @printf "$(C_CYAN)[install]$(C_RESET) relaunching from /Applications\n" |
| let folded = target.folding( | ||
| options: [.diacriticInsensitive, .caseInsensitive], | ||
| locale: .current | ||
| ) |
- Introduce `DebugTrace` for runtime tracing of window and document flow issues, activated via the `PENSIEVE_TRACE=1` environment flag. - Implement `DocumentWindowFactory` to create AppKit-backed document windows with proper lifecycle handling, tab management, and SwiftUI hosting. - Prevent retain cycles and window leaks during tab closure with deferred cleanups. - Add support for bridging SwiftUI toolbars and titles into AppKit windows on macOS 14+.
This pull request introduces several significant improvements and new features to the Pensieve macOS markdown editor, focused on agent prompt dispatching, transcription integration, build and clean process enhancements, and package configuration. The most notable changes are the addition of agent prompt dispatching infrastructure, integration of a transcription panel with new document and agent actions, and improvements to the build system for robustness and CI support.
Agent Prompt Dispatching & Transcription Integration:
AgentPromptDispatcherinfrastructure, enabling dispatching of prompts to an external agent process and parsing its output, along with a newAgentPromptLaunchingprotocol and a concrete implementation (VibecraftedAgentPromptLauncher). This allows the app to send prompts (such as transcriptions) to an external tool and receive structured feedback.TranscriptionTaflaPanelController) intoAppController, with methods to show/hide/toggle the panel and send transcriptions either to the active editor or dispatch them to the agent. The transcription dispatch process is now asynchronous and updates status in the UI. [1] [2] [3]Document and Window Management:
AppController, adding methods for opening/closing files and windows, clearing open files, and improved logic for switching between documents and tabs. This provides a more robust and flexible user experience, especially when handling multiple documents. [1] [2] [3]Build System & CI Improvements:
install-apptarget to theMakefilefor atomically installing the signed.appbundle to/Applications, including safe process quitting and relaunching. Improved thecleantarget to avoid race conditions with live indexers by atomically renaming before deletion.lintandformattargets to exclude generated files from formatting checks, ensuring faster and more reliable linting.ci.yml) that runs tests on pushes and pull requests to themainbranch, improving code quality assurance.Swift Package Configuration:
Package.swiftto support linking with the externalqube_ffilibrary, including dynamic linker flags and a newsystemLibrarytarget forqube_ffiFFI. This sets up the infrastructure for integrating native code via FFI. [1] [2] [3]Other Changes:
.claude/settings.local.jsonpermissions file.References: