@miakapp/cli 4.0.0-alpha.0 → 4.0.0-alpha.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 (63) hide show
  1. package/README.md +151 -35
  2. package/assets/agent-guide.md +232 -79
  3. package/assets/design/OFL-Manrope.txt +93 -0
  4. package/assets/design/components.css +139 -0
  5. package/assets/design/fonts.css +9 -0
  6. package/assets/design/gallery.html +667 -0
  7. package/assets/design/guide.md +77 -0
  8. package/assets/design/tokens.css +185 -0
  9. package/assets/starter/app/app/README.md +74 -0
  10. package/assets/starter/app/app/main.ts +124 -0
  11. package/assets/starter/app/app/miakapp.ts +156 -0
  12. package/assets/starter/app/app/theme.ts +8 -0
  13. package/assets/starter/app/tsconfig.json +23 -0
  14. package/bin/miakapp.js +5 -1
  15. package/dist/agent-pack.d.ts +11 -3
  16. package/dist/agent-pack.d.ts.map +1 -1
  17. package/dist/agent-pack.js +26 -10
  18. package/dist/agent-pack.js.map +1 -1
  19. package/dist/contexts.d.ts +59 -0
  20. package/dist/contexts.d.ts.map +1 -0
  21. package/dist/contexts.js +388 -0
  22. package/dist/contexts.js.map +1 -0
  23. package/dist/control-plane.d.ts +14 -0
  24. package/dist/control-plane.d.ts.map +1 -1
  25. package/dist/control-plane.js +33 -1
  26. package/dist/control-plane.js.map +1 -1
  27. package/dist/internal/names.d.ts +5 -0
  28. package/dist/internal/names.d.ts.map +1 -1
  29. package/dist/internal/names.js +6 -0
  30. package/dist/internal/names.js.map +1 -1
  31. package/dist/main.d.ts +22 -5
  32. package/dist/main.d.ts.map +1 -1
  33. package/dist/main.js +673 -60
  34. package/dist/main.js.map +1 -1
  35. package/dist/mcp.d.ts +7 -1
  36. package/dist/mcp.d.ts.map +1 -1
  37. package/dist/mcp.js +195 -26
  38. package/dist/mcp.js.map +1 -1
  39. package/dist/pairing.d.ts +27 -0
  40. package/dist/pairing.d.ts.map +1 -0
  41. package/dist/pairing.js +148 -0
  42. package/dist/pairing.js.map +1 -0
  43. package/dist/project.d.ts +3 -1
  44. package/dist/project.d.ts.map +1 -1
  45. package/dist/project.js +33 -6
  46. package/dist/project.js.map +1 -1
  47. package/dist/publication.d.ts +20 -5
  48. package/dist/publication.d.ts.map +1 -1
  49. package/dist/publication.js +58 -16
  50. package/dist/publication.js.map +1 -1
  51. package/dist/starter.d.ts +17 -0
  52. package/dist/starter.d.ts.map +1 -0
  53. package/dist/starter.js +72 -0
  54. package/dist/starter.js.map +1 -0
  55. package/dist/terminal.d.ts +10 -0
  56. package/dist/terminal.d.ts.map +1 -0
  57. package/dist/terminal.js +70 -0
  58. package/dist/terminal.js.map +1 -0
  59. package/dist/version.d.ts +15 -0
  60. package/dist/version.d.ts.map +1 -0
  61. package/dist/version.js +15 -0
  62. package/dist/version.js.map +1 -0
  63. package/package.json +6 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @miakapp/cli
2
2
 
3
- Build, validate, publish and roll back one Miakapp home component.
3
+ Pair, build, validate, publish and roll back independent Miakapp house applications.
4
4
 
5
5
  The CLI is the deployment mechanism, not the source of truth. **Git belongs to
6
6
  you**: this tool never commits, never rewrites sources it did not generate and
@@ -12,11 +12,60 @@ stable exit code and one stable failure kind, and `--json` prints exactly one
12
12
  object on stdout.
13
13
 
