@wix/himalaya-cli 0.1110.0 → 0.1112.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
@@ -994,8 +994,8 @@ function mobileUxDocumentBody(mobile) {
994
994
  }
995
995
  return out2 + mobile.slice(last);
996
996
  }
997
- function mobileUxSection(text6, heading) {
998
- const match = new RegExp(`(?:^|\\n)##[ \\t]+${heading}\\b[^\\n]*([\\s\\S]*?)(?=\\n##[ \\t]|$)`, "i").exec(text6);
997
+ function mobileUxSection(text8, heading) {
998
+ const match = new RegExp(`(?:^|\\n)##[ \\t]+${heading}\\b[^\\n]*([\\s\\S]*?)(?=\\n##[ \\t]|$)`, "i").exec(text8);
999
999
  return match ? match[1] : null;
1000
1000
  }
1001
1001
  function sectionTables(markdown) {
@@ -1024,8 +1024,8 @@ function namesOneCta(cell) {
1024
1024
  if (!cell) return false;
1025
1025
  return !/[,;]|\s\/\s/.test(cell);
1026
1026
  }
1027
- function declaredStates(text6) {
1028
- const contract = section(text6, "Screen contract");
1027
+ function declaredStates(text8) {
1028
+ const contract = section(text8, "Screen contract");
1029
1029
  if (!contract) return [];
1030
1030
  const states = [];
1031
1031
  for (const bullet of contract.matchAll(/^[ \t]*[-*][ \t]*[^:\n]*\bstates?[ \t]*:[ \t]*(\S.*)$/gim)) {
@@ -1035,8 +1035,8 @@ function declaredStates(text6) {
1035
1035
  }
1036
1036
  return [...new Set(states.map((state) => state.toLowerCase()))];
1037
1037
  }
1038
- function primaryCtaStructureGap(text6) {
1039
- const acceptance = section(text6, "Implementation acceptance");
1038
+ function primaryCtaStructureGap(text8) {
1039
+ const acceptance = section(text8, "Implementation acceptance");
1040
1040
  if (acceptance === null) return "There is no `## Implementation acceptance` section to read it from.";
1041
1041
  const tables = sectionTables(acceptance).filter((table) => table.data.length > 0);
1042
1042
  if (!tables.length) return "Its acceptance table has no rows.";
@@ -1049,7 +1049,7 @@ function primaryCtaStructureGap(text6) {
1049
1049
  const data = ctaTables.flatMap(({ table }) => table.data);
1050
1050
  const flat = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
1051
1051
  const rowText = data.map((row) => flat(row.join(" ")));
1052
- const missing = declaredStates(text6).filter((state) => !rowText.some((row) => row.includes(flat(state))));
1052
+ const missing = declaredStates(text8).filter((state) => !rowText.some((row) => row.includes(flat(state))));
1053
1053
  if (missing.length) return `The acceptance table has no row for the declared state(s): ${missing.join(", ")}.`;
1054
1054
  return null;
1055
1055
  }
@@ -1064,16 +1064,16 @@ function hasUnterminatedComment(mobile) {
1064
1064
  }
1065
1065
  }
1066
1066
  function mobileUxMarkerFindings(mobile, renderedWidths = []) {
1067
- const text6 = mobileUxDocumentBody(mobile);
1067
+ const text8 = mobileUxDocumentBody(mobile);
1068
1068
  const findings = [];
1069
- if (!/^## Implementation acceptance\b/im.test(text6)) {
1069
+ if (!/^## Implementation acceptance\b/im.test(text8)) {
1070
1070
  findings.push({ code: "missing-acceptance-matrix", message: "MOBILE-UX.md must contain the heading `## Implementation acceptance` at the start of a line. Case is not checked, but use this spelling: other tooling addresses the document by it." });
1071
1071
  }
1072
- if (!/^## Evidence\b/im.test(text6)) {
1072
+ if (!/^## Evidence\b/im.test(text8)) {
1073
1073
  findings.push({ code: "missing-evidence-section", message: "MOBILE-UX.md must contain the heading `## Evidence` at the start of a line. Case is not checked, but use this spelling: other tooling addresses the document by it." });
1074
1074
  }
1075
- if (!/one primary CTA per state/i.test(text6)) {
1076
- const gap = primaryCtaStructureGap(text6);
1075
+ if (!/one primary CTA per state/i.test(text8)) {
1076
+ const gap = primaryCtaStructureGap(text8);
1077
1077
  if (gap) {
1078
1078
  findings.push({
1079
1079
  code: "missing-primary-cta-rule",
@@ -1081,8 +1081,8 @@ function mobileUxMarkerFindings(mobile, renderedWidths = []) {
1081
1081
  });
1082
1082
  }
1083
1083
  }
1084
- if (!hasWidthEvidence(text6, renderedWidths)) {
1085
- findings.push({ code: "missing-width-evidence", message: widthEvidenceMessage(text6, renderedWidths) });
1084
+ if (!hasWidthEvidence(text8, renderedWidths)) {
1085
+ findings.push({ code: "missing-width-evidence", message: widthEvidenceMessage(text8, renderedWidths) });
1086
1086
  }
1087
1087
  if (findings.length && hasUnterminatedComment(mobile)) {
1088
1088
  return [{
@@ -1092,15 +1092,15 @@ function mobileUxMarkerFindings(mobile, renderedWidths = []) {
1092
1092
  }
1093
1093
  return findings;
1094
1094
  }
1095
- function widthMentions(text6) {
1095
+ function widthMentions(text8) {
1096
1096
  const mentions = [];
1097
- for (const match of text6.matchAll(/\d+/g)) {
1097
+ for (const match of text8.matchAll(/\d+/g)) {
1098
1098
  const value = Number(match[0]);
1099
1099
  const start = match.index ?? 0;
1100
1100
  if (!inRange(value)) continue;
1101
1101
  const end = start + match[0].length;
1102
- const after = text6.slice(end, end + EDGE_WINDOW);
1103
- const before = text6.slice(Math.max(0, start - EDGE_WINDOW), start);
1102
+ const after = text8.slice(end, end + EDGE_WINDOW);
1103
+ const before = text8.slice(Math.max(0, start - EDGE_WINDOW), start);
1104
1104
  if (looksLikeYear(value) && !(UNIT_ATTACHED.test(after) || UNIT_WORD_ATTACHED.test(after))) continue;
1105
1105
  const spelledAsWidth = UNIT_ATTACHED.test(after) || UNIT_WORD_ATTACHED.test(after) || FILENAME_AFTER.test(after);
1106
1106
  const vetoed = spelledAsWidth && (ANTI_CUE_BEFORE.test(before) || PAIR_HEIGHT_BEFORE.test(before) || ANTI_CUE_AFTER.test(after));
@@ -2093,7 +2093,7 @@ function foldLegacyReport(legacy, seed2) {
2093
2093
  ...arrayField(legacy.failures),
2094
2094
  ...arrayField(legacy.warnings)
2095
2095
  ];
2096
- const report2 = emptyReport({
2096
+ const report3 = emptyReport({
2097
2097
  ...seed2,
2098
2098
  ok: typeof legacy.ok === "boolean" ? legacy.ok : seed2.ok,
2099
2099
  app: seed2.app ?? stringField(legacy.app),
@@ -2104,12 +2104,12 @@ function foldLegacyReport(legacy, seed2) {
2104
2104
  const oldCounts = recordField(legacy.counts);
2105
2105
  return {
2106
2106
  ...legacy,
2107
- ...report2,
2107
+ ...report3,
2108
2108
  counts: {
2109
2109
  ...oldCounts,
2110
- errors: numberField(oldCounts.errors) ?? report2.counts.errors,
2111
- warnings: numberField(oldCounts.warnings) ?? report2.counts.warnings,
2112
- gaps: report2.counts.gaps
2110
+ errors: numberField(oldCounts.errors) ?? report3.counts.errors,
2111
+ warnings: numberField(oldCounts.warnings) ?? report3.counts.warnings,
2112
+ gaps: report3.counts.gaps
2113
2113
  }
2114
2114
  };
2115
2115
  }
@@ -2773,8 +2773,8 @@ function isAttestationV2(value) {
2773
2773
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2774
2774
  const a = value;
2775
2775
  const coverage = a.coverage;
2776
- const report2 = a.report;
2777
- return a.attestation === 2 && typeof a.runId === "string" && ["himi-test", "himi-render", "himi-shots"].includes(a.tool) && [a.app, a.contentDir, a.gitDiffHash, a.gitUntrackedHash, a.releaseId, a.releaseHash, a.selfHash].every((item) => typeof item === "string" && item.length > 0) && stringRecord(a.descriptorHashes) && stringRecord(a.screenshots) && !!coverage && [coverage.screens, coverage.actionsDispatched, coverage.uncoveredFns, coverage.gaps].every((count2) => typeof count2 === "number" && Number.isFinite(count2) && count2 >= 0) && typeof report2?.ok === "boolean" && !!report2.counts && [report2.counts.errors, report2.counts.warnings, report2.counts.gaps].every((count2) => typeof count2 === "number" && Number.isFinite(count2) && count2 >= 0) && (a.prev === null || typeof a.prev === "string");
2776
+ const report3 = a.report;
2777
+ return a.attestation === 2 && typeof a.runId === "string" && ["himi-test", "himi-render", "himi-shots"].includes(a.tool) && [a.app, a.contentDir, a.gitDiffHash, a.gitUntrackedHash, a.releaseId, a.releaseHash, a.selfHash].every((item) => typeof item === "string" && item.length > 0) && stringRecord(a.descriptorHashes) && stringRecord(a.screenshots) && !!coverage && [coverage.screens, coverage.actionsDispatched, coverage.uncoveredFns, coverage.gaps].every((count2) => typeof count2 === "number" && Number.isFinite(count2) && count2 >= 0) && typeof report3?.ok === "boolean" && !!report3.counts && [report3.counts.errors, report3.counts.warnings, report3.counts.gaps].every((count2) => typeof count2 === "number" && Number.isFinite(count2) && count2 >= 0) && (a.prev === null || typeof a.prev === "string");
2778
2778
  }
2779
2779
  function readLatestAttestation(contentDir2) {
2780
2780
  try {
@@ -3170,8 +3170,8 @@ function penalty(m, size) {
3170
3170
  score += Math.floor(Math.abs(dark * 20 - total * 10) / total) * 10;
3171
3171
  return score;
3172
3172
  }
3173
- function encodeQr(text6) {
3174
- const bytes2 = [...new TextEncoder().encode(text6)];
3173
+ function encodeQr(text8) {
3174
+ const bytes2 = [...new TextEncoder().encode(text8)];
3175
3175
  const version2 = fitVersion(bytes2.length);
3176
3176
  if (!version2) {
3177
3177
  throw new RangeError(`QR payload too long: ${bytes2.length} bytes exceeds version ${QR_MAX_VERSION} at EC level L`);
@@ -3742,7 +3742,7 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
3742
3742
  tokenCache.set(cacheKey, fromEnv);
3743
3743
  return fromEnv;
3744
3744
  }
3745
- const token = await new Promise((resolve52, reject) => {
3745
+ const token = await new Promise((resolve53, reject) => {
3746
3746
  let child;
3747
3747
  try {
3748
3748
  child = spawnImpl("wix", [...args]);
@@ -3771,12 +3771,12 @@ async function mintToken(args, label2, cacheKey, spawnImpl) {
3771
3771
  child.stdout?.on("data", (d) => {
3772
3772
  out2 += String(d);
3773
3773
  const m = out2.match(TOKEN_RE);
3774
- if (m) done(() => resolve52(m[0]));
3774
+ if (m) done(() => resolve53(m[0]));
3775
3775
  });
3776
3776
  child.stderr?.on("data", (d) => {
3777
3777
  out2 += String(d);
3778
3778
  const m = out2.match(TOKEN_RE);
3779
- if (m) done(() => resolve52(m[0]));
3779
+ if (m) done(() => resolve53(m[0]));
3780
3780
  });
3781
3781
  child.on("error", (e) => done(() => reject(new Error(mintHelp(label2, e.message)))));
3782
3782
  child.on("exit", (code) => done(() => reject(new Error(
@@ -3821,10 +3821,10 @@ function ownerTransport(msid, fetchImpl = fetch, timeoutMs = DEFAULT_TIMEOUT_MS2
3821
3821
  }
3822
3822
  throw new Error(`${method} ${path2} failed: ${err?.message ?? String(e)}`);
3823
3823
  }
3824
- const text6 = await res.text();
3825
- let parsed = text6;
3824
+ const text8 = await res.text();
3825
+ let parsed = text8;
3826
3826
  try {
3827
- parsed = text6 ? JSON.parse(text6) : null;
3827
+ parsed = text8 ? JSON.parse(text8) : null;
3828
3828
  } catch {
3829
3829
  }
3830
3830
  if (!res.ok) throw new WixApiError(res.status, method, path2, parsed);
@@ -4486,18 +4486,18 @@ function confinementPlugin(contentRoot) {
4486
4486
  }
4487
4487
  function assertConfinedTsconfig(entry, contentRoot, allows) {
4488
4488
  const seen = /* @__PURE__ */ new Set();
4489
- const refuse4 = (p, why) => {
4489
+ const refuse5 = (p, why) => {
4490
4490
  throw new Error(
4491
4491
  `refused to read ${p}: ${why}. A tsconfig may extend a file from its own package or an installed dependency \u2014 nothing else.`
4492
4492
  );
4493
4493
  };
4494
- const stripJsonc = (text6) => {
4495
- if (text6.charCodeAt(0) === 65279) text6 = text6.slice(1);
4494
+ const stripJsonc = (text8) => {
4495
+ if (text8.charCodeAt(0) === 65279) text8 = text8.slice(1);
4496
4496
  let out2 = "";
4497
4497
  let inStr = false;
4498
4498
  let esc = false;
4499
- for (let i = 0; i < text6.length; i++) {
4500
- const c = text6[i];
4499
+ for (let i = 0; i < text8.length; i++) {
4500
+ const c = text8[i];
4501
4501
  if (inStr) {
4502
4502
  out2 += c;
4503
4503
  if (esc) esc = false;
@@ -4510,13 +4510,13 @@ function assertConfinedTsconfig(entry, contentRoot, allows) {
4510
4510
  out2 += c;
4511
4511
  continue;
4512
4512
  }
4513
- if (c === "/" && text6[i + 1] === "/") {
4514
- while (i < text6.length && text6[i] !== "\n") i++;
4513
+ if (c === "/" && text8[i + 1] === "/") {
4514
+ while (i < text8.length && text8[i] !== "\n") i++;
4515
4515
  continue;
4516
4516
  }
4517
- if (c === "/" && text6[i + 1] === "*") {
4517
+ if (c === "/" && text8[i + 1] === "*") {
4518
4518
  i += 2;
4519
- while (i < text6.length && !(text6[i] === "*" && text6[i + 1] === "/")) i++;
4519
+ while (i < text8.length && !(text8[i] === "*" && text8[i + 1] === "/")) i++;
4520
4520
  i++;
4521
4521
  continue;
4522
4522
  }
@@ -4552,7 +4552,7 @@ function assertConfinedTsconfig(entry, contentRoot, allows) {
4552
4552
  try {
4553
4553
  manifest = JSON.parse(stripJsonc(readFileSync10(pj, "utf8")));
4554
4554
  } catch {
4555
- refuse4(pj, "its package.json could not be parsed, so its `tsconfig` field cannot be checked");
4555
+ refuse5(pj, "its package.json could not be parsed, so its `tsconfig` field cannot be checked");
4556
4556
  }
4557
4557
  const field = manifest?.tsconfig;
4558
4558
  if (typeof field === "string" && field) {
@@ -4568,7 +4568,7 @@ function assertConfinedTsconfig(entry, contentRoot, allows) {
4568
4568
  const real = realpathOrSelf(file);
4569
4569
  if (seen.has(real)) return;
4570
4570
  seen.add(real);
4571
- if (!allows(real)) refuse4(file, "it is outside this content package");
4571
+ if (!allows(real)) refuse5(file, "it is outside this content package");
4572
4572
  let raw;
4573
4573
  try {
4574
4574
  raw = readFileSync10(real, "utf8");
@@ -4579,7 +4579,7 @@ function assertConfinedTsconfig(entry, contentRoot, allows) {
4579
4579
  try {
4580
4580
  parsed = JSON.parse(stripJsonc(raw));
4581
4581
  } catch {
4582
- refuse4(file, "its tsconfig could not be parsed, so its `extends` cannot be checked");
4582
+ refuse5(file, "its tsconfig could not be parsed, so its `extends` cannot be checked");
4583
4583
  }
4584
4584
  const ext = parsed?.extends;
4585
4585
  for (const one of Array.isArray(ext) ? ext : ext ? [ext] : []) {
@@ -8420,8 +8420,8 @@ function pushSpan(out2, s) {
8420
8420
  else out2.push(s);
8421
8421
  }
8422
8422
  function spanOf(textNode) {
8423
- const text6 = str(at(textNode, "textData", "text"));
8424
- if (text6 === "") return null;
8423
+ const text8 = str(at(textNode, "textData", "text"));
8424
+ if (text8 === "") return null;
8425
8425
  let bold = false, italic = false, underline = false;
8426
8426
  let link;
8427
8427
  const decorations = at(textNode, "textData", "decorations");
@@ -8448,7 +8448,7 @@ function spanOf(textNode) {
8448
8448
  }
8449
8449
  }
8450
8450
  }
8451
- const span = { text: text6 };
8451
+ const span = { text: text8 };
8452
8452
  if (bold) span.bold = true;
8453
8453
  if (italic) span.italic = true;
8454
8454
  if (underline) span.underline = true;
@@ -8670,8 +8670,8 @@ function blockOf(ids, n, path2) {
8670
8670
  const { title, url } = cardFields(n, type);
8671
8671
  return [card(ids.claim(n, path2), type, title, url)];
8672
8672
  }
8673
- const text6 = plainText(n);
8674
- return text6.trim() !== "" ? [{ kind: "paragraph", id: ids.claim(n, path2), spans: [{ text: text6 }] }] : [];
8673
+ const text8 = plainText(n);
8674
+ return text8.trim() !== "" ? [{ kind: "paragraph", id: ids.claim(n, path2), spans: [{ text: text8 }] }] : [];
8675
8675
  }
8676
8676
  }
8677
8677
  }
@@ -9942,26 +9942,26 @@ function serviceOnlyBindingValues(props, key2) {
9942
9942
  });
9943
9943
  return out2;
9944
9944
  }
9945
- function matchBraceSafe(text6, open) {
9945
+ function matchBraceSafe(text8, open) {
9946
9946
  let depth = 0;
9947
- for (let i = open; i < text6.length; i++) {
9948
- const c = text6[i];
9947
+ for (let i = open; i < text8.length; i++) {
9948
+ const c = text8[i];
9949
9949
  if (c === '"' || c === "'" || c === "`") {
9950
9950
  const q = c;
9951
9951
  i++;
9952
- while (i < text6.length && text6[i] !== q) {
9953
- if (text6[i] === "\\") i++;
9952
+ while (i < text8.length && text8[i] !== q) {
9953
+ if (text8[i] === "\\") i++;
9954
9954
  i++;
9955
9955
  }
9956
9956
  continue;
9957
9957
  }
9958
- if (c === "/" && text6[i + 1] === "/") {
9959
- while (i < text6.length && text6[i] !== "\n") i++;
9958
+ if (c === "/" && text8[i + 1] === "/") {
9959
+ while (i < text8.length && text8[i] !== "\n") i++;
9960
9960
  continue;
9961
9961
  }
9962
- if (c === "/" && text6[i + 1] === "*") {
9962
+ if (c === "/" && text8[i + 1] === "*") {
9963
9963
  i += 2;
9964
- while (i < text6.length && !(text6[i] === "*" && text6[i + 1] === "/")) i++;
9964
+ while (i < text8.length && !(text8[i] === "*" && text8[i + 1] === "/")) i++;
9965
9965
  i++;
9966
9966
  continue;
9967
9967
  }
@@ -12909,8 +12909,8 @@ var init_owner_claim = __esm({
12909
12909
 
12910
12910
  // ../native-config/car.ts
12911
12911
  function parseCarConfig(configTs) {
12912
- const { text: text6, inString } = scanConfig(configTs);
12913
- for (const m of text6.matchAll(/\bcar\s*[:=]\s*\{([^}]*)\}/g)) {
12912
+ const { text: text8, inString } = scanConfig(configTs);
12913
+ for (const m of text8.matchAll(/\bcar\s*[:=]\s*\{([^}]*)\}/g)) {
12914
12914
  if (inString[m.index]) continue;
12915
12915
  return { category: /category\s*:\s*["']([^"']+)["']/.exec(m[1])?.[1] };
12916
12916
  }
@@ -17996,12 +17996,12 @@ function hostAppliesDeferredWidgetActions(app) {
17996
17996
  }
17997
17997
  return false;
17998
17998
  }
17999
- function hasMarkers(text6, kind, label2) {
18000
- const lines = text6.split("\n");
17999
+ function hasMarkers(text8, kind, label2) {
18000
+ const lines = text8.split("\n");
18001
18001
  return lines.some((l) => isBegin(l, kind, label2)) && lines.some((l) => isEnd(l, kind, label2));
18002
18002
  }
18003
- function injectBlock(text6, kind, label2, render) {
18004
- const lines = text6.split("\n");
18003
+ function injectBlock(text8, kind, label2, render) {
18004
+ const lines = text8.split("\n");
18005
18005
  const beginIdx = lines.findIndex((l) => isBegin(l, kind, label2));
18006
18006
  const endIdx = lines.findIndex((l) => isEnd(l, kind, label2));
18007
18007
  if (beginIdx === -1 || endIdx === -1 || endIdx < beginIdx) {
@@ -18116,8 +18116,8 @@ function genNativeConfig(app, opts = {}) {
18116
18116
  ];
18117
18117
  const rce = declaresRichContentEditor(configTs);
18118
18118
  for (const yml of [iosYml, macosProjectYml(app)]) {
18119
- const text6 = existsSync26(yml) ? readFileSync26(yml, "utf8") : "";
18120
- const r = applyToFile(yml, "yaml", LABEL_LOCALWEB, renderLocalWebYaml(resourcesDirOf(text6), rce), check);
18119
+ const text8 = existsSync26(yml) ? readFileSync26(yml, "utf8") : "";
18120
+ const r = applyToFile(yml, "yaml", LABEL_LOCALWEB, renderLocalWebYaml(resourcesDirOf(text8), rce), check);
18121
18121
  if (existsSync26(yml)) assertLocalWebBlockLanded(app, rce, yml, r.outcome);
18122
18122
  files.push(r);
18123
18123
  }
@@ -18527,21 +18527,21 @@ function carryPlanningJournal(parentDir, appDir3) {
18527
18527
  return carried;
18528
18528
  }
18529
18529
  function formatBrief(input) {
18530
- const { summary, open } = input;
18530
+ const { summary: summary2, open } = input;
18531
18531
  const who = `himi \u2014 ${input.appName ?? "this folder"}`;
18532
18532
  const lines = [];
18533
- if (!summary.count) {
18533
+ if (!summary2.count) {
18534
18534
  lines.push(`${who}: no journey journal yet (${PROGRESS_FILE.split(sep6).join("/")}).`);
18535
18535
  lines.push(
18536
18536
  'A new app starts with discovery (step 1). An app built before journaling existed continues from its current state instead: confirm with the customer that its SPEC.md was approved rather than re-running discovery. Either way, journal each milestone with `himi progress "<what changed>" --step <n>` so the next session can pick up from it.'
18537
18537
  );
18538
18538
  } else {
18539
- const at2 = summary.current ? `journey step ${summary.current.stepNumber}/${summary.current.of} (${summary.current.step})` : "no journey step recorded yet";
18540
- lines.push(`${who}: ${at2} \xB7 ${summary.count} postcard${summary.count === 1 ? "" : "s"} since ${minute(summary.startedAt)}.`);
18541
- if (summary.last) lines.push(`Last postcard (${minute(summary.last.ts)}): ${summary.last.message}`);
18542
- const pastPlan = (summary.current?.stepNumber ?? 0) > JOURNEY_STEPS.indexOf("plan") + 1;
18539
+ const at2 = summary2.current ? `journey step ${summary2.current.stepNumber}/${summary2.current.of} (${summary2.current.step})` : "no journey step recorded yet";
18540
+ lines.push(`${who}: ${at2} \xB7 ${summary2.count} postcard${summary2.count === 1 ? "" : "s"} since ${minute(summary2.startedAt)}.`);
18541
+ if (summary2.last) lines.push(`Last postcard (${minute(summary2.last.ts)}): ${summary2.last.message}`);
18542
+ const pastPlan = (summary2.current?.stepNumber ?? 0) > JOURNEY_STEPS.indexOf("plan") + 1;
18543
18543
  lines.push(
18544
- !summary.current ? "No journey step recorded yet: a new app starts with discovery (step 1); one whose SPEC.md the customer approved continues from its current state. `himi progress` prints every postcard." : pastPlan ? `Resume at step ${summary.current.stepNumber}. Do not restart discovery: the approved plan is SPEC.md + MOBILE-UX.md.` : `Resume at step ${summary.current.stepNumber}. Implementation has not started: treat SPEC.md + MOBILE-UX.md as a draft unless the journal records the customer approving them.`
18544
+ !summary2.current ? "No journey step recorded yet: a new app starts with discovery (step 1); one whose SPEC.md the customer approved continues from its current state. `himi progress` prints every postcard." : pastPlan ? `Resume at step ${summary2.current.stepNumber}. Do not restart discovery: the approved plan is SPEC.md + MOBILE-UX.md.` : `Resume at step ${summary2.current.stepNumber}. Implementation has not started: treat SPEC.md + MOBILE-UX.md as a draft unless the journal records the customer approving them.`
18545
18545
  );
18546
18546
  }
18547
18547
  if (open.length) {
@@ -19465,10 +19465,10 @@ var init_preview = __esm({
19465
19465
  }
19466
19466
  },
19467
19467
  kill: (pid, signal) => process.kill(pid, signal),
19468
- portFree: (port) => new Promise((resolve52) => {
19468
+ portFree: (port) => new Promise((resolve53) => {
19469
19469
  const s = createServer2();
19470
- s.once("error", () => resolve52(false));
19471
- s.listen(port, "127.0.0.1", () => s.close(() => resolve52(true)));
19470
+ s.once("error", () => resolve53(false));
19471
+ s.listen(port, "127.0.0.1", () => s.close(() => resolve53(true)));
19472
19472
  }),
19473
19473
  sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
19474
19474
  servingIdentity: async (origin) => {
@@ -19652,17 +19652,17 @@ ${BLOCK_END}`;
19652
19652
  ${block}
19653
19653
  `;
19654
19654
  }
19655
- function markersIntact(text6) {
19656
- const begins = text6.split(BLOCK_BEGIN).length - 1;
19657
- const ends = text6.split(BLOCK_END).length - 1;
19655
+ function markersIntact(text8) {
19656
+ const begins = text8.split(BLOCK_BEGIN).length - 1;
19657
+ const ends = text8.split(BLOCK_END).length - 1;
19658
19658
  if (begins === 0 && ends === 0) return true;
19659
- return begins === 1 && ends === 1 && text6.indexOf(BLOCK_BEGIN) < text6.indexOf(BLOCK_END) && BLOCK_RE.test(text6);
19659
+ return begins === 1 && ends === 1 && text8.indexOf(BLOCK_BEGIN) < text8.indexOf(BLOCK_END) && BLOCK_RE.test(text8);
19660
19660
  }
19661
- function withoutBlock(text6) {
19662
- const m = BLOCK_RE.exec(text6);
19663
- if (!m) return text6;
19664
- const before = text6.slice(0, m.index).replace(/\n+$/, "");
19665
- const after = text6.slice(m.index + m[0].length).replace(/^\n+/, "");
19661
+ function withoutBlock(text8) {
19662
+ const m = BLOCK_RE.exec(text8);
19663
+ if (!m) return text8;
19664
+ const before = text8.slice(0, m.index).replace(/\n+$/, "");
19665
+ const after = text8.slice(m.index + m[0].length).replace(/^\n+/, "");
19666
19666
  if (!before) return after;
19667
19667
  if (!after) return `${before}
19668
19668
  `;
@@ -19670,8 +19670,8 @@ function withoutBlock(text6) {
19670
19670
 
19671
19671
  ${after}`;
19672
19672
  }
19673
- function blockVersion(text6) {
19674
- return STAMP_RE.exec(text6)?.[1] ?? null;
19673
+ function blockVersion(text8) {
19674
+ return STAMP_RE.exec(text8)?.[1] ?? null;
19675
19675
  }
19676
19676
  function agentsMdBody(appName2) {
19677
19677
  const gates = APPROVAL_GATES.map((g) => `- \`${g.id}\` \u2014 ${g.label}`).join("\n");
@@ -20612,7 +20612,7 @@ async function injectRequest(listener, request) {
20612
20612
  req.headers.host ??= url.host;
20613
20613
  if (body && body.length > 0) req.push(body);
20614
20614
  req.push(null);
20615
- return await new Promise((resolve52, reject) => {
20615
+ return await new Promise((resolve53, reject) => {
20616
20616
  const streamed = () => {
20617
20617
  queueMicrotask(() => {
20618
20618
  req.emit("close");
@@ -20628,7 +20628,7 @@ async function injectRequest(listener, request) {
20628
20628
  else headers2.set(name, value);
20629
20629
  }
20630
20630
  const bodyless = out2.status === 204 || out2.status === 304 || request.method === "HEAD";
20631
- resolve52(new Response(bodyless ? null : out2.body, { status: out2.status, headers: headers2 }));
20631
+ resolve53(new Response(bodyless ? null : out2.body, { status: out2.status, headers: headers2 }));
20632
20632
  }, streamed);
20633
20633
  res.on("inject-error", reject);
20634
20634
  try {
@@ -21166,8 +21166,8 @@ async function postJson(path2, body, auth) {
21166
21166
  headers: { "Content-Type": "application/json", ...auth ? { Authorization: auth } : {} },
21167
21167
  body: JSON.stringify(body)
21168
21168
  });
21169
- const text6 = await res.text();
21170
- return { status: res.status, json: text6 ? JSON.parse(text6) : {} };
21169
+ const text8 = await res.text();
21170
+ return { status: res.status, json: text8 ? JSON.parse(text8) : {} };
21171
21171
  }
21172
21172
  async function mintVisitor(clientId) {
21173
21173
  const r = await postJson("/oauth2/token", { clientId, grantType: "anonymous" });
@@ -21413,13 +21413,13 @@ function recordWixTraffic(gw, app, adminUrl, ev) {
21413
21413
  full.respBody = truncate(redactBodyString(full.respBody));
21414
21414
  gw.traffic.push(full);
21415
21415
  if (gw.traffic.length > TRAFFIC_CAP) gw.traffic.splice(0, gw.traffic.length - TRAFFIC_CAP);
21416
- const text6 = `event: wix.traffic
21416
+ const text8 = `event: wix.traffic
21417
21417
  data: ${JSON.stringify(full)}
21418
21418
 
21419
21419
  `;
21420
21420
  for (const res of [...gw.clients]) {
21421
21421
  try {
21422
- res.write(text6);
21422
+ res.write(text8);
21423
21423
  } catch {
21424
21424
  gw.clients.delete(res);
21425
21425
  }
@@ -21781,10 +21781,10 @@ async function mintAnonymousVisitor(clientId, fetchImpl = fetch) {
21781
21781
  headers: { "Content-Type": "application/json" },
21782
21782
  body: JSON.stringify({ clientId, grantType: "anonymous" })
21783
21783
  });
21784
- const text6 = await res.text();
21784
+ const text8 = await res.text();
21785
21785
  let j = {};
21786
21786
  try {
21787
- j = text6 ? JSON.parse(text6) : {};
21787
+ j = text8 ? JSON.parse(text8) : {};
21788
21788
  } catch {
21789
21789
  }
21790
21790
  if (res.status !== 200 || !j.access_token) throw new Error(`visitor mint failed (${res.status})`);
@@ -21948,10 +21948,10 @@ ${session}`);
21948
21948
  }),
21949
21949
  timedOut
21950
21950
  ]);
21951
- const text6 = await Promise.race([res.text(), timedOut]);
21951
+ const text8 = await Promise.race([res.text(), timedOut]);
21952
21952
  let j = {};
21953
21953
  try {
21954
- j = text6 ? JSON.parse(text6) : {};
21954
+ j = text8 ? JSON.parse(text8) : {};
21955
21955
  } catch {
21956
21956
  }
21957
21957
  if (res.status < 200 || res.status >= 300 || !j.signedInstance)
@@ -22302,9 +22302,9 @@ var init_images = __esm({
22302
22302
  });
22303
22303
 
22304
22304
  // ../../core/dev-server/src/l10n-catalog.ts
22305
- function parseCatalog(text6) {
22305
+ function parseCatalog(text8) {
22306
22306
  try {
22307
- const c = JSON.parse(text6);
22307
+ const c = JSON.parse(text8);
22308
22308
  return c && typeof c === "object" && c.messages && typeof c.messages === "object" ? c : void 0;
22309
22309
  } catch {
22310
22310
  return void 0;
@@ -22785,9 +22785,9 @@ async function getAndroidPixelDims(serial) {
22785
22785
  try {
22786
22786
  const args = serial ? ["-s", serial, "shell", "wm", "size"] : ["shell", "wm", "size"];
22787
22787
  const out2 = await runner.capture(ADB_BIN, args);
22788
- const text6 = out2.toString("utf8");
22789
- const override = /Override size:\s*(\d+)x(\d+)/.exec(text6);
22790
- const physical = /Physical size:\s*(\d+)x(\d+)/.exec(text6);
22788
+ const text8 = out2.toString("utf8");
22789
+ const override = /Override size:\s*(\d+)x(\d+)/.exec(text8);
22790
+ const physical = /Physical size:\s*(\d+)x(\d+)/.exec(text8);
22791
22791
  const m = override ?? physical;
22792
22792
  if (!m) throw new Error("could not parse wm size");
22793
22793
  const dims = { width: parseInt(m[1], 10), height: parseInt(m[2], 10) };
@@ -23162,12 +23162,12 @@ function finalizeRecording(key2, rec) {
23162
23162
  if (rec.finalize) return rec.finalize;
23163
23163
  rec.finalize = (async () => {
23164
23164
  clearTimeout(rec.autoStop);
23165
- await new Promise((resolve52) => {
23165
+ await new Promise((resolve53) => {
23166
23166
  let done = false;
23167
23167
  const finish2 = () => {
23168
23168
  if (!done) {
23169
23169
  done = true;
23170
- resolve52();
23170
+ resolve53();
23171
23171
  }
23172
23172
  };
23173
23173
  rec.child.once("close", finish2);
@@ -23278,7 +23278,7 @@ var init_preview2 = __esm({
23278
23278
  DEVICE_LIST_TIMEOUT_MS = 5e3;
23279
23279
  defaultRunner2 = {
23280
23280
  capture(cmd, args, timeoutMs = DEFAULT_CAPTURE_TIMEOUT_MS) {
23281
- return new Promise((resolve52, reject) => {
23281
+ return new Promise((resolve53, reject) => {
23282
23282
  const child = spawn4(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
23283
23283
  const out2 = [];
23284
23284
  const err = [];
@@ -23300,7 +23300,7 @@ var init_preview2 = __esm({
23300
23300
  child.stderr.on("data", (b) => err.push(b));
23301
23301
  child.on("error", (e) => settle(reject, e));
23302
23302
  child.on("close", (code) => {
23303
- if (code === 0) settle(resolve52, Buffer.concat(out2));
23303
+ if (code === 0) settle(resolve53, Buffer.concat(out2));
23304
23304
  else settle(reject, new Error(`${cmd} exited ${code}: ${Buffer.concat(err).toString("utf8")}`));
23305
23305
  });
23306
23306
  });
@@ -23720,7 +23720,7 @@ function buildOpenApi(descriptors) {
23720
23720
  // Widgets
23721
23721
  "/__dev/widget/preview": ["get", "Render a frozen widget snapshot."]
23722
23722
  };
23723
- for (const [p, [method, summary]] of Object.entries(control)) {
23723
+ for (const [p, [method, summary2]] of Object.entries(control)) {
23724
23724
  const responses = p === "/__dev/render" ? {
23725
23725
  "200": { description: "completed render (legacy mode, or clean envelope verdict)" },
23726
23726
  "400": { description: "invalid_json" },
@@ -23728,7 +23728,7 @@ function buildOpenApi(descriptors) {
23728
23728
  "422": { description: "completed render with a failing envelope:1 verdict" },
23729
23729
  "503": { description: "dev plane unavailable" }
23730
23730
  } : { "200": { description: "ok" } };
23731
- paths[p] = { [method]: { summary, responses } };
23731
+ paths[p] = { [method]: { summary: summary2, responses } };
23732
23732
  }
23733
23733
  for (const scope of ["net", "wix"]) {
23734
23734
  paths[`/__dev/${scope}/rules`] = {
@@ -24156,9 +24156,9 @@ function mdScan(src, linkStyle = "") {
24156
24156
  }
24157
24157
  return out2 + mdEsc(src.slice(last));
24158
24158
  }
24159
- function mdInline(text6, linkColor) {
24159
+ function mdInline(text8, linkColor) {
24160
24160
  const safe = typeof linkColor === "string" && /^[#a-zA-Z0-9(),.%\s-]+$/.test(linkColor) ? linkColor : "";
24161
- return { __html: mdScan(text6, safe ? ` style="color:${safe}"` : "") };
24161
+ return { __html: mdScan(text8, safe ? ` style="color:${safe}"` : "") };
24162
24162
  }
24163
24163
  function sevColor(ctx, sev) {
24164
24164
  switch (sev) {
@@ -27527,9 +27527,9 @@ function createRicosHostSession(o) {
27527
27527
  if (!state.ready || state.unavailable) return;
27528
27528
  o.send({ v: 1, type: "command", name, ...arg?.level ? { level: arg.level } : {}, ...arg?.value ? { value: arg.value } : {} });
27529
27529
  },
27530
- insertLink(url, text6) {
27530
+ insertLink(url, text8) {
27531
27531
  if (!state.ready || state.unavailable || !isSafeEditorLink(url)) return false;
27532
- o.send({ v: 1, type: "insertLink", url: url.trim(), ...text6 ? { text: text6 } : {} });
27532
+ o.send({ v: 1, type: "insertLink", url: url.trim(), ...text8 ? { text: text8 } : {} });
27533
27533
  return true;
27534
27534
  },
27535
27535
  removeLink() {
@@ -27552,12 +27552,12 @@ function createRicosHostSession(o) {
27552
27552
  flush() {
27553
27553
  if (!state.ready || state.unavailable || disposed) return Promise.resolve(null);
27554
27554
  const requestId2 = newId();
27555
- return new Promise((resolve52) => {
27555
+ return new Promise((resolve53) => {
27556
27556
  const timer = t.setTimeout(() => {
27557
27557
  flushes.delete(requestId2);
27558
- resolve52(null);
27558
+ resolve53(null);
27559
27559
  }, flushMs);
27560
- flushes.set(requestId2, { resolve: resolve52, timer });
27560
+ flushes.set(requestId2, { resolve: resolve53, timer });
27561
27561
  o.send({ v: 1, type: "requestContent", requestId: requestId2 });
27562
27562
  });
27563
27563
  },
@@ -27610,7 +27610,7 @@ async function runRicosImageUpload(o) {
27610
27610
  };
27611
27611
  session.insertMediaPlaceholder(requestId2);
27612
27612
  try {
27613
- const entry = await new Promise((resolve52) => {
27613
+ const entry = await new Promise((resolve53) => {
27614
27614
  let done = false;
27615
27615
  let unsub = () => {
27616
27616
  };
@@ -27619,7 +27619,7 @@ async function runRicosImageUpload(o) {
27619
27619
  done = true;
27620
27620
  t.clearTimeout(timer);
27621
27621
  queueMicrotask(() => unsub());
27622
- resolve52(v);
27622
+ resolve53(v);
27623
27623
  };
27624
27624
  const timer = t.setTimeout(() => finish2(null), o.timeoutMs ?? RICOS_UPLOAD_TIMEOUT_MS);
27625
27625
  unsub = deps.subscribe(`${svc}.uploads.${requestId2}`, (v) => {
@@ -29226,13 +29226,13 @@ function NamedImage({ node, alt, env }) {
29226
29226
  }
29227
29227
  function Block({ b, env, depth }) {
29228
29228
  const { ctx } = env;
29229
- const text6 = ctx.color("textPrimary", "#13171e");
29229
+ const text8 = ctx.color("textPrimary", "#13171e");
29230
29230
  const secondary = ctx.color("textSecondary", "#5c6370");
29231
29231
  const border = ctx.color("border", "#e5e5e5");
29232
29232
  switch (b.kind) {
29233
29233
  case "paragraph":
29234
29234
  return /* @__PURE__ */ jsx7("p", { ...tid(env, b.id, b.kind), style: {
29235
- ...textStyle(ctx, "body", text6),
29235
+ ...textStyle(ctx, "body", text8),
29236
29236
  textAlign: b.align,
29237
29237
  paddingInlineStart: b.indent ? Math.min(b.indent, 8) * 16 : void 0,
29238
29238
  minHeight: b.spans.length ? void 0 : "1.5em"
@@ -29240,7 +29240,7 @@ function Block({ b, env, depth }) {
29240
29240
  case "heading":
29241
29241
  return React6.createElement(
29242
29242
  `h${b.level}`,
29243
- { ...tid(env, b.id, b.kind), style: textStyle(ctx, RICH_CONTENT_HEADING_TOKENS[b.level - 1], text6) },
29243
+ { ...tid(env, b.id, b.kind), style: textStyle(ctx, RICH_CONTENT_HEADING_TOKENS[b.level - 1], text8) },
29244
29244
  /* @__PURE__ */ jsx7(Spans, { spans: b.spans, env })
29245
29245
  );
29246
29246
  case "list": {
@@ -29250,7 +29250,7 @@ function Block({ b, env, depth }) {
29250
29250
  {
29251
29251
  ...tid(env, b.id, b.kind),
29252
29252
  start: b.ordered ? b.start : void 0,
29253
- style: { ...textStyle(ctx, "body", text6), paddingInlineStart: 24, listStyleType: b.ordered ? "decimal" : depth % 2 ? "circle" : "disc" },
29253
+ style: { ...textStyle(ctx, "body", text8), paddingInlineStart: 24, listStyleType: b.ordered ? "decimal" : depth % 2 ? "circle" : "disc" },
29254
29254
  children: b.items.map((item, i) => /* @__PURE__ */ jsx7("li", { "data-component-id": `${env.componentId}/${item.id}`, id: `${env.componentId}/${item.id}`, style: { marginBottom: 6 }, children: /* @__PURE__ */ jsx7("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: item.blocks.map((child, j) => /* @__PURE__ */ jsx7(Block, { b: child, env, depth: depth + 1 }, `${j}:${child.id}`)) }) }, `${i}:${item.id}`))
29255
29255
  }
29256
29256
  );
@@ -29264,7 +29264,7 @@ function Block({ b, env, depth }) {
29264
29264
  overflowWrap: "anywhere",
29265
29265
  fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
29266
29266
  fontSize: "0.9em",
29267
- color: text6,
29267
+ color: text8,
29268
29268
  background: ctx.color("surfaceSecondary", "#f5f5f7"),
29269
29269
  padding: 10,
29270
29270
  borderRadius: 6
@@ -29283,11 +29283,11 @@ function Block({ b, env, depth }) {
29283
29283
  case "button":
29284
29284
  return /* @__PURE__ */ jsx7(LinkButton, { label: b.label, url: b.url, env, testId: `${env.componentId}/${b.id}` });
29285
29285
  case "table":
29286
- return /* @__PURE__ */ jsx7("table", { ...tid(env, b.id, b.kind), style: { width: "100%", borderCollapse: "collapse", ...textStyle(ctx, "body", text6) }, children: /* @__PURE__ */ jsx7("tbody", { children: b.rows.map((row, r) => /* @__PURE__ */ jsx7("tr", { children: row.map((cell, c) => /* @__PURE__ */ jsx7("td", { style: { border: `1px solid ${border}`, padding: 6, whiteSpace: "pre-wrap", verticalAlign: "top" }, children: cell }, c)) }, r)) }) });
29286
+ return /* @__PURE__ */ jsx7("table", { ...tid(env, b.id, b.kind), style: { width: "100%", borderCollapse: "collapse", ...textStyle(ctx, "body", text8) }, children: /* @__PURE__ */ jsx7("tbody", { children: b.rows.map((row, r) => /* @__PURE__ */ jsx7("tr", { children: row.map((cell, c) => /* @__PURE__ */ jsx7("td", { style: { border: `1px solid ${border}`, padding: 6, whiteSpace: "pre-wrap", verticalAlign: "top" }, children: cell }, c)) }, r)) }) });
29287
29287
  case "card": {
29288
29288
  const title = richContentCardTitle(b);
29289
29289
  return /* @__PURE__ */ jsxs4("div", { ...tid(env, b.id, b.kind), role: "group", "aria-label": title, style: { border: `1px solid ${border}`, borderRadius: 8, padding: 12, display: "flex", flexDirection: "column", gap: 6 }, children: [
29290
- /* @__PURE__ */ jsx7("div", { style: textStyle(ctx, "bodyEmphasis", text6), children: title }),
29290
+ /* @__PURE__ */ jsx7("div", { style: textStyle(ctx, "bodyEmphasis", text8), children: title }),
29291
29291
  b.url ? /* @__PURE__ */ jsxs4(Fragment3, { children: [
29292
29292
  /* @__PURE__ */ jsx7("div", { style: textStyle(ctx, "caption", secondary), children: richContentHost(b.url) }),
29293
29293
  /* @__PURE__ */ jsx7(LinkButton, { label: RICH_CONTENT_OPEN_LABEL, url: b.url, env, testId: `${env.componentId}/${b.id}/open` })
@@ -30883,8 +30883,8 @@ function applyA11ySemantics(node, ctx, extra) {
30883
30883
  extra["aria-live"] = str9(announce.politeness) === "assertive" ? "assertive" : "polite";
30884
30884
  extra["aria-atomic"] = "true";
30885
30885
  extra["aria-relevant"] = trigger === "on_appear" ? "additions" : trigger === "both" ? "additions text" : "text";
30886
- const text6 = str9(announce.text);
30887
- if (text6 && extra["aria-label"] == null) extra["aria-label"] = text6;
30886
+ const text8 = str9(announce.text);
30887
+ if (text8 && extra["aria-label"] == null) extra["aria-label"] = text8;
30888
30888
  }
30889
30889
  }
30890
30890
  return hint;
@@ -32474,13 +32474,13 @@ var init_renderNode = __esm({
32474
32474
  const C = ctx.color;
32475
32475
  const isBoundText = typeof props.textPath === "string" && isBinding(props.textPath);
32476
32476
  const bound = useResolvedScalar(isBoundText ? props.textPath : void 0, ctx);
32477
- const text6 = isBoundText ? typeof bound === "string" || typeof bound === "number" ? String(bound) : "" : literalErrorText;
32477
+ const text8 = isBoundText ? typeof bound === "string" || typeof bound === "number" ? String(bound) : "" : literalErrorText;
32478
32478
  if (props.visible === false) return null;
32479
- if (isBoundText && !text6) return null;
32479
+ if (isBoundText && !text8) return null;
32480
32480
  const c = (props.severity ?? "error") === "warning" ? C("warning", "#E89F00") : C("danger", "#E62214");
32481
32481
  return /* @__PURE__ */ jsxs5("div", { role: "alert", style: { display: "flex", gap: 6, alignItems: "center", color: c, fontSize: 13, fontFamily: bodyFont(ctx), ...wrap }, children: [
32482
32482
  /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: "\u26A0" }),
32483
- text6
32483
+ text8
32484
32484
  ] });
32485
32485
  });
32486
32486
  FormView = withExtras("FormView", ({ props, ctx, wrap }) => {
@@ -33967,8 +33967,8 @@ var init_renderNode = __esm({
33967
33967
  const base = invalidIcon ? ICON_FALLBACK : (typeof props.icon === "string" && props.icon ? props.icon : "star").replace(/_fill$/, "");
33968
33968
  const filledCount = Math.round(val);
33969
33969
  const onClickStar = (i) => ctx.onAction && props.interactive && props.onChange ? () => ctx.onAction({ ...props.onChange, params: { ...props.onChange?.params ?? {}, value: String(i + 1) } }) : void 0;
33970
- const cv = Number.isFinite(val) ? Math.max(0, Math.min(max, val)) : 0, summary = `${Number.isInteger(cv) ? cv : cv.toFixed(1)} of ${max}`;
33971
- return /* @__PURE__ */ jsx8("span", { style: { display: "inline-flex", alignItems: "center", gap: m.gap, ...wrap }, role: props.interactive ? "group" : "img", "aria-label": `Rating, ${summary}`, "data-a11y-value": summary, children: Array.from({ length: max }).map((_, i) => {
33970
+ const cv = Number.isFinite(val) ? Math.max(0, Math.min(max, val)) : 0, summary2 = `${Number.isInteger(cv) ? cv : cv.toFixed(1)} of ${max}`;
33971
+ return /* @__PURE__ */ jsx8("span", { style: { display: "inline-flex", alignItems: "center", gap: m.gap, ...wrap }, role: props.interactive ? "group" : "img", "aria-label": `Rating, ${summary2}`, "data-a11y-value": summary2, children: Array.from({ length: max }).map((_, i) => {
33972
33972
  const filled = i < filledCount;
33973
33973
  return /* @__PURE__ */ jsx8("span", { onClick: onClickStar(i), style: { display: "inline-grid", placeItems: "center", width: m.cell, height: m.cell, cursor: props.interactive ? "pointer" : "default", opacity: filled ? 1 : 0.28 }, children: iconSvg(filled ? `${base}_fill` : base, { size: m.glyph, color: col }) }, i);
33974
33974
  }) });
@@ -35720,8 +35720,8 @@ function buildRenderTree(node, path2 = "$", provider = null, itemScope = void 0,
35720
35720
  const asText3 = VALUE_PATH_TEXT.get(type);
35721
35721
  if (typeof valuePath === "string" && asText3 && (valuePath.startsWith("$service:") || /^\$item\.[^.]/.test(valuePath))) {
35722
35722
  const r = resolveTreeScalar(valuePath, provider, itemScope);
35723
- const text6 = asText3(r, props);
35724
- if (text6 !== void 0) values.value = text6;
35723
+ const text8 = asText3(r, props);
35724
+ if (text8 !== void 0) values.value = text8;
35725
35725
  else if (r !== void 0 && r !== null) {
35726
35726
  delete values.value;
35727
35727
  }
@@ -35902,7 +35902,7 @@ async function stabilizePngPage(page, scheme) {
35902
35902
  const browser = globalThis;
35903
35903
  browser.document.documentElement.style.colorScheme = selected;
35904
35904
  await browser.document.fonts?.ready;
35905
- await new Promise((resolve52) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve52())));
35905
+ await new Promise((resolve53) => browser.requestAnimationFrame(() => browser.requestAnimationFrame(() => resolve53())));
35906
35906
  }, scheme);
35907
35907
  }
35908
35908
  async function renderPngBatch(items) {
@@ -37916,14 +37916,14 @@ function discoverNativeActions(appDir3) {
37916
37916
  const roots = NATIVE_SOURCE_ROOTS.filter(({ directory }) => existsSync38(resolve31(appDir3, directory)));
37917
37917
  const sources = roots.flatMap(({ directory, extension, buildDirMaxDepth }) => nativeSourceFiles(resolve31(appDir3, directory), extension, buildDirMaxDepth));
37918
37918
  const registered = sources.flatMap((source) => {
37919
- let text6;
37919
+ let text8;
37920
37920
  try {
37921
- text6 = readFileSync40(source, "utf8");
37921
+ text8 = readFileSync40(source, "utf8");
37922
37922
  } catch (err) {
37923
37923
  if (!vanished(err)) throw err;
37924
37924
  return [];
37925
37925
  }
37926
- return registeredActions(text6);
37926
+ return registeredActions(text8);
37927
37927
  });
37928
37928
  return {
37929
37929
  registered: new Set(registered),
@@ -38022,11 +38022,11 @@ function strip(line) {
38022
38022
  function scalar(v) {
38023
38023
  return v.trim().replace(/^["']|["']$/g, "");
38024
38024
  }
38025
- function parseRolloutYaml(text6) {
38025
+ function parseRolloutYaml(text8) {
38026
38026
  const cfg = { app: "", rings: [] };
38027
38027
  let cur = null;
38028
38028
  let inRings = false;
38029
- for (const raw of text6.split("\n")) {
38029
+ for (const raw of text8.split("\n")) {
38030
38030
  const line = strip(raw);
38031
38031
  if (!line.trim()) continue;
38032
38032
  const top = /^([a-zA-Z_]+):\s*(.*)$/.exec(line);
@@ -38057,10 +38057,10 @@ function assignRing(r, key2, val) {
38057
38057
  else if (key2 === "percent") r.percent = Number(v);
38058
38058
  else if (key2 === "minBinaryVersion") r.minBinaryVersion = v;
38059
38059
  }
38060
- function parseRevocationsYaml(text6) {
38060
+ function parseRevocationsYaml(text8) {
38061
38061
  const out2 = { app: "", revoked: [] };
38062
38062
  let inList = false;
38063
- for (const raw of text6.split("\n")) {
38063
+ for (const raw of text8.split("\n")) {
38064
38064
  const line = strip(raw);
38065
38065
  if (!line.trim()) continue;
38066
38066
  const top = /^([a-zA-Z_]+):\s*(.*)$/.exec(line);
@@ -38417,7 +38417,7 @@ async function runScreenDiagnostics(state, screenId, descriptor) {
38417
38417
  state.app?.module.config,
38418
38418
  state.tier5Dir ?? TIER5_ROOT2
38419
38419
  );
38420
- const report2 = validateScreenDescriptor2(screenId, descriptor, {
38420
+ const report3 = validateScreenDescriptor2(screenId, descriptor, {
38421
38421
  tokens,
38422
38422
  allowedComponents,
38423
38423
  bundleJs,
@@ -38430,7 +38430,7 @@ async function runScreenDiagnostics(state, screenId, descriptor) {
38430
38430
  });
38431
38431
  const telemetry = state.telemetryEvents.filter((e) => e.screenId === screenId && (/^worker_/.test(e.type) || e.type === "bundle_load_revoked")).slice(-20);
38432
38432
  const lastError = [...telemetry].reverse().find((e) => /crash|revoked|error|fail/i.test(e.type)) ?? null;
38433
- const legacy = { ...report2, bundle: bundleName ?? null, telemetry, lastError };
38433
+ const legacy = { ...report3, bundle: bundleName ?? null, telemetry, lastError };
38434
38434
  return foldLegacyReport(legacy, {
38435
38435
  source: "diagnostics",
38436
38436
  screenId,
@@ -38639,11 +38639,11 @@ async function handleOwnerChatRequest(req, res) {
38639
38639
  return sendJson(res, 400, { error: "invalid_json" }, cors);
38640
38640
  }
38641
38641
  const chatroomId = (parsed.chatroomId ?? "").trim();
38642
- const text6 = (parsed.text ?? "").trim();
38643
- if (!chatroomId || !text6) return sendJson(res, 400, { error: "chatroomId_and_text_required" }, cors);
38642
+ const text8 = (parsed.text ?? "").trim();
38643
+ if (!chatroomId || !text8) return sendJson(res, 400, { error: "chatroomId_and_text_required" }, cors);
38644
38644
  const metaSiteId = (parsed.metaSiteId ?? "").trim() || await resolveMetaSiteId();
38645
38645
  if (!metaSiteId) return sendJson(res, 400, { error: "no_meta_site" }, cors);
38646
- const result = await sendChatMessageLive(metaSiteId, chatroomId, text6);
38646
+ const result = await sendChatMessageLive(metaSiteId, chatroomId, text8);
38647
38647
  if (result.ok) return sendJson(res, 200, { ok: true, message: result.message }, cors);
38648
38648
  return sendJson(res, result.status >= 400 && result.status < 600 ? result.status : 502, { ok: false, status: result.status, error: result.error }, cors);
38649
38649
  }
@@ -38904,13 +38904,13 @@ function invalidate(state, ...screenIds) {
38904
38904
  publishSSE(state, "screen.invalidated", { screenIds });
38905
38905
  }
38906
38906
  function publishSSE(state, type, payload) {
38907
- const text6 = `event: ${type}
38907
+ const text8 = `event: ${type}
38908
38908
  data: ${JSON.stringify(payload)}
38909
38909
 
38910
38910
  `;
38911
38911
  for (const res of [...state.sseClients]) {
38912
38912
  try {
38913
- res.write(text6);
38913
+ res.write(text8);
38914
38914
  } catch {
38915
38915
  state.sseClients.delete(res);
38916
38916
  }
@@ -38926,13 +38926,13 @@ function publishAdminSSE(state, type, payload) {
38926
38926
  state.lastDeviceScreen.set(key2, screenId);
38927
38927
  }
38928
38928
  }
38929
- const text6 = `event: ${type}
38929
+ const text8 = `event: ${type}
38930
38930
  data: ${JSON.stringify(payload)}
38931
38931
 
38932
38932
  `;
38933
38933
  for (const res of [...state.adminClients]) {
38934
38934
  try {
38935
- res.write(text6);
38935
+ res.write(text8);
38936
38936
  } catch {
38937
38937
  state.adminClients.delete(res);
38938
38938
  }
@@ -38953,12 +38953,12 @@ function publishDevReady(state, res, extra = {}) {
38953
38953
  hotReloadEnabled: state.hotReloadEnabled,
38954
38954
  ...extra
38955
38955
  };
38956
- const text6 = `event: dev.ready
38956
+ const text8 = `event: dev.ready
38957
38957
  data: ${JSON.stringify(payload)}
38958
38958
 
38959
38959
  `;
38960
38960
  if (res) {
38961
- res.write(text6);
38961
+ res.write(text8);
38962
38962
  } else {
38963
38963
  publishSSE(state, "dev.ready", payload);
38964
38964
  }
@@ -39543,7 +39543,7 @@ async function handleWebWix(req, res, state) {
39543
39543
  }
39544
39544
  if (match) {
39545
39545
  const mocked = match.rule.response;
39546
- if (mocked.delayMs) await new Promise((resolve52) => setTimeout(resolve52, mocked.delayMs));
39546
+ if (mocked.delayMs) await new Promise((resolve53) => setTimeout(resolve53, mocked.delayMs));
39547
39547
  const responseBody = mocked.template ? renderTemplate(mocked.body, match.captures) : mocked.body;
39548
39548
  record2("mock", mocked.status, responseBody, match.rule.id, mocked.headers);
39549
39549
  return reply(200, { status: mocked.status, body: responseBody ?? "" });
@@ -39709,7 +39709,7 @@ async function handleDev(req, res, state) {
39709
39709
  idiomContext
39710
39710
  );
39711
39711
  const legacy = { screenId, scheme, ...render, diagnostics };
39712
- const report2 = foldLegacyReport(legacy, {
39712
+ const report3 = foldLegacyReport(legacy, {
39713
39713
  source: "render",
39714
39714
  screenId,
39715
39715
  ok: diagnostics.ok !== false && render.renderable !== false,
@@ -39721,8 +39721,8 @@ async function handleDev(req, res, state) {
39721
39721
  ],
39722
39722
  evidence: { runId: `dev:${state.startedAt}:${screenId}`, ts: (/* @__PURE__ */ new Date()).toISOString() }
39723
39723
  });
39724
- const status = body.envelope === 1 && !report2.ok ? 422 : 200;
39725
- return sendJson(res, status, report2);
39724
+ const status = body.envelope === 1 && !report3.ok ? 422 : 200;
39725
+ return sendJson(res, status, report3);
39726
39726
  }
39727
39727
  {
39728
39728
  const diagMatch = /^\/__dev\/screen\/(.+?)\/diagnostics(?:\?|$)/.exec(url);
@@ -40183,7 +40183,7 @@ async function handleAdminPlayground(req, res, state) {
40183
40183
  state.app?.module.config,
40184
40184
  state.tier5Dir ?? TIER5_ROOT2
40185
40185
  );
40186
- const report2 = validateScreenDescriptor2(screenId, descriptor, {
40186
+ const report3 = validateScreenDescriptor2(screenId, descriptor, {
40187
40187
  tokens,
40188
40188
  allowedComponents,
40189
40189
  bundleJs,
@@ -40193,7 +40193,7 @@ async function handleAdminPlayground(req, res, state) {
40193
40193
  workerSubtreeScreens: new Set(uiConfig(state.app?.module.config).workerSubtreeScreens ?? []),
40194
40194
  a11y: uiConfig(state.app?.module.config).a11y
40195
40195
  });
40196
- return sendJson(res, report2.ok ? 200 : 422, report2);
40196
+ return sendJson(res, report3.ok ? 200 : 422, report3);
40197
40197
  }
40198
40198
  const detailMatch = /^\/v1\/admin\/screens\/([^/]+)$/.exec(path2);
40199
40199
  if (detailMatch && req.method === "GET") {
@@ -40648,9 +40648,9 @@ async function handleLiveSubscription(req, res, state) {
40648
40648
  },
40649
40649
  body: JSON.stringify({ ...body, app })
40650
40650
  });
40651
- const text6 = await upstream.text();
40651
+ const text8 = await upstream.text();
40652
40652
  res.writeHead(upstream.status, { "Content-Type": "application/json", ...cors });
40653
- res.end(text6 || JSON.stringify({ ok: upstream.ok }));
40653
+ res.end(text8 || JSON.stringify({ ok: upstream.ok }));
40654
40654
  } catch (error) {
40655
40655
  sendJson(res, 502, { error: "admin_server_unreachable", detail: String(error) }, cors);
40656
40656
  }
@@ -41642,12 +41642,12 @@ var init_query = __esm({
41642
41642
  });
41643
41643
 
41644
41644
  // ../../core/dev-server/src/crawl-input.ts
41645
- function resolved(v, resolve52) {
41646
- if (typeof v === "string") return v.startsWith("$service:") ? resolve52(v) : v;
41645
+ function resolved(v, resolve53) {
41646
+ if (typeof v === "string") return v.startsWith("$service:") ? resolve53(v) : v;
41647
41647
  if (Array.isArray(v)) {
41648
41648
  const out2 = v.flatMap((el) => {
41649
41649
  if (typeof el !== "string" || !el.startsWith("$service:")) return [el];
41650
- const r = resolve52(el);
41650
+ const r = resolve53(el);
41651
41651
  return Array.isArray(r) ? r : [r];
41652
41652
  });
41653
41653
  return out2;
@@ -41661,9 +41661,9 @@ function hasRowBinding(props) {
41661
41661
  return itemToken(v) || Array.isArray(v) && v.some(itemToken);
41662
41662
  });
41663
41663
  }
41664
- function declaredOptionIds(props, resolve52) {
41664
+ function declaredOptionIds(props, resolve53) {
41665
41665
  const literal = props.options ?? props.tabs ?? props.chips;
41666
- const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve52) : void 0;
41666
+ const bound = props.optionsPath !== void 0 ? resolved(props.optionsPath, resolve53) : void 0;
41667
41667
  const raw = Array.isArray(bound) ? bound : literal;
41668
41668
  if (!Array.isArray(raw)) return [];
41669
41669
  const out2 = [];
@@ -41706,24 +41706,24 @@ function seedTokens(state, limit = 48) {
41706
41706
  walk2(state, 0);
41707
41707
  return out2;
41708
41708
  }
41709
- function synthesizeInput(control, resolve52, tokens) {
41709
+ function synthesizeInput(control, resolve53, tokens) {
41710
41710
  const id = `${control.type}.${control.callback}`;
41711
41711
  const row = SYNTHESIZED_CONTROLS[id];
41712
41712
  if (!row) return null;
41713
41713
  const props = control.props;
41714
41714
  if (hasRowBinding(props)) return null;
41715
41715
  if (row.from === "declared-options") {
41716
- const ids = declaredOptionIds(props, resolve52);
41716
+ const ids = declaredOptionIds(props, resolve53);
41717
41717
  if (!ids.length) return null;
41718
41718
  if (row.encoding === "string-array") {
41719
- const currentRaw2 = resolved(props.selectedIds, resolve52);
41719
+ const currentRaw2 = resolved(props.selectedIds, resolve53);
41720
41720
  const current3 = (Array.isArray(currentRaw2) ? currentRaw2 : []).filter((x) => typeof x === "string");
41721
41721
  const pick4 = ids.find((o) => !current3.includes(o));
41722
41722
  if (pick4 === void 0) return null;
41723
41723
  const value = props.multiSelect === true ? [...current3, pick4] : [pick4];
41724
41724
  return { key: row.key, value, from: row.from, current: current3, control: id };
41725
41725
  }
41726
- const currentRaw = resolved(props.selectedId, resolve52);
41726
+ const currentRaw = resolved(props.selectedId, resolve53);
41727
41727
  const current2 = typeof currentRaw === "string" ? currentRaw : void 0;
41728
41728
  const pick3 = ids.find((o) => o !== current2);
41729
41729
  if (pick3 === void 0) return null;
@@ -41731,7 +41731,7 @@ function synthesizeInput(control, resolve52, tokens) {
41731
41731
  }
41732
41732
  if (!acceptsWords(props) || !acceptsWords(control.wrapper ?? {})) return null;
41733
41733
  const binding2 = typeof props.valuePath === "string" ? props.valuePath : typeof props.value === "string" && props.value.startsWith("$service:") ? props.value : void 0;
41734
- const bound = binding2 === void 0 ? void 0 : resolve52(binding2);
41734
+ const bound = binding2 === void 0 ? void 0 : resolve53(binding2);
41735
41735
  const literal = typeof props.value === "string" && !props.value.startsWith("$") ? props.value : void 0;
41736
41736
  const current = typeof bound === "string" ? bound : typeof bound === "number" ? String(bound) : literal ?? "";
41737
41737
  const max = typeof props.maxLength === "number" && props.maxLength > 0 ? props.maxLength : void 0;
@@ -42095,10 +42095,10 @@ function netTransport(rules) {
42095
42095
  if (res.needsUpstream) {
42096
42096
  throw new Error(`net fixture rule ${res.ruleId} is a \`transform\` rule, which needs a real upstream \u2014 not usable in a hermetic crawl`);
42097
42097
  }
42098
- const { status, body: text6 } = res.resolved;
42098
+ const { status, body: text8 } = res.resolved;
42099
42099
  if (status < 200 || status >= 300) throw new Error(`Wix ${status} for ${method} ${bare}`);
42100
42100
  try {
42101
- return text6 ? JSON.parse(text6) : {};
42101
+ return text8 ? JSON.parse(text8) : {};
42102
42102
  } catch {
42103
42103
  return {};
42104
42104
  }
@@ -42142,10 +42142,10 @@ function layeredTransport(layers2) {
42142
42142
  });
42143
42143
  if (res.matched) {
42144
42144
  if (res.needsUpstream) throw new Error(`net fixture rule ${res.ruleId} is a \`transform\` rule, which needs a real upstream \u2014 not usable in a hermetic crawl`);
42145
- const { status, body: text6 } = res.resolved;
42145
+ const { status, body: text8 } = res.resolved;
42146
42146
  if (status < 200 || status >= 300) throw new Error(`Wix ${status} for ${m} ${bare}`);
42147
42147
  try {
42148
- return text6 ? JSON.parse(text6) : {};
42148
+ return text8 ? JSON.parse(text8) : {};
42149
42149
  } catch {
42150
42150
  return {};
42151
42151
  }
@@ -44167,13 +44167,13 @@ var init_build2 = __esm({
44167
44167
  });
44168
44168
 
44169
44169
  // ../mobile-dist/release-pin.ts
44170
- function withPinnedRelease(text6, releaseId) {
44171
- if (!releaseId) return text6;
44170
+ function withPinnedRelease(text8, releaseId) {
44171
+ if (!releaseId) return text8;
44172
44172
  let cfg;
44173
44173
  try {
44174
- cfg = JSON.parse(text6);
44174
+ cfg = JSON.parse(text8);
44175
44175
  } catch {
44176
- return text6;
44176
+ return text8;
44177
44177
  }
44178
44178
  cfg.releaseId = releaseId;
44179
44179
  cfg.releasePinned = true;
@@ -44291,10 +44291,10 @@ async function bakeCatalogs(app, locale, fetchCatalog, putDoc) {
44291
44291
  if (!declared.length) return out2;
44292
44292
  const tags = [.../* @__PURE__ */ new Set([...locale?.default ? [locale.default] : [], ...declared])];
44293
44293
  for (const tag of tags) {
44294
- const text6 = await fetchCatalog(tag);
44295
- if (!text6) continue;
44296
- const hash = sha2564(text6);
44297
- await putDoc(app, hash, text6);
44294
+ const text8 = await fetchCatalog(tag);
44295
+ if (!text8) continue;
44296
+ const hash = sha2564(text8);
44297
+ await putDoc(app, hash, text8);
44298
44298
  out2[tag] = hash;
44299
44299
  }
44300
44300
  return out2;
@@ -44386,9 +44386,9 @@ async function snapshotTokens(app, base, fetchTokens, put) {
44386
44386
  }
44387
44387
  };
44388
44388
  }
44389
- const text6 = await res.text();
44390
- await put(text6);
44391
- return { hash: sha2564(text6) };
44389
+ const text8 = await res.text();
44390
+ await put(text8);
44391
+ return { hash: sha2564(text8) };
44392
44392
  }
44393
44393
  function tokensSnapshotMessage(app, base, status) {
44394
44394
  const why = status === 400 ? `the dev-server rejected the app id as malformed (400 bad_app). It must be lowercase letters, digits and hyphens, starting with a letter or digit, at most 63 characters, with at most one interior dot \u2014 so a leading underscore or an uppercase letter fails, on every build of that app. A single dot is FINE (an owner-namespaced slug), so do not remove one to get past this` : `${status} from the tokens route`;
@@ -44482,23 +44482,23 @@ function maximumBinaryVersion(current, candidate) {
44482
44482
  }
44483
44483
  return current;
44484
44484
  }
44485
- async function withStoreNavBundle(text6, address) {
44485
+ async function withStoreNavBundle(text8, address) {
44486
44486
  let cfg;
44487
44487
  try {
44488
- cfg = JSON.parse(text6);
44488
+ cfg = JSON.parse(text8);
44489
44489
  } catch {
44490
- return text6;
44490
+ return text8;
44491
44491
  }
44492
44492
  const refs = [cfg?.navigation?.navLogicBundle, cfg?.navLogicBundle].filter(
44493
44493
  (r) => !!r && typeof r === "object" && typeof r.url === "string"
44494
44494
  );
44495
- if (refs.length === 0) return text6;
44495
+ if (refs.length === 0) return text8;
44496
44496
  const resolved2 = [];
44497
44497
  for (const ref of refs) {
44498
44498
  const name = bundleNameFromUrl(ref.url);
44499
- if (!name) return text6;
44499
+ if (!name) return text8;
44500
44500
  const addressed = await address(name);
44501
- if (!addressed) return text6;
44501
+ if (!addressed) return text8;
44502
44502
  resolved2.push({ ref, url: addressed.url, sri: addressed.sri });
44503
44503
  }
44504
44504
  for (const { ref, url, sri: integrity2 } of resolved2) {
@@ -44507,10 +44507,10 @@ async function withStoreNavBundle(text6, address) {
44507
44507
  }
44508
44508
  return JSON.stringify(cfg);
44509
44509
  }
44510
- function linkableScreenIdsFrom(text6) {
44510
+ function linkableScreenIdsFrom(text8) {
44511
44511
  let cfg;
44512
44512
  try {
44513
- cfg = JSON.parse(text6);
44513
+ cfg = JSON.parse(text8);
44514
44514
  } catch {
44515
44515
  return [];
44516
44516
  }
@@ -44522,24 +44522,24 @@ function linkableScreenIdsFrom(text6) {
44522
44522
  }
44523
44523
  return [...ids];
44524
44524
  }
44525
- function withoutDevOnlyAppConfig(text6) {
44525
+ function withoutDevOnlyAppConfig(text8) {
44526
44526
  let cfg;
44527
44527
  try {
44528
- cfg = JSON.parse(text6);
44528
+ cfg = JSON.parse(text8);
44529
44529
  } catch {
44530
- return text6;
44530
+ return text8;
44531
44531
  }
44532
- if (!cfg || typeof cfg !== "object" || !("devGatewayConfig" in cfg)) return text6;
44532
+ if (!cfg || typeof cfg !== "object" || !("devGatewayConfig" in cfg)) return text8;
44533
44533
  delete cfg.devGatewayConfig;
44534
44534
  return JSON.stringify(cfg);
44535
44535
  }
44536
- function withProdServeAppConfig(text6, prod) {
44537
- if (!prod?.serve) return text6;
44536
+ function withProdServeAppConfig(text8, prod) {
44537
+ if (!prod?.serve) return text8;
44538
44538
  let cfg;
44539
44539
  try {
44540
- cfg = JSON.parse(text6);
44540
+ cfg = JSON.parse(text8);
44541
44541
  } catch {
44542
- return text6;
44542
+ return text8;
44543
44543
  }
44544
44544
  cfg.useProdServe = true;
44545
44545
  cfg.prodServeBaseUrl = prod.serve;
@@ -44760,10 +44760,10 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
44760
44760
  if (bytes2.length === 0 || bytes2.length > MAX_AUTHORING_DOC_BYTES) {
44761
44761
  throw new Error(`${file} must be non-empty and at most ${MAX_AUTHORING_DOC_BYTES} bytes to ship with a release.`);
44762
44762
  }
44763
- const text6 = bytes2.toString("utf8");
44764
- if (!Buffer.from(text6, "utf8").equals(bytes2)) throw new Error(`${file} must be canonical UTF-8 Markdown.`);
44763
+ const text8 = bytes2.toString("utf8");
44764
+ if (!Buffer.from(text8, "utf8").equals(bytes2)) throw new Error(`${file} must be canonical UTF-8 Markdown.`);
44765
44765
  const hash = sha2564(bytes2);
44766
- await store.putDoc(app, hash, text6);
44766
+ await store.putDoc(app, hash, text8);
44767
44767
  authoringDocs[name] = { sha256: hash, sri: sri2(bytes2), bytes: bytes2.length, contentType: "text/markdown; charset=utf-8" };
44768
44768
  }
44769
44769
  }
@@ -44962,7 +44962,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
44962
44962
  }
44963
44963
  if (collect2?.lint) {
44964
44964
  const bundleJs = bundleName ? readBuiltBundle(tier5Dir, bundleName) : void 0;
44965
- const report2 = validateScreenDescriptor(screenId, descriptor, {
44965
+ const report3 = validateScreenDescriptor(screenId, descriptor, {
44966
44966
  tokens: lintTokens,
44967
44967
  allowedComponents,
44968
44968
  allowedIcons: KNOWN_ICONS,
@@ -44976,7 +44976,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
44976
44976
  // default, "error"; an in-repo app with ratcheted debt declares "warn".
44977
44977
  a11y: config.a11y
44978
44978
  });
44979
- lint.push({ screenId, ok: report2.ok, issues: report2.issues });
44979
+ lint.push({ screenId, ok: report3.ok, issues: report3.issues });
44980
44980
  }
44981
44981
  if (collect2?.render && (!collect2.render.screenId || collect2.render.screenId === screenId)) {
44982
44982
  const { services, liveCalls, liveReturned, liveErrors } = await renderServicesFor(bundleName, descriptor);
@@ -44994,7 +44994,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
44994
44994
  const bundleName = lb ? bundleNameFromUrl(lb.url) : null;
44995
44995
  if (collect2?.lint) {
44996
44996
  const bundleJs = bundleName ? readBuiltBundle(tier5Dir, bundleName) : void 0;
44997
- const report2 = validateScreenDescriptor(wantedRender, descriptor, {
44997
+ const report3 = validateScreenDescriptor(wantedRender, descriptor, {
44998
44998
  tokens: lintTokens,
44999
44999
  allowedComponents,
45000
45000
  allowedIcons: KNOWN_ICONS,
@@ -45005,7 +45005,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
45005
45005
  workerSubtreeScreens: new Set(config.workerSubtreeScreens ?? []),
45006
45006
  a11y: config.a11y
45007
45007
  });
45008
- lint.push({ screenId: wantedRender, ok: report2.ok, issues: report2.issues });
45008
+ lint.push({ screenId: wantedRender, ok: report3.ok, issues: report3.issues });
45009
45009
  }
45010
45010
  const { services, liveCalls, liveReturned, liveErrors } = await renderServicesFor(bundleName, descriptor);
45011
45011
  const rr = await renderDescriptorWeb(descriptor, renderTokens, renderScheme, collect2.render.png === true, services, collect2.render.width, collect2.render.rtl === true);
@@ -45123,11 +45123,11 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
45123
45123
  ok: res.ok,
45124
45124
  status: res.status,
45125
45125
  text: async () => {
45126
- const text6 = await res.text();
45126
+ const text8 = await res.text();
45127
45127
  try {
45128
- const doc = JSON.parse(text6);
45128
+ const doc = JSON.parse(text8);
45129
45129
  if (!publishedFontPlan) {
45130
- if (!("fontFaces" in doc)) return text6;
45130
+ if (!("fontFaces" in doc)) return text8;
45131
45131
  const kept = publishableFontFaces(doc.fontFaces);
45132
45132
  if (kept) doc.fontFaces = kept;
45133
45133
  else delete doc.fontFaces;
@@ -45136,12 +45136,12 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
45136
45136
  doc.fontFaces = servedProjection(publishedFontPlan);
45137
45137
  return JSON.stringify(doc);
45138
45138
  } catch {
45139
- return text6;
45139
+ return text8;
45140
45140
  }
45141
45141
  }
45142
45142
  };
45143
45143
  },
45144
- (text6) => store.putTokens(app, text6)
45144
+ (text8) => store.putTokens(app, text8)
45145
45145
  );
45146
45146
  if (snapshot2.hash) tokensHash = snapshot2.hash;
45147
45147
  if (snapshot2.failure) {
@@ -45171,14 +45171,14 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
45171
45171
  if (streamPolicyErrors.length) {
45172
45172
  throw new Error(`invalid streamPolicy for release ${app}: ${streamPolicyErrors.join("; ")}`);
45173
45173
  }
45174
- const text6 = await withStoreNavBundle(prodText, async (name) => {
45174
+ const text8 = await withStoreNavBundle(prodText, async (name) => {
45175
45175
  const hash = await addressBundle(name) ?? null;
45176
45176
  const entry = hash ? bundles[name] : void 0;
45177
45177
  return entry ? { url: store.bundleUrl(app, entry.sha256), sri: entry.sri } : null;
45178
45178
  });
45179
- await store.putAppConfig(app, text6);
45180
- appConfigHash = sha2564(text6);
45181
- if (collect2?.descriptors) for (const id of linkableScreenIdsFrom(text6)) linkable.add(id);
45179
+ await store.putAppConfig(app, text8);
45180
+ appConfigHash = sha2564(text8);
45181
+ if (collect2?.descriptors) for (const id of linkableScreenIdsFrom(text8)) linkable.add(id);
45182
45182
  }
45183
45183
  const ahRes = await devFetch(`${base}/v1/action-handlers/${encodeURIComponent(app)}`, { headers: { "X-Himalaya-App": app } });
45184
45184
  if (ahRes.ok) {
@@ -46044,14 +46044,14 @@ function headline(changes) {
46044
46044
  function boardLines(changes) {
46045
46045
  const lines = [];
46046
46046
  for (const c of changes.items) {
46047
- const text6 = lineOf(c);
46048
- const same3 = lines.find((l) => l.text === text6);
46047
+ const text8 = lineOf(c);
46048
+ const same3 = lines.find((l) => l.text === text8);
46049
46049
  if (same3) {
46050
46050
  same3.n++;
46051
46051
  continue;
46052
46052
  }
46053
46053
  lines.push({
46054
- text: text6,
46054
+ text: text8,
46055
46055
  n: 1,
46056
46056
  ...c.kind === "token" && c.from && HEX.test(c.from) ? { from: c.from } : {},
46057
46057
  ...c.kind === "token" && c.to && HEX.test(c.to) ? { to: c.to } : {}
@@ -46371,12 +46371,12 @@ function testRuns(dir) {
46371
46371
  if (!f.endsWith(".json") || f === "latest.json") continue;
46372
46372
  const r = obj(readJson3(join41(att, f)));
46373
46373
  if (!r || r.tool !== "himi-test" || typeof r.runId !== "string") continue;
46374
- const report2 = obj(r.report);
46374
+ const report3 = obj(r.report);
46375
46375
  const coverage = obj(r.coverage);
46376
46376
  runs.push({
46377
46377
  runId: r.runId,
46378
- ok: report2?.ok === true,
46379
- errors: num(obj(report2?.counts)?.errors),
46378
+ ok: report3?.ok === true,
46379
+ errors: num(obj(report3?.counts)?.errors),
46380
46380
  screens: num(coverage?.screens),
46381
46381
  actions: num(coverage?.actionsDispatched),
46382
46382
  gaps: num(coverage?.gaps)
@@ -46495,7 +46495,7 @@ function focusScreen(memory) {
46495
46495
  }
46496
46496
  function buildView(dir, memory, now) {
46497
46497
  const { entries } = readProgress(dir);
46498
- const summary = summarizeProgress(entries);
46498
+ const summary2 = summarizeProgress(entries);
46499
46499
  const { name, iconFile } = appIdentity(dir);
46500
46500
  const iconArchived = iconFile ? archiveFile(dir, memory, iconFile) : null;
46501
46501
  const icon = iconArchived ? historyUrl(iconArchived.file) : null;
@@ -46524,12 +46524,12 @@ function buildView(dir, memory, now) {
46524
46524
  }
46525
46525
  }
46526
46526
  const firstShot = screens.map((s) => s.firstSeen).sort()[0];
46527
- const startedAt = [summary.startedAt, firstShot, memory.createdAt].filter((x) => !!x).sort()[0] ?? null;
46527
+ const startedAt = [summary2.startedAt, firstShot, memory.createdAt].filter((x) => !!x).sort()[0] ?? null;
46528
46528
  const view = {
46529
46529
  generatedAt: now,
46530
46530
  app: { name, icon, palette: palette(dir) },
46531
46531
  steps: JOURNEY_STEPS,
46532
- current: summary.current ?? null,
46532
+ current: summary2.current ?? null,
46533
46533
  startedAt,
46534
46534
  journal: entries.slice(-MAX_JOURNAL).reverse().map((e) => ({
46535
46535
  ts: e.ts,
@@ -47194,16 +47194,16 @@ function pushSetupBodyBytes(body) {
47194
47194
  return Buffer.byteLength(JSON.stringify(body), "utf8");
47195
47195
  }
47196
47196
  async function pushSetupRequest(options) {
47197
- const refuse4 = (error) => ({ ok: false, status: 0, body: null, error });
47198
- if (!options.target.controlToken) return refuse4("control_token_required");
47199
- if (!options.wixToken) return refuse4("wix_account_token_required");
47200
- if (credentialHostRefusal(options.target.control)) return refuse4("insecure_target");
47201
- if (options.previewTag !== void 0 && !PREVIEW_TAG.test(options.previewTag)) return refuse4("invalid_preview_tag");
47197
+ const refuse5 = (error) => ({ ok: false, status: 0, body: null, error });
47198
+ if (!options.target.controlToken) return refuse5("control_token_required");
47199
+ if (!options.wixToken) return refuse5("wix_account_token_required");
47200
+ if (credentialHostRefusal(options.target.control)) return refuse5("insecure_target");
47201
+ if (options.previewTag !== void 0 && !PREVIEW_TAG.test(options.previewTag)) return refuse5("invalid_preview_tag");
47202
47202
  const setup = options.operation === "setup";
47203
- if (setup && !options.body) return refuse4("push_setup_body_required");
47204
- if (!setup && (!options.query?.app || !options.query?.site)) return refuse4("push_setup_query_required");
47203
+ if (setup && !options.body) return refuse5("push_setup_body_required");
47204
+ if (!setup && (!options.query?.app || !options.query?.site)) return refuse5("push_setup_query_required");
47205
47205
  if (setup && pushSetupBodyBytes(options.body) > MAX_PUSH_SETUP_BODY_BYTES) {
47206
- return refuse4("push_setup_body_too_large");
47206
+ return refuse5("push_setup_body_too_large");
47207
47207
  }
47208
47208
  const base = options.target.control.replace(/\/+$/, "");
47209
47209
  let path2 = "/v1/admin/push/setup";
@@ -47228,10 +47228,10 @@ async function pushSetupRequest(options) {
47228
47228
  signal: AbortSignal.timeout(options.timeoutMs ?? (setup ? 12e4 : 3e4)),
47229
47229
  ...setup ? { body: JSON.stringify(options.body) } : {}
47230
47230
  });
47231
- const text6 = await response.text();
47231
+ const text8 = await response.text();
47232
47232
  let parsed = null;
47233
47233
  try {
47234
- const value = text6 ? JSON.parse(text6) : null;
47234
+ const value = text8 ? JSON.parse(text8) : null;
47235
47235
  parsed = value && typeof value === "object" && !Array.isArray(value) ? value : null;
47236
47236
  } catch {
47237
47237
  parsed = null;
@@ -47271,6 +47271,41 @@ var init_push_setup_apple_credentials = __esm({
47271
47271
  }
47272
47272
  });
47273
47273
 
47274
+ // src/hosted-owner.ts
47275
+ async function hostedOwnerSession(flags, deps = {}) {
47276
+ let target;
47277
+ try {
47278
+ target = resolveTarget({ target: text3(flags.target), defaultTarget: "wix", controlUrl: text3(flags["control-url"]), controlToken: text3(flags["control-token"]), ownerIssueUrl: text3(flags["owner-issue-url"]) });
47279
+ } catch {
47280
+ return refused("unknown_target", "Select a configured serve target.");
47281
+ }
47282
+ if (credentialHostRefusal(target.control)) return refused("insecure_target");
47283
+ const previewTag = text3(flags["preview-tag"]) ?? process.env.HIMI_SERVE_PREVIEW_TAG;
47284
+ if (previewTag !== void 0 && !/^dp-[a-z0-9]+$/.test(previewTag)) return refused("invalid_preview_tag");
47285
+ const controlToken = target.controlToken;
47286
+ if (!controlToken || !decodeControlTokenClaims(controlToken)?.sub) return refused("owner_login_required", "Run himi login --browser --target wix.");
47287
+ let wixToken;
47288
+ try {
47289
+ wixToken = await (deps.wixToken ?? accountToken)();
47290
+ } catch {
47291
+ return refused("wix_account_token_required", "Browser login supplies a Himi control token only. Sign into the Wix CLI with wix login, using the same Wix account, then retry. You can continue building without push setup.", 1);
47292
+ }
47293
+ if (!wixToken) return refused("wix_account_token_required", "Run wix login using the same Wix account.", 1);
47294
+ if (!target.ownerIssue) return refused("owner_issuer_required");
47295
+ return { ok: true, session: { target, controlToken, wixToken, ownerIssue: target.ownerIssue, ...previewTag ? { previewTag } : {} } };
47296
+ }
47297
+ var text3, refused;
47298
+ var init_hosted_owner = __esm({
47299
+ "src/hosted-owner.ts"() {
47300
+ init_config();
47301
+ init_credential_hosts();
47302
+ init_owner_claim();
47303
+ init_wix_owner();
47304
+ text3 = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
47305
+ refused = (error, hint, exit = 2) => ({ ok: false, error, ...hint ? { hint } : {}, exit });
47306
+ }
47307
+ });
47308
+
47274
47309
  // src/push-onboarding.ts
47275
47310
  import { existsSync as existsSync44, mkdirSync as mkdirSync20, readFileSync as readFileSync48, statSync as statSync9, writeFileSync as writeFileSync15, chmodSync as chmodSync2 } from "node:fs";
47276
47311
  import { basename as basename12, dirname as dirname25, join as join42, resolve as resolve37 } from "node:path";
@@ -47294,26 +47329,26 @@ function pushInputsFromContent(dir) {
47294
47329
  // autoClaimSlug's docblock describes as the project-declared slug. Without the fallback a
47295
47330
  // package with no `name` sent a body missing `app` and earned `400 invalid_app_id` with both
47296
47331
  // private keys already on the wire.
47297
- app: text3(content.name) ?? basename12(root),
47298
- ...text3(provisioning.siteId) ? { site: text3(provisioning.siteId) } : {},
47299
- ...text3(native.iosBundleId) ? { bundleId: text3(native.iosBundleId) } : {},
47300
- ...text3(native.androidApplicationId) ? { androidApplicationId: text3(native.androidApplicationId) } : {}
47332
+ app: text4(content.name) ?? basename12(root),
47333
+ ...text4(provisioning.siteId) ? { site: text4(provisioning.siteId) } : {},
47334
+ ...text4(native.iosBundleId) ? { bundleId: text4(native.iosBundleId) } : {},
47335
+ ...text4(native.androidApplicationId) ? { androidApplicationId: text4(native.androidApplicationId) } : {}
47301
47336
  };
47302
47337
  }
47303
47338
  function mergePushInputs(content, flags) {
47304
47339
  const merged = { ...content };
47305
47340
  for (const [flag, apply] of FLAG_SETTERS) {
47306
- const value = text3(flags[flag]);
47341
+ const value = text4(flags[flag]);
47307
47342
  if (value !== void 0) apply(merged, value);
47308
47343
  }
47309
47344
  return merged;
47310
47345
  }
47311
47346
  function missingPushInputs(i, scope) {
47312
47347
  const needed = scope === "push_and_signing" ? [...REQUIRED_ORDER, ...ASC_ORDER] : REQUIRED_ORDER;
47313
- return needed.filter((name) => !text3(i[name]));
47348
+ return needed.filter((name) => !text4(i[name]));
47314
47349
  }
47315
47350
  function ascGroupError(i) {
47316
- const present = ASC_ORDER.filter((name) => text3(i[name])).length;
47351
+ const present = ASC_ORDER.filter((name) => text4(i[name])).length;
47317
47352
  return present === 0 || present === ASC_ORDER.length ? null : "incomplete_asc_group";
47318
47353
  }
47319
47354
  function localIdentityRefusal(i) {
@@ -47382,8 +47417,8 @@ function validateApnsAuthKey(body) {
47382
47417
  return { ok: true };
47383
47418
  }
47384
47419
  function buildPushSetupBody(i, keys) {
47385
- const missing = REQUIRED_ORDER.filter((name) => !text3(i[name]));
47386
- const app = text3(i.app);
47420
+ const missing = REQUIRED_ORDER.filter((name) => !text4(i[name]));
47421
+ const app = text4(i.app);
47387
47422
  if (!app) return { ok: false, code: "app_not_initialized", missing };
47388
47423
  if (missing.length > 0) return { ok: false, code: "needs_input", missing };
47389
47424
  if (i.apnsEnvironment !== "development" && i.apnsEnvironment !== "production") {
@@ -47463,7 +47498,7 @@ function savePushSelection(dir, input) {
47463
47498
  if (input.androidApplicationId) selection.androidApplicationId = input.androidApplicationId;
47464
47499
  writeFile(dir, { ...readPushOnboarding(dir), selection });
47465
47500
  }
47466
- var PUSH_ONBOARDING_PATH, MAX_KEY_FILE_BYTES, SITE_RE, APP_RE, ANDROID_ID_RE, PLACEHOLDER_BUNDLE_RE, text3, FLAG_SETTERS, REQUIRED_ORDER, ASC_ORDER, NOTE;
47501
+ var PUSH_ONBOARDING_PATH, MAX_KEY_FILE_BYTES, SITE_RE, APP_RE, ANDROID_ID_RE, PLACEHOLDER_BUNDLE_RE, text4, FLAG_SETTERS, REQUIRED_ORDER, ASC_ORDER, NOTE;
47467
47502
  var init_push_onboarding = __esm({
47468
47503
  "src/push-onboarding.ts"() {
47469
47504
  PUSH_ONBOARDING_PATH = ".himi/push-onboarding.json";
@@ -47472,7 +47507,7 @@ var init_push_onboarding = __esm({
47472
47507
  APP_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
47473
47508
  ANDROID_ID_RE = /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$/;
47474
47509
  PLACEHOLDER_BUNDLE_RE = /^com\.example\.|^__HIMI_APP_/;
47475
- text3 = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
47510
+ text4 = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
47476
47511
  FLAG_SETTERS = [
47477
47512
  ["app", (m, v) => {
47478
47513
  m.app = v;
@@ -47604,7 +47639,7 @@ async function runNotifySetup(pos, flags, io, deps = {}) {
47604
47639
  if (operation !== "setup" && operation !== "status") return refuse2(io, "invalid_notify_operation");
47605
47640
  const flagError = pushSetupFlagError(flags);
47606
47641
  if (flagError) return refuse2(io, flagError);
47607
- const dir = resolve38(text4(flags.content) ?? process.cwd());
47642
+ const dir = resolve38(text5(flags.content) ?? process.cwd());
47608
47643
  const local = readPushOnboarding(dir);
47609
47644
  const progress = local.push;
47610
47645
  const content = pushInputsFromContent(dir);
@@ -47636,26 +47671,10 @@ async function runNotifySetup(pos, flags, io, deps = {}) {
47636
47671
  return 2;
47637
47672
  }
47638
47673
  if (operation === "setup" && ascGroupError(input)) return refuse2(io, "incomplete_asc_group");
47639
- let target;
47640
- try {
47641
- target = resolveTarget({ target: text4(flags.target), defaultTarget: "wix", controlUrl: text4(flags["control-url"]), controlToken: text4(flags["control-token"]), ownerIssueUrl: text4(flags["owner-issue-url"]) });
47642
- } catch {
47643
- return refuse2(io, "unknown_target", "Select a configured serve target.");
47644
- }
47645
- if (credentialHostRefusal(target.control)) return refuse2(io, "insecure_target");
47646
- const previewTag = text4(flags["preview-tag"]) ?? process.env.HIMI_SERVE_PREVIEW_TAG;
47647
- if (previewTag !== void 0 && !/^dp-[a-z0-9]+$/.test(previewTag)) return refuse2(io, "invalid_preview_tag");
47648
- const token = target.controlToken;
47649
- if (!token || !decodeControlTokenClaims(token)?.sub) return refuse2(io, "owner_login_required", "Run himi login --browser --target wix.");
47650
- let wixToken;
47651
- try {
47652
- wixToken = await (deps.wixToken ?? accountToken)();
47653
- } catch {
47654
- return refuse2(io, "wix_account_token_required", "Browser login supplies a Himi control token only. Sign into the Wix CLI with wix login, using the same Wix account, then retry. You can continue building without push setup.", 1);
47655
- }
47656
- if (!wixToken) return refuse2(io, "wix_account_token_required", "Run wix login using the same Wix account.", 1);
47657
- if (!target.ownerIssue) return refuse2(io, "owner_issuer_required");
47658
- const ownershipArgs = { ownerIssue: target.ownerIssue, controlToken: token, declaredName: input.app, fetchImpl: deps.fetchImpl };
47674
+ const owner = await hostedOwnerSession(flags, deps);
47675
+ if (!owner.ok) return refuse2(io, owner.error, owner.hint, owner.exit);
47676
+ const { target, controlToken: token, wixToken, previewTag, ownerIssue } = owner.session;
47677
+ const ownershipArgs = { ownerIssue, controlToken: token, declaredName: input.app, fetchImpl: deps.fetchImpl };
47659
47678
  let ownership = await verifyAppOwnership(ownershipArgs);
47660
47679
  logOwnershipFailure(io, ownership);
47661
47680
  if (ownership.state !== "owned" && ownership.state !== "not_claimed") return refuse2(io, `app_ownership_${ownership.state}`, "Setup requires the app owner; retry after ownership is verified.", 1);
@@ -47701,7 +47720,7 @@ async function runNotifySetup(pos, flags, io, deps = {}) {
47701
47720
  }
47702
47721
  }
47703
47722
  if (ownership.state === "not_claimed") {
47704
- const claim = await autoClaimSlug({ ownerIssue: target.ownerIssue, controlToken: token, app: input.app, accountId: text4(flags["account-id"]), fetchImpl: deps.fetchImpl });
47723
+ const claim = await autoClaimSlug({ ownerIssue, controlToken: token, app: input.app, accountId: text5(flags["account-id"]), fetchImpl: deps.fetchImpl });
47705
47724
  if (claim.fatal) return refuse2(io, "app_claim_refused", "Check app ownership and the selected account.", 1);
47706
47725
  ownership = await verifyAppOwnership({ ...ownershipArgs, declaredName: claim.slug ?? input.app });
47707
47726
  logOwnershipFailure(io, ownership);
@@ -47751,17 +47770,15 @@ async function offerPushSetup(options) {
47751
47770
  return { status: "needs_attention", resume: resume(contentDir2) };
47752
47771
  }
47753
47772
  }
47754
- var text4, obj2, STATES, CHECKS, CHECK_STATES, STAGES, ERROR_CODES, PROMPTS, later, resume;
47773
+ var text5, obj2, STATES, CHECKS, CHECK_STATES, STAGES, ERROR_CODES, PROMPTS, later, resume;
47755
47774
  var init_notify_setup = __esm({
47756
47775
  "src/notify-setup.ts"() {
47757
- init_config();
47758
- init_credential_hosts();
47759
47776
  init_push_setup();
47760
47777
  init_push_setup_apple_credentials();
47761
- init_wix_owner();
47762
47778
  init_owner_claim();
47779
+ init_hosted_owner();
47763
47780
  init_push_onboarding();
47764
- text4 = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
47781
+ text5 = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
47765
47782
  obj2 = (v) => v && typeof v === "object" && !Array.isArray(v) ? v : {};
47766
47783
  STATES = /* @__PURE__ */ new Set(["not_configured", "provisioning", "ready", "needs_attention"]);
47767
47784
  CHECKS = ["brandedRecord", "pingApns", "pingFcm", "appleSigning", "nativeBuild", "himiRouting", "deviceDelivery"];
@@ -48456,7 +48473,7 @@ function thin(items, max) {
48456
48473
  function planReel(dir) {
48457
48474
  const memory = loadMemory2(dir);
48458
48475
  const { entries } = readProgress(dir);
48459
- const summary = summarizeProgress(entries);
48476
+ const summary2 = summarizeProgress(entries);
48460
48477
  const manifest = readJson5(join45(dir, "himalaya.content.json"));
48461
48478
  const tokens = readJson5(join45(dir, "tokens.json"));
48462
48479
  const accentToken = tokens?.colors?.accentPrimary;
@@ -48476,9 +48493,9 @@ function planReel(dir) {
48476
48493
  by: isCliEntry(e) ? CLI_AUTHOR : null,
48477
48494
  files: (Array.isArray(e.images) ? e.images : []).map((i) => isObj3(i) && typeof i.file === "string" ? basename13(i.file) : "").filter((f) => HISTORY_NAME.test(f))
48478
48495
  }));
48479
- const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
48496
+ const times = [summary2.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
48480
48497
  const startedAt = times[0] ?? null;
48481
- const endedAt = [summary.lastAt, ...timeline.map((t) => t.ts)].filter((x) => !!x).sort().pop() ?? null;
48498
+ const endedAt = [summary2.lastAt, ...timeline.map((t) => t.ts)].filter((x) => !!x).sort().pop() ?? null;
48482
48499
  return {
48483
48500
  app: typeof manifest?.name === "string" && manifest.name ? manifest.name : basename13(dir),
48484
48501
  accent,
@@ -48778,9 +48795,9 @@ async function firstLookAtInit(dir, opts) {
48778
48795
  child.on("error", (e) => finish2({ skipped: `the render did not start: ${e.message}` }));
48779
48796
  child.on("close", (code) => {
48780
48797
  clearTimeout(hardKill);
48781
- let report2 = null;
48798
+ let report3 = null;
48782
48799
  try {
48783
- report2 = JSON.parse(Buffer.concat(out2).toString("utf8"));
48800
+ report3 = JSON.parse(Buffer.concat(out2).toString("utf8"));
48784
48801
  } catch {
48785
48802
  }
48786
48803
  let fresh = false;
@@ -48789,7 +48806,7 @@ async function firstLookAtInit(dir, opts) {
48789
48806
  } catch {
48790
48807
  }
48791
48808
  if (code === 0 && fresh) return finish2({ image: `.himi/shots/${home}.png` });
48792
- if (report2?.pngUnavailable) return finish2({ skipped: "no headless browser to draw the PNG \u2014 `npx playwright install chromium`, then run the render step below" });
48809
+ if (report3?.pngUnavailable) return finish2({ skipped: "no headless browser to draw the PNG \u2014 `npx playwright install chromium`, then run the render step below" });
48793
48810
  let refusal = null;
48794
48811
  for (const line of errTail.trim().split("\n").reverse()) {
48795
48812
  try {
@@ -48799,7 +48816,7 @@ async function firstLookAtInit(dir, opts) {
48799
48816
  }
48800
48817
  if (refusal) break;
48801
48818
  }
48802
- const why = typeof report2?.reason === "string" ? report2.reason : typeof report2?.error === "string" ? report2.error : refusal;
48819
+ const why = typeof report3?.reason === "string" ? report3.reason : typeof report3?.error === "string" ? report3.error : refusal;
48803
48820
  finish2({ skipped: `the render made no picture (exit ${code ?? "killed"})${why ? `: ${why.slice(0, 200)}` : ""}` });
48804
48821
  });
48805
48822
  });
@@ -49754,9 +49771,9 @@ function bundlesOf(block) {
49754
49771
  walk2(block);
49755
49772
  return [...out2];
49756
49773
  }
49757
- function parseJson2(text6, what) {
49774
+ function parseJson2(text8, what) {
49758
49775
  try {
49759
- const value = JSON.parse(text6);
49776
+ const value = JSON.parse(text8);
49760
49777
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("not an object");
49761
49778
  return value;
49762
49779
  } catch (e) {
@@ -49991,25 +50008,25 @@ function pruneChrome(items, removed, ledger) {
49991
50008
  }
49992
50009
  function rewriteNav(nav, removed, homeId) {
49993
50010
  const next = structuredClone(nav);
49994
- const report2 = { linkable: [], tabs: [], drawer: [], sidebar: [], deepLinkPatterns: [], topBarActions: [], headerActions: [], surfaceDestinations: [], appIconBadgeSources: [], reparented: [] };
50011
+ const report3 = { linkable: [], tabs: [], drawer: [], sidebar: [], deepLinkPatterns: [], topBarActions: [], headerActions: [], surfaceDestinations: [], appIconBadgeSources: [], reparented: [] };
49995
50012
  const tabItems = asItems(next.tabBar);
49996
50013
  const hadTabs = !!tabItems?.length;
49997
- if (tabItems) next.tabBar.items = pruneChrome(tabItems, removed, report2.tabs);
50014
+ if (tabItems) next.tabBar.items = pruneChrome(tabItems, removed, report3.tabs);
49998
50015
  const drawerItems = asItems(next.drawer);
49999
- if (drawerItems) next.drawer.items = pruneChrome(drawerItems, removed, report2.drawer);
50016
+ if (drawerItems) next.drawer.items = pruneChrome(drawerItems, removed, report3.drawer);
50000
50017
  const sidebarItems = asItems(next.sidebar);
50001
- if (sidebarItems) next.sidebar.items = pruneChrome(sidebarItems, removed, report2.sidebar);
50018
+ if (sidebarItems) next.sidebar.items = pruneChrome(sidebarItems, removed, report3.sidebar);
50002
50019
  if (hadTabs && !asItems(next.tabBar).length) {
50003
- throw new TrimRefusal(`no tab would remain \u2014 every tabBar item opens a screen this trim removes (${report2.tabs.join(", ")}); keep at least one tab's screen`, { removedTabs: report2.tabs });
50020
+ throw new TrimRefusal(`no tab would remain \u2014 every tabBar item opens a screen this trim removes (${report3.tabs.join(", ")}); keep at least one tab's screen`, { removedTabs: report3.tabs });
50004
50021
  }
50005
50022
  const remainingRoots = [...asItems(next.tabBar) ?? [], ...asItems(next.sidebar) ?? []].filter((i) => i.role !== "section");
50006
50023
  const remainingRootIds = new Set(remainingRoots.map((i) => i.id).filter((id) => typeof id === "string"));
50007
- const removedRootIds = /* @__PURE__ */ new Set([...report2.tabs, ...report2.sidebar]);
50024
+ const removedRootIds = /* @__PURE__ */ new Set([...report3.tabs, ...report3.sidebar]);
50008
50025
  if (Array.isArray(next.deepLinkPatterns)) {
50009
50026
  next.deepLinkPatterns = next.deepLinkPatterns.filter((p) => {
50010
50027
  const id = p?.params?.screenId ?? p?.screenId;
50011
50028
  if (typeof id === "string" && removed(id)) {
50012
- report2.deepLinkPatterns.push(String(p.pattern ?? id));
50029
+ report3.deepLinkPatterns.push(String(p.pattern ?? id));
50013
50030
  return false;
50014
50031
  }
50015
50032
  return true;
@@ -50020,7 +50037,7 @@ function rewriteNav(nav, removed, homeId) {
50020
50037
  if (!Array.isArray(actions)) continue;
50021
50038
  next[key2].header.actions = actions.filter((a) => {
50022
50039
  if (!(typeof a?.screenId === "string" && removed(a.screenId))) return true;
50023
- report2.headerActions.push(`${key2}:${String(a.icon ?? a.screenId)}`);
50040
+ report3.headerActions.push(`${key2}:${String(a.icon ?? a.screenId)}`);
50024
50041
  return false;
50025
50042
  });
50026
50043
  }
@@ -50029,7 +50046,7 @@ function rewriteNav(nav, removed, homeId) {
50029
50046
  next.topBarDefault.actions = topActions.filter((a) => {
50030
50047
  const to = openTarget(a?.onTap) ?? openTarget(a?.action);
50031
50048
  if (to && removed(to)) {
50032
- report2.topBarActions.push(entryLabel(a));
50049
+ report3.topBarActions.push(entryLabel(a));
50033
50050
  return false;
50034
50051
  }
50035
50052
  return true;
@@ -50044,7 +50061,7 @@ function rewriteNav(nav, removed, homeId) {
50044
50061
  for (const [dest, screenId] of Object.entries(cfg.screenIds)) {
50045
50062
  if (goneDest(dest) || typeof screenId === "string" && removed(screenId)) {
50046
50063
  delete cfg.screenIds[dest];
50047
- report2.surfaceDestinations.push(`${surface}:${dest}`);
50064
+ report3.surfaceDestinations.push(`${surface}:${dest}`);
50048
50065
  if (!remainingRootIds.has(dest)) unmapped.add(dest);
50049
50066
  }
50050
50067
  }
@@ -50054,24 +50071,24 @@ function rewriteNav(nav, removed, homeId) {
50054
50071
  const gone = goneDest(id) || typeof id === "string" && unmapped.has(id);
50055
50072
  if (!gone) return true;
50056
50073
  const entry = `${surface}:${String(id)}`;
50057
- if (!report2.surfaceDestinations.includes(entry)) report2.surfaceDestinations.push(entry);
50074
+ if (!report3.surfaceDestinations.includes(entry)) report3.surfaceDestinations.push(entry);
50058
50075
  return false;
50059
50076
  });
50060
50077
  }
50061
50078
  }
50062
50079
  }
50063
50080
  if (Array.isArray(next.appIconBadgeSources)) {
50064
- const goneActions = new Set(report2.topBarActions);
50081
+ const goneActions = new Set(report3.topBarActions);
50065
50082
  const idsOf = (items) => new Set((items ?? []).map((i) => i.id).filter((x) => typeof x === "string"));
50066
- const removedTabs = new Set(report2.tabs);
50067
- const removedDrawer = new Set(report2.drawer);
50083
+ const removedTabs = new Set(report3.tabs);
50084
+ const removedDrawer = new Set(report3.drawer);
50068
50085
  const remainingTabIds = idsOf(asItems(next.tabBar));
50069
50086
  const remainingDrawerIds = idsOf(asItems(next.drawer));
50070
50087
  next.appIconBadgeSources = next.appIconBadgeSources.filter((s) => {
50071
50088
  if (typeof s !== "string") return true;
50072
50089
  const [kind, id] = [s.slice(0, s.indexOf(":")), s.slice(s.indexOf(":") + 1)];
50073
50090
  const gone = kind === "topBarAction" ? goneActions.has(id) : kind === "tab" ? removedTabs.has(id) && !remainingTabIds.has(id) : kind === "drawer" ? removedDrawer.has(id) && !remainingDrawerIds.has(id) : false;
50074
- if (gone) report2.appIconBadgeSources.push(s);
50091
+ if (gone) report3.appIconBadgeSources.push(s);
50075
50092
  return !gone;
50076
50093
  });
50077
50094
  }
@@ -50081,7 +50098,7 @@ function rewriteNav(nav, removed, homeId) {
50081
50098
  for (const l of original) if (typeof l.screenId === "string") byId.set(l.screenId, l);
50082
50099
  const kept = original.filter((l) => {
50083
50100
  if (typeof l.screenId === "string" && removed(l.screenId)) {
50084
- report2.linkable.push(l.screenId);
50101
+ report3.linkable.push(l.screenId);
50085
50102
  return false;
50086
50103
  }
50087
50104
  return true;
@@ -50125,7 +50142,7 @@ function rewriteNav(nav, removed, homeId) {
50125
50142
  const entry = { screenId: String(l.screenId) };
50126
50143
  if (toParent !== fromParent) entry.parentScreenId = { from: fromParent, to: toParent };
50127
50144
  if (toTab !== fromTab) entry.tabId = { from: fromTab, to: toTab };
50128
- report2.reparented.push(entry);
50145
+ report3.reparented.push(entry);
50129
50146
  }
50130
50147
  for (const l of kept) {
50131
50148
  if (typeof l.parentScreenId === "string") l.parentScreenId = newParent(l);
@@ -50133,7 +50150,7 @@ function rewriteNav(nav, removed, homeId) {
50133
50150
  }
50134
50151
  next.linkableScreens = kept;
50135
50152
  }
50136
- return { nav: next, report: report2 };
50153
+ return { nav: next, report: report3 };
50137
50154
  }
50138
50155
  function leftoverNavRefs(nav, removedIds) {
50139
50156
  const gone = new Set(removedIds);
@@ -50292,9 +50309,9 @@ function planTrim(src, keepIds, links) {
50292
50309
  for (const r of keptRoutes) for (const b of r.bundles) keptWorkers.add(b);
50293
50310
  const importsOf = (dir) => {
50294
50311
  const out2 = [];
50295
- for (const [rel, text6] of Object.entries(src.workerFiles)) {
50312
+ for (const [rel, text8] of Object.entries(src.workerFiles)) {
50296
50313
  if (!rel.startsWith(`tier5-src/${dir}/`)) continue;
50297
- for (const m of text6.matchAll(/(?:\bfrom\s*|\bimport\s*\(?\s*|\brequire\s*\(\s*)["']\.\.\/([A-Za-z0-9_.-]+)(?:\/|["'])/g)) out2.push(m[1]);
50314
+ for (const m of text8.matchAll(/(?:\bfrom\s*|\bimport\s*\(?\s*|\brequire\s*\(\s*)["']\.\.\/([A-Za-z0-9_.-]+)(?:\/|["'])/g)) out2.push(m[1]);
50298
50315
  }
50299
50316
  return out2;
50300
50317
  };
@@ -50340,9 +50357,9 @@ function planTrim(src, keepIds, links) {
50340
50357
  continue;
50341
50358
  }
50342
50359
  const block = edited.get(r);
50343
- let text6 = block ? serializeAt(block, app.dev, r.open) : void 0;
50344
- if (r === app.home && homeModules?.text !== void 0) text6 = homeModules.text;
50345
- if (text6 !== void 0) cut2(r.open, r.close, text6);
50360
+ let text8 = block ? serializeAt(block, app.dev, r.open) : void 0;
50361
+ if (r === app.home && homeModules?.text !== void 0) text8 = homeModules.text;
50362
+ if (text8 !== void 0) cut2(r.open, r.close, text8);
50346
50363
  }
50347
50364
  if (templatedEmptied) cut2(templatedEmptied[0], templatedEmptied[1], "\n");
50348
50365
  dev += app.dev.slice(cursor);
@@ -50358,7 +50375,7 @@ function planTrim(src, keepIds, links) {
50358
50375
  for (const e of edits.sort((a, b) => b.start - a.start)) config = config.slice(0, e.start) + e.text + config.slice(e.end);
50359
50376
  const keptExact = keptRoutes.filter((r) => r.kind === "screen");
50360
50377
  const keptTemplated = keptRoutes.filter((r) => r.kind === "templated");
50361
- const report2 = {
50378
+ const report3 = {
50362
50379
  ...links ? { links } : {},
50363
50380
  kept: { screens: sorted(keptExact.map((r) => r.label)), templated: sorted(keptTemplated.map((r) => r.label)) },
50364
50381
  implicit: implicit.map((r) => r.label),
@@ -50388,16 +50405,16 @@ function planTrim(src, keepIds, links) {
50388
50405
  },
50389
50406
  bytes: { before: Buffer.byteLength(app.dev), after: Buffer.byteLength(dev) }
50390
50407
  };
50391
- return { dev, config, removedWorkers, removedIds, report: report2 };
50408
+ return { dev, config, removedWorkers, removedIds, report: report3 };
50392
50409
  }
50393
50410
  function homeModulesPass(app, kept, edited) {
50394
50411
  const verticals = Object.entries(EXPLORE_CARDS).filter(([, card2]) => app.exact.has(card2.screenId));
50395
50412
  const removedVertical = verticals.some(([, card2]) => !kept.has(app.exact.get(card2.screenId)));
50396
50413
  if (!removedVertical) return { dropped: [] };
50397
50414
  const block = edited.get(app.home);
50398
- const text6 = block ? serializeAt(block, app.dev, app.home.open) : app.dev.slice(app.home.open, app.home.close);
50415
+ const text8 = block ? serializeAt(block, app.dev, app.home.open) : app.dev.slice(app.home.open, app.home.close);
50399
50416
  const installed = verticals.filter(([, card2]) => kept.has(app.exact.get(card2.screenId))).map(([v]) => v);
50400
- const patched = patchHomeModules(text6, installed);
50417
+ const patched = patchHomeModules(text8, installed);
50401
50418
  if (!patched.droppedModules.length) return { dropped: [] };
50402
50419
  return { text: patched.src, dropped: patched.droppedModules };
50403
50420
  }
@@ -51111,8 +51128,8 @@ function isNoneEntry(entry) {
51111
51128
  const head = entryHead(entry);
51112
51129
  return NONE.test(entry) || head !== "" && NONE.test(head);
51113
51130
  }
51114
- function parseDataAccess(text6, from) {
51115
- const body = text6.replace(/<!--[\s\S]*?(?:-->|$)/g, "");
51131
+ function parseDataAccess(text8, from) {
51132
+ const body = text8.replace(/<!--[\s\S]*?(?:-->|$)/g, "");
51116
51133
  const heading = new RegExp(`(?:^|\\n)##[ \\t]+${DATA_ACCESS_HEADING}\\b[^\\n]*([\\s\\S]*?)(?=\\n##[ \\t]|$)`, "i").exec(body);
51117
51134
  if (!heading) return null;
51118
51135
  const lines = heading[1].split("\n").map((l) => l.trim()).filter((l) => l.startsWith("|"));
@@ -51139,13 +51156,13 @@ function readDataAccess(dir) {
51139
51156
  for (const name of ["SPEC.md", "MOBILE-UX.md"]) {
51140
51157
  const p = join49(dir, name);
51141
51158
  if (!existsSync50(p)) continue;
51142
- let text6;
51159
+ let text8;
51143
51160
  try {
51144
- text6 = readFileSync55(p, "utf8");
51161
+ text8 = readFileSync55(p, "utf8");
51145
51162
  } catch {
51146
51163
  continue;
51147
51164
  }
51148
- const plan = parseDataAccess(text6, name);
51165
+ const plan = parseDataAccess(text8, name);
51149
51166
  if (plan) return plan;
51150
51167
  }
51151
51168
  return null;
@@ -51298,7 +51315,7 @@ function readTestConfig(dir) {
51298
51315
  if (input !== void 0 && (!input || typeof input !== "object" || Array.isArray(input) || Object.values(input).some((v) => typeof v !== "string"))) {
51299
51316
  throw new Error(`${TEST_CONFIG_FILE}: journeys[${i}].input must be an object of string values \u2014 the screen input a nav edge would send, e.g. { "id": "svc-0001" }`);
51300
51317
  }
51301
- if (!Array.isArray(journey.expectText) || !journey.expectText.length || journey.expectText.some((text6) => typeof text6 !== "string" || !text6.trim())) {
51318
+ if (!Array.isArray(journey.expectText) || !journey.expectText.length || journey.expectText.some((text8) => typeof text8 !== "string" || !text8.trim())) {
51302
51319
  throw new Error(`${TEST_CONFIG_FILE}: journeys[${i}] needs non-empty expectText values that prove a visible result`);
51303
51320
  }
51304
51321
  });
@@ -51359,16 +51376,16 @@ function readCannedResponses() {
51359
51376
  }
51360
51377
  function makeRecordingWixCall(send2, token, app) {
51361
51378
  const events = [];
51362
- const refused = [];
51379
+ const refused2 = [];
51363
51380
  let id = 0;
51364
51381
  const call = async (method, path2, body) => {
51365
51382
  const verb = method.toUpperCase();
51366
51383
  if (/[#\x00-\x1F\x7F]/.test(path2)) {
51367
- refused.push(`${verb} ${path2}`);
51384
+ refused2.push(`${verb} ${path2}`);
51368
51385
  throw new Error(`--record refused ${verb} ${path2}: the path carries a fragment or control character \u2014 not a provable read`);
51369
51386
  }
51370
51387
  if (!isProvenRead(verb, path2)) {
51371
- refused.push(`${verb} ${path2}`);
51388
+ refused2.push(`${verb} ${path2}`);
51372
51389
  throw new Error(`--record refused ${verb} ${path2}: recording sends only proven reads (GET, or POST ending in /query, /search, /list*, /get*, /count, /aggregate, /facets, /connections) \u2014 if this IS a read, add its rule to dev/net-mocks.json by hand`);
51373
51390
  }
51374
51391
  const bodyStr = body === void 0 ? void 0 : typeof body === "string" ? body : JSON.stringify(body);
@@ -51395,7 +51412,7 @@ function makeRecordingWixCall(send2, token, app) {
51395
51412
  return r.body;
51396
51413
  }
51397
51414
  };
51398
- return { call, events, refused };
51415
+ return { call, events, refused: refused2 };
51399
51416
  }
51400
51417
  async function runRecordPass(opts) {
51401
51418
  const bootErrors = [];
@@ -51799,9 +51816,9 @@ function formatReport(r) {
51799
51816
  out2.push(`transport: ${r.transport}`);
51800
51817
  if (r.nativeDecode) {
51801
51818
  for (const platform of ["ios", "android"]) {
51802
- const summary = r.nativeDecode[platform];
51803
- if (!summary) continue;
51804
- out2.push("unavailable" in summary ? `native decode ${platform}: unavailable \u2014 ${summary.reason}` : `native decode ${platform}: ${summary.checked} checked, ${summary.failed} failed in ${r.nativeDecode.wallMs}ms`);
51819
+ const summary2 = r.nativeDecode[platform];
51820
+ if (!summary2) continue;
51821
+ out2.push("unavailable" in summary2 ? `native decode ${platform}: unavailable \u2014 ${summary2.reason}` : `native decode ${platform}: ${summary2.checked} checked, ${summary2.failed} failed in ${r.nativeDecode.wallMs}ms`);
51805
51822
  }
51806
51823
  }
51807
51824
  out2.push("");
@@ -51944,14 +51961,14 @@ import { join as join51 } from "node:path";
51944
51961
  function mobileUxIssues(dir, strict) {
51945
51962
  const file = join51(dir, "MOBILE-UX.md");
51946
51963
  if (!existsSync52(file)) return [];
51947
- let text6;
51964
+ let text8;
51948
51965
  try {
51949
- text6 = readFileSync57(file, "utf8");
51966
+ text8 = readFileSync57(file, "utf8");
51950
51967
  } catch {
51951
51968
  return [];
51952
51969
  }
51953
- if (!text6) return [];
51954
- return mobileUxMarkerFindings(text6, recordedRenderWidths(dir)).map((finding) => {
51970
+ if (!text8) return [];
51971
+ return mobileUxMarkerFindings(text8, recordedRenderWidths(dir)).map((finding) => {
51955
51972
  const scaffoldAdvisory = finding.code === "missing-width-evidence";
51956
51973
  return {
51957
51974
  screen: null,
@@ -52246,7 +52263,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
52246
52263
  const headers2 = Object.fromEntries(new Headers(init.headers).entries());
52247
52264
  const request = url.protocol === "https:" ? httpsRequest : httpRequest;
52248
52265
  const hostname2 = url.hostname.replace(/^\[|\]$/g, "");
52249
- return await new Promise((resolve52, reject) => {
52266
+ return await new Promise((resolve53, reject) => {
52250
52267
  let settled = false;
52251
52268
  const finish2 = (fn) => {
52252
52269
  if (settled) return;
@@ -52283,7 +52300,7 @@ async function pinnedFetch(url, init, addresses, maxResponseBytes) {
52283
52300
  }
52284
52301
  const responseHeaders = new Headers();
52285
52302
  for (const [key2, value] of Object.entries(response.headers)) if (value !== void 0) responseHeaders.set(key2, Array.isArray(value) ? value.join(", ") : value);
52286
- resolve52(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
52303
+ resolve53(new Response(bytes2, { status: response.statusCode, statusText: response.statusMessage, headers: responseHeaders }));
52287
52304
  }));
52288
52305
  });
52289
52306
  req.once("error", (error) => finish2(() => reject(error)));
@@ -52583,7 +52600,7 @@ function createLocalTestSandbox() {
52583
52600
  }
52584
52601
  })();
52585
52602
  `;
52586
- return await new Promise((resolve52, reject) => {
52603
+ return await new Promise((resolve53, reject) => {
52587
52604
  const { port1, port2 } = new MessageChannel();
52588
52605
  const serializableContext = {
52589
52606
  auth: context.auth,
@@ -52659,7 +52676,7 @@ function createLocalTestSandbox() {
52659
52676
  timer = setTimeout(() => finish2(() => reject(new SandboxError("timeout", `execution exceeded ${limits.timeoutMs}ms`))), Math.max(1, limits.timeoutMs));
52660
52677
  return;
52661
52678
  }
52662
- if (message.ok) finish2(() => resolve52({ value: message.value, durationMs: Date.now() - started }));
52679
+ if (message.ok) finish2(() => resolve53({ value: message.value, durationMs: Date.now() - started }));
52663
52680
  else finish2(() => reject(new SandboxError("execution_failed", message.message ?? "handler failed")));
52664
52681
  });
52665
52682
  worker.once("error", (error) => finish2(() => reject(new SandboxError("execution_failed", error.message))));
@@ -53775,12 +53792,12 @@ async function runRemoteFunctionOperation(input) {
53775
53792
  if (input.boCookie) headers2.cookie = input.boCookie;
53776
53793
  if (input.previewToken) headers2["x-himalaya-preview-token"] = input.previewToken;
53777
53794
  const response = await (input.fetchImpl ?? fetch)(url, { method, headers: headers2 });
53778
- const text6 = await response.text();
53795
+ const text8 = await response.text();
53779
53796
  let body;
53780
53797
  try {
53781
- body = JSON.parse(text6);
53798
+ body = JSON.parse(text8);
53782
53799
  } catch {
53783
- body = text6;
53800
+ body = text8;
53784
53801
  }
53785
53802
  return { ok: response.ok, status: response.status, body };
53786
53803
  }
@@ -53868,7 +53885,7 @@ function flagShapedInputs(args) {
53868
53885
  function guarded(h) {
53869
53886
  return async (args, deps) => {
53870
53887
  const bad2 = flagShapedInputs(args);
53871
- if (bad2.length) return text5(`refused: ${bad2.join(", ")} may not start with "-" (it would be read as a himi flag)`, true);
53888
+ if (bad2.length) return text6(`refused: ${bad2.join(", ")} may not start with "-" (it would be read as a himi flag)`, true);
53872
53889
  return h(args, deps);
53873
53890
  };
53874
53891
  }
@@ -54021,7 +54038,7 @@ function rawTools() {
54021
54038
  return json3({ ...await d.preview.start(await appDir2(a, d)), hint: PREVIEW_HINT });
54022
54039
  } catch (e) {
54023
54040
  const log = e.log;
54024
- return text5(`${e.message}${typeof log === "string" && log ? `
54041
+ return text6(`${e.message}${typeof log === "string" && log ? `
54025
54042
 
54026
54043
  ${log}` : ""}`, true);
54027
54044
  }
@@ -54086,7 +54103,9 @@ ${log}` : ""}`, true);
54086
54103
  name: "himi_preview_links",
54087
54104
  title: "Preview links for a release",
54088
54105
  description: "The shareable web preview URL, the Himi Player deep link and the agent preview JSON URLs for an app + release (for example the draft `himi_push` just published).",
54089
- annotations: { ...PUBLISH, readOnlyHint: true, idempotentHint: true },
54106
+ // Not idempotent: with credentials, each `himi preview` mints a fresh single-use handover —
54107
+ // the same reason the hosted connector's tool of this name says false (RFC 0064 §5).
54108
+ annotations: { ...PUBLISH, readOnlyHint: true, idempotentHint: false },
54090
54109
  inputSchema: z.object({
54091
54110
  app: z.string().min(1),
54092
54111
  release: z.string().min(1),
@@ -54097,14 +54116,14 @@ ${log}` : ""}`, true);
54097
54116
  }
54098
54117
  ];
54099
54118
  }
54100
- var MAX_TEXT2, clip, text5, json3, opt, sw, DIR, LEARN, CHECK, LOCAL_WRITE, PUBLISH, PREVIEW_HINT, LOGIN_HINT;
54119
+ var MAX_TEXT2, clip, text6, json3, opt, sw, DIR, LEARN, CHECK, LOCAL_WRITE, PUBLISH, PREVIEW_HINT, LOGIN_HINT;
54101
54120
  var init_tools = __esm({
54102
54121
  "src/mcp/tools.ts"() {
54103
54122
  MAX_TEXT2 = 8e4;
54104
54123
  clip = (s) => s.length <= MAX_TEXT2 ? s : `${s.slice(0, MAX_TEXT2)}
54105
54124
  \u2026 [truncated ${s.length - MAX_TEXT2} chars \u2014 re-run the command in a terminal for the full output]`;
54106
- text5 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
54107
- json3 = (o) => text5(JSON.stringify(o, null, 2));
54125
+ text6 = (t, isError = false) => ({ content: [{ type: "text", text: t }], ...isError ? { isError: true } : {} });
54126
+ json3 = (o) => text6(JSON.stringify(o, null, 2));
54108
54127
  opt = (flag, v) => typeof v === "string" && v ? [flag, v] : typeof v === "number" ? [flag, String(v)] : [];
54109
54128
  sw = (flag, v) => v === true ? [flag] : [];
54110
54129
  DIR = z.string().optional().describe("The app (content package) directory. Default: the workspace root the host opened, else the server's working directory.");
@@ -54180,9 +54199,9 @@ async function startMcpServer(opts) {
54180
54199
  },
54181
54200
  readFile: (p) => readFileSync59(p)
54182
54201
  };
54183
- const closed = new Promise((resolve52) => {
54184
- stdin.once("end", resolve52);
54185
- stdin.once("close", resolve52);
54202
+ const closed = new Promise((resolve53) => {
54203
+ stdin.once("end", resolve53);
54204
+ stdin.once("close", resolve53);
54186
54205
  });
54187
54206
  const handle = serveStdio(
54188
54207
  () => {
@@ -54424,7 +54443,7 @@ function fieldAt(path2) {
54424
54443
  if (path2 === null) return void 0;
54425
54444
  return path2.match(/\.([^.[\]]+)$/)?.[1];
54426
54445
  }
54427
- function mergeNativeDecode(report2, run2) {
54446
+ function mergeNativeDecode(report3, run2) {
54428
54447
  const platformLabel = run2.platform === "ios" ? "iOS" : "Android";
54429
54448
  const nativeFailures = run2.verdicts.flatMap((verdict) => verdict.errors.map((error) => ({
54430
54449
  screen: verdict.screenId,
@@ -54437,18 +54456,18 @@ function mergeNativeDecode(report2, run2) {
54437
54456
  ...error.actual ? { actual: error.actual } : {},
54438
54457
  hint: `This descriptor ships as a full-screen \u201CCouldn't load\u201D; fix the typed field and rerun \`himi test --native ${run2.platform}\`.`
54439
54458
  })));
54440
- const failures = [...report2.failures, ...nativeFailures];
54459
+ const failures = [...report3.failures, ...nativeFailures];
54441
54460
  const failedScreens = new Set(failures.map((finding) => finding.screen));
54442
54461
  return {
54443
- ...report2,
54444
- ok: report2.ok && nativeFailures.length === 0,
54462
+ ...report3,
54463
+ ok: report3.ok && nativeFailures.length === 0,
54445
54464
  failures,
54446
- counts: { ...report2.counts, errors: failures.length },
54447
- screens: { ...report2.screens, clean: report2.screens.total - failedScreens.size, failed: failedScreens.size },
54465
+ counts: { ...report3.counts, errors: failures.length },
54466
+ screens: { ...report3.screens, clean: report3.screens.total - failedScreens.size, failed: failedScreens.size },
54448
54467
  nativeDecode: {
54449
- ...report2.nativeDecode,
54468
+ ...report3.nativeDecode,
54450
54469
  [run2.platform]: { checked: run2.verdicts.length, failed: run2.verdicts.filter((verdict) => !verdict.ok).length },
54451
- wallMs: (report2.nativeDecode?.wallMs ?? 0) + run2.wallMs
54470
+ wallMs: (report3.nativeDecode?.wallMs ?? 0) + run2.wallMs
54452
54471
  }
54453
54472
  };
54454
54473
  }
@@ -54561,10 +54580,10 @@ function collectSdkModules(files, resolveSubpath) {
54561
54580
  for (const source of Object.values(files)) visit(source);
54562
54581
  return { modules, unsupported };
54563
54582
  }
54564
- function sdkSubpathReader(resolve52) {
54583
+ function sdkSubpathReader(resolve53) {
54565
54584
  return (sub) => {
54566
54585
  try {
54567
- return readFileSync61(resolve52(`@wix/himalaya/${sub}`), "utf8");
54586
+ return readFileSync61(resolve53(`@wix/himalaya/${sub}`), "utf8");
54568
54587
  } catch {
54569
54588
  return null;
54570
54589
  }
@@ -54642,7 +54661,7 @@ async function runBrowserAuthoring(opts) {
54642
54661
  const token = mintToken2(payload);
54643
54662
  const unusable = await probeAuthoringPage(opts.authoringBase, opts.fetchImpl, opts.probeTimeoutMs);
54644
54663
  if (unusable) throw new Error(unusable);
54645
- return await new Promise((resolve52, reject) => {
54664
+ return await new Promise((resolve53, reject) => {
54646
54665
  let settled = false;
54647
54666
  let url = "";
54648
54667
  const server = createServer5();
@@ -54693,8 +54712,8 @@ async function runBrowserAuthoring(opts) {
54693
54712
  return;
54694
54713
  }
54695
54714
  res.writeHead(200, { "content-type": "text/plain" }).end("ok");
54696
- const report2 = body.result;
54697
- finish2(() => resolve52({ report: report2, url }));
54715
+ const report3 = body.result;
54716
+ finish2(() => resolve53({ report: report3, url }));
54698
54717
  })();
54699
54718
  });
54700
54719
  server.on("error", (e) => finish2(() => reject(e)));
@@ -55371,10 +55390,10 @@ async function hostedAuthUrl(req, visitorToken, fetchImpl = fetch) {
55371
55390
  }
55372
55391
  })
55373
55392
  });
55374
- const text6 = await res.text();
55393
+ const text8 = await res.text();
55375
55394
  let parsed = {};
55376
55395
  try {
55377
- parsed = text6 ? JSON.parse(text6) : {};
55396
+ parsed = text8 ? JSON.parse(text8) : {};
55378
55397
  } catch {
55379
55398
  }
55380
55399
  const fullUrl = parsed.redirectSession?.fullUrl;
@@ -55394,10 +55413,10 @@ async function exchangeAuthCode(cfg, code, verifier, fetchImpl = fetch) {
55394
55413
  redirectUri: cfg.redirectUri
55395
55414
  })
55396
55415
  });
55397
- const text6 = await res.text();
55416
+ const text8 = await res.text();
55398
55417
  let parsed = {};
55399
55418
  try {
55400
- parsed = text6 ? JSON.parse(text6) : {};
55419
+ parsed = text8 ? JSON.parse(text8) : {};
55401
55420
  } catch {
55402
55421
  }
55403
55422
  if (res.status !== 200 || !parsed.access_token) throw new Error(`token exchange failed (${res.status})`);
@@ -56611,11 +56630,11 @@ async function localizeConfigResponse(res, kind, header) {
56611
56630
  header
56612
56631
  )
56613
56632
  };
56614
- const text6 = JSON.stringify(next);
56633
+ const text8 = JSON.stringify(next);
56615
56634
  const headers2 = new Headers(res.headers);
56616
56635
  headers2.delete("etag");
56617
- headers2.set("content-length", String(new TextEncoder().encode(text6).length));
56618
- return new Response(text6, { status: 200, headers: headers2 });
56636
+ headers2.set("content-length", String(new TextEncoder().encode(text8).length));
56637
+ return new Response(text8, { status: 200, headers: headers2 });
56619
56638
  }
56620
56639
  function makeRunHandler(opts) {
56621
56640
  const mount = opts.chrome === "app" ? "/app" : "/preview";
@@ -56803,8 +56822,8 @@ var init_node_adapter = __esm({
56803
56822
  function authConfigOf(appConfig) {
56804
56823
  if (!appConfig) return void 0;
56805
56824
  try {
56806
- const text6 = typeof appConfig === "string" ? appConfig : new TextDecoder().decode(appConfig);
56807
- return JSON.parse(text6)?.authConfig ?? void 0;
56825
+ const text8 = typeof appConfig === "string" ? appConfig : new TextDecoder().decode(appConfig);
56826
+ return JSON.parse(text8)?.authConfig ?? void 0;
56808
56827
  } catch {
56809
56828
  return void 0;
56810
56829
  }
@@ -57414,16 +57433,16 @@ async function releasePayloadFromDir(root, app, header) {
57414
57433
  const manifest = await store.getManifest(app);
57415
57434
  if (!manifest) throw new Error(`no release manifest for ${app} under ${root}`);
57416
57435
  const b64 = (b) => b ? Buffer.from(b).toString("base64") : void 0;
57417
- const text6 = (b) => b ? new TextDecoder().decode(b) : void 0;
57436
+ const text8 = (b) => b ? new TextDecoder().decode(b) : void 0;
57418
57437
  const screens = {};
57419
57438
  const docs = {};
57420
57439
  const addDoc = async (hash) => {
57421
57440
  if (!hash || docs[hash] !== void 0) return;
57422
- const d = text6(await store.getDoc?.(app, hash) ?? null);
57441
+ const d = text8(await store.getDoc?.(app, hash) ?? null);
57423
57442
  if (d !== void 0) docs[hash] = d;
57424
57443
  };
57425
57444
  for (const [id, meta] of Object.entries(manifest.screens ?? {})) {
57426
- const s = text6(await store.getScreen(app, id));
57445
+ const s = text8(await store.getScreen(app, id));
57427
57446
  if (s !== void 0) screens[id] = s;
57428
57447
  await addDoc(meta.descriptorHash);
57429
57448
  }
@@ -57444,10 +57463,10 @@ async function releasePayloadFromDir(root, app, header) {
57444
57463
  }
57445
57464
  const widgets = {};
57446
57465
  for (const id of Object.keys(manifest.widgets ?? {})) {
57447
- const w = text6(await store.getWidget?.(app, id) ?? null);
57466
+ const w = text8(await store.getWidget?.(app, id) ?? null);
57448
57467
  if (w !== void 0) widgets[id] = w;
57449
57468
  }
57450
- const appConfig = text6(await store.getAppConfig(app));
57469
+ const appConfig = text8(await store.getAppConfig(app));
57451
57470
  const wixClientId = appConfigWixClientId(appConfig);
57452
57471
  return {
57453
57472
  app,
@@ -57457,7 +57476,7 @@ async function releasePayloadFromDir(root, app, header) {
57457
57476
  docs,
57458
57477
  assets,
57459
57478
  widgets,
57460
- tokens: text6(await store.getTokens(app)),
57479
+ tokens: text8(await store.getTokens(app)),
57461
57480
  appConfig,
57462
57481
  icon: b64(await store.getIcon?.(app) ?? null),
57463
57482
  header,
@@ -57987,10 +58006,10 @@ function scalar3(v) {
57987
58006
  }
57988
58007
  return t;
57989
58008
  }
57990
- function parseStoreConfig(text6) {
58009
+ function parseStoreConfig(text8) {
57991
58010
  const cfg = {};
57992
58011
  let section2 = null;
57993
- for (const raw of text6.split("\n")) {
58012
+ for (const raw of text8.split("\n")) {
57994
58013
  const line = strip2(raw);
57995
58014
  if (!line.trim()) continue;
57996
58015
  const indented = /^\s+/.test(raw);
@@ -58049,10 +58068,10 @@ function profilePath(name, home = homedir5()) {
58049
58068
  }
58050
58069
  return join59(credentialsDir(home), `${name}.json`);
58051
58070
  }
58052
- function parseProfile(text6, label2) {
58071
+ function parseProfile(text8, label2) {
58053
58072
  let doc;
58054
58073
  try {
58055
- doc = JSON.parse(text6);
58074
+ doc = JSON.parse(text8);
58056
58075
  } catch (e) {
58057
58076
  throw new Error(`${label2} is not valid JSON: ${e.message}`);
58058
58077
  }
@@ -58661,11 +58680,11 @@ async function registerBundleId(opts) {
58661
58680
  const j = await res.json();
58662
58681
  return { status: "created", id: j.data?.id };
58663
58682
  }
58664
- const text6 = await res.text();
58665
- if (res.status === 409 || /already (exists|in use)|duplicate|ENTITY_ERROR.*identifier/i.test(text6)) {
58683
+ const text8 = await res.text();
58684
+ if (res.status === 409 || /already (exists|in use)|duplicate|ENTITY_ERROR.*identifier/i.test(text8)) {
58666
58685
  return { status: "exists" };
58667
58686
  }
58668
- throw new Error(`POST /v1/bundleIds \u2192 ${res.status}: ${text6.slice(0, 300)}`);
58687
+ throw new Error(`POST /v1/bundleIds \u2192 ${res.status}: ${text8.slice(0, 300)}`);
58669
58688
  }
58670
58689
  async function main2() {
58671
58690
  const [app, ...rest] = process.argv.slice(2);
@@ -58943,12 +58962,12 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
58943
58962
  body = JSON.stringify({ value });
58944
58963
  }
58945
58964
  const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
58946
- const text6 = await response.text();
58965
+ const text8 = await response.text();
58947
58966
  let output;
58948
58967
  try {
58949
- output = JSON.parse(text6);
58968
+ output = JSON.parse(text8);
58950
58969
  } catch {
58951
- output = text6;
58970
+ output = text8;
58952
58971
  }
58953
58972
  if (!response.ok) throw new Error(typeof output === "string" ? output : JSON.stringify(output));
58954
58973
  io.log(JSON.stringify(output));
@@ -58964,6 +58983,217 @@ var init_secrets2 = __esm({
58964
58983
  }
58965
58984
  });
58966
58985
 
58986
+ // ../serve-cli/src/push-send.ts
58987
+ async function pushSendRequest(options) {
58988
+ const refusal = localRefusal(options);
58989
+ if (refusal) return { ok: false, status: 0, body: null, error: refusal };
58990
+ try {
58991
+ const response = await (options.fetchImpl ?? fetch)(`${options.target.control.replace(/\/+$/, "")}/v1/admin/push/send`, {
58992
+ method: "POST",
58993
+ headers: headersFor(options),
58994
+ redirect: "error",
58995
+ signal: AbortSignal.timeout(TIMEOUT_MS),
58996
+ body: JSON.stringify(options.body)
58997
+ });
58998
+ const retryAfterSec = response.status === 429 ? Number(response.headers.get("retry-after")) : NaN;
58999
+ return {
59000
+ ok: response.ok,
59001
+ status: response.status,
59002
+ body: objectFrom(await response.text()),
59003
+ ...Number.isFinite(retryAfterSec) && retryAfterSec > 0 ? { retryAfterSec } : {}
59004
+ };
59005
+ } catch {
59006
+ return { ok: false, status: 0, body: null, error: "push_send_unreachable" };
59007
+ }
59008
+ }
59009
+ function localRefusal(options) {
59010
+ if (!options.target.controlToken) return "control_token_required";
59011
+ if (!options.wixToken) return "wix_account_token_required";
59012
+ if (!options.siteToken) return "site_token_required";
59013
+ if (credentialHostRefusal(options.target.control)) return "insecure_target";
59014
+ if (options.previewTag !== void 0 && !PREVIEW_TAG2.test(options.previewTag)) return "invalid_preview_tag";
59015
+ return void 0;
59016
+ }
59017
+ function headersFor(options) {
59018
+ return {
59019
+ "x-control-token": options.target.controlToken,
59020
+ // RAW, never `Bearer ` — what normalizeWixAuthorization and token-info expect.
59021
+ Authorization: options.wixToken,
59022
+ [SITE_TOKEN_HEADER]: options.siteToken,
59023
+ accept: "application/json",
59024
+ "content-type": "application/json",
59025
+ ...options.previewTag ? { "x-wix-route-serve": options.previewTag } : {}
59026
+ };
59027
+ }
59028
+ function objectFrom(text8) {
59029
+ try {
59030
+ const value = text8 ? JSON.parse(text8) : null;
59031
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
59032
+ } catch {
59033
+ return null;
59034
+ }
59035
+ }
59036
+ var SITE_TOKEN_HEADER, PREVIEW_TAG2, TIMEOUT_MS;
59037
+ var init_push_send = __esm({
59038
+ "../serve-cli/src/push-send.ts"() {
59039
+ init_credential_hosts();
59040
+ SITE_TOKEN_HEADER = "x-himi-site-token";
59041
+ PREVIEW_TAG2 = /^dp-[a-z0-9]+$/;
59042
+ TIMEOUT_MS = 6e4;
59043
+ }
59044
+ });
59045
+
59046
+ // ../../core/serve-control/src/push-send-service.ts
59047
+ var PUSH_SEND_ERROR_CODES;
59048
+ var init_push_send_service = __esm({
59049
+ "../../core/serve-control/src/push-send-service.ts"() {
59050
+ PUSH_SEND_ERROR_CODES = [
59051
+ "unauthorized",
59052
+ "token_revoked",
59053
+ "revocation_check_unavailable",
59054
+ "method_not_allowed",
59055
+ "rate_limited",
59056
+ "forbidden_cross_tenant",
59057
+ "forbidden_site",
59058
+ "site_check_unavailable",
59059
+ "push_send_unconfigured",
59060
+ "push_send_unavailable",
59061
+ "invalid_input",
59062
+ "payload_too_large",
59063
+ "unknown_field",
59064
+ "invalid_app_id",
59065
+ "invalid_site_id",
59066
+ "invalid_member_email",
59067
+ "invalid_title",
59068
+ "invalid_body",
59069
+ "invalid_link",
59070
+ "invalid_request_id",
59071
+ "invalid_dry_run",
59072
+ "link_not_routable",
59073
+ "app_config_unavailable",
59074
+ "push_not_ready",
59075
+ "site_token_required",
59076
+ "site_token_invalid",
59077
+ "site_token_unverifiable",
59078
+ "member_not_found",
59079
+ "member_ambiguous",
59080
+ "member_not_active",
59081
+ "member_read_forbidden",
59082
+ "member_lookup_unavailable",
59083
+ "ping_unconfigured",
59084
+ "ping_permission_denied",
59085
+ "ping_rejected",
59086
+ "ping_rate_limited",
59087
+ "send_outcome_unknown"
59088
+ ];
59089
+ }
59090
+ });
59091
+
59092
+ // src/notify-ping.ts
59093
+ var notify_ping_exports = {};
59094
+ __export(notify_ping_exports, {
59095
+ runNotifyPing: () => runNotifyPing
59096
+ });
59097
+ import { randomUUID as randomUUID5 } from "node:crypto";
59098
+ import { resolve as resolve49 } from "node:path";
59099
+ function refuse4(io, error, hint, exit = 2, extra = {}) {
59100
+ io.error(JSON.stringify({ ok: false, error, ...hint ? { hint } : {}, ...extra }));
59101
+ return exit;
59102
+ }
59103
+ async function runNotifyPing(flags, io, deps = {}) {
59104
+ const flagError = flagRefusal(flags);
59105
+ if (flagError) return refuse4(io, flagError);
59106
+ const input = mergePushInputs(pushInputsFromContent(resolve49(text7(flags.content) ?? process.cwd())), flags);
59107
+ const missing = [...input.app ? [] : ["app"], ...input.site ? [] : ["site"], ...REQUIRED_FLAGS.filter((f) => !text7(flags[f]))];
59108
+ if (missing.length) return refuse4(io, "needs_input", "Name the app and site (or --content), the member's login email, a title and a link.", 2, { missing });
59109
+ const requestId2 = text7(flags["request-id"]) ?? (deps.newRequestId ?? randomUUID5)();
59110
+ if (!UUID_RE.test(requestId2)) return refuse4(io, "invalid_request_id", "Reuse the requestId a previous send printed.");
59111
+ const owner = await hostedOwnerSession(flags, deps);
59112
+ if (!owner.ok) return refuse4(io, owner.error, owner.hint, owner.exit);
59113
+ const { session } = owner;
59114
+ const ownership = await verifyAppOwnership({ ownerIssue: session.ownerIssue, controlToken: session.controlToken, declaredName: input.app, fetchImpl: deps.fetchImpl });
59115
+ if (ownership.state !== "owned") return refuse4(io, `app_ownership_${ownership.state}`, "Sending requires the app owner.", 1);
59116
+ let siteToken2;
59117
+ try {
59118
+ siteToken2 = await (deps.siteToken ?? siteToken)(input.site);
59119
+ } catch {
59120
+ return refuse4(io, "wix_site_token_required", "Run wix login as the site owner; the site token reads this site's members.", 1);
59121
+ }
59122
+ const body = {
59123
+ app: ownership.slug,
59124
+ site: input.site,
59125
+ memberEmail: text7(flags["member-email"]),
59126
+ title: text7(flags.title),
59127
+ ...text7(flags.body) ? { body: text7(flags.body) } : {},
59128
+ link: text7(flags.link),
59129
+ requestId: requestId2,
59130
+ ...flags["dry-run"] === true ? { dryRun: true } : {}
59131
+ };
59132
+ const http = await pushSendRequest({ target: session.target, wixToken: session.wixToken, siteToken: siteToken2, body, previewTag: session.previewTag, fetchImpl: deps.fetchImpl });
59133
+ return report2(http, body, flags, io);
59134
+ }
59135
+ function flagRefusal(flags) {
59136
+ if (LOCAL_SENDER_FLAGS.some((f) => flags[f] !== void 0)) return "flag_not_supported_with_ping";
59137
+ if (SWITCHES.some((f) => flags[f] !== void 0 && typeof flags[f] !== "boolean")) return "invalid_boolean_flag";
59138
+ return void 0;
59139
+ }
59140
+ function report2(http, sent, flags, io) {
59141
+ const code = refusalCode(http);
59142
+ if (code === "send_outcome_unknown") {
59143
+ return refuse4(io, code, `Ping may have accepted it. Re-run the same command with --request-id ${sent.requestId}: Ping runs one request at most once per site for 24 hours.`, 1, { requestId: sent.requestId });
59144
+ }
59145
+ if (code === "rate_limited" && http.retryAfterSec) {
59146
+ return refuse4(io, code, `Test sends are limited per owner; retry in ${http.retryAfterSec} seconds.`, 1, { retryAfterSec: http.retryAfterSec });
59147
+ }
59148
+ if (code) return refuse4(io, code, HINTS[code], 1);
59149
+ if (flags.json === true) io.log(JSON.stringify(http.body, null, 2));
59150
+ else io.log(summary(http.body ?? {}, sent));
59151
+ return 0;
59152
+ }
59153
+ function refusalCode(http) {
59154
+ if (http.error) return http.error === "push_send_unreachable" ? "send_outcome_unknown" : http.error;
59155
+ if (http.ok && (http.body?.state === "accepted" || http.body?.state === "dry_run")) return void 0;
59156
+ const code = String(http.body?.error ?? "");
59157
+ if (KNOWN_CODES.has(code)) return code;
59158
+ return http.ok || http.status >= 500 ? "send_outcome_unknown" : "push_send_failed";
59159
+ }
59160
+ function summary(result, sent) {
59161
+ if (result.state === "dry_run") {
59162
+ return `Dry run passed: ${sent.memberEmail} is an approved member, the link routes, and push is ready for ${sent.app}. No notification was sent.`;
59163
+ }
59164
+ if (result.deduplicated === true) {
59165
+ return `Ping already ran request ${sent.requestId}; the earlier send stands and no second notification was sent.`;
59166
+ }
59167
+ return `Ping accepted request ${sent.requestId} for ${sent.memberEmail}. Ping does not confirm delivery: it reaches the member's signed-in devices with notifications allowed.`;
59168
+ }
59169
+ var LOCAL_SENDER_FLAGS, SWITCHES, REQUIRED_FLAGS, UUID_RE, KNOWN_CODES, HINTS, text7;
59170
+ var init_notify_ping = __esm({
59171
+ "src/notify-ping.ts"() {
59172
+ init_push_send();
59173
+ init_push_send_service();
59174
+ init_hosted_owner();
59175
+ init_owner_claim();
59176
+ init_push_onboarding();
59177
+ init_wix_owner();
59178
+ LOCAL_SENDER_FLAGS = ["token", "device", "all", "admin-url", "admin-session", "silent", "badge", "data", "category", "channel", "platform", "bundle-id"];
59179
+ SWITCHES = ["json", "dry-run"];
59180
+ REQUIRED_FLAGS = ["member-email", "title", "link"];
59181
+ UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
59182
+ KNOWN_CODES = new Set(PUSH_SEND_ERROR_CODES);
59183
+ HINTS = {
59184
+ push_not_ready: "Run himi notify setup for this app and site first; status must be ready.",
59185
+ member_not_found: "Use the login email of an approved member of this site.",
59186
+ member_ambiguous: "More than one member has this login email; resolve it in the site's Members.",
59187
+ member_not_active: "The member must be approved before they can be notified.",
59188
+ link_not_routable: "Link to a screen this app's published release ships, e.g. <scheme>://screen/<screenId>?id=\u2026.",
59189
+ forbidden_site: "The Wix account from wix login must own this site.",
59190
+ site_token_invalid: "Run wix login as the site owner; the site token must belong to the app owner's account.",
59191
+ ping_permission_denied: "Himi Serve is not permitted to send through Ping; this is a platform issue, not your setup."
59192
+ };
59193
+ text7 = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
59194
+ }
59195
+ });
59196
+
58967
59197
  // src/notify.ts
58968
59198
  var notify_exports = {};
58969
59199
  __export(notify_exports, {
@@ -59066,7 +59296,7 @@ async function runNotify(pos, flags, io, deps = {}) {
59066
59296
  } catch {
59067
59297
  reachable = false;
59068
59298
  }
59069
- const report2 = {
59299
+ const report3 = {
59070
59300
  // BOTH platforms must be ready. Considering only iOS meant a server with an APNs
59071
59301
  // key but no Firebase credentials reported ok and exited 0, while every Android
59072
59302
  // send would fail — from the command whose whole job is to answer that question.
@@ -59079,15 +59309,15 @@ async function runNotify(pos, flags, io, deps = {}) {
59079
59309
  ...reachable && authed && !senders ? { hint: "this admin-server predates /v1/admin/push-doctor \u2014 upgrade it to see sender readiness" } : {}
59080
59310
  };
59081
59311
  if (json6) {
59082
- print(report2);
59083
- return report2.ok ? 0 : 1;
59312
+ print(report3);
59313
+ return report3.ok ? 0 : 1;
59084
59314
  }
59085
59315
  io.log(
59086
59316
  `admin ${adminUrl} ${reachable ? authed ? "reachable, authenticated" : "reachable, NOT authenticated" : "UNREACHABLE"}`
59087
59317
  );
59088
59318
  if (!senders) {
59089
59319
  io.log("senders unknown \u2014 credentials live on the admin-server, and it did not report them");
59090
- if (report2.hint) io.log(` ${report2.hint}`);
59320
+ if (report3.hint) io.log(` ${report3.hint}`);
59091
59321
  return 1;
59092
59322
  }
59093
59323
  for (const [platform, r] of [
@@ -59097,7 +59327,7 @@ async function runNotify(pos, flags, io, deps = {}) {
59097
59327
  io.log(`${platform.padEnd(11)} ${r.sender}${r.note ? ` \u2014 ${r.note}` : ""}`);
59098
59328
  if (r.missing.length) io.log(` missing on the server: ${r.missing.join(", ")}`);
59099
59329
  }
59100
- return report2.ok ? 0 : 1;
59330
+ return report3.ok ? 0 : 1;
59101
59331
  }
59102
59332
  const app = str9(flags.app);
59103
59333
  if (!app) {
@@ -59276,10 +59506,10 @@ function makeTransport(fetchImpl, auth, timeoutMs = DEFAULT_TIMEOUT_MS4) {
59276
59506
  body: body === void 0 ? void 0 : JSON.stringify(body),
59277
59507
  signal: AbortSignal.timeout(timeoutMs)
59278
59508
  });
59279
- const text6 = await res.text();
59280
- let parsed = text6;
59509
+ const text8 = await res.text();
59510
+ let parsed = text8;
59281
59511
  try {
59282
- parsed = text6 ? JSON.parse(text6) : null;
59512
+ parsed = text8 ? JSON.parse(text8) : null;
59283
59513
  } catch {
59284
59514
  }
59285
59515
  if (!res.ok) throw new WixApiError2(res.status, method, path2, parsed);
@@ -59376,10 +59606,10 @@ async function mintVisitorToken(fetchImpl, clientId) {
59376
59606
  body: JSON.stringify({ clientId, grantType: "anonymous" }),
59377
59607
  signal: AbortSignal.timeout(8e3)
59378
59608
  });
59379
- const text6 = await res.text();
59380
- let parsed = text6;
59609
+ const text8 = await res.text();
59610
+ let parsed = text8;
59381
59611
  try {
59382
- parsed = text6 ? JSON.parse(text6) : null;
59612
+ parsed = text8 ? JSON.parse(text8) : null;
59383
59613
  } catch {
59384
59614
  }
59385
59615
  if (!res.ok) throw new WixApiError2(res.status, "POST", "/oauth2/token", parsed);
@@ -59394,28 +59624,28 @@ var init_visitor_auth = __esm({
59394
59624
  });
59395
59625
 
59396
59626
  // src/site-analyze/copy-clean.ts
59397
- function isTemplatePlaceholder(text6) {
59398
- return PLACEHOLDER_RE.test(text6);
59627
+ function isTemplatePlaceholder(text8) {
59628
+ return PLACEHOLDER_RE.test(text8);
59399
59629
  }
59400
59630
  function cleanText(raw, cap) {
59401
59631
  const s = String(raw ?? "").replace(/[\u0000-\u001F\u007F]/g, " ").replace(/\s+/g, " ").trim();
59402
59632
  return s.length > cap ? `${s.slice(0, cap - 1).trimEnd()}\u2026` : s;
59403
59633
  }
59404
- function stripPii(text6) {
59405
- return text6.replace(EMAIL_RE2, "").replace(PHONE_SHAPE_RE, (m) => {
59634
+ function stripPii(text8) {
59635
+ return text8.replace(EMAIL_RE2, "").replace(PHONE_SHAPE_RE, (m) => {
59406
59636
  const digits2 = (m.match(ANY_DIGIT_RE) ?? []).length;
59407
59637
  return digits2 >= PHONE_MIN_DIGITS && PHONE_DIGIT_RUN_RE.test(m) ? "" : m;
59408
59638
  }).replace(/\s+/g, " ").trim();
59409
59639
  }
59410
- function isBoilerplate(text6) {
59411
- return BOILERPLATE_RE.test(text6) || PLACEHOLDER_RE.test(text6);
59640
+ function isBoilerplate(text8) {
59641
+ return BOILERPLATE_RE.test(text8) || PLACEHOLDER_RE.test(text8);
59412
59642
  }
59413
59643
  function copyOrDrop(raw, cap) {
59414
- const text6 = stripPii(cleanText(raw, cap));
59415
- if (text6.length < 2) return "";
59416
- if (isBoilerplate(text6)) return "";
59417
- if (!/[A-Za-zͰ-῿぀-힯]/.test(text6)) return "";
59418
- return text6;
59644
+ const text8 = stripPii(cleanText(raw, cap));
59645
+ if (text8.length < 2) return "";
59646
+ if (isBoilerplate(text8)) return "";
59647
+ if (!/[A-Za-zͰ-῿぀-힯]/.test(text8)) return "";
59648
+ return text8;
59419
59649
  }
59420
59650
  function dedupe2(values, cap) {
59421
59651
  const out2 = [];
@@ -59449,9 +59679,9 @@ var init_copy_clean = __esm({
59449
59679
  function genericDescription(it) {
59450
59680
  for (const field of DESCRIPTION_FIELDS) {
59451
59681
  const raw = it[field];
59452
- const text6 = typeof raw === "string" ? raw : str6(raw?.text);
59453
- if (!text6) continue;
59454
- const plain2 = text6.replace(/<[^>]*>/g, " ").replace(/&nbsp;/g, " ");
59682
+ const text8 = typeof raw === "string" ? raw : str6(raw?.text);
59683
+ if (!text8) continue;
59684
+ const plain2 = text8.replace(/<[^>]*>/g, " ").replace(/&nbsp;/g, " ");
59455
59685
  if (plain2.trim()) return plain2;
59456
59686
  }
59457
59687
  return void 0;
@@ -59564,7 +59794,7 @@ function formLabels(x, depth = 0, out2 = []) {
59564
59794
  if (typeof x !== "object") return out2;
59565
59795
  const o = x;
59566
59796
  const label2 = str6(o.label ?? o.displayName ?? o.fieldTitle ?? o.title);
59567
- if (label2 && !UUID_RE.test(label2) && label2.length < 80 && !out2.includes(label2)) out2.push(label2);
59797
+ if (label2 && !UUID_RE2.test(label2) && label2.length < 80 && !out2.includes(label2)) out2.push(label2);
59568
59798
  for (const k of ["fields", "formFields", "form", "schema", "properties"]) {
59569
59799
  if (o[k] != null) formLabels(o[k], depth + 1, out2);
59570
59800
  }
@@ -59682,7 +59912,7 @@ function sampleTitle(data) {
59682
59912
  for (const [k, v] of Object.entries(data)) {
59683
59913
  if (k.startsWith("_") || typeof v !== "string") continue;
59684
59914
  const s = v.trim();
59685
- if (s.length > 2 && s.length < 80 && !s.includes("@") && !/^https?:/i.test(s) && !UUID_RE.test(s)) return s;
59915
+ if (s.length > 2 && s.length < 80 && !s.includes("@") && !/^https?:/i.test(s) && !UUID_RE2.test(s)) return s;
59686
59916
  }
59687
59917
  return void 0;
59688
59918
  }
@@ -59781,7 +60011,7 @@ async function readMemberRoles(call) {
59781
60011
  if (sawAuthError) return { names: [], status: "error" };
59782
60012
  return { names: [], status: "empty" };
59783
60013
  }
59784
- var asArr, str6, DESCRIPTION_FIELDS, UUID_RE, CORE_PROBES, OPTIONAL_PROBES, ALL, CMS_LIST_LIMIT;
60014
+ var asArr, str6, DESCRIPTION_FIELDS, UUID_RE2, CORE_PROBES, OPTIONAL_PROBES, ALL, CMS_LIST_LIMIT;
59785
60015
  var init_probes = __esm({
59786
60016
  "src/site-analyze/probes.ts"() {
59787
60017
  init_rest();
@@ -59789,7 +60019,7 @@ var init_probes = __esm({
59789
60019
  asArr = (x) => Array.isArray(x) ? x : [];
59790
60020
  str6 = (x) => typeof x === "string" ? x : "";
59791
60021
  DESCRIPTION_FIELDS = ["plainDescription", "description", "shortDescription", "excerpt", "tagLine", "subtitle"];
59792
- UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
60022
+ UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
59793
60023
  CORE_PROBES = [
59794
60024
  {
59795
60025
  vertical: "store",
@@ -60496,12 +60726,12 @@ function mergeWst(pages) {
60496
60726
  return acc;
60497
60727
  }
60498
60728
  function fontSlug(value) {
60499
- let text6 = value;
60729
+ let text8 = value;
60500
60730
  try {
60501
- text6 = decodeURIComponent(value);
60731
+ text8 = decodeURIComponent(value);
60502
60732
  } catch {
60503
60733
  }
60504
- return text6.toLowerCase().replace(/[^a-z0-9]+/g, "");
60734
+ return text8.toLowerCase().replace(/[^a-z0-9]+/g, "");
60505
60735
  }
60506
60736
  function fontUrlSlug(url) {
60507
60737
  const last = url.split("?")[0].split("#")[0].split("/").pop() ?? "";
@@ -60675,8 +60905,8 @@ function parsePublishedHtml(html) {
60675
60905
  const rawHeadings = [];
60676
60906
  HEADING_RE.lastIndex = 0;
60677
60907
  while (m = HEADING_RE.exec(html)) {
60678
- const text6 = copyOrDrop(textFromHtml(m[1] ?? ""), 120);
60679
- if (text6) rawHeadings.push(text6);
60908
+ const text8 = copyOrDrop(textFromHtml(m[1] ?? ""), 120);
60909
+ if (text8) rawHeadings.push(text8);
60680
60910
  if (rawHeadings.length >= 40) break;
60681
60911
  }
60682
60912
  const headings = dedupe2(rawHeadings, 20);
@@ -61503,16 +61733,16 @@ function isPrivateV4([a, b, c]) {
61503
61733
  return a >= 224;
61504
61734
  }
61505
61735
  function v6Groups(host) {
61506
- let text6 = host;
61507
- const dotted = /:((?:\d{1,3}\.){3}\d{1,3})$/.exec(text6);
61736
+ let text8 = host;
61737
+ const dotted = /:((?:\d{1,3}\.){3}\d{1,3})$/.exec(text8);
61508
61738
  if (dotted) {
61509
61739
  const octets = ipv4Octets(dotted[1]);
61510
61740
  if (!octets) return null;
61511
61741
  const hi = (octets[0] << 8 | octets[1]).toString(16);
61512
61742
  const lo = (octets[2] << 8 | octets[3]).toString(16);
61513
- text6 = `${text6.slice(0, dotted.index)}:${hi}:${lo}`;
61743
+ text8 = `${text8.slice(0, dotted.index)}:${hi}:${lo}`;
61514
61744
  }
61515
- const halves = text6.split("::");
61745
+ const halves = text8.split("::");
61516
61746
  if (halves.length > 2) return null;
61517
61747
  const parts = (part) => part ? part.split(":") : [];
61518
61748
  const head = parts(halves[0]);
@@ -61594,10 +61824,10 @@ function assertPublicSiteUrl(raw) {
61594
61824
  if (refusal) throw new Error(refusal);
61595
61825
  }
61596
61826
  function resolveAll(hostname2) {
61597
- return new Promise((resolve52, reject) => {
61827
+ return new Promise((resolve53, reject) => {
61598
61828
  dnsLookup(hostname2, { all: true, verbatim: true }, (err, addresses) => {
61599
61829
  if (err) reject(err);
61600
- else resolve52(addresses);
61830
+ else resolve53(addresses);
61601
61831
  });
61602
61832
  });
61603
61833
  }
@@ -61605,13 +61835,13 @@ function withAbort(start, signal, what) {
61605
61835
  if (signal?.aborted) return Promise.reject(new Error(`${what} aborted`));
61606
61836
  const work = start();
61607
61837
  if (!signal) return work;
61608
- return new Promise((resolve52, reject) => {
61838
+ return new Promise((resolve53, reject) => {
61609
61839
  const onAbort = () => reject(new Error(`${what} aborted`));
61610
61840
  signal.addEventListener("abort", onAbort, { once: true });
61611
- work.then(resolve52, reject).finally(() => signal.removeEventListener("abort", onAbort));
61841
+ work.then(resolve53, reject).finally(() => signal.removeEventListener("abort", onAbort));
61612
61842
  });
61613
61843
  }
61614
- async function pinAddress(url, resolve52 = resolveAll, signal) {
61844
+ async function pinAddress(url, resolve53 = resolveAll, signal) {
61615
61845
  const host = url.hostname.replace(/^\[|\]$/g, "");
61616
61846
  if (ipv4Octets(host)) {
61617
61847
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
@@ -61621,7 +61851,7 @@ async function pinAddress(url, resolve52 = resolveAll, signal) {
61621
61851
  if (isBlockedAddress(host)) throw new Error(`${host} is a blocked address`);
61622
61852
  return { address: host, family: 6 };
61623
61853
  }
61624
- const addresses = await withAbort(() => resolve52(host), signal, `${host} lookup`);
61854
+ const addresses = await withAbort(() => resolve53(host), signal, `${host} lookup`);
61625
61855
  if (!addresses.length) throw new Error(`${host} resolved to no address`);
61626
61856
  const blocked = addresses.filter((a) => isBlockedAddress(a.address)).map((a) => a.address);
61627
61857
  if (blocked.length) throw new Error(`${host} resolves to a blocked address (${blocked.join(", ")})`);
@@ -61661,7 +61891,7 @@ function copyIncomingHeaders(headers2) {
61661
61891
  return out2;
61662
61892
  }
61663
61893
  function requestOnce(url, pinned, init) {
61664
- return new Promise((resolve52, reject) => {
61894
+ return new Promise((resolve53, reject) => {
61665
61895
  const headers2 = { host: url.host, "accept-encoding": "identity" };
61666
61896
  new Headers(init.headers ?? {}).forEach((value, key2) => {
61667
61897
  if (key2.toLowerCase() !== "host") headers2[key2] = value;
@@ -61691,7 +61921,7 @@ function requestOnce(url, pinned, init) {
61691
61921
  reject(err);
61692
61922
  return;
61693
61923
  }
61694
- resolve52(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out2 }));
61924
+ resolve53(new Response(body, { status, statusText: res.statusMessage ?? "", headers: out2 }));
61695
61925
  }
61696
61926
  );
61697
61927
  req.on("error", reject);
@@ -61767,8 +61997,8 @@ var init_net_guard = __esm({
61767
61997
  function textFields(look) {
61768
61998
  if (look.unavailable) return [];
61769
61999
  const out2 = [];
61770
- const add = (text6, where, narrative = false) => {
61771
- if (text6 && text6.trim()) out2.push({ text: text6, where, narrative });
62000
+ const add = (text8, where, narrative = false) => {
62001
+ if (text8 && text8.trim()) out2.push({ text: text8, where, narrative });
61772
62002
  };
61773
62003
  for (const label2 of look.navLabels) add(label2, "nav");
61774
62004
  for (const p of look.pages) {
@@ -62159,8 +62389,8 @@ async function analyzeSite(input, ports) {
62159
62389
  if (locale) plan.provisioning.locale = locale;
62160
62390
  const velo = buildVeloChapter({ look, owner: ownerVelo });
62161
62391
  const veloFiles = ownerVelo.files.flatMap((f) => {
62162
- const text6 = f.content ?? f.excerpt;
62163
- return text6 ? [{ path: f.path, text: text6 }] : [];
62392
+ const text8 = f.content ?? f.excerpt;
62393
+ return text8 ? [{ path: f.path, text: text8 }] : [];
62164
62394
  }).slice(0, 80);
62165
62395
  const permissions = buildPermissionsChapter({
62166
62396
  cms,
@@ -62382,8 +62612,8 @@ function cmsStatusNote(taxonomy) {
62382
62612
  function yn(v) {
62383
62613
  return v == null || v === "" ? "\u2014" : String(v);
62384
62614
  }
62385
- function isAuthPhrase(text6) {
62386
- const t = text6.trim();
62615
+ function isAuthPhrase(text8) {
62616
+ const t = text8.trim();
62387
62617
  return AUTH_ONLY_ASCII.test(t) || LOGIN_HE.includes(t);
62388
62618
  }
62389
62619
  function looksGated(page) {
@@ -62760,9 +62990,9 @@ function attachVeloSources(book, sources, put) {
62760
62990
  if (isSecretVeloPath(f.path)) continue;
62761
62991
  const rel = veloArtifactRelPath(f.path);
62762
62992
  if (!rel) continue;
62763
- const text6 = byPath.get(f.path) ?? f.excerpt;
62764
- if (!text6) continue;
62765
- put(rel, text6);
62993
+ const text8 = byPath.get(f.path) ?? f.excerpt;
62994
+ if (!text8) continue;
62995
+ put(rel, text8);
62766
62996
  f.localPath = rel;
62767
62997
  }
62768
62998
  }
@@ -63007,14 +63237,14 @@ var init_customer_build = __esm({
63007
63237
 
63008
63238
  // src/site-analyze/apply.ts
63009
63239
  import { existsSync as existsSync64, readFileSync as readFileSync76, writeFileSync as writeFileSync27, copyFileSync as copyFileSync3, mkdirSync as mkdirSync31, realpathSync as realpathSync9, statSync as statSync17 } from "node:fs";
63010
- import { dirname as dirname35, isAbsolute as isAbsolute6, join as join63, resolve as resolve49, sep as sep16 } from "node:path";
63240
+ import { dirname as dirname35, isAbsolute as isAbsolute6, join as join63, resolve as resolve50, sep as sep16 } from "node:path";
63011
63241
  import { spawnSync as spawnSync4 } from "node:child_process";
63012
63242
  function unpairedRedirectNote(overlay) {
63013
63243
  if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
63014
63244
  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)`;
63015
63245
  }
63016
63246
  function posix3(p) {
63017
- return resolve49(p).replace(/\\/g, "/");
63247
+ return resolve50(p).replace(/\\/g, "/");
63018
63248
  }
63019
63249
  function committedShellProvisioning(path2) {
63020
63250
  return committedShellFor(posix3(path2));
@@ -63048,7 +63278,7 @@ function assertNotCommitted(path2, forbidden) {
63048
63278
  `refusing to overwrite committed ${committedProvisioningPath(committed)} \u2014 use prepare:customer --contract`
63049
63279
  );
63050
63280
  }
63051
- if (forbidden && resolve49(path2) === resolve49(forbidden)) {
63281
+ if (forbidden && resolve50(path2) === resolve50(forbidden)) {
63052
63282
  const named = committedShellProvisioning(forbidden);
63053
63283
  throw new Error(
63054
63284
  `refusing to overwrite committed ${named ? committedProvisioningPath(named) : forbidden} \u2014 pass a content-package provisioning.json or use prepare:customer --contract`
@@ -63104,8 +63334,8 @@ function buildMergedContract(options) {
63104
63334
  const staged = [];
63105
63335
  const contained = (root, rel) => {
63106
63336
  if (isAbsolute6(rel)) return void 0;
63107
- const full = resolve49(root, rel);
63108
- return full.startsWith(resolve49(root) + sep16) ? full : void 0;
63337
+ const full = resolve50(root, rel);
63338
+ return full.startsWith(resolve50(root) + sep16) ? full : void 0;
63109
63339
  };
63110
63340
  const stage = (fromRel, toRel) => {
63111
63341
  const from = contained(packageDir, fromRel);
@@ -63194,7 +63424,7 @@ function catalogTypography(overlay, template) {
63194
63424
  function staticFaqFor(overlay, overlayPath) {
63195
63425
  const own3 = overlay.faq;
63196
63426
  if (own3 !== void 0) return deriveStaticFaq(own3);
63197
- const bookPath = join63(dirname35(resolve49(overlayPath)), "book.json");
63427
+ const bookPath = join63(dirname35(resolve50(overlayPath)), "book.json");
63198
63428
  if (!existsSync64(bookPath)) return void 0;
63199
63429
  try {
63200
63430
  const book = JSON.parse(readFileSync76(bookPath, "utf8"));
@@ -63208,7 +63438,7 @@ function staticFaqFor(overlay, overlayPath) {
63208
63438
  }
63209
63439
  }
63210
63440
  async function applyOverlays(input) {
63211
- const cwd = resolve49(input.cwd);
63441
+ const cwd = resolve50(input.cwd);
63212
63442
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
63213
63443
  assertKnownShell(shell);
63214
63444
  const overlay = JSON.parse(readFileSync76(input.overlayPath, "utf8"));
@@ -63232,7 +63462,7 @@ async function applyOverlays(input) {
63232
63462
  `shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block), and this overlay has none. Re-run \`himi site analyze --url <site> --shell ${shell}\` to derive the site's page map (edit \`site.pages\` in provisioning.overlay.json if needed), then --apply.`
63233
63463
  );
63234
63464
  }
63235
- const packageDir = dirname35(resolve49(input.overlayPath));
63465
+ const packageDir = dirname35(resolve50(input.overlayPath));
63236
63466
  const { path: contract, staged } = buildMergedContract({ appDir: appDir3, packageDir, overlay });
63237
63467
  wrote.push(...staged);
63238
63468
  const r = spawnSync4("npm", ["run", "prepare:customer", "--", "--contract", contract], {
@@ -63327,7 +63557,7 @@ async function applyOverlays(input) {
63327
63557
  }
63328
63558
  }
63329
63559
  if (!input.iconPath || !existsSync64(input.iconPath)) {
63330
- const book = input.iconPath ? dirname35(dirname35(resolve49(input.iconPath))) : void 0;
63560
+ const book = input.iconPath ? dirname35(dirname35(resolve50(input.iconPath))) : void 0;
63331
63561
  notes.push(
63332
63562
  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"
63333
63563
  );
@@ -64446,10 +64676,10 @@ function permuteDomain(domain, allowSpecialUseDomain) {
64446
64676
  }
64447
64677
  function createPromiseCallback(cb) {
64448
64678
  let callback;
64449
- let resolve52;
64679
+ let resolve53;
64450
64680
  let reject;
64451
64681
  const promise = new Promise((_resolve, _reject) => {
64452
- resolve52 = _resolve;
64682
+ resolve53 = _resolve;
64453
64683
  reject = _reject;
64454
64684
  });
64455
64685
  if (typeof cb === "function") {
@@ -64465,7 +64695,7 @@ function createPromiseCallback(cb) {
64465
64695
  callback = (err, result) => {
64466
64696
  try {
64467
64697
  if (err) reject(err);
64468
- else resolve52(result);
64698
+ else resolve53(result);
64469
64699
  } catch (e) {
64470
64700
  reject(e instanceof Error ? e : new Error());
64471
64701
  }
@@ -66532,8 +66762,8 @@ function copyFromEval(evaled) {
66532
66762
  evaled.meta?.ogTitle,
66533
66763
  evaled.meta?.ogDescription
66534
66764
  ].map((raw) => {
66535
- const text6 = cleanText(raw, 400);
66536
- return text6 && isTemplatePlaceholder(text6) ? stripPii(cleanText(text6, 90)) : "";
66765
+ const text8 = cleanText(raw, 400);
66766
+ return text8 && isTemplatePlaceholder(text8) ? stripPii(cleanText(text8, 90)) : "";
66537
66767
  }),
66538
66768
  8
66539
66769
  );
@@ -67065,7 +67295,7 @@ var init_crawl_look = __esm({
67065
67295
  });
67066
67296
 
67067
67297
  // src/site-analyze/site-function.ts
67068
- import { randomUUID as randomUUID5 } from "node:crypto";
67298
+ import { randomUUID as randomUUID6 } from "node:crypto";
67069
67299
  function createRevisionUrl(msid, esi) {
67070
67300
  const q = new URLSearchParams({ editorSessionId: esi, esi, metaSiteId: msid });
67071
67301
  return `https://editor.wix.com/html/v1/create_revision?${q}`;
@@ -67432,13 +67662,13 @@ async function veloCall(fetchImpl, method, url, opts = {}) {
67432
67662
  body: opts.body === void 0 ? void 0 : JSON.stringify(opts.body),
67433
67663
  signal: AbortSignal.timeout(opts.timeoutMs ?? 3e4)
67434
67664
  });
67435
- const text6 = await res.text();
67436
- let json6 = text6;
67665
+ const text8 = await res.text();
67666
+ let json6 = text8;
67437
67667
  try {
67438
- json6 = text6 ? JSON.parse(text6) : null;
67668
+ json6 = text8 ? JSON.parse(text8) : null;
67439
67669
  } catch {
67440
67670
  }
67441
- return { status: res.status, json: json6, text: text6 };
67671
+ return { status: res.status, json: json6, text: text8 };
67442
67672
  }
67443
67673
  function snippet2(x, cap = 180) {
67444
67674
  const s = typeof x === "string" ? x : JSON.stringify(x) ?? "";
@@ -67510,7 +67740,7 @@ function codeAppIdFromRevision(json6) {
67510
67740
  async function snapshotAndPublish(fetchImpl, token, msid, opts = {}) {
67511
67741
  const production = opts.production !== false;
67512
67742
  const initiator = opts.initiator ?? "himi";
67513
- const esi = randomUUID5();
67743
+ const esi = randomUUID6();
67514
67744
  const rev = await veloCall(fetchImpl, "POST", createRevisionUrl(msid, esi), {
67515
67745
  token,
67516
67746
  msid,
@@ -67607,7 +67837,7 @@ async function runSiteFunction(opts) {
67607
67837
  if (!httpOk(patched)) {
67608
67838
  return { ...base, error: `UpdateFiles ${patched.status}: ${snippet2(patched.json ?? patched.text)}` };
67609
67839
  }
67610
- let report2 = {
67840
+ let report3 = {
67611
67841
  ...base,
67612
67842
  ok: true,
67613
67843
  source: extractHttpFunction(next, method, name),
@@ -67616,21 +67846,21 @@ async function runSiteFunction(opts) {
67616
67846
  if (opts.publish) {
67617
67847
  const snap = await snapshotAndPublish(fetchImpl, opts.token, opts.msid, { production: true, initiator: "himi" });
67618
67848
  const pubOk = httpOk(snap.rev) && httpOk(snap.live);
67619
- report2 = {
67620
- ...report2,
67621
- ok: report2.ok && pubOk,
67849
+ report3 = {
67850
+ ...report3,
67851
+ ok: report3.ok && pubOk,
67622
67852
  revision: snap.revision,
67623
67853
  codeAppId: snap.codeAppId,
67624
67854
  publish: { revision: httpOk(snap.rev), rc: httpOk(snap.rc), live: httpOk(snap.live), status: snap.live?.status },
67625
- error: pubOk ? report2.error : snippet2(snap.live?.json ?? snap.rev.json)
67855
+ error: pubOk ? report3.error : snippet2(snap.live?.json ?? snap.rev.json)
67626
67856
  };
67627
67857
  }
67628
67858
  if (opts.invoke) {
67629
- if (!opts.siteUrl) return { ...report2, ok: false, error: "put --invoke needs --url" };
67630
- const invoked = await invokeAndReport(fetchImpl, opts, report2, name, method);
67631
- return { ...report2, ...invoked, op: "put", ok: report2.ok && invoked.ok };
67859
+ if (!opts.siteUrl) return { ...report3, ok: false, error: "put --invoke needs --url" };
67860
+ const invoked = await invokeAndReport(fetchImpl, opts, report3, name, method);
67861
+ return { ...report3, ...invoked, op: "put", ok: report3.ok && invoked.ok };
67632
67862
  }
67633
- return report2;
67863
+ return report3;
67634
67864
  }
67635
67865
  async function invokeAndReport(fetchImpl, opts, base, name, method) {
67636
67866
  const siteUrl = opts.siteUrl;
@@ -67695,7 +67925,7 @@ __export(cli_exports, {
67695
67925
  runSiteFunctionCli: () => runSiteFunctionCli
67696
67926
  });
67697
67927
  import { readFileSync as readFileSync77 } from "node:fs";
67698
- import { resolve as resolve50 } from "node:path";
67928
+ import { resolve as resolve51 } from "node:path";
67699
67929
  function assetFetchFor(_opts) {
67700
67930
  return pinnedFetch2;
67701
67931
  }
@@ -67715,7 +67945,7 @@ async function runSiteAnalyze(opts) {
67715
67945
  const assetFetch = assetFetchFor(opts);
67716
67946
  const siteFetch = guardedSiteFetch;
67717
67947
  const cwd = opts.cwd ?? process.cwd();
67718
- const outDir = resolve50(cwd, opts.outDir ?? ".himi/business-book");
67948
+ const outDir = resolve51(cwd, opts.outDir ?? ".himi/business-book");
67719
67949
  let ownerAuth;
67720
67950
  let msid;
67721
67951
  const ownerSite = ownerSiteFor(opts);
@@ -67767,9 +67997,9 @@ async function runSiteAnalyze(opts) {
67767
67997
  if (opts.apply) {
67768
67998
  applied = await applyOverlays({
67769
67999
  cwd,
67770
- overlayPath: resolve50(outDir, "provisioning.overlay.json"),
67771
- tokensPath: resolve50(outDir, "tokens.overlay.json"),
67772
- iconPath: resolve50(outDir, "media/icon.png"),
68000
+ overlayPath: resolve51(outDir, "provisioning.overlay.json"),
68001
+ tokensPath: resolve51(outDir, "tokens.overlay.json"),
68002
+ iconPath: resolve51(outDir, "media/icon.png"),
67773
68003
  shell: opts.shell
67774
68004
  });
67775
68005
  const note = noteWithWarnings(applied.note, warnings);
@@ -67805,7 +68035,7 @@ async function runSiteFunctionCli(opts) {
67805
68035
  const token = opts.token ?? await siteToken(msid);
67806
68036
  let source;
67807
68037
  if (opts.sourcePath) {
67808
- const p = resolve50(opts.cwd ?? process.cwd(), opts.sourcePath);
68038
+ const p = resolve51(opts.cwd ?? process.cwd(), opts.sourcePath);
67809
68039
  source = readFileSync77(p, "utf8");
67810
68040
  }
67811
68041
  let body;
@@ -67861,7 +68091,7 @@ async function accountToken2(spawnImpl = spawn6) {
67861
68091
  cached2 = fromEnv;
67862
68092
  return fromEnv;
67863
68093
  }
67864
- const token = await new Promise((resolve52, reject) => {
68094
+ const token = await new Promise((resolve53, reject) => {
67865
68095
  let child;
67866
68096
  try {
67867
68097
  child = spawnImpl("wix", ["token"]);
@@ -67890,7 +68120,7 @@ async function accountToken2(spawnImpl = spawn6) {
67890
68120
  const scan = (d) => {
67891
68121
  out2 += String(d);
67892
68122
  const m = out2.match(TOKEN_RE2);
67893
- if (m) done(() => resolve52(m[0]));
68123
+ if (m) done(() => resolve53(m[0]));
67894
68124
  };
67895
68125
  child.stdout?.on("data", scan);
67896
68126
  child.stderr?.on("data", scan);
@@ -67933,10 +68163,10 @@ function accountTransport(fetchImpl = fetch, timeoutMs = DEFAULT_TIMEOUT_MS5, sp
67933
68163
  }
67934
68164
  throw new Error(`${method} ${path2} failed: ${err?.message ?? String(e)}`);
67935
68165
  }
67936
- const text6 = await res.text();
67937
- let parsed = text6;
68166
+ const text8 = await res.text();
68167
+ let parsed = text8;
67938
68168
  try {
67939
- parsed = text6 ? JSON.parse(text6) : null;
68169
+ parsed = text8 ? JSON.parse(text8) : null;
67940
68170
  } catch {
67941
68171
  }
67942
68172
  if (!res.ok) throw new WixApiError(res.status, method, path2, parsed);
@@ -67997,16 +68227,16 @@ async function installVerticals(msid, wanted, token, fetchImpl = fetch, timeoutM
67997
68227
  body: JSON.stringify({ apps: wanted.map((w) => ({ id: w.appDefId })) }),
67998
68228
  signal: AbortSignal.timeout(timeoutMs)
67999
68229
  });
68000
- const text6 = await res.text();
68230
+ const text8 = await res.text();
68001
68231
  if (!res.ok) {
68002
68232
  return {
68003
68233
  ...empty,
68004
- errors: wanted.map((w) => ({ ...w, message: `bulk-install -> ${res.status}: ${text6.slice(0, 200)}` }))
68234
+ errors: wanted.map((w) => ({ ...w, message: `bulk-install -> ${res.status}: ${text8.slice(0, 200)}` }))
68005
68235
  };
68006
68236
  }
68007
68237
  let body = {};
68008
68238
  try {
68009
- body = text6 ? JSON.parse(text6) : {};
68239
+ body = text8 ? JSON.parse(text8) : {};
68010
68240
  } catch {
68011
68241
  }
68012
68242
  const nameOf = (appDefId) => wanted.find((w) => w.appDefId === appDefId)?.vertical ?? appDefId;
@@ -68609,9 +68839,9 @@ function redactVeloSource(source, knownSecrets = []) {
68609
68839
  const visitLiterals = (node) => {
68610
68840
  if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node) || ts.isTemplateExpression(node)) {
68611
68841
  const start = node.getStart(clean2);
68612
- const text6 = source.slice(start, node.end);
68613
- const redacted = redactLiteral(text6, start);
68614
- if (redacted !== text6) {
68842
+ const text8 = source.slice(start, node.end);
68843
+ const redacted = redactLiteral(text8, start);
68844
+ if (redacted !== text8) {
68615
68845
  edits.push({ start, end: node.end, text: redacted });
68616
68846
  return;
68617
68847
  }
@@ -68892,9 +69122,9 @@ var init_context = __esm({
68892
69122
  import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync79, mkdirSync as mkdirSync32, writeFileSync as writeFileSync29, existsSync as existsSync66, rmSync as rmSync15, readdirSync as readdirSync30, statSync as statSync18, lstatSync as lstatSync13, accessSync, constants as constants2, renameSync as renameSync7, cpSync as cpSync3 } from "node:fs";
68893
69123
  import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn7 } from "node:child_process";
68894
69124
  import { AsyncLocalStorage } from "node:async_hooks";
68895
- import { createHash as createHash31, randomUUID as randomUUID6 } from "node:crypto";
69125
+ import { createHash as createHash31, randomUUID as randomUUID7 } from "node:crypto";
68896
69126
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
68897
- import { join as join64, resolve as resolve51, relative as relative13, basename as basename17, dirname as dirname36 } from "node:path";
69127
+ import { join as join64, resolve as resolve52, relative as relative13, basename as basename17, dirname as dirname36 } from "node:path";
68898
69128
  import { fileURLToPath as fileURLToPath26 } from "node:url";
68899
69129
 
68900
69130
  // ../serve-cli/src/client.ts
@@ -68935,10 +69165,10 @@ var ServeCliClient = class {
68935
69165
  ...carriesCredential ? { redirect: "error" } : {},
68936
69166
  body: opts.body !== void 0 ? JSON.stringify(opts.body) : void 0
68937
69167
  });
68938
- const text6 = await res.text();
69168
+ const text8 = await res.text();
68939
69169
  let json6 = null;
68940
69170
  try {
68941
- json6 = text6 ? JSON.parse(text6) : null;
69171
+ json6 = text8 ? JSON.parse(text8) : null;
68942
69172
  } catch {
68943
69173
  json6 = null;
68944
69174
  }
@@ -68946,7 +69176,7 @@ var ServeCliClient = class {
68946
69176
  res.headers.forEach((v, k) => {
68947
69177
  h[k] = v;
68948
69178
  });
68949
- return { status: res.status, ok: res.ok, json: json6, text: text6, headers: h };
69179
+ return { status: res.status, ok: res.ok, json: json6, text: text8, headers: h };
68950
69180
  }
68951
69181
  // ---- serve (device-facing reads) ----
68952
69182
  health(plane) {
@@ -69511,8 +69741,8 @@ init_attestation();
69511
69741
 
69512
69742
  // ../../core/admin-web/src/utils/qr-terminal.ts
69513
69743
  init_qr();
69514
- function qrTerminal(text6, opts = {}) {
69515
- const { modules, size } = encodeQr(text6);
69744
+ function qrTerminal(text8, opts = {}) {
69745
+ const { modules, size } = encodeQr(text8);
69516
69746
  const quietZone = opts.quietZone ?? 4;
69517
69747
  const dim = size + quietZone * 2;
69518
69748
  const dark = (x, y) => x >= quietZone && x < quietZone + size && y >= quietZone && y < quietZone + size ? modules[y - quietZone][x - quietZone] : false;
@@ -69568,9 +69798,9 @@ function dpxSessionPresent(path2 = dpxSessionTokenPath()) {
69568
69798
  return false;
69569
69799
  }
69570
69800
  }
69571
- function isPortInUseError(text6) {
69572
- if (!text6) return false;
69573
- return /EADDRINUSE/i.test(text6) || new RegExp(`(:::|:)${DPX_SESSION_PORT}\\b`).test(text6);
69801
+ function isPortInUseError(text8) {
69802
+ if (!text8) return false;
69803
+ return /EADDRINUSE/i.test(text8) || new RegExp(`(:::|:)${DPX_SESSION_PORT}\\b`).test(text8);
69574
69804
  }
69575
69805
  function parseDpxAuthStatusIdentity(stdout) {
69576
69806
  if (!stdout) return void 0;
@@ -69635,7 +69865,7 @@ async function browserLogin(opts) {
69635
69865
  const log = opts.log ?? (() => {
69636
69866
  });
69637
69867
  const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
69638
- return await new Promise((resolve52, reject) => {
69868
+ return await new Promise((resolve53, reject) => {
69639
69869
  let settled = false;
69640
69870
  let loginUrl = "";
69641
69871
  const server = createServer();
@@ -69699,7 +69929,7 @@ async function browserLogin(opts) {
69699
69929
  return;
69700
69930
  }
69701
69931
  res.writeHead(200, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store", connection: "close" }).end(CLOSE_PAGE);
69702
- finish2(() => resolve52({ token, loginUrl }));
69932
+ finish2(() => resolve53({ token, loginUrl }));
69703
69933
  });
69704
69934
  });
69705
69935
  server.on("error", (err) => finish2(() => reject(err)));
@@ -69963,7 +70193,7 @@ async function queryCms(opts) {
69963
70193
  async function createCms(opts) {
69964
70194
  const { app, cms, call, dryRun = false, allowDestructive = false, applyPermissions = false } = opts;
69965
70195
  const prefix = namespacePrefix(app);
69966
- const report2 = {
70196
+ const report3 = {
69967
70197
  ok: true,
69968
70198
  app,
69969
70199
  namespace: prefix,
@@ -69985,19 +70215,19 @@ async function createCms(opts) {
69985
70215
  for (const spec of cms?.collections ?? []) {
69986
70216
  const id = physicalId(spec, app);
69987
70217
  if (spec.wixId) {
69988
- report2.skipped.push({
70218
+ report3.skipped.push({
69989
70219
  collection: id,
69990
70220
  reason: remoteById.has(id) ? "adopted (read-only) \u2014 himi never changes the schema of a collection it does not own" : `adopted but absent from this site \u2014 create it in the Wix dashboard, or declare it as owned ("${prefix}\u2026")`
69991
70221
  });
69992
- if (!remoteById.has(id)) report2.ok = false;
70222
+ if (!remoteById.has(id)) report3.ok = false;
69993
70223
  continue;
69994
70224
  }
69995
70225
  if (!spec.id?.startsWith(prefix)) {
69996
- report2.refused.push({
70226
+ report3.refused.push({
69997
70227
  collection: id || "<unnamed>",
69998
70228
  reason: `"${id}" is outside this app's namespace "${prefix}" \u2014 himi only writes collections it owns. Rename it in config.ts, or bind an existing collection read-only with \`wixId\`.`
69999
70229
  });
70000
- report2.ok = false;
70230
+ report3.ok = false;
70001
70231
  continue;
70002
70232
  }
70003
70233
  const existing = remoteById.get(id);
@@ -70005,35 +70235,35 @@ async function createCms(opts) {
70005
70235
  if (!dryRun) {
70006
70236
  await call("POST", "/data/v2/collections", { collection: toWixCollection(spec, app) });
70007
70237
  }
70008
- report2.created.push(id);
70238
+ report3.created.push(id);
70009
70239
  continue;
70010
70240
  }
70011
70241
  const permDrift = diffPermissions(spec, existing);
70012
- for (const d of permDrift) report2.permissionDrift.push({ collection: id, ...d });
70242
+ for (const d of permDrift) report3.permissionDrift.push({ collection: id, ...d });
70013
70243
  const applyingPermissions = applyPermissions && permDrift.length > 0;
70014
70244
  const drift = diffFields(spec, existing);
70015
70245
  const extras = drift.filter((d) => d.kind === "extra-field");
70016
70246
  const mismatches = drift.filter((d) => d.kind === "type-mismatch");
70017
70247
  const missing = drift.filter((d) => d.kind === "missing-field");
70018
70248
  for (const m of mismatches) {
70019
- report2.skipped.push({ collection: id, reason: m.detail });
70020
- report2.ok = false;
70249
+ report3.skipped.push({ collection: id, reason: m.detail });
70250
+ report3.ok = false;
70021
70251
  }
70022
70252
  for (const e of extras) {
70023
70253
  if (allowDestructive) continue;
70024
- report2.skipped.push({ collection: id, reason: e.detail });
70254
+ report3.skipped.push({ collection: id, reason: e.detail });
70025
70255
  }
70026
70256
  if (mismatches.length > 0) continue;
70027
70257
  if (missing.length === 0 && (extras.length === 0 || !allowDestructive) && !applyingPermissions) {
70028
- report2.unchanged.push(id);
70258
+ report3.unchanged.push(id);
70029
70259
  continue;
70030
70260
  }
70031
70261
  if (!allowDestructive && !Array.isArray(existing.fields)) {
70032
- report2.skipped.push({
70262
+ report3.skipped.push({
70033
70263
  collection: id,
70034
70264
  reason: "the site returned this collection without a `fields` array, so an update would drop every field (and its data) by omission. Re-run to retry the read; pass --allow-destructive only if narrowing to the declaration is genuinely what you want."
70035
70265
  });
70036
- report2.ok = false;
70266
+ report3.ok = false;
70037
70267
  continue;
70038
70268
  }
70039
70269
  if (applyingPermissions) {
@@ -70070,14 +70300,14 @@ async function createCms(opts) {
70070
70300
  }
70071
70301
  }
70072
70302
  }
70073
- report2.updated.push(id);
70303
+ report3.updated.push(id);
70074
70304
  }
70075
- return report2;
70305
+ return report3;
70076
70306
  }
70077
70307
  async function seedCms(opts) {
70078
70308
  const { app, cms, call, dryRun = false, force = false, only, dir } = opts;
70079
70309
  const prefix = namespacePrefix(app);
70080
- const report2 = { ok: true, app, inserted: {}, sources: {}, skipped: [], refused: [], dryRun };
70310
+ const report3 = { ok: true, app, inserted: {}, sources: {}, skipped: [], refused: [], dryRun };
70081
70311
  const fileRows = dir ? readSeedFile(dir) : {};
70082
70312
  const rowsFor = (id, spec) => fileRows[id]?.length ? { rows: fileRows[id], source: "cms-seed.json" } : { rows: spec.seed ?? [], source: "config.ts" };
70083
70313
  const remoteIds = /* @__PURE__ */ new Set();
@@ -70094,30 +70324,30 @@ async function seedCms(opts) {
70094
70324
  const { rows, source } = rowsFor(id, spec);
70095
70325
  considered++;
70096
70326
  if (!rows.length) {
70097
- report2.skipped.push({
70327
+ report3.skipped.push({
70098
70328
  collection: id,
70099
70329
  reason: `no seed rows \u2014 add a \`seed\` array to this collection in config.ts, or run \`himi cms seed --ai\` and refine ${dir ? "cms-seed.json" : "the generated cms-seed.json"}`
70100
70330
  });
70101
70331
  continue;
70102
70332
  }
70103
70333
  if (!spec.id?.startsWith(prefix)) {
70104
- report2.refused.push({ collection: id, reason: `"${id}" is outside this app's namespace "${prefix}" \u2014 himi only seeds collections it owns.` });
70105
- report2.ok = false;
70334
+ report3.refused.push({ collection: id, reason: `"${id}" is outside this app's namespace "${prefix}" \u2014 himi only seeds collections it owns.` });
70335
+ report3.ok = false;
70106
70336
  continue;
70107
70337
  }
70108
70338
  if (!remoteIds.has(id)) {
70109
- report2.skipped.push({ collection: id, reason: `not on the site yet \u2014 run \`himi cms create\` first` });
70110
- report2.ok = false;
70339
+ report3.skipped.push({ collection: id, reason: `not on the site yet \u2014 run \`himi cms create\` first` });
70340
+ report3.ok = false;
70111
70341
  continue;
70112
70342
  }
70113
70343
  const count2 = await countItems(call, id);
70114
70344
  if (count2 === null && !force) {
70115
- report2.skipped.push({ collection: id, reason: "could not read the current row count, so seeding might bury existing content. Re-run, or pass --force if you are sure." });
70116
- report2.ok = false;
70345
+ report3.skipped.push({ collection: id, reason: "could not read the current row count, so seeding might bury existing content. Re-run, or pass --force if you are sure." });
70346
+ report3.ok = false;
70117
70347
  continue;
70118
70348
  }
70119
70349
  if (count2 !== null && count2 > 0 && !force) {
70120
- report2.skipped.push({ collection: id, reason: `already has ${count2} items \u2014 seeding an already-populated collection needs --force so real content is never buried under sample rows` });
70350
+ report3.skipped.push({ collection: id, reason: `already has ${count2} items \u2014 seeding an already-populated collection needs --force so real content is never buried under sample rows` });
70121
70351
  continue;
70122
70352
  }
70123
70353
  if (!dryRun) {
@@ -70129,7 +70359,7 @@ async function seedCms(opts) {
70129
70359
  });
70130
70360
  const droppedKeys = [...new Set(rows.flatMap((r) => Object.keys(r).filter((k) => !declaredKeys.has(k))))];
70131
70361
  if (droppedKeys.length > 0) {
70132
- report2.skipped.push({
70362
+ report3.skipped.push({
70133
70363
  collection: id,
70134
70364
  reason: `ignored undeclared key(s) in seed rows: ${droppedKeys.join(", ")} \u2014 only declared fields are written (a row cannot set system keys such as _id or _owner)`
70135
70365
  });
@@ -70145,18 +70375,18 @@ async function seedCms(opts) {
70145
70375
  )
70146
70376
  );
70147
70377
  }
70148
- report2.inserted[id] = rows.length;
70149
- report2.sources[id] = source;
70378
+ report3.inserted[id] = rows.length;
70379
+ report3.sources[id] = source;
70150
70380
  }
70151
70381
  if (considered === 0) {
70152
70382
  const adopted = (cms?.collections ?? []).map((spec) => ({ spec, id: physicalId(spec, app) })).filter(({ spec, id }) => !!spec.wixId && (!only || id === only));
70153
- report2.skipped.push({
70383
+ report3.skipped.push({
70154
70384
  collection: only ?? "<none>",
70155
70385
  reason: adopted.length ? `the selected collection${adopted.length === 1 ? " is" : "s are"} adopted and read-only \u2014 himi never seeds ${adopted.map(({ id }) => `"${id}"`).join(", ")}. Add rows in Wix CMS, or declare an owned collection with an id beginning "${prefix}".` : only ? `--only "${only}" matched no owned collection declared by this app` : "this app declares no owned CMS collections to seed"
70156
70386
  });
70157
- report2.ok = false;
70387
+ report3.ok = false;
70158
70388
  }
70159
- return report2;
70389
+ return report3;
70160
70390
  }
70161
70391
  function readSeedFile(dir) {
70162
70392
  const file = join8(dir, "cms-seed.json");
@@ -70457,57 +70687,57 @@ function summarizeLint(app, bres, outcome, strict, extraIssues = []) {
70457
70687
  }
70458
70688
  };
70459
70689
  const record2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
70460
- const text6 = (value) => typeof value === "string" && value ? value : void 0;
70690
+ const text8 = (value) => typeof value === "string" && value ? value : void 0;
70461
70691
  const message = (value) => {
70462
70692
  const item = record2(value);
70463
- if (text6(item.message)) return text6(item.message);
70464
- if (text6(item.error)) return text6(item.error);
70693
+ if (text8(item.message)) return text8(item.message);
70694
+ if (text8(item.error)) return text8(item.error);
70465
70695
  if (Array.isArray(item.errors)) {
70466
70696
  const diagnostics = item.errors.map((entry) => {
70467
70697
  const diagnostic = record2(entry);
70468
- return text6(diagnostic.text) ?? text6(diagnostic.message);
70698
+ return text8(diagnostic.text) ?? text8(diagnostic.message);
70469
70699
  }).filter((entry) => !!entry);
70470
70700
  if (diagnostics.length) return diagnostics.join("; ");
70471
70701
  }
70472
70702
  return typeof value === "string" ? value : JSON.stringify(value);
70473
70703
  };
70474
- const report2 = foldLegacyReport(legacy, {
70704
+ const report3 = foldLegacyReport(legacy, {
70475
70705
  source: "validate",
70476
70706
  evidence: { runId: `validate:${outcome.manifest.releaseId}`, ts: (/* @__PURE__ */ new Date()).toISOString() },
70477
70707
  findings: [
70478
70708
  ...issues,
70479
70709
  ...bres.compileErrors.map((value) => ({
70480
70710
  pass: "compile",
70481
- path: text6(record2(value).bundle),
70711
+ path: text8(record2(value).bundle),
70482
70712
  ruleCode: "compile-error",
70483
70713
  severity: "error",
70484
70714
  message: message(value)
70485
70715
  })),
70486
70716
  ...outcome.failedToBuild.map((value) => ({
70487
70717
  pass: "build",
70488
- screen: text6(record2(value).screenId),
70718
+ screen: text8(record2(value).screenId),
70489
70719
  ruleCode: "failed-to-build",
70490
70720
  severity: "error",
70491
70721
  message: message(value)
70492
70722
  })),
70493
70723
  ...outcome.missingBundles.map((value) => ({
70494
70724
  pass: "build",
70495
- screen: text6(record2(value).screen),
70496
- path: text6(record2(value).bundle),
70725
+ screen: text8(record2(value).screen),
70726
+ path: text8(record2(value).bundle),
70497
70727
  ruleCode: "missing-bundle",
70498
70728
  severity: "error",
70499
70729
  message: message(value)
70500
70730
  })),
70501
70731
  ...workerThrows.map((value) => ({
70502
70732
  pass: "worker",
70503
- path: text6(record2(value).bundle),
70733
+ path: text8(record2(value).bundle),
70504
70734
  ruleCode: "worker-threw",
70505
70735
  severity: "error",
70506
70736
  message: message(value.threw)
70507
70737
  }))
70508
70738
  ]
70509
70739
  });
70510
- return { report: report2, hasErrors };
70740
+ return { report: report3, hasErrors };
70511
70741
  }
70512
70742
 
70513
70743
  // src/cms-lint.ts
@@ -70631,8 +70861,8 @@ function surfaceIssues(dir, surfaceNav, strict) {
70631
70861
  if (requested.length) {
70632
70862
  const { rejected } = resolveSurfaceEnvelope(platforms, requested);
70633
70863
  for (const r of rejected) {
70634
- const report2 = surfaceById(r.id) ? warn : error;
70635
- report2(`navigation.surfaces: ${r.reason} \u2014 the server will drop this key (narrow-only rule, RFC 0051 \xA73.6)`);
70864
+ const report3 = surfaceById(r.id) ? warn : error;
70865
+ report3(`navigation.surfaces: ${r.reason} \u2014 the server will drop this key (narrow-only rule, RFC 0051 \xA73.6)`);
70636
70866
  }
70637
70867
  }
70638
70868
  return issues;
@@ -70779,18 +71009,18 @@ function walkSource(dir, root = dir) {
70779
71009
  const ext = entry.name.slice(entry.name.lastIndexOf("."));
70780
71010
  if (!SOURCE_EXTENSIONS.has(ext)) continue;
70781
71011
  const absolute = join25(dir, entry.name);
70782
- const text6 = readText2(absolute);
70783
- if (text6 !== null) found.push({ path: relative4(root, absolute), text: text6 });
71012
+ const text8 = readText2(absolute);
71013
+ if (text8 !== null) found.push({ path: relative4(root, absolute), text: text8 });
70784
71014
  }
70785
71015
  return found;
70786
71016
  }
70787
- function blankMatrixRows(text6) {
70788
- const acceptance = mobileUxSection(mobileUxDocumentBody(text6), "Implementation acceptance") ?? "";
71017
+ function blankMatrixRows(text8) {
71018
+ const acceptance = mobileUxSection(mobileUxDocumentBody(text8), "Implementation acceptance") ?? "";
70789
71019
  return /\|\s*(?:Ready|Empty|Add\s*\/\s*edit|Saved\s*\/\s*completed|Error\s*\/\s*recovery)\s*\|\s*\|\s*\|\s*\|\s*\|/i.test(acceptance);
70790
71020
  }
70791
71021
  function usesAppNetwork(source) {
70792
- const code = (text6) => text6.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
70793
- return source.some(({ text: text6 }) => /\bwixApi\b|(?:from|import)\s*["']@(?:himalaya|wix\/himalaya)\/wix-[^"']+["']/.test(code(text6)));
71022
+ const code = (text8) => text8.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/[^\n]*/g, "");
71023
+ return source.some(({ text: text8 }) => /\bwixApi\b|(?:from|import)\s*["']@(?:himalaya|wix\/himalaya)\/wix-[^"']+["']/.test(code(text8)));
70794
71024
  }
70795
71025
  function auditUx(content, strict = false) {
70796
71026
  const dir = resolve16(content);
@@ -71504,6 +71734,13 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
71504
71734
  Requires Himi owner login plus Wix CLI login for site authorization.
71505
71735
  himi notify status --content <dir> [--site <msid>] [--refresh] [--json]
71506
71736
  Reads server setup status. --refresh checks Branded/Ping live; it does not send push.
71737
+ himi notify send --provider ping --target wix --app <a> --site <msid> --member-email <email>
71738
+ --title <s> [--body <s>] --link <scheme>://screen/<id>[?\u2026] [--request-id <uuid>] [--dry-run] [--json]
71739
+ Hosted test notification to ONE site member's devices: Himi Serve sends it through Ping
71740
+ as Himalaya, so no Apple/Firebase keys or Fire Console. Needs himi login --browser and
71741
+ wix login as the site owner, and a ready notify setup. Acceptance is not delivery.
71742
+ --dry-run checks ownership, member, link and readiness without sending. After an unknown
71743
+ outcome, re-run the same command with the printed --request-id; Ping never runs it twice.
71507
71744
  himi notify send --app <a> (--token <t> | --device <id> | --all) --title <s> [--body <s>] [--link <url>]
71508
71745
  deliver a REAL push notification to registered devices \u2014
71509
71746
  APNs (.p8) for iOS, FCM v1 for Android. --all fans out to
@@ -71695,7 +71932,7 @@ var COMMANDS = [
71695
71932
  { name: "icon", summary: "the app's LAUNCHER icon \u2014 the home-screen / store mark, which is BINARY-floor and never over-the-air (distinct from `himi icons`, the in-screen glyph vocabulary). `status`/`check` report what this app would actually ship and validate it against both stores: exact 1024x1024, no tRNS chunk, non-interlaced, and \u2014 when the optional image toolchain is installed \u2014 no transparent regions (Apple permits an alpha channel but not transparent pixels: ITMS-90717), no pre-masked corners, no letterboxed wordmark; they also print the store-policy checklist no checker can decide. `set <file.png>` installs supplied art, `from-site` installs the logo `himi site analyze` downloaded, and `generate` makes a gradient tile + glyph \u2014 all three trim, flatten onto the app's accent, write the 1024 opaque master plus the 512 Play listing icon (Play wants 32-bit WITH alpha, so it is a separate file), and DECLARE it in himalaya.content.json, without which the release bakes no icon at all", required: "[status|check] | set <file.png> | from-site [--book <dir>] | generate [--glyph <g>] [--accent <hex>] | glyphs [--content <dir>] [--json]" },
71696
71933
  { name: "login", summary: "obtain a scoped serve-control token from Wix identity and store it in ~/.himalaya/serve-targets.json (so push/promote need no hand-pasted token). Three modes: --browser (your own Wix account, no VPN/BO), --wix (HEADLESS \u2014 the machine's own Wix CLI credential; the mode a CI pod or agent container can satisfy), --dpx (Wix employee, reads ~/.dpx/session/token). RFC 0026 WS3.", required: "[--browser|--wix|--dpx] [--target <t>] [--issue-url <url>]" },
71697
71934
  { name: "logout", summary: "remove the stored control token for a target", required: "[--target <t>]" },
71698
- { name: "notify", summary: "`setup` optionally configures Branded/Ping from local customer key files; `status --refresh` reads live backend readiness. Setup may be deferred while building. These use serve-control and require owner plus Wix account authentication. `send`, `tokens`, `doctor`: send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
71935
+ { name: "notify", summary: "`setup` optionally configures Branded/Ping from local customer key files; `status --refresh` reads live backend readiness. Setup may be deferred while building. These use serve-control and require owner plus Wix account authentication. `send`, `tokens`, `doctor`: send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. `send --provider ping` is the hosted alternative: the serve plane sends one test notification to one site member through Ping as Himalaya, with owner login instead of provider keys, and reports acceptance, never delivery. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send --provider ping [--content <dir>] [--app <a>] [--site <msid>] --member-email <email> --title <s> [--body <s>] --link <url> [--request-id <uuid>] [--dry-run] [--json] | send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
71699
71936
  { name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze --read-only` returns API-only generation context as JSON (identity, access probes, CMS permissions and selected redacted Velo source); it needs no URL/browser and never uploads or applies anything. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `--url` alone is the visitor-only pass over the published pages, and `--client-id` adds the vertical probes and the app binding `--apply` requires; `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell; `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. `--shell brandy` (the site shell, RFC 0062) also derives the site's page map from its published pages and header menu \u2014 Home first, up to four tabs for the pages a visitor returns to, the rest in the drawer \u2014 into the overlay's `site` block, so it can be edited before `--apply`; only a site shell ever receives that block. It never overwrites any shell's committed apps/<shell>/provisioning.json.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --read-only [--site <msid>] [--client-id <id>] [--json] | analyze --url <https> [--client-id <id>] [--site <msid>] [--out <dir>] [--redirect-uri <uri>] [--apply] [--shell " + SHELL_ENUM + "] | function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET|POST|PUT|DELETE] [--source <file>] [--body <json>] [--publish] [--invoke]" },
71700
71937
  { name: "doctor", summary: 'off-VPN preflight in one shot: probe the PUBLIC data plane (www.wixapis.com \u2014 reachable off-VPN), the INTERNAL serve/control plane for the selected target (VPN-gated), and report auth state (dpx session on disk + stored control token). --dpx additionally runs a live, EADDRINUSE-safe `dpx whoami`. Machine-readable with --json (an unreachable internal plane carries a stable code:"needs_vpn" so an agent branches on the code, not the prose); human-readable otherwise. Never loads the authoring runtime \u2014 works off-repo.', required: "[--target <t>] [--dpx] [--json] [--data-url <url>] [--timeout <ms>]" },
71701
71938
  { name: "upgrade", summary: "install the newest published CLI (`npm i -g @wix/himalaya-cli@latest`) and report what moved. This is the explicit door: himi also updates itself when the running build is more than a week old \u2014 unattended it just does it and re-runs your command, at a terminal it asks first \u2014 and `HIMI_NO_UPDATE_CHECK=1` turns that off, leaving this command as the way to catch up. Reports `unchanged` rather than claiming success when npm exits 0 without moving the version, which is what a registry mirror serving its own pinned copy looks like.", required: "[--json]" },
@@ -71788,16 +72025,16 @@ function createScopedRegistryResolver(exec = execNpmConfig) {
71788
72025
  }
71789
72026
  var SCOPED_REGISTRY_TIMEOUT_MS = 5e3;
71790
72027
  function execNpmConfig(file, args, options) {
71791
- return new Promise((resolve52, reject) => {
71792
- execFile(file, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve52(String(stdout)));
72028
+ return new Promise((resolve53, reject) => {
72029
+ execFile(file, args, { ...options, windowsHide: true }, (error, stdout) => error ? reject(error) : resolve53(String(stdout)));
71793
72030
  });
71794
72031
  }
71795
72032
  var npmScopedWixRegistry = createScopedRegistryResolver();
71796
72033
  async function scopedRegistryBefore(lookup2, deadline) {
71797
72034
  let cancel = () => {
71798
72035
  };
71799
- const expired = new Promise((resolve52) => {
71800
- const timer = setTimeout(() => resolve52(void 0), Math.max(0, deadline - Date.now()));
72036
+ const expired = new Promise((resolve53) => {
72037
+ const timer = setTimeout(() => resolve53(void 0), Math.max(0, deadline - Date.now()));
71801
72038
  cancel = () => clearTimeout(timer);
71802
72039
  });
71803
72040
  try {
@@ -71862,7 +72099,7 @@ function packageVersion(path2) {
71862
72099
  }
71863
72100
  }
71864
72101
  function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
71865
- let dir = resolve51(fromDir);
72102
+ let dir = resolve52(fromDir);
71866
72103
  for (; ; ) {
71867
72104
  const version2 = packageVersion(join64(dir, "node_modules", "@wix", "himalaya", "package.json"));
71868
72105
  if (version2) return { version: version2, source: "local" };
@@ -72027,7 +72264,7 @@ function thisHost() {
72027
72264
  return hostname().replace(/\s+/g, "_");
72028
72265
  }
72029
72266
  function lockStamp(now) {
72030
- return `${now} ${process.pid} ${thisHost()} ${randomUUID6()}`;
72267
+ return `${now} ${process.pid} ${thisHost()} ${randomUUID7()}`;
72031
72268
  }
72032
72269
  function processAlive(pid) {
72033
72270
  try {
@@ -72181,21 +72418,21 @@ function loaderArgs(execArgv) {
72181
72418
  }
72182
72419
  var spawnUpdateRefresh = createUpdateRefreshSpawner();
72183
72420
  function createTrimValidator(deps = {}, spawnFn = spawn7) {
72184
- const outcome = (code, report2, said) => {
72421
+ const outcome = (code, report3, said) => {
72185
72422
  let counts;
72186
72423
  let errors;
72187
72424
  try {
72188
- const parsed = JSON.parse(report2);
72425
+ const parsed = JSON.parse(report3);
72189
72426
  counts = parsed.counts;
72190
72427
  if (Array.isArray(parsed.findings)) {
72191
- const text6 = (v) => typeof v === "string" && v ? v : void 0;
72428
+ const text8 = (v) => typeof v === "string" && v ? v : void 0;
72192
72429
  errors = parsed.findings.filter((f) => f && f.severity === "error" && typeof f.id === "string").map((f) => ({
72193
72430
  id: f.id,
72194
- message: text6(f.message) ?? "",
72195
- ...text6(f.pass) ? { pass: text6(f.pass) } : {},
72196
- ...text6(f.screen) ? { screen: text6(f.screen) } : {},
72197
- ...text6(f.path) ? { path: text6(f.path) } : {},
72198
- ...text6(f.ruleCode) ? { ruleCode: text6(f.ruleCode) } : {}
72431
+ message: text8(f.message) ?? "",
72432
+ ...text8(f.pass) ? { pass: text8(f.pass) } : {},
72433
+ ...text8(f.screen) ? { screen: text8(f.screen) } : {},
72434
+ ...text8(f.path) ? { path: text8(f.path) } : {},
72435
+ ...text8(f.ruleCode) ? { ruleCode: text8(f.ruleCode) } : {}
72199
72436
  }));
72200
72437
  }
72201
72438
  } catch {
@@ -72203,7 +72440,7 @@ function createTrimValidator(deps = {}, spawnFn = spawn7) {
72203
72440
  return { code, counts, ...errors ? { errors } : {}, ...code !== 0 ? { tail: said.slice(-4e3) } : {} };
72204
72441
  };
72205
72442
  return async (dir, opts = {}) => {
72206
- const argv = ["validate", "--content", resolve51(dir), "--strict", "--skip-version-check"];
72443
+ const argv = ["validate", "--content", resolve52(dir), "--strict", "--skip-version-check"];
72207
72444
  if (!opts.fresh) {
72208
72445
  const out2 = [];
72209
72446
  const err = [];
@@ -72819,7 +73056,7 @@ function keptPlan(kept) {
72819
73056
  return note ? { kept, note } : {};
72820
73057
  }
72821
73058
  async function initFromRemoteTemplate(name, parentDir, template, c) {
72822
- const dir = resolve51(parentDir, name);
73059
+ const dir = resolve52(parentDir, name);
72823
73060
  if (existsSync66(join64(dir, "himalaya.content.json"))) {
72824
73061
  throw new Error(`content package already exists at ${dir}`);
72825
73062
  }
@@ -72832,17 +73069,17 @@ async function initFromRemoteTemplate(name, parentDir, template, c) {
72832
73069
  return finishScaffold(materializeSource(archive.files, name, dir), template);
72833
73070
  }
72834
73071
  function contentDir(flags) {
72835
- return resolve51(str8(flags.content) ?? process.cwd());
73072
+ return resolve52(str8(flags.content) ?? process.cwd());
72836
73073
  }
72837
73074
  function renameRestoredSource(restored, declaredApp, renamed) {
72838
- const text6 = {};
73075
+ const text8 = {};
72839
73076
  for (const entry of restored) {
72840
73077
  const decoded = entry.bytes.toString("utf8");
72841
- if (Buffer.from(decoded, "utf8").equals(entry.bytes)) text6[entry.path] = decoded;
73078
+ if (Buffer.from(decoded, "utf8").equals(entry.bytes)) text8[entry.path] = decoded;
72842
73079
  }
72843
- const sentineled = sentinelizeArchive(text6, declaredApp);
73080
+ const sentineled = sentinelizeArchive(text8, declaredApp);
72844
73081
  for (const entry of restored) {
72845
- if (!(entry.path in text6)) continue;
73082
+ if (!(entry.path in text8)) continue;
72846
73083
  const body = sentineled[entry.path];
72847
73084
  if (body !== void 0) entry.bytes = Buffer.from(substituteIdentity(body, renamed), "utf8");
72848
73085
  }
@@ -72876,7 +73113,7 @@ function restoreDestinationIssue(dest, force) {
72876
73113
  return null;
72877
73114
  }
72878
73115
  function isHimalayaMonorepoCheckout(start) {
72879
- let dir = resolve51(start);
73116
+ let dir = resolve52(start);
72880
73117
  for (; ; ) {
72881
73118
  if (existsSync66(join64(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync66(join64(dir, "core", "serve", "src", "server.ts"))) return true;
72882
73119
  const parent = dirname36(dir);
@@ -72938,7 +73175,7 @@ function materializeForPreview(appDir3, slug, displayName) {
72938
73175
  const forBuild = Object.fromEntries(
72939
73176
  Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
72940
73177
  );
72941
- const repoRoot2 = resolve51(fileURLToPath26(new URL("../../..", import.meta.url)));
73178
+ const repoRoot2 = resolve52(fileURLToPath26(new URL("../../..", import.meta.url)));
72942
73179
  const root = join64(repoRoot2, "node_modules", ".cache", "himi-template-preview");
72943
73180
  const stillRunning = (pid) => {
72944
73181
  try {
@@ -73184,7 +73421,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
73184
73421
  return 0;
73185
73422
  }
73186
73423
  case "agent-init": {
73187
- const dir = resolve51(str8(flags.dir) ?? process.cwd());
73424
+ const dir = resolve52(str8(flags.dir) ?? process.cwd());
73188
73425
  const { seedAgentFiles: seedAgentFiles2, NotAContentPackage: NotAContentPackage2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
73189
73426
  let res;
73190
73427
  try {
@@ -73741,7 +73978,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
73741
73978
  return 2;
73742
73979
  }
73743
73980
  const template = str8(flags.template);
73744
- const parentDir = resolve51(str8(flags.dir) ?? process.cwd());
73981
+ const parentDir = resolve52(str8(flags.dir) ?? process.cwd());
73745
73982
  const withAgentFiles = async (dir) => {
73746
73983
  const seeded = await seedAgentFilesFor(dir, flags);
73747
73984
  if (!seeded.agent || "error" in seeded.agent) return seeded;
@@ -73902,8 +74139,8 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
73902
74139
  return 2;
73903
74140
  }
73904
74141
  }
73905
- const appDir3 = resolve51(str8(flags.dir) ?? process.cwd());
73906
- const sourceDir = resolve51(str8(flags["source-dir"]) ?? appDir3);
74142
+ const appDir3 = resolve52(str8(flags.dir) ?? process.cwd());
74143
+ const sourceDir = resolve52(str8(flags["source-dir"]) ?? appDir3);
73907
74144
  let meta;
73908
74145
  try {
73909
74146
  meta = JSON.parse(readFileSync79(join64(sourceDir, TEMPLATE_META_FILE), "utf8"));
@@ -73945,7 +74182,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
73945
74182
  ...hasWorkers ? { tier5Dir: bundleOutDir2(buildDir) } : {},
73946
74183
  collect: { lint: true, strict }
73947
74184
  });
73948
- const scaffoldSourceFindings = resolve51(sourceDir) === resolve51(appDir3) ? [] : [
74185
+ const scaffoldSourceFindings = resolve52(sourceDir) === resolve52(appDir3) ? [] : [
73949
74186
  ...tokenColorIssues(sourceDir),
73950
74187
  ...surfaceIssues(sourceDir, void 0, strict),
73951
74188
  ...await fontIssues(sourceDir, strict),
@@ -73957,7 +74194,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
73957
74194
  message: `scaffold source (--source-dir ${sourceDir}): ${issue2.message}`
73958
74195
  }));
73959
74196
  const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
73960
- const { report: report2, hasErrors } = summarizeLint(app, bres, outcome, strict, [
74197
+ const { report: report3, hasErrors } = summarizeLint(app, bres, outcome, strict, [
73961
74198
  ...await cmsIssues(buildDir, app, strict, { local: true }),
73962
74199
  ...surfaceIssues(buildDir, outcome.surfaceNav, strict),
73963
74200
  ...tokenColorIssues(buildDir),
@@ -73967,7 +74204,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
73967
74204
  ...scaffoldSourceFindings
73968
74205
  ]);
73969
74206
  if (hasErrors && !force) {
73970
- print({ ...report2, published: false, hint: "lint found errors \u2014 fix them, or re-run with --force to publish anyway" });
74207
+ print({ ...report3, published: false, hint: "lint found errors \u2014 fix them, or re-run with --force to publish anyway" });
73971
74208
  return 1;
73972
74209
  }
73973
74210
  const payload = await loadReleaseFromDir(app, out2);
@@ -73988,7 +74225,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
73988
74225
  }));
73989
74226
  return 1;
73990
74227
  }
73991
- const iconPath = str8(flags.icon) ? resolve51(str8(flags.icon)) : templateIconPath(name);
74228
+ const iconPath = str8(flags.icon) ? resolve52(str8(flags.icon)) : templateIconPath(name);
73992
74229
  let iconHash;
73993
74230
  if (iconPath) {
73994
74231
  try {
@@ -74242,7 +74479,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74242
74479
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
74243
74480
  collect: { lint: true, strict }
74244
74481
  });
74245
- const { report: report2, hasErrors } = summarizeLint(app, bres, outcome, strict, [
74482
+ const { report: report3, hasErrors } = summarizeLint(app, bres, outcome, strict, [
74246
74483
  ...await cmsIssues(dir, app, strict, { local: true }),
74247
74484
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
74248
74485
  ...tokenColorIssues(dir),
@@ -74259,10 +74496,10 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74259
74496
  if (authWarning) advisories.push(authWarning);
74260
74497
  advisories.push(...await nativeConfigAdvisories(app, configSource));
74261
74498
  const finalReport = advisories.length ? {
74262
- ...report2,
74263
- warnings: [...report2.warnings ?? [], ...advisories],
74264
- counts: { ...report2.counts, warnings: report2.counts.warnings + advisories.length }
74265
- } : report2;
74499
+ ...report3,
74500
+ warnings: [...report3.warnings ?? [], ...advisories],
74501
+ counts: { ...report3.counts, warnings: report3.counts.warnings + advisories.length }
74502
+ } : report3;
74266
74503
  await leaveForBoard(dir, "validate", {
74267
74504
  ok: !hasErrors,
74268
74505
  errors: finalReport.counts.errors,
@@ -74375,23 +74612,23 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74375
74612
  const app = str8(flags.app) ?? loaded.app;
74376
74613
  const invoked2 = await invokeRemoteFunction2({ baseUrl: target.baseUrl, app, definition, body: input, params, releaseId: remoteRelease, previewToken: str8(flags["preview-token"]), boCookie: boCookie() });
74377
74614
  const response = invoked2.response;
74378
- const text7 = await response.text();
74615
+ const text9 = await response.text();
74379
74616
  let body2;
74380
74617
  try {
74381
- body2 = JSON.parse(text7);
74618
+ body2 = JSON.parse(text9);
74382
74619
  } catch {
74383
- body2 = text7;
74620
+ body2 = text9;
74384
74621
  }
74385
74622
  print({ ok: response.ok, app, releaseId: remoteRelease ?? null, url: invoked2.url, status: response.status, body: body2 });
74386
74623
  return response.ok ? 0 : 1;
74387
74624
  }
74388
74625
  const invoked = await invokeLocalFunction2(loaded, name, input, params);
74389
- const text6 = await invoked.response.text();
74626
+ const text8 = await invoked.response.text();
74390
74627
  let body;
74391
74628
  try {
74392
- body = JSON.parse(text6);
74629
+ body = JSON.parse(text8);
74393
74630
  } catch {
74394
- body = text6;
74631
+ body = text8;
74395
74632
  }
74396
74633
  print({ ok: invoked.response.ok, app: loaded.app, releaseId: invoked.releaseId, status: invoked.response.status, body });
74397
74634
  return invoked.response.ok ? 0 : 1;
@@ -74410,7 +74647,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74410
74647
  return 1;
74411
74648
  }
74412
74649
  const { himiPluginFiles: himiPluginFiles2 } = await Promise.resolve().then(() => (init_claude_plugin(), claude_plugin_exports));
74413
- const dir = resolve51(out2);
74650
+ const dir = resolve52(out2);
74414
74651
  const files = himiPluginFiles2(skills.skillMd);
74415
74652
  for (const f of files) {
74416
74653
  mkdirSync32(dirname36(join64(dir, f.path)), { recursive: true });
@@ -74432,7 +74669,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74432
74669
  }
74433
74670
  if (pos[1] === "reel") {
74434
74671
  const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
74435
- const out2 = resolve51(str8(flags.out) ?? join64(dir, ".himi", "making-of.html"));
74672
+ const out2 = resolve52(str8(flags.out) ?? join64(dir, ".himi", "making-of.html"));
74436
74673
  const { html, plan } = buildReel2(dir);
74437
74674
  mkdirSync32(dirname36(out2), { recursive: true });
74438
74675
  writeFileSync29(out2, html);
@@ -74444,7 +74681,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74444
74681
  openUrl2(url2);
74445
74682
  }
74446
74683
  const handover = { file: out2, hint: `hand ${basename17(out2)} to the owner at the handover \u2014 one self-contained page of their app taking shape; send it beside the preview link, never instead of it` };
74447
- const report2 = {
74684
+ const report3 = {
74448
74685
  ok: true,
74449
74686
  file: out2,
74450
74687
  url: url2,
@@ -74457,7 +74694,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74457
74694
  ...plan.dropped ? { dropped: plan.dropped, note: "pictures were left out to keep the file attachable" } : {},
74458
74695
  ...plan.frames.length === 0 ? { hint: "no screen versions were recorded \u2014 run `himi studio` before building so the board keeps them" } : {}
74459
74696
  };
74460
- if (flags.json === true || io.isTTY !== true) print(report2);
74697
+ if (flags.json === true || io.isTTY !== true) print(report3);
74461
74698
  else io.log(`The making-of: ${out2}
74462
74699
  ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
74463
74700
  return 0;
@@ -74543,10 +74780,10 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
74543
74780
  }
74544
74781
  if (flags.brief === true) {
74545
74782
  const { agentContextNote: agentContextNote2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
74546
- const summary = summarizeProgress2(readProgress2(dir).entries);
74783
+ const summary2 = summarizeProgress2(readProgress2(dir).entries);
74547
74784
  const open = openApprovals2(readApprovals2(dir).events);
74548
74785
  const note = agentContextNote2(dir, cliVersion());
74549
- io.log(formatBrief2({ appName: appLabel2(dir), isContentPackage, summary, open, ...note ? { agentContextNote: note } : {} }));
74786
+ io.log(formatBrief2({ appName: appLabel2(dir), isContentPackage, summary: summary2, open, ...note ? { agentContextNote: note } : {} }));
74550
74787
  return 0;
74551
74788
  }
74552
74789
  if (!message) {
@@ -74604,9 +74841,9 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
74604
74841
  const sub = pos[1] ?? "audit";
74605
74842
  const dir = contentDir(flags);
74606
74843
  if (sub === "audit") {
74607
- const report2 = auditUx(dir, flags.strict === true);
74608
- print(report2);
74609
- return report2.ok ? 0 : 1;
74844
+ const report3 = auditUx(dir, flags.strict === true);
74845
+ print(report3);
74846
+ return report3.ok ? 0 : 1;
74610
74847
  }
74611
74848
  if (sub !== "record") {
74612
74849
  io.error(JSON.stringify({ error: "ux needs audit | record" }));
@@ -74818,7 +75055,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
74818
75055
  }
74819
75056
  const authoringBase = serveBase();
74820
75057
  try {
74821
- const { report: report2 } = await (deps.browserAuthoring ?? runBrowserAuthoring2)({
75058
+ const { report: report3 } = await (deps.browserAuthoring ?? runBrowserAuthoring2)({
74822
75059
  authoringBase,
74823
75060
  job: {
74824
75061
  entry: sources.entry,
@@ -74835,10 +75072,10 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
74835
75072
  log: (line) => io.error(line)
74836
75073
  });
74837
75074
  const { afterBrowserTestRun: afterBrowserTestRun2, watchReminder: watchReminder3 } = await Promise.resolve().then(() => (init_milestones(), milestones_exports));
74838
- const afterRun2 = afterBrowserTestRun2(dir, { screen: screen.screenId, report: report2, boardOpen: boardOpen(dir) });
75075
+ const afterRun2 = afterBrowserTestRun2(dir, { screen: screen.screenId, report: report3, boardOpen: boardOpen(dir) });
74839
75076
  const browserReminder = watchReminder3(dir, { content: str8(flags.content) });
74840
75077
  print({
74841
- ...report2,
75078
+ ...report3,
74842
75079
  screen: screen.screenId,
74843
75080
  ranIn: "browser",
74844
75081
  liveRequested: jobWix !== void 0,
@@ -74847,7 +75084,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
74847
75084
  // Also the envelope's LAST key (`tailLast` keeps it there): an agent may read only the tail.
74848
75085
  ...browserReminder ? { reminder: browserReminder } : {}
74849
75086
  });
74850
- return report2.ok ? 0 : 1;
75087
+ return report3.ok ? 0 : 1;
74851
75088
  } catch (e) {
74852
75089
  io.error(JSON.stringify({ error: e.message }));
74853
75090
  return 1;
@@ -75193,7 +75430,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
75193
75430
  const pngTarget = typeof flags.png === "string" ? str8(flags.png) : flags.png === true ? shotPath : void 0;
75194
75431
  if (pngTarget && r.pngBase64) {
75195
75432
  pngFile = writePngFile(pngTarget, r.pngBase64);
75196
- attestationPngFile = resolve51(pngTarget) === resolve51(shotPath) ? pngFile : writePngFile(shotPath, r.pngBase64);
75433
+ attestationPngFile = resolve52(pngTarget) === resolve52(shotPath) ? pngFile : writePngFile(shotPath, r.pngBase64);
75197
75434
  }
75198
75435
  if (renderWidth !== void 0 && r.renderable) {
75199
75436
  recordRenderWidth(dir, {
@@ -75285,23 +75522,23 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
75285
75522
  return 2;
75286
75523
  }
75287
75524
  const { kitReport: kitReport2 } = await Promise.resolve().then(() => (init_design_kits(), design_kits_exports));
75288
- const report2 = kitReport2(pos[2]);
75289
- print(report2);
75290
- return report2.ok ? 0 : 1;
75525
+ const report3 = kitReport2(pos[2]);
75526
+ print(report3);
75527
+ return report3.ok ? 0 : 1;
75291
75528
  }
75292
75529
  case "fonts": {
75293
75530
  const sub = pos[1];
75294
75531
  const dir = contentDir(flags);
75295
75532
  const { listReport: listReport3, checkReport: checkReport2, addReport: addReport2 } = await Promise.resolve().then(() => (init_fonts(), fonts_exports));
75296
75533
  if (sub === void 0 || sub === "list") {
75297
- const report2 = listReport3({ licenses: flags.licenses === true });
75298
- print(report2);
75299
- return report2.ok ? 0 : 1;
75534
+ const report3 = listReport3({ licenses: flags.licenses === true });
75535
+ print(report3);
75536
+ return report3.ok ? 0 : 1;
75300
75537
  }
75301
75538
  if (sub === "check") {
75302
- const report2 = await checkReport2(dir);
75303
- print(report2);
75304
- return report2.ok ? 0 : 1;
75539
+ const report3 = await checkReport2(dir);
75540
+ print(report3);
75541
+ return report3.ok ? 0 : 1;
75305
75542
  }
75306
75543
  if (sub === "add") {
75307
75544
  const family = pos[2];
@@ -75309,9 +75546,9 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
75309
75546
  print({ ok: false, problems: ["usage: himi fonts add <Family>"] });
75310
75547
  return 2;
75311
75548
  }
75312
- const report2 = addReport2(dir, family);
75313
- print(report2);
75314
- return report2.ok ? 0 : 1;
75549
+ const report3 = addReport2(dir, family);
75550
+ print(report3);
75551
+ return report3.ok ? 0 : 1;
75315
75552
  }
75316
75553
  print({ ok: false, problems: [`unknown subcommand "${sub}"`], hint: "himi fonts [list|check|add]" });
75317
75554
  return 2;
@@ -75332,7 +75569,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
75332
75569
  summarize: summarize4
75333
75570
  } = await Promise.resolve().then(() => (init_icon(), icon_exports));
75334
75571
  const requireVerified = sub === "check";
75335
- const report2 = async (status, extra = {}) => {
75572
+ const report3 = async (status, extra = {}) => {
75336
75573
  const findings = [
75337
75574
  // Not a store rule, so it is not in byteIssues — but it is the one `himi dist`
75338
75575
  // will refuse, and the point of `check` is to say so before the build does.
@@ -75370,7 +75607,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
75370
75607
  }
75371
75608
  return blocksRelease2(status, { requireVerified }) ? 1 : 0;
75372
75609
  };
75373
- if (sub === "status" || sub === "check") return report2(await iconStatus2(dir));
75610
+ if (sub === "status" || sub === "check") return report3(await iconStatus2(dir));
75374
75611
  if (sub === "set") {
75375
75612
  const file = pos[2];
75376
75613
  if (!file) {
@@ -75378,7 +75615,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
75378
75615
  return 1;
75379
75616
  }
75380
75617
  const res = await installIcon2(dir, file, { derivePlay: true });
75381
- return report2(res.status, { wrote: res.wrote, normalized: res.normalized, playListingIcon: res.playDerived });
75618
+ return report3(res.status, { wrote: res.wrote, normalized: res.normalized, playListingIcon: res.playDerived });
75382
75619
  }
75383
75620
  if (sub === "from-site") {
75384
75621
  const book = str8(flags.book) ?? ".himi/business-book";
@@ -75393,11 +75630,11 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
75393
75630
  return 1;
75394
75631
  }
75395
75632
  const res = await installIcon2(dir, logo, { derivePlay: true });
75396
- return report2(res.status, { from: logo, wrote: res.wrote, normalized: res.normalized, playListingIcon: res.playDerived });
75633
+ return report3(res.status, { from: logo, wrote: res.wrote, normalized: res.normalized, playListingIcon: res.playDerived });
75397
75634
  }
75398
75635
  if (sub === "generate") {
75399
75636
  const res = await generateIcon2(dir, { glyph: str8(flags.glyph), background: str8(flags.accent), derivePlay: true });
75400
- return report2(res.status, { wrote: res.wrote });
75637
+ return report3(res.status, { wrote: res.wrote });
75401
75638
  }
75402
75639
  if (sub === "glyphs") {
75403
75640
  const names = glyphNames2();
@@ -75423,9 +75660,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75423
75660
  const dir = contentDir(flags);
75424
75661
  const { listReport: listReport3, verifyReport: verifyReport2, addAssetPayload: addAssetPayload2, removeAssetPayload: removeAssetPayload2 } = await Promise.resolve().then(() => (init_assets(), assets_exports));
75425
75662
  if (sub === void 0 || sub === "list") {
75426
- const report2 = listReport3(dir);
75427
- print(report2);
75428
- return report2.ok ? 0 : 1;
75663
+ const report3 = listReport3(dir);
75664
+ print(report3);
75665
+ return report3.ok ? 0 : 1;
75429
75666
  }
75430
75667
  if (sub === "verify") {
75431
75668
  const app = str8(flags.app) ?? await appId(dir);
@@ -75434,9 +75671,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75434
75671
  io.error(JSON.stringify(found));
75435
75672
  return 1;
75436
75673
  }
75437
- const report2 = verifyReport2(dir, app, found.manifest);
75438
- print(report2);
75439
- return report2.ok ? 0 : 1;
75674
+ const report3 = verifyReport2(dir, app, found.manifest);
75675
+ print(report3);
75676
+ return report3.ok ? 0 : 1;
75440
75677
  }
75441
75678
  if (sub === "add" || sub === "rm") {
75442
75679
  const app = str8(flags.app) ?? await appId(dir);
@@ -75529,7 +75766,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75529
75766
  return 2;
75530
75767
  }
75531
75768
  const renamed = str8(flags.name);
75532
- const dest = resolve51(str8(flags.out) ?? process.cwd(), renamed ?? wanted);
75769
+ const dest = resolve52(str8(flags.out) ?? process.cwd(), renamed ?? wanted);
75533
75770
  const replace = flags.replace === true;
75534
75771
  const force = replace || flags.force === true;
75535
75772
  const linked = symlinkDestinationIssue(dest);
@@ -75602,7 +75839,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75602
75839
  let removed = [];
75603
75840
  if (replace) removed = removeStaleSource2(restored, dest);
75604
75841
  else left = staleSourcePaths2(restored, dest);
75605
- const refused = deniedArchivePaths2(restored);
75842
+ const refused2 = deniedArchivePaths2(restored);
75606
75843
  const written = writeAppSource2(restored, dest);
75607
75844
  const agent = await seedAgentFilesFor(dest, flags, "restore");
75608
75845
  print({
@@ -75613,8 +75850,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75613
75850
  ...agent,
75614
75851
  ...renamed ? { renamedTo: renamed } : {},
75615
75852
  ...removed.length ? { removed } : {},
75616
- ...refused.length ? {
75617
- refused,
75853
+ ...refused2.length ? {
75854
+ refused: refused2,
75618
75855
  refusedNote: "this archive carries paths a restore will not write (the deny-list has grown since it was published) \u2014 they were skipped, not written over"
75619
75856
  } : {},
75620
75857
  // EVERY path, not a count and not a sample: the whole failure was that a hybrid tree
@@ -75698,7 +75935,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75698
75935
  collect: { lint: true, strict }
75699
75936
  });
75700
75937
  const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
75701
- const { report: report2, hasErrors } = summarizeLint(declared, bres, outcome, strict, [
75938
+ const { report: report3, hasErrors } = summarizeLint(declared, bres, outcome, strict, [
75702
75939
  ...await cmsIssues(dir, declared, strict, { local: true }),
75703
75940
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
75704
75941
  ...tokenColorIssues(dir),
@@ -75708,7 +75945,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75708
75945
  ...await navIssues2(dir, strict)
75709
75946
  ]);
75710
75947
  if (hasErrors && !force) {
75711
- print({ ...report2, pushed: false, hint: "lint found errors \u2014 fix them, or re-run `himi push --force` to publish anyway" });
75948
+ print({ ...report3, pushed: false, hint: "lint found errors \u2014 fix them, or re-run `himi push --force` to publish anyway" });
75712
75949
  return 1;
75713
75950
  }
75714
75951
  const declaredData = await loadDataResourcesQuietly(dir);
@@ -75807,7 +76044,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
75807
76044
  // Reaches here ONLY on the forced path — the refusal above returned otherwise — so
75808
76045
  // this is the override's record, and the case it matters most for is a `failed` drive.
75809
76046
  ux: { evidence: patchUxEvidence, ctx: patchUxContext },
75810
- lint: report2.counts ?? null,
76047
+ lint: report3.counts ?? null,
75811
76048
  extra: { selector: parsed.selectors.map((s) => "pattern" in s ? `${s.kind}:${s.pattern}` : s.kind) }
75812
76049
  });
75813
76050
  }
@@ -76059,7 +76296,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76059
76296
  // print a `himi pull` command that answers app_source_not_found later — the worst
76060
76297
  // shape for a backup, which is one you are told you have.
76061
76298
  ...sourceSummary ? sourceStored === true ? { source: { ...sourceSummary, restore: `himi pull ${app} --release ${release}` } } : sourceStored === false ? { source: { ...sourceSummary, archived: false, note: "this serve target cannot store source archives, so this release cannot be restored with `himi pull`" } } : { source: { ...sourceSummary, archived: "unconfirmed", note: `this serve target did not report whether it stored the source (it may predate the field). Verify with \`himi pull ${app} --release ${release}\` before relying on it.` } } : { source: { archived: false, note: "pushed with --no-source \u2014 this release cannot be restored with `himi pull`" } },
76062
- lint: report2.counts,
76299
+ lint: report3.counts,
76063
76300
  // A push ships content, not backends. If the app declares CMS
76064
76301
  // collections, say so and point at the verbs — but never mutate the
76065
76302
  // site as a side effect of publishing a release.
@@ -76091,7 +76328,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76091
76328
  nondeterministicWorkers: drifting
76092
76329
  }),
76093
76330
  ...loopbackWarning ? { warning: loopbackWarning } : {},
76094
- ...report2.issues ? { issues: report2.issues } : {},
76331
+ ...report3.issues ? { issues: report3.issues } : {},
76095
76332
  previewWeb: base ? previewWebUrl(base, app, release, void 0, void 0, previewToken, previewHandover) : null,
76096
76333
  // A timestamp alone leaves the reader to work out both how long they have and how to
76097
76334
  // get another one. Print the duration and the re-mint command beside it (#2502 item 3).
@@ -76188,7 +76425,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76188
76425
  return 2;
76189
76426
  }
76190
76427
  try {
76191
- const res = writePack(resolve51(releaseDir), only, resolve51(str8(flags.out) ?? process.cwd()));
76428
+ const res = writePack(resolve52(releaseDir), only, resolve52(str8(flags.out) ?? process.cwd()));
76192
76429
  print({
76193
76430
  ok: true,
76194
76431
  app: res.app,
@@ -76244,7 +76481,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76244
76481
  collect: { lint: true, strict }
76245
76482
  });
76246
76483
  const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
76247
- const { report: report2, hasErrors } = summarizeLint(app, bres, outcome, strict, [
76484
+ const { report: report3, hasErrors } = summarizeLint(app, bres, outcome, strict, [
76248
76485
  ...await cmsIssues(dir, app, strict, { local: true }),
76249
76486
  ...surfaceIssues(dir, outcome.surfaceNav, strict),
76250
76487
  ...tokenColorIssues(dir),
@@ -76255,11 +76492,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76255
76492
  ]);
76256
76493
  if (hasErrors && !force) {
76257
76494
  rmSync15(built, { recursive: true, force: true });
76258
- print({ ...report2, packed: false, hint: "lint found errors \u2014 fix them, or re-run `himi pack --force` to pack anyway" });
76495
+ print({ ...report3, packed: false, hint: "lint found errors \u2014 fix them, or re-run `himi pack --force` to pack anyway" });
76259
76496
  return 1;
76260
76497
  }
76261
76498
  try {
76262
- const res = writePack(built, app, resolve51(str8(flags.out) ?? dir), sourceArchive);
76499
+ const res = writePack(built, app, resolve52(str8(flags.out) ?? dir), sourceArchive);
76263
76500
  print({
76264
76501
  ok: true,
76265
76502
  app: res.app,
@@ -76269,12 +76506,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76269
76506
  entries: res.entryCount,
76270
76507
  format,
76271
76508
  launchMode,
76272
- lint: report2.counts,
76509
+ lint: report3.counts,
76273
76510
  contents: withSource ? "dev" : "release",
76274
76511
  ...sourceSummary ? { source: sourceSummary } : {},
76275
76512
  ...res.skipped.length ? { skipped: res.skipped } : {},
76276
76513
  ...hasErrors && force ? { forcedPastErrors: true } : {},
76277
- ...report2.issues ? { issues: report2.issues } : {},
76514
+ ...report3.issues ? { issues: report3.issues } : {},
76278
76515
  open: [
76279
76516
  ...withSource ? [`himi import ${res.out}`] : [],
76280
76517
  `himi run ${res.out}`,
@@ -76304,7 +76541,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76304
76541
  const { HIMI_PACKAGE_SOURCE_PATH: HIMI_PACKAGE_SOURCE_PATH2, isSafeAppId: isSafeAppId2, packageContents: packageContents2 } = await Promise.resolve().then(() => (init_himi_package(), himi_package_exports));
76305
76542
  let opened;
76306
76543
  try {
76307
- opened = openPackageFile2(resolve51(file));
76544
+ opened = openPackageFile2(resolve52(file));
76308
76545
  } catch (e) {
76309
76546
  io.error(JSON.stringify({ error: e.message }));
76310
76547
  return 1;
@@ -76317,7 +76554,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76317
76554
  io.error(JSON.stringify({
76318
76555
  ok: false,
76319
76556
  error: "app_source_not_in_package",
76320
- detail: `${resolve51(file)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
76557
+ detail: `${resolve52(file)} is a release package: it carries built output (screens, bundles, tokens) and no source`,
76321
76558
  hint: "re-pack it from the content package with `himi pack --dev`, or restore from the serve plane with `himi pull <app>`"
76322
76559
  }));
76323
76560
  return 1;
@@ -76340,7 +76577,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76340
76577
  return 1;
76341
76578
  }
76342
76579
  }
76343
- const dest = resolve51(str8(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
76580
+ const dest = resolve52(str8(flags.out) ?? process.cwd(), renamed ?? opened.header.app);
76344
76581
  const issue2 = restoreDestinationIssue(dest, flags.force === true);
76345
76582
  if (issue2) {
76346
76583
  io.error(JSON.stringify(issue2));
@@ -76379,7 +76616,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76379
76616
  return 1;
76380
76617
  }
76381
76618
  const left = staleSourcePaths2(restored, dest);
76382
- const refused = deniedArchivePaths2(restored);
76619
+ const refused2 = deniedArchivePaths2(restored);
76383
76620
  const written = writeAppSource2(restored, dest);
76384
76621
  const agent = await seedAgentFilesFor(dest, flags, "restore");
76385
76622
  print({
@@ -76390,8 +76627,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76390
76627
  files: written.length,
76391
76628
  ...agent,
76392
76629
  ...renamed ? { renamedTo: renamed } : {},
76393
- ...refused.length ? {
76394
- refused,
76630
+ ...refused2.length ? {
76631
+ refused: refused2,
76395
76632
  refusedNote: "this package carries paths a restore will not write (the deny-list has grown since it was packed) \u2014 they were skipped, not written over"
76396
76633
  } : {},
76397
76634
  ...left.length ? {
@@ -76427,7 +76664,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76427
76664
  }
76428
76665
  try {
76429
76666
  const { openPackageFile: openPackageFile2 } = await Promise.resolve().then(() => (init_pack(), pack_exports));
76430
- const opened = openPackageFile2(resolve51(file));
76667
+ const opened = openPackageFile2(resolve52(file));
76431
76668
  if (!opened.validation.ok || !opened.header) {
76432
76669
  io.error(JSON.stringify({ error: "refusing to share an invalid package", issues: opened.validation.errors }));
76433
76670
  return 1;
@@ -76437,12 +76674,12 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76437
76674
  io.error(JSON.stringify({
76438
76675
  ok: false,
76439
76676
  error: "refusing to share a package that carries the app's source",
76440
- detail: `${resolve51(file)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
76677
+ detail: `${resolve52(file)} was packed with --dev, and a share link is public and unauthenticated \u2014 anyone with the URL could \`himi import\` your codebase`,
76441
76678
  hint: "share a release package instead (`himi pack` with no --dev), or hand the dev package over directly"
76442
76679
  }));
76443
76680
  return 1;
76444
76681
  }
76445
- const archive = readFileSync79(resolve51(file));
76682
+ const archive = readFileSync79(resolve52(file));
76446
76683
  const result = await client2().createPackageShare({
76447
76684
  app: opened.header.app,
76448
76685
  releaseId: opened.header.releaseId,
@@ -76581,9 +76818,9 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76581
76818
  });
76582
76819
  await announce(run2);
76583
76820
  print({ ok: true, app: run2.app, url: run2.url, port: run2.port, plane: "browser" });
76584
- await new Promise((resolve52) => {
76821
+ await new Promise((resolve53) => {
76585
76822
  const stop = () => {
76586
- void retract().catch((e) => io.error(JSON.stringify({ run: "stop_cleanup_failed", message: e.message }))).finally(() => run2.close().finally(() => resolve52()));
76823
+ void retract().catch((e) => io.error(JSON.stringify({ run: "stop_cleanup_failed", message: e.message }))).finally(() => run2.close().finally(() => resolve53()));
76587
76824
  };
76588
76825
  process.once("SIGINT", stop);
76589
76826
  process.once("SIGTERM", stop);
@@ -78623,13 +78860,13 @@ ${label2}`);
78623
78860
  // advertisable for the target this report is about.
78624
78861
  hasOwnerIssuer: (resolved2?.ownerIssue ?? "") !== ""
78625
78862
  });
78626
- const report2 = buildDoctorReport({ target, version: cliVersion(), data, serve, auth, loginModes, dpxStatus, versions });
78627
- if (targetError) report2.targetError = targetError;
78863
+ const report3 = buildDoctorReport({ target, version: cliVersion(), data, serve, auth, loginModes, dpxStatus, versions });
78864
+ if (targetError) report3.targetError = targetError;
78628
78865
  const { agentContextStatus: agentContextStatus2 } = await Promise.resolve().then(() => (init_agent_context(), agent_context_exports));
78629
78866
  const agentContext = agentContextStatus2(contentDir(flags), cliVersion());
78630
- if (agentContext) report2.agentContext = agentContext;
78867
+ if (agentContext) report3.agentContext = agentContext;
78631
78868
  if (flags.json === true) {
78632
- print(report2);
78869
+ print(report3);
78633
78870
  return 0;
78634
78871
  }
78635
78872
  const mark = (r) => r.reachable ? `reachable${r.status ? ` [${r.status}]` : ""}` : `UNREACHABLE${r.error ? ` (${r.error})` : ""}`;
@@ -78639,7 +78876,7 @@ ${label2}`);
78639
78876
  io.log(` ${mark(data)}`);
78640
78877
  io.log(` serve plane ${serveUrl || "(no serve url)"}`);
78641
78878
  io.log(` ${mark(serve)}`);
78642
- const serveCode = report2.servePlane.code;
78879
+ const serveCode = report3.servePlane.code;
78643
78880
  if (serveCode) io.log(` ${serveCode}: ${serveUnreachableHint(target)}`);
78644
78881
  io.log(` auth dpx session: ${auth.dpxSession ? "yes" : "no"} control token: ${auth.controlToken ? "yes" : controlHostRefused ? "REFUSED" : auth.controlTokenPresent ? "STALE" : "no"}`);
78645
78882
  if (auth.controlTokenHint) io.log(` ${auth.controlTokenHint}`);
@@ -78662,7 +78899,7 @@ ${label2}`);
78662
78899
  }
78663
78900
  io.log(
78664
78901
  `
78665
- ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint === "string" && report2.hint ? report2.hint : serve.reachable ? "Data plane unreachable \u2014 check basic connectivity." : serveUnreachableHint(target)}`
78902
+ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint === "string" && report3.hint ? report3.hint : serve.reachable ? "Data plane unreachable \u2014 check basic connectivity." : serveUnreachableHint(target)}`
78666
78903
  );
78667
78904
  return 0;
78668
78905
  }
@@ -78775,9 +79012,9 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
78775
79012
  }
78776
79013
  const scope = { app, siteId: site, environment: environment2 };
78777
79014
  try {
78778
- const report2 = sub === "plan" ? await planData({ scope, data, kv, call }) : sub === "create" ? await createData({ scope, data, kv, call, dryRun: flags["dry-run"] === true }) : await seedData({ scope, data, kv, call, dir, dryRun: flags["dry-run"] === true, force: flags.force === true });
78779
- print(report2);
78780
- return report2.ok ? 0 : 1;
79015
+ const report3 = sub === "plan" ? await planData({ scope, data, kv, call }) : sub === "create" ? await createData({ scope, data, kv, call, dryRun: flags["dry-run"] === true }) : await seedData({ scope, data, kv, call, dir, dryRun: flags["dry-run"] === true, force: flags.force === true });
79016
+ print(report3);
79017
+ return report3.ok ? 0 : 1;
78781
79018
  } catch (error) {
78782
79019
  io.error(JSON.stringify({ error: error.message, app, site, environment: environment2, hint: "run `himi data plan` to re-read actual state before retrying" }));
78783
79020
  return 1;
@@ -78792,6 +79029,14 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
78792
79029
  const { runNotifySetup: runNotifySetup2 } = await Promise.resolve().then(() => (init_notify_setup(), notify_setup_exports));
78793
79030
  return runNotifySetup2(pos, flags, io);
78794
79031
  }
79032
+ if (pos[1] === "send" && flags.provider !== void 0) {
79033
+ if (flags.provider !== "ping") {
79034
+ io.error(JSON.stringify({ ok: false, error: "unknown_provider", hint: "The hosted sender is --provider ping." }));
79035
+ return 2;
79036
+ }
79037
+ const { runNotifyPing: runNotifyPing2 } = await Promise.resolve().then(() => (init_notify_ping(), notify_ping_exports));
79038
+ return runNotifyPing2(flags, io);
79039
+ }
78795
79040
  const { runNotify: runNotify2 } = await Promise.resolve().then(() => (init_notify(), notify_exports));
78796
79041
  return await runNotify2(pos, flags, io);
78797
79042
  case "cms": {
@@ -78850,9 +79095,9 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
78850
79095
  return 2;
78851
79096
  }
78852
79097
  const common = { app, cms, call };
78853
- let report2;
79098
+ let report3;
78854
79099
  try {
78855
- report2 = sub === "query" ? await queryCms({ ...common, all: flags.all === true }) : sub === "create" ? await createCms({ ...common, dryRun: flags["dry-run"] === true, allowDestructive: flags["allow-destructive"] === true, applyPermissions: flags["apply-permissions"] === true }) : await seedCms({ ...common, dir, dryRun: flags["dry-run"] === true, force: flags.force === true, only: str8(flags.only) });
79100
+ report3 = sub === "query" ? await queryCms({ ...common, all: flags.all === true }) : sub === "create" ? await createCms({ ...common, dryRun: flags["dry-run"] === true, allowDestructive: flags["allow-destructive"] === true, applyPermissions: flags["apply-permissions"] === true }) : await seedCms({ ...common, dir, dryRun: flags["dry-run"] === true, force: flags.force === true, only: str8(flags.only) });
78856
79101
  } catch (e) {
78857
79102
  const partial = e.partial;
78858
79103
  io.error(JSON.stringify({
@@ -78864,8 +79109,8 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
78864
79109
  }));
78865
79110
  return 1;
78866
79111
  }
78867
- print({ ...report2, site });
78868
- return report2.ok ? 0 : 1;
79112
+ print({ ...report3, site });
79113
+ return report3.ok ? 0 : 1;
78869
79114
  }
78870
79115
  case "site": {
78871
79116
  const sub = pos[1];