Skip to content

feat(desktop): add cross-platform window capture - #8103

Merged
juliusmarminge merged 261 commits into
pingdotgg:mainfrom
Bil0000:feat/window-capture
Sep 8, 2026
Merged

feat(desktop): add cross-platform window capture#8103
juliusmarminge merged 261 commits into
pingdotgg:mainfrom
Bil0000:feat/window-capture

Conversation

@Bil0000

@Bil0000 Bil0000 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Adds opt-in window capture for macOS, Windows, and Linux Wayland.
  • Uses Shift + Shift by default on macOS and Windows. Wayland requires a key chord because its portal does not support modifier-pair shortcuts.
  • Checks T3 Code keybindings, common system and app chords, and live OS registration before a normal key chord can be saved on supported desktop sessions.
  • Requests macOS Accessibility and Screen Recording only when the user turns Window Capture on and the permission is not already granted. Startup only reads permission state.
  • Attaches the image with app name and window title, plus the app icon and accessibility data when they are available.
  • Runs accessibility extraction in a short-lived helper, so a native provider crash or timeout falls back to screenshot-only instead of crashing or blocking T3 Code.
  • Adds a dedicated settings page, command palette entry, onboarding, platform-aware shortcut key caps, inline sound play controls, capture sound, high-density app icons, an early and gentler visual cue, compact image cards, and one-shot attachment animation.
  • Stores pending captures durably and preserves their metadata through drafts, uploads, timeline rendering, and provider input.

Why

Users can add visual and text context from another app without leaving their T3 Code workflow or managing screenshot files. Native behavior stays in the desktop service, while the existing settings, IPC, draft, attachment, and provider paths carry the result.

Platform Details

  • macOS and Windows capture the active window. Linux supports Wayland sessions; X11 sessions are unavailable.
  • macOS permission prompts only run on the off-to-on settings transition. Already-granted permissions do not prompt again.
  • Linux Wayland uses the system portal or the optional GNOME extension and requires a key chord. Portal captures omit accessibility data because the portal does not identify the selected window.
  • Outside Wayland, normal key chords are probed through the OS global-shortcut registry. Wayland submits key chords to the desktop portal without claiming that the desktop accepted them. Modifier-only shortcuts cannot be reserved exclusively by any operating system.
  • Modifier-pair listeners run only while Window Capture is enabled, require both physical keys to be held together, and stop on disable or app shutdown. macOS uses a permission-free polling helper; Windows and Linux use the isolated Node-mode hook.

Demo

CleanShot.2026-08-31.at.3.17.42.mp4

Testing on macOS

  1. Run pnpm dev:desktop, then open Settings > Window Capture.
  2. Turn Window Capture on. Permission requests should appear during this off-to-on change, not at startup or on the first capture.
  3. In System Settings > Privacy & Security, allow both T3 Code (Dev).app and the terminal app used to run pnpm (such as Terminal, iTerm, or Warp) in:
    • Accessibility — lets T3 Code identify the active window and attach available text.
    • Screen & System Audio Recording (called Screen Recording on older macOS) — lets T3 Code capture the window image.
      If T3 Code is missing, use the + button to select <repo>/apps/desktop/.electron-runtime/T3 Code (Dev).app.
  4. Fully restart dev mode after changing either permission: stop pnpm dev:desktop with Ctrl+C, then run it again. If macOS offers Quit & Reopen, still restart the terminal command so the dev server and app start together.
  5. Open another app and press both Shift keys together. Confirm T3 Code attaches the image, app name, window title, and available icon and text to the current draft.
  6. Turn Window Capture off and on again. Already-granted permissions must not prompt again.
  7. Check a custom shortcut, each inline sound play button, Capture flash, Capture animations, and Capture window from the command palette.

Verification

  • Focused tests passed for contracts, desktop capture, modifier-pair state, shortcut conflicts, typed IPC, durable delivery, settings support, draft bridge behavior, and timeline rendering.
  • Strict focused lint, formatting, and whitespace checks passed.
  • Contracts, web, server, and desktop type checks passed.
  • Production web, server, and desktop builds passed.
  • Electron desktop smoke test passed with isolated state under Xvfb.
  • Desktop startup was verified with Window Capture and Capture Flash already enabled.
  • Modifier-pair observation and accessibility extraction run outside the Electron main process. Native accessibility crashes, early exits, and timeouts fall back to screenshot-only; source thumbnails remain memory-bounded.
  • The capture flash uses renderer-free native windows on macOS and Windows. Linux uses a short-lived renderer fallback. Every flash timer and window is destroyed after playback.
  • The desktop bundle keeps uiohook-napi as a packaged runtime dependency with prebuilt macOS, Windows, and Linux binaries for the supported CPU architectures.

Checklist

  • One user workflow
  • Cross-platform behavior is explicit
  • Permission timing is explicit
  • UI evidence is included
  • Focused tests and builds pass

Generated by GPT-5.6-sol in T3 Code using the Codex harness.

Note

Add cross-platform window capture (SnapShots) to desktop app

  • Adds native capture backends for macOS (screencapture), Windows (forked xa11y worker), and Linux (GNOME extension, KDE KWin script, Hyprland Wayland, Niri IPC, and portal fallback)
  • Introduces DesktopSnapShot service with IPC handlers for state, setup, permissions, config preview/apply, shortcut registration, and capture delivery; renderer bridge methods and lifecycle events are added to the contracts package
  • Adds accessibility extraction via a warm-pooled Electron child process, with bounded text and structured element-tree results scaled to compressed image dimensions
  • Adds web settings page at /settings/snap-shot, setup wizard, shortcut recorder with physical-key layout handling, capture animation coordinator, snapshot attachment rendering in composer and timeline, and snapshot source/accessibility metadata in provider prompts
  • Builds and stages Linux native capture helpers (KDE, Hyprland) per architecture, bundles the GNOME extension, and disables Windows ASAR smart unpacking so only native binaries are unpacked
  • Risk: bumps Electron from 43.4.1 to 44.1.0 (apps/desktop/package.json); patches dbus-next@0.10.2 to use Node native Unix sockets instead of usocket (patches/dbus-next@0.10.2.patch); root route now redirects authenticated desktop sessions requiring setup to /settings/snap-shot (apps/web/src/routes/__root.tsx)

Macroscope summarized 07c887d.

Summary by CodeRabbit

  • New Features
    • Added desktop SnapShots for capturing application windows and attaching them to drafts.
    • Added capture setup and preferences for shortcuts, accessibility data, sounds, flash, and animations.
    • Added support across Windows, macOS, and Linux desktop environments, including setup guidance and fallbacks.
    • Added capture metadata, accessibility inspection, previews, and animated delivery into the composer.
    • Added a “Take snapshot” command and dedicated SnapShots settings section.
  • Bug Fixes
    • Improved keyboard shortcut recognition and desktop window focusing.
    • Improved capture delivery reliability and attachment metadata preservation.
  • Documentation
    • Added user and Linux capture documentation.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: b89b0292-7355-41c8-9420-68f886f4056f

📥 Commits

Reviewing files that changed from the base of the PR and between cbfd64c and 994d8c8.

📒 Files selected for processing (18)
  • apps/desktop/src/electron/ElectronWindow.test.ts
  • apps/desktop/src/electron/ElectronWindow.ts
  • apps/desktop/src/electron/WindowsForegroundFocusWorker.test.ts
  • apps/desktop/src/electron/WindowsForegroundFocusWorker.ts
  • apps/desktop/src/snapShot/CaptureShortcutConfig.test.ts
  • apps/desktop/src/snapShot/LinuxSnapShot.dbus.test.ts
  • apps/desktop/src/snapShot/RegionSnapShot.test.ts
  • apps/desktop/src/snapShot/RegionSnapShot.ts
  • apps/desktop/src/snapShot/SnapShotAccessibilityProcess.test.ts
  • apps/desktop/src/snapShot/SnapShotAccessibilityProcess.ts
  • apps/desktop/src/snapShot/captureConfigEdit.test.ts
  • apps/desktop/src/snapShot/captureConfigKdl.ts
  • apps/server/src/provider/Layers/ProviderService.test.ts
  • apps/web/src/components/settings/SnapShotSetupDialog.logic.test.ts
  • apps/web/src/components/settings/SnapShotSetupDialog.logic.ts
  • docs/internals/linux-snap-shot.md
  • docs/user/snap-shot.md
  • native/kde-snap-shot/src/main.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • native/kde-snap-shot/src/main.rs

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

This pull request adds a "SnapShots" window-capture feature for the desktop app. It provides shared contracts, native capture backends for macOS, Windows, GNOME, KDE, Hyprland, and Niri, IPC and preload wiring, a GNOME Shell extension, Rust helper binaries, web composer and settings UI, provider prompt handling, packaging, and documentation.

Changes

SnapShot window capture feature

Layer / File(s) Summary
Shared contracts and schemas
packages/contracts/src/ipc.ts, orchestration.ts, settings.ts, *.test.ts
Adds snapshot state, source, accessibility-tree, and shortcut schemas plus DesktopBridge methods used across the feature.
Dependencies and build packaging
apps/desktop/package.json, pnpm-workspace.yaml, package.json, scripts/build-desktop-artifact.ts, apps/desktop/vite.config.ts
Adds native capture dependencies, workspace overrides, and packaging rules for capture helpers and worker bundles.
Electron launcher and Linux startup identity
apps/desktop/scripts/electron-launcher.mjs, apps/desktop/src/app/*
Updates macOS launcher signing and environment handling. Adds Linux desktop-entry identity resolution used before app readiness.
Desktop IPC handlers, preload bridge, and renderer dispatch
apps/desktop/src/ipc/..., apps/desktop/src/window/DesktopWindow.ts, apps/desktop/src/preload.ts, apps/desktop/src/main.ts
Adds snapshot IPC channels and methods, preload bridge methods, bootstrap wiring, and reveal/ready dispatch for captured windows.
Windows foreground focus, icon extraction, and clipboard helpers
apps/desktop/src/electron/*, apps/desktop/src/preview/Manager.ts
Adds Windows window activation, an accessibility focus worker, native icon extraction, and asynchronous clipboard writes.
DesktopSnapShot core service and platform capture
apps/desktop/src/snapShot/DesktopSnapShot.ts, MacSnapShot.ts, RegionSnapShot.ts, SnapShotAccessibility*.ts, SnapShotTransition.ts, NativeCaptureFeedback.ts, shortcut process files
Implements the core Effect service, macOS/region capture, accessibility extraction, animation overlay, and shortcut worker processes.
Linux capture backends (portal, GNOME, KDE, Hyprland, Niri)
apps/desktop/src/snapShot/LinuxSnapShot.ts, PortalCaptureShortcut.ts, GnomeCaptureSetup.ts, KdeSnapShot.ts, HyprlandSnapShot.ts, NiriSnapShot.ts, captureConfigEdit.ts, captureConfigKdl.ts
Adds Linux backend selection, D-Bus portal and GNOME integration, KDE/Hyprland/Niri capture, and config-file shortcut editing.
GNOME Shell extension
apps/desktop/gnome-extension/*
Adds the bundled GNOME Shell extension for D-Bus capture and animated feedback on GNOME Wayland.
Native Rust capture helpers (Hyprland, KDE)
native/hyprland-snap-shot/*, native/kde-snap-shot/*
Adds standalone Rust binaries and protocol/QML files for Hyprland and KDE window export and feedback overlays.
Web composer capture attachment and animation flow
apps/web/src/components/chat/*, apps/web/src/components/desktop/SnapShotCoordinator.tsx, composerDraftStore.ts, apps/web/src/lib/snapShotAnimation.ts, desktopSnapShot.ts
Delivers captures into the composer, animates arrival, renders attachment details, and persists snapshot sources.
Web SnapShots settings and setup wizard
apps/web/src/components/settings/SnapShot*.tsx, useSnapShotShortcutRecorder.tsx, keybindings.ts, settingsSearch.ts, ui/wizard-steps.tsx
Adds the SnapShots settings page, setup wizard, shortcut recorder, search entries, and a shared wizard-steps component.
Provider prompt handling and client settings persistence
apps/server/src/provider/Layers/ProviderService.ts, Normalizer.ts, apps/web/src/hooks/useSettings.ts
Compacts accessibility trees in provider prompts, persists snapshot source metadata, and fixes settings-persistence ordering.
Documentation
docs/internals/linux-snap-shot.md, docs/user/snap-shot.md, docs/README.md
Adds internal Linux capture design docs and a user-facing SnapShots guide.

Estimated code review effort: 5 (Critical) | ~180 minutes

Merge Risk: 🟡 Moderate · up to 994d8

SnapShots adds cross-platform capture and provider context handling, but unresolved risks remain around untrusted captured text reaching provider input, captures attaching to the wrong draft, stalled native operations, and platform shortcut or build behavior. These issues should be resolved or explicitly accepted before merge.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DesktopSnapShot
  participant LinuxSnapShot
  participant CaptureBackend
  participant SnapShotCoordinator
  participant ComposerDraftStore

  User->>DesktopSnapShot: trigger shortcut or command
  DesktopSnapShot->>LinuxSnapShot: captureLinuxWindow(appId)
  LinuxSnapShot->>CaptureBackend: capture via portal/GNOME/KDE/Hyprland/Niri
  CaptureBackend-->>LinuxSnapShot: PNG plus window metadata
  LinuxSnapShot-->>DesktopSnapShot: LinuxWindowSnapshot
  DesktopSnapShot->>DesktopSnapShot: persistCapture(png, metadata)
  DesktopSnapShot->>SnapShotCoordinator: dispatch snap-shot-ready
  SnapShotCoordinator->>DesktopSnapShot: listPendingSnapShots / readSnapShot
  SnapShotCoordinator->>ComposerDraftStore: addImage(source)
  SnapShotCoordinator->>DesktopSnapShot: acknowledgeSnapShot(id)
Loading
sequenceDiagram
  participant WebSettingsUI
  participant DesktopBridge
  participant DesktopSnapShot
  participant GnomeCaptureSetup
  participant PortalCaptureShortcut

  WebSettingsUI->>DesktopBridge: setupSnapShot(action)
  DesktopBridge->>DesktopSnapShot: setup(action)
  DesktopSnapShot->>GnomeCaptureSetup: perform(install-extension)
  GnomeCaptureSetup-->>DesktopSnapShot: extension state
  DesktopSnapShot->>PortalCaptureShortcut: configure()/bind shortcut
  PortalCaptureShortcut-->>DesktopSnapShot: PortalShortcutState
  DesktopSnapShot-->>DesktopBridge: DesktopSnapShotState
  DesktopBridge-->>WebSettingsUI: updated snapshot state
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.75% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 163 functions across 92 files. (2 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary change: cross-platform desktop window capture.
Description check ✅ Passed The description explains what changed, why it changed, platform behavior, UI impact, testing, and verification. It includes demo evidence and checklist coverage, so it is sufficiently complete despite…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 6.75% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 163 functions across 92 files. (2 skipped: 2 unsupported.)

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Aug 24, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the new Effect service (apps/desktop/src/windowCapture/DesktopWindowCapture.ts), its IPC methods, layer wiring, and contract additions. Module shape (namespace imports, Context.Service with inline interface, exported make/layer, dependencies acquired via yield*) follows the conventions; the Effect.runPromiseWith bridge for the Electron globalShortcut callback matches the existing desktop native-callback pattern. Two error-modeling issues below.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated
Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated
Comment thread apps/web/src/components/desktop/WindowCaptureCoordinator.tsx Outdated
Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated
Comment thread apps/web/src/components/desktop/WindowCaptureCoordinator.tsx Outdated
Comment thread packages/contracts/src/ipc.ts Outdated
Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated
Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

UI consistency review

Two findings, both in the new window-capture UI.

  1. apps/web/src/index.css introduces a global rule keyed on the class trio .animate-in.fade-in.zoom-in-95, which does not exist as a utility in this project. The repo's established pattern (see ComposerStashBadge/prompt-stash-count-enter) is keyframes in index.css plus an animate-[…] utility at the owner. As written, the unlayered global rule wins over Tailwind's layered animate-none, so the call-site motion-reduce:animate-none is inert (reduced motion only works because of the duplicated media query), duration-200 never affects the animation, and any future element combining those class names silently inherits this animation.

  2. WindowCaptureSettings records a shortcut on a Button without the data-keybinding-capture opt-out that app-level shortcut handlers check, so global capture-phase handlers (e.g. sidebar.toggle in AppSidebarLayout) consume the keypress before the recorder sees it.

Details inline.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/chat/ChatComposer.tsx Outdated
Comment thread apps/web/src/index.css Outdated
Comment thread apps/web/src/components/settings/WindowCaptureSettings.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a large cross-platform window-capture product workflow with new native helpers, desktop integrations, persistence, provider routing, UI, and release packaging. It also changes product defaults and static-analysis directives, making the scope and operational risk unsuitable for automatic approval.

Not approved because:

  • Per-review cost limit exceeded (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings, or comment @macroscope-app review this PR to bypass the limit and review now. You can add or adjust custom eligibility rules. Learn more.

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Window capture UI review: one new finding on WindowCaptureOnboardingDialog (dialog body bypasses the DialogPanel contract). The three findings from the previous run (index.css .animate-in.fade-in.zoom-in-95 global override, the matching ChatComposer class string, and the missing data-keybinding-capture on the shortcut recorder) are unchanged in this head commit and are not re-posted.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/desktop/WindowCaptureOnboardingDialog.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

UI consistency review of the web-side window capture surfaces. Four findings, all on newly added lines; the three items flagged in the previous run (global .animate-in override, call-site animation ownership, and the missing data-keybinding-capture marker) are resolved in this revision.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/chat/WindowCaptureAttachmentDetails.tsx Outdated
Comment thread apps/web/src/components/desktop/WindowCaptureOnboardingDialog.tsx Outdated
Comment thread apps/web/src/components/desktop/WindowCaptureOnboardingDialog.tsx Outdated
Comment thread apps/web/src/components/settings/WindowCaptureSettings.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

UI consistency review of the window-capture web surfaces. Two findings on the new settings page; the composer/timeline attachment cards, the onboarding dialog, the keyframe ownership, and the command palette action all follow the existing primitives and conventions.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/WindowCaptureSettings.tsx Outdated
Comment thread apps/web/src/components/settings/WindowCaptureSettings.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the web UI surface of this feature (composer/timeline capture cards, capture settings page, onboarding dialog, command palette entry, keyframe ownership). The earlier findings on the window-capture-card-enter keyframe ownership, data-keybinding-capture, DialogPanel composition, capability gating of the onboarding dialog, and the disabled state of the sound/flash/animation switches are all resolved. Two remaining items below.

Still open from earlier reviews (not re-posted): the shortcut recorder still preventDefault()s Tab so focus cannot leave the button, and WindowCaptureAttachmentDetails still anchors its title to text-foreground while rendering on bg-background/70 inside the text-message-foreground bubble.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/desktop/WindowCaptureCoordinator.tsx Outdated
Comment thread apps/web/src/components/chat/ChatComposer.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One consistency finding on the new window-capture web code. Previously flagged items (recorder Tab handling, data-keybinding-capture, disabled-state parity for the feedback switches, capability gating on the onboarding dialog, DialogPanel composition, and the named window-capture-card-enter keyframes) all look resolved at this head.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/desktop/WindowCaptureCoordinator.tsx Outdated
Comment thread apps/web/src/components/desktop/WindowCaptureCoordinator.tsx Outdated
Comment thread apps/web/src/components/desktop/WindowCaptureCoordinator.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the changed web UI surfaces (window-capture settings page, onboarding dialog, composer/timeline attachment cards, command palette entry, index.css keyframe). Earlier rounds' items (shared focus-event constant, DialogPanel composition, data-keybinding-capture, Tab handling, named keyframe animation, uniformly gated switches) all look resolved. Two remaining consistency points on the new settings page.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/WindowCaptureSettings.tsx Outdated
Comment thread apps/web/src/components/settings/WindowCaptureSettings.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two findings on the settings surface introduced/changed here. The composer and timeline capture cards, the extracted SettingsUnavailableGroup, the keyframe ownership, and the onboarding dialog composition all look consistent with the existing primitives now.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/settings/settingsLayout.tsx
Comment thread apps/web/src/components/settings/WindowCaptureSettings.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One consistency finding on the new window-capture attachment card; everything else (settings layout group, dialog composition, keyframe ownership, palette action) matches the existing contracts.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/chat/ChatComposer.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One error-modeling finding on the new DesktopWindowCapture service. The rest of the service (namespace imports, make/layer exports, dependency acquisition via yield*, native-callback runPromiseWith boundary, structured tagged error with cause) follows the conventions.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated
Comment thread apps/desktop/scripts/electron-launcher.mjs

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the Effect service changes in apps/desktop/src/windowCapture/DesktopWindowCapture.ts, the new IPC methods, layer wiring in main.ts, and the contracts schemas. Service definition order, namespace imports, make/layer export shape, and dependency acquisition via yield* Foo.Foo all look correct. Two error-modeling conventions are still not met in the capture error path.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated
Comment thread apps/desktop/src/windowCapture/DesktopWindowCapture.ts Outdated
Bil0000 and others added 7 commits September 5, 2026 10:06
…indow-capture

# Conflicts:
#	apps/web/src/components/settings/IntegrationsSettings.tsx
#	pnpm-lock.yaml
…ngs.ts

knip flagged DEFAULT_SNAP_SHOT_SOUND and DEFAULT_SNAP_SHOT_SHORTCUT as unused
exports. Both are only consumed by the schema defaults in the same file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Fixed the three audit findings in ae6cc08:

  • Capture acknowledgement now waits for verified draft persistence. A rejected storage write keeps the native capture available for retry, without duplicating the attachment.
  • Captures keep their existing draft destination independently of animation state. Navigation, blur, and disabled animations no longer redirect delayed captures to a different thread or environment.
  • Delivery and stash compression now rescale accessibility bounds and image dimensions together. Restored attachments retain coordinates that match their image.

Validation: 255 focused tests passed across snapshot delivery, the composer draft store, image compression, and desktop capture. Web and desktop typechecks passed. Targeted lint completed with warnings on unchanged code. No live capture or browser verification was performed.

Model: GPT-6. Harness: Codex.

…thout accessibility

Native app names and window titles are unbounded, so a long label failed
schema decoding and dropped an otherwise valid capture. Truncate them to
the contract limits before persisting. The provider prompt also skipped
the app name and title whenever no accessibility data was available;
send them regardless.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
juliusmarminge and others added 6 commits September 7, 2026 15:11
The palette path captured the previous app by hiding T3 Code, which
needed a second capture target and a window hide/show dance, and it
skipped the enabled check, so a fresh install with SnapShots off could
trigger the macOS Screen Recording prompt from the palette. The
shortcut is the one way in.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
get-windows and every dbus-next module were static imports of the
snapshot service, so macOS and Windows loaded a D-Bus client at boot and
Linux paid for node-pre-gyp even with SnapShots off. Both now load at
their use sites. The pure Linux helpers (session detection, Niri binding
text, portal key mapping, PNG reading) move to linuxCaptureSession.ts so
nothing D-Bus-flavoured is reachable from main.ts statically.

Also stop re-registering the global shortcut on every client-settings
save. Only the enabled flag, the accessibility toggle, and the shortcut
itself decide which listener runs; a font-size change no longer kills
and respawns the macOS poller or the Windows keyboard hook. The macOS
permission-recovery path forces a re-registration explicitly.

Tests: drop the palette and hidden-window cases, the icon fallback-order
and error-copy tests, and assertions on executeJavaScript source
strings. Add coverage that an unrelated setting keeps the shortcut and
that capture fails closed while disabled without touching native APIs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ElectronWindow started a worker thread that imports the xa11y native
module at construction, and every reveal on Windows loaded ffi-rs and
opened user32. Users who never capture paid both at launch. The worker
now starts on the first capture reveal, and only a window that had
prepareReveal called on it takes the Win32 foreground path; ordinary
reveals keep Electron's native behaviour from main.

Renderer events are sent before the reveal runs and the reveal is best
effort, so a foreground refusal on Windows no longer drops the message
or duplicates it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Release builds compiled the KDE and Hyprland helpers unconditionally
while only installing Rust on a resource-monitor cache miss. Cache both
binaries keyed on their crate sources, skip the build on a hit, and keep
the toolchain step when either cache misses. The Rust CI job now formats
and tests all three crates.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The user guide narrated UI states, env vars, D-Bus versions, and tool
binaries. It now explains how to turn the feature on, capture, change
the shortcut, and what each Linux desktop needs. The internals page
kept only cross-component traps a maintainer would otherwise rediscover.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Five prefixed strings rode the generic menu-action channel and were
parsed by prefix in the renderer, next to a separate ready channel. One
DesktopSnapShotEvent union now carries requested, started, ready, failed,
and shortcut-changed, and only started reveals the window.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Pushed seven commits on top of ae6cc08 addressing the audit:

  • Palette action removed. It skipped the enabled check, so a fresh install with SnapShots off could get the macOS Screen Recording prompt from the palette, and it needed a second capture target plus a window hide/show dance. The shortcut is now the only way in (aafd0d1).
  • Nothing native on the startup path. get-windows and every dbus-next module were static imports of the snapshot service. They are dynamic at their use sites now, and the pure Linux helpers moved to linuxCaptureSession.ts so nothing D-Bus-flavoured is statically reachable from main.ts. On Windows the xa11y focus worker starts on the first capture reveal instead of at construction, and only capture reveals take the ffi-rs foreground path (7bc2113, c4000a3).
  • Unrelated setting saves no longer restart the shortcut hook. Only the enabled flag, the accessibility toggle, and the shortcut itself trigger re-registration.
  • Renderer events are sent before the reveal, and the reveal is best effort, so a foreground refusal on Windows no longer drops or duplicates the message.
  • Release CI caches the KDE and Hyprland helper binaries and only installs Rust when a cache misses. The Rust CI job formats and tests all three crates (8dd75a3).
  • Docs cut from 685 lines to about 170 (5e0bb76).
  • Typed event channel replaces the five snap-shot-* menu-action strings (bfb2e42).
  • Tests: dropped palette, hidden-window, icon-fallback-order, error-copy, and executeJavaScript source-string assertions. Added coverage that an unrelated setting keeps the shortcut and that capture fails closed while disabled without touching native APIs.

The Electron 44 bump is split out as #10591 so this PR can rebase onto it. Still open from the audit: the dbus-next abstract-socket break from the usocket override, and the dependency footprint (get-windows and uiohook-napi are candidates for small vendored replacements; WindowsWindowIcon.ts can drop in favour of app.getFileIcon).

Focused tests: 1005 passed across desktop snapshot, IPC, electron, window, web coordinator, settings, palette, and contracts. Desktop, web, and contracts typecheck clean. No live capture or browser verification.

Model: Claude Fable 5.1. Harness: Claude Code.

juliusmarminge and others added 2 commits September 7, 2026 15:37
The workspace override drops usocket from dbus-next because we never
pass Unix descriptors, but upstream only falls back to net for
unix:path= addresses. Sessions whose bus lives on an abstract socket,
which is what dbus-launch produces outside systemd, threw on require.
Patch the abstract branch to use net with the NUL prefix Node supports.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
get-windows brought node-pre-gyp, a GitHub-downloaded Windows addon, and
an ad-hoc-signed Mach-O spawned per capture, for one function. The
snapshot service now resolves the foreground window itself: a short
osascript JXA lookup on macOS and seven Win32 calls through the ffi-rs
loader we already ship on Windows.

uiohook-napi installed a system-wide keyboard hook from a single-maintainer
package for the Windows modifier-pair shortcut. The forked listener now
polls GetAsyncKeyState at 20 Hz, mirroring the macOS design.

xa11y no longer loads in the main process. Windows region capture runs in
a forked RegionSnapShotWorker with a warm standby and a deadline, and the
in-process UIA focus fallback is gone; the worker thread covers that path.
WindowsWindowIcon.ts is dropped in favour of app.getFileIcon, which was
already the fallback.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Two more commits from the dependency audit:

  • e4c5de0 patches dbus-next so unix:abstract= session buses connect through net now that usocket is removed. Smoke-tested: an abstract address no longer throws on require, it connects and gets a normal socket error when no daemon is present.
  • 7520bc9 drops get-windows and uiohook-napi and moves every xa11y load out of the main process.
    • Foreground window lookup is now ActiveWindow.ts: an osascript JXA call on macOS (verified against this machine, it returns the frontmost app's layer-0 window with bundle id and path) and seven Win32 calls through the ffi-rs loader we already ship on Windows.
    • The Windows modifier-pair listener polls GetAsyncKeyState at 20 Hz in the same forked child, mirroring the macOS design. No system-wide keyboard hook.
    • Windows region capture runs in a new forked RegionSnapShotWorker with a warm standby and a deadline. The in-process UIA focus fallback is gone; the worker thread already covered that path. WindowsWindowIcon.ts is dropped in favour of app.getFileIcon.
    • Net: two fewer runtime deps, no install-time build scripts left for the feature, and the built main.cjs has zero static references to xa11y, dbus-next, ffi-rs, get-windows, or uiohook.

Remaining runtime deps for the feature are @crowecawcaw/xa11y (children and worker only) and ffi-rs (already on main via fff-node), plus dbus-next on Linux. 742 focused tests pass; desktop, web, and scripts typecheck clean. The desktop bundle builds with the three worker entries. Windows and Linux paths are tested with fakes only; I have no Windows or Linux box to run them live.

Model: Claude Fable 5.1. Harness: Claude Code.

juliusmarminge and others added 4 commits September 7, 2026 15:58
The patch now removes usocket from dbus-next's manifest and routes both
unix:path= and unix:abstract= connections through net, so the unix:path=
branch no longer attempts a doomed require on every connect. The
workspace override stays because pnpm resolves from the registry
manifest, not the patched one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…indow-capture

# Conflicts:
#	apps/desktop/src/app/DesktopLinuxUrlHandler.ts
Main now gates desktop exports with knip. Three helpers introduced by
this branch were exported without an external importer.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@juliusmarminge
juliusmarminge merged commit 299404a into pingdotgg:main Sep 8, 2026
26 checks passed
aorwall added a commit to aorwall/t3code that referenced this pull request Sep 8, 2026
Merges `pingdotgg/t3code` `8b2838e0e..a37c664` — 43 commits.

`343` files landed against `343` changed in the upstream range; fork
delta `723` files. Exact match, so nothing upstream changed was dropped.

Details in
[`docs/fork/upstream-merge-log.md`](../blob/merge/upstream-2026-09-08/docs/fork/upstream-merge-log.md).

## Two fork deltas this merge had to re-apply

**Upstream split the server-update banner into two routes.** pingdotgg#10596
added `useAutoBalanceUpdateBanner` beside the single-machine condition
the fork already gates. The conflict was on the first line only, so
resolving it correctly still left the auto-balance route ungated — an
auto-balanced project would have been offered `npx t3` against a backend
that does not implement `server.updateServer`.
`FEATURES.serverUpdateBanner` now carries two gates in `ChatView.tsx`.

**A new settings page needs a gate even though it degrades politely.**
pingdotgg#8103 added `/settings/snap-shot` for desktop window capture. Every
control drives `window.desktopBridge`, and upstream renders an
"unavailable" notice rather than hiding the page, so a hosted build
listed a sidebar section and six searchable rows for a feature it can
never run. Gated with `FEATURES.snapShots`.

Two smaller fixes: `packages/moatless-api` still ran `tsgo --noEmit`
after upstream replaced `@typescript/native-preview` with TypeScript
7.0.2, and `duplicate-adds.mjs` now skips `pnpm-lock.yaml` (it read
`iconv-lite: 0.6.3` as taken twice; `d3-dsv` and `encoding` each declare
it).

## Usable as-is

- Stop-thread keybinding command (pingdotgg#4308).
- Project import tolerates servers that predate the git-identity scan
(pingdotgg#10547).
- Proactive panels open when entering a thread (pingdotgg#10610); pull-request
markdown links open in the panel (pingdotgg#10623); markdown images navigate as
galleries (pingdotgg#10625); pull-request videos play inline (pingdotgg#10617).
- Settings project scopes are searchable and scrollable (pingdotgg#10570); ref
picker stays steady when opening (pingdotgg#9472); sidebar timer uses
`tabular-nums` (pingdotgg#10592); popup triggers stay steady when pressed
(pingdotgg#9468); settled PR colors restore on hover (pingdotgg#10023).
- Composer Fast mode persists across new chats (pingdotgg#2981); inserted
citations are removed on cancel (pingdotgg#10518).
- TypeScript 7.0.2 (pingdotgg#10663) and the knip desktop-export rules (pingdotgg#10269).

## Unsupported in Moatless / needs implementation

- **Cross-platform window capture** (pingdotgg#8103) —
`apps/desktop/src/snapShot/**`,
`apps/web/src/components/settings/SnapShotSettings.tsx`,
`apps/web/src/lib/desktopSnapShot.ts`. Needs an Electron
`window.desktopBridge`; a browser tab has none. Gated behind
`FEATURES.snapShots` in this PR.
- **Auto-balance server update** (pingdotgg#10596) —
`apps/web/src/components/chat/useAutoBalanceUpdateBanner.tsx`. Needs
`server.updateServer`, which Moatless does not dispatch. Gated behind
`FEATURES.serverUpdateBanner` in this PR.
- **Preview recording transfer** (pingdotgg#10572) —
`apps/server/src/mcp/toolkits/preview/handlers.ts`,
`apps/web/src/browser/browserRecordingUpload.ts`. Moves a finished
preview recording into the agent environment over the desktop bridge.
Adds four error types to `packages/contracts/src/previewAutomation.ts`
and no new RPC method, so no union changed. Sits behind the
`previewAutomation.connect` / `focusHost` / `respond` gap already in the
register.
- **Local media linked from remote threads** (pingdotgg#10619) and **browser
editing shortcuts** (pingdotgg#10621) — Electron shell only.
- **iOS Keychain access group** (pingdotgg#3665) and the mobile provider account
badge (pingdotgg#9899) — the fork ships no mobile build against Moatless.

## Backend behavior to consider reproducing in Moatless

- **Name the usage limit and its reset instead of relaying "out of
credits"** (pingdotgg#10473, `apps/server/src/provider/**` Codex adapter).
Moatless owns its provider runtime, so the clearer limit message has to
be produced there.
- **Report usage limits on retried turns** (pingdotgg#10549, Claude adapter). A
retry currently loses the limit signal; same ownership.
- **Disable executable capabilities in Claude metadata generation**
(pingdotgg#4169, `apps/server/src/textGeneration/ClaudeTextGeneration.ts`). Title
and metadata generation should not be able to run tools. Worth mirroring
wherever Moatless generates thread titles.

## Verification

`verify.mjs`: duplicate-adds, tripwires, resolution-check,
unsupported-methods (0 ADD, 0 DROP, 2 KEEP), fmt, lint and typecheck all
pass.

Tests pass except `@t3tools/desktop`, which cannot compile
`scripts/browser-secret-native.test.mjs` because the sandbox has no
`libsecret-1` — 1283 tests pass, 0 fail, and the file is byte-identical
to upstream. New entry in `docs/fork/gaps.md`. `t3` failed
`GrokAdapter.test.ts` once under parallel load and passes 42/42 alone.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
Moatless task:
https://moatless.soaplabstest.com/tasks/6d8ea486-2fcb-4c25-bd34-dcd15cc4a7ac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants