Commit graph

213 commits

Author SHA1 Message Date
Johannes Millan
fb306e34b8 fix(document-mode): P1 sweep — context-switch races, flood, re-reg
Addresses the P1 findings from the multi-agent branch review:

- setActiveContext is now guarded by a monotonic activeContextSeq:
  concurrent context switches that resolve out-of-order bail after
  each await instead of writing the previous editor doc under the
  new context's id. Title write timers and pendingTitleWrites are
  cleared on every switch so they can't mutate the next context's
  cache.

- setContent catch path no longer silently overwrites a corrupt
  blob: when parsing fails we set isDocCorrupt and gate scheduleSave
  on it, so the empty seed shown in the editor is never persisted on
  top of the original (possibly recoverable) JSON.

- findParentTaskIdBefore and validInsertRange now iterate
  doc.childCount manually instead of doc.resolve(...).index(0).
  Provably correct at every top-level gap; the resolve+index path
  was flagged by review as mis-resolving for some positions.

- onAnyTaskUpdate only auto-appends a chip on a transition
  absent → present in taskCache (tracked via lastSeenTaskIds).
  Updates for existing tasks — including time-tracking ticks — no
  longer re-insert chips the user has intentionally removed.

- Work-context header button re-registration is now replace, not
  skip. Iframes that re-mount (work-view embed cycling with
  skipCleanupOnDestroy: true) produce a new onClick closure pointing
  at the new Window; the bridge would previously reject the new
  entry as a duplicate and keep posting to the detached Window.
  Spec updated to assert replacement instead of dedup-skip.

- Track lastWrittenTitles per task to seed a future, more robust
  echo-vs-remote-change discrimination in refreshTaskRef (the
  current 500 ms pendingTitleWrites window can still race with a
  concurrent remote edit, but the deeper fix needs a follow-up).
2026-05-21 19:21:12 +02:00
Johannes Millan
b7140027d9 fix(document-mode): tolerant delete, safe logging, subtask drag clamp
Three issues hit while editing subtasks; all fixed in one pass:

- PluginAPI.log is declared on the type but never assigned in the
  iframe's runtime PluginAPI (see plugin-iframe.util.ts). Every
  PluginAPI.log.err call inside a .catch() callback then threw
  "Cannot read properties of undefined (reading 'err')", which
  surfaced as the user-visible crash on double-Enter on an empty
  subtask. Replace all usages with a logErr helper that calls
  PluginAPI.log?.err?.() and always falls back to console.error.

- deleteTask rejects with "Task data not found" when a stale chip
  points at a task already removed in the host (sync removal, etc.).
  The unhandled rejection cascaded with the log bug. Add
  deleteTaskTolerant: skip if the task isn't in the local cache,
  swallow "not found" responses, log anything else.

- After setParagraph() on an empty taskRef/subTaskRef, the selection
  remained a NodeSelection on the new paragraph. A follow-up Enter
  on a NodeSelection takes a different path in ProseMirror and could
  resolve a bad position. Chain setTextSelection(nodePos + 1) so the
  caret lands inside the paragraph as text.

- Subtask drag now stays inside the parent's group. Adds
  validInsertRange(draggingPos): for a subTaskRef, returns the
  [parentIdx+1, groupEnd] range. computeDropTarget clamps the
  candidate insertion index and recomputes the indicator Y so the
  drop line follows the clamped target. Top-level taskRef drag is
  unchanged for now.
2026-05-21 18:58:02 +02:00
Johannes Millan
17c6eae37c fix(document-mode): correct slash-menu anchor + guard posAtDOM -1
Two issues hit when the gutter "+" inserts a paragraph and then opens
the slash menu, and when clicks land on a hovered block that has
already been re-rendered:

- Slash menu landed in the top-left corner because the anchor used
  getRangeAt(0).getBoundingClientRect(), which returns a zero rect at
  (0, 0) for empty blocks (which is what we just inserted). Switch
  the slash-menu anchor to editor.view.coordsAtPos(selection.from)
  via a new caretRect() helper — ProseMirror always returns real
  coords there. The same helper is now used by the slash-menu
  keyboard handlers (arrow keys, backspace, typing filter) so the
  menu stays anchored consistently.

- Uncaught "Position -1 out of range" came from
  editor.view.posAtDOM(hoveredBlock, 0) returning -1 when the hovered
  block was unmapped between hover and click (e.g. doc re-rendered,
  block replaced). The gutter "+" and openBlockMenu both blindly
  passed that value to doc.resolve, which threw. Bail when pos < 0,
  and also when the resolved position has depth 0 (no enclosing
  block, no nodePos to compute).
2026-05-21 18:47:14 +02:00
Johannes Millan
a37ae1e150 fix(document-mode): backfill missing subtasks into previously-saved docs
setActiveContext loads the per-context doc from storage and only fell
back to buildSeedDoc when no doc existed. Docs saved before subtask
support didn't contain subTaskRef blocks, so reopening such a context
showed parents with no children even though task.subTaskIds was
populated in the host.

Add ensureSubtasksInJSON: walks the loaded top-level content and, for
each taskRef, inserts any subTaskRefs from the host that aren't yet
present right after the parent's existing subtask group. Idempotent;
preserves existing order and never removes subtasks that have been
removed in the host (left to a future "sync remove" pass).
2026-05-21 18:41:42 +02:00
Johannes Millan
e428e20700 feat(document-mode): subtask support, squircle done-toggle
Adds first-class subtask rendering and editing in the document-mode
plugin, plus a couple of polish fixes:

- New `subTaskRef` node — same shape as taskRef (content: inline*,
  taskId + isDone attrs, identical NodeView wiring) but rendered with
  a `.sub-task-ref` class so CSS indents it under the parent and
  draws a short connector line. Subtask Enter at end creates another
  subtask under the same parent (resolved via findParentTaskIdBefore);
  Enter on an empty subtask deletes the task and outdents.

- Seeding (buildSeedDoc) now emits each parent followed by its
  subTaskRefs from task.subTaskIds, so opening a context shows the
  full task tree. migrateStoredDoc handles both taskRef and
  subTaskRef. collectKnownTaskIds, reconcileTitlesFromDoc,
  refreshTaskRef and isTaskRefFocused all walk both node types.

- appendMissingTask now routes subtasks to insertSubtaskByParent
  (which places the new subTaskRef after the parent's existing
  subtask group), so an externally-added subtask appears under
  its parent instead of at the doc tail.

- Enter at the end of a parent taskRef now uses
  positionAfterParentGroup so the new sibling lands past any
  subtasks — previously it would interleave with the parent's
  children.

- Done-toggle is now a squircle (`<rect rx="5">` instead of
  `<circle>`) to match the shape used in the actual app's task list.
2026-05-21 18:39:29 +02:00
Johannes Millan
1931455ac1 fix(document-mode): reliable grip drag, app-style task chips
- Replace the HTML5 drag-API grip with a pointer-event-driven drag.
  The native API was unreliable because the grip lives outside the
  ProseMirror view (in document.body), and the editor's contentEditable
  region interfered with dragstart on a sibling button. Pointer events
  also give us setPointerCapture for stable tracking and a clean
  click-vs-drag split (with a justDragged guard so the synthetic click
  doesn't open the block menu right after a drop).

- Slash and block menus now add window.scrollX/Y when positioning,
  so they stay anchored to the caret when the iframe is scrolled.
  Previously the popovers used viewport-relative coords with
  position:absolute and drifted off when the document scrolled.

- Task chips now render the app's <done-toggle> visual instead of a
  native checkbox: faint outline circle with an animated checkmark
  that fades in once done. Mirrors src/app/ui/done-toggle styling
  (stroke widths, opacities, transitions) so chips feel like the
  rest of the app.
2026-05-21 18:29:24 +02:00
Johannes Millan
aa7b27c547 feat(document-mode): block reorder, smart popovers, inline-SVG icons
Adds three editor UX improvements in the document-mode plugin iframe:

- Move up / Move down entries in the block menu, plus full HTML5
  drag-to-reorder via the grip handle (with a horizontal drop
  indicator between blocks).
- Slash and block menus flip above the caret when there is no
  room below, avoiding clipped popovers near the viewport bottom.
- Inline-SVG Material icon fallback so the editor renders
  correctly offline (drops the Google Fonts dependency).
2026-05-21 18:10:01 +02:00
Johannes Millan
aa7b2d1e9d feat(document-mode): keyboard handling for task chips, reachable gutter
Two issues:

1. Enter/Backspace inside a task chip had no special handling. Enter
   would split a taskRef into two with the same taskId (broken).
   Backspace at start could merge the chip's content into the previous
   block, detaching the title from its task entity.

2. The block hover gutter sat outside #editor-root. Moving the mouse
   from a block toward the gutter crossed an unwatched gap, firing
   mouseleave on the root and hiding the gutter before the mouse
   reached it.

Fixes:

- TaskRefNode.addKeyboardShortcuts:
  - Enter at end of chip → addTask + insert new chip below; cursor
    lands inside it. Async; chain runs after refreshTaskCache.
  - Enter on an empty chip → convert to paragraph + deleteTask.
  - Enter in middle → swallow (no-op for POC).
  - Backspace at start of empty chip → deleteTask + remove chip.
  - Backspace at start of non-empty chip → swallow (no merge).
- #editor-root padding-left bumped to 60px so the gutter (positioned
  52px left of each block) renders inside the root — the mouse stays
  inside the root the whole time.
- .block-gutter adds padding-right so its hit area extends rightward
  toward the block, and uses [style*='flex'] as the visibility cue
  rather than the previous brittle hover chain.
2026-05-21 17:47:54 +02:00
Johannes Millan
cae32b6db7 feat(document-mode): editable task titles, tight inline list layout
Task chips were atom nodes that just displayed the title and floated as
cards, with extra block spacing between them. Now they're content-bearing
nodes whose inline content IS the task title — typing inside one edits
the linked task.

- taskRef switches from atom to content: 'inline*', exposes contentDOM
  on the .title span so ProseMirror manages the editable content.
- isDone moves to an attr (instead of read-from-cache) so undo/redo
  carries it; the checkbox dispatches a setNodeAttribute transaction.
- buildSeedDoc populates each taskRef with the task title from cache.
- migrateStoredDoc walks older atom-style stored docs and backfills
  content from the cache so they load under the new schema.
- Title write-back: walking the doc on each onUpdate, per-task debounced
  updateTask. pendingTitleWrites + isTaskRefFocused guard the
  reconciler from clobbering an active edit with the echo of our own
  write (or an unrelated ANY_TASK_UPDATE).
- ANY_TASK_UPDATE now refreshes only the affected node via a precise
  replaceWith on the taskRef's inline range — preserves cursor on
  surrounding blocks.
- CSS: zero margin between consecutive taskRefs, baseline-aligned
  checkbox, no card background — the chip reads as a list item.
2026-05-21 17:40:53 +02:00
Johannes Millan
73487e5c17 feat(document-mode): Notion-style UX (gutter, bubble menu, block menu)
Layer Notion-like interaction on top of the TipTap editor:
- Block hover gutter on the left margin with `+` (insert below + open
  slash menu) and `⋮⋮` (select node and open block menu) buttons.
- Bubble menu on text selection with Bold / Italic / Strike / Code
  (via @tiptap/extension-bubble-menu).
- Slash menu shows icons next to labels, supports keyboard nav, and
  now includes bullet list, numbered list, quote, code block, and
  divider in addition to paragraph / headings / new task.
- Block menu (from ⋮⋮) offers turn-into for paragraph + H1-H3,
  duplicate, and delete.
- Tighter CSS — Material Icons via Google Fonts, cleaner spacing
  matching Notion-style density, selectednode highlight on taskRef.
2026-05-21 17:34:13 +02:00
Johannes Millan
f695460bf8 feat(document-mode): persist per-context enable state
Document mode is now remembered per context across sessions. Toggling
the header button writes the ctxId to enabledCtxIds in the shared blob;
on app start (and on every WORK_CONTEXT_CHANGE), the background script
auto-shows or -closes the embed based on whether the active context is
enabled.

The editor's debounced save now does a read-modify-write so it doesn't
clobber enabledCtxIds (or any other field future code adds to the blob).
2026-05-21 17:29:35 +02:00
Johannes Millan
47b7346742 fix(document-mode): make header button toggle on/off
Previously clicking the button only enabled the embed; user was stuck
in document mode with no way back to the task list. Track isShown in
memory and toggle showInWorkContext / closeWorkContextView. State is
not persisted — restart returns to the task list.
2026-05-21 17:24:06 +02:00
Johannes Millan
d429900665 feat(document-mode): add TipTap-based document-mode plugin (POC)
A bundled plugin that replaces the work-view task list with a TipTap
editor for projects and the TODAY tag. Task references are read-only
chips with a checkbox; everything else is normal ProseMirror content
(paragraphs, headings, dividers) plus a simple slash menu for inserts.

- Iframe plugin scaffolded under packages/plugin-dev/document-mode with
  esbuild bundling. The editor.js bundle is inlined into index.html
  because the blob-URL iframe can't resolve relative scripts.
- background.ts registers a work-context header button with
  showFor: ['PROJECT', 'TODAY']; click calls showInWorkContext().
- editor.ts: TipTap (core + StarterKit + Placeholder) with a custom
  taskRef atom node-view (checkbox + title from getTasks() cache).
  Subscribes to WORK_CONTEXT_CHANGE for nav and ANY_TASK_UPDATE for
  title/done-state refresh. Persists per-ctx ProseMirror JSON inside
  the existing single plugin blob ({ docs: { [ctxId]: doc } }) with
  5 s debounced save and a pagehide flush.
- Plugin auto-bundled by packages/plugin-dev/scripts/build-all.js and
  registered in BUNDLED_PLUGIN_PATHS.

Out of scope for the POC (documented in the plan): inline-editable
task titles, keyed persistDataSynced API, removal of in-tree
document-mode, data migration, Electron beforeUnload hook.
2026-05-21 17:22:31 +02:00
Johannes Millan
f71fc0c543 fix(calendar): request verified Google OAuth scopes
Refs #7221
2026-05-13 14:11:15 +02:00
Johannes Millan
cdff2b3907 fix(oauth): disable insecure Google Calendar web flow 2026-05-09 18:14:38 +02:00
johannesjo
989563dc79 test(e2e): scope reminder-default lookups to avoid theme tooltip match
The new theme upload button's matTooltip ("...never run code...") leaves its
text in the DOM via cdk-describedby, so case-insensitive getByText('never')
matched both the "Never" reminder option and the tooltip. Target the
mat-option by ARIA role and exact case, and scope the post-schedule
assertion to the dialog so only the mat-select trigger text qualifies.

Also prunes a stale nested vitest/esbuild tree from the caldav plugin's
package-lock.json.
2026-05-09 11:28:52 +02:00
Johannes Millan
0d51c22a54 fix(oauth): support Google Web client for the browser build
The web build at app.super-productivity.com was inheriting the desktop
OAuth client whose accepted redirect URIs are loopback-only, so Google
rejected the https callback with redirect_uri_mismatch.

