Development
Commands
| Command | What it does |
|---|---|
npm run build | Builds into dist/. |
npm run typecheck | Type-checks src/ and test/. |
npm run lint | Runs ESLint with type-aware rules. |
npm run format | Formats the code with Prettier. format:check only verifies. |
npm test | Builds and runs the unit and end-to-end tests. They need no Mac. |
npm run test:watch | Runs the tests in watch mode while you develop. |
npm run test:integration | Tests against a real simulator. macOS only; they boot a device. |
npm run docs:dev | Serves this documentation locally. |
npm run docs:build | Builds the static site. |
npm run docs:tools | Regenerates the tool reference from the server, in both languages. |
Tests
npm test runs five groups of tests, none of which need a Mac:
| Folder | What it tests | What is replaced |
|---|---|---|
test/domain/ | Model, element queries, errors. | Nothing: it is pure code. |
test/application/ | The rules of each service: cache, waiting, validation, sequences, pasting, scrolling. | The ports, by in-memory implementations. |
test/infrastructure/ | The commands each gateway builds and how it parses their output. | Command execution. |
test/mcp/ | The whole server through a real MCP client, in memory. | Command execution and the clock. |
test/process/ | The compiled binary, started as a process and driven over stdio. | Nothing. |
npm run test:integration adds another level: it boots a real simulator and runs the tools against it. It is what proves that the commands the other tests expect are commands the real tools accept. It has two suites:
simulator.integration.test.tsuses the apps that ship with iOS.fixture.integration.test.tsinstalls a small SwiftUI app fromtest/fixtures/app/, built withswiftcand no Xcode project, and asserts on what it shows after typing, pasting, scrolling, opening a deep link or receiving a push. It also records timings and response sizes. It needs theFIXTURE_APPvariable:
FIXTURE_APP="$(bash test/fixtures/app/build.sh | tail -n 1)" npm run test:integrationThe UI tests are skipped when idb is not installed.
Continuous integration runs linting, npm test on Ubuntu and macOS with Node 20 and 22, and the integration tests on a macOS runner with idb installed.
Test utilities in test/support/:
Harness: an MCP client connected to the whole server, with fake commands and a fake clock.FakeCommandRunner: records commands and answers with canned output or failures.FakeClock: a clock that only advances when the code sleeps.fakes.ts: in-memory implementations of every domain port.
Adding a tool
- If a new capability is needed, add it to the matching port in
src/domain/ports/and implement it in its gateway insrc/infrastructure/. - Expose the use case in the service in
src/application/. - Declare the tool in the
ToolProviderinsrc/mcp/tools/:
defineTool({
name: 'set_appearance',
title: 'Set light or dark mode',
description: 'Switches the simulator between light and dark appearance.',
inputSchema: {
appearance: z.enum(APPEARANCES).describe('Appearance to apply.'),
device: deviceParam,
},
annotations: { ...Hints.mutating, idempotentHint: true },
execute: async ({ appearance, device }) => {
const target = await this.environment.setAppearance(appearance, device);
return text(`${target.label} now uses the ${appearance} appearance.`);
},
}),- Add tests: the rule in
test/application/, the command intest/infrastructure/and the visible behaviour intest/mcp/. Add the name to the list inprotocol.e2e.test.ts. - Run
npm run docs:toolsto regenerate the reference.
Documentation
The site is built with VitePress. The content is the Markdown files in docs/ (Spanish at the root, English under docs/en/) and the configuration lives in docs/.vitepress/config.ts. Every change on main is published to GitHub Pages by the .github/workflows/docs.yml workflow.
The Tools page is generated by scripts/generate-tool-docs.mjs and must not be edited by hand.
Releasing
- Update the version in
package.jsonand add an entry toCHANGELOG.md. - Tag the commit (
git tag v1.2.0 && git push --tags) and create a GitHub release. - Publishing the release runs
.github/workflows/publish.yml, which publishes the package to npm when theNPM_TOKENsecret is configured.