@wix/himalaya-cli 0.1432.0 → 0.1434.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
 
@@ -61,8 +61,8 @@ whose `Task` entity anyone may read and write:
61
61
 
62
62
  | Tab | Screen | Worker | Pattern it shows |
63
63
  |---|---|---|---|
64
- | Tasks | `b44_tasks` | `tasks` | list, create, bulk-create, update, delete; loading / empty / error / ready; pull to refresh |
65
- | (pushed) | `b44_task` | `task` | read one row by its id (a nav param), edit, delete then go back |
64
+ | Tasks | `b44_tasks` | `b44-task-list` | **generated** by `himi base44 screens`: list, create, delete; loading / empty / error / ready; pull to refresh |
65
+ | (pushed) | `b44_task` | `b44-task` | **generated**: read one row by its id (a nav param), edit, delete then go back |
66
66
  | Functions | `b44_functions` | `functions` | `functions.invoke(name, payload)` with the reply and the error painted |
67
67
  | Account | `b44_account` | `account` | Native Google sign-in (requires tenant app-link associations), email + password and emailed-code sign-in, register, reset, profile, sign out |
68
68
 
@@ -89,10 +89,14 @@ Turn the book's entities and functions into an adopted declaration, then wire it
89
89
  himi base44 adopt --content . --book ../.himi/base44-book --write # the book step 1 wrote, one level up → base44-entities.ts (never overwrites)
90
90
  ```
91
91
 
92
+ The starter's `config.ts` declares the sample `Task` as a local `const base44Entities = [...]`.
93
+ Delete that declaration, then import yours in its place (keeping both fails with "Identifier
94
+ 'base44Entities' has already been declared"):
95
+
92
96
  ```ts
93
97
  import { base44Entities, base44Functions } from "./base44-entities.js";
94
98
  // …
95
- base44: { appId: "<id>", entities: base44Entities, functions: base44Functions },
99
+ base44: { appId: base44AppId, entities: base44Entities, functions: base44Functions },
96
100
  ```
97
101
 
98
102
  `himi validate` then lints the declaration (`pass: "base44"`), and `himi base44 entities query`
@@ -112,15 +116,21 @@ until you do. See [`base44-sdk`](base44-sdk.md#typed-rows).
112
116
 
113
117
  ## 3. Plan the screens from the book
114
118
 
119
+ `himi base44 screens` (step 4) applies the rules below for you, so this step is about choosing
120
+ **what to declare**: which entities, in what order (with up to three entities each gets a tab; with
121
+ four or more, the first two get tabs and the rest go under More), which fields and which `rls`. The rules describe what the generator emits. Read them to predict the result, and to
122
+ know what to customise afterwards.
123
+
115
124
  Write `.himi/screen-plan.md` before editing code. For each entity in `book.entities`:
116
125
 
117
126
  1. **Decide whether it gets a tab.** An entity that a top-level route reads (`routes[].entities`)
118
127
  and that a user browses gets a tab. A child entity (one whose rows only make sense under a
119
128
  parent, such as `OrderItem` under `Order`) gets a section on the parent's detail screen
120
129
  instead. Keep to 3–5 tabs. Account always takes one when the app is not public (step 5).
121
- 2. **Pick the list row.** The title is the first `required` string field, preferring one named
122
- `title`, `name` or `label`. The subtitle is one or two short fields (a status `enum`, a date, a
123
- number). Never put a long text field in a row.
130
+ 2. **Pick the list row.** The title is the entity's `displayField` if it declares one, else the
131
+ first `required` string field, preferring one named `title`, `name` or `label`. The subtitle is
132
+ one or two short fields (a status `enum`, a date, a number). Never put a long text field in a
133
+ row.
124
134
  3. **Pick the detail and form fields** from each field's JSON Schema type:
125
135
 
126
136
  | Field (`type` / `format` / `enum`) | Detail shows | Form control |
@@ -129,20 +139,28 @@ Write `.himi/screen-plan.md` before editing code. For each entity in `book.entit
129
139
  | `string` + long text (`description`, `notes`, `body`, …) | `Text` with `maxLines` | `TextField` with `multilineMaxLines` |
130
140
  | `string` + `enum` | `Badge` / `Text` | `SegmentedControl` (≤ 4 values) or `Picker` |
131
141
  | `string` + `format: date` / `date-time` | formatted `Text` | `DatePicker` |
