Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
# Repository Guidelines
# Cherry Studio Mobile

Follow the project naming rules in
[docs/references/naming-conventions.md](docs/references/naming-conventions.md).
Cherry Mobile is Cherry Studio's Expo and React Native client.

# Operational Rules
- **Write conventional commits**: Commit small, focused changes using Conventional Commit messages (e.g., `feat(data-api):`, `fix(lifecycle):`, `refactor(quick-assistant):`, `docs(testing):`, `chore(deps):`, `test(window-manager):`). Scope must be a specific kebab-case module, never generic like `main` — when `git log` conflicts with this rule, this rule wins.
- **Test behaviour, at the lowest layer that has it**: A test earns its place by failing when a defect exists and only then. Never assert that a wrapper forwards its props, that a mock was called, or that a render produced something. Cover logic in pure functions and hooks instead of re-asserting it through a screen render — screen-level render suites are not written here at all, because device coverage runs through agent-device. Always cover data contracts (DB schema, migrations, anything serialized), upstream patch guards, and regressions for bugs that were actually fixed. When removing a test, the justification must be that it has no protective value; slowness is a reason to change how it runs, not whether it exists.
Use `pnpm@11.8.0`. This repository has no root application build script: build workspace packages
with `pnpm packages:build`, and run the complete repository type check with `pnpm typecheck`.

- When naming or renaming files, directories, identifiers, or documentation, read
[Naming Conventions](docs/references/naming-conventions.md).
- When adding, moving, or exposing modules, read
[Code Organization](docs/references/code-organization.md).
- When adding, changing, removing, or running tests, read
[Testing And CI](docs/guides/testing-and-ci.md).
- Before creating commits, splitting work, or opening a pull request, read
[Git Workflow](docs/guides/git-workflow.md).
- When building or changing product UI, read
[UI Development](docs/guides/ui-development.md).
- When running iOS device acceptance in a Conductor workspace, read
[Parallel Device Testing](docs/guides/parallel-device-testing.md).
1 change: 1 addition & 0 deletions CLAUDE.md
8 changes: 6 additions & 2 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Rules for visual decisions: where colour comes from, how hierarchy is built, when a surface or border is allowed, and where literal values are still permitted.

Interaction component ownership is in [UI Components](docs/references/ui-components.md). Router structure and safe areas are in [Navigation And Insets](docs/references/navigation-and-insets.md). Naming is in [Naming Conventions](docs/references/naming-conventions.md).
Interaction component ownership is in [UI Components](docs/references/ui-components.md). Router structure and safe areas are in [Navigation And Insets](docs/references/navigation-and-insets.md). Naming is in [Naming Conventions](docs/references/naming-conventions.md). Local and remote validation ownership is in [Testing And CI](docs/guides/testing-and-ci.md).

## Priority Order

Expand Down Expand Up @@ -190,11 +190,15 @@ Any visual change:

```bash
pnpm typecheck:app
pnpm test:app -- <pattern> # affected suites only; run the full suite once before opening a PR
pnpm test:app -- <pattern> # affected suites only
pnpm lint
pnpm format:check
```

Before opening a draft PR, follow the complete local gate in
[Testing And CI](docs/guides/testing-and-ci.md). If the draft changes later, rerun that gate on the
final head before marking it ready. The full test suite then runs in remote CI.

**Plus: look at it in both light and dark on a device or simulator.** Structural verification is not the same as having seen it — contrast, hierarchy, and how a colour reads against real content only show up on screen.

`pnpm design:sync` syncs icons only. `packages/design-tokens/src/styles/` and `scripts/theme-contract.ts` are mobile-owned in both names and values: no token name is ever serialized between the two apps, so there is no contract to align — only a presentation layer that would diverge. Restoring the sync would reinstate every deleted name.
Expand Down
69 changes: 30 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,47 @@
# Welcome to your Expo app 👋
# Cherry Studio Mobile

This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
Cherry Mobile is the Expo and React Native client for Cherry Studio. It keeps Cherry's chat and
provider model compatible with Desktop while using mobile-native data, navigation, rendering, and
resource ownership.

## Get started
## Requirements

1. Install dependencies
- Node.js 24, matching pull request CI
- `pnpm@11.8.0`
- Xcode for iOS development or Android Studio for Android development

```bash
npm install
```
## Install

2. Start the app

```bash
npx expo start
```

In the output, you'll find options to open the app in a

