Skip to content

fix(release): cut v0.15.4 — E1 packaged editor and desktop bugs - #474

Closed
tomymaritano wants to merge 251 commits into
mainfrom
develop
Closed

fix(release): cut v0.15.4 — E1 packaged editor and desktop bugs#474
tomymaritano wants to merge 251 commits into
mainfrom
develop

Conversation

@tomymaritano

Copy link
Copy Markdown
Collaborator

Closes #315
Closes #317 (promotion step; Release workflow + PAT still after merge)

Merge with a merge commit — do not squash. Squashing would collapse every fix:/feat: and semantic-release would only see this title.

Why

E1 (v0.15.4) is on develop: packaged editor crash, Sign In hang, table overflow + decoration order, AI key hydration, AI stream destroy, e2e as a required check.

Packaged verification (#315)

Unpacked arm64 .app via electron-builder --dir --mac --arm64 (unsigned, no notarize), launched with Playwright against Dripnex.app:

  • Note with heading + fenced JS + GFM table → 0 tags is not iterable / [CodeMirror] plugin error. Table rendered as WYSIWYG widget. After the first pack, a Ranges must be added sorted error showed; fixed in chore(release): fail loud on sync-develop + runbook #472 (widget XOR line marks). Re-pack: 0 range errors.
  • Update race (local feed + long AI stream + Install Now ×3–5) — not run. Needs a local update feed on a signed build.
  • API key survives update-install — not run (depends on the update path). partialize + boot hydrate are covered by unit tests; dripnex-settings strips apiKey.
  • Network blackholed Sign In — not run on the .app. Code + unit tests cover 15s timeout and ungated Sign In.
  • open "dripnex://auth/verify?token=x" after closing the main window — not run. Deep-link guards now check webContents.isDestroyed() (fix(desktop): drop AI IPC after window destroy #470).

After merge

  1. Rotate GH_TOKEN (fine-grained PAT: contents + pull-requests + actions write). Current secret is from 2026-01-03 and broke v0.15.3.
  2. Actions → Release → Run workflow on main.
  3. If the tag does not start Build & Publish: gh workflow run "Build & Publish" --ref v0.15.4.
  4. Confirm three platform builds, undraft, auto-update 0.15.3 → 0.15.4.

#316

Code side landed in #472 (|| echo gone). PAT rotation is still a human step in the GitHub UI.

tomymaritano and others added 30 commits March 11, 2026 01:42
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Notebooks now sync before notes in syncNow() to ensure note-notebook
dependencies are satisfied. Adds pullNotebooks/pushNotebooks methods
and applyRemoteNotebookChange for bidirectional notebook sync.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move validateNotebookTree from inline test definition to a shared module
so it can be reused by the API route and other consumers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add conflict state to SyncStatusIndicator with amber warning icon
and count. Conflicts now take priority over idle state so users
discover them without navigating to Settings.

Also export ConflictResolver from sync components barrel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DatabaseConnection.transaction() already calls the inner fn — no need
for extra () at call site.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix pullNotebooks() to only advance cursor to last successfully
  applied change (prevents skipping failed changes on retry)
- Fix tree validation snapshot to properly exclude deleted notebooks
  (prevents ghost parent references in validation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: add bidirectional notebook sync
test: add sync-core unit tests (62 tests)
feat: surface sync conflicts in status indicator
# Conflicts:
#	apps/desktop/src/main/services/apiClient.ts
#	apps/desktop/src/main/services/syncService.ts
#	packages/api/src/db/schema.ts
#	packages/api/src/routes/sync.ts
#	packages/storage-sqlite/src/migrations/index.ts
Configure automated code review with path-specific instructions
for core, storage, desktop, and API packages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ration

Add optional metadata (name, version, priority) to registerRemarkPlugin
and registerRehypePlugin signatures for debugging and execution ordering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wraps remark/rehype plugins so that if a transformer throws, the error
is caught, logged, and an error marker node is injected into the AST
instead of crashing the entire preview pipeline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tomymaritano and others added 27 commits June 9, 2026 13:53
…postinstall in setup (#296)

## Why

Two distinct CI issues, both blocking every Phase 0 PR (#290, #292,
#294). Bundling them is OK because they're orthogonal-but-related: both
clear a "lint-or-setup says no, so I can't merge" path on develop.

### Issue 1: Prettier fails on \`CHANGELOG.md\`

semantic-release writes CHANGELOG entries without prettier formatting.
The root \`format:check\` script uses \`--ignore-path .gitignore\`,
which **overrides** Prettier's default \`.prettierignore\` lookup.
CHANGELOG.md correctly isn't gitignored (it's tracked), so it gets
linted, fails, kills lint.

### Issue 2: \`setup\` job fails when native deps don't match the host
Electron

\`setup\` runs \`pnpm install --frozen-lockfile\` (no
\`--ignore-scripts\`). That triggers apps/desktop's \`electron-builder
install-app-deps\` postinstall, which **rebuilds better-sqlite3 from
source against Electron's bundled Node headers**. When better-sqlite3
lags an Electron major (the v0.15.0 incident: Electron 42 +
better-sqlite3 12.10.0, V8 \`External::Value\` signature mismatch), the
rebuild fails and setup dies — taking lint/test/typecheck/build down
with it.

The same shape took down deploy-api.yml (#287) and release.yml (#288).
This brings ci.yml in line.

## What changes

- **\`.prettierignore\`** (new) — CHANGELOG.md + local build artefacts
(.next/, .source/, .astro/, .wrangler/, dist/, out/, release/,
coverage/, pnpm-lock.yaml).
- **\`package.json\`** — \`format\` and \`format:check\` now pass
\`--ignore-path .gitignore --ignore-path .prettierignore\` (Prettier 3.x
supports repeated \`--ignore-path\`).
- **\`.github/workflows/ci.yml\`** — \`setup\` job install:
\`--ignore-scripts\` added with explanatory comment.

## Verification

- \`pnpm format:check\` locally → "All matched files use Prettier code
style!"
- CI doesn't need a runtime-functional better-sqlite3: lint and
typecheck don't load native modules, and \`pnpm test\` excludes
storage-sqlite per CLAUDE.md.

## Order of operations

After this lands → rebase #290 / #292 / #294 → CI green → merge them in
order → cut v0.15.1.
…pat (Phase 0 A1) (#290)

## Summary

Phase 0 A1 of the post-audit devops roadmap. **Unblocks v0.15.x Build.**

The v0.15.0 Build workflow failed on all 3 platforms (run
[27184736470](https://github.com/tomymaritano/readide/actions/runs/27184736470))
because **better-sqlite3 12.10.0 explicitly removed Electron v42
prebuilds**
([WiseLibs/better-sqlite3#1470](WiseLibs/better-sqlite3#1470)).
Without a prebuild, \`electron-builder install-app-deps\` falls through
to a source build via \`@electron/rebuild\`, which then hits V8 13.x API
breakages:
- \`SetNativeDataProperty\` ambiguity (3 candidate overloads)
- \`External::Value()\` requires \`ExternalPointerTypeTag\` argument
- \`External::New()\` signature change

Same root cause on Linux/macOS (GCC/clang) and Windows (MSVC).

## Fix

Pin Electron to \`^41.7.1\` (latest 41.x as of 2026-05-26).
better-sqlite3 has prebuilts for it.

## Local validation

\`\`\`
apps/desktop postinstall: electronVersion=41.7.1 arch=arm64
apps/desktop postinstall: buildFromSource=false
apps/desktop postinstall: preparing       moduleName=better-sqlite3
apps/desktop postinstall: finished        moduleName=better-sqlite3
apps/desktop postinstall: completed installing native dependencies
\`\`\`

\`buildFromSource=false\` = the prebuilt was found and consumed; no V8
errors.

- ✅ \`pnpm install\` (with scripts) — succeeds
- ✅ \`pnpm -r typecheck\` — green
- ✅ \`pnpm test\` — 17/17 packages

## When to bump back to 42

Watch [WiseLibs/better-sqlite3
releases](https://github.com/WiseLibs/better-sqlite3/releases) for v42
prebuild restoration. As of 2026-06-09 there's no public ETA. When it
lands: bump electron to \`^42.x\` + better-sqlite3 to the version that
re-includes v42 prebuilds, in a single PR.

## Stack context

This is **A1** of Phase 0 (devops stabilization). A2-A4, B1-B5, C1-C2, D
follow in subsequent PRs against develop.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
  * Updated the runtime dependency for the desktop application.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary

Phase 0 B-bundle of the post-audit roadmap. Six independent fixes
batched into one PR because they all touch the workflow YAML surface and
reviewing them together is faster than three ping-pong PRs that all
conflict on the same files.

## docs.yml

| Change | Why |
|---|---|
| \`pnpm install\` → \`pnpm install --filter '@readied/web...'
--ignore-scripts\` | Marketing-site install was the last workflow still
firing apps/desktop's \`electron-builder install-app-deps\` step that
fails on Linux + Node 22. Same shape as #287 (deploy-api) and #288
(release). |
| Added \`permissions: contents: read\` | Cloudflare Pages deploy
doesn't need anything beyond checkout |
| Build step moved into \`working-directory: apps/web\` | Was inline
\`cd apps/web && ...\` — explicit working-directory reads better |

## build.yml

| Change | Why |
|---|---|
| \`windows-latest\` → \`windows-2025-vs2026\` | GitHub announced
\`windows-latest\` migration to that image on **2026-06-15** (6 days
from this commit). Pinning ahead avoids a surprise toolchain swap
mid-release. |
| Removed \`FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true\` env | This was
the migration toggle for the Node 20→24 actions rollout. With all
actions now on @v5 (Node 24-native) it's no-op. |
| Artifact upload \`if-no-files-found: ignore\` → \`error\` | Silent
zero-asset releases are worse than a failed upload. If electron-builder
swallowed an error, signing failed, working-directory drifted, etc., we
want loud failure here, not a release un-drafted with no installers. |

## release.yml

| Change | Why |
|---|---|
| Removed \`HUSKY: '0'\` env | Leftover from the husky → lefthook
migration in #267. Lefthook only reads .git/hooks if those files exist;
on fresh CI clones they don't. |

## deploy-api.yml

| Change | Why |
|---|---|
| Added \`permissions: contents: read\` | Cloudflare deploy doesn't push
commits or create issues; minimum-privilege default. |

## Action versions sweep (all 8 workflows)

| From | To |
|---|---|
| \`actions/checkout@v4\` | \`@v5\` |
| \`actions/setup-node@v4\` | \`@v5\` |
| \`actions/cache@v4\` | \`@v5\` |
| \`actions/cache/save@v4\` | \`@v5\` |
| \`actions/cache/restore@v4\` | \`@v5\` |
| \`actions/upload-artifact@v4\` | \`@v5\` |

GitHub announced Node 20-based actions deprecation on **2026-06-16** (7
days from this commit). The \`@v5\` family runs on Node 24.

## Verification

- ✅ \`pnpm -r typecheck\` — green
- ✅ \`pnpm test\` — 17/17 (untouched)
- ✅ YAML parsed locally; no syntax errors

## Stack context

Phase 0 B-bundle. Pairs with #290 (A1 electron pin) and #291 (A2
bump-version). Independent files, can land in any order.

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

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Why

v0.15.1 Build run (27212685957) failed on linux:

\`\`\`
⨯ failed to build AppImage error=executableName contains characters that
  cannot be safely used in file paths: @readieddesktop. Please use only
  letters, digits, hyphens, underscores, dots, and spaces.
\`\`\`

electron-builder defaults Linux's \`executableName\` to the package.json
\`name\` field, stripped of unsafe chars. \`@readied/desktop\` →
\`@readieddesktop\`, still leading with \`@\`, still invalid.

mac and win didn't fail because they use \`productName\` ("Readied") and
the \`appId\` (\`app.readied.desktop\`) respectively — Linux is the
strict one for the on-disk binary name.

## Fix

Add \`linux.executableName: "readied"\` to apps/desktop/package.json's
\`build\` config.

## Knock-on

v0.15.1 Build flow was:
1. linux job ⨯ fails at AppImage step
2. \`publish\` job (\`needs: build\`) skipped
3. \`sync-develop\` (\`needs: publish\`) skipped
4. Release left with no binary assets, no electron-updater feed

After this lands, the next Release will produce binaries for all 3
platforms.

## v0.15.1 cleanup

The published v0.15.1 GitHub Release will be marked as draft via gh api
so it doesn't surface to users with electron-updater. v0.15.2 will be
cut after this PR merges.
## Why

semantic-release's \`@semantic-release/git\` plugin pushed two commits
directly to main during the v0.15.1 release:
- CHANGELOG.md update for v0.15.1 release notes
- \`chore(release): v0.15.1 [skip ci]\` (package.json +
apps/desktop/package.json bumped to 0.15.1)

These need to come back to develop so develop stays a superset of main.
The \`sync-develop\` job in build.yml normally does this automatically,
but it was skipped on the v0.15.1 Build run because the \`publish\` job
was skipped (linux failed).

Doing it manually here so #299 (develop → main for v0.15.2) is
mergeable.

## What's in the merge

\`CHANGELOG.md\`, \`package.json\`, \`apps/desktop/package.json\`
(3-file delta). No conflicts.

## Note

After this merges, #299 (develop → main, cuts v0.15.2) will be
up-to-date and mergeable.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Auto sync of v0.15.2 release commits (CHANGELOG.md + version bump to
0.15.2). The build.yml sync-develop job tried to create this but
GH_TOKEN lacks createPullRequest permission (`Resource not accessible by
personal access token`), so it's done manually here. Same root cause as
the tag→Build auto-trigger gap (A3 — token scope).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
  * Resolved a Linux executable name issue.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
…rashes (#303)

## Summary

Two related lifecycle bugs reported after v0.15.2 install (production):

1. **`TypeError: Object has been destroyed`** at
`BrowserWindow.<anonymous>` / `WebContents.<anonymous>` — surfaced as an
`Uncaught Exception` dialog.
2. **`TypeError: The database connection is not open`** thrown by
`notebooks:tree` IPC handler.

## Root cause

**(1) Object has been destroyed:** `mainWindow` event handlers
(`maximize`, `unmaximize`, `ready-to-show`, `did-finish-load`) called
`getBounds()`/`show()`/`focus()`/`webContents.send()` without checking
`isDestroyed()`. During shutdown or auto-update restart, these events
can fire after the window is destroyed, throwing.
`noteWindow.ready-to-show` had the same gap.
`pluginWatcher.broadcastReload` was missing the
`webContents.isDestroyed` + `try/catch` pattern used elsewhere.

**(2) DB not open:** `db.close()` ran inside `before-quit` *before*
windows finished unmounting, so the renderer could fire an IPC request
(e.g. `notebooks:tree` on a late reload) between `close()` and actual
quit, hitting a closed connection.

## Changes

- `apps/desktop/src/main/index.ts`
- Add `isDestroyed()` guard to `mainWindow` handlers (`maximize`,
`unmaximize`, `ready-to-show`, `did-finish-load`) and to
`noteWindow.ready-to-show`.
- Move `db.close()` from `before-quit` to a new `will-quit` listener
(fires after `window-all-closed`), with `try/catch` and null-out so
re-entry is safe.
- `apps/desktop/src/main/pluginWatcher.ts`
- Harden `broadcastReload` with `webContents.isDestroyed()` check and
`try/catch`, matching the production `broadcastToWindows` pattern.

## Out of scope (follow-up)

`dataHandlers.ts:setDb` updates the top-level `db` reference after
backup restore but doesn't recreate `noteRepository` /
`notebookRepository` — those still hold the closed connection. A restore
today leaves the app in a broken state until manual restart. Tracking
separately; not in this PR.

## Test plan

- [x] `pnpm typecheck` — all 4 desktop projects pass
- [x] `pnpm test` — 17/17 successful
- [x] `pnpm --filter @readied/desktop build` — succeeds
- [ ] Manual: quit + relaunch the packaged app, confirm no uncaught
exception dialog and notebooks load on first paint
- [ ] Manual: trigger Cmd+Q while the renderer is reloading, confirm no
`notebooks:tree` error toast

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **Bug Fixes**
* Improved stability when closing windows by preventing errors during
shutdown
* Enhanced app shutdown sequence to better handle timing issues with
database closure

* **Refactor**
* Strengthened plugin reload mechanism with additional safety checks and
error handling

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ync (#305)

## Summary

The v0.15.2 sync (#302) committed `CHANGELOG.md` with unresolved merge
conflict markers (`<<<<<<< HEAD` / `=======` / `>>>>>>> origin/main`).
This makes the release PR #304 (`develop` → `main`) report
`CONFLICTING`.

This PR restores `CHANGELOG.md` on `develop` to match `main` exactly
(the canonical version — semantic-release writes the changelog on
`main`). Identical content on both sides means #304 merges cleanly.

**Diff: 3 deleted lines** (the markers), nothing else.

## Unblocks

- #304 — release PR for v0.15.3

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

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…#432)

## Summary

Resolves all 5 findings from the security audit in a single hardening
pass. Scoped to `apps/desktop` (plus `rehype-sanitize` added to
lockfile).

| # | Sev | Fix |
|---|-----|-----|
| 1 | **HIGH** | **Path traversal in git handlers** — `IdSchema` now
restricts notebook/note IDs to `[A-Za-z0-9_-]`; `GitService` adds
`resolveWithin()` containment checks so a resolved path can never escape
the notebooks dir. |
| 2 | **HIGH** | **LLM API key in localStorage** — settings store no
longer persists `ai.apiKey` (persist `partialize`) and strips it from
the cross-window broadcast. Key lives only in the OS keychain
(`safeStorage`); `AiPanel` rehydrates it into memory on demand. |
| 3 | **MEDIUM** | **Weak CSP** — dropped `'unsafe-eval'` from renderer
`script-src`, aligning with `settings.html`. |
| 4 | **MEDIUM** | **Unvalidated AI IPC** — bounded Zod schemas on
`ai:chat` / `ai:cancel` / `ai:validate` / `ai:tool-confirm` /
`ai:tool-renderer-result`. |
| 5 | **LOW** | **XSS surface + navigation** — `rehype-sanitize` on
`rehypeRaw` output (schema preserves `embed-image`, task checkboxes,
`className`/`data-*`, `asset://` URLs, plugin elements); global deny of
in-app navigation / `window.open`, external links routed through
`shell.openExternal`. |

## Verification

- ✅ `pnpm typecheck` (main / preload / renderer / e2e)
- ✅ `pnpm lint` (0 errors)
- ✅ `pnpm test` — 17/17 packages pass
- ✅ App boots clean in dev with all changes loaded

## Notes / follow-ups

- **CSP `img-src https:` left as-is.** Tightening it would break
legitimate remote images embedded in user notes — that's a product
decision, flagged for discussion rather than silently changed.
- **Needs a manual visual QA pass on Markdown preview** (finding #5):
syntax highlighting, `![[embed]]` images, task-list checkboxes, and
wikilinks — to confirm the sanitize schema preserves them. Automated
checks (typecheck/lint/tests) pass but can't exercise the rendered
preview.
- Pre-existing, unrelated: a CodeMirror `tags is not iterable` console
error on note open, and 38 Dependabot advisories on the default branch —
out of scope for this PR.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Security Improvements**
* Tightened app navigation and external link handling for safer
browsing.
* Added stronger protection against unsafe file paths and restricted
content rendering.

* **Bug Fixes**
* Improved AI settings recovery so saved API keys reappear more reliably
when available.
* Prevented invalid AI and note inputs from causing unexpected behavior.

* **New Features**
* Added safer handling for rendered Markdown content, including local
embedded assets.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Problem

Desktop users receive the sign-in email but **can't click the link to
log in**.

Root cause: `packages/api/src/routes/auth.ts` emailed a raw
custom-scheme URL for desktop clients:

```ts
client === 'desktop'
  ? `readied://auth/verify?token=${token}`   // ← not clickable in email
  : `https://readied.app/auth/verify?token=${token}`
```

Email clients (Gmail, Apple Mail, Outlook) only render `http(s)://` and
`mailto:` as clickable anchors — a `readied://` href is stripped or
shown as inert text.

## Fix

Always link to the **https web verify page**, which is clickable and
already performs the deep-link handoff
(`apps/web/.../auth/verify/AuthVerifyContent.tsx` redirects to
`readied://auth/verify` and shows an "Open in Readied" fallback button).
The `client` value is forwarded as a query param.

## Verification

- ✅ `pnpm --filter @readied/api typecheck`
- ✅ `pnpm lint` (0 errors)
- ✅ `pnpm --filter @readied/api test` — 42 tests pass

## Notes

- **Dev caveat:** even with the email fixed, in a dev build the
`readied://` protocol may not be registered to the unbundled Electron on
macOS, so the handoff can fail locally. The audit also flagged
`readied.app` must be deployed for the link to resolve.
- **Rename dependency:** `readied.app` and the `readied://` scheme will
change with the dripnex rename — this fix is orthogonal (it's about link
*structure*, not the brand).

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Magic-link emails now always use a clickable HTTPS verification link,
improving reliability across devices.
* Client type is included in the verification link so the sign-in flow
can adapt appropriately after email verification.
* Removed the desktop-specific deep link behavior in favor of a
consistent web-based flow.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary

First remediation pass from the multi-agent audit. Fixes the
**critical** finding plus the exploitable **high**/security items, and
adds the full prioritized roadmap (`docs/FIX_PLAN.md`).

| Sev | Finding | Fix |
|-----|---------|-----|
| **CRITICAL** | Admin routes trusted an **unverified** JWT (`atob` of
the payload) — anyone could forge admin access by setting the `email`
claim | Verify signature with `jose.jwtVerify` + `JWT_SECRET` (reuses
the `middleware/auth.ts` pattern); enforces `exp`; rejects refresh
tokens — `packages/api/src/routes/admin.ts` |
| **HIGH** | Local HTTP server auth crashed on a multibyte
`Authorization` header (`timingSafeEqual` RangeError → hung socket +
unhandled rejection) | Compare **byte** lengths (`Buffer.length`) before
`timingSafeEqual` — `localServer.ts` |
| **MED** | `editor:fetchUrlTitle` SSRF — protocol was checked but not
the host | Block loopback/private/link-local hosts (incl.
`169.254.169.254` metadata) + URL length cap — `index.ts` |
| **MED** | `TokenStorage` deleted the encrypted file on **any** decrypt
error → a transiently locked keychain permanently logged the user out |
Keep the file, return `null` until the keychain recovers; only explicit
logout clears — `tokenStorage.ts` |

Also adds **`docs/FIX_PLAN.md`** — the 61-finding prioritized
remediation plan + the phased roadmap to the local knowledge base
(AI-over-notes via RAG).

## Verification

- ✅ `pnpm --filter @readied/api typecheck` + desktop `typecheck:main`
- ✅ `pnpm lint` (0 errors)
- ✅ `pnpm test` — 17/17 packages pass

## Deferred / follow-ups

- **`ai:chat` server-side key resolution** (MED) is deferred: it edits
the same `ipc-ai.ts` as the open `fix/security-hardening` PR (#432) and
should be sequenced after that merges.
- The SSRF guard checks the literal host only — it does not defend
against DNS rebinding or a public host redirecting to an internal one. A
follow-up could resolve + pin the IP and validate each redirect hop
(noted in code).

Related: builds on the audit that also produced PR #432 (5 desktop
hardening fixes).

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Security**
* Hardened URL title fetching with stricter input limits and improved
blocking of localhost/loopback, private, link-local, and other
non-routable hosts to mitigate SSRF/loopback risks.
* Strengthened admin authentication by verifying JWTs with HS256,
validating claims, denying refresh-token types, and ensuring the
verified email matches authorized admin emails.
* **Bug Fixes**
* Improved bearer-token verification in the local server to be safer
with encoding and length mismatches.
* Improved token loading to preserve encrypted data on decrypt/parse
failures and added stricter token shape validation.
* **Documentation**
  * Added/expanded a detailed remediation and recovery roadmap plan.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Why

PR #432 was merged **without** the follow-up commit that addressed
CodeRabbit's review, so develop currently contains the flagged issues.
This PR re-applies those fixes (cherry-picked from the #432 branch).

## Fixes (from CodeRabbit review of #432)

- **nav guard**: `isInternalNavigation` compares parsed origins and
restricts `file://` to the app's `out/` dir, instead of `startsWith`
(which let `http://localhost:5174.evil.com` / `file:///etc/passwd`
through).
- **ipc-ai**: key `pendingRendererResults` by `${requestId}:${callId}` —
callId is only unique within a request, so concurrent requests could
resolve the wrong renderer-tool promise.
- **settings cross-window sync**: preserve this window's in-memory
`ai.apiKey` when applying an incoming (key-stripped) broadcast, so a
setting change in one window no longer wipes the key in others.
- **settings**: one-time scrub of any `ai.apiKey` previously persisted
to localStorage by pre-`partialize` builds.
- **AiPanel**: rehydrate the key per-provider (effect keyed on provider
only) so switching providers loads the right key.

## Verification

- ✅ typecheck (main + renderer), lint (0 errors), `pnpm --filter
@readied/desktop test` (51 pass)

Follow-up to #432. Not addressed (by design): rehype-sanitize `asset:`
on src — app-internal protocol required for embeds.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Bug Fixes**
* Fixed AI tool-result matching for concurrent tool runs so responses
are routed to the correct request.
* Strengthened internal navigation validation to block
malformed/unintended URLs and restrict file-based loads to within the
app output.
* Refined AI provider key handling: keys now refresh only when the
selected provider changes, and missing keys are cleared.
* Improved AI settings synchronization by preserving the current key
only when the provider matches, and removing any previously stored
legacy cleartext AI key on startup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary

Full product rename **Readied → Dripnex** across the monorepo (domain
`dripnex.app`). Mechanical codemod + verification. Fresh start
(pre-release): the userData dir / DB path change, so existing local
notes are intentionally **not** migrated.

## What changed
- **Package scope** `@readied/*` → `@dripnex/*` (18 packages) + every
import. (Imports were reordered — `@dripnex` sorts before `@readied`.)
- **Electron identity**: appId `app.readied.desktop` →
`app.dripnex.desktop`; userData dir `@dripnex/desktop`; DB `dripnex.db`.
- **Deep-link scheme**: `readied://` → `dripnex://` (registration +
`open-url`/`second-instance`/startup handlers + web `/auth/verify`
handoff).
- **Domains**: `readied.app` / `api.readied.app` → `dripnex.app` /
`api.dripnex.app`.
- **GitHub owner** `tomymaritano` → `dripnex` in URLs (repo stays
`readide`); electron-updater publish owner is now `dripnex/readide`.
- Brand copy, docs (README / CLAUDE.md / ROADMAP), Sentry tag, logger
`app` field, lockfile regenerated.

## Intentionally NOT renamed
- **CODEOWNERS** keeps `@tomymaritano` (real reviewer, not an org).
- **automerge.yml** owner check keeps `'tomymaritano'` (PR *author*
login; orgs don't author PRs — renaming this would silently disable
owner auto-merge).

## Verification
- ✅ `pnpm install` (workspace relinked, native rebuild OK)
- ✅ `pnpm typecheck` — 17/17
- ✅ `pnpm lint` — 0 warnings / 0 errors
- ✅ `pnpm test` — 17/17
- ✅ Desktop app **boots clean** under the dripnex identity
(`app:"dripnex"`, dataDir `@dripnex/desktop`, `dripnex.db`, IPC +
auth/sync initialized)

## Follow-ups (not in this PR)
- Docs hosting: `dripnex.github.io/readide` URLs assume GitHub Pages
under the org — confirm or point docs at `dripnex.app`.
- Deep-link `dripnex://` only registers reliably in a packaged build
(dev caveat).
- Renaming the GitHub **repo** itself (`readide` → `dripnex`) is a
separate decision.

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

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

## Summary

Resolves the **5 CodeQL `js/polynomial-redos` (high)** alerts surfaced
on develop. Each regex runs on config- or content-controlled input and
could backtrack polynomially on crafted input (hang the thread).

| File | Fix |
|------|-----|
| `packages/wikilinks/src/core/parsing.ts` | `WIKILINK_PATTERN`: bound
the three adjacent segment quantifiers to `{1,200}` (overlapping
unbounded `+` groups were the ReDoS source). 200 chars ≫ any real
target/anchor/alias. |
| `packages/ai-core/src/providers/ollama.ts` (×3) | Replace
`(baseUrl).replace(/\/+$/, '')` with a backtracking-free
`stripTrailingSlashes()` linear scan. |
| `packages/ai-core/src/retry.ts` | `/invalid.*key/` →
`/invalid.{0,80}key/` (unbounded `.*` between anchors is O(n²) with
repeated "invalid"). |

These were **pre-existing** on develop (not introduced by any recent PR)
— CodeQL re-attributed them to the large rename PR (#437), which is how
they surfaced.

## Verification
- ✅ typecheck, lint (0 warnings)
- ✅ `@dripnex/wikilinks` (17) + `@dripnex/ai-core` (128) tests pass

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved reliability of Ollama endpoint handling by normalizing server
URLs more consistently.
* Refined error detection for invalid API keys, reducing
misclassification of certain failures.
* Updated wikilink parsing to better handle long inputs and reduce the
risk of slow or problematic link matching.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
)

## Summary

The API (`routes/sync.ts`) had an **inline copy** of
`validateNotebookTree` byte-identical to the one already exported by
`@dripnex/sync-core` (same `TreeNode` / `TreeValidationResult` shapes).
Import the shared one and delete the duplicate.

- Single source of truth for the notebook-tree rules (depth ≤ 2, parent
exists, no cycles).
- **Resolves the "sync-core is dead code" finding**: the package was
previously unused; the API is now its first consumer, so it earns its
keep as the shared sync-logic source.
- First workspace dependency in the API Worker — verified it **bundles
cleanly** via `wrangler deploy --dry-run`.

## Verification
- ✅ `pnpm install`, api `typecheck`, api tests (42), lint (0)
- ✅ `wrangler deploy --dry-run` builds the Worker with the new dep

## Multi-repo note
When the repo is split, `@dripnex/sync-core` is a natural **shared
package** between the API repo and the desktop repo — this consolidation
is exactly the seam that becomes a published shared lib.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved notebook sync consistency by using a shared validation
source, reducing the chance of tree integrity mismatches during pushes.
* Kept notebook update and conflict handling behavior unchanged while
aligning validation data with the sync engine’s expected structure.

* **Chores**
* Added a shared sync package dependency to support the updated notebook
validation flow.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary

A draft **repo split plan** (`docs/SPLIT_PLAN.md`) to review with Alicio
+ the incoming team, since the direction is multi-repo as the team
grows.

Covers:
- **Why/when** to split (ownership + access control are the real
drivers, not team size) and the cost caveat (publish/version shared
packages).
- **Candidate repo seams**: `dripnex-shared` (published libs),
`dripnex-desktop`, `dripnex-api`, `dripnex-web`, `dripnex-mcp`.
- **Non-regretful extraction sequence**: Phase A groundwork in the
monorepo now (shared-models consolidation — #439/#440 done, NoteSnapshot
pending; dead-code cleanup; changesets) → Phase B publish shared package
→ Phase C extract repos.
- **Open decisions** for you + Alicio (ownership, registry, versioning,
web/mcp placement, repo naming).

Nothing is executed — groundwork first, split once ownership boundaries
are agreed with the team.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added a new repo split plan document outlining the proposed move from
a monorepo to multiple repositories.
* Includes the current app/package layout, suggested split points, a
phased extraction approach, key decisions to make, and known risks.
* Recommends completing the initial groundwork phase before starting
further repository extraction.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary

First increment of the shared-models single-source-of-truth work: export
`DEFAULT_MODEL` from `@dripnex/ai-core` and import it instead of
repeating the `'claude-sonnet-4-20250514'` literal.

Consolidated the 4 **default-model** sites:
- `stores/settings/schema.ts` (settings default)
- `components/ai/AiPanel.tsx` (×2 fallbacks)
- `main/ai/ipc-ai.ts` (validate default)
- `plugins/aiAssistant.tsx` (plugin default)

Left as-is (separate concern): model **catalog/option lists** in
`AiSection`, `aiAssistant` options, and `anthropic` model info.

## Verification
- ✅ typecheck (main + renderer), lint (0), `@dripnex/ai-core` tests
(128)

Groundwork for the shared-contracts consolidation — the same seam that
becomes a shared package when the repo is split for the incoming team.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced a shared app-wide default AI model used across desktop
settings, the AI assistant configuration, command execution, and
connection validation.
* **Bug Fixes**
* Replaced hardcoded fallback model values with the shared default to
keep behavior consistent across missing/validation flows.
* Updated available Anthropic model options to use the newer Sonnet 5
and Opus 4.8 entries instead of the previous versions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ing (#442)

## Summary

The audit found the API rate limiter was a **per-isolate in-memory Map**
— it reset on every isolate and shared no state, so in production it
didn't actually limit anything. This replaces it with **Cloudflare's
Workers Rate Limiting binding** (account-global, consistent across
isolates). Stays on Cloudflare per the platform decision.

## Changes
- `middleware/rateLimit.ts`: enforce via `env.AUTH_RL` / `env.SYNC_RL`
`.limit({key})`. Keeps the auth (10/60s) and sync (100/60s) **per-IP**
limiters; drops the unused `generalRateLimit` and the in-memory store.
**Fails open only when the binding is absent** (unit tests / local
without it) — deployed Workers always have it.
- `db/client.ts`: `RateLimitBinding` type + optional `AUTH_RL`/`SYNC_RL`
on `Env`.
- `wrangler.toml`: `[[unsafe.bindings]]` (`type = "ratelimit"`) for
default/staging/production, with **distinct `namespace_id`s per env** so
staging and production don't share counters. `period = 60` fits both
limiters; `namespace_id` is a self-assigned integer — **no resource to
provision, no migration**.

## Verification
- ✅ `pnpm --filter @dripnex/api typecheck`, 42 tests, lint (0)
- ✅ `wrangler deploy --dry-run` (default **and** `--env production`) —
both recognize `env.AUTH_RL (ratelimit)` / `env.SYNC_RL (ratelimit)`

## Notes
- The `[[unsafe.bindings]]` form emits a "unsafe fields are
experimental" wrangler warning — expected; the Workers Rate Limiting
binding still lives under `unsafe`.
- Trade-off vs the old code: the binding returns `{ success }` only, so
exact `X-RateLimit-Remaining`/`Reset` headers are dropped (kept
`X-RateLimit-Limit` + `Retry-After`). Enforcement is now real and
distributed, which is the point.
- Recommend deploying **staging first** to confirm the binding behaves
before production.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Rate limiting now uses configured edge rate-limit bindings for more
consistent enforcement across environments.
* Added separate limits for authentication and synchronization traffic.
* When rate limiting isn’t available, requests are allowed through
(fail-open).

* **Bug Fixes**
* Exceeded-limit responses now include `Retry-After` aligned to the
configured window.
* Rate-limit header behavior was adjusted to match binding-based
enforcement (no longer includes previous reset/remaining fields).

* **Configuration**
* Updated Workers rate-limit configuration for local, staging, and
production environments.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… test (#443)

## Summary

Deferred-debt cleanup (single source of truth for AI command types).

- **Delete `packages/ai-assistant/`** — an orphan with **no
`package.json`** (not a workspace, nothing imports it). Its
`aiCommandTypes.ts` was **byte-identical** to
`packages/ai-core/src/ai-command-types.ts`. (The `dripnex-ai-assistant`
references in the app are the runtime **plugin id**, unrelated to this
package.)
- **Delete `packages/ai-core/src/ai-command-types.test.ts`** — a
duplicate of `tests/ai-command-types.test.ts` (the same suite ran twice;
~28 double-counted tests). Kept the `tests/` copy to match the dir
convention.
- **Fix stale comment** in `plugin-api/src/ai/aiCommandStore.ts`:
`@dripnex/ai-assistant` → `@dripnex/ai-core` (the real source of
`AiCommandDefinition`).

## Verification
- ✅ `@dripnex/ai-core` + `@dripnex/plugin-api` typecheck, ai-core tests
(100 — the drop from 128 is the removed duplicate runs, no coverage
lost), lint (0)
- ✅ No dangling imports to `@dripnex/ai-assistant`

First of the deferred-debt items (next: changesets, then NoteSnapshot
consolidation).

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Removed AI command template, validation, and preset serialization
helpers.
  * Removed related automated test coverage.
* **Bug Fixes**
* Updated internal API documentation to match the current shared AI
command model reference.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Tomas Maritano <tm@psynth.ai>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Problem

The Auto-merge workflow enabled auto-merge on **every** owner PR on
`opened`/`synchronize`/`reopened`/`ready_for_review`. Consequences:

- PRs to `develop` had auto-merge enabled automatically, so they merged
the moment branch protection was satisfied — **before CodeRabbit review
was resolved** (the exact CodeRabbit-first violation we keep hitting).
- **Stacked PRs targeting an unprotected feature branch merged
instantly** (no protection to hold them). This is what collapsed the
stacked UI PR (#445) into its base branch before review.

## Fix

Owner auto-merge is now **opt-in via the `automerge` label**:
- The `automerge-owner` job only runs when the PR carries the
`automerge` label, and the workflow now also reacts to the `labeled`
event.
- Add the label when a PR is genuinely ready to merge; leave it off (or
remove it) to hold — no more surprise merges.
- Dependabot auto-merge is unchanged.

The `automerge` label has been created in the repo.

## Testing
Workflow-only change (YAML). Verified the `if:` uses
`contains(github.event.pull_request.labels.*.name, 'automerge')` and the
`labeled` trigger is present so applying the label enables auto-merge.

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

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated automated merge behavior to require both a matching PR author
and an automation label before merging.
* Expanded event handling so labeled pull requests are evaluated for
auto-merge eligibility.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes #311

## Why

The packaged editor crashed on first note with `[CodeMirror] plugin
error: TypeError: tags is not iterable`. Two things had to be true at
once:

1. **The Vite config was never loaded.** The file was named
`electron-vite.config.ts`; electron-vite only reads
`electron.vite.config.ts`. `optimizeDeps.include` and every other
renderer option were no-ops.
2. **Two `@lezer/common` copies** (1.5.0 nested under
`@lezer/highlight`, 1.5.2 under language/markdown). Each has its own
`NodeProp`, so `HighlightStyle.style` received `undefined`.

Chunk splitting alone did not fix it — the smoke test still went red
until common was pinned.

## What

- Rename the config so electron-vite actually loads it
- `manualChunks`: `@codemirror/*` + `@lezer/*` → `codemirror`
- `resolve.dedupe` + alias `@lezer/common` to the desktop copy
- pnpm override `@lezer/common@1.5.2` and add it as a desktop dependency
- Smoke: click “Create Your First Note”, wait for `.cm-content`, fail if
`[CodeMirror]` appears in the console
- Main/preload stay on electron-vite 5 defaults (`externalizeDeps:
true`) so `better-sqlite3` is not inlined

## Verify

```
pnpm --filter @dripnex/desktop build
# one @lezer/common region in out/renderer/assets/codemirror-*.js
pnpm --filter @dripnex/desktop e2e
# smoke 3 passed, notes 2 passed
```

Local e2e needs `better-sqlite3` rebuilt for Electron 41
(`electron-rebuild --force --only better-sqlite3`).

## Deploy order

Desktop only. No contract change for other repos.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Improved reliability when opening notes with the CodeMirror editor,
including lazy-loaded editor content.
  - Prevented related console and page errors during note editing.

- **Tests**
- Added automated coverage to verify note creation and editor rendering
work as expected.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Closes #314

## Why

`.cm-table-visual` / `.sortable-table` were `width: 100%` with no
`max-width` and no wrapping on cells. `.cm-table-widget` set
`overflow-x: auto` then overwrote it with `overflow: hidden`, so long
cells painted past the pane.

## What

- `max-width: 100%` on both table classes
- `overflow-wrap` / `word-break` on `th`/`td`
- Keep `overflow-x: auto` on the editor wrapper; add
`.sortable-table-wrap` for preview
- Line decoration `.cm-table-range` over every table (including the one
under the cursor)
- No hard pixel cell widths
- Unit test for `findTableRanges`; e2e inserts a wide table and asserts
the widget is not wider than `.cm-scroller`

**Note:** real per-range no-wrap while editing is deferred to the
plugin-tables extraction. Editor-global `lineWrapping` still wraps raw
pipe rows.

The e2e opens the packaged editor, so it depends on #466 landing (or a
local Electron rebuild of `better-sqlite3`).

## Verify

```
pnpm --filter @dripnex/desktop exec vitest run src/renderer/plugins/__tests__/tables.test.ts
pnpm --filter @dripnex/desktop typecheck:renderer
```
Closes #313

## Why

The Account Sign In button stayed disabled forever when
`auth:getSession` hung (no `AbortSignal` on `fetch`). `Button` disables
on `loading`, and `loading` was the session-restore `isLoading` flag.

## What

- `AbortSignal.timeout(15_000)` on request + refresh
- Abort → `ApiError("Request timed out")`; refresh abort is `network`,
never `expired` (tokens stay)
- Sign In is no longer gated on session restore; it only opens
`MagicLinkFlow`
- Render `authStore.error` in Account
- Vitest for timeout mapping + no token wipe

## Verify

```
pnpm --filter @dripnex/desktop exec vitest run src/main/services/__tests__/apiClient.test.ts
pnpm --filter @dripnex/desktop typecheck:main
pnpm --filter @dripnex/desktop typecheck:renderer
```
Closes #312

## Why

\`partialize\` already stopped writing \`ai.apiKey\` to localStorage,
but nothing loaded the key from \`safeStorage\` at boot except AiPanel
(and AiSection had no \`.catch\`). After restart or a locked keychain
the key vanished or failed silently.

## What

- Boot-time \`getKey(provider)\` into the in-memory store
- Failures set \`aiKeyHydrationError\` and render in AiSection
- AiSection \`loadKeyForProvider\` catch → \`connectError\`
- Broadcast still strips the key (already in place)
- Vitest: \`partializeSettings\` keeps provider, never the secret

## Verify

\`\`\`
pnpm --filter @dripnex/desktop exec vitest run
src/renderer/stores/settings/__tests__/settingsStore.test.ts
pnpm --filter @dripnex/desktop typecheck:renderer
\`\`\`
Closes #310

## Why

\`updates:installNow\` destroys every window then calls
\`quitAndInstall()\` while \`consumeStream()\` still has a 50ms batch
timer and pending iterations. \`flush()\` was guarded; the non-text
\`sender.send('ai:event')\`, tool-confirm send, and renderer-tool send
were not. Same TOCTOU on deep-link handlers that checked
\`win.isDestroyed()\` but not \`webContents.isDestroyed()\`.

## What

- \`safeSend()\`: skip + WARN \`dropped IPC send: webContents
destroyed\` (no throw)
- Unguarded sends replaced; non-text branch aborts+breaks on drop
- \`activeStreamHandles\` + \`abortAllStreams()\` called before window
destroy
- Deep-link finds also require \`!webContents.isDestroyed()\`
- No \`process.on('uncaughtException')\` swallow
- Vitest: fake sender dies mid-stream (fake timers) → no throw, abort,
warn

## Verify

\`\`\`
pnpm --filter @dripnex/desktop exec vitest run
src/main/ai/__tests__/ipc-ai.test.ts
pnpm --filter @dripnex/desktop typecheck:main
\`\`\`
Closes #309
Supersedes #447 (that PR still left \`continue-on-error: true\`)

## Why

The shared \`setup\` job uses \`pnpm install --frozen-lockfile
--ignore-scripts\`. Restoring that cache means \`electron.launch()\`
fails for every test (\`Electron failed to install correctly\`) and
\`continue-on-error: true\` hid the red.

## What

- e2e job does its own \`pnpm install --frozen-lockfile\` (scripts on)
- \`node node_modules/electron/install.js\` in \`apps/desktop\`
- \`pnpm --filter @dripnex/desktop exec electron-builder
install-app-deps\`
- \`continue-on-error\` removed — this check is required
- Playwright report upload on failure kept

This PR's own CI run is the proof. Do not merge if the e2e job is red.
Closes #316 (code side). Does **not** rotate the PAT — that is a secret
you have to mint in the GitHub UI.
Feeds #315 / #317.

## What

- \`sync-develop\` no longer swallows errors with \`|| echo\`. If a PR
is already open it exits 0; any other \`gh pr create\` failure is red.
- \`RELEASES.md\` now describes the real pipeline (promotion PR →
Release workflow → tag → Build & Publish) and how to rotate
\`GH_TOKEN\`.
- Packaged-app checklist for v0.15.4 is in that file so the promotion PR
can record results.

## You still need to do

Create a fine-grained PAT (contents:write + pull-requests:write) on the
\`dripnex\` org for \`readide\`, and replace the repo secret
\`GH_TOKEN\`. The current secret is from 2026-01-03 and is what broke
v0.15.3.

Until the next tag auto-starts Build & Publish, the fallback remains:

\`\`\`
gh workflow run "Build & Publish" --ref v0.15.4
\`\`\`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Prevented duplicate pull requests when synchronizing the main and
development branches.
  * Improved error reporting for failed pull-request creation.

* **Documentation**
* Updated release instructions to reflect automated publishing and
branch synchronization.
  * Added guidance for required release permissions and token rotation.
* Documented packaged macOS update and application verification checks.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 358 files, which is 258 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c0ac702b-2db6-4ed8-b217-a3361fe72c59

📥 Commits

Reviewing files that changed from the base of the PR and between 1cb1640 and 354e7c7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (358)
  • .coderabbit.yaml
  • .github/CONTRIBUTING.md
  • .github/FUNDING.yml
  • .github/ISSUE_TEMPLATE/bug_report.md
  • .github/ISSUE_TEMPLATE/config.yml
  • .github/ISSUE_TEMPLATE/feature_request.md
  • .github/RELEASE.md
  • .github/workflows/automerge.yml
  • .github/workflows/build.yml
  • .github/workflows/ci.yml
  • .github/workflows/codeql.yml
  • .github/workflows/deploy-api.yml
  • .github/workflows/docs.yml
  • .github/workflows/pr-title.yml
  • .github/workflows/release.yml
  • .mcp.json
  • .prettierignore
  • CHANGELOG.md
  • CLAUDE.md
  • CODE_OF_CONDUCT.md
  • CONTRIBUTING.md
  • README.md
  • ROADMAP.md
  • SECURITY.md
  • apps/desktop/RELEASES.md
  • apps/desktop/e2e/README.md
  • apps/desktop/e2e/fixtures.ts
  • apps/desktop/e2e/notes.spec.ts
  • apps/desktop/e2e/smoke.spec.ts
  • apps/desktop/e2e/tables.spec.ts
  • apps/desktop/electron-vite.config.ts
  • apps/desktop/electron.vite.config.ts
  • apps/desktop/package.json
  • apps/desktop/playwright.config.ts
  • apps/desktop/src/main/ai/__tests__/ipc-ai.test.ts
  • apps/desktop/src/main/ai/built-in-tools.ts
  • apps/desktop/src/main/ai/ipc-ai.ts
  • apps/desktop/src/main/ai/setup.ts
  • apps/desktop/src/main/handlers/authSyncHandlers.ts
  • apps/desktop/src/main/handlers/dataHandlers.ts
  • apps/desktop/src/main/handlers/gitHandlers.ts
  • apps/desktop/src/main/handlers/licenseHandlers.ts
  • apps/desktop/src/main/handlers/localServerHandlers.ts
  • apps/desktop/src/main/handlers/noteHandlers.ts
  • apps/desktop/src/main/handlers/notebookHandlers.ts
  • apps/desktop/src/main/handlers/types.ts
  • apps/desktop/src/main/handlers/updateHandlers.ts
  • apps/desktop/src/main/index.ts
  • apps/desktop/src/main/logger.ts
  • apps/desktop/src/main/pluginScanner.ts
  • apps/desktop/src/main/pluginWatcher.ts
  • apps/desktop/src/main/sentry.ts
  • apps/desktop/src/main/services/__tests__/apiClient.test.ts
  • apps/desktop/src/main/services/apiClient.ts
  • apps/desktop/src/main/services/encryptionService.ts
  • apps/desktop/src/main/services/fileLicenseStorage.ts
  • apps/desktop/src/main/services/gitService.ts
  • apps/desktop/src/main/services/localServer.ts
  • apps/desktop/src/main/services/sync/SyncService.ts
  • apps/desktop/src/main/services/tokenStorage.ts
  • apps/desktop/src/preload/api/types.ts
  • apps/desktop/src/preload/index.ts
  • apps/desktop/src/renderer/App.tsx
  • apps/desktop/src/renderer/components/CommandPalette.tsx
  • apps/desktop/src/renderer/components/ErrorBoundary/ErrorBoundary.tsx
  • apps/desktop/src/renderer/components/MarkdownEditor.tsx
  • apps/desktop/src/renderer/components/NoteEditor.tsx
  • apps/desktop/src/renderer/components/NoteList.tsx
  • apps/desktop/src/renderer/components/NoteListFilterBar.tsx
  • apps/desktop/src/renderer/components/NoteWindow.tsx
  • apps/desktop/src/renderer/components/QuickCapture.tsx
  • apps/desktop/src/renderer/components/UpdateBanner.tsx
  • apps/desktop/src/renderer/components/Welcome.tsx
  • apps/desktop/src/renderer/components/ai/AiPanel.tsx
  • apps/desktop/src/renderer/components/auth/MagicLinkFlow.tsx
  • apps/desktop/src/renderer/components/editor/ActionsPanel/ActionsPanel.tsx
  • apps/desktop/src/renderer/components/editor/MarkdownPreview.tsx
  • apps/desktop/src/renderer/components/editor/RevisionHistoryPanel/RevisionHistoryPanel.tsx
  • apps/desktop/src/renderer/components/editorTheme.ts
  • apps/desktop/src/renderer/components/git/CommitHistory.tsx
  • apps/desktop/src/renderer/components/sidebar/NotebookItem.tsx
  • apps/desktop/src/renderer/components/sidebar/Sidebar.tsx
  • apps/desktop/src/renderer/components/sidebar/TagsList.tsx
  • apps/desktop/src/renderer/components/sync/EnableSyncModal.tsx
  • apps/desktop/src/renderer/contexts/LicenseContext.tsx
  • apps/desktop/src/renderer/hooks/useAppCommands.ts
  • apps/desktop/src/renderer/hooks/useAppearanceSettings.ts
  • apps/desktop/src/renderer/hooks/useCommandKeybindings.ts
  • apps/desktop/src/renderer/hooks/useCommandRegistry.ts
  • apps/desktop/src/renderer/hooks/useDeepLinks.ts
  • apps/desktop/src/renderer/hooks/useEmbedResolver.ts
  • apps/desktop/src/renderer/hooks/useLinks.ts
  • apps/desktop/src/renderer/hooks/useManualTags.ts
  • apps/desktop/src/renderer/hooks/useNoteActions.ts
  • apps/desktop/src/renderer/hooks/useNotebooks.ts
  • apps/desktop/src/renderer/hooks/useNotes.ts
  • apps/desktop/src/renderer/hooks/useRegisterAiCommands.ts
  • apps/desktop/src/renderer/hooks/useRegisterAppCommands.ts
  • apps/desktop/src/renderer/hooks/useRegisterPluginAiCommands.ts
  • apps/desktop/src/renderer/hooks/useResizableLayout.ts
  • apps/desktop/src/renderer/index.html
  • apps/desktop/src/renderer/pages/settings/sections/AboutSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/AccountSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/AiSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/AppearanceSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/BackupSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/DevicesSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/GeneralSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/UpdatesSection.tsx
  • apps/desktop/src/renderer/pages/settings/sections/plugins/BrowseTab.tsx
  • apps/desktop/src/renderer/pages/settings/sections/plugins/PluginInspector.tsx
  • apps/desktop/src/renderer/pages/settings/sections/plugins/index.tsx
  • apps/desktop/src/renderer/plugins/__tests__/tables.test.ts
  • apps/desktop/src/renderer/plugins/activeLineHighlight.ts
  • apps/desktop/src/renderer/plugins/aiAssistant.tsx
  • apps/desktop/src/renderer/plugins/exportMarkdown.ts
  • apps/desktop/src/renderer/plugins/focusMode.ts
  • apps/desktop/src/renderer/plugins/index.ts
  • apps/desktop/src/renderer/plugins/math.tsx
  • apps/desktop/src/renderer/plugins/mermaid.tsx
  • apps/desktop/src/renderer/plugins/readingTime.tsx
  • apps/desktop/src/renderer/plugins/tables.tsx
  • apps/desktop/src/renderer/plugins/typewriterMode.ts
  • apps/desktop/src/renderer/plugins/vimMode.tsx
  • apps/desktop/src/renderer/plugins/wordCount.tsx
  • apps/desktop/src/renderer/settings.html
  • apps/desktop/src/renderer/stores/authStore.ts
  • apps/desktop/src/renderer/stores/editorPreferencesStore.ts
  • apps/desktop/src/renderer/stores/pluginRuntimeStore.ts
  • apps/desktop/src/renderer/stores/settings/__tests__/settingsStore.test.ts
  • apps/desktop/src/renderer/stores/settings/schema.ts
  • apps/desktop/src/renderer/stores/settings/settingsStore.ts
  • apps/desktop/src/renderer/stores/shareStore.ts
  • apps/desktop/src/renderer/stores/syncStore.ts
  • apps/desktop/src/renderer/stores/tagColorsStore.ts
  • apps/desktop/src/renderer/styles/README.md
  • apps/desktop/src/renderer/styles/code-highlight.css
  • apps/desktop/src/renderer/styles/global.css
  • apps/desktop/src/renderer/styles/tables.css
  • apps/desktop/src/renderer/ui/README.md
  • apps/desktop/src/renderer/ui/tokens/tokens.css
  • apps/web/app/(dashboard)/dashboard/DashboardContent.tsx
  • apps/web/app/(dashboard)/dashboard/page.tsx
  • apps/web/app/(marketing)/auth/verify/AuthVerifyContent.tsx
  • apps/web/app/(marketing)/changelog/page.tsx
  • apps/web/app/(marketing)/download/page.tsx
  • apps/web/app/(marketing)/faq/page.tsx
  • apps/web/app/(marketing)/newsletter/unsubscribe/UnsubscribeContent.tsx
  • apps/web/app/(marketing)/newsletter/unsubscribe/page.tsx
  • apps/web/app/(marketing)/philosophy/page.tsx
  • apps/web/app/(marketing)/plugins/page.tsx
  • apps/web/app/(marketing)/pricing/page.tsx
  • apps/web/app/(marketing)/privacy/page.tsx
  • apps/web/app/(marketing)/shared/SharedNoteContent.tsx
  • apps/web/app/(marketing)/shared/page.tsx
  • apps/web/app/(marketing)/subscribe/page.tsx
  • apps/web/app/(marketing)/subscription/cancel/page.tsx
  • apps/web/app/(marketing)/subscription/success/page.tsx
  • apps/web/app/(marketing)/terms/page.tsx
  • apps/web/app/docs/[[...slug]]/page.tsx
  • apps/web/app/docs/layout.tsx
  • apps/web/app/layout.tsx
  • apps/web/app/not-found.tsx
  • apps/web/components/Footer.tsx
  • apps/web/components/Navbar.tsx
  • apps/web/components/NewsletterForm.tsx
  • apps/web/components/PluginFilter.tsx
  • apps/web/components/SubscribeFlow.tsx
  • apps/web/components/landing/CreatorStory.tsx
  • apps/web/components/landing/Features.tsx
  • apps/web/components/landing/Hero.tsx
  • apps/web/components/landing/SocialProof.tsx
  • apps/web/components/landing/Testimonials.tsx
  • apps/web/components/landing/VideoGuides.tsx
  • apps/web/components/landing/WhyLocal.tsx
  • apps/web/components/magicui/animated-beam.tsx
  • apps/web/components/magicui/animated-grid-pattern.tsx
  • apps/web/components/magicui/border-beam.tsx
  • apps/web/components/magicui/dot-pattern.tsx
  • apps/web/components/magicui/hero-video-dialog.tsx
  • apps/web/components/magicui/marquee.tsx
  • apps/web/components/magicui/number-ticker.tsx
  • apps/web/components/magicui/shimmer-button.tsx
  • apps/web/components/magicui/text-reveal.tsx
  • apps/web/content/docs/architecture/core.mdx
  • apps/web/content/docs/architecture/editor.mdx
  • apps/web/content/docs/architecture/ipc.mdx
  • apps/web/content/docs/architecture/overview.mdx
  • apps/web/content/docs/architecture/storage.mdx
  • apps/web/content/docs/architecture/theming.mdx
  • apps/web/content/docs/decisions/adr-001-runtime-contract.mdx
  • apps/web/content/docs/decisions/adr-003-storage.mdx
  • apps/web/content/docs/decisions/index.mdx
  • apps/web/content/docs/guide/built-in-plugins.mdx
  • apps/web/content/docs/guide/getting-started.mdx
  • apps/web/content/docs/guide/principles.mdx
  • apps/web/content/docs/guide/sync.mdx
  • apps/web/content/docs/index.mdx
  • apps/web/content/docs/plugins/api-reference.mdx
  • apps/web/content/docs/plugins/examples.mdx
  • apps/web/content/docs/plugins/getting-started.mdx
  • apps/web/content/docs/plugins/layout-zones.mdx
  • apps/web/content/docs/plugins/tutorial.mdx
  • apps/web/data/plugins.json
  • apps/web/lib/github.ts
  • apps/web/lib/layout.shared.tsx
  • apps/web/next.config.mjs
  • apps/web/package.json
  • docs/BRAND.md
  • docs/FIX_PLAN.md
  • docs/PLUGIN_SYSTEM.md
  • docs/ROADMAP.md
  • docs/SPLIT_PLAN.md
  • docs/adr/001-git-backed-notes.md
  • docs/architecture-audit.md
  • docs/archived/plans-2026/2026-02-18-marketing-site-redesign-design.md
  • docs/archived/plans-2026/2026-02-18-marketing-site-redesign.md
  • docs/archived/plans-2026/2026-02-19-phase1-fix-and-polish.md
  • docs/archived/plans-2026/2026-02-19-phase2-plugin-marketplace.md
  • docs/archived/plans-2026/2026-02-19-plugin-ecosystem-design.md
  • docs/archived/plans-2026/2026-03-11-data-access-api-design.md
  • docs/archived/plans-2026/2026-03-11-data-access-api-implementation.md
  • docs/archived/plans-2026/2026-03-11-notebook-sync-implementation.md
  • docs/archived/plans-2026/2026-03-11-phase2-completion-design.md
  • docs/archived/plans-2026/2026-03-11-phase2-completion-implementation.md
  • docs/archived/plans-2026/2026-03-11-remark-rehype-hooks-enhancement.md
  • docs/archived/plans-2026/2026-03-11-sync-hardening-implementation.md
  • docs/archived/plans-2026/2026-03-11-theme-system-design.md
  • docs/archived/plans-2026/2026-03-11-theme-system-implementation.md
  • docs/archived/plans-2026/2026-03-12-roadmap-auth-sync-ai.md
  • docs/archived/plans-2026/2026-03-12-website-redesign-design.md
  • docs/archived/plans-2026/2026-03-12-website-redesign-implementation.md
  • docs/archived/plans-2026/api-reference.md
  • docs/archived/superpowers-2026/2026-03-14-ai-core-provider-abstraction-design.md
  • docs/archived/superpowers-2026/2026-03-14-ai-core-provider-abstraction.md
  • docs/archived/superpowers-2026/2026-03-14-automated-release-pipeline-design.md
  • docs/archived/superpowers-2026/2026-03-14-automated-release-pipeline.md
  • docs/archived/superpowers-2026/2026-03-18-ai-tool-use-design.md
  • docs/archived/superpowers-2026/2026-03-18-ai-tool-use.md
  • docs/domain-invariants.md
  • docs/marketing-content.md
  • docs/philosophy.md
  • docs/tables-plugin.md
  • eslint.config.js
  • knip.json
  • package.json
  • packages/ai-assistant/src/aiCommandTypes.test.ts
  • packages/ai-assistant/src/aiCommandTypes.ts
  • packages/ai-core/package.json
  • packages/ai-core/src/ai-command-types.test.ts
  • packages/ai-core/src/context-builder.ts
  • packages/ai-core/src/index.ts
  • packages/ai-core/src/providers/anthropic.ts
  • packages/ai-core/src/providers/ollama.ts
  • packages/ai-core/src/retry.ts
  • packages/api/README.md
  • packages/api/SETUP.md
  • packages/api/docs/DEPLOYMENT.md
  • packages/api/docs/OBSERVABILITY.md
  • packages/api/docs/STRIPE_WEBHOOKS.md
  • packages/api/package.json
  • packages/api/src/db/client.ts
  • packages/api/src/db/schema.ts
  • packages/api/src/index.ts
  • packages/api/src/middleware/rateLimit.ts
  • packages/api/src/routes/admin.ts
  • packages/api/src/routes/auth.ts
  • packages/api/src/routes/share.ts
  • packages/api/src/routes/subscription.ts
  • packages/api/src/routes/sync.ts
  • packages/api/src/services/email.ts
  • packages/api/tests/encryption-roundtrip.test.ts
  • packages/api/tests/helpers.ts
  • packages/api/tests/sync-notebooks.test.ts
  • packages/api/tests/sync-pull.test.ts
  • packages/api/tests/sync-push.test.ts
  • packages/api/tests/sync-status.test.ts
  • packages/api/tests/sync-tags.test.ts
  • packages/api/wrangler.toml
  • packages/command-registry/package.json
  • packages/commands/package.json
  • packages/commands/src/index.ts
  • packages/commands/src/markdown/commands.test.ts
  • packages/core/package.json
  • packages/core/src/domain/invariants.ts
  • packages/core/src/domain/types.ts
  • packages/core/src/index.ts
  • packages/embeds/package.json
  • packages/embeds/src/index.ts
  • packages/licensing/README.md
  • packages/licensing/package.json
  • packages/licensing/src/trial.ts
  • packages/mcp-server/package.json
  • packages/mcp-server/src/__tests__/fts5-triggers.test.ts
  • packages/mcp-server/src/db.ts
  • packages/mcp-server/src/index.ts
  • packages/mcp-server/tsconfig.build.json
  • packages/mcp-server/tsconfig.json
  • packages/plugin-api/package.json
  • packages/plugin-api/src/ai/aiCommandStore.ts
  • packages/plugin-cli/package.json
  • packages/plugin-cli/src/cli.ts
  • packages/plugin-cli/src/commands/install.ts
  • packages/plugin-cli/src/commands/link.ts
  • packages/plugin-cli/src/commands/uninstall.ts
  • packages/plugin-cli/src/templates/index.ts.ts
  • packages/plugin-cli/src/templates/manifest.json.ts
  • packages/plugin-cli/src/templates/package.json.ts
  • packages/plugin-cli/src/utils.ts
  • packages/plugin-cli/tests/init.test.ts
  • packages/product-config/package.json
  • packages/product-config/src/pricing.ts
  • packages/product-config/src/urls.ts
  • packages/storage-core/package.json
  • packages/storage-core/src/data/DataPaths.ts
  • packages/storage-core/src/data/Import.ts
  • packages/storage-core/src/index.ts
  • packages/storage-core/src/interfaces/ExtendedNoteRepository.ts
  • packages/storage-core/src/repositories/InMemoryNoteRepository.ts
  • packages/storage-core/tests/in-memory-repository.test.ts
  • packages/storage-sqlite/package.json
  • packages/storage-sqlite/src/database.ts
  • packages/storage-sqlite/src/index.ts
  • packages/storage-sqlite/src/migrations/001_initial_schema.ts
  • packages/storage-sqlite/src/migrations/002_add_archived_at.ts
  • packages/storage-sqlite/src/migrations/003_notebooks.ts
  • packages/storage-sqlite/src/migrations/004_note_fields.ts
  • packages/storage-sqlite/src/migrations/005_manual_tags.ts
  • packages/storage-sqlite/src/migrations/006_tag_colors.ts
  • packages/storage-sqlite/src/migrations/007_links.ts
  • packages/storage-sqlite/src/migrations/008_fts5_index.ts
  • packages/storage-sqlite/src/migrations/009_link_anchors.ts
  • packages/storage-sqlite/src/migrations/010_sync_fields.ts
  • packages/storage-sqlite/src/migrations/011_sync_tracking.ts
  • packages/storage-sqlite/src/migrations/012_git_notebooks.ts
  • packages/storage-sqlite/src/migrations/013_plugin_config.ts
  • packages/storage-sqlite/src/migrations/014_plugin_registry.ts
  • packages/storage-sqlite/src/migrations/015_notebook_sync_tracking.ts
  • packages/storage-sqlite/src/migrations/016_tag_sync_tracking.ts
  • packages/storage-sqlite/src/migrations/017_sync_history.ts
  • packages/storage-sqlite/src/migrations/index.ts
  • packages/storage-sqlite/src/repositories/SQLiteNoteRepository.ts
  • packages/storage-sqlite/src/repositories/SQLiteNotebookRepository.ts
  • packages/storage-sqlite/src/repositories/noteMapping.ts
  • packages/storage-sqlite/tests/repository.test.ts
  • packages/sync-core/package.json
  • packages/sync-core/src/engine.ts
  • packages/sync-core/src/index.ts
  • packages/sync-core/tests/engine.test.ts
  • packages/tasks/package.json
  • packages/tasks/src/index.ts
  • packages/wikilinks/package.json
  • packages/wikilinks/src/core/parsing.ts
  • packages/wikilinks/src/index.ts
  • plan.md
  • release.config.js
  • scripts/bump-version.mjs
  • vercel.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@tomymaritano

Copy link
Copy Markdown
Collaborator Author

No mergear. Es un promote viejo develop→main (v0.15.4) y está en conflicto. El land actual es #475. Cuando #475 entre a develop, el promote correcto es develop→staging→main (merge commit, sin squash).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant