@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.
Files changed (52) hide show
  1. package/README.md +257 -0
  2. package/dist/cli.d.ts +18 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +1326 -0
  5. package/dist/config.d.ts +10 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +20 -0
  8. package/dist/discovery.d.ts +44 -0
  9. package/dist/discovery.d.ts.map +1 -0
  10. package/dist/discovery.js +151 -0
  11. package/dist/drivers/apple.d.ts +68 -0
  12. package/dist/drivers/apple.d.ts.map +1 -0
  13. package/dist/drivers/apple.js +360 -0
  14. package/dist/drivers/expo.d.ts +14 -0
  15. package/dist/drivers/expo.d.ts.map +1 -0
  16. package/dist/drivers/expo.js +42 -0
  17. package/dist/drivers/idb.d.ts +38 -0
  18. package/dist/drivers/idb.d.ts.map +1 -0
  19. package/dist/drivers/idb.js +52 -0
  20. package/dist/drivers/maestro.d.ts +37 -0
  21. package/dist/drivers/maestro.d.ts.map +1 -0
  22. package/dist/drivers/maestro.js +64 -0
  23. package/dist/drivers/types.d.ts +23 -0
  24. package/dist/drivers/types.d.ts.map +1 -0
  25. package/dist/drivers/types.js +1 -0
  26. package/dist/errors.d.ts +31 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +59 -0
  29. package/dist/events.d.ts +33 -0
  30. package/dist/events.d.ts.map +1 -0
  31. package/dist/events.js +26 -0
  32. package/dist/executor.d.ts +11 -0
  33. package/dist/executor.d.ts.map +1 -0
  34. package/dist/executor.js +17 -0
  35. package/dist/index.d.ts +14 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +13 -0
  38. package/dist/planning.d.ts +18 -0
  39. package/dist/planning.d.ts.map +1 -0
  40. package/dist/planning.js +75 -0
  41. package/dist/runtime.d.ts +157 -0
  42. package/dist/runtime.d.ts.map +1 -0
  43. package/dist/runtime.js +650 -0
  44. package/dist/safety.d.ts +8 -0
  45. package/dist/safety.d.ts.map +1 -0
  46. package/dist/safety.js +84 -0
  47. package/dist/spawn.d.ts +30 -0
  48. package/dist/spawn.d.ts.map +1 -0
  49. package/dist/spawn.js +178 -0
  50. package/dist/tsconfig.tsbuildinfo +1 -0
  51. package/package.json +64 -0
  52. package/sophy.png +0 -0
@@ -0,0 +1,14 @@
1
+ import type { ProcessSpawner, ProcessResult } from "../spawn.js";
2
+ import type { Driver, ToolStatus } from "./types.js";
3
+ export declare class ExpoDriver implements Driver {
4
+ private readonly spawner;
5
+ readonly name = "expo";
6
+ constructor(spawner?: ProcessSpawner);
7
+ check(): Promise<ToolStatus>;
8
+ prebuild(cwd: string, platform?: "ios" | "android"): Promise<ProcessResult>;
9
+ runIos(cwd: string, device?: string): Promise<ProcessResult>;
10
+ runAndroid(cwd: string, device?: string): Promise<ProcessResult>;
11
+ start(cwd: string): Promise<ProcessResult>;
12
+ doctor(cwd: string): Promise<ProcessResult>;
13
+ }
14
+ //# sourceMappingURL=expo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expo.d.ts","sourceRoot":"","sources":["../../src/drivers/expo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErD,qBAAa,UAAW,YAAW,MAAM;IAG3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,QAAQ,CAAC,IAAI,UAAU;gBAEM,OAAO,GAAE,cAA+B;IAE/D,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;IAW5B,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;IAM3E,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAM5D,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAMhE,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI1C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAGlD"}
@@ -0,0 +1,42 @@
1
+ import { defaultSpawner } from "../spawn.js";
2
+ export class ExpoDriver {
3
+ spawner;
4
+ name = "expo";
5
+ constructor(spawner = defaultSpawner) {
6
+ this.spawner = spawner;
7
+ }
8
+ async check() {
9
+ const result = await this.spawner.run("npx", ["expo", "--version"]);
10
+ if (result.exitCode !== 0) {
11
+ return { status: "missing", reason: "expo-cli not available" };
12
+ }
13
+ return {
14
+ status: "available",
15
+ version: result.stdout.trim().split("\n")[0]
16
+ };
17
+ }
18
+ async prebuild(cwd, platform) {
19
+ const args = ["expo", "prebuild"];
20
+ if (platform)
21
+ args.push("--platform", platform);
22
+ return this.spawner.run("npx", args, { cwd });
23
+ }
24
+ async runIos(cwd, device) {
25
+ const args = ["expo", "run:ios"];
26
+ if (device)
27
+ args.push("--device", device);
28
+ return this.spawner.run("npx", args, { cwd });
29
+ }
30
+ async runAndroid(cwd, device) {
31
+ const args = ["expo", "run:android"];
32
+ if (device)
33
+ args.push("--device", device);
34
+ return this.spawner.run("npx", args, { cwd });
35
+ }
36
+ async start(cwd) {
37
+ return this.spawner.run("npx", ["expo", "start"], { cwd });
38
+ }
39
+ async doctor(cwd) {
40
+ return this.spawner.run("npx", ["expo-doctor"], { cwd });
41
+ }
42
+ }
@@ -0,0 +1,38 @@
1
+ import type { ProcessSpawner, ProcessResult } from "../spawn.js";
2
+ export interface IdbAccessibilityElement {
3
+ readonly type?: string;
4
+ readonly label?: string;
5
+ readonly value?: string;
6
+ readonly identifier?: string;
7
+ readonly frame?: {
8
+ readonly x: number;
9
+ readonly y: number;
10
+ readonly width: number;
11
+ readonly height: number;
12
+ };
13
+ readonly traits?: readonly string[];
14
+ readonly children?: readonly IdbAccessibilityElement[];
15
+ }
16
+ export interface IdbCrashLog {
17
+ readonly name: string;
18
+ readonly process: string;
19
+ readonly date: string;
20
+ }
21
+ export declare class IdbDriver {
22
+ private readonly spawner;
23
+ constructor(spawner: ProcessSpawner);
24
+ available(): Promise<boolean>;
25
+ describeAll(udid: string): Promise<ProcessResult>;
26
+ describePoint(udid: string, x: number, y: number): Promise<ProcessResult>;
27
+ tap(udid: string, x: number, y: number): Promise<ProcessResult>;
28
+ swipe(udid: string, x1: number, y1: number, x2: number, y2: number): Promise<ProcessResult>;
29
+ pressButton(udid: string, button: string): Promise<ProcessResult>;
30
+ inputText(udid: string, text: string): Promise<ProcessResult>;
31
+ listCrashes(udid: string): Promise<ProcessResult>;
32
+ showCrash(udid: string, name: string): Promise<ProcessResult>;
33
+ deleteCrash(udid: string, name: string): Promise<ProcessResult>;
34
+ approve(udid: string, bundleId: string, permissions: readonly string[]): Promise<ProcessResult>;
35
+ setLocation(udid: string, latitude: number, longitude: number): Promise<ProcessResult>;
36
+ focus(udid: string): Promise<ProcessResult>;
37
+ }
38
+ //# sourceMappingURL=idb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idb.d.ts","sourceRoot":"","sources":["../../src/drivers/idb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7G,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;CACxD;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,cAAc;IAE9C,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAO7B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIjD,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAMzE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI/D,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI3F,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIjE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAM7D,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIjD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI7D,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAM/D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAM/F,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAMtF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAGlD"}
@@ -0,0 +1,52 @@
1
+ export class IdbDriver {
2
+ spawner;
3
+ constructor(spawner) {
4
+ this.spawner = spawner;
5
+ }
6
+ async available() {
7
+ const result = await this.spawner.run("idb", ["--version"]);
8
+ return result.exitCode === 0;
9
+ }
10
+ // === Accessibility ===
11
+ async describeAll(udid) {
12
+ return this.spawner.run("idb", ["ui", "describe-all", "--udid", udid]);
13
+ }
14
+ async describePoint(udid, x, y) {
15
+ return this.spawner.run("idb", ["ui", "describe-point", String(x), String(y), "--udid", udid]);
16
+ }
17
+ // === HID / UI Interactions ===
18
+ async tap(udid, x, y) {
19
+ return this.spawner.run("idb", ["ui", "tap", String(x), String(y), "--udid", udid]);
20
+ }
21
+ async swipe(udid, x1, y1, x2, y2) {
22
+ return this.spawner.run("idb", ["ui", "swipe", String(x1), String(y1), String(x2), String(y2), "--udid", udid]);
23
+ }
24
+ async pressButton(udid, button) {
25
+ return this.spawner.run("idb", ["ui", "button", button, "--udid", udid]);
26
+ }
27
+ async inputText(udid, text) {
28
+ return this.spawner.run("idb", ["ui", "text", text, "--udid", udid]);
29
+ }
30
+ // === Crash Logs ===
31
+ async listCrashes(udid) {
32
+ return this.spawner.run("idb", ["crash", "list", "--udid", udid]);
33
+ }
34
+ async showCrash(udid, name) {
35
+ return this.spawner.run("idb", ["crash", "show", name, "--udid", udid]);
36
+ }
37
+ async deleteCrash(udid, name) {
38
+ return this.spawner.run("idb", ["crash", "delete", name, "--udid", udid]);
39
+ }
40
+ // === Settings / Permissions ===
41
+ async approve(udid, bundleId, permissions) {
42
+ return this.spawner.run("idb", ["approve", bundleId, ...permissions, "--udid", udid]);
43
+ }
44
+ // === Location ===
45
+ async setLocation(udid, latitude, longitude) {
46
+ return this.spawner.run("idb", ["set-location", String(latitude), String(longitude), "--udid", udid]);
47
+ }
48
+ // === Focus ===
49
+ async focus(udid) {
50
+ return this.spawner.run("idb", ["focus", "--udid", udid]);
51
+ }
52
+ }
@@ -0,0 +1,37 @@
1
+ import type { ProcessSpawner, ProcessResult } from "../spawn.js";
2
+ import type { Driver, ToolStatus } from "./types.js";
3
+ export declare class MaestroDriver implements Driver {
4
+ private readonly spawner;
5
+ readonly name = "maestro";
6
+ constructor(spawner?: ProcessSpawner);
7
+ check(): Promise<ToolStatus>;
8
+ test(flowPath: string, options: {
9
+ cwd: string;
10
+ device?: string;
11
+ platform?: "ios" | "android";
12
+ format?: "junit" | "json";
13
+ output?: string;
14
+ }): Promise<ProcessResult>;
15
+ hierarchy(options: {
16
+ cwd: string;
17
+ device?: string;
18
+ }): Promise<ProcessResult>;
19
+ record(options: {
20
+ cwd: string;
21
+ flowPath: string;
22
+ device?: string;
23
+ }): Promise<ProcessResult>;
24
+ testContinuous(options: {
25
+ cwd: string;
26
+ flowPath: string;
27
+ device?: string;
28
+ platform?: "ios" | "android";
29
+ }): Promise<ProcessResult>;
30
+ driverSetup(cwd: string): Promise<ProcessResult>;
31
+ startDevice(options: {
32
+ cwd: string;
33
+ platform?: "ios" | "android" | undefined;
34
+ device?: string | undefined;
35
+ }): Promise<ProcessResult>;
36
+ }
37
+ //# sourceMappingURL=maestro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maestro.d.ts","sourceRoot":"","sources":["../../src/drivers/maestro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErD,qBAAa,aAAc,YAAW,MAAM;IAG9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,QAAQ,CAAC,IAAI,aAAa;gBAEG,OAAO,GAAE,cAA+B;IAE/D,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;IAW5B,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;QAC7B,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC,aAAa,CAAC;IAUnB,SAAS,CAAC,OAAO,EAAE;QACvB,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,aAAa,CAAC;IAMpB,MAAM,CAAC,OAAO,EAAE;QACpB,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,aAAa,CAAC;IAOpB,cAAc,CAAC,OAAO,EAAE;QAC5B,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;KAC9B,GAAG,OAAO,CAAC,aAAa,CAAC;IAQpB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIhD,WAAW,CAAC,OAAO,EAAE;QACzB,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;QACzC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC7B,GAAG,OAAO,CAAC,aAAa,CAAC;CAM3B"}
@@ -0,0 +1,64 @@
1
+ import { defaultSpawner } from "../spawn.js";
2
+ export class MaestroDriver {
3
+ spawner;
4
+ name = "maestro";
5
+ constructor(spawner = defaultSpawner) {
6
+ this.spawner = spawner;
7
+ }
8
+ async check() {
9
+ const result = await this.spawner.run("maestro", ["--version"]);
10
+ if (result.exitCode !== 0) {
11
+ return { status: "missing", reason: result.stderr || "maestro not on PATH" };
12
+ }
13
+ return {
14
+ status: "available",
15
+ version: result.stdout.trim().split("\n")[0]
16
+ };
17
+ }
18
+ async test(flowPath, options) {
19
+ const args = ["test"];
20
+ if (options.device)
21
+ args.push("--device", options.device);
22
+ if (options.platform)
23
+ args.push("--platform", options.platform);
24
+ if (options.format)
25
+ args.push("--format", options.format);
26
+ if (options.output)
27
+ args.push("--output", options.output);
28
+ args.push(flowPath);
29
+ return this.spawner.run("maestro", args, { cwd: options.cwd });
30
+ }
31
+ async hierarchy(options) {
32
+ const args = ["hierarchy"];
33
+ if (options.device)
34
+ args.push("--device", options.device);
35
+ return this.spawner.run("maestro", args, { cwd: options.cwd });
36
+ }
37
+ async record(options) {
38
+ const args = ["record"];
39
+ if (options.device)
40
+ args.push("--device", options.device);
41
+ args.push(options.flowPath);
42
+ return this.spawner.run("maestro", args, { cwd: options.cwd });
43
+ }
44
+ async testContinuous(options) {
45
+ const args = ["test", "-c"];
46
+ if (options.device)
47
+ args.push("--device", options.device);
48
+ if (options.platform)
49
+ args.push("--platform", options.platform);
50
+ args.push(options.flowPath);
51
+ return this.spawner.run("maestro", args, { cwd: options.cwd });
52
+ }
53
+ async driverSetup(cwd) {
54
+ return this.spawner.run("maestro", ["driver-setup"], { cwd });
55
+ }
56
+ async startDevice(options) {
57
+ const args = ["start-device"];
58
+ if (options.platform)
59
+ args.push("--platform", options.platform);
60
+ if (options.device)
61
+ args.push("--device", options.device);
62
+ return this.spawner.run("maestro", args, { cwd: options.cwd });
63
+ }
64
+ }
@@ -0,0 +1,23 @@
1
+ export interface DriverResult {
2
+ readonly durationMs: number;
3
+ readonly exitCode: number;
4
+ readonly stderr: string;
5
+ readonly stdout: string;
6
+ }
7
+ export interface Driver {
8
+ readonly name: string;
9
+ check(): Promise<ToolStatus>;
10
+ }
11
+ export type ToolStatus = {
12
+ readonly status: "available";
13
+ readonly version?: string | undefined;
14
+ } | {
15
+ readonly status: "missing";
16
+ readonly reason?: string | undefined;
17
+ };
18
+ export interface SimDevice {
19
+ readonly name: string;
20
+ readonly state: "Booted" | "Shutdown" | string;
21
+ readonly udid: string;
22
+ }
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/drivers/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACvE;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEzE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ export declare class ChofiError extends Error {
2
+ readonly code: string;
3
+ readonly recoverySuggestion?: string | undefined;
4
+ constructor(message: string, code: string, recoverySuggestion?: string | undefined);
5
+ }
6
+ export declare class SimulatorNotFoundError extends ChofiError {
7
+ constructor(target: string, detail?: string);
8
+ }
9
+ export declare class SimulatorStateError extends ChofiError {
10
+ constructor(udid: string, requiredState: string, actualState: string);
11
+ }
12
+ export declare class AppNotInstalledError extends ChofiError {
13
+ constructor(bundleId: string, udid: string);
14
+ }
15
+ export declare class AppNotRunningError extends ChofiError {
16
+ constructor(bundleId: string, udid: string);
17
+ }
18
+ export declare class BuildFailedError extends ChofiError {
19
+ constructor(stderr: string);
20
+ }
21
+ export declare class TestsFailedError extends ChofiError {
22
+ constructor(stderr: string);
23
+ }
24
+ export declare class ConfigParseError extends ChofiError {
25
+ constructor(path: string, reason: string);
26
+ }
27
+ export declare class ToolOutputError extends ChofiError {
28
+ constructor(tool: string, stderr: string);
29
+ }
30
+ export declare function classifyError(error: unknown): ChofiError;
31
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAW,SAAQ,KAAK;IAGjC,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM;gBAFpC,OAAO,EAAE,MAAM,EACN,IAAI,EAAE,MAAM,EACZ,kBAAkB,CAAC,EAAE,MAAM,YAAA;CAKvC;AAED,qBAAa,sBAAuB,SAAQ,UAAU;gBACxC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAO5C;AAED,qBAAa,mBAAoB,SAAQ,UAAU;gBACrC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAOrE;AAED,qBAAa,oBAAqB,SAAQ,UAAU;gBACtC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAO3C;AAED,qBAAa,kBAAmB,SAAQ,UAAU;gBACpC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAO3C;AAED,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,MAAM,EAAE,MAAM;CAO3B;AAED,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,MAAM,EAAE,MAAM;CAO3B;AAED,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAOzC;AAED,qBAAa,eAAgB,SAAQ,UAAU;gBACjC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAOzC;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAQxD"}
package/dist/errors.js ADDED
@@ -0,0 +1,59 @@
1
+ export class ChofiError extends Error {
2
+ code;
3
+ recoverySuggestion;
4
+ constructor(message, code, recoverySuggestion) {
5
+ super(message);
6
+ this.code = code;
7
+ this.recoverySuggestion = recoverySuggestion;
8
+ this.name = "ChofiError";
9
+ }
10
+ }
11
+ export class SimulatorNotFoundError extends ChofiError {
12
+ constructor(target, detail) {
13
+ super(detail || `Simulator not found: ${target}`, "SIMULATOR_NOT_FOUND", "Run 'chofi sim list --json' to see available simulators.");
14
+ }
15
+ }
16
+ export class SimulatorStateError extends ChofiError {
17
+ constructor(udid, requiredState, actualState) {
18
+ super(`Simulator ${udid} is ${actualState}, but ${requiredState} is required`, "SIMULATOR_STATE_INVALID", `Use 'chofi sim boot ${udid} --json' to boot, or 'chofi sim shutdown ${udid} --json' to shutdown.`);
19
+ }
20
+ }
21
+ export class AppNotInstalledError extends ChofiError {
22
+ constructor(bundleId, udid) {
23
+ super(`App ${bundleId} is not installed on ${udid}`, "APP_NOT_INSTALLED", `Use 'chofi app install ${udid} <appPath> --json' to install the app first.`);
24
+ }
25
+ }
26
+ export class AppNotRunningError extends ChofiError {
27
+ constructor(bundleId, udid) {
28
+ super(`App ${bundleId} is not running on ${udid}`, "APP_NOT_RUNNING", `Use 'chofi app launch ${udid} ${bundleId} --json' to launch the app first.`);
29
+ }
30
+ }
31
+ export class BuildFailedError extends ChofiError {
32
+ constructor(stderr) {
33
+ super(`Build failed: ${stderr.slice(0, 200)}`, "BUILD_FAILED", "Check the build output for compile errors. Use 'chofi clean --json --scheme <scheme>' if needed.");
34
+ }
35
+ }
36
+ export class TestsFailedError extends ChofiError {
37
+ constructor(stderr) {
38
+ super(`Tests failed: ${stderr.slice(0, 200)}`, "TESTS_FAILED", "Check test output for failures. Use 'chofi test --json --scheme <scheme>' to re-run.");
39
+ }
40
+ }
41
+ export class ConfigParseError extends ChofiError {
42
+ constructor(path, reason) {
43
+ super(`Failed to parse config at ${path}: ${reason}`, "CONFIG_PARSE_ERROR", "Fix the JSON syntax in .chofi.json or delete it to reset.");
44
+ }
45
+ }
46
+ export class ToolOutputError extends ChofiError {
47
+ constructor(tool, stderr) {
48
+ super(`${tool} failed: ${stderr.slice(0, 200)}`, "TOOL_EXECUTION_FAILED", "Check that the tool is installed and the arguments are valid.");
49
+ }
50
+ }
51
+ export function classifyError(error) {
52
+ if (error instanceof ChofiError) {
53
+ return error;
54
+ }
55
+ if (error instanceof Error) {
56
+ return new ChofiError(error.message, "UNKNOWN_ERROR");
57
+ }
58
+ return new ChofiError(String(error), "UNKNOWN_ERROR");
59
+ }
@@ -0,0 +1,33 @@
1
+ export declare const chofiSchemaVersion = "0.1.0";
2
+ export declare const chofiToolName = "chofi";
3
+ export type ChofiEventName = "command_completed" | "command_failed" | "command_started" | "plan" | "summary" | "tool_checked";
4
+ export type ChofiStatus = "available" | "failed" | "missing" | "passed" | "planned";
5
+ export interface ChofiEvent<TData = unknown> {
6
+ readonly data: TData;
7
+ readonly errorType?: string;
8
+ readonly event: ChofiEventName;
9
+ readonly phase: string;
10
+ readonly schemaVersion: typeof chofiSchemaVersion;
11
+ readonly status?: ChofiStatus;
12
+ readonly timestamp: string;
13
+ readonly tool: typeof chofiToolName;
14
+ }
15
+ export type Clock = () => Date;
16
+ export declare function createChofiEvent<TData>(input: {
17
+ readonly clock?: Clock | undefined;
18
+ readonly data: TData;
19
+ readonly errorType?: string | undefined;
20
+ readonly event: ChofiEventName;
21
+ readonly phase: string;
22
+ readonly status?: ChofiStatus | undefined;
23
+ }): ChofiEvent<TData>;
24
+ export declare function serializeNdjsonEvent(event: ChofiEvent): string;
25
+ export interface EventWriter {
26
+ write(event: ChofiEvent): void;
27
+ }
28
+ export declare class NdjsonEventWriter implements EventWriter {
29
+ private readonly output;
30
+ constructor(output?: NodeJS.WritableStream);
31
+ write(event: ChofiEvent): void;
32
+ }
33
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAC1C,eAAO,MAAM,aAAa,UAAU,CAAC;AAErC,MAAM,MAAM,cAAc,GACtB,mBAAmB,GACnB,gBAAgB,GAChB,iBAAiB,GACjB,MAAM,GACN,SAAS,GACT,cAAc,CAAC;AAEnB,MAAM,MAAM,WAAW,GACnB,WAAW,GACX,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,UAAU,CAAC,KAAK,GAAG,OAAO;IACzC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,EAAE,OAAO,kBAAkB,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,aAAa,CAAC;CACrC;AAED,MAAM,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC;AAE/B,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C,GAAG,UAAU,CAAC,KAAK,CAAC,CAWpB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAE9D;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAChC;AAED,qBAAa,iBAAkB,YAAW,WAAW;IAEjD,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,GAAE,MAAM,CAAC,cAA+B;IAGjE,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;CAG/B"}
package/dist/events.js ADDED
@@ -0,0 +1,26 @@
1
+ export const chofiSchemaVersion = "0.1.0";
2
+ export const chofiToolName = "chofi";
3
+ export function createChofiEvent(input) {
4
+ return {
5
+ schemaVersion: chofiSchemaVersion,
6
+ tool: chofiToolName,
7
+ event: input.event,
8
+ phase: input.phase,
9
+ ...(input.status === undefined ? {} : { status: input.status }),
10
+ ...(input.errorType === undefined ? {} : { errorType: input.errorType }),
11
+ timestamp: (input.clock ?? (() => new Date()))().toISOString(),
12
+ data: input.data
13
+ };
14
+ }
15
+ export function serializeNdjsonEvent(event) {
16
+ return `${JSON.stringify(event)}\n`;
17
+ }
18
+ export class NdjsonEventWriter {
19
+ output;
20
+ constructor(output = process.stdout) {
21
+ this.output = output;
22
+ }
23
+ write(event) {
24
+ this.output.write(serializeNdjsonEvent(event));
25
+ }
26
+ }
@@ -0,0 +1,11 @@
1
+ import type { ProcessSpawner, ProcessResult } from "./spawn.js";
2
+ import type { CommandPlan } from "./planning.js";
3
+ export type CommandExecutionResult = ProcessResult;
4
+ export type CommandRunner = (command: CommandPlan) => Promise<CommandExecutionResult>;
5
+ export declare function createCommandRunner(spawner?: ProcessSpawner): CommandRunner;
6
+ export declare const nodeCommandRunner: CommandRunner;
7
+ export declare function summarizeOutput(output: string): {
8
+ readonly bytes: number;
9
+ readonly tail: string;
10
+ };
11
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,MAAM,sBAAsB,GAAG,aAAa,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG,CAC1B,OAAO,EAAE,WAAW,KACjB,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAErC,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,cAA+B,GACvC,aAAa,CAOf;AAED,eAAO,MAAM,iBAAiB,EAAE,aAAqC,CAAC;AAEtE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAMA"}
@@ -0,0 +1,17 @@
1
+ import { defaultSpawner } from "./spawn.js";
2
+ export function createCommandRunner(spawner = defaultSpawner) {
3
+ return async (command) => {
4
+ const result = await spawner.run(command.command, command.args, {
5
+ cwd: command.cwd
6
+ });
7
+ return result;
8
+ };
9
+ }
10
+ export const nodeCommandRunner = createCommandRunner();
11
+ export function summarizeOutput(output) {
12
+ const trimmed = output.trim();
13
+ return {
14
+ bytes: Buffer.byteLength(output),
15
+ tail: trimmed.length <= 2_000 ? trimmed : trimmed.slice(-2_000)
16
+ };
17
+ }
@@ -0,0 +1,14 @@
1
+ export * from "./cli.js";
2
+ export * from "./config.js";
3
+ export * from "./discovery.js";
4
+ export * from "./events.js";
5
+ export * from "./executor.js";
6
+ export * from "./planning.js";
7
+ export * from "./runtime.js";
8
+ export * from "./safety.js";
9
+ export * from "./spawn.js";
10
+ export * from "./drivers/apple.js";
11
+ export * from "./drivers/expo.js";
12
+ export * from "./drivers/maestro.js";
13
+ export * from "./drivers/types.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ export * from "./cli.js";
2
+ export * from "./config.js";
3
+ export * from "./discovery.js";
4
+ export * from "./events.js";
5
+ export * from "./executor.js";
6
+ export * from "./planning.js";
7
+ export * from "./runtime.js";
8
+ export * from "./safety.js";
9
+ export * from "./spawn.js";
10
+ export * from "./drivers/apple.js";
11
+ export * from "./drivers/expo.js";
12
+ export * from "./drivers/maestro.js";
13
+ export * from "./drivers/types.js";
@@ -0,0 +1,18 @@
1
+ import type { MobileProjectContext } from "./discovery.js";
2
+ export interface CommandPlan {
3
+ readonly args: readonly string[];
4
+ readonly command: string;
5
+ readonly cwd: string;
6
+ readonly name: string;
7
+ readonly optional?: boolean | undefined;
8
+ }
9
+ export interface PlanResult {
10
+ readonly commands: readonly CommandPlan[];
11
+ readonly notes: readonly string[];
12
+ readonly phase: string;
13
+ readonly status: "planned";
14
+ }
15
+ export declare function createIosRunPlan(context: MobileProjectContext): PlanResult;
16
+ export declare function createMaestroPlan(context: MobileProjectContext): PlanResult;
17
+ export declare function doctorChecks(context: MobileProjectContext): readonly CommandPlan[];
18
+ //# sourceMappingURL=planning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../src/planning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACzC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU,CAgC1E;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU,CA2B3E;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,oBAAoB,GAC5B,SAAS,WAAW,EAAE,CAexB"}
@@ -0,0 +1,75 @@
1
+ export function createIosRunPlan(context) {
2
+ return {
3
+ phase: "plan.run.ios",
4
+ status: "planned",
5
+ commands: [
6
+ {
7
+ name: "doctor preflight",
8
+ command: "pnpm",
9
+ args: ["--filter", context.mobilePackageName, "run", "doctor"],
10
+ cwd: context.repoRoot,
11
+ optional: true
12
+ },
13
+ {
14
+ name: "expo native project sync",
15
+ command: "pnpm",
16
+ args: ["--filter", context.mobilePackageName, "run", "prebuild"],
17
+ cwd: context.repoRoot,
18
+ optional: true
19
+ },
20
+ {
21
+ name: "run ios",
22
+ command: "pnpm",
23
+ args: ["--filter", context.mobilePackageName, "run", "ios"],
24
+ cwd: context.repoRoot
25
+ }
26
+ ],
27
+ notes: [
28
+ "This is a plan only; no command was executed.",
29
+ "The actual iOS run launches or focuses simulator processes and requires an explicit user request.",
30
+ "Run doctor/typecheck before launch when checking environment health."
31
+ ]
32
+ };
33
+ }
34
+ export function createMaestroPlan(context) {
35
+ const flows = context.maestroFlows.length === 0
36
+ ? [".maestro/smoke.yaml"]
37
+ : context.maestroFlows;
38
+ return {
39
+ phase: "plan.maestro",
40
+ status: "planned",
41
+ commands: flows.map((flow) => ({
42
+ name: context.maestroFlows.length === 0 ? "proposed maestro flow" : flow,
43
+ command: "maestro",
44
+ args: ["test", flow],
45
+ cwd: context.repoRoot,
46
+ optional: context.maestroFlows.length === 0
47
+ })),
48
+ notes: [
49
+ "This is a plan only; no Maestro flow was executed.",
50
+ "Maestro must be installed locally before execution; chofi does not install it.",
51
+ "Maestro Cloud is not required.",
52
+ ...(context.maestroFlows.length === 0
53
+ ? [
54
+ "No .maestro/*.yaml flows were found; author .maestro/smoke.yaml before running the proposed command."
55
+ ]
56
+ : [])
57
+ ]
58
+ };
59
+ }
60
+ export function doctorChecks(context) {
61
+ return [
62
+ {
63
+ name: "expo-doctor",
64
+ command: "pnpm",
65
+ args: ["--filter", context.mobilePackageName, "run", "doctor"],
66
+ cwd: context.repoRoot
67
+ },
68
+ {
69
+ name: "typecheck",
70
+ command: "pnpm",
71
+ args: ["--filter", context.mobilePackageName, "run", "typecheck"],
72
+ cwd: context.repoRoot
73
+ }
74
+ ];
75
+ }