chore(knip): delete verified-unused files (PR-Knip-1)#279
Conversation
Knip surfaced 28 unused files in #267. After per-file verification, 12 were genuinely orphaned. Deleting them: apps/desktop: - src/renderer/analytics.ts — no imports anywhere - src/renderer/hooks/useTheme.ts — no imports anywhere - src/renderer/settings.tsx — no imports anywhere - src/renderer/ui/patterns/Modal.tsx — only its sibling index.ts - src/renderer/ui/patterns/index.ts — barrel that nothing imports - src/renderer/ui/patterns/Modal.module.css + .gitkeep — left over packages: - plugin-api/src/editor/types.ts — not re-exported by index.ts - storage-core/src/interfaces/index.ts \ - storage-core/src/migrations/index.ts \ - storage-core/src/repositories/index.ts \ — main package index imports - storage-core/src/types/index.ts / directly from concrete files, - storage-sqlite/src/repositories/index.ts/ not these barrels scripts: - scripts/bump-version.js — not in any package.json script and not referenced by any CI workflow Kept (Knip false positives — auto-discovered files Knip can't see): - vite-env.d.ts (vite reference declaration) - css-modules.d.ts (TypeScript module shim) - turndown-plugin-gfm.d.ts (TypeScript module shim) - apps/web/mdx-components.tsx (Next.js MDX convention, no import) Kept (Knip wrong — barrel that IS used): - renderer/pages/settings/components/controls/{NumberInput,Select,TextInput,Toggle}.tsx All four are imported by EditorSection / AiSection / UpdatesSection through the controls/index.ts barrel. Skipped (out of audit scope): - apps/web/components/magicui/*, NavDropdown, ui/separator Validates: - pnpm -r typecheck — green - pnpm test — 17/17 packages, all cached except plugin-api which ran fresh after the editor/types.ts deletion. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
0ad51bb
into
refactor/extract-from-main-index
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (14)
📝 WalkthroughWalkthroughThis PR removes desktop UI components (Modal, analytics, theme hook, settings page), eliminates re-exports from plugin-api and storage packages (interfaces, types, migrations, repositories), and deletes the version bumping build script. The changes represent a significant API surface reduction and UI component consolidation across desktop and package layers. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd9b809cd7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -1,33 +0,0 @@ | |||
| #!/usr/bin/env node | |||
There was a problem hiding this comment.
Restore the release bump script
When the manual release workflow runs npx semantic-release (.github/workflows/release.yml), semantic-release's documented default config lookup includes release.config.js, and @semantic-release/exec documents prepareCmd as the shell command executed in the prepare step; this repo's config still has prepareCmd: 'node scripts/bump-version.js ${nextRelease.version}'. Deleting this file means any release that reaches the prepare step will fail with a missing module instead of bumping package.json/apps/desktop/package.json; the existing scripts/bump-version.test.js also still invokes the same path.
Useful? React with 👍 / 👎.
## Summary Phase 2 of knip cleanup. Knip flagged 11 unused dependencies in #267; per-dep verification confirmed **6 are genuinely unused** in our scope. Removing them shrinks the lockfile by ~120 lines. ## Removed ### \`apps/desktop\` production | Dep | Why safe | |---|---| | \`highlight.js\` | We use \`rehype-highlight\`, which depends on \`lowlight\` (NOT \`highlight.js\` directly). \`lowlight\` ships its own grammars. | | \`pino-roll\` | \`logger.ts\` writes directly via \`createWriteStream\` — no pino transport / no rolling pipeline | | \`react-resizable-panels\` | No imports anywhere | | \`unist-util-visit\` | No imports anywhere (the only consumer is \`@readied/wikilinks\`, which declares it itself) | ### \`apps/desktop\` dev | Dep | Why safe | |---|---| | \`@types/mdast\` | No imports anywhere | | \`pino-pretty\` | \`logger.ts\` doesn't pipe through a transport; dev output is raw JSON via the synchronous pino factory | ### \`packages\` | Package | Dep removed | Why | |---|---|---| | \`@readied/sync-core\` | \`@readied/core\` | No imports of \`@readied/core\` in \`src/*\` — workspace link was stale | | \`@readied/wikilinks\` | \`unified\` | \`src/*\` uses \`unist-util-visit\` directly (kept) but never \`unified\` | ## Skipped (out of audit scope) \`apps/web\`: \`@radix-ui/react-separator\`, \`next-themes\`, \`tailwindcss-animate\` — marketing site, separate pass. ## Test plan - [x] \`pnpm install --ignore-scripts\` — succeeds. Pre-existing peer warnings about electron-builder / electron-vite are unrelated. - [x] \`pnpm -r typecheck\` — green. - [x] \`pnpm test\` — 17/17 packages. - [ ] Manual smoke on the desktop app after merge — verify nothing transitively depended on highlight.js / pino-roll / etc. that grep missed. ## Stack context Stacked on **PR-Knip-1** (#279) → PR-G (#278) → PR-E (#277) → ... down to PR-B (#265). 16 PRs deep. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ge layer (PR-F3-Wiring) (#281) ## Summary Wires the verification primitive from #276 into the desktop's \`FileLicenseStorage\`. The path from server → disk → in-memory now has a real Ed25519 verification step at read time, with **lenient fallthrough** during the migration window. ## Changes ### \`packages/licensing/src/types.ts\` \`StoredSubscriptionData\` now allows an optional \`signedEnvelope\`: \`\`\`ts interface StoredSubscriptionData { readonly subscription: SubscriptionInfo; readonly lastVerified: string; readonly cacheExpiresAt: string; readonly signedEnvelope?: SignedSubscriptionEnvelope; // NEW } \`\`\` Both can coexist during migration. Long-term, the unsigned \`subscription\` field becomes a derived view of the envelope payload. ### \`apps/desktop/src/main/services/fileLicenseStorage.ts\` \`readSubscriptionData\` now branches on envelope presence: | State on disk | Behavior | |---|---| | **Envelope present + signature valid** | Return cache as-is | | **Envelope present + signature invalid** | Log error, **refuse the cache** (return null). Next caller fetches fresh from the API | | **Envelope absent** | Log warning, accept the cache (lenient migration mode) | Plus a \`SUBSCRIPTION_PUBLIC_KEY\` constant at the top of the file with a **REPLACE BEFORE SHIPPING** note. The all-zeros placeholder means any real envelope will fail verification — that's the *correct* failure mode while the placeholder is in place. The lenient "no envelope" branch is what runs today. ## What's NOT in this PR (still pending the server team) - \`ApiClient.getSubscriptionStatus\` does not yet return an envelope. When it does, \`mapApiToSubscriptionData\` in \`licenseHandlers.ts\` grows one more field (\`signedEnvelope\`) and \`writeSubscriptionData\` persists it. That change is one-liner plumbing, blocked only on the API contract being updated. - The placeholder public key gets swapped for the real server key in the release that first ships signed envelopes. ## Behavior matrix | Disk state | Today (placeholder key) | After server rollout (real key) | |---|---|---| | Empty | null returned, no log | null returned, no log | | Old shape (no envelope) | Warning logged, accepted | Warning logged, accepted (until strict mode) | | Real envelope, valid sig | Cannot occur (server isn't signing yet) | Silently accepted | | Real envelope, invalid sig | Will fail (placeholder key) → refused → refetch | Refused → refetch | | Tampered envelope | Refused → refetch | Refused → refetch | ## Test plan - [x] \`pnpm -r typecheck\` — green - [x] \`pnpm test\` — 17/17 packages (the 18 signature tests from #276 cover the verify path; this PR just calls into them) - [ ] Manual: edit \`subscription.json\` to flip a single byte in the cached \`subscription.subscriptionId\` field. Reopen the app. Once server signs envelopes: expect error log + refetch. Today: warning log + cache accepted (no envelope to verify). ## Stack context Stacked on **PR-Knip-2** (#280) → PR-Knip-1 (#279) → PR-G (#278) → PR-E (#277) → ... down to PR-B (#265). **17 PRs deep.** 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Repository (#282) ## Summary **Phase 1 of the SQLiteNoteRepository split.** Pure helpers come out to their own file so future sub-repositories (sync, tag, archive) can reuse them without inheriting from the 1000-line class. | Metric | Before | After | |---|---|---| | \`SQLiteNoteRepository.ts\` | 1121 lines | **1038 lines** (-7%) | | \`noteMapping.ts\` | — | 133 lines (new) | ## Extracted | Symbol | Kind | Notes | |---|---|---| | \`NoteRow\`, \`TagRow\`, \`TagWithColorRow\`, \`BacklinkInfo\` | Row types | Re-exported by SQLiteNoteRepository so external imports keep working | | \`rowToNote(row, tags) -> Note\` | Pure mapper | Reconstructs a domain Note from a SQLite row + its tags | | \`prepareFtsQuery(input) -> string\` | Pure helper | FTS5 query escaper + tokenizer | | \`archivedConditionSql(filter, alias) -> string\` | Pure helper | SQL fragment for archived filtering | Call sites swapped from \`this.<helper>()\` to plain function imports. **The public class signature is unchanged** — \`BacklinkInfo\` is re-exported so external consumers (e.g. \`apps/desktop/src/main/handlers/types.ts\`) keep working without edits. ## What this PR DELIBERATELY does NOT do - **Extract sync methods** (\`getPendingChanges\` through \`getSyncHistory\` ~430 lines) into a \`SQLiteNoteSyncRepository\`. Those share state — tag queries, transactions, FTS sync triggers — with the main class in ways that need real-DB integration coverage to refactor safely. The helpers extracted here are the foundation: a follow-up PR can build the sync sub-repo on top of them without touching the helpers again. - **Extract tag methods** (\`setManualTags\`, \`renameTag\`, \`getAllTagsWithColors\`, etc.) for the same reason. The audit aspired to a 4-way split (NoteCrudRepository + NoteTagRepository + NoteArchiveRepository + NoteSyncRepository). That remains the destination. This PR ships the **foundation** that makes those splits low-risk; each can ride its own PR with focused review. ## Test plan - [x] \`pnpm -r typecheck\` — green - [x] \`pnpm test\` — 17/17 packages - [ ] Manual: launch the desktop, exercise notes CRUD + search + tag operations. Behavior should be identical (no observable change). ## Stack context Stacked on **PR-F3 wiring** (#281) → PR-Knip-2 (#280) → PR-Knip-1 (#279) → PR-G (#278) → PR-E (#277) → ... down to PR-B (#265). **18 PRs deep.** 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
**Phase 1 of the MarkdownEditor split.** Pure theme + markdown
HighlightStyle move to their own file so further extractions (extensions
array, keymap bindings) can ride on top without merging against a
churn-prone component shell.
| Metric | Before | After |
|---|---|---|
| \`MarkdownEditor.tsx\` | 737 lines | **612 lines** (-17%) |
| \`editorTheme.ts\` | — | 139 lines (new) |
## Extracted
| Symbol | Kind |
|---|---|
| \`SCROLL_PAST_END_PADDING\` | constant |
| \`createEditorTheme(fontSize, fontFamily, lineHeight)\` | factory
returning \`EditorView.theme({...})\` |
| \`markdownHighlighting\` | \`HighlightStyle.define([...])\` with all
tag styles for markdown |
## Imports cleaned up
- Drop \`HighlightStyle\` from \`@codemirror/language\` import (no
longer referenced in this file)
- Drop \`tags\` from \`@lezer/highlight\` (moved into editorTheme.ts)
## What this PR DELIBERATELY does NOT do
- **Extract the extensions array** (~96 lines of \`createExtensions\`).
It closes over user settings (\`lineNumbersCompartment\` etc.) and mixes
context-coupled values like \`wikilinkAutocomplete\` from a hook. Safely
pulling that out requires either passing the closure context via a
builder, or moving the whole \`useMemo\` into its own hook. **Better
done under Playwright coverage (PR-E #277) so renderer regressions
surface.**
- **Extract the keymap.** Same reason — bindings reference
view-imperatives + the command-registry which are constructed inside the
React tree.
## Test plan
- [x] \`pnpm -r typecheck\` — green (renderer + e2e tsconfigs)
- [x] \`pnpm test\` — 17/17 packages
- [ ] Manual: open the editor, type in a markdown note with headings,
emphasis, lists, code blocks. The look must be identical (theme is
byte-for-byte the same; just moved).
## Stack context
Stacked on **note repo split** (#282) → PR-F3 wiring (#281) → PR-Knip-2
(#280) → PR-Knip-1 (#279) → PR-G (#278) → PR-E (#277) → ... down to PR-B
(#265). **19 PRs deep.**
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary Promotes `develop` to `main` for **v0.15.0**. Originally opened 2026-04-24; now refreshed with the 19-PR tech-debt audit shipped via #285 plus the accumulated dependabot bumps reconciled. `semantic-release` will pick the version bump. Expected: **minor (v0.14.x → v0.15.0)** because of multiple \`feat:\` commits. ## What ships (audit highlights, from #285) ### Runtime fixes (user-facing) - **Editor no longer crashes on table-containing notes** (#266) — \`Decoration.replace\` over multi-line ranges moved from a ViewPlugin to a StateField, plus an EditorView.exceptionSink so any future plugin error no longer tears down the EditorView. - **AI keys survive sleep/wake** (#275) — \`aiKeyStorage\` stopped silently deleting the encrypted store when the keychain was temporarily locked after macOS sleep. - **Backup restore is now safe** (#271) — restored DBs go through \`PRAGMA integrity_check\` before being swapped in; corrupt backups roll back to the safety copy. - **MCP server runs without electron-builder rebuilds** (#264 → #270) — migrated from native \`better-sqlite3\` to built-in \`node:sqlite\` (Node 22.5+), updated to the new \`registerTool\` MCP SDK API. ### Security - **Typed IPC boundary** (#272 + #273 + #274) — 130+ IPC channels now validated with Zod tuples at the main↔renderer boundary. Garbage in fails fast with \`IpcValidationError\` instead of corrupting downstream code. - **Ed25519 license verification scaffolding** (#276 + #281 + #284) — \`signSubscriptionPayload\` / \`verifySubscriptionSignature\` helpers ship in \`@readied/licensing\`, wired into \`FileLicenseStorage.readSubscriptionData\` with lenient fallthrough during migration. Real public key embedded (\`d04901…\`). Server-side \`LICENSE_SIGNING_PRIVATE_KEY\` already set in Cloudflare staging + production. ### Developer experience - **Husky → Lefthook** (#267) plus lint-staged that now runs ESLint, not just Prettier. - **\`knip\` added** (#267) + 12 unused files deleted (#279) + 6 unused deps dropped (#280). - **Playwright Electron E2E scaffold** (#277) with smoke + notes-IPC specs and a Linux+xvfb CI job (\`continue-on-error: true\` while it stabilises). - **Vitest coverage baseline** (#269) — 12 packages share a coverage config; smoke tests added for \`@readied/commands\`. ### Refactor (no behavior change) - **Zustand selectors migration** (#268) — 3 components stopped destructuring entire stores. - **God-file extractions**: - \`main/index.ts\` 1065 → 950 lines (#278) — \`FileLicenseStorage\`, \`windowState\` extracted to services - \`SQLiteNoteRepository.ts\` 1121 → 1038 lines (#282) — pure helpers extracted to \`noteMapping.ts\` - \`MarkdownEditor.tsx\` 737 → 612 lines (#283) — theme + markdownHighlighting extracted to \`editorTheme.ts\` ## Deploys triggered | Workflow | Trigger | What happens | |---|---|---| | \`deploy-api.yml\` | Auto on \`push\` to main affecting \`packages/api/**\` | Tests + deploys \`@readied/api\` to Cloudflare Workers (\`readied-api-production\`). This stack only touched \`wrangler.toml\` + \`.dev.vars\` docs, no production code change. | | \`release.yml\` | Manual \`workflow_dispatch\` post-merge | \`semantic-release\` analyses conventional commits, bumps version, creates GitHub Release draft + tag | | \`build.yml\` | Auto on tag push from release.yml | mac / windows / linux parallel builds, artefacts attached to the GitHub Release | ## Pre-merge verification (local, this branch) - ✅ \`pnpm -r typecheck\` — green across 18 workspace projects - ✅ \`pnpm test\` — 17/17 packages - ✅ Merge resolved: take develop versions for 19 conflicted package.jsons (develop has equal or newer deps than main's dependabot bumps) ## Post-merge action items (operator) 1. **Deploy API to staging first** (smoke test): \`\`\` gh workflow run deploy-api.yml -f environment=staging \`\`\` 2. Confirm staging API responds correctly (subscription endpoint with new \`LICENSE_SIGNING_PRIVATE_KEY\` secret already set in CF). 3. Merge this PR → auto-deploys API to production. 4. Trigger Release workflow: GitHub → Actions → Release → "Run workflow" → main. 5. Watch Build workflow for mac/win/linux completion. 6. Confirm the release un-drafts itself. ## Known risks / follow-ups - **Pre-existing Vercel preview failure for \`apps/web\`** — marketing site, scheduled to be extracted to its own repo (P3 in the roadmap). - **\`SUBSCRIPTION_PUBLIC_KEY\` is dev-grade** — generated in a Claude session. Before the licensing server emits envelopes for real paid users, rotate the keypair from a trusted machine and ship a follow-up release. - **Branch protection should require CodeRabbit completion before automerge** — added to the roadmap as a process item; this very PR was BLOCKED correctly because of that policy gap being closed. 🤖 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>
## Why this PR PR #245 squash-merged 19 individual PRs (#266-#284) into a single commit on main: \`release: audit + Ed25519 signed envelopes + lefthook (v0.15.0) (#245)\`. That message **isn't a conventional commit type that semantic-release recognises**, so the analyser saw 11 commits since the last tag and concluded *"no release"*. The actual feat:/fix:/refactor: messages from the 19 underlying PRs were lost in the squash. Concretely, run [27184456847](https://github.com/tomymaritano/readide/actions/runs/27184456847) finished cleanly but logged: \`\`\` [semantic-release] [@semantic-release/commit-analyzer] › ℹ Analysis of 11 commits complete: no release [semantic-release] › ℹ There are no relevant changes, so no new version is released. \`\`\` ## What this PR does ### 1. Provides the release signal This commit's title is \`feat(release): cut v0.15.0 audit release\` — a recognised conventional type. semantic-release will analyse it as a **minor bump** (v0.14.x → v0.15.0). ### 2. Drops the broken \`@semantic-release/exec\` step \`release.config.js\` referenced \`node scripts/bump-version.js \${nextRelease.version}\` in a prepareCmd, but that script was deleted in the knip cleanup (#279) and the config wasn't updated. Any release triggered now would fail at the prepare step with \`ENOENT\`. The remaining \`@semantic-release/git\` plugin already commits root \`package.json\` + \`apps/desktop/package.json\` + \`CHANGELOG.md\` via its \`assets\` list — that's everything the desktop release needs bumped. Workspace packages stay at \`workspace:*\` and their numeric versions aren't user-visible. ## Side effect \`@semantic-release/exec\` is still listed in \`package.json\` devDeps but unused after this PR. Not removing it here to keep this PR surgical; can be dropped in the next knip pass. ## After this merges 1. Manually re-trigger Release workflow on main 2. semantic-release picks up this commit + the existing release notes generator → cuts **v0.15.0** 3. Creates GitHub Release draft + tag 4. Tag push fires Build workflow → mac/win/linux artefacts 5. Builds complete → release un-drafts → electron-updater serves it ## Related - #287 (deploy-api workflow fix) - #288 (release workflow install fix) - #279 (knip cleanup that deleted bump-version.js without updating release.config.js) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…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>
Summary
First slice of the knip cleanup. Knip surfaced 28 unused files in #267. After per-file verification (greps, import tracing, barrel resolution), 12 were genuinely orphaned — those are deleted here. The rest stay for reasons documented below.
Deleted (12 files, 659 lines)
`apps/desktop`
`packages`
`scripts`
Kept (Knip false positives)
Auto-discovered files Knip can't see
Knip wrong about being unused
Skipped (out of audit scope)
apps/web cleanup: `magicui/*`, `NavDropdown`, `ui/separator`. The audit excluded apps/web; leaving them for a separate marketing-site pass.
Test plan
What's next in this cleanup track
Stack context
Stacked on top of #278 (PR-G) → #277 (PR-E) → #276 (PR-F3) → #275 (PR-F2) → #274 (PR-F5) → #273 (PR-F4) → #272 (PR-F1) → #271 (PR-I) → #270 (PR-J) → #269 (PR-D) → #268 (PR-H) → #267 (PR-C) → #266 (PR-A) → #265 (PR-B). 15 PRs deep.
🤖 Generated with Claude Code
Summary by CodeRabbit