Add webClientId / webClientSecret to OAuthFlowConfig and route the
browser branch through them. Google's "Web application" client type is
provisioned as confidential, so PKCE alone is not enough — the secret
ships in client JS like the desktop one. Electron and native mobile
flows are unchanged.
2026-05-08 22:31:00 +02:00
Johannes Millan
31cc191826 fix(caldav): expand RRULE recurring events into individual occurrences (#7492)
Bundle ical.js into the plugin and use it for the read path. The hand-rolled
parser stays for getById/updateIssue/deleteIssue. Anchor the sync window to
start-of-UTC-day so in-progress events stay visible, count only emitted
occurrences toward the per-event safety cap, and isolate per-VEVENT failures
so one malformed event can't drop the rest. Compound id uses '#occ=<ms>' so
a server-controlled href cannot collide with the occurrence delimiter.
2026-05-06 21:37:06 +02:00
johannesjo
1b4d0c1710 18.4.2 2026-05-01 23:07:19 +02:00
Johannes Millan
8423d51701 docs(github-plugin): note token-less import returns all open issues
Make explicit in the backlog-query help text that the default behavior
without a token imports every open issue, not just the user's, so anyone
enabling auto-import without credentials understands the scope.
2026-04-27 13:18:58 +02:00
Johannes Millan
41c596f904 fix(github-plugin): drop assignee:@me from default backlog query when no token
The default backlog query 'sort:updated state:open assignee:@me' fails with
HTTP 422 ("The listed users cannot be searched...") when the provider has
no token configured, because GitHub's Search API can't resolve @me without
an authenticated request. This broke auto-import for public repos, which
the docs and UI advertise as not requiring a token.

Fall back to 'sort:updated state:open' when no token is set, and update
the help text to describe both defaults.

Closes #7381
2026-04-27 13:18:58 +02:00
Spyros Seimenis
32c138b5f6
feat(github): add "Include pull requests" option to issue provider (#7358)
Adds an advanced checkbox on the GitHub issue provider that, when enabled,
drops the hardcoded `is:issue` filter in both backlog auto-import and
in-provider search. Lets users sync PRs (assigned, authored, or
review-requested) into their backlog with a query like
`state:open is:pull-request (assignee:@me OR review-requested:@me)`.

Default is off, existing behavior is unchanged.
2026-04-25 14:29:08 +02:00
dependabot[bot]
94842d6123
chore(deps): bump the npm_and_yarn group across 1 directory with 3 updates (#7332)
Bumps the npm_and_yarn group with 3 updates in the /packages/plugin-dev directory: [lodash](https://github.com/lodash/lodash), [picomatch](https://github.com/micromatch/picomatch) and [rollup](https://github.com/rollup/rollup).


Updates `lodash` from 4.17.21 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `rollup` from 4.44.0 to 4.60.2
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.44.0...v4.60.2)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: rollup
  dependency-version: 4.60.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-23 13:54:43 +02:00
Johannes Millan
30550efa34 chore(deps): sync plugin lockfiles after vite-plugin bump to ^6.4.2
packages/vite-plugin/package.json was bumped to vite ^6.4.2 in
4b9bd23e56 but dependent plugin lockfiles still referenced ^6.0.0.
npm install during the e2e build brought them in sync and hoisted
vitest's nested esbuild binaries, dropping ~500 redundant entries.
2026-04-21 21:50:53 +02:00
Aki
f0b4be592e
fix(github-plugin): enable github advanced search to make queries including "OR" or "AND" logic operators work (#7304) 2026-04-21 15:56:29 +02:00
Johannes Millan
7fa03c489e fix(github-plugin): encode parentheses in search queries (#4913)
encodeURIComponent leaves ( and ) intact per RFC 3986, but GitHub's
search API treats them as grouping operators that must be percent-encoded,
returning HTTP 422 on queries like "(author:@me OR assignee:@me)".

The in-repo provider was fixed in 960330dd56 but the fix didn't carry
over when GitHub moved to a plugin. Reapply via a small encodeGithubQuery
helper used at both call sites.
2026-04-21 15:03:41 +02:00
Johannes Millan
01e30b9c7e
Feat/to me it looks like there are lots of 60dd04 (#7280)
* 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)
2026-04-20 12:04:38 +02:00
Johannes Millan
e113cd8d21 18.2.4 2026-04-19 19:21:50 +02:00
adnoh
941e95bc12
Implement task parsing with sub-tasks (#7184)
* Implement task parsing with sub-tasks

Added a new function to parse tasks with sub-tasks from a text input, improving task management capabilities. Updated the task addition logic to utilize this new parsing method.
Should solve #7183

* Enhance task parsing and user information

    Key Changes Summary:
     Critical Fix #1 - 4-space indentation: Detects minimum indent and normalizes relative to it
     Critical Fix #2 - Mixed input: Plain-text lines no longer silently dropped; warning shown
     Critical Fix #3 - Deeply-nested items: Now flattened to sub-task level with user notification
     Minor - Sub-task dueDay: Documented that it inherits from parent (not passed independently)
     Suggestion - UI/UX: Updated placeholder text to show expected format with examples

* fix indentation calculation and missing isBullet: true

* fix(brain-dump-plugin): keep sub-tasks when plain-text lines interrupt

Previously, a plain-text line between a bullet and its indented sub-task
caused the sub-task to be silently dropped: the outer loop advanced past
the plain-text entry but the inner look-ahead had already exited at
indent 0, so the following indented bullet was never attached to the
parent and was rejected by the outer loop's else branch.

The sub-task scan now skips over plain-text lines while still breaking
at the next top-level bullet, so indented bullets attach to the previous
parent regardless of interleaved plain text. The plain-text line itself
is still emitted as its own top-level task by the outer loop.

Also drops dead code:
- findMinimumIndent() was declared but never called.
- dueDay on sub-task payload was forwarded but silently discarded by the
  plugin bridge (sub-tasks inherit the parent's date).

And de-duplicates the "Note: ... Note: ..." prefix in the deeply-nested
warning snack.

---------

Co-authored-by: Adnoh <git@rotzefull.de>
Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
2026-04-19 16:44:19 +02:00
Johannes Millan
b9d6dc6d86
test(e2e): update Show/hide task panel button label (#7260)
* test(e2e): update Show/hide task panel button label

The TOGGLE_DETAIL_PANEL translation was renamed from "Show/Hide
additional info" to "Show/hide task panel" in dd789d2, but e2e
selectors still referenced the old string, causing every test that
opens the task detail panel to time out.

https://claude.ai/code/session_011mX4Pr24S42svmA5j7fRux

* 18.2.1

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-17 22:19:22 +02:00
Johannes Millan
0e9218bd68 fix(sync): handle data validation errors and improve client ID management
- 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)
2026-04-16 17:41:39 +02:00
Johannes Millan
81788143b6 chore(plugin-dev): bump vite to ^7.3.2 in lock files 2026-04-16 17:41:38 +02:00
cpa2027
c678db23c8
Update TOKEN description in en.json (#7205) 2026-04-13 16:51:56 +02:00
dependabot[bot]
6d244fa691
chore(deps): bump the npm_and_yarn group across 8 directories with 2 updates (#7159)
Bumps the npm_and_yarn group with 2 updates in the /packages/plugin-dev/ai-productivity-prompts directory: [lodash](https://github.com/lodash/lodash) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/automations directory: [lodash](https://github.com/lodash/lodash).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/boilerplate-solid-js directory: [lodash](https://github.com/lodash/lodash).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/caldav-calendar-provider directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/clickup-issue-provider directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/google-calendar-provider directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/procrastination-buster directory: [lodash](https://github.com/lodash/lodash).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/sync-md directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `vite` from 7.1.12 to 7.3.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `vite` from 8.0.3 to 8.0.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

Updates `vite` from 7.3.1 to 7.3.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

Updates `vite` from 8.0.1 to 8.0.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: vite
  dependency-version: 7.3.2
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: vite
  dependency-version: 8.0.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: vite
  dependency-version: 7.3.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: vite
  dependency-version: 8.0.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-09 20:34:47 +02:00
dependabot[bot]
91d7d733d4
chore(deps): bump the npm_and_yarn group across 5 directories with 1 update (#7172)
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/ai-productivity-prompts directory: [lodash](https://github.com/lodash/lodash).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/automations directory: [lodash](https://github.com/lodash/lodash).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/boilerplate-solid-js directory: [lodash](https://github.com/lodash/lodash).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/procrastination-buster directory: [lodash](https://github.com/lodash/lodash).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/sync-md directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

Updates `lodash` from 4.17.23 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.23...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-09 20:34:44 +02:00
Johannes Millan
d32f7037a3 fix(sync): preserve own vector clock counter across full-state op resets
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.
2026-04-01 15:41:13 +02:00
Johannes Millan
375274e3ea fix(deps): update vulnerable transitive dependencies
Update path-to-regexp, serialize-javascript, brace-expansion, and
nodemailer to patched versions to resolve 30 Dependabot security alerts.
2026-03-31 19:40:37 +02:00
Johannes Millan
020fd56504 feat(calendar): add CalDAV Calendar plugin with time-blocking support
Add a CalDAV Calendar plugin that syncs tasks with calendar events via
the CalDAV/WebDAV protocol, supporting self-hosted servers like Nextcloud.

Plugin features:
- CalDAV PROPFIND/REPORT for calendar discovery and event fetching
- iCal parsing and serialization with RFC 5545 compliance
- Two-way sync with field mappings (title, notes, dates, duration)
- Time-block integration for auto-creating calendar events
- Multi-calendar support with compound IDs

Host-side changes:
- Add generic request() method to PluginHttp for WebDAV methods
- Add allowPrivateNetwork manifest flag (bundled plugins only)
- Add dynamic loadOptions support for config field dropdowns
- Add backfill effect for existing scheduled tasks
- Generify translation keys (LOAD_OPTIONS instead of LOAD_CALENDARS)

Security:
- SSRF protection via origin validation in resolveHref
- allowPrivateNetwork gated by _isPluginBundled check
- XML parse error detection in CalDAV response parsing
- Description rendered as plain text (not markdown)

Correctness:
- TZID conversion uses formatToParts (no local timezone contamination)
- modifyICalEvent scoped to VEVENT block (preserves VTIMEZONE)
- responseType: 'text' on all CalDAV PUT/DELETE calls
- CR characters handled in iCal text escaping
- Trailing CRLF added to modifyICalEvent output per RFC 5545
2026-03-28 23:10:08 +01:00
Johannes Millan
fed69b0ac1 refactor(calendar): address multi-review findings
- Fix taskIdToGcalEventId collision by hex-encoding nanoid bytes
- Add timeBlock API to plugin interface, move Google Calendar-specific
  logic into the plugin, make TimeBlockSyncEffects provider-agnostic
- Use isPluginIssueProvider() in task selectors
- Replace console.error with Log.err, add i18n for time-block errors
- Use 1-hour default when rescheduling all-day event to timed slot
- Apply config migration in dialog for legacy single-calendar configs
- Remove planTaskForDay/moveBeforeTask from deleteOnUnschedule$
- Rename icalEvents$ to calendarEvents$
- Make issueProviderKey required on CalendarIntegrationEvent
- Parameterize loadAllCalendars/loadWritableCalendars
- Replace deprecated unescape() with TextEncoder in iCal util
- Fix btoa() non-ASCII throw in getIssueLink
- Fix timezone bug in all-day reschedule date parsing
- Deep-clone pluginConfig before mutating in migration dialog
2026-03-28 23:10:08 +01:00
Johannes Millan
5e446a4506 feat(calendar): add showIf for conditional plugin config fields
- Add showIf property to PluginFormField so fields can depend on
  another config value being truthy
- Show timeBlockCalendarId only when isAutoTimeBlock is enabled
- Improve wording for auto time blocking and calendar field descriptions
2026-03-28 23:10:08 +01:00
Johannes Millan
3e2265fa57 feat(calendar): add auto time blocking to Google Calendar
Automatically push scheduled tasks (with dueWithTime) to Google Calendar
as time-block events. Uses deterministic event IDs derived from task IDs,
eliminating the need for any persistent mapping.

- Add isAutoTimeBlock toggle and timeBlockCalendarId config to plugin
- Create TimeBlockSyncEffects watching schedule/update/delete actions
- Handle create (POST, 409→PATCH), update (PATCH, 404→recreate),
  complete ([DONE] prefix), un-done, unschedule/delete (DELETE)
- Add TimeBlockDeleteSidecarService for bulk delete support
2026-03-28 23:10:08 +01:00
Johannes Millan
472ab99189 feat(calendar): implement Google Calendar plugin with reschedule and delete
Add Google Calendar as a plugin-based calendar provider with OAuth 2.0
authentication, multi-calendar support, and event management.

- Plugin fetches events from selected read calendars, merged into the
  existing calendar integration pipeline
- Context menus on planner and schedule views for calendar events:
  open link, reschedule, create as task, hide forever, delete
- Reschedule opens date/time picker and updates event via plugin API,
  handling both timed and all-day events correctly
- Delete with confirmation dialog
- CalendarEventActionsService extracts shared event action logic
- HiddenCalendarEventsService for permanent event hiding
- triggerRefresh() for immediate UI updates after mutations
- Multi-select config fields for choosing calendars to display
- Fix change detection for plugin select fields in provider dialog
- Electron-safe URL opening with scheme validation
2026-03-28 23:10:08 +01:00
Johannes Millan
9f8cf0a3d0 fix(oauth): use platform-specific redirect URIs and iOS client ID
Google rejects custom scheme redirect URIs that don't match the
platform's app identifier. Use the Android applicationId
(com.superproductivity.superproductivity) on Android and the iOS
bundle ID (com.super-productivity.app) on iOS, with single-slash
URI format per Google's documentation.

- Add iosClientId to OAuthFlowConfig and plugin API types
- Add iOS OAuth client ID to Google Calendar plugin
- Select client ID per platform (Android/iOS/Desktop) in bridge service
- Add Android package name intent filter in AndroidManifest
- Accept both URI schemes in OAuth callback handler
- Fix redirect handler to use IS_NATIVE_PLATFORM consistently
2026-03-27 17:33:38 +01:00
Johannes Millan
1e9eafa0aa fix(oauth): use platform-specific client ID for mobile OAuth flows
Google rejects Desktop OAuth client IDs when the redirect URI is a
custom scheme (as used on mobile via Capacitor), returning a 400 error.

Add mobileClientId to OAuthFlowConfig so plugins can specify a separate
Android/iOS client ID that authenticates via app signing instead of a
client secret. On native platforms, the bridge service automatically
uses the mobile client ID with PKCE only.

Also fix getRedirectUri() to return the custom scheme for all native
platforms (not just Android WebView), and align inline types in the
dialog component and plugin declaration with OAuthFlowConfig.
2026-03-27 17:33:38 +01:00
johannesjo
926e9d46a8 build: update pdfile and package-lock 2026-03-26 21:06:33 +01:00
Johannes Millan
f885336aa3 feat(plugins): enable google-calendar-provider bundled plugin 2026-03-26 17:43:03 +01:00
dependabot[bot]
c519092ab2
chore(deps): bump the npm_and_yarn group across 6 directories with 1 update (#6962)
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/ai-productivity-prompts directory: [picomatch](https://github.com/micromatch/picomatch).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/automations directory: [picomatch](https://github.com/micromatch/picomatch).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/boilerplate-solid-js directory: [picomatch](https://github.com/micromatch/picomatch).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/clickup-issue-provider directory: [picomatch](https://github.com/micromatch/picomatch).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/google-calendar-provider directory: [picomatch](https://github.com/micromatch/picomatch).
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/procrastination-buster directory: [picomatch](https://github.com/micromatch/picomatch).


Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-26 15:19:41 +01:00
dependabot[bot]
111d096496
chore(deps-dev): bump picomatch (#6961)
Bumps the npm_and_yarn group with 1 update in the /packages/plugin-dev/sync-md directory: [picomatch](https://github.com/micromatch/picomatch).


Updates `picomatch` from 2.3.1 to 2.3.2
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-25 23:51:38 +01:00
Johannes Millan
c73eeff75b fix(sync-md): prevent crash from sync oscillation when adding subtask to markdown file
When a user adds a subtask by editing the markdown file directly, the
MD→SP sync creates the task which triggers SP hooks, which trigger
SP→MD sync, which writes the file, which the file watcher detects,
creating a rapid sync oscillation loop that crashes the app.

Three-layer fix:
1. Stop file watcher for the entire MD→SP sync duration and cancel
   pending SP→MD debounce timers
2. Add a cooldown after MD→SP sync (set before and after in finally
   block) to suppress SP hooks that fire as side-effects
3. Simplify lazySetInterval with async/await and a stopped flag to
   prevent zombie rescheduling when cancelled during async callbacks

Also fixes a file watcher race condition where polling could start
before initial mtime was resolved.

Fixes #6021
2026-03-24 14:12:50 +01:00
LokiStar
6ded0c19a9
Feat/automations 6453 (#6784)
* fix(plugin-bridge): enhance task update logic and validation for project movement

* fix(plugin-bridge): include changes in task update event payload

* feat(RuleEditor): add tests for rule editing functionality and enhance action handling

* test(RuleEditor): add comprehensive tests for rule editing and condition handling

* feat(RuleRegistry): enhance rule validation and add support for advanced conditions and actions

* feat(types): extend condition and action types for enhanced automation capabilities

* feat(conditions): add regex support for title conditions and enhance checks

* feat(actions): add ActionMoveToProject to move tasks between projects

* feat(ActionDialog, ActionInput): add support for moveToProject action and enhance input handling

* feat(ConditionDialog, ConditionInput): add support for titleStartsWith and weekdayIs conditions, enhance regex handling

* feat(styles): add new input-with-toggle and field-error styles for improved layout and error handling

* feat(automation): add titleStartsWith condition and enhance task event handling

* feat(automations): add delete task action

add a new `deleteTask` action to the automations plugin

- register the action in the automation runtime
- expose it in the rule editor UI
- restrict it to task-based triggers
- validate and persist rules using `deleteTask`
- add focused tests for runtime behavior, validation, persistence, and UI

* feat(automations): remove false trigger workaround

remove the temporary taskCreated fallback after confirming the
reported trigger bug was a mistaken assumption

* fix(automations): address PR review feedback

- Add regex pattern length cap (200 chars) to mitigate ReDoS risk
- Use project ID instead of title as option value to prevent duplicate name collisions
- Replace dynamic import('rxjs') with static import for firstValueFrom
- Replace any[] with proper types for projects/tags props
- Replace changes?: any with Record<string, unknown> in TaskEvent
- Use createMemo + <Show> for regexError to avoid double reactive computation
- Remove noisy/inconsistent debug logging from automation-manager
- Remove verbose intermediate log from moveToProject action
- Clean up mock: remove unused moveTaskToProject, restore PluginAPI type
- Prefer ID lookup over title in ActionMoveToProject

* fix(automations): harden regex, use IDs for conditions, add validation and tests

- Add dangerous-pattern heuristic to reject nested quantifiers (e.g. (a+)+$)
  that cause catastrophic backtracking, supplementing the length cap
- Switch projectIs/hasTag condition dropdowns to store IDs instead of titles
  to survive project/tag renames (with title fallback for backward compat)
- Disable ActionDialog Save button when value is empty (except deleteTask)
- Fix webhook test to actually validate payload sanitization
- Add test for HTML escaping in ActionDisplayDialog
- Add tests for regex length cap and dangerous-pattern rejection
- Add tests for ConditionWeekdayIs (7 test cases covering full names,
  abbreviations, comma-separated lists, case insensitivity, edge cases)

* test(automations): build dangerous regex pattern dynamically to avoid CodeQL flag

The test intentionally uses a catastrophic-backtracking pattern to verify
our safety heuristic rejects it. Build it via string concatenation so
CodeQL's static analysis doesn't flag the test itself.

* fix(automations): addTag lookup by ID, widen ReDoS heuristic to catch {n,}

- ActionAddTag now looks up tags by ID first (with title fallback),
  consistent with all other condition/action lookups
- Extend DANGEROUS_REGEX_PATTERN to also detect {n,} quantifiers
  inside nested groups (e.g. (a{2,})+) which also cause backtracking

---------

Co-authored-by: Johannes Millan <johannes.millan@gmail.com>
2026-03-23 20:13:50 +01:00