@wix/himalaya-cli 0.1009.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 };
@@ -17969,12 +17967,12 @@ function finalizeRecording(key2, rec) {
17969
17967
  if (rec.finalize) return rec.finalize;
17970
17968
  rec.finalize = (async () => {
17971
17969
  clearTimeout(rec.autoStop);
17972
- await new Promise((resolve45) => {
17970
+ await new Promise((resolve46) => {
17973
17971
  let done = false;
17974
17972
  const finish2 = () => {
17975
17973
  if (!done) {
17976
17974
  done = true;
17977
- resolve45();
17975
+ resolve46();
17978
17976
  }
17979
17977
  };
17980
17978
  rec.child.once("close", finish2);
@@ -18085,7 +18083,7 @@ var init_preview = __esm({
18085
18083
  DEVICE_LIST_TIMEOUT_MS = 5e3;
18086
18084
  defaultRunner2 = {
18087
18085
  capture(cmd, args, timeoutMs = DEFAULT_CAPTURE_TIMEOUT_MS) {
18088
- return new Promise((resolve45, reject) => {
18086
+ return new Promise((resolve46, reject) => {
18089
18087
  const child = spawn2(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
18090
18088
  const out = [];
18091
18089
  const err = [];
@@ -18107,7 +18105,7 @@ var init_preview = __esm({
18107
18105
  child.stderr.on("data", (b) => err.push(b));
18108
18106
  child.on("error", (e) => settle(reject, e));
18109
18107
  child.on("close", (code) => {
18110
- if (code === 0) settle(resolve45, Buffer.concat(out));
18108
+ if (code === 0) settle(resolve46, Buffer.concat(out));
18111
18109
  else settle(reject, new Error(`${cmd} exited ${code}: ${Buffer.concat(err).toString("utf8")}`));
18112
18110
  });
18113
18111
  });
@@ -19509,6 +19507,7 @@ function shouldRevealError(args) {
19509
19507
  var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
19510
19508
  var init_validation = __esm({
19511
19509
  "../../core/ts/src/validation.ts"() {
19510
+ "use strict";
19512
19511
  EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
19513
19512
  URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
19514
19513
  INTEGER_RE = /^[+-]?[0-9]+$/;
@@ -22933,6 +22932,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
22933
22932
  var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
22934
22933
  var init_worker_subtree = __esm({
22935
22934
  "../../core/ts/src/worker-subtree.ts"() {
22935
+ "use strict";
22936
22936
  init_worker_subtree_safe_types_generated();
22937
22937
  WORKER_SUBTREE_CEILINGS = Object.freeze({
22938
22938
  maxEncodedBytes: 65536,
@@ -23160,8 +23160,8 @@ function ensureCountUpRuntime() {
23160
23160
  const neg = fixed.startsWith("-");
23161
23161
  const body = neg ? fixed.slice(1) : fixed;
23162
23162
  const [int, frac] = body.split(".");
23163
- const sep12 = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
23164
- return (neg ? "-" : "") + sep12 + (frac ? "." + frac : "");
23163
+ const sep13 = int.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
23164
+ return (neg ? "-" : "") + sep13 + (frac ? "." + frac : "");
23165
23165
  };
23166
23166
  const animateEl = (el) => {
23167
23167
  const node = el;
@@ -28885,7 +28885,7 @@ async function stabilizePngPage(page, scheme) {
28885
28885
  const browser = globalThis;
28886
28886
  browser.document.documentElement.style.colorScheme = selected;
28887
28887
  await browser.document.fonts?.ready;
28888
- await new Promise((resolve45) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve45())));
28888
+ await new Promise((resolve46) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve46())));
28889
28889
  }, scheme);
28890
28890
  }
28891
28891
  async function renderPngBatch(items) {
@@ -32457,7 +32457,7 @@ async function handleWebWix(req, res, state) {
32457
32457
  }
32458
32458
  if (match && (match.rule.kind ?? "mock") === "mock") {
32459
32459
  const mocked = match.rule.response;
32460
- if (mocked.delayMs) await new Promise((resolve45) => setTimeout(resolve45, mocked.delayMs));
32460
+ if (mocked.delayMs) await new Promise((resolve46) => setTimeout(resolve46, mocked.delayMs));
32461
32461
  const responseBody = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
32462
32462
  recordWixTraffic(state.wix, state.appName, state.adminUrl, {
32463
32463
  ts: started,
@@ -33423,8 +33423,8 @@ async function handleActionHandlerBundleGet(res, app) {
33423
33423
  }
33424
33424
  async function serveStatic(req, res, root, prefix) {
33425
33425
  const requested = decodeURIComponent((req.url ?? "").split("?")[0]);
33426
- const relative9 = requested.replace(prefix, "").replace(/^\//, "");
33427
- const safe = normalize3(relative9).replace(/^(\.\.[\/\\])+/, "");
33426
+ const relative10 = requested.replace(prefix, "").replace(/^\//, "");
33427
+ const safe = normalize3(relative10).replace(/^(\.\.[\/\\])+/, "");
33428
33428
  const fullPath = resolve30(root, safe);
33429
33429
  if (!fullPath.startsWith(root)) {
33430
33430
  return send(res, 403, "forbidden");
@@ -34459,12 +34459,12 @@ var init_query = __esm({
34459
34459
  });
34460
34460
 
34461
34461
  // ../../core/dev-server/src/crawl-input.ts
34462
- function resolved(v, resolve45) {
34463
- 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;
34464
34464
  if (Array.isArray(v)) {
34465
34465
  const out = v.flatMap((el) => {
34466
34466
  if (typeof el !== "string" || !el.startsWith("$service:")) return [el];
34467
- const r = resolve45(el);
34467
+ const r = resolve46(el);
34468
34468
  return Array.isArray(r) ? r : [r];
34469
34469
  });
34470
34470
  return out;
@@ -34478,9 +34478,9 @@ function hasRowBinding(props) {
34478
34478
  return itemToken(v) || Array.isArray(v) && v.some(itemToken);
34479
34479
  });
34480
34480
  }
34481
- function declaredOptionIds(props, resolve45) {
34481
+ function declaredOptionIds(props, resolve46) {
34482
34482
  const literal = props.options ?? props.tabs ?? props.chips;
34483
- 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;
34484
34484
  const raw = Array.isArray(bound) ? bound : literal;
34485
34485
  if (!Array.isArray(raw)) return [];
34486
34486
  const out = [];
@@ -34523,24 +34523,24 @@ function seedTokens(state, limit = 48) {
34523
34523
  walk2(state, 0);
34524
34524
  return out;
34525
34525
  }
34526
- function synthesizeInput(control, resolve45, tokens) {
34526
+ function synthesizeInput(control, resolve46, tokens) {
34527
34527
  const id = `${control.type}.${control.callback}`;
34528
34528
  const row = SYNTHESIZED_CONTROLS[id];
34529
34529
  if (!row) return null;
34530
34530
  const props = control.props;
34531
34531
  if (hasRowBinding(props)) return null;
34532
34532
  if (row.from === "declared-options") {
34533
- const ids = declaredOptionIds(props, resolve45);
34533
+ const ids = declaredOptionIds(props, resolve46);
34534
34534
  if (!ids.length) return null;
34535
34535
  if (row.encoding === "string-array") {
34536
- const currentRaw2 = resolved(props.selectedIds, resolve45);
34536
+ const currentRaw2 = resolved(props.selectedIds, resolve46);
34537
34537
  const current3 = (Array.isArray(currentRaw2) ? currentRaw2 : []).filter((x) => typeof x === "string");
34538
34538
  const pick4 = ids.find((o) => !current3.includes(o));
34539
34539
  if (pick4 === void 0) return null;
34540
34540
  const value = props.multiSelect === true ? [...current3, pick4] : [pick4];
34541
34541
  return { key: row.key, value, from: row.from, current: current3, control: id };
34542
34542
  }
34543
- const currentRaw = resolved(props.selectedId, resolve45);
34543
+ const currentRaw = resolved(props.selectedId, resolve46);
34544
34544
  const current2 = typeof currentRaw === "string" ? currentRaw : void 0;
34545
34545
  const pick3 = ids.find((o) => o !== current2);
34546
34546
  if (pick3 === void 0) return null;
@@ -34548,7 +34548,7 @@ function synthesizeInput(control, resolve45, tokens) {
34548
34548
  }
34549
34549
  if (!acceptsWords(props) || !acceptsWords(control.wrapper ?? {})) return null;
34550
34550
  const binding2 = typeof props.valuePath === "string" ? props.valuePath : typeof props.value === "string" && props.value.startsWith("$service:") ? props.value : void 0;
34551
- const bound = binding2 === void 0 ? void 0 : resolve45(binding2);
34551
+ const bound = binding2 === void 0 ? void 0 : resolve46(binding2);
34552
34552
  const literal = typeof props.value === "string" && !props.value.startsWith("$") ? props.value : void 0;
34553
34553
  const current = typeof bound === "string" ? bound : typeof bound === "number" ? String(bound) : literal ?? "";
34554
34554
  const max = typeof props.maxLength === "number" && props.maxLength > 0 ? props.maxLength : void 0;
@@ -35806,8 +35806,8 @@ async function crawlScreenInner(opts) {
35806
35806
  if (linkable.has(target)) return true;
35807
35807
  for (const base of linkable) {
35808
35808
  if (target.length > base.length + 1 && target.startsWith(base)) {
35809
- const sep12 = target[base.length];
35810
- if (sep12 === "_" || sep12 === "/") return true;
35809
+ const sep13 = target[base.length];
35810
+ if (sep13 === "_" || sep13 === "/") return true;
35811
35811
  }
35812
35812
  }
35813
35813
  return false;
@@ -42699,7 +42699,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
42699
42699
  const headers2 = Object.fromEntries(new Headers(init.headers).entries());
42700
42700
  const request = url.protocol === "https:" ? httpsRequest : httpRequest;
42701
42701
  const hostname2 = url.hostname.replace(/^\[|\]$/g, "");
42702
- return await new Promise((resolve45, reject) => {
42702
+ return await new Promise((resolve46, reject) => {
42703
42703
  let settled = false;
42704
42704
  const finish2 = (fn) => {
42705
42705
  if (settled) return;
@@ -42736,7 +42736,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
42736
42736
  }
42737
42737
  const responseHeaders = new Headers();
42738
42738
  for (const [key2, value] of Object.entries(response.headers)) if (value !== void 0) responseHeaders.set(key2, Array.isArray(value) ? value.join(", ") : value);
42739
- 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 }));
42740
42740
  }));
42741
42741
  });
42742
42742
  req.once("error", (error) => finish2(() => reject(error)));
@@ -43036,7 +43036,7 @@ function createLocalTestSandbox() {
43036
43036
  }
43037
43037
  })();
43038
43038
  `;
43039
- return await new Promise((resolve45, reject) => {
43039
+ return await new Promise((resolve46, reject) => {
43040
43040
  const { port1, port2 } = new MessageChannel();
43041
43041
  const serializableContext = {
43042
43042
  auth: context.auth,
@@ -43112,7 +43112,7 @@ function createLocalTestSandbox() {
43112
43112
  timer = setTimeout(() => finish2(() => reject(new SandboxError("timeout", `execution exceeded ${limits.timeoutMs}ms`))), Math.max(1, limits.timeoutMs));
43113
43113
  return;
43114
43114
  }
43115
- 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 }));
43116
43116
  else finish2(() => reject(new SandboxError("execution_failed", message.message ?? "handler failed")));
43117
43117
  });
43118
43118
  worker.once("error", (error) => finish2(() => reject(new SandboxError("execution_failed", error.message))));
@@ -44242,6 +44242,213 @@ var init_functions = __esm({
44242
44242
  }
44243
44243
  });
44244
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
+
44245
44452
  // src/native-decode.ts
44246
44453
  var native_decode_exports = {};
44247
44454
  __export(native_decode_exports, {
@@ -44257,9 +44464,9 @@ __export(native_decode_exports, {
44257
44464
  runNativeDecode: () => runNativeDecode
44258
44465
  });
44259
44466
  import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
44260
- 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";
44261
44468
  import { tmpdir as tmpdir3 } from "node:os";
44262
- import { join as join43 } from "node:path";
44469
+ import { join as join44 } from "node:path";
44263
44470
  import { fileURLToPath as fileURLToPath20 } from "node:url";
44264
44471
  function nativeDecodePackageDir() {
44265
44472
  return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
@@ -44269,8 +44476,8 @@ function nativeDecodeAndroidHarnessDir() {
44269
44476
  }
44270
44477
  function nativeOracleShipped() {
44271
44478
  return {
44272
- ios: existsSync46(join43(nativeDecodePackageDir(), "Package.swift")),
44273
- android: existsSync46(join43(nativeDecodeAndroidHarnessDir(), "gradlew"))
44479
+ ios: existsSync47(join44(nativeDecodePackageDir(), "Package.swift")),
44480
+ android: existsSync47(join44(nativeDecodeAndroidHarnessDir(), "gradlew"))
44274
44481
  };
44275
44482
  }
44276
44483
  function detectNativeDecode(options = {}) {
@@ -44281,7 +44488,7 @@ function detectNativeDecode(options = {}) {
44281
44488
  return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
44282
44489
  }
44283
44490
  if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
44284
- const packageAvailable = options.packageAvailable ?? existsSync46(join43(packageDir, "Package.swift"));
44491
+ const packageAvailable = options.packageAvailable ?? existsSync47(join44(packageDir, "Package.swift"));
44285
44492
  if (!packageAvailable) {
44286
44493
  return {
44287
44494
  platform: "ios",
@@ -44293,7 +44500,7 @@ function detectNativeDecode(options = {}) {
44293
44500
  }
44294
44501
  function localPropertiesSdk(harnessDir) {
44295
44502
  try {
44296
- 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);
44297
44504
  return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
44298
44505
  } catch {
44299
44506
  return null;
@@ -44301,8 +44508,8 @@ function localPropertiesSdk(harnessDir) {
44301
44508
  }
44302
44509
  function detectAndroidNativeDecode(options = {}) {
44303
44510
  const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
44304
- const gradlew = join43(harnessDir, "gradlew");
44305
- const gradlewAvailable = options.gradlewAvailable ?? existsSync46(gradlew);
44511
+ const gradlew = join44(harnessDir, "gradlew");
44512
+ const gradlewAvailable = options.gradlewAvailable ?? existsSync47(gradlew);
44306
44513
  if (!gradlewAvailable) {
44307
44514
  return {
44308
44515
  platform: "android",
@@ -44312,7 +44519,7 @@ function detectAndroidNativeDecode(options = {}) {
44312
44519
  }
44313
44520
  const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
44314
44521
  const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
44315
- 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));
44316
44523
  if (!sdkAvailable) {
44317
44524
  return {
44318
44525
  platform: "android",
@@ -44384,14 +44591,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
44384
44591
  return verdicts;
44385
44592
  }
44386
44593
  function runNativeDecode(options) {
44387
- const descriptorDir = mkdtempSync2(join43(tmpdir3(), "himi-native-decode-"));
44594
+ const descriptorDir = mkdtempSync2(join44(tmpdir3(), "himi-native-decode-"));
44388
44595
  const startedAt = Date.now();
44389
44596
  try {
44390
44597
  for (const descriptor of options.descriptors) {
44391
44598
  if (typeof descriptor.descriptorJson !== "string") {
44392
44599
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
44393
44600
  }
44394
- writeFileSync19(join43(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44601
+ writeFileSync20(join44(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44395
44602
  }
44396
44603
  options.progress?.("building cached Swift oracle");
44397
44604
  execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
@@ -44403,7 +44610,7 @@ function runNativeDecode(options) {
44403
44610
  encoding: "utf8"
44404
44611
  }).trim();
44405
44612
  options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
44406
- const stdout = execFileSync5(join43(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
44613
+ const stdout = execFileSync5(join44(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
44407
44614
  stdio: ["ignore", "pipe", "pipe"],
44408
44615
  encoding: "utf8"
44409
44616
  });
@@ -44421,15 +44628,15 @@ function runNativeDecode(options) {
44421
44628
  }
44422
44629
  }
44423
44630
  function runAndroidNativeDecode(options) {
44424
- const descriptorDir = mkdtempSync2(join43(tmpdir3(), "himi-native-decode-android-"));
44425
- const outputPath = join43(descriptorDir, "verdicts.ndjson");
44631
+ const descriptorDir = mkdtempSync2(join44(tmpdir3(), "himi-native-decode-android-"));
44632
+ const outputPath = join44(descriptorDir, "verdicts.ndjson");
44426
44633
  const startedAt = Date.now();
44427
44634
  try {
44428
44635
  for (const descriptor of options.descriptors) {
44429
44636
  if (typeof descriptor.descriptorJson !== "string") {
44430
44637
  throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
44431
44638
  }
44432
- writeFileSync19(join43(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44639
+ writeFileSync20(join44(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
44433
44640
  }
44434
44641
  options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
44435
44642
  execFileSync5(options.gradlew, [
@@ -44444,7 +44651,7 @@ function runAndroidNativeDecode(options) {
44444
44651
  stdio: ["ignore", "ignore", "pipe"],
44445
44652
  encoding: "utf8"
44446
44653
  });
44447
- const stdout = readFileSync50(outputPath, "utf8");
44654
+ const stdout = readFileSync51(outputPath, "utf8");
44448
44655
  return {
44449
44656
  platform: "android",
44450
44657
  verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
@@ -44513,15 +44720,15 @@ __export(browser_authoring_exports, {
44513
44720
  sdkSubpathReader: () => sdkSubpathReader
44514
44721
  });
44515
44722
  import { createServer as createServer3 } from "node:http";
44516
- import { createHash as createHash22, randomBytes as randomBytes4 } from "node:crypto";
44723
+ import { createHash as createHash23, randomBytes as randomBytes4 } from "node:crypto";
44517
44724
  import { execFile as execFile2 } from "node:child_process";
44518
- import { existsSync as existsSync47, readdirSync as readdirSync23, readFileSync as readFileSync51, realpathSync as realpathSync4, statSync as statSync10 } from "node:fs";
44519
- 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";
44520
44727
  function humanMs(ms) {
44521
44728
  return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
44522
44729
  }
44523
44730
  function collectWorkerSources(tier5SrcDir, bundleName) {
44524
- const root = join44(tier5SrcDir, bundleName);
44731
+ const root = join45(tier5SrcDir, bundleName);
44525
44732
  const files = {};
44526
44733
  const visitedDirs = /* @__PURE__ */ new Set();
44527
44734
  const walk2 = (abs, rel) => {
@@ -44529,16 +44736,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
44529
44736
  if (visitedDirs.has(real)) return;
44530
44737
  visitedDirs.add(real);
44531
44738
  for (const name of readdirSync23(abs).sort()) {
44532
- const childAbs = join44(abs, name);
44739
+ const childAbs = join45(abs, name);
44533
44740
  const childRel = posix.join(rel, name);
44534
- if (statSync10(childAbs).isDirectory()) {
44741
+ if (statSync11(childAbs).isDirectory()) {
44535
44742
  walk2(childAbs, childRel);
44536
44743
  } else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
44537
- files[childRel] = readFileSync51(childAbs, "utf8");
44744
+ files[childRel] = readFileSync52(childAbs, "utf8");
44538
44745
  }
44539
44746
  }
44540
44747
  };
44541
- if (!existsSync47(root)) return null;
44748
+ if (!existsSync48(root)) return null;
44542
44749
  walk2(root, `/tier5-src/${bundleName}`);
44543
44750
  const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
44544
44751
  if (!entry) return null;
@@ -44555,20 +44762,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
44555
44762
  const spec = m[1];
44556
44763
  const virtual = posix.normalize(posix.join(dir, spec));
44557
44764
  if (!virtual.startsWith("/tier5-src/")) continue;
44558
- const onDisk = join44(tier5SrcDir, virtual.slice("/tier5-src/".length));
44765
+ const onDisk = join45(tier5SrcDir, virtual.slice("/tier5-src/".length));
44559
44766
  const candidates = [
44560
44767
  onDisk,
44561
44768
  `${onDisk}.ts`,
44562
44769
  `${onDisk}.js`,
44563
44770
  onDisk.replace(/\.js$/, ".ts"),
44564
- join44(onDisk, "index.ts"),
44565
- join44(onDisk, "index.js")
44771
+ join45(onDisk, "index.ts"),
44772
+ join45(onDisk, "index.js")
44566
44773
  ];
44567
44774
  for (const abs of candidates) {
44568
- if (!existsSync47(abs) || statSync10(abs).isDirectory()) continue;
44569
- 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)}`;
44570
44777
  if (key2 in files) break;
44571
- files[key2] = readFileSync51(abs, "utf8");
44778
+ files[key2] = readFileSync52(abs, "utf8");
44572
44779
  queue.push(key2);
44573
44780
  break;
44574
44781
  }
@@ -44600,10 +44807,10 @@ function collectSdkModules(files, resolveSubpath) {
44600
44807
  for (const source of Object.values(files)) visit(source);
44601
44808
  return { modules, unsupported };
44602
44809
  }
44603
- function sdkSubpathReader(resolve45) {
44810
+ function sdkSubpathReader(resolve46) {
44604
44811
  return (sub) => {
44605
44812
  try {
44606
- return readFileSync51(resolve45(`@wix/himalaya/${sub}`), "utf8");
44813
+ return readFileSync52(resolve46(`@wix/himalaya/${sub}`), "utf8");
44607
44814
  } catch {
44608
44815
  return null;
44609
44816
  }
@@ -44613,7 +44820,7 @@ function encodeJob(job) {
44613
44820
  return Buffer.from(JSON.stringify(job), "utf8").toString("base64");
44614
44821
  }
44615
44822
  function mintToken2(payload, nonce = randomBytes4(16).toString("hex")) {
44616
- const digest2 = createHash22("sha256").update(payload, "utf8").digest("base64url");
44823
+ const digest2 = createHash23("sha256").update(payload, "utf8").digest("base64url");
44617
44824
  return `${nonce}.${digest2}`;
44618
44825
  }
44619
44826
  function defaultOpenBrowser2(url) {
@@ -44684,7 +44891,7 @@ async function runBrowserAuthoring(opts) {
44684
44891
  const token = mintToken2(payload);
44685
44892
  const unusable = await probeAuthoringPage(opts.authoringBase, opts.fetchImpl, opts.probeTimeoutMs);
44686
44893
  if (unusable) throw new Error(unusable);
44687
- return await new Promise((resolve45, reject) => {
44894
+ return await new Promise((resolve46, reject) => {
44688
44895
  let settled = false;
44689
44896
  let url = "";
44690
44897
  const server = createServer3();
@@ -44736,7 +44943,7 @@ async function runBrowserAuthoring(opts) {
44736
44943
  }
44737
44944
  res.writeHead(200, { "content-type": "text/plain" }).end("ok");
44738
44945
  const report2 = body.result;
44739
- finish2(() => resolve45({ report: report2, url }));
44946
+ finish2(() => resolve46({ report: report2, url }));
44740
44947
  })();
44741
44948
  });
44742
44949
  server.on("error", (e) => finish2(() => reject(e)));
@@ -44777,8 +44984,8 @@ __export(coverage_exports, {
44777
44984
  suppressedNativeKeys: () => suppressedNativeKeys,
44778
44985
  trendAndStore: () => trendAndStore
44779
44986
  });
44780
- import { existsSync as existsSync48, mkdirSync as mkdirSync23, readFileSync as readFileSync52, writeFileSync as writeFileSync20 } from "node:fs";
44781
- 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";
44782
44989
  function suppressedNativeKeys(oracle) {
44783
44990
  return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
44784
44991
  }
@@ -44948,11 +45155,11 @@ function assembleLedger(r, options = {}) {
44948
45155
  return out;
44949
45156
  }
44950
45157
  function trendAndStore(dir, entries, suppressed) {
44951
- const p = join45(dir, LEDGER_FILE);
45158
+ const p = join46(dir, LEDGER_FILE);
44952
45159
  let previous = null;
44953
45160
  try {
44954
- if (existsSync48(p)) {
44955
- const parsed = JSON.parse(readFileSync52(p, "utf8"));
45161
+ if (existsSync49(p)) {
45162
+ const parsed = JSON.parse(readFileSync53(p, "utf8"));
44956
45163
  if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
44957
45164
  }
44958
45165
  } catch {
@@ -44960,8 +45167,8 @@ function trendAndStore(dir, entries, suppressed) {
44960
45167
  const current = entries.map((e) => e.key);
44961
45168
  const stored = [.../* @__PURE__ */ new Set([...current, ...(previous ?? []).filter((key2) => (suppressed ?? []).includes(key2))])];
44962
45169
  try {
44963
- mkdirSync23(dirname26(p), { recursive: true });
44964
- 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));
44965
45172
  } catch {
44966
45173
  return null;
44967
45174
  }
@@ -44991,11 +45198,11 @@ function formatLedger(entries, trend) {
44991
45198
  return out.join("\n");
44992
45199
  }
44993
45200
  function diffAndStoreObservations(dir, current) {
44994
- const p = join45(dir, OBS_FILE);
45201
+ const p = join46(dir, OBS_FILE);
44995
45202
  let previous = null;
44996
45203
  try {
44997
- if (existsSync48(p)) {
44998
- const parsed = JSON.parse(readFileSync52(p, "utf8"));
45204
+ if (existsSync49(p)) {
45205
+ const parsed = JSON.parse(readFileSync53(p, "utf8"));
44999
45206
  if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
45000
45207
  (v) => Array.isArray(v) && v.every((l) => typeof l === "string")
45001
45208
  )) {
@@ -45005,8 +45212,8 @@ function diffAndStoreObservations(dir, current) {
45005
45212
  } catch {
45006
45213
  }
45007
45214
  try {
45008
- mkdirSync23(dirname26(p), { recursive: true });
45009
- 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));
45010
45217
  } catch {
45011
45218
  return null;
45012
45219
  }
@@ -45044,8 +45251,8 @@ var LEDGER_FILE, OBS_FILE;
45044
45251
  var init_coverage = __esm({
45045
45252
  "src/coverage.ts"() {
45046
45253
  init_native_decode();
45047
- LEDGER_FILE = join45(".himi", "test-ledger.json");
45048
- OBS_FILE = join45(".himi", "test-observations.json");
45254
+ LEDGER_FILE = join46(".himi", "test-ledger.json");
45255
+ OBS_FILE = join46(".himi", "test-observations.json");
45049
45256
  }
45050
45257
  });
45051
45258
 
@@ -45056,11 +45263,11 @@ __export(design_kits_exports, {
45056
45263
  kitsDir: () => kitsDir,
45057
45264
  listKits: () => listKits2
45058
45265
  });
45059
- import { existsSync as existsSync49, readFileSync as readFileSync53, readdirSync as readdirSync24 } from "node:fs";
45060
- 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";
45061
45268
  import { fileURLToPath as fileURLToPath21 } from "node:url";
45062
45269
  function kitsDir() {
45063
- return KIT_DIR_CANDIDATES.find((p) => existsSync49(p));
45270
+ return KIT_DIR_CANDIDATES.find((p) => existsSync50(p));
45064
45271
  }
45065
45272
  function listKits2() {
45066
45273
  const dir = kitsDir();
@@ -45084,7 +45291,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
45084
45291
  if (!kits.includes(name)) {
45085
45292
  return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
45086
45293
  }
45087
- const raw = readFileSync53(join46(dir, `${name}.json`), "utf8");
45294
+ const raw = readFileSync54(join47(dir, `${name}.json`), "utf8");
45088
45295
  let parsed;
45089
45296
  try {
45090
45297
  parsed = JSON.parse(raw);
@@ -45108,9 +45315,9 @@ var init_design_kits = __esm({
45108
45315
  "src/design-kits.ts"() {
45109
45316
  KIT_DIR_CANDIDATES = [
45110
45317
  // in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
45111
- join46(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
45318
+ join47(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
45112
45319
  // published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
45113
- join46(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
45320
+ join47(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
45114
45321
  ];
45115
45322
  }
45116
45323
  });
@@ -45124,11 +45331,11 @@ __export(assets_exports, {
45124
45331
  removeAssetPayload: () => removeAssetPayload,
45125
45332
  verifyReport: () => verifyReport
45126
45333
  });
45127
- import { readFileSync as readFileSync54 } from "node:fs";
45334
+ import { readFileSync as readFileSync55 } from "node:fs";
45128
45335
  import { basename as basename11 } from "node:path";
45129
45336
  function declaredAssets(dir) {
45130
45337
  return collectAssets(dir).map((a) => {
45131
- const bytes2 = readFileSync54(a.path);
45338
+ const bytes2 = readFileSync55(a.path);
45132
45339
  return {
45133
45340
  name: a.name,
45134
45341
  sha256: assetSha256(bytes2),
@@ -45205,7 +45412,7 @@ function verifyReport(dir, app, manifest) {
45205
45412
  };
45206
45413
  }
45207
45414
  function addAssetPayload(manifest, filePath, opts) {
45208
- const bytes2 = readFileSync54(filePath);
45415
+ const bytes2 = readFileSync55(filePath);
45209
45416
  const name = opts.name ?? basename11(filePath);
45210
45417
  const sha2565 = assetSha256(bytes2);
45211
45418
  const record2 = {
@@ -46681,19 +46888,19 @@ var init_preview_assets_generated = __esm({
46681
46888
  "../../packages/serve/src/preview-assets.generated.ts"() {
46682
46889
  init_preview_assets_format();
46683
46890
  PREVIEW_ASSET_MANIFEST = [
46684
- { key: "assets/index-BKft9wm1.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1012166, sha256: "3a87519baabf67cecf163d20ea1eaaeba288fdeab2fc00cc3d22f09b6a29a194" },
46685
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1012174, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
46686
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1103098, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
46687
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1194082, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
46688
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1285062, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
46689
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1375934, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
46690
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 1466914, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
46691
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 1575550, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
46692
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 1684634, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
46693
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 1793682, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
46694
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 1901382, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
46695
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 1989490, length: 4448, sha256: "71627ade6c0e47a8956b4841c1f6d644fee50a9a4ca9e6d9106b589e84891bd7" },
46696
- { 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" }
46697
46904
  ];
46698
46905
  }
46699
46906
  });
@@ -46709,11 +46916,11 @@ __export(run_exports, {
46709
46916
  runPackage: () => runPackage,
46710
46917
  withoutProdServe: () => withoutProdServe
46711
46918
  });
46712
- 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";
46713
46920
  import { tmpdir as tmpdir4 } from "node:os";
46714
- import { dirname as dirname27, join as join47 } from "node:path";
46921
+ import { dirname as dirname27, join as join48 } from "node:path";
46715
46922
  import { fileURLToPath as fileURLToPath22 } from "node:url";
46716
- import { spawn as spawn3 } from "node:child_process";
46923
+ import { spawn as spawn4 } from "node:child_process";
46717
46924
  function makePackageRunHandler(opts) {
46718
46925
  return makeRunHandler({
46719
46926
  store: new FileReleaseStore(opts.releaseRoot),
@@ -46730,9 +46937,9 @@ async function fetchBytes(url) {
46730
46937
  }
46731
46938
  async function resolvePackage(source, workDir) {
46732
46939
  const isUrl2 = /^https?:\/\//i.test(source);
46733
- if (!isUrl2 && existsSync50(source) && statSync11(source).isDirectory()) {
46734
- const appDirManifest = join47(source, "release-manifest.json");
46735
- if (existsSync50(appDirManifest)) {
46940
+ if (!isUrl2 && existsSync51(source) && statSync12(source).isDirectory()) {
46941
+ const appDirManifest = join48(source, "release-manifest.json");
46942
+ if (existsSync51(appDirManifest)) {
46736
46943
  const opened2 = openPackageDir(source);
46737
46944
  if (!opened2.validation.ok) {
46738
46945
  throw new Error(`package is not valid:
@@ -46741,10 +46948,10 @@ async function resolvePackage(source, workDir) {
46741
46948
  const app2 = opened2.header?.app ?? opened2.manifest?.app;
46742
46949
  if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
46743
46950
  if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
46744
- const root2 = workDir ?? mkdtempSync3(join47(tmpdir4(), "himi-run-"));
46745
- const target = join47(root2, app2);
46746
- if (join47(source) !== target) {
46747
- 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 });
46748
46955
  rmSync10(target, { recursive: true, force: true });
46749
46956
  cpSync2(source, target, { recursive: true });
46750
46957
  }
@@ -46760,8 +46967,8 @@ async function resolvePackage(source, workDir) {
46760
46967
  }
46761
46968
  throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
46762
46969
  }
46763
- const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync55(source);
46764
- 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-"));
46765
46972
  const { app, appDir: appDir2 } = unpackTo(bytes2, root);
46766
46973
  const opened = openPackageDir(appDir2);
46767
46974
  if (!opened.validation.ok) {
@@ -46784,14 +46991,14 @@ async function loadPreviewAssets() {
46784
46991
  const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
46785
46992
  const here = dirname27(fileURLToPath22(import.meta.url));
46786
46993
  const candidates = [
46787
- join47(here, "preview-assets.generated.bin"),
46994
+ join48(here, "preview-assets.generated.bin"),
46788
46995
  // published: copied next to the bundled CLI
46789
- join47(here, "../../../packages/serve/src/preview-assets.generated.bin")
46996
+ join48(here, "../../../packages/serve/src/preview-assets.generated.bin")
46790
46997
  // in-repo checkout
46791
46998
  ];
46792
46999
  for (const path2 of candidates) {
46793
- if (!existsSync50(path2)) continue;
46794
- const blob = readFileSync55(path2);
47000
+ if (!existsSync51(path2)) continue;
47001
+ const blob = readFileSync56(path2);
46795
47002
  return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
46796
47003
  }
46797
47004
  return /* @__PURE__ */ new Map();
@@ -46808,7 +47015,7 @@ function packageUrl(origin, app, opts = {}) {
46808
47015
  function openBrowser(url) {
46809
47016
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
46810
47017
  try {
46811
- 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();
46812
47019
  } catch {
46813
47020
  }
46814
47021
  }
@@ -46873,19 +47080,19 @@ __export(run_browser_exports, {
46873
47080
  runInBrowser: () => runInBrowser
46874
47081
  });
46875
47082
  import { createServer as createServer5 } from "node:http";
46876
- import { existsSync as existsSync51, readFileSync as readFileSync56 } from "node:fs";
47083
+ import { existsSync as existsSync52, readFileSync as readFileSync57 } from "node:fs";
46877
47084
  import { spawnSync as spawnSync3, execFile as execFile3 } from "node:child_process";
46878
- import { dirname as dirname28, resolve as resolve40 } from "node:path";
47085
+ import { dirname as dirname28, resolve as resolve41 } from "node:path";
46879
47086
  import { fileURLToPath as fileURLToPath23 } from "node:url";
46880
47087
  function stagedDir() {
46881
- 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");
46882
47089
  }
46883
47090
  function missingStaged() {
46884
- return [...SERVED].filter((f) => !existsSync51(resolve40(stagedDir(), f))).sort();
47091
+ return [...SERVED].filter((f) => !existsSync52(resolve41(stagedDir(), f))).sort();
46885
47092
  }
46886
47093
  function ensureBrowserPlaneStaged() {
46887
47094
  if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
46888
- 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")], {
46889
47096
  cwd: REPO,
46890
47097
  encoding: "utf8"
46891
47098
  });
@@ -46971,7 +47178,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
46971
47178
  }
46972
47179
  const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
46973
47180
  if (SERVED.has(name)) {
46974
- if (!existsSync51(resolve40(stagedDir(), name))) {
47181
+ if (!existsSync52(resolve41(stagedDir(), name))) {
46975
47182
  const restaged = ensureBrowserPlaneStaged();
46976
47183
  if (!restaged.ok) {
46977
47184
  res.writeHead(503, { "content-type": "application/json" });
@@ -46981,7 +47188,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
46981
47188
  }
46982
47189
  let bytes2;
46983
47190
  try {
46984
- bytes2 = readFileSync56(resolve40(stagedDir(), name));
47191
+ bytes2 = readFileSync57(resolve41(stagedDir(), name));
46985
47192
  } catch (e) {
46986
47193
  res.writeHead(503, { "content-type": "application/json" });
46987
47194
  res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
@@ -47025,7 +47232,7 @@ var init_run_browser = __esm({
47025
47232
  "src/run-browser.ts"() {
47026
47233
  init_file_store();
47027
47234
  HERE = dirname28(fileURLToPath23(import.meta.url));
47028
- REPO = resolve40(HERE, "..", "..", "..");
47235
+ REPO = resolve41(HERE, "..", "..", "..");
47029
47236
  SERVED = /* @__PURE__ */ new Set(["host.html", "sw.js", "package-reader.js"]);
47030
47237
  }
47031
47238
  });
@@ -47444,10 +47651,10 @@ __export(preflight_exports, {
47444
47651
  parseStoreConfig: () => parseStoreConfig,
47445
47652
  requireEnv: () => requireEnv
47446
47653
  });
47447
- import { existsSync as existsSync52, readFileSync as readFileSync57 } from "node:fs";
47448
- 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";
47449
47656
  function isInsideRepo(p) {
47450
- const rel = relative7(REPO_ROOT3, resolve41(p));
47657
+ const rel = relative8(REPO_ROOT3, resolve42(p));
47451
47658
  return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
47452
47659
  }
47453
47660
  function assertCredentialOutsideRepo(label2, p) {
@@ -47501,10 +47708,10 @@ function parseStoreConfig(text4) {
47501
47708
  }
47502
47709
  function loadStoreConfig(app) {
47503
47710
  const p = storeConfigPath(app);
47504
- if (!existsSync52(p)) {
47711
+ if (!existsSync53(p)) {
47505
47712
  throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
47506
47713
  }
47507
- return parseStoreConfig(readFileSync57(p, "utf8"));
47714
+ return parseStoreConfig(readFileSync58(p, "utf8"));
47508
47715
  }
47509
47716
  var init_preflight = __esm({
47510
47717
  "../store-release/preflight.ts"() {
@@ -47523,19 +47730,19 @@ __export(credential_profile_exports, {
47523
47730
  profilePath: () => profilePath,
47524
47731
  resolveStoreCredentials: () => resolveStoreCredentials
47525
47732
  });
47526
- import { existsSync as existsSync53, readFileSync as readFileSync58 } from "node:fs";
47733
+ import { existsSync as existsSync54, readFileSync as readFileSync59 } from "node:fs";
47527
47734
  import { homedir as homedir5 } from "node:os";
47528
- import { join as join48 } from "node:path";
47735
+ import { join as join49 } from "node:path";
47529
47736
  function credentialsDir(home = homedir5()) {
47530
- return join48(home, ".himalaya", "store-credentials");
47737
+ return join49(home, ".himalaya", "store-credentials");
47531
47738
  }
47532
47739
  function profilePath(name, home = homedir5()) {
47533
47740
  if (!PROFILE_NAME.test(name)) {
47534
47741
  throw new Error(
47535
- `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.`
47536
47743
  );
47537
47744
  }
47538
- return join48(credentialsDir(home), `${name}.json`);
47745
+ return join49(credentialsDir(home), `${name}.json`);
47539
47746
  }
47540
47747
  function parseProfile(text4, label2) {
47541
47748
  let doc;
@@ -47566,8 +47773,8 @@ function resolveStoreCredentials(opts) {
47566
47773
  const { app, cfg } = opts;
47567
47774
  const env = opts.env ?? process.env;
47568
47775
  const home = opts.home ?? homedir5();
47569
- const read = opts.readProfile ?? ((p) => readFileSync58(p, "utf8"));
47570
- const exists = opts.profileExists ?? existsSync53;
47776
+ const read = opts.readProfile ?? ((p) => readFileSync59(p, "utf8"));
47777
+ const exists = opts.profileExists ?? existsSync54;
47571
47778
  const ios = cfg.ios ?? {};
47572
47779
  const flagName = opts.profileFlag?.trim();
47573
47780
  const named = namedProfile(cfg, opts.profileFlag);
@@ -47647,9 +47854,9 @@ __export(preflight_app_exports, {
47647
47854
  preflightApp: () => preflightApp,
47648
47855
  profileAccount: () => profileAccount
47649
47856
  });
47650
- import { readFileSync as readFileSync59, existsSync as existsSync54, readdirSync as readdirSync25, statSync as statSync12 } from "node:fs";
47651
- import { createHash as createHash23 } from "node:crypto";
47652
- 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";
47653
47860
  function analyze(projectYml, storeConfig, icon, account) {
47654
47861
  const f = [];
47655
47862
  const has = (re, s) => re.test(s);
@@ -47713,13 +47920,13 @@ function profileAccount(app, storeConfig, opts = {}) {
47713
47920
  }
47714
47921
  }
47715
47922
  async function preflightApp(app, opts = {}) {
47716
- const projectYml = existsSync54(iosProjectYml(app)) ? readFileSync59(iosProjectYml(app), "utf8") : "";
47717
- 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") : "";
47718
47925
  if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
47719
47926
  const findings = analyze(
47720
47927
  projectYml,
47721
47928
  storeConfig,
47722
- await appIconState(join49(appDir(app), "ios")),
47929
+ await appIconState(join50(appDir(app), "ios")),
47723
47930
  profileAccount(app, storeConfig, opts)
47724
47931
  );
47725
47932
  findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
@@ -47748,17 +47955,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
47748
47955
  return f;
47749
47956
  }
47750
47957
  function appLevelMetadataFiles(app, locale = "en-US") {
47751
- const root = join49(storeDir(app), "metadata");
47958
+ const root = join50(storeDir(app), "metadata");
47752
47959
  const out = /* @__PURE__ */ new Set();
47753
- if (existsSync54(root)) {
47960
+ if (existsSync55(root)) {
47754
47961
  for (const n of readdirSync25(root)) if (n.endsWith(".txt")) out.add(n);
47755
47962
  }
47756
- 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");
47757
47964
  return out;
47758
47965
  }
47759
47966
  function reviewInfoFiles(app) {
47760
- const dir = join49(storeDir(app), "review_information");
47761
- if (!existsSync54(dir)) return /* @__PURE__ */ new Set();
47967
+ const dir = join50(storeDir(app), "review_information");
47968
+ if (!existsSync55(dir)) return /* @__PURE__ */ new Set();
47762
47969
  return new Set(readdirSync25(dir).filter((n) => n.endsWith(".txt")));
47763
47970
  }
47764
47971
  function isValidAppStoreSize(w, h) {
@@ -47868,12 +48075,12 @@ function analyzePlayListing(assets) {
47868
48075
  return f;
47869
48076
  }
47870
48077
  function playListingAssets(app, locale = "en-US") {
47871
- const dir = join49(storeDir(app), "play", locale, "images");
48078
+ const dir = join50(storeDir(app), "play", locale, "images");
47872
48079
  const read = (names) => {
47873
48080
  for (const name of names) {
47874
- const p = join49(dir, name);
48081
+ const p = join50(dir, name);
47875
48082
  try {
47876
- if (statSync12(p).isFile()) return { name, bytes: readFileSync59(p) };
48083
+ if (statSync13(p).isFile()) return { name, bytes: readFileSync60(p) };
47877
48084
  } catch {
47878
48085
  }
47879
48086
  }
@@ -47904,26 +48111,26 @@ function analyzeListing(metaFiles, shots) {
47904
48111
  return f;
47905
48112
  }
47906
48113
  function metadataFilesPresent(app, locale = "en-US") {
47907
- const dir = join49(storeDir(app), "metadata", locale);
47908
- if (!existsSync54(dir)) return /* @__PURE__ */ new Set();
48114
+ const dir = join50(storeDir(app), "metadata", locale);
48115
+ if (!existsSync55(dir)) return /* @__PURE__ */ new Set();
47909
48116
  return new Set(readdirSync25(dir).filter((n) => n.endsWith(".txt")));
47910
48117
  }
47911
48118
  function listScreenshots(app, locale = "en-US") {
47912
48119
  const out = [];
47913
- const flat = join49(storeDir(app), "screenshots", locale);
47914
- if (existsSync54(flat)) {
48120
+ const flat = join50(storeDir(app), "screenshots", locale);
48121
+ if (existsSync55(flat)) {
47915
48122
  for (const png of readdirSync25(flat).filter((n) => n.endsWith(".png"))) {
47916
- const sz = pngSize(readFileSync59(join49(flat, png)));
48123
+ const sz = pngSize(readFileSync60(join50(flat, png)));
47917
48124
  if (sz) out.push({ name: png, w: sz.w, h: sz.h });
47918
48125
  }
47919
48126
  }
47920
- const legacy = join49(storeDir(app), "metadata", locale, "screenshots");
47921
- if (existsSync54(legacy)) {
48127
+ const legacy = join50(storeDir(app), "metadata", locale, "screenshots");
48128
+ if (existsSync55(legacy)) {
47922
48129
  for (const deviceDir of readdirSync25(legacy)) {
47923
- const d = join49(legacy, deviceDir);
47924
- if (!statSync12(d).isDirectory()) continue;
48130
+ const d = join50(legacy, deviceDir);
48131
+ if (!statSync13(d).isDirectory()) continue;
47925
48132
  for (const png of readdirSync25(d).filter((n) => n.endsWith(".png"))) {
47926
- const sz = pngSize(readFileSync59(join49(d, png)));
48133
+ const sz = pngSize(readFileSync60(join50(d, png)));
47927
48134
  if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
47928
48135
  }
47929
48136
  }
@@ -47931,13 +48138,13 @@ function listScreenshots(app, locale = "en-US") {
47931
48138
  return out;
47932
48139
  }
47933
48140
  function placeholderHashes2() {
47934
- const templateIos = join49(appDir("_template"), "ios");
47935
- if (!existsSync54(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
48141
+ const templateIos = join50(appDir("_template"), "ios");
48142
+ if (!existsSync55(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
47936
48143
  for (const target of readdirSync25(templateIos)) {
47937
- 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");
47938
48145
  try {
47939
- if (!statSync12(p).isFile()) continue;
47940
- 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")];
47941
48148
  } catch {
47942
48149
  }
47943
48150
  }
@@ -47968,13 +48175,13 @@ async function pixelIssues(bytes2) {
47968
48175
  }
47969
48176
  }
47970
48177
  async function appIconState(iosDir) {
47971
- if (!existsSync54(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
48178
+ if (!existsSync55(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
47972
48179
  for (const target of readdirSync25(iosDir)) {
47973
- 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");
47974
48181
  try {
47975
- if (!statSync12(p).isFile()) continue;
47976
- const bytes2 = readFileSync59(p);
47977
- 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");
47978
48185
  const pixels = await pixelIssues(bytes2);
47979
48186
  return {
47980
48187
  exists: true,
@@ -48045,7 +48252,7 @@ __export(version_exports, {
48045
48252
  setAndroidVersion: () => setAndroidVersion,
48046
48253
  setIosVersion: () => setIosVersion
48047
48254
  });
48048
- import { readFileSync as readFileSync60, writeFileSync as writeFileSync21 } from "node:fs";
48255
+ import { readFileSync as readFileSync61, writeFileSync as writeFileSync22 } from "node:fs";
48049
48256
  function readIosVersion(projectYml) {
48050
48257
  const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
48051
48258
  const build2 = matchScalar(projectYml, "CFBundleVersion");
@@ -48103,15 +48310,15 @@ function setAndroidVersion(gradle, v) {
48103
48310
  function bumpVersion(app, opts) {
48104
48311
  const iosPath = iosProjectYml(app);
48105
48312
  const gradlePath = androidGradle(app);
48106
- const iosYml = readFileSync60(iosPath, "utf8");
48107
- const gradle = readFileSync60(gradlePath, "utf8");
48313
+ const iosYml = readFileSync61(iosPath, "utf8");
48314
+ const gradle = readFileSync61(gradlePath, "utf8");
48108
48315
  const current = readIosVersion(iosYml);
48109
48316
  const next = {
48110
48317
  marketing: opts.marketing ?? current.marketing,
48111
48318
  build: opts.build === "increment" || opts.build === void 0 ? current.build + (opts.build === "increment" ? 1 : 0) : opts.build
48112
48319
  };
48113
- writeFileSync21(iosPath, setIosVersion(iosYml, next));
48114
- writeFileSync21(gradlePath, setAndroidVersion(gradle, next));
48320
+ writeFileSync22(iosPath, setIosVersion(iosYml, next));
48321
+ writeFileSync22(gradlePath, setAndroidVersion(gradle, next));
48115
48322
  return next;
48116
48323
  }
48117
48324
  var init_version = __esm({
@@ -48121,7 +48328,7 @@ var init_version = __esm({
48121
48328
  });
48122
48329
 
48123
48330
  // ../store-release/register-bundle.ts
48124
- import { readFileSync as readFileSync61 } from "node:fs";
48331
+ import { readFileSync as readFileSync62 } from "node:fs";
48125
48332
  import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
48126
48333
  function b64url2(b) {
48127
48334
  return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
@@ -48139,7 +48346,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
48139
48346
  async function registerBundleId(opts) {
48140
48347
  const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
48141
48348
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
48142
- 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));
48143
48350
  const res = await fetch(`${ASC_API}/v1/bundleIds`, {
48144
48351
  method: "POST",
48145
48352
  headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
@@ -48193,7 +48400,7 @@ __export(asc_status_exports, {
48193
48400
  ascStatus: () => ascStatus,
48194
48401
  buildVerdict: () => buildVerdict
48195
48402
  });
48196
- import { readFileSync as readFileSync62 } from "node:fs";
48403
+ import { readFileSync as readFileSync63 } from "node:fs";
48197
48404
  function buildVerdict(builds) {
48198
48405
  if (!builds.length) {
48199
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).";
@@ -48207,7 +48414,7 @@ function buildVerdict(builds) {
48207
48414
  function client(creds) {
48208
48415
  const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
48209
48416
  assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
48210
- 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));
48211
48418
  return async (path2) => {
48212
48419
  const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
48213
48420
  return { status: r.status, json: await r.json().catch(() => ({})) };
@@ -48367,7 +48574,7 @@ __export(secrets_exports, {
48367
48574
  runRemoteSecretsCommand: () => runRemoteSecretsCommand,
48368
48575
  runSecretsCommand: () => runSecretsCommand
48369
48576
  });
48370
- import { readFileSync as readFileSync63 } from "node:fs";
48577
+ import { readFileSync as readFileSync64 } from "node:fs";
48371
48578
  function environment(value) {
48372
48579
  if (value === "preview" || value === "production") return value;
48373
48580
  throw new Error("--environment must be preview or production");
@@ -48398,7 +48605,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
48398
48605
  io.log(JSON.stringify(await vault.list({ app, environment: env })));
48399
48606
  return 0;
48400
48607
  }
48401
- 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$/, "");
48402
48609
  if (operation === "set") await vault.set({ app, environment: env, name, value });
48403
48610
  else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
48404
48611
  else throw new Error(`unknown secrets operation ${operation}`);
@@ -48427,7 +48634,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
48427
48634
  }
48428
48635
  let body;
48429
48636
  if (operation !== "list") {
48430
- 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$/, "");
48431
48638
  body = JSON.stringify({ value });
48432
48639
  }
48433
48640
  const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
@@ -48463,15 +48670,15 @@ __export(notify_exports, {
48463
48670
  runNotify: () => runNotify,
48464
48671
  saveAdminSession: () => saveAdminSession
48465
48672
  });
48466
- 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";
48467
48674
  import { homedir as homedir6 } from "node:os";
48468
- import { dirname as dirname30, join as join50 } from "node:path";
48675
+ import { dirname as dirname30, join as join51 } from "node:path";
48469
48676
  function defaultSessionsPath() {
48470
- 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");
48471
48678
  }
48472
48679
  function loadSessionsFile(path2 = defaultSessionsPath()) {
48473
48680
  try {
48474
- return JSON.parse(readFileSync64(path2, "utf8"));
48681
+ return JSON.parse(readFileSync65(path2, "utf8"));
48475
48682
  } catch {
48476
48683
  return {};
48477
48684
  }
@@ -48479,8 +48686,8 @@ function loadSessionsFile(path2 = defaultSessionsPath()) {
48479
48686
  function saveAdminSession(adminUrl, session, path2 = defaultSessionsPath()) {
48480
48687
  const file = loadSessionsFile(path2);
48481
48688
  file.sessions = { ...file.sessions, [adminUrl]: session };
48482
- mkdirSync25(dirname30(path2), { recursive: true, mode: 448 });
48483
- 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 });
48484
48691
  try {
48485
48692
  chmodSync3(dirname30(path2), 448);
48486
48693
  chmodSync3(path2, 384);
@@ -50018,6 +50225,26 @@ function tuneHighContrastAccent(brand, surface) {
50018
50225
  }
50019
50226
  return candidate;
50020
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
+ }
50021
50248
  function deriveAccentFamily(primary, secondary, surfaces) {
50022
50249
  const primaryDark = tuneDarkAccent(primary, surfaces.dark, surfaces.light);
50023
50250
  const secondaryDark = tuneDarkAccent(secondary, surfaces.dark, surfaces.light);
@@ -50038,7 +50265,7 @@ function deriveAccentFamily(primary, secondary, surfaces) {
50038
50265
  }
50039
50266
  };
50040
50267
  }
50041
- 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;
50042
50269
  var init_brand_color_math = __esm({
50043
50270
  "../../core/ts/src/brand-color-math.ts"() {
50044
50271
  ACCENT_SURFACE_MIN_DELTA = 1.08;
@@ -50050,6 +50277,8 @@ var init_brand_color_math = __esm({
50050
50277
  DARK_ARM_FLOOR_CONTRAST = 3;
50051
50278
  DARK_ARM_LSTAR_CAP = 80;
50052
50279
  HIGH_CONTRAST_TARGET = 8.5;
50280
+ BRAND_COLOR_TOKENS = ["accentPrimary", "accentSecondary", "accentSurface", "textOnAccent"];
50281
+ BRAND_GLOW_SHADOW = "glow";
50053
50282
  }
50054
50283
  });
50055
50284
 
@@ -51106,10 +51335,10 @@ function assertPublicSiteUrl(raw) {
51106
51335
  if (refusal) throw new Error(refusal);
51107
51336
  }
51108
51337
  function resolveAll(hostname2) {
51109
- return new Promise((resolve45, reject) => {
51338
+ return new Promise((resolve46, reject) => {
51110
51339
  dnsLookup(hostname2, { all: true, verbatim: true }, (err, addresses) => {
51111
51340
  if (err) reject(err);
51112
- else resolve45(addresses);
51341
+ else resolve46(addresses);
51113
51342
  });
51114
51343
  });
51115
51344
  }
@@ -51117,13 +51346,13 @@ function withAbort(start, signal, what) {
51117
51346
  if (signal?.aborted) return Promise.reject(new Error(`${what} aborted`));
51118
51347
  const work = start();
51119
51348
  if (!signal) return work;
51120
- return new Promise((resolve45, reject) => {
51349
+ return new Promise((resolve46, reject) => {
51121
51350
  const onAbort = () => reject(new Error(`${what} aborted`));
51122
51351
  signal.addEventListener("abort", onAbort, { once: true });
51123
- work.then(resolve45, reject).finally(() => signal.removeEventListener("abort", onAbort));
51352
+ work.then(resolve46, reject).finally(() => signal.removeEventListener("abort", onAbort));
51124
51353
  });
51125
51354
  }
51126
- async function pinAddress(url, resolve45 = resolveAll, signal) {
51355
+ async function pinAddress(url, resolve46 = resolveAll, signal) {
51127
51356
  const host = url.hostname.replace(/^\[|\]$/g, "");
51128
51357
  if (ipv4Octets(host)) {
51129
51358
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
@@ -51133,7 +51362,7 @@ async function pinAddress(url, resolve45 = resolveAll, signal) {
51133
51362
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
51134
51363
  return { address: host, family: 6 };
51135
51364
  }
51136
- const addresses = await withAbort(() => resolve45(host), signal, `${host} lookup`);
51365
+ const addresses = await withAbort(() => resolve46(host), signal, `${host} lookup`);
51137
51366
  if (!addresses.length) throw new Error(`${host} resolved to no address`);
51138
51367
  const blocked = addresses.filter((a) => isBlockedAddress(a.address)).map((a) => a.address);
51139
51368
  if (blocked.length) throw new Error(`${host} resolves to a blocked address (${blocked.join(", ")})`);
@@ -51173,7 +51402,7 @@ function copyIncomingHeaders(headers2) {
51173
51402
  return out;
51174
51403
  }
51175
51404
  function requestOnce(url, pinned, init) {
51176
- return new Promise((resolve45, reject) => {
51405
+ return new Promise((resolve46, reject) => {
51177
51406
  const headers2 = { host: url.host, "accept-encoding": "identity" };
51178
51407
  new Headers(init.headers ?? {}).forEach((value, key2) => {
51179
51408
  if (key2.toLowerCase() !== "host") headers2[key2] = value;
@@ -51203,7 +51432,7 @@ function requestOnce(url, pinned, init) {
51203
51432
  reject(err);
51204
51433
  return;
51205
51434
  }
51206
- resolve45(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out }));
51435
+ resolve46(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out }));
51207
51436
  }
51208
51437
  );
51209
51438
  req.on("error", reject);
@@ -52006,8 +52235,8 @@ var init_brand_font = __esm({
52006
52235
  });
52007
52236
 
52008
52237
  // src/site-analyze/write-artifacts.ts
52009
- import { mkdirSync as mkdirSync26, writeFileSync as writeFileSync23 } from "node:fs";
52010
- 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";
52011
52240
  function attachVeloSources(book, sources, put) {
52012
52241
  const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
52013
52242
  for (const f of book.velo.files) {
@@ -52162,13 +52391,13 @@ async function downloadMedia(book, fetchImpl, put) {
52162
52391
  }
52163
52392
  async function writeBusinessBook(result, opts) {
52164
52393
  const out = opts.outDir;
52165
- mkdirSync26(join51(out, "evidence/pages"), { recursive: true });
52166
- mkdirSync26(join51(out, "media/catalog"), { recursive: true });
52394
+ mkdirSync27(join52(out, "evidence/pages"), { recursive: true });
52395
+ mkdirSync27(join52(out, "media/catalog"), { recursive: true });
52167
52396
  const files = [];
52168
52397
  const put = (rel, body) => {
52169
- const p = join51(out, rel);
52170
- mkdirSync26(join51(p, ".."), { recursive: true });
52171
- writeFileSync23(p, body);
52398
+ const p = join52(out, rel);
52399
+ mkdirSync27(join52(p, ".."), { recursive: true });
52400
+ writeFileSync24(p, body);
52172
52401
  files.push(rel);
52173
52402
  };
52174
52403
  const book = result.book;
@@ -52261,15 +52490,15 @@ var init_customer_build = __esm({
52261
52490
  });
52262
52491
 
52263
52492
  // src/site-analyze/apply.ts
52264
- 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";
52265
- 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";
52266
52495
  import { spawnSync as spawnSync4 } from "node:child_process";
52267
52496
  function unpairedRedirectNote(overlay) {
52268
52497
  if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
52269
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)`;
52270
52499
  }
52271
52500
  function posix2(p) {
52272
- return resolve42(p).replace(/\\/g, "/");
52501
+ return resolve43(p).replace(/\\/g, "/");
52273
52502
  }
52274
52503
  function committedShellProvisioning(path2) {
52275
52504
  return committedShellFor(posix2(path2));
@@ -52277,7 +52506,7 @@ function committedShellProvisioning(path2) {
52277
52506
  function findRepoRoot(cwd) {
52278
52507
  let dir = cwd;
52279
52508
  for (let i = 0; i < 8; i++) {
52280
- 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;
52281
52510
  const next = dirname31(dir);
52282
52511
  if (next === dir) break;
52283
52512
  dir = next;
@@ -52303,7 +52532,7 @@ function assertNotCommitted(path2, forbidden) {
52303
52532
  `refusing to overwrite committed ${committedProvisioningPath(committed)} \u2014 use prepare:customer --contract`
52304
52533
  );
52305
52534
  }
52306
- if (forbidden && resolve42(path2) === resolve42(forbidden)) {
52535
+ if (forbidden && resolve43(path2) === resolve43(forbidden)) {
52307
52536
  const named = committedShellProvisioning(forbidden);
52308
52537
  throw new Error(
52309
52538
  `refusing to overwrite committed ${named ? committedProvisioningPath(named) : forbidden} \u2014 pass a content-package provisioning.json or use prepare:customer --contract`
@@ -52345,24 +52574,24 @@ function mergeCustomerOwned(committed, overlay) {
52345
52574
  }
52346
52575
  function buildMergedContract(options) {
52347
52576
  const { appDir: appDir2, packageDir, overlay } = options;
52348
- const committedPath = join52(appDir2, "provisioning.json");
52349
- if (!existsSync55(committedPath)) {
52577
+ const committedPath = join53(appDir2, "provisioning.json");
52578
+ if (!existsSync56(committedPath)) {
52350
52579
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
52351
52580
  }
52352
- const committed = JSON.parse(readFileSync65(committedPath, "utf8"));
52581
+ const committed = JSON.parse(readFileSync66(committedPath, "utf8"));
52353
52582
  const merged = mergeCustomerOwned(committed, overlay);
52354
52583
  const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
52355
52584
  const branding = merged.branding ?? {};
52356
52585
  const staged = [];
52357
52586
  const contained = (root, rel) => {
52358
52587
  if (isAbsolute4(rel)) return void 0;
52359
- const full = resolve42(root, rel);
52360
- 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;
52361
52590
  };
52362
52591
  const stage = (fromRel, toRel) => {
52363
52592
  const from = contained(packageDir, fromRel);
52364
- const to = contained(join52(appDir2, STAGED), toRel.slice(STAGED.length + 1));
52365
- 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;
52366
52595
  let real;
52367
52596
  let realRoot;
52368
52597
  try {
@@ -52371,10 +52600,10 @@ function buildMergedContract(options) {
52371
52600
  } catch {
52372
52601
  return void 0;
52373
52602
  }
52374
- if (!real.startsWith(realRoot + sep11)) return void 0;
52603
+ if (!real.startsWith(realRoot + sep12)) return void 0;
52375
52604
  try {
52376
- if (!statSync13(real).isFile()) return void 0;
52377
- mkdirSync27(dirname31(to), { recursive: true });
52605
+ if (!statSync14(real).isFile()) return void 0;
52606
+ mkdirSync28(dirname31(to), { recursive: true });
52378
52607
  copyFileSync3(real, to);
52379
52608
  } catch {
52380
52609
  return void 0;
@@ -52384,11 +52613,11 @@ function buildMergedContract(options) {
52384
52613
  };
52385
52614
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
52386
52615
  if (icon) branding.appIconPath = icon;
52387
- const facesPath = join52(packageDir, "media/fonts/faces.json");
52388
- if (existsSync55(facesPath)) {
52616
+ const facesPath = join53(packageDir, "media/fonts/faces.json");
52617
+ if (existsSync56(facesPath)) {
52389
52618
  let faces = [];
52390
52619
  try {
52391
- const parsed = JSON.parse(readFileSync65(facesPath, "utf8"));
52620
+ const parsed = JSON.parse(readFileSync66(facesPath, "utf8"));
52392
52621
  faces = Array.isArray(parsed) ? parsed : [];
52393
52622
  } catch {
52394
52623
  faces = [];
@@ -52409,20 +52638,20 @@ function buildMergedContract(options) {
52409
52638
  merged.branding = branding;
52410
52639
  const body = `${JSON.stringify(merged, null, 2)}
52411
52640
  `;
52412
- const path2 = join52(packageDir, "provisioning.contract.json");
52413
- writeFileSync24(path2, body);
52414
- const localPath = join52(appDir2, LOCAL_CONTRACT_REL);
52415
- mkdirSync27(dirname31(localPath), { recursive: true });
52416
- 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);
52417
52646
  staged.push(localPath);
52418
52647
  return { path: path2, staged };
52419
52648
  }
52420
52649
  async function applyOverlays(input) {
52421
- const cwd = resolve42(input.cwd);
52650
+ const cwd = resolve43(input.cwd);
52422
52651
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
52423
52652
  assertKnownShell(shell);
52424
- const overlay = JSON.parse(readFileSync65(input.overlayPath, "utf8"));
52425
- 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"));
52426
52655
  const wrote = [];
52427
52656
  const notes = [];
52428
52657
  const repoRoot2 = findRepoRoot(cwd);
@@ -52432,8 +52661,8 @@ async function applyOverlays(input) {
52432
52661
  `shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
52433
52662
  );
52434
52663
  }
52435
- const appDir2 = join52(repoRoot2, shellAppDir(shell));
52436
- const packageDir = dirname31(resolve42(input.overlayPath));
52664
+ const appDir2 = join53(repoRoot2, shellAppDir(shell));
52665
+ const packageDir = dirname31(resolve43(input.overlayPath));
52437
52666
  const { path: contract, staged } = buildMergedContract({ appDir: appDir2, packageDir, overlay });
52438
52667
  wrote.push(...staged);
52439
52668
  const r = spawnSync4("npm", ["run", "prepare:customer", "--", "--contract", contract], {
@@ -52454,32 +52683,41 @@ async function applyOverlays(input) {
52454
52683
  note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
52455
52684
  };
52456
52685
  }
52457
- const pkgProv = join52(cwd, "provisioning.json");
52686
+ const pkgProv = join53(cwd, "provisioning.json");
52458
52687
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
52459
- if (existsSync55(pkgProv)) {
52460
- const cur = JSON.parse(readFileSync65(pkgProv, "utf8"));
52688
+ if (existsSync56(pkgProv)) {
52689
+ const cur = JSON.parse(readFileSync66(pkgProv, "utf8"));
52461
52690
  const merged = deepMerge4(cur, overlay);
52462
- writeFileSync24(pkgProv, JSON.stringify(merged, null, 2) + "\n");
52691
+ writeFileSync25(pkgProv, JSON.stringify(merged, null, 2) + "\n");
52463
52692
  wrote.push(pkgProv);
52464
52693
  } else {
52465
- writeFileSync24(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
52694
+ writeFileSync25(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
52466
52695
  wrote.push(pkgProv);
52467
52696
  }
52468
- const pkgTokens = join52(cwd, "tokens.json");
52469
- if (existsSync55(pkgTokens) && (tokens.colors || tokens.typography)) {
52470
- 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"));
52471
52700
  const merged = deepMerge4(cur, tokens);
52472
52701
  const mergedColors = merged.colors;
52473
52702
  if (mergedColors && typeof mergedColors === "object" && !Array.isArray(mergedColors)) {
52474
52703
  merged.colors = alignAccentsToSurfaces(mergedColors, tokens.colors);
52475
52704
  }
52476
- 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");
52477
52715
  wrote.push(pkgTokens);
52478
52716
  }
52479
52717
  const homeAction = homeRefreshActionId(shell);
52480
- const homeSrc = join52(cwd, "dev/index.ts");
52481
- if (homeAction && existsSync55(homeSrc)) {
52482
- const prev = readFileSync65(homeSrc, "utf8");
52718
+ const homeSrc = join53(cwd, "dev/index.ts");
52719
+ if (homeAction && existsSync56(homeSrc)) {
52720
+ const prev = readFileSync66(homeSrc, "utf8");
52483
52721
  const patched = patchBrandParams(prev, overlay, homeAction);
52484
52722
  let next = patched.src;
52485
52723
  if (!patched.foreign && overlay.installedVerticals?.length) {
@@ -52495,20 +52733,20 @@ async function applyOverlays(input) {
52495
52733
  }
52496
52734
  }
52497
52735
  if (next !== prev) {
52498
- writeFileSync24(homeSrc, next);
52736
+ writeFileSync25(homeSrc, next);
52499
52737
  wrote.push(homeSrc);
52500
52738
  }
52501
52739
  if (patched.unparsed) {
52502
52740
  notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
52503
52741
  }
52504
52742
  }
52505
- if (!input.iconPath || !existsSync55(input.iconPath)) {
52506
- 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;
52507
52745
  notes.push(
52508
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"
52509
52747
  );
52510
52748
  }
52511
- if (input.iconPath && existsSync55(input.iconPath)) {
52749
+ if (input.iconPath && existsSync56(input.iconPath)) {
52512
52750
  try {
52513
52751
  const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
52514
52752
  wrote.push(...installed.wrote);
@@ -52593,6 +52831,7 @@ var init_apply2 = __esm({
52593
52831
  init_brandable_shells();
52594
52832
  init_customer_build();
52595
52833
  init_branding_derive();
52834
+ init_brand_color_math();
52596
52835
  init_home_descriptor();
52597
52836
  STAGED = ".himi/brand";
52598
52837
  }
@@ -53445,10 +53684,10 @@ function permuteDomain(domain, allowSpecialUseDomain) {
53445
53684
  }
53446
53685
  function createPromiseCallback(cb) {
53447
53686
  let callback;
53448
- let resolve45;
53687
+ let resolve46;
53449
53688
  let reject;
53450
53689
  const promise = new Promise((_resolve, _reject) => {
53451
- resolve45 = _resolve;
53690
+ resolve46 = _resolve;
53452
53691
  reject = _reject;
53453
53692
  });
53454
53693
  if (typeof cb === "function") {
@@ -53464,7 +53703,7 @@ function createPromiseCallback(cb) {
53464
53703
  callback = (err, result) => {
53465
53704
  try {
53466
53705
  if (err) reject(err);
53467
- else resolve45(result);
53706
+ else resolve46(result);
53468
53707
  } catch (e) {
53469
53708
  reject(e instanceof Error ? e : new Error());
53470
53709
  }
@@ -56662,8 +56901,8 @@ __export(cli_exports, {
56662
56901
  runSiteAnalyze: () => runSiteAnalyze,
56663
56902
  runSiteFunctionCli: () => runSiteFunctionCli
56664
56903
  });
56665
- import { readFileSync as readFileSync66 } from "node:fs";
56666
- import { resolve as resolve43 } from "node:path";
56904
+ import { readFileSync as readFileSync67 } from "node:fs";
56905
+ import { resolve as resolve44 } from "node:path";
56667
56906
  function assetFetchFor(_opts) {
56668
56907
  return pinnedFetch2;
56669
56908
  }
@@ -56672,7 +56911,7 @@ async function runSiteAnalyze(opts) {
56672
56911
  const assetFetch = assetFetchFor(opts);
56673
56912
  const siteFetch = guardedSiteFetch;
56674
56913
  const cwd = opts.cwd ?? process.cwd();
56675
- const outDir = resolve43(cwd, opts.outDir ?? ".himi/business-book");
56914
+ const outDir = resolve44(cwd, opts.outDir ?? ".himi/business-book");
56676
56915
  let ownerAuth;
56677
56916
  let msid;
56678
56917
  try {
@@ -56710,9 +56949,9 @@ async function runSiteAnalyze(opts) {
56710
56949
  if (opts.apply) {
56711
56950
  applied = await applyOverlays({
56712
56951
  cwd,
56713
- overlayPath: resolve43(outDir, "provisioning.overlay.json"),
56714
- tokensPath: resolve43(outDir, "tokens.overlay.json"),
56715
- 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"),
56716
56955
  shell: opts.shell
56717
56956
  });
56718
56957
  const note = noteWithWarnings(applied.note, warnings);
@@ -56748,8 +56987,8 @@ async function runSiteFunctionCli(opts) {
56748
56987
  const token = opts.token ?? await siteToken(msid);
56749
56988
  let source;
56750
56989
  if (opts.sourcePath) {
56751
- const p = resolve43(opts.cwd ?? process.cwd(), opts.sourcePath);
56752
- source = readFileSync66(p, "utf8");
56990
+ const p = resolve44(opts.cwd ?? process.cwd(), opts.sourcePath);
56991
+ source = readFileSync67(p, "utf8");
56753
56992
  }
56754
56993
  let body;
56755
56994
  if (opts.bodyRaw != null) {
@@ -56792,15 +57031,15 @@ var init_cli = __esm({
56792
57031
  });
56793
57032
 
56794
57033
  // src/wix-account.ts
56795
- import { spawn as spawn4 } from "node:child_process";
56796
- async function accountToken2(spawnImpl = spawn4) {
57034
+ import { spawn as spawn5 } from "node:child_process";
57035
+ async function accountToken2(spawnImpl = spawn5) {
56797
57036
  if (cached2) return cached2;
56798
57037
  const fromEnv = process.env.WIX_TEST_TOKEN?.trim();
56799
57038
  if (fromEnv) {
56800
57039
  cached2 = fromEnv;
56801
57040
  return fromEnv;
56802
57041
  }
56803
- const token = await new Promise((resolve45, reject) => {
57042
+ const token = await new Promise((resolve46, reject) => {
56804
57043
  let child;
56805
57044
  try {
56806
57045
  child = spawnImpl("wix", ["token"]);
@@ -56829,7 +57068,7 @@ async function accountToken2(spawnImpl = spawn4) {
56829
57068
  const scan = (d) => {
56830
57069
  out += String(d);
56831
57070
  const m = out.match(TOKEN_RE2);
56832
- if (m) done(() => resolve45(m[0]));
57071
+ if (m) done(() => resolve46(m[0]));
56833
57072
  };
56834
57073
  child.stdout?.on("data", scan);
56835
57074
  child.stderr?.on("data", scan);
@@ -56849,7 +57088,7 @@ function apiKeyAuth(env = process.env) {
56849
57088
  const accountId = env.WIX_ACCOUNT_ID?.trim();
56850
57089
  return key2 && accountId ? { key: key2, accountId } : void 0;
56851
57090
  }
56852
- function accountTransport(fetchImpl = fetch, timeoutMs = DEFAULT_TIMEOUT_MS5, spawnImpl = spawn4) {
57091
+ function accountTransport(fetchImpl = fetch, timeoutMs = DEFAULT_TIMEOUT_MS5, spawnImpl = spawn5) {
56853
57092
  return async (method, path2, body) => {
56854
57093
  const viaKey = apiKeyAuth();
56855
57094
  const headers2 = viaKey ? { Authorization: viaKey.key, "wix-account-id": viaKey.accountId, Accept: "application/json" } : { Authorization: await accountToken2(spawnImpl), Accept: "application/json" };
@@ -57006,7 +57245,7 @@ __export(site_create_exports, {
57006
57245
  runSiteList: () => runSiteList,
57007
57246
  writeProvisioningBinding: () => writeProvisioningBinding
57008
57247
  });
57009
- 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";
57010
57249
  import { resolve as resolvePath2 } from "node:path";
57011
57250
  function oauthClientName(projectName) {
57012
57251
  return `${projectName} client`;
@@ -57155,7 +57394,7 @@ async function runSiteCreate(opts) {
57155
57394
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
57156
57395
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
57157
57396
  }
57158
- function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync56, readFileSync: readFileSync67, writeFileSync: writeFileSync25 }) {
57397
+ function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync57, readFileSync: readFileSync68, writeFileSync: writeFileSync26 }) {
57159
57398
  const msid = binding2.siteId;
57160
57399
  const path2 = resolvePath2(target);
57161
57400
  const committed = committedShellProvisioning(path2);
@@ -57828,11 +58067,11 @@ var init_context = __esm({
57828
58067
  });
57829
58068
 
57830
58069
  // src/cli.ts
57831
- 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";
57832
- import { execFile as execFile4, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn5 } from "node:child_process";
57833
- 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";
57834
58073
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
57835
- 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";
57836
58075
  import { fileURLToPath as fileURLToPath24 } from "node:url";
57837
58076
 
57838
58077
  // ../serve-cli/src/client.ts
@@ -59544,7 +59783,7 @@ async function browserLogin(opts) {
59544
59783
  const log = opts.log ?? (() => {
59545
59784
  });
59546
59785
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
59547
- return await new Promise((resolve45, reject) => {
59786
+ return await new Promise((resolve46, reject) => {
59548
59787
  let settled = false;
59549
59788
  let loginUrl = "";
59550
59789
  const server = createServer();
@@ -59608,7 +59847,7 @@ async function browserLogin(opts) {
59608
59847
  return;
59609
59848
  }
59610
59849
  res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store", connection: "close" }).end(CLOSE_PAGE);
59611
- finish2(() => resolve45({ token, loginUrl }));
59850
+ finish2(() => resolve46({ token, loginUrl }));
59612
59851
  });
59613
59852
  });
59614
59853
  server.on("error", (err) => finish2(() => reject(err)));
@@ -60974,7 +61213,7 @@ function writeAgentContext(targetDir) {
60974
61213
  // src/cli.ts
60975
61214
  init_wix_placeholders();
60976
61215
  var defaultIO = { log: (l) => console.log(l), error: (l) => console.error(l), isTTY: process.stdout.isTTY === true };
60977
- var REPEATABLE_FLAGS = /* @__PURE__ */ new Set(["data"]);
61216
+ var REPEATABLE_FLAGS = /* @__PURE__ */ new Set(["data", "image"]);
60978
61217
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
60979
61218
  "browser",
60980
61219
  "no-open",
@@ -61041,7 +61280,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
61041
61280
  "refresh",
61042
61281
  "push-setup",
61043
61282
  "no-push-setup",
61044
- "apple-signing"
61283
+ "apple-signing",
61284
+ "notify"
61045
61285
  ]);
61046
61286
  var SHELL_ENUM = SHELL_NAMES2.join("|");
61047
61287
  var SWITCH_FLAGS = new Set([...BOOLEAN_FLAGS].filter((name) => name !== "deep"));
@@ -61110,8 +61350,8 @@ var str5 = (v) => typeof v === "string" ? v : void 0;
61110
61350
  var num = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
61111
61351
  function embeddedTemplateCatalog() {
61112
61352
  return availableTemplates().map((name) => {
61113
- const path2 = join53(templateSourceDir(name), TEMPLATE_META_FILE);
61114
- const meta = JSON.parse(readFileSync68(path2, "utf8"));
61353
+ const path2 = join54(templateSourceDir(name), TEMPLATE_META_FILE);
61354
+ const meta = JSON.parse(readFileSync69(path2, "utf8"));
61115
61355
  if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
61116
61356
  throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
61117
61357
  }
@@ -61168,6 +61408,11 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
61168
61408
  verticals; zero network). Catches the wrong reducers
61169
61409
  validate/render pass (NaN totals, stuck skeletons, dead
61170
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.
61171
61416
  himi ux audit [--content <dir>] [--strict] [--json]
61172
61417
  inspect the mobile UX contract, template placeholders, app fixtures,
61173
61418
  and recorded iOS/Android audit evidence. Advisory by default; --strict
@@ -61712,6 +61957,7 @@ var COMMANDS = [
61712
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]" },
61713
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]" },
61714
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>]' },
61715
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]" },
61716
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>]" },
61717
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]" },
@@ -61760,7 +62006,7 @@ var COMMANDS = [
61760
62006
  ];
61761
62007
  function cliVersion() {
61762
62008
  try {
61763
- 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";
61764
62010
  } catch {
61765
62011
  return "unknown";
61766
62012
  }
@@ -61811,16 +62057,16 @@ function createScopedRegistryResolver(exec = execNpmConfig) {
61811
62057
  }
61812
62058
  var SCOPED_REGISTRY_TIMEOUT_MS = 5e3;
61813
62059
  function execNpmConfig(file, args, options) {
61814
- return new Promise((resolve45, reject) => {
61815
- 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)));
61816
62062
  });
61817
62063
  }
61818
62064
  var npmScopedWixRegistry = createScopedRegistryResolver();
61819
62065
  async function scopedRegistryBefore(lookup2, deadline) {
61820
62066
  let cancel = () => {
61821
62067
  };
61822
- const expired = new Promise((resolve45) => {
61823
- 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()));
61824
62070
  cancel = () => clearTimeout(timer);
61825
62071
  });
61826
62072
  try {
@@ -61878,16 +62124,16 @@ function ageInDays(publishedAt, now = Date.now()) {
61878
62124
  }
61879
62125
  function packageVersion(path2) {
61880
62126
  try {
61881
- const version2 = JSON.parse(readFileSync68(path2, "utf8")).version;
62127
+ const version2 = JSON.parse(readFileSync69(path2, "utf8")).version;
61882
62128
  return typeof version2 === "string" && version2 ? version2 : void 0;
61883
62129
  } catch {
61884
62130
  return void 0;
61885
62131
  }
61886
62132
  }
61887
62133
  function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
61888
- let dir = resolve44(fromDir);
62134
+ let dir = resolve45(fromDir);
61889
62135
  for (; ; ) {
61890
- const version2 = packageVersion(join53(dir, "node_modules", "@wix", "himalaya", "package.json"));
62136
+ const version2 = packageVersion(join54(dir, "node_modules", "@wix", "himalaya", "package.json"));
61891
62137
  if (version2) return { version: version2, source: "local" };
61892
62138
  const parent = dirname32(dir);
61893
62139
  if (parent === dir) break;
@@ -61897,7 +62143,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
61897
62143
  if (bundled) return { version: bundled, source: "bundled" };
61898
62144
  try {
61899
62145
  const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
61900
- 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;
61901
62147
  return version2 ? { version: version2, source: "global" } : {};
61902
62148
  } catch {
61903
62149
  return {};
@@ -61944,11 +62190,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
61944
62190
  var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
61945
62191
  var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
61946
62192
  function updateCachePath(env = process.env) {
61947
- 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");
61948
62194
  }
61949
62195
  function readUpdateCache(path2) {
61950
62196
  try {
61951
- const parsed = JSON.parse(readFileSync68(path2, "utf8"));
62197
+ const parsed = JSON.parse(readFileSync69(path2, "utf8"));
61952
62198
  return parsed && typeof parsed === "object" ? parsed : {};
61953
62199
  } catch {
61954
62200
  return {};
@@ -61956,8 +62202,8 @@ function readUpdateCache(path2) {
61956
62202
  }
61957
62203
  function writeUpdateCache(path2, cache) {
61958
62204
  try {
61959
- mkdirSync28(dirname32(path2), { recursive: true, mode: 448 });
61960
- 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 });
61961
62207
  } catch {
61962
62208
  }
61963
62209
  }
@@ -61998,12 +62244,12 @@ function npmInstallArgs(registry, version2) {
61998
62244
  return ["i", "-g", `${CLI_PACKAGE}@${version2}`, `--registry=${pinned}`, `--@wix:registry=${pinned}`];
61999
62245
  }
62000
62246
  var INSTALLABLE_SPEC = /^(?:latest|\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/;
62001
- function createUpdateRunner(spawn6 = spawnSync5) {
62247
+ function createUpdateRunner(spawn7 = spawnSync5) {
62002
62248
  return {
62003
62249
  install: async (registry, version2) => {
62004
62250
  if (!isTrustedRegistry(registry)) return { ok: false, detail: `refusing untrusted registry ${registry}` };
62005
62251
  if (!INSTALLABLE_SPEC.test(version2)) return { ok: false, detail: `refusing install spec ${JSON.stringify(version2)}` };
62006
- const result = spawn6("npm", npmInstallArgs(registry, version2), {
62252
+ const result = spawn7("npm", npmInstallArgs(registry, version2), {
62007
62253
  // npm's stdout goes to OUR stderr: in `himi <cmd> --json | jq` (and `himi upgrade --json`) its
62008
62254
  // "added 212 packages" would otherwise land in stdout ahead of the envelope and break the
62009
62255
  // parse — the agent case this whole feature exists for (#2985 review). And no stdin: an
@@ -62016,12 +62262,12 @@ function createUpdateRunner(spawn6 = spawnSync5) {
62016
62262
  },
62017
62263
  installedVersion: () => {
62018
62264
  const root = globalNodeModulesRoot();
62019
- 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;
62020
62266
  },
62021
62267
  reexec: (argv) => {
62022
62268
  const root = globalNodeModulesRoot();
62023
- const entry = root ? join53(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
62024
- 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;
62025
62271
  const result = spawnSync5(process.execPath, [entry, ...argv], {
62026
62272
  // inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
62027
62273
  stdio: "inherit",
@@ -62068,7 +62314,7 @@ function staleUpdateLockFile(cachePath, now) {
62068
62314
  for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
62069
62315
  let content;
62070
62316
  try {
62071
- content = readFileSync68(path2, "utf8");
62317
+ content = readFileSync69(path2, "utf8");
62072
62318
  } catch {
62073
62319
  continue;
62074
62320
  }
@@ -62076,7 +62322,7 @@ function staleUpdateLockFile(cachePath, now) {
62076
62322
  let since = stamped;
62077
62323
  if (!Number.isFinite(since)) {
62078
62324
  try {
62079
- since = statSync14(path2).mtimeMs;
62325
+ since = statSync15(path2).mtimeMs;
62080
62326
  } catch {
62081
62327
  continue;
62082
62328
  }
@@ -62091,14 +62337,14 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
62091
62337
  const mine = lockStamp(now);
62092
62338
  const readLock = (path2) => {
62093
62339
  try {
62094
- return readFileSync68(path2, "utf8");
62340
+ return readFileSync69(path2, "utf8");
62095
62341
  } catch {
62096
62342
  return void 0;
62097
62343
  }
62098
62344
  };
62099
62345
  const tryCreate = (path2) => {
62100
62346
  try {
62101
- writeFileSync26(path2, mine, { flag: "wx", mode: 384 });
62347
+ writeFileSync27(path2, mine, { flag: "wx", mode: 384 });
62102
62348
  return true;
62103
62349
  } catch {
62104
62350
  return false;
@@ -62112,7 +62358,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
62112
62358
  };
62113
62359
  const release = () => removeIfMine(lockPath);
62114
62360
  try {
62115
- mkdirSync28(dirname32(lockPath), { recursive: true, mode: 448 });
62361
+ mkdirSync29(dirname32(lockPath), { recursive: true, mode: 448 });
62116
62362
  } catch {
62117
62363
  return () => {
62118
62364
  };
@@ -62176,7 +62422,7 @@ function supersededInCache(current, latest, now) {
62176
62422
  const checkedAt = current.checkedAt ? Date.parse(current.checkedAt) : Number.NaN;
62177
62423
  return Number.isFinite(checkedAt) && now - checkedAt < UPDATE_CHECK_INTERVAL_MS;
62178
62424
  }
62179
- function createUpdateRefreshSpawner(spawnFn = spawn5, execArgv = process.execArgv) {
62425
+ function createUpdateRefreshSpawner(spawnFn = spawn6, execArgv = process.execArgv) {
62180
62426
  return () => {
62181
62427
  try {
62182
62428
  const child = spawnFn(process.execPath, [...loaderArgs(execArgv), fileURLToPath24(import.meta.url), UPDATE_REFRESH_COMMAND], {
@@ -62629,9 +62875,9 @@ function executableOnPath(name, env = process.env) {
62629
62875
  const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
62630
62876
  for (const dir of entries) {
62631
62877
  for (const suffix of suffixes) {
62632
- const candidate = join53(dir, `${name}${suffix}`);
62878
+ const candidate = join54(dir, `${name}${suffix}`);
62633
62879
  try {
62634
- if (!statSync14(candidate).isFile()) continue;
62880
+ if (!statSync15(candidate).isFile()) continue;
62635
62881
  if (process.platform !== "win32") accessSync(candidate, constants.X_OK);
62636
62882
  return true;
62637
62883
  } catch {
@@ -62738,7 +62984,7 @@ async function nativeConfigAdvisories(app, configSource) {
62738
62984
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
62739
62985
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
62740
62986
  const iosYmlPath = iosProjectYml2(app);
62741
- const iosYml = existsSync57(iosYmlPath) ? readFileSync68(iosYmlPath, "utf8") : "";
62987
+ const iosYml = existsSync58(iosYmlPath) ? readFileSync69(iosYmlPath, "utf8") : "";
62742
62988
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
62743
62989
  if (!optedIn) {
62744
62990
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -62752,19 +62998,19 @@ async function nativeConfigAdvisories(app, configSource) {
62752
62998
  }
62753
62999
  function readConfigSource(dir) {
62754
63000
  try {
62755
- return readFileSync68(join53(dir, "config.ts"), "utf8");
63001
+ return readFileSync69(join54(dir, "config.ts"), "utf8");
62756
63002
  } catch {
62757
63003
  return null;
62758
63004
  }
62759
63005
  }
62760
63006
  function writePngFile(path2, base64) {
62761
- mkdirSync28(dirname32(path2), { recursive: true });
62762
- writeFileSync26(path2, Buffer.from(base64, "base64"));
63007
+ mkdirSync29(dirname32(path2), { recursive: true });
63008
+ writeFileSync27(path2, Buffer.from(base64, "base64"));
62763
63009
  return path2;
62764
63010
  }
62765
63011
  async function initFromRemoteTemplate(name, parentDir, template, c) {
62766
- const dir = resolve44(parentDir, name);
62767
- if (existsSync57(join53(dir, "himalaya.content.json"))) {
63012
+ const dir = resolve45(parentDir, name);
63013
+ if (existsSync58(join54(dir, "himalaya.content.json"))) {
62768
63014
  throw new Error(`content package already exists at ${dir}`);
62769
63015
  }
62770
63016
  const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -62776,7 +63022,7 @@ async function initFromRemoteTemplate(name, parentDir, template, c) {
62776
63022
  return finishScaffold(materializeSource(archive.files, name, dir), template);
62777
63023
  }
62778
63024
  function contentDir(flags) {
62779
- return resolve44(str5(flags.content) ?? process.cwd());
63025
+ return resolve45(str5(flags.content) ?? process.cwd());
62780
63026
  }
62781
63027
  function renameRestoredSource(restored, declaredApp, renamed) {
62782
63028
  const text4 = {};
@@ -62807,8 +63053,8 @@ function symlinkDestinationIssue(dest) {
62807
63053
  function restoreDestinationIssue(dest, force) {
62808
63054
  const link = symlinkDestinationIssue(dest);
62809
63055
  if (link) return link;
62810
- if (!existsSync57(dest)) return null;
62811
- if (!statSync14(dest).isDirectory()) {
63056
+ if (!existsSync58(dest)) return null;
63057
+ if (!statSync15(dest).isDirectory()) {
62812
63058
  return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
62813
63059
  }
62814
63060
  if (readdirSync26(dest).length > 0 && !force) {
@@ -62820,9 +63066,9 @@ function restoreDestinationIssue(dest, force) {
62820
63066
  return null;
62821
63067
  }
62822
63068
  function isHimalayaMonorepoCheckout(start) {
62823
- let dir = resolve44(start);
63069
+ let dir = resolve45(start);
62824
63070
  for (; ; ) {
62825
- 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;
62826
63072
  const parent = dirname32(dir);
62827
63073
  if (parent === dir) return false;
62828
63074
  dir = parent;
@@ -62864,8 +63110,8 @@ function materializeForPreview(appDir2, slug, displayName) {
62864
63110
  const forBuild = Object.fromEntries(
62865
63111
  Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
62866
63112
  );
62867
- const repoRoot2 = resolve44(fileURLToPath24(new URL("../../..", import.meta.url)));
62868
- 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");
62869
63115
  const stillRunning = (pid) => {
62870
63116
  try {
62871
63117
  process.kill(pid, 0);
@@ -62879,21 +63125,21 @@ function materializeForPreview(appDir2, slug, displayName) {
62879
63125
  if (!entry.isDirectory()) continue;
62880
63126
  const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
62881
63127
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
62882
- rmSync11(join53(root, entry.name), { recursive: true, force: true });
63128
+ rmSync11(join54(root, entry.name), { recursive: true, force: true });
62883
63129
  }
62884
63130
  }
62885
63131
  } catch {
62886
63132
  }
62887
- const dest = join53(root, `${slug}-${process.pid}`);
63133
+ const dest = join54(root, `${slug}-${process.pid}`);
62888
63134
  rmSync11(dest, { recursive: true, force: true });
62889
- mkdirSync28(dest, { recursive: true });
63135
+ mkdirSync29(dest, { recursive: true });
62890
63136
  materializeSource(forBuild, displayName, dest, slug);
62891
63137
  return dest;
62892
63138
  }
62893
63139
  async function appId(dir) {
62894
63140
  try {
62895
- const { readFileSync: readFileSync69 } = await import("node:fs");
62896
- 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"));
62897
63143
  if (m.name) return m.name;
62898
63144
  } catch {
62899
63145
  }
@@ -62901,8 +63147,8 @@ async function appId(dir) {
62901
63147
  }
62902
63148
  async function contentVisibility(dir) {
62903
63149
  try {
62904
- const { readFileSync: readFileSync69 } = await import("node:fs");
62905
- 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"));
62906
63152
  if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
62907
63153
  } catch {
62908
63154
  }
@@ -63104,7 +63350,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
63104
63350
  return 0;
63105
63351
  }
63106
63352
  case "agent-init": {
63107
- const dir = resolve44(str5(flags.dir) ?? process.cwd());
63353
+ const dir = resolve45(str5(flags.dir) ?? process.cwd());
63108
63354
  const res = writeAgentContext(dir);
63109
63355
  print({ ok: true, dir: res.dir, files: res.files, portalUrl: idx.portalUrl });
63110
63356
  return 0;
@@ -63126,7 +63372,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
63126
63372
  try {
63127
63373
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
63128
63374
  const bres = await buildContentForValidation2(dir, { resolution });
63129
- out = mkdtempSync4(join53(tmpdir5(), "himi-ux-record-"));
63375
+ out = mkdtempSync4(join54(tmpdir5(), "himi-ux-record-"));
63130
63376
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
63131
63377
  const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
63132
63378
  const releaseId = outcome.manifest.releaseId;
@@ -63304,7 +63550,7 @@ async function producedWidgetFamilies(dir) {
63304
63550
  let js;
63305
63551
  for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
63306
63552
  try {
63307
- js = readFileSync68(join53(outDir, candidate), "utf8");
63553
+ js = readFileSync69(join54(outDir, candidate), "utf8");
63308
63554
  break;
63309
63555
  } catch {
63310
63556
  }
@@ -63580,7 +63826,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63580
63826
  return 2;
63581
63827
  }
63582
63828
  const template = str5(flags.template);
63583
- const parentDir = resolve44(str5(flags.dir) ?? process.cwd());
63829
+ const parentDir = resolve45(str5(flags.dir) ?? process.cwd());
63584
63830
  if (template && flags.remote === true) {
63585
63831
  try {
63586
63832
  const res2 = await initFromRemoteTemplate(name, parentDir, template, client2());
@@ -63697,11 +63943,11 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63697
63943
  return outcome.code;
63698
63944
  }
63699
63945
  if (sub === "publish") {
63700
- const appDir2 = resolve44(str5(flags.dir) ?? process.cwd());
63701
- 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);
63702
63948
  let meta;
63703
63949
  try {
63704
- meta = JSON.parse(readFileSync68(join53(sourceDir, TEMPLATE_META_FILE), "utf8"));
63950
+ meta = JSON.parse(readFileSync69(join54(sourceDir, TEMPLATE_META_FILE), "utf8"));
63705
63951
  } catch {
63706
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>)` }));
63707
63953
  return 2;
@@ -63711,7 +63957,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63711
63957
  return 2;
63712
63958
  }
63713
63959
  try {
63714
- const appearance = extractTemplateAppearance(JSON.parse(readFileSync68(join53(sourceDir, "tokens.json"), "utf8")));
63960
+ const appearance = extractTemplateAppearance(JSON.parse(readFileSync69(join54(sourceDir, "tokens.json"), "utf8")));
63715
63961
  meta = { ...appearance, ...meta };
63716
63962
  } catch {
63717
63963
  }
@@ -63723,13 +63969,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63723
63969
  const force = flags.force === true;
63724
63970
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
63725
63971
  const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
63726
- const out = mkdtempSync4(join53(tmpdir5(), "himi-template-"));
63972
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-template-"));
63727
63973
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
63728
63974
  const outcome = await buildReleaseFromContent2(buildDir, out, {
63729
63975
  ...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
63730
63976
  collect: { lint: true, strict }
63731
63977
  });
63732
- const scaffoldSourceFindings = resolve44(sourceDir) === resolve44(appDir2) ? [] : [
63978
+ const scaffoldSourceFindings = resolve45(sourceDir) === resolve45(appDir2) ? [] : [
63733
63979
  ...tokenColorIssues(sourceDir),
63734
63980
  ...surfaceIssues(sourceDir, void 0, strict),
63735
63981
  ...await fontIssues(sourceDir, strict),
@@ -63772,13 +64018,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
63772
64018
  }));
63773
64019
  return 1;
63774
64020
  }
63775
- const iconPath = str5(flags.icon) ? resolve44(str5(flags.icon)) : templateIconPath(name);
64021
+ const iconPath = str5(flags.icon) ? resolve45(str5(flags.icon)) : templateIconPath(name);
63776
64022
  let iconHash;
63777
64023
  if (iconPath) {
63778
64024
  try {
63779
- const bytes2 = readFileSync68(iconPath);
64025
+ const bytes2 = readFileSync69(iconPath);
63780
64026
  payload.icon = bytes2.toString("base64");
63781
- iconHash = createHash24("sha256").update(bytes2).digest("hex");
64027
+ iconHash = createHash25("sha256").update(bytes2).digest("hex");
63782
64028
  } catch {
63783
64029
  }
63784
64030
  }
@@ -64009,7 +64255,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64009
64255
  const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
64010
64256
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
64011
64257
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
64012
- const out = mkdtempSync4(join53(tmpdir5(), "himi-validate-"));
64258
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-validate-"));
64013
64259
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64014
64260
  const outcome = await buildReleaseFromContent2(dir, out, {
64015
64261
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -64046,7 +64292,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64046
64292
  const path2 = dpxSessionTokenPath();
64047
64293
  let raw;
64048
64294
  try {
64049
- raw = readFileSync68(path2, "utf8");
64295
+ raw = readFileSync69(path2, "utf8");
64050
64296
  } catch {
64051
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`);
64052
64298
  }
@@ -64163,6 +64409,49 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64163
64409
  print({ ok: invoked.response.ok, app: loaded.app, releaseId: invoked.releaseId, status: invoked.response.status, body });
64164
64410
  return invoked.response.ok ? 0 : 1;
64165
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
+ }
64166
64455
  case "ux": {
64167
64456
  const sub = pos[1] ?? "audit";
64168
64457
  const dir = contentDir(flags);
@@ -64216,7 +64505,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64216
64505
  case "test": {
64217
64506
  const dir = contentDir(flags);
64218
64507
  const structuredOutput = flags.json === true || io.isTTY !== true;
64219
- if (existsSync57(join53(dir, "functions"))) {
64508
+ if (existsSync58(join54(dir, "functions"))) {
64220
64509
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
64221
64510
  const loaded = await loadFunctionsApp2(dir);
64222
64511
  const results = [];
@@ -64303,7 +64592,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64303
64592
  }
64304
64593
  }
64305
64594
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
64306
- const out = mkdtempSync4(join53(tmpdir5(), "himi-test-"));
64595
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-test-"));
64307
64596
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64308
64597
  const outcome = await buildReleaseFromContent2(dir, out, {
64309
64598
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -64348,7 +64637,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64348
64637
  io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
64349
64638
  return 2;
64350
64639
  }
64351
- const sources = collectWorkerSources2(join53(dir, "tier5-src"), screen.bundleName);
64640
+ const sources = collectWorkerSources2(join54(dir, "tier5-src"), screen.bundleName);
64352
64641
  if (!sources) {
64353
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` }));
64354
64643
  return 2;
@@ -64509,7 +64798,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64509
64798
  const sp = await runShotsPass2({
64510
64799
  descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
64511
64800
  tokens: outcome.tokens,
64512
- outDir: join53(dir, ".himi", "shots"),
64801
+ outDir: join54(dir, ".himi", "shots"),
64513
64802
  width: 390,
64514
64803
  layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
64515
64804
  ...budgetMs ? { budgetMs } : {},
@@ -64547,7 +64836,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64547
64836
  releaseId: result.releaseId,
64548
64837
  releasePayload: release,
64549
64838
  descriptors: attestedDescriptors,
64550
- 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)])),
64551
64840
  coverage: {
64552
64841
  screens: crawledScreens.size,
64553
64842
  actionsDispatched: result.actions.exercised,
@@ -64636,7 +64925,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64636
64925
  return 2;
64637
64926
  }
64638
64927
  try {
64639
- const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync68(stateArg.replace(/^@/, ""), "utf8");
64928
+ const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync69(stateArg.replace(/^@/, ""), "utf8");
64640
64929
  injectedState = JSON.parse(raw);
64641
64930
  } catch (e) {
64642
64931
  io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
@@ -64651,7 +64940,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64651
64940
  return 2;
64652
64941
  }
64653
64942
  try {
64654
- const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync68(inputArg.replace(/^@/, ""), "utf8");
64943
+ const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync69(inputArg.replace(/^@/, ""), "utf8");
64655
64944
  const parsed = JSON.parse(raw);
64656
64945
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
64657
64946
  injectedInput = parsed;
@@ -64700,7 +64989,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64700
64989
  }
64701
64990
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
64702
64991
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
64703
- const out = mkdtempSync4(join53(tmpdir5(), "himi-render-"));
64992
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-render-"));
64704
64993
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
64705
64994
  const outcome = await buildReleaseFromContent2(dir, out, {
64706
64995
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -64716,7 +65005,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
64716
65005
  let attestationPngFile;
64717
65006
  if (typeof flags.png === "string" && r.pngBase64) {
64718
65007
  pngFile = writePngFile(str5(flags.png), r.pngBase64);
64719
- attestationPngFile = writePngFile(join53(dir, ".himi", "shots", `${screenId}.png`), r.pngBase64);
65008
+ attestationPngFile = writePngFile(join54(dir, ".himi", "shots", `${screenId}.png`), r.pngBase64);
64720
65009
  }
64721
65010
  if (renderWidth !== void 0 && r.renderable) {
64722
65011
  recordRenderWidth(dir, {
@@ -65040,7 +65329,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65040
65329
  return 2;
65041
65330
  }
65042
65331
  const renamed = str5(flags.name);
65043
- const dest = resolve44(str5(flags.out) ?? process.cwd(), renamed ?? wanted);
65332
+ const dest = resolve45(str5(flags.out) ?? process.cwd(), renamed ?? wanted);
65044
65333
  const replace = flags.replace === true;
65045
65334
  const force = replace || flags.force === true;
65046
65335
  const linked = symlinkDestinationIssue(dest);
@@ -65048,8 +65337,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65048
65337
  io.error(JSON.stringify(linked));
65049
65338
  return 1;
65050
65339
  }
65051
- if (existsSync57(dest)) {
65052
- if (!statSync14(dest).isDirectory()) {
65340
+ if (existsSync58(dest)) {
65341
+ if (!statSync15(dest).isDirectory()) {
65053
65342
  io.error(JSON.stringify({
65054
65343
  error: `${dest} exists and is not a directory`,
65055
65344
  hint: "pass --out/--name to land somewhere else, or remove the file"
@@ -65061,7 +65350,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65061
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" }));
65062
65351
  return 1;
65063
65352
  }
65064
- if (replace && occupied && !existsSync57(join53(dest, "himalaya.content.json"))) {
65353
+ if (replace && occupied && !existsSync58(join54(dest, "himalaya.content.json"))) {
65065
65354
  io.error(JSON.stringify({
65066
65355
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
65067
65356
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -65200,7 +65489,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65200
65489
  const force = flags.force === true;
65201
65490
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65202
65491
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
65203
- const out = mkdtempSync4(join53(tmpdir5(), "himi-push-"));
65492
+ const out = mkdtempSync4(join54(tmpdir5(), "himi-push-"));
65204
65493
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65205
65494
  const outcome = await buildReleaseFromContent2(dir, out, {
65206
65495
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65226,7 +65515,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65226
65515
  const manifest = outcome.manifest;
65227
65516
  const payload = await loadReleaseFromDir(declared, out);
65228
65517
  const { shellQuote: shellQuote2 } = await Promise.resolve().then(() => (init_shell_quote(), shell_quote_exports));
65229
- const contentRel = relative8(process.cwd(), dir) || ".";
65518
+ const contentRel = relative9(process.cwd(), dir) || ".";
65230
65519
  const contentArg = shellQuote2(contentRel);
65231
65520
  if (onlyRaw !== void 0) {
65232
65521
  const onlyDraft = flags.draft === true;
@@ -65288,7 +65577,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65288
65577
  let localSourceHash;
65289
65578
  try {
65290
65579
  const { collectAppSource: collectAppSource2, zipAppSource: zipAppSource2 } = await Promise.resolve().then(() => (init_app_source(), app_source_exports));
65291
- 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");
65292
65581
  } catch {
65293
65582
  }
65294
65583
  return runReleasePatch({
@@ -65671,7 +65960,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65671
65960
  return 2;
65672
65961
  }
65673
65962
  try {
65674
- 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()));
65675
65964
  print({
65676
65965
  ok: true,
65677
65966
  app: res.app,
@@ -65720,7 +66009,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65720
66009
  }
65721
66010
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65722
66011
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
65723
- const built = mkdtempSync4(join53(tmpdir5(), "himi-pack-"));
66012
+ const built = mkdtempSync4(join54(tmpdir5(), "himi-pack-"));
65724
66013
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65725
66014
  const outcome = await buildReleaseFromContent2(dir, built, {
65726
66015
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -65742,7 +66031,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65742
66031
  return 1;
65743
66032
  }
65744
66033
  try {
65745
- const res = writePack(built, app, resolve44(str5(flags.out) ?? dir), sourceArchive);
66034
+ const res = writePack(built, app, resolve45(str5(flags.out) ?? dir), sourceArchive);
65746
66035
  print({
65747
66036
  ok: true,
65748
66037
  app: res.app,
@@ -65787,7 +66076,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65787
66076
  const { HIMI_PACKAGE_SOURCE_PATH: HIMI_PACKAGE_SOURCE_PATH2, isSafeAppId: isSafeAppId2, packageContents: packageContents2 } = await Promise.resolve().then(() => (init_himi_package(), himi_package_exports));
65788
66077
  let opened;
65789
66078
  try {
65790
- opened = openPackageFile2(resolve44(file));
66079
+ opened = openPackageFile2(resolve45(file));
65791
66080
  } catch (e) {
65792
66081
  io.error(JSON.stringify({ error: e.message }));
65793
66082
  return 1;
@@ -65800,7 +66089,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65800
66089
  io.error(JSON.stringify({
65801
66090
  ok: false,
65802
66091
  error: "app_source_not_in_package",
65803
- 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`,
65804
66093
  hint: "re-pack it from the content package with `himi pack --dev`, or restore from the serve plane with `himi pull <app>`"
65805
66094
  }));
65806
66095
  return 1;
@@ -65823,7 +66112,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65823
66112
  return 1;
65824
66113
  }
65825
66114
  }
65826
- 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);
65827
66116
  const issue2 = restoreDestinationIssue(dest, flags.force === true);
65828
66117
  if (issue2) {
65829
66118
  io.error(JSON.stringify(issue2));
@@ -65908,7 +66197,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65908
66197
  }
65909
66198
  try {
65910
66199
  const { openPackageFile: openPackageFile2 } = await Promise.resolve().then(() => (init_pack(), pack_exports));
65911
- const opened = openPackageFile2(resolve44(file));
66200
+ const opened = openPackageFile2(resolve45(file));
65912
66201
  if (!opened.validation.ok || !opened.header) {
65913
66202
  io.error(JSON.stringify({ error: "refusing to share an invalid package", issues: opened.validation.errors }));
65914
66203
  return 1;
@@ -65918,12 +66207,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65918
66207
  io.error(JSON.stringify({
65919
66208
  ok: false,
65920
66209
  error: "refusing to share a package that carries the app's source",
65921
- 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`,
65922
66211
  hint: "share a release package instead (`himi pack` with no --dev), or hand the dev package over directly"
65923
66212
  }));
65924
66213
  return 1;
65925
66214
  }
65926
- const archive = readFileSync68(resolve44(file));
66215
+ const archive = readFileSync69(resolve45(file));
65927
66216
  const result = await client2().createPackageShare({
65928
66217
  app: opened.header.app,
65929
66218
  releaseId: opened.header.releaseId,
@@ -65960,10 +66249,10 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65960
66249
  const app = await appId(dir);
65961
66250
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
65962
66251
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
65963
- temp = mkdtempSync4(join53(tmpdir5(), "himi-run-build-"));
66252
+ temp = mkdtempSync4(join54(tmpdir5(), "himi-run-build-"));
65964
66253
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
65965
66254
  await buildReleaseFromContent2(dir, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {} });
65966
- source = join53(temp, app);
66255
+ source = join54(temp, app);
65967
66256
  }
65968
66257
  const chromeArg = str5(flags.chrome) ?? "preview";
65969
66258
  if (chromeArg !== "preview" && chromeArg !== "app") {
@@ -65988,9 +66277,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
65988
66277
  open: flags["no-open"] !== true
65989
66278
  });
65990
66279
  print({ ok: true, app: run2.app, url: run2.url, port: run2.port, plane: "browser" });
65991
- await new Promise((resolve45) => {
66280
+ await new Promise((resolve46) => {
65992
66281
  const stop = () => {
65993
- void run2.close().finally(() => resolve45());
66282
+ void run2.close().finally(() => resolve46());
65994
66283
  };
65995
66284
  process.once("SIGINT", stop);
65996
66285
  process.once("SIGTERM", stop);
@@ -66567,7 +66856,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66567
66856
  io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
66568
66857
  return 2;
66569
66858
  }
66570
- if (!existsSync57(file)) {
66859
+ if (!existsSync58(file)) {
66571
66860
  io.error(JSON.stringify({ error: `no such file: ${file}` }));
66572
66861
  return 2;
66573
66862
  }
@@ -66623,7 +66912,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66623
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."
66624
66913
  };
66625
66914
  if (kind === "tokens" || kind === "app-config") {
66626
- const body = readFileSync68(file, "utf8");
66915
+ const body = readFileSync69(file, "utf8");
66627
66916
  const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
66628
66917
  return runReleasePatch({
66629
66918
  ...common,
@@ -66638,7 +66927,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66638
66927
  io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
66639
66928
  return 2;
66640
66929
  }
66641
- const descriptor = readFileSync68(file, "utf8");
66930
+ const descriptor = readFileSync69(file, "utf8");
66642
66931
  try {
66643
66932
  JSON.parse(descriptor);
66644
66933
  } catch (e) {
@@ -66678,8 +66967,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66678
66967
  extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
66679
66968
  });
66680
66969
  }
66681
- const bytes2 = readFileSync68(file);
66682
- const sha = createHash24("sha256").update(bytes2).digest("hex");
66970
+ const bytes2 = readFileSync69(file);
66971
+ const sha = createHash25("sha256").update(bytes2).digest("hex");
66683
66972
  const forScreens = (str5(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
66684
66973
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
66685
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 }));
@@ -66822,7 +67111,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
66822
67111
  }
66823
67112
  let def;
66824
67113
  try {
66825
- 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);
66826
67115
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
66827
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}`] }));
66828
67117
  return 2;
@@ -67286,7 +67575,7 @@ ${label2}`);
67286
67575
  const platform = str5(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
67287
67576
  {
67288
67577
  const distDir = contentDir(flags);
67289
- if (existsSync57(join53(distDir, "himalaya.content.json"))) {
67578
+ if (existsSync58(join54(distDir, "himalaya.content.json"))) {
67290
67579
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
67291
67580
  const errors = issues.filter((i) => i.severity === "error");
67292
67581
  for (const i of issues.filter((i2) => i2.severity === "warning")) {
@@ -67555,7 +67844,7 @@ ${label2}`);
67555
67844
  const dpxPath = dpxSessionTokenPath();
67556
67845
  let dpx;
67557
67846
  try {
67558
- dpx = readFileSync68(dpxPath, "utf8").trim();
67847
+ dpx = readFileSync69(dpxPath, "utf8").trim();
67559
67848
  } catch {
67560
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` }));
67561
67850
  return 1;
@@ -67957,7 +68246,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
67957
68246
  const path2 = dpxSessionTokenPath();
67958
68247
  let raw;
67959
68248
  try {
67960
- raw = readFileSync68(path2, "utf8");
68249
+ raw = readFileSync69(path2, "utf8");
67961
68250
  } catch {
67962
68251
  io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
67963
68252
  return 1;