fix(release): cut v0.15.4 — E1 packaged editor and desktop bugs - #474
Closed
tomymaritano wants to merge 251 commits into
Closed
fix(release): cut v0.15.4 — E1 packaged editor and desktop bugs#474tomymaritano wants to merge 251 commits into
tomymaritano wants to merge 251 commits into
Conversation
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
feat: add bidirectional tag sync
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>
…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 -->
|
Important Review skippedToo 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (358)
You can disable this status message by setting the 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. Comment |
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
.appviaelectron-builder --dir --mac --arm64(unsigned, no notarize), launched with Playwright againstDripnex.app:tags is not iterable/[CodeMirror] plugin error. Table rendered as WYSIWYG widget. After the first pack, aRanges must be added sortederror showed; fixed in chore(release): fail loud on sync-develop + runbook #472 (widget XOR line marks). Re-pack: 0 range errors.partialize+ boot hydrate are covered by unit tests;dripnex-settingsstripsapiKey..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 checkwebContents.isDestroyed()(fix(desktop): drop AI IPC after window destroy #470).After merge
GH_TOKEN(fine-grained PAT: contents + pull-requests + actions write). Current secret is from 2026-01-03 and broke v0.15.3.main.gh workflow run "Build & Publish" --ref v0.15.4.#316
Code side landed in #472 (
|| echogone). PAT rotation is still a human step in the GitHub UI.