14
14
  ```bash
15
- bunx @miakapp/cli init --home my-home --control-plane https://control.miakapp.app
16
- bunx @miakapp/cli check
17
- bunx @miakapp/cli publish --expected-generation 0
15
+ printf '%s\n' "$CODE" | bunx @miakapp/cli pair --issuer "$MIAKAPP_ISSUER"
16
+ bunx @miakapp/cli init --starter app # manifest + app to edit; home and issuer from the context
17
+ bun run build && bun run check # after the inventory and adapting app/main.ts
18
+ bunx @miakapp/cli publish
19
+ bunx @miakapp/cli status # verify what is live
18
20
  ```
19
21
 
22
+ Use the exact issuer command shown by your deployment's `/pair` page; do not
23
+ guess a staging issuer. Open and verify the returned `home_url` as a resident
24
+ before handing it over.
25
+
26
+ ## The app starter
27
+
28
+ `miakapp init --starter app` writes, beside `miakapp.yaml`, everything needed to
29
+ build a whole-house application with nothing but this package and Bun:
30
+
31
+ | File | |
32
+ | --- | --- |
33
+ | `app/main.ts` | the interface to edit: shows what the home shares, grouped, with stale and empty states |
34
+ | `app/miakapp.ts` | the bridge to `window.miakapp` — byte for byte the `@miakapp/app` SDK source, which is not on npm yet |
35
+ | `app/theme.ts` | Miakapp design tokens, themes (Minuit in dark mode, Lumière in light) and recipes, with Manrope embedded |
36
+ | `package.json` | `build` (Bun IIFE to the manifest's artifact), `typecheck`, `check`; pins this CLI and TypeScript |
37
+ | `tsconfig.json` | strict TypeScript for `app/` |
38
+ | `app/README.md` | the loop, the prerequisites and what to do before publishing |
39
+
40
+ Prerequisites: Node.js ≥ 22.9 for the CLI, Bun ≥ 1.2.23 for `bun run build`
41
+ (TypeScript, from `bun install`, only for `typecheck`). The starter accepts
42
+ `--artifact` (a plain relative `.js` path), `--release`, `--home`,
43
+ `--control-plane` and `--context`; it cannot be combined with
44
+ `--kind component`.
45
+
46
+ It never overwrites anything: every target is checked first, and if any one
47
+ exists the command fails with exit 2 and writes nothing. Without `--starter`,
48
+ `init` writes `miakapp.yaml` alone, as before.
49
+
50
+ The starter invents no value and offers no control. `app.requires` starts
51
+ empty, so a fresh build shows only an empty state: inventory the house, declare
52
+ the paths and calls, give them resident-facing names and a real layout, then
53
+ publish.
54
+
55
+ ## Design
56
+
57
+ `miakapp docs design` prints a short design guide and the directory of the
58
+ files it describes: `tokens.css` (four themes: Minuit, Lumière, Miel, Craie),
59
+ `components.css` (glass, device tile, scene, switch, level slider, stale
60
+ banner), `fonts.css` (Manrope as a `data:` URL, since the frame has no network)
61
+ and `gallery.html`, example screens to open in a browser. They are a starting
62
+ point, not a framework: copy, change or ignore them.
63
+
64
+ Maintainers: the generated files (`fonts.css`, `gallery.html`, the starter's
65
+ `app/theme.ts`) come from `packages/cli/design/`; run `bun design/build.ts` in
66
+ `packages/cli` after editing `tokens.css`, `components.css` or the gallery
67
+ template. A test fails when they drift.
68
+
20
69
  ## The project file
21
70
 
22
71
  `miakapp.yaml` sits at the root of your repository:
@@ -24,24 +73,25 @@ bunx @miakapp/cli publish --expected-generation 0
24
73
  ```yaml
25
74
  schema: miakapp.project/1
26
75
  home: my-home
27
- control_plane: https://control.miakapp.app
76
+ control_plane: https://control.example.test
28
77
 
29
- component:
30
- artifact: dist/component.js
31
- release: 2026-09-13.1
78
+ app:
79
+ artifact: dist/app.js
80
+ release: 2026-10-03.1
32
81
  requires:
33
82
  state_read:
34
83
  - climate.living_room.temperature
35
- event_subscribe: []
36
- event_publish: []
37
84
  call:
38
85
  - lighting.set
39
- presentation: []
40
86
 
41
87
  coordinator:
42
88
  entry: coordinator/main.ts
43
89
  ```
44
90
 
91
+ `app` declares only `state_read` and `call`; events, media and reserved
92
+ `miakapp.*` calls are unavailable. Use `miakapp init --kind component` for the
93
+ semantic component ABI instead. Choose exactly one of `app` and `component`.
94
+
45
95
  `requires` is the closed RFC 0002 capability object. Lists are de-duplicated and
46
96
  sorted before they are bound into an upload capability, so the value the CLI
47
97
  sends is byte-identical on every later reconciliation read.
@@ -55,10 +105,13 @@ duplicate keys — is rejected with the offending line rather than guessed at.
55
105
 
56
106
  | Command | What it does |
57
107
  | --- | --- |
58
- | `init` | Writes `miakapp.yaml`. Never overwrites an existing one. |
108
+ | `pair` | Redeems a one-time pairing code into a new stored context. |
109
+ | `context list\|show\|use\|remove` | Manages stored contexts. Never prints a key. |
110
+ | `init` | Writes `miakapp.yaml`; with `--starter app`, also a buildable app. Never overwrites. |
59
111
  | `agent-pack` | Offline. Installs the guide and the MCP wiring into a repository. |
60
112
  | `discover` | Offline. Inventories a Node-RED installation from its flows export. |
61
113
  | `check` | Offline. Parses the project, verifies the artifact, prints the digest. |
114
+ | `status` | Reads the live generation, release and digest of the home. |
62
115
  | `publish` | Capability → delivery → finalization → activation, in one run. |
63
116
  | `activate` | Activates an already finalized digest at a new generation. |
64
117
  | `rollback` | Alias of `activate`, for returning to a known-good digest. |
@@ -111,9 +164,9 @@ place instead of appending another copy. `.mcp.json` is merged as a structure
111
164
  one key, by name — so every other server in it survives, and a file that does
112
165
  not parse is refused rather than replaced with a valid one.
113
166
 
114
- The server is registered as the bare `miakapp` command rather than an absolute
115
- path, because the file is committed and the next machine to check it out will
116
- not have this one's directory layout.
167
+ The generated server entry uses `npx -y @miakapp/cli@<installed-version> mcp`,
168
+ so a new machine gets the same executable as the bundled guide without relying
169
+ on a global binary or this machine's directory layout.
117
170
 
118
171
  Run it again whenever the CLI is upgraded: an unchanged file is reported
119
172
  `unchanged`, and a guide that moved on is reported `updated`.
@@ -129,8 +182,7 @@ tools over newline-delimited JSON-RPC on stdio.
129
182
  "mcpServers": {
130
183
  "miakapp": {
131
184
  "command": "bunx",
132
- "args": ["@miakapp/cli", "mcp"],
133
- "env": { "MIAKAPP_HOME_KEY": "${MIAKAPP_HOME_KEY}" }
185
+ "args": ["@miakapp/cli", "mcp"]
134
186
  }
135
187
  }
136
188
  }
@@ -138,11 +190,17 @@ tools over newline-delimited JSON-RPC on stdio.
138
190
 
139
191
  | Tool | Command | |
140
192
  | --- | --- | --- |
193
+ | `miakapp_pair` | `pair` | stores a new context; the code is a tool argument |
194
+ | `miakapp_context_list` | `context list` | read-only, offline |
195
+ | `miakapp_context_show` | `context show` | read-only, offline |
196
+ | `miakapp_context_use` | `context use` | offline, changes the current context |
197
+ | `miakapp_context_remove` | `context remove` | **deletes a stored key — needs `confirm: true`** |
198
+ | `miakapp_status` | `status` | read-only |
141
199
  | `miakapp_discover` | `discover` | read-only, offline |
142
200
  | `miakapp_check` | `check` | read-only, offline |
143
201
  | `miakapp_release` | `release` | read-only |
144
202
  | `miakapp_upload` | `upload` | read-only |
145
- | `miakapp_init` | `init` | writes `miakapp.yaml`, never overwrites |
203
+ | `miakapp_init` | `init` | writes `miakapp.yaml` (and the app starter with `starter: "app"`), never overwrites |
146
204
  | `miakapp_agent_pack` | `agent-pack` | offline, writes the pack into a repository |
147
205
  | `miakapp_publish` | `publish` | **moves the pointer — needs `confirm: true`** |