132
- | `string` + `format: email` / `uri` | `Text`, tap opens mail / URL | `TextField` with `keyboard: "email"` / `"url"` |
142
+ | `string` + `format: email` / `uri` | `Text` (the generator does not make it tappable yet) | `TextField` with `keyboard: "email"` / `"url"` |
133
143
  | `string` holding an image URL (`image`, `photo`, `avatar`, `*_url`) | `Image` | read-only, see [file upload](#what-the-sdk-cannot-do) |
134
144
  | `number` / `integer` | `Text` (with unit) | `Stepper` (small ranges) or numeric `TextField` |
135
145
  | `boolean` | `Badge` or `Text` | `Toggle` |
136
- | `array` of strings | `FilterChips` / `ChipsInput` (read-only) | `ChipsInput` |
137
- | `object` / nested `array` of objects | a sub-section of rows | none at first. Edit it on the web app |
146
+ | `array` of strings | comma-joined `Text` | `ChipsInput` |
147
+ | `object` / nested `array` of objects | its JSON as `Text` (a sub-section of rows is yours to build) | none. Edit it on the web app |
138
148
  | built-ins `id`, `created_date`, `updated_date`, `created_by` | "Created …" metadata row | never editable |
139
149
 
140
150
  4. **Respect the entity's rules.** `rls` (and field-level `rls`) decide what the signed-in user
141
- may do. Offer only the writes `BOOK.md` lists for the entity. An operation whose rule is
142
- `false` gets no button. A rule that is a condition (`{ "created_by": "{{user.email}}" }`)
143
- means the write only works for a signed-in user, on their own rows, so it belongs behind
144
- sign-in (step 5). A denied call still fails with Base44's message, and every screen must paint
145
- that error rather than swallow it.
151
+ may do. Declare the `rls` `BOOK.md` lists for the entity. The generator gates each write
152
+ control on its operation's rule (falling back to the entity-level `write` rule):
153
+
154
+ | Rule | Control |
155
+ |---|---|
156
+ | `false`, or absent | not emitted at all |
157
+ | `true` | always shown |
158
+ | exactly `{ "created_by": "{{user.email}}" }` or `{ "created_by_id": "{{user.id}}" }` | shown only on the signed-in user's own rows |
159
+ | any other condition | shown only when signed in |
160
+
161
+ A field whose field-level `rls.write` is not `true` is read-only in the form. The gate is
162
+ advisory: a denied call still fails with Base44's message, and every screen paints that error
163
+ rather than swallowing it.
146
164
  5. **Use the sample rows** (`sampleRows`, already redacted) to size rows and choose the subtitle,
147
165
  never as data the app ships.
148
166
 
@@ -151,22 +169,48 @@ Compose each screen with [`designing-himi-screens`](designing-himi-screens.md)
151
169
 
152
170
  ## 4. Build one list + detail per entity
153
171
 
154
- Copy the Task pair and rename it. For an entity `Project`:
172
+ Declare the entity, then generate its screens:
173
+
174
+ ```bash
175
+ himi base44 adopt --content . --book ../.himi/base44-book --write # or declare by hand (step 2)
176
+ himi base44 screens --content . --json
177
+ ```
178
+
179
+ For each entity in `config.ts` `base44.entities`, `himi base44 screens` writes a list screen
180
+ (`b44_<plural>`, e.g. `b44_projects`) and a detail screen (`b44_<name>`, e.g. `b44_project`):
181
+
182
+ - `tier5-src/_shared/b44-<entity>-plan.ts`: the plan (row title and subtitle, facts, form
183
+ controls, write gates) the rules in step 3 produce. The list, the detail and the descriptors all
184
+ read it, so this is the file to customise.
185
+ - `tier5-src/b44-<entity>-list/index.ts` and `tier5-src/b44-<entity>/index.ts`: one-line worker
186
+ entries over the template's shared engine (`_shared/entity-list.ts`, `_shared/entity-detail.ts`).
187
+ Each entity gets its own bundle and service, so two entity tabs never share state.
188
+ - `dev/entities.generated.ts` and `config.entities.generated.ts`: the screen registrations and the
189
+ `linkableScreens` / `tabBar` items. `dev/index.ts` and `config.ts` already import them.
190
+
191
+ The first three entities in config order get a tab, in front of Functions and Account. With more,
192
+ the last entity slot becomes a generated `b44_more` screen listing the rest, so the bar never has
193
+ more than five items. Ids pluralise naively (`Category` → `b44_categories`, `Person` →
194
+ `b44_persons`); give the entity a `title` for the visible name. Two entities that would share an id
195
+ are refused with `code: "entity_id_collision"`.
196
+
197
+ Re-running is safe. Each generated file starts with
198
+ `// @generated by himi base44 screens — sha256:<hash>`:
199
+
200
+ - an unchanged config reports every file `unchanged` and writes nothing;
201
+ - a generated file you edited by hand (its body no longer matches the hash) is reported
202
+ `skipped-edited` and left alone, and the command still exits 0. Pass `--force` to overwrite it;
203
+ - files for an entity you removed from `config.ts` are reported in `orphaned[]` and never deleted.
204
+
205
+ `--dry-run` reports the same outcomes without writing. Failures carry a top-level `code`
206
+ (`no_entities_block`, `entity_id_collision`, `content_dir_not_base44_starter`), per
207
+ [`himi-json-output`](himi-json-output.md). The generator never calls Base44.
155
208
 
156
- - `tier5-src/projects/index.ts` from `tier5-src/tasks/index.ts`. Set `ENTITY = "Project"`, the
157
- service name (`b44Projects`), and `toRow()` for the fields you chose. Keep the structure:
158
- module-eval `load()`, the `latestList` sequence that drops stale replies, the `pendingWrites`
159
- guard, and `derive()` producing the `hide*` flags.
160
- - `tier5-src/project/index.ts` from `tier5-src/task/index.ts`. `inputId()` reads the row id from
161
- the nav param, `get(id)` loads it, and `remove` returns `navigate(…, { presentation: "back" })`
162
- from the action the host dispatched.
163
- - In `dev/index.ts`, a `projects()` and a `project()` builder (copy `tasks()` and `task()`), each
164
- bound with `bundle: "<worker dir>"` and `declaredCapabilities: ["base44"]`. Register both in
165
- `screens.exact` and the tab root in `seed.screens`.
166
- - In `config.ts`, a `linkableScreens` entry for each (the detail with `paramKeys: ["id"]` and its
167
- list as `parentScreenId`) and a `tabBar` item for the list.
209
+ To change a screen beyond what the plan expresses (a filtered list, a child section, a custom
210
+ action), edit its generated entry or plan. The edit makes the file `skipped-edited`, so the
211
+ generator leaves it alone from then on.
168
212
 
169
- The calls a worker makes, all on `entities("<Name>")`:
213
+ The calls the engine makes (and a customised worker can make), all on `entities("<Name>")`:
170
214
 
171
215
  | Need | Call |
172
216
  |---|---|
@@ -187,7 +231,9 @@ Rules that keep it correct:
187
231
  `$item.openLabel`. `himi validate` flags this as an error.
188
232
  - **Every write re-lists**, and a failed write keeps the list on screen with the error above it.
189
233
  Only a failed *first* list is the error state.
190
- - Remove `tasks` / `task` once your own entities replace them, and change `homeScreenId`.
234
+ - Replace the sample `Task` declaration with your own entities and re-run `himi base44 screens`.
235
+ The home screen is the first entity's list. The generator reports the sample's files as
236
+ `orphaned`; delete them by hand.
191
237
 
192
238
  ## 5. Auth: the Account tab
193
239
 
@@ -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,11 +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.
150
- - **Generated screens**: list and detail screens per declared entity.
@@ -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,88 @@ 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
+
316
+ ## `himi base44 screens` codes
317
+
318
+ `himi base44 screens` (#4560, [base44-app-to-himi-app](base44-app-to-himi-app.md)) generates one
319
+ list + detail screen per declared `base44.entities` entity. Failures print `ok: false` and `code`
320
+ on stderr (exit 1):
321
+
322
+ - `content_dir_not_base44_starter`: the directory lacks the shared engine the generated files
323
+ import (`missing[]` names the files). Scaffold with `himi init --template base44-starter`.
324
+ - `no_entities_block`: `config.ts` declares no `base44.entities`, so there is nothing to generate.
325
+ - `entity_id_collision`: two entities would generate the same screen id (or one would shadow
326
+ `b44_functions` / `b44_account` / `b44_more`); `entity`, `screenId` and `with` name the clash.
327
+ - `config_unloadable` / `invalid_config`: as for `himi base44 entities` above.
328
+
329
+ On success (`ok: true`, stdout, exit 0) `files[]` gives every generated path with its `outcome`:
330
+ `written`, `unchanged`, or `skipped-edited` (the file was edited by hand and was left alone; pass
331
+ `--force` to overwrite it). A skipped file is not a failure. `orphaned[]`, when present, lists
332
+ generated files for entities no longer declared. They are never deleted.
333
+
252
334
  ## Follow-ups
253
335
 
254
336
  - Migrate failure envelopes in subcommands other than `push`, keeping this contract.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1432.0",
3
+ "version": "0.1434.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": "796dbf6642a176106f5ab3335bbab9788c281db7f264524e0c7fb8e3"
74
+ "falconPackageHash": "cb5b7712df9ddebe73b144d2897a1f0c22f171a5e4e2f908546c7509"
75
75
  }