Skip to content

Enhance editor features, improve performance, and fix bugs#6

Open
Szowesgad wants to merge 61 commits into
mainfrom
fix/broken-native-toolbar-and-others
Open

Enhance editor features, improve performance, and fix bugs#6
Szowesgad wants to merge 61 commits into
mainfrom
fix/broken-native-toolbar-and-others

Conversation

@Szowesgad

Copy link
Copy Markdown

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:

  • Added the AgentPromptDispatcher infrastructure, enabling dispatching of prompts to an external agent process and parsing its output, along with a new AgentPromptLaunching protocol and a concrete implementation (VibecraftedAgentPromptLauncher). This allows the app to send prompts (such as transcriptions) to an external tool and receive structured feedback.
  • Integrated a new transcription panel (TranscriptionTaflaPanelController) into AppController, 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:

  • Refactored document and window management in 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:

  • Added a new install-app target to the Makefile for atomically installing the signed .app bundle to /Applications, including safe process quitting and relaunching. Improved the clean target to avoid race conditions with live indexers by atomically renaming before deletion.
  • Updated the lint and format targets to exclude generated files from formatting checks, ensuring faster and more reliable linting.
  • Introduced a GitHub Actions CI workflow (ci.yml) that runs tests on pushes and pull requests to the main branch, improving code quality assurance.

Swift Package Configuration:

  • Enhanced Package.swift to support linking with the external qube_ffi library, including dynamic linker flags and a new systemLibrary target for qube_ffiFFI. This sets up the infrastructure for integrating native code via FFI. [1] [2] [3]

Other Changes:

  • Removed the .claude/settings.local.json permissions file.
  • Minor bug fixes and code cleanups, such as correcting untitled document title generation and simplifying tab navigation to use native macOS window tab actions. [1] [2]

References:

Szowesgad and others added 30 commits June 3, 2026 08:40
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
Szowesgad and others added 23 commits June 8, 2026 03:53
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).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +66 to +67
static let executablePath =
"/Users/maciejgad/.local/share/vibecrafted/tools/vibecrafted-current/scripts/vibecrafted"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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"
  }

Comment on lines +50 to +51
agentWorkspaceRoot: URL = URL(
fileURLWithPath: "/Users/maciejgad/vc-workspace/vetcoders/pensieve"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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.

Suggested change
agentWorkspaceRoot: URL = URL(
fileURLWithPath: "/Users/maciejgad/vc-workspace/vetcoders/pensieve"),
agentWorkspaceRoot: URL = FileManager.default.homeDirectoryForCurrentUser
.appendingPathComponent("vc-workspace/vetcoders/pensieve"),

Comment on lines +22 to +25
/// 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>?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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.

Suggested change
/// 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()

Comment on lines 41 to +50
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)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Synchronize the synchronous open(into:) method using the recursive lock to prevent data races when called concurrently with background open operations.

Suggested change
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)
}
}

Comment on lines +60 to +89
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
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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
    }
  }

Comment on lines +155 to +161
case .success(let data):
do {
try data.write(to: outputURL, options: .atomic)
finish(.success(()))
} catch {
finish(.failure(error))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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))
            }
          }
        }

Comment on lines +269 to +275
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
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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
}
}

Comment on lines +1653 to +1654
init?(line rawLine: String, baseRelativePath: String) {
var line = rawLine.trimmingCharacters(in: .whitespaces)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
final class AutocompleteController: ObservableObject, @unchecked Sendable {
@MainActor
final class AutocompleteController: ObservableObject {

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +19 to +23
init(
engine: VistaEngineProtocol? = nil,
engineFactory: @escaping EngineFactory = { MockVistaAutocompleteEngine() },
debounceNanoseconds: UInt64 = AutocompleteController.defaultDebounceNanoseconds,
maxTokens: UInt32 = 32
Comment on lines +49 to 52
agentPromptLauncher: AgentPromptLaunching = VibecraftedAgentPromptLauncher(),
agentWorkspaceRoot: URL = URL(
fileURLWithPath: "/Users/maciejgad/vc-workspace/vetcoders/pensieve"),
importsFoldersInBackground: Bool = false,
Comment on lines +65 to +68
final class VibecraftedAgentPromptLauncher: AgentPromptLaunching, @unchecked Sendable {
static let executablePath =
"/Users/maciejgad/.local/share/vibecrafted/tools/vibecrafted-current/scripts/vibecrafted"

Comment thread Pensieve/Package.swift
Comment on lines +37 to 44
linkerSettings: [
.unsafeFlags([
"-L", qubeFFILibraryPath,
"-lqube_ffi",
"-Xlinker", "-rpath",
"-Xlinker", qubeFFILibraryPath
])
]
Comment thread Makefile
Comment on lines +59 to +62
@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"
Comment on lines +84 to +87
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+.
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.

2 participants