- [development build](https://docs.expo.dev/develop/development-builds/introduction/)
- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo

You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
```bash
pnpm install
```

## Get a fresh project
## Run

When you're ready, run:
The app uses an Expo development client because it includes custom native modules. Build and install
the client for the target platform:

```bash
npm run reset-project
pnpm ios
pnpm android
```

This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.

### Other setup steps

- To set up ESLint for linting, run `npx expo lint`, or follow our guide on ["Using ESLint and Prettier"](https://docs.expo.dev/guides/using-eslint/)
- If you'd like to set up unit testing, follow our guide on ["Unit Testing with Jest"](https://docs.expo.dev/develop/unit-testing/)
- Learn more about the TypeScript setup in this template in our guide on ["Using TypeScript"](https://docs.expo.dev/guides/typescript/)
After the development client is installed, start Metro with:

## Learn more
```bash
pnpm dev
```

To learn more about developing your project with Expo, look at the following resources:
Rebuild the development client after native dependency or native configuration changes. Use
`pnpm dev:clear` when the Metro cache must be reset.

- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
## Validate

## Join the community
Use the focused development loop and pre-PR gates in
[Testing And CI](docs/guides/testing-and-ci.md). Pull request CI runs the complete repository test
suite after a draft is marked ready for review.

Join our community of developers creating universal apps.
## Documentation

- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
Start with the [project documentation index](docs/README.md) for architecture, conventions, and
task-oriented guides.
5 changes: 5 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Guides are task-oriented procedures for changing or extending the application.
| Document | Description |
| --- | --- |
| [Extending Cherry Mobile](./guides/extending.md) | Add resource endpoints, workflows, persistence, backend behavior, and UI |
| [Git Workflow](./guides/git-workflow.md) | Commits, stacked PRs, review readiness, and case-only renames |
| [Parallel Device Testing](./guides/parallel-device-testing.md) | Conductor port and iOS simulator isolation and cleanup |
| [Testing And CI](./guides/testing-and-ci.md) | Focused checks, test value, local PR gates, and remote CI |
| [UI Development](./guides/ui-development.md) | CherryUI ownership and reusable React component composition |

## References

Expand All @@ -20,6 +24,7 @@ They are the source of truth for how the repository works today.
| Document | Description |
| --- | --- |
| [Architecture Overview](./references/architecture-overview.md) | Runtime model, source ownership, dependency boundaries, and frontend/backend interfaces |
| [Code Organization](./references/code-organization.md) | Module placement, domain promotion, layer ownership, and public surfaces |
| [Domain Language](./references/domain-language.md) | Shared product and architecture terminology |
| [Naming Conventions](./references/naming-conventions.md) | File, directory, identifier, and documentation naming rules |
| [Runtime Ownership](./references/runtime-ownership.md) | Bootstrap, app runtimes, caller-owned sessions, cleanup, and post-ready work |
Expand Down
9 changes: 5 additions & 4 deletions docs/guides/extending.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Extending Cherry Mobile

This is a placement guide for extending the in-process frontend/backend architecture. Prefer an
existing deep module over a new registry or pass-through wrapper. Read the
[Architecture Overview](../references/architecture-overview.md) and [Data Layer](../references/data/README.md)
before introducing a new cross-layer interface.
existing deep module over a new registry or pass-through wrapper. Read
[Code Organization](../references/code-organization.md), the
[Architecture Overview](../references/architecture-overview.md), and
[Data Layer](../references/data/README.md) before introducing a new cross-layer interface.

## Add A Resource Endpoint

Expand Down Expand Up @@ -60,7 +61,7 @@ including model capability checks.
Keep a direct Cherry Desktop service counterpart's `Service` name and public methods. Name
mobile-only owners by role: `Module`, `Runtime`, `Session`, `Client`, `Adapter`, or `Manager`; never
add an `Impl` suffix or a forwarding `Service` wrapper. See
[Naming Conventions](../references/naming-conventions.md#52-architectural-role-names).
[Runtime Ownership](../references/runtime-ownership.md#role-names).

App-level tools are resolved by `ToolResolver` and attached in
`src/backend/ai/runtime/aiSdk/params/buildAgentParams.ts`. Provider plugins are
Expand Down
48 changes: 48 additions & 0 deletions docs/guides/git-workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Git Workflow

This guide defines commit, stacked-review, pull request, and case-only rename procedures.

## Commits

Write small, focused Conventional Commits:

```text
<type>(<specific-kebab-case-scope>): <description>
```

Use a module scope such as `data-api`, `chat-input`, `testing`, or `window-manager`. Generic scopes
such as `main` are not valid. Older unscoped commits are not precedents.

## Stacked Pull Requests

Use the project `gh-stack` skill before implementation when one coherent story contains multiple
dependent concerns that can be reviewed in sequence. Plan the layers first, put foundations at the
bottom, and keep Conventional Commit messages in every layer.

Use one stack for one coherent story. Put unrelated features, bug fixes, or refactors in separate
Conductor workspaces and separate stacks. A linear stack is not a container for parallel independent
work.

When a feature needs a new reusable CherryUI component, place the component package change in its
own bottom PR and the feature integration in the PR above it. See
[UI Development](./ui-development.md).

## Pull Request Lifecycle

1. Run the local gates in [Testing And CI](./testing-and-ci.md).
2. Create a normal PR as a draft, or submit an entire stack with `gh stack submit --auto`.
3. After successful PR or stack creation, release the workspace simulator and its allocated port
range using [Parallel Device Testing](./parallel-device-testing.md).
4. Rerun local gates after later draft changes, then mark the final head ready for review.
5. Treat the remote CI result as the complete-suite gate.

For a stack, release resources once after all layers have been submitted, not after each layer.

## Case-Only Renames

Git on macOS may ignore a rename that changes only letter case. Use an intermediate name:

```bash
git mv Foo.tsx _tmp_foo.tsx
git mv _tmp_foo.tsx foo.tsx
```
58 changes: 58 additions & 0 deletions docs/guides/parallel-device-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Parallel Device Testing

This guide defines iOS simulator and Metro isolation for concurrent Conductor worktrees. Android
emulator provisioning is outside this workflow.

## Workspace Resources

Conductor assigns each workspace ten ports: `$CONDUCTOR_PORT` through
`$((CONDUCTOR_PORT + 9))`. Use the base port for Metro and only that reserved range for companion
services. A Conductor device test must not use a fixed port such as `8081` or `8084`.

Each worktree uses a dedicated simulator named:

```text
iPhone 17 Pro ($CONDUCTOR_WORKSPACE_NAME)
```

Provision it lazily for the workspace, record its UDID under that workspace's `.context`, and never
reuse a simulator with a live ownership claim. If the dedicated simulator cannot be provisioned,
stop and report the blocker rather than taking another workspace's device.

Before opening the app, inspect devices and ownership:

```bash
agent-device devices --platform ios
agent-device device status --platform ios
```

## Metro And App Session

Start Metro on the allocated base port:

```bash
pnpm dev --port "$CONDUCTOR_PORT"
```

Use a workspace-unique session, explicit simulator, and explicit Metro hint:

```bash
agent-device open com.cherry-ai.cherry-studio-app --session "$CONDUCTOR_WORKSPACE_NAME" --platform ios --device "iPhone 17 Pro ($CONDUCTOR_WORKSPACE_NAME)" --metro-host 127.0.0.1 --metro-port "$CONDUCTOR_PORT" --relaunch
```

Keep commands for one session serial. Different sessions may run concurrently only when their
devices and port ranges differ.

## Cleanup

After a PR or complete stack is created:

1. Close the workspace session with `agent-device close --session "$CONDUCTOR_WORKSPACE_NAME"
--platform ios --shutdown`.
2. Stop listeners only in `$CONDUCTOR_PORT..$((CONDUCTOR_PORT + 9))`.
3. Delete only the simulator whose recorded UDID and expected workspace name both match.
4. Remove the workspace simulator metadata after deletion succeeds or the recorded device is
already absent.

The local Conductor archive script repeats this cleanup as a fallback. Cleanup must be idempotent and
must refuse to delete an unrecorded or name-mismatched simulator.
70 changes: 70 additions & 0 deletions docs/guides/testing-and-ci.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Testing And CI

This guide defines the focused development loop, test-value rules, local pull request gates, and
the remote CI boundary.

## Test The Owned Behavior

- Put a test at the lowest layer that owns the behavior. Prefer pure functions and hooks over
reasserting the same behavior through a screen.
- A test must fail when its protected behavior regresses and remain stable across unrelated
implementation changes.
- Do not write tests whose only claim is that a wrapper forwards props, a component renders without
throwing, or an implementation collaborator was called.
- A mock interaction is valid when the interaction itself is the observable contract, such as a
transaction boundary, request shape, callback order, cancellation, subscription, or cleanup.
- Do not add screen-level render suites. Exercise screen workflows on a device with `agent-device`;
test their pure logic and hooks directly.
- Always cover database schemas and migrations, serialized contracts, upstream patch guards, and a
regression that reproduces a bug being fixed.
- Remove a test only when it protects no behavior. If a valuable test is slow, change how it runs.

## Focused Development Loop

Format and lint only the files being changed:

```bash
pnpm exec oxfmt --no-error-on-unmatched-pattern <files...>
pnpm exec oxlint <files...>
pnpm exec expo lint <files...>
```

Run every fixed suite that protects the changed behavior, including relevant suites whose files were
not edited:

```bash
pnpm test:app -- path/to/file.test.ts --runInBand
pnpm --filter @cherrystudio/ai-runtime test src/path/to/file.test.ts
```

Use the owning package filter for `ai-core`, `ai-runtime`, `ai-sdk-provider`, and
`provider-registry`. Jest owns app tests; package scripts select their package test runner.

Run only the specialized contract checks triggered by the change. Examples include
`pnpm docs:check-links`, `pnpm skills:check`, `pnpm design:check`, database migration checks, and
desktop synchronization guards.

## Before Creating A Draft PR

Run these full local gates on the final local head:

```bash
pnpm lint
pnpm format:check
pnpm typecheck
```

Also rerun the behavior-related fixed suites and specialized checks selected above. Do not run the
full local `pnpm test`; the complete suite belongs to remote PR CI.

## Ready For Review

Pull requests start as drafts. If the draft changed after its local gates, rerun the gates on the
final head before marking it ready. The existing GitHub workflow runs the complete tests, typecheck,
lint, format check, package build, and documentation link check only after the PR is ready.

A PR is merge-ready only after its remote checks pass.

`src/frontend/features/settings/__tests__/ModelSettingsScreen.test.tsx` predates the screen-suite
rule. Treat it as follow-up migration debt: move any protected behavior to its owning hook or pure
module before removing the render suite.
Loading
Loading