@wix/himalaya-cli 0.1008.0 → 0.1010.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.
package/dist/cli.mjs CHANGED
@@ -1341,7 +1341,7 @@ function sentinelizeIdentity(body, identity) {
1341
1341
  }
1342
1342
  if (identity.name) {
1343
1343
  const re = new RegExp(`\\b(${NAME_FIELDS.join("|")})(["']?\\s*[:=]\\s*)(["'])${escapeRe(identity.name)}\\3`, "g");
1344
- out = out.replace(re, (_m, key2, sep12, q) => `${key2}${sep12}${q}__HIMI_APP_NAME__${q}`);
1344
+ out = out.replace(re, (_m, key2, sep13, q) => `${key2}${sep13}${q}__HIMI_APP_NAME__${q}`);
1345
1345
  }
1346
1346
  return out;
1347
1347
  }
@@ -2341,7 +2341,7 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
2341
2341
  tokenCache.set(cacheKey, fromEnv);
2342
2342
  return fromEnv;
2343
2343
  }
2344
- const token = await new Promise((resolve45, reject) => {
2344
+ const token = await new Promise((resolve46, reject) => {
2345
2345
  let child;
2346
2346
  try {
2347
2347
  child = spawnImpl("wix", [...args]);
@@ -2370,12 +2370,12 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
2370
2370
  child.stdout?.on("data", (d) => {
2371
2371
  out += String(d);
2372
2372
  const m = out.match(TOKEN_RE);
2373
- if (m) done(() => resolve45(m[0]));
2373
+ if (m) done(() => resolve46(m[0]));
2374
2374
  });
2375
2375
  child.stderr?.on("data", (d) => {
2376
2376
  out += String(d);
2377
2377
  const m = out.match(TOKEN_RE);
2378
- if (m) done(() => resolve45(m[0]));
2378
+ if (m) done(() => resolve46(m[0]));
2379
2379
  });
2380
2380
  child.on("error", (e) => done(() => reject(new Error(mintHelp(label2, e.message)))));
2381
2381
  child.on("exit", (code) => done(() => reject(new Error(
@@ -2556,8 +2556,8 @@ function committedProvisioningPath(name) {
2556
2556
  function committedShellFor(path2) {
2557
2557
  const normalized = path2.replace(/\\/g, "/");
2558
2558
  return SHELL_NAMES2.find((name) => {
2559
- const relative9 = committedProvisioningPath(name);
2560
- return normalized === relative9 || normalized.endsWith(`/${relative9}`);
2559
+ const relative10 = committedProvisioningPath(name);
2560
+ return normalized === relative10 || normalized.endsWith(`/${relative10}`);
2561
2561
  });
2562
2562
  }
2563
2563
  function isBrandable(repoRoot2, name) {
@@ -5318,7 +5318,6 @@ function walk(node, registry, path2, out) {
5318
5318
  var SYSTEM_FONT_FAMILY;
5319
5319
  var init_tokens = __esm({
5320
5320
  "../../core/ts/src/tokens.ts"() {
5321
- "use strict";
5322
5321
  SYSTEM_FONT_FAMILY = "$system";
5323
5322
  }
5324
5323
  });
@@ -5344,7 +5343,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
5344
5343
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
5345
5344
  var init_bindings = __esm({
5346
5345
  "../../core/ts/src/bindings.ts"() {
5347
- "use strict";
5348
5346
  BINDING_SIGILS = ["service", "flag", "item", "t"];
5349
5347
  BINDING_SIGIL_RE = new RegExp(
5350
5348
  `^\\$(?:${BINDING_SIGILS.filter((s) => s !== "t").join("|")})\\b|^\\$t:`
@@ -15566,7 +15564,7 @@ async function injectRequest(listener, request) {
15566
15564
  req.headers.host ??= url.host;
15567
15565
  if (body && body.length > 0) req.push(body);
15568
15566
  req.push(null);
15569
- return await new Promise((resolve45, reject) => {
15567
+ return await new Promise((resolve46, reject) => {
15570
15568
  const streamed = () => {
15571
15569
  queueMicrotask(() => {
15572
15570
  req.emit("close");
@@ -15582,7 +15580,7 @@ async function injectRequest(listener, request) {
15582
15580
  else headers2.set(name, value);
15583
15581
  }
15584
15582
  const bodyless = out.status === 204 || out.status === 304 || request.method === "HEAD";
15585
- resolve45(new Response(bodyless ? null : out.body, { status: out.status, headers: headers2 }));
15583
+ resolve46(new Response(bodyless ? null : out.body, { status: out.status, headers: headers2 }));
15586
15584
  }, streamed);
15587
15585
  res.on("inject-error", reject);
15588
15586
  try {
@@ -16277,7 +16275,7 @@ function redactBodyString(body) {
16277
16275
  } catch {
16278
16276
  }
16279
16277
  }
16280
- return body.replace(FORM_ASSIGNMENT_RE, (m, name) => isSensitiveBodyName(name) ? `${name}=${REDACTED}` : m).replace(JSON_FIELD_RE, (m, name, sep12) => isSensitiveBodyName(name) ? `"${name}"${sep12}"${REDACTED}"` : m).replace(JSON_FIELD_UNTERMINATED_RE, (m, name, sep12) => isSensitiveBodyName(name) ? `"${name}"${sep12}"${REDACTED}` : m).replace(BEARER_RE, (_m, s) => `${s} ${REDACTED}`);
16278
+ return body.replace(FORM_ASSIGNMENT_RE, (m, name) => isSensitiveBodyName(name) ? `${name}=${REDACTED}` : m).replace(JSON_FIELD_RE, (m, name, sep13) => isSensitiveBodyName(name) ? `"${name}"${sep13}"${REDACTED}"` : m).replace(JSON_FIELD_UNTERMINATED_RE, (m, name, sep13) => isSensitiveBodyName(name) ? `"${name}"${sep13}"${REDACTED}` : m).replace(BEARER_RE, (_m, s) => `${s} ${REDACTED}`);
16281
16279
  }
16282
16280
  function createWixGatewayState() {
16283
16281
  return { mode: "record", rules: [], traffic: [], clients: /* @__PURE__ */ new Set(), seq: 0, ruleSeq: 0 };
@@ -16874,7 +16872,7 @@ function wixClientIdOf(appConfigJson) {
16874
16872
  if (typeof clientId !== "string" || !clientId) return { error: "no_client_id" };
16875
16873
  return { clientId };
16876
16874
  }
16877
- var WIX_API, ONE_APP_SESSION, OWNER_SCOPED_WIX_HOST, VisitorTokenCache, OWNER_REFRESH_MARGIN_MS, OwnerInstanceCache, OWNER_SITES_QUERY_PATH, OWNER_SITES_COUNT_PATH, OwnerSitesCache;
16875
+ var WIX_API, ONE_APP_SESSION, OWNER_SCOPED_WIX_HOST, VisitorTokenCache, OWNER_REFRESH_MARGIN_MS, OWNER_RENEW_MIN_AGE_MS, OWNER_MINT_TIMEOUT_MS, OwnerInstanceCache, OWNER_SITES_QUERY_PATH, OWNER_SITES_COUNT_PATH, OwnerSitesCache;
16878
16876
  var init_wix_bridge = __esm({
16879
16877
  "../../core/serve-runtime/src/wix-bridge.ts"() {
16880
16878
  init_sha256();
@@ -16912,12 +16910,19 @@ var init_wix_bridge = __esm({
16912
16910
  }
16913
16911
  };
16914
16912
  OWNER_REFRESH_MARGIN_MS = 6e4;
16913
+ OWNER_RENEW_MIN_AGE_MS = 5e3;
16914
+ OWNER_MINT_TIMEOUT_MS = 8e3;
16915
16915
  OwnerInstanceCache = class {
16916
- constructor(fetchImpl = fetch, ttlMs = 5 * 6e4) {
16916
+ constructor(fetchImpl = fetch, ttlMs = 5 * 6e4, mintTimeoutMs = OWNER_MINT_TIMEOUT_MS, elapsedClock = () => performance.now()) {
16917
16917
  this.fetchImpl = fetchImpl;
16918
16918
  this.ttlMs = ttlMs;
16919
+ this.mintTimeoutMs = mintTimeoutMs;
16920
+ this.elapsedClock = elapsedClock;
16919
16921
  }
16920
16922
  cache = /* @__PURE__ */ new Map();
16923
+ /** The one mint on its way per (business, session). Every caller, plain or renewing, joins it:
16924
+ * it started after whatever is cached was minted, so it is the fresh instance. */
16925
+ inflight = /* @__PURE__ */ new Map();
16921
16926
  /** Keyed on the SESSION (`wixSession2`), not the whole cookie header: manage.wix.com's jar churns
16922
16927
  * (analytics, experiments), and keying on all of it re-minted on nearly every call (#3044). A
16923
16928
  * header with no session cookie falls back to itself — callers refuse that case before here. */
@@ -16929,28 +16934,62 @@ ${session}`);
16929
16934
  async instance(msid, cookieHeader, now = Date.now()) {
16930
16935
  return (await this.entry(msid, cookieHeader, now)).instance;
16931
16936
  }
16932
- /** The instance and the time this cache stops trusting it (#3044: the web host caches until then). */
16933
- async entry(msid, cookieHeader, now = Date.now()) {
16937
+ /** The instance and the time this cache stops trusting it (#3044: the web host caches until then).
16938
+ * `renew`: Wix refused the instance this cache handed out (the route's `renew=1`, #3140) — mint a
16939
+ * new one, unless the cached one is younger than OWNER_RENEW_MIN_AGE_MS or a mint is already on
16940
+ * its way, in which case that IS the new one. */
16941
+ async entry(msid, cookieHeader, now = Date.now(), opts = {}) {
16934
16942
  const key2 = this.key(msid, cookieHeader);
16935
- const hit = this.cache.get(key2);
16943
+ const pending = this.inflight.get(key2);
16944
+ if (pending) return { ...await pending };
16945
+ let hit = this.cache.get(key2);
16946
+ if (opts.renew && hit && now - hit.mintedAt >= OWNER_RENEW_MIN_AGE_MS) hit = void 0;
16936
16947
  if (hit && hit.expiresAt - OWNER_REFRESH_MARGIN_MS > now) return { instance: hit.instance, expiresAt: hit.expiresAt };
16937
- const res = await this.fetchImpl(`${ONE_APP_SESSION}/${msid}/signed-instance?signed_instance_type=User`, {
16938
- method: "GET",
16939
- headers: { Cookie: cookieHeader }
16948
+ const mint = this.mint(key2, msid, cookieHeader, now).finally(() => this.inflight.delete(key2));
16949
+ this.inflight.set(key2, mint);
16950
+ return { ...await mint };
16951
+ }
16952
+ async mint(key2, msid, cookieHeader, now) {
16953
+ const startedAt = this.elapsedClock();
16954
+ const abort = new AbortController();
16955
+ let timer;
16956
+ const timedOut = new Promise((_, reject) => {
16957
+ timer = setTimeout(() => {
16958
+ abort.abort();
16959
+ reject(new Error(`owner mint timed out after ${this.mintTimeoutMs}ms`));
16960
+ }, this.mintTimeoutMs);
16940
16961
  });
16941
- const text4 = await res.text();
16942
- let j = {};
16943
16962
  try {
16944
- j = text4 ? JSON.parse(text4) : {};
16945
- } catch {
16963
+ const res = await Promise.race([
16964
+ this.fetchImpl(`${ONE_APP_SESSION}/${msid}/signed-instance?signed_instance_type=User`, {
16965
+ method: "GET",
16966
+ headers: { Cookie: cookieHeader },
16967
+ signal: abort.signal
16968
+ }),
16969
+ timedOut
16970
+ ]);
16971
+ const text4 = await Promise.race([res.text(), timedOut]);
16972
+ let j = {};
16973
+ try {
16974
+ j = text4 ? JSON.parse(text4) : {};
16975
+ } catch {
16976
+ }
16977
+ if (res.status < 200 || res.status >= 300 || !j.signedInstance)
16978
+ throw new Error(`owner mint failed (${res.status})`);
16979
+ const elapsed = Math.max(0, this.elapsedClock() - startedAt);
16980
+ const mintedAt = now + elapsed;
16981
+ const entry = { instance: j.signedInstance, expiresAt: now + Math.floor(elapsed / 1e3) * 1e3 + this.ttlMs };
16982
+ this.cache.set(key2, { ...entry, mintedAt });
16983
+ return entry;
16984
+ } catch (e) {
16985
+ this.cache.delete(key2);
16986
+ throw e;
16987
+ } finally {
16988
+ clearTimeout(timer);
16946
16989
  }
16947
- if (res.status < 200 || res.status >= 300 || !j.signedInstance)
16948
- throw new Error(`owner mint failed (${res.status})`);
16949
- const entry = { instance: j.signedInstance, expiresAt: now + this.ttlMs };
16950
- this.cache.set(key2, entry);
16951
- return { ...entry };
16952
16990
  }
16953
- /** Drop a cached instance (e.g. after a 401 from wixapis) so the next call re-mints. */
16991
+ /** Drop a cached instance so the next call re-mints. The envelope owner branch's own 401 retry;
16992
+ * the route's `renew=1` goes through `entry(…, { renew: true })` instead. */
16954
16993
  invalidate(msid, cookieHeader) {
16955
16994
  this.cache.delete(this.key(msid, cookieHeader));
16956
16995
  }
@@ -17928,12 +17967,12 @@ function finalizeRecording(key2, rec) {
17928
17967
  if (rec.finalize) return rec.finalize;
17929
17968
  rec.finalize = (async () => {
17930
17969
  clearTimeout(rec.autoStop);
17931
- await new Promise((resolve45) => {
17970
+ await new Promise((resolve46) => {
17932
17971
  let done = false;
17933
17972
  const finish2 = () => {
17934
17973
  if (!done) {
17935
17974
  done = true;
17936
- resolve45();
17975
+ resolve46();
17937
17976
  }
17938
17977
  };
17939
17978
  rec.child.once("close", finish2);
@@ -18044,7 +18083,7 @@ var init_preview = __esm({
18044
18083
  DEVICE_LIST_TIMEOUT_MS = 5e3;
18045
18084
  defaultRunner2 = {
18046
18085
  capture(cmd, args, timeoutMs = DEFAULT_CAPTURE_TIMEOUT_MS) {
18047
- return new Promise((resolve45, reject) => {
18086
+ return new Promise((resolve46, reject) => {
18048
18087
  const child = spawn2(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
18049
18088
  const out = [];
18050
18089
  const err = [];
@@ -18066,7 +18105,7 @@ var init_preview = __esm({
18066
18105
  child.stderr.on("data", (b) => err.push(b));
18067
18106
  child.on("error", (e) => settle(reject, e));
18068
18107
  child.on("close", (code) => {
18069
- if (code === 0) settle(resolve45, Buffer.concat(out));
18108
+ if (code === 0) settle(resolve46, Buffer.concat(out));
18070
18109
  else settle(reject, new Error(`${cmd} exited ${code}: ${Buffer.concat(err).toString("utf8")}`));
18071
18110
  });
18072
18111
  });
@@ -23121,8 +23160,8 @@ function ensureCountUpRuntime() {
23121
23160
  const neg = fixed.startsWith("-");
23122
23161
  const body = neg ? fixed.slice(1) : fixed;
23123
23162
  const [int, frac] = body.split(".");
23124
- const sep12 = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
23125
- return (neg ? "-" : "") + sep12 + (frac ? "." + frac : "");
23163
+ const sep13 = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
23164
+ return (neg ? "-" : "") + sep13 + (frac ? "." + frac : "");
23126
23165
  };
23127
23166
  const animateEl = (el) => {
23128
23167
  const node = el;
@@ -28846,7 +28885,7 @@ async function stabilizePngPage(page, scheme) {
28846
28885
  const browser = globalThis;
28847
28886
  browser.document.documentElement.style.colorScheme = selected;
28848
28887
  await browser.document.fonts?.ready;
28849
- await new Promise((resolve45) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve45())));
28888
+ await new Promise((resolve46) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve46())));
28850
28889
  }, scheme);
28851
28890
  }
28852
28891
  async function renderPngBatch(items) {
@@ -32418,7 +32457,7 @@ async function handleWebWix(req, res, state) {
32418
32457
  }
32419
32458
  if (match && (match.rule.kind ?? "mock") === "mock") {
32420
32459
  const mocked = match.rule.response;
32421
- if (mocked.delayMs) await new Promise((resolve45) => setTimeout(resolve45, mocked.delayMs));
32460
+ if (mocked.delayMs) await new Promise((resolve46) => setTimeout(resolve46, mocked.delayMs));
32422
32461
  const responseBody = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
32423
32462
  recordWixTraffic(state.wix, state.appName, state.adminUrl, {
32424
32463
  ts: started,
@@ -33384,8 +33423,8 @@ async function handleActionHandlerBundleGet(res, app) {
33384
33423
  }
33385
33424
  async function serveStatic(req, res, root, prefix) {
33386
33425
  const requested = decodeURIComponent((req.url ?? "").split("?")[0]);
33387
- const relative9 = requested.replace(prefix, "").replace(/^\//, "");
33388
- const safe = normalize3(relative9).replace(/^(\.\.[\/\\])+/, "");
33426
+ const relative10 = requested.replace(prefix, "").replace(/^\//, "");
33427
+ const safe = normalize3(relative10).replace(/^(\.\.[\/\\])+/, "");
33389
33428
  const fullPath = resolve30(root, safe);
33390
33429
  if (!fullPath.startsWith(root)) {
33391
33430
  return send(res, 403, "forbidden");
@@ -34420,12 +34459,12 @@ var init_query = __esm({
34420
34459
  });
34421
34460
 
34422
34461
  // ../../core/dev-server/src/crawl-input.ts
34423
- function resolved(v, resolve45) {
34424
- if (typeof v === "string") return v.startsWith("$service:") ? resolve45(v) : v;
34462
+ function resolved(v, resolve46) {
34463
+ if (typeof v === "string") return v.startsWith("$service:") ? resolve46(v) : v;
34425
34464
  if (Array.isArray(v)) {
34426
34465
  const out = v.flatMap((el) => {
34427
34466
  if (typeof el !== "string" || !el.startsWith("$service:")) return [el];
34428
- const r = resolve45(el);
34467
+ const r = resolve46(el);
34429
34468
  return Array.isArray(r) ? r : [r];
34430
34469
  });
34431
34470
  return out;
@@ -34439,9 +34478,9 @@ function hasRowBinding(props) {
34439
34478
  return itemToken(v) || Array.isArray(v) && v.some(itemToken);
34440
34479
  });
34441
34480
  }
34442
- function declaredOptionIds(props, resolve45) {
34481
+ function declaredOptionIds(props, resolve46) {
34443
34482
  const literal = props.options ?? props.tabs ?? props.chips;
34444
- const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve45) : void 0;
34483
+ const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve46) : void 0;
34445
34484
  const raw = Array.isArray(bound) ? bound : literal;
34446
34485
  if (!Array.isArray(raw)) return [];
34447
34486
  const out = [];
@@ -34484,24 +34523,24 @@ function seedTokens(state, limit = 48) {
34484
34523
  walk2(state, 0);
34485
34524
  return out;
34486
34525
  }
34487
- function synthesizeInput(control, resolve45, tokens) {
34526
+ function synthesizeInput(control, resolve46, tokens) {
34488
34527
  const id = `${control.type}.${control.callback}`;
34489
34528
  const row = SYNTHESIZED_CONTROLS[id];
34490
34529
  if (!row) return null;
34491
34530
  const props = control.props;
34492
34531
  if (hasRowBinding(props)) return null;
34493
34532
  if (row.from === "declared-options") {
34494
- const ids = declaredOptionIds(props, resolve45);
34533
+ const ids = declaredOptionIds(props, resolve46);
34495
34534
  if (!ids.length) return null;
34496
34535
  if (row.encoding === "string-array") {
34497
- const currentRaw2 = resolved(props.selectedIds, resolve45);
34536
+ const currentRaw2 = resolved(props.selectedIds, resolve46);
34498
34537
  const current3 = (Array.isArray(currentRaw2) ? currentRaw2 : []).filter((x) => typeof x === "string");
34499
34538
  const pick4 = ids.find((o) => !current3.includes(o));
34500
34539
  if (pick4 === void 0) return null;
34501
34540
  const value = props.multiSelect === true ? [...current3, pick4] : [pick4];
34502
34541
  return { key: row.key, value, from: row.from, current: current3, control: id };
34503
34542
  }
34504
- const currentRaw = resolved(props.selectedId, resolve45);
34543
+ const currentRaw = resolved(props.selectedId, resolve46);
34505
34544
  const current2 = typeof currentRaw === "string" ? currentRaw : void 0;
34506
34545
  const pick3 = ids.find((o) => o !== current2);
34507
34546
  if (pick3 === void 0) return null;
@@ -34509,7 +34548,7 @@ function synthesizeInput(control, resolve45, tokens) {
34509
34548
  }
34510
34549
  if (!acceptsWords(props) || !acceptsWords(control.wrapper ?? {})) return null;
34511
34550
  const binding2 = typeof props.valuePath === "string" ? props.valuePath : typeof props.value === "string" && props.value.startsWith("$service:") ? props.value : void 0;
34512
- const bound = binding2 === void 0 ? void 0 : resolve45(binding2);
34551
+ const bound = binding2 === void 0 ? void 0 : resolve46(binding2);
34513
34552
  const literal = typeof props.value === "string" && !props.value.startsWith("$") ? props.value : void 0;
34514
34553
  const current = typeof bound === "string" ? bound : typeof bound === "number" ? String(bound) : literal ?? "";
34515
34554
  const max = typeof props.maxLength === "number" && props.maxLength > 0 ? props.maxLength : void 0;
@@ -35767,8 +35806,8 @@ async function crawlScreenInner(opts) {
35767
35806
  if (linkable.has(target)) return true;
35768
35807
  for (const base of linkable) {
35769
35808
  if (target.length > base.length + 1 && target.startsWith(base)) {
35770
- const sep12 = target[base.length];
35771
- if (sep12 === "_" || sep12 === "/") return true;
35809
+ const sep13 = target[base.length];
35810
+ if (sep13 === "_" || sep13 === "/") return true;
35772
35811
  }
35773
35812
  }
35774
35813
  return false;
@@ -42660,7 +42699,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
42660
42699
  const headers2 = Object.fromEntries(new Headers(init.headers).entries());
42661
42700
  const request = url.protocol === "https:" ? httpsRequest : httpRequest;
42662
42701
  const hostname2 = url.hostname.replace(/^\[|\]$/g, "");
42663
- return await new Promise((resolve45, reject) => {
42702
+ return await new Promise((resolve46, reject) => {
42664
42703
  let settled = false;
42665
42704
  const finish2 = (fn) => {
42666
42705
  if (settled) return;
@@ -42697,7 +42736,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
42697
42736
  }
42698
42737
  const responseHeaders = new Headers();
42699
42738
  for (const [key2, value] of Object.entries(response.headers)) if (value !== void 0) responseHeaders.set(key2, Array.isArray(value) ? value.join(", ") : value);
42700
- resolve45(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
42739
+ resolve46(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
42701
42740
  }));
42702
42741
  });
42703
42742
  req.once("error", (error) => finish2(() => reject(error)));
@@ -42997,7 +43036,7 @@ function createLocalTestSandbox() {
42997
43036
  }
42998
43037
  })();
42999
43038
  `;
43000
- return await new Promise((resolve45, reject) => {
43039
+ return await new Promise((resolve46, reject) => {
43001
43040
  const { port1, port2 } = new MessageChannel();
43002
43041
  const serializableContext = {
43003
43042
  auth: context.auth,
@@ -43073,7 +43112,7 @@ function createLocalTestSandbox() {
43073
43112
  timer = setTimeout(() => finish2(() => reject(new SandboxError("timeout", `execution exceeded ${limits.timeoutMs}ms`))), Math.max(1, limits.timeoutMs));
43074
43113
  return;
43075
43114
  }
43076
- if (message.ok) finish2(() => resolve45({ value: message.value, durationMs: Date.now() - started }));
43115
+ if (message.ok) finish2(() => resolve46({ value: message.value, durationMs: Date.now() - started }));
43077
43116
  else finish2(() => reject(new SandboxError("execution_failed", message.message ?? "handler failed")));
43078
43117
  });
43079
43118
  worker.once("error", (error) => finish2(() => reject(new SandboxError("execution_failed", error.message))));
@@ -44203,6 +44242,213 @@ var init_functions = __esm({
44203
44242
  }
44204
44243
  });
44205
44244
 
44245
+ // src/progress.ts
44246
+ var progress_exports = {};
44247
+ __export(progress_exports, {
44248
+ HISTORY_DIR: () => HISTORY_DIR,
44249
+ JOURNEY_STEPS: () => JOURNEY_STEPS,
44250
+ MAX_IMAGE_BYTES: () => MAX_IMAGE_BYTES,
44251
+ MAX_MESSAGE_CHARS: () => MAX_MESSAGE_CHARS,
44252
+ PROGRESS_FILE: () => PROGRESS_FILE,
44253
+ ProgressError: () => ProgressError,
44254
+ appLabel: () => appLabel,
44255
+ appendProgress: () => appendProgress,
44256
+ appleScriptString: () => appleScriptString,
44257
+ archiveBytes: () => archiveBytes,
44258
+ archiveImage: () => archiveImage,
44259
+ journalPath: () => journalPath,
44260
+ notifyDesktop: () => notifyDesktop,
44261
+ parseStep: () => parseStep,
44262
+ readProgress: () => readProgress,
44263
+ summarizeProgress: () => summarizeProgress
44264
+ });
44265
+ import { spawn as spawn3 } from "node:child_process";
44266
+ import { createHash as createHash22 } from "node:crypto";
44267
+ import { appendFileSync, closeSync, existsSync as existsSync46, mkdirSync as mkdirSync23, openSync, readFileSync as readFileSync50, readSync, renameSync as renameSync4, statSync as statSync10, writeFileSync as writeFileSync19 } from "node:fs";
44268
+ import { join as join43, relative as relative6, resolve as resolve40, sep as sep10 } from "node:path";
44269
+ function parseStep(raw) {
44270
+ const v = raw.trim().toLowerCase();
44271
+ if (/^[1-8]$/.test(v)) return JOURNEY_STEPS[Number(v) - 1];
44272
+ return JOURNEY_STEPS.includes(v) ? v : null;
44273
+ }
44274
+ function imageExtension(buf) {
44275
+ const starts = (...bytes2) => bytes2.every((b, i) => buf[i] === b);
44276
+ if (starts(137, 80, 78, 71, 13, 10, 26, 10)) return "png";
44277
+ if (starts(255, 216, 255)) return "jpg";
44278
+ if (starts(71, 73, 70, 56)) return "gif";
44279
+ if (starts(82, 73, 70, 70) && buf.subarray(8, 12).toString("ascii") === "WEBP") return "webp";
44280
+ return null;
44281
+ }
44282
+ function locateImage(dir, src) {
44283
+ for (const candidate of [resolve40(src), resolve40(dir, src)]) {
44284
+ if (existsSync46(candidate) && statSync10(candidate).isFile()) return candidate;
44285
+ }
44286
+ return null;
44287
+ }
44288
+ function archiveImage(dir, src) {
44289
+ const abs = locateImage(dir, src);
44290
+ if (!abs) throw new ProgressError("image_not_found", `no image at ${src} (looked relative to the current directory and to ${dir})`);
44291
+ const size = statSync10(abs).size;
44292
+ if (size > MAX_IMAGE_BYTES) {
44293
+ throw new ProgressError("image_too_large", `${src} is ${size} bytes; a progress image is capped at ${MAX_IMAGE_BYTES} \u2014 render at phone width (--device iphone)`);
44294
+ }
44295
+ const archived = archiveBytes(dir, readFileSync50(abs));
44296
+ if (!archived) throw new ProgressError("not_an_image", `${src} is not a PNG, JPEG, GIF or WebP image`);
44297
+ return { file: archived.file, sha256: archived.sha256, source: src };
44298
+ }
44299
+ function archiveBytes(dir, bytes2) {
44300
+ const ext = imageExtension(bytes2);
44301
+ if (!ext) return null;
44302
+ const sha2565 = createHash22("sha256").update(bytes2).digest("hex");
44303
+ const rel = join43(HISTORY_DIR, `${sha2565}.${ext}`);
44304
+ const dest = join43(dir, rel);
44305
+ if (!existsSync46(dest)) {
44306
+ mkdirSync23(join43(dir, HISTORY_DIR), { recursive: true });
44307
+ const tmp = `${dest}.${process.pid}.tmp`;
44308
+ writeFileSync19(tmp, bytes2);
44309
+ renameSync4(tmp, dest);
44310
+ }
44311
+ return { sha256: sha2565, ext, file: toPosix(rel) };
44312
+ }
44313
+ function appendProgress(dir, input) {
44314
+ const message = input.message.trim();
44315
+ if (!message) throw new ProgressError("message_required", "a progress entry needs a message");
44316
+ if (message.length > MAX_MESSAGE_CHARS) {
44317
+ throw new ProgressError(
44318
+ "message_too_long",
44319
+ `a postcard is a line or two (${message.length} chars; the cap is ${MAX_MESSAGE_CHARS}) \u2014 put the detail in your reply and journal the headline`
44320
+ );
44321
+ }
44322
+ const images = (input.images ?? []).map((src) => archiveImage(dir, src));
44323
+ const entry = {
44324
+ ts: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
44325
+ message,
44326
+ ...input.step ? { step: input.step, stepNumber: JOURNEY_STEPS.indexOf(input.step) + 1 } : {},
44327
+ ...images.length ? { images } : {}
44328
+ };
44329
+ mkdirSync23(join43(dir, ".himi"), { recursive: true });
44330
+ const file = join43(dir, PROGRESS_FILE);
44331
+ appendFileSync(file, `${endsWithNewline(file) ? "" : "\n"}${JSON.stringify(entry)}
44332
+ `);
44333
+ return entry;
44334
+ }
44335
+ function endsWithNewline(file) {
44336
+ if (!existsSync46(file)) return true;
44337
+ const size = statSync10(file).size;
44338
+ if (size === 0) return true;
44339
+ const fd = openSync(file, "r");
44340
+ try {
44341
+ const last = Buffer.alloc(1);
44342
+ readSync(fd, last, 0, 1, size - 1);
44343
+ return last[0] === 10;
44344
+ } finally {
44345
+ closeSync(fd);
44346
+ }
44347
+ }
44348
+ function isEntry(v) {
44349
+ if (!v || typeof v !== "object") return false;
44350
+ const e = v;
44351
+ return typeof e.ts === "string" && typeof e.message === "string";
44352
+ }
44353
+ function readProgress(dir) {
44354
+ const file = join43(dir, PROGRESS_FILE);
44355
+ if (!existsSync46(file)) return { entries: [], skipped: 0 };
44356
+ const entries = [];
44357
+ let skipped = 0;
44358
+ for (const line of readFileSync50(file, "utf8").split("\n")) {
44359
+ if (!line.trim()) continue;
44360
+ try {
44361
+ const parsed = JSON.parse(line);
44362
+ if (isEntry(parsed)) entries.push(parsed);
44363
+ else skipped++;
44364
+ } catch {
44365
+ skipped++;
44366
+ }
44367
+ }
44368
+ return { entries, skipped };
44369
+ }
44370
+ function summarizeProgress(entries) {
44371
+ if (!entries.length) return { count: 0 };
44372
+ const stepped = [...entries].reverse().find((e) => e.step && JOURNEY_STEPS.includes(e.step));
44373
+ const first = entries[0];
44374
+ const last = entries[entries.length - 1];
44375
+ const elapsed = Date.parse(last.ts) - Date.parse(first.ts);
44376
+ return {
44377
+ count: entries.length,
44378
+ ...stepped?.step ? { current: { step: stepped.step, stepNumber: JOURNEY_STEPS.indexOf(stepped.step) + 1, of: JOURNEY_STEPS.length } } : {},
44379
+ startedAt: first.ts,
44380
+ lastAt: last.ts,
44381
+ ...Number.isFinite(elapsed) ? { elapsedMs: elapsed } : {},
44382
+ last
44383
+ };
44384
+ }
44385
+ function appleScriptString(s) {
44386
+ return `"${s.replace(/[\r\n]+/g, " ").replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
44387
+ }
44388
+ function runNotifier(cmd, args) {
44389
+ return new Promise((done) => {
44390
+ let settled = false;
44391
+ const finish2 = (ok) => {
44392
+ if (!settled) {
44393
+ settled = true;
44394
+ clearTimeout(timer);
44395
+ done(ok);
44396
+ }
44397
+ };
44398
+ const child = spawn3(cmd, args, { stdio: "ignore" });
44399
+ const timer = setTimeout(() => {
44400
+ child.kill();
44401
+ finish2(false);
44402
+ }, NOTIFY_TIMEOUT_MS);
44403
+ child.on("error", () => finish2(false));
44404
+ child.on("exit", (code) => finish2(code === 0));
44405
+ });
44406
+ }
44407
+ async function notifyDesktop(title, body, deps = {}) {
44408
+ const platform = deps.platform ?? process.platform;
44409
+ const run2 = deps.run ?? runNotifier;
44410
+ try {
44411
+ if (platform === "darwin") {
44412
+ return await run2("osascript", ["-e", `display notification ${appleScriptString(body)} with title ${appleScriptString(title)}`]);
44413
+ }
44414
+ if (platform === "linux") return await run2("notify-send", [title, body]);
44415
+ } catch {
44416
+ return false;
44417
+ }
44418
+ return false;
44419
+ }
44420
+ function appLabel(dir) {
44421
+ try {
44422
+ const manifest = JSON.parse(readFileSync50(join43(dir, "himalaya.content.json"), "utf8"));
44423
+ return typeof manifest.name === "string" && manifest.name ? manifest.name : null;
44424
+ } catch {
44425
+ return null;
44426
+ }
44427
+ }
44428
+ function journalPath(dir) {
44429
+ const abs = join43(dir, PROGRESS_FILE);
44430
+ const rel = relative6(process.cwd(), abs);
44431
+ return rel && !rel.startsWith("..") ? rel : abs;
44432
+ }
44433
+ var JOURNEY_STEPS, PROGRESS_FILE, HISTORY_DIR, MAX_MESSAGE_CHARS, MAX_IMAGE_BYTES, ProgressError, toPosix, NOTIFY_TIMEOUT_MS;
44434
+ var init_progress = __esm({
44435
+ "src/progress.ts"() {
44436
+ JOURNEY_STEPS = ["discover", "classify", "plan", "implement", "brand", "validate", "review", "download"];
44437
+ PROGRESS_FILE = join43(".himi", "progress.jsonl");
44438
+ HISTORY_DIR = join43(".himi", "history");
44439
+ MAX_MESSAGE_CHARS = 500;
44440
+ MAX_IMAGE_BYTES = 10 * 1024 * 1024;
44441
+ ProgressError = class extends Error {
44442
+ constructor(code, message) {
44443
+ super(message);
44444
+ this.code = code;
44445
+ }
44446
+ };
44447
+ toPosix = (p) => p.split(sep10).join("/");
44448
+ NOTIFY_TIMEOUT_MS = 3e3;
44449
+ }
44450
+ });
44451
+
44206
44452
  // src/native-decode.ts
44207
44453
  var native_decode_exports = {};
44208
44454
  __export(native_decode_exports, {
@@ -44218,9 +44464,9 @@ __export(native_decode_exports, {
44218
44464
  runNativeDecode: () => runNativeDecode
44219
44465
  });
44220
44466
  import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
44221
- import { existsSync as existsSync46, mkdtempSync as mkdtempSync2, readFileSync as readFileSync50, rmSync as rmSync9, writeFileSync as writeFileSync19 } from "node:fs";
44467
+ import { existsSync as existsSync47, mkdtempSync as mkdtempSync2, readFileSync as readFileSync51, rmSync as rmSync9, writeFileSync as writeFileSync20 } from "node:fs";
44222
44468
  import { tmpdir as tmpdir3 } from "node:os";
44223
- import { join as join43 } from "node:path";
44469
+ import { join as join44 } from "node:path";
44224
44470
  import { fileURLToPath as fileURLToPath20 } from "node:url";
44225
44471
  function nativeDecodePackageDir() {
44226
44472
  return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
@@ -44230,8 +44476,8 @@ function nativeDecodeAndroidHarnessDir() {
44230
44476
  }
44231
44477
  function nativeOracleShipped() {
44232
44478
  return {
44233
- ios: existsSync46(join43(nativeDecodePackageDir(), "Package.swift")),
44234
- android: existsSync46(join43(nativeDecodeAndroidHarnessDir(), "gradlew"))
44479
+ ios: existsSync47(join44(nativeDecodePackageDir(), "Package.swift")),
44480
+ android: existsSync47(join44(nativeDecodeAndroidHarnessDir(), "gradlew"))
44235
44481
  };
44236
44482
  }
44237
44483
  function detectNativeDecode(options = {}) {
@@ -44242,7 +44488,7 @@ function detectNativeDecode(options = {}) {
44242
44488
  return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
44243
44489
  }
44244
44490
  if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
44245
- const packageAvailable = options.packageAvailable ?? existsSync46(join43(packageDir, "Package.swift"));
44491
+ const packageAvailable = options.packageAvailable ?? existsSync47(join44(packageDir, "Package.swift"));
44246
44492
  if (!packageAvailable) {
44247
44493
  return {
44248
44494
  platform: "ios",
@@ -44254,7 +44500,7 @@ function detectNativeDecode(options = {}) {
44254
44500
  }
44255
44501
  function localPropertiesSdk(harnessDir) {
44256
44502
  try {
44257
- const match = readFileSync50(join43(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
44503
+ const match = readFileSync51(join44(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
44258
44504
  return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
44259
44505
  } catch {
44260
44506
  return null;
@@ -44262,8 +44508,8 @@ function localPropertiesSdk(harnessDir) {
44262
44508
  }
44263
44509
  function detectAndroidNativeDecode(options = {}) {
44264
44510
  const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
44265
- const gradlew = join43(harnessDir, "gradlew");
44266
- const gradlewAvailable = options.gradlewAvailable ?? existsSync46(gradlew);
44511
+ const gradlew = join44(harnessDir, "gradlew");
44512
+ const gradlewAvailable = options.gradlewAvailable ?? existsSync47(gradlew);
44267
44513
  if (!gradlewAvailable) {
44268
44514
  return {
44269
44515
  platform: "android",
@@ -44273,7 +44519,7 @@ function detectAndroidNativeDecode(options = {}) {
44273
44519
  }
44274
44520
  const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
44275
44521
  const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
44276
- const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync46(sdk));
44522
+ const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync47(sdk));
44277
44523
  if (!sdkAvailable) {
44278
44524
  return {
44279
44525
  platform: "android",
@@ -44345,14 +44591,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
44345
44591
  return verdicts;
44346
44592
  }
44347
44593
  function runNativeDecode(options) {
44348
- const descriptorDir = mkdtempSync2(join43(tmpdir3(), "himi-native-decode-"));
44594
+ const descriptorDir = mkdtempSync2(join44(tmpdir3(), "himi-native-decode-"));
44349
44595
  const startedAt = Date.now();
44350
44596
  try {
44351
44597
  for (const descriptor of options.descriptors) {
44352
44598
  if (typeof descriptor.descriptorJson !== "string") {
44353
44599
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
44354
44600
  }
44355
- writeFileSync19(join43(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44601
+ writeFileSync20(join44(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44356
44602
  }
44357
44603
  options.progress?.("building cached Swift oracle");
44358
44604
  execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
@@ -44364,7 +44610,7 @@ function runNativeDecode(options) {
44364
44610
  encoding: "utf8"
44365
44611
  }).trim();
44366
44612
  options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
44367
- const stdout = execFileSync5(join43(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
44613
+ const stdout = execFileSync5(join44(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
44368
44614
  stdio: ["ignore", "pipe", "pipe"],
44369
44615
  encoding: "utf8"
44370
44616
  });
@@ -44382,15 +44628,15 @@ function runNativeDecode(options) {
44382
44628
  }
44383
44629
  }
44384
44630
  function runAndroidNativeDecode(options) {
44385
- const descriptorDir = mkdtempSync2(join43(tmpdir3(), "himi-native-decode-android-"));
44386
- const outputPath = join43(descriptorDir, "verdicts.ndjson");
44631
+ const descriptorDir = mkdtempSync2(join44(tmpdir3(), "himi-native-decode-android-"));
44632
+ const outputPath = join44(descriptorDir, "verdicts.ndjson");
44387
44633
  const startedAt = Date.now();
44388
44634
  try {
44389
44635
  for (const descriptor of options.descriptors) {
44390
44636
  if (typeof descriptor.descriptorJson !== "string") {
44391
44637
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
44392
44638
  }
44393
- writeFileSync19(join43(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44639
+ writeFileSync20(join44(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44394
44640
  }
44395
44641
  options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
44396
44642
  execFileSync5(options.gradlew, [
@@ -44405,7 +44651,7 @@ function runAndroidNativeDecode(options) {
44405
44651
  stdio: ["ignore", "ignore", "pipe"],
44406
44652
  encoding: "utf8"
44407
44653
  });
44408
- const stdout = readFileSync50(outputPath, "utf8");
44654
+ const stdout = readFileSync51(outputPath, "utf8");
44409
44655
  return {
44410
44656
  platform: "android",
44411
44657
  verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
@@ -44474,15 +44720,15 @@ __export(browser_authoring_exports, {
44474
44720
  sdkSubpathReader: () => sdkSubpathReader
44475
44721
  });
44476
44722
  import { createServer as createServer3 } from "node:http";
44477
- import { createHash as createHash22, randomBytes as randomBytes4 } from "node:crypto";
44723
+ import { createHash as createHash23, randomBytes as randomBytes4 } from "node:crypto";
44478
44724
  import { execFile as execFile2 } from "node:child_process";
44479
- import { existsSync as existsSync47, readdirSync as readdirSync23, readFileSync as readFileSync51, realpathSync as realpathSync4, statSync as statSync10 } from "node:fs";
44480
- import { join as join44, posix, relative as relative6, sep as sep10 } from "node:path";
44725
+ import { existsSync as existsSync48, readdirSync as readdirSync23, readFileSync as readFileSync52, realpathSync as realpathSync4, statSync as statSync11 } from "node:fs";
44726
+ import { join as join45, posix, relative as relative7, sep as sep11 } from "node:path";
44481
44727
  function humanMs(ms) {
44482
44728
  return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
44483
44729
  }
44484
44730
  function collectWorkerSources(tier5SrcDir, bundleName) {
44485
- const root = join44(tier5SrcDir, bundleName);
44731
+ const root = join45(tier5SrcDir, bundleName);
44486
44732
  const files = {};
44487
44733
  const visitedDirs = /* @__PURE__ */ new Set();
44488
44734
  const walk2 = (abs, rel) => {
@@ -44490,16 +44736,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
44490
44736
  if (visitedDirs.has(real)) return;
44491
44737
  visitedDirs.add(real);
44492
44738
  for (const name of readdirSync23(abs).sort()) {
44493
- const childAbs = join44(abs, name);
44739
+ const childAbs = join45(abs, name);
44494
44740
  const childRel = posix.join(rel, name);
44495
- if (statSync10(childAbs).isDirectory()) {
44741
+ if (statSync11(childAbs).isDirectory()) {
44496
44742
  walk2(childAbs, childRel);
44497
44743
  } else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
44498
- files[childRel] = readFileSync51(childAbs, "utf8");
44744
+ files[childRel] = readFileSync52(childAbs, "utf8");
44499
44745
  }
44500
44746
  }
44501
44747
  };
44502
- if (!existsSync47(root)) return null;
44748
+ if (!existsSync48(root)) return null;
44503
44749
  walk2(root, `/tier5-src/${bundleName}`);
44504
44750
  const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
44505
44751
  if (!entry) return null;
@@ -44516,20 +44762,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
44516
44762
  const spec = m[1];
44517
44763
  const virtual = posix.normalize(posix.join(dir, spec));
44518
44764
  if (!virtual.startsWith("/tier5-src/")) continue;
44519
- const onDisk = join44(tier5SrcDir, virtual.slice("/tier5-src/".length));
44765
+ const onDisk = join45(tier5SrcDir, virtual.slice("/tier5-src/".length));
44520
44766
  const candidates = [
44521
44767
  onDisk,
44522
44768
  `${onDisk}.ts`,
44523
44769
  `${onDisk}.js`,
44524
44770
  onDisk.replace(/\.js$/, ".ts"),
44525
- join44(onDisk, "index.ts"),
44526
- join44(onDisk, "index.js")
44771
+ join45(onDisk, "index.ts"),
44772
+ join45(onDisk, "index.js")
44527
44773
  ];
44528
44774
  for (const abs of candidates) {
44529
- if (!existsSync47(abs) || statSync10(abs).isDirectory()) continue;
44530
- const key2 = `/tier5-src/${relative6(tier5SrcDir, abs).split(sep10).join(posix.sep)}`;
44775
+ if (!existsSync48(abs) || statSync11(abs).isDirectory()) continue;
44776
+ const key2 = `/tier5-src/${relative7(tier5SrcDir, abs).split(sep11).join(posix.sep)}`;
44531
44777
  if (key2 in files) break;
44532
- files[key2] = readFileSync51(abs, "utf8");
44778
+ files[key2] = readFileSync52(abs, "utf8");
44533
44779
  queue.push(key2);
44534
44780
  break;
44535
44781
  }
@@ -44561,10 +44807,10 @@ function collectSdkModules(files, resolveSubpath) {
44561
44807
  for (const source of Object.values(files)) visit(source);
44562
44808
  return { modules, unsupported };
44563
44809
  }
44564
- function sdkSubpathReader(resolve45) {
44810
+ function sdkSubpathReader(resolve46) {
44565
44811
  return (sub) => {
44566
44812
  try {
44567
- return readFileSync51(resolve45(`@wix/himalaya/${sub}`), "utf8");
44813
+ return readFileSync52(resolve46(`@wix/himalaya/${sub}`), "utf8");
44568
44814
  } catch {
44569
44815
  return null;
44570
44816
  }
@@ -44574,7 +44820,7 @@ function encodeJob(job) {
44574
44820
  return Buffer.from(JSON.stringify(job), "utf8").toString("base64");
44575
44821
  }
44576
44822
  function mintToken2(payload, nonce = randomBytes4(16).toString("hex")) {
44577
- const digest2 = createHash22("sha256").update(payload, "utf8").digest("base64url");
44823
+ const digest2 = createHash23("sha256").update(payload, "utf8").digest("base64url");
44578
44824
  return `${nonce}.${digest2}`;
44579
44825
  }
44580
44826
  function defaultOpenBrowser2(url) {
@@ -44645,7 +44891,7 @@ async function runBrowserAuthoring(opts) {
44645
44891
  const token = mintToken2(payload);
44646
44892
  const unusable = await probeAuthoringPage(opts.authoringBase, opts.fetchImpl, opts.probeTimeoutMs);
44647
44893
  if (unusable) throw new Error(unusable);
44648
- return await new Promise((resolve45, reject) => {
44894
+ return await new Promise((resolve46, reject) => {
44649
44895
  let settled = false;
44650
44896
  let url = "";
44651
44897
  const server = createServer3();
@@ -44697,7 +44943,7 @@ async function runBrowserAuthoring(opts) {
44697
44943
  }
44698
44944
  res.writeHead(200, { "content-type": "text/plain" }).end("ok");
44699
44945
  const report2 = body.result;
44700
- finish2(() => resolve45({ report: report2, url }));
44946
+ finish2(() => resolve46({ report: report2, url }));
44701
44947
  })();
44702
44948
  });
44703
44949
  server.on("error", (e) => finish2(() => reject(e)));
@@ -44738,8 +44984,8 @@ __export(coverage_exports, {
44738
44984
  suppressedNativeKeys: () => suppressedNativeKeys,
44739
44985
  trendAndStore: () => trendAndStore
44740
44986
  });
44741
- import { existsSync as existsSync48, mkdirSync as mkdirSync23, readFileSync as readFileSync52, writeFileSync as writeFileSync20 } from "node:fs";
44742
- import { dirname as dirname26, join as join45 } from "node:path";
44987
+ import { existsSync as existsSync49, mkdirSync as mkdirSync24, readFileSync as readFileSync53, writeFileSync as writeFileSync21 } from "node:fs";
44988
+ import { dirname as dirname26, join as join46 } from "node:path";
44743
44989
  function suppressedNativeKeys(oracle) {
44744
44990
  return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
44745
44991
  }
@@ -44909,11 +45155,11 @@ function assembleLedger(r, options = {}) {
44909
45155
  return out;
44910
45156
  }
44911
45157
  function trendAndStore(dir, entries, suppressed) {
44912
- const p = join45(dir, LEDGER_FILE);
45158
+ const p = join46(dir, LEDGER_FILE);
44913
45159
  let previous = null;
44914
45160
  try {
44915
- if (existsSync48(p)) {
44916
- const parsed = JSON.parse(readFileSync52(p, "utf8"));
45161
+ if (existsSync49(p)) {
45162
+ const parsed = JSON.parse(readFileSync53(p, "utf8"));
44917
45163
  if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
44918
45164
  }
44919
45165
  } catch {
@@ -44921,8 +45167,8 @@ function trendAndStore(dir, entries, suppressed) {
44921
45167
  const current = entries.map((e) => e.key);
44922
45168
  const stored = [.../* @__PURE__ */ new Set([...current, ...(previous ?? []).filter((key2) => (suppressed ?? []).includes(key2))])];
44923
45169
  try {
44924
- mkdirSync23(dirname26(p), { recursive: true });
44925
- writeFileSync20(p, JSON.stringify({ keys: stored, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
45170
+ mkdirSync24(dirname26(p), { recursive: true });
45171
+ writeFileSync21(p, JSON.stringify({ keys: stored, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
44926
45172
  } catch {
44927
45173
  return null;
44928
45174
  }
@@ -44952,11 +45198,11 @@ function formatLedger(entries, trend) {
44952
45198
  return out.join("\n");
44953
45199
  }
44954
45200
  function diffAndStoreObservations(dir, current) {
44955
- const p = join45(dir, OBS_FILE);
45201
+ const p = join46(dir, OBS_FILE);
44956
45202
  let previous = null;
44957
45203
  try {
44958
- if (existsSync48(p)) {
44959
- const parsed = JSON.parse(readFileSync52(p, "utf8"));
45204
+ if (existsSync49(p)) {
45205
+ const parsed = JSON.parse(readFileSync53(p, "utf8"));
44960
45206
  if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
44961
45207
  (v) => Array.isArray(v) && v.every((l) => typeof l === "string")
44962
45208
  )) {
@@ -44966,8 +45212,8 @@ function diffAndStoreObservations(dir, current) {
44966
45212
  } catch {
44967
45213
  }
44968
45214
  try {
44969
- mkdirSync23(dirname26(p), { recursive: true });
44970
- writeFileSync20(p, JSON.stringify({ screens: current, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
45215
+ mkdirSync24(dirname26(p), { recursive: true });
45216
+ writeFileSync21(p, JSON.stringify({ screens: current, ts: (/* @__PURE__ */ new Date()).toISOString() }, null, 2));
44971
45217
  } catch {
44972
45218
  return null;
44973
45219
  }
@@ -45005,8 +45251,8 @@ var LEDGER_FILE, OBS_FILE;
45005
45251
  var init_coverage = __esm({
45006
45252
  "src/coverage.ts"() {
45007
45253
  init_native_decode();
45008
- LEDGER_FILE = join45(".himi", "test-ledger.json");
45009
- OBS_FILE = join45(".himi", "test-observations.json");
45254
+ LEDGER_FILE = join46(".himi", "test-ledger.json");
45255
+ OBS_FILE = join46(".himi", "test-observations.json");
45010
45256
  }
45011
45257
  });
45012
45258
 
@@ -45017,11 +45263,11 @@ __export(design_kits_exports, {
45017
45263
  kitsDir: () => kitsDir,
45018
45264
  listKits: () => listKits2
45019
45265
  });
45020
- import { existsSync as existsSync49, readFileSync as readFileSync53, readdirSync as readdirSync24 } from "node:fs";
45021
- import { join as join46, basename as basename10 } from "node:path";
45266
+ import { existsSync as existsSync50, readFileSync as readFileSync54, readdirSync as readdirSync24 } from "node:fs";
45267
+ import { join as join47, basename as basename10 } from "node:path";
45022
45268
  import { fileURLToPath as fileURLToPath21 } from "node:url";
45023
45269
  function kitsDir() {
45024
- return KIT_DIR_CANDIDATES.find((p) => existsSync49(p));
45270
+ return KIT_DIR_CANDIDATES.find((p) => existsSync50(p));
45025
45271
  }
45026
45272
  function listKits2() {
45027
45273
  const dir = kitsDir();
@@ -45045,7 +45291,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
45045
45291
  if (!kits.includes(name)) {
45046
45292
  return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
45047
45293
  }
45048
- const raw = readFileSync53(join46(dir, `${name}.json`), "utf8");
45294
+ const raw = readFileSync54(join47(dir, `${name}.json`), "utf8");
45049
45295
  let parsed;
45050
45296
  try {
45051
45297
  parsed = JSON.parse(raw);
@@ -45069,9 +45315,9 @@ var init_design_kits = __esm({
45069
45315
  "src/design-kits.ts"() {
45070
45316
  KIT_DIR_CANDIDATES = [
45071
45317
  // in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
45072
- join46(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
45318
+ join47(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
45073
45319
  // published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
45074
- join46(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
45320
+ join47(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
45075
45321
  ];
45076
45322
  }
45077
45323
  });
@@ -45085,11 +45331,11 @@ __export(assets_exports, {
45085
45331
  removeAssetPayload: () => removeAssetPayload,
45086
45332
  verifyReport: () => verifyReport
45087
45333
  });
45088
- import { readFileSync as readFileSync54 } from "node:fs";
45334
+ import { readFileSync as readFileSync55 } from "node:fs";
45089
45335
  import { basename as basename11 } from "node:path";
45090
45336
  function declaredAssets(dir) {
45091
45337
  return collectAssets(dir).map((a) => {
45092
- const bytes2 = readFileSync54(a.path);
45338
+ const bytes2 = readFileSync55(a.path);
45093
45339
  return {
45094
45340
  name: a.name,
45095
45341
  sha256: assetSha256(bytes2),
@@ -45166,7 +45412,7 @@ function verifyReport(dir, app, manifest) {
45166
45412
  };
45167
45413
  }
45168
45414
  function addAssetPayload(manifest, filePath, opts) {
45169
- const bytes2 = readFileSync54(filePath);
45415
+ const bytes2 = readFileSync55(filePath);
45170
45416
  const name = opts.name ?? basename11(filePath);
45171
45417
  const sha2565 = assetSha256(bytes2);
45172
45418
  const record2 = {
@@ -45863,9 +46109,9 @@ ${releaseId}`;
45863
46109
  if (!isSafeMsid(msid)) return json3(400, { error: "webwix_owner_bad_msid" });
45864
46110
  const cookie = request.headers.get("cookie") ?? "";
45865
46111
  if (!/wixSession2=/.test(cookie)) return json3(401, { error: "webwix_owner_no_session" });
45866
- if (url.searchParams.get("renew") === "1") webwixOwnerInstances.invalidate(msid, cookie);
46112
+ const renew = url.searchParams.get("renew") === "1";
45867
46113
  try {
45868
- const entry = await webwixOwnerInstances.entry(msid, cookie);
46114
+ const entry = await webwixOwnerInstances.entry(msid, cookie, Date.now(), { renew });
45869
46115
  return json3(200, { ...entry, expiresInMs: Math.max(0, entry.expiresAt - Date.now()) }, { "cache-control": "no-store" });
45870
46116
  } catch (e) {
45871
46117
  const msg = String(e?.message ?? e);
@@ -46642,19 +46888,19 @@ var init_preview_assets_generated = __esm({
46642
46888
  "../../packages/serve/src/preview-assets.generated.ts"() {
46643
46889
  init_preview_assets_format();
46644
46890
  PREVIEW_ASSET_MANIFEST = [
46645
- { key: "assets/index-BKft9wm1.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1012166, sha256: "3a87519baabf67cecf163d20ea1eaaeba288fdeab2fc00cc3d22f09b6a29a194" },
46646
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1012174, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
46647
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1103098, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
46648
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1194082, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
46649
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1285062, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
46650
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1375934, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
46651
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1466914, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
46652
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1575550, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
46653
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1684634, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
46654
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1793682, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
46655
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1901382, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
46656
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1989490, length: 4448, sha256: "71627ade6c0e47a8956b4841c1f6d644fee50a9a4ca9e6d9106b589e84891bd7" },
46657
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1993938, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
46891
+ { key: "assets/index-tPdez24X.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1012335, sha256: "9af3d246668e3b69acbdbaebf33129e45f99fdaa32230f782b675fcdeeb38773" },
46892
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1012343, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
46893
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1103267, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
46894
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1194251, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
46895
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1285231, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
46896
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1376103, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
46897
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1467083, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
46898
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1575719, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
46899
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1684803, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
46900
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1793851, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
46901
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1901551, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
46902
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1989659, length: 4448, sha256: "c4235c7ba4a7bdea831017711424c9e4f8a8b33466bef53f4def1bfcea6a3b15" },
46903
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 1994107, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
46658
46904
  ];
46659
46905
  }
46660
46906
  });
@@ -46670,11 +46916,11 @@ __export(run_exports, {
46670
46916
  runPackage: () => runPackage,
46671
46917
  withoutProdServe: () => withoutProdServe
46672
46918
  });
46673
- import { cpSync as cpSync2, existsSync as existsSync50, mkdirSync as mkdirSync24, mkdtempSync as mkdtempSync3, readFileSync as readFileSync55, rmSync as rmSync10, statSync as statSync11 } from "node:fs";
46919
+ import { cpSync as cpSync2, existsSync as existsSync51, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, readFileSync as readFileSync56, rmSync as rmSync10, statSync as statSync12 } from "node:fs";
46674
46920
  import { tmpdir as tmpdir4 } from "node:os";
46675
- import { dirname as dirname27, join as join47 } from "node:path";
46921
+ import { dirname as dirname27, join as join48 } from "node:path";
46676
46922
  import { fileURLToPath as fileURLToPath22 } from "node:url";
46677
- import { spawn as spawn3 } from "node:child_process";
46923
+ import { spawn as spawn4 } from "node:child_process";
46678
46924
  function makePackageRunHandler(opts) {
46679
46925
  return makeRunHandler({
46680
46926
  store: new FileReleaseStore(opts.releaseRoot),
@@ -46691,9 +46937,9 @@ async function fetchBytes(url) {
46691
46937
  }
46692
46938
  async function resolvePackage(source, workDir) {
46693
46939
  const isUrl2 = /^https?:\/\//i.test(source);
46694
- if (!isUrl2 && existsSync50(source) && statSync11(source).isDirectory()) {
46695
- const appDirManifest = join47(source, "release-manifest.json");
46696
- if (existsSync50(appDirManifest)) {
46940
+ if (!isUrl2 && existsSync51(source) && statSync12(source).isDirectory()) {
46941
+ const appDirManifest = join48(source, "release-manifest.json");
46942
+ if (existsSync51(appDirManifest)) {
46697
46943
  const opened2 = openPackageDir(source);
46698
46944
  if (!opened2.validation.ok) {
46699
46945
  throw new Error(`package is not valid:
@@ -46702,10 +46948,10 @@ async function resolvePackage(source, workDir) {
46702
46948
  const app2 = opened2.header?.app ?? opened2.manifest?.app;
46703
46949
  if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
46704
46950
  if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
46705
- const root2 = workDir ?? mkdtempSync3(join47(tmpdir4(), "himi-run-"));
46706
- const target = join47(root2, app2);
46707
- if (join47(source) !== target) {
46708
- mkdirSync24(root2, { recursive: true });
46951
+ const root2 = workDir ?? mkdtempSync3(join48(tmpdir4(), "himi-run-"));
46952
+ const target = join48(root2, app2);
46953
+ if (join48(source) !== target) {
46954
+ mkdirSync25(root2, { recursive: true });
46709
46955
  rmSync10(target, { recursive: true, force: true });
46710
46956
  cpSync2(source, target, { recursive: true });
46711
46957
  }
@@ -46721,8 +46967,8 @@ async function resolvePackage(source, workDir) {
46721
46967
  }
46722
46968
  throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
46723
46969
  }
46724
- const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync55(source);
46725
- const root = workDir ?? mkdtempSync3(join47(tmpdir4(), "himi-run-"));
46970
+ const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync56(source);
46971
+ const root = workDir ?? mkdtempSync3(join48(tmpdir4(), "himi-run-"));
46726
46972
  const { app, appDir: appDir2 } = unpackTo(bytes2, root);
46727
46973
  const opened = openPackageDir(appDir2);
46728
46974
  if (!opened.validation.ok) {
@@ -46745,14 +46991,14 @@ async function loadPreviewAssets() {
46745
46991
  const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
46746
46992
  const here = dirname27(fileURLToPath22(import.meta.url));
46747
46993
  const candidates = [
46748
- join47(here, "preview-assets.generated.bin"),
46994
+ join48(here, "preview-assets.generated.bin"),
46749
46995
  // published: copied next to the bundled CLI
46750
- join47(here, "../../../packages/serve/src/preview-assets.generated.bin")
46996
+ join48(here, "../../../packages/serve/src/preview-assets.generated.bin")
46751
46997
  // in-repo checkout
46752
46998
  ];
46753
46999
  for (const path2 of candidates) {
46754
- if (!existsSync50(path2)) continue;
46755
- const blob = readFileSync55(path2);
47000
+ if (!existsSync51(path2)) continue;
47001
+ const blob = readFileSync56(path2);
46756
47002
  return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
46757
47003
  }
46758
47004
  return /* @__PURE__ */ new Map();
@@ -46769,7 +47015,7 @@ function packageUrl(origin, app, opts = {}) {
46769
47015
  function openBrowser(url) {
46770
47016
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
46771
47017
  try {
46772
- spawn3(cmd, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" }).unref();
47018
+ spawn4(cmd, [url], { stdio: "ignore", detached: true, shell: process.platform === "win32" }).unref();
46773
47019
  } catch {
46774
47020
  }
46775
47021
  }
@@ -46834,19 +47080,19 @@ __export(run_browser_exports, {
46834
47080
  runInBrowser: () => runInBrowser
46835
47081
  });
46836
47082
  import { createServer as createServer5 } from "node:http";
46837
- import { existsSync as existsSync51, readFileSync as readFileSync56 } from "node:fs";
47083
+ import { existsSync as existsSync52, readFileSync as readFileSync57 } from "node:fs";
46838
47084
  import { spawnSync as spawnSync3, execFile as execFile3 } from "node:child_process";
46839
- import { dirname as dirname28, resolve as resolve40 } from "node:path";
47085
+ import { dirname as dirname28, resolve as resolve41 } from "node:path";
46840
47086
  import { fileURLToPath as fileURLToPath23 } from "node:url";
46841
47087
  function stagedDir() {
46842
- return process.env.HIMI_BROWSER_PLANE_OUT ? resolve40(process.env.HIMI_BROWSER_PLANE_OUT) : resolve40(REPO, "packages", "serve", "dist", "browser-plane");
47088
+ return process.env.HIMI_BROWSER_PLANE_OUT ? resolve41(process.env.HIMI_BROWSER_PLANE_OUT) : resolve41(REPO, "packages", "serve", "dist", "browser-plane");
46843
47089
  }
46844
47090
  function missingStaged() {
46845
- return [...SERVED].filter((f) => !existsSync51(resolve40(stagedDir(), f))).sort();
47091
+ return [...SERVED].filter((f) => !existsSync52(resolve41(stagedDir(), f))).sort();
46846
47092
  }
46847
47093
  function ensureBrowserPlaneStaged() {
46848
47094
  if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
46849
- const r = spawnSync3(process.execPath, [resolve40(REPO, "core/serve/scripts/stage-browser-plane.mjs")], {
47095
+ const r = spawnSync3(process.execPath, [resolve41(REPO, "core/serve/scripts/stage-browser-plane.mjs")], {
46850
47096
  cwd: REPO,
46851
47097
  encoding: "utf8"
46852
47098
  });
@@ -46932,7 +47178,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
46932
47178
  }
46933
47179
  const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
46934
47180
  if (SERVED.has(name)) {
46935
- if (!existsSync51(resolve40(stagedDir(), name))) {
47181
+ if (!existsSync52(resolve41(stagedDir(), name))) {
46936
47182
  const restaged = ensureBrowserPlaneStaged();
46937
47183
  if (!restaged.ok) {
46938
47184
  res.writeHead(503, { "content-type": "application/json" });
@@ -46942,7 +47188,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
46942
47188
  }
46943
47189
  let bytes2;
46944
47190
  try {
46945
- bytes2 = readFileSync56(resolve40(stagedDir(), name));
47191
+ bytes2 = readFileSync57(resolve41(stagedDir(), name));
46946
47192
  } catch (e) {
46947
47193
  res.writeHead(503, { "content-type": "application/json" });
46948
47194
  res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
@@ -46986,7 +47232,7 @@ var init_run_browser = __esm({
46986
47232
  "src/run-browser.ts"() {
46987
47233
  init_file_store();
46988
47234
  HERE = dirname28(fileURLToPath23(import.meta.url));
46989
- REPO = resolve40(HERE, "..", "..", "..");
47235
+ REPO = resolve41(HERE, "..", "..", "..");
46990
47236
  SERVED = /* @__PURE__ */ new Set(["host.html", "sw.js", "package-reader.js"]);
46991
47237
  }
46992
47238
  });
@@ -47405,10 +47651,10 @@ __export(preflight_exports, {
47405
47651
  parseStoreConfig: () => parseStoreConfig,
47406
47652
  requireEnv: () => requireEnv
47407
47653
  });
47408
- import { existsSync as existsSync52, readFileSync as readFileSync57 } from "node:fs";
47409
- import { isAbsolute as isAbsolute3, relative as relative7, resolve as resolve41 } from "node:path";
47654
+ import { existsSync as existsSync53, readFileSync as readFileSync58 } from "node:fs";
47655
+ import { isAbsolute as isAbsolute3, relative as relative8, resolve as resolve42 } from "node:path";
47410
47656
  function isInsideRepo(p) {
47411
- const rel = relative7(REPO_ROOT3, resolve41(p));
47657
+ const rel = relative8(REPO_ROOT3, resolve42(p));
47412
47658
  return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
47413
47659
  }
47414
47660
  function assertCredentialOutsideRepo(label2, p) {
@@ -47462,10 +47708,10 @@ function parseStoreConfig(text4) {
47462
47708
  }
47463
47709
  function loadStoreConfig(app) {
47464
47710
  const p = storeConfigPath(app);
47465
- if (!existsSync52(p)) {
47711
+ if (!existsSync53(p)) {
47466
47712
  throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
47467
47713
  }
47468
- return parseStoreConfig(readFileSync57(p, "utf8"));
47714
+ return parseStoreConfig(readFileSync58(p, "utf8"));
47469
47715
  }
47470
47716
  var init_preflight = __esm({
47471
47717
  "../store-release/preflight.ts"() {
@@ -47484,19 +47730,19 @@ __export(credential_profile_exports, {
47484
47730
  profilePath: () => profilePath,
47485
47731
  resolveStoreCredentials: () => resolveStoreCredentials
47486
47732
  });
47487
- import { existsSync as existsSync53, readFileSync as readFileSync58 } from "node:fs";
47733
+ import { existsSync as existsSync54, readFileSync as readFileSync59 } from "node:fs";
47488
47734
  import { homedir as homedir5 } from "node:os";
47489
- import { join as join48 } from "node:path";
47735
+ import { join as join49 } from "node:path";
47490
47736
  function credentialsDir(home = homedir5()) {
47491
- return join48(home, ".himalaya", "store-credentials");
47737
+ return join49(home, ".himalaya", "store-credentials");
47492
47738
  }
47493
47739
  function profilePath(name, home = homedir5()) {
47494
47740
  if (!PROFILE_NAME.test(name)) {
47495
47741
  throw new Error(
47496
- `credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join48(credentialsDir(home), "<name>.json")}; it is never a path.`
47742
+ `credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join49(credentialsDir(home), "<name>.json")}; it is never a path.`
47497
47743
  );
47498
47744
  }
47499
- return join48(credentialsDir(home), `${name}.json`);
47745
+ return join49(credentialsDir(home), `${name}.json`);
47500
47746
  }
47501
47747
  function parseProfile(text4, label2) {
47502
47748
  let doc;
@@ -47527,8 +47773,8 @@ function resolveStoreCredentials(opts) {
47527
47773
  const { app, cfg } = opts;
47528
47774
  const env = opts.env ?? process.env;
47529
47775
  const home = opts.home ?? homedir5();
47530
- const read = opts.readProfile ?? ((p) => readFileSync58(p, "utf8"));
47531
- const exists = opts.profileExists ?? existsSync53;
47776
+ const read = opts.readProfile ?? ((p) => readFileSync59(p, "utf8"));
47777
+ const exists = opts.profileExists ?? existsSync54;
47532
47778
  const ios = cfg.ios ?? {};
47533
47779
  const flagName = opts.profileFlag?.trim();
47534
47780
  const named = namedProfile(cfg, opts.profileFlag);
@@ -47608,9 +47854,9 @@ __export(preflight_app_exports, {
47608
47854
  preflightApp: () => preflightApp,
47609
47855
  profileAccount: () => profileAccount
47610
47856
  });
47611
- import { readFileSync as readFileSync59, existsSync as existsSync54, readdirSync as readdirSync25, statSync as statSync12 } from "node:fs";
47612
- import { createHash as createHash23 } from "node:crypto";
47613
- import { join as join49 } from "node:path";
47857
+ import { readFileSync as readFileSync60, existsSync as existsSync55, readdirSync as readdirSync25, statSync as statSync13 } from "node:fs";
47858
+ import { createHash as createHash24 } from "node:crypto";
47859
+ import { join as join50 } from "node:path";
47614
47860
  function analyze(projectYml, storeConfig, icon, account) {
47615
47861
  const f = [];
47616
47862
  const has = (re, s) => re.test(s);
@@ -47674,13 +47920,13 @@ function profileAccount(app, storeConfig, opts = {}) {
47674
47920
  }
47675
47921
  }
47676
47922
  async function preflightApp(app, opts = {}) {
47677
- const projectYml = existsSync54(iosProjectYml(app)) ? readFileSync59(iosProjectYml(app), "utf8") : "";
47678
- const storeConfig = existsSync54(storeConfigPath(app)) ? readFileSync59(storeConfigPath(app), "utf8") : "";
47923
+ const projectYml = existsSync55(iosProjectYml(app)) ? readFileSync60(iosProjectYml(app), "utf8") : "";
47924
+ const storeConfig = existsSync55(storeConfigPath(app)) ? readFileSync60(storeConfigPath(app), "utf8") : "";
47679
47925
  if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
47680
47926
  const findings = analyze(
47681
47927
  projectYml,
47682
47928
  storeConfig,
47683
- await appIconState(join49(appDir(app), "ios")),
47929
+ await appIconState(join50(appDir(app), "ios")),
47684
47930
  profileAccount(app, storeConfig, opts)
47685
47931
  );
47686
47932
  findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
@@ -47709,17 +47955,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
47709
47955
  return f;
47710
47956
  }
47711
47957
  function appLevelMetadataFiles(app, locale = "en-US") {
47712
- const root = join49(storeDir(app), "metadata");
47958
+ const root = join50(storeDir(app), "metadata");
47713
47959
  const out = /* @__PURE__ */ new Set();
47714
- if (existsSync54(root)) {
47960
+ if (existsSync55(root)) {
47715
47961
  for (const n of readdirSync25(root)) if (n.endsWith(".txt")) out.add(n);
47716
47962
  }
47717
- if (existsSync54(join49(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
47963
+ if (existsSync55(join50(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
47718
47964
  return out;
47719
47965
  }
47720
47966
  function reviewInfoFiles(app) {
47721
- const dir = join49(storeDir(app), "review_information");
47722
- if (!existsSync54(dir)) return /* @__PURE__ */ new Set();
47967
+ const dir = join50(storeDir(app), "review_information");
47968
+ if (!existsSync55(dir)) return /* @__PURE__ */ new Set();
47723
47969
  return new Set(readdirSync25(dir).filter((n) => n.endsWith(".txt")));
47724
47970
  }
47725
47971
  function isValidAppStoreSize(w, h) {
@@ -47829,12 +48075,12 @@ function analyzePlayListing(assets) {
47829
48075
  return f;
47830
48076
  }
47831
48077
  function playListingAssets(app, locale = "en-US") {
47832
- const dir = join49(storeDir(app), "play", locale, "images");
48078
+ const dir = join50(storeDir(app), "play", locale, "images");
47833
48079
  const read = (names) => {
47834
48080
  for (const name of names) {
47835
- const p = join49(dir, name);
48081
+ const p = join50(dir, name);
47836
48082
  try {
47837
- if (statSync12(p).isFile()) return { name, bytes: readFileSync59(p) };
48083
+ if (statSync13(p).isFile()) return { name, bytes: readFileSync60(p) };
47838
48084
  } catch {
47839
48085
  }
47840
48086
  }
@@ -47865,26 +48111,26 @@ function analyzeListing(metaFiles, shots) {
47865
48111
  return f;
47866
48112
  }
47867
48113
  function metadataFilesPresent(app, locale = "en-US") {
47868
- const dir = join49(storeDir(app), "metadata", locale);
47869
- if (!existsSync54(dir)) return /* @__PURE__ */ new Set();
48114
+ const dir = join50(storeDir(app), "metadata", locale);
48115
+ if (!existsSync55(dir)) return /* @__PURE__ */ new Set();
47870
48116
  return new Set(readdirSync25(dir).filter((n) => n.endsWith(".txt")));
47871
48117
  }
47872
48118
  function listScreenshots(app, locale = "en-US") {
47873
48119
  const out = [];
47874
- const flat = join49(storeDir(app), "screenshots", locale);
47875
- if (existsSync54(flat)) {
48120
+ const flat = join50(storeDir(app), "screenshots", locale);
48121
+ if (existsSync55(flat)) {
47876
48122
  for (const png of readdirSync25(flat).filter((n) => n.endsWith(".png"))) {
47877
- const sz = pngSize(readFileSync59(join49(flat, png)));
48123
+ const sz = pngSize(readFileSync60(join50(flat, png)));
47878
48124
  if (sz) out.push({ name: png, w: sz.w, h: sz.h });
47879
48125
  }
47880
48126
  }
47881
- const legacy = join49(storeDir(app), "metadata", locale, "screenshots");
47882
- if (existsSync54(legacy)) {
48127
+ const legacy = join50(storeDir(app), "metadata", locale, "screenshots");
48128
+ if (existsSync55(legacy)) {
47883
48129
  for (const deviceDir of readdirSync25(legacy)) {
47884
- const d = join49(legacy, deviceDir);
47885
- if (!statSync12(d).isDirectory()) continue;
48130
+ const d = join50(legacy, deviceDir);
48131
+ if (!statSync13(d).isDirectory()) continue;
47886
48132
  for (const png of readdirSync25(d).filter((n) => n.endsWith(".png"))) {
47887
- const sz = pngSize(readFileSync59(join49(d, png)));
48133
+ const sz = pngSize(readFileSync60(join50(d, png)));
47888
48134
  if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
47889
48135
  }
47890
48136
  }
@@ -47892,13 +48138,13 @@ function listScreenshots(app, locale = "en-US") {
47892
48138
  return out;
47893
48139
  }
47894
48140
  function placeholderHashes2() {
47895
- const templateIos = join49(appDir("_template"), "ios");
47896
- if (!existsSync54(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
48141
+ const templateIos = join50(appDir("_template"), "ios");
48142
+ if (!existsSync55(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
47897
48143
  for (const target of readdirSync25(templateIos)) {
47898
- const p = join49(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48144
+ const p = join50(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
47899
48145
  try {
47900
- if (!statSync12(p).isFile()) continue;
47901
- return [LEGACY_PLACEHOLDER_SHA2562, createHash23("sha256").update(readFileSync59(p)).digest("hex")];
48146
+ if (!statSync13(p).isFile()) continue;
48147
+ return [LEGACY_PLACEHOLDER_SHA2562, createHash24("sha256").update(readFileSync60(p)).digest("hex")];
47902
48148
  } catch {
47903
48149
  }
47904
48150
  }
@@ -47929,13 +48175,13 @@ async function pixelIssues(bytes2) {
47929
48175
  }
47930
48176
  }
47931
48177
  async function appIconState(iosDir) {
47932
- if (!existsSync54(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
48178
+ if (!existsSync55(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
47933
48179
  for (const target of readdirSync25(iosDir)) {
47934
- const p = join49(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
48180
+ const p = join50(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
47935
48181
  try {
47936
- if (!statSync12(p).isFile()) continue;
47937
- const bytes2 = readFileSync59(p);
47938
- const hash = createHash23("sha256").update(bytes2).digest("hex");
48182
+ if (!statSync13(p).isFile()) continue;
48183
+ const bytes2 = readFileSync60(p);
48184
+ const hash = createHash24("sha256").update(bytes2).digest("hex");
47939
48185
  const pixels = await pixelIssues(bytes2);
47940
48186
  return {
47941
48187
  exists: true,
@@ -48006,7 +48252,7 @@ __export(version_exports, {
48006
48252
  setAndroidVersion: () => setAndroidVersion,
48007
48253
  setIosVersion: () => setIosVersion
48008
48254
  });
48009
- import { readFileSync as readFileSync60, writeFileSync as writeFileSync21 } from "node:fs";
48255
+ import { readFileSync as readFileSync61, writeFileSync as writeFileSync22 } from "node:fs";
48010
48256
  function readIosVersion(projectYml) {
48011
48257
  const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
48012
48258
  const build2 = matchScalar(projectYml, "CFBundleVersion");
@@ -48064,15 +48310,15 @@ function setAndroidVersion(gradle, v) {
48064
48310
  function bumpVersion(app, opts) {
48065
48311
  const iosPath = iosProjectYml(app);
48066
48312
  const gradlePath = androidGradle(app);
48067
- const iosYml = readFileSync60(iosPath, "utf8");
48068
- const gradle = readFileSync60(gradlePath, "utf8");
48313
+ const iosYml = readFileSync61(iosPath, "utf8");
48314
+ const gradle = readFileSync61(gradlePath, "utf8");
48069
48315
  const current = readIosVersion(iosYml);
48070
48316
  const next = {
48071
48317
  marketing: opts.marketing ?? current.marketing,
48072
48318
  build: opts.build === "increment" || opts.build === void 0 ? current.build + (opts.build === "increment" ? 1 : 0) : opts.build
48073
48319
  };
48074
- writeFileSync21(iosPath, setIosVersion(iosYml, next));
48075
- writeFileSync21(gradlePath, setAndroidVersion(gradle, next));
48320
+ writeFileSync22(iosPath, setIosVersion(iosYml, next));
48321
+ writeFileSync22(gradlePath, setAndroidVersion(gradle, next));
48076
48322
  return next;
48077
48323
  }
48078
48324
  var init_version = __esm({
@@ -48082,7 +48328,7 @@ var init_version = __esm({
48082
48328
  });
48083
48329
 
48084
48330
  // ../store-release/register-bundle.ts
48085
- import { readFileSync as readFileSync61 } from "node:fs";
48331
+ import { readFileSync as readFileSync62 } from "node:fs";
48086
48332
  import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
48087
48333
  function b64url2(b) {
48088
48334
  return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -48100,7 +48346,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
48100
48346
  async function registerBundleId(opts) {
48101
48347
  const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
48102
48348
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
48103
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync61(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
48349
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync62(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
48104
48350
  const res = await fetch(`${ASC_API}/v1/bundleIds`, {
48105
48351
  method: "POST",
48106
48352
  headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
@@ -48154,7 +48400,7 @@ __export(asc_status_exports, {
48154
48400
  ascStatus: () => ascStatus,
48155
48401
  buildVerdict: () => buildVerdict
48156
48402
  });
48157
- import { readFileSync as readFileSync62 } from "node:fs";
48403
+ import { readFileSync as readFileSync63 } from "node:fs";
48158
48404
  function buildVerdict(builds) {
48159
48405
  if (!builds.length) {
48160
48406
  return "NO builds registered \u2014 if you uploaded recently and it's been >15 min, the binary was REJECTED IN PROCESSING (reason is email-only; run validate-binary.ts / scan-purpose-strings.ts to reproduce it).";
@@ -48168,7 +48414,7 @@ function buildVerdict(builds) {
48168
48414
  function client(creds) {
48169
48415
  const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
48170
48416
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
48171
- const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync62(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
48417
+ const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync63(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
48172
48418
  return async (path2) => {
48173
48419
  const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
48174
48420
  return { status: r.status, json: await r.json().catch(() => ({})) };
@@ -48328,7 +48574,7 @@ __export(secrets_exports, {
48328
48574
  runRemoteSecretsCommand: () => runRemoteSecretsCommand,
48329
48575
  runSecretsCommand: () => runSecretsCommand
48330
48576
  });
48331
- import { readFileSync as readFileSync63 } from "node:fs";
48577
+ import { readFileSync as readFileSync64 } from "node:fs";
48332
48578
  function environment(value) {
48333
48579
  if (value === "preview" || value === "production") return value;
48334
48580
  throw new Error("--environment must be preview or production");
@@ -48359,7 +48605,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
48359
48605
  io.log(JSON.stringify(await vault.list({ app, environment: env })));
48360
48606
  return 0;
48361
48607
  }
48362
- const value = options.readValue ? options.readValue() : readFileSync63(0, "utf8").replace(/\r?\n$/, "");
48608
+ const value = options.readValue ? options.readValue() : readFileSync64(0, "utf8").replace(/\r?\n$/, "");
48363
48609
  if (operation === "set") await vault.set({ app, environment: env, name, value });
48364
48610
  else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
48365
48611
  else throw new Error(`unknown secrets operation ${operation}`);
@@ -48388,7 +48634,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
48388
48634
  }
48389
48635
  let body;
48390
48636
  if (operation !== "list") {
48391
- const value = options.readValue ? options.readValue() : readFileSync63(0, "utf8").replace(/\r?\n$/, "");
48637
+ const value = options.readValue ? options.readValue() : readFileSync64(0, "utf8").replace(/\r?\n$/, "");
48392
48638
  body = JSON.stringify({ value });
48393
48639
  }
48394
48640
  const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
@@ -48424,15 +48670,15 @@ __export(notify_exports, {
48424
48670
  runNotify: () => runNotify,
48425
48671
  saveAdminSession: () => saveAdminSession
48426
48672
  });
48427
- import { chmodSync as chmodSync3, mkdirSync as mkdirSync25, readFileSync as readFileSync64, writeFileSync as writeFileSync22 } from "node:fs";
48673
+ import { chmodSync as chmodSync3, mkdirSync as mkdirSync26, readFileSync as readFileSync65, writeFileSync as writeFileSync23 } from "node:fs";
48428
48674
  import { homedir as homedir6 } from "node:os";
48429
- import { dirname as dirname30, join as join50 } from "node:path";
48675
+ import { dirname as dirname30, join as join51 } from "node:path";
48430
48676
  function defaultSessionsPath() {
48431
- return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join50(homedir6(), ".himalaya", "admin-sessions.json");
48677
+ return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join51(homedir6(), ".himalaya", "admin-sessions.json");
48432
48678
  }
48433
48679
  function loadSessionsFile(path2 = defaultSessionsPath()) {
48434
48680
  try {
48435
- return JSON.parse(readFileSync64(path2, "utf8"));
48681
+ return JSON.parse(readFileSync65(path2, "utf8"));
48436
48682
  } catch {
48437
48683
  return {};
48438
48684
  }
@@ -48440,8 +48686,8 @@ function loadSessionsFile(path2 = defaultSessionsPath()) {
48440
48686
  function saveAdminSession(adminUrl, session, path2 = defaultSessionsPath()) {
48441
48687
  const file = loadSessionsFile(path2);
48442
48688
  file.sessions = { ...file.sessions, [adminUrl]: session };
48443
- mkdirSync25(dirname30(path2), { recursive: true, mode: 448 });
48444
- writeFileSync22(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
48689
+ mkdirSync26(dirname30(path2), { recursive: true, mode: 448 });
48690
+ writeFileSync23(path2, JSON.stringify(file, null, 2) + "\n", { mode: 384 });
48445
48691
  try {
48446
48692
  chmodSync3(dirname30(path2), 448);
48447
48693
  chmodSync3(path2, 384);
@@ -49979,6 +50225,26 @@ function tuneHighContrastAccent(brand, surface) {
49979
50225
  }
49980
50226
  return candidate;
49981
50227
  }
50228
+ function stripBrandFromIdiom(tokens) {
50229
+ const idiom = tokens.idiom;
50230
+ if (!idiom || typeof idiom !== "object" || Array.isArray(idiom)) return;
50231
+ for (const overlay of Object.values(idiom)) {
50232
+ if (!overlay || typeof overlay !== "object" || Array.isArray(overlay)) continue;
50233
+ const o = overlay;
50234
+ const colors = o.colors;
50235
+ if (colors && typeof colors === "object" && !Array.isArray(colors)) {
50236
+ for (const key2 of BRAND_COLOR_TOKENS) delete colors[key2];
50237
+ if (Object.keys(colors).length === 0) delete o.colors;
50238
+ }
50239
+ const shadows = o.shadows;
50240
+ const glow = shadows && typeof shadows === "object" && !Array.isArray(shadows) ? shadows[BRAND_GLOW_SHADOW] : void 0;
50241
+ if (glow && typeof glow === "object" && !Array.isArray(glow) && "color" in glow) {
50242
+ delete glow.color;
50243
+ if (Object.keys(glow).length === 0) delete shadows[BRAND_GLOW_SHADOW];
50244
+ if (Object.keys(shadows).length === 0) delete o.shadows;
50245
+ }
50246
+ }
50247
+ }
49982
50248
  function deriveAccentFamily(primary, secondary, surfaces) {
49983
50249
  const primaryDark = tuneDarkAccent(primary, surfaces.dark, surfaces.light);
49984
50250
  const secondaryDark = tuneDarkAccent(secondary, surfaces.dark, surfaces.light);
@@ -49999,7 +50265,7 @@ function deriveAccentFamily(primary, secondary, surfaces) {
49999
50265
  }
50000
50266
  };
50001
50267
  }
50002
- var ACCENT_SURFACE_MIN_DELTA, ACCENT_SURFACE_LIGHT_WEIGHT, SECONDARY_SHADE_WEIGHT, SECONDARY_MIN_LSTAR, DARK_ARM_MIN_LIFT, DARK_ARM_TARGET_CONTRAST, DARK_ARM_FLOOR_CONTRAST, DARK_ARM_LSTAR_CAP, HIGH_CONTRAST_TARGET;
50268
+ var ACCENT_SURFACE_MIN_DELTA, ACCENT_SURFACE_LIGHT_WEIGHT, SECONDARY_SHADE_WEIGHT, SECONDARY_MIN_LSTAR, DARK_ARM_MIN_LIFT, DARK_ARM_TARGET_CONTRAST, DARK_ARM_FLOOR_CONTRAST, DARK_ARM_LSTAR_CAP, HIGH_CONTRAST_TARGET, BRAND_COLOR_TOKENS, BRAND_GLOW_SHADOW;
50003
50269
  var init_brand_color_math = __esm({
50004
50270
  "../../core/ts/src/brand-color-math.ts"() {
50005
50271
  ACCENT_SURFACE_MIN_DELTA = 1.08;
@@ -50011,6 +50277,8 @@ var init_brand_color_math = __esm({
50011
50277
  DARK_ARM_FLOOR_CONTRAST = 3;
50012
50278
  DARK_ARM_LSTAR_CAP = 80;
50013
50279
  HIGH_CONTRAST_TARGET = 8.5;
50280
+ BRAND_COLOR_TOKENS = ["accentPrimary", "accentSecondary", "accentSurface", "textOnAccent"];
50281
+ BRAND_GLOW_SHADOW = "glow";
50014
50282
  }
50015
50283
  });
50016
50284
 
@@ -51067,10 +51335,10 @@ function assertPublicSiteUrl(raw) {
51067
51335
  if (refusal) throw new Error(refusal);
51068
51336
  }
51069
51337
  function resolveAll(hostname2) {
51070
- return new Promise((resolve45, reject) => {
51338
+ return new Promise((resolve46, reject) => {
51071
51339
  dnsLookup(hostname2, { all: true, verbatim: true }, (err, addresses) => {
51072
51340
  if (err) reject(err);
51073
- else resolve45(addresses);
51341
+ else resolve46(addresses);
51074
51342
  });
51075
51343
  });
51076
51344
  }
@@ -51078,13 +51346,13 @@ function withAbort(start, signal, what) {
51078
51346
  if (signal?.aborted) return Promise.reject(new Error(`${what} aborted`));
51079
51347
  const work = start();
51080
51348
  if (!signal) return work;
51081
- return new Promise((resolve45, reject) => {
51349
+ return new Promise((resolve46, reject) => {
51082
51350
  const onAbort = () => reject(new Error(`${what} aborted`));
51083
51351
  signal.addEventListener("abort", onAbort, { once: true });
51084
- work.then(resolve45, reject).finally(() => signal.removeEventListener("abort", onAbort));
51352
+ work.then(resolve46, reject).finally(() => signal.removeEventListener("abort", onAbort));
51085
51353
  });
51086
51354
  }
51087
- async function pinAddress(url, resolve45 = resolveAll, signal) {
51355
+ async function pinAddress(url, resolve46 = resolveAll, signal) {
51088
51356
  const host = url.hostname.replace(/^\[|\]$/g, "");
51089
51357
  if (ipv4Octets(host)) {
51090
51358
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
@@ -51094,7 +51362,7 @@ async function pinAddress(url, resolve45 = resolveAll, signal) {
51094
51362
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
51095
51363
  return { address: host, family: 6 };
51096
51364
  }
51097
- const addresses = await withAbort(() => resolve45(host), signal, `${host} lookup`);
51365
+ const addresses = await withAbort(() => resolve46(host), signal, `${host} lookup`);
51098
51366
  if (!addresses.length) throw new Error(`${host} resolved to no address`);
51099
51367
  const blocked = addresses.filter((a) => isBlockedAddress(a.address)).map((a) => a.address);
51100
51368
  if (blocked.length) throw new Error(`${host} resolves to a blocked address (${blocked.join(", ")})`);
@@ -51134,7 +51402,7 @@ function copyIncomingHeaders(headers2) {
51134
51402
  return out;
51135
51403
  }
51136
51404
  function requestOnce(url, pinned, init) {
51137
- return new Promise((resolve45, reject) => {
51405
+ return new Promise((resolve46, reject) => {
51138
51406
  const headers2 = { host: url.host, "accept-encoding": "identity" };
51139
51407
  new Headers(init.headers ?? {}).forEach((value, key2) => {
51140
51408
  if (key2.toLowerCase() !== "host") headers2[key2] = value;
@@ -51164,7 +51432,7 @@ function requestOnce(url, pinned, init) {
51164
51432
  reject(err);
51165
51433
  return;
51166
51434
  }
51167
- resolve45(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out }));
51435
+ resolve46(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out }));
51168
51436
  }
51169
51437
  );
51170
51438
  req.on("error", reject);
@@ -51967,8 +52235,8 @@ var init_brand_font = __esm({
51967
52235
  });
51968
52236
 
51969
52237
  // src/site-analyze/write-artifacts.ts
51970
- import { mkdirSync as mkdirSync26, writeFileSync as writeFileSync23 } from "node:fs";
51971
- import { join as join51 } from "node:path";
52238
+ import { mkdirSync as mkdirSync27, writeFileSync as writeFileSync24 } from "node:fs";
52239
+ import { join as join52 } from "node:path";
51972
52240
  function attachVeloSources(book, sources, put) {
51973
52241
  const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
51974
52242
  for (const f of book.velo.files) {
@@ -52123,13 +52391,13 @@ async function downloadMedia(book, fetchImpl, put) {
52123
52391
  }
52124
52392
  async function writeBusinessBook(result, opts) {
52125
52393
  const out = opts.outDir;
52126
- mkdirSync26(join51(out, "evidence/pages"), { recursive: true });
52127
- mkdirSync26(join51(out, "media/catalog"), { recursive: true });
52394
+ mkdirSync27(join52(out, "evidence/pages"), { recursive: true });
52395
+ mkdirSync27(join52(out, "media/catalog"), { recursive: true });
52128
52396
  const files = [];
52129
52397
  const put = (rel, body) => {
52130
- const p = join51(out, rel);
52131
- mkdirSync26(join51(p, ".."), { recursive: true });
52132
- writeFileSync23(p, body);
52398
+ const p = join52(out, rel);
52399
+ mkdirSync27(join52(p, ".."), { recursive: true });
52400
+ writeFileSync24(p, body);
52133
52401
  files.push(rel);
52134
52402
  };
52135
52403
  const book = result.book;
@@ -52222,15 +52490,15 @@ var init_customer_build = __esm({
52222
52490
  });
52223
52491
 
52224
52492
  // src/site-analyze/apply.ts
52225
- import { existsSync as existsSync55, readFileSync as readFileSync65, writeFileSync as writeFileSync24, copyFileSync as copyFileSync3, mkdirSync as mkdirSync27, realpathSync as realpathSync5, statSync as statSync13 } from "node:fs";
52226
- import { dirname as dirname31, isAbsolute as isAbsolute4, join as join52, resolve as resolve42, sep as sep11 } from "node:path";
52493
+ import { existsSync as existsSync56, readFileSync as readFileSync66, writeFileSync as writeFileSync25, copyFileSync as copyFileSync3, mkdirSync as mkdirSync28, realpathSync as realpathSync5, statSync as statSync14 } from "node:fs";
52494
+ import { dirname as dirname31, isAbsolute as isAbsolute4, join as join53, resolve as resolve43, sep as sep12 } from "node:path";
52227
52495
  import { spawnSync as spawnSync4 } from "node:child_process";
52228
52496
  function unpairedRedirectNote(overlay) {
52229
52497
  if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
52230
52498
  return `no OAuth redirect paired with client ${overlay.wix.clientId} \u2014 the app (and prepare:customer) will refuse to start until one is set. Register it with \`himi site client ensure --site ${overlay.siteId?.trim() || "<msid>"} --redirect-uri <uri> --yes\`, then re-run analyze with \`--redirect-uri <uri>\` (or export HIMI_BRANDED_LITE_WIX_REDIRECT_URI)`;
52231
52499
  }
52232
52500
  function posix2(p) {
52233
- return resolve42(p).replace(/\\/g, "/");
52501
+ return resolve43(p).replace(/\\/g, "/");
52234
52502
  }
52235
52503
  function committedShellProvisioning(path2) {
52236
52504
  return committedShellFor(posix2(path2));
@@ -52238,7 +52506,7 @@ function committedShellProvisioning(path2) {
52238
52506
  function findRepoRoot(cwd) {
52239
52507
  let dir = cwd;
52240
52508
  for (let i = 0; i < 8; i++) {
52241
- if (SHELL_NAMES2.some((name) => existsSync55(join52(dir, shellAppDir(name), "package.json")))) return dir;
52509
+ if (SHELL_NAMES2.some((name) => existsSync56(join53(dir, shellAppDir(name), "package.json")))) return dir;
52242
52510
  const next = dirname31(dir);
52243
52511
  if (next === dir) break;
52244
52512
  dir = next;
@@ -52264,7 +52532,7 @@ function assertNotCommitted(path2, forbidden) {
52264
52532
  `refusing to overwrite committed ${committedProvisioningPath(committed)} \u2014 use prepare:customer --contract`
52265
52533
  );
52266
52534
  }
52267
- if (forbidden && resolve42(path2) === resolve42(forbidden)) {
52535
+ if (forbidden && resolve43(path2) === resolve43(forbidden)) {
52268
52536
  const named = committedShellProvisioning(forbidden);
52269
52537
  throw new Error(
52270
52538
  `refusing to overwrite committed ${named ? committedProvisioningPath(named) : forbidden} \u2014 pass a content-package provisioning.json or use prepare:customer --contract`
@@ -52306,24 +52574,24 @@ function mergeCustomerOwned(committed, overlay) {
52306
52574
  }
52307
52575
  function buildMergedContract(options) {
52308
52576
  const { appDir: appDir2, packageDir, overlay } = options;
52309
- const committedPath = join52(appDir2, "provisioning.json");
52310
- if (!existsSync55(committedPath)) {
52577
+ const committedPath = join53(appDir2, "provisioning.json");
52578
+ if (!existsSync56(committedPath)) {
52311
52579
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
52312
52580
  }
52313
- const committed = JSON.parse(readFileSync65(committedPath, "utf8"));
52581
+ const committed = JSON.parse(readFileSync66(committedPath, "utf8"));
52314
52582
  const merged = mergeCustomerOwned(committed, overlay);
52315
52583
  const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
52316
52584
  const branding = merged.branding ?? {};
52317
52585
  const staged = [];
52318
52586
  const contained = (root, rel) => {
52319
52587
  if (isAbsolute4(rel)) return void 0;
52320
- const full = resolve42(root, rel);
52321
- return full.startsWith(resolve42(root) + sep11) ? full : void 0;
52588
+ const full = resolve43(root, rel);
52589
+ return full.startsWith(resolve43(root) + sep12) ? full : void 0;
52322
52590
  };
52323
52591
  const stage = (fromRel, toRel) => {
52324
52592
  const from = contained(packageDir, fromRel);
52325
- const to = contained(join52(appDir2, STAGED), toRel.slice(STAGED.length + 1));
52326
- if (!from || !to || !existsSync55(from)) return void 0;
52593
+ const to = contained(join53(appDir2, STAGED), toRel.slice(STAGED.length + 1));
52594
+ if (!from || !to || !existsSync56(from)) return void 0;
52327
52595
  let real;
52328
52596
  let realRoot;
52329
52597
  try {
@@ -52332,10 +52600,10 @@ function buildMergedContract(options) {
52332
52600
  } catch {
52333
52601
  return void 0;
52334
52602
  }
52335
- if (!real.startsWith(realRoot + sep11)) return void 0;
52603
+ if (!real.startsWith(realRoot + sep12)) return void 0;
52336
52604
  try {
52337
- if (!statSync13(real).isFile()) return void 0;
52338
- mkdirSync27(dirname31(to), { recursive: true });
52605
+ if (!statSync14(real).isFile()) return void 0;
52606
+ mkdirSync28(dirname31(to), { recursive: true });
52339
52607
  copyFileSync3(real, to);
52340
52608
  } catch {
52341
52609
  return void 0;
@@ -52345,11 +52613,11 @@ function buildMergedContract(options) {
52345
52613
  };
52346
52614
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
52347
52615
  if (icon) branding.appIconPath = icon;
52348
- const facesPath = join52(packageDir, "media/fonts/faces.json");
52349
- if (existsSync55(facesPath)) {
52616
+ const facesPath = join53(packageDir, "media/fonts/faces.json");
52617
+ if (existsSync56(facesPath)) {
52350
52618
  let faces = [];
52351
52619
  try {
52352
- const parsed = JSON.parse(readFileSync65(facesPath, "utf8"));
52620
+ const parsed = JSON.parse(readFileSync66(facesPath, "utf8"));
52353
52621
  faces = Array.isArray(parsed) ? parsed : [];
52354
52622
  } catch {
52355
52623
  faces = [];
@@ -52370,20 +52638,20 @@ function buildMergedContract(options) {
52370
52638
  merged.branding = branding;
52371
52639
  const body = `${JSON.stringify(merged, null, 2)}
52372
52640
  `;
52373
- const path2 = join52(packageDir, "provisioning.contract.json");
52374
- writeFileSync24(path2, body);
52375
- const localPath = join52(appDir2, LOCAL_CONTRACT_REL);
52376
- mkdirSync27(dirname31(localPath), { recursive: true });
52377
- writeFileSync24(localPath, body);
52641
+ const path2 = join53(packageDir, "provisioning.contract.json");
52642
+ writeFileSync25(path2, body);
52643
+ const localPath = join53(appDir2, LOCAL_CONTRACT_REL);
52644
+ mkdirSync28(dirname31(localPath), { recursive: true });
52645
+ writeFileSync25(localPath, body);
52378
52646
  staged.push(localPath);
52379
52647
  return { path: path2, staged };
52380
52648
  }
52381
52649
  async function applyOverlays(input) {
52382
- const cwd = resolve42(input.cwd);
52650
+ const cwd = resolve43(input.cwd);
52383
52651
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
52384
52652
  assertKnownShell(shell);
52385
- const overlay = JSON.parse(readFileSync65(input.overlayPath, "utf8"));
52386
- const tokens = JSON.parse(readFileSync65(input.tokensPath, "utf8"));
52653
+ const overlay = JSON.parse(readFileSync66(input.overlayPath, "utf8"));
52654
+ const tokens = JSON.parse(readFileSync66(input.tokensPath, "utf8"));
52387
52655
  const wrote = [];
52388
52656
  const notes = [];
52389
52657
  const repoRoot2 = findRepoRoot(cwd);
@@ -52393,8 +52661,8 @@ async function applyOverlays(input) {
52393
52661
  `shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
52394
52662
  );
52395
52663
  }
52396
- const appDir2 = join52(repoRoot2, shellAppDir(shell));
52397
- const packageDir = dirname31(resolve42(input.overlayPath));
52664
+ const appDir2 = join53(repoRoot2, shellAppDir(shell));
52665
+ const packageDir = dirname31(resolve43(input.overlayPath));
52398
52666
  const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
52399
52667
  wrote.push(...staged);
52400
52668
  const r = spawnSync4("npm", ["run", "prepare:customer", "--", "--contract", contract], {
@@ -52415,32 +52683,41 @@ async function applyOverlays(input) {
52415
52683
  note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
52416
52684
  };
52417
52685
  }
52418
- const pkgProv = join52(cwd, "provisioning.json");
52686
+ const pkgProv = join53(cwd, "provisioning.json");
52419
52687
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
52420
- if (existsSync55(pkgProv)) {
52421
- const cur = JSON.parse(readFileSync65(pkgProv, "utf8"));
52688
+ if (existsSync56(pkgProv)) {
52689
+ const cur = JSON.parse(readFileSync66(pkgProv, "utf8"));
52422
52690
  const merged = deepMerge4(cur, overlay);
52423
- writeFileSync24(pkgProv, JSON.stringify(merged, null, 2) + "\n");
52691
+ writeFileSync25(pkgProv, JSON.stringify(merged, null, 2) + "\n");
52424
52692
  wrote.push(pkgProv);
52425
52693
  } else {
52426
- writeFileSync24(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
52694
+ writeFileSync25(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
52427
52695
  wrote.push(pkgProv);
52428
52696
  }
52429
- const pkgTokens = join52(cwd, "tokens.json");
52430
- if (existsSync55(pkgTokens) && (tokens.colors || tokens.typography)) {
52431
- const cur = JSON.parse(readFileSync65(pkgTokens, "utf8"));
52697
+ const pkgTokens = join53(cwd, "tokens.json");
52698
+ if (existsSync56(pkgTokens) && (tokens.colors || tokens.typography)) {
52699
+ const cur = JSON.parse(readFileSync66(pkgTokens, "utf8"));
52432
52700
  const merged = deepMerge4(cur, tokens);
52433
52701
  const mergedColors = merged.colors;
52434
52702
  if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
52435
52703
  merged.colors = alignAccentsToSurfaces(mergedColors, tokens.colors);
52436
52704
  }
52437
- writeFileSync24(pkgTokens, JSON.stringify(merged, null, 2) + "\n");
52705
+ const bringsBrand = Object.keys(tokens.colors ?? {}).some((k) => BRAND_COLOR_TOKENS.includes(k));
52706
+ if (bringsBrand) {
52707
+ const accent = tokens.colors?.accentPrimary;
52708
+ const primary = typeof accent === "string" ? accent : accent?.light;
52709
+ const shadows = merged.shadows;
52710
+ const glow = shadows && typeof shadows === "object" && !Array.isArray(shadows) ? shadows[BRAND_GLOW_SHADOW] : void 0;
52711
+ if (primary && glow && typeof glow.color === "string") glow.color = primary;
52712
+ stripBrandFromIdiom(merged);
52713
+ }
52714
+ writeFileSync25(pkgTokens, JSON.stringify(merged, null, 2) + "\n");
52438
52715
  wrote.push(pkgTokens);
52439
52716
  }
52440
52717
  const homeAction = homeRefreshActionId(shell);
52441
- const homeSrc = join52(cwd, "dev/index.ts");
52442
- if (homeAction && existsSync55(homeSrc)) {
52443
- const prev = readFileSync65(homeSrc, "utf8");
52718
+ const homeSrc = join53(cwd, "dev/index.ts");
52719
+ if (homeAction && existsSync56(homeSrc)) {
52720
+ const prev = readFileSync66(homeSrc, "utf8");
52444
52721
  const patched = patchBrandParams(prev, overlay, homeAction);
52445
52722
  let next = patched.src;
52446
52723
  if (!patched.foreign && overlay.installedVerticals?.length) {
@@ -52456,20 +52733,20 @@ async function applyOverlays(input) {
52456
52733
  }
52457
52734
  }
52458
52735
  if (next !== prev) {
52459
- writeFileSync24(homeSrc, next);
52736
+ writeFileSync25(homeSrc, next);
52460
52737
  wrote.push(homeSrc);
52461
52738
  }
52462
52739
  if (patched.unparsed) {
52463
52740
  notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
52464
52741
  }
52465
52742
  }
52466
- if (!input.iconPath || !existsSync55(input.iconPath)) {
52467
- const book = input.iconPath ? dirname31(dirname31(resolve42(input.iconPath))) : void 0;
52743
+ if (!input.iconPath || !existsSync56(input.iconPath)) {
52744
+ const book = input.iconPath ? dirname31(dirname31(resolve43(input.iconPath))) : void 0;
52468
52745
  notes.push(
52469
52746
  book ? `no icon installed \u2014 ${siteLogoAbsence(book).hint}` : "no icon installed and no business book to say why \u2014 `himi icon generate` draws one from the accent, or `himi icon set <file.png>` installs the customer's own mark"
52470
52747
  );
52471
52748
  }
52472
- if (input.iconPath && existsSync55(input.iconPath)) {
52749
+ if (input.iconPath && existsSync56(input.iconPath)) {
52473
52750
  try {
52474
52751
  const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
52475
52752
  wrote.push(...installed.wrote);
@@ -52554,6 +52831,7 @@ var init_apply2 = __esm({
52554
52831
  init_brandable_shells();
52555
52832
  init_customer_build();
52556
52833
  init_branding_derive();
52834
+ init_brand_color_math();
52557
52835
  init_home_descriptor();
52558
52836
  STAGED = ".himi/brand";
52559
52837
  }
@@ -53406,10 +53684,10 @@ function permuteDomain(domain, allowSpecialUseDomain) {
53406
53684
  }
53407
53685
  function createPromiseCallback(cb) {
53408
53686
  let callback;
53409
- let resolve45;
53687
+ let resolve46;
53410
53688
  let reject;
53411
53689
  const promise = new Promise((_resolve, _reject) => {
53412
- resolve45 = _resolve;
53690
+ resolve46 = _resolve;
53413
53691
  reject = _reject;
53414
53692
  });
53415
53693
  if (typeof cb === "function") {
@@ -53425,7 +53703,7 @@ function createPromiseCallback(cb) {
53425
53703
  callback = (err, result) => {
53426
53704
  try {
53427
53705
  if (err) reject(err);
53428
- else resolve45(result);
53706
+ else resolve46(result);
53429
53707
  } catch (e) {
53430
53708
  reject(e instanceof Error ? e : new Error());
53431
53709
  }
@@ -56623,8 +56901,8 @@ __export(cli_exports, {
56623
56901
  runSiteAnalyze: () => runSiteAnalyze,
56624
56902
  runSiteFunctionCli: () => runSiteFunctionCli
56625
56903
  });
56626
- import { readFileSync as readFileSync66 } from "node:fs";
56627
- import { resolve as resolve43 } from "node:path";
56904
+ import { readFileSync as readFileSync67 } from "node:fs";
56905
+ import { resolve as resolve44 } from "node:path";
56628
56906
  function assetFetchFor(_opts) {
56629
56907
  return pinnedFetch2;
56630
56908
  }
@@ -56633,7 +56911,7 @@ async function runSiteAnalyze(opts) {
56633
56911
  const assetFetch = assetFetchFor(opts);
56634
56912
  const siteFetch = guardedSiteFetch;
56635
56913
  const cwd = opts.cwd ?? process.cwd();
56636
- const outDir = resolve43(cwd, opts.outDir ?? ".himi/business-book");
56914
+ const outDir = resolve44(cwd, opts.outDir ?? ".himi/business-book");
56637
56915
  let ownerAuth;
56638
56916
  let msid;
56639
56917
  try {
@@ -56671,9 +56949,9 @@ async function runSiteAnalyze(opts) {
56671
56949
  if (opts.apply) {
56672
56950
  applied = await applyOverlays({
56673
56951
  cwd,
56674
- overlayPath: resolve43(outDir, "provisioning.overlay.json"),
56675
- tokensPath: resolve43(outDir, "tokens.overlay.json"),
56676
- iconPath: resolve43(outDir, "media/icon.png"),
56952
+ overlayPath: resolve44(outDir, "provisioning.overlay.json"),
56953
+ tokensPath: resolve44(outDir, "tokens.overlay.json"),
56954
+ iconPath: resolve44(outDir, "media/icon.png"),
56677
56955
  shell: opts.shell
56678
56956
  });
56679
56957
  const note = noteWithWarnings(applied.note, warnings);
@@ -56709,8 +56987,8 @@ async function runSiteFunctionCli(opts) {
56709
56987
  const token = opts.token ?? await siteToken(msid);
56710
56988
  let source;
56711
56989
  if (opts.sourcePath) {
56712
- const p = resolve43(opts.cwd ?? process.cwd(), opts.sourcePath);
56713
- source = readFileSync66(p, "utf8");
56990
+ const p = resolve44(opts.cwd ?? process.cwd(), opts.sourcePath);
56991
+ source = readFileSync67(p, "utf8");
56714
56992
  }
56715
56993
  let body;
56716
56994
  if (opts.bodyRaw != null) {
@@ -56753,15 +57031,15 @@ var init_cli = __esm({
56753
57031
  });
56754
57032
 
56755
57033
  // src/wix-account.ts
56756
- import { spawn as spawn4 } from "node:child_process";
56757
- async function accountToken2(spawnImpl = spawn4) {
57034
+ import { spawn as spawn5 } from "node:child_process";
57035
+ async function accountToken2(spawnImpl = spawn5) {
56758
57036
  if (cached2) return cached2;
56759
57037
  const fromEnv = process.env.WIX_TEST_TOKEN?.trim();
56760
57038
  if (fromEnv) {
56761
57039
  cached2 = fromEnv;
56762
57040
  return fromEnv;
56763
57041
  }
56764
- const token = await new Promise((resolve45, reject) => {
57042
+ const token = await new Promise((resolve46, reject) => {
56765
57043
  let child;
56766
57044
  try {
56767
57045
  child = spawnImpl("wix", ["token"]);
@@ -56790,7 +57068,7 @@ async function accountToken2(spawnImpl = spawn4) {
56790
57068
  const scan = (d) => {
56791
57069
  out += String(d);
56792
57070
  const m = out.match(TOKEN_RE2);
56793
- if (m) done(() => resolve45(m[0]));
57071
+ if (m) done(() => resolve46(m[0]));
56794
57072
  };
56795
57073
  child.stdout?.on("data", scan);
56796
57074
  child.stderr?.on("data", scan);
@@ -56810,7 +57088,7 @@ function apiKeyAuth(env = process.env) {
56810
57088
  const accountId = env.WIX_ACCOUNT_ID?.trim();
56811
57089
  return key2 && accountId ? { key: key2, accountId } : void 0;
56812
57090
  }
56813
- function accountTransport(fetchImpl = fetch, timeoutMs = DEFAULT_TIMEOUT_MS5, spawnImpl = spawn4) {
57091
+ function accountTransport(fetchImpl = fetch, timeoutMs = DEFAULT_TIMEOUT_MS5, spawnImpl = spawn5) {
56814
57092
  return async (method, path2, body) => {
56815
57093
  const viaKey = apiKeyAuth();
56816
57094
  const headers2 = viaKey ? { Authorization: viaKey.key, "wix-account-id": viaKey.accountId, Accept: "application/json" } : { Authorization: await accountToken2(spawnImpl), Accept: "application/json" };
@@ -56967,7 +57245,7 @@ __export(site_create_exports, {
56967
57245
  runSiteList: () => runSiteList,
56968
57246
  writeProvisioningBinding: () => writeProvisioningBinding
56969
57247
  });
56970
- import { existsSync as existsSync56, readFileSync as readFileSync67, writeFileSync as writeFileSync25 } from "node:fs";
57248
+ import { existsSync as existsSync57, readFileSync as readFileSync68, writeFileSync as writeFileSync26 } from "node:fs";
56971
57249
  import { resolve as resolvePath2 } from "node:path";
56972
57250
  function oauthClientName(projectName) {
56973
57251
  return `${projectName} client`;
@@ -57116,7 +57394,7 @@ async function runSiteCreate(opts) {
57116
57394
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
57117
57395
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
57118
57396
  }
57119
- function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync56, readFileSync: readFileSync67, writeFileSync: writeFileSync25 }) {
57397
+ function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync57, readFileSync: readFileSync68, writeFileSync: writeFileSync26 }) {
57120
57398
  const msid = binding2.siteId;
57121
57399
  const path2 = resolvePath2(target);
57122
57400
  const committed = committedShellProvisioning(path2);
@@ -57789,11 +58067,11 @@ var init_context = __esm({
57789
58067
  });
57790
58068
 
57791
58069
  // src/cli.ts
57792
- import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync68, mkdirSync as mkdirSync28, writeFileSync as writeFileSync26, existsSync as existsSync57, rmSync as rmSync11, readdirSync as readdirSync26, statSync as statSync14, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
57793
- import { execFile as execFile4, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn5 } from "node:child_process";
57794
- import { createHash as createHash24, randomUUID as randomUUID3 } from "node:crypto";
58070
+ import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync69, mkdirSync as mkdirSync29, writeFileSync as writeFileSync27, existsSync as existsSync58, rmSync as rmSync11, readdirSync as readdirSync26, statSync as statSync15, lstatSync as lstatSync6, accessSync, constants } from "node:fs";
58071
+ import { execFile as execFile4, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
58072
+ import { createHash as createHash25, randomUUID as randomUUID3 } from "node:crypto";
57795
58073
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
57796
- import { join as join53, resolve as resolve44, relative as relative8, basename as basename12, dirname as dirname32 } from "node:path";
58074
+ import { join as join54, resolve as resolve45, relative as relative9, basename as basename12, dirname as dirname32 } from "node:path";
57797
58075
  import { fileURLToPath as fileURLToPath24 } from "node:url";
57798
58076
 
57799
58077
  // ../serve-cli/src/client.ts
@@ -59505,7 +59783,7 @@ async function browserLogin(opts) {
59505
59783
  const log = opts.log ?? (() => {
59506
59784
  });
59507
59785
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
59508
- return await new Promise((resolve45, reject) => {
59786
+ return await new Promise((resolve46, reject) => {
59509
59787
  let settled = false;
59510
59788
  let loginUrl = "";
59511
59789
  const server = createServer();
@@ -59569,7 +59847,7 @@ async function browserLogin(opts) {
59569
59847
  return;
59570
59848
  }
59571
59849
  res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store", connection: "close" }).end(CLOSE_PAGE);
59572
- finish2(() => resolve45({ token, loginUrl }));
59850
+ finish2(() => resolve46({ token, loginUrl }));
59573
59851
  });
59574
59852
  });
59575
59853
  server.on("error", (err) => finish2(() => reject(err)));
@@ -60935,7 +61213,7 @@ function writeAgentContext(targetDir) {
60935
61213
  // src/cli.ts
60936
61214
  init_wix_placeholders();
60937
61215
  var defaultIO = { log: (l) => console.log(l), error: (l) => console.error(l), isTTY: process.stdout.isTTY === true };
60938
- var REPEATABLE_FLAGS = /* @__PURE__ */ new Set(["data"]);
61216
+ var REPEATABLE_FLAGS = /* @__PURE__ */ new Set(["data", "image"]);
60939
61217
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
60940
61218
  "browser",
60941
61219
  "no-open",
@@ -61002,7 +61280,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
61002
61280
  "refresh",
61003
61281
  "push-setup",
61004
61282
  "no-push-setup",
61005
- "apple-signing"
61283
+ "apple-signing",
61284
+ "notify"
61006
61285
  ]);
61007
61286
  var SHELL_ENUM = SHELL_NAMES2.join("|");
61008
61287
  var SWITCH_FLAGS = new Set([...BOOLEAN_FLAGS].filter((name) => name !== "deep"));
@@ -61071,8 +61350,8 @@ var str5 = (v) => typeof v === "string" ? v : void 0;
61071
61350
  var num = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
61072
61351
  function embeddedTemplateCatalog() {
61073
61352
  return availableTemplates().map((name) => {
61074
- const path2 = join53(templateSourceDir(name), TEMPLATE_META_FILE);
61075
- const meta = JSON.parse(readFileSync68(path2, "utf8"));
61353
+ const path2 = join54(templateSourceDir(name), TEMPLATE_META_FILE);
61354
+ const meta = JSON.parse(readFileSync69(path2, "utf8"));
61076
61355
  if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
61077
61356
  throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
61078
61357
  }
@@ -61129,6 +61408,11 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
61129
61408
  verticals; zero network). Catches the wrong reducers
61130
61409
  validate/render pass (NaN totals, stuck skeletons, dead
61131
61410
  taps). Exit 1 on any error. Run it after every edit.
61411
+ himi progress ["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>]
61412
+ journal a postcard for the owner (.himi/progress.jsonl): what
61413
+ changed, which journey step, and the image that shows it (copied
61414
+ into .himi/history/ so later renders cannot replace it). Bare
61415
+ prints the journal, the current step and the elapsed time.
61132
61416
  himi ux audit [--content <dir>] [--strict] [--json]
61133
61417
  inspect the mobile UX contract, template placeholders, app fixtures,
61134
61418
  and recorded iOS/Android audit evidence. Advisory by default; --strict
@@ -61673,6 +61957,7 @@ var COMMANDS = [
61673
61957
  { name: "validate", summary: "lint the content package (no push): fixed-contract TypeScript checking for tier5-src workers + schema/proto + token refs + component allowlist + $service bindings + strict-enum foot-guns + capability decls + worker boot dry-run + build/compile failures. Type issues are advisory warnings normally; --strict promotes them and hygiene warnings to errors. Exit 1 on any error. Off-repo, the CLI supplies its compiler and SDK declarations.", required: "[--content <dir>] [--strict]" },
61674
61958
  { name: "test", summary: "DERIVED behavioral crawl \u2014 no test files to write. Boots each screen's real worker, replays its onAppear, then dispatches every action site the descriptor already declares (each from a fresh boot) and checks a narrow set of unambiguous invariants: no uncaught throw, never stuck on `loading`, no `$service:` token or NaN/undefined/[object Object] reaching visible text, no binding aimed at state the worker never defines, no nav param silently dropped, no dead nav target. Catches what validate/render cannot \u2014 a WRONG REDUCER passes both with ok:true. Runs the worker in a DEVICE-PARITY sandbox (no setTimeout/setInterval, as on JSC/WebView) so a bundle that would die on device fails here. Crawls on HERMETIC DATA by default \u2014 zero network: the app's own dev/net-mocks.json first (--net <file> overrides), then the config's CMS `seed:` rows, then a canned fixture of frozen real vertical responses shipped with the CLI (exercises code paths, not API-contract truth) \u2014 so the success/mapping path runs, not just the failure UI. Two boot-only HOSTILE passes (every list empty; every request 500) then check the failure/empty day \u2014 corpus-proven, so their findings are errors. NAV EDGES are followed too: every himi.open site ($item params resolved against row 0 of its list, $service against worker state) and worker _nav directive is harvested, and each baked target is booted WITH the params the source sends \u2014 detail screens finally run their content arm; edge findings are errors tagged edge:<source>. --native runs both real native decoders over the exact baked JSON bytes; --native ios or --native android selects one. It is explicit, runs only from a Himalaya SOURCE CHECKOUT (the decoder oracles are that tree's own HimalayaCore Swift package and Gradle harness, which a published install does not ship), and needs the selected local toolchain. From a source checkout, default runs name missing native verdicts in the coverage ledger; elsewhere the ledger stays silent about them rather than offering a remedy you cannot run. --offline strips all data layers (the old reject-all axis); --no-hostile skips the hostile passes. --record (EXPLICIT, never automatic) refreshes dev/net-mocks.json from live reads first: it boots each screen (load + root onAppear ONLY \u2014 nothing the app's own launch would not fire; the tap/action crawl never sees the live transport, and only proven reads \u2014 GET, or read-shaped POST (/query, /search, /list*, \u2026) \u2014 ever reach the wire), freezes the round-trips, then crawls hermetically on the fresh fixture; record against a QA site, not production. Nodes it cannot judge headless are named, never silently passed. Exit 1 on any error. The CLI carries the authoring runtime off-repo; no per-app SDK install is required. --browser runs the whole loop (build \u2192 extract \u2192 validate \u2192 render \u2192 test) in YOUR browser instead of here, so the source never reaches a pod: it opens one screen's worker + descriptor in a tab, blocks on a loopback callback, and prints the report it posts back. One screen per tab \u2014 name it. --no-open prints the URL rather than launching a browser (SSH); --timeout <ms> bounds the wait, which matters because the page has no execution deadline of its own and an infinite loop in the worker hangs the tab.", required: "[<screenId>\u2026] [--content <dir>] [--net <file>] [--budget <ms>] [--deep [n]] [--record] [--native [ios|android]] [--no-shots] [--offline] [--no-hostile] [--all-screens] [--browser] [--no-open] [--timeout <ms>] [--json]" },
61675
61959
  { name: "ux", summary: "audit or record mobile UX evidence. `audit` checks the public-safe contract, seeded blank acceptance rows, placeholder source copy, app-specific mocks, and iOS/Android audit records. It warns while existing templates migrate; `--strict` promotes missing evidence. `record` stores checks performed on an installed iOS/Android build: `--checks` is required for passed|failed and empty for unavailable, which drove nothing and needs a `--reason` instead. `record` also STAMPS the release it audited (it resolves the id from a build, the same one a push would publish), because an unforced `himi push` of a release with screens refuses when no drive is recorded for THAT release, or when the one that is recorded says `failed` \u2014 the artifact stopped being advice nobody reads (#2955). `unavailable` still satisfies it; only `failed` refuses.", required: "audit [--content <dir>] [--strict] [--json] | record --content <dir> --platform ios|android --status passed|failed|unavailable [--checks back,keyboard,...] [--reason <text>]" },
61960
+ { name: "progress", summary: 'the build JOURNAL an agent keeps for the owner while it works. `himi progress "<what changed>" --step <1-8|name> --image <png>` appends one postcard to .himi/progress.jsonl \u2014 the step is one of the customer journey\'s eight (discover, classify, plan, implement, brand, validate, review, download) \u2014 and COPIES each image, content-addressed, into .himi/history/, because .himi/shots/ is overwritten by every render and cleared by every full `himi test`, so a path into it would later show a different picture than the one the owner was sent. --image repeats. --notify also raises a best-effort desktop notification for an owner who stepped away. A bare `himi progress` prints the journal with the current step and elapsed time \u2014 also how an agent recovers its place after its context was compacted. Local only: nothing is sent anywhere.', required: '["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>]' },
61676
61961
  { name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png <file>, --scheme dark, --tree. Local by default (content dir). Pass --remote --app --release to hit GET /v1/preview/\u2026/render on the serve plane after a push. Boots the worker so $service bindings resolve; --static raw bindings; --live real Wix fetches; --state injects worker state; --input supplies pre-boot navigation params; --width/--device for PNG viewport; --rtl for dir=rtl + $env:isRTL.", required: "<screenId> [--content <dir>] [--scheme dark] [--png <file>] [--tree] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--remote --app --release]" },
61677
61962
  { name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 it follows the list endpoint's pages, and `listingIncomplete: true` says when the walk stopped short of the end, with `unlistedCollections` counting what it left out when Wix gave a paging total \u2014 and `foreign.truncated` says how many of those went undescribed, each still NAMED in `foreign.others` (id + displayName), so a collection the site already has is never hidden behind the cap. The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
61678
61963
  { name: "data", summary: "read-only plan or explicitly provision/seed declared KV and Wix Data resources. Preview and production are separate scopes. KV administration uses the operator data plane from --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN; draft push never calls it.", required: "plan|create|seed [--site <msid>] [--environment preview|production] [--content <dir>] [--data-url <url>] [--dry-run] [--force]" },
@@ -61721,7 +62006,7 @@ var COMMANDS = [
61721
62006
  ];
61722
62007
  function cliVersion() {
61723
62008
  try {
61724
- return JSON.parse(readFileSync68(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
62009
+ return JSON.parse(readFileSync69(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
61725
62010
  } catch {
61726
62011
  return "unknown";
61727
62012
  }
@@ -61772,16 +62057,16 @@ function createScopedRegistryResolver(exec = execNpmConfig) {
61772
62057
  }
61773
62058
  var SCOPED_REGISTRY_TIMEOUT_MS = 5e3;
61774
62059
  function execNpmConfig(file, args, options) {
61775
- return new Promise((resolve45, reject) => {
61776
- execFile4(file, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve45(String(stdout)));
62060
+ return new Promise((resolve46, reject) => {
62061
+ execFile4(file, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve46(String(stdout)));
61777
62062
  });
61778
62063
  }
61779
62064
  var npmScopedWixRegistry = createScopedRegistryResolver();
61780
62065
  async function scopedRegistryBefore(lookup2, deadline) {
61781
62066
  let cancel = () => {
61782
62067
  };
61783
- const expired = new Promise((resolve45) => {
61784
- const timer = setTimeout(() => resolve45(void 0), Math.max(0, deadline - Date.now()));
62068
+ const expired = new Promise((resolve46) => {
62069
+ const timer = setTimeout(() => resolve46(void 0), Math.max(0, deadline - Date.now()));
61785
62070
  cancel = () => clearTimeout(timer);
61786
62071
  });
61787
62072
  try {
@@ -61839,16 +62124,16 @@ function ageInDays(publishedAt, now = Date.now()) {
61839
62124
  }
61840
62125
  function packageVersion(path2) {
61841
62126
  try {
61842
- const version2 = JSON.parse(readFileSync68(path2, "utf8")).version;
62127
+ const version2 = JSON.parse(readFileSync69(path2, "utf8")).version;
61843
62128
  return typeof version2 === "string" && version2 ? version2 : void 0;
61844
62129
  } catch {
61845
62130
  return void 0;
61846
62131
  }
61847
62132
  }
61848
62133
  function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
61849
- let dir = resolve44(fromDir);
62134
+ let dir = resolve45(fromDir);
61850
62135
  for (; ; ) {
61851
- const version2 = packageVersion(join53(dir, "node_modules", "@wix", "himalaya", "package.json"));
62136
+ const version2 = packageVersion(join54(dir, "node_modules", "@wix", "himalaya", "package.json"));
61852
62137
  if (version2) return { version: version2, source: "local" };
61853
62138
  const parent = dirname32(dir);
61854
62139
  if (parent === dir) break;
@@ -61858,7 +62143,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
61858
62143
  if (bundled) return { version: bundled, source: "bundled" };
61859
62144
  try {
61860
62145
  const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
61861
- const version2 = root ? packageVersion(join53(root, "@wix", "himalaya", "package.json")) : void 0;
62146
+ const version2 = root ? packageVersion(join54(root, "@wix", "himalaya", "package.json")) : void 0;
61862
62147
  return version2 ? { version: version2, source: "global" } : {};
61863
62148
  } catch {
61864
62149
  return {};
@@ -61905,11 +62190,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
61905
62190
  var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
61906
62191
  var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
61907
62192
  function updateCachePath(env = process.env) {
61908
- return env.HIMI_UPDATE_CACHE_FILE ?? join53(homedir7(), ".himalaya", "update-check.json");
62193
+ return env.HIMI_UPDATE_CACHE_FILE ?? join54(homedir7(), ".himalaya", "update-check.json");
61909
62194
  }
61910
62195
  function readUpdateCache(path2) {
61911
62196
  try {
61912
- const parsed = JSON.parse(readFileSync68(path2, "utf8"));
62197
+ const parsed = JSON.parse(readFileSync69(path2, "utf8"));
61913
62198
  return parsed && typeof parsed === "object" ? parsed : {};
61914
62199
  } catch {
61915
62200
  return {};
@@ -61917,8 +62202,8 @@ function readUpdateCache(path2) {
61917
62202
  }
61918
62203
  function writeUpdateCache(path2, cache) {
61919
62204
  try {
61920
- mkdirSync28(dirname32(path2), { recursive: true, mode: 448 });
61921
- writeFileSync26(path2, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
62205
+ mkdirSync29(dirname32(path2), { recursive: true, mode: 448 });
62206
+ writeFileSync27(path2, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
61922
62207
  } catch {
61923
62208
  }
61924
62209
  }
@@ -61959,12 +62244,12 @@ function npmInstallArgs(registry, version2) {
61959
62244
  return ["i", "-g", `${CLI_PACKAGE}@${version2}`, `--registry=${pinned}`, `--@wix:registry=${pinned}`];
61960
62245
  }
61961
62246
  var INSTALLABLE_SPEC = /^(?:latest|\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/;
61962
- function createUpdateRunner(spawn6 = spawnSync5) {
62247
+ function createUpdateRunner(spawn7 = spawnSync5) {
61963
62248
  return {
61964
62249
  install: async (registry, version2) => {
61965
62250
  if (!isTrustedRegistry(registry)) return { ok: false, detail: `refusing untrusted registry ${registry}` };
61966
62251
  if (!INSTALLABLE_SPEC.test(version2)) return { ok: false, detail: `refusing install spec ${JSON.stringify(version2)}` };
61967
- const result = spawn6("npm", npmInstallArgs(registry, version2), {
62252
+ const result = spawn7("npm", npmInstallArgs(registry, version2), {
61968
62253
  // npm's stdout goes to OUR stderr: in `himi <cmd> --json | jq` (and `himi upgrade --json`) its
61969
62254
  // "added 212 packages" would otherwise land in stdout ahead of the envelope and break the
61970
62255
  // parse — the agent case this whole feature exists for (#2985 review). And no stdin: an
@@ -61977,12 +62262,12 @@ function createUpdateRunner(spawn6 = spawnSync5) {
61977
62262
  },
61978
62263
  installedVersion: () => {
61979
62264
  const root = globalNodeModulesRoot();
61980
- return root ? packageVersion(join53(root, "@wix", "himalaya-cli", "package.json")) : void 0;
62265
+ return root ? packageVersion(join54(root, "@wix", "himalaya-cli", "package.json")) : void 0;
61981
62266
  },
61982
62267
  reexec: (argv) => {
61983
62268
  const root = globalNodeModulesRoot();
61984
- const entry = root ? join53(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
61985
- if (!entry || !existsSync57(entry)) return void 0;
62269
+ const entry = root ? join54(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
62270
+ if (!entry || !existsSync58(entry)) return void 0;
61986
62271
  const result = spawnSync5(process.execPath, [entry, ...argv], {
61987
62272
  // inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
61988
62273
  stdio: "inherit",
@@ -62029,7 +62314,7 @@ function staleUpdateLockFile(cachePath, now) {
62029
62314
  for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
62030
62315
  let content;
62031
62316
  try {
62032
- content = readFileSync68(path2, "utf8");
62317
+ content = readFileSync69(path2, "utf8");
62033
62318
  } catch {
62034
62319
  continue;
62035
62320
  }
@@ -62037,7 +62322,7 @@ function staleUpdateLockFile(cachePath, now) {
62037
62322
  let since = stamped;
62038
62323
  if (!Number.isFinite(since)) {
62039
62324
  try {
62040
- since = statSync14(path2).mtimeMs;
62325
+ since = statSync15(path2).mtimeMs;
62041
62326
  } catch {
62042
62327
  continue;
62043
62328
  }
@@ -62052,14 +62337,14 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
62052
62337
  const mine = lockStamp(now);
62053
62338
  const readLock = (path2) => {
62054
62339
  try {
62055
- return readFileSync68(path2, "utf8");
62340
+ return readFileSync69(path2, "utf8");
62056
62341
  } catch {
62057
62342
  return void 0;
62058
62343
  }
62059
62344
  };
62060
62345
  const tryCreate = (path2) => {
62061
62346
  try {
62062
- writeFileSync26(path2, mine, { flag: "wx", mode: 384 });
62347
+ writeFileSync27(path2, mine, { flag: "wx", mode: 384 });
62063
62348
  return true;
62064
62349
  } catch {
62065
62350
  return false;
@@ -62073,7 +62358,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
62073
62358
  };
62074
62359
  const release = () => removeIfMine(lockPath);
62075
62360
  try {
62076
- mkdirSync28(dirname32(lockPath), { recursive: true, mode: 448 });
62361
+ mkdirSync29(dirname32(lockPath), { recursive: true, mode: 448 });
62077
62362
  } catch {
62078
62363
  return () => {
62079
62364
  };
@@ -62137,7 +62422,7 @@ function supersededInCache(current, latest, now) {
62137
62422
  const checkedAt = current.checkedAt ? Date.parse(current.checkedAt) : Number.NaN;
62138
62423
  return Number.isFinite(checkedAt) && now - checkedAt < UPDATE_CHECK_INTERVAL_MS;
62139
62424
  }
62140
- function createUpdateRefreshSpawner(spawnFn = spawn5, execArgv = process.execArgv) {
62425
+ function createUpdateRefreshSpawner(spawnFn = spawn6, execArgv = process.execArgv) {
62141
62426
  return () => {
62142
62427
  try {
62143
62428
  const child = spawnFn(process.execPath, [...loaderArgs(execArgv), fileURLToPath24(import.meta.url), UPDATE_REFRESH_COMMAND], {
@@ -62590,9 +62875,9 @@ function executableOnPath(name, env = process.env) {
62590
62875
  const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
62591
62876
  for (const dir of entries) {
62592
62877
  for (const suffix of suffixes) {
62593
- const candidate = join53(dir, `${name}${suffix}`);
62878
+ const candidate = join54(dir, `${name}${suffix}`);
62594
62879
  try {
62595
- if (!statSync14(candidate).isFile()) continue;
62880
+ if (!statSync15(candidate).isFile()) continue;
62596
62881
  if (process.platform !== "win32") accessSync(candidate, constants.X_OK);
62597
62882
  return true;
62598
62883
  } catch {
@@ -62699,7 +62984,7 @@ async function nativeConfigAdvisories(app, configSource) {
62699
62984
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
62700
62985
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
62701
62986
  const iosYmlPath = iosProjectYml2(app);
62702
- const iosYml = existsSync57(iosYmlPath) ? readFileSync68(iosYmlPath, "utf8") : "";
62987
+ const iosYml = existsSync58(iosYmlPath) ? readFileSync69(iosYmlPath, "utf8") : "";
62703
62988
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
62704
62989
  if (!optedIn) {
62705
62990
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -62713,19 +62998,19 @@ async function nativeConfigAdvisories(app, configSource) {
62713
62998
  }
62714
62999
  function readConfigSource(dir) {
62715
63000
  try {
62716
- return readFileSync68(join53(dir, "config.ts"), "utf8");
63001
+ return readFileSync69(join54(dir, "config.ts"), "utf8");
62717
63002
  } catch {
62718
63003
  return null;
62719
63004
  }
62720
63005
  }
62721
63006
  function writePngFile(path2, base64) {
62722
- mkdirSync28(dirname32(path2), { recursive: true });
62723
- writeFileSync26(path2, Buffer.from(base64, "base64"));
63007
+ mkdirSync29(dirname32(path2), { recursive: true });
63008
+ writeFileSync27(path2, Buffer.from(base64, "base64"));
62724
63009
  return path2;
62725
63010
  }
62726
63011
  async function initFromRemoteTemplate(name, parentDir, template, c) {
62727
- const dir = resolve44(parentDir, name);
62728
- if (existsSync57(join53(dir, "himalaya.content.json"))) {
63012
+ const dir = resolve45(parentDir, name);
63013
+ if (existsSync58(join54(dir, "himalaya.content.json"))) {
62729
63014
  throw new Error(`content package already exists at ${dir}`);
62730
63015
  }
62731
63016
  const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -62737,7 +63022,7 @@ async function initFromRemoteTemplate(name, parentDir, template, c) {
62737
63022
  return finishScaffold(materializeSource(archive.files, name, dir), template);
62738
63023
  }
62739
63024
  function contentDir(flags) {
62740
- return resolve44(str5(flags.content) ?? process.cwd());
63025
+ return resolve45(str5(flags.content) ?? process.cwd());
62741
63026
  }
62742
63027
  function renameRestoredSource(restored, declaredApp, renamed) {
62743
63028
  const text4 = {};
@@ -62768,8 +63053,8 @@ function symlinkDestinationIssue(dest) {
62768
63053
  function restoreDestinationIssue(dest, force) {
62769
63054
  const link = symlinkDestinationIssue(dest);
62770
63055
  if (link) return link;
62771
- if (!existsSync57(dest)) return null;
62772
- if (!statSync14(dest).isDirectory()) {
63056
+ if (!existsSync58(dest)) return null;
63057
+ if (!statSync15(dest).isDirectory()) {
62773
63058
  return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
62774
63059
  }
62775
63060
  if (readdirSync26(dest).length > 0 && !force) {
@@ -62781,9 +63066,9 @@ function restoreDestinationIssue(dest, force) {
62781
63066
  return null;
62782
63067
  }
62783
63068
  function isHimalayaMonorepoCheckout(start) {
62784
- let dir = resolve44(start);
63069
+ let dir = resolve45(start);
62785
63070
  for (; ; ) {
62786
- if (existsSync57(join53(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync57(join53(dir, "core", "serve", "src", "server.ts"))) return true;
63071
+ if (existsSync58(join54(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync58(join54(dir, "core", "serve", "src", "server.ts"))) return true;
62787
63072
  const parent = dirname32(dir);
62788
63073
  if (parent === dir) return false;
62789
63074
  dir = parent;
@@ -62825,8 +63110,8 @@ function materializeForPreview(appDir2, slug, displayName) {
62825
63110
  const forBuild = Object.fromEntries(
62826
63111
  Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
62827
63112
  );
62828
- const repoRoot2 = resolve44(fileURLToPath24(new URL("../../..", import.meta.url)));
62829
- const root = join53(repoRoot2, "node_modules", ".cache", "himi-template-preview");
63113
+ const repoRoot2 = resolve45(fileURLToPath24(new URL("../../..", import.meta.url)));
63114
+ const root = join54(repoRoot2, "node_modules", ".cache", "himi-template-preview");
62830
63115
  const stillRunning = (pid) => {
62831
63116
  try {
62832
63117
  process.kill(pid, 0);
@@ -62840,21 +63125,21 @@ function materializeForPreview(appDir2, slug, displayName) {
62840
63125
  if (!entry.isDirectory()) continue;
62841
63126
  const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
62842
63127
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
62843
- rmSync11(join53(root, entry.name), { recursive: true, force: true });
63128
+ rmSync11(join54(root, entry.name), { recursive: true, force: true });
62844
63129
  }
62845
63130
  }
62846
63131
  } catch {
62847
63132
  }
62848
- const dest = join53(root, `${slug}-${process.pid}`);
63133
+ const dest = join54(root, `${slug}-${process.pid}`);
62849
63134
  rmSync11(dest, { recursive: true, force: true });
62850
- mkdirSync28(dest, { recursive: true });
63135
+ mkdirSync29(dest, { recursive: true });
62851
63136
  materializeSource(forBuild, displayName, dest, slug);
62852
63137
  return dest;
62853
63138
  }
62854
63139
  async function appId(dir) {
62855
63140
  try {
62856
- const { readFileSync: readFileSync69 } = await import("node:fs");
62857
- const m = JSON.parse(readFileSync69(join53(dir, "himalaya.content.json"), "utf8"));
63141
+ const { readFileSync: readFileSync70 } = await import("node:fs");
63142
+ const m = JSON.parse(readFileSync70(join54(dir, "himalaya.content.json"), "utf8"));
62858
63143
  if (m.name) return m.name;
62859
63144
  } catch {
62860
63145
  }
@@ -62862,8 +63147,8 @@ async function appId(dir) {
62862
63147
  }
62863
63148
  async function contentVisibility(dir) {
62864
63149
  try {
62865
- const { readFileSync: readFileSync69 } = await import("node:fs");
62866
- const m = JSON.parse(readFileSync69(join53(dir, "himalaya.content.json"), "utf8"));
63150
+ const { readFileSync: readFileSync70 } = await import("node:fs");
63151
+ const m = JSON.parse(readFileSync70(join54(dir, "himalaya.content.json"), "utf8"));
62867
63152
  if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
62868
63153
  } catch {
62869
63154
  }
@@ -63065,7 +63350,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
63065
63350
  return 0;
63066
63351
  }
63067
63352
  case "agent-init": {
63068
- const dir = resolve44(str5(flags.dir) ?? process.cwd());
63353
+ const dir = resolve45(str5(flags.dir) ?? process.cwd());
63069
63354
  const res = writeAgentContext(dir);
63070
63355
  print({ ok: true, dir: res.dir, files: res.files, portalUrl: idx.portalUrl });
63071
63356
  return 0;
@@ -63087,7 +63372,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
63087
63372
  try {
63088
63373
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
63089
63374
  const bres = await buildContentForValidation2(dir, { resolution });
63090
- out = mkdtempSync4(join53(tmpdir5(), "himi-ux-record-"));
63375
+ out = mkdtempSync4(join54(tmpdir5(), "himi-ux-record-"));
63091
63376
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
63092
63377
  const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
63093
63378
  const releaseId = outcome.manifest.releaseId;
@@ -63265,7 +63550,7 @@ async function producedWidgetFamilies(dir) {
63265
63550
  let js;
63266
63551
  for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
63267
63552
  try {
63268
- js = readFileSync68(join53(outDir, candidate), "utf8");
63553
+ js = readFileSync69(join54(outDir, candidate), "utf8");
63269
63554
  break;
63270
63555
  } catch {
63271
63556
  }
@@ -63541,7 +63826,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63541
63826
  return 2;
63542
63827
  }
63543
63828
  const template = str5(flags.template);
63544
- const parentDir = resolve44(str5(flags.dir) ?? process.cwd());
63829
+ const parentDir = resolve45(str5(flags.dir) ?? process.cwd());
63545
63830
  if (template && flags.remote === true) {
63546
63831
  try {
63547
63832
  const res2 = await initFromRemoteTemplate(name, parentDir, template, client2());
@@ -63658,11 +63943,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63658
63943
  return outcome.code;
63659
63944
  }
63660
63945
  if (sub === "publish") {
63661
- const appDir2 = resolve44(str5(flags.dir) ?? process.cwd());
63662
- const sourceDir = resolve44(str5(flags["source-dir"]) ?? appDir2);
63946
+ const appDir2 = resolve45(str5(flags.dir) ?? process.cwd());
63947
+ const sourceDir = resolve45(str5(flags["source-dir"]) ?? appDir2);
63663
63948
  let meta;
63664
63949
  try {
63665
- meta = JSON.parse(readFileSync68(join53(sourceDir, TEMPLATE_META_FILE), "utf8"));
63950
+ meta = JSON.parse(readFileSync69(join54(sourceDir, TEMPLATE_META_FILE), "utf8"));
63666
63951
  } catch {
63667
63952
  io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
63668
63953
  return 2;
@@ -63672,7 +63957,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63672
63957
  return 2;
63673
63958
  }
63674
63959
  try {
63675
- const appearance = extractTemplateAppearance(JSON.parse(readFileSync68(join53(sourceDir, "tokens.json"), "utf8")));
63960
+ const appearance = extractTemplateAppearance(JSON.parse(readFileSync69(join54(sourceDir, "tokens.json"), "utf8")));
63676
63961
  meta = { ...appearance, ...meta };
63677
63962
  } catch {
63678
63963
  }
@@ -63684,13 +63969,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63684
63969
  const force = flags.force === true;
63685
63970
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
63686
63971
  const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
63687
- const out = mkdtempSync4(join53(tmpdir5(), "himi-template-"));
63972
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-template-"));
63688
63973
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
63689
63974
  const outcome = await buildReleaseFromContent2(buildDir, out, {
63690
63975
  ...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
63691
63976
  collect: { lint: true, strict }
63692
63977
  });
63693
- const scaffoldSourceFindings = resolve44(sourceDir) === resolve44(appDir2) ? [] : [
63978
+ const scaffoldSourceFindings = resolve45(sourceDir) === resolve45(appDir2) ? [] : [
63694
63979
  ...tokenColorIssues(sourceDir),
63695
63980
  ...surfaceIssues(sourceDir, void 0, strict),
63696
63981
  ...await fontIssues(sourceDir, strict),
@@ -63733,13 +64018,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63733
64018
  }));
63734
64019
  return 1;
63735
64020
  }
63736
- const iconPath = str5(flags.icon) ? resolve44(str5(flags.icon)) : templateIconPath(name);
64021
+ const iconPath = str5(flags.icon) ? resolve45(str5(flags.icon)) : templateIconPath(name);
63737
64022
  let iconHash;
63738
64023
  if (iconPath) {
63739
64024
  try {
63740
- const bytes2 = readFileSync68(iconPath);
64025
+ const bytes2 = readFileSync69(iconPath);
63741
64026
  payload.icon = bytes2.toString("base64");
63742
- iconHash = createHash24("sha256").update(bytes2).digest("hex");
64027
+ iconHash = createHash25("sha256").update(bytes2).digest("hex");
63743
64028
  } catch {
63744
64029
  }
63745
64030
  }
@@ -63970,7 +64255,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63970
64255
  const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
63971
64256
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
63972
64257
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
63973
- const out = mkdtempSync4(join53(tmpdir5(), "himi-validate-"));
64258
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-validate-"));
63974
64259
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
63975
64260
  const outcome = await buildReleaseFromContent2(dir, out, {
63976
64261
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -64007,7 +64292,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64007
64292
  const path2 = dpxSessionTokenPath();
64008
64293
  let raw;
64009
64294
  try {
64010
- raw = readFileSync68(path2, "utf8");
64295
+ raw = readFileSync69(path2, "utf8");
64011
64296
  } catch {
64012
64297
  throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
64013
64298
  }
@@ -64124,6 +64409,49 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64124
64409
  print({ ok: invoked.response.ok, app: loaded.app, releaseId: invoked.releaseId, status: invoked.response.status, body });
64125
64410
  return invoked.response.ok ? 0 : 1;
64126
64411
  }
64412
+ case "progress": {
64413
+ const { appendProgress: appendProgress2, readProgress: readProgress2, summarizeProgress: summarizeProgress2, parseStep: parseStep2, notifyDesktop: notifyDesktop2, appLabel: appLabel2, journalPath: journalPath2, ProgressError: ProgressError2, JOURNEY_STEPS: JOURNEY_STEPS2 } = await Promise.resolve().then(() => (init_progress(), progress_exports));
64414
+ const dir = contentDir(flags);
64415
+ const journal = journalPath2(dir);
64416
+ const hint = existsSync58(join54(dir, "himalaya.content.json")) ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
64417
+ const message = pos.slice(1).join(" ").trim();
64418
+ if (!message) {
64419
+ if (flags.step !== void 0 || flags.image !== void 0 || flags.notify === true) {
64420
+ io.error(JSON.stringify({ ok: false, error: "message_required", hint: 'progress "<what changed>" --step <n> --image <png>' }));
64421
+ return 2;
64422
+ }
64423
+ const { entries, skipped } = readProgress2(dir);
64424
+ print({ ok: true, journal, ...summarizeProgress2(entries), entries, ...skipped ? { skipped } : {}, ...hint });
64425
+ return 0;
64426
+ }
64427
+ let step;
64428
+ if (flags.step !== void 0) {
64429
+ step = typeof flags.step === "string" ? parseStep2(flags.step) : null;
64430
+ if (!step) {
64431
+ io.error(JSON.stringify({ ok: false, error: "invalid_step", got: flags.step, expected: `1-8 or ${JOURNEY_STEPS2.join("|")}` }));
64432
+ return 2;
64433
+ }
64434
+ }
64435
+ const rawImages = flags.image;
64436
+ const images = rawImages === void 0 ? [] : Array.isArray(rawImages) ? rawImages : typeof rawImages === "string" ? [rawImages] : null;
64437
+ if (!images) {
64438
+ io.error(JSON.stringify({ ok: false, error: "image_path_required", hint: "--image <png>, repeatable" }));
64439
+ return 2;
64440
+ }
64441
+ try {
64442
+ const entry = appendProgress2(dir, { message, ...step ? { step } : {}, images });
64443
+ const notified = flags.notify === true ? await notifyDesktop2(`himi \xB7 ${appLabel2(dir) ?? "your app"}`, message) : void 0;
64444
+ const { count } = summarizeProgress2(readProgress2(dir).entries);
64445
+ print({ ok: true, entry, journal, count, ...notified === void 0 ? {} : { notified }, ...hint });
64446
+ return 0;
64447
+ } catch (e) {
64448
+ if (e instanceof ProgressError2) {
64449
+ io.error(JSON.stringify({ ok: false, error: e.code, message: e.message }));
64450
+ return 2;
64451
+ }
64452
+ throw e;
64453
+ }
64454
+ }
64127
64455
  case "ux": {
64128
64456
  const sub = pos[1] ?? "audit";
64129
64457
  const dir = contentDir(flags);
@@ -64177,7 +64505,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64177
64505
  case "test": {
64178
64506
  const dir = contentDir(flags);
64179
64507
  const structuredOutput = flags.json === true || io.isTTY !== true;
64180
- if (existsSync57(join53(dir, "functions"))) {
64508
+ if (existsSync58(join54(dir, "functions"))) {
64181
64509
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
64182
64510
  const loaded = await loadFunctionsApp2(dir);
64183
64511
  const results = [];
@@ -64264,7 +64592,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64264
64592
  }
64265
64593
  }
64266
64594
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
64267
- const out = mkdtempSync4(join53(tmpdir5(), "himi-test-"));
64595
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-test-"));
64268
64596
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64269
64597
  const outcome = await buildReleaseFromContent2(dir, out, {
64270
64598
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -64309,7 +64637,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64309
64637
  io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
64310
64638
  return 2;
64311
64639
  }
64312
- const sources = collectWorkerSources2(join53(dir, "tier5-src"), screen.bundleName);
64640
+ const sources = collectWorkerSources2(join54(dir, "tier5-src"), screen.bundleName);
64313
64641
  if (!sources) {
64314
64642
  io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
64315
64643
  return 2;
@@ -64470,7 +64798,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64470
64798
  const sp = await runShotsPass2({
64471
64799
  descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
64472
64800
  tokens: outcome.tokens,
64473
- outDir: join53(dir, ".himi", "shots"),
64801
+ outDir: join54(dir, ".himi", "shots"),
64474
64802
  width: 390,
64475
64803
  layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
64476
64804
  ...budgetMs ? { budgetMs } : {},
@@ -64508,7 +64836,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64508
64836
  releaseId: result.releaseId,
64509
64837
  releasePayload: release,
64510
64838
  descriptors: attestedDescriptors,
64511
- screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join53(dir, ".himi", "shots", name)])),
64839
+ screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join54(dir, ".himi", "shots", name)])),
64512
64840
  coverage: {
64513
64841
  screens: crawledScreens.size,
64514
64842
  actionsDispatched: result.actions.exercised,
@@ -64597,7 +64925,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64597
64925
  return 2;
64598
64926
  }
64599
64927
  try {
64600
- const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync68(stateArg.replace(/^@/, ""), "utf8");
64928
+ const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync69(stateArg.replace(/^@/, ""), "utf8");
64601
64929
  injectedState = JSON.parse(raw);
64602
64930
  } catch (e) {
64603
64931
  io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
@@ -64612,7 +64940,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64612
64940
  return 2;
64613
64941
  }
64614
64942
  try {
64615
- const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync68(inputArg.replace(/^@/, ""), "utf8");
64943
+ const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync69(inputArg.replace(/^@/, ""), "utf8");
64616
64944
  const parsed = JSON.parse(raw);
64617
64945
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
64618
64946
  injectedInput = parsed;
@@ -64661,7 +64989,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64661
64989
  }
64662
64990
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
64663
64991
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
64664
- const out = mkdtempSync4(join53(tmpdir5(), "himi-render-"));
64992
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-render-"));
64665
64993
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64666
64994
  const outcome = await buildReleaseFromContent2(dir, out, {
64667
64995
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -64677,7 +65005,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64677
65005
  let attestationPngFile;
64678
65006
  if (typeof flags.png === "string" && r.pngBase64) {
64679
65007
  pngFile = writePngFile(str5(flags.png), r.pngBase64);
64680
- attestationPngFile = writePngFile(join53(dir, ".himi", "shots", `${screenId}.png`), r.pngBase64);
65008
+ attestationPngFile = writePngFile(join54(dir, ".himi", "shots", `${screenId}.png`), r.pngBase64);
64681
65009
  }
64682
65010
  if (renderWidth !== void 0 && r.renderable) {
64683
65011
  recordRenderWidth(dir, {
@@ -65001,7 +65329,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65001
65329
  return 2;
65002
65330
  }
65003
65331
  const renamed = str5(flags.name);
65004
- const dest = resolve44(str5(flags.out) ?? process.cwd(), renamed ?? wanted);
65332
+ const dest = resolve45(str5(flags.out) ?? process.cwd(), renamed ?? wanted);
65005
65333
  const replace = flags.replace === true;
65006
65334
  const force = replace || flags.force === true;
65007
65335
  const linked = symlinkDestinationIssue(dest);
@@ -65009,8 +65337,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65009
65337
  io.error(JSON.stringify(linked));
65010
65338
  return 1;
65011
65339
  }
65012
- if (existsSync57(dest)) {
65013
- if (!statSync14(dest).isDirectory()) {
65340
+ if (existsSync58(dest)) {
65341
+ if (!statSync15(dest).isDirectory()) {
65014
65342
  io.error(JSON.stringify({
65015
65343
  error: `${dest} exists and is not a directory`,
65016
65344
  hint: "pass --out/--name to land somewhere else, or remove the file"
@@ -65022,7 +65350,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65022
65350
  io.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
65023
65351
  return 1;
65024
65352
  }
65025
- if (replace && occupied && !existsSync57(join53(dest, "himalaya.content.json"))) {
65353
+ if (replace && occupied && !existsSync58(join54(dest, "himalaya.content.json"))) {
65026
65354
  io.error(JSON.stringify({
65027
65355
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
65028
65356
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -65161,7 +65489,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65161
65489
  const force = flags.force === true;
65162
65490
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65163
65491
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
65164
- const out = mkdtempSync4(join53(tmpdir5(), "himi-push-"));
65492
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-push-"));
65165
65493
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65166
65494
  const outcome = await buildReleaseFromContent2(dir, out, {
65167
65495
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65187,7 +65515,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65187
65515
  const manifest = outcome.manifest;
65188
65516
  const payload = await loadReleaseFromDir(declared, out);
65189
65517
  const { shellQuote: shellQuote2 } = await Promise.resolve().then(() => (init_shell_quote(), shell_quote_exports));
65190
- const contentRel = relative8(process.cwd(), dir) || ".";
65518
+ const contentRel = relative9(process.cwd(), dir) || ".";
65191
65519
  const contentArg = shellQuote2(contentRel);
65192
65520
  if (onlyRaw !== void 0) {
65193
65521
  const onlyDraft = flags.draft === true;
@@ -65249,7 +65577,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65249
65577
  let localSourceHash;
65250
65578
  try {
65251
65579
  const { collectAppSource: collectAppSource2, zipAppSource: zipAppSource2 } = await Promise.resolve().then(() => (init_app_source(), app_source_exports));
65252
- localSourceHash = createHash24("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
65580
+ localSourceHash = createHash25("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
65253
65581
  } catch {
65254
65582
  }
65255
65583
  return runReleasePatch({
@@ -65632,7 +65960,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65632
65960
  return 2;
65633
65961
  }
65634
65962
  try {
65635
- const res = writePack(resolve44(releaseDir), only, resolve44(str5(flags.out) ?? process.cwd()));
65963
+ const res = writePack(resolve45(releaseDir), only, resolve45(str5(flags.out) ?? process.cwd()));
65636
65964
  print({
65637
65965
  ok: true,
65638
65966
  app: res.app,
@@ -65681,7 +66009,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65681
66009
  }
65682
66010
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65683
66011
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
65684
- const built = mkdtempSync4(join53(tmpdir5(), "himi-pack-"));
66012
+ const built = mkdtempSync4(join54(tmpdir5(), "himi-pack-"));
65685
66013
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65686
66014
  const outcome = await buildReleaseFromContent2(dir, built, {
65687
66015
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65703,7 +66031,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65703
66031
  return 1;
65704
66032
  }
65705
66033
  try {
65706
- const res = writePack(built, app, resolve44(str5(flags.out) ?? dir), sourceArchive);
66034
+ const res = writePack(built, app, resolve45(str5(flags.out) ?? dir), sourceArchive);
65707
66035
  print({
65708
66036
  ok: true,
65709
66037
  app: res.app,
@@ -65748,7 +66076,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65748
66076
  const { HIMI_PACKAGE_SOURCE_PATH: HIMI_PACKAGE_SOURCE_PATH2, isSafeAppId: isSafeAppId2, packageContents: packageContents2 } = await Promise.resolve().then(() => (init_himi_package(), himi_package_exports));
65749
66077
  let opened;
65750
66078
  try {
65751
- opened = openPackageFile2(resolve44(file));
66079
+ opened = openPackageFile2(resolve45(file));
65752
66080
  } catch (e) {
65753
66081
  io.error(JSON.stringify({ error: e.message }));
65754
66082
  return 1;
@@ -65761,7 +66089,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65761
66089
  io.error(JSON.stringify({
65762
66090
  ok: false,
65763
66091
  error: "app_source_not_in_package",
65764
- detail: `${resolve44(file)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
66092
+ detail: `${resolve45(file)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
65765
66093
  hint: "re-pack it from the content package with `himi pack --dev`, or restore from the serve plane with `himi pull <app>`"
65766
66094
  }));
65767
66095
  return 1;
@@ -65784,7 +66112,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65784
66112
  return 1;
65785
66113
  }
65786
66114
  }
65787
- const dest = resolve44(str5(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
66115
+ const dest = resolve45(str5(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
65788
66116
  const issue2 = restoreDestinationIssue(dest, flags.force === true);
65789
66117
  if (issue2) {
65790
66118
  io.error(JSON.stringify(issue2));
@@ -65869,7 +66197,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65869
66197
  }
65870
66198
  try {
65871
66199
  const { openPackageFile: openPackageFile2 } = await Promise.resolve().then(() => (init_pack(), pack_exports));
65872
- const opened = openPackageFile2(resolve44(file));
66200
+ const opened = openPackageFile2(resolve45(file));
65873
66201
  if (!opened.validation.ok || !opened.header) {
65874
66202
  io.error(JSON.stringify({ error: "refusing to share an invalid package", issues: opened.validation.errors }));
65875
66203
  return 1;
@@ -65879,12 +66207,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65879
66207
  io.error(JSON.stringify({
65880
66208
  ok: false,
65881
66209
  error: "refusing to share a package that carries the app's source",
65882
- detail: `${resolve44(file)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
66210
+ detail: `${resolve45(file)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
65883
66211
  hint: "share a release package instead (`himi pack` with no --dev), or hand the dev package over directly"
65884
66212
  }));
65885
66213
  return 1;
65886
66214
  }
65887
- const archive = readFileSync68(resolve44(file));
66215
+ const archive = readFileSync69(resolve45(file));
65888
66216
  const result = await client2().createPackageShare({
65889
66217
  app: opened.header.app,
65890
66218
  releaseId: opened.header.releaseId,
@@ -65921,10 +66249,10 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65921
66249
  const app = await appId(dir);
65922
66250
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65923
66251
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
65924
- temp = mkdtempSync4(join53(tmpdir5(), "himi-run-build-"));
66252
+ temp = mkdtempSync4(join54(tmpdir5(), "himi-run-build-"));
65925
66253
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65926
66254
  await buildReleaseFromContent2(dir, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {} });
65927
- source = join53(temp, app);
66255
+ source = join54(temp, app);
65928
66256
  }
65929
66257
  const chromeArg = str5(flags.chrome) ?? "preview";
65930
66258
  if (chromeArg !== "preview" && chromeArg !== "app") {
@@ -65949,9 +66277,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65949
66277
  open: flags["no-open"] !== true
65950
66278
  });
65951
66279
  print({ ok: true, app: run2.app, url: run2.url, port: run2.port, plane: "browser" });
65952
- await new Promise((resolve45) => {
66280
+ await new Promise((resolve46) => {
65953
66281
  const stop = () => {
65954
- void run2.close().finally(() => resolve45());
66282
+ void run2.close().finally(() => resolve46());
65955
66283
  };
65956
66284
  process.once("SIGINT", stop);
65957
66285
  process.once("SIGTERM", stop);
@@ -66528,7 +66856,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66528
66856
  io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
66529
66857
  return 2;
66530
66858
  }
66531
- if (!existsSync57(file)) {
66859
+ if (!existsSync58(file)) {
66532
66860
  io.error(JSON.stringify({ error: `no such file: ${file}` }));
66533
66861
  return 2;
66534
66862
  }
@@ -66584,7 +66912,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66584
66912
  lintNote: "`himi patch` sends a raw file. Nothing here built or linted your app \u2014 `himi push --only <selector>` is the same edit with the full lint gate in front of it."
66585
66913
  };
66586
66914
  if (kind === "tokens" || kind === "app-config") {
66587
- const body = readFileSync68(file, "utf8");
66915
+ const body = readFileSync69(file, "utf8");
66588
66916
  const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
66589
66917
  return runReleasePatch({
66590
66918
  ...common,
@@ -66599,7 +66927,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66599
66927
  io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
66600
66928
  return 2;
66601
66929
  }
66602
- const descriptor = readFileSync68(file, "utf8");
66930
+ const descriptor = readFileSync69(file, "utf8");
66603
66931
  try {
66604
66932
  JSON.parse(descriptor);
66605
66933
  } catch (e) {
@@ -66639,8 +66967,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66639
66967
  extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
66640
66968
  });
66641
66969
  }
66642
- const bytes2 = readFileSync68(file);
66643
- const sha = createHash24("sha256").update(bytes2).digest("hex");
66970
+ const bytes2 = readFileSync69(file);
66971
+ const sha = createHash25("sha256").update(bytes2).digest("hex");
66644
66972
  const forScreens = (str5(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
66645
66973
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
66646
66974
  io.error(JSON.stringify({ ok: false, error: "no_rebind_takes_no_value", message: "--no-rebind is a switch and takes no value; pass it bare.", usage: PATCH_USAGE }));
@@ -66783,7 +67111,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66783
67111
  }
66784
67112
  let def;
66785
67113
  try {
66786
- const parsed = JSON.parse(arg.startsWith("@") ? readFileSync68(arg.slice(1), "utf8") : arg);
67114
+ const parsed = JSON.parse(arg.startsWith("@") ? readFileSync69(arg.slice(1), "utf8") : arg);
66787
67115
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
66788
67116
  io.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
66789
67117
  return 2;
@@ -67247,7 +67575,7 @@ ${label2}`);
67247
67575
  const platform = str5(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
67248
67576
  {
67249
67577
  const distDir = contentDir(flags);
67250
- if (existsSync57(join53(distDir, "himalaya.content.json"))) {
67578
+ if (existsSync58(join54(distDir, "himalaya.content.json"))) {
67251
67579
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
67252
67580
  const errors = issues.filter((i) => i.severity === "error");
67253
67581
  for (const i of issues.filter((i2) => i2.severity === "warning")) {
@@ -67516,7 +67844,7 @@ ${label2}`);
67516
67844
  const dpxPath = dpxSessionTokenPath();
67517
67845
  let dpx;
67518
67846
  try {
67519
- dpx = readFileSync68(dpxPath, "utf8").trim();
67847
+ dpx = readFileSync69(dpxPath, "utf8").trim();
67520
67848
  } catch {
67521
67849
  io.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
67522
67850
  return 1;
@@ -67918,7 +68246,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
67918
68246
  const path2 = dpxSessionTokenPath();
67919
68247
  let raw;
67920
68248
  try {
67921
- raw = readFileSync68(path2, "utf8");
68249
+ raw = readFileSync69(path2, "utf8");
67922
68250
  } catch {
67923
68251
  io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
67924
68252
  return 1;