148
206
  | `miakapp_activate` | `activate` | **moves the pointer — needs `confirm: true`** |
@@ -154,7 +212,8 @@ drift apart. A tool argument is the option name with `_` for `-`
154
212
  (`expected_generation` → `--expected-generation`); an argument the tool does not
155
213
  declare is refused rather than ignored.
156
214
 
157
- The three pointer-moving tools additionally require `confirm: true`. It is
215
+ The three pointer-moving tools and `miakapp_context_remove` additionally
216
+ require `confirm: true`. It is
158
217
  checked before anything else and never reaches the command line, so a model that
159
218
  hallucinated a publication spends the mistake on an argument check instead of on
160
219
  a generation.
@@ -165,20 +224,69 @@ remedy — not as a JSON-RPC error. That distinction matters: a protocol error
165
224
  means the call never happened, while a publication that reached the control
166
225
  plane and failed did happen, and only `kind` says whether to reconcile.
167
226
 
168
- ## Authorization
227
+ ## Access: pairing and contexts
228
+
229
+ The owner grants access in their own browser; the agent never signs in. They
230
+ open `https://miakapp.com/pair`, choose the home, confirm, and send the
231
+ one-time code, which `pair` trades for a **new, separately revocable** Home Key:
232
+
233
+ ```bash
234
+ printf '%s\n' "$CODE" | miakapp pair # or run it in a terminal: hidden prompt
235
+ miakapp pair --code "$CODE" # allowed, but lands in shell history
236
+ ```
237
+
238
+ | Option | Default |
239
+ | --- | --- |
240
+ | `--issuer <https url>` | `https://control.miakapp.com` |
241
+ | `--label <label>` | `miakapp-cli@<host name>`, shown in the owner's key list |
242
+ | `--name <context>` | the paired home ID (`-2`, `-3`… if taken) |
243
+
244
+ Before the code is sent, the issuer must serve a discovery document naming
245
+ exactly itself; redirects are refused. The redeem response —
246
+ `POST {issuer}/v1/pairing/redeem` with `{code, label}`, answered with
247
+ `{home_key, home_id, key_id, issuer}` and `Cache-Control: no-store` — must name
248
+ the same issuer and a key whose ID is embedded in the key. The code is sent
249
+ once and never retried: a lost response is exit 7, because a key may exist.
250
+ `pair` then exchanges the key for a publication token, reported as
251
+ `publish_access`, so a key without the publish scope is caught now rather than
252
+ at the first publication.
253
+
254
+ Contexts live in `~/.miakapp` (or `$MIAKAPP_CONFIG_DIR`, absolute):
255
+
256
+ | File | Holds | Mode |
257
+ | --- | --- | --- |
258
+ | `config.json` | context names, home IDs, issuers, key IDs, labels, current context | 0600 |
259
+ | `credentials.json` | the Home Keys, nothing else | 0600 |
169
260
 
170
- The Home Key is read from `MIAKAPP_HOME_KEY` and from nowhere else. No command
171
- accepts it as an argument, because an argument lands in shell history, in a
172
- process listing and in most CI logs.
261
+ The directory is 0700. Both files are replaced through a temporary file, an
262
+ fsync and a rename, under a lock file, so concurrent runs never lose a context
263
+ and a crash never leaves half a file. A credentials file readable by another
264
+ account, a symbolic link, a foreign owner or a key that is not the one the
265
+ context was paired with is refused rather than used.
173
266
 
