@wix/himalaya-cli 0.1433.0 → 0.1435.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.
@@ -55,7 +55,7 @@ listed in `gaps[]`.
55
55
 
56
56
  | Mode | How | Stored where |
57
57
  |---|---|---|
58
- | Interactive | `himi base44 login` runs Base44's device sign-in. You approve a code in the browser, and only read access (`apps:read`) is asked for | `~/.himi/base44/session.json`, mode 0600 |
58
+ | Interactive | `himi base44 login` runs Base44's device sign-in. You approve a code in the browser, and only read access (`apps:read`) is asked for. `--write` also asks for `apps:write`, which only the provisioning verbs need ([base44-entities](base44-entities.md#provisioning-create-seed-deploy)) | `~/.himi/base44/session.json`, mode 0600 |
59
59
  | Reuse the Base44 CLI's session | `himi base44 login --from-base44-cli` imports what `npx base44 login` stored | the same file |
60
60
  | CI | `BASE44_ACCESS_TOKEN=<token>` in the environment | nowhere, it is read from the environment |
61
61
 
@@ -1,4 +1,4 @@
1
- # Base44 entities and functions (declare, lint, adopt, query)
1
+ # Base44 entities and functions (declare, lint, adopt, query, provision)
2
2
 
3
3
  A Himi app on [Base44](https://base44.com) names the entities and backend functions it depends on
4
4
  in `config.ts`. With that declaration, `himi validate` lints it, `himi base44 adopt` writes it from
@@ -8,8 +8,9 @@ This is the Base44 sibling of [`cms-collections`](cms-collections.md) (`himi doc
8
8
  It reuses the same ideas (owned versus adopted, an offline lint, a read-only drift report) but not
9
9
  the same block: Base44 field types, access rules and naming differ from Wix Data.
10
10
 
11
- > **Read-only in this release.** Nothing here writes to a Base44 app. Creating schemas, seeding
12
- > rows and deploying functions come next (see [Coming next](#coming-next)).
11
+ > **Writes are separate and deliberate.** `adopt`, `query` and the lint never write to a Base44
12
+ > app. Creating schemas, seeding rows and deploying functions are their own verbs. Each one prints
13
+ > a plan and writes only with `--yes` (see [Provisioning](#provisioning-create-seed-deploy)).
13
14
 
14
15
  ## The block
15
16
 
@@ -35,7 +36,7 @@ Each entity is one of two kinds:
35
36
 
36
37
  | Kind | Declared by | Physical entity | himi may |
37
38
  |---|---|---|---|
38
- | **Owned** | `name: "Note"` (alphanumeric) | `Himi<AppPascal>Note`. For app `todo` that is `HimiTodoNote`, and for `video-courses` it is `HimiVideoCoursesNote` | create, seed (coming next) |
39
+ | **Owned** | `name: "Note"` (alphanumeric) | `Himi<AppPascal>Note`. For app `todo` that is `HimiTodoNote`, and for `video-courses` it is `HimiVideoCoursesNote` | create, seed |
39
40
  | **Adopted** | `base44Name: "Customer"` | `Customer`, verbatim | read only |
40
41
 
41
42
  Base44 entity names are alphanumeric only, so the CMS `himi_<app>_` prefix cannot be used. The
@@ -140,10 +141,119 @@ makes is a `GET`.
140
141
 
141
142
  Failure codes are listed in [`himi-json-output`](himi-json-output.md#himi-base44-entities-codes).
142
143
 
144
+ ## Provisioning: create, seed, deploy
145
+
146
+ ```bash
147
+ himi base44 login --write # once: a session with apps:read apps:write
148
+ himi base44 entities create --app todo # the plan: create / update / unchanged / refused per entity
149
+ himi base44 entities create --app todo --yes # send it
150
+ himi base44 entities seed --app todo --yes # fill EMPTY owned entities
151
+ himi base44 functions deploy --app todo --yes # ship owned functions
152
+ ```
153
+
154
+ `--app <slug>` resolves to `apps/<slug>/`, and `--content <dir>` points anywhere. Without `--yes`
155
+ each verb makes only reads and sends no write.
156
+
157
+ **Base44's schema write is a destructive full-set sync.** `PUT /api/apps/<id>/entity-schemas`
158
+ with `{ entityNameToSchema }` **deletes every entity the body leaves out**, along with its rows.
159
+ Base44 has no read for schemas. So `entities create` downloads the live project (the same eject
160
+ read as `query`) and builds the body from every entity in it:
161
+
162
+ - Owned entities are built from `config.ts`.
163
+ - Every other entity is passed through as the exact schema object the download holds. It is never
164
+ rebuilt, renamed, changed or dropped.
165
+
166
+ A **live** entity counts as owned only if `base44-provisioned.json`, beside `config.ts`, records
167
+ that this app provisioned it. `entities create` keeps that file up to date. **Commit it** like a
168
+ lockfile, so every machine and CI agrees on what the app owns. A bare prefix is not enough on its
169
+ own. If app `todo` (`HimiTodo…`) declares `ListNote`, that names the entity app `todo-list` owns
170
+ as `Note` (`HimiTodoListNote`). So:
171
+
172
+ - A declared entity that already exists but is not in the file is refused with
173
+ `owned_entity_unclaimed`. If it really is this app's, record it in the file; otherwise rename the
174
+ declaration.
175
+ - An undeclared entity in the namespace that the file does not list is left untouched and listed
176
+ in `warnings`.
177
+ - When a sync's outcome is uncertain (a lost reply, a 5xx, a reply with no `deleted[]`),
178
+ `entities create` re-reads the app and records only the creates that are live, and keeps every
179
+ name the file already held. If that re-read fails too, nothing new is recorded, and the next run
180
+ refuses the entity with `owned_entity_unclaimed`, which you fix by recording it by hand.
181
+ - `entities seed` only writes entities the file lists.
182
+
183
+ If any entity file in the download fails to parse, or the source walk drops it (a symlink, a
184
+ denied name), the snapshot counts as unreadable. A sync without that file would delete the
185
+ entity.
186
+
187
+ ```mermaid
188
+ flowchart TD
189
+ A[entities create] --> Y{--yes?}
190
+ Y -- yes --> S{token has apps:write?}
191
+ S -- no --> R1[write_scope_missing<br/>no request]
192
+ S -- yes --> C
193
+ Y -- no --> C["GET …/eject → every live entity, verbatim"]
194
+ C -- failed --> R2[schema_snapshot_unavailable]
195
+ C -- no entities, no --empty-app-ok --> R3[schema_snapshot_empty]
196
+ C --> P["plan: foreign as-is + owned from config"]
197
+ P -- a foreign entity missing or altered --> R4[would_delete_foreign_entity]
198
+ P -- owned entity / field dropped, no --allow-destructive --> R5[owned_*_removal_needs_flag]
199
+ P -- no --yes --> D[print the plan, exit 0]
200
+ P -- --yes --> H[re-read the eject, re-plan]
201
+ H -- plan differs --> R6[snapshot_changed]
202
+ H -- same --> I["one PUT …/entity-schemas"]
203
+ I -- deleted[] names an entity the plan kept --> R7[foreign_entity_deleted]
204
+ I --> K[created / updated / unchanged]
205
+ ```
206
+
207
+ Every refusal except the last one happens before the `PUT`.
208
+
209
+ - `--allow-destructive` lets an **owned** entity or field be removed. It only reaches entities this
210
+ app provisioned, never another app's.
211
+ - `--apply-permissions` writes a changed owned `rls` (entity- or field-level). Without it the live
212
+ rules are kept and the difference is reported as `permissions` drift. A rule the declaration
213
+ does not state never clears a live one.
214
+ - `--empty-app-ok` accepts a download with no entities. An empty app cannot be told apart from a
215
+ failed read, so this has to be opted into.
216
+
217
+ Because this is a full-set sync, an entity added in the Base44 builder between the plan and the
218
+ `PUT` is caught by the re-read (`snapshot_changed`). Whether the eject download always reflects
219
+ builder edits that were never exported is not yet proven against a live app. Before the first
220
+ live `--yes`, check it on a throwaway app: add an entity in the builder and confirm `entities
221
+ create` lists it.
222
+
223
+ **`entities seed`** checks each owned entity with `GET …/entities/<E>?limit=1`:
224
+
225
+ - An empty entity gets one `POST …/entities/<E>/bulk` with its rows.
226
+ - An entity that already has rows is skipped with `skipped: "not-empty"`.
227
+ - An adopted entity is never read or written.
228
+
229
+ Rows from `base44-seed.json` take precedence over `config.ts` `seed`. Only declared keys are sent,
230
+ so a row cannot set `id` or `created_by`. `--ai` writes placeholder rows to `base44-seed.json`
231
+ offline and returns an `agentPrompt` for the agent to rewrite them, exactly like `himi cms seed
232
+ --ai`.
233
+
234
+ **`functions deploy`** reads each owned function from `base44/functions/<name>/`. The entry file is
235
+ `entry.ts` or `entry.js`, or the one `function.jsonc`'s `entry` names. The folder is read with
236
+ `himi push`'s own walk: symlinks are never followed, the deny-list applies, and the secret scan
237
+ runs. Anything those flag refuses the deploy with `function_source_unsafe`. Each function is sent
238
+ with
239
+ one `PUT …/backend-functions/<name>` and body `{ entry, files, automations? }`. It never uses the
240
+ bulk `PUT …/backend-functions`, which deletes the functions it omits, and never sends `DELETE`.
241
+
242
+ Owned functions keep their plain `name`, so every deploy adds a `.himi-owned` marker file naming
243
+ the app. A deployed function with a declared name that lacks this app's marker is refused with
244
+ `function_name_taken` and nothing is deployed. That covers a function built in the builder,
245
+ another himi app's function, or a listing that returns no files. A listing with no `functions`
246
+ array is refused outright and is never read as "nothing deployed".
247
+
248
+ **Scope.** The default `himi base44 login` stays `apps:read`, so the analyzer and `query` keep
249
+ least privilege. `--yes` on any of these verbs needs a token whose `scope` claim includes
250
+ `apps:write`. A token whose claims cannot be read (an opaque `BASE44_ACCESS_TOKEN`) is refused
251
+ rather than guessed.
252
+
253
+ Failure codes are listed in
254
+ [`himi-json-output`](himi-json-output.md#himi-base44-entities--functions-provisioning-codes).
255
+
143
256
  ## Coming next
144
257
 
145
- - **Provisioning**: `create`, `seed` and `functions deploy` for owned entities and functions. It
146
- consumes `diffEntityFields` and the `Base44QueryReport`. Base44's schema write is a destructive
147
- full-set sync, which is why it is a separate, deliberate step.
148
258
  - **Typed clients and hermetic test data**: `entities<"X">()` typed from the declaration, with
149
259
  `seed` rows as mocks.
@@ -6,7 +6,7 @@ repurposed when human wording changes. New codes may be added; consumers must
6
6
  handle an unknown code as a failure, without parsing prose.
7
7
 
8
8
  **Rollout:** this contract is enforced for **`himi push`**, including `--only`,
9
- first, for **`himi store iap connect`**, and for **`himi site member-app`**. Other subcommands still have legacy failures without codes and are a
9
+ first, for **`himi store iap connect`**, for **`himi site member-app`**, and for the **`himi base44`** entity and function verbs. Other subcommands still have legacy failures without codes and are a
10
10
  follow-up migration. This is an additive change: existing `error`, `errors`,
11
11
  `message`, `hint`, status, body, and gate-specific fields stay as they were.
12
12
  Some legacy envelopes have no singular `error` or `hint`; consumers must not
@@ -234,7 +234,7 @@ Covers `himi base44 adopt` and `himi base44 entities query` (#4557,
234
234
  carries each `ruleCode`. Adopt only emits what the lint accepts, so this means a bug in
235
235
  `adopt` (exit 1).
236
236
  - `unknown_subcommand`: `himi base44 entities` was given no subcommand, or one other than
237
- `query` (exit 2).
237
+ `query`, `create` or `seed` (exit 2).
238
238
  - `config_unloadable`: `entities query` could not load `config.ts` (exit 1).
239
239
  - `invalid_config`: the `base44` block has lint errors; `issues[]` carries each one's
240
240
  `ruleCode` (exit 1). `himi validate` reports the same findings with `pass: "base44"`.
@@ -249,6 +249,70 @@ branch on them without parsing prose:
249
249
  - `source_unavailable`: the project download (the eject read) failed, so no drift was
250
250
  computed. Row counts still ran; `sourceRead` is `"unavailable"` and `sourceError` says why.
251
251
 
252
+ ## `himi base44 entities | functions` provisioning codes
253
+
254
+ Covers `himi base44 entities create`, `himi base44 entities seed` and `himi base44 functions
255
+ deploy` (#4558, [base44-entities](base44-entities.md#provisioning-create-seed-deploy)). Failures
256
+ print `ok: false` and `code` on stderr. Every code below that refuses a write does so **before**
257
+ the write request is sent.
258
+
259
+ - `invalid_usage`: an unknown `functions` subcommand, a bare `--only`, `--only` on `entities
260
+ create` (always a full-set sync), an `--app` with no `apps/<slug>/config.ts`, or nothing to
261
+ deploy (no owned function, or `--only` matched none) (exit 2).
262
+ - `unknown_subcommand`: `himi base44 entities` was given no subcommand, or one other than `query`,
263
+ `create` or `seed` (exit 2).
264
+ - `config_unloadable`: `config.ts` could not be loaded (exit 1).
265
+ - `invalid_config`: the `base44` block has lint errors; `issues[]` carries each `ruleCode` (exit 1).
266
+ - `no_app_id`: the config has no `base44` block, or no `base44.appId` (exit 1).
267
+ - `not_signed_in`: there is no session and no `BASE44_ACCESS_TOKEN`. Run `himi base44 login
268
+ --write` (exit 2).
269
+ - `write_scope_missing`: `--yes` was given, but the token's `scope` claim lacks `apps:write` or
270
+ cannot be read. Nothing is sent, not even a read. Run `himi base44 login --write` (exit 2).
271
+ - `schema_snapshot_unavailable`: the project download (`GET …/eject`) failed, or one of its entity
272
+ files does not parse or was dropped by the source walk. The current entity set is unknown, and
273
+ a sync without that file would delete the entity (exit 1).
274
+ - `schema_snapshot_empty`: the download has no entity schemas. That cannot be told apart from a
275
+ failed read, so the run refuses unless `--empty-app-ok` is passed (exit 1).
276
+ - `would_delete_foreign_entity`: the sync body would omit or alter an entity himi does not own.
277
+ The guard, which should never trip (exit 1).
278
+ - `owned_entity_removal_needs_flag`: an entity this app provisioned (recorded in
279
+ `base44-provisioned.json`) is no longer declared. Dropping it deletes its rows; pass
280
+ `--allow-destructive`. An entity in the namespace that this app never provisioned is left
281
+ untouched and only warned about (exit 1).
282
+ - `owned_field_removal_needs_flag`: an owned entity lost a declared field. Pass
283
+ `--allow-destructive` (exit 1).
284
+ - `owned_entity_unclaimed`: a declared owned entity already exists on the app, but
285
+ `base44-provisioned.json` does not record this app provisioning it, so it may belong to another
286
+ himi app whose slug shares the prefix. If it is this app's, record it in that file; otherwise
287
+ rename the declaration (exit 1).
288
+ - `snapshot_changed`: the entities changed between the plan and the re-read just before the
289
+ `PUT`. Nothing was sent; re-run (exit 1).
290
+ - `ledger_unreadable`: `base44-provisioned.json` exists but is not a JSON object (a merge
291
+ conflict, say). himi will not rewrite it from scratch, because that would drop other app ids'
292
+ records, so fix the file. The same code means the sync was sent but the file could not be
293
+ written afterwards; `error` names the entities to record by hand (exit 1).
294
+ - `foreign_entity_deleted`: after the `PUT`, Base44's `deleted[]` named an entity the plan did not
295
+ drop on purpose; `foreignDeleted` lists them. Defence in depth: the guard should make this
296
+ unreachable (exit 1).
297
+ - `nothing_to_seed`: `seed` found no owned entity (adopted ones are never seeded), or `--ai`
298
+ had none to write (exit 1).
299
+ - `seed_incomplete`: one or more owned entities were not seeded because they are missing from
300
+ the app, unrecorded in `base44-provisioned.json` (`skipped: "unclaimed"`), or their rows could
301
+ not be read; `skipped[]` names each one. Not-empty entities are
302
+ skipped (`skipped: "not-empty"`) without failing (exit 1).
303
+ - `seed_file_invalid`: `base44-seed.json` is not a JSON object keyed by entity name, one of
304
+ its entries is not an array of row objects, or a row has no declared field left once undeclared
305
+ keys are dropped (a blank record would make the entity non-empty for good) (exit 1).
306
+ - `function_name_taken`: a declared function name is already deployed and does not carry this
307
+ app's `.himi-owned` marker. Nothing was deployed (exit 1).
308
+ - `function_source_missing`: an owned function has no `base44/functions/<name>/` folder or no
309
+ entry file (exit 1).
310
+ - `function_source_unsafe`: the function folder contains a symlink or a denied path, the secret
311
+ scan flags a file, or the folder is over the file or byte cap. Nothing is uploaded (exit 1).
312
+ - `request_failed`: any other refused request, or a reply himi cannot read. That includes a sync
313
+ response with no `deleted[]` and a function listing with no `functions` array. `status` and
314
+ `serverError` are included when the server answered (exit 1).
315
+
252
316
  ## `himi base44 screens` codes
253
317
 
254
318
  `himi base44 screens` (#4560, [base44-app-to-himi-app](base44-app-to-himi-app.md)) generates one
@@ -52,6 +52,7 @@ business from an idea to a preview and has the tools to do it. In a Claude Code
52
52
  ```text
53
53
  /plugin marketplace add https://apps.wix.com/_api/himi-serve/.claude-plugin/marketplace.json
54
54
  /plugin install himi@wix-himi
55
+ /plugin install himi-studio@wix-himi # optional: the Himi Studio pane (below)
55
56
  ```
56
57
 
57
58
  The marketplace hands the plugin out as a zip archive, which needs Claude Code 2.1.224 or later;
@@ -129,6 +130,30 @@ worker-backed flow, open the same URL in your regular browser.
129
130
  When `himi studio` has written the build board, the preview also serves it at `/__himi/studio/` on
130
131
  the same origin, and `himi_preview_start` returns that URL as `board`.
131
132
 
133
+ ### Himi Studio: the app beside the chat in Claude Code
134
+
135
+ `himi-studio` is the marketplace's second, optional plugin, a Claude Code *mod*. It adds a pane
136
+ beside the conversation with four views:
137
+
138
+ - **Now:** the screen being worked on, in a phone frame, with the live build's state and what the
139
+ last rebuild changed.
140
+ - **Screens:** every rendered screen.
141
+ - **Checks:** the journey step, and validate, test, the UX audit and the last push.
142
+ - **Activity:** the progress postcards.
143
+
144
+ When the last rebuild failed, a band above the prompt says so and offers **Fix it**. The agent gets
145
+ two tools: `studio_focus` shows you the screen it just changed, and `studio_snapshot` reads the
146
+ status.
147
+
148
+ ```
149
+ /plugin install himi-studio@wix-himi
150
+ ```
151
+
152
+ The pane shows screenshots, not the live app: a mod cannot host a web page. For the interactive
153
+ app, use its **Open live preview** button or the `himi-preview` launch configuration. The pane reads
154
+ only what the CLI already writes under `.himi/` (the board's `state.json` and its screenshots). It
155
+ opens by itself in an app folder; elsewhere, run `/himi <app folder>`.
156
+
132
157
  To see the app **on your phone**, `himi_push` publishes a draft and returns a link that opens it in
133
158
  Himi Player.
134
159
 
package/guides/skill.md CHANGED
@@ -74,6 +74,7 @@ A build takes most of an hour. An owner who sees nothing for that long assumes n
74
74
  - **Give them a board to leave open.** When the installed CLI lists `studio`, run `himi studio` once, right after that first picture, and tell the owner it is there (a current `himi init` has already made the board; this opens it). It opens a local page in their browser that fills itself in — every screen as it renders, the journey step and your latest postcard, each check as it runs — so they can watch between your messages. It is a view of your local work, not the preview of step 7.
75
75
  - **Let them click around while you work — the live preview runs from init on.** A current `himi init` started it (`watch.url` in its output); if it isn't running (`--remote`, CI), start it once step 4's startup preflight says the app may boot locally, when the installed CLI's `himi run` accepts `--watch`: run `himi run --watch --content <dir> &` at once and leave it running until the handover; do not wait for a `reminder` to ask. Give the owner its url, and open it only after the preflight. `himi run --watch` serves the app on this machine, opens it in their browser when you start it yourself (no `--browser` flag — that is a different mode, and `--watch` refuses it; the one init starts opens nothing), and repaints that tab every time you save — and the board frames the same live app. Once the app is bound to their site, the watch preview shows that site's live data, fetched by their own browser as an anonymous visitor. It is a local preview of your working copy, never the owner-private preview, and a save that does not build leaves the last good version on screen while you fix it.
76
76
  - **Inside a coding agent, prefer the `himi_*` tools.** When your tool list has them (`himi init` configures the `himi` MCP server for Claude Code, Cursor, Codex and VS Code), call them instead of shelling out: `himi_render` hands you the PNG to show, and `himi_preview_start` returns the live preview's URL. Open that URL in your own built-in browser — Claude Code desktop: start the `himi-preview` launch configuration; Cursor: its Browser tool; Codex in the ChatGPT desktop app: its Browser; VS Code: the integrated browser — so the owner watches the app take shape beside the chat.
77
+ - **When the Himi Studio pane is open, show the work there.** In Claude Code, a tool list with `mcp__himi-studio__studio_focus` means the owner has the Himi Studio pane beside the chat. It shows each screen as it renders, the live build and every check, and it keeps itself current. Right after you change or render a screen, call `studio_focus` with its screen id rather than pasting the picture into the chat. For the build status, read `studio_snapshot` rather than re-running status commands. Postcards still go in the chat and the journal. Without the pane, in Claude Code you may offer it once: `/plugin install himi-studio@wix-himi`.
77
78
  - **Hand over the story too.** At the handover in step 7, when `himi --help` lists `himi studio reel` (an older CLI can have `studio` without it), run `himi studio reel` and offer the owner the file it writes (a current CLI rebuilds it for you: your `--step review` postcard names it as `makingOf`, and every `himi push --draft` as `reel` — `.himi/making-of.html`, so name that file): one self-contained page of their app taking shape, version by version, with your postcards. It shows how the app was built; it is never a substitute for the preview URL, and it carries the same sample-data captions the postcards did.
78
79
 
79
80
  ## Approval gates
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1433.0",
3
+ "version": "0.1435.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -71,5 +71,5 @@
71
71
  "artifactId": "himalaya-cli"
72
72
  }
73
73
  },
74
- "falconPackageHash": "f0352e9dd51208b098564413b02976840565ff1539e321ae4ea327f5"
74
+ "falconPackageHash": "6cb6bc97630844062dc1646da097c2c60c5cb15c1afcb1a9e2d01b68"
75
75
  }