@wix/himalaya-cli 0.1609.0 → 0.1611.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.
Binary file
@@ -134,6 +134,10 @@ async function boot(msg) {
134
134
  let sweepError = null;
135
135
  try {
136
136
  actions = drain(ctx, runtime, msg.skipLoad ? "himi.quickjs.actions" : "himi.quickjs.loads");
137
+ if (msg.settleAuthoredActions) {
138
+ drainDetachedJobs(ctx, runtime);
139
+ actions = readbackJson(ctx, actionsReadback);
140
+ }
137
141
  } catch (e) {
138
142
  sweepError = String(e?.message ?? e);
139
143
  }
@@ -166,7 +166,9 @@ worker layer — trim it or mine it (`himi docs trim-a-template`): **trim** to t
166
166
  lists its screens (size, workers, `onAppear`), `--show <id>` prints one entry, and
167
167
  `--write <id> --from <file>` puts an edited entry back (refused if it breaks the file), and
168
168
  `--add <id> --from <file>` appends a NEW screen and registers it as linkable — the authoring half
169
- of mining a template. Not sure
169
+ of mining a template. To add a screen, clone the closest one: `--show <closest>`, change the id
170
+ and content, then `--add <new> --from <file> --display-name "<New title>"` (view names must be unique). `--from` takes that entry, a ScreenDescriptor
171
+ JSON object, or `{ "<id>": <ScreenDescriptor> }`; never edit `dev/index.ts` by hand. Not sure
170
172
  which template fits? `himi template recommend --text "<the business>"` (or `--book <site analyze
171
173
  dir>` for a site's verticals) ranks the catalog with reasons. For a small **non-Wix** pattern, `himi init --template chat-bot --remote`. `himi template
172
174
  list --remote` shows the full catalog (title/description/tags) — including templates published
@@ -40,6 +40,17 @@ keeps its existing fields and adds the code:
40
40
  }
41
41
  ```
42
42
 
43
+ ## `himi test` authored journey failures
44
+
45
+ | Code | Meaning |
46
+ | --- | --- |
47
+ | `test_journey_failed` | At least one unsuppressed authored journey failed: its destination is absent, initialization/action failed, or the expected rendered values were missing. The existing `failures`, `journeys`, counts and exit 1 remain. This includes cold-entry journeys with `steps: []`. |
48
+ | `test_input_evidence_requires_json` | `--input-evidence` was requested without explicit `--json`. Exit 2 before build or worker execution. |
49
+ | `test_input_evidence_unsupported_mode` | `--input-evidence` was combined with `--browser`, or the content is a functions package rather than an app worker crawl. Exit 2 before execution. |
50
+ | `test_input_evidence_unavailable` | The isolated input crawl cannot establish all contained realms, cannot read a stable source archive before/after the crawl, or fails to return one complete JSON report (including interruption, process timeout or output limit). Exit 1; no host-realm fallback or positive input acceptance. |
51
+
52
+ This is a scoped migration. Other legacy `himi test` failure paths retain their existing envelopes.
53
+
43
54
  ## `himi icon from-one-app` codes
44
55
 
45
56
  | Code | Meaning |
@@ -300,15 +311,17 @@ whole body gzip-encoded because it is over the plain 8 MB cap:
300
311
  |---|---|
301
312
  | `compressed_publish_unsupported` | The publish body went out gzipped and the publishing service did not accept it compressed. It either read the bytes as malformed JSON, or measured the decompressed body against the 8 MB uncompressed limit (HTTP 413). Either the service does not accept compressed bodies yet, or the credential is a self-serve one, which keeps the 8 MB uncompressed limit. Nothing was written. |
302
313
 
303
- ## `himi template screens --upsert` codes
314
+ ## `himi template screens --upsert | --add | --write` codes
304
315
 
305
- `--upsert` writes many generated screens at once. Its refusals carry a code; nothing is written
306
- on any of them (a failed batch restores every file). Other `template screens` paths stay legacy.
316
+ `--upsert` writes many generated screens at once; `--add <id>` and `--write <id>` write one. Their
317
+ `--from` refusals carry a code; nothing is written on any of them (a failed batch restores every
318
+ file). Other `template screens` paths, and `--add`/`--write` refusals about the package itself
319
+ (an existing id, a symlink, a result that would not parse), stay legacy.
307
320
 
308
321
  | Code | Meaning |
309
322
  |---|---|
310
- | `invalid_usage` | `--upsert` was given without `--from <file>`. Exit 2. |
311
- | `invalid_input` | The `--from` file cannot be read or is not JSON. Exit 2. |
323
+ | `invalid_usage` | `--upsert`, `--add` or `--write` was given without `--from <file>`. Exit 2. |
324
+ | `invalid_input` | The `--from` file is missing, unreadable or not JSON. For `--add`/`--write` also: it is not a ScreenDescriptor object, `{ "<id>": <ScreenDescriptor> }` or the entry `--show` prints, or its key or `screenId` is not the `<id>` given; a templated route (`{ pattern, display, template }`) takes back only the text `--show` prints for it. `error` names the file. Exit 2. |
312
325
  | `upsert_refused` | The JSON is not `{ "<screenId>": <ScreenDescriptor> }`, an id or `screenId` does not match, the result would not parse as plain SCREENS entries, or a target file is a symlink. `error` names which. Exit 2. |
313
326
 
314
327
  ## `himi site member-app` codes
@@ -189,7 +189,9 @@ worker layer — trim it or mine it (`himi docs trim-a-template`): **trim** to t
189
189
  lists its screens (size, workers, `onAppear`), `--show <id>` prints one entry, and
190
190
  `--write <id> --from <file>` puts an edited entry back (refused if it breaks the file), and
191
191
  `--add <id> --from <file>` appends a NEW screen and registers it as linkable — the authoring half
192
- of mining a template. Not sure
192
+ of mining a template. To add a screen, clone the closest one: `--show <closest>`, change the id
193
+ and content, then `--add <new> --from <file> --display-name "<New title>"` (view names must be unique). `--from` takes that entry, a ScreenDescriptor
194
+ JSON object, or `{ "<id>": <ScreenDescriptor> }`; never edit `dev/index.ts` by hand. Not sure
193
195
  which template fits? `himi template recommend --text "<the business>"` (or `--book <site analyze
194
196
  dir>` for a site's verticals) ranks the catalog with reasons. For a small **non-Wix** pattern, `himi init --template chat-bot --remote`. `himi template
195
197
  list --remote` shows the full catalog (title/description/tags) — including templates published
@@ -74,6 +74,80 @@ Each stage runs on hermetic data with zero network:
74
74
  Engine: `core/dev-server/src/screen-crawl.ts`.
75
75
  CLI orchestration: `tools/himi-cli/src/test.ts`.
76
76
 
77
+ ## Machine input evidence
78
+
79
+ `himi test --content <dir> --input-evidence --json` opts into additive
80
+ `inputEvidence.version: 1` output. The local evaluator records actual dispatches; it
81
+ does not interpret a Plan or decide whether a warning is benign. The flag requires
82
+ explicit `--json`; browser-loop and functions-package modes refuse it with typed
83
+ failure codes. An older CLI may omit the field: treat that as capability missing,
84
+ never as a passing scan.
85
+
86
+ The CLI runs this opt-in crawl in a separate process, enables the existing compiler
87
+ import confinement, and establishes QuickJS/WASM realms for generated dev modules,
88
+ config, worker boot and worker actions before loading generated modules. Explicit
89
+ host-realm overrides or unavailable isolation refuse with
90
+ `test_input_evidence_unavailable`; there is no host fallback. Packages containing
91
+ symlinks are refused. The compiler accepts package-owned files and CLI-owned
92
+ source/staged SDK roots; it does not expand arbitrary app or ancestor dependency
93
+ links into trusted roots. A separate editor SDK install cannot substitute for the
94
+ pinned CLI's runtime in this mode. The trusted caller must keep the generated
95
+ source and its environment quiescent during capture and bind the final subject. The local
96
+ receipt CLI projects only the caller-owned public `WIX_CLIENT_ID` and `WIX_SITE_URL`
97
+ into contained config/dev compilation, preserving their supplied values. Other
98
+ host environment keys (including secrets) are omitted; tokenless/default contained
99
+ callers still receive an empty environment. Capture those public bindings with
100
+ the run environment; the CLI does not choose an identity or provision a site.
101
+ Packages requiring host filesystem/network work during config or descriptor construction must report
102
+ that limitation instead of issuing contained evidence. The isolated crawl has a
103
+ three-minute process limit; interruption forwards SIGTERM/SIGINT to its child.
104
+
105
+ The receipt has these fields:
106
+
107
+ | Field | Evidence |
108
+ | --- | --- |
109
+ | `subject` | Actual app, tested release ID and payload hash, test run ID, source diff/untracked hashes, and SHA256 of the exact `himi-test.json` bytes parsed for the run (`absent` when missing). `sourceArchiveHash` is SHA256 of the base64 deterministic ZIP from the publish source collector, including authored `himi-test.json`. It is captured before loading generated modules and rechecked after the crawl; unreadable or changed source refuses with `test_input_evidence_unavailable`. Generated `.himi` outputs are excluded by the shared archive rules. Git hashes may explicitly be `unavailable`. |
110
+ | `execution` | CLI-established `devModule`, `appConfig`, `workerBoot` and `workerAction` modes, each `quickjs-wasm`. A v1 report missing these fields predates the contained CLI path; do not accept it as contained execution. This marker is meaningful only when captured from the trusted pinned producer. |
111
+ | `probes` | Each synthesized typed dispatch's screen/component/action/hook, contract control and injected field/value, actual argument list, precondition input/current value/state hash, post-state hash, and observed state/navigation/request/host-call/throw results. Zero probes is not proof that required controls ran. |
112
+ | `journeys` | Actual screen/input, each attempted step's scope, raw `declaredPayload`, effective row-resolved `descriptorPayload`, exact `testOverrides`, final merged `payload`, pre/post state hashes, executed/threw/not-dispatched status, final visible observations and evaluator-computed assertions. Unavailable actions remain not-dispatched, never successful steps. |
113
+ | `unavailableScreens`, `unavailableJourneys` | Requested coverage for which the evaluator did not supply v1 evidence, including older engines, invalid/collapsed screens and unavailable journeys. With positional screen IDs, these lists contain only requested roots; requested unknown IDs remain unavailable. Unrelated configured journeys do not run or fail a scoped run. These gaps are not accepted behavior. |
114
+
115
+ State hashes fingerprint the exact serialized worker snapshot captured at the dispatch
116
+ boundary. `currentValuePresent` distinguishes an absent current value from null.
117
+ Input records include the implicit screen ID, then baked descriptor input and route
118
+ overrides with the same precedence the worker receives.
119
+ Requests and host calls are attempted hermetic effects, not live-service success.
120
+ Journey assertion kind `observation-substring` states the existing operator exactly:
121
+ substring inclusion in joined visible `nodeId.field=value` lines. It does not prove
122
+ exact text equality, complete result sets, absence of extra rows, or that an
123
+ agent-authored expected value is an independently approved oracle.
124
+
125
+ Journey parameters are synthetic overrides. A journey that replaces a descriptor's
126
+ literal service-reference ID with a real ID tests that synthetic dispatch, not the
127
+ actual UI tap. Inspect `testOverrides` alongside `descriptorPayload`; a passing
128
+ assertion cannot waive a failing descriptor-driven flow. Worker (`tier5.*`) actions
129
+ keep authored params/args literal by the existing action contract; reducers read
130
+ their selected record from state/input rather than expecting nested service binding
131
+ evaluation. This evidence does not change that contract.
132
+ The origin fields are always present: unavailable declared/effective payloads and
133
+ absent test parameters are explicit `null`; an explicitly empty override is `{}`.
134
+ An omitted origin field is unknown, not evidence that no override occurred.
135
+
136
+ This output leaves `ok`, finding severities and suppressions unchanged. In particular,
137
+ `typed-value-ignored` remains a warning and can coexist with `ok: true`. Use the
138
+ structured finding invariant/screen/trigger/field/axis to apply a separate trusted
139
+ acceptance policy; do not parse message prose or reject every warning. Finding IDs
140
+ are stable grouping identities, not unique case/dispatch IDs. Inspect suppressed,
141
+ skipped and absent coverage explicitly. A different successful input cannot excuse
142
+ an untested or failed required input.
143
+
144
+ Attestation v2 still binds only aggregate report/coverage values alongside its
145
+ existing source/release/descriptor/screenshot hashes; it does not acquire new
146
+ acceptance semantics. A trusted host must capture the actual pinned CLI process
147
+ exit/stdout, bind the full report to its own run and immutable final source/release,
148
+ and supply independent required-control/case policy. Neither a negative-clear scan
149
+ nor an unkeyed receipt is whole-product acceptance or trusted agent prose.
150
+
77
151
  ## Typed form journeys
78
152
 
79
153
  The crawl types into a control **only when it can read a legal value off the app itself** — an id
@@ -115,6 +189,19 @@ edge would hand it — so the journey boots the way a real tap into it would. Ke
115
189
  navigation in the ordinary edge pass, which boots the destination with real source
116
190
  parameters. Pair dynamic journeys with app-specific `dev/net-mocks.json` fixtures.
117
191
 
192
+ Journeys run only the initialization the bundle and descriptor actually declare: module-scope
193
+ calls and the root `onAppear`. Unlike the discovery crawl's convenience `load()` sweep, they do
194
+ not call an otherwise uncalled loader. A declaration of `actions.load` alone does not initialize
195
+ a cold screen on device.
196
+
197
+ Use `"steps": []` to assert the result of entering a detail screen, without adding a synthetic
198
+ load tap that could conceal missing initialization. Add separate journeys with different `input`
199
+ IDs and requirement-derived `expectText` (title, notes, metadata and numeric values). Include
200
+ missing/stale IDs and a not-found expectation. These are independent cold entries, not proof of
201
+ back/return, state carry-over or the source row's emitted navigation params; verify those with
202
+ real interactions as well. A green derived crawl without such expectations does not establish
203
+ that a detail shows the selected record.
204
+
118
205
  ## What it checks
119
206
 
120
207
  Only **unambiguous** defects, so a green run stays worth trusting:
@@ -483,6 +570,7 @@ behavior. This instruction does not add an automatic suppression or retry gate t
483
570
  | `--offline` | Strip every data layer — see the failure UI head-on. (Excludes `--net`.) |
484
571
  | `--no-hostile` | Skip the empty-list / all-500 passes. |
485
572
  | `--no-shots` | Skip the per-screen PNGs written to `.himi/shots/`. |
573
+ | `--input-evidence` | Requires `--json`; capture actual typed probes and authored-journey receipts in contained local worker mode (see the receipt contract above). |
486
574
  | `--net <file>` | Use an explicit net-mocks file instead of the app's own. |
487
575
  | `--budget <ms>` | Per-action settle budget (default 2000). |
488
576
  | `--native` | Also decode every baked descriptor, and the release's `tokens.json`, with the real native decoders; bare `--native` runs whichever toolchains are present and names each one it could NOT check in a top-level `skippedPlatforms: [{ platform, reason }]` (never a pass), while `--native ios` or `--native android` selects one and exits 2 when it is unavailable. The Android SDK is found from `ANDROID_HOME`, then `ANDROID_SDK_ROOT`, then `sdk.dir` in the source checkout's Android test harness `local.properties`, then the default install path (`~/Library/Android/sdk` on macOS, `~/Android/Sdk` on Linux). **Source-checkout only** — the decoder oracles are that tree's own HimalayaCore Swift package and Gradle harness, which a published install does not ship, so it cannot run this at all (and its coverage ledger stays silent about native decoding rather than suggesting it). |
@@ -199,7 +199,20 @@ by this job, and its temporary files. It preserves the agent's keychain; it does
199
199
  certificate or delete the original profile in Apple/Branded. A matching identity already in the
200
200
  keychain is refused before import so cleanup cannot delete a pre-existing identity.
201
201
 
202
- Outside that runner mode, Himi creates a temporary keychain and deletes it during cleanup. A
202
+ A job that is killed before its cleanup runs (SIGKILL) leaves the customer's material behind, so
203
+ each job records what it places before placing it: its signing folder (which holds the private key
204
+ until it is imported), the identity it imports into the agent keychain, and every copy of the App
205
+ Store Connect key (`~/.private_keys/AuthKey_<id>.p8`, also when it replaces a file already there,
206
+ and the temporary copy `altool` reads). The records live in `~/.himalaya/customer-secret-claims` in the account home.
207
+ At the start of the next customer build on that Mac, before the pre-existing check, Himi removes
208
+ what a job whose process has ended recorded, and leaves alone what a running job recorded, since a
209
+ Mac may run more than one job at once. A matching identity that a running job owns, or that no
210
+ record names, is still refused. SIGTERM and process exit remove the key copies directly, as they do
211
+ the signing directory.
212
+
213
+ Outside that runner mode, Himi creates a temporary keychain and deletes it during cleanup. That
214
+ keychain is recorded the same way before it is created, and the next customer build deletes one an
215
+ ended job left (`security delete-keychain`, which also drops it from the search list). A
203
216
  missing password or keychain in agent-keychain mode fails the build instead of silently switching
204
217
  modes. Private key material does not enter job parameters or the public job record. The runner
205
218
  source SHA must advertise support for this protocol and be reachable from the pool before BYO
@@ -623,6 +636,14 @@ gradle read the tree. The shell supplies the project; it no longer supplies the
623
636
  | `apps/<app>/ios/project.yml`, then its `build.gradle.kts` | the content app has source in this checkout — it already declared a version, so nothing new has to be declared |
624
637
  | the SHELL's own declared version | an off-repo app that declares nothing anywhere. Deliberate: `CFBundleShortVersionString` is **also** the OTA rollout floor (`HimalayaApp.swift` passes it as `binaryVersion`; serve-control's `resolveRelease` skips any ring whose `minBinaryVersion` it fails, and returns nothing when none qualifies), and the shell's version is the truth about what the binary can render |
625
638
 
639
+ Branded Lite keeps the two apart, so the store version never moves its rollout floor. Its Android
640
+ app reports `BuildConfig.SHELL_VERSION` as the OTA `binaryVersion`, and its iOS app the Info.plist
641
+ key `HimalayaShellVersion`. Each is pinned equal to the shell's committed version. So a
642
+ Containers app's App Store build, which stamps the owner's version into `CFBundleShortVersionString`
643
+ through `APP_VERSION`, still reports the shell's version to update checks, and the build log says so.
644
+ A shell commit older than the key reports `CFBundleShortVersionString`, as before. Force update
645
+ (`minVersion`) compares the store version on both.
646
+
626
647
  The **build number** (`CFBundleVersion` / `versionCode`) is seconds since 2020-01-01Z, so it is
627
648
  monotonic and unique per app per second — App Store Connect rejects a duplicate version/build pair,
628
649
  and Play requires `versionCode` to increase.
@@ -14,6 +14,18 @@ areas, always in the same order, so you can skim for the one you care about.
14
14
 
15
15
  ---
16
16
 
17
+ ## 2026-11-08
18
+
19
+ ### Getting started & the CLI
20
+
21
+ - **`himi template screens --add` and `--write` now take the screen as JSON.** `--from` accepts a
22
+ plain ScreenDescriptor (the id comes from `--add <id>` / `--write <id>`), `{ "<id>": <ScreenDescriptor> }`,
23
+ or the entry `--show` prints. Before, only that `--show` entry worked, and a JSON file failed with an
24
+ error pointing at a line of `dev/index.ts`. A file that is not one of these shapes, has a different
25
+ id or cannot be read is refused with `code: "invalid_input"`, and the error names your file. To add
26
+ a screen, clone the closest one: `--show <closest>`, edit it, then
27
+ `--add <new> --from <file> --display-name "<title>"`. (#5422)
28
+
17
29
  ## 2026-11-04
18
30
 
19
31
  ### Branded Lite & Owner Lite
@@ -117,6 +117,8 @@ himi template screens # list the screens and their worker
117
117
  himi template screens --show himi_saved > saved.txt # ONE screen's entry
118
118
  himi template screens --write himi_saved --from saved.txt # put it back — re-parsed, refused if it breaks the file
119
119
  himi template screens --add himi_sellers --from sellers.txt --parent himi_branded_home # a NEW screen, registered as linkable
120
+ # --add/--write --from takes a ScreenDescriptor JSON object, { "<id>": <ScreenDescriptor> }, or the --show entry.
121
+ # To add a screen, clone the closest one: --show it, change the id and content, then --add it.
120
122
  himi template sweep --set "Sample content=>Our latest" --dry-run # copy inside string literals only
121
123
  himi template trim --from-spec --links drop --dry-run # keep SPEC.md's Screen catalogue ids — read fromSpec.droppedPrimary first
122
124
  ```
@@ -779,6 +779,20 @@ This works identically on web, iOS, and Android. (Regression-guarded by
779
779
  detail bundles for BOTH the primary `input.id` param and the back-compat
780
780
  `input.screenId` recovery.)
781
781
 
782
+ **Prove the selected record, not just a successful build.** Each screen has its own worker,
783
+ even when several screens name the same bundle and service. Setting a selected id in the list's
784
+ service does not set the detail's state. Trace the tapped row id → navigation params →
785
+ `himalaya.input` → the detail's initialized state. Route input is not automatically a loader
786
+ argument, and `$input.id` is not a descriptor binding; read input in the worker as above.
787
+
788
+ Add cold-entry journeys (`steps: []`) in `himi-test.json` for at least two distinct records per
789
+ detail, asserting their requirement-derived title, metadata, notes and numeric values. Also
790
+ assert missing/stale ids. See [cold-entry assertions](himi-test.md#typed-form-journeys). Do not
791
+ manually dispatch `load` in these checks: that can make an uninitialized generated screen look
792
+ correct. Then drive the actual row taps and back/return on each required surface, confirming
793
+ that the second selection and a missing id show none of the first record's fields. Keep the
794
+ source-nav and return evidence separate from the screen-local cold-entry assertions.
795
+
782
796
  **Alternative — a templated route that bakes a static `input`.** When the id space is
783
797
  enumerable, a `screens.templated` route can bake the id straight into the descriptor's
784
798
  **static `input`** instead of relying on a nav param — the `property_<id>` pattern. The
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1609.0",
3
+ "version": "0.1611.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": [
@@ -72,5 +72,5 @@
72
72
  "artifactId": "himalaya-cli"
73
73
  }
74
74
  },
75
- "falconPackageHash": "fa0e34282ffa10a702049aac3eee4901f37a114adb15ad682acd5013"
75
+ "falconPackageHash": "5919de535cfa33dabfeb372e350f3934dc2b5ccd610a7c9acdea0c51"
76
76
  }