@e2edev/e2e 0.5.0 → 0.6.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 (415) hide show
  1. package/README.md +64 -25
  2. package/dist/agent/act.d.ts +2 -2
  3. package/dist/agent/act.js +14 -37
  4. package/dist/agent/act.js.map +1 -1
  5. package/dist/agent/actions.d.ts +2 -2
  6. package/dist/agent/actions.d.ts.map +1 -1
  7. package/dist/agent/actions.js +1 -1
  8. package/dist/agent/ai-sdk.d.ts +1 -2
  9. package/dist/agent/ai-sdk.d.ts.map +1 -1
  10. package/dist/agent/ai-sdk.js +1 -2
  11. package/dist/agent/ai-sdk.js.map +1 -1
  12. package/dist/agent/default-agent.d.ts +10 -32
  13. package/dist/agent/default-agent.d.ts.map +1 -1
  14. package/dist/agent/default-agent.js +6 -13
  15. package/dist/agent/default-agent.js.map +1 -1
  16. package/dist/agent/derived.d.ts +1 -1
  17. package/dist/agent/derived.js +1 -1
  18. package/dist/agent/error.d.ts +2 -4
  19. package/dist/agent/error.d.ts.map +1 -1
  20. package/dist/agent/error.js +3 -5
  21. package/dist/agent/error.js.map +1 -1
  22. package/dist/agent/executor.d.ts +23 -52
  23. package/dist/agent/executor.d.ts.map +1 -1
  24. package/dist/agent/executor.js +1 -2
  25. package/dist/agent/executor.js.map +1 -1
  26. package/dist/agent/index.d.ts +1 -1
  27. package/dist/agent/index.d.ts.map +1 -1
  28. package/dist/agent/index.js +10 -7
  29. package/dist/agent/index.js.map +1 -1
  30. package/dist/agent/invocation.d.ts +8 -6
  31. package/dist/agent/invocation.d.ts.map +1 -1
  32. package/dist/agent/invocation.js +9 -4
  33. package/dist/agent/invocation.js.map +1 -1
  34. package/dist/agent/ledger.d.ts +17 -12
  35. package/dist/agent/ledger.d.ts.map +1 -1
  36. package/dist/agent/ledger.js +6 -9
  37. package/dist/agent/ledger.js.map +1 -1
  38. package/dist/agent/model/adapter.d.ts +7 -4
  39. package/dist/agent/model/adapter.d.ts.map +1 -1
  40. package/dist/agent/model/adapter.js +2 -2
  41. package/dist/agent/model/adapter.js.map +1 -1
  42. package/dist/agent/model/router.d.ts +1 -1
  43. package/dist/agent/model/router.d.ts.map +1 -1
  44. package/dist/agent/model/router.js +1 -1
  45. package/dist/agent/model/router.js.map +1 -1
  46. package/dist/agent/model/sdk.d.ts +11 -1
  47. package/dist/agent/model/sdk.d.ts.map +1 -1
  48. package/dist/agent/model/sdk.js +54 -10
  49. package/dist/agent/model/sdk.js.map +1 -1
  50. package/dist/agent/observation.d.ts +7 -7
  51. package/dist/agent/observation.d.ts.map +1 -1
  52. package/dist/agent/observation.js +7 -7
  53. package/dist/agent/observation.js.map +1 -1
  54. package/dist/agent/phases.d.ts +3 -3
  55. package/dist/agent/phases.d.ts.map +1 -1
  56. package/dist/agent/phases.js +4 -4
  57. package/dist/agent/phases.js.map +1 -1
  58. package/dist/agent/primitives.d.ts +4 -25
  59. package/dist/agent/primitives.d.ts.map +1 -1
  60. package/dist/agent/primitives.js +3 -36
  61. package/dist/agent/primitives.js.map +1 -1
  62. package/dist/agent/prompts.d.ts +1 -1
  63. package/dist/agent/prompts.js +1 -1
  64. package/dist/agent/protocol.d.ts +2 -3
  65. package/dist/agent/protocol.d.ts.map +1 -1
  66. package/dist/agent/protocol.js +2 -3
  67. package/dist/agent/protocol.js.map +1 -1
  68. package/dist/agent/public.d.ts +8 -10
  69. package/dist/agent/public.d.ts.map +1 -1
  70. package/dist/agent/public.js +7 -8
  71. package/dist/agent/public.js.map +1 -1
  72. package/dist/agent/replay.d.ts +2 -2
  73. package/dist/agent/replay.d.ts.map +1 -1
  74. package/dist/agent/replay.js +1 -1
  75. package/dist/agent/secrets.d.ts +3 -3
  76. package/dist/agent/secrets.d.ts.map +1 -1
  77. package/dist/agent/secrets.js +4 -4
  78. package/dist/agent/secrets.js.map +1 -1
  79. package/dist/agent/step-cache.d.ts +1 -1
  80. package/dist/agent/step-cache.d.ts.map +1 -1
  81. package/dist/agent/step-cache.js +7 -1
  82. package/dist/agent/step-cache.js.map +1 -1
  83. package/dist/agent/tool-loop.d.ts +9 -33
  84. package/dist/agent/tool-loop.d.ts.map +1 -1
  85. package/dist/agent/tool-loop.js +15 -38
  86. package/dist/agent/tool-loop.js.map +1 -1
  87. package/dist/agent/tool.d.ts +4 -5
  88. package/dist/agent/tool.d.ts.map +1 -1
  89. package/dist/agent/tool.js +2 -7
  90. package/dist/agent/tool.js.map +1 -1
  91. package/dist/cache/anchors.d.ts +2 -2
  92. package/dist/cache/anchors.d.ts.map +1 -1
  93. package/dist/cache/anchors.js +1 -1
  94. package/dist/cache/context.d.ts +6 -1
  95. package/dist/cache/context.d.ts.map +1 -1
  96. package/dist/cache/context.js +2 -1
  97. package/dist/cache/context.js.map +1 -1
  98. package/dist/cache/decide.d.ts +1 -1
  99. package/dist/cache/decide.js +1 -1
  100. package/dist/cache/identity.d.ts +9 -9
  101. package/dist/cache/identity.d.ts.map +1 -1
  102. package/dist/cache/identity.js +6 -6
  103. package/dist/cache/identity.js.map +1 -1
  104. package/dist/cache/recorder.d.ts +4 -2
  105. package/dist/cache/recorder.d.ts.map +1 -1
  106. package/dist/cache/recorder.js +10 -1
  107. package/dist/cache/recorder.js.map +1 -1
  108. package/dist/cache/relocate.d.ts +2 -2
  109. package/dist/cache/relocate.d.ts.map +1 -1
  110. package/dist/cache/relocate.js +1 -1
  111. package/dist/cache/store.d.ts +1 -1
  112. package/dist/cache/store.js +1 -1
  113. package/dist/cache/trace.d.ts +16 -1
  114. package/dist/cache/trace.d.ts.map +1 -1
  115. package/dist/cache/trace.js +22 -1
  116. package/dist/cache/trace.js.map +1 -1
  117. package/dist/cli/bin.js +9 -1
  118. package/dist/cli/bin.js.map +1 -1
  119. package/dist/cli/cache.d.ts +25 -0
  120. package/dist/cli/cache.d.ts.map +1 -0
  121. package/dist/cli/cache.js +249 -0
  122. package/dist/cli/cache.js.map +1 -0
  123. package/dist/cli/docs-url.d.ts +3 -0
  124. package/dist/cli/docs-url.d.ts.map +1 -0
  125. package/dist/cli/docs-url.js +3 -0
  126. package/dist/cli/docs-url.js.map +1 -0
  127. package/dist/cli/guide.d.ts +4 -0
  128. package/dist/cli/guide.d.ts.map +1 -0
  129. package/dist/cli/guide.js +16 -0
  130. package/dist/cli/guide.js.map +1 -0
  131. package/dist/cli/index.d.ts +1 -1
  132. package/dist/cli/index.d.ts.map +1 -1
  133. package/dist/cli/index.js +211 -42
  134. package/dist/cli/index.js.map +1 -1
  135. package/dist/cli/init/agent-skill.d.ts +34 -0
  136. package/dist/cli/init/agent-skill.d.ts.map +1 -0
  137. package/dist/cli/init/agent-skill.js +44 -0
  138. package/dist/cli/init/agent-skill.js.map +1 -0
  139. package/dist/cli/init/{backends.d.ts → engines.d.ts} +39 -32
  140. package/dist/cli/init/engines.d.ts.map +1 -0
  141. package/dist/cli/init/{backends.js → engines.js} +43 -34
  142. package/dist/cli/init/engines.js.map +1 -0
  143. package/dist/cli/init/package.d.ts +19 -3
  144. package/dist/cli/init/package.d.ts.map +1 -1
  145. package/dist/cli/init/package.js +20 -20
  146. package/dist/cli/init/package.js.map +1 -1
  147. package/dist/cli/init/scaffold.d.ts +3 -3
  148. package/dist/cli/init/scaffold.d.ts.map +1 -1
  149. package/dist/cli/init/scaffold.js +13 -12
  150. package/dist/cli/init/scaffold.js.map +1 -1
  151. package/dist/cli/init.d.ts +14 -2
  152. package/dist/cli/init.d.ts.map +1 -1
  153. package/dist/cli/init.js +104 -25
  154. package/dist/cli/init.js.map +1 -1
  155. package/dist/cli/signals.d.ts +5 -2
  156. package/dist/cli/signals.d.ts.map +1 -1
  157. package/dist/cli/signals.js +9 -3
  158. package/dist/cli/signals.js.map +1 -1
  159. package/dist/cli/skill.d.ts +16 -0
  160. package/dist/cli/skill.d.ts.map +1 -0
  161. package/dist/cli/skill.js +57 -0
  162. package/dist/cli/skill.js.map +1 -0
  163. package/dist/collect/collect.d.ts +40 -3
  164. package/dist/collect/collect.d.ts.map +1 -1
  165. package/dist/collect/collect.js +142 -19
  166. package/dist/collect/collect.js.map +1 -1
  167. package/dist/collect/registry.d.ts +1 -1
  168. package/dist/collect/registry.d.ts.map +1 -1
  169. package/dist/collect/registry.js +2 -2
  170. package/dist/collect/registry.js.map +1 -1
  171. package/dist/collect/select.d.ts +1 -1
  172. package/dist/collect/select.d.ts.map +1 -1
  173. package/dist/collect/select.js +81 -8
  174. package/dist/collect/select.js.map +1 -1
  175. package/dist/config/agent.d.ts +14 -2
  176. package/dist/config/agent.d.ts.map +1 -1
  177. package/dist/config/agent.js +36 -11
  178. package/dist/config/agent.js.map +1 -1
  179. package/dist/config/app.d.ts +76 -19
  180. package/dist/config/app.d.ts.map +1 -1
  181. package/dist/config/app.js +159 -104
  182. package/dist/config/app.js.map +1 -1
  183. package/dist/config/diagnose.d.ts +15 -0
  184. package/dist/config/diagnose.d.ts.map +1 -0
  185. package/dist/config/diagnose.js +122 -0
  186. package/dist/config/diagnose.js.map +1 -0
  187. package/dist/config/load.d.ts +9 -1
  188. package/dist/config/load.d.ts.map +1 -1
  189. package/dist/config/load.js +35 -3
  190. package/dist/config/load.js.map +1 -1
  191. package/dist/config/resolve.d.ts +8 -7
  192. package/dist/config/resolve.d.ts.map +1 -1
  193. package/dist/config/resolve.js +73 -40
  194. package/dist/config/resolve.js.map +1 -1
  195. package/dist/config/validate.d.ts +6 -2
  196. package/dist/config/validate.d.ts.map +1 -1
  197. package/dist/config/validate.js +20 -3
  198. package/dist/config/validate.js.map +1 -1
  199. package/dist/credentials.d.ts +1 -1
  200. package/dist/credentials.d.ts.map +1 -1
  201. package/dist/credentials.js +1 -1
  202. package/dist/credentials.js.map +1 -1
  203. package/dist/{backend → engine}/contract.d.ts +27 -19
  204. package/dist/engine/contract.d.ts.map +1 -0
  205. package/dist/{backend → engine}/contract.js +18 -18
  206. package/dist/engine/contract.js.map +1 -0
  207. package/dist/{backend → engine}/index.d.ts +141 -79
  208. package/dist/engine/index.d.ts.map +1 -0
  209. package/dist/{backend → engine}/index.js +62 -37
  210. package/dist/engine/index.js.map +1 -0
  211. package/dist/engine/session.d.ts +23 -0
  212. package/dist/engine/session.d.ts.map +1 -0
  213. package/dist/{backend → engine}/session.js +58 -51
  214. package/dist/engine/session.js.map +1 -0
  215. package/dist/{backend → engine}/surface.d.ts +11 -11
  216. package/dist/engine/surface.d.ts.map +1 -0
  217. package/dist/{backend → engine}/surface.js +2 -2
  218. package/dist/engine/surface.js.map +1 -0
  219. package/dist/engine/timing.d.ts.map +1 -0
  220. package/dist/engine/timing.js +8 -0
  221. package/dist/engine/timing.js.map +1 -0
  222. package/dist/expect/async.d.ts +1 -1
  223. package/dist/expect/async.d.ts.map +1 -1
  224. package/dist/expect/async.js +37 -1
  225. package/dist/expect/async.js.map +1 -1
  226. package/dist/expect/index.js +1 -1
  227. package/dist/expect/values.d.ts +1 -1
  228. package/dist/expect/values.d.ts.map +1 -1
  229. package/dist/expect/values.js +1 -1
  230. package/dist/expect/values.js.map +1 -1
  231. package/dist/index.d.ts +3 -5
  232. package/dist/index.d.ts.map +1 -1
  233. package/dist/index.js +1 -5
  234. package/dist/index.js.map +1 -1
  235. package/dist/internal/brands.d.ts +1 -1
  236. package/dist/internal/brands.d.ts.map +1 -1
  237. package/dist/internal/brands.js +1 -1
  238. package/dist/internal/brands.js.map +1 -1
  239. package/dist/internal/errors.d.ts +37 -19
  240. package/dist/internal/errors.d.ts.map +1 -1
  241. package/dist/internal/errors.js +94 -44
  242. package/dist/internal/errors.js.map +1 -1
  243. package/dist/internal/globs.d.ts +2 -2
  244. package/dist/internal/globs.d.ts.map +1 -1
  245. package/dist/internal/globs.js +2 -2
  246. package/dist/internal/globs.js.map +1 -1
  247. package/dist/internal/ids.d.ts +3 -3
  248. package/dist/internal/ids.d.ts.map +1 -1
  249. package/dist/internal/ids.js +3 -3
  250. package/dist/internal/ids.js.map +1 -1
  251. package/dist/internal/node-version.d.ts +10 -0
  252. package/dist/internal/node-version.d.ts.map +1 -0
  253. package/dist/internal/node-version.js +28 -0
  254. package/dist/internal/node-version.js.map +1 -0
  255. package/dist/internal/objects.d.ts +21 -0
  256. package/dist/internal/objects.d.ts.map +1 -0
  257. package/dist/internal/objects.js +14 -0
  258. package/dist/internal/objects.js.map +1 -0
  259. package/dist/internal/package-manager.d.ts +10 -0
  260. package/dist/internal/package-manager.d.ts.map +1 -0
  261. package/dist/internal/package-manager.js +43 -0
  262. package/dist/internal/package-manager.js.map +1 -0
  263. package/dist/internal/redact.d.ts +1 -1
  264. package/dist/internal/redact.d.ts.map +1 -1
  265. package/dist/internal/redact.js +1 -1
  266. package/dist/internal/redact.js.map +1 -1
  267. package/dist/internal/suggest.d.ts +16 -0
  268. package/dist/internal/suggest.d.ts.map +1 -0
  269. package/dist/internal/suggest.js +61 -0
  270. package/dist/internal/suggest.js.map +1 -0
  271. package/dist/internal/text.d.ts +1 -1
  272. package/dist/internal/text.d.ts.map +1 -1
  273. package/dist/internal/text.js +1 -1
  274. package/dist/internal/text.js.map +1 -1
  275. package/dist/internal/urls.d.ts +3 -3
  276. package/dist/internal/urls.d.ts.map +1 -1
  277. package/dist/internal/urls.js +8 -3
  278. package/dist/internal/urls.js.map +1 -1
  279. package/dist/locator/engine.d.ts +7 -7
  280. package/dist/locator/engine.d.ts.map +1 -1
  281. package/dist/locator/engine.js +14 -14
  282. package/dist/locator/engine.js.map +1 -1
  283. package/dist/locator/expression.d.ts +5 -3
  284. package/dist/locator/expression.d.ts.map +1 -1
  285. package/dist/locator/expression.js +25 -5
  286. package/dist/locator/expression.js.map +1 -1
  287. package/dist/locator/screen.d.ts +1 -1
  288. package/dist/locator/screen.d.ts.map +1 -1
  289. package/dist/locator/screen.js +3 -3
  290. package/dist/locator/screen.js.map +1 -1
  291. package/dist/report/build.d.ts +10 -9
  292. package/dist/report/build.d.ts.map +1 -1
  293. package/dist/report/build.js +25 -22
  294. package/dist/report/build.js.map +1 -1
  295. package/dist/report/code-frame.d.ts +8 -4
  296. package/dist/report/code-frame.d.ts.map +1 -1
  297. package/dist/report/code-frame.js +23 -18
  298. package/dist/report/code-frame.js.map +1 -1
  299. package/dist/report/debug-steps.js +1 -1
  300. package/dist/report/debug-steps.js.map +1 -1
  301. package/dist/report/format.d.ts +73 -0
  302. package/dist/report/format.d.ts.map +1 -0
  303. package/dist/report/format.js +147 -0
  304. package/dist/report/format.js.map +1 -0
  305. package/dist/report/junit.d.ts +1 -1
  306. package/dist/report/junit.d.ts.map +1 -1
  307. package/dist/report/junit.js +1 -1
  308. package/dist/report/junit.js.map +1 -1
  309. package/dist/report/list.d.ts +96 -47
  310. package/dist/report/list.d.ts.map +1 -1
  311. package/dist/report/list.js +489 -244
  312. package/dist/report/list.js.map +1 -1
  313. package/dist/report/live-window.d.ts +28 -0
  314. package/dist/report/live-window.d.ts.map +1 -0
  315. package/dist/report/live-window.js +102 -0
  316. package/dist/report/live-window.js.map +1 -0
  317. package/dist/report/write.d.ts +1 -1
  318. package/dist/report/write.d.ts.map +1 -1
  319. package/dist/report/write.js +1 -1
  320. package/dist/report/write.js.map +1 -1
  321. package/dist/run/budget.d.ts +2 -2
  322. package/dist/run/budget.js +2 -2
  323. package/dist/run/declared-processes.d.ts +30 -0
  324. package/dist/run/declared-processes.d.ts.map +1 -0
  325. package/dist/run/declared-processes.js +61 -0
  326. package/dist/run/declared-processes.js.map +1 -0
  327. package/dist/run/events.d.ts +30 -2
  328. package/dist/run/events.d.ts.map +1 -1
  329. package/dist/run/events.js.map +1 -1
  330. package/dist/run/execute.d.ts +19 -16
  331. package/dist/run/execute.d.ts.map +1 -1
  332. package/dist/run/execute.js +65 -67
  333. package/dist/run/execute.js.map +1 -1
  334. package/dist/run/fixture-recording.d.ts +10 -4
  335. package/dist/run/fixture-recording.d.ts.map +1 -1
  336. package/dist/run/fixture-recording.js +19 -6
  337. package/dist/run/fixture-recording.js.map +1 -1
  338. package/dist/run/fixtures.d.ts +2 -2
  339. package/dist/run/fixtures.d.ts.map +1 -1
  340. package/dist/run/fixtures.js +72 -44
  341. package/dist/run/fixtures.js.map +1 -1
  342. package/dist/run/in-process.d.ts +1 -1
  343. package/dist/run/in-process.js +1 -1
  344. package/dist/run/managed-process.d.ts +46 -9
  345. package/dist/run/managed-process.d.ts.map +1 -1
  346. package/dist/run/managed-process.js +136 -50
  347. package/dist/run/managed-process.js.map +1 -1
  348. package/dist/run/realm.d.ts +2 -2
  349. package/dist/run/realm.js +2 -2
  350. package/dist/run/runner.d.ts +23 -1
  351. package/dist/run/runner.d.ts.map +1 -1
  352. package/dist/run/runner.js +111 -40
  353. package/dist/run/runner.js.map +1 -1
  354. package/dist/run/scheduler.d.ts +5 -5
  355. package/dist/run/scheduler.d.ts.map +1 -1
  356. package/dist/run/scheduler.js +7 -7
  357. package/dist/run/scheduler.js.map +1 -1
  358. package/dist/run/serial.d.ts +10 -2
  359. package/dist/run/serial.d.ts.map +1 -1
  360. package/dist/run/serial.js +5 -3
  361. package/dist/run/serial.js.map +1 -1
  362. package/dist/run/sessions.d.ts +10 -10
  363. package/dist/run/sessions.d.ts.map +1 -1
  364. package/dist/run/sessions.js +11 -11
  365. package/dist/run/sessions.js.map +1 -1
  366. package/dist/run/steps.d.ts +3 -3
  367. package/dist/run/steps.d.ts.map +1 -1
  368. package/dist/run/steps.js +1 -1
  369. package/dist/run/steps.js.map +1 -1
  370. package/dist/run/units.d.ts +1 -1
  371. package/dist/run/units.js +1 -1
  372. package/dist/run/worker/entry.d.ts +1 -1
  373. package/dist/run/worker/entry.js +2 -2
  374. package/dist/run/worker/entry.js.map +1 -1
  375. package/dist/run/worker/protocol.d.ts +18 -6
  376. package/dist/run/worker/protocol.d.ts.map +1 -1
  377. package/dist/run/worker/protocol.js +1 -1
  378. package/dist/run/worker/protocol.js.map +1 -1
  379. package/dist/run/worker/session.d.ts +2 -2
  380. package/dist/run/worker/session.d.ts.map +1 -1
  381. package/dist/run/worker/session.js +5 -3
  382. package/dist/run/worker/session.js.map +1 -1
  383. package/dist/types.d.ts +58 -41
  384. package/dist/types.d.ts.map +1 -1
  385. package/dist/types.js +2 -2
  386. package/package.json +13 -12
  387. package/skills/e2e/SKILL.md +110 -0
  388. package/skills/e2e/references/agent.md +210 -0
  389. package/skills/e2e/references/debugging.md +81 -0
  390. package/skills/e2e/references/running.md +153 -0
  391. package/skills/e2e/references/setup.md +238 -0
  392. package/skills/e2e/references/writing-tests.md +289 -0
  393. package/dist/backend/contract.d.ts.map +0 -1
  394. package/dist/backend/contract.js.map +0 -1
  395. package/dist/backend/index.d.ts.map +0 -1
  396. package/dist/backend/index.js.map +0 -1
  397. package/dist/backend/session.d.ts +0 -23
  398. package/dist/backend/session.d.ts.map +0 -1
  399. package/dist/backend/session.js.map +0 -1
  400. package/dist/backend/surface.d.ts.map +0 -1
  401. package/dist/backend/surface.js.map +0 -1
  402. package/dist/backend/timing.d.ts.map +0 -1
  403. package/dist/backend/timing.js +0 -8
  404. package/dist/backend/timing.js.map +0 -1
  405. package/dist/cli/init/backends.d.ts.map +0 -1
  406. package/dist/cli/init/backends.js.map +0 -1
  407. package/dist/report/live-status.d.ts +0 -51
  408. package/dist/report/live-status.d.ts.map +0 -1
  409. package/dist/report/live-status.js +0 -163
  410. package/dist/report/live-status.js.map +0 -1
  411. package/dist/run/fixture-legacy.d.ts +0 -36
  412. package/dist/run/fixture-legacy.d.ts.map +0 -1
  413. package/dist/run/fixture-legacy.js +0 -143
  414. package/dist/run/fixture-legacy.js.map +0 -1
  415. /package/dist/{backend → engine}/timing.d.ts +0 -0