174
267
  ```bash
175
- export MIAKAPP_HOME_KEY="$(op read op://home/miakapp/home-key)" # or your own vault
176
- bunx @miakapp/cli publish --expected-generation 4
268
+ miakapp context list
269
+ miakapp context show [name] # credential: stored (never printed)
270
+ miakapp context use <name>
271
+ miakapp context remove <name> # local only: the owner revokes the key server-side
177
272
  ```
178
273
 
179
- The key is exchanged for a five-minute `components:publish` token before every
180
- run. Publication endpoints never accept the Home Key itself, and the CLI never
181
- prints either credential.
274
+ Which Home Key a command uses, highest precedence first:
275
+
276
+ 1. `--context <name>`, then `MIAKAPP_CONTEXT=<name>`;
277
+ 2. `MIAKAPP_HOME_KEY` — a raw key, kept for CI and compatibility;
278
+ 3. the stored context whose home and issuer match `miakapp.yaml`, the current
279
+ context breaking a tie between keys for that same home.
280
+
281
+ A selected context for another home — or a `MIAKAPP_HOME_KEY` this machine
282
+ knows was paired with another home — is refused before any request, so a key
283
+ can never publish into the wrong house. Every networked result reports
284
+ `credential_source` and `context`, never the key.
285
+
286
+ No command accepts a Home Key as an argument: an argument lands in shell
287
+ history, in a process listing and in most CI logs. The key is exchanged for a
288
+ five-minute `components:publish` token before every run, and publication
289
+ endpoints never see the Home Key itself.
182
290
 
183
291
  ## Generations
184
292
 
@@ -187,11 +295,11 @@ believe the pointer holds, and `--generation` (default: expected + 1) is the one
187
295
  you are publishing. A stale expectation fails with `generation_conflict` and
188
296
  exit code 6 rather than last-write-wins.
189
297
 
190
- `--expected-generation` is required rather than discovered, because RFC 0004
191
- §13.2 publishes no read for the current pointer: the pointer lives in
192
- `components/{homeID}` and reaches clients as authenticated platform data. Until
193
- that surface exists, the CLI asks you for the number instead of guessing one —
194
- inventing an endpoint would be worse than an explicit flag.
298
+ Without `--expected-generation`, `publish` and `activate` read the live pointer
299
+ first (`GET /v1/homes/{homeId}/component-pointer`, RFC 0004 §13.2) and use its
300
+ generation. That read takes no lock, so the activation is still a
301
+ compare-and-set: a publication that lands in between makes this one fail with
302
+ exit 6, never overwrites it. `miakapp status` prints the same read.
195
303
 
196
304
  ## Exit codes
197
305
 
@@ -213,14 +321,14 @@ committed, so the next step is a read — `miakapp upload <id>` or
213
321
  ## Failure output
214
322
 
215
323
  ```console
216
- $ miakapp publish --expected-generation 0
324
+ $ miakapp publish
217
325
  miakapp: conflict: Activation failed with HTTP 409 generation_conflict (request Zq1...)
218
326
  Another publication advanced the pointer. Read the active generation and retry
219
327
  the activation with the observed expected_generation.
220
328
  ```
221
329
 
222
330
  ```console
223
- $ miakapp publish --expected-generation 0 --json
331
+ $ miakapp publish --json
224
332
  {"ok":false,"kind":"conflict","exit_code":6,"message":"...","remedy":"..."}
225
333
  ```
226
334
 
@@ -228,3 +336,11 @@ $ miakapp publish --expected-generation 0 --json
228
336
 
229
337
  Alpha, tracking Miakapp 4. The package is `private` until the control plane it
230
338
  talks to is deployed; publishing it to npm is a deliberate, separate step.
339
+
340
+ ### Command help
341
+
342
+ Run `miakapp help` or append `--help` / `-h` to any command, including
343
+ `miakapp pair --help`. Help never prompts for a code or executes the command.
344
+ `miakapp init` defaults to a whole-house app at `dist/app.js`; add
345
+ `--starter app` for the buildable starter, or use `--kind component` for a
346
+ semantic component at `dist/component.js`.