fix(desktop): pin electron to ^41.7.1 for better-sqlite3 prebuild compat (Phase 0 A1)#290
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 6 minutes and 6 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe electron development dependency in the desktop application package is downgraded from version ChangesElectron Dependency Version
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~2 minutes Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
…hase 0 A2) (#291) ## Summary Phase 0 A2. Restores the version-bump step semantic-release needs to actually write the new version into the package.json files BEFORE the git plugin commits them. ## What was broken The v0.15.0 tag points at a commit where both \`package.json\` and \`apps/desktop/package.json\` still read \`0.14.0\`: \`\`\` $ git show v0.15.0:package.json | jq -r .version 0.14.0 $ git show v0.15.0:apps/desktop/package.json | jq -r .version 0.14.0 \`\`\` Symptom: electron-updater sees mismatched versions; any consumer reading from package.json drifts from the tag; ship-it-and-forget-it release becomes "wait, what version is this?". ### Why semantic-release pipeline is a chain. Each plugin has a contract. | Plugin | Contract | |---|---| | \`commit-analyzer\` | decides next version | | \`release-notes-generator\` | writes release notes | | \`changelog\` | mutates CHANGELOG.md | | \`exec.prepareCmd\` | **mutates package.json (this step was missing)** | | \`git\` | commits the mutated files via \`assets:\` list | | \`github\` | creates draft release | The \`assets:\` list in \`@semantic-release/git\` ONLY commits files; it doesn't create the diff. Without an explicit mutation step, the git plugin sees no changes to package.json and commits an effectively empty diff (just the CHANGELOG update). The original \`scripts/bump-version.js\` performed that mutation, wired via \`@semantic-release/exec\`. It was deleted in the knip cleanup (#279) under the false assumption nothing referenced it — knip didn't scan \`release.config.js\` as an entry point. PR #289 patched \`release.config.js\` to remove the dangling \`prepareCmd\`, which made the workflow stop crashing but left versions stale. ## Fix 1. **\`scripts/bump-version.mjs\`** (new) — pure-ESM, zero dependencies, updates ONLY the \`version\` field of exactly two files (\`package.json\` and \`apps/desktop/package.json\`). Preserves existing trailing-newline. Fails non-zero on missing version arg, unparseable JSON, or absent version field. 2. **\`release.config.js\`** — re-wires the \`@semantic-release/exec\` plugin (already a devDep) with \`prepareCmd: 'node scripts/bump-version.mjs \${nextRelease.version}'\`. Comment block in the file documents the history so the next maintainer doesn't repeat the mistake. Packages with independent release cycles (notably \`packages/api\` on Cloudflare Workers, \`packages/mcp-server\`) are deliberately NOT in the target list. If we ever need to bump them, that's a separate concern with a separate script. ## Verification \`\`\` $ node scripts/bump-version.mjs 0.15.1 bump-version: package.json 0.14.0 -> 0.15.1 bump-version: apps/desktop/package.json 0.14.0 -> 0.15.1 bump-version: updated 2 of 2 target(s) \`\`\` Edge cases: - \`node scripts/bump-version.mjs\` (no arg) → \`missing version argument\`, exit 1 - \`node scripts/bump-version.mjs 0.14.0\` (already at version) → \`already at 0.14.0, skipped\`, exit 0 - Same version on already-bumped files → idempotent, no diff - ✅ \`pnpm -r typecheck\` — green - ✅ \`pnpm test\` — 17/17 packages ## Stack context Phase 0 A2 of the post-audit devops roadmap. Pairs with #290 (A1, electron pin). 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>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop/package.json`:
- Line 78: Add an inline comment next to the "electron": "^41.7.1" dependency in
apps/desktop/package.json explaining that the Electron version is intentionally
pinned to 41.x as a temporary workaround for better-sqlite3 prebuild
compatibility (reference WiseLibs/better-sqlite3#1470), include the date or
PR/issue that motivated the pin and a note to revisit/unpin when the upstream
fix is available; update the comment when you later remove the pin.
- Line 78: Update the package.json electron dependency entry ("electron":
"^41.7.1") to include a short follow-up: add a comment or project note (e.g., in
package.json's "comments" field or repo docs/changelog) documenting the
downgrade rationale and the prebuild workaround for better-sqlite3, and consider
tightening the version specifier (remove caret or pin to "41.7.1") if prebuilds
only support specific 41.x releases; modify the "electron" dependency line and
add the tracking note in the repository docs or package metadata accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b6f7260f-c58a-4c89-8463-36fe4ea7cc06
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (1)
apps/desktop/package.json
| "@playwright/test": "^1.49.1", | ||
| "@vitejs/plugin-react": "^6.0.2", | ||
| "electron": "^42.3.3", | ||
| "electron": "^41.7.1", |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Consider adding an inline comment documenting the version constraint.
To help future maintainers understand why Electron is pinned to 41.x, consider adding a comment explaining that this is a temporary workaround for better-sqlite3 prebuild compatibility (WiseLibs/better-sqlite3#1470).
📝 Suggested documentation addition
+ // TODO: Upgrade to ^42.x when better-sqlite3 restores Electron 42 prebuilds
+ // See: https://github.com/WiseLibs/better-sqlite3/issues/1470
"electron": "^41.7.1",🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/package.json` at line 78, Add an inline comment next to the
"electron": "^41.7.1" dependency in apps/desktop/package.json explaining that
the Electron version is intentionally pinned to 41.x as a temporary workaround
for better-sqlite3 prebuild compatibility (reference
WiseLibs/better-sqlite3#1470), include the date or PR/issue that motivated the
pin and a note to revisit/unpin when the upstream fix is available; update the
comment when you later remove the pin.
🧹 Nitpick | 🔵 Trivial
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify Electron 41.7.1 exists and check for security advisories
echo "=== Checking Electron 41.7.1 availability on npm ==="
npm view electron@41.7.1 version 2>/dev/null || echo "Version 41.7.1 not found"
echo -e "\n=== Checking latest Electron 41.x version ==="
npm view electron@^41.0.0 version
echo -e "\n=== Checking for Electron security advisories ==="
gh api graphql -f query='
{
securityVulnerabilities(first: 10, ecosystem: NPM, package: "electron") {
nodes {
advisory {
summary
severity
publishedAt
}
vulnerableVersionRange
firstPatchedVersion {
identifier
}
}
}
}'Repository: tomymaritano/readide
Length of output: 3359
🌐 Web query:
better-sqlite3 12.10.0 Electron 41 prebuild support compatibility
💡 Result:
Better-sqlite3 version 12.10.0 provides full support and prebuilt binaries for Electron 41 [1][2]. Compatibility for Electron 41 was introduced in the 12.x release cycle to address V8 API breaking changes, specifically the removal of PropertyCallbackInfo::This in newer V8 versions used by Electron 41 [3]. The library was updated to use Holder instead, and further adjustments were made to ensure compatibility with V8 API evolutions [3][4]. As of June 9, 2026, the CI build configuration in version 12.10.0 explicitly includes prebuild targets for Electron 41.0.0 [2]. While recent efforts have also explored support for Electron 42, that support has been temporarily rolled back due to unresolved build issues, leaving Electron 41 as a supported, stable target in the current version [5][6].
Citations:
- 1: https://github.com/WiseLibs/better-sqlite3/releases/tag/v12.10.0
- 2: WiseLibs/better-sqlite3@v12.9.1...v12.10.0
- 3: fix: use Holder() instead of This() for Electron 41 compatibility WiseLibs/better-sqlite3#1456
- 4: WiseLibs/better-sqlite3@v12.6.2...v12.8.0
- 5: Temporarily rollback support for Electron v42 prebuilds WiseLibs/better-sqlite3#1470
- 6: Add support for electron v42 prebuilds WiseLibs/better-sqlite3#1466
Electron 41.7.1 downgrade rationale is supported; consider small follow-ups
electron@41.7.1is a published version, and the available Electron advisory data shown affects 41.x only up to<41.1.0(patched at41.1.0), so41.7.1doesn’t fall into those ranges.better-sqlite3@12.10.0includes prebuild support for Electron 41 (workaround for the Electron 42 prebuild gap is reasonable given the downgrade intent).- Optional: add a brief tracking/upgrading note (and consider whether
^41.7.1should be tightened if prebuilds only cover certain Electron 41.x versions).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/desktop/package.json` at line 78, Update the package.json electron
dependency entry ("electron": "^41.7.1") to include a short follow-up: add a
comment or project note (e.g., in package.json's "comments" field or repo
docs/changelog) documenting the downgrade rationale and the prebuild workaround
for better-sqlite3, and consider tightening the version specifier (remove caret
or pin to "41.7.1") if prebuilds only support specific 41.x releases; modify the
"electron" dependency line and add the tracking note in the repository docs or
package metadata accordingly.
…se 0 A4) (#293) ## Summary Phase 0 A4. Two guardrails on \`release.yml\` to make a silent or partial release impossible. ## Why The v0.15.0 release pipeline failed silently twice: 1. **Silent no-op**: PR #245's squash-merge title (\`release: audit + Ed25519 signed envelopes + lefthook (v0.15.0) (#245)\`) didn't match a conventional commit type in \`releaseRules\`. semantic-release exited cleanly with \"no release\" and the workflow ended green; the operator only noticed because no tag appeared. We patched this with #289 by adding a forcing \`feat:\` commit, but the trap will fire again on the next big squash unless the workflow refuses to silently no-op. 2. **Stale version**: even when the release finally cut, both \`package.json\` files still read \`0.14.0\` because the deleted \`scripts/bump-version.js\` was never re-introduced (fixed in PR #291). Tag points at one version, file content reads another — visible by anyone running \`jq .version package.json\` against the tag. ## Guardrails ### Pre-flight (dry-run) \`\`\`yaml - name: Pre-flight (dry-run) check run: | npx semantic-release --dry-run 2>&1 | tee /tmp/sr-dry.log if grep -qE \"There are no relevant changes\" /tmp/sr-dry.log; then echo \"::error::semantic-release dry-run: no release will be cut.\" exit 1 fi if ! grep -qE \"next release version is\" /tmp/sr-dry.log; then echo \"::error::semantic-release dry-run did not announce a next release version.\" exit 1 fi \`\`\` Stops the workflow loud and clear before \`--ci\` if commit-analyzer would have returned \"no release\". Actionable error messages point at \`release.config.js > releaseRules\` and the commit log. ### Post-flight (version assertion) \`\`\`yaml - name: Verify version bump applied run: | expected=$(grep -oE \"next release version is [0-9]+\\.[0-9]+\\.[0-9]+\" /tmp/sr-dry.log | tail -n 1 | awk '{print $NF}') root_v=$(jq -r .version package.json) desk_v=$(jq -r .version apps/desktop/package.json) if [ \"$root_v\" != \"$expected\" ] || [ \"$desk_v\" != \"$expected\" ]; then echo \"::error::Version mismatch after semantic-release.\" exit 1 fi \`\`\` Re-uses the captured dry-run log to know what version SHOULD have been written. Catches a misconfigured or skipped \`scripts/bump-version.mjs\` (PR #291) BEFORE the tag-triggered build downloads the stale package.json. ## What gets caught | Trap | Caught by | |---|---| | Non-conventional PR title (#245 trap) | Pre-flight: \"no relevant changes\" | | Wrong releaseRules / type filter | Pre-flight: \"did not announce next release\" | | \`prepareCmd\` missing or wrong path | Post-flight: version mismatch | | \`bump-version.mjs\` only updated one file | Post-flight: per-file diff | | semantic-release crashed mid-cycle | Native exit code from \`Run semantic-release\` step | ## Verification I dry-ran the gate logic locally against the current main commit log; the dry-run output contains the expected lines for both happy-path and no-op cases. No way to test end-to-end without actually invoking the workflow. ## Stack context Phase 0 A4. Independent from A1 (#290), A2 (#291), B-bundle (#292). Different files / steps; no overlapping changes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Why develop's lint job has been failing since **2026-04-24** (over a month). Until this lands, **every Phase 0 PR (#290–#294) is structurally unmergeable** because branch protection requires \`lint\` to pass and \`strict: true\` requires PRs to match develop's tip. This is the unblock for the whole post-audit release stack. ## What Two orthogonal fixes that together get \`pnpm lint\` to **0 errors**. ### 1. \`preserve-caught-error\` × 4 in \`encryptionService.ts\` Four \`try/catch\` blocks re-throw a wrapped error without attaching the caught one: \`\`\`ts } catch (error) { throw new Error( \`Failed to encrypt content: \${error instanceof Error ? error.message : 'Unknown error'}\`, + { cause: error } // ← lints clean and preserves the stack ); } \`\`\` Affected throw sites: \`initialize\` (114), \`encrypt\` (261), \`decrypt\` (292), \`importKey\` (351). The \`{ cause }\` payload is the standard ES2022 way to chain errors; runtime semantics unchanged. ### 2. mcp-server tsconfig refactor for ESLint projectService \`packages/mcp-server/tsconfig.json\` was excluding \`src/__tests__\`. ESLint uses \`@typescript-eslint/parser\` with \`projectService: true\`, which delegates project discovery to the TypeScript LSP. The LSP walked up from the test file, found mcp-server/tsconfig.json with the explicit exclude, and rejected the test → **parsing error: \"was not found by the project service\"**. Fix: split build vs editor configs. - **tsconfig.json** — single source of truth for editors/lint/test. Includes everything under \`src\`. Adds \`vitest/globals\` to \`types\`. - **tsconfig.build.json** — extends tsconfig.json, re-adds \`exclude: [\"src/__tests__\"]\`. Used by the build script. - **package.json** — \`\"build\": \"tsc\"\` → \`\"build\": \"tsc -p tsconfig.build.json\"\`. Confirmed locally: - \`pnpm lint\` → 0 errors (39 warnings unchanged, all pre-existing import-x/order). - \`pnpm --filter @readied/mcp-server build\` succeeds; \`dist/__tests__/\` does not exist. - \`pnpm --filter @readied/mcp-server test\` → 5/5 pass. - \`pnpm -r typecheck\` succeeds. ## Why a separate PR (not bundled with #290 / A1) A1 is the Electron-pin commit. Mixing in a multi-file lint fix would muddy what's a release-pipeline change vs a code-hygiene change. Keeping this separate also means: this PR can go in first, then #290–#294 can rebase one by one and pass CI cleanly. ## Roadmap status - [ ] **this PR** — lint baseline unblock - [ ] #290 A1 (electron 41.7.1) - [ ] #291 A2 (bump-version.mjs) - [ ] #292 B (workflow surface) - [ ] #293 A4 (release guardrails) - [ ] #294 C1 (pr-title commitlint) - [ ] C2 follow-up — add \`commitlint\` to required checks after #294 lands - [ ] D — cut v0.15.1
d5aea6d to
693a6c8
Compare
## Why Phase 0 **C1** of the DevOps cleanup roadmap. After v0.15.0 traced back to PR #245's squash-merge producing a non-conventional commit message (`release: audit...`) which semantic-release silently rejected, the merge gate needs to block non-conventional PR titles **upstream of merge** — not just whine in CI. The check already existed as a step inside `ci.yml`'s `lint` job, but it shipped as a sub-step of a multi-purpose job. Branch protection can only require whole status checks, so requiring \`lint\` would also block on ESLint/Prettier failures. Pulling commitlint into its own workflow gives branch protection a clean, single-responsibility check name to require: \`PR title / commitlint\`. ## What changes - **New: \`.github/workflows/pr-title.yml\`** — runs commitlint against \`github.event.pull_request.title\` on pull_request \`opened\`, \`edited\`, \`reopened\`, \`synchronize\`. - **\`ci.yml\`** — drops the duplicated step from the \`lint\` job and leaves a one-line breadcrumb pointing at the new workflow. ## Security shape The workflow follows the [GitHub command-injection guidance](https://github.blog/security/vulnerability-research/how-to-catch-github-actions-workflow-injections-before-attackers-do/): - \`github.event.pull_request.title\` is **never** interpolated directly into a \`run:\` script. It passes through \`env:\` as \`PR_TITLE\` and the shell reads \`\$PR_TITLE\` from the process environment. - The script uses \`printf '%s' "\$PR_TITLE" | pnpm commitlint\` instead of \`echo\` — a PR title beginning with \`-e\` or \`-n\` would otherwise be treated as an echo flag in bash/sh. ## Verification - \`pnpm commitlint --config commitlint.config.js\` on the local checkout exits non-zero for \`release: foo\`, \`hotfix: foo\`, \`Add feature\`; zero for \`feat: foo\`, \`fix(scope): foo\`, \`chore!: foo\`. - Type enum used: \`feat | fix | refactor | docs | test | chore | style | perf | ci | build | revert\` (sourced from \`commitlint.config.js\`). ## Follow-ups (Phase 0 C2) Once this merges, **C2** sets \`PR title / commitlint\` as a required status check on \`develop\` and \`main\` via \`gh api\` — that's the step that actually blocks #245-style merges. C1 is the pre-req: required checks must exist on the default branch before they can be required. ## Roadmap status - [x] A1 #290 — electron 41.7.1 pin - [x] A2 #291 — \`scripts/bump-version.mjs\` + release.config.js wire - [x] B #292 — workflow surface cleanup - [x] A4 #293 — release dry-run + version-assertion guardrails - [x] **C1 (this PR)** — PR-title commitlint standalone - [ ] C2 — branch protection \`gh api\` (next) - [ ] D — cut v0.15.1
…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.
The v0.15.0 Build workflow failed on all three platforms (mac/win/linux, run 27184736470) because better-sqlite3 12.10.0 explicitly removed Electron v42 prebuilds in release notes: > Temporarily rollback support for Electron v42 prebuilds > (WiseLibs/better-sqlite3#1470) Without a prebuild for Electron 42, electron-builder install-app-deps falls through to a source build via @electron/rebuild. That build then hits V8 API breakages introduced in Electron 42's V8 (V8 13.x): - SetNativeDataProperty ambiguity (3 candidate overloads) - External::Value() now requires an ExternalPointerTypeTag argument - External::New() signature change Until better-sqlite3 ships v42 prebuilds again (no public ETA), pin Electron to its previous major. v41.7.1 is the latest 41.x as of 2026-05-26 and has a complete prebuild matrix. After this change, `pnpm install` locally: 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` = we used the prebuilt binary; no V8 compile errors. CI Build for v0.15.1 should now succeed on all platforms without further changes to electron-builder, codesign, or notarize config. This is Phase 0 A1 in the post-audit roadmap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
693a6c8 to
7c8a18e
Compare
## 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>
## Release v0.15.1 — Phase 0 DevOps stabilization Brings the 7-PR DevOps cleanup chain to main and cuts a clean release. This is the verification gate for the whole Phase 0 effort — if anything breaks at tag, build, or publish, Phase 0 isn't done. ### What landed since v0.15.0 | PR | Phase | Summary | |----|-------|---------| | #290 | **A1** | \`fix(desktop)\`: pin Electron to ^41.7.1 so better-sqlite3 prebuilts apply (closes the v0.15.0 V8 ABI failure on all 3 build platforms) | | #291 | **A2** | \`fix(release)\`: restore version bumping via \`scripts/bump-version.mjs\` + \`@semantic-release/exec\` (closes the "tag at 0.14.0" trap) | | #292 | **B** | \`chore(ci)\`: workflow surface cleanup — actions @v4→@v5 sweep, \`windows-latest\` → \`windows-2025-vs2026\` pin, drop \`FORCE_JAVASCRIPT_ACTIONS_TO_NODE24\`, \`if-no-files-found: error\`, \`permissions:\` blocks, HUSKY: '0' removal | | #293 | **A4** | \`chore(ci)\`: \`release.yml\` pre-flight dry-run gate + post-flight version assertion (closes the "silent no-release" trap) | | #294 | **C1** | \`ci\`: PR-title commitlint as a standalone workflow → required check on develop + main | | #295 | | \`fix(lint)\`: develop lint baseline (preserve-caught-error × 4 in encryptionService + mcp-server tsconfig split for ESLint projectService) | | #296 | | \`chore(ci)\`: unblock CI on develop — ignore CHANGELOG.md in Prettier (semantic-release writes it), \`pnpm install --ignore-scripts\` in setup job (same shape as release.yml + deploy-api.yml) | ### C2 — branch protection updates (already applied via gh api) Both \`develop\` and \`main\`: - **Required status checks**: \`lint\`, \`test\`, \`typecheck\`, \`CodeRabbit\`, \`commitlint\` - Force-pushes blocked - \`strict: true\` (PRs must be up to date) ### Release pipeline guardrails now in place - **Pre-merge**: PR-title commitlint blocks \`release:\`-style non-conventional squash titles upstream. - **Mid-release**: \`release.yml\` dry-run check fails loud if no release would be cut. \`scripts/bump-version.mjs\` mutates both \`package.json\` files. Post-flight assertion verifies both match the dry-run-announced version. - **Post-release**: \`build.yml\` artifact upload uses \`if-no-files-found: error\` (silent zero-asset releases die at upload). - **Native deps**: \`apps/desktop\` pinned to Electron 41.7.1 with prebuilt better-sqlite3. CI \`setup\` skips postinstall so workflow-side install never rebuilds native modules. ### Expected behavior of the Release pipeline after merge 1. Merge this PR → main tip advances. 2. Manually dispatch the **Release** workflow. 3. \`release.yml\` runs: - \`pnpm install --ignore-scripts\` (no native rebuild needed for semantic-release). - **Pre-flight dry-run** → "next release version is 0.15.1" (single \`fix(release):\` commit since v0.15.0). - \`npx semantic-release\`: - \`@semantic-release/exec\` runs \`node scripts/bump-version.mjs 0.15.1\` → both package.json files updated. - \`@semantic-release/git\` commits + pushes tag \`v0.15.1\`. - \`@semantic-release/github\` creates draft Release. - **Post-flight assertion** → both package.jsons read \`0.15.1\`. 4. Tag push triggers \`build.yml\` on macOS-14, windows-2025-vs2026, ubuntu-latest. 5. All 3 platforms succeed → publish job un-drafts the GitHub Release. 6. Auto-sync PR opens to merge main → develop. ### What still needs verification (post-release) - [ ] Tag push actually triggers Build (needs GH_TOKEN with workflow scope — A3 deferred, may need PAT regen) - [ ] Build completes on all 3 platforms with prebuilt better-sqlite3 (smoke-test desktop bundle after publish) - [ ] Auto-sync PR back to develop is created 🤖 This is the Phase 0 verification gate. Mobile + Plugin Marketplace UI remain deferred. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added PR title validation workflow for automated commit message compliance checks. * **Bug Fixes** * Enhanced error diagnostics in encryption operations. * Added pre-flight checks to release process to prevent failed deployments. * Stricter artifact validation in builds. * **Chores** * Updated GitHub Actions to latest stable versions. * Improved code formatting configuration and build scripts. * Adjusted Electron dependency version. <!-- 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>
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) because better-sqlite3 12.10.0 explicitly removed Electron v42 prebuilds (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:
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.
When to bump back to 42
Watch 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
Summary by CodeRabbit