chore(release): promote 0.17.0 - #571
Conversation
…tach (#570) <!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Build & Publish **#27** ([run 32590544551](https://github.com/dripnex/app/actions/runs/32590544551)) built signed mac/win/linux installers, then the run went red. [v0.16.1](https://github.com/dripnex/app/releases/tag/v0.16.1) notes exist; assets were empty. **Job that made #27 red:** `sync-develop` / Create sync PR ``` pull request create failed: GraphQL: GitHub Actions is not permitted to create or approve pull requests (createPullRequest) ``` Tomás: Settings → Actions → General → Workflow permissions → enable **Allow GitHub Actions to create and approve pull requests**. That is not why binaries are missing. **Why assets were empty (all three `build` jobs + `publish` succeeded):** `workflow_run` uses **develop**'s YAML (default branch), which lacked the stamp step already on `main`. Tree version is still `0.15.2` (tag-without-bump). electron-builder packaged `Dripnex-0.15.2.*` and skipped upload onto the already-published `v0.15.2`: ``` GitHub release not created reason=existing type not compatible with publishing type tag=v0.15.2 version=0.15.2 existingType=release publishingType=draft ``` Signing/notary is fine (`notarization successful`; `CSC_*` / `APPLE_*` present). Not a flake. This PR (develop — the file `workflow_run` actually runs): 1. Stamp `package.json` from the tag before packaging (same step as `main` / #540). 2. Re-draft the target GitHub Release so `--publish always` can attach assets on retry. No product code. AuthGate untouched. No store. No iOS. ### Retry (Tomás — cloud agent token cannot `workflow_dispatch`, HTTP 403) v0.16.1 is already converted back to **draft** so electron-builder can upload. Either: ```bash # fastest: main already has the stamp step gh workflow run "Build & Publish" --ref main -f tag=v0.16.1 ``` ```bash # or this branch (stamp + auto re-draft) gh workflow run "Build & Publish" --ref cursor/fix-v0161-build-assets-f239 -f tag=v0.16.1 ``` Actions UI: Run workflow → branch `main` or `cursor/fix-v0161-build-assets-f239` → tag `v0.16.1`. `sync-develop` will fail again on the retry until the Actions PR setting above is enabled. Installers still attach before that job. ## Type of Change - [x] Bug fix - [ ] New feature - [ ] Breaking change - [ ] Documentation update ## Related Issues Unblocks empty v0.16.1 assets after promotion #569 / Build #27. ## Checklist - [x] I've read CONTRIBUTING.md - [x] Workflow-only change (no product tests) - [x] PR targets `develop` branch (not `main`) <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-3629b701-130d-4cce-99f3-8e22cf2ff239?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-3629b701-130d-4cce-99f3-8e22cf2ff239&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
|
Warning Review limit reached
Next review available in: 17 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (47)
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 |
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Summary
Packaged Linux 0.16.1 still wrote plugins/DB/logs under
`~/.config/@dripnex/desktop` because Electron `app.getPath('userData')`
follows package.json `name` `@dripnex/desktop`. #567 only aligned CLI
`resolveUserDataRoot`. This PR sets the Electron app name and userData
to productName `Dripnex` before `createDataPaths`, so the packaged app
and `dripnex-plugin` share one folder.
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [x] Documentation update
## Related Issues
Closes #572
## What changed
1. **Runtime** — `applyProductUserData()` runs before Sentry and
`requestSingleInstanceLock`. It calls `app.setName('Dripnex')` and
`app.setPath('userData', resolveUserDataRoot())` unless Chromium already
has `--user-data-dir` (e2e).
2. **Package metadata** — root `productName: "Dripnex"` plus
electron-builder `extraMetadata.productName` so packaged `package.json`
does not rely on the scoped npm name for `app.getName()`.
3. **No silent migrate** — existing `@dripnex/desktop` with `dripnex.db`
or `plugins/` stays put via `pickUserDataRoot`. Fresh installs use
`~/.config/Dripnex` / `%APPDATA%/Dripnex` / `~/Library/Application
Support/Dripnex`.
4. **Docs** —
[`docs/plugins/install-path.md`](docs/plugins/install-path.md) records
the packaged-app contract.
No marketplace. No iOS. No release cut.
## Checklist
- [x] I've read [CONTRIBUTING.md](../CONTRIBUTING.md)
- [x] Targeted tests pass (`@dripnex/storage-core` 29,
`@dripnex/plugin-cli` 19) and desktop/storage-core typecheck
- [ ] Full `pnpm test` / `pnpm build` (not required for this path-only
change)
- [x] PR targets `develop` branch (not `main`)
## Test plan
- [x] Unit: `resolveElectronUserData` names the app `Dripnex`, defaults
to the packaged folder on Linux/Windows/macOS, keeps an existing scoped
folder that already has `dripnex.db`, honors `DRIPNEX_DATA_DIR`, leaves
`--user-data-dir` alone
- [ ] Packaged Linux log `dataDir` is `~/.config/Dripnex` on a fresh
machine
- [ ] CLI `dripnex-plugin` and the packaged app resolve the same plugins
dir
- [ ] e2e `--user-data-dir` / `DRIPNEX_DATA_DIR` still isolate tests
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a
href="https://cursor.com/agents/bc-4d7bdc7f-21c2-43f5-9215-8ae46bc3b625?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a
href="https://cursor.com/background-agent?bcId=bc-4d7bdc7f-21c2-43f5-9215-8ae46bc3b625&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Rebranded the desktop app as Dripnex.
* Improved shared data-folder handling between the desktop app and CLI.
* Added support for explicitly configured custom user-data directories.
* Preserved existing application data across supported configurations.
* **Documentation**
* Updated installation guidance for user-data directory resolution.
* **Tests**
* Added coverage for platform-specific paths, custom directories, and
application naming.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Adds three first-party desktop palettes on the existing `ThemeDefinition` token contract. No stylesheet fork, no plugin packages, no frosted window vibrancy. - **Matcha** (`dripnex-matcha`) — light green-tea paper for calm reading - **Phosphor** (`dripnex-phosphor`) — dark amber CRT / terminal glow - **Fog** (`dripnex-fog`) — light coastal gray morning with a muted blue accent Author is Dripnex; `pluginId` is `dripnex`. Body text on `--bg-base` is well above WCAG AA (≈10.8 / 13.2 / 10.6:1). `validateThemeTokens` still copies `--accent` to `--accent-primary`. Also creates `docs/themes/LOG.md` with today's three lines (2026-08-22, America/Argentina/Buenos_Aires) so later daily theme runs skip these ids and topics. ## Type of Change - [ ] Bug fix - [x] New feature - [ ] Breaking change - [x] Documentation update ## Related Issues Daily official-theme run (Matcha, Phosphor, Fog). ## Checklist - [x] I've read [CONTRIBUTING.md](../CONTRIBUTING.md) - [x] Tests pass locally (`pnpm --filter @dripnex/desktop test` 303, `pnpm --filter @dripnex/plugin-api test` 255). Full `pnpm test` failed only on unrelated `@dripnex/mcp-server` FTS5 (`no such module: fts5` in this environment) - [x] Desktop + plugin-api typecheck succeed - [x] PR targets `develop` branch (not `main`) ## Screenshots N/A — token palettes only. Preview in Settings → Themes after this lands. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-4779a3f7-42ad-426d-ab28-cde61d50e8d0?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-4779a3f7-42ad-426d-ab28-cde61d50e8d0&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added three official themes: Matcha, Phosphor, and Fog. - Each theme includes tailored interface and status colors for light or dark mode. - **Documentation** - Added an official theme log documenting the new palettes and their color schemes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> First visual polish pass after v0.16.0. AuthGate stays (ADR 002 / #545). No new product surfaces. **Visual source of truth is in-repo only:** `tokens.css`, existing desktop CSS/primitives, and `docs/VISUAL_LANGUAGE.md`. Confirmed 22 Aug 2026: `dripnex.app` is a GoDaddy parking page (black CTA, pale-blue tiles, Helvetica). `dripnex.github.io/readide` is 404. This PR does **not** match either. No new palette. ## Visual changes ### AuthGate (worst first-run screen) - **Before:** Hardcoded zinc `#09090b` screen, blue-tinted mesh (`#152036`), 16px card radius, inverted ink/black submit (`--text-primary` on `--bg-base`), weak input focus, always-dark. - **After:** Tokens throughout (`--bg-base`, `--glass-bg`, `--radius-xl`, `--font-sans`). Mesh colors come from surface tokens and follow `data-color-scheme`. Submit matches in-app `Button` primary (`--accent` / `--accent-hover`), not a parking-page black CTA. Input focus matches the Input primitive. Signup copy drops “Free to start.” - **Why:** First-run was a one-off dark lander. Black CTA would copy GoDaddy, not the app. Flow is unchanged. ### Empty states - **Before:** 200px stub, Sparkles icon, “No matches found,” pinned filter reused “No notes yet,” Mac-only ⌘N, 48px editor icon. - **After:** Centered 28px faint icon + 14/500 title + 12px hint. `modAccel()` prints ⌘ or Ctrl. Pinned empty is “Nothing pinned.” Search is “No matches.” - **Why:** Sparkles and “found” are energetic. Pinned-with-notes-but-none-pinned was a copy bug. ### Note list chrome - **Before:** Header 16/600, row pad 12×16, accent timestamps, no search focus ring, stagger ignored reduced motion. - **After:** `--text-lg` / 500 titles, 10×14 rows, muted timestamps, Input-style search ring, `prefers-reduced-motion`. - **Why:** Accent on every timestamp steers the eye. Header was shoutier than the notes. ### Editor chrome - **Before:** Title turned accent on focus (16/600). Toolbar 32px hovering `--bg-elevated` on an elevated pane. - **After:** Title stays `--text-primary` at 14/500. Toolbar 28×28, hover `--bg-hover`. - **Why:** Title-as-accent is color directing. Toolbar was a size off the 28px chrome controls. ## Docs `docs/VISUAL_LANGUAGE.md` now records: - Source order: tokens → this file → primitives → BRAND.md voice - Explicit **not** sources: parking page, GitHub Pages 404, archived violet/Raycast draft - Type, spacing, color, empty-state voice, AuthGate / list / editor rules - `tokens.css` points at that file ## Remaining issues filed - #557 Nested list marks use blue and violet - #558 Settings MagicLinkFlow does not match AuthGate chrome - #559 Welcome wordmark and frosted accent wash need a brand call ## Tomás — brand calls, not guessed - **Accent hue:** shipped teal (`#5eead4` / `#0d8a80`) vs `BRAND.md` muted gray. Left teal alone. - **AuthGate mesh:** quieted and tokenized; brand says no gradients. Keep moving wash or a still surface? - **Font stack:** `--font-sans` still includes Helvetica Neue as a fallback. Did not promote Helvetica to first family. - **Logo / wordmark:** AuthGate still uses `logo.png` at 40px. Welcome still uses the accent wordmark (#559). - **Site:** parking page + 404. Real site is #546. Not this PR. ## Screenshots Could not capture the Electron renderer here. Exact surfaces: AuthGate sign-in / sign-up / hydrating / sent; list empty / pinned / trash / search; editor empty, title focus, toolbar hover. ## Checklist - [x] AuthGate kept - [x] Parking page / 404 not used as visual reference - [x] No new product features or palette - [x] No CI / release / version / iOS / Psynth / Linear - [x] No new tests - [x] Targets `develop` <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-e1f2eaa1-e66c-4829-babc-c5e71deb73a6?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-e1f2eaa1-e66c-4829-babc-c5e71deb73a6&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
## Summary Documents the MCP / other-AI plan in a new folder `docs/ai/` (plan only, no product code). - `docs/ai/README.md` index - `docs/ai/mcp-plan.md` Inkdrop shape: local HTTP after AuthGate + one MCP; Grok Bot / Claude / Cursor share it - `docs/ai/updates.md` 22 Aug decisions (AuthGate stays, #541/#552, Project 3, no CouchDB, mobile Later) Does not implement MCP HTTP. Existing `packages/mcp-server` stays as the current stdio path. ## Test plan - [ ] Read the three files on the PR - [ ] Confirm no app/CI files changed
…rap (#575) ## Problem Creating a sync passphrase fails with `Error: Unknown cipher`. `encryptionService.wrapKey()` called `createCipheriv('aes-256-wrap', ...)`. That cipher exists in **OpenSSL** but **not in BoringSSL**, which is what Electron ships. The call therefore always threw in the main process and the CEK could never be wrapped. Reproduced directly: | Runtime | `aes-256-wrap` | | --- | --- | | Node 20 (OpenSSL 3.0.17) | available | | Electron 41.7.1 (BoringSSL, `process.versions.openssl === '0.0.0'`) | **`Unknown cipher`** | Vitest never caught this because it runs on Node/OpenSSL, where the cipher exists. ## Fix New `aesKeyWrap.ts` implements RFC 3394 over the raw AES block primitive BoringSSL *does* expose. `encryptionService` delegates to it. Output is **byte-identical** to `aes-256-wrap`, so keys wrapped by earlier builds still unwrap — pinned by the RFC 3394 §4.6 known-answer vector (which I generated from OpenSSL's own `aes-256-wrap` before writing the implementation). `aes-256-ecb` here is the single-block AES call the spec is defined on, with padding disabled — not a mode for bulk data. The chaining, counter and integrity check are RFC 3394's. This is documented at the top of the module. Neither `webcrypto.subtle` AES-KW (`Unrecognized algorithm name`) nor any other built-in wrap is available in Electron, so reimplementing was the only option that preserves the on-disk format. ## Verification - 6 new unit tests: KAT wrap, KAT unwrap, overhead size, tampered ciphertext rejected, wrong KEK rejected, cipher-name guard against a revert to `aes-256-wrap`. - Executed under the **Electron 41.7.1 binary** (`ELECTRON_RUN_AS_NODE=1`): wrap matches the vector, round-trip succeeds, wrong key rejected. - `pnpm test` — 19/19 tasks green. - `pnpm --filter @dripnex/desktop typecheck` — clean. - `eslint` — clean. ## Note for a separate PR `.nvmrc` pins Node 20, but `packages/mcp-server` needs >= 22.5 (`node:sqlite`) and `packages/api` needs >= 22 (wrangler). On Node 20 `pnpm test` and `pnpm dev` both fail for reasons unrelated to this change. 🤖 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 encrypted key wrapping and unwrapping compatibility. * Corrected passphrase handling so invalid or corrupted encrypted data is reliably rejected. * Added validation for malformed keys and tampered encrypted content. * **Tests** * Added coverage for standard AES key-wrapping compatibility, successful recovery, wrong passphrases, and modified data. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> ## Summary Wire `@dripnex/mcp-server` to Dripnex Local HTTP so Cursor / Grok / Claude talk Bearer loopback instead of opening SQLite when the HTTP env is set. Settings → Integrations → MCP now copies that same HTTP env. - Prefer `DRIPNEX_LOCAL_SERVER_URL` + `DRIPNEX_LOCAL_TOKEN` (loopback only). SQLite (`DRIPNEX_DB_PATH`) remains the fallback when those are unset. - Map existing tools onto the real routes in `localServer.ts` (notes, search, books=notebooks, tags). - Add the missing HTTP surfaces: `dripnex_status`, notebook CRUD, tag create/update, `dripnex_get_changes`. - Soft-delete vs hard-delete follows the desktop handler: `DELETE /api/notes/:id` is trash; `?permanent=1` is hard delete (`dripnex_trash_note` `permanent`). - Writes stay gated by Settings → Integrations → Allow writes (`mcp.json`) / `DRIPNEX_MCP_WRITES`. Enabling Local HTTP is **not** a write grant (verified: `httpApiEnabled` vs `mcpWrites` are separate). Flipping Allow writes does not change the copied snippet. - **Settings snippets:** Claude Code / Codex copy `DRIPNEX_LOCAL_SERVER_URL` + `DRIPNEX_LOCAL_TOKEN` (the URL and token already shown in the panel) when Local HTTP or MCP is on. `DRIPNEX_DB_PATH` is only used when HTTP is off. The launch path stays the real `mcp-server` entry when the app knows it; otherwise `/ABS/PATH/...` remains a placeholder — HTTP env is still preferred. - HTTP client unit tests use mocked `fetch`. HTTP store mapping is covered with a stub client. Snippet tests use `placeholder-token` and `/tmp` paths only. `docs/ai/` is not on `develop` — it lives on `docs/ai-mcp-plan`. Env and Cursor/Grok config are in `packages/mcp-server/README.md` (placeholders only; no tokens). ## Type of Change - [x] New feature - [x] Documentation update ## Checklist - [x] PR targets `develop` branch (not `main`) - [x] MCP tests: 35 passed (http client/config/store, writes, notes, sqliteRepo) - [x] Snippet tests: 7 passed - [x] Monorepo `typecheck` passed on push - [ ] `fts5-triggers` fails in this cloud Node build (`no such module: fts5`) — pre-existing, file not changed <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-487fd9fa-1c5e-4511-9bda-c020a67bd6ed?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-487fd9fa-1c5e-4511-9bda-c020a67bd6ed&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Summary
Non-draft PRs into `develop` now get `gh pr merge --auto --squash`.
`--auto` waits for required status checks, so red CI does not merge.
Drafts stay out. PRs targeting a feature branch stay out (no stacked-PR
instant merge). Dependabot uses the same rule. No `automerge` label.
## Type of Change
- [x] Documentation update
- [x] CI / repo rule (not a product feature)
## What changed
- `.github/workflows/automerge.yml` — one rule for every non-draft PR
into `develop`; disable auto-merge if the PR is drafted or retargeted
off `develop`.
- `docs/ci.md` + `docs/adr/006-ci-green-automerge.md` — CI green on
develop = squash auto-merge.
- `docs/RELEASE.md` — one-line pointer to that rule.
## Repo settings
- `allow_auto_merge` is **on**.
- Develop ruleset already requires `lint`, `test`, `typecheck`,
`security`, `commitlint`. Auto-merge cannot fire without those green.
- `--auto` is enabled on this PR and on 561, 560, 554, 553 (Dependabot
PRs already had it). They still only merge when required checks are
green.
This token cannot PATCH rulesets (403). CodeRabbit is still a required
check, and `e2e` is not yet required. Drop CodeRabbit, add `e2e`, and
turn off review-thread resolution (no reviews / no CodeRabbit gate) on
ruleset `13807741`:
```bash
gh api --method PUT repos/dripnex/app/rulesets/13807741 --input - <<'EOF'
{
"name": "develop",
"target": "branch",
"enforcement": "active",
"conditions": { "ref_name": { "exclude": [], "include": ["refs/heads/develop"] } },
"rules": [
{ "type": "deletion" },
{ "type": "non_fast_forward" },
{
"type": "pull_request",
"parameters": {
"required_approving_review_count": 0,
"dismiss_stale_reviews_on_push": true,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_review_thread_resolution": false,
"require_extra_approval_for_unattributed_changes": false,
"allowed_merge_methods": ["squash", "merge", "rebase"]
}
},
{
"type": "required_status_checks",
"parameters": {
"strict_required_status_checks_policy": false,
"do_not_enforce_on_create": false,
"required_status_checks": [
{ "context": "lint" },
{ "context": "test" },
{ "context": "typecheck" },
{ "context": "e2e" },
{ "context": "security" },
{ "context": "commitlint" }
]
}
}
]
}
EOF
```
Not deploy. Do not require reviews or CodeRabbit.
## Related Issues
Tomás: auto-merge Dripnex PRs automatically ONLY if CI passes. No review
required. No automerge label.
## Checklist
- [x] PR targets `develop` branch (not `main`)
- [x] No marketplace/product changes
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a
href="https://cursor.com/agents/bc-4c013d92-1b7f-4f10-ad90-a79e531700cf?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a
href="https://cursor.com/background-agent?bcId=bc-4c013d92-1b7f-4f10-ad90-a79e531700cf&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Automation**
* Non-draft pull requests targeting `develop` are now automatically
squash-merged after required CI checks pass.
* Draft pull requests and pull requests retargeted away from `develop`
are excluded from auto-merge.
* **Documentation**
* Updated release and CI documentation to clarify the auto-merge policy,
required checks, and exclusions.
* Added an architectural decision record documenting the policy.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Back-merge so the promotion PR #571 can satisfy `main`'s up-to-date requirement. `main` carries release-tooling commits `develop` never received — notably #540 (tag without pushing a bump commit) and #537 (point semantic-release at `dripnex/app`). `main` is authoritative for release tooling, so those come back here. **Why a branch and not `gh pr update-branch`:** GitHub refuses to update a PR whose head is a protected branch. And a direct `develop ← main` PR (#577) deadlocks — `develop` requires the head to be up to date, but `main` is inherently behind `develop`. A branch descended from `develop` with `main` merged in satisfies both. No product changes: release config, workflow, and doc URLs only. `package.json` stays at 0.15.2, which is expected under the post-#540 flow. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- 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> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Establishes `main` as an ancestor of `develop` so the promotion PR #571 can satisfy `main`'s up-to-date requirement. **This must be merged with a merge commit, not squashed.** #578 squashed the same content and that is exactly why it did not work: a squash replays the changes as a new commit, so `main`'s commits never become ancestors of `develop` and #571 stayed BEHIND. `git merge-base --is-ancestor origin/main origin/develop` still failed after it. `git diff origin/develop` on this branch is **empty** — #578 already brought the content across. This PR carries ancestry only. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- 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> Co-authored-by: Cursor Agent <cursoragent@cursor.com>
## Problem #566 made every non-draft PR into `develop` squash auto-merge. That breaks the release flow, and I found it by hitting it twice. A back-merge exists for its **topology**, not its content. Squashing one replays `main`'s changes as a fresh commit, so `main` never becomes an ancestor of `develop`. `main`'s ruleset has `strict_required_status_checks_policy: true`, so the promotion PR #571 stays `BEHIND` forever. Both #578 and #579 hit it. On #579 I explicitly ran `gh pr merge --auto --merge`, and the workflow re-armed auto-merge with `--squash` and overrode it. The resulting commit `00ac6d5` has a single parent, and `git merge-base --is-ancestor origin/main origin/develop` still fails. ## Fix Skip PRs whose head branch starts with `chore/backmerge-`. Those get merged by hand with a merge commit. Also documents the back-merge recipe in `docs/RELEASE.md` next to the promotion steps, since the failure mode is silent — the PR just sits at BEHIND with every check green and no explanation. ## Not changed The auto-merge policy itself, permissions, and the concurrency/live-recheck hardening from earlier in #566 all stay as they are. This is one `if:` clause plus docs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
chore(release): merge main into develop
|
🎉 This PR is included in version 0.17.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
## What removing `|| true` revealed The `disable-automerge` job fails with: ``` FORBIDDEN — Resource not accessible by integration ``` It had been failing silently behind `|| true` (see run [32602609796](https://github.com/dripnex/app/actions/runs/32602609796) on #571). The safety net that is supposed to stop a queued auto-merge from landing on an unprotected base **has never actually worked** — it just reported green. ## Honest note on cause I cannot prove this was pre-existing. The job lost `contents: write` earlier in #566 when I scoped workflow-level permissions per job on a least-privilege review, and `|| true` meant no run before or after ever surfaced a failure. Two live hypotheses: 1. The mutation needs `contents: write` and the least-privilege narrowing broke it. 2. It was already FORBIDDEN and the suppression hid it. This PR tests hypothesis 1 by granting the scope back. If FORBIDDEN returns with both scopes present, the cause is a repository or org restriction on `GITHUB_TOKEN` and needs a settings change or a PAT — the comment in the file says so, so the next person does not have to rediscover it. ## Scope narrowing The job fired on every PR whose base was not `develop`, which includes release promotions into `main`. `main` is protected; there is no unsafe queued merge to undo there. The risk this job exists for is landing on an **unprotected** base, so it now fires only on drafts, or on a base that is neither `develop` nor `main`. ## Not changed The loud failure stays. Going back to `|| true` would restore exactly the false confidence that hid this. 🤖 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 handling for draft pull requests. * Protected pull requests targeting `main` and `develop` from automatic processing. * Enabled the required repository content permissions for the automation workflow. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Workflow-only. Copies #570 onto
mainsoworkflow_dispatch(which reads this branch's YAML) has the same stamp + re-draft asdevelop(whatworkflow_runreads).Does not cut a product release. Do not squash if more than this commit lands; this should be the #570 stamp/re-draft only.
Build & Publish #28 is already running on
mainfor v0.16.1 — this PR is for the next dispatch, not that run.