@wix/himalaya-cli 0.830.0 → 0.831.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.
Files changed (2) hide show
  1. package/dist/cli.mjs +256 -14
  2. package/package.json +2 -2
package/dist/cli.mjs CHANGED
@@ -40331,6 +40331,205 @@ var init_net_scenario = __esm({
40331
40331
  }
40332
40332
  });
40333
40333
 
40334
+ // ../../core/dev-server/src/capability-fixtures.ts
40335
+ function capabilityIdsIn(bundleJs) {
40336
+ const out = /* @__PURE__ */ new Set();
40337
+ for (const m of bundleJs.matchAll(/["'`]capability\.([a-z_]+)\.([A-Za-z]+)["'`]/g)) {
40338
+ if (m[1] === "local_database") continue;
40339
+ out.add(`capability.${m[1]}.${m[2]}`);
40340
+ }
40341
+ return [...out].sort();
40342
+ }
40343
+ var decodeItem, MEDIA_EXT, MEDIA_MIME, FILE, CALL, MEDIA_STATUS, CAPABILITY_SUCCESS;
40344
+ var init_capability_fixtures = __esm({
40345
+ "../../core/dev-server/src/capability-fixtures.ts"() {
40346
+ decodeItem = (raw) => {
40347
+ if (typeof raw !== "string") return {};
40348
+ try {
40349
+ const v = JSON.parse(raw);
40350
+ return v && typeof v === "object" ? v : {};
40351
+ } catch {
40352
+ return {};
40353
+ }
40354
+ };
40355
+ MEDIA_EXT = (url) => {
40356
+ if (typeof url !== "string") return null;
40357
+ let path;
40358
+ try {
40359
+ path = new URL(url).pathname;
40360
+ } catch {
40361
+ path = url.split("#")[0].split("?")[0];
40362
+ }
40363
+ const segment = path.split("/").pop() ?? "";
40364
+ const m = /\.([a-z0-9]{2,5})$/i.exec(segment);
40365
+ return m ? m[1].toLowerCase() : null;
40366
+ };
40367
+ MEDIA_MIME = {
40368
+ mp4: "video/mp4",
40369
+ m4v: "video/mp4",
40370
+ mov: "video/quicktime",
40371
+ webm: "video/webm",
40372
+ mp3: "audio/mpeg",
40373
+ m4a: "audio/mp4",
40374
+ aac: "audio/aac",
40375
+ wav: "audio/wav",
40376
+ ogg: "audio/ogg"
40377
+ };
40378
+ FILE = (name) => ({ uri: `file:///crawl/${name}`, name, mimeType: "audio/m4a", sizeBytes: 4096 });
40379
+ CALL = (peerId, state, clock) => ({
40380
+ callId: "crawl-call-1",
40381
+ kind: "audio",
40382
+ state,
40383
+ peerId,
40384
+ muted: false,
40385
+ route: "earpiece",
40386
+ startedAtMs: clock
40387
+ });
40388
+ MEDIA_STATUS = (clock, autoplay = true) => ({
40389
+ // A real host reports `paused` when a queue is set with `autoplay: false` — which is exactly what
40390
+ // video-courses does. Always answering "playing" exercises the wrong branch and hides the
40391
+ // paused-state behaviour the screen actually has.
40392
+ state: autoplay ? "playing" : "paused",
40393
+ currentIndex: 0,
40394
+ positionMs: 1e3,
40395
+ durationMs: 6e5,
40396
+ rate: 1,
40397
+ bufferedMs: 6e4,
40398
+ queue: [{ id: "lesson-1", title: "Lesson one", url: "https://crawl.invalid/lesson-1.mp4", durationMs: 6e5 }],
40399
+ currentItem: { id: "lesson-1", title: "Lesson one", url: "https://crawl.invalid/lesson-1.mp4", durationMs: 6e5 },
40400
+ startedAtMs: clock
40401
+ });
40402
+ CAPABILITY_SUCCESS = {
40403
+ // --- audio-record ---------------------------------------------------------------------------
40404
+ "capability.audio_record.startSession": (p, ctx) => ({
40405
+ session: {
40406
+ id: "crawl-session-1",
40407
+ mode: p.mode === "background" ? "background" : "foreground",
40408
+ state: "recording",
40409
+ startedAtMs: ctx.clock,
40410
+ segmentCount: 1
40411
+ }
40412
+ }),
40413
+ "capability.audio_record.getSession": (_p, ctx) => ({
40414
+ session: { id: "crawl-session-1", mode: "foreground", state: "recording", startedAtMs: ctx.clock, segmentCount: 1 }
40415
+ }),
40416
+ "capability.audio_record.stopSession": (_p, ctx) => ({
40417
+ session: { id: "crawl-session-1", mode: "foreground", state: "stopped", startedAtMs: ctx.clock, segmentCount: 1 }
40418
+ }),
40419
+ "capability.audio_record.listSegments": (_p, ctx) => ({
40420
+ segments: [
40421
+ { id: "seg-1", sequence: 0, file: FILE("segment-1.m4a"), startedAtMs: ctx.clock, endedAtMs: ctx.clock + 3e4, durationMs: 3e4, transcriptionState: "complete" }
40422
+ ]
40423
+ }),
40424
+ "capability.audio_record.listSessions": (_p, ctx) => ({
40425
+ sessions: [{ id: "crawl-session-1", mode: "foreground", state: "stopped", startedAtMs: ctx.clock, segmentCount: 1 }]
40426
+ }),
40427
+ "capability.audio_record.getPermissionStatus": () => ({ status: "granted" }),
40428
+ "capability.audio_record.requestPermission": () => ({ status: "granted" }),
40429
+ // --- speech ---------------------------------------------------------------------------------
40430
+ "capability.speech.availability": () => ({ recognition: "full", synthesis: "full" }),
40431
+ "capability.speech.transcribeFile": () => ({
40432
+ complete: true,
40433
+ language: "en-US",
40434
+ segments: [{ id: "t-1", text: "crawl transcript", startMs: 0, endMs: 3e4 }]
40435
+ }),
40436
+ "capability.speech.recognizeOnce": () => ({ transcript: "crawl transcript", cancelled: false }),
40437
+ // --- speaker-diarization --------------------------------------------------------------------
40438
+ "capability.speaker_diarization.availability": () => ({ diarization: "full" }),
40439
+ "capability.speaker_diarization.analyzeFile": () => ({
40440
+ speakers: ["speaker-1", "speaker-2"],
40441
+ segments: [
40442
+ { id: "d-1", speakerId: "speaker-1", startMs: 0, endMs: 15e3 },
40443
+ { id: "d-2", speakerId: "speaker-2", startMs: 15e3, endMs: 3e4 }
40444
+ ],
40445
+ complete: true,
40446
+ deferred: false
40447
+ }),
40448
+ // --- on-device-ai ---------------------------------------------------------------------------
40449
+ "capability.on_device_ai.availability": () => ({ textGeneration: "full" }),
40450
+ "capability.on_device_ai.generateText": () => ({ success: true, text: "crawl summary" }),
40451
+ // --- pdf / open-url / share (coach-lab, himi-social) ------------------------------------------
40452
+ "capability.pdf.isAvailable": () => ({ availability: "full" }),
40453
+ "capability.pdf.open": () => ({ opened: true }),
40454
+ "capability.open_url.canOpen": () => ({ canOpen: true }),
40455
+ "capability.open_url.open": () => ({ opened: true }),
40456
+ "capability.share.availability": () => ({ availability: "full" }),
40457
+ "capability.share.share": () => ({ completed: true }),
40458
+ // --- photos (himi-social) ---------------------------------------------------------------------
40459
+ "capability.photos.getSavePermissionStatus": () => ({ status: "granted" }),
40460
+ "capability.photos.saveToLibrary": () => ({ saved: true }),
40461
+ "capability.photos.pick": () => ({
40462
+ items: [{ uri: "file:///crawl/photo-1.jpg", name: "photo-1.jpg", mimeType: "image/jpeg", sizeBytes: 20480 }]
40463
+ }),
40464
+ // --- calls (msgr) -----------------------------------------------------------------------------
40465
+ //
40466
+ // `callStateFrom` drops anything without a non-empty string `callId`, and coerces an unrecognised
40467
+ // `state`/`route` to "failed"/"earpiece" rather than rejecting — so a wrong enum here would not
40468
+ // throw, it would quietly put every call in a failed phase and look like an app bug.
40469
+ "capability.calls.availability": () => ({ availability: "full" }),
40470
+ "capability.calls.getPermissionStatus": () => ({ status: "granted" }),
40471
+ "capability.calls.requestPermission": () => ({ status: "granted" }),
40472
+ "capability.calls.listCalls": () => ({ calls: [] }),
40473
+ "capability.calls.start": (p, ctx) => ({ call: CALL(String(p.peerId ?? "peer-1"), "dialing", ctx.clock) }),
40474
+ "capability.calls.offer": (p, ctx) => ({ call: CALL(String(p.peerId ?? "peer-1"), "ringing", ctx.clock) }),
40475
+ "capability.calls.answer": (_p, ctx) => ({ call: CALL("peer-1", "connected", ctx.clock) }),
40476
+ "capability.calls.getState": (_p, ctx) => ({ call: CALL("peer-1", "connected", ctx.clock) }),
40477
+ "capability.calls.reject": (_p, ctx) => ({ call: CALL("peer-1", "ended", ctx.clock) }),
40478
+ "capability.calls.hangup": (_p, ctx) => ({ call: CALL("peer-1", "ended", ctx.clock) }),
40479
+ "capability.calls.setMuted": (_p, ctx) => ({ call: { ...CALL("peer-1", "connected", ctx.clock), muted: true } }),
40480
+ "capability.calls.setSpeaker": (_p, ctx) => ({ call: { ...CALL("peer-1", "connected", ctx.clock), route: "speaker" } }),
40481
+ // --- media-playback / calendar (video-courses-preview) ----------------------------------------
40482
+ "capability.media_playback.getCapabilities": () => ({ download: true, pictureInPicture: true }),
40483
+ // `autoplay` arrives stringified — the binding sends `String(options.autoplay === true)`.
40484
+ "capability.media_playback.setQueue": (p, ctx) => MEDIA_STATUS(ctx.clock, p.autoplay === true || p.autoplay === "true"),
40485
+ "capability.media_playback.status": (_p, ctx) => MEDIA_STATUS(ctx.clock),
40486
+ "capability.media_playback.getState": (_p, ctx) => MEDIA_STATUS(ctx.clock),
40487
+ // `status` defaults to "failed" when absent and must be one of the MediaDownloadResult literals;
40488
+ // `file` is the handle. Returning `state`/`localUri` modelled a FAILED download while intending
40489
+ // completion, so video-courses took its failure-label branch under a fixture meant to succeed.
40490
+ //
40491
+ // ECHOES THE REQUESTED ITEM. Hard-coding `id: "lesson-1"` overrode the binding's `r?.id ?? item.id`
40492
+ // fallback, so ANY other caller — the demo bundle downloads `demo-tone` — got a lesson-1 handle
40493
+ // back and the crawl labelled the wrong download. A fixture that ignores its request and answers
40494
+ // a constant is the same defect as a screen that renders one.
40495
+ "capability.media_playback.download": (p, ctx) => {
40496
+ const item = decodeItem(p.item);
40497
+ const id = item.id ?? "crawl-item";
40498
+ const ext = MEDIA_EXT(item.url);
40499
+ const name = ext ? `${id}.${ext}` : id;
40500
+ return {
40501
+ id,
40502
+ status: "downloaded",
40503
+ progress: 1,
40504
+ file: { uri: `file:///crawl/${name}`, name, mimeType: ext && MEDIA_MIME[ext] || "application/octet-stream", sizeBytes: 1048576, modifiedAt: ctx.clock }
40505
+ };
40506
+ },
40507
+ "capability.calendar.getPermissionStatus": () => ({ status: "granted" }),
40508
+ "capability.calendar.requestPermission": () => ({ status: "granted" }),
40509
+ "capability.calendar.listEvents": () => ({ events: [] }),
40510
+ "capability.calendar.createEvent": () => ({ id: "crawl-event-1" }),
40511
+ // --- files ----------------------------------------------------------------------------------
40512
+ // `list` reads `r.items` as FileStat[] — `{ handle, modifiedAt }`, not a bare handle — and `stat`
40513
+ // reads `r.stat`. Returning `files`/`file` gave the binding an empty list and a null stat, so the
40514
+ // file flow could not reach its read/remove paths at all. `write` returns the handle itself,
40515
+ // which `toHandle` normalises, NOT an envelope.
40516
+ "capability.files.list": (_p, ctx) => ({ items: [{ handle: FILE("segment-1.m4a"), modifiedAt: ctx.clock }] }),
40517
+ "capability.files.stat": (_p, ctx) => ({ stat: { handle: FILE("segment-1.m4a"), modifiedAt: ctx.clock } }),
40518
+ "capability.files.readText": () => ({ text: "crawl file contents" }),
40519
+ // ECHOES THE REQUESTED PATH. `files.write` returns this object DIRECTLY to `toHandle`, whose
40520
+ // fallback to the requested path only applies when a field is absent — so a hard-coded handle
40521
+ // made every write resolve to the same file, and a consumer passing that handle onward (an export
40522
+ // writing `exports/<id>.gpx`) referenced something that does not exist.
40523
+ "capability.files.write": (p, ctx) => {
40524
+ const path = typeof p.path === "string" && p.path ? p.path : "crawl/written.txt";
40525
+ const name = path.split("/").pop() || path;
40526
+ return { uri: `file:///${path.replace(/^\/+/, "")}`, name, mimeType: typeof p.mimeType === "string" ? p.mimeType : "application/octet-stream", sizeBytes: 1024, modifiedAt: ctx.clock };
40527
+ },
40528
+ "capability.files.remove": () => ({ removed: true })
40529
+ };
40530
+ }
40531
+ });
40532
+
40334
40533
  // ../../core/dev-server/src/crawl-relations.ts
40335
40534
  function inversePartner(action, declared) {
40336
40535
  if (/^toggle/i.test(action)) return null;
@@ -40467,6 +40666,7 @@ __export(screen_crawl_exports, {
40467
40666
  bootAndSnapshotState: () => bootAndSnapshotState,
40468
40667
  bootScreenWorker: () => bootScreenWorker,
40469
40668
  crawlScreen: () => crawlScreen,
40669
+ crawlScreenCapabilitySuccess: () => crawlScreenCapabilitySuccess,
40470
40670
  crawlScreenDeep: () => crawlScreenDeep,
40471
40671
  crawlScreenHostile: () => crawlScreenHostile,
40472
40672
  crawlScreenJourney: () => crawlScreenJourney,
@@ -40746,7 +40946,7 @@ function declaredCapabilitiesOf(descriptor) {
40746
40946
  const list = Array.isArray(lb?.declaredCapabilities) ? lb.declaredCapabilities : [];
40747
40947
  return new Set(list.filter((c) => typeof c === "string"));
40748
40948
  }
40749
- function hostDispatch(localDbSchema, declaredCapabilities = /* @__PURE__ */ new Set()) {
40949
+ function hostDispatch(localDbSchema, declaredCapabilities = /* @__PURE__ */ new Set(), capabilitySuccess = false, clock = 0) {
40750
40950
  return async (action, params) => {
40751
40951
  if (/memberIdentity|member\.identity|currentMember/i.test(action)) {
40752
40952
  return { id: "crawl-member-0001", loggedIn: true, memberId: "crawl-member-0001" };
@@ -40759,6 +40959,10 @@ function hostDispatch(localDbSchema, declaredCapabilities = /* @__PURE__ */ new
40759
40959
  );
40760
40960
  }
40761
40961
  if (cap[1] === "local_database") return localDatabaseAnswer(localDbSchema, cap[2], params ?? {});
40962
+ if (capabilitySuccess) {
40963
+ const answer = CAPABILITY_SUCCESS[action];
40964
+ if (answer) return answer(params ?? {}, { clock });
40965
+ }
40762
40966
  }
40763
40967
  return null;
40764
40968
  };
@@ -40865,9 +41069,13 @@ async function bootScreenWorker(opts) {
40865
41069
  wixCall: opts.wixCall,
40866
41070
  input,
40867
41071
  budgetMs: opts.budgetMs ?? 2e3,
40868
- dispatch: hostDispatch(opts.localDbSchema, declaredCapabilitiesOf(opts.descriptor)),
41072
+ // THE SAME CLOCK THE WORKER IS PINNED TO, one line below. `?? 0` gave the fixtures epoch 1970
41073
+ // while the worker believed it was 2026, so a modelled session carried a timestamp fifty-six
41074
+ // years before the "now" the app computes against — inconsistent rendered dates, and any
41075
+ // time-dependent branch taking the wrong arm.
41076
+ dispatch: hostDispatch(opts.localDbSchema, declaredCapabilitiesOf(opts.descriptor), opts.capabilitySuccess === true, opts.clock ?? CRAWL_CLOCK),
40869
41077
  deviceParity: true,
40870
- clock: opts.clock ?? Date.parse("2026-01-01T00:00:00.000Z"),
41078
+ clock: opts.clock ?? CRAWL_CLOCK,
40871
41079
  seed: opts.seed ?? 1,
40872
41080
  skipLoad: !!(appear && parseWorkerAction(appear.actionId)),
40873
41081
  ...opts.evaluator ? { evaluator: opts.evaluator } : {}
@@ -40941,6 +41149,18 @@ async function withSwallowedRejections(fn) {
40941
41149
  else globalThis.removeEventListener?.("unhandledrejection", swallow);
40942
41150
  }
40943
41151
  }
41152
+ async function crawlScreenCapabilitySuccess(opts) {
41153
+ return withSwallowedRejections(async () => {
41154
+ const declared = declaredCapabilitiesOf(opts.descriptor);
41155
+ const modelled = opts.bundleJs ? capabilityIdsIn(opts.bundleJs).filter((id) => CAPABILITY_SUCCESS[id] && grants(declared, id.split(".")[1])) : [];
41156
+ if (!modelled.length) return { findings: [], modelled: 0 };
41157
+ const r = await crawlScreenInner({ ...opts, capabilitySuccess: true });
41158
+ return {
41159
+ findings: r.findings.map((f) => ({ ...f, axis: f.axis ? `capability:success+${f.axis}` : "capability:success" })),
41160
+ modelled: modelled.length
41161
+ };
41162
+ });
41163
+ }
40944
41164
  async function crawlScreen(opts) {
40945
41165
  return withSwallowedRejections(() => crawlScreenInner(opts));
40946
41166
  }
@@ -40972,6 +41192,7 @@ async function crawlScreenJourney(opts) {
40972
41192
  clock: opts.clock,
40973
41193
  seed: opts.seed,
40974
41194
  localDbSchema: opts.localDbSchema,
41195
+ capabilitySuccess: opts.capabilitySuccess === true,
40975
41196
  ...opts.evaluator ? { evaluator: opts.evaluator } : {}
40976
41197
  });
40977
41198
  const sites = actionSitesForDescriptor(opts.descriptor);
@@ -41145,7 +41366,7 @@ async function crawlScreenInner(opts) {
41145
41366
  actionsSkipped.push({ action: s.actionId, why: "embedded-preview" });
41146
41367
  return false;
41147
41368
  });
41148
- const boot = (skipAppear = false) => bundleJs ? bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, inputOverride: opts.inputOverride, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, skipAppear, localDbSchema: opts.localDbSchema, ...opts.evaluator ? { evaluator: opts.evaluator } : {} }) : null;
41369
+ const boot = (skipAppear = false) => bundleJs ? bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, inputOverride: opts.inputOverride, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, skipAppear, localDbSchema: opts.localDbSchema, capabilitySuccess: opts.capabilitySuccess === true, ...opts.evaluator ? { evaluator: opts.evaluator } : {} }) : null;
41149
41370
  const check = (trigger, state, errors, defects = {}) => {
41150
41371
  for (const [svc, paths] of Object.entries(defects)) {
41151
41372
  for (const p of paths) {
@@ -41422,7 +41643,7 @@ async function crawlScreenHostileInner(opts, variant5) {
41422
41643
  };
41423
41644
  let w;
41424
41645
  try {
41425
- w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, localDbSchema: opts.localDbSchema, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
41646
+ w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, clock: opts.clock, seed: opts.seed, localDbSchema: opts.localDbSchema, capabilitySuccess: opts.capabilitySuccess === true, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
41426
41647
  } catch (e) {
41427
41648
  return [{
41428
41649
  screen: screenId,
@@ -41567,7 +41788,7 @@ async function bootAndSnapshotState(opts) {
41567
41788
  const { call: wixCall } = layeredTransport({ rules: opts.rules, cmsSeed: opts.cmsSeed, canned: opts.canned });
41568
41789
  let w;
41569
41790
  try {
41570
- w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, localDbSchema: opts.localDbSchema, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
41791
+ w = await bootScreenWorker({ bundleJs, descriptor, wixCall, screenId, budgetMs: opts.budgetMs, localDbSchema: opts.localDbSchema, capabilitySuccess: opts.capabilitySuccess === true, ...opts.evaluator ? { evaluator: opts.evaluator } : {} });
41571
41792
  } catch {
41572
41793
  return null;
41573
41794
  }
@@ -41618,7 +41839,8 @@ async function crawlScreenDeep(opts, deep) {
41618
41839
  budgetMs: opts.budgetMs,
41619
41840
  clock: opts.clock,
41620
41841
  seed: opts.seed,
41621
- localDbSchema: opts.localDbSchema
41842
+ localDbSchema: opts.localDbSchema,
41843
+ capabilitySuccess: opts.capabilitySuccess === true
41622
41844
  });
41623
41845
  const pathLabel = (path) => path.map((i) => sites[i].actionId.replace(/^tier5\./, "")).join(" \u2192 ");
41624
41846
  while (queue.length) {
@@ -41780,6 +42002,7 @@ async function crawlScreenRelations(opts) {
41780
42002
  clock: opts.clock,
41781
42003
  seed: opts.seed,
41782
42004
  localDbSchema: opts.localDbSchema,
42005
+ capabilitySuccess: opts.capabilitySuccess === true,
41783
42006
  ...opts.evaluator ? { evaluator: opts.evaluator } : {}
41784
42007
  });
41785
42008
  const replay = async (path, rowFor = () => null) => {
@@ -41920,7 +42143,7 @@ async function crawlScreenRelations(opts) {
41920
42143
  return { findings: dedupe(findings), checked, byKind };
41921
42144
  });
41922
42145
  }
41923
- var ACTION_KEYS, UNTRACKED_ITEMS, NESTED_ITEMS_SEP, REJECT_ALL_MESSAGE, VLQ, WIX_DATA_QUERY, WIX_DATA_ANY, CAPABILITY_ACTION, BLANK_WHEN_BOUND, UNBINDABLE_ROW;
42146
+ var ACTION_KEYS, UNTRACKED_ITEMS, NESTED_ITEMS_SEP, REJECT_ALL_MESSAGE, VLQ, WIX_DATA_QUERY, WIX_DATA_ANY, CAPABILITY_ACTION, CRAWL_CLOCK, BLANK_WHEN_BOUND, UNBINDABLE_ROW;
41924
42147
  var init_screen_crawl = __esm({
41925
42148
  "../../core/dev-server/src/screen-crawl.ts"() {
41926
42149
  init_validate_descriptor_core();
@@ -41930,6 +42153,7 @@ var init_screen_crawl = __esm({
41930
42153
  init_FakeServiceProvider();
41931
42154
  init_actionParams();
41932
42155
  init_implications();
42156
+ init_capability_fixtures();
41933
42157
  init_crawl_relations();
41934
42158
  ACTION_KEYS = [
41935
42159
  "action",
@@ -41950,6 +42174,7 @@ var init_screen_crawl = __esm({
41950
42174
  WIX_DATA_QUERY = /\/wix-data\/v2\/items\/query$/;
41951
42175
  WIX_DATA_ANY = /\/wix-data\//;
41952
42176
  CAPABILITY_ACTION = /^capability\.([a-z0-9_]+)\.([A-Za-z0-9_]+)$/;
42177
+ CRAWL_CLOCK = Date.parse("2026-01-01T00:00:00.000Z");
41953
42178
  BLANK_WHEN_BOUND = {
41954
42179
  Marquee: ["items", "itemsPath", "text"],
41955
42180
  MediaPlayer: ["items", "itemsPath"]
@@ -43530,6 +43755,7 @@ async function runCrawl(opts) {
43530
43755
  const hostileFindings = [];
43531
43756
  const relationFindings = [];
43532
43757
  let relationsChecked = 0;
43758
+ let capabilityModelled = 0;
43533
43759
  const relationsByKind = { inverse: 0, refresh: 0, loadMore: 0, filter: 0 };
43534
43760
  const deepFindings = [];
43535
43761
  const journeyFindings = [];
@@ -43608,6 +43834,20 @@ async function runCrawl(opts) {
43608
43834
  const already = new Set(r.findings.map(keyOf));
43609
43835
  for (const f of rr.findings) if (!already.has(keyOf(f))) relationFindings.push(f);
43610
43836
  }
43837
+ if (deps.crawlScreenCapabilitySuccess && baked.bundleJs) {
43838
+ const cr = await deps.crawlScreenCapabilitySuccess(args);
43839
+ capabilityModelled += cr.modelled;
43840
+ const keyOfC = deps.findingKey ?? ((f) => `${f.invariant}|${f.at ?? ""}|${f.screen}|${f.message}`);
43841
+ const seen = new Set([...r.findings, ...relationFindings].map(keyOfC));
43842
+ for (const f of cr.findings) if (!seen.has(keyOfC(f))) relationFindings.push(f);
43843
+ if (cr.modelled > 0 && deps.crawlScreenRelations) {
43844
+ const rs = await deps.crawlScreenRelations({ ...args, capabilitySuccess: true });
43845
+ const seen2 = new Set([...r.findings, ...relationFindings].map(keyOfC));
43846
+ for (const f of rs.findings) {
43847
+ if (!seen2.has(keyOfC(f))) relationFindings.push({ ...f, axis: f.axis ? `capability:success+${f.axis}` : "capability:success" });
43848
+ }
43849
+ }
43850
+ }
43611
43851
  await finishScreenCoverage();
43612
43852
  }
43613
43853
  const keep = (f) => {
@@ -43748,6 +43988,7 @@ async function runCrawl(opts) {
43748
43988
  ...retired.length ? { retired } : {},
43749
43989
  ...opts.deep && opts.deep >= 2 ? { deep: { depth: opts.deep, ...deepTotals } } : {},
43750
43990
  ...deps.crawlScreenRelations ? { relations: { checked: relationsChecked, byKind: relationsByKind } } : {},
43991
+ ...deps.crawlScreenCapabilitySuccess ? { capabilities: { modelled: capabilityModelled } } : {},
43751
43992
  ...journeyResults.length ? { journeys: journeyResults } : {},
43752
43993
  ...results.some((r) => r.observations) ? { observations: Object.fromEntries(results.filter((r) => r.observations).map((r) => [r.screen, r.observations])) } : {}
43753
43994
  };
@@ -45175,15 +45416,15 @@ function createFunctionDataCapability(options) {
45175
45416
  const decode = (result) => {
45176
45417
  if (!result || typeof result !== "object") return result;
45177
45418
  const output = structuredClone(result);
45178
- const decodeItem = (item) => {
45419
+ const decodeItem2 = (item) => {
45179
45420
  if (!item || typeof item !== "object") return item;
45180
45421
  const record2 = item;
45181
45422
  if (!record2.data || typeof record2.data !== "object" || Array.isArray(record2.data)) return item;
45182
45423
  return { ...record2, data: Object.fromEntries(Object.entries(record2.data).map(([key2, value]) => [physicalFields.get(key2) ?? key2, value])) };
45183
45424
  };
45184
- if (Array.isArray(output.dataItems)) output.dataItems = output.dataItems.map(decodeItem);
45185
- if (Array.isArray(output.items)) output.items = output.items.map(decodeItem);
45186
- if (output.dataItem !== void 0) output.dataItem = decodeItem(output.dataItem);
45425
+ if (Array.isArray(output.dataItems)) output.dataItems = output.dataItems.map(decodeItem2);
45426
+ if (Array.isArray(output.items)) output.items = output.items.map(decodeItem2);
45427
+ if (output.dataItem !== void 0) output.dataItem = decodeItem2(output.dataItem);
45187
45428
  return output;
45188
45429
  };
45189
45430
  return Object.freeze({
@@ -59976,6 +60217,7 @@ async function loadAuthoring() {
59976
60217
  crawlScreenJourney: crawl.crawlScreenJourney,
59977
60218
  crawlScreenHostile: crawl.crawlScreenHostile,
59978
60219
  crawlScreenRelations: crawl.crawlScreenRelations,
60220
+ crawlScreenCapabilitySuccess: crawl.crawlScreenCapabilitySuccess,
59979
60221
  findingKey: crawl.findingKey,
59980
60222
  startWorkerCoverage: cov.startWorkerCoverage,
59981
60223
  uncoveredFunctions: cov.uncoveredFunctions,
@@ -60562,7 +60804,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
60562
60804
  return results.every((result2) => result2.ok) ? 0 : 1;
60563
60805
  }
60564
60806
  const app = await appId(dir);
60565
- const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2, crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2, recordScreenTraffic: recordScreenTraffic2, mintVisitor: mintVisitor2, webWixCall: webWixCall2, freezeTrafficToMocks: freezeTrafficToMocks2, bootAndSnapshotState: bootAndSnapshotState2, renderDescriptorWeb: renderDescriptorWeb2, renderPngBatch: renderPngBatch2, pngAvailable: pngAvailable2, crawlBlockingPasses } = await loadAuthoring();
60807
+ const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2, crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, crawlScreenCapabilitySuccess: crawlScreenCapabilitySuccess2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2, recordScreenTraffic: recordScreenTraffic2, mintVisitor: mintVisitor2, webWixCall: webWixCall2, freezeTrafficToMocks: freezeTrafficToMocks2, bootAndSnapshotState: bootAndSnapshotState2, renderDescriptorWeb: renderDescriptorWeb2, renderPngBatch: renderPngBatch2, pngAvailable: pngAvailable2, crawlBlockingPasses } = await loadAuthoring();
60566
60808
  const { readTestConfig: readTestConfig2, runCrawl: runCrawl2, formatReport: formatReport2, readCannedResponses: readCannedResponses2, makeRecordingWixCall: makeRecordingWixCall2, runRecordPass: runRecordPass2, runShotsPass: runShotsPass2, defaultNetRules: defaultNetRules2, readNetRules: readNetRules2, scopeDescriptors: scopeDescriptors2, writeRecordedMocks: writeRecordedMocks2 } = await Promise.resolve().then(() => (init_test(), test_exports));
60567
60809
  let config;
60568
60810
  try {
@@ -60800,7 +61042,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
60800
61042
  ...deep ? { deep } : {},
60801
61043
  ...offline ? { offline: true } : {},
60802
61044
  ...offline || flags["no-hostile"] === true ? { hostile: false } : {},
60803
- deps: { crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2 }
61045
+ deps: { crawlScreen: crawlScreen2, crawlScreenJourney: crawlScreenJourney2, crawlScreenHostile: crawlScreenHostile2, crawlScreenRelations: crawlScreenRelations2, crawlScreenCapabilitySuccess: crawlScreenCapabilitySuccess2, findingKey: findingKey2, startWorkerCoverage: startWorkerCoverage2, uncoveredFunctions: uncoveredFunctions2, crawlScreenDeep: crawlScreenDeep2, crawlSignature: crawlSignature2 }
60804
61046
  });
60805
61047
  } catch (e) {
60806
61048
  io.error(JSON.stringify({ error: e.message }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.830.0",
3
+ "version": "0.831.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": [
@@ -63,5 +63,5 @@
63
63
  "artifactId": "himalaya-cli"
64
64
  }
65
65
  },
66
- "falconPackageHash": "bdb0d9a1e6584ff150b26a219383712dd907441944ed2cc044ddb3f6"
66
+ "falconPackageHash": "9eca5fa77da9176ee861671ba78d5bc9d24d392c07e23217890cabcd"
67
67
  }