@@ -1,50 +1,59 @@
1
- /** CLI scaffold presets. Backend packages are referenced as generated source, never imported. */
1
+ /** CLI scaffold presets. Engine packages are referenced as generated source, never imported. */
2
2
  import os from 'node:os';
3
+ /** Engines version independently of the runner and pin the runner through their own peer range. */
4
+ const ENGINE_RANGE = '0.x';
3
5
  /** Builds prompt choices and scaffolds with defaults for the machine running init. */
4
- export function getBackendPresets() {
6
+ export function getEnginePresets() {
5
7
  const ios = os.platform() === 'darwin';
6
8
  return [
7
- {
8
- id: 'none',
9
- label: 'None',
10
- hint: 'HTTP tests or your own backend',
11
- dependencies: {},
12
- imports: [],
13
- config: ` app: { url: process.env.APP_URL ?? 'http://localhost:3000' },
14
- // Add a backend here when your tests need to drive an app.
15
- targets: [{ name: 'default', platform: 'custom' }],`,
16
- example: `import { test, expect } from '@e2edev/e2e';
17
-
18
- test('app responds', async () => {
19
- const response = await fetch(process.env.APP_URL ?? 'http://localhost:3000');
20
- expect(response.ok).toBe(true);
21
- });
22
- `,
23
- runCommand: 'APP_URL=http://localhost:3000 npx --no-install e2e run',
24
- },
25
9
  {
26
10
  id: 'playwright',
27
11
  label: 'Playwright',
28
12
  hint: 'browser testing',
29
- dependencies: { '@e2edev/playwright': 'beta' },
13
+ dependencies: { '@e2edev/playwright': ENGINE_RANGE },
30
14
  imports: ["import { playwright } from '@e2edev/playwright';"],
31
- config: ` app: { url: process.env.APP_URL ?? 'http://localhost:3000' },
32
- targets: [{ name: 'web', platform: 'web', backend: playwright() }],`,
15
+ config: ` // The engine declares the app it drives; APP_URL overrides the default at run time.
16
+ targets: [{
17
+ name: 'web',
18
+ platform: 'web',
19
+ engine: playwright({
20
+ url: process.env.APP_URL ?? 'http://localhost:3000',
21
+ // Let the runner start the dev server and wait for url to answer:
22
+ // command: { executable: 'npm', args: ['run', 'dev'] },
23
+ }),
24
+ }],`,
33
25
  example: `import { test } from '@e2edev/playwright';
34
26
  import { expect } from '@e2edev/e2e';
35
27
 
36
28
  test('app opens', async ({ app, web }) => {
37
- await app.open();
38
- await expect(web).toHaveURL('/');
29
+ await app.open('/');
30
+ await expect(web.locator('body')).toBeVisible();
39
31
  });
40
32
  `,
41
33
  aiExample: `
42
34
  // Runs when E2E_MODEL and E2E_MODEL_API_KEY are set:
43
35
  // test('the agent drives a flow', async ({ app, agent }) => {
44
- // await app.open();
36
+ // await app.open('/');
45
37
  // await agent.act('one goal in plain language');
46
38
  // await agent.assert('one question about the screen');
47
39
  // });
40
+ `,
41
+ runCommand: 'APP_URL=http://localhost:3000 npx --no-install e2e run',
42
+ },
43
+ {
44
+ id: 'none',
45
+ label: 'None',
46
+ hint: 'HTTP tests or your own engine',
47
+ dependencies: {},
48
+ imports: [],
49
+ config: ` // Add an engine here when your tests need to drive an app.
50
+ targets: [{ name: 'default', platform: 'custom' }],`,
51
+ example: `import { test, expect } from '@e2edev/e2e';
52
+
53
+ test('app responds', async () => {
54
+ const response = await fetch(process.env.APP_URL ?? 'http://localhost:3000');
55
+ expect(response.ok).toBe(true);
56
+ });
48
57
  `,
49
58
  runCommand: 'APP_URL=http://localhost:3000 npx --no-install e2e run',
50
59
  },
@@ -52,14 +61,14 @@ test('app opens', async ({ app, web }) => {
52
61
  id: 'agent-device',
53
62
  label: 'agent-device',
54
63
  hint: 'mobile testing: iOS and Android',
55
- dependencies: { '@e2edev/agent-device': 'beta' },
64
+ dependencies: { '@e2edev/agent-device': ENGINE_RANGE },
56
65
  imports: ["import { agentDevice } from '@e2edev/agent-device';"],
57
66
  config: ios
58
67
  ? ` // Requires Xcode and an iOS simulator. Replace Settings with your app's bundle ID.
59
- targets: [{ name: 'ios', platform: 'ios', backend: agentDevice({ platform: 'ios', app: 'Settings' }) }],
68
+ targets: [{ name: 'ios', platform: 'ios', engine: agentDevice({ platform: 'ios', app: 'Settings' }) }],
60
69
  workers: 1,`
61
70
  : ` // Requires the Android SDK and an emulator. Replace com.android.settings with your app's package.
62
- targets: [{ name: 'android', platform: 'android', backend: agentDevice({ platform: 'android', app: 'com.android.settings' }) }],
71
+ targets: [{ name: 'android', platform: 'android', engine: agentDevice({ platform: 'android', app: 'com.android.settings' }) }],
63
72
  workers: 1,`,
64
73
  example: `import { test } from '@e2edev/agent-device';
65
74
  import { expect } from '@e2edev/e2e';
@@ -87,12 +96,12 @@ test('Settings opens', async ({ screen }) => {
87
96
  },
88
97
  ];
89
98
  }
90
- export const DEFAULT_BACKEND_ID = 'none';
99
+ export const DEFAULT_ENGINE_ID = 'playwright';
91
100
  /** Resolves a preset with the common shape used by scaffold generation. */
92
- export function getBackendPreset(id) {
93
- const preset = getBackendPresets().find((entry) => entry.id === id);
101
+ export function getEnginePreset(id) {
102
+ const preset = getEnginePresets().find((entry) => entry.id === id);
94
103
  if (preset === undefined)
95
- throw new Error(`unknown backend: ${id}`);
104
+ throw new Error(`unknown engine: ${id}`);
96
105
  return preset;
97
106
  }
98
- //# sourceMappingURL=backends.js.map
107
+ //# sourceMappingURL=engines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engines.js","sourceRoot":"","sources":["../../../src/cli/init/engines.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAEhG,OAAO,EAAE,MAAM,SAAS,CAAC;AAczB,mGAAmG;AACnG,MAAM,YAAY,GAAG,KAAK,CAAC;AAE3B,sFAAsF;AACtF,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,QAAQ,CAAC;IACvC,OAAO;QACL;YACE,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,YAAY;YACnB,IAAI,EAAE,iBAAiB;YACvB,YAAY,EAAE,EAAE,oBAAoB,EAAE,YAAY,EAAE;YACpD,OAAO,EAAE,CAAC,kDAAkD,CAAC;YAC7D,MAAM,EAAE;;;;;;;;;MASR;YACA,OAAO,EAAE;;;;;;;CAOd;YACK,SAAS,EAAE;;;;;;;CAOhB;YACK,UAAU,EAAE,wDAAwD;SACrE;QACD;YACE,EAAE,EAAE,MAAM;YACV,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,+BAA+B;YACrC,YAAY,EAAE,EAAE;YAChB,OAAO,EAAE,EAAE;YACX,MAAM,EAAE;sDACwC;YAChD,OAAO,EAAE;;;;;;CAMd;YACK,UAAU,EAAE,wDAAwD;SACrE;QACD;YACE,EAAE,EAAE,cAAc;YAClB,KAAK,EAAE,cAAc;YACrB,IAAI,EAAE,iCAAiC;YACvC,YAAY,EAAE,EAAE,sBAAsB,EAAE,YAAY,EAAE;YACtD,OAAO,EAAE,CAAC,qDAAqD,CAAC;YAChE,MAAM,EAAE,GAAG;gBACT,CAAC,CAAC;;cAEI;gBACN,CAAC,CAAC;;cAEI;YACR,OAAO,EAAE;;;;iBAIE,GAAG,CAAC,CAAC,CAAC,iDAAiD,CAAC,CAAC,CAAC,wCAAwC;;CAElH;YACK,SAAS,EAAE,GAAG;gBACZ,CAAC,CAAC;;;;;;CAMT;gBACO,CAAC,CAAC;;;;;;CAMT;YACK,UAAU,EAAE,0BAA0B;SACvC;KACyC,CAAC;AAC/C,CAAC;AAGD,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAA+B,CAAC;AAEjE,2EAA2E;AAC3E,MAAM,UAAU,eAAe,CAAC,EAAY;IAC1C,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,IAAI,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;IACnE,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,4 +1,4 @@
1
- /** package.json reading, dependency additions, and package-manager detection for `e2e init`. */
1
+ /** package.json reading and dependency additions for `e2e init`. */
2
2
  import { z } from 'zod';
3
3
  declare const packageSchema: z.ZodObject<{
4
4
  dependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
@@ -6,6 +6,7 @@ declare const packageSchema: z.ZodObject<{
6
6
  peerDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
7
7
  optionalDependencies: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
8
8
  packageManager: z.ZodOptional<z.ZodString>;
9
+ scripts: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
9
10
  }, z.core.$loose>;
10
11
  type PackageManifest = z.infer<typeof packageSchema>;
11
12
  /**
@@ -21,8 +22,11 @@ export declare function readPackage(cwd: string): {
21
22
  peerDependencies?: Record<string, string> | undefined;
22
23
  optionalDependencies?: Record<string, string> | undefined;
23
24
  packageManager?: string | undefined;
25
+ scripts?: Record<string, string> | undefined;
24
26
  };
25
27
  };
28
+ /** Why a manifest failed to read: the JSON parser's own position, or the field that has the wrong shape. */
29
+ export declare function describeManifestError(cause: unknown): string;
26
30
  /** Adds only missing dependencies to devDependencies and returns what was added. */
27
31
  export declare function addDependencies(manifest: PackageManifest, dependencies: Readonly<Record<string, string>>): {
28
32
  manifest: {
@@ -32,11 +36,23 @@ export declare function addDependencies(manifest: PackageManifest, dependencies:
32
36
  peerDependencies?: Record<string, string> | undefined;
33
37
  optionalDependencies?: Record<string, string> | undefined;
34
38
  packageManager?: string | undefined;
39
+ scripts?: Record<string, string> | undefined;
40
+ };
41
+ additions: [string, string][];
42
+ };
43
+ /** Adds only missing scripts and returns what was added. */
44
+ export declare function addScripts(manifest: PackageManifest, scripts: Readonly<Record<string, string>>): {
45
+ manifest: {
46
+ [x: string]: unknown;
47
+ dependencies?: Record<string, string> | undefined;
48
+ devDependencies?: Record<string, string> | undefined;
49
+ peerDependencies?: Record<string, string> | undefined;
50
+ optionalDependencies?: Record<string, string> | undefined;
51
+ packageManager?: string | undefined;
52
+ scripts?: Record<string, string> | undefined;
35
53
  };
36
54
  additions: [string, string][];
37
55
  };
38
- /** The `packageManager` field wins, then a lockfile, then the manager that invoked the CLI, then npm. */
39
- export declare function detectPackageManager(cwd: string, manifest: PackageManifest): string;
40
56
  /** Serializes with the original manifest's indentation and newline convention. */
41
57
  export declare function serializePackage(manifest: PackageManifest, original: string | undefined): string;
42
58
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"package.d.ts","sourceRoot":"","sources":["../../../src/cli/init/package.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAIhG,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,aAAa;;;;;;iBAMjB,CAAC;AACH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAWrD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM;;;;;;;;;;EAKtC;AAQD,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;;;;;;;;;EAOxG;AAED,yGAAyG;AACzG,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,MAAM,CAQnF;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAIhG"}
1
+ {"version":3,"file":"package.d.ts","sourceRoot":"","sources":["../../../src/cli/init/package.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAIpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,aAAa;;;;;;;iBAOjB,CAAC;AACH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAErD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM;;;;;;;;;;;EAKtC;AAED,4GAA4G;AAC5G,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAO5D;AAQD,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;;;;;;;;;;EAOxG;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;;;;;;;;;;EAO9F;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAIhG"}
@@ -1,4 +1,4 @@
1
- /** package.json reading, dependency additions, and package-manager detection for `e2e init`. */
1
+ /** package.json reading and dependency additions for `e2e init`. */
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { z } from 'zod';
@@ -9,15 +9,8 @@ const packageSchema = z.looseObject({
9
9
  peerDependencies: dependencyBlock,
10
10
  optionalDependencies: dependencyBlock,
11
11
  packageManager: z.string().optional(),
12
+ scripts: z.record(z.string(), z.string()).optional(),
12
13
  });
13
- const PACKAGE_MANAGERS = new Set(['npm', 'pnpm', 'yarn', 'bun']);
14
- const LOCKFILES = [
15
- ['pnpm-lock.yaml', 'pnpm'],
16
- ['yarn.lock', 'yarn'],
17
- ['bun.lock', 'bun'],
18
- ['bun.lockb', 'bun'],
19
- ['package-lock.json', 'npm'],
20
- ];
21
14
  /**
22
15
  * Reads and validates the manifest, keeping its original text so edits can
23
16
  * preserve formatting. A missing manifest starts as a private ESM package.
@@ -28,6 +21,15 @@ export function readPackage(cwd) {
28
21
  const manifest = packageSchema.parse(original === undefined ? { private: true, type: 'module' } : JSON.parse(original));
29
22
  return { original, manifest };
30
23
  }
24
+ /** Why a manifest failed to read: the JSON parser's own position, or the field that has the wrong shape. */
25
+ export function describeManifestError(cause) {
26
+ if (cause instanceof z.ZodError) {
27
+ return cause.issues
28
+ .map((issue) => `${issue.path.length === 0 ? 'package.json' : issue.path.join('.')}: ${issue.message}`)
29
+ .join('; ');
30
+ }
31
+ return cause instanceof Error ? cause.message : String(cause);
32
+ }
31
33
  /** True when any dependency section lists `name`, so existing versions and workspace links are kept. */
32
34
  function declaresDependency(manifest, name) {
33
35
  return [manifest.dependencies, manifest.devDependencies, manifest.peerDependencies, manifest.optionalDependencies]
@@ -43,17 +45,15 @@ export function addDependencies(manifest, dependencies) {
43
45
  additions,
44
46
  };
45
47
  }
46
- /** The `packageManager` field wins, then a lockfile, then the manager that invoked the CLI, then npm. */
47
- export function detectPackageManager(cwd, manifest) {
48
- const configured = manifest.packageManager?.split('@')[0];
49
- if (configured !== undefined && PACKAGE_MANAGERS.has(configured))
50
- return configured;
51
- for (const [lock, manager] of LOCKFILES) {
52
- if (existsSync(path.join(cwd, lock)))
53
- return manager;
54
- }
55
- const invoking = process.env['npm_config_user_agent']?.split('/')[0];
56
- return invoking !== undefined && PACKAGE_MANAGERS.has(invoking) ? invoking : 'npm';
48
+ /** Adds only missing scripts and returns what was added. */
49
+ export function addScripts(manifest, scripts) {
50
+ const additions = Object.entries(scripts).filter(([name]) => manifest.scripts?.[name] === undefined);
51
+ if (additions.length === 0)
52
+ return { manifest, additions };
53
+ return {
54
+ manifest: { ...manifest, scripts: { ...manifest.scripts, ...Object.fromEntries(additions) } },
55
+ additions,
56
+ };
57
57
  }
58
58
  /** Serializes with the original manifest's indentation and newline convention. */
59
59
  export function serializePackage(manifest, original) {
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","sourceRoot":"","sources":["../../../src/cli/init/package.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"package.js","sourceRoot":"","sources":["../../../src/cli/init/package.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { type BackendId } from './backends.ts';
2
- /** Composes common setup, the selected backend, and optional AI support. */
3
- export declare function createScaffold(backendId: BackendId, ai: boolean): {
1
+ import { type EngineId } from './engines.ts';
2
+ /** Composes common setup, the selected engine, and optional AI support. */
3
+ export declare function createScaffold(engineId: EngineId, ai: boolean): {
4
4
  dependencies: {
5
5
  '@e2edev/e2e': string;
6
6
  ai?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/init/scaffold.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAQjE,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO;;;;;;;;EA2B/D"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../../../src/cli/init/scaffold.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAS9D,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO;;;;;;;;EA2B7D"}
@@ -1,36 +1,37 @@
1
1
  import { packageVersion } from '../../internal/package-version.js';
2
- import { getBackendPreset } from './backends.js';
2
+ import { getEnginePreset } from './engines.js';
3
3
  const AGENT_IMPORT = "import { createAgent } from '@e2edev/e2e/agent';";
4
4
  const AGENT_CONFIG = ` // The model comes from E2E_MODEL; authenticate with E2E_MODEL_API_KEY.
5
+ // To call a provider directly, pass an AI SDK model: createAgent({ model: openai('gpt-5.4-mini') }).
5
6
  agent: createAgent({
6
7
  system: 'You are a thorough QA agent. Verify every outcome.',
7
8
  }),`;
8
- /** Composes common setup, the selected backend, and optional AI support. */
9
- export function createScaffold(backendId, ai) {
10
- const backend = getBackendPreset(backendId);
9
+ /** Composes common setup, the selected engine, and optional AI support. */
10
+ export function createScaffold(engineId, ai) {
11
+ const engine = getEnginePreset(engineId);
11
12
  const imports = [
12
- "import { defineConfig } from '@e2edev/e2e';",
13
+ "import type { E2EConfig } from '@e2edev/e2e';",
13
14
  ...(ai ? [AGENT_IMPORT] : []),
14
- ...backend.imports,
15
+ ...engine.imports,
15
16
  ];
16
17
  const configFields = [
17
18
  ...(ai ? [AGENT_CONFIG] : []),
18
- backend.config,
19
+ engine.config,
19
20
  ];
20
21
  return {
21
22
  dependencies: {
22
23
  '@e2edev/e2e': `^${packageVersion(import.meta.url, '../../../package.json', '0.0.0')}`,
23
- ...backend.dependencies,
24
+ ...engine.dependencies,
24
25
  ...(ai ? { ai: '^7.0.0' } : {}),
25
26
  },
26
27
  config: `${imports.join('\n')}
27
28
 
28
- export default defineConfig({
29
+ export default {
29
30
  ${configFields.join('\n')}
30
- });
31
+ } satisfies E2EConfig;
31
32
  `,
32
- example: backend.example + (ai ? backend.aiExample ?? '' : ''),
33
- runCommand: backend.runCommand,
33
+ example: engine.example + (ai ? engine.aiExample ?? '' : ''),
34
+ runCommand: engine.runCommand,
34
35
  };
35
36
  }
36
37
  //# sourceMappingURL=scaffold.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/cli/init/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAkB,MAAM,eAAe,CAAC;AAEjE,MAAM,YAAY,GAAG,kDAAkD,CAAC;AACxE,MAAM,YAAY,GAAG;;;MAGf,CAAC;AAEP,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,SAAoB,EAAE,EAAW;IAC9D,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG;QACd,6CAA6C;QAC7C,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,OAAO,CAAC,OAAO;KACnB,CAAC;IACF,MAAM,YAAY,GAAG;QACnB,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,MAAM;KACf,CAAC;IAEF,OAAO;QACL,YAAY,EAAE;YACZ,aAAa,EAAE,IAAI,cAAc,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE;YACtF,GAAG,OAAO,CAAC,YAAY;YACvB,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChC;QACD,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG/B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;;CAExB;QACG,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/cli/init/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAiB,MAAM,cAAc,CAAC;AAE9D,MAAM,YAAY,GAAG,kDAAkD,CAAC;AACxE,MAAM,YAAY,GAAG;;;;MAIf,CAAC;AAEP,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,QAAkB,EAAE,EAAW;IAC5D,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG;QACd,+CAA+C;QAC/C,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,MAAM,CAAC,OAAO;KAClB,CAAC;IACF,MAAM,YAAY,GAAG;QACnB,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,MAAM,CAAC,MAAM;KACd,CAAC;IAEF,OAAO;QACL,YAAY,EAAE;YACZ,aAAa,EAAE,IAAI,cAAc,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE;YACtF,GAAG,MAAM,CAAC,YAAY;YACtB,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChC;QACD,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG/B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;;CAExB;QACG,OAAO,EAAE,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC;AACJ,CAAC"}
@@ -1,11 +1,23 @@
1
- /** Non-destructive project scaffolding (spec 06-cli.md). */
1
+ /** Non-destructive project scaffolding. */
2
2
  export interface InitOptions {
3
3
  yes?: boolean;
4
+ /**
5
+ * The directory argument as the user typed it, when `cwd` was chosen from
6
+ * one; the closing `next:` line then starts with `cd` into it.
7
+ */
8
+ directory?: string;
9
+ /**
10
+ * Whether prompts can be answered. The CLI passes its terminal state; a
11
+ * non-interactive run without `--yes` stops before asking anything, since
12
+ * a prompt nobody can answer would otherwise wait forever.
13
+ */
14
+ interactive?: boolean;
4
15
  }
5
16
  /**
6
17
  * Runs `e2e init`. Every prompt happens before the first write, existing
7
18
  * config and test files are never touched, and dependencies install only when
8
- * the user asks.
19
+ * the user asks. The agent skill is offered once; later runs refresh the
20
+ * copies that exist and never add new locations.
9
21
  */
10
22
  export declare function init(cwd: string, options?: InitOptions): Promise<number>;
11
23
  //# sourceMappingURL=init.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAW5D,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAYD;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsGlF"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAgB3C,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAiBD;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoKlF"}
package/dist/cli/init.js CHANGED
@@ -1,34 +1,56 @@
1
- /** Non-destructive project scaffolding (spec 06-cli.md). */
1
+ /** Non-destructive project scaffolding. */
2
2
  import * as clack from '@clack/prompts';
3
3
  import { spawnSync } from 'node:child_process';
4
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
5
+ import os from 'node:os';
5
6
  import path from 'node:path';
6
7
  import { esmPackageHint } from '../config/esm.js';
7
- import { getBackendPresets, DEFAULT_BACKEND_ID } from './init/backends.js';
8
- import { addDependencies, detectPackageManager, readPackage, serializePackage } from './init/package.js';
8
+ import { detectPackageManager } from '../internal/package-manager.js';
9
+ import { DOCS_URL } from './docs-url.js';
10
+ import { findInstalledSkillDirs, planSkillInstall, SKILL_LOCATIONS } from './init/agent-skill.js';
11
+ import { getEnginePresets, DEFAULT_ENGINE_ID } from './init/engines.js';
12
+ import { addDependencies, addScripts, describeManifestError, readPackage, serializePackage } from './init/package.js';
9
13
  import { createScaffold } from './init/scaffold.js';
14
+ import { MISSING_SKILL_MESSAGE, readSkillFiles } from './skill.js';
15
+ const CACHE_IGNORE_ENTRY = '.e2e/cache/';
10
16
  const GITIGNORE_ENTRIES = [
11
17
  'node_modules/',
12
18
  '.e2e/artifacts/',
13
- '.e2e/cache/',
19
+ CACHE_IGNORE_ENTRY,
14
20
  '.e2e/sessions/',
15
21
  '.e2e/report.json',
16
22
  '.e2e/ai-trace.json',
17
23
  '.e2e/junit.xml',
24
+ '.e2e/logs/',
18
25
  ];
26
+ const SCRIPTS = { 'test:e2e': 'e2e run' };
19
27
  /**
20
28
  * Runs `e2e init`. Every prompt happens before the first write, existing
21
29
  * config and test files are never touched, and dependencies install only when
22
- * the user asks.
30
+ * the user asks. The agent skill is offered once; later runs refresh the
31
+ * copies that exist and never add new locations.
23
32
  */
24
33
  export async function init(cwd, options = {}) {
25
- clack.intro('e2e init');
34
+ clack.intro(options.directory === undefined ? 'e2e init' : `e2e init ${options.directory}`);
35
+ if (options.interactive === false && !options.yes) {
36
+ clack.log.error('e2e init asks questions and needs an interactive terminal; run it from a terminal, or pass --yes to accept the defaults (Playwright, AI on, no installation)');
37
+ return 2;
38
+ }
39
+ if (existsSync(cwd) && !statSync(cwd).isDirectory()) {
40
+ clack.log.error(`${options.directory ?? cwd} is a file, not a directory`);
41
+ return 2;
42
+ }
26
43
  let pkg;
27
44
  try {
28
45
  pkg = readPackage(cwd);
29
46
  }
30
- catch {
31
- clack.log.error('invalid package.json; fix it before running e2e init');
47
+ catch (cause) {
48
+ clack.log.error(`${path.join(cwd, 'package.json')} could not be read: ${describeManifestError(cause)}; fix it before running e2e init`);
49
+ return 2;
50
+ }
51
+ const bundledSkill = readSkillFiles();
52
+ if (bundledSkill.length === 0) {
53
+ clack.log.error(MISSING_SKILL_MESSAGE);
32
54
  return 2;
33
55
  }
34
56
  const existingConfig = ['e2e.config.ts', 'e2e.config.mts'].find((file) => existsSync(path.join(cwd, file)));
@@ -47,49 +69,73 @@ export async function init(cwd, options = {}) {
47
69
  const existingIgnore = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf8') : '';
48
70
  const ignoreLines = existingIgnore.split(/\r?\n/);
49
71
  const missingIgnore = GITIGNORE_ENTRIES.filter((entry) => !ignoreLines.includes(entry));
50
- // Backend and AI are choices for a new config only; an existing config keeps its own dependencies.
51
- let backend = DEFAULT_BACKEND_ID;
72
+ // Engine and AI are choices for a new config only; an existing config keeps its own dependencies.
73
+ let engine = existingConfig === undefined ? DEFAULT_ENGINE_ID : 'none';
52
74
  let ai = existingConfig === undefined;
53
75
  if (existingConfig === undefined && !options.yes) {
54
- const selectedBackend = await clack.select({
55
- message: 'Which backend?',
56
- initialValue: DEFAULT_BACKEND_ID,
57
- options: getBackendPresets().map(({ id, label, hint }) => ({ value: id, label, hint })),
76
+ const selectedEngine = await clack.select({
77
+ message: 'Which engine?',
78
+ initialValue: DEFAULT_ENGINE_ID,
79
+ options: getEnginePresets().map(({ id, label, hint }) => ({ value: id, label, hint })),
58
80
  });
59
- if (clack.isCancel(selectedBackend))
81
+ if (clack.isCancel(selectedEngine))
60
82
  return cancelled();
61
- backend = selectedBackend;
83
+ engine = selectedEngine;
62
84
  const enableAi = await clack.confirm({ message: 'Enable AI testing? Adds AI SDK v7.', initialValue: true });
63
85
  if (clack.isCancel(enableAi))
64
86
  return cancelled();
65
87
  ai = enableAi;
66
88
  }
67
- const scaffold = createScaffold(backend, ai);
68
- const { manifest, additions } = addDependencies(pkg.manifest, scaffold.dependencies);
69
- if (additions.length > 0) {
70
- clack.log.info(`add dev dependencies: ${additions.map(([name, version]) => `${name}@${version}`).join(', ')}`);
89
+ // The skill goes where an earlier run put it; a project without one chooses.
90
+ let skillDirs = findInstalledSkillDirs(cwd);
91
+ if (skillDirs.length === 0) {
92
+ if (options.yes) {
93
+ skillDirs = SKILL_LOCATIONS.map((location) => location.dir);
94
+ }
95
+ else {
96
+ const selected = await clack.multiselect({
97
+ message: 'Install the e2e skill for coding agents?',
98
+ options: SKILL_LOCATIONS.map(({ dir, hint }) => ({ value: dir, label: dir, hint })),
99
+ initialValues: SKILL_LOCATIONS.map((location) => location.dir),
100
+ required: false,
101
+ });
102
+ if (clack.isCancel(selected))
103
+ return cancelled();
104
+ skillDirs = selected;
105
+ }
106
+ }
107
+ const skillInstalls = planSkillInstall(cwd, skillDirs, bundledSkill);
108
+ const scaffold = createScaffold(engine, ai);
109
+ const dependencies = addDependencies(pkg.manifest, scaffold.dependencies);
110
+ const { manifest, additions: scripts } = addScripts(dependencies.manifest, SCRIPTS);
111
+ if (dependencies.additions.length > 0) {
112
+ clack.log.info(`add dev dependencies: ${dependencies.additions.map(([name, version]) => `${name}@${version}`).join(', ')}`);
113
+ }
114
+ if (scripts.length > 0) {
115
+ clack.log.info(`add scripts: ${scripts.map(([name, command]) => `${name} (${command})`).join(', ')}`);
71
116
  }
72
117
  const files = [
73
- ...(pkg.original === undefined || additions.length > 0
118
+ ...(pkg.original === undefined || dependencies.additions.length > 0 || scripts.length > 0
74
119
  ? [{ relative: 'package.json', content: serializePackage(manifest, pkg.original), existing: pkg.original !== undefined }]
75
120
  : []),
76
121
  ...(existingConfig === undefined ? [{ relative: 'e2e.config.ts', content: scaffold.config, existing: false }] : []),
77
122
  ...(exampleExists ? [] : [{ relative: examplePath, content: scaffold.example, existing: false }]),
78
123
  ];
79
- if (files.length === 0 && missingIgnore.length === 0) {
124
+ if (files.length === 0 && skillInstalls.length === 0 && missingIgnore.length === 0) {
80
125
  clack.outro('nothing to create; project already initialized');
81
126
  return 0;
82
127
  }
83
128
  if (!options.yes) {
84
129
  const actions = [
85
130
  ...files.map((file) => `${file.existing ? 'update' : 'create'} ${file.relative}`),
131
+ ...skillInstalls.map((install) => `${install.existing ? 'update' : 'create'} ${install.relative}/`),
86
132
  ...(missingIgnore.length > 0 ? ['update .gitignore'] : []),
87
133
  ];
88
134
  const proceed = await clack.confirm({ message: `${actions.join(', ')}?` });
89
135
  if (clack.isCancel(proceed) || !proceed)
90
136
  return cancelled();
91
137
  }
92
- const manager = detectPackageManager(cwd, manifest);
138
+ const manager = detectPackageManager(cwd, manifest.packageManager);
93
139
  let install = false;
94
140
  if (!options.yes) {
95
141
  const selected = await clack.confirm({ message: `Install dependencies with ${manager}?`, initialValue: true });
@@ -97,16 +143,31 @@ export async function init(cwd, options = {}) {
97
143
  return cancelled();
98
144
  install = selected;
99
145
  }
146
+ // The first write; a directory named on the command line comes into being here.
147
+ mkdirSync(cwd, { recursive: true });
100
148
  for (const file of files) {
101
149
  const absolute = path.join(cwd, file.relative);
102
150
  mkdirSync(path.dirname(absolute), { recursive: true });
103
151
  writeFileSync(absolute, file.content, 'utf8');
104
152
  clack.log.success(`${file.existing ? 'updated' : 'created'} ${file.relative}`);
105
153
  }
154
+ for (const skill of skillInstalls) {
155
+ for (const file of skill.files) {
156
+ mkdirSync(path.dirname(file.absolute), { recursive: true });
157
+ writeFileSync(file.absolute, file.content, 'utf8');
158
+ }
159
+ clack.log.success(`${skill.existing ? 'updated' : 'created'} ${skill.relative}/ (${skill.files.length} files)`);
160
+ }
161
+ if (skillDirs.length === 0) {
162
+ clack.log.info('skipped the agent skill; agents can still print it with npx --no-install e2e guide');
163
+ }
106
164
  if (missingIgnore.length > 0) {
107
165
  const prefix = existingIgnore === '' || existingIgnore.endsWith('\n') ? '' : '\n';
108
166
  writeFileSync(gitignorePath, `${existingIgnore}${prefix}${missingIgnore.join('\n')}\n`, 'utf8');
109
167
  clack.log.success(`updated .gitignore (${missingIgnore.length} entries)`);
168
+ if (missingIgnore.includes(CACHE_IGNORE_ENTRY)) {
169
+ clack.log.info(`${CACHE_IGNORE_ENTRY} is ignored; committing agent.act replays is opt-in, see ${DOCS_URL}/reference/config#commit-your-traces`);
170
+ }
110
171
  }
111
172
  if (install) {
112
173
  const result = spawnSync(manager, ['install'], { cwd, stdio: 'inherit', shell: process.platform === 'win32' });
@@ -117,9 +178,27 @@ export async function init(cwd, options = {}) {
117
178
  return result.signal === 'SIGINT' ? 130 : 2;
118
179
  }
119
180
  }
120
- clack.outro(`next: ${install ? '' : `${manager} install, then `}${scaffold.runCommand}`);
181
+ if (!existsSync(path.join(cwd, 'tsconfig.json'))) {
182
+ clack.log.info('no tsconfig.json; add one for editor completions on e2e.config.ts and tests/');
183
+ }
184
+ const next = [
185
+ options.directory === undefined ? undefined : `cd ${shellArgument(options.directory)}`,
186
+ install ? undefined : `${manager} install`,
187
+ scaffold.runCommand,
188
+ ].filter((step) => step !== undefined);
189
+ clack.outro(`next: ${next.join(', then ')}`);
121
190
  return 0;
122
191
  }
192
+ /**
193
+ * A path as the user will paste it into their shell: bare while every character
194
+ * is safe, otherwise quoted for the platform (single quotes for POSIX shells,
195
+ * double quotes for cmd and PowerShell), so `apps/my web` stays one argument.
196
+ */
197
+ function shellArgument(value) {
198
+ if (/^[A-Za-z0-9_./@%+=:,-]+$/.test(value))
199
+ return value;
200
+ return os.platform() === 'win32' ? `"${value.replaceAll('"', '""')}"` : `'${value.replaceAll("'", "'\\''")}'`;
201
+ }
123
202
  /** Cancellation is only reachable before the first write, so nothing needs undoing. */
124
203
  function cancelled() {
125
204
  clack.cancel('cancelled; no changes were made');