Main previously imported all 12 renderer translation JSONs by relative path to
build its t() table — a main->renderer boundary violation that also inlined
~3.86 MB of translations the main process never uses. Main now owns a small,
independent catalog under src/main/i18n (~59 keys: app menu, tray, dialogs,
context menu, the OAuth callback page and a few shared strings), statically
imported for all 12 languages (~48 KB total).
- src/main/utils/language.ts -> src/main/i18n/index.ts (git mv): swap the renderer
JSON imports for the local catalog, add an en-US fallback to t(), and narrow the
now-internal `locales` export. AppMenuService reads getI18n() instead of the
locales map; the OAuth callback drops its duplicate translator for t().
- src/main/i18n/{locales,translate}/*.json: the main catalog, extracted from the
renderer catalog (zero translation loss), aligned and sorted across all 12 files.
- Renderer catalog: delete the now main-exclusive keys (appMenu.*, tray.*, dialog.*,
settings.mcp.oauth.callback.*, common.{inspect,paste,cut},
agent.session.workspace_status.{missing,not_directory}).
- Composer delete buttons used t('appMenu.delete') by mistake; switch to
t('common.delete') (byte-identical in all 12 languages) so appMenu is fully
main-owned.
- readErrorMessage: take a pre-translated `fallback` string instead of an i18next
key, and move it from @shared/ai into src/main/ai/provider/custom (main-only after
the change); its 6 provider call sites pass main's t(...).
- Tooling: check-i18n now validates the main catalog's 12 files plus a literal-t()
key-coverage check for main sources; sync-i18n and auto-translate-i18n cover both
catalogs. eslint bans relative **/renderer/** in main/preload; TopicNamingService
test reads the renderer catalog from disk instead of importing it.
- Docs: main-process-architecture.md records i18n as a governed top-level expansion
and closes the resolved deviation; CLAUDE.md lists the new directory.
Add an independent, main-authoritative persist tier to the main-process
CacheService, stored as a JSON file at {userData}/cache.json. It is inline
(mirroring the renderer persist structure), fixed-keys-only, with no delete
or TTL; values are loseable and fall back to schema defaults on miss.
Writes are debounced (200ms) and flushed atomically (temp file + rename),
with a flush on service stop. Unknown/stale keys in the file are pruned on
load to keep the fixed-keys contract. The renderer persist IPC relay is
untouched: Main cannot read renderer persist and vice versa.
This phase is architecture-only: the schema ships a single scaffold key
(internal.persist_probe) and no business consumer; window-state and other
consumers will follow. Docs under docs/references/data and CLAUDE.md are
updated to distinguish the new Main persist store from the relay.
With ImportService migrated to DataApi (#16415), the v1 Redux store at
src/renderer/store/ has zero runtime consumers. Delete the directory (30
files) along with the already-stubbed main-process ReduxService bridge.
Clean up the now-stale residue:
- Remove dead vi.mock('@renderer/store') factories from 14 test files
whose code under test no longer imports the store.
- Drop Redux from the CLAUDE.md "Removing" enumerations and refresh the
renderer-architecture / knowledge-service / v2-todo docs.
- Fix dangling store/ references in the MiniAppMigrator and
builtinMcpServers comments.
The v2 migration's Redux Persist readers (ReduxStateReader etc.) are left
untouched: they read serialized on-disk data, not this store.
- remove the Security section: two bullets pointed at non-existent tooling (express-validator, ipaddr.js mislabeled as API-server validation) and the rest restated framework-enforced or generic Electron hygiene; the load-bearing conventions already live in their source files and reference docs
- pnpm lint: describe the final step as "format (writes files)" instead of "format check" — it mutates, it is not read-only
- pnpm build:check: drop the drift-prone "= pnpm lint && pnpm test" enumeration (the real chain also runs docs:check-links) and add a broken-doc-links troubleshooting hint
- data-classify: point classification.json / target-key-definitions.json at their real location (.../data-classify/data/)
- v1 residue: shift Coexistence Mindset from "leave alone" to opportunistic removal now that the refactor is in its cleanup stage, with a matching exception added to the Surgical Changes principle
- drop volatile specifics that duplicate the real source of truth: Node/pnpm version pins (enforced by package.json) and IpcApi migration progress ("Stage 0")
- de-duplicate: keep the v1-fix branch policy, the UI library prohibition, and the no-console.log rule in their durable homes; the v2 section and Logging section now point to them instead of restating
### What this PR does
**Before this PR**, Cherry Studio managed external CLI binaries through
five uncoordinated mechanisms — each requiring its own download script,
IPC channel, and on-disk layout:
| Mechanism | Where it lived | How it worked |
|---|---|---|
| rtk extraction | `src/main/utils/rtk.ts` + `AgentBootstrapService` |
Copies bundled binary to `~/.cherrystudio/bin/` |
| OpenClaw installer | `resources/scripts/install-openclaw.js` |
Downloads from GitHub/mirror with custom extraction |
| CodeCliService | `src/main/services/CodeCliService.ts` | `bun install
-g` to `~/.cherrystudio/install/global/` |
| ripgrep | `node_modules/@anthropic-ai/claude-agent-sdk/vendor/` |
Vendored, hardcoded path in `FileStorage` |
| (old) MiseService | `src/main/services/MiseService.ts` | Bundled mise
+ `mise use -g` |
**After this PR**, a single `BinaryManager` lifecycle service owns all
third-party CLI binary acquisition. It wraps
[mise](https://mise.jdx.dev) as the only acquisition backend (no custom
`BinaryBackend` interface — mise's polyglot grammar already covers
`npm:`, `pipx:`, `github:`, registry entries). Tools install into an
isolated environment under `~/.cherrystudio/mise/` so user-level mise
installs are never touched. `uv`, `bun`, `rg`, and mise itself ship
bundled at build time for instant first-run availability; everything
else flows through mise on demand.
<img width=\"1304\" height=\"714\" alt=\"BinaryManager settings UI\"
src=\"https://github.com/user-attachments/assets/7a4b78ab-5aa2-4e97-9ab7-134b20a4d78d\"
/>
<img width=\"1165\" height=\"748\" alt=\"Three-state managed vs bundled
vs not-installed\"
src=\"https://github.com/user-attachments/assets/a0dcfb7d-8bc3-4acd-b563-0fc04d99e252\"
/>
<img width=\"523\" height=\"328\" alt=\"Custom tool dialog\"
src=\"https://github.com/user-attachments/assets/90c3ee95-7f2a-4daf-a334-f20de6ff5ca2\"
/>
Fixes#15183. Addresses #15370.
### Why we need it and why it was done in this way
Adding a new managed CLI tool should be a one-line preset entry — not 4+
files of bespoke download/extract/IPC code. mise is a mature polyglot
tool manager that already speaks the backends Cherry needs.
**Tradeoffs made:**
- **mise bundled at build time** (~15 MB per platform) rather than
downloaded at first run — faster first-run UX, no chicken-and-egg on a
fresh install.
- **Fully isolated mise environment** (\`HOME\`/\`XDG_*\`/\`MISE_*\` all
relocated under \`feature.binaries.data\`) — Cherry never reads or
writes the user's own \`~/.config/mise/\` or \`~/.local/share/mise/\`.
- **No custom \`BinaryBackend\` interface.** mise's grammar (\`npm:\`,
\`pipx:\`, \`github:\`, registry) is already polyglot; wrapping it would
be a shallow seam that re-implements what mise owns. Removing this
abstraction makes consumers simpler (deletion test passes).
- **Auth-token policy: opt-in only.** Ambient \`GITHUB_TOKEN\` /
\`GH_TOKEN\` are not forwarded into mise's process env. Users who hit
GitHub's unauthenticated 60 req/hr API limit can set
\`CHERRY_GITHUB_TOKEN\` to raise it to 5000 req/hr without consenting to
share their general shell token.
- **China mirror auto-detection.** \`isUserInChina()\` toggles
\`NPM_CONFIG_REGISTRY=registry.npmmirror.com\` +
\`PIP_INDEX_URL=pypi.tuna.tsinghua.edu.cn\` for every npm/pipx backend
transparently.
**Alternatives considered:**
- *Keep per-tool install scripts.* Doesn't scale — each new tool is 4+
files of duplicated logic.
- *Use mise from user's \`PATH\`.* Would depend on user having mise
installed and could conflict with their config.
- *Custom \`BinaryBackend\` abstraction.* Shallow wrapper over mise's
grammar; no second backend in sight; deletion test passes.
**Scope (what's in / what's out):**
- **In:** uv, bun, ripgrep, claude-code, openclaw, gh, opencode,
gemini-cli, lark, kimi-cli, qwen-code, iflow-cli, github-copilot-cli —
anything mise can install as a single relocatable binary.
- **Out:** \`OvmsManager\` (multi-file server provisioning, hardware
detection, generated config); Tesseract OCR data (not a binary; lives
with \`OvOcrService\`).
### Breaking changes
None at the user-facing layer. v2 data is throwaway per CLAUDE.md, so
the preference-key rename (\`feature.mise.*\` → \`feature.binaries.*\`)
intentionally ships without a migrator.
### Special notes for your reviewer
**Architecture & docs**
- \`docs/references/binary-manager/README.md\` — scope criterion,
persisted/contract surface, bundled-vs-mise state contract, China mirror
behavior, \`CHERRY_GITHUB_TOKEN\` opt-in, adding a new managed binary.
- \`CLAUDE.md\` adds a \`**MUST READ**\` link next to Lifecycle / Window
Manager / Data / Paths.
- The mise-shim-wins-over-\`cherry.bin\` precedence rule is documented
in the README's "State contract" section.
**Code orientation**
- \`src/main/services/BinaryManager.ts\` — the lifecycle service. Wraps
mise via \`runMise()\`; isolated env in \`buildIsolatedEnv()\`; bundled
extraction with atomic tmp+rename; per-tool try/catch so a single
failure can't abort init; \`isManagedBinaryReady()\` verifies the
resolved file is executable (not just that mise thinks it's installed).
- \`packages/shared/data/presets/binary-tools.ts\` —
\`PREDEFINED_BINARY_TOOLS\` registry; \`tool\` field is a mise spec.
-
\`src/renderer/src/pages/settings/McpSettings/EnvironmentDependencies.tsx\`
— three-state UI (\`managed\` / \`bundled\` / \`not-installed\`) backed
by \`Binary_GetState\` + \`Binary_ProbeBundled\`.
- \`scripts/download-binaries.js\` — build-time downloader for mise / uv
/ bun / rg (HTTPS + sha256-verified, archive-aware extraction).
**Migration**
- \`OpenClawService.install()\` is now two lines delegating to
\`BinaryManager\` — \`install-openclaw.js\` is gone.
- \`CodeCliService\` no longer uses \`bun install -g\`; the
\`BUN_INSTALL\` / \`~/.cherrystudio/install/global/\` path is removed.
- \`FileStorage.getRipgrepBinaryPath()\` now resolves via
\`getBinaryPath('rg')\`; the vendored SDK rg is no longer used.
- \`extractRtkBinaries\` + the \`AgentBootstrapService\` call are
deleted. \`rtkRewrite()\` degrades gracefully when rtk is absent;
\`rtkAvailable\` caches with a 60s TTL so install-via-mise takes effect
without restart.
**Multi-round review**
Two adversarial review rounds against this branch (Bug Hunter / Security
/ Architecture / Correctness) ran during development; both rounds'
High-severity findings are addressed in commits \`70afde6af\` and
\`1d864439d\`. R3 known follow-ups (architecture duplications in
\`CodeCliService\`'s switch statements, etc.) are tracked as Medium and
intentionally deferred.
### Checklist
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: Write code that humans can understand and Keep it simple
- [x] Refactor: Leaves binary acquisition meaningfully cleaner than
before (five mechanisms → one)
- [x] Upgrade: v2 data is throwaway; no migrator needed and the absence
is intentional
- [x] Documentation: \`docs/references/binary-manager/README.md\` +
\`CLAUDE.md\` Architecture section
- [x] Self-review: Two multi-perspective review rounds against the
branch; all Highs addressed
### Release note
\`\`\`release-note
NONE
\`\`\`
---------
Signed-off-by: Vaayne <liu.vaayne@gmail.com>
Signed-off-by: Vaayne Liu <vaayne@macos.shared>
Co-authored-by: fullex <106392080+0xfullex@users.noreply.github.com>
Add a Code Organization subsection that points to the main, renderer, and shared-layer architecture references so contributors learn where code goes before adding it.
The former v2 branch has merged into main, making the old "main is frozen,
submit to v2" guidance backwards. Update all contributor-facing entry points
to the current model: main is the active v2 development line; v1 maintenance
fixes target the v1 branch.
- CLAUDE.md: add a v2 "Current state" callout and a branch-targeting
Operational Rule (the AI-facing context).
- gh-create-pr skill: route v1 maintenance PRs to base v1.
- PR template: replace the stale hidden comment with a visible branch
callout and add a branch checklist item.
- CONTRIBUTING.md / docs/guides/contributing.md: rewrite the branch strategy
section to the new model.
- docs/guides/branching-strategy.md: add a current-model note and fix the PR
target guideline.
Move all renderer source from src/renderer/src/* up one level to
src/renderer/*, removing the redundant nested src directory.
- Update path aliases (@renderer, @types, @logger, @data) and TanStack
Router paths in electron.vite.config.ts; update tsconfig.{json,web,node}
path mappings and include globs.
- Fix Vite root-relative script paths in the 8 renderer HTML entries.
- Update cross-process relative imports in main/preload (language,
apiServer models, preload index) to drop the /src segment.
- Switch renderer test imports of the logger mock to the @test-mocks alias.
- Update hardcoded renderer paths in scripts and their fixtures, lint
configs (eslint/oxlint/biome), CODEOWNERS, docs, and the data-classify tool.
- Convert deep (../../+) relative imports within the renderer to the
@renderer alias (69 files, 108 imports); keep single-level relatives.
- Fix doc links broken by the move and correct one pre-existing broken
link in naming-conventions.md.
packages/shared was never a real pnpm workspace package (no package.json); it was referenced only through the @shared TypeScript path alias. Relocate it under src/ via git mv (143 files, detected as pure renames).
Repoint the @shared alias and include globs to src/shared across electron.vite.config.ts, tsconfig.{json,node,web}.json and vitest.config.ts; update scripts/check-custom-exts.ts, scripts/update-languages.ts, the eslint.config.mjs generated-file globs, the data-classify generator output targets, .github/CODEOWNERS path rules, and CLAUDE.md/docs/source-comment references.
The @shared alias name is unchanged, so all 1403 @shared/* import sites resolve without modification. Verified with typecheck:node, typecheck:web and the full test suite (700 files, 9739 tests passing).
libsql client-ts upstream issue #288 makes PRAGMA busy_timeout ineffective
for async transactions, so concurrent db.transaction() calls reliably surface
SQLITE_BUSY. Introduce DbService.withWriteTx as a serialized write helper:
- Process-wide FIFO mutex (async-mutex) serializes write transactions.
- libsql client's default BEGIN IMMEDIATE protects against read-then-write
tx upgrade failures (no override needed at the drizzle layer).
- Single 50ms BUSY retry guards against transient external locks.
Reads do NOT need this — WAL gives readers snapshot isolation that is never
blocked by writers.
Includes unit tests (FIFO ordering, finally release on throw, single BUSY
retry, persistent BUSY rethrow, non-BUSY passthrough) plus a real-libsql
integration test. Updates the DbService test mock with a passthrough
withWriteTx so dependent services do not throw "is not a function" in
tests. Documents the API in database-patterns.md and points
CLAUDE.md / data-api-overview.md at the new pattern.
Wraps setInterval with auto-unref, exception isolation, and cleanup
via the existing registerDisposable channel. Returns a Disposable.
Replaces 5 ad-hoc setInterval patterns (CacheService, PreferenceService,
WindowManager, ProxyManager, FileProcessingTaskService) — unifies
three pre-existing cleanup styles and fixes a missing unref() in
ProxyManager.
WindowManager: warmupGcTimer cleanup moves from onDestroy to onStop
(via registerDisposable) — acceptable for this singleton.
Skipped (YAGNI): registerTimeout, immediate/unref options,
activation-scoped variant. QuickAssistantService keeps bare
setInterval — its lifecycle is finer than activation.
- Add Mindset subsection covering Think Before Coding, Simplicity First,
Surgical Changes, and Goal-Driven Execution so behavior guardrails sit
alongside project-specific rules under a single MUST FOLLOW section.
- Reorganize existing rules into an Operational Rules subsection.
- Drop entries absorbed by the new mindset principles
("Start simple", "Match the house style").
- Trim GitHub section: drop narrative bridges and generic gh CLI listings
that any LLM agent already knows; keep only project-specific policy.
Reset version to 2.0.0-dev to reflect this branch is internal-only and
not user-facing, and add a Coexistence Mindset section to CLAUDE.md so
AI agents stop writing defensive code for two throwaway things:
- v1 code and data (Redux, Dexie, ElectronStore) — all v1 code is
deleted before v2 ships; v1 data reaches v2 only via migrators in
src/main/data/migration/v2/.
- Drizzle schemas and migrations/sqlite-drizzle/*.sql — rewritten
freely until release, then wiped and regenerated as a single clean
initial migration. Only the final regenerated migration is the
correctness target.
Also extend the Data Layer "Removing" list with ElectronStore so the
v1 boundary referenced by the new section is canonical.
Add an internal record for v2 changes that affect how users use the
app. PR authors drop a fragment .md per change; the release manager
aggregates and translates them into the Chinese user-facing release
note at v2.0.0, then discards the fragments with v2-refactor-temp/.
Also translate v2-refactor-temp/README.md to English and link the new
directory from it.
Align cache-overview.md and cache-usage.md with the template-key and
subscribe* APIs (sharedCasual was dropped in 3fbc52e05). Extract the
"adding keys" content into a new cache-schema-guide.md aligned with
preference and boot-config schema guides. Lift non-obvious invariants
(isEqual short-circuit, TTL-with-hooks warning, Persist has no delete,
Main-wins convergence, template placeholder rules) into a first-class
Design Invariants section in the overview.
Fix two code-contradicted claims:
- useCache does not accept a TTL options argument (hook signature is
(key, initValue?)).
- Persist is renderer-authoritative; Main only relays IPC and does
not store (CacheService.ts:477-479 is "Reserved, not implemented").
Update peripheral references in the same pass so cross-references stay
coherent: v2-renderer skill, CLAUDE.md, architecture-overview.md,
api-design-guidelines.md (Cache vs DataApi matcher contrast), and the
package READMEs.
Net change: +249 / -579.
Add a guiding principle that forbids plain `git pull` on shared
branches and requires fetch-then-rebase before push, to prevent merge
commits from slipping into shared history.
Phase ordering already guarantees BeforeReady services (PreferenceService,
DbService, CacheService, DataApiService) are ready before WhenReady starts,
so declaring @DependsOn across phases adds noise and misleads readers about
same-phase coupling. The rule existed in lifecycle-overview but was buried
in a bullet; reinforce it in the docs AI assistants scan first.
- CLAUDE.md: add a bullet under the Lifecycle section stating @DependsOn
is for same-phase deps only
- lifecycle/README.md: new "Cross-Phase Dependencies Are Automatic"
callout section and a matching Anti-patterns row
- lifecycle/lifecycle-overview.md: promote the line-87 note to a blockquote
callout and annotate the Dependency Rules table
- lifecycle/lifecycle-decision-guide.md: add Common Mistake #5 with
bad/good code examples
New guide at docs/references/testing/database-testing.md describing:
- When to use setupTestDatabase() (and when not to).
- Options, lifecycle behaviour, and PRAGMA handling.
- Migration recipe (before/after diffs) for converting legacy tests.
- Anti-patterns: vi.mock('@application') override, hand-written
CREATE TABLE SQL, describe.concurrent within harness scope,
nested setupTestDatabase() calls, re-adding the
vi.mock('node:fs', importOriginal) escape hatch.
- Gotchas: LibSQL transaction connection recycle + setPragma replay,
pathToFileURL for Windows, FTS5 with NULL content, truncate-vs-drop.
Linked from CLAUDE.md's Testing Guidelines section so future
contributors find the convention.
Align with the existing @logger alias convention by introducing
@application as a short alias for src/main/core/application. This
reduces import verbosity across ~130 main-process files while keeping
4 intentional sub-path imports (@main/core/application/Application)
unchanged to preserve the vi.mock bypass mechanism in tests.
Configured in tsconfig.node.json and electron.vite.config.ts; Vitest
inherits the alias automatically.
Signed-off-by: fullex <0xfullex@gmail.com>
Centralize all main-process filesystem path access behind a single
entry point: application.getPath('namespace.key', filename?).
- Add src/main/core/paths/ module:
* constants.ts — zero-dep CHERRY_HOME / BOOT_CONFIG_PATH for early
boot use (importable before Electron `app` is ready).
* pathRegistry.ts — frozen PATHS object with 49 keys across five
namespaces (cherry / sys / app / feature / external).
* index.ts — re-exports PATHS and PathKey only.
* README.md — naming conventions, namespace taxonomy, dot semantics,
how to add a new key, and testing patterns.
- Add Application.getPath(key, filename?) as the sole entry point.
PathKey is a string-literal union derived from PATHS, so invalid keys
fail at compile time. Suspicious filenames (absolute, '..', or path
separator) are logged via loggerService and joined anyway — graceful
degradation, not a hard error.
- Refactor BootConfigService to consume BOOT_CONFIG_PATH from
paths/constants.ts instead of building the path from os.homedir() +
HOME_CHERRY_DIR.
- Extend ESLint data-schema-key/valid-key rule to enforce the
namespace.sub.key naming convention on pathRegistry.ts.
- Add Application.getPath unit tests covering filename validation
graceful-degradation behavior.
- Document the rule in CLAUDE.md (new Guiding Principle + concise
Path Management section); detailed conventions live in
src/main/core/paths/README.md.
This PR is the scaffolding only. Migrating existing call sites
(getFilesDir(), os.homedir() + HOME_CHERRY_DIR, scattered app.getPath()
calls, etc.) is left to follow-up PRs.
Signed-off-by: fullex <0xfullex@gmail.com>
- Add toDisposable() utility to bridge () => void callbacks to Disposable
- Overload registerDisposable() to accept both Disposable and () => void,
with return value for inline assignment
- Unify IPC tracking into Disposable: remove _ipcHandleChannels,
_ipcOnListeners, _cleanupIpc(); ipcHandle/ipcOn now return Disposable
and delegate cleanup to registerDisposable
- Add _doDestroy idempotency guard (safe no-op on already-destroyed)
- Export toDisposable from lifecycle module
- Update lifecycle docs to reflect unified cleanup and new APIs
Signed-off-by: fullex <0xfullex@gmail.com>
Replace ~70 lines of inline code examples and detailed explanations
with a concise bullet-point summary of core rules. All details are
already covered by the lifecycle documentation under docs/en/references/lifecycle/.
Signed-off-by: fullex <0xfullex@gmail.com>
Add a new optional lifecycle capability (symmetric with Pausable) that
allows services to defer loading heavy resources (native modules,
windows, caches) until a runtime condition is met.
- Add Activatable interface with onActivate()/onDeactivate() hooks
- Add isActivatable() type guard
- Add _doActivate()/_doDeactivate() to BaseService with idempotency
and concurrency guards (_activating flag)
- Add protected activate()/deactivate() for self-activation within
services
- Add activate()/deactivate() to LifecycleManager and Application
- Auto-deactivate in _doStop() (independent try/catch) and
_doDestroy() (safety net)
- Add SERVICE_ACTIVATED/DEACTIVATED lifecycle events
- Add [A]/[C] tags to bootstrap summary for Activatable/Conditional
- Add comprehensive tests (20 cases)
- Update lifecycle-usage.md, lifecycle-decision-guide.md, CLAUDE.md
Signed-off-by: fullex <0xfullex@gmail.com>
Introduce VS Code-style typed event primitives to the lifecycle system,
replacing ad-hoc app.emit patterns with type-safe, lifecycle-managed
alternatives.
- Add Emitter<T>/Event<T> for repeatable inter-service events
- Add Signal<T> for one-shot completion (implements PromiseLike)
- Add Disposable interface and BaseService.registerDisposable()
for automatic cleanup on service stop/destroy
- Add comprehensive tests for event, signal, and disposable cleanup
- Update lifecycle documentation with new patterns and usage guide
Signed-off-by: fullex <0xfullex@gmail.com>
Add ipcHandle() and ipcOn() helper methods to BaseService that
automatically track registered IPC handlers and clean them up on
service stop/destroy, eliminating manual unregisterIpcHandlers()
boilerplate and preventing handler leaks.
Key changes:
- BaseService.ipcHandle(): wraps ipcMain.handle() with auto-tracking
- BaseService.ipcOn(): wraps ipcMain.on() with auto-tracking
- _doStop(): uses try/finally to guarantee IPC cleanup even on error
- _doDestroy(): safety-net cleanup for services destroyed without stop
- 9 new test cases covering all IPC lifecycle scenarios
- Updated lifecycle docs (decision guide, usage, overview, migration)
Signed-off-by: fullex <0xfullex@gmail.com>
Add overview and schema guide for the BootConfig data system,
which provides synchronous file-based configuration before the
lifecycle system takes over. Update data README with BootConfig
navigation, decision table, and characteristics. Add BootConfig
row to CLAUDE.md data management table.
Signed-off-by: fullex <0xfullex@gmail.com>
Move detailed lifecycle and application documentation from source-adjacent
READMEs to docs/en/references/lifecycle/, following the same organizational
pattern as docs/en/references/data/. Source-adjacent READMEs are reduced to
lean pointers. Also add main process application.get() examples to data docs.
Signed-off-by: fullex <0xfullex@gmail.com>
Replace ad-hoc vi.mock('@main/core/application') calls across test files
with a centralized mockApplicationFactory(overrides?) utility that provides
all registered services by default and supports per-service overrides.
- Add tests/__mocks__/main/DbService.ts (standalone DbService mock)
- Add tests/__mocks__/main/application.ts (unified factory)
- Simplify tests/main.setup.ts global mock
- Migrate 4 test files to use mockApplicationFactory
- Document unified mock system in CLAUDE.md and README.md
Signed-off-by: fullex <0xfullex@gmail.com>
- Update lifecycle README to reference application.get() instead of
raw container/manager APIs
- Fix @Injectable() examples to include required name parameter
- Use actual service names (DbService) instead of fictional ones
- Add "Migrating from Old Service Patterns" section with step-by-step
guide covering manual singleton, raw new, and free function patterns
- Cross-link lifecycle README from application README and CLAUDE.md
Signed-off-by: fullex <0xfullex@gmail.com>
### What this PR does
Before this PR:
CLAUDE.md described agents.db path as `~/.cherrystudio/data/agents.db`
(dev) / `userData/agents.db` (prod), which is outdated after #13392.
After this PR:
Updated to reflect the unified path `{userData}/Data/agents.db` with
macOS examples for both dev and prod.
Fixes #
N/A
### Why we need it and why it was done in this way
The following tradeoffs were made:
None. Straightforward documentation update.
The following alternatives were considered:
N/A
Links to places where the discussion took place:
https://github.com/CherryHQ/cherry-studio/pull/13392
### Breaking changes
None.
### Special notes for your reviewer
N/A
### Checklist
- [x] PR: The PR description is expressive enough and will help future
contributors
- [x] Code: [Write code that humans can
understand](https://en.wikiquote.org/wiki/Martin_Fowler#code-for-humans)
and [Keep it simple](https://en.wikipedia.org/wiki/KISS_principle)
- [x] Refactor: You have [left the code cleaner than you found it (Boy
Scout
Rule)](https://learning.oreilly.com/library/view/97-things-every/9780596809515/ch08.html)
- [x] Upgrade: Impact of this change on upgrade flows was considered and
addressed if required
- [ ] Documentation: A [user-guide update](https://docs.cherry-ai.com)
was considered and is present (link) or not required. Check this only
when the PR introduces or changes a user-facing feature or behavior.
- [x] Self-review: I have reviewed my own code (e.g., via
[`/gh-pr-review`](/.claude/skills/gh-pr-review/SKILL.md), `gh pr diff`,
or GitHub UI) before requesting review from others
### Release note
```release-note
NONE
```
Signed-off-by: icarus <eurfelux@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
### What this PR does
Before this PR:
- CLAUDE.md contained minimal guidance on development commands and
project structure
- Lacked detailed information about architecture, services, database
layers, and conventions
- Missing documentation on contribution restrictions and tech stack
details
After this PR:
- Comprehensive architecture documentation covering Electron structure,
main/renderer processes, and packages
- Detailed service registry for main process (WindowService, MCPService,
KnowledgeService, etc.)
- Complete Redux store slice documentation with state shape reference
- Database layer documentation (IndexedDB + SQLite/Drizzle)
- IPC communication patterns and tracing setup
- AI Core package architecture and provider abstraction details
- Multi-window architecture overview
- Tech stack matrix with all key dependencies
- Code style conventions, file naming, i18n guidelines
- Testing guidelines and v2 refactoring blockers
- Security best practices
### Why we need it and why it was done in this way
This documentation update serves as a comprehensive reference for AI
coding assistants and contributors working on the Cherry Studio
codebase. The expanded guide:
1. **Reduces onboarding friction** - New contributors and AI assistants
can understand the full architecture without diving into source code
2. **Clarifies contribution restrictions** - Explicitly documents the
v2.0.0 refactoring blockers to prevent rejected PRs
3. **Standardizes conventions** - Provides clear guidelines on code
style, naming, i18n, and testing expectations
4. **Documents critical systems** - Details the complex multi-process
architecture, IPC patterns, and service layer
5. **Improves maintainability** - Future changes to architecture can be
documented here for consistency
The documentation is organized hierarchically from high-level overview
to specific implementation details, making it easy to navigate.
### Breaking changes
None - this is documentation only.
### Special notes for your reviewer
- Added new section "Current Contribution Restrictions" to highlight
v2.0.0 blockers
- Expanded development commands with detailed descriptions and all
available scripts
- Added comprehensive "Project Architecture" section with ASCII diagrams
and tables
- Included path aliases reference table for quick lookup
- Added "Tech Stack" matrix for technology overview
- Included "Conventions" section covering TypeScript, code style, file
naming, i18n, and patched packages
- Added "Testing Guidelines" and "Important Notes" sections for v2
refactoring and security
### Checklist
- [x] PR: The PR description is expressive and documents the changes
clearly
- [x] Documentation: Comprehensive guide added for future contributors
and AI assistants
- [x] Self-review: Content reviewed for accuracy and completeness
### Release note
```release-note
NONE
```
https://claude.ai/code/session_01DCYQm925rdYraLMBiQ9fZx
Co-authored-by: Claude <noreply@anthropic.com>