@ramarivera/chofi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +257 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1326 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +20 -0
- package/dist/discovery.d.ts +44 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +151 -0
- package/dist/drivers/apple.d.ts +68 -0
- package/dist/drivers/apple.d.ts.map +1 -0
- package/dist/drivers/apple.js +360 -0
- package/dist/drivers/expo.d.ts +14 -0
- package/dist/drivers/expo.d.ts.map +1 -0
- package/dist/drivers/expo.js +42 -0
- package/dist/drivers/idb.d.ts +38 -0
- package/dist/drivers/idb.d.ts.map +1 -0
- package/dist/drivers/idb.js +52 -0
- package/dist/drivers/maestro.d.ts +37 -0
- package/dist/drivers/maestro.d.ts.map +1 -0
- package/dist/drivers/maestro.js +64 -0
- package/dist/drivers/types.d.ts +23 -0
- package/dist/drivers/types.d.ts.map +1 -0
- package/dist/drivers/types.js +1 -0
- package/dist/errors.d.ts +31 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +59 -0
- package/dist/events.d.ts +33 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +26 -0
- package/dist/executor.d.ts +11 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +17 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/planning.d.ts +18 -0
- package/dist/planning.d.ts.map +1 -0
- package/dist/planning.js +75 -0
- package/dist/runtime.d.ts +157 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +650 -0
- package/dist/safety.d.ts +8 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +84 -0
- package/dist/spawn.d.ts +30 -0
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +178 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +64 -0
- package/sophy.png +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# chofi
|
|
2
|
+
|
|
3
|
+
<img src="sophy.png" alt="chofi mascot" width="200" />
|
|
4
|
+
|
|
5
|
+
**chofi** is a JSON-first CLI for iOS, Android, Expo, and React Native workflows — simulator management, builds, tests, screenshots, device operations, and Maestro UI automation.
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
- **JSON-first**: Every command emits NDJSON events for both humans and machines
|
|
10
|
+
- **Planning before execution**: `plan` commands show what *would* happen; execution requires explicit confirmation
|
|
11
|
+
- **Clean-room**: Inspired by public CLI patterns, but owned code with no proprietary dependencies
|
|
12
|
+
- **Maestro-native**: UI automation flows through Maestro's open-source local runner
|
|
13
|
+
- **Subprocess-based**: Uses `xcrun`, `simctl`, `devicectl`, and `maestro` via typed subprocess calls — no native framework linking
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @ramarivera/chofi
|
|
19
|
+
# or
|
|
20
|
+
pnpm add -g @ramarivera/chofi
|
|
21
|
+
# or
|
|
22
|
+
npx @ramarivera/chofi context --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Discover your project
|
|
29
|
+
chofi context --json
|
|
30
|
+
|
|
31
|
+
# Boot a simulator
|
|
32
|
+
chofi sim boot "iPhone 17 Pro" --json
|
|
33
|
+
|
|
34
|
+
# Take a screenshot
|
|
35
|
+
chofi sim screenshot "iPhone 17 Pro" --output ./shot.png --json
|
|
36
|
+
|
|
37
|
+
# Run Maestro flow
|
|
38
|
+
chofi maestro run flows/smoke.yaml --json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Command Reference
|
|
42
|
+
|
|
43
|
+
### Context & Discovery
|
|
44
|
+
|
|
45
|
+
| Command | Description |
|
|
46
|
+
|---------|-------------|
|
|
47
|
+
| `chofi context --json` | Project metadata, detected platforms, tool availability |
|
|
48
|
+
| `chofi doctor --json` | Health checks (Xcode, simctl, node, pnpm, typecheck) |
|
|
49
|
+
| `chofi plan run ios --json` | Show what an iOS run would do |
|
|
50
|
+
| `chofi plan run maestro --json` | Show what Maestro flows would run |
|
|
51
|
+
|
|
52
|
+
### Simulator
|
|
53
|
+
|
|
54
|
+
| Command | Description |
|
|
55
|
+
|---------|-------------|
|
|
56
|
+
| `chofi sim list --json` | List all simulators |
|
|
57
|
+
| `chofi sim runtime --json` | List available runtimes |
|
|
58
|
+
| `chofi sim device-types --json` | List available device types |
|
|
59
|
+
| `chofi sim boot <target> --json` | Boot simulator (fuzzy match) |
|
|
60
|
+
| `chofi sim shutdown <target> --json` | Shutdown simulator |
|
|
61
|
+
| `chofi sim open <target> --json` | Open Simulator.app GUI |
|
|
62
|
+
| `chofi sim screenshot <target> --output <path> --json` | Screenshot (PNG) |
|
|
63
|
+
| `chofi sim screenshot <target> --output <path> --format jpeg --json` | Screenshot (JPEG) |
|
|
64
|
+
| `chofi sim erase <target> --confirm --json` | **Erase simulator data** |
|
|
65
|
+
| `chofi sim create <name> <deviceType> <runtime> --json` | Create simulator |
|
|
66
|
+
| `chofi sim clone <target> <newName> --json` | Clone simulator |
|
|
67
|
+
| `chofi sim delete <target> --confirm --json` | **Delete simulator** |
|
|
68
|
+
| `chofi sim prune --confirm --json` | **Remove unavailable simulators** |
|
|
69
|
+
| `chofi sim set-appearance <target> <dark\|light> --json` | Set appearance |
|
|
70
|
+
| `chofi sim clear-cache <target> --json` | Clear simulator cache |
|
|
71
|
+
| `chofi sim add-media <target> <paths...> --json` | Add photos/videos to Photos |
|
|
72
|
+
| `chofi sim record start <target> <path> --json` | Start video recording |
|
|
73
|
+
| `chofi sim record stop <target> --json` | Stop video recording |
|
|
74
|
+
|
|
75
|
+
### Physical Devices
|
|
76
|
+
|
|
77
|
+
| Command | Description |
|
|
78
|
+
|---------|-------------|
|
|
79
|
+
| `chofi device list --json` | List connected devices |
|
|
80
|
+
| `chofi device list --platform connected --json` | Filter by status |
|
|
81
|
+
|
|
82
|
+
### App Lifecycle
|
|
83
|
+
|
|
84
|
+
| Command | Description |
|
|
85
|
+
|---------|-------------|
|
|
86
|
+
| `chofi app install <udid> <path> --json` | Install .app bundle |
|
|
87
|
+
| `chofi app launch <udid> <bundleId> --json` | Launch app |
|
|
88
|
+
| `chofi app terminate <udid> <bundleId> --json` | Terminate app |
|
|
89
|
+
| `chofi app terminate <udid> <bundleId> --force --json` | Force kill (SIGKILL) |
|
|
90
|
+
| `chofi app terminate-all <udid> --force --json` | Kill ALL apps |
|
|
91
|
+
| `chofi app uninstall <udid> <bundleId> --json` | Uninstall app |
|
|
92
|
+
| `chofi apps list <udid> --json` | List running apps |
|
|
93
|
+
| `chofi apps prune <udid> --json` | Remove stale registry entries |
|
|
94
|
+
|
|
95
|
+
### Build & Test
|
|
96
|
+
|
|
97
|
+
| Command | Description |
|
|
98
|
+
|---------|-------------|
|
|
99
|
+
| `chofi build ios --scheme <scheme> --json` | Build via xcodebuild |
|
|
100
|
+
| `chofi build ios --scheme <scheme> --progress --json` | Streaming build output |
|
|
101
|
+
| `chofi test ios --scheme <scheme> --json` | Run tests |
|
|
102
|
+
| `chofi test ios --scheme <scheme> --only <test> --json` | Run specific tests |
|
|
103
|
+
| `chofi test ios --scheme <scheme> --skip <test> --json` | Skip specific tests |
|
|
104
|
+
| `chofi test ios --scheme <scheme> --retry --json` | Retry failed tests |
|
|
105
|
+
| `chofi test ios --scheme <scheme> --progress --json` | Real-time test progress |
|
|
106
|
+
| `chofi test discover ios --scheme <scheme> --json` | Discover available tests |
|
|
107
|
+
| `chofi clean ios --scheme <scheme> --json` | Clean build artifacts |
|
|
108
|
+
| `chofi clean ios --scheme <scheme> --derived-data --json` | Clean derived data |
|
|
109
|
+
|
|
110
|
+
### Run
|
|
111
|
+
|
|
112
|
+
| Command | Description |
|
|
113
|
+
|---------|-------------|
|
|
114
|
+
| `chofi run ios --json` | Build and run on iOS simulator |
|
|
115
|
+
| `chofi run ios --no-build --json` | Skip build, just run |
|
|
116
|
+
| `chofi run ios --launch-env KEY=value --json` | Pass launch env vars |
|
|
117
|
+
| `chofi run android --confirm --json` | Build and run on Android |
|
|
118
|
+
|
|
119
|
+
### Maestro
|
|
120
|
+
|
|
121
|
+
| Command | Description |
|
|
122
|
+
|---------|-------------|
|
|
123
|
+
| `chofi maestro check --json` | Check Maestro installation |
|
|
124
|
+
| `chofi maestro run <flow> --json` | Run a Maestro flow |
|
|
125
|
+
| `chofi maestro continuous <flow> --json` | Run in continuous mode |
|
|
126
|
+
| `chofi maestro hierarchy --json` | Dump UI hierarchy |
|
|
127
|
+
| `chofi maestro record <flow> --json` | Record a test session |
|
|
128
|
+
| `chofi maestro driver-setup --json` | Setup Maestro driver |
|
|
129
|
+
| `chofi maestro start-device --platform ios --json` | Start Maestro device |
|
|
130
|
+
|
|
131
|
+
### Project Introspection
|
|
132
|
+
|
|
133
|
+
| Command | Description |
|
|
134
|
+
|---------|-------------|
|
|
135
|
+
| `chofi project build-config --json` | List build configurations |
|
|
136
|
+
| `chofi project schemes --json` | Auto-detect schemes |
|
|
137
|
+
|
|
138
|
+
### Configuration
|
|
139
|
+
|
|
140
|
+
| Command | Description |
|
|
141
|
+
|---------|-------------|
|
|
142
|
+
| `chofi config get <key> --json` | Get config value |
|
|
143
|
+
| `chofi config set <key> <value> --json` | Set config value |
|
|
144
|
+
| `chofi config reset --confirm --json` | **Reset config** |
|
|
145
|
+
|
|
146
|
+
## JSON Event Format
|
|
147
|
+
|
|
148
|
+
Every command emits newline-delimited JSON events:
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{"schemaVersion":"0.1.0","tool":"chofi","event":"command_started","phase":"sim.boot","timestamp":"2026-05-03T00:00:00.000Z","data":{"target":"iPhone 17 Pro"}}
|
|
152
|
+
{"schemaVersion":"0.1.0","tool":"chofi","event":"command_completed","phase":"sim.boot","status":"passed","timestamp":"2026-05-03T00:00:02.000Z","data":{"target":"iPhone 17 Pro"}}
|
|
153
|
+
{"schemaVersion":"0.1.0","tool":"chofi","event":"summary","phase":"sim.boot","status":"passed","timestamp":"2026-05-03T00:00:02.000Z","data":{"target":"iPhone 17 Pro"}}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Event Types
|
|
157
|
+
|
|
158
|
+
| Event | Description |
|
|
159
|
+
|-------|-------------|
|
|
160
|
+
| `command_started` | Command began execution |
|
|
161
|
+
| `command_completed` | Success — contains result data |
|
|
162
|
+
| `command_failed` | Failure — contains `message` and `recoverySuggestion` |
|
|
163
|
+
| `summary` | Final event (always emitted) |
|
|
164
|
+
| `tool_checked` | Tool availability report |
|
|
165
|
+
| `plan` | Execution plan (non-executing) |
|
|
166
|
+
| `progress` | Build/test progress stream |
|
|
167
|
+
|
|
168
|
+
## Architecture
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
chofi
|
|
172
|
+
├── src/
|
|
173
|
+
│ ├── cli.ts # Commander.js CLI parsing & routing
|
|
174
|
+
│ ├── runtime.ts # Execution orchestrator (20+ operations)
|
|
175
|
+
│ ├── drivers/
|
|
176
|
+
│ │ ├── apple.ts # simctl, xcrun, devicectl, xcodebuild
|
|
177
|
+
│ │ ├── maestro.ts # Maestro CLI wrapper
|
|
178
|
+
│ │ └── expo.ts # Expo CLI wrapper
|
|
179
|
+
│ ├── spawn.ts # ProcessSpawner abstraction (testable)
|
|
180
|
+
│ ├── events.ts # NDJSON event envelope
|
|
181
|
+
│ ├── discovery.ts # Workspace & tool discovery
|
|
182
|
+
│ ├── planning.ts # Non-executing command plans
|
|
183
|
+
│ ├── safety.ts # Explicit confirmation gates
|
|
184
|
+
│ ├── config.ts # .chofi.json persistence
|
|
185
|
+
│ └── errors.ts # Structured error hierarchy
|
|
186
|
+
└── test/
|
|
187
|
+
├── drivers/ # Driver unit tests
|
|
188
|
+
├── e2e.test.ts # End-to-end CLI tests
|
|
189
|
+
├── integration.test.ts # Live tests (CHOFI_LIVE=1)
|
|
190
|
+
└── *.test.ts # Unit tests
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Safety Gates
|
|
194
|
+
|
|
195
|
+
Dangerous operations require explicit confirmation:
|
|
196
|
+
|
|
197
|
+
| Command | Gate |
|
|
198
|
+
|---------|------|
|
|
199
|
+
| `sim erase` | `--confirm` |
|
|
200
|
+
| `sim delete` | `--confirm` |
|
|
201
|
+
| `sim prune` | `--confirm` |
|
|
202
|
+
| `run ios` (device) | `--confirm` |
|
|
203
|
+
| `run android` | `--confirm` |
|
|
204
|
+
| `config reset` | `--confirm` |
|
|
205
|
+
|
|
206
|
+
## Configuration
|
|
207
|
+
|
|
208
|
+
Create `.chofi.json` in the project root:
|
|
209
|
+
|
|
210
|
+
```json
|
|
211
|
+
{
|
|
212
|
+
"scheme": "MyApp",
|
|
213
|
+
"workspace": "MyApp.xcworkspace",
|
|
214
|
+
"destination": "platform=iOS Simulator,name=iPhone 17 Pro"
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Or use environment variables:
|
|
219
|
+
|
|
220
|
+
| Variable | Purpose |
|
|
221
|
+
|----------|---------|
|
|
222
|
+
| `CHOFI_SCHEME` | Default Xcode scheme |
|
|
223
|
+
| `CHOFI_WORKSPACE` | Default Xcode workspace |
|
|
224
|
+
| `CHOFI_PROJECT` | Default Xcode project |
|
|
225
|
+
| `CHOFI_DESTINATION` | Default build destination |
|
|
226
|
+
|
|
227
|
+
## Environment Variables
|
|
228
|
+
|
|
229
|
+
| Variable | Purpose |
|
|
230
|
+
|----------|---------|
|
|
231
|
+
| `CHOFI_LIVE` | Set to `1` to enable live integration tests |
|
|
232
|
+
|
|
233
|
+
## Development
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
# Install dependencies
|
|
237
|
+
pnpm install
|
|
238
|
+
|
|
239
|
+
# Run all tests
|
|
240
|
+
pnpm test
|
|
241
|
+
|
|
242
|
+
# Run live integration tests
|
|
243
|
+
CHOFI_LIVE=1 pnpm test:live
|
|
244
|
+
|
|
245
|
+
# Typecheck
|
|
246
|
+
pnpm typecheck
|
|
247
|
+
|
|
248
|
+
# Build
|
|
249
|
+
pnpm build
|
|
250
|
+
|
|
251
|
+
# Run locally
|
|
252
|
+
node dist/cli.js context --json
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type Clock, type EventWriter } from "./events.js";
|
|
3
|
+
import { type ToolChecker } from "./discovery.js";
|
|
4
|
+
import { type CommandRunner } from "./executor.js";
|
|
5
|
+
import { RuntimeController } from "./runtime.js";
|
|
6
|
+
import type { ProcessSpawner } from "./spawn.js";
|
|
7
|
+
export interface CliDependencies {
|
|
8
|
+
readonly clock?: Clock | undefined;
|
|
9
|
+
readonly cwd?: string | undefined;
|
|
10
|
+
readonly pathEnv?: string | undefined;
|
|
11
|
+
readonly runner?: CommandRunner | undefined;
|
|
12
|
+
readonly runtime?: RuntimeController | undefined;
|
|
13
|
+
readonly spawner?: ProcessSpawner | undefined;
|
|
14
|
+
readonly toolChecker?: ToolChecker | undefined;
|
|
15
|
+
readonly writer?: EventWriter | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare function runChofiCli(argv: readonly string[], dependencies?: CliDependencies): Promise<number>;
|
|
18
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AAQvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AA0pCD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,YAAY,GAAE,eAAoB,GACjC,OAAO,CAAC,MAAM,CAAC,CA2DjB"}
|