@ethlete/cli 2.0.1-next.2 → 2.1.0-next.10

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 (159) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/README.md +173 -6
  3. package/design/define-call.ts +92 -0
  4. package/design/web/env.d.ts +11 -0
  5. package/design/web/frame.html +17 -0
  6. package/design/web/frame.ts +38 -0
  7. package/design/web/host.css +494 -0
  8. package/design/web/host.ts +445 -0
  9. package/design/web/index.html +11 -0
  10. package/package.json +12 -1
  11. package/src/index.d.ts +1 -1
  12. package/src/index.js +96 -10
  13. package/src/index.js.map +1 -1
  14. package/src/lib/api/api-command.d.ts +5 -0
  15. package/src/lib/api/api-command.js +27 -0
  16. package/src/lib/api/api-command.js.map +1 -0
  17. package/src/lib/api/auth-hint.d.ts +16 -0
  18. package/src/lib/api/auth-hint.js +59 -0
  19. package/src/lib/api/auth-hint.js.map +1 -0
  20. package/src/lib/api/clear.d.ts +36 -0
  21. package/src/lib/api/clear.js +121 -0
  22. package/src/lib/api/clear.js.map +1 -0
  23. package/src/lib/api/clone.d.ts +12 -0
  24. package/src/lib/api/clone.js +24 -0
  25. package/src/lib/api/clone.js.map +1 -0
  26. package/src/lib/api/compose.d.ts +46 -0
  27. package/src/lib/api/compose.js +101 -0
  28. package/src/lib/api/compose.js.map +1 -0
  29. package/src/lib/api/definition.d.ts +37 -0
  30. package/src/lib/api/definition.js +33 -0
  31. package/src/lib/api/definition.js.map +1 -0
  32. package/src/lib/api/git.d.ts +25 -0
  33. package/src/lib/api/git.js +71 -0
  34. package/src/lib/api/git.js.map +1 -0
  35. package/src/lib/api/help.d.ts +11 -0
  36. package/src/lib/api/help.js +72 -0
  37. package/src/lib/api/help.js.map +1 -0
  38. package/src/lib/api/index.d.ts +15 -0
  39. package/src/lib/api/index.js +19 -0
  40. package/src/lib/api/index.js.map +1 -0
  41. package/src/lib/api/load-definitions.d.ts +16 -0
  42. package/src/lib/api/load-definitions.js +22 -0
  43. package/src/lib/api/load-definitions.js.map +1 -0
  44. package/src/lib/api/ports.d.ts +13 -0
  45. package/src/lib/api/ports.js +98 -0
  46. package/src/lib/api/ports.js.map +1 -0
  47. package/src/lib/api/resolve-checkout.d.ts +45 -0
  48. package/src/lib/api/resolve-checkout.js +91 -0
  49. package/src/lib/api/resolve-checkout.js.map +1 -0
  50. package/src/lib/api/run.d.ts +10 -0
  51. package/src/lib/api/run.js +332 -0
  52. package/src/lib/api/run.js.map +1 -0
  53. package/src/lib/api/setup.d.ts +15 -0
  54. package/src/lib/api/setup.js +41 -0
  55. package/src/lib/api/setup.js.map +1 -0
  56. package/src/lib/api/state.d.ts +20 -0
  57. package/src/lib/api/state.js +33 -0
  58. package/src/lib/api/state.js.map +1 -0
  59. package/src/lib/api/suggest.d.ts +7 -0
  60. package/src/lib/api/suggest.js +35 -0
  61. package/src/lib/api/suggest.js.map +1 -0
  62. package/src/lib/auth/auth-command.d.ts +11 -0
  63. package/src/lib/auth/auth-command.js +165 -0
  64. package/src/lib/auth/auth-command.js.map +1 -0
  65. package/src/lib/auth/composer-auth.d.ts +30 -0
  66. package/src/lib/auth/composer-auth.js +70 -0
  67. package/src/lib/auth/composer-auth.js.map +1 -0
  68. package/src/lib/auth/composer-repositories.d.ts +5 -0
  69. package/src/lib/auth/composer-repositories.js +33 -0
  70. package/src/lib/auth/composer-repositories.js.map +1 -0
  71. package/src/lib/auth/gitlab-token.d.ts +43 -0
  72. package/src/lib/auth/gitlab-token.js +72 -0
  73. package/src/lib/auth/gitlab-token.js.map +1 -0
  74. package/src/lib/auth/index.d.ts +4 -0
  75. package/src/lib/auth/index.js +8 -0
  76. package/src/lib/auth/index.js.map +1 -0
  77. package/src/lib/config/diagnose.d.ts +7 -0
  78. package/src/lib/config/diagnose.js +112 -0
  79. package/src/lib/config/diagnose.js.map +1 -0
  80. package/src/lib/config/index.d.ts +2 -0
  81. package/src/lib/config/index.js +6 -0
  82. package/src/lib/config/index.js.map +1 -0
  83. package/src/lib/config/local-config.d.ts +46 -0
  84. package/src/lib/config/local-config.js +57 -0
  85. package/src/lib/config/local-config.js.map +1 -0
  86. package/src/lib/design/calls-tsconfig.d.ts +6 -0
  87. package/src/lib/design/calls-tsconfig.js +37 -0
  88. package/src/lib/design/calls-tsconfig.js.map +1 -0
  89. package/src/lib/design/check.d.ts +11 -0
  90. package/src/lib/design/check.js +192 -0
  91. package/src/lib/design/check.js.map +1 -0
  92. package/src/lib/design/design-command.d.ts +10 -0
  93. package/src/lib/design/design-command.js +32 -0
  94. package/src/lib/design/design-command.js.map +1 -0
  95. package/src/lib/design/index.d.ts +5 -0
  96. package/src/lib/design/index.js +9 -0
  97. package/src/lib/design/index.js.map +1 -0
  98. package/src/lib/design/paths.d.ts +24 -0
  99. package/src/lib/design/paths.js +31 -0
  100. package/src/lib/design/paths.js.map +1 -0
  101. package/src/lib/design/serve.d.ts +7 -0
  102. package/src/lib/design/serve.js +144 -0
  103. package/src/lib/design/serve.js.map +1 -0
  104. package/src/lib/doctor/doctor-command.d.ts +7 -0
  105. package/src/lib/doctor/doctor-command.js +62 -0
  106. package/src/lib/doctor/doctor-command.js.map +1 -0
  107. package/src/lib/doctor/index.d.ts +1 -0
  108. package/src/lib/doctor/index.js +5 -0
  109. package/src/lib/doctor/index.js.map +1 -0
  110. package/src/lib/index.d.ts +7 -0
  111. package/src/lib/index.js +7 -0
  112. package/src/lib/index.js.map +1 -1
  113. package/src/lib/invocation.d.ts +9 -0
  114. package/src/lib/invocation.js +47 -0
  115. package/src/lib/invocation.js.map +1 -0
  116. package/src/lib/release.js +21 -3
  117. package/src/lib/release.js.map +1 -1
  118. package/src/lib/update/ai.d.ts +30 -0
  119. package/src/lib/update/ai.js +44 -0
  120. package/src/lib/update/ai.js.map +1 -0
  121. package/src/lib/update/args.d.ts +21 -0
  122. package/src/lib/update/args.js +89 -0
  123. package/src/lib/update/args.js.map +1 -0
  124. package/src/lib/update/index.d.ts +12 -0
  125. package/src/lib/update/index.js +16 -0
  126. package/src/lib/update/index.js.map +1 -0
  127. package/src/lib/update/migration-manifest.d.ts +40 -0
  128. package/src/lib/update/migration-manifest.js +137 -0
  129. package/src/lib/update/migration-manifest.js.map +1 -0
  130. package/src/lib/update/package-manager.d.ts +23 -0
  131. package/src/lib/update/package-manager.js +47 -0
  132. package/src/lib/update/package-manager.js.map +1 -0
  133. package/src/lib/update/packages.d.ts +65 -0
  134. package/src/lib/update/packages.js +147 -0
  135. package/src/lib/update/packages.js.map +1 -0
  136. package/src/lib/update/pending.d.ts +21 -0
  137. package/src/lib/update/pending.js +41 -0
  138. package/src/lib/update/pending.js.map +1 -0
  139. package/src/lib/update/plan.d.ts +51 -0
  140. package/src/lib/update/plan.js +101 -0
  141. package/src/lib/update/plan.js.map +1 -0
  142. package/src/lib/update/registry.d.ts +31 -0
  143. package/src/lib/update/registry.js +54 -0
  144. package/src/lib/update/registry.js.map +1 -0
  145. package/src/lib/update/run-migrations.d.ts +44 -0
  146. package/src/lib/update/run-migrations.js +73 -0
  147. package/src/lib/update/run-migrations.js.map +1 -0
  148. package/src/lib/update/semver.d.ts +19 -0
  149. package/src/lib/update/semver.js +79 -0
  150. package/src/lib/update/semver.js.map +1 -0
  151. package/src/lib/update/tasks.d.ts +58 -0
  152. package/src/lib/update/tasks.js +174 -0
  153. package/src/lib/update/tasks.js.map +1 -0
  154. package/src/lib/update/update-command.d.ts +12 -0
  155. package/src/lib/update/update-command.js +304 -0
  156. package/src/lib/update/update-command.js.map +1 -0
  157. package/src/lib/utils.d.ts +14 -0
  158. package/src/lib/utils.js +14 -1
  159. package/src/lib/utils.js.map +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,100 @@
