Skip to content

Commit c18ea31

Browse files
committed
fix(runner): fail keepalive on an unreachable runner and bound SDK imports
1 parent 4ae7a8a commit c18ea31

4 files changed

Lines changed: 107 additions & 58 deletions

File tree

.oxlintrc.json

Lines changed: 71 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
{
1515
"group": ["bun", "bun:*"],
16-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
16+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
1717
}
1818
]
1919
}
@@ -28,7 +28,7 @@
2828
"error",
2929
{
3030
"name": "Bun",
31-
"message": "Bun global is not available in the nodejs build use a Bun-compatible API or guard with typeof Bun !== 'undefined'."
31+
"message": "Bun global is not available in the nodejs build \u2014 use a Bun-compatible API or guard with typeof Bun !== 'undefined'."
3232
}
3333
],
3434
"eslint/eqeqeq": "error",
@@ -124,11 +124,11 @@
124124
},
125125
{
126126
"group": ["bun", "bun:*"],
127-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
127+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
128128
},
129129
{
130130
"group": ["~/shell/*", "~/shell/**"],
131-
"message": "core/ must not import from shell/ keep core/ pure."
131+
"message": "core/ must not import from shell/ \u2014 keep core/ pure."
132132
},
133133
{
134134
"group": ["~/domains/*", "~/domains/**"],
@@ -140,15 +140,15 @@
140140
},
141141
{
142142
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
143-
"message": "core/ must not import node:fs keep core/ pure."
143+
"message": "core/ must not import node:fs \u2014 keep core/ pure."
144144
},
145145
{
146146
"group": ["node:child_process", "child_process"],
147-
"message": "core/ must not import node:child_process keep core/ pure."
147+
"message": "core/ must not import node:child_process \u2014 keep core/ pure."
148148
},
149149
{
150150
"group": ["node:readline", "readline"],
151-
"message": "core/ must not import node:readline keep core/ pure."
151+
"message": "core/ must not import node:readline \u2014 keep core/ pure."
152152
}
153153
]
154154
}
@@ -168,7 +168,7 @@
168168
},
169169
{
170170
"group": ["bun", "bun:*"],
171-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
171+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
172172
},
173173
{
174174
"group": ["~/domains/*", "~/domains/**"],
@@ -196,7 +196,7 @@
196196
},
197197
{
198198
"group": ["bun", "bun:*"],
199-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
199+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
200200
},
201201
{
202202
"group": ["~/commands/*", "~/commands/**"],
@@ -239,15 +239,15 @@
239239
},
240240
{
241241
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
242-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
242+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
243243
},
244244
{
245245
"group": ["node:child_process", "child_process"],
246-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
246+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
247247
},
248248
{
249249
"group": ["node:readline", "readline"],
250-
"message": "domains/ must not import node:readline use UI from shell/ui/."
250+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
251251
}
252252
]
253253
}
@@ -267,7 +267,7 @@
267267
},
268268
{
269269
"group": ["bun", "bun:*"],
270-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
270+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
271271
},
272272
{
273273
"group": ["~/commands/*", "~/commands/**"],
@@ -310,15 +310,15 @@
310310
},
311311
{
312312
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
313-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
313+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
314314
},
315315
{
316316
"group": ["node:child_process", "child_process"],
317-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
317+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
318318
},
319319
{
320320
"group": ["node:readline", "readline"],
321-
"message": "domains/ must not import node:readline use UI from shell/ui/."
321+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
322322
}
323323
]
324324
}
@@ -338,7 +338,7 @@
338338
},
339339
{
340340
"group": ["bun", "bun:*"],
341-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
341+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
342342
},
343343
{
344344
"group": ["~/commands/*", "~/commands/**"],
@@ -381,15 +381,15 @@
381381
},
382382
{
383383
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
384-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
384+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
385385
},
386386
{
387387
"group": ["node:child_process", "child_process"],
388-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
388+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
389389
},
390390
{
391391
"group": ["node:readline", "readline"],
392-
"message": "domains/ must not import node:readline use UI from shell/ui/."
392+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
393393
}
394394
]
395395
}
@@ -409,7 +409,7 @@
409409
},
410410
{
411411
"group": ["bun", "bun:*"],
412-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
412+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
413413
},
414414
{
415415
"group": ["~/commands/*", "~/commands/**"],
@@ -452,15 +452,15 @@
452452
},
453453
{
454454
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
455-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
455+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
456456
},
457457
{
458458
"group": ["node:child_process", "child_process"],
459-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
459+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
460460
},
461461
{
462462
"group": ["node:readline", "readline"],
463-
"message": "domains/ must not import node:readline use UI from shell/ui/."
463+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
464464
}
465465
]
466466
}
@@ -480,7 +480,7 @@
480480
},
481481
{
482482
"group": ["bun", "bun:*"],
483-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
483+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
484484
},
485485
{
486486
"group": ["~/commands/*", "~/commands/**"],
@@ -523,15 +523,15 @@
523523
},
524524
{
525525
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
526-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
526+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
527527
},
528528
{
529529
"group": ["node:child_process", "child_process"],
530-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
530+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
531531
},
532532
{
533533
"group": ["node:readline", "readline"],
534-
"message": "domains/ must not import node:readline use UI from shell/ui/."
534+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
535535
}
536536
]
537537
}
@@ -551,7 +551,7 @@
551551
},
552552
{
553553
"group": ["bun", "bun:*"],
554-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
554+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
555555
},
556556
{
557557
"group": ["~/commands/*", "~/commands/**"],
@@ -594,15 +594,15 @@
594594
},
595595
{
596596
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
597-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
597+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
598598
},
599599
{
600600
"group": ["node:child_process", "child_process"],
601-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
601+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
602602
},
603603
{
604604
"group": ["node:readline", "readline"],
605-
"message": "domains/ must not import node:readline use UI from shell/ui/."
605+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
606606
}
607607
]
608608
}
@@ -622,7 +622,7 @@
622622
},
623623
{
624624
"group": ["bun", "bun:*"],
625-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
625+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
626626
},
627627
{
628628
"group": ["~/commands/*", "~/commands/**"],
@@ -665,15 +665,15 @@
665665
},
666666
{
667667
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
668-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
668+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
669669
},
670670
{
671671
"group": ["node:child_process", "child_process"],
672-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
672+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
673673
},
674674
{
675675
"group": ["node:readline", "readline"],
676-
"message": "domains/ must not import node:readline use UI from shell/ui/."
676+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
677677
}
678678
]
679679
}
@@ -693,7 +693,7 @@
693693
},
694694
{
695695
"group": ["bun", "bun:*"],
696-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
696+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
697697
},
698698
{
699699
"group": ["~/commands/*", "~/commands/**"],
@@ -733,15 +733,15 @@
733733
},
734734
{
735735
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
736-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
736+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
737737
},
738738
{
739739
"group": ["node:child_process", "child_process"],
740-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
740+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
741741
},
742742
{
743743
"group": ["node:readline", "readline"],
744-
"message": "domains/ must not import node:readline use UI from shell/ui/."
744+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
745745
}
746746
]
747747
}
@@ -761,7 +761,7 @@
761761
},
762762
{
763763
"group": ["bun", "bun:*"],
764-
"message": "Bun module imports are not available in the nodejs build use a portable alternative."
764+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
765765
},
766766
{
767767
"group": ["~/commands/*", "~/commands/**"],
@@ -804,15 +804,39 @@
804804
},
805805
{
806806
"group": ["node:fs", "fs", "node:fs/promises", "fs/promises"],
807-
"message": "domains/ must not import node:fs file I/O belongs in shell/."
807+
"message": "domains/ must not import node:fs \u2014 file I/O belongs in shell/."
808808
},
809809
{
810810
"group": ["node:child_process", "child_process"],
811-
"message": "domains/ must not import node:child_process use SpawnFn from shell/spawn.js."
811+
"message": "domains/ must not import node:child_process \u2014 use SpawnFn from shell/spawn.js."
812812
},
813813
{
814814
"group": ["node:readline", "readline"],
815-
"message": "domains/ must not import node:readline — use UI from shell/ui/."
815+
"message": "domains/ must not import node:readline \u2014 use UI from shell/ui/."
816+
}
817+
]
818+
}
819+
]
820+
}
821+
},
822+
{
823+
"files": ["src/runnerSdk/**/*.ts"],
824+
"rules": {
825+
"eslint/no-restricted-imports": [
826+
"error",
827+
{
828+
"patterns": [
829+
{
830+
"group": ["../*"],
831+
"message": "Use \"~/\" path alias instead of relative parent imports."
832+
},
833+
{
834+
"group": ["bun", "bun:*"],
835+
"message": "Bun module imports are not available in the nodejs build \u2014 use a portable alternative."
836+
},
837+
{
838+
"group": ["~/commands/*", "~/commands/**"],
839+
"message": "runnerSdk/ is the published library entry and must not import from commands/."
816840
}
817841
]
818842
}
@@ -827,17 +851,17 @@
827851
{
828852
"object": "process",
829853
"property": "stdout",
830-
"message": "core/ and domains/ must not write to process.stdout return data and let shell/ render it."
854+
"message": "core/ and domains/ must not write to process.stdout \u2014 return data and let shell/ render it."
831855
},
832856
{
833857
"object": "process",
834858
"property": "stderr",
835-
"message": "core/ and domains/ must not write to process.stderr return data and let shell/ render it."
859+
"message": "core/ and domains/ must not write to process.stderr \u2014 return data and let shell/ render it."
836860
},
837861
{
838862
"object": "process",
839863
"property": "stdin",
840-
"message": "core/ and domains/ must not read from process.stdin use UI from shell/ui/."
864+
"message": "core/ and domains/ must not read from process.stdin \u2014 use UI from shell/ui/."
841865
}
842866
]
843867
}

AGENTS.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ src/
7474
│ ├── interactiveRunner/ # remote runners: launch, stop, keepalive, runFlow, journal, screenshot, act, exec
7575
│ ├── runner/ # the LOCAL execution engine: flowsRun, runWebFlow, runAndroidFlow, worker dispatch + pool
7676
│ └── updateCheck/ # startUpdateCheck: new-version notice after commands
77-
── commands/ # Thin CLI glue — Commander registration + composite root
77+
── commands/ # Thin CLI glue — Commander registration + composite root
7878
├── context.ts # withContext() Commander action wrapper
7979
├── program.ts # createProgram() factory
8080
├── auth/ # login, logout, whoami handlers
@@ -83,9 +83,13 @@ src/
8383
├── init/ # init handler
8484
├── install/ # install browsers/android handlers
8585
└── runner/ # lifecycle/run/interact registrations (domains/interactiveRunner)
86+
└── runnerSdk/ # Published library entry — @qawolf/cli/runner-sdk
87+
├── index.ts # createRunnerSdk() — the only file `exports` points at
88+
├── types.ts # the public types; imports only @qawolf/api-contracts
89+
└── *Verbs.ts # one file per verb group
8690
```
8791

88-
The codebase is organized into four strict layers. **`core/`** holds pure functions and types with zero I/O. **`shell/`** holds I/O executors (process spawning, Playwright, UI rendering, API clients). **`domains/`** holds bounded-context business logic; each domain may import `core/` and `shell/` but never a sibling domain. **`commands/`** is the composite root: thin Commander registration plus `runDefaults.ts`, which bridges multiple domains to assemble the `flows run` command. oxlint enforces these boundaries via per-layer `no-restricted-imports` overrides in `.oxlintrc.json`.
92+
The codebase is organized into five layers. **`core/`** holds pure functions and types with zero I/O. **`shell/`** holds I/O executors (process spawning, Playwright, UI rendering, API clients). **`domains/`** holds bounded-context business logic; each domain may import `core/` and `shell/` but never a sibling domain. **`commands/`** is the composite root: thin Commander registration plus `runDefaults.ts`, which bridges multiple domains to assemble the `flows run` command. **`runnerSdk/`** is the second composite root, serving a library consumer where `commands/` serves the terminal: it is the only directory the `exports` field points at, and it reuses `domains/interactiveRunner` rather than reimplementing it. oxlint enforces these boundaries via per-layer `no-restricted-imports` overrides in `.oxlintrc.json`; `runnerSdk/` additionally may not import from `commands/` or from `bun`, since it is published and runs under Node.
8993

9094
API clients (tRPC for the QA Wolf platform, GitHub REST) live in `src/shell/platform/` and `src/shell/` respectively — one module per auth boundary.
9195

0 commit comments

Comments
 (0)