electron/backup.ts imported getBackupTimestamp from src/app/util/, which
tsc compiled alongside the source. electron-builder only packages
electron/** and the Angular renderer bundle, so the compiled util was
missing from app.asar and the main process crashed on launch with
"Cannot find module '../src/app/util/get-backup-timestamp'".
Moved the util to electron/shared-with-frontend/ (existing convention
for code shared between main and renderer), updated all importers.
Fixes#7270
Refs #7315, #7323, #7265, #7320
Address findings from code-reviewer + debugger-assistant +
refactor-specialist multi-review on 8e1c47ebc2:
- afterPack: read wrapper source before rename; on writeFile failure,
roll the rename back so a broken intermediate state can't ship a
package with no launcher. Strengthen idempotency check to require a
shebang at binPath (both files alone no longer counts as "installed").
- wrapper: gate the X11 injection on \$SNAP_NAME = "superproductivity",
not just \$SNAP set. An xdg-open from a sibling snap (e.g. Firefox)
leaks \$SNAP into the child env, which previously would have silently
forced XWayland on .deb/.rpm users. Derive BIN_DIR from \$SNAP
directly when we are our snap, avoiding fragile \$0 resolution
through snapd's wrapper chain. Stop argv scanning at -- so positional
args that resemble --ozone-platform aren't misread as a user override.
- app-control: point app.relaunch() execPath at the sibling shell
wrapper instead of the default process.execPath (which is the renamed
ELF and would bypass the flag injection on a relaunched Snap+Wayland
instance).
- Move build/snap-wrapper.sh -> build/linux/snap-wrapper.sh to match
the existing build/linux/ layout convention.
- Update research doc §18 to reflect the tightened predicate and the
relaunch fix.
electron-window-state reads isMaximized() on an already-hidden window in
its `closed` handler, which returns false (electron#27838). Patch the
persisted state file in will-quit using our own wasMaximizedBeforeHide
flag, which is kept accurate by the maximize/unmaximize event listeners.
Defense-in-depth against GPU init failures on Snap/Flatpak Linux where
the main process stays alive but the GPU process crashes at init and
the window never renders. Field data in #7270 (two post-v18.2.4
reports) shows this happens on Ubuntu 24.04+/25.10 regardless of GPU
vendor — the driver is core22 Mesa/libgbm drifted from the host Mesa.
See §12–§17 in docs/research/snap-wayland-gpu-fix-research.md.
Mechanism (electron/gpu-startup-guard.ts):
- Content-based crash marker in userData with {ts, electronVersion}.
Written before app.whenReady() on confined Linux; cleared via
IPC.APP_READY after Angular boot — not ready-to-show, which fires
on blank/broken renderers too.
- Previous-crash detection: marker present AND recent (<5 min) AND
matching Electron version. Staleness bound + version gating drop
systemd-SIGKILL-mid-boot and post-upgrade-residue false-negatives.
- Env overrides SP_DISABLE_GPU=1 / SP_ENABLE_GPU=1 work on all
platforms; auto-detection is Linux+Snap/Flatpak-only.
- Non-ENOENT fs errors logged at warn — a swallowed write-fail
previously meant the guard could re-enter the loop with no
diagnostic trail; a swallowed unlink-fail meant a successful boot
could get permanently stuck in crash-recovery.
Fallback flag bundle (start-app.ts):
--disable-gpu
--disable-software-rasterizer
--ozone-platform=x11
The pair matches Chromium's GPU integration tests' "no GPU process"
invariant; DisplayCompositor handles 2D in the browser process
without spawning a GPU child. app.disableHardwareAcceleration()
alone does NOT — verified against electron/electron#17180/#20702.
The extra --ozone-platform=x11 closes the Chromium 140+
browser-side Wayland/libgbm-dlopen gap on Flatpak (redundant with
the existing Snap X11 widening branch; last flag wins).
Novelty: R3 survey of VS Code, Slack, Insomnia, LosslessCut,
Obsidian flatpak, Firefox snap, and Canonical's gpu-2404-wrapper
found no peer Electron-snap implementing an equivalent reactive
crash-detection + auto-fallback. Prevailing patterns are manual
--ozone-platform=x11, proactive env-sniff, or do-nothing.
Review: §14–§15 multi-agent verification on the original PR #7273;
re-reviewed via 7-agent multi-review (6 Claude focus-agents + Codex
CLI) + 5 research agents here (§17). Live-tested with
SP_DISABLE_GPU=1 on a KDE/X11 dev host — window rendered normally
via DisplayCompositor.
Refs: #7270
The globalShowHide shortcut called mainWin.hide() unconditionally. On
Windows/Linux hide() removes the taskbar entry, so with no tray icon
the window became unreachable.
- macOS: use hide() (dock icon always remains).
- Windows/Linux: hide to tray only when minimize-to-tray is on AND the
tray was created; otherwise minimize() to keep a taskbar handle.
- Log whether Windows tray creation used the GUID path, to help diagnose
cases where the icon lands in the hidden overflow area.
Refs #7282
* fix(issue): prevent crash from orphan issueProviderId (#7135)
The Jira image-headers effect in task-detail-panel subscribed to
selectIssueProviderById without an error handler, so a task with an
issueProviderId pointing at a deleted provider (e.g. after sync
convergence where taskIdsToUnlink didn't cover all local tasks)
propagated the selector throw to Zone.js as a crash dialog. Wrap the
inner selector observable in catchError that logs and falls back to
of(null); the downstream jiraCfg?.isEnabled guard handles the fallback.
Also drop IssueLog.log(issueProviderKey, issueProvider) from the
throwing variant of the selector: providers may carry credentials
(host, token, apiKey) and IssueLog history is exportable.
* fix(focus-mode): sync tray countdown with in-app timer during breaks
Tray title was rebuilt from a cached currentFocusSessionTime that only
refreshed when CURRENT_TASK_UPDATED fired. addTimeSpent is gated on an
active current task, so during focus-mode breaks or task-less focus
sessions the cache froze while the in-app timer kept ticking.
Add the tick action to taskChangeElectron$ so the cache refreshes every
second whenever the focus timer is running.
Fixes#7278
* fix(ci): restore GitHub Actions SHA pins undone by 0e9218bd68
Commit 0e9218bd68 silently reverted PR #7212 (github-actions-minor group
bump) along with its stated sync/client-id work. This restores the 15
workflow files to their pre-revert state.
Actions restored to newer pinned SHAs:
- actions/upload-artifact v7.0.0 -> v7.0.1
- step-security/harden-runner v2.16.1 -> v2.17.0
- softprops/action-gh-release v2.6.1 -> v3.0.0
- signpath/github-action-submit-signing-request v2.0 -> v2.1
- anthropics/claude-code-action v1.0.89 -> v1.0.93
- docker/build-push-action v7.0.0 -> v7.1.0
- easingthemes/ssh-deploy v5.1.1 -> v6.0.3
* fix: restore i18n, UI, and docs work undone by 0e9218bd68
Commit 0e9218bd68 silently reverted the following work alongside its stated
sync/client-id changes. Files where later master commits (fec7b25f23, etc.)
already re-applied the reverted work are intentionally left untouched.
Restored:
- #7232 docs/long-term-plans/location-based-reminders.md (513 lines)
- #7199 Romanian i18n phase 3 (ro.json + ro-md.json, ~1168 lines)
- #7049 Polish translation improvements
- #7143 planner component styling (4 scss files)
- #7211 add-task-bar preserve time estimate when typing title
- #7208 task.reducer roll-up estimates for added subtasks
- #6767 focus-mode pomodoro reset button
- #7205 plugin-dev github-issue-provider TOKEN description
- #7231 mobile-bottom-nav FAB fix
- a4fe03272 iOS keyboard accessory bar (global-theme + dialog-fullscreen-markdown)
- 309670db3 ShortSyntaxEffects undefined guard
- 667a7986f Dropbox PKCE auth comment/behavior
* fix(electron): restore electron + e2e work undone by 0e9218bd68
Commit 0e9218bd68 silently reverted the following electron/e2e work.
Files already re-fixed by later master commits are left as-is:
- e2e/tests/sync/supersync-archive-conflict.spec.ts (de33234976 + 191d129ff3)
Restored:
- e8a3e156eb fix(electron): Linux autostart IDB backing-store recovery
(re-adds electron/clear-stale-idb-locks.ts + start-app.ts wiring)
- 5ce78a5b63 fix(electron): macOS Cmd+Q / Dock > Quit hang
(setIsQuiting + before-quit delegate to close-handler)
- 46e0fa2d01 fix(sync): FILE_SYNC_LIST_FILES IPC contract
(electronAPI.d.ts + local-file-sync + preload + ipc-events)
- ea1ef16307 fix(android): session-only SAF permissions on OEM devices
- 8865dc0a50 test(e2e): supersync parallel-worker stampede guard
(SUPERSYNC_SERVER_HEALTHY env-var fallback + goto retry loop)
- af7c7687e2 test(e2e): block WS-triggered downloads in non-WS specs
- 265b44db5d test(e2e): premature waitForURL on daily-summary
(this is literally the fix the bad commit's message claimed to add)
Conflict resolutions:
- e2e/utils/supersync-helpers.ts: kept the refined getDoneTaskElement
checks from d64014d086 (later than c558bcab5e) while restoring the
goto retry loop from 8865dc0a50.
- electron/start-app.ts: unioned imports (setIsQuiting +
clearStaleLevelDbLocks from theirs, fs from ours).
* fix(sync): restore sync-core work undone by 0e9218bd68
Commit 0e9218bd68 silently reverted parts of several sync fixes. Most
sync-core reverts have already been re-addressed differently on master
by later commits (1f5184f6e7, 05cd875dd6, 09f5ced2c9, 7df43358ab,
d9158d6adb, 32dbc95ed9, 8c3b08e016, f89fe1ebc3) — those files are
intentionally left untouched to avoid reverting master's newer work.
This PR restores only the pieces that are genuinely still missing:
- e8a3e156eb fix(electron): IDB backing-store autoreload (in-app piece)
operation-log-hydrator.service.ts + .spec.ts (the electron/clear-
stale-idb-locks.ts piece was restored in the prior commit)
Plus three low-risk documentation/cleanup restorations:
- operation-sync.util.ts — add "Nextcloud" to isFileBasedProvider JSDoc
- dropbox.ts — restore improved _getRedirectUri JSDoc (667a7986fb)
- dialog-get-and-enter-auth-code.component.ts — restore isNativePlatform
comment explaining why manual code entry flow is used (667a7986fb)
- file-adapter.interface.ts — remove stray "// NEW" comment (46e0fa2d01)
Intentionally NOT restored (master's newer work covers or supersedes):
- sync-trigger.service.ts / sync.effects.ts (05cd875dd6)
- sync-wrapper.service.ts (1f5184f6e7)
- sync-errors.ts (1f5184f6e7 re-added LegacySyncFormatDetectedError)
- file-based-sync-adapter.service.ts + spec (1f5184f6e7 + d9158d6adb)
- file-based-sync.types.ts (1f5184f6e7)
- operation-log.const.ts (32dbc95ed9 bumped IDB_OPEN_RETRIES to 5)
- dialog-sync-initial-cfg.component.ts (f89fe1ebc3)
* docs(research): add Snap + Wayland GPU init failure research
Synthesizes root cause (Mesa ABI drift in gnome-42-2204), scope,
peer-app consensus, and ranked options. Recommends widening the
existing Snap-gated --ozone-platform=x11 guard in start-app.ts to
cover Snap + Wayland sessions, with core24 + gpu-2404 migration
as the long-term fix.
https://claude.ai/code/session_01Hu6EP7Xux9JRvGGGKpBfwm
* docs(research): correct electron timing and soften unverified peer claims
* fix(electron): force X11 on Snap Wayland to avoid Mesa ABI drift
The existing Snap-only X11 fallback triggered only when $SNAP/gnome-platform
was empty. In practice gnome-platform is populated but its Mesa can drift
out of ABI sync with Electron's bundled libgbm, producing
"Failed to get system egl display" and a GPU process respawn loop on
Wayland sessions. Widen the guard to also fire when the session is
Wayland (XDG_SESSION_TYPE=wayland or WAYLAND_DISPLAY set). X11/GLX
avoids the failing Wayland EGL init path entirely while preserving
hardware acceleration.
Refs: electron-builder#9452, super-productivity#5672,
forum.snapcraft.io #40975, #49173https://claude.ai/code/session_01JNxazJmDhpMp9UYV6SqnBG
* refactor(electron): address review feedback on Snap X11 force
- Handle space-separated `--ozone-platform wayland` override in addition
to the `=` form; tighten the argv scan to reject accidental substring
matches (e.g., arg values that happen to contain `--ozone-platform=`).
- Enrich the log line with raw XDG_SESSION_TYPE and WAYLAND_DISPLAY
values to make user-reported triage faster.
- Tighten comment: correct "X11/GLX" to "X11 ozone backend" (modern
Chromium uses EGL on X11), clarify the root cause as Mesa version
drift rather than bundled-library ABI drift, broaden the loss list
beyond fractional scaling, and move issue references to the commit
body per CLAUDE.md guidance.
Follow-ups flagged but not addressed here: possible interaction with
`allowNativeWayland: true` in electron-builder.yaml, GPU cache keyed
by effective ozone platform, and the longer-term core24 migration
already in docs/long-term-plans/electron-upgrade-to-v40.md.
Refs: electron-builder#9452, super-productivity#5672,
forum.snapcraft.io #40975, #49173https://claude.ai/code/session_01JNxazJmDhpMp9UYV6SqnBG
* docs(research): verify peer-app claims, correct SP electron timing
---------
Co-authored-by: Claude <noreply@anthropic.com>
* chore: update electron to v41.1.1
* feat(start-app): clear GPU cache on Electron version change for Linux
* fix(window-decorators): disable custom window title bar for GNOME
This fixes some issues when moving and resizing the window
* refactor: Migrate url.format() (DEP0116) to file:// path approach
* refactor(start-app): remove deprecated protocol.registerFileProtocol in start-app.ts
* feat(electron-builder): update gnome content snap to gnome-42-2204 for improved compatibility and update flatpak permissions
* fix(window-decorators): improve handling of custom window title bar for GNOME
* feat(start-app): implement fallback to X11 in Snap if gnome-42-2204 runtime is unavailable
* chore: update electron to v41.1.1
* chore(package-lock): remove unused dependencies from package-lock.json
* fix(electron): move snap ozone-platform switch before app ready event
app.commandLine.appendSwitch() must be called before Chromium
initializes — after the ready event fires the GPU backend is already
running and the switch is a no-op. Move the Snap X11 fallback (defense-
in-depth for missing gnome-42-2204 runtime) to run synchronously at
startup, alongside the existing gtk-version and speech-dispatcher
switches.
* fix(electron): align IS_GNOME_DESKTOP detection with preload.ts logic
The original implementation only matched Ubuntu's GNOME session
(XDG_CURRENT_DESKTOP contains both 'gnome' AND 'ubuntu'), missing plain
GNOME on Fedora, Arch, etc. The preload.ts isGnomeDesktop() already
used the correct approach: check four environment variables with OR
logic. Align common.const.ts to match, preventing a split-brain where
the main process and renderer disagree on whether the user is on GNOME
— which would produce no title bar at all on non-Ubuntu GNOME desktops.
* fix(electron): restore v41 bump lost in merge and gate title-bar toggle
- Re-apply electron 41.2.0 + minimatch 10.2.5 override (master's 0e9218bd
reverted the dependabot bump back to 37.10.3 while this branch's
merge-base still contained 41.2.0, so the pre-merge diff was empty).
- Regenerate root package-lock.json accordingly.
- Drop unrelated esbuild additions from plugin-dev sub-lockfiles.
- misc-settings-form: gate isUseCustomWindowTitleBar on IS_ELECTRON &&
!IS_GNOME_DESKTOP so the toggle does not appear in the web/PWA build.
---------
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
The "Get Authorization Code" button silently fails on some Linux
packagings (Flatpak, AUR) because shell.openExternal() can reject
without visible feedback — the wasOpened boolean check in
openUrlInBrowser has been dead code since the call was migrated from
shell.openPath to shell.openExternal (which returns Promise<void>).
- Add a "Copy URL" button to the auth dialog as a reliable fallback
users can paste into a manually-opened browser.
- Replace the dead wasOpened check with a .catch() that logs the
rejection reason, so future portal failures surface in electron logs.
- Add regression tests documenting the PKCE verifier/challenge
invariants that make stale auth codes fail with "invalid code
verifier" when the dialog is reopened.
The osascript -e argument used nested unescaped double quotes, causing sh
to split it into multiple tokens so System Events never saw a valid
AppleScript. This has been broken since a 2022 prettier run stripped the
backslash escapes. Use a template literal so the inner quotes survive
formatting, and drop the CGSession path comment since it was removed in
Big Sur and only kept for pre-Big Sur fallback.
Closes#7217
- Separate JsonParseError and SyncDataCorruptedError handlers in sync wrapper
- Handle corrupted remote data gracefully instead of throwing
- Add getOrGenerateClientId() as unified entry point, eliminating dual injection
of ClientIdService + CLIENT_ID_PROVIDER in snapshot-upload, file-based-encryption,
and sync-hydration services
- Use crypto.getRandomValues() instead of Math.random() for client ID generation
- Warn user when stored client ID is invalid and must be regenerated
- Fix flaky e2e supersync tests (premature waitForURL match on daily-summary URL)
Three-layer defense for issue #7191 (Flatpak/Snap/autostart startup race):
1. Increase IDB_OPEN_RETRIES 3→4 (total retry window 3.5s→7.5s) to give
OS/Flatpak storage more time to initialize before giving up.
2. Silent auto-reload on first backing-store error: instead of a blocking
alert that requires user interaction before the reload (bad for autostart
where nobody is watching), reload immediately and only show the manual
recovery dialog if the reload does not fix the problem.
3. Clear stale LevelDB LOCK files in the Electron main process before the
renderer opens IndexedDB. Orphaned locks from unclean session shutdowns
block the backing store open; safe to remove because requestSingleInstanceLock()
already confirmed we are the only running instance.
Fixes https://github.com/super-productivity/super-productivity/issues/7191
On macOS, native quit fires before-quit BEFORE window close events. The
before-quit handler was calling ipcMain.removeAllListeners(), which destroyed
the BEFORE_CLOSE_DONE IPC listener. The close handler then sent NOTIFY_ON_CLOSE
to the renderer (for sync/finish-day callbacks), the renderer responded with
BEFORE_CLOSE_DONE, but the listener was gone — causing a permanent hang.
Fix: intercept before-quit when isQuiting=false and delegate to win.close(),
which re-enters the existing close handler and runs before-close callbacks
normally. Move ipcMain.removeAllListeners() to will-quit, which fires after
all windows are closed and all IPC flows are guaranteed complete.
Also improves close event log to include pending before-close handler IDs.
Add missing IPC handler for file listing used by local-file sync, and fix
preload.ts passing bare dirPath string instead of the expected { dirPath }
object — causing IPC handler to destructure undefined.
When a full-state op (SYNC_IMPORT/BACKUP_IMPORT) arrived from another
client, mergeRemoteOpClocks reset the local clock to a "minimal" form
but only preserved the current client's counter from the incoming op's
clock. If the current client had issued ops (e.g. GLOBAL_CONFIG) not
reflected in the incoming full-state op's clock, its counter was dropped,
causing subsequent ops to reuse the same counter value. Downstream clients
then saw these ops as EQUAL (duplicate) and skipped them silently.
Fix: take max(mergedClock[clientId], currentClock[clientId]) when
rebuilding the clock after a full-state op reset.
Also add __SP_E2E_BLOCK_WS_DOWNLOAD flag to WsTriggeredDownloadService
to allow E2E tests to block automatic WS-triggered downloads during
concurrent conflict scenarios.
Fix archive conflict test by blocking WS downloads on Client A during
the concurrent edit phase so it doesn't auto-receive B's rename via
WebSocket before archiving (restoring the intended conflict scenario).
Fix LWW singleton test to assert convergence rather than specific winner.
Fix renameTask helper to avoid Playwright/Angular re-render races.
Fix shepherd.js import paths that broke the Angular dev server build.
electron-dl v4 is a pure ESM package. Since the Electron main process
is compiled with TypeScript "module": "commonjs", static import() gets
transformed to require() which cannot load ESM. Use Function() to
preserve a real dynamic import() at runtime.
Rename the "overlay indicator" feature to "task widget" across the
entire codebase for clearer naming. Includes file renames, config key
migration, IPC event rename, and translation key updates.
Migration handles old persisted data from both the `overlayIndicator`
config key and the deprecated `misc.isOverlayIndicatorEnabled` field.
The `taskWidget` type is made optional in GlobalConfigState to prevent
Typia auto-fix from overwriting migrated values during upgrade.
* fix(security): harden Local REST API against DNS rebinding and field injection
- Add Host header validation to block DNS rebinding attacks from
malicious websites targeting the localhost API
- Add IS_ELECTRON guard in handler init() for defense-in-depth
- Add allowlist of task fields settable via API (title, notes, isDone,
timeEstimate, timeSpent, projectId, tagIds, dueDay, dueWithTime,
plannedAt) to prevent state corruption via injected internal fields
- Validate source query parameter instead of blind cast
- Add tests verifying disallowed fields are stripped from POST and PATCH
https://claude.ai/code/session_01YJNc4gUCkHHrAAhXJBEaop
* fix: address review findings from daily code review
Security hardening:
- Block cloud metadata endpoints (169.254.169.254, metadata.google.internal)
even when allowPrivateNetwork is true (SSRF protection)
- Add HTTP method allowlist to PluginHttp request() to prevent abuse
- Add rate limiting (max 50 concurrent) to Local REST API
Bug fixes:
- Fix hardcoded 'ICAL' issueProviderKey in calendar effects; use event's
actual provider key with ICAL fallback
- Fix race condition in TimeBlockDeleteSidecarService: push IDs instead
of replacing to prevent data loss on rapid bulk deletes
- Backfill missing issueProviderKey on cached calendar events from
localStorage (backward compatibility)
- Fix btoa(String.fromCharCode(...spread)) overflow for long strings
by using loop-based approach
Minor:
- Cap HiddenCalendarEventsService to 500 entries max (prevent
unbounded localStorage growth)
- Fix misleading "deep clone" comment to "shallow clone"
https://claude.ai/code/session_01YJNc4gUCkHHrAAhXJBEaop
* test: fix unit test failures from review hardening changes
- Replace IS_ELECTRON guard with window.ea?.onLocalRestApiRequest check
in handler init() so tests can mock the API without navigator.userAgent
- Update plugin-http spec to expect "cloud metadata endpoints" error
message (was "private/local") for 169.254.169.254 and metadata.google
- Fix allowlist test expectation: title is an allowed field and passes
through pickAllowedFields as expected
https://claude.ai/code/session_01YJNc4gUCkHHrAAhXJBEaop
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat(electron): add Local REST API for desktop automation
Add a local HTTP server (port 3876) that allows external scripts and
tools to interact with a running Super Productivity desktop app.
Features:
- Task CRUD operations (create, read, update, delete)
- Task control (start, stop, set current)
- Task archive/restore operations
- Query filters for tasks (by title, project, tag, done status)
- Read-only project and tag listing
The API is disabled by default and can be enabled in Settings > Misc.
Only accepts connections from localhost (127.0.0.1) for security.
* fix: resolve lint errors for local REST API
* fix: use lazy injection for LocalRestApiHandlerService
Fixes StartupService tests by using Injector.get() instead of direct
injection, preventing LocalRestApiHandlerService from being instantiated
when StartupService tests don't have NgRx providers.
* fix: resolve markdown lint errors in API docs
* fix: add security warning to Local REST API hint
Google's Desktop OAuth client requires loopback redirect URIs
(http://127.0.0.1:<port>) and blocks embedded webviews. This replaces
the custom URI scheme + BrowserWindow approach with a temporary loopback
HTTP server and shell.openExternal for the system browser.
- Add PLUGIN_OAUTH_PREPARE IPC to start loopback server and return port
- Open auth URL in system browser instead of Electron BrowserWindow
- Make getRedirectUri() async to support IPC port retrieval
- Validate OAuth config before starting loopback server to prevent leaks
- Force 200 status on OPTIONS preflight responses in CORS bypass
* fix: address review findings from daily changes
- Add setPermissionCheckHandler alongside setPermissionRequestHandler
for defense-in-depth in Electron (permission queries now also denied)
- Fix tagIds merge ordering in issue service: provider adapter tags are
now merged with default tags instead of being silently overwritten
- Execute deleteTask action last in automations to prevent subsequent
actions from failing on a deleted task
- Add unit tests for getTaskDefaults logic (TODAY_TAG filtering,
defaultNote, tagIds merging, deduplication, context tags)
- Add test for deleteTask execution ordering in ActionExecutor
https://claude.ai/code/session_01UhoR5g7RQgm4E6bZCvU9PS
* refactor: revert YAGNI changes from review fixes
- Revert tagIds merge in issue.service.ts: no provider currently sets
tagIds in getAddTaskData, so merging solves a hypothetical problem
- Revert deleteTask sort in action-executor: the automations feature is
new and nobody has hit this edge case yet
- Remove tests for reverted behavior, keep tests for existing features
(TODAY_TAG filtering, defaultNote, note override prevention)
https://claude.ai/code/session_01UhoR5g7RQgm4E6bZCvU9PS
---------
Co-authored-by: Claude <noreply@anthropic.com>
Enable webSecurity (same-origin policy) since CORS is already handled at
the session level via onBeforeSendHeaders and onHeadersReceived. Add
setPermissionRequestHandler to deny unnecessary permissions (webcam,
microphone, geolocation). Improve certificate-error logging with warn
level and URL context.
Bundle preload.ts into a single file so all local imports (e.g.
ipc-events.const) are inlined at build time. This allows removing
sandbox: false since the bundled preload only requires the built-in
electron module, which is allowed in sandboxed preloads.
The preload script uses require() for local modules which is not
supported in Electron's sandboxed preload environment (default since
Electron 20). This only affects Electron's preload API restrictions,
not Chromium's OS-level process sandbox which remains active.
Add OAuth support for plugins with PKCE, token persistence in local-only
IndexedDB, and Electron/web redirect handling. Extend two-way sync with
dueDay, dueWithTime, and timeEstimate field mappings including mutually
exclusive field clearing. Support remote issue deletion on task delete
and remote deletion detection during polling.
Add Google Calendar plugin (disabled from bundled builds pending legal
review) as a development reference for the plugin OAuth and two-way
sync APIs.
Additional fixes:
- Restore accidentally deleted focus-mode translation keys
- Remove full Task[] from deleteTasks action to prevent op-log bloat
- Add dueDay/deadlineDay format validation guards (#6908)
- Fix Android reminder alarm cancel intent matching
- Validate dueDay format to prevent false overdue from corrupted data
- Fix PKCE test expectation after utility consolidation
- Make overlay window resizable with persisted bounds via simpleStore
- Add new OverlayIndicatorConfig section (isEnabled, isAlwaysShow, opacity)
- Move setting from misc.isOverlayIndicatorEnabled to overlayIndicator
with migration in reducer
- Add responsive CSS with scale variable (full/tiny modes)
- Add always-show mode that keeps overlay visible when main window is open
- Add opacity slider (10-100%) applied as CSS variable
- Consolidate overlay init into single updateOverlayEnabled path
- Remove dead code: updateOverlayTheme, setIgnoreMouseEvents, unused
shortcut param
Guard the SET_PROGRESS_BAR tray icon update with an _isRunning check so
that late IPC events (e.g. trailing throttle emissions from focus mode)
cannot override the correct stopped icon after a task is unset.
Closes#3410
Previously the 1px border only appeared with the custom title bar
enabled. Now it shows for all Electron windows and is hidden during
fullscreen via IPC-driven body class toggling.
* fix: add proxy env support for jira integration #6324
* refactor(providers): address code review feedback from proxy support for jira provider
* refactor(providers): removed manually setting electron session proxy as settings are automatically picked
---------
Co-authored-by: Thomas Tisch <thomas.tisch@hobex.at>
Suppress noisy "EXITING due to failed single instance lock" message when
a second instance is launched via xdg-open for protocol URL handling.
Register superproductivity:// as a MIME type handler in the .desktop file
so Linux users no longer need manual xdg-settings configuration.
Remove duplicate requestSingleInstanceLock() call in start-app.ts.
Closes#173
Previously the tray icon only changed from "stopped" to "running" when
SET_PROGRESS_BAR fired on the first addTimeSpent tick, which could take
up to 60 seconds depending on the tracking interval. Now the
CURRENT_TASK_UPDATED handler sets the running icon immediately.
Extracts getRunningIconPath() helper to share icon selection logic
between SET_PROGRESS_BAR and CURRENT_TASK_UPDATED handlers.
Closes#6566
- Gate blur() to Windows only (not supported on Wayland, limited on macOS)
- Add setTimeout delay in ready-to-show to match showOrFocus pattern
- Add webContents.focus() in ready-to-show for renderer-level focus
- Add isDestroyed() guards in setTimeout callbacks
- Only restore focus on resume/unlock if window was visible before
suspend/lock to avoid surfacing hidden/minimized windows
On Windows, BrowserWindow.show() can silently fail to acquire keyboard
focus after a system reboot (electron#20464). This leaves the window in
a "phantom focus" state where clicks work but typing does not.
- Add blur()+focus() cycle after show() in ready-to-show handler
- Add webContents.focus() in showOrFocus() delayed callback
- Add showOrFocus() call in resume/unlock-screen power monitor handlers
Fixes#6663
Windows ties tray icon GUIDs to the executable path when unsigned.
Portable and NSIS builds have different exe paths, so sharing a single
GUID caused silent tray creation failure in whichever distribution
registered second. Each distribution type now gets its own stable GUID.
Portable keeps the original GUID to avoid disrupting existing users.
NSIS and Store get new GUIDs for a clean start.
Also adds a try/catch fallback that retries without GUID if creation
fails (e.g., stale GUID registrations).
Closes#6647
In older app versions simpleSettings was stored as a directory. Reading
it as a file threw EISDIR which was caught/logged but saveSimpleStore()
would subsequently fail with an uncaught EISDIR when writing to the
same path.
- Catch EISDIR in loadSimpleStoreAll and rename legacy dir to .bak
- Catch EISDIR in saveSimpleStore, remove dir and retry write
- Replace module-level DATA_PATH with lazy getDataPath() to fix
stale path when --user-data-dir or Snap overrides userData
- Remove debug console.log that leaked settings to stdout
- Replace console.error with electron-log for consistency
Closes#4791
Remove dead methods (getCurrentSyncData, wouldConflict), dead types
(SyncVersionConflictError, MigrationInProgressError, MigrationLockContent),
dead IPC handler (fileSyncGetRevAndClientUpdate), and a dead mutation.
Deduplicate retry logic in _uploadWithRetry by reusing _buildMergedSyncData.
Make Electron file writes atomic via write-to-temp-then-rename.
Clear _processedOpIds and persist state in _deleteAllData() to prevent
stale localStorage from surviving app restart after a delete-all operation.
Preserve original Error objects in electron/local-file-sync.ts catch
blocks instead of wrapping with `new Error(e as string)`, which loses
structured fields like `code` and the original stack trace.
Backups now use YYYY-MM-DD_HHmmss.json naming instead of YYYY-MM-DD.json,
allowing multiple backups per day instead of overwriting. A cleanup routine
keeps the 14 most recent backups plus the last backup of each day for 7 days.
requestSingleInstanceLock() creates a Unix domain socket blocked by the
macOS App Store sandbox, causing the app to silently fail to start (#6275).
macOS natively prevents multiple app launches, so the lock is unnecessary.
* docs(clipboard): Added the plan to guide AI implementation.
* feat(clipboard): Changed requirement to reflect the fact that some functions can't be done in browsers.
* feat(clipboard): Added Ctrl-v pasting functionality from clipboard.
- Storing image in IndexedDB in browser, and storing image in userdata path in Electron.
- Added image resizing in markdown.
* docs(clipboard): Removed requirement file since it's implemented.
* feat(clipboard): Added clipboard images management in settings.
* feat(tests): Enhance focus mode and inline markdown tests with mock store and actions
* feat(clipboard): Add electron-only annotation to findImageFile function
* feat(clipboard): Prevent memory leaks by revoking cached blob URLs on image deletion
* feat(clipboard): Improve paste handling by tracking current placeholder and cleaning up old progress
* Merge branch 'master' into feat/clipboard-files
* feat(marked-options): Refactor renderer methods and add hooks for image sizing syntax
* feat(clipboard): Added feature that pasted image will be added to task attachment.
* revert: Revert the change of lock file from last merge.
* revert: Removed unwanted changes.
* refactor(clipboard): Cleaned up code that seems not necessary.
* feat(clipboard): Handle storage quota exceeded error and update messages
* feat(clipboard): Implement validated IPC handlers for clipboard image operations
* feat(clipboard): Add error handling for clipboard image URL resolution
* feat(clipboard): Refactor file operations to use async fs promises
* feat(clipboard): Integrate ClipboardPasteHandlerService for improved paste handling
* feat(clipboard): Rename resolveUrl to resolveIndexedDbUrl for clarity and update references
* feat(clipboard): Add defaultPath option to showOpenDialog for improved user experience
* feat(clipboard): Implement getDefaultClipboardImagesPath utility for consistent image path retrieval
* feat(clipboard): Refactor MIME type handling to use centralized mapping for improved maintainability
* feat(clipboard): Add computed property to toggle markdown parsing based on formatting settings
* revert: Removed unwanted changes.
* revert: Removed unwanted chagnes.
* revert: Removed unwanted chagnes.
* fix(clipboard-images-cfg): remove debug log from selectImagePath method
* refactor(paste-handler): update currentPlaceholder to use getter/setter methods
* fix(docs): correct formatting and improve clarity in multiple wiki pages
* fix: update dialog handling in initLocalFileSyncAdapter for type safety
* revert: Revert space change.
* fix(inline-markdown): ensure model is set to an empty string instead of undefined
* fix(tests): update clipboard images section locator to use collapsible title