1
1
  # @ethlete/cli
2
2
 
3
+ ## 2.1.0-next.10
4
+
5
+ ### Patch Changes
6
+
7
+ - A design call now lists its drawings as `variants` in `variant-<key>.ts` files, and `et design check` takes `--variant`; the old `options` key and `--option` flag are gone.
8
+
9
+ ## 2.1.0-next.9
10
+
11
+ ### Minor Changes
12
+
13
+ - `et update` now writes the new range into every `package.json` in the repo, not only the root one, and refuses a dist tag that points at an older version than the repo is on.
14
+ - `et design [checkout]` serves the design page of any repository that keeps a `.ethlete/design`
15
+ folder, and `et design check` says why a call does not render.
16
+
17
+ ### Patch Changes
18
+
19
+ - `et release` now works with Changesets 3 and aborts when there are no pending changesets.
20
+ - `et design` now rules a drawing with its own Tailwind 4 pipeline, so a repository on Tailwind 3, or none at all, can hold design calls.
21
+ - `et design check --call` now reports `NO BROWSER` when neither the checkout nor the package
22
+ resolves `playwright`, instead of throwing the module loader's own error.
23
+
24
+ ## 2.1.0-next.8
25
+
26
+ ### Minor Changes
27
+
28
+ - [#3075](https://github.com/ethlete-io/ethdk/pull/3075) [`004c32d`](https://github.com/ethlete-io/ethdk/commit/004c32d0ada3d7862947843dd6e8b204876160fe) Thanks [@github-actions](https://github.com/apps/github-actions)! - `doctorCommand` accepts an optional `composeTools` override for the container-engine check.
29
+
30
+ - [#3075](https://github.com/ethlete-io/ethdk/pull/3075) [`1d38e7e`](https://github.com/ethlete-io/ethdk/commit/1d38e7e0a025769f065d8ca7d506cb75ad89139a) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et update` moves the `@ethlete/*` packages to a newer version, runs the codemods those versions
31
+ declare in their own `migrations.json`, and reports what needs a decision or an agent.
32
+
33
+ ## 2.1.0-next.7
34
+
35
+ ### Patch Changes
36
+
37
+ - [#3074](https://github.com/ethlete-io/ethdk/pull/3074) [`63a528a`](https://github.com/ethlete-io/ethdk/commit/63a528a0ab1b1e7163e71c1cf5f65415bdda32d9) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et auth` now takes a host written as a url, and asks before it replaces a token `auth.json`
38
+ already holds for that host.
39
+
40
+ ## 2.1.0-next.6
41
+
42
+ ### Minor Changes
43
+
44
+ - [`a1c489e`](https://github.com/ethlete-io/ethdk/commit/a1c489e0a1da4b479fd6e47743dec4c1bad0152f) Thanks [@TomTomB](https://github.com/TomTomB)! - `et api up` now refuses a port another program holds and prints a per-service state table instead of
45
+ the engine's output. New `et api clear` removes a managed checkout, and offers to take its containers down first.
46
+
47
+ - [`12dcd51`](https://github.com/ethlete-io/ethdk/commit/12dcd5118ca8d2089cc3e9379efe4e9d0502a0f6) Thanks [@TomTomB](https://github.com/TomTomB)! - Every `et api` command now takes a comma-separated list of names, so `et api up hub,platform` starts
48
+ both APIs.
49
+
50
+ - [`0e060b2`](https://github.com/ethlete-io/ethdk/commit/0e060b28436e9444726a35a93264a046242e348e) Thanks [@TomTomB](https://github.com/TomTomB)! - `et api help <name>` now answers for one API: the commands it accepts, what each one runs, its url
51
+ and services, and the state of its checkout. `--help` after a known API name prints the same text.
52
+
53
+ - [`0e060b2`](https://github.com/ethlete-io/ethdk/commit/0e060b28436e9444726a35a93264a046242e348e) Thanks [@TomTomB](https://github.com/TomTomB)! - `et api` now runs an API's `setupCommand` itself: `et api setup <name>` on its own, or as an offer
54
+ when a command finds the `envFile` missing. `--setup` accepts that offer without the question.
55
+
56
+ - [`c3dd7c3`](https://github.com/ethlete-io/ethdk/commit/c3dd7c3d7e0e2a060e081c7fe820f9774537418b) Thanks [@TomTomB](https://github.com/TomTomB)! - `et auth <token>` writes a GitLab token into composer's `auth.json`, which the API containers mount. It asks the host whether the token can download code before it writes anything.
57
+
58
+ ### Patch Changes
59
+
60
+ - [`0e060b2`](https://github.com/ethlete-io/ethdk/commit/0e060b28436e9444726a35a93264a046242e348e) Thanks [@TomTomB](https://github.com/TomTomB)! - An unknown API name in `et api` now names the closest match and the APIs there are, in place of the
61
+ whole help text. An unknown command suggests the closest command the same way.
62
+
63
+ - [`c3dd7c3`](https://github.com/ethlete-io/ethdk/commit/c3dd7c3d7e0e2a060e081c7fe820f9774537418b) Thanks [@TomTomB](https://github.com/TomTomB)! - A failing `et api` exec command no longer always blames a private dependency. That hint is kept for a command that installs dependencies; any other one suggests running the install command first.
64
+
65
+ - [`0e060b2`](https://github.com/ethlete-io/ethdk/commit/0e060b28436e9444726a35a93264a046242e348e) Thanks [@TomTomB](https://github.com/TomTomB)! - `et api setup` keeps the setup command's own output back and prints one line for the result. The output is only shown when the command fails, so a checkout's advice about its Makefile no longer competes with the CLI.
66
+
67
+ - [`0e060b2`](https://github.com/ethlete-io/ethdk/commit/0e060b28436e9444726a35a93264a046242e348e) Thanks [@TomTomB](https://github.com/TomTomB)! - Every `et` message now names a command the reader can type, for example `yarn api` or `npx et api`,
68
+ in place of a bare `et`. `et doctor` names the `et api` command that fixes each problem.
69
+
70
+ ## 2.1.0-next.5
71
+
72
+ ### Minor Changes
73
+
74
+ - [`612d735`](https://github.com/ethlete-io/ethdk/commit/612d73563e1689bbfcf948d26ebe7c59d2420781) Thanks [@TomTomB](https://github.com/TomTomB)! - `et api` now clones a missing API checkout from a `repoUrl` in `ethlete.apis.js`, making
75
+ `apiRepoPaths` optional. `runApiCommand` is async as a result.
76
+
77
+ - [#3072](https://github.com/ethlete-io/ethdk/pull/3072) [`4bbbb51`](https://github.com/ethlete-io/ethdk/commit/4bbbb5167989a1c3ef2ffeba09fcfd18ba953fba) Thanks [@github-actions](https://github.com/apps/github-actions)! - Add `et doctor` to check this machine's config, container engine and API checkouts, `et api
78
+ checkout` and `et api pull` (with `--force`) to move an API checkout to the branch it should be on,
79
+ and `et api --help`.
80
+
81
+ ### Patch Changes
82
+
83
+ - [#3072](https://github.com/ethlete-io/ethdk/pull/3072) [`0fd8ba3`](https://github.com/ethlete-io/ethdk/commit/0fd8ba3dd61cc78409c397c8180f0a675282642f) Thanks [@github-actions](https://github.com/apps/github-actions)! - `et doctor` now says when a directory has neither config file rather than reporting no problems.
84
+
85
+ ## 2.1.0-next.4
86
+
87
+ ### Minor Changes
88
+
89
+ - [`b6fe4be`](https://github.com/ethlete-io/ethdk/commit/b6fe4beae010aaa2e0e367d636f6759442983395) Thanks [@TomTomB](https://github.com/TomTomB)! - Add `et api` to run an app's backend from a local checkout, declared in `ethlete.apis.js`. The new
90
+ `ethlete.config.local.json` says where the sibling checkouts on this machine live.
91
+
92
+ ## 2.1.0-next.3
93
+
94
+ ### Minor Changes
95
+
96
+ - [`edea44b`](https://github.com/ethlete-io/ethdk/commit/edea44bf1c494420f02b545202f4b24db9a6395c) Thanks [@TomTomB](https://github.com/TomTomB)! - Update to angular 22
97
+
3
98
  ## 2.0.1-next.2
4
99
 
5
100
  ### Patch Changes
package/README.md CHANGED
@@ -1,11 +1,178 @@
1
- # cli
1
+ # @ethlete/cli
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ Repo tooling - installs the `et` binary.
4
4
 
5
- ## Building
5
+ ## Installation
6
6
 
7
- Run `nx build cli` to build the library.
7
+ ```bash
8
+ yarn add --dev @ethlete/cli
9
+ ```
8
10
 
9
- ## Running unit tests
11
+ ## `et release`
10
12
 
11
- Run `nx test cli` to execute the unit tests via [Jest](https://jestjs.io).
13
+ ```bash
14
+ yarn et release
15
+ ```
16
+
17
+ Turns pending changesets into a tagged, pushed release commit (version → tag → commit → push).
18
+
19
+ ## `et auth`
20
+
21
+ Writes a GitLab token into composer's `auth.json`, so a private PHP dependency can be downloaded.
22
+ The compose file of each API mounts `$HOME/.composer` into its container, so this is the token the
23
+ composer inside the container reads.
24
+
25
+ ```bash
26
+ yarn et auth glpat-xxxxxxxxxxxxxxxxxxxx # the host comes from ethlete.apis.js
27
+ yarn et auth gitlab.example.com glpat-xxxxxxxxxxxxxxxxxxxx # name it when more than one is in use
28
+ ```
29
+
30
+ The host may be written as a url. Only its host name is used.
31
+
32
+ The token is checked against the host first: once for the token itself, and once with the request
33
+ `git clone` makes for a private dependency. A token that can read the API but not fetch code answers
34
+ `403` there, and nothing is written. A token the file already holds for that host is replaced only
35
+ after a question. `--force` skips both.
36
+
37
+ ## `et update`
38
+
39
+ Moves this repo's `@ethlete/*` dependencies to a newer version and runs the migrations those versions
40
+ ship.
41
+
42
+ ```bash
43
+ yarn et update --check # what would change; exits 1 while an update is pending
44
+ yarn et update # bump, install, run the codemods, report the rest
45
+ yarn et update core # only @ethlete/core
46
+ yarn et update --tag latest # leave the prerelease line
47
+ yarn et update core --to 5.0.0-next.55 # an exact version for the package you name
48
+ yarn et update --continue # finish a run that stopped
49
+ yarn et update --ai # hand every agent-assisted task to an agent
50
+ ```
51
+
52
+ The target follows the dist tag the installed version is on, so a repo on a `-next` prerelease stays
53
+ on `next`. The working tree must be clean, because the codemods rewrite files; `--force` skips that
54
+ check.
55
+
56
+ The install runs before the migrations are read, because the migrations of a version ship inside that
57
+ version. A run that stops leaves `.ethlete/update/pending.json` behind, and `--continue` picks it up -
58
+ starting over would skip every migration the stopped run had not reached.
59
+
60
+ Everything a codemod cannot decide is written to `.ethlete/update`: `tasks.md` for you, `tasks.json`
61
+ for an agent, and one file per task holding the instructions the package ships. A task is `manual` (it
62
+ needs a decision), `assisted` (written as a prompt for an agent) or `unsupported` (a codemod this repo
63
+ has no Nx to run, with the command to run it by hand).
64
+
65
+ `--ai` hands each assisted task to the command in `updateAgentCommand` in
66
+ `ethlete.config.local.json`, one run per task. No agent is detected automatically.
67
+
68
+ A package declares its migrations in `migrations.json` at its own root, pointed at from `package.json`
69
+ with `"ethlete": { "migrations": "./migrations.json" }`. The full format is on the docs site.
70
+
71
+ ## `et api`
72
+
73
+ Runs the API an app in this repo talks to, from a checkout on your own machine.
74
+
75
+ ```bash
76
+ yarn et api --help # the commands, the APIs and what each one accepts
77
+ yarn et api help hub # what hub accepts, and where its checkout is
78
+ yarn et api up hub # start the containers
79
+ yarn et api up hub,platform # the same, for both APIs
80
+ yarn et api down hub # stop them
81
+ yarn et api logs hub # follow the API's log
82
+ yarn et api shell hub # a shell in the API container
83
+ yarn et api install hub # an entry from that API's own "exec" map
84
+ yarn et api up hub --host # also print the address other devices can reach
85
+ yarn et api checkout hub # switch the checkout to the branch apiRepoBranches names
86
+ yarn et api pull hub # fetch and fast-forward the checked-out branch
87
+ yarn et api pull hub --force # the same, discarding local commits and tracked changes
88
+ yarn et api clone hub # clone the API into .ethlete/hub
89
+ yarn et api clear hub # remove that clone again
90
+ yarn et api clear --all # remove every managed clone
91
+ yarn et api setup hub # run the API's own setupCommand, which writes its .env
92
+ ```
93
+
94
+ Every command takes a comma-separated list of names, and acts on each API in turn.
95
+
96
+ `clone`, `checkout`, `pull`, `setup` and `clear` act on the checkout itself, so they work before the
97
+ API has an `.env` and need no container engine. `pull` refuses to run on a checkout with uncommitted
98
+ changes unless you pass `--force`. `--force` resets the branch to its remote and throws away local
99
+ commits and tracked changes; it never touches untracked or ignored files, so a `vendor/` directory or
100
+ a `.env` survives.
101
+
102
+ `clear` removes a managed checkout in `.ethlete/<name>`, and only that one: a path you set in
103
+ `apiRepoPaths` is your own. It asks one question for every API you named, takes their containers down
104
+ first, and refuses a checkout that holds uncommitted changes or commits no remote holds. `--force`
105
+ skips those two git checks.
106
+
107
+ Before it starts anything, `up` reads the host ports the requested services publish and checks
108
+ whether something already holds them. In a terminal it offers to stop the containers that hold them.
109
+ `--force` skips the check and lets the engine report the conflict itself.
110
+
111
+ The first container tool that answers is used, in this order: `docker compose`,
112
+ `container compose`, `podman-compose`, `podman compose`.
113
+
114
+ ## `et doctor`
115
+
116
+ ```bash
117
+ yarn et doctor
118
+ ```
119
+
120
+ Checks `ethlete.config.local.json`, reports the container engine it would use, and resolves every
121
+ API declared in `ethlete.apis.js`. It exits non-zero when it finds a problem, so CI can run it.
122
+
123
+ ### Declaring the APIs
124
+
125
+ `ethlete.apis.js` at the repo root describes each API's compose setup. It is a module rather
126
+ than JSON because `env` is a function:
127
+
128
+ ```js
129
+ const { sshKeyPath } = require('@ethlete/cli');
130
+
131
+ module.exports = {
132
+ hub: {
133
+ composeDir: 'development',
134
+ services: ['app', 'database', 'mailhog'],
135
+ execService: 'app',
136
+ port: 8040,
137
+ envFile: '.env',
138
+ setupCommand: 'make setup',
139
+ network: 'shared-fut',
140
+ envKey: 'hubApiEnv',
141
+ examplePath: '../fut-hub-backend',
142
+ env: () => ({ SSH_PRIVATE_KEY: sshKeyPath() }),
143
+ exec: {
144
+ install: ['composer', 'install'],
145
+ 'reset-db': ['make', 'reset-db-with-dev-fixtures'],
146
+ },
147
+ },
148
+ };
149
+ ```
150
+
151
+ Adding an API is an entry in this map. Nothing else changes.
152
+
153
+ ### Where the checkouts live
154
+
155
+ Give an API a `repoUrl` and `et api` clones it into a gitignored `.ethlete/<name>` when you have no
156
+ checkout of your own, asking first (or use `--clone`). To point at a checkout you already have - which
157
+ you want whenever you work in the backend, since compose mounts it into the container - set
158
+ `apiRepoPaths` in a gitignored `ethlete.config.local.json` at the repo root. `@ethlete/agent-rules` reads the same file, so its skills and `et` agree on where a
159
+ checkout is:
160
+
161
+ ```json
162
+ {
163
+ "sdkSourcePath": "/absolute/path/to/ethlete-sdk",
164
+ "apiRepoPaths": { "hub": "../fut-hub-backend", "*": "../shared-backend" },
165
+ "apiRepoBranches": { "hub": "develop", "*": "main" }
166
+ }
167
+ ```
168
+
169
+ Matching is exact; `"*"` is an explicit shared fallback. A relative path resolves from the repo
170
+ root. These keys used to live in `ethlete-agents.config.local.json`, which is still read as a
171
+ fallback with a warning. Add `ethlete.config.local.json` to your `.gitignore`.
172
+
173
+ ## Documentation
174
+
175
+ Full command reference on the docs site:
176
+
177
+ - [Overview & usage](https://ethlete-sdk-docs.web.app/cli/)
178
+ - [Updating the SDK](https://ethlete-sdk-docs.web.app/cli/update)
@@ -0,0 +1,92 @@
1
+ /**
2
+ * A value inside a template. An array joins with nothing between, and `null`, `undefined` and
3
+ * `false` write nothing, so `${rows.map(row)}` and `${isOn && html`…`}` both read as they look.
4
+ */
5
+ const flatten = (value: unknown): string => {
6
+ if (Array.isArray(value)) return value.map(flatten).join('');
7
+ if (value === null || value === undefined || value === false) return '';
8
+
9
+ return String(value);
10
+ };
11
+
12
+ const join = (strings: TemplateStringsArray, values: unknown[]) =>
13
+ strings.reduce((out, part, index) => out + flatten(values[index - 1]) + part);
14
+
15
+ /**
16
+ * Marks a template literal as HTML, so Prettier formats it and an editor highlights it. It escapes
17
+ * nothing: a drawing writes its own markup, and nothing a call draws comes from outside the
18
+ * repository.
19
+ */
20
+ export const html = (strings: TemplateStringsArray, ...values: unknown[]) => join(strings, values);
21
+
22
+ /** Marks a template literal as CSS, for the same reason `html` does it for markup. */
23
+ export const css = (strings: TemplateStringsArray, ...values: unknown[]) => join(strings, values);
24
+
25
+ /**
26
+ * One drawn answer, as the frame renders it: the markup that goes in the frame root, and the CSS
27
+ * that styles it. A drawing runs no logic, so it is a value the module builds when the frame
28
+ * imports it, not a component the frame has to instantiate.
29
+ */
30
+ export type Drawing = {
31
+ body: string;
32
+ styles: string;
33
+ };
34
+
35
+ /** Types a drawing where it is written, so a mistake reads in its own file and not in `call.ts`. */
36
+ export const drawing = (drawn: Drawing): Drawing => drawn;
37
+
38
+ /**
39
+ * One drawn answer to a call. `load` resolves the module whose default export is the
40
+ * drawing that answers it, so a broken variant breaks its own frame only.
41
+ */
42
+ export type CallVariant = {
43
+ key: string;
44
+ name: string;
45
+ /** Left out by a view: a single drawing answers no question, so it argues nothing. */
46
+ claim?: string;
47
+ cost?: string;
48
+ /** Left out while the call is open. The user sets it, never the drawing. */
49
+ verdict?: 'chosen' | 'rejected';
50
+ /** The `key` of the round that drew it. Left out by a call that runs no rounds. */
51
+ round?: string;
52
+ load: () => Promise<{ default: Drawing }>;
53
+ };
54
+
55
+ /**
56
+ * One pass over a call: the variants drawn together, and what came out of them. A round
57
+ * whose variants all carry a verdict is settled, and the page folds it down to its winner.
58
+ */
59
+ export type CallRound = {
60
+ key: string;
61
+ /** What this pass asked, in a few words. */
62
+ title: string;
63
+ /** What it answered. Write it once the user has ruled, so the next round reads as a reply. */
64
+ note: string;
65
+ };
66
+
67
+ /**
68
+ * How a call is drawn. A wireframe shows the bare workflow with mocked values, and draws no
69
+ * logic and no interaction state. A design call draws the real thing.
70
+ */
71
+ export type CallMode = 'wireframe' | 'design';
72
+
73
+ /**
74
+ * One open question of an exploration, with every variant drawn at the same geometry.
75
+ * A call with one variant and no claim is a view: one reference picture, drawn full width.
76
+ */
77
+ export type Call = {
78
+ /** The feature this call belongs to, for example 'the hour strip'. Left out by a loose call. */
79
+ feature?: string;
80
+ eyebrow: string;
81
+ headline: string;
82
+ intro: string;
83
+ /** The width every variant frame gets, in px. The geometry the thing ships in. */
84
+ frameWidth: number;
85
+ /** Left out by a call that draws the real thing, which is what `design` means. */
86
+ mode?: CallMode;
87
+ /** Left out by a short call. With rounds, the intro says only what the call is about. */
88
+ rounds?: CallRound[];
89
+ variants: CallVariant[];
90
+ };
91
+
92
+ export const defineCall = (call: Call): Call => call;
@@ -0,0 +1,11 @@
1
+ declare module 'virtual:design-explore' {
2
+ import type { Call } from '@design-explore';
3
+
4
+ export const calls: Record<string, () => Promise<{ default: Call }>>;
5
+ export const defaultCall: string | null;
6
+ }
7
+
8
+ declare module 'virtual:design-explore/env' {
9
+ /** Loads the stylesheet the project draws under. A project the config names not draws bare. */
10
+ export const loadEnv: (project: string) => Promise<unknown>;
11
+ }
@@ -0,0 +1,17 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <!--head-->
6
+ <style>
7
+ html,
8
+ body {
9
+ margin: 0;
10
+ }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ <script type="module" src="./frame.ts"></script>
16
+ </body>
17
+ </html>
@@ -0,0 +1,38 @@
1
+ import { calls } from 'virtual:design-explore';
2
+ import { loadEnv } from 'virtual:design-explore/env';
3
+
4
+ const params = new URLSearchParams(location.search);
5
+ const slug = params.get('call') ?? '';
6
+ const key = params.get('variant') ?? '';
7
+
8
+ await loadEnv(slug.split('/')[0] ?? '');
9
+
10
+ const root = document.querySelector('#root') as HTMLElement;
11
+
12
+ const fail = (message: string) => {
13
+ root.textContent = message;
14
+ root.setAttribute('style', 'padding:16px;font:14px monospace;color:#f0a0a0;background:#1a1414');
15
+ };
16
+
17
+ const call = calls[slug];
18
+ if (!call) fail(`design-explore: no call "${slug}"`);
19
+ else {
20
+ const variant = (await call()).default.variants.find((o) => o.key === key);
21
+ if (!variant) fail(`design-explore: call "${slug}" has no variant "${key}"`);
22
+ else {
23
+ const loaded = (await variant.load()).default;
24
+ const style = document.createElement('style');
25
+
26
+ style.textContent = loaded.styles;
27
+ document.head.append(style);
28
+ root.innerHTML = loaded.body;
29
+ }
30
+ }
31
+
32
+ const report = () => {
33
+ const height = Math.ceil(document.documentElement.getBoundingClientRect().height);
34
+ parent.postMessage({ type: 'design-explore:height', variant: key, height }, '*');
35
+ };
36
+
37
+ new ResizeObserver(report).observe(document.documentElement);
38
+ report();