@wix/himalaya-cli 0.1433.0 → 0.1434.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
@@ -240,6 +240,9 @@ function physicalEntityName(spec, app) {
240
240
  if (isAdoptedEntity(spec)) return spec.base44Name;
241
241
  return nonEmpty(spec.name) ? `${base44Prefix(app)}${spec.name}` : "";
242
242
  }
243
+ function isOwnedFunction(spec) {
244
+ return !nonEmpty(spec.base44Name) && nonEmpty(spec.name);
245
+ }
243
246
  function physicalFunctionName(spec) {
244
247
  return nonEmpty(spec.base44Name) ? spec.base44Name : nonEmpty(spec.name) ? spec.name : "";
245
248
  }
@@ -3013,10 +3016,10 @@ function readRetainedAttestations(contentDir2) {
3013
3016
  const dir = join6(resolve6(contentDir2), ".himi", "attestations");
3014
3017
  if (!existsSync3(dir)) return { runs: [], errors: [] };
3015
3018
  try {
3016
- const names = readdirSync3(dir).filter((name) => name.endsWith(".json") && name !== "latest.json");
3019
+ const names2 = readdirSync3(dir).filter((name) => name.endsWith(".json") && name !== "latest.json");
3017
3020
  const parsedRuns = [];
3018
3021
  const errors = [];
3019
- for (const name of names) {
3022
+ for (const name of names2) {
3020
3023
  const classified = classifyRetainedRun(dir, name);
3021
3024
  if (classified.kind === "current") parsedRuns.push(classified.run);
3022
3025
  else if (classified.kind === "legacy") {
@@ -3029,7 +3032,7 @@ function readRetainedAttestations(contentDir2) {
3029
3032
  }
3030
3033
  const latest = readLatestAttestation(contentDir2);
3031
3034
  if (existsSync3(join6(dir, "latest.json")) && !latest) errors.push("attestation history has no valid latest.json");
3032
- else if (names.length > 0 && !latest) errors.push("attestation history has no latest.json");
3035
+ else if (names2.length > 0 && !latest) errors.push("attestation history has no latest.json");
3033
3036
  const byHash = new Map(parsedRuns.map((run2) => [run2.selfHash, run2]));
3034
3037
  if (byHash.size !== parsedRuns.length) errors.push("attestation history contains duplicate self hashes");
3035
3038
  for (const run2 of parsedRuns) {
@@ -5731,18 +5734,18 @@ function servedBundleName(fileName) {
5731
5734
  return void 0;
5732
5735
  }
5733
5736
  function servedBundleNames(dir) {
5734
- const names = /* @__PURE__ */ new Set();
5737
+ const names2 = /* @__PURE__ */ new Set();
5735
5738
  let entries;
5736
5739
  try {
5737
5740
  entries = readdirSync7(dir);
5738
5741
  } catch {
5739
- return names;
5742
+ return names2;
5740
5743
  }
5741
5744
  for (const entry of entries) {
5742
5745
  const name = servedBundleName(entry);
5743
- if (name !== void 0) names.add(name);
5746
+ if (name !== void 0) names2.add(name);
5744
5747
  }
5745
- return names;
5748
+ return names2;
5746
5749
  }
5747
5750
  var init_tier5_dir = __esm({
5748
5751
  "../../core/dev-server/src/tier5-dir.ts"() {
@@ -6004,14 +6007,14 @@ function analyzeService(source, forbidden2) {
6004
6007
  for (const stmt of sf2.statements) {
6005
6008
  if (ts.isImportDeclaration(stmt) && ts.isStringLiteral(stmt.moduleSpecifier)) {
6006
6009
  const mod = stmt.moduleSpecifier.text;
6007
- const names = [];
6010
+ const names2 = [];
6008
6011
  const ic = stmt.importClause;
6009
- if (ic?.name) names.push(ic.name.text);
6012
+ if (ic?.name) names2.push(ic.name.text);
6010
6013
  if (ic?.namedBindings) {
6011
- if (ts.isNamedImports(ic.namedBindings)) for (const el2 of ic.namedBindings.elements) names.push(el2.name.text);
6012
- else if (ts.isNamespaceImport(ic.namedBindings)) names.push(ic.namedBindings.name.text);
6014
+ if (ts.isNamedImports(ic.namedBindings)) for (const el2 of ic.namedBindings.elements) names2.push(el2.name.text);
6015
+ else if (ts.isNamespaceImport(ic.namedBindings)) names2.push(ic.namedBindings.name.text);
6013
6016
  }
6014
- info4.imports.push({ module: mod, names, line: lineOfPos(stmt.getStart(sf2)) });
6017
+ info4.imports.push({ module: mod, names: names2, line: lineOfPos(stmt.getStart(sf2)) });
6015
6018
  if (mod.startsWith("@himalaya/")) info4.usedModules.add(mod);
6016
6019
  }
6017
6020
  }
@@ -6222,7 +6225,7 @@ function analyzeController(source, file2, profile, diagnostics) {
6222
6225
  if (!initial || typeof initial !== "object" || Array.isArray(initial)) throw new Error("initialState must be a JSON object.");
6223
6226
  const paths = /* @__PURE__ */ new Map();
6224
6227
  collect2(initial);
6225
- const names = /* @__PURE__ */ new Set();
6228
+ const names2 = /* @__PURE__ */ new Set();
6226
6229
  for (const handler of handlers.initializer.properties) {
6227
6230
  if (!handler.name || ts2.isComputedPropertyName(handler.name) || ts2.isSpreadAssignment(handler)) {
6228
6231
  error(handler, "Handlers need static names.");
@@ -6230,9 +6233,9 @@ function analyzeController(source, file2, profile, diagnostics) {
6230
6233
  }
6231
6234
  const name = handler.name.getText(sf2).replace(/^["']|["']$/g, "");
6232
6235
  if (!/^[a-zA-Z_]\w*$/.test(name) || name.startsWith("__hhp") || unsafe.has(name)) error(handler, `Invalid handler name ${name}.`);
6233
- names.add(name);
6236
+ names2.add(name);
6234
6237
  }
6235
- return { state: initial, paths, handlers: names };
6238
+ return { state: initial, paths, handlers: names2 };
6236
6239
  } catch (e2) {
6237
6240
  error(state, e2.message);
6238
6241
  return;
@@ -11006,18 +11009,18 @@ function nondeterministicServices(bundleJs, opts = {}) {
11006
11009
  const threw = boots.filter((b3) => b3.threw !== null).length;
11007
11010
  if (threw === boots.length) return [];
11008
11011
  const [a2, b2] = boots.map((boot) => boot.services);
11009
- const names = [.../* @__PURE__ */ new Set([...Object.keys(a2), ...Object.keys(b2)])];
11010
- if (threw > 0) return names.sort();
11011
- return names.filter((name) => safeStringify(a2[name]) !== safeStringify(b2[name])).sort();
11012
+ const names2 = [.../* @__PURE__ */ new Set([...Object.keys(a2), ...Object.keys(b2)])];
11013
+ if (threw > 0) return names2.sort();
11014
+ return names2.filter((name) => safeStringify(a2[name]) !== safeStringify(b2[name])).sort();
11012
11015
  }
11013
11016
  function deviceParityWithheldFrom(root) {
11014
- const names = new Set(DEVICE_PARITY_CANDIDATES);
11017
+ const names2 = new Set(DEVICE_PARITY_CANDIDATES);
11015
11018
  for (let o2 = root; o2 && o2 !== Object.prototype; o2 = Object.getPrototypeOf(o2)) {
11016
- for (const name of Object.getOwnPropertyNames(o2)) names.add(name);
11019
+ for (const name of Object.getOwnPropertyNames(o2)) names2.add(name);
11017
11020
  }
11018
- names.delete("constructor");
11019
- names.delete("__proto__");
11020
- return [...names].filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && !WORKER_ALLOWLIST.has(name)).sort();
11021
+ names2.delete("constructor");
11022
+ names2.delete("__proto__");
11023
+ return [...names2].filter((name) => /^[A-Za-z_$][\w$]*$/.test(name) && !WORKER_ALLOWLIST.has(name)).sort();
11021
11024
  }
11022
11025
  function setDefaultEvaluator(evaluator) {
11023
11026
  defaultEvaluator = evaluator;
@@ -11925,11 +11928,11 @@ function componentPropFindings(descriptor) {
11925
11928
  return out2;
11926
11929
  }
11927
11930
  function enumFieldNames(schema = screenDescriptorSchema) {
11928
- const names = /* @__PURE__ */ new Set();
11931
+ const names2 = /* @__PURE__ */ new Set();
11929
11932
  const visit = (node, propName5) => {
11930
11933
  if (!node || typeof node !== "object") return;
11931
11934
  const obj4 = node;
11932
- if (propName5 && Array.isArray(obj4.enum)) names.add(propName5);
11935
+ if (propName5 && Array.isArray(obj4.enum)) names2.add(propName5);
11933
11936
  if (obj4.properties && typeof obj4.properties === "object") {
11934
11937
  for (const [k2, v2] of Object.entries(obj4.properties)) visit(v2, k2);
11935
11938
  }
@@ -11944,7 +11947,7 @@ function enumFieldNames(schema = screenDescriptorSchema) {
11944
11947
  }
11945
11948
  };
11946
11949
  visit(schema, null);
11947
- return names;
11950
+ return names2;
11948
11951
  }
11949
11952
  function serviceOnlyBindingValues(props, key3) {
11950
11953
  const arrayAt = key3.indexOf("[]");
@@ -14155,17 +14158,17 @@ function devModuleRealm() {
14155
14158
  return devRealm;
14156
14159
  }
14157
14160
  function bundleNamesFor(dir) {
14158
- const names = /* @__PURE__ */ new Set();
14161
+ const names2 = /* @__PURE__ */ new Set();
14159
14162
  for (const root of [bundleOutDir(dir), TIER5_ROOT]) {
14160
14163
  if (!root || !existsSync11(root)) continue;
14161
14164
  try {
14162
14165
  for (const f2 of readdirSync9(root)) {
14163
- if (f2.endsWith(".bundle.js")) names.add(basename5(f2, ".bundle.js"));
14166
+ if (f2.endsWith(".bundle.js")) names2.add(basename5(f2, ".bundle.js"));
14164
14167
  }
14165
14168
  } catch {
14166
14169
  }
14167
14170
  }
14168
- return [...names];
14171
+ return [...names2];
14169
14172
  }
14170
14173
  function crossContext(ctx, bundleNames, assetNames, integrityMemo, assetMemo) {
14171
14174
  const probe = bundleNames[0];
@@ -19472,10 +19475,10 @@ function glyphNames() {
19472
19475
  return Object.keys(GLYPHS).sort();
19473
19476
  }
19474
19477
  async function generateIcon(dir, opts = {}) {
19475
- const names = glyphNames();
19478
+ const names2 = glyphNames();
19476
19479
  const chosen = opts.glyph ?? DEFAULT_GLYPH;
19477
- if (!names.includes(chosen)) {
19478
- throw new Error(`himi icon: unknown glyph "${chosen}". Available: ${names.join(", ")}`);
19480
+ if (!names2.includes(chosen)) {
19481
+ throw new Error(`himi icon: unknown glyph "${chosen}". Available: ${names2.join(", ")}`);
19479
19482
  }
19480
19483
  const background = opts.background ?? backdropFromTokens(dir);
19481
19484
  if (!HEX_COLOR2.test(background)) {
@@ -19554,9 +19557,9 @@ function renderableFamilies(catalog3 = loadCatalog()) {
19554
19557
  function findFamily(name, catalog3 = loadCatalog()) {
19555
19558
  const exact = catalog3.families[name] ?? catalog3.bundled[name];
19556
19559
  if (exact) return exact;
19557
- const canonical5 = familyIndex(catalog3).get(normalizeFamily(name));
19558
- if (!canonical5) return void 0;
19559
- return catalog3.families[canonical5] ?? catalog3.bundled[canonical5];
19560
+ const canonical6 = familyIndex(catalog3).get(normalizeFamily(name));
19561
+ if (!canonical6) return void 0;
19562
+ return catalog3.families[canonical6] ?? catalog3.bundled[canonical6];
19560
19563
  }
19561
19564
  function canonicalFamilyName(name, catalog3 = loadCatalog()) {
19562
19565
  if (catalog3.families[name] ?? catalog3.bundled[name] ?? catalog3.system[name]) return name;
@@ -20694,8 +20697,8 @@ async function navEntryScreens(dir, homeScreenId) {
20694
20697
  }
20695
20698
  async function localDbEntities(dir) {
20696
20699
  const schema = (await loadContentConfigQuietly(dir))?.dataSchema;
20697
- const names = (schema?.entities ?? []).map((e2) => e2?.name).filter((n2) => typeof n2 === "string" && n2.length > 0);
20698
- return names.length ? names.map((name) => ({ name })) : null;
20700
+ const names2 = (schema?.entities ?? []).map((e2) => e2?.name).filter((n2) => typeof n2 === "string" && n2.length > 0);
20701
+ return names2.length ? names2.map((name) => ({ name })) : null;
20699
20702
  }
20700
20703
  function renderMocksFrom(rules, bad2, seeded) {
20701
20704
  if (rules || seeded) {
@@ -24280,7 +24283,7 @@ function parseOrientationEnvelope(configTs) {
24280
24283
  };
24281
24284
  }
24282
24285
  function orientationPlistPlan(env) {
24283
- const map = (names) => ALL_ORIENTATIONS.filter((o2) => names.includes(o2)).map((o2) => IOS_ORIENTATION[o2]);
24286
+ const map = (names2) => ALL_ORIENTATIONS.filter((o2) => names2.includes(o2)).map((o2) => IOS_ORIENTATION[o2]);
24284
24287
  return {
24285
24288
  UISupportedInterfaceOrientations: map(env.phone),
24286
24289
  "UISupportedInterfaceOrientations~ipad": map(env.tablet)
@@ -25619,12 +25622,12 @@ function carryPlanningJournal(parentDir, appDir3) {
25619
25622
  }
25620
25623
  if (carried.includes(toPosix(PROGRESS_FILE))) {
25621
25624
  const hist = join36(parentDir, HISTORY_DIR);
25622
- let names = [];
25625
+ let names2 = [];
25623
25626
  try {
25624
- if (lstatSync8(hist).isDirectory()) names = readdirSync21(hist);
25627
+ if (lstatSync8(hist).isDirectory()) names2 = readdirSync21(hist);
25625
25628
  } catch {
25626
25629
  }
25627
- for (const name of names) {
25630
+ for (const name of names2) {
25628
25631
  const from = join36(hist, name);
25629
25632
  if (isSymlink(from) || !lstatSync8(from).isFile()) continue;
25630
25633
  const bytes2 = readFileSync35(from);
@@ -27153,9 +27156,9 @@ function validateScreenMetadata(screens) {
27153
27156
  labels.set(key3, { viewId, explicit: name !== void 0 || other?.explicit === true });
27154
27157
  }
27155
27158
  }
27156
- function screenMetadataFor(definitions2, id, canonical5) {
27159
+ function screenMetadataFor(definitions2, id, canonical6) {
27157
27160
  if (definitions2 && Object.hasOwn(definitions2, id)) return definitions2[id];
27158
- if (canonical5 && definitions2 && Object.hasOwn(definitions2, canonical5)) return { ...definitions2[canonical5], viewId: definitions2[canonical5].viewId ?? canonical5 };
27161
+ if (canonical6 && definitions2 && Object.hasOwn(definitions2, canonical6)) return { ...definitions2[canonical6], viewId: definitions2[canonical6].viewId ?? canonical6 };
27159
27162
  return {};
27160
27163
  }
27161
27164
  function screenViewRepresentatives(screens) {
@@ -31364,8 +31367,8 @@ function validateStringList(kind, values) {
31364
31367
  }
31365
31368
  return [...values].sort();
31366
31369
  }
31367
- function validateNames(kind, names) {
31368
- const result = validateStringList(`${kind} names`, names);
31370
+ function validateNames(kind, names2) {
31371
+ const result = validateStringList(`${kind} names`, names2);
31369
31372
  if (new Set(result).size !== result.length) fail2(`${kind} names must not contain duplicates`);
31370
31373
  for (const name of result) {
31371
31374
  if (kind === "secret" && !/^[A-Z][A-Z0-9_]{0,63}$/.test(name)) fail2(`secret name must be uppercase: "${name}"`);
@@ -38882,7 +38885,7 @@ var init_icons = __esm({
38882
38885
  // table by the NORMALIZED name, so those separator-free spellings were in the accepted set and
38883
38886
  // are authored in the wild (#473). The validator compares literally against this list, so
38884
38887
  // omitting them would silently start flagging descriptors that render perfectly.
38885
- ...Object.entries(ICON_NORMALIZED_INDEX).filter(([, canonical5]) => !canonical5.startsWith("_")).map(([normalized]) => normalized)
38888
+ ...Object.entries(ICON_NORMALIZED_INDEX).filter(([, canonical6]) => !canonical6.startsWith("_")).map(([normalized]) => normalized)
38886
38889
  ])
38887
38890
  ].sort();
38888
38891
  FALLBACK = ICON_CATALOG[ICON_FALLBACK];
@@ -39784,7 +39787,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
39784
39787
  const boundSeed = useBoundValue(ctx, seedMode === "binding" ? props.documentPath : "");
39785
39788
  const fill = props.fillAvailable === true;
39786
39789
  const minHeight = typeof props.minHeight === "number" && props.minHeight >= 0 ? props.minHeight : 240;
39787
- const placeholder2 = typeof props.placeholder === "string" ? props.placeholder : "";
39790
+ const placeholder3 = typeof props.placeholder === "string" ? props.placeholder : "";
39788
39791
  const onChangeRef = React4.useRef(props.onChange);
39789
39792
  onChangeRef.current = props.onChange;
39790
39793
  const bagRef = React4.useRef(bag);
@@ -39829,7 +39832,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
39829
39832
  const session = createRicosHostSession({
39830
39833
  send: (msg) => frame.contentWindow?.postMessage({ ricos: 1, msg }, "*"),
39831
39834
  seedMode,
39832
- placeholder: placeholder2 || void 0,
39835
+ placeholder: placeholder3 || void 0,
39833
39836
  locale: ctx.localeTag ?? "en",
39834
39837
  rtl: ctx.isRTL ?? document.documentElement.dir === "rtl",
39835
39838
  palette: { text: C2("textPrimary", "#13171E"), background: C2("surfacePrimary", "#FFFFFF"), accent: C2("accentPrimary", "#116DFF") },
@@ -39931,7 +39934,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
39931
39934
  if (!live3) {
39932
39935
  const { paddingTop: _t2, paddingBottom: _b, paddingLeft: _l2, paddingRight: _r2, ...rootNoSides } = root;
39933
39936
  const own5 = { ...rootNoSides, border: `1px solid ${C2("border", "#e3e3e3")}`, borderRadius: 8, padding: 12, boxSizing: "border-box" };
39934
- return /* @__PURE__ */ jsx5("div", { ...dom, style: addIntrinsicPadding(own5, wrap) ?? own5, children: /* @__PURE__ */ jsx5("span", { style: { color: C2("textSecondary", "#636B78") }, children: placeholder2 || "Rich text editor" }) });
39937
+ return /* @__PURE__ */ jsx5("div", { ...dom, style: addIntrinsicPadding(own5, wrap) ?? own5, children: /* @__PURE__ */ jsx5("span", { style: { color: C2("textSecondary", "#636B78") }, children: placeholder3 || "Rich text editor" }) });
39935
39938
  }
39936
39939
  if (status === "unavailable") {
39937
39940
  return /* @__PURE__ */ jsx5("div", { ...dom, style: root, children: /* @__PURE__ */ jsx5("div", { "data-component-id": `${id}/fallback`, children: props.fallback ? renderChild(props.fallback) : /* @__PURE__ */ jsx5("p", { style: { margin: 0, color: C2("textSecondary", "#636B78") }, children: "Editor unavailable" }) }) });
@@ -40010,7 +40013,7 @@ function RichContentEditorView({ props, ctx, wrap, nodeId, renderChild, ...dom }
40010
40013
  ref: iframeRef,
40011
40014
  src,
40012
40015
  sandbox: "allow-scripts",
40013
- title: placeholder2 || "Rich text editor",
40016
+ title: placeholder3 || "Rich text editor",
40014
40017
  "data-component-id": `${id}/webview`,
40015
40018
  style: { flex: "1 1 auto", width: "100%", border: 0, minHeight: fill ? 0 : minHeight, background: "transparent" }
40016
40019
  }
@@ -42718,8 +42721,8 @@ function makePathFromDrawOPS(data) {
42718
42721
  }
42719
42722
  return path2;
42720
42723
  }
42721
- function bindEvents(obj4, element, names) {
42722
- for (const name of names) {
42724
+ function bindEvents(obj4, element, names2) {
42725
+ for (const name of names2) {
42723
42726
  element.addEventListener(name, obj4[name].bind(obj4));
42724
42727
  }
42725
42728
  }
@@ -45273,7 +45276,7 @@ var init_pdf = __esm({
45273
45276
  var defineProperty = Object.defineProperty;
45274
45277
  var stringSlice = uncurryThis("".slice);
45275
45278
  var replace = uncurryThis("".replace);
45276
- var join92 = uncurryThis([].join);
45279
+ var join95 = uncurryThis([].join);
45277
45280
  var CONFIGURABLE_LENGTH = DESCRIPTORS && !fails(function() {
45278
45281
  return defineProperty(function() {
45279
45282
  }, "length", { value: 8 }).length !== 8;
@@ -45300,7 +45303,7 @@ var init_pdf = __esm({
45300
45303
  }
45301
45304
  var state = enforceInternalState(value);
45302
45305
  if (!hasOwn(state, "source")) {
45303
- state.source = join92(TEMPLATE, typeof name == "string" ? name : "");
45306
+ state.source = join95(TEMPLATE, typeof name == "string" ? name : "");
45304
45307
  }
45305
45308
  return value;
45306
45309
  };
@@ -45563,13 +45566,13 @@ var init_pdf = __esm({
45563
45566
  var indexOf = __webpack_require__3(9617).indexOf;
45564
45567
  var hiddenKeys = __webpack_require__3(421);
45565
45568
  var push = uncurryThis([].push);
45566
- module.exports = function(object6, names) {
45569
+ module.exports = function(object6, names2) {
45567
45570
  var O2 = toIndexedObject(object6);
45568
45571
  var i2 = 0;
45569
45572
  var result = [];
45570
45573
  var key3;
45571
45574
  for (key3 in O2) !hasOwn(hiddenKeys, key3) && hasOwn(O2, key3) && push(result, key3);
45572
- while (names.length > i2) if (hasOwn(O2, key3 = names[i2++])) {
45575
+ while (names2.length > i2) if (hasOwn(O2, key3 = names2[i2++])) {
45573
45576
  ~indexOf(result, key3) || push(result, key3);
45574
45577
  }
45575
45578
  return result;
@@ -47823,7 +47826,7 @@ var init_pdf = __esm({
47823
47826
  var charAt = uncurryThis("".charAt);
47824
47827
  var Uint8Array2 = globalThis2.Uint8Array;
47825
47828
  var $Array = globalThis2.Array;
47826
- var join92 = uncurryThis([].join);
47829
+ var join95 = uncurryThis([].join);
47827
47830
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toBase64 || !(function() {
47828
47831
  try {
47829
47832
  var target = new Uint8Array2();
@@ -47869,7 +47872,7 @@ var init_pdf = __esm({
47869
47872
  result[written++] = "=";
47870
47873
  }
47871
47874
  }
47872
- return join92(result, "");
47875
+ return join95(result, "");
47873
47876
  }
47874
47877
  });
47875
47878
  },
@@ -47881,7 +47884,7 @@ var init_pdf = __esm({
47881
47884
  var anUint8Array = __webpack_require__3(4154);
47882
47885
  var notDetached = __webpack_require__3(5169);
47883
47886
  var numberToString2 = uncurryThis(1.1.toString);
47884
- var join92 = uncurryThis([].join);
47887
+ var join95 = uncurryThis([].join);
47885
47888
  var $Array = Array;
47886
47889
  var Uint8Array2 = globalThis2.Uint8Array;
47887
47890
  var INCORRECT_BEHAVIOR_OR_DOESNT_EXISTS = !Uint8Array2 || !Uint8Array2.prototype.toHex || !(function() {
@@ -47901,7 +47904,7 @@ var init_pdf = __esm({
47901
47904
  var hex2 = numberToString2(this[i2], 16);
47902
47905
  result[i2] = hex2.length === 1 ? "0" + hex2 : hex2;
47903
47906
  }
47904
- return join92(result, "");
47907
+ return join95(result, "");
47905
47908
  }
47906
47909
  });
47907
47910
  },
@@ -54695,7 +54698,7 @@ var init_pdf = __esm({
54695
54698
  recordFutureForcedDependency(name, idx) {
54696
54699
  return this;
54697
54700
  }
54698
- inheritSimpleDataAsFutureForcedDependencies(names) {
54701
+ inheritSimpleDataAsFutureForcedDependencies(names2) {
54699
54702
  return this;
54700
54703
  }
54701
54704
  inheritPendingDependenciesAsFutureForcedDependencies() {
@@ -54831,8 +54834,8 @@ var init_pdf = __esm({
54831
54834
  this.recordIncrementalData(FORCED_DEPENDENCY_LABEL, idx);
54832
54835
  return this;
54833
54836
  }
54834
- inheritSimpleDataAsFutureForcedDependencies(names) {
54835
- for (const name of names) {
54837
+ inheritSimpleDataAsFutureForcedDependencies(names2) {
54838
+ for (const name of names2) {
54836
54839
  if (name in this.#simple) {
54837
54840
  this.recordFutureForcedDependency(name, this.#simple[name]);
54838
54841
  }
@@ -55038,8 +55041,8 @@ var init_pdf = __esm({
55038
55041
  this.#dependencyTracker.recordFutureForcedDependency(name, this.#opIdx);
55039
55042
  return this;
55040
55043
  }
55041
- inheritSimpleDataAsFutureForcedDependencies(names) {
55042
- this.#dependencyTracker.inheritSimpleDataAsFutureForcedDependencies(names);
55044
+ inheritSimpleDataAsFutureForcedDependencies(names2) {
55045
+ this.#dependencyTracker.inheritSimpleDataAsFutureForcedDependencies(names2);
55043
55046
  return this;
55044
55047
  }
55045
55048
  inheritPendingDependenciesAsFutureForcedDependencies() {
@@ -64948,11 +64951,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
64948
64951
  });
64949
64952
  }
64950
64953
  }
64951
- _setEventListeners(element, elementData, names, getter) {
64954
+ _setEventListeners(element, elementData, names2, getter) {
64952
64955
  const {
64953
64956
  actions
64954
64957
  } = this.data;
64955
- for (const [baseName, eventName] of names) {
64958
+ for (const [baseName, eventName] of names2) {
64956
64959
  if (eventName === "Action" || actions?.has(eventName)) {
64957
64960
  if (eventName === "Focus" || eventName === "Blur") {
64958
64961
  elementData ||= {
@@ -126398,8 +126401,8 @@ var init_renderNode = __esm({
126398
126401
  const rawPlaceholder = props.placeholder ?? cfg.placeholder;
126399
126402
  const resolvedPlaceholder = useResolvedScalar(rawPlaceholder, ctx);
126400
126403
  const placeholderIsBinding = isBinding(rawPlaceholder);
126401
- const placeholder2 = rawPlaceholder == null || placeholderIsBinding && resolvedPlaceholder == null ? "" : placeholderIsBinding ? asTextL10n(resolvedPlaceholder, ctx) : asText2(rawPlaceholder);
126402
- const placeholderName = placeholder2 || void 0;
126404
+ const placeholder3 = rawPlaceholder == null || placeholderIsBinding && resolvedPlaceholder == null ? "" : placeholderIsBinding ? asTextL10n(resolvedPlaceholder, ctx) : asText2(rawPlaceholder);
126405
+ const placeholderName = placeholder3 || void 0;
126403
126406
  const prefixText = useBoundString(props.prefix, ctx);
126404
126407
  const suffixText = useBoundString(props.suffix, ctx);
126405
126408
  const valueBinding = typeof ctrl === "string" ? ctrl : cfg.value;
@@ -126636,7 +126639,7 @@ var init_renderNode = __esm({
126636
126639
  /* @__PURE__ */ jsxs7("div", { style: composedBox, children: [
126637
126640
  props.leadingIcon && accIcon(props.leadingIcon),
126638
126641
  prefixText && /* @__PURE__ */ jsx10("span", { style: { color: muted, flex: "none" }, children: prefixText }),
126639
- multilineBox ? /* @__PURE__ */ jsx10("textarea", { "data-component-id": componentId, id: fieldDomId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder2, rows: 2, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, style: inputBase }) : /* @__PURE__ */ jsx10("input", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, type: secure && !(visibilityToggle && valueVisible) ? "password" : "text", value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder2, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, enterKeyHint, style: inputBase }),
126642
+ multilineBox ? /* @__PURE__ */ jsx10("textarea", { "data-component-id": componentId, id: fieldDomId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, rows: 2, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, style: inputBase }) : /* @__PURE__ */ jsx10("input", { "data-component-id": componentId, id: htmlId, "data-component-type": componentType, ...a11yFwd, ref: inputRef, type: secure && !(visibilityToggle && valueVisible) ? "password" : "text", value: local, onChange: onInput, onKeyDown, onFocus: onFieldFocus, onBlur: onFieldBlur, placeholder: placeholder3, "aria-label": ariaLabelProp ?? placeholderName, "aria-labelledby": labelledBy, "aria-required": required3, "aria-invalid": errored || void 0, "aria-describedby": [errorId, describedByProp].filter(Boolean).join(" ") || void 0, inputMode, autoCapitalize, maxLength, autoCorrect: suggestOff ? "off" : suggestOn ? "on" : void 0, spellCheck: suggestOff ? false : suggestOn ? true : void 0, autoComplete: suggestOff ? "off" : void 0, enterKeyHint, style: inputBase }),
126640
126643
  suffixText && /* @__PURE__ */ jsx10("span", { style: { color: muted, flex: "none" }, children: suffixText }),
126641
126644
  props.clearButton && local && /* @__PURE__ */ jsx10("span", { onClick: () => {
126642
126645
  setLocal("");
@@ -132373,7 +132376,7 @@ function interpretProduce(services, parsed) {
132373
132376
  return { services, widgets, views };
132374
132377
  }
132375
132378
  function contentEtag(snapshot2) {
132376
- const canonical5 = JSON.stringify({
132379
+ const canonical6 = JSON.stringify({
132377
132380
  widgetId: snapshot2.widgetId,
132378
132381
  family: snapshot2.family,
132379
132382
  size: snapshot2.size,
@@ -132382,7 +132385,7 @@ function contentEtag(snapshot2) {
132382
132385
  // Lever A — a timeline change must bump the etag (frame values/times are content).
132383
132386
  frames: snapshot2.frames ?? null
132384
132387
  });
132385
- return "sha256-" + createHash20("sha256").update(canonical5).digest("base64");
132388
+ return "sha256-" + createHash20("sha256").update(canonical6).digest("base64");
132386
132389
  }
132387
132390
  async function buildWidgetSnapshot(bundleJs, widgetId, opts = {}) {
132388
132391
  const { widgets } = await extractWidgets(bundleJs, opts);
@@ -133721,11 +133724,11 @@ function startBundleSourceWatcher(state) {
133721
133724
  timer = setTimeout(flush, 120);
133722
133725
  return;
133723
133726
  }
133724
- const names = [...pending].sort();
133727
+ const names2 = [...pending].sort();
133725
133728
  pending.clear();
133726
- if (names.length === 0) return;
133729
+ if (names2.length === 0) return;
133727
133730
  building = true;
133728
- for (const name of names) {
133731
+ for (const name of names2) {
133729
133732
  try {
133730
133733
  await rebuildBundleSource(name);
133731
133734
  console.log(`[himalaya-dev] rebuilt T5 bundle from source: ${name}`);
@@ -133913,10 +133916,10 @@ function syncAppDependencyWatchers(state, inputs) {
133913
133916
  let timer;
133914
133917
  const changed = /* @__PURE__ */ new Set();
133915
133918
  const watchers = [];
133916
- for (const [dir, names] of byDir) {
133919
+ for (const [dir, names2] of byDir) {
133917
133920
  try {
133918
133921
  const w2 = watch(dir, { persistent: false }, (_event, filename) => {
133919
- if (!filename || !names.has(String(filename))) return;
133922
+ if (!filename || !names2.has(String(filename))) return;
133920
133923
  changed.add(join47(dir, String(filename)));
133921
133924
  if (timer) clearTimeout(timer);
133922
133925
  timer = setTimeout(() => {
@@ -135380,7 +135383,7 @@ async function readBundleFile(name, dir) {
135380
135383
  async function listBundles(dir) {
135381
135384
  const fs2 = await import("node:fs/promises");
135382
135385
  const roots = dir ? [dir, TIER5_ROOT2] : [TIER5_ROOT2];
135383
- const names = /* @__PURE__ */ new Set();
135386
+ const names2 = /* @__PURE__ */ new Set();
135384
135387
  for (const root of roots) {
135385
135388
  let entries;
135386
135389
  try {
@@ -135390,11 +135393,11 @@ async function listBundles(dir) {
135390
135393
  }
135391
135394
  for (const entry of entries) {
135392
135395
  const name = servedBundleName(entry);
135393
- if (name !== void 0) names.add(name);
135396
+ if (name !== void 0) names2.add(name);
135394
135397
  }
135395
135398
  }
135396
135399
  const result = [];
135397
- for (const name of names) {
135400
+ for (const name of names2) {
135398
135401
  const loaded = await readBundleFile(name, dir);
135399
135402
  if (!loaded) continue;
135400
135403
  result.push({ name, integrity: loaded.integrity, sizeBytes: loaded.bytes.length });
@@ -139337,12 +139340,12 @@ function validateDependencyPolicy(packages, policy = {}) {
139337
139340
  const allowedLicenses = new Set(policy.allowedLicenses ?? ["MIT", "ISC", "BSD-2-Clause", "BSD-3-Clause", "Apache-2.0"]);
139338
139341
  const maxBytes = policy.maxBytes ?? 5 * 1024 * 1024;
139339
139342
  const maxVulnerability = policy.maxVulnerability ?? "low";
139340
- const names = /* @__PURE__ */ new Set();
139343
+ const names2 = /* @__PURE__ */ new Set();
139341
139344
  let totalBytes = 0;
139342
139345
  for (const dependency of packages) {
139343
139346
  if (!/^@[a-z0-9._-]+\/[a-z0-9._-]+$|^[a-z0-9._-]+$/.test(dependency.name) || !pinnedSemver.test(dependency.version)) throw new Error(`dependency ${dependency.name} must use a pinned semver version`);
139344
- if (names.has(dependency.name)) throw new Error(`dependency ${dependency.name} is duplicated`);
139345
- names.add(dependency.name);
139347
+ if (names2.has(dependency.name)) throw new Error(`dependency ${dependency.name} is duplicated`);
139348
+ names2.add(dependency.name);
139346
139349
  if (!/^sha512-/.test(dependency.integrity)) throw new Error(`dependency ${dependency.name} is missing an exact lockfile integrity hash`);
139347
139350
  if (!allowedLicenses.has(dependency.license)) throw new Error(`dependency ${dependency.name} has blocked license ${dependency.license}`);
139348
139351
  if (dependency.scripts?.length) throw new Error(`dependency ${dependency.name} declares install scripts`);
@@ -140099,8 +140102,8 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
140099
140102
  const LIVE_LOAD_BUDGET_MS = 3e4;
140100
140103
  const appLocalDbSchema = (() => {
140101
140104
  const entities = config.dataSchema?.entities ?? [];
140102
- const names = entities.map((e2) => e2?.name).filter((n2) => typeof n2 === "string" && n2.length > 0);
140103
- return names.length ? names.map((name) => ({ name })) : null;
140105
+ const names2 = entities.map((e2) => e2?.name).filter((n2) => typeof n2 === "string" && n2.length > 0);
140106
+ return names2.length ? names2.map((name) => ({ name })) : null;
140104
140107
  })();
140105
140108
  let liveWixCall = null;
140106
140109
  const ensureLiveWixCall = async () => {
@@ -140590,7 +140593,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
140590
140593
  const src = t2.pattern.source;
140591
140594
  const raw = src.startsWith("^") && src.endsWith(DUAL_FORM_TAIL) ? src.slice(1, src.length - DUAL_FORM_TAIL.length) : null;
140592
140595
  return { t: t2, canonical: raw && /^[A-Za-z0-9_]+$/.test(raw) ? raw : null };
140593
- }).filter(({ t: t2, canonical: canonical5 }) => canonical5 !== null || typeof t2.seedIds === "function");
140596
+ }).filter(({ t: t2, canonical: canonical6 }) => canonical6 !== null || typeof t2.seedIds === "function");
140594
140597
  if (bakeRoutes.length) {
140595
140598
  const seedCtx = {
140596
140599
  store: preloaded.module.createStore(app),
@@ -140606,7 +140609,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
140606
140609
  // carry a working URL + digest into the release, not a null.
140607
140610
  asset: (name) => resolveAssetForBuild(preloaded.dir, name, base, app)
140608
140611
  };
140609
- for (const { t: t2, canonical: canonical5 } of bakeRoutes) {
140612
+ for (const { t: t2, canonical: canonical6 } of bakeRoutes) {
140610
140613
  let ids = [];
140611
140614
  try {
140612
140615
  ids = typeof t2.seedIds === "function" ? await t2.seedIds(seedCtx) ?? [] : [];
@@ -140617,7 +140620,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
140617
140620
  `[release-build] seedIds threw for templated route ${String(t2.pattern)} in "${app}" \u2014 no instances of it will be baked. If it reaches the network, note that the bake origin is ${base} and a plain bake opens no socket. ${String(err)}`
140618
140621
  );
140619
140622
  }
140620
- if (canonical5) ids = [canonical5, ...ids.filter((id) => id !== canonical5)];
140623
+ if (canonical6) ids = [canonical6, ...ids.filter((id) => id !== canonical6)];
140621
140624
  for (const screenId of ids) {
140622
140625
  if (screens[screenId]) continue;
140623
140626
  if (screenId.includes("/") || screenId.includes("..")) continue;
@@ -140664,7 +140667,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
140664
140667
  }
140665
140668
  const json8 = pinBakedServerBaseUrl(JSON.stringify(descriptor), base);
140666
140669
  await store.putScreen(app, screenId, json8);
140667
- screens[screenId] = { descriptorHash: sha2564(json8), bundle: bundleName, ...screenMetadataFor(screenMetadata, screenId, canonical5) };
140670
+ screens[screenId] = { descriptorHash: sha2564(json8), bundle: bundleName, ...screenMetadataFor(screenMetadata, screenId, canonical6) };
140668
140671
  rememberInput(bundleName, JSON.parse(json8));
140669
140672
  if (collect2?.descriptors) {
140670
140673
  baked.push({
@@ -142886,12 +142889,12 @@ function assertCredentialOutsideRepo(label3, p2) {
142886
142889
  );
142887
142890
  }
142888
142891
  }
142889
- function requireEnv(names) {
142890
- const missing = names.filter((n2) => !process.env[n2]);
142892
+ function requireEnv(names2) {
142893
+ const missing = names2.filter((n2) => !process.env[n2]);
142891
142894
  if (missing.length) {
142892
142895
  throw new Error(`Missing required environment variable(s): ${missing.join(", ")}`);
142893
142896
  }
142894
- return Object.fromEntries(names.map((n2) => [n2, process.env[n2]]));
142897
+ return Object.fromEntries(names2.map((n2) => [n2, process.env[n2]]));
142895
142898
  }
142896
142899
  function strip2(line) {
142897
142900
  const hash2 = line.indexOf("#");
@@ -153578,7 +153581,7 @@ function pushRouteAdvisories(pushRoutes) {
153578
153581
  ];
153579
153582
  }
153580
153583
  function unmappedAdvisory({ destination, vertical, reason, screenId, paramKey }) {
153581
- const canonical5 = WIX_MEMBER_PUSH_DESTINATIONS.find((d2) => d2.id === destination)?.canonicalScreen;
153584
+ const canonical6 = WIX_MEMBER_PUSH_DESTINATIONS.find((d2) => d2.id === destination)?.canonicalScreen;
153582
153585
  if (reason === "param_not_declared") {
153583
153586
  return `push-route-unmapped: push.screens sends "${destination}" notifications to "${screenId}" with paramKey "${paramKey}", which "${screenId}" does not declare, so a shell would drop it. Use one of the keys its linkable screen declares, or add "${paramKey}" to its paramKeys.`;
153584
153587
  }
@@ -153588,7 +153591,7 @@ function unmappedAdvisory({ destination, vertical, reason, screenId, paramKey })
153588
153591
  if (screenId) {
153589
153592
  return `push-route-unmapped: push.screens maps "${destination}" to "${screenId}", which is not a linkable screen, so the device could not open it. Add it to navigation.linkableScreens, or map another screen.`;
153590
153593
  }
153591
- return `push-route-unmapped: the site has ${vertical}, but no screen opens "${destination}" notifications. Name that screen "${canonical5}", or map it: push.screens: { "${destination}": "<screenId>" }.`;
153594
+ return `push-route-unmapped: the site has ${vertical}, but no screen opens "${destination}" notifications. Name that screen "${canonical6}", or map it: push.screens: { "${destination}": "<screenId>" }.`;
153592
153595
  }
153593
153596
  function navSharedIdErrors(nav) {
153594
153597
  const items = (key3) => {
@@ -153726,8 +153729,8 @@ function fieldType(f2) {
153726
153729
  }
153727
153730
  function renderBase44Types(entities, app) {
153728
153731
  const candidates = entities.filter((e2) => e2 && typeof e2 === "object" && Array.isArray(e2.fields) && IDENT.test(logicalName(e2)) && physicalEntityName(e2, app));
153729
- const names = exportNames(candidates, app);
153730
- const exportName = (e2) => names.get(e2);
153732
+ const names2 = exportNames(candidates, app);
153733
+ const exportName = (e2) => names2.get(e2);
153731
153734
  const sortKey = (e2) => `${exportName(e2)}\0${physicalEntityName(e2, app)}`;
153732
153735
  const usable = [...candidates].sort((a2, b2) => sortKey(a2) < sortKey(b2) ? -1 : sortKey(a2) > sortKey(b2) ? 1 : 0);
153733
153736
  const L2 = [
@@ -154171,8 +154174,8 @@ function hasNote(entry) {
154171
154174
  return entryHead(entry) !== entry.trim();
154172
154175
  }
154173
154176
  function namesLine(allowed2) {
154174
- const names = [...new Set(allowed2.flatMap(entryNames))];
154175
- return names.length ? `it names: ${names.join(", ")}` : "its entries are only notes, which approve nothing";
154177
+ const names2 = [...new Set(allowed2.flatMap(entryNames))];
154178
+ return names2.length ? `it names: ${names2.join(", ")}` : "its entries are only notes, which approve nothing";
154176
154179
  }
154177
154180
  function isNoneEntry(entry) {
154178
154181
  const head = entryHead(entry);
@@ -156782,8 +156785,8 @@ function describeFunction(definitions2, name) {
156782
156785
  return definition ? { ...listFunctions([definition])[0], wixIdentity: definition.wixIdentity, wixPermissions: [...definition.wixPermissions], capabilities: [...definition.capabilities], secrets: [...definition.secrets], outboundHosts: [...definition.outboundHosts], inputSchema: definition.input?.kind ?? null, outputSchema: definition.output?.kind ?? null } : null;
156783
156786
  }
156784
156787
  function materializeFunctionPath(path2, params = {}) {
156785
- const names = [...path2.matchAll(/:([A-Za-z][A-Za-z0-9_]*)/g)].map((match) => match[1]);
156786
- for (const name of names) {
156788
+ const names2 = [...path2.matchAll(/:([A-Za-z][A-Za-z0-9_]*)/g)].map((match) => match[1]);
156789
+ for (const name of names2) {
156787
156790
  if (typeof params[name] !== "string" || params[name] === "") throw new Error(`missing route parameter "${name}"; pass --params {"${name}":"value"}`);
156788
156791
  }
156789
156792
  return path2.replace(/:([A-Za-z][A-Za-z0-9_]*)/g, (_match, name) => encodeURIComponent(params[name]));
@@ -163512,7 +163515,7 @@ function skipReason(item, options) {
163512
163515
  function priceFor(amount, options) {
163513
163516
  return { baseTerritory: options.baseTerritory, currency: options.currency, amount: normalizeAmount(amount), rule: "atLeast" };
163514
163517
  }
163515
- function perItemProduct(item, options, names) {
163518
+ function perItemProduct(item, options, names2) {
163516
163519
  const plainDescription = item.description ? plainText2(item.description) : "";
163517
163520
  const name = nameOf(item);
163518
163521
  return {
@@ -163521,7 +163524,7 @@ function perItemProduct(item, options, names) {
163521
163524
  entitlement: entityKey(item.source, item.id),
163522
163525
  productId: productIdFor(options.target.bundleId, SOURCE_SLUGS[item.source], item.id),
163523
163526
  type: "nonConsumable",
163524
- referenceName: names.claim(name, item.id),
163527
+ referenceName: names2.claim(name, item.id),
163525
163528
  localizations: [{ locale: options.locale, name: displayName(name), description: fit(plainDescription || `Unlock ${name}`, APPLE_LIMITS.description) }],
163526
163529
  price: priceFor(item.price.amount, options),
163527
163530
  territories: options.territories
@@ -163537,7 +163540,7 @@ function tierPrice(amount, applePoint, options) {
163537
163540
  if (!applePoint) return priceFor(amount, options);
163538
163541
  return { baseTerritory: options.baseTerritory, currency: options.currency, amount: normalizeAmount(applePoint) };
163539
163542
  }
163540
- function newTier(key3, price, options, names) {
163543
+ function newTier(key3, price, options, names2) {
163541
163544
  const label3 = `${price.amount} ${options.currency}`;
163542
163545
  return {
163543
163546
  unlocks: [],
@@ -163545,13 +163548,13 @@ function newTier(key3, price, options, names) {
163545
163548
  entitlement: `tier:${key3}`,
163546
163549
  productId: tierProductId(options, key3),
163547
163550
  type: "consumable",
163548
- referenceName: names.claim(`Credit ${label3}`, key3),
163551
+ referenceName: names2.claim(`Credit ${label3}`, key3),
163549
163552
  localizations: [{ locale: options.locale, name: displayName(`Unlock (${label3})`), description: TIER_DESCRIPTION }],
163550
163553
  price,
163551
163554
  territories: options.territories
163552
163555
  };
163553
163556
  }
163554
- function draftTiers(items, options, names, existingItems) {
163557
+ function draftTiers(items, options, names2, existingItems) {
163555
163558
  const byProductId = new Map(existingItems.map((i2) => [i2.productId, i2]));
163556
163559
  const created = [];
163557
163560
  for (const item of items) {
@@ -163561,7 +163564,7 @@ function draftTiers(items, options, names, existingItems) {
163561
163564
  const productId = tierProductId(options, key3);
163562
163565
  let tier = byProductId.get(productId);
163563
163566
  if (!tier) {
163564
- tier = newTier(key3, price, options, names);
163567
+ tier = newTier(key3, price, options, names2);
163565
163568
  byProductId.set(productId, tier);
163566
163569
  created.push(tier);
163567
163570
  }
@@ -163584,7 +163587,7 @@ function refreshMergedPrices(items, catalog3, options) {
163584
163587
  function draftManifest(catalog3, options) {
163585
163588
  const existingItems = structuredClone(options.existing?.items ?? []);
163586
163589
  const mapped = new Set(existingItems.flatMap((i2) => wixEntitiesOf(i2).map((e2) => entityKey(e2.entityType, e2.entityId))));
163587
- const names = new ReferenceNames(existingItems);
163590
+ const names2 = new ReferenceNames(existingItems);
163588
163591
  const skipped = refreshMergedPrices(existingItems, catalog3, options);
163589
163592
  const toDraft = [];
163590
163593
  let kept = 0;
@@ -163596,7 +163599,7 @@ function draftManifest(catalog3, options) {
163596
163599
  else toDraft.push(item);
163597
163600
  }
163598
163601
  }
163599
- const drafted = options.mode === "tiers" ? draftTiers(toDraft, options, names, existingItems) : toDraft.map((item) => perItemProduct(item, options, names));
163602
+ const drafted = options.mode === "tiers" ? draftTiers(toDraft, options, names2, existingItems) : toDraft.map((item) => perItemProduct(item, options, names2));
163600
163603
  const items = [...existingItems, ...drafted];
163601
163604
  const newlyMapped = toDraft.length;
163602
163605
  if (!items.length) return { skipped, kept, newlyMapped };
@@ -166214,8 +166217,8 @@ function analyzePlayListing(assets) {
166214
166217
  }
166215
166218
  function playListingAssets(app, locale = "en-US") {
166216
166219
  const dir = join81(storeDir(app), "play", locale, "images");
166217
- const read = (names) => {
166218
- for (const name of names) {
166220
+ const read = (names2) => {
166221
+ for (const name of names2) {
166219
166222
  const p2 = join81(dir, name);
166220
166223
  try {
166221
166224
  if (statSync21(p2).isFile()) return { name, bytes: readFileSync95(p2) };
@@ -167900,9 +167903,9 @@ function planEntityScreens(specs, app = "") {
167900
167903
  owners.set(what, `entity "${p2.name}"`);
167901
167904
  }
167902
167905
  }
167903
- const names = plans.map((p2) => p2.name);
167904
- if (names.length <= ENTITY_TAB_SLOTS) return { plans, tabs: names, more: [] };
167905
- return { plans, tabs: names.slice(0, ENTITY_TAB_SLOTS - 1), more: names.slice(ENTITY_TAB_SLOTS - 1) };
167906
+ const names2 = plans.map((p2) => p2.name);
167907
+ if (names2.length <= ENTITY_TAB_SLOTS) return { plans, tabs: names2, more: [] };
167908
+ return { plans, tabs: names2.slice(0, ENTITY_TAB_SLOTS - 1), more: names2.slice(ENTITY_TAB_SLOTS - 1) };
167906
167909
  }
167907
167910
  var PlanError, RESERVED_SCREEN_IDS, MORE_SCREEN_ID, ENTITY_TAB_SLOTS, OWNER_RULES, pascal, PREFERRED_TITLES, LONG_TEXT, IMAGE_KEY, SEGMENTED_MAX, isPlainString, isEnum, isDate, isImage, isLongText, nounOf;
167908
167911
  var init_plan4 = __esm({
@@ -168117,12 +168120,14 @@ var base44_auth_exports = {};
168117
168120
  __export(base44_auth_exports, {
168118
168121
  BASE44_LOGIN_SCOPE: () => BASE44_LOGIN_SCOPE,
168119
168122
  BASE44_OAUTH_CLIENT_ID: () => BASE44_OAUTH_CLIENT_ID,
168123
+ BASE44_WRITE_SCOPE: () => BASE44_WRITE_SCOPE,
168120
168124
  base44ApiBase: () => base44ApiBase,
168121
168125
  base44DeviceLogin: () => base44DeviceLogin,
168122
168126
  base44SessionPath: () => base44SessionPath,
168123
168127
  base44Whoami: () => base44Whoami,
168124
168128
  currentBase44Auth: () => currentBase44Auth,
168125
168129
  deleteBase44Session: () => deleteBase44Session,
168130
+ hasBase44WriteScope: () => hasBase44WriteScope,
168126
168131
  importBase44CliSession: () => importBase44CliSession,
168127
168132
  jwtClaims: () => jwtClaims,
168128
168133
  readBase44Session: () => readBase44Session,
@@ -168216,7 +168221,7 @@ async function base44DeviceLogin(opts) {
168216
168221
  const res = await fetchImpl(`${apiBase}/oauth/device/code`, {
168217
168222
  method: "POST",
168218
168223
  headers: { "Content-Type": "application/json", Accept: "application/json" },
168219
- body: JSON.stringify({ client_id: BASE44_OAUTH_CLIENT_ID, scope: BASE44_LOGIN_SCOPE })
168224
+ body: JSON.stringify({ client_id: BASE44_OAUTH_CLIENT_ID, scope: opts.scope ?? BASE44_LOGIN_SCOPE })
168220
168225
  });
168221
168226
  if (!res.ok) throw new Error(`Base44 refused a device code: HTTP ${res.status}`);
168222
168227
  const code = await res.json();
@@ -168252,6 +168257,13 @@ async function base44DeviceLogin(opts) {
168252
168257
  }
168253
168258
  throw new Error("the Base44 sign-in code expired before it was approved \u2014 run `himi base44 login` again");
168254
168259
  }
168260
+ function hasBase44WriteScope(auth) {
168261
+ const c2 = jwtClaims(auth.token);
168262
+ const raw = c2?.scope ?? c2?.scp;
168263
+ const scopes = typeof raw === "string" ? raw.split(/\s+/) : Array.isArray(raw) ? raw.map(String) : void 0;
168264
+ if (!scopes) return "unknown";
168265
+ return scopes.includes("apps:write");
168266
+ }
168255
168267
  function importBase44CliSession(home = homedir13(), env = process.env) {
168256
168268
  const src = join85(home, ".base44", "auth", "auth.json");
168257
168269
  if (!existsSync80(src)) throw new Error(`no Base44 CLI session at ${src} \u2014 run \`npx base44 login\` first, or use \`himi base44 login\``);
@@ -168279,15 +168291,1063 @@ function base44Whoami(auth, now = Date.now()) {
168279
168291
  ...auth.expiresAt ? { expiresAt: new Date(auth.expiresAt).toISOString(), expired: now >= auth.expiresAt } : {}
168280
168292
  };
168281
168293
  }
168282
- var BASE44_OAUTH_CLIENT_ID, BASE44_LOGIN_SCOPE, REFRESH_BUFFER_MS;
168294
+ var BASE44_OAUTH_CLIENT_ID, BASE44_LOGIN_SCOPE, BASE44_WRITE_SCOPE, REFRESH_BUFFER_MS;
168283
168295
  var init_base44_auth = __esm({
168284
168296
  "src/base44-auth.ts"() {
168285
168297
  BASE44_OAUTH_CLIENT_ID = "base44_cli";
168286
168298
  BASE44_LOGIN_SCOPE = "apps:read";
168299
+ BASE44_WRITE_SCOPE = "apps:read apps:write";
168287
168300
  REFRESH_BUFFER_MS = 6e4;
168288
168301
  }
168289
168302
  });
168290
168303
 
168304
+ // src/base44-provision/http.ts
168305
+ function appUrl(t2, appId2, path2) {
168306
+ return new URL(`/api/apps/${encodeURIComponent(appId2)}/${path2}`, t2.apiBase).href;
168307
+ }
168308
+ async function callJson(t2, appId2, method, path2, what, body) {
168309
+ const res = await t2.apiFetch(appUrl(t2, appId2, path2), {
168310
+ method,
168311
+ headers: {
168312
+ Authorization: `Bearer ${t2.auth.token}`,
168313
+ Accept: "application/json",
168314
+ "User-Agent": "himi base44 provision",
168315
+ ...body !== void 0 ? { "Content-Type": "application/json" } : {}
168316
+ },
168317
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
168318
+ });
168319
+ if (!res.ok) {
168320
+ const text10 = await res.text().catch(() => "");
168321
+ throw new Base44RequestError(res.status, text10.slice(0, 500), what);
168322
+ }
168323
+ const text9 = await res.text();
168324
+ try {
168325
+ return JSON.parse(text9);
168326
+ } catch {
168327
+ throw new Base44RequestError(res.status, `unreadable response: ${text9.slice(0, 200)}`, what);
168328
+ }
168329
+ }
168330
+ function requestFailure(e2) {
168331
+ if (e2 instanceof Base44RequestError) return { ok: false, code: "request_failed", error: e2.message, status: e2.status, ...e2.serverError ? { serverError: e2.serverError } : {} };
168332
+ return { ok: false, code: "request_failed", error: e2 instanceof Error ? e2.message : String(e2) };
168333
+ }
168334
+ function writeScopeFailure(auth) {
168335
+ const w2 = hasBase44WriteScope(auth);
168336
+ if (w2 === true) return void 0;
168337
+ return {
168338
+ ok: false,
168339
+ code: "write_scope_missing",
168340
+ error: w2 === false ? "the Base44 session was minted read-only (apps:read) \u2014 writing needs apps:write" : "the Base44 token's scope cannot be read, so himi will not assume it may write",
168341
+ hint: "run `himi base44 login --write` (or set BASE44_ACCESS_TOKEN to a token whose claims carry apps:write)"
168342
+ };
168343
+ }
168344
+ var Base44RequestError;
168345
+ var init_http2 = __esm({
168346
+ "src/base44-provision/http.ts"() {
168347
+ init_base44_auth();
168348
+ Base44RequestError = class extends Error {
168349
+ constructor(status, serverError, what) {
168350
+ super(`${what}: HTTP ${status}${serverError ? ` \u2014 ${serverError}` : ""}`);
168351
+ this.status = status;
168352
+ this.serverError = serverError;
168353
+ }
168354
+ };
168355
+ }
168356
+ });
168357
+
168358
+ // src/base44-provision/seed.ts
168359
+ var seed_exports = {};
168360
+ __export(seed_exports, {
168361
+ BASE44_SEED_FILE: () => BASE44_SEED_FILE,
168362
+ SeedFileError: () => SeedFileError,
168363
+ readBase44SeedFile: () => readBase44SeedFile,
168364
+ seedBase44Entities: () => seedBase44Entities,
168365
+ writeBase44SeedRows: () => writeBase44SeedRows
168366
+ });
168367
+ import { existsSync as existsSync81, readFileSync as readFileSync102, writeFileSync as writeFileSync36 } from "node:fs";
168368
+ import { join as join86 } from "node:path";
168369
+ function readBase44SeedFile(dir) {
168370
+ const file2 = join86(dir, BASE44_SEED_FILE);
168371
+ if (!existsSync81(file2)) return {};
168372
+ let parsed;
168373
+ try {
168374
+ parsed = JSON.parse(readFileSync102(file2, "utf8"));
168375
+ } catch (e2) {
168376
+ throw new SeedFileError(`${BASE44_SEED_FILE} is not valid JSON (${e2.message}). Fix or delete it.`);
168377
+ }
168378
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new SeedFileError(`${BASE44_SEED_FILE} must be an object keyed by entity name.`);
168379
+ const out2 = /* @__PURE__ */ Object.create(null);
168380
+ for (const [name, rows] of Object.entries(parsed)) {
168381
+ if (!Array.isArray(rows)) throw new SeedFileError(`${BASE44_SEED_FILE}: "${name}" must be an array of row objects.`);
168382
+ const bad2 = rows.findIndex((r2) => !r2 || typeof r2 !== "object" || Array.isArray(r2));
168383
+ if (bad2 !== -1) throw new SeedFileError(`${BASE44_SEED_FILE}: "${name}" row ${bad2} is not an object.`);
168384
+ out2[name] = rows;
168385
+ }
168386
+ return out2;
168387
+ }
168388
+ async function seedBase44Entities(opts) {
168389
+ const { app, appId: appId2, yes = false } = opts;
168390
+ const report3 = { ok: true, app, appId: appId2, dryRun: !yes, inserted: {}, sources: {}, skipped: [] };
168391
+ if (yes) {
168392
+ const denied2 = writeScopeFailure(opts.auth);
168393
+ if (denied2) return { ...report3, ...denied2 };
168394
+ }
168395
+ let fileRows = {};
168396
+ try {
168397
+ fileRows = opts.dir ? readBase44SeedFile(opts.dir) : {};
168398
+ } catch (e2) {
168399
+ return { ...report3, ok: false, code: "seed_file_invalid", error: e2.message };
168400
+ }
168401
+ const specs = opts.entities.filter((s2) => !!s2 && typeof s2 === "object");
168402
+ const queue = [];
168403
+ let considered = 0;
168404
+ for (const spec of specs) {
168405
+ const name = physicalEntityName(spec, app);
168406
+ if (!name || opts.only && !opts.only.includes(name) && !opts.only.includes(spec.name ?? "")) continue;
168407
+ if (!isOwnedEntity(spec)) {
168408
+ if (opts.only) report3.skipped.push({ entity: name, skipped: "adopted", detail: "adopted entities are read-only \u2014 himi never seeds an entity it does not own" });
168409
+ continue;
168410
+ }
168411
+ if (!name.startsWith(base44Prefix(app))) continue;
168412
+ considered++;
168413
+ const inFile = Object.hasOwn(fileRows, name);
168414
+ const fromFile = inFile ? fileRows[name] : void 0;
168415
+ const rows = inFile ? fromFile ?? [] : spec.seed ?? [];
168416
+ const source = inFile ? "base44-seed.json" : "config.ts";
168417
+ if (!rows.length) {
168418
+ report3.skipped.push({ entity: name, skipped: "no-rows", detail: `no seed rows \u2014 add \`seed\` to this entity in config.ts, or run \`himi base44 entities seed --ai\` and refine ${BASE44_SEED_FILE}` });
168419
+ continue;
168420
+ }
168421
+ if (opts.provisioned && !opts.provisioned.includes(name)) {
168422
+ report3.skipped.push({ entity: name, skipped: "unclaimed", detail: "not recorded in base44-provisioned.json as provisioned by this app \u2014 run `himi base44 entities create --yes` first (or, if it is this app's, record it there)" });
168423
+ report3.ok = false;
168424
+ continue;
168425
+ }
168426
+ let existing;
168427
+ try {
168428
+ existing = await callJson(opts, appId2, "GET", `entities/${encodeURIComponent(name)}?limit=1`, `listing ${name}`);
168429
+ } catch (e2) {
168430
+ const missing = e2 instanceof Base44RequestError && e2.status === 404;
168431
+ report3.skipped.push(missing ? { entity: name, skipped: "missing", detail: "not on the app yet \u2014 run `himi base44 entities create --yes` first" } : { entity: name, skipped: "unreadable", detail: `could not read whether it has rows, so seeding might bury content: ${e2.message}` });
168432
+ report3.ok = false;
168433
+ continue;
168434
+ }
168435
+ const page = Array.isArray(existing) ? existing : Array.isArray(existing?.items) ? existing.items : null;
168436
+ if (page === null) {
168437
+ report3.skipped.push({ entity: name, skipped: "unreadable", detail: "the row listing came back in an unrecognised shape, so emptiness is unknown" });
168438
+ report3.ok = false;
168439
+ continue;
168440
+ }
168441
+ if (page.length > 0) {
168442
+ report3.skipped.push({ entity: name, skipped: "not-empty", detail: "already has rows \u2014 seeding only fills empty entities" });
168443
+ continue;
168444
+ }
168445
+ const declared = new Set((spec.fields ?? []).map((f2) => f2.key));
168446
+ const clean2 = rows.map((row) => Object.fromEntries(Object.entries(row).filter(([k2]) => declared.has(k2))));
168447
+ const dropped = [...new Set(rows.flatMap((r2) => Object.keys(r2).filter((k2) => !declared.has(k2))))];
168448
+ if (dropped.length) (report3.droppedKeys ??= {})[name] = dropped;
168449
+ if (clean2.some((r2) => Object.keys(r2).length === 0)) {
168450
+ return { ...report3, ok: false, code: "seed_file_invalid", error: `${name}: ${clean2.filter((r2) => Object.keys(r2).length === 0).length} seed row(s) have no declared field (dropped: ${dropped.join(", ") || "none"}) \u2014 fix the keys in ${BASE44_SEED_FILE}; nothing was sent` };
168451
+ }
168452
+ queue.push({ name, clean: clean2, source });
168453
+ }
168454
+ for (const { name, clean: clean2, source } of queue) {
168455
+ if (yes) {
168456
+ try {
168457
+ await callJson(opts, appId2, "POST", `entities/${encodeURIComponent(name)}/bulk`, `seeding ${name}`, clean2);
168458
+ } catch (e2) {
168459
+ return { ...report3, ...requestFailure(e2) };
168460
+ }
168461
+ }
168462
+ report3.inserted[name] = clean2.length;
168463
+ report3.sources[name] = source;
168464
+ }
168465
+ if (considered === 0) {
168466
+ return {
168467
+ ...report3,
168468
+ ok: false,
168469
+ code: "nothing_to_seed",
168470
+ error: opts.only ? `--only ${opts.only.join(",")} matched no owned entity` : "this app declares no owned Base44 entities to seed",
168471
+ hint: `declare an owned entity with \`name\` (physically ${base44Prefix(app)}<Name>) \u2014 adopted entities are never seeded`
168472
+ };
168473
+ }
168474
+ if (!report3.ok) return { ...report3, code: "seed_incomplete", error: "one or more owned entities could not be seeded; `skipped[]` says why" };
168475
+ return report3;
168476
+ }
168477
+ function placeholder2(f2, i2) {
168478
+ const n2 = i2 + 1;
168479
+ if (f2.enum?.length) return f2.enum[i2 % f2.enum.length];
168480
+ switch (f2.type) {
168481
+ case "number":
168482
+ return n2 * 10;
168483
+ case "integer":
168484
+ return n2;
168485
+ case "boolean":
168486
+ return i2 % 2 === 0;
168487
+ case "array":
168488
+ switch (f2.items?.type) {
168489
+ case "number":
168490
+ case "integer":
168491
+ return [n2];
168492
+ case "boolean":
168493
+ return [i2 % 2 === 0];
168494
+ case "object":
168495
+ return [{}];
168496
+ case "array":
168497
+ return [[]];
168498
+ default:
168499
+ return [`${f2.key}-${n2}`];
168500
+ }
168501
+ case "object":
168502
+ return {};
168503
+ default:
168504
+ switch (f2.format) {
168505
+ case "date":
168506
+ return `2026-0${i2 % 9 + 1}-15`;
168507
+ case "date-time":
168508
+ return `2026-0${i2 % 9 + 1}-15T12:00:00.000Z`;
168509
+ case "time":
168510
+ return `1${i2 % 10}:00`;
168511
+ case "email":
168512
+ return `person${n2}@example.com`;
168513
+ case "uri":
168514
+ case "file":
168515
+ return `https://example.com/${f2.key}-${n2}`;
168516
+ case "uuid":
168517
+ return `00000000-0000-4000-8000-${String(n2).padStart(12, "0")}`;
168518
+ default:
168519
+ return `${f2.key} ${n2}`;
168520
+ }
168521
+ }
168522
+ }
168523
+ function writeBase44SeedRows(opts) {
168524
+ const { dir, app, count: count2 = 8 } = opts;
168525
+ const path2 = join86(dir, BASE44_SEED_FILE);
168526
+ const owned = opts.entities.filter((s2) => !!s2 && typeof s2 === "object" && isOwnedEntity(s2) && (!opts.only || opts.only.includes(physicalEntityName(s2, app)) || opts.only.includes(s2.name ?? "")));
168527
+ if (!owned.length) {
168528
+ return { ok: false, path: path2, entities: {}, agentPrompt: "", next: [], note: opts.only ? `--only ${opts.only.join(",")} matched no owned entity` : `no owned Base44 entities declared \u2014 add one with \`name\` (physically ${base44Prefix(app)}<Name>). Adopted entities are never seeded.` };
168529
+ }
168530
+ let existing = {};
168531
+ if (existsSync81(path2)) {
168532
+ let parsed;
168533
+ try {
168534
+ parsed = JSON.parse(readFileSync102(path2, "utf8"));
168535
+ } catch (e2) {
168536
+ throw new SeedFileError(`${BASE44_SEED_FILE} is not valid JSON (${e2.message}). Refusing to regenerate, because overwriting it would discard the rows already in it.`);
168537
+ }
168538
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new SeedFileError(`${BASE44_SEED_FILE} must be an object keyed by entity name. Fix or delete it.`);
168539
+ existing = parsed;
168540
+ }
168541
+ const entities = {};
168542
+ const fieldless = [];
168543
+ for (const spec of owned) {
168544
+ const name = physicalEntityName(spec, app);
168545
+ if (!(spec.fields ?? []).length) {
168546
+ fieldless.push(name);
168547
+ continue;
168548
+ }
168549
+ existing[name] = Array.from({ length: count2 }, (_2, i2) => Object.fromEntries((spec.fields ?? []).map((f2) => [f2.key, placeholder2(f2, i2)])));
168550
+ entities[name] = count2;
168551
+ }
168552
+ writeFileSync36(path2, `${JSON.stringify(existing, null, 2)}
168553
+ `);
168554
+ const seedable = owned.filter((s2) => (s2.fields ?? []).length);
168555
+ if (!seedable.length) {
168556
+ return { ok: false, path: path2, entities: {}, agentPrompt: "", next: [], note: `no owned entity has a declared field to seed (${fieldless.join(", ")}) \u2014 declare fields first` };
168557
+ }
168558
+ const schema = seedable.map((s2) => ` ${physicalEntityName(s2, app)}
168559
+ ${(s2.fields ?? []).map((f2) => ` ${f2.key} (${f2.type}${f2.format ? `, ${f2.format}` : ""}${f2.enum ? `, one of ${f2.enum.join("|")}` : ""})`).join("\n")}`).join("\n");
168560
+ const agentPrompt = [
168561
+ `Rewrite the placeholder rows in ${BASE44_SEED_FILE} as realistic content for the app "${app}".`,
168562
+ ``,
168563
+ `Entities and their fields:`,
168564
+ schema,
168565
+ ``,
168566
+ `Rules:`,
168567
+ ` - Keep the exact JSON shape: one key per entity name, an array of ${count2} row objects.`,
168568
+ ` - Use ONLY the field keys listed above and keep each value's JSON type; an enum field takes one of its listed values.`,
168569
+ ` - Make the content specific and plausible for this app's domain. No "Lorem ipsum", no "Sample item 1".`,
168570
+ ` - Leave any entity key already in the file that is not listed above untouched.`,
168571
+ ``,
168572
+ `Then run \`himi base44 entities create --yes\` followed by \`himi base44 entities seed --yes\`.`
168573
+ ].join("\n");
168574
+ return {
168575
+ ok: true,
168576
+ path: path2,
168577
+ entities,
168578
+ agentPrompt,
168579
+ next: [`# review/refine ${path2} (see agentPrompt), then:`, "himi base44 entities seed --yes"],
168580
+ ...fieldless.length ? { note: `skipped entities with no declared field (nothing to seed): ${fieldless.join(", ")}` } : {}
168581
+ };
168582
+ }
168583
+ var BASE44_SEED_FILE, SeedFileError;
168584
+ var init_seed = __esm({
168585
+ "src/base44-provision/seed.ts"() {
168586
+ init_base44_schema();
168587
+ init_http2();
168588
+ BASE44_SEED_FILE = "base44-seed.json";
168589
+ SeedFileError = class extends Error {
168590
+ };
168591
+ }
168592
+ });
168593
+
168594
+ // src/base44-analyze/project.ts
168595
+ function parseJsonc(text9) {
168596
+ let out2 = "";
168597
+ let i2 = 0;
168598
+ let inStr = false;
168599
+ while (i2 < text9.length) {
168600
+ const c2 = text9[i2];
168601
+ if (inStr) {
168602
+ out2 += c2;
168603
+ if (c2 === "\\") {
168604
+ out2 += text9[i2 + 1] ?? "";
168605
+ i2 += 2;
168606
+ continue;
168607
+ }
168608
+ if (c2 === '"') inStr = false;
168609
+ i2++;
168610
+ continue;
168611
+ }
168612
+ if (c2 === '"') {
168613
+ inStr = true;
168614
+ out2 += c2;
168615
+ i2++;
168616
+ } else if (c2 === "/" && text9[i2 + 1] === "/") {
168617
+ while (i2 < text9.length && text9[i2] !== "\n") i2++;
168618
+ } else if (c2 === "/" && text9[i2 + 1] === "*") {
168619
+ i2 += 2;
168620
+ while (i2 < text9.length && !(text9[i2] === "*" && text9[i2 + 1] === "/")) i2++;
168621
+ i2 += 2;
168622
+ } else {
168623
+ out2 += c2;
168624
+ i2++;
168625
+ }
168626
+ }
168627
+ return JSON.parse(dropTrailingCommas(out2));
168628
+ }
168629
+ function dropTrailingCommas(text9) {
168630
+ let out2 = "";
168631
+ let inStr = false;
168632
+ for (let i2 = 0; i2 < text9.length; i2++) {
168633
+ const c2 = text9[i2];
168634
+ if (inStr) {
168635
+ out2 += c2;
168636
+ if (c2 === "\\") out2 += text9[++i2] ?? "";
168637
+ else if (c2 === '"') inStr = false;
168638
+ continue;
168639
+ }
168640
+ if (c2 === '"') inStr = true;
168641
+ if (c2 === ",") {
168642
+ let j2 = i2 + 1;
168643
+ while (j2 < text9.length && /\s/.test(text9[j2])) j2++;
168644
+ if (text9[j2] === "}" || text9[j2] === "]") continue;
168645
+ }
168646
+ out2 += c2;
168647
+ }
168648
+ return out2;
168649
+ }
168650
+ function readJson8(files, path2) {
168651
+ const text9 = files.get(path2);
168652
+ if (text9 === void 0) return void 0;
168653
+ try {
168654
+ const v2 = parseJsonc(text9);
168655
+ return v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
168656
+ } catch {
168657
+ return void 0;
168658
+ }
168659
+ }
168660
+ function filesIn(files, dir, re2) {
168661
+ const prefix = dir ? `${dir.replace(/\/+$/, "")}/` : "";
168662
+ return [...files.keys()].filter((p2) => p2.startsWith(prefix) && !p2.slice(prefix.length).includes("/") && re2.test(p2)).sort();
168663
+ }
168664
+ function projectDirs(files) {
168665
+ const cfg = readJson8(files, "base44/config.jsonc") ?? readJson8(files, "base44/config.json") ?? {};
168666
+ const dir = (k2, d2) => {
168667
+ const v2 = cfg[k2];
168668
+ return `base44/${typeof v2 === "string" && v2 && !v2.includes("..") ? v2.replace(/^\.\/|\/+$/g, "") : d2}`;
168669
+ };
168670
+ return {
168671
+ root: "base44",
168672
+ entities: dir("entitiesDir", "entities"),
168673
+ functions: dir("functionsDir", "functions"),
168674
+ agents: dir("agentsDir", "agents"),
168675
+ connectors: dir("connectorsDir", "connectors"),
168676
+ auth: dir("authDir", "auth")
168677
+ };
168678
+ }
168679
+ function fieldsOf(schema) {
168680
+ const required3 = Array.isArray(schema.required) ? schema.required.filter((x2) => typeof x2 === "string") : [];
168681
+ const props = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
168682
+ const fields = Object.entries(props).map(([name, p2]) => ({
168683
+ name,
168684
+ type: Array.isArray(p2?.type) ? p2.type.join("|") : typeof p2?.type === "string" ? p2.type : typeof p2?.$ref === "string" ? `ref:${p2.$ref}` : "unknown",
168685
+ required: required3.includes(name),
168686
+ ...typeof p2?.format === "string" ? { format: p2.format } : {},
168687
+ ...Array.isArray(p2?.enum) ? { enum: p2.enum } : {},
168688
+ ...typeof p2?.description === "string" ? { description: p2.description } : {},
168689
+ ...p2?.rls !== void 0 ? { rls: p2.rls } : {}
168690
+ }));
168691
+ return { fields, required: required3 };
168692
+ }
168693
+ function readEntities(files, dirs) {
168694
+ const out2 = [];
168695
+ for (const path2 of [...filesIn(files, dirs.entities, JSON_FILE), ...filesIn(files, "entities", JSON_FILE)]) {
168696
+ const schema = readJson8(files, path2);
168697
+ if (!schema) continue;
168698
+ const base = path2.split("/").pop().replace(JSON_FILE, "");
168699
+ const name = typeof schema.name === "string" && schema.name ? schema.name : base;
168700
+ if (out2.some((e2) => e2.name === name)) continue;
168701
+ const { fields, required: required3 } = fieldsOf(schema);
168702
+ out2.push({
168703
+ name,
168704
+ ...typeof schema.title === "string" ? { title: schema.title } : {},
168705
+ ...typeof schema.description === "string" ? { description: schema.description } : {},
168706
+ fields,
168707
+ required: required3,
168708
+ schema,
168709
+ ...schema.rls && typeof schema.rls === "object" ? { rls: schema.rls } : {},
168710
+ file: path2,
168711
+ source: "project-files"
168712
+ });
168713
+ }
168714
+ return out2;
168715
+ }
168716
+ function functionSignature(code) {
168717
+ if (code === void 0) return { kind: "unknown" };
168718
+ const methods = [...new Set([...code.matchAll(/\b(?:req|request)\.method\s*[!=]==?\s*["'](GET|POST|PUT|PATCH|DELETE)["']/g)].map((m2) => m2[1]))];
168719
+ const http = /\bDeno\.serve\s*\(|\bserve\s*\(\s*(?:async\s*)?\(?\s*req/.test(code);
168720
+ return { kind: http ? "http" : "invoke", ...methods.length ? { methods } : {} };
168721
+ }
168722
+ function automationsOf(v2) {
168723
+ if (!Array.isArray(v2)) return void 0;
168724
+ const out2 = v2.filter((a2) => !!a2 && typeof a2 === "object").map((a2) => ({
168725
+ name: String(a2.name ?? ""),
168726
+ type: String(a2.type ?? "unknown"),
168727
+ ...typeof a2.cron_expression === "string" ? { schedule: a2.cron_expression } : typeof a2.repeat_unit === "string" ? { schedule: `every ${a2.repeat_interval ?? 1} ${a2.repeat_unit}` } : {},
168728
+ ...typeof a2.entity_name === "string" ? { entity: a2.entity_name } : {}
168729
+ }));
168730
+ return out2.length ? out2 : void 0;
168731
+ }
168732
+ function readFunctions(files, dirs) {
168733
+ const out2 = [];
168734
+ const push = (fn2) => {
168735
+ if (!out2.some((f2) => f2.name === fn2.name)) out2.push(fn2);
168736
+ };
168737
+ const prefix = `${dirs.functions}/`;
168738
+ const under = [...files.keys()].filter((p2) => p2.startsWith(prefix)).sort();
168739
+ for (const cfgPath of under.filter((p2) => /\/function\.jsonc?$/i.test(p2))) {
168740
+ const cfg = readJson8(files, cfgPath);
168741
+ if (!cfg || typeof cfg.name !== "string") continue;
168742
+ const folder = cfgPath.slice(0, cfgPath.lastIndexOf("/"));
168743
+ const entry = typeof cfg.entry === "string" ? `${folder}/${cfg.entry.replace(/^\.\//, "")}` : void 0;
168744
+ push({ name: cfg.name, ...entry ? { sourcePath: entry } : {}, ...functionSignature(entry ? files.get(entry) : void 0), invoke: invokeOf(cfg.name), ...automationsOf(cfg.automations) ? { automations: automationsOf(cfg.automations) } : {}, source: "project-files" });
168745
+ }
168746
+ for (const entry of under.filter((p2) => /\/entry\.[jt]s$/i.test(p2))) {
168747
+ const folder = entry.slice(prefix.length, entry.lastIndexOf("/"));
168748
+ if (!folder || folder.split("/").some((s2) => s2.includes("."))) continue;
168749
+ push({ name: folder, sourcePath: entry, ...functionSignature(files.get(entry)), invoke: invokeOf(folder), source: "project-files" });
168750
+ }
168751
+ for (const file2 of filesIn(files, "functions", CODE_FILE2)) {
168752
+ const name = file2.split("/").pop().replace(CODE_FILE2, "");
168753
+ push({ name, sourcePath: file2, ...functionSignature(files.get(file2)), invoke: invokeOf(name), source: "project-files" });
168754
+ }
168755
+ return out2;
168756
+ }
168757
+ function agentFromConfig(cfg, source) {
168758
+ if (typeof cfg.name !== "string" || !cfg.name) return void 0;
168759
+ const tools = (Array.isArray(cfg.tool_configs) ? cfg.tool_configs : []).filter((t2) => !!t2 && typeof t2 === "object").map((t2) => ({
168760
+ ...typeof t2.entity_name === "string" ? { entity: t2.entity_name } : {},
168761
+ ...typeof t2.function_name === "string" ? { function: t2.function_name } : {},
168762
+ ...Array.isArray(t2.allowed_operations) ? { operations: t2.allowed_operations.map(String) } : {}
168763
+ }));
168764
+ return { name: cfg.name, ...typeof cfg.description === "string" ? { description: cfg.description } : {}, tools, source };
168765
+ }
168766
+ function readAgents(files, dirs) {
168767
+ return filesIn(files, dirs.agents, JSON_FILE).map((p2) => readJson8(files, p2)).map((cfg) => cfg ? agentFromConfig(cfg, "project-files") : void 0).filter((a2) => !!a2);
168768
+ }
168769
+ function readConnectors(files, dirs) {
168770
+ const out2 = [];
168771
+ for (const p2 of filesIn(files, dirs.connectors, JSON_FILE)) {
168772
+ const cfg = readJson8(files, p2);
168773
+ if (!cfg || typeof cfg.type !== "string") continue;
168774
+ out2.push({ type: cfg.type, scopes: Array.isArray(cfg.scopes) ? cfg.scopes.map(String) : [], source: "project-files" });
168775
+ }
168776
+ return out2;
168777
+ }
168778
+ function providersOf(cfg) {
168779
+ const on4 = (camel2, snake2) => cfg[camel2] === true || cfg[snake2] === true;
168780
+ const out2 = [];
168781
+ if (on4("enableUsernamePassword", "enable_username_password")) out2.push("email-password");
168782
+ if (on4("enableGoogleLogin", "enable_google_login")) out2.push("google");
168783
+ if (on4("enableMicrosoftLogin", "enable_microsoft_login")) out2.push("microsoft");
168784
+ if (on4("enableFacebookLogin", "enable_facebook_login")) out2.push("facebook");
168785
+ if (on4("enableAppleLogin", "enable_apple_login")) out2.push("apple");
168786
+ if (on4("enableSSOLogin", "enable_sso_login")) out2.push("sso");
168787
+ return out2;
168788
+ }
168789
+ function readAuthConfig(files, dirs) {
168790
+ for (const p2 of filesIn(files, dirs.auth, JSON_FILE)) {
168791
+ const cfg = readJson8(files, p2);
168792
+ if (cfg && Object.keys(cfg).some((k2) => /^enable/.test(k2))) return { providers: providersOf(cfg), source: "project-files" };
168793
+ }
168794
+ return void 0;
168795
+ }
168796
+ function resolveImport2(files, fromFile, spec) {
168797
+ let base;
168798
+ if (spec.startsWith("@/")) base = `src/${spec.slice(2)}`;
168799
+ else if (spec.startsWith(".")) {
168800
+ const parts = fromFile.split("/").slice(0, -1);
168801
+ for (const seg of spec.split("/")) {
168802
+ if (seg === "..") parts.pop();
168803
+ else if (seg !== ".") parts.push(seg);
168804
+ }
168805
+ base = parts.join("/");
168806
+ } else return void 0;
168807
+ return RESOLVE_EXT.map((e2) => base + e2).find((p2) => files.has(p2));
168808
+ }
168809
+ function importsOf(code) {
168810
+ const out2 = /* @__PURE__ */ new Map();
168811
+ for (const m2 of code.matchAll(/import\s+([^'";]+?)\s+from\s+["']([^"']+)["']/g)) {
168812
+ const clause = m2[1];
168813
+ const spec = m2[2];
168814
+ const def = /^([A-Za-z_$][\w$]*)/.exec(clause);
168815
+ if (def && !clause.startsWith("{")) out2.set(def[1], spec);
168816
+ const named = /\{([^}]*)\}/.exec(clause);
168817
+ if (named) {
168818
+ for (const part3 of named[1].split(",")) {
168819
+ const [orig, alias2] = part3.trim().split(/\s+as\s+/);
168820
+ if (orig) out2.set((alias2 ?? orig).trim(), spec);
168821
+ }
168822
+ }
168823
+ }
168824
+ return out2;
168825
+ }
168826
+ function entitiesReadBy(code, known) {
168827
+ const out2 = /* @__PURE__ */ new Set();
168828
+ for (const m2 of code.matchAll(/\bentities\.([A-Z][A-Za-z0-9_]*)/g)) out2.add(m2[1]);
168829
+ for (const [local, spec] of importsOf(code)) if (/(^|\/)(api\/)?entities(\.[jt]s)?$/.test(spec) && known.includes(local)) out2.add(local);
168830
+ const list = [...out2];
168831
+ return known.length ? list.filter((n2) => known.includes(n2)) : list;
168832
+ }
168833
+ function readRoutes(files, knownEntities) {
168834
+ const out2 = [];
168835
+ const add = (path2, component, fromFile, imports) => {
168836
+ if (out2.some((r2) => r2.path === path2)) return;
168837
+ const spec = component ? imports.get(component) : void 0;
168838
+ const file2 = spec ? resolveImport2(files, fromFile, spec) : void 0;
168839
+ const code = file2 ? files.get(file2) : void 0;
168840
+ out2.push({ path: path2, ...component ? { component } : {}, ...file2 ? { file: file2 } : {}, entities: code ? entitiesReadBy(code, knownEntities) : [], source: "project-files" });
168841
+ };
168842
+ const src = [...files.keys()].filter((p2) => p2.startsWith("src/") && CODE_FILE2.test(p2)).sort();
168843
+ for (const file2 of src) {
168844
+ const code = files.get(file2);
168845
+ if (!/\bRoute\b|\bpath\s*:|\bPAGES\b/.test(code)) continue;
168846
+ const imports = importsOf(code);
168847
+ for (const m2 of code.matchAll(/<Route\b([^>]*?)\/?>/g)) {
168848
+ const path2 = /\bpath\s*=\s*["'{]\s*["'`]?([^"'`}]+)["'`]?\s*}?/.exec(m2[1])?.[1]?.trim();
168849
+ const comp = /\belement\s*=\s*\{\s*<\s*([A-Z][\w.]*)/.exec(m2[1])?.[1];
168850
+ if (path2 && /^(?:\/|\*$|[A-Za-z0-9_:.-]+(?:\/[A-Za-z0-9_:.*-]*)*$)/.test(path2)) add(path2, comp, file2, imports);
168851
+ }
168852
+ for (const m2 of code.matchAll(/\{\s*path\s*:\s*["'`]([^"'`]+)["'`]\s*,\s*(?:element|Component)\s*:\s*<?\s*([A-Z][\w.]*)/g)) add(m2[1], m2[2], file2, imports);
168853
+ const pages2 = /\bPAGES\s*=\s*\{([^}]*)\}/.exec(code);
168854
+ if (pages2) {
168855
+ const main4 = /\bmainPage\s*[:=]\s*["']([A-Za-z0-9_]+)["']/.exec(code)?.[1];
168856
+ for (const pm of pages2[1].matchAll(/["']?([A-Z][A-Za-z0-9_]*)["']?\s*(?::\s*([A-Za-z_$][\w$]*))?\s*(?:,|$)/g)) {
168857
+ const name = pm[1];
168858
+ const comp = pm[2] ?? name;
168859
+ if (main4 === name) add("/", comp, file2, imports);
168860
+ add(`/${name}`, comp, file2, imports);
168861
+ }
168862
+ }
168863
+ }
168864
+ return out2;
168865
+ }
168866
+ var JSON_FILE, CODE_FILE2, invokeOf, RESOLVE_EXT;
168867
+ var init_project = __esm({
168868
+ "src/base44-analyze/project.ts"() {
168869
+ JSON_FILE = /\.jsonc?$/i;
168870
+ CODE_FILE2 = /\.(?:[cm]?[jt]sx?)$/i;
168871
+ invokeOf = (name) => `functions.invoke(${JSON.stringify(name)}, payload)`;
168872
+ RESOLVE_EXT = ["", ".jsx", ".tsx", ".js", ".ts", "/index.jsx", "/index.tsx", "/index.js", "/index.ts"];
168873
+ }
168874
+ });
168875
+
168876
+ // src/base44-provision/functions.ts
168877
+ var functions_exports2 = {};
168878
+ __export(functions_exports2, {
168879
+ FunctionSourceError: () => FunctionSourceError,
168880
+ OWNER_MARKER: () => OWNER_MARKER,
168881
+ deployBase44Functions: () => deployBase44Functions,
168882
+ deployedOwnedBy: () => deployedOwnedBy,
168883
+ markerContent: () => markerContent,
168884
+ readFunctionSource: () => readFunctionSource
168885
+ });
168886
+ import { existsSync as existsSync82, lstatSync as lstatSync21 } from "node:fs";
168887
+ import { join as join87 } from "node:path";
168888
+ function markerContent(app) {
168889
+ return `${JSON.stringify({ app, by: "himi" })}
168890
+ `;
168891
+ }
168892
+ function readFunctionSource(appDir3, name, app) {
168893
+ const rel = `base44/functions/${name}/`;
168894
+ const folder = join87(appDir3, "base44", "functions", name);
168895
+ if (!existsSync82(folder) || !lstatSync21(folder).isDirectory()) throw new FunctionSourceError("function_source_missing", `no source folder at ${rel}`);
168896
+ const { entries, skipped } = collectAppSource(folder);
168897
+ if (skipped.length) throw new FunctionSourceError("function_source_unsafe", `${rel} holds paths himi will not upload (symlinks or denied names): ${skipped.join(", ")} \u2014 remove them`);
168898
+ const secrets = secretFindings(entries);
168899
+ if (secrets.length) throw new FunctionSourceError("function_source_unsafe", `${rel} looks like it holds a credential: ${secrets.map((x2) => `${x2.path} (${x2.reason})`).join(", ")}`);
168900
+ const paths = entries.map((e2) => e2.path);
168901
+ let entry;
168902
+ let automations;
168903
+ const cfg = entries.find((e2) => CONFIG_FILES.has(e2.path));
168904
+ if (cfg) {
168905
+ let parsed;
168906
+ try {
168907
+ parsed = parseJsonc(cfg.bytes.toString("utf8"));
168908
+ } catch (e2) {
168909
+ throw new FunctionSourceError("function_source_missing", `${rel}${cfg.path} is not valid JSON: ${e2.message}`);
168910
+ }
168911
+ if (typeof parsed?.entry === "string") entry = parsed.entry.replace(/^\.\//, "");
168912
+ if (Array.isArray(parsed?.automations)) automations = parsed.automations;
168913
+ }
168914
+ entry ??= ENTRY_CANDIDATES.find((c2) => paths.includes(c2));
168915
+ if (!entry || !paths.includes(entry)) throw new FunctionSourceError("function_source_missing", `no entry file in ${rel} (expected ${entry ?? ENTRY_CANDIDATES.join(" or ")})`);
168916
+ const sources = entries.filter((e2) => !CONFIG_FILES.has(e2.path) && e2.path.split("/").pop() !== OWNER_MARKER);
168917
+ if (sources.length > MAX_FILES) throw new FunctionSourceError("function_source_unsafe", `${rel} has ${sources.length} files \u2014 over the ${MAX_FILES}-file cap`);
168918
+ const bytes2 = sources.reduce((n2, e2) => n2 + e2.bytes.length, 0);
168919
+ if (bytes2 > MAX_BYTES) throw new FunctionSourceError("function_source_unsafe", `${rel} is ${bytes2} bytes \u2014 over the ${MAX_BYTES}-byte cap`);
168920
+ const files = sources.map((e2) => ({ path: e2.path, content: e2.bytes.toString("utf8") }));
168921
+ files.push({ path: OWNER_MARKER, content: markerContent(app) });
168922
+ return { entry, files, ...automations ? { automations } : {} };
168923
+ }
168924
+ function deployedOwnedBy(fn2, app) {
168925
+ const files = Array.isArray(fn2.files) ? fn2.files : [];
168926
+ return files.some((f2) => {
168927
+ if (!f2 || typeof f2 !== "object") return false;
168928
+ const { path: path2, content } = f2;
168929
+ if (typeof path2 !== "string" || path2.split("/").pop() !== OWNER_MARKER || typeof content !== "string") return false;
168930
+ try {
168931
+ return JSON.parse(content).app === app;
168932
+ } catch {
168933
+ return false;
168934
+ }
168935
+ });
168936
+ }
168937
+ async function deployBase44Functions(opts) {
168938
+ const { app, appId: appId2, yes = false } = opts;
168939
+ const report3 = { ok: true, app, appId: appId2, dryRun: !yes, functions: [] };
168940
+ if (yes) {
168941
+ const denied2 = writeScopeFailure(opts.auth);
168942
+ if (denied2) return { ...report3, ...denied2 };
168943
+ }
168944
+ const owned = opts.functions.filter((s2) => !!s2 && typeof s2 === "object" && isOwnedFunction(s2)).map((s2) => physicalFunctionName(s2)).filter((n2) => !opts.only || opts.only.includes(n2));
168945
+ if (!owned.length) {
168946
+ return { ...report3, ok: false, code: "invalid_usage", error: opts.only ? `--only ${opts.only.join(",")} matched no owned function` : "this app declares no owned Base44 functions to deploy", hint: "declare one in config.ts with `base44.functions: [{ name }]` and its source under base44/functions/<name>/" };
168947
+ }
168948
+ const payloads = /* @__PURE__ */ new Map();
168949
+ for (const name of owned) {
168950
+ try {
168951
+ payloads.set(name, readFunctionSource(opts.appDir, name, app));
168952
+ } catch (e2) {
168953
+ if (!(e2 instanceof FunctionSourceError)) throw e2;
168954
+ report3.functions.push({ name, action: "refused", detail: e2.message });
168955
+ return { ...report3, ok: false, code: e2.code, error: `function "${name}": ${e2.message}` };
168956
+ }
168957
+ }
168958
+ let listed;
168959
+ try {
168960
+ listed = await callJson(opts, appId2, "GET", "backend-functions", "listing deployed functions");
168961
+ } catch (e2) {
168962
+ return { ...report3, ...requestFailure(e2), hint: "the deployed functions must be listed to prove no declared name belongs to someone else; nothing was deployed" };
168963
+ }
168964
+ if (!Array.isArray(listed?.functions)) {
168965
+ return { ...report3, ok: false, code: "request_failed", error: "the deployed-functions listing came back without a `functions` array, so no declared name can be proven free \u2014 nothing was deployed" };
168966
+ }
168967
+ const deployed = /* @__PURE__ */ new Map();
168968
+ for (const f2 of listed.functions) {
168969
+ if (f2 && typeof f2 === "object" && typeof f2.name === "string") deployed.set(f2.name, f2);
168970
+ }
168971
+ const taken = owned.filter((n2) => deployed.has(n2) && !deployedOwnedBy(deployed.get(n2), app));
168972
+ if (taken.length) {
168973
+ for (const name of owned) report3.functions.push({ name, action: taken.includes(name) ? "refused" : "deploy", ...taken.includes(name) ? { detail: "already deployed and not himi's for this app" } : {} });
168974
+ return { ...report3, ok: false, code: "function_name_taken", error: `already deployed and not owned by himi for "${app}": ${taken.join(", ")} \u2014 nothing was deployed`, hint: "rename the owned function, or declare the existing one with `base44Name` to invoke it read-only" };
168975
+ }
168976
+ for (const name of owned) {
168977
+ const payload = payloads.get(name);
168978
+ if (!yes) {
168979
+ report3.functions.push({ name, action: "deploy", files: payload.files.length });
168980
+ continue;
168981
+ }
168982
+ try {
168983
+ const r2 = await callJson(opts, appId2, "PUT", `backend-functions/${encodeURIComponent(name)}`, `deploying function "${name}"`, payload);
168984
+ report3.functions.push({ name, action: r2.status === "unchanged" ? "unchanged" : "deployed", files: payload.files.length });
168985
+ } catch (e2) {
168986
+ report3.functions.push({ name, action: "refused", detail: e2.message });
168987
+ return { ...report3, ...requestFailure(e2) };
168988
+ }
168989
+ }
168990
+ return report3;
168991
+ }
168992
+ var OWNER_MARKER, ENTRY_CANDIDATES, CONFIG_FILES, MAX_FILES, MAX_BYTES, FunctionSourceError;
168993
+ var init_functions2 = __esm({
168994
+ "src/base44-provision/functions.ts"() {
168995
+ init_app_source();
168996
+ init_project();
168997
+ init_ownership();
168998
+ init_base44_schema();
168999
+ init_http2();
169000
+ OWNER_MARKER = ".himi-owned";
169001
+ ENTRY_CANDIDATES = ["entry.ts", "entry.js", "index.ts", "index.js"];
169002
+ CONFIG_FILES = /* @__PURE__ */ new Set(["function.jsonc", "function.json"]);
169003
+ MAX_FILES = 200;
169004
+ MAX_BYTES = 5 * 1024 * 1024;
169005
+ FunctionSourceError = class extends Error {
169006
+ constructor(code, message) {
169007
+ super(message);
169008
+ this.code = code;
169009
+ }
169010
+ };
169011
+ }
169012
+ });
169013
+
169014
+ // src/base44-provision/plan.ts
169015
+ function canonical4(v2) {
169016
+ if (Array.isArray(v2)) return `[${v2.map(canonical4).join(",")}]`;
169017
+ if (v2 && typeof v2 === "object") {
169018
+ return `{${Object.keys(v2).sort().map((k2) => `${JSON.stringify(k2)}:${canonical4(v2[k2])}`).join(",")}}`;
169019
+ }
169020
+ return JSON.stringify(v2) ?? "undefined";
169021
+ }
169022
+ function toProperty(f2) {
169023
+ return {
169024
+ type: f2.type,
169025
+ ...f2.format !== void 0 ? { format: f2.format } : {},
169026
+ ...f2.enum !== void 0 ? { enum: f2.enum } : {},
169027
+ ...f2.default !== void 0 ? { default: f2.default } : {},
169028
+ ...f2.items !== void 0 ? { items: { type: f2.items.type } } : {},
169029
+ ...f2.description !== void 0 ? { description: f2.description } : {},
169030
+ ...f2.rls !== void 0 ? { rls: f2.rls } : {}
169031
+ };
169032
+ }
169033
+ function toBase44Schema(spec, app) {
169034
+ return {
169035
+ name: physicalEntityName(spec, app),
169036
+ type: "object",
169037
+ ...spec.title !== void 0 ? { title: spec.title } : {},
169038
+ properties: Object.fromEntries((spec.fields ?? []).map((f2) => [f2.key, toProperty(f2)])),
169039
+ ...spec.required?.length ? { required: [...spec.required] } : {},
169040
+ ...spec.rls !== void 0 ? { rls: spec.rls } : {}
169041
+ };
169042
+ }
169043
+ function propsOf(schema) {
169044
+ const p2 = schema?.properties;
169045
+ return p2 && typeof p2 === "object" && !Array.isArray(p2) ? p2 : {};
169046
+ }
169047
+ function isOwnedPhysical(name, app) {
169048
+ return name.startsWith(base44Prefix(app));
169049
+ }
169050
+ function foreignGuard(snapshot2, next, owned) {
169051
+ const out2 = [];
169052
+ for (const e2 of snapshot2) {
169053
+ if (owned.has(e2.name)) continue;
169054
+ if (!Object.prototype.hasOwnProperty.call(next, e2.name)) {
169055
+ out2.push({ code: "would_delete_foreign_entity", entity: e2.name, detail: `"${e2.name}" is not himi's and would be left out of the full-set sync \u2014 Base44 would delete it and its rows` });
169056
+ } else if (JSON.stringify(next[e2.name]) !== JSON.stringify(e2.schema)) {
169057
+ out2.push({ code: "would_delete_foreign_entity", entity: e2.name, detail: `"${e2.name}" is not himi's and its schema would be altered by the sync` });
169058
+ }
169059
+ }
169060
+ return out2;
169061
+ }
169062
+ function keepRemotePermissions(desired, remote, spec) {
169063
+ const drift = [];
169064
+ if (spec.rls !== void 0 && canonical4(spec.rls) !== canonical4(remote.rls ?? {})) {
169065
+ drift.push({ kind: "permissions", detail: `declared rls ${canonical4(spec.rls)} differs from the live rls ${canonical4(remote.rls ?? {})} \u2014 the live rules are kept (pass --apply-permissions to write the declared ones)` });
169066
+ if (remote.rls === void 0) delete desired.rls;
169067
+ else desired.rls = remote.rls;
169068
+ }
169069
+ const remoteProps = propsOf(remote);
169070
+ const desiredProps = propsOf(desired);
169071
+ for (const f2 of spec.fields ?? []) {
169072
+ const live3 = remoteProps[f2.key];
169073
+ if (!live3 || f2.rls === void 0) continue;
169074
+ if (canonical4(f2.rls) === canonical4(live3.rls ?? {})) continue;
169075
+ drift.push({ kind: "permissions", detail: `field "${f2.key}": declared rls ${canonical4(f2.rls)} differs from the live ${canonical4(live3.rls ?? {})} \u2014 the live rules are kept` });
169076
+ if (live3.rls === void 0) delete desiredProps[f2.key].rls;
169077
+ else desiredProps[f2.key].rls = live3.rls;
169078
+ }
169079
+ return drift;
169080
+ }
169081
+ function inheritUndeclaredPermissions(desired, remote, spec) {
169082
+ if (spec.rls === void 0 && remote.rls !== void 0) desired.rls = remote.rls;
169083
+ const remoteProps = propsOf(remote);
169084
+ const desiredProps = propsOf(desired);
169085
+ for (const f2 of spec.fields ?? []) {
169086
+ if (f2.rls === void 0 && remoteProps[f2.key]?.rls !== void 0) desiredProps[f2.key].rls = remoteProps[f2.key].rls;
169087
+ }
169088
+ }
169089
+ function planEntitySync(declared, snapshot2, opts) {
169090
+ const { app, allowDestructive = false, applyPermissions = false, emptyAppOk = false } = opts;
169091
+ const plan = { next: {}, actions: [], refusals: [], warnings: [], owned: [] };
169092
+ if (snapshot2.length === 0 && !emptyAppOk) {
169093
+ plan.refusals.push({ code: "schema_snapshot_empty", detail: "the project download holds no entity schemas \u2014 if the Base44 app really has no entities, pass --empty-app-ok" });
169094
+ }
169095
+ const specs = declared.filter((s2) => !!s2 && typeof s2 === "object");
169096
+ const owned = new Map(specs.filter(isOwnedEntity).map((s2) => [physicalEntityName(s2, app), s2]));
169097
+ const adopted = new Set(specs.filter(isAdoptedEntity).map((s2) => physicalEntityName(s2, app)));
169098
+ const live3 = new Map(snapshot2.map((e2) => [e2.name, e2]));
169099
+ const provisioned = new Set((opts.provisioned ?? []).filter((n2) => isOwnedPhysical(n2, app)));
169100
+ const ownedHere = /* @__PURE__ */ new Set([...snapshot2.map((e2) => e2.name).filter((n2) => provisioned.has(n2)), ...[...owned.keys()].filter((n2) => !live3.has(n2))]);
169101
+ plan.owned = [...ownedHere].sort();
169102
+ for (const e2 of snapshot2) {
169103
+ if (!ownedHere.has(e2.name)) {
169104
+ plan.next[e2.name] = e2.schema;
169105
+ if (owned.has(e2.name)) {
169106
+ plan.actions.push({ name: e2.name, ownership: "foreign", action: "refused" });
169107
+ plan.refusals.push({ code: "owned_entity_unclaimed", entity: e2.name, detail: `"${e2.name}" is declared and already exists, but this app's base44-provisioned.json does not record provisioning it \u2014 it may be another himi app's (a prefix such as "${base44Prefix(app)}" is shared by longer slugs). If it is this app's, add it to base44-provisioned.json under the Base44 app id; otherwise rename the declaration` });
169108
+ continue;
169109
+ }
169110
+ plan.actions.push({ name: e2.name, ownership: adopted.has(e2.name) ? "adopted" : "foreign", action: "unchanged" });
169111
+ if (isOwnedPhysical(e2.name, app) && !adopted.has(e2.name)) {
169112
+ plan.warnings.push(`"${e2.name}" is in this app's namespace but neither declared nor provisioned by this app here \u2014 left untouched (it may belong to another himi app on this Base44 app)`);
169113
+ }
169114
+ continue;
169115
+ }
169116
+ const spec = owned.get(e2.name);
169117
+ if (!spec) {
169118
+ if (allowDestructive) {
169119
+ plan.actions.push({ name: e2.name, ownership: "owned", action: "delete" });
169120
+ } else {
169121
+ plan.next[e2.name] = e2.schema;
169122
+ plan.actions.push({ name: e2.name, ownership: "owned", action: "refused" });
169123
+ plan.refusals.push({ code: "owned_entity_removal_needs_flag", entity: e2.name, detail: `"${e2.name}" is in this app's namespace but no longer declared \u2014 dropping it deletes the entity and its rows; pass --allow-destructive if that is intended, or declare it again` });
169124
+ }
169125
+ continue;
169126
+ }
169127
+ const desired = toBase44Schema(spec, app);
169128
+ const drift = [];
169129
+ const remoteProps = propsOf(e2.schema);
169130
+ const desiredProps = propsOf(desired);
169131
+ for (const [key3, p2] of Object.entries(desiredProps)) {
169132
+ const r2 = remoteProps[key3];
169133
+ if (!r2) drift.push({ kind: "add-field", detail: `field "${key3}" (${String(p2.type)}) is added` });
169134
+ else {
169135
+ const strip3 = (x2) => {
169136
+ const { rls: _rls, ...rest } = x2;
169137
+ return canonical4(rest);
169138
+ };
169139
+ if (strip3(r2) !== strip3(p2)) drift.push({ kind: "change-field", detail: `field "${key3}" changes from ${strip3(r2)} to ${strip3(p2)}` });
169140
+ }
169141
+ }
169142
+ const removed = Object.keys(remoteProps).filter((k2) => !BUILTINS2.has(k2) && !(k2 in desiredProps));
169143
+ for (const key3 of removed) drift.push({ kind: "remove-field", detail: `field "${key3}" is removed (its values are lost)` });
169144
+ inheritUndeclaredPermissions(desired, e2.schema, spec);
169145
+ if (!applyPermissions) drift.push(...keepRemotePermissions(desired, e2.schema, spec));
169146
+ if (removed.length && !allowDestructive) {
169147
+ plan.next[e2.name] = e2.schema;
169148
+ plan.actions.push({ name: e2.name, ownership: "owned", action: "refused", drift });
169149
+ for (const key3 of removed) {
169150
+ plan.refusals.push({ code: "owned_field_removal_needs_flag", entity: e2.name, detail: `field "${key3}" of "${e2.name}" is no longer declared \u2014 removing it drops its values; pass --allow-destructive if that is intended` });
169151
+ }
169152
+ continue;
169153
+ }
169154
+ plan.next[e2.name] = desired;
169155
+ const changed = canonical4(desired) !== canonical4(e2.schema);
169156
+ plan.actions.push({ name: e2.name, ownership: "owned", action: changed ? "update" : "unchanged", ...drift.length ? { drift } : {} });
169157
+ }
169158
+ for (const [name, spec] of owned) {
169159
+ if (live3.has(name)) continue;
169160
+ plan.next[name] = toBase44Schema(spec, app);
169161
+ plan.actions.push({ name, ownership: "owned", action: "create" });
169162
+ }
169163
+ for (const name of adopted) {
169164
+ if (!live3.has(name)) plan.warnings.push(`adopted entity "${name}" is not on the live app \u2014 himi never creates an entity it does not own`);
169165
+ }
169166
+ plan.refusals.push(...foreignGuard(snapshot2, plan.next, ownedHere));
169167
+ return plan;
169168
+ }
169169
+ var BUILTINS2;
169170
+ var init_plan5 = __esm({
169171
+ "src/base44-provision/plan.ts"() {
169172
+ init_base44_schema();
169173
+ BUILTINS2 = new Set(BASE44_BUILTIN_FIELDS);
169174
+ }
169175
+ });
169176
+
169177
+ // src/base44-provision/snapshot.ts
169178
+ async function readEntitySnapshot(appId2, deps) {
169179
+ const dl2 = await deps.download(appId2);
169180
+ try {
169181
+ const { entries, skipped } = collectAppSource(dl2.dir);
169182
+ const files = new Map(entries.map((e2) => [e2.path, e2.bytes.toString("utf8")]));
169183
+ for (const cfgPath of ["base44/config.jsonc", "base44/config.json"]) {
169184
+ const text9 = files.get(cfgPath);
169185
+ if (text9 === void 0) continue;
169186
+ let cfg;
169187
+ try {
169188
+ cfg = parseJsonc(text9);
169189
+ } catch (e2) {
169190
+ throw new Error(`${cfgPath} does not parse (${e2.message}) \u2014 the entity directory it names cannot be trusted, so the snapshot may be incomplete`);
169191
+ }
169192
+ if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) throw new Error(`${cfgPath} is not a JSON object \u2014 the entity directory it names cannot be trusted`);
169193
+ const dir = cfg.entitiesDir;
169194
+ if (dir !== void 0 && (typeof dir !== "string" || !dir.trim() || /^(?:[\\/]|[A-Za-z]:)/.test(dir) || dir.includes(".."))) throw new Error(`${cfgPath} names entitiesDir ${JSON.stringify(dir)}, which does not stay inside the project \u2014 the snapshot cannot trust it`);
169195
+ }
169196
+ const dirs = projectDirs(files);
169197
+ const entityDirs = [.../* @__PURE__ */ new Set([dirs.entities, "entities"])].map((d2) => `${d2}/`);
169198
+ const isEntityFile = (p2) => entityDirs.some((d2) => p2.startsWith(d2) && !p2.slice(d2.length).includes("/") && JSON_FILE2.test(p2));
169199
+ const dropped = skipped.map((p2) => p2.split(/[\\/]/).join("/")).filter((p2) => entityDirs.some((d2) => p2.startsWith(d2) || d2.startsWith(`${p2}/`)));
169200
+ if (dropped.length) throw new Error(`the download's entity files include ones himi will not read (${dropped.join(", ")}) \u2014 a sync without them would delete those entities`);
169201
+ for (const [path2, text9] of files) {
169202
+ if (!isEntityFile(path2)) continue;
169203
+ let v2;
169204
+ try {
169205
+ v2 = parseJsonc(text9);
169206
+ } catch (e2) {
169207
+ throw new Error(`entity file ${path2} does not parse (${e2.message}) \u2014 a sync without it would delete that entity`);
169208
+ }
169209
+ if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) throw new Error(`entity file ${path2} is not a JSON object \u2014 a sync without it would delete that entity`);
169210
+ }
169211
+ return { entities: readEntities(files, dirs) };
169212
+ } finally {
169213
+ dl2.cleanup();
169214
+ }
169215
+ }
169216
+ var JSON_FILE2;
169217
+ var init_snapshot = __esm({
169218
+ "src/base44-provision/snapshot.ts"() {
169219
+ init_app_source();
169220
+ init_project();
169221
+ JSON_FILE2 = /\.jsonc?$/i;
169222
+ }
169223
+ });
169224
+
169225
+ // src/base44-provision/apply.ts
169226
+ var apply_exports = {};
169227
+ __export(apply_exports, {
169228
+ LEDGER_FILE: () => LEDGER_FILE2,
169229
+ LedgerError: () => LedgerError,
169230
+ createBase44Entities: () => createBase44Entities,
169231
+ fileLedger: () => fileLedger
169232
+ });
169233
+ import { existsSync as existsSync83, readFileSync as readFileSync103, writeFileSync as writeFileSync37 } from "node:fs";
169234
+ import { join as join88 } from "node:path";
169235
+ function fileLedger(dir, appId2) {
169236
+ const path2 = join88(dir, LEDGER_FILE2);
169237
+ const load3 = () => {
169238
+ if (!existsSync83(path2)) return {};
169239
+ let v2;
169240
+ try {
169241
+ v2 = JSON.parse(readFileSync103(path2, "utf8"));
169242
+ } catch (e2) {
169243
+ throw new LedgerError(`${LEDGER_FILE2} is not valid JSON (${e2.message}) \u2014 fix it (a merge conflict?) rather than let himi rewrite it`);
169244
+ }
169245
+ if (!v2 || typeof v2 !== "object" || Array.isArray(v2)) throw new LedgerError(`${LEDGER_FILE2} must be an object keyed by Base44 app id`);
169246
+ return v2;
169247
+ };
169248
+ return {
169249
+ read: () => {
169250
+ const v2 = load3()[appId2];
169251
+ return Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
169252
+ },
169253
+ write: (names2) => {
169254
+ writeFileSync37(path2, `${JSON.stringify({ ...load3(), [appId2]: [...names2].sort() }, null, 2)}
169255
+ `);
169256
+ }
169257
+ };
169258
+ }
169259
+ async function createBase44Entities(opts) {
169260
+ const { app, appId: appId2, yes = false } = opts;
169261
+ const base = { ok: true, app, appId: appId2, prefix: base44Prefix(app), dryRun: !yes };
169262
+ if (yes) {
169263
+ const denied2 = writeScopeFailure(opts.auth);
169264
+ if (denied2) return { ...base, ...denied2 };
169265
+ }
169266
+ let provisioned;
169267
+ try {
169268
+ provisioned = opts.ledger?.read() ?? [];
169269
+ } catch (e2) {
169270
+ return { ...base, ok: false, code: "ledger_unreadable", error: e2.message };
169271
+ }
169272
+ const flags = { app, allowDestructive: opts.allowDestructive, applyPermissions: opts.applyPermissions, emptyAppOk: opts.emptyAppOk, provisioned };
169273
+ const plan = async () => {
169274
+ try {
169275
+ const snap = await readEntitySnapshot(appId2, { download: opts.download });
169276
+ return planEntitySync(opts.entities, snap.entities, flags);
169277
+ } catch (e2) {
169278
+ return { ...base, ok: false, code: "schema_snapshot_unavailable", error: `could not read the app's live entity schemas: ${e2.message}`, hint: "the full-set sync needs a fresh copy of every entity; nothing was sent. Check the session has editor access (`himi base44 whoami`) and re-run." };
169279
+ }
169280
+ };
169281
+ const first = await plan();
169282
+ if ("ok" in first) return first;
169283
+ if (first.refusals.length) {
169284
+ const r2 = first.refusals[0];
169285
+ return { ...base, ok: false, code: r2.code, error: r2.detail, plan: first };
169286
+ }
169287
+ if (!yes) return { ...base, plan: first };
169288
+ const second = await plan();
169289
+ if ("ok" in second) return second;
169290
+ if (second.refusals.length) {
169291
+ const r2 = second.refusals[0];
169292
+ return { ...base, ok: false, code: r2.code, error: r2.detail, plan: second };
169293
+ }
169294
+ if (canonical4(second.next) !== canonical4(first.next) || canonical4(second.actions) !== canonical4(first.actions)) {
169295
+ return { ...base, ok: false, code: "snapshot_changed", error: "the app's entities changed between the plan and the apply \u2014 nothing was sent", hint: "re-run to plan against the current entities", plan: second };
169296
+ }
169297
+ const owned = new Set(second.owned);
169298
+ const ledgerNames = Object.keys(second.next).filter((n2) => owned.has(n2));
169299
+ const maybeApplied = async () => {
169300
+ let live3 = /* @__PURE__ */ new Set();
169301
+ try {
169302
+ live3 = new Set((await readEntitySnapshot(appId2, { download: opts.download })).entities.map((e2) => e2.name));
169303
+ } catch {
169304
+ }
169305
+ return [.../* @__PURE__ */ new Set([...provisioned, ...ledgerNames.filter((n2) => provisioned.includes(n2) || live3.has(n2))])];
169306
+ };
169307
+ let res;
169308
+ try {
169309
+ res = await callJson(opts, appId2, "PUT", "entity-schemas", "syncing entity schemas", { entityNameToSchema: second.next });
169310
+ } catch (e2) {
169311
+ const refused2 = e2 instanceof Base44RequestError && e2.status >= 400 && e2.status < 500;
169312
+ const failure = { ...base, ...requestFailure(e2), plan: second };
169313
+ return refused2 ? failure : recordLedger(opts.ledger, await maybeApplied(), failure);
169314
+ }
169315
+ if (!Array.isArray(res.deleted) || res.deleted.some((n2) => typeof n2 !== "string")) {
169316
+ return recordLedger(opts.ledger, await maybeApplied(), { ...base, ok: false, code: "request_failed", error: "the entity-schemas sync was sent, but its response has no readable deleted[] list (missing, or not all names), so the deletions cannot be checked \u2014 inspect the app's entities", plan: second });
169317
+ }
169318
+ const applied = { created: names(res.created), updated: names(res.updated), deleted: names(res.deleted) };
169319
+ const intended = new Set(second.actions.filter((a2) => a2.action === "delete").map((a2) => a2.name));
169320
+ const foreignDeleted = applied.deleted.filter((n2) => !intended.has(n2));
169321
+ const confirmed = new Set(applied.deleted);
169322
+ const kept = [.../* @__PURE__ */ new Set([...ledgerNames, ...[...intended].filter((n2) => !confirmed.has(n2))])];
169323
+ if (foreignDeleted.length) {
169324
+ return recordLedger(opts.ledger, kept, { ...base, ok: false, code: "foreign_entity_deleted", error: `Base44 reported deleting entities the plan did not drop: ${foreignDeleted.join(", ")}`, foreignDeleted, plan: second, applied });
169325
+ }
169326
+ return recordLedger(opts.ledger, kept, { ...base, plan: second, applied });
169327
+ }
169328
+ function recordLedger(ledger, names2, report3) {
169329
+ try {
169330
+ ledger?.write(names2);
169331
+ return report3;
169332
+ } catch (e2) {
169333
+ const detail = `the sync was sent, but ${LEDGER_FILE2} could not be written (${e2.message}) \u2014 record ${names2.join(", ") || "nothing"} there by hand`;
169334
+ return report3.ok ? { ...report3, ok: false, code: "ledger_unreadable", error: detail } : { ...report3, ledgerError: detail };
169335
+ }
169336
+ }
169337
+ var LEDGER_FILE2, LedgerError, names;
169338
+ var init_apply2 = __esm({
169339
+ "src/base44-provision/apply.ts"() {
169340
+ init_base44_schema();
169341
+ init_http2();
169342
+ init_plan5();
169343
+ init_snapshot();
169344
+ LEDGER_FILE2 = "base44-provisioned.json";
169345
+ LedgerError = class extends Error {
169346
+ };
169347
+ names = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : [];
169348
+ }
169349
+ });
169350
+
168291
169351
  // src/site-analyze/net-guard.ts
168292
169352
  var net_guard_exports = {};
168293
169353
  __export(net_guard_exports, {
@@ -169303,8 +170363,8 @@ function formLabels(x2, depth = 0, out2 = []) {
169303
170363
  return out2;
169304
170364
  }
169305
170365
  function formDetail(f2) {
169306
- const names = formLabels(f2).slice(0, 8);
169307
- return names.length ? names.join(", ") : void 0;
170366
+ const names2 = formLabels(f2).slice(0, 8);
170367
+ return names2.length ? names2.join(", ") : void 0;
169308
170368
  }
169309
170369
  function side(call, def) {
169310
170370
  if (!call) return Promise.resolve({ status: "skipped", count: 0, note: "no-auth", items: [] });
@@ -169505,8 +170565,8 @@ async function readMemberRoles(call) {
169505
170565
  }
169506
170566
  if (!data) continue;
169507
170567
  const raw = asArr(data.roles ?? data.items);
169508
- const names = raw.map((r2) => str7(r2.title ?? r2.name ?? r2.id)).filter((n2) => n2 && !n2.includes("@"));
169509
- if (names.length) return { names: names.slice(0, 24), status: "ok" };
170568
+ const names2 = raw.map((r2) => str7(r2.title ?? r2.name ?? r2.id)).filter((n2) => n2 && !n2.includes("@"));
170569
+ if (names2.length) return { names: names2.slice(0, 24), status: "ok" };
169510
170570
  sawEmptyPayload = true;
169511
170571
  }
169512
170572
  if (sawEmptyPayload) return { names: [], status: "empty" };
@@ -170353,12 +171413,12 @@ var init_velo = __esm({
170353
171413
 
170354
171414
  // src/site-analyze/tokens.ts
170355
171415
  function channels2(css) {
170356
- const canonical5 = canonicalHex(css);
170357
- if (!canonical5) return null;
171416
+ const canonical6 = canonicalHex(css);
171417
+ if (!canonical6) return null;
170358
171418
  return [
170359
- parseInt(canonical5.slice(1, 3), 16),
170360
- parseInt(canonical5.slice(3, 5), 16),
170361
- parseInt(canonical5.slice(5, 7), 16)
171419
+ parseInt(canonical6.slice(1, 3), 16),
171420
+ parseInt(canonical6.slice(3, 5), 16),
171421
+ parseInt(canonical6.slice(5, 7), 16)
170362
171422
  ];
170363
171423
  }
170364
171424
  function isNearWhite(css) {
@@ -170548,8 +171608,8 @@ var init_brand_font = __esm({
170548
171608
  });
170549
171609
 
170550
171610
  // src/site-analyze/write-artifacts.ts
170551
- import { mkdirSync as mkdirSync39, rmSync as rmSync21, writeFileSync as writeFileSync36 } from "node:fs";
170552
- import { join as join86 } from "node:path";
171611
+ import { mkdirSync as mkdirSync39, rmSync as rmSync21, writeFileSync as writeFileSync38 } from "node:fs";
171612
+ import { join as join89 } from "node:path";
170553
171613
  function attachVeloSources(book, sources, put) {
170554
171614
  const byPath = new Map((sources ?? []).map((s2) => [s2.path, s2.text]));
170555
171615
  for (const f2 of book.velo.files) {
@@ -170704,13 +171764,13 @@ async function downloadMedia(book, fetchImpl, put) {
170704
171764
  }
170705
171765
  async function writeBusinessBook(result, opts) {
170706
171766
  const out2 = opts.outDir;
170707
- mkdirSync39(join86(out2, "evidence/pages"), { recursive: true });
170708
- mkdirSync39(join86(out2, "media/catalog"), { recursive: true });
171767
+ mkdirSync39(join89(out2, "evidence/pages"), { recursive: true });
171768
+ mkdirSync39(join89(out2, "media/catalog"), { recursive: true });
170709
171769
  const files = [];
170710
171770
  const put = (rel, body) => {
170711
- const p2 = join86(out2, rel);
170712
- mkdirSync39(join86(p2, ".."), { recursive: true });
170713
- writeFileSync36(p2, body);
171771
+ const p2 = join89(out2, rel);
171772
+ mkdirSync39(join89(p2, ".."), { recursive: true });
171773
+ writeFileSync38(p2, body);
170714
171774
  files.push(rel);
170715
171775
  };
170716
171776
  const book = result.book;
@@ -170752,7 +171812,7 @@ async function writeBusinessBook(result, opts) {
170752
171812
  const allGated = shots.length > 0 && gatedPages.length > 0 && usablePages.length === 0;
170753
171813
  put("README.md", folderReadme(shots.length > 0 && !allGated, book.look.unavailable, allGated));
170754
171814
  put("evidence/probes.json", JSON.stringify(book.probes, null, 2) + "\n");
170755
- rmSync21(join86(out2, "evidence/mobile-app"), { recursive: true, force: true });
171815
+ rmSync21(join89(out2, "evidence/mobile-app"), { recursive: true, force: true });
170756
171816
  for (const [name, value] of Object.entries(result.mobileAppEvidence ?? {})) {
170757
171817
  if (/^[a-z-]+\.json$/.test(name)) put(`evidence/mobile-app/${name}`, JSON.stringify(value, null, 2) + "\n");
170758
171818
  }
@@ -170798,288 +171858,6 @@ var init_write_artifacts = __esm({
170798
171858
  }
170799
171859
  });
170800
171860
 
170801
- // src/base44-analyze/project.ts
170802
- function parseJsonc(text9) {
170803
- let out2 = "";
170804
- let i2 = 0;
170805
- let inStr = false;
170806
- while (i2 < text9.length) {
170807
- const c2 = text9[i2];
170808
- if (inStr) {
170809
- out2 += c2;
170810
- if (c2 === "\\") {
170811
- out2 += text9[i2 + 1] ?? "";
170812
- i2 += 2;
170813
- continue;
170814
- }
170815
- if (c2 === '"') inStr = false;
170816
- i2++;
170817
- continue;
170818
- }
170819
- if (c2 === '"') {
170820
- inStr = true;
170821
- out2 += c2;
170822
- i2++;
170823
- } else if (c2 === "/" && text9[i2 + 1] === "/") {
170824
- while (i2 < text9.length && text9[i2] !== "\n") i2++;
170825
- } else if (c2 === "/" && text9[i2 + 1] === "*") {
170826
- i2 += 2;
170827
- while (i2 < text9.length && !(text9[i2] === "*" && text9[i2 + 1] === "/")) i2++;
170828
- i2 += 2;
170829
- } else {
170830
- out2 += c2;
170831
- i2++;
170832
- }
170833
- }
170834
- return JSON.parse(dropTrailingCommas(out2));
170835
- }
170836
- function dropTrailingCommas(text9) {
170837
- let out2 = "";
170838
- let inStr = false;
170839
- for (let i2 = 0; i2 < text9.length; i2++) {
170840
- const c2 = text9[i2];
170841
- if (inStr) {
170842
- out2 += c2;
170843
- if (c2 === "\\") out2 += text9[++i2] ?? "";
170844
- else if (c2 === '"') inStr = false;
170845
- continue;
170846
- }
170847
- if (c2 === '"') inStr = true;
170848
- if (c2 === ",") {
170849
- let j2 = i2 + 1;
170850
- while (j2 < text9.length && /\s/.test(text9[j2])) j2++;
170851
- if (text9[j2] === "}" || text9[j2] === "]") continue;
170852
- }
170853
- out2 += c2;
170854
- }
170855
- return out2;
170856
- }
170857
- function readJson8(files, path2) {
170858
- const text9 = files.get(path2);
170859
- if (text9 === void 0) return void 0;
170860
- try {
170861
- const v2 = parseJsonc(text9);
170862
- return v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
170863
- } catch {
170864
- return void 0;
170865
- }
170866
- }
170867
- function filesIn(files, dir, re2) {
170868
- const prefix = dir ? `${dir.replace(/\/+$/, "")}/` : "";
170869
- return [...files.keys()].filter((p2) => p2.startsWith(prefix) && !p2.slice(prefix.length).includes("/") && re2.test(p2)).sort();
170870
- }
170871
- function projectDirs(files) {
170872
- const cfg = readJson8(files, "base44/config.jsonc") ?? readJson8(files, "base44/config.json") ?? {};
170873
- const dir = (k2, d2) => {
170874
- const v2 = cfg[k2];
170875
- return `base44/${typeof v2 === "string" && v2 && !v2.includes("..") ? v2.replace(/^\.\/|\/+$/g, "") : d2}`;
170876
- };
170877
- return {
170878
- root: "base44",
170879
- entities: dir("entitiesDir", "entities"),
170880
- functions: dir("functionsDir", "functions"),
170881
- agents: dir("agentsDir", "agents"),
170882
- connectors: dir("connectorsDir", "connectors"),
170883
- auth: dir("authDir", "auth")
170884
- };
170885
- }
170886
- function fieldsOf(schema) {
170887
- const required3 = Array.isArray(schema.required) ? schema.required.filter((x2) => typeof x2 === "string") : [];
170888
- const props = schema.properties && typeof schema.properties === "object" ? schema.properties : {};
170889
- const fields = Object.entries(props).map(([name, p2]) => ({
170890
- name,
170891
- type: Array.isArray(p2?.type) ? p2.type.join("|") : typeof p2?.type === "string" ? p2.type : typeof p2?.$ref === "string" ? `ref:${p2.$ref}` : "unknown",
170892
- required: required3.includes(name),
170893
- ...typeof p2?.format === "string" ? { format: p2.format } : {},
170894
- ...Array.isArray(p2?.enum) ? { enum: p2.enum } : {},
170895
- ...typeof p2?.description === "string" ? { description: p2.description } : {},
170896
- ...p2?.rls !== void 0 ? { rls: p2.rls } : {}
170897
- }));
170898
- return { fields, required: required3 };
170899
- }
170900
- function readEntities(files, dirs) {
170901
- const out2 = [];
170902
- for (const path2 of [...filesIn(files, dirs.entities, JSON_FILE), ...filesIn(files, "entities", JSON_FILE)]) {
170903
- const schema = readJson8(files, path2);
170904
- if (!schema) continue;
170905
- const base = path2.split("/").pop().replace(JSON_FILE, "");
170906
- const name = typeof schema.name === "string" && schema.name ? schema.name : base;
170907
- if (out2.some((e2) => e2.name === name)) continue;
170908
- const { fields, required: required3 } = fieldsOf(schema);
170909
- out2.push({
170910
- name,
170911
- ...typeof schema.title === "string" ? { title: schema.title } : {},
170912
- ...typeof schema.description === "string" ? { description: schema.description } : {},
170913
- fields,
170914
- required: required3,
170915
- schema,
170916
- ...schema.rls && typeof schema.rls === "object" ? { rls: schema.rls } : {},
170917
- file: path2,
170918
- source: "project-files"
170919
- });
170920
- }
170921
- return out2;
170922
- }
170923
- function functionSignature(code) {
170924
- if (code === void 0) return { kind: "unknown" };
170925
- const methods = [...new Set([...code.matchAll(/\b(?:req|request)\.method\s*[!=]==?\s*["'](GET|POST|PUT|PATCH|DELETE)["']/g)].map((m2) => m2[1]))];
170926
- const http = /\bDeno\.serve\s*\(|\bserve\s*\(\s*(?:async\s*)?\(?\s*req/.test(code);
170927
- return { kind: http ? "http" : "invoke", ...methods.length ? { methods } : {} };
170928
- }
170929
- function automationsOf(v2) {
170930
- if (!Array.isArray(v2)) return void 0;
170931
- const out2 = v2.filter((a2) => !!a2 && typeof a2 === "object").map((a2) => ({
170932
- name: String(a2.name ?? ""),
170933
- type: String(a2.type ?? "unknown"),
170934
- ...typeof a2.cron_expression === "string" ? { schedule: a2.cron_expression } : typeof a2.repeat_unit === "string" ? { schedule: `every ${a2.repeat_interval ?? 1} ${a2.repeat_unit}` } : {},
170935
- ...typeof a2.entity_name === "string" ? { entity: a2.entity_name } : {}
170936
- }));
170937
- return out2.length ? out2 : void 0;
170938
- }
170939
- function readFunctions(files, dirs) {
170940
- const out2 = [];
170941
- const push = (fn2) => {
170942
- if (!out2.some((f2) => f2.name === fn2.name)) out2.push(fn2);
170943
- };
170944
- const prefix = `${dirs.functions}/`;
170945
- const under = [...files.keys()].filter((p2) => p2.startsWith(prefix)).sort();
170946
- for (const cfgPath of under.filter((p2) => /\/function\.jsonc?$/i.test(p2))) {
170947
- const cfg = readJson8(files, cfgPath);
170948
- if (!cfg || typeof cfg.name !== "string") continue;
170949
- const folder = cfgPath.slice(0, cfgPath.lastIndexOf("/"));
170950
- const entry = typeof cfg.entry === "string" ? `${folder}/${cfg.entry.replace(/^\.\//, "")}` : void 0;
170951
- push({ name: cfg.name, ...entry ? { sourcePath: entry } : {}, ...functionSignature(entry ? files.get(entry) : void 0), invoke: invokeOf(cfg.name), ...automationsOf(cfg.automations) ? { automations: automationsOf(cfg.automations) } : {}, source: "project-files" });
170952
- }
170953
- for (const entry of under.filter((p2) => /\/entry\.[jt]s$/i.test(p2))) {
170954
- const folder = entry.slice(prefix.length, entry.lastIndexOf("/"));
170955
- if (!folder || folder.split("/").some((s2) => s2.includes("."))) continue;
170956
- push({ name: folder, sourcePath: entry, ...functionSignature(files.get(entry)), invoke: invokeOf(folder), source: "project-files" });
170957
- }
170958
- for (const file2 of filesIn(files, "functions", CODE_FILE2)) {
170959
- const name = file2.split("/").pop().replace(CODE_FILE2, "");
170960
- push({ name, sourcePath: file2, ...functionSignature(files.get(file2)), invoke: invokeOf(name), source: "project-files" });
170961
- }
170962
- return out2;
170963
- }
170964
- function agentFromConfig(cfg, source) {
170965
- if (typeof cfg.name !== "string" || !cfg.name) return void 0;
170966
- const tools = (Array.isArray(cfg.tool_configs) ? cfg.tool_configs : []).filter((t2) => !!t2 && typeof t2 === "object").map((t2) => ({
170967
- ...typeof t2.entity_name === "string" ? { entity: t2.entity_name } : {},
170968
- ...typeof t2.function_name === "string" ? { function: t2.function_name } : {},
170969
- ...Array.isArray(t2.allowed_operations) ? { operations: t2.allowed_operations.map(String) } : {}
170970
- }));
170971
- return { name: cfg.name, ...typeof cfg.description === "string" ? { description: cfg.description } : {}, tools, source };
170972
- }
170973
- function readAgents(files, dirs) {
170974
- return filesIn(files, dirs.agents, JSON_FILE).map((p2) => readJson8(files, p2)).map((cfg) => cfg ? agentFromConfig(cfg, "project-files") : void 0).filter((a2) => !!a2);
170975
- }
170976
- function readConnectors(files, dirs) {
170977
- const out2 = [];
170978
- for (const p2 of filesIn(files, dirs.connectors, JSON_FILE)) {
170979
- const cfg = readJson8(files, p2);
170980
- if (!cfg || typeof cfg.type !== "string") continue;
170981
- out2.push({ type: cfg.type, scopes: Array.isArray(cfg.scopes) ? cfg.scopes.map(String) : [], source: "project-files" });
170982
- }
170983
- return out2;
170984
- }
170985
- function providersOf(cfg) {
170986
- const on4 = (camel2, snake2) => cfg[camel2] === true || cfg[snake2] === true;
170987
- const out2 = [];
170988
- if (on4("enableUsernamePassword", "enable_username_password")) out2.push("email-password");
170989
- if (on4("enableGoogleLogin", "enable_google_login")) out2.push("google");
170990
- if (on4("enableMicrosoftLogin", "enable_microsoft_login")) out2.push("microsoft");
170991
- if (on4("enableFacebookLogin", "enable_facebook_login")) out2.push("facebook");
170992
- if (on4("enableAppleLogin", "enable_apple_login")) out2.push("apple");
170993
- if (on4("enableSSOLogin", "enable_sso_login")) out2.push("sso");
170994
- return out2;
170995
- }
170996
- function readAuthConfig(files, dirs) {
170997
- for (const p2 of filesIn(files, dirs.auth, JSON_FILE)) {
170998
- const cfg = readJson8(files, p2);
170999
- if (cfg && Object.keys(cfg).some((k2) => /^enable/.test(k2))) return { providers: providersOf(cfg), source: "project-files" };
171000
- }
171001
- return void 0;
171002
- }
171003
- function resolveImport2(files, fromFile, spec) {
171004
- let base;
171005
- if (spec.startsWith("@/")) base = `src/${spec.slice(2)}`;
171006
- else if (spec.startsWith(".")) {
171007
- const parts = fromFile.split("/").slice(0, -1);
171008
- for (const seg of spec.split("/")) {
171009
- if (seg === "..") parts.pop();
171010
- else if (seg !== ".") parts.push(seg);
171011
- }
171012
- base = parts.join("/");
171013
- } else return void 0;
171014
- return RESOLVE_EXT.map((e2) => base + e2).find((p2) => files.has(p2));
171015
- }
171016
- function importsOf(code) {
171017
- const out2 = /* @__PURE__ */ new Map();
171018
- for (const m2 of code.matchAll(/import\s+([^'";]+?)\s+from\s+["']([^"']+)["']/g)) {
171019
- const clause = m2[1];
171020
- const spec = m2[2];
171021
- const def = /^([A-Za-z_$][\w$]*)/.exec(clause);
171022
- if (def && !clause.startsWith("{")) out2.set(def[1], spec);
171023
- const named = /\{([^}]*)\}/.exec(clause);
171024
- if (named) {
171025
- for (const part3 of named[1].split(",")) {
171026
- const [orig, alias2] = part3.trim().split(/\s+as\s+/);
171027
- if (orig) out2.set((alias2 ?? orig).trim(), spec);
171028
- }
171029
- }
171030
- }
171031
- return out2;
171032
- }
171033
- function entitiesReadBy(code, known) {
171034
- const out2 = /* @__PURE__ */ new Set();
171035
- for (const m2 of code.matchAll(/\bentities\.([A-Z][A-Za-z0-9_]*)/g)) out2.add(m2[1]);
171036
- for (const [local, spec] of importsOf(code)) if (/(^|\/)(api\/)?entities(\.[jt]s)?$/.test(spec) && known.includes(local)) out2.add(local);
171037
- const list = [...out2];
171038
- return known.length ? list.filter((n2) => known.includes(n2)) : list;
171039
- }
171040
- function readRoutes(files, knownEntities) {
171041
- const out2 = [];
171042
- const add = (path2, component, fromFile, imports) => {
171043
- if (out2.some((r2) => r2.path === path2)) return;
171044
- const spec = component ? imports.get(component) : void 0;
171045
- const file2 = spec ? resolveImport2(files, fromFile, spec) : void 0;
171046
- const code = file2 ? files.get(file2) : void 0;
171047
- out2.push({ path: path2, ...component ? { component } : {}, ...file2 ? { file: file2 } : {}, entities: code ? entitiesReadBy(code, knownEntities) : [], source: "project-files" });
171048
- };
171049
- const src = [...files.keys()].filter((p2) => p2.startsWith("src/") && CODE_FILE2.test(p2)).sort();
171050
- for (const file2 of src) {
171051
- const code = files.get(file2);
171052
- if (!/\bRoute\b|\bpath\s*:|\bPAGES\b/.test(code)) continue;
171053
- const imports = importsOf(code);
171054
- for (const m2 of code.matchAll(/<Route\b([^>]*?)\/?>/g)) {
171055
- const path2 = /\bpath\s*=\s*["'{]\s*["'`]?([^"'`}]+)["'`]?\s*}?/.exec(m2[1])?.[1]?.trim();
171056
- const comp = /\belement\s*=\s*\{\s*<\s*([A-Z][\w.]*)/.exec(m2[1])?.[1];
171057
- if (path2 && /^(?:\/|\*$|[A-Za-z0-9_:.-]+(?:\/[A-Za-z0-9_:.*-]*)*$)/.test(path2)) add(path2, comp, file2, imports);
171058
- }
171059
- for (const m2 of code.matchAll(/\{\s*path\s*:\s*["'`]([^"'`]+)["'`]\s*,\s*(?:element|Component)\s*:\s*<?\s*([A-Z][\w.]*)/g)) add(m2[1], m2[2], file2, imports);
171060
- const pages2 = /\bPAGES\s*=\s*\{([^}]*)\}/.exec(code);
171061
- if (pages2) {
171062
- const main4 = /\bmainPage\s*[:=]\s*["']([A-Za-z0-9_]+)["']/.exec(code)?.[1];
171063
- for (const pm of pages2[1].matchAll(/["']?([A-Z][A-Za-z0-9_]*)["']?\s*(?::\s*([A-Za-z_$][\w$]*))?\s*(?:,|$)/g)) {
171064
- const name = pm[1];
171065
- const comp = pm[2] ?? name;
171066
- if (main4 === name) add("/", comp, file2, imports);
171067
- add(`/${name}`, comp, file2, imports);
171068
- }
171069
- }
171070
- }
171071
- return out2;
171072
- }
171073
- var JSON_FILE, CODE_FILE2, invokeOf, RESOLVE_EXT;
171074
- var init_project = __esm({
171075
- "src/base44-analyze/project.ts"() {
171076
- JSON_FILE = /\.jsonc?$/i;
171077
- CODE_FILE2 = /\.(?:[cm]?[jt]sx?)$/i;
171078
- invokeOf = (name) => `functions.invoke(${JSON.stringify(name)}, payload)`;
171079
- RESOLVE_EXT = ["", ".jsx", ".tsx", ".js", ".ts", "/index.jsx", "/index.tsx", "/index.js", "/index.ts"];
171080
- }
171081
- });
171082
-
171083
171861
  // src/base44-analyze/owner.ts
171084
171862
  function api(ports, appId2) {
171085
171863
  const root = new URL(`/api/apps/${encodeURIComponent(appId2)}`, ports.apiBase).href;
@@ -171617,11 +172395,11 @@ var init_analyze = __esm({
171617
172395
  });
171618
172396
 
171619
172397
  // src/base44-analyze/write-artifacts.ts
171620
- import { existsSync as existsSync81, mkdirSync as mkdirSync40, readFileSync as readFileSync102, rmSync as rmSync22, writeFileSync as writeFileSync37 } from "node:fs";
171621
- import { dirname as dirname48, join as join87, resolve as resolve60, sep as sep19 } from "node:path";
172398
+ import { existsSync as existsSync84, mkdirSync as mkdirSync40, readFileSync as readFileSync104, rmSync as rmSync22, writeFileSync as writeFileSync39 } from "node:fs";
172399
+ import { dirname as dirname48, join as join90, resolve as resolve60, sep as sep19 } from "node:path";
171622
172400
  function isBookFolder(dir) {
171623
172401
  try {
171624
- return JSON.parse(readFileSync102(join87(dir, "book.json"), "utf8")).kind === "base44-app-book";
172402
+ return JSON.parse(readFileSync104(join90(dir, "book.json"), "utf8")).kind === "base44-app-book";
171625
172403
  } catch {
171626
172404
  return false;
171627
172405
  }
@@ -171708,27 +172486,27 @@ function writeBase44Book(result, outDir, opts = {}) {
171708
172486
  const md = renderBookMd(book);
171709
172487
  assertNoSecrets(json8);
171710
172488
  assertNoSecrets(md);
171711
- const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) => existsSync81(join87(out2, n2)));
172489
+ const owned = ["book.json", "BOOK.md", "source", "screenshots"].filter((n2) => existsSync84(join90(out2, n2)));
171712
172490
  if (owned.length) {
171713
172491
  if (!isBookFolder(out2)) throw new Error(`refusing to write the app book into ${out2}: it already has ${owned.join(", ")} that ${owned.length === 1 ? "is" : "are"} not from an app book \u2014 pick an empty --out`);
171714
- for (const d2 of ["source", "screenshots"]) rmSync22(join87(out2, d2), { recursive: true, force: true });
172492
+ for (const d2 of ["source", "screenshots"]) rmSync22(join90(out2, d2), { recursive: true, force: true });
171715
172493
  }
171716
172494
  mkdirSync40(out2, { recursive: true });
171717
- writeFileSync37(join87(out2, "book.json"), json8);
171718
- writeFileSync37(join87(out2, "BOOK.md"), md);
172495
+ writeFileSync39(join90(out2, "book.json"), json8);
172496
+ writeFileSync39(join90(out2, "BOOK.md"), md);
171719
172497
  files.push("book.json", "BOOK.md");
171720
172498
  for (const s2 of shots) {
171721
- mkdirSync40(join87(out2, "screenshots"), { recursive: true });
171722
- writeFileSync37(join87(out2, "screenshots", s2.filename), s2.bytes);
172499
+ mkdirSync40(join90(out2, "screenshots"), { recursive: true });
172500
+ writeFileSync39(join90(out2, "screenshots", s2.filename), s2.bytes);
171723
172501
  files.push(`screenshots/${s2.filename}`);
171724
172502
  }
171725
- const sourceRoot = join87(out2, "source");
172503
+ const sourceRoot = join90(out2, "source");
171726
172504
  for (const f2 of result.sourceFiles) {
171727
172505
  if (!safeRel(f2.path)) continue;
171728
- const dest = join87(sourceRoot, ...f2.path.split("/"));
172506
+ const dest = join90(sourceRoot, ...f2.path.split("/"));
171729
172507
  if (!dest.startsWith(sourceRoot + sep19)) continue;
171730
172508
  mkdirSync40(dirname48(dest), { recursive: true });
171731
- writeFileSync37(dest, f2.bytes);
172509
+ writeFileSync39(dest, f2.bytes);
171732
172510
  }
171733
172511
  if (result.sourceFiles.length) files.push(`source/ (${result.sourceFiles.length} files)`);
171734
172512
  return { outDir: out2, files };
@@ -175269,9 +176047,9 @@ __export(cli_exports, {
175269
176047
  systemTar: () => systemTar
175270
176048
  });
175271
176049
  import { execFile } from "node:child_process";
175272
- import { mkdirSync as mkdirSync41, mkdtempSync as mkdtempSync5, rmSync as rmSync23, writeFileSync as writeFileSync38 } from "node:fs";
176050
+ import { mkdirSync as mkdirSync41, mkdtempSync as mkdtempSync5, rmSync as rmSync23, writeFileSync as writeFileSync40 } from "node:fs";
175273
176051
  import { tmpdir as tmpdir6 } from "node:os";
175274
- import { join as join88, resolve as resolve61 } from "node:path";
176052
+ import { join as join91, resolve as resolve61 } from "node:path";
175275
176053
  import { promisify } from "node:util";
175276
176054
  function projectDownloader(apiFetch, apiBase, token, extract = systemTar) {
175277
176055
  return async (appId2) => {
@@ -175284,12 +176062,12 @@ function projectDownloader(apiFetch, apiBase, token, extract = systemTar) {
175284
176062
  }
175285
176063
  const bytes2 = await readCapped(res, MAX_TARBALL_BYTES);
175286
176064
  if (!bytes2) throw new Error(`project download is over the ${MAX_TARBALL_BYTES}-byte cap`);
175287
- const root = mkdtempSync5(join88(tmpdir6(), "himi-base44-"));
176065
+ const root = mkdtempSync5(join91(tmpdir6(), "himi-base44-"));
175288
176066
  const cleanup = () => rmSync23(root, { recursive: true, force: true });
175289
176067
  try {
175290
- const archive = join88(root, "project.tar");
175291
- const dir = join88(root, "project");
175292
- writeFileSync38(archive, bytes2);
176068
+ const archive = join91(root, "project.tar");
176069
+ const dir = join91(root, "project");
176070
+ writeFileSync40(archive, bytes2);
175293
176071
  mkdirSync41(dir);
175294
176072
  await extract(archive, dir);
175295
176073
  return { dir, cleanup };
@@ -175356,10 +176134,10 @@ __export(base44_entities_exports, {
175356
176134
  function typeLabel(type, format) {
175357
176135
  return format ? `${type} (${format})` : type;
175358
176136
  }
175359
- function canonical4(v2) {
175360
- if (Array.isArray(v2)) return `[${v2.map(canonical4).join(",")}]`;
176137
+ function canonical5(v2) {
176138
+ if (Array.isArray(v2)) return `[${v2.map(canonical5).join(",")}]`;
175361
176139
  if (v2 && typeof v2 === "object") {
175362
- return `{${Object.keys(v2).sort().map((k2) => `${JSON.stringify(k2)}:${canonical4(v2[k2])}`).join(",")}}`;
176140
+ return `{${Object.keys(v2).sort().map((k2) => `${JSON.stringify(k2)}:${canonical5(v2[k2])}`).join(",")}}`;
175363
176141
  }
175364
176142
  return JSON.stringify(v2) ?? "undefined";
175365
176143
  }
@@ -175372,7 +176150,7 @@ function liveItemType(live3, key3) {
175372
176150
  function diffEntityFields(spec, live3) {
175373
176151
  const entity = live3.name;
175374
176152
  const out2 = [];
175375
- const liveFields = new Map(live3.fields.filter((f2) => !BUILTINS2.has(f2.name)).map((f2) => [f2.name, f2]));
176153
+ const liveFields = new Map(live3.fields.filter((f2) => !BUILTINS3.has(f2.name)).map((f2) => [f2.name, f2]));
175376
176154
  for (const f2 of spec.fields ?? []) {
175377
176155
  const remote = liveFields.get(f2.key);
175378
176156
  const declared = typeLabel(f2.type, f2.format);
@@ -175395,8 +176173,8 @@ function diffEntityFields(spec, live3) {
175395
176173
  if (!DECLARABLE_TYPES.has(f2.type)) continue;
175396
176174
  out2.push({ entity, kind: "extra-field", detail: `field "${key3}" (${typeLabel(f2.type, f2.format)}) exists on the live entity but is not declared` });
175397
176175
  }
175398
- if (spec.rls !== void 0 && canonical4(spec.rls) !== canonical4(live3.rls ?? {})) {
175399
- out2.push({ entity, kind: "rls-mismatch", detail: `declared rls ${canonical4(spec.rls)} differs from the live rls ${canonical4(live3.rls ?? {})} \u2014 informational; nothing is changed` });
176176
+ if (spec.rls !== void 0 && canonical5(spec.rls) !== canonical5(live3.rls ?? {})) {
176177
+ out2.push({ entity, kind: "rls-mismatch", detail: `declared rls ${canonical5(spec.rls)} differs from the live rls ${canonical5(live3.rls ?? {})} \u2014 informational; nothing is changed` });
175400
176178
  }
175401
176179
  return out2;
175402
176180
  }
@@ -175479,7 +176257,7 @@ async function queryBase44Entities(opts) {
175479
176257
  ...sourceError ? { sourceError } : {}
175480
176258
  };
175481
176259
  }
175482
- var ROW_PAGE, ROW_COUNT_CAP, BUILTINS2, DECLARABLE_FORMATS, DECLARABLE_TYPES;
176260
+ var ROW_PAGE, ROW_COUNT_CAP, BUILTINS3, DECLARABLE_FORMATS, DECLARABLE_TYPES;
175483
176261
  var init_base44_entities2 = __esm({
175484
176262
  "src/base44-entities.ts"() {
175485
176263
  init_app_source();
@@ -175487,7 +176265,7 @@ var init_base44_entities2 = __esm({
175487
176265
  init_base44_schema();
175488
176266
  ROW_PAGE = 500;
175489
176267
  ROW_COUNT_CAP = 5e3;
175490
- BUILTINS2 = new Set(BASE44_BUILTIN_FIELDS);
176268
+ BUILTINS3 = new Set(BASE44_BUILTIN_FIELDS);
175491
176269
  DECLARABLE_FORMATS = new Set(BASE44_STRING_FORMATS);
175492
176270
  DECLARABLE_TYPES = new Set(BASE44_FIELD_TYPES);
175493
176271
  }
@@ -175574,14 +176352,14 @@ function boundedSetting(value, ceiling) {
175574
176352
  return value !== void 0 && Number.isFinite(value) && value > 0 ? Math.min(value, ceiling) : ceiling;
175575
176353
  }
175576
176354
  function semanticFingerprint(structure) {
175577
- const canonical5 = (value, root = false) => {
175578
- if (Array.isArray(value)) return `[${value.map((item) => canonical5(item)).join(",")}]`;
176355
+ const canonical6 = (value, root = false) => {
176356
+ if (Array.isArray(value)) return `[${value.map((item) => canonical6(item)).join(",")}]`;
175579
176357
  if (isObject2(value)) {
175580
- return `{${Object.keys(value).filter((key3) => !root || !LIFECYCLE_FIELDS.has(key3)).sort().map((key3) => `${JSON.stringify(key3)}:${canonical5(value[key3])}`).join(",")}}`;
176358
+ return `{${Object.keys(value).filter((key3) => !root || !LIFECYCLE_FIELDS.has(key3)).sort().map((key3) => `${JSON.stringify(key3)}:${canonical6(value[key3])}`).join(",")}}`;
175581
176359
  }
175582
176360
  return JSON.stringify(value);
175583
176361
  };
175584
- return createHash44("sha256").update(canonical5(structure, true)).digest("hex");
176362
+ return createHash44("sha256").update(canonical6(structure, true)).digest("hex");
175585
176363
  }
175586
176364
  async function collectOneApp(input, deps = {}) {
175587
176365
  if (typeof input.metaSiteId !== "string" || !UUID.test(input.metaSiteId)) {
@@ -176205,9 +176983,9 @@ __export(cli_exports2, {
176205
176983
  ONE_APP_WORKFLOW: () => ONE_APP_WORKFLOW,
176206
176984
  runOneAppCommand: () => runOneAppCommand
176207
176985
  });
176208
- import { closeSync as closeSync7, constants as constants4, lstatSync as lstatSync21, mkdirSync as mkdirSync42, openSync as openSync6, readFileSync as readFileSync103, realpathSync as realpathSync14, writeFileSync as writeFileSync39 } from "node:fs";
176986
+ import { closeSync as closeSync7, constants as constants4, lstatSync as lstatSync22, mkdirSync as mkdirSync42, openSync as openSync6, readFileSync as readFileSync105, realpathSync as realpathSync14, writeFileSync as writeFileSync41 } from "node:fs";
176209
176987
  import { createHash as createHash45 } from "node:crypto";
176210
- import { dirname as dirname49, join as join89, parse as parse3, resolve as resolve62 } from "node:path";
176988
+ import { dirname as dirname49, join as join92, parse as parse3, resolve as resolve62 } from "node:path";
176211
176989
  function readOptions(argv, cwd, commandIncluded) {
176212
176990
  let cursor = 0;
176213
176991
  const skipGlobalSwitches = () => {
@@ -176253,9 +177031,9 @@ function readOptions(argv, cwd, commandIncluded) {
176253
177031
  if (flags["prompt-file"] !== void 0) {
176254
177032
  try {
176255
177033
  const file2 = resolve62(cwd, flags["prompt-file"]);
176256
- const stat2 = lstatSync21(file2);
177034
+ const stat2 = lstatSync22(file2);
176257
177035
  if (!stat2.isFile() || stat2.size > MAX_PROMPT_BYTES) throw new Error("invalid prompt file");
176258
- prompt = readFileSync103(file2, "utf8");
177036
+ prompt = readFileSync105(file2, "utf8");
176259
177037
  } catch {
176260
177038
  throw new OneAppError("invalid_prompt", "Use a readable text file of at most 64 KiB for --prompt-file.");
176261
177039
  }
@@ -176271,14 +177049,14 @@ function readOptions(argv, cwd, commandIncluded) {
176271
177049
  throw new OneAppError("invalid_output_path", "Pass a parent directory with --dir.");
176272
177050
  }
176273
177051
  const parentDir = resolve62(cwd, flags.dir ?? ".");
176274
- const workspace = join89(parentDir, name);
177052
+ const workspace = join92(parentDir, name);
176275
177053
  assertSafeParents(parentDir);
176276
177054
  if (pathExists(workspace)) throw new OneAppError("output_exists", "The destination already exists. Choose a new --name or --dir.");
176277
177055
  return { metaSiteId, appInstance, prompt, name, parentDir, workspace, target, topTabs };
176278
177056
  }
176279
177057
  function pathExists(path2) {
176280
177058
  try {
176281
- lstatSync21(path2);
177059
+ lstatSync22(path2);
176282
177060
  return true;
176283
177061
  } catch (error) {
176284
177062
  if (error.code === "ENOENT") return false;
@@ -176290,7 +177068,7 @@ function assertSafeParents(path2) {
176290
177068
  let current = path2;
176291
177069
  while (current !== root) {
176292
177070
  try {
176293
- const stat2 = lstatSync21(current);
177071
+ const stat2 = lstatSync22(current);
176294
177072
  if (stat2.isSymbolicLink() || !stat2.isDirectory()) {
176295
177073
  throw new OneAppError("invalid_output_path", "Choose an output parent without symlinks or non-directory components.");
176296
177074
  }
@@ -176306,7 +177084,7 @@ function assertSafeParents(path2) {
176306
177084
  function writePrivate(path2, contents, append) {
176307
177085
  const fd = openSync6(path2, constants4.O_WRONLY | constants4.O_CREAT | constants4.O_NOFOLLOW | (append ? constants4.O_APPEND : constants4.O_EXCL), 384);
176308
177086
  try {
176309
- writeFileSync39(fd, contents, { encoding: "utf8" });
177087
+ writeFileSync41(fd, contents, { encoding: "utf8" });
176310
177088
  } finally {
176311
177089
  closeSync7(fd);
176312
177090
  }
@@ -176328,7 +177106,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
176328
177106
  const hashes = {};
176329
177107
  const diskWrite = deps.writeFile ?? writePrivate;
176330
177108
  const put = (name, content) => {
176331
- const path2 = join89(evidenceDir, name);
177109
+ const path2 = join92(evidenceDir, name);
176332
177110
  try {
176333
177111
  assertSafeParents(evidenceDir);
176334
177112
  diskWrite(path2, content, false);
@@ -176344,7 +177122,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
176344
177122
  if (!evidenceDir) return;
176345
177123
  try {
176346
177124
  assertSafeParents(evidenceDir);
176347
- diskWrite(join89(evidenceDir, "progress.jsonl"), JSON.stringify({ stage, at: now() }) + "\n", true);
177125
+ diskWrite(join92(evidenceDir, "progress.jsonl"), JSON.stringify({ stage, at: now() }) + "\n", true);
176348
177126
  } catch {
176349
177127
  throw new OneAppError("artifact_write_failed", "Could not record migration progress. Existing files were kept.", { stage });
176350
177128
  }
@@ -176360,7 +177138,7 @@ Collect the source mobile app and hand it to the current coding agent. The agent
176360
177138
  assertSafeParents(options.parentDir);
176361
177139
  mkdirSync42(options.workspace, { mode: 448 });
176362
177140
  if (realpathSync14(options.workspace) !== options.workspace) throw new Error("destination changed");
176363
- evidenceDir = join89(options.workspace, ".himi", "one-app");
177141
+ evidenceDir = join92(options.workspace, ".himi", "one-app");
176364
177142
  mkdirSync42(evidenceDir, { recursive: true, mode: 448 });
176365
177143
  } catch (error) {
176366
177144
  if (error.code === "EEXIST") {
@@ -176729,8 +177507,8 @@ function siteAppPickFrom(value) {
176729
177507
  function siteAppRequirementsFrom(appId2, entry) {
176730
177508
  if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return { ok: false, reason: `No release of ${appId2} to judge` };
176731
177509
  const e2 = entry;
176732
- const names = e2.id !== void 0 ? e2.id : e2.app;
176733
- if (names !== appId2) return { ok: false, reason: `No release of ${appId2} to judge` };
177510
+ const names2 = e2.id !== void 0 ? e2.id : e2.app;
177511
+ if (names2 !== appId2) return { ok: false, reason: `No release of ${appId2} to judge` };
176734
177512
  if (!isPlayerRequirements(e2.playerRequirements)) {
176735
177513
  return { ok: false, reason: e2.playerRequirements === void 0 ? `${appId2}'s release does not declare what it requires (republish it)` : `${appId2}'s release declares malformed requirements` };
176736
177514
  }
@@ -177762,8 +178540,8 @@ function placeholderWarnings(findings) {
177762
178540
  if (contact) out2.push(`template placeholder contact details on the site: ${quote(contact)} \u2014 the Wix template's samples, not the business's; get the real ones before any screen shows them (book.placeholders)`);
177763
178541
  const editor = byKind.get("editor-text");
177764
178542
  if (editor) out2.push(`${editor.length} unedited Wix editor/template string(s) on the published site, e.g. ${quote(editor.slice(0, 1))} \u2014 dropped from book.copy, never ship them (book.placeholders)`);
177765
- const names = byKind.get("name-mismatch");
177766
- if (names) out2.push(`the site names the business inconsistently \u2014 it also says ${quote(names)}; likely the template's name left in the copy, so confirm with the owner (book.placeholders)`);
178543
+ const names2 = byKind.get("name-mismatch");
178544
+ if (names2) out2.push(`the site names the business inconsistently \u2014 it also says ${quote(names2)}; likely the template's name left in the copy, so confirm with the owner (book.placeholders)`);
177767
178545
  const media = byKind.get("duplicate-media");
177768
178546
  if (media) out2.push(`${media.length} place(s) repeat one image ${DUPLICATE_MEDIA_MIN}+ times (${media.slice(0, 3).map((m2) => m2.where[0]).join(", ")}) \u2014 template filler, not real photos (book.placeholders)`);
177769
178547
  return out2;
@@ -178497,8 +179275,8 @@ var init_customer_build = __esm({
178497
179275
  });
178498
179276
 
178499
179277
  // src/site-analyze/apply.ts
178500
- import { existsSync as existsSync82, readFileSync as readFileSync104, writeFileSync as writeFileSync40, copyFileSync as copyFileSync2, mkdirSync as mkdirSync43, realpathSync as realpathSync15, statSync as statSync22 } from "node:fs";
178501
- import { dirname as dirname50, isAbsolute as isAbsolute8, join as join90, resolve as resolve63, sep as sep20 } from "node:path";
179278
+ import { existsSync as existsSync85, readFileSync as readFileSync106, writeFileSync as writeFileSync42, copyFileSync as copyFileSync2, mkdirSync as mkdirSync43, realpathSync as realpathSync15, statSync as statSync22 } from "node:fs";
179279
+ import { dirname as dirname50, isAbsolute as isAbsolute8, join as join93, resolve as resolve63, sep as sep20 } from "node:path";
178502
179280
  import { spawnSync as spawnSync4 } from "node:child_process";
178503
179281
  function unpairedRedirectNote(overlay) {
178504
179282
  if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
@@ -178513,7 +179291,7 @@ function committedShellProvisioning(path2) {
178513
179291
  function findRepoRoot(cwd) {
178514
179292
  let dir = cwd;
178515
179293
  for (let i2 = 0; i2 < 8; i2++) {
178516
- if (SHELL_NAMES2.some((name) => existsSync82(join90(dir, shellAppDir(name), "package.json")))) return dir;
179294
+ if (SHELL_NAMES2.some((name) => existsSync85(join93(dir, shellAppDir(name), "package.json")))) return dir;
178517
179295
  const next = dirname50(dir);
178518
179296
  if (next === dir) break;
178519
179297
  dir = next;
@@ -178616,11 +179394,11 @@ function sameKnownSite(previous, next) {
178616
179394
  }
178617
179395
  function buildMergedContract(options) {
178618
179396
  const { appDir: appDir3, packageDir, overlay } = options;
178619
- const committedPath = join90(appDir3, "provisioning.json");
178620
- if (!existsSync82(committedPath)) {
179397
+ const committedPath = join93(appDir3, "provisioning.json");
179398
+ if (!existsSync85(committedPath)) {
178621
179399
  throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
178622
179400
  }
178623
- const committed = JSON.parse(readFileSync104(committedPath, "utf8"));
179401
+ const committed = JSON.parse(readFileSync106(committedPath, "utf8"));
178624
179402
  const merged = mergeCustomerOwned(committed, overlay);
178625
179403
  const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
178626
179404
  const branding = merged.branding ?? {};
@@ -178632,8 +179410,8 @@ function buildMergedContract(options) {
178632
179410
  };
178633
179411
  const stage = (fromRel, toRel) => {
178634
179412
  const from = contained(packageDir, fromRel);
178635
- const to2 = contained(join90(appDir3, STAGED), toRel.slice(STAGED.length + 1));
178636
- if (!from || !to2 || !existsSync82(from)) return void 0;
179413
+ const to2 = contained(join93(appDir3, STAGED), toRel.slice(STAGED.length + 1));
179414
+ if (!from || !to2 || !existsSync85(from)) return void 0;
178637
179415
  let real;
178638
179416
  let realRoot;
178639
179417
  try {
@@ -178655,11 +179433,11 @@ function buildMergedContract(options) {
178655
179433
  };
178656
179434
  const icon = stage("media/icon.png", `${STAGED}/icon.png`);
178657
179435
  if (icon) branding.appIconPath = icon;
178658
- const facesPath = join90(packageDir, "media/fonts/faces.json");
178659
- if (existsSync82(facesPath)) {
179436
+ const facesPath = join93(packageDir, "media/fonts/faces.json");
179437
+ if (existsSync85(facesPath)) {
178660
179438
  let faces = [];
178661
179439
  try {
178662
- const parsed = JSON.parse(readFileSync104(facesPath, "utf8"));
179440
+ const parsed = JSON.parse(readFileSync106(facesPath, "utf8"));
178663
179441
  faces = Array.isArray(parsed) ? parsed : [];
178664
179442
  } catch {
178665
179443
  faces = [];
@@ -178680,11 +179458,11 @@ function buildMergedContract(options) {
178680
179458
  merged.branding = branding;
178681
179459
  const body = `${JSON.stringify(merged, null, 2)}
178682
179460
  `;
178683
- const path2 = join90(packageDir, "provisioning.contract.json");
178684
- writeFileSync40(path2, body);
178685
- const localPath2 = join90(appDir3, LOCAL_CONTRACT_REL);
179461
+ const path2 = join93(packageDir, "provisioning.contract.json");
179462
+ writeFileSync42(path2, body);
179463
+ const localPath2 = join93(appDir3, LOCAL_CONTRACT_REL);
178686
179464
  mkdirSync43(dirname50(localPath2), { recursive: true });
178687
- writeFileSync40(localPath2, body);
179465
+ writeFileSync42(localPath2, body);
178688
179466
  staged.push(localPath2);
178689
179467
  return { path: path2, staged };
178690
179468
  }
@@ -178703,9 +179481,9 @@ function catalogTypography(overlay, template) {
178703
179481
  typography[role] = token;
178704
179482
  continue;
178705
179483
  }
178706
- const canonical5 = canonicalFamilyName(family.trim());
178707
- if (canonical5) {
178708
- typography[role] = { ...token, family: canonical5 };
179484
+ const canonical6 = canonicalFamilyName(family.trim());
179485
+ if (canonical6) {
179486
+ typography[role] = { ...token, family: canonical6 };
178709
179487
  continue;
178710
179488
  }
178711
179489
  const kept = base[role]?.family;
@@ -178717,10 +179495,10 @@ function catalogTypography(overlay, template) {
178717
179495
  function staticFaqFor(overlay, overlayPath) {
178718
179496
  const own5 = overlay.faq;
178719
179497
  if (own5 !== void 0) return deriveStaticFaq(own5);
178720
- const bookPath = join90(dirname50(resolve63(overlayPath)), "book.json");
178721
- if (!existsSync82(bookPath)) return void 0;
179498
+ const bookPath = join93(dirname50(resolve63(overlayPath)), "book.json");
179499
+ if (!existsSync85(bookPath)) return void 0;
178722
179500
  try {
178723
- const book = JSON.parse(readFileSync104(bookPath, "utf8"));
179501
+ const book = JSON.parse(readFileSync106(bookPath, "utf8"));
178724
179502
  const copy = book?.copy;
178725
179503
  if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
178726
179504
  const pairs = deriveStaticFaq(copy.faq);
@@ -178734,10 +179512,10 @@ function staticGalleriesFor(overlay, overlayPath) {
178734
179512
  if (overlay.galleries !== void 0) return deriveStaticGalleries(
178735
179513
  overlay.galleries.map((gallery) => ({ role: "gallery", title: gallery.title, galleryImageUrls: gallery.photos }))
178736
179514
  );
178737
- const bookPath = join90(dirname50(resolve63(overlayPath)), "book.json");
178738
- if (!existsSync82(bookPath)) return void 0;
179515
+ const bookPath = join93(dirname50(resolve63(overlayPath)), "book.json");
179516
+ if (!existsSync85(bookPath)) return void 0;
178739
179517
  try {
178740
- const book = JSON.parse(readFileSync104(bookPath, "utf8"));
179518
+ const book = JSON.parse(readFileSync106(bookPath, "utf8"));
178741
179519
  if (!book.look || book.look.unavailable || !Array.isArray(book.look.pages)) return void 0;
178742
179520
  const galleries = deriveStaticGalleries(book.look.pages);
178743
179521
  return galleries.length || book.look.complete === true ? galleries : void 0;
@@ -178749,8 +179527,8 @@ async function applyOverlays(input) {
178749
179527
  const cwd = resolve63(input.cwd);
178750
179528
  const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
178751
179529
  assertKnownShell(shell);
178752
- const overlay = JSON.parse(readFileSync104(input.overlayPath, "utf8"));
178753
- const tokens2 = JSON.parse(readFileSync104(input.tokensPath, "utf8"));
179530
+ const overlay = JSON.parse(readFileSync106(input.overlayPath, "utf8"));
179531
+ const tokens2 = JSON.parse(readFileSync106(input.tokensPath, "utf8"));
178754
179532
  const faq = staticFaqFor(overlay, input.overlayPath);
178755
179533
  if (faq !== void 0) overlay.faq = faq;
178756
179534
  const galleries = staticGalleriesFor(overlay, input.overlayPath);
@@ -178767,9 +179545,9 @@ async function applyOverlays(input) {
178767
179545
  `shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
178768
179546
  );
178769
179547
  }
178770
- const appDir3 = join90(repoRoot2, shellAppDir(shell));
178771
- const committedPath = join90(appDir3, "provisioning.json");
178772
- const committedSite = existsSync82(committedPath) ? JSON.parse(readFileSync104(committedPath, "utf8")).site : void 0;
179548
+ const appDir3 = join93(repoRoot2, shellAppDir(shell));
179549
+ const committedPath = join93(appDir3, "provisioning.json");
179550
+ const committedSite = existsSync85(committedPath) ? JSON.parse(readFileSync106(committedPath, "utf8")).site : void 0;
178773
179551
  if (committedSite !== void 0 && overlay.site === void 0) {
178774
179552
  throw new Error(
178775
179553
  `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.`
@@ -178796,9 +179574,9 @@ async function applyOverlays(input) {
178796
179574
  note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
178797
179575
  };
178798
179576
  }
178799
- const pkgProv = join90(cwd, "provisioning.json");
179577
+ const pkgProv = join93(cwd, "provisioning.json");
178800
179578
  assertNotCommitted(pkgProv, input.forbiddenProvisioning);
178801
- const contentPath = join90(cwd, "himalaya.content.json");
179579
+ const contentPath = join93(cwd, "himalaya.content.json");
178802
179580
  const syncViewNames = (before, after) => {
178803
179581
  const content = readContentManifest(cwd);
178804
179582
  if (!content) return;
@@ -178810,26 +179588,26 @@ async function applyOverlays(input) {
178810
179588
  };
178811
179589
  let packageFaq = faq;
178812
179590
  let packageGalleries = galleries;
178813
- if (existsSync82(pkgProv)) {
178814
- const cur = JSON.parse(readFileSync104(pkgProv, "utf8"));
179591
+ if (existsSync85(pkgProv)) {
179592
+ const cur = JSON.parse(readFileSync106(pkgProv, "utf8"));
178815
179593
  if (galleries === void 0 && !sameKnownSite(cur, overlay)) overlay.galleries = [];
178816
179594
  const merged = deepMerge4(cur, overlay);
178817
179595
  packageFaq = merged.faq;
178818
179596
  packageGalleries = merged.galleries;
178819
179597
  syncViewNames(cur.site, merged.site);
178820
- writeFileSync40(pkgProv, JSON.stringify(merged, null, 2) + "\n");
179598
+ writeFileSync42(pkgProv, JSON.stringify(merged, null, 2) + "\n");
178821
179599
  wrote.push(pkgProv);
178822
179600
  } else {
178823
179601
  syncViewNames(void 0, overlay.site);
178824
- writeFileSync40(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
179602
+ writeFileSync42(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
178825
179603
  wrote.push(pkgProv);
178826
179604
  }
178827
179605
  if (Array.isArray(packageGalleries) && packageGalleries.length && !overlay.installedVerticals.includes("galleries")) {
178828
179606
  overlay.installedVerticals.push("galleries");
178829
179607
  }
178830
- const pkgTokens = join90(cwd, "tokens.json");
178831
- if (existsSync82(pkgTokens) && (tokens2.colors || tokens2.typography)) {
178832
- const cur = JSON.parse(readFileSync104(pkgTokens, "utf8"));
179608
+ const pkgTokens = join93(cwd, "tokens.json");
179609
+ if (existsSync85(pkgTokens) && (tokens2.colors || tokens2.typography)) {
179610
+ const cur = JSON.parse(readFileSync106(pkgTokens, "utf8"));
178833
179611
  let tokensIn = tokens2;
178834
179612
  if (tokens2.typography) {
178835
179613
  const fonts = catalogTypography(tokens2.typography, cur.typography);
@@ -178850,13 +179628,13 @@ async function applyOverlays(input) {
178850
179628
  if (primary && glow && typeof glow.color === "string") glow.color = primary;
178851
179629
  stripBrandFromIdiom(merged);
178852
179630
  }
178853
- writeFileSync40(pkgTokens, JSON.stringify(merged, null, 2) + "\n");
179631
+ writeFileSync42(pkgTokens, JSON.stringify(merged, null, 2) + "\n");
178854
179632
  wrote.push(pkgTokens);
178855
179633
  }
178856
179634
  const homeAction = homeRefreshActionId(shell);
178857
- const homeSrc = join90(cwd, "dev/index.ts");
178858
- if (homeAction && existsSync82(homeSrc)) {
178859
- const prev = readFileSync104(homeSrc, "utf8");
179635
+ const homeSrc = join93(cwd, "dev/index.ts");
179636
+ if (homeAction && existsSync85(homeSrc)) {
179637
+ const prev = readFileSync106(homeSrc, "utf8");
178860
179638
  const patched = patchBrandParams(prev, overlay, homeAction);
178861
179639
  let next = patched.src;
178862
179640
  if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
@@ -178884,20 +179662,20 @@ async function applyOverlays(input) {
178884
179662
  }
178885
179663
  }
178886
179664
  if (next !== prev) {
178887
- writeFileSync40(homeSrc, next);
179665
+ writeFileSync42(homeSrc, next);
178888
179666
  wrote.push(homeSrc);
178889
179667
  }
178890
179668
  if (patched.unparsed) {
178891
179669
  notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
178892
179670
  }
178893
179671
  }
178894
- if (!input.iconPath || !existsSync82(input.iconPath)) {
179672
+ if (!input.iconPath || !existsSync85(input.iconPath)) {
178895
179673
  const book = input.iconPath ? dirname50(dirname50(resolve63(input.iconPath))) : void 0;
178896
179674
  notes.push(
178897
179675
  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"
178898
179676
  );
178899
179677
  }
178900
- if (input.iconPath && existsSync82(input.iconPath)) {
179678
+ if (input.iconPath && existsSync85(input.iconPath)) {
178901
179679
  try {
178902
179680
  const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
178903
179681
  wrote.push(...installed.wrote);
@@ -178986,7 +179764,7 @@ function patchBrandParams(src, overlay, homeActionId) {
178986
179764
  return { src: out2 + src.slice(cursor), applied, unparsed, foreign: false };
178987
179765
  }
178988
179766
  var STAGED;
178989
- var init_apply2 = __esm({
179767
+ var init_apply3 = __esm({
178990
179768
  "src/site-analyze/apply.ts"() {
178991
179769
  init_content_manifest();
178992
179770
  init_site_view_metadata();
@@ -179856,7 +180634,7 @@ __export(cli_exports3, {
179856
180634
  runSiteAnalyze: () => runSiteAnalyze,
179857
180635
  runSiteFunctionCli: () => runSiteFunctionCli
179858
180636
  });
179859
- import { existsSync as existsSync83, readFileSync as readFileSync105 } from "node:fs";
180637
+ import { existsSync as existsSync86, readFileSync as readFileSync107 } from "node:fs";
179860
180638
  import { resolve as resolve64 } from "node:path";
179861
180639
  function applyNeedsClient(shell) {
179862
180640
  if (shell === void 0 || !SHELL_NAMES2.includes(shell)) return true;
@@ -179924,9 +180702,9 @@ async function runSiteAnalyze(opts) {
179924
180702
  if (book?.skipped) result.warnings = [...result.warnings ?? [], book.skipped];
179925
180703
  const derived = deriveSiteShell({ siteUrl: result.book.input.siteUrl, look: result.book.look, kind, routes });
179926
180704
  const prevOverlayPath = resolve64(outDir, "provisioning.overlay.json");
179927
- const prevSite = existsSync83(prevOverlayPath) ? (() => {
180705
+ const prevSite = existsSync86(prevOverlayPath) ? (() => {
179928
180706
  try {
179929
- return JSON.parse(readFileSync105(prevOverlayPath, "utf8")).site;
180707
+ return JSON.parse(readFileSync107(prevOverlayPath, "utf8")).site;
179930
180708
  } catch {
179931
180709
  return void 0;
179932
180710
  }
@@ -179945,7 +180723,7 @@ async function runSiteAnalyze(opts) {
179945
180723
  }
179946
180724
  const previousOverlay = resolve64(outDir, "provisioning.overlay.json");
179947
180725
  carryOverGoals(
179948
- existsSync83(previousOverlay) ? readFileSync105(previousOverlay, "utf8") : void 0,
180726
+ existsSync86(previousOverlay) ? readFileSync107(previousOverlay, "utf8") : void 0,
179949
180727
  result.provisioningOverlay
179950
180728
  );
179951
180729
  const ownerCall = ownerAuth ? ownerTransportFrom(fetchImpl, ownerAuth) : void 0;
@@ -180003,7 +180781,7 @@ async function runSiteFunctionCli(opts) {
180003
180781
  let source;
180004
180782
  if (opts.sourcePath) {
180005
180783
  const p2 = resolve64(opts.cwd ?? process.cwd(), opts.sourcePath);
180006
- source = readFileSync105(p2, "utf8");
180784
+ source = readFileSync107(p2, "utf8");
180007
180785
  }
180008
180786
  let body;
180009
180787
  if (opts.bodyRaw != null) {
@@ -180031,9 +180809,9 @@ async function runSiteFunctionCli(opts) {
180031
180809
  });
180032
180810
  }
180033
180811
  function base44BookRoutes(bookPath, siteUrl) {
180034
- if (!existsSync83(bookPath)) return void 0;
180812
+ if (!existsSync86(bookPath)) return void 0;
180035
180813
  try {
180036
- const book = JSON.parse(readFileSync105(bookPath, "utf8"));
180814
+ const book = JSON.parse(readFileSync107(bookPath, "utf8"));
180037
180815
  if (book.kind !== "base44-app-book" || !Array.isArray(book.routes)) return void 0;
180038
180816
  const host = (u2) => {
180039
180817
  try {
@@ -180060,7 +180838,7 @@ var init_cli3 = __esm({
180060
180838
  init_analyze2();
180061
180839
  init_write_artifacts();
180062
180840
  init_net_guard();
180063
- init_apply2();
180841
+ init_apply3();
180064
180842
  init_site_shell_derive();
180065
180843
  init_brandable_shells();
180066
180844
  init_crawl_look();
@@ -180187,10 +180965,10 @@ var init_wix_account2 = __esm({
180187
180965
  // src/wix-verticals.ts
180188
180966
  function resolveVerticals(csv2) {
180189
180967
  if (!csv2) return [];
180190
- const names = csv2.split(",").map((s2) => s2.trim()).filter(Boolean);
180968
+ const names2 = csv2.split(",").map((s2) => s2.trim()).filter(Boolean);
180191
180969
  const out2 = [];
180192
180970
  const seen = /* @__PURE__ */ new Set();
180193
- for (const name of names) {
180971
+ for (const name of names2) {
180194
180972
  const appDefId = APP_IDS[name];
180195
180973
  if (!appDefId) {
180196
180974
  const why = UNAVAILABLE[name];
@@ -180288,7 +181066,7 @@ __export(site_create_exports, {
180288
181066
  runSiteList: () => runSiteList,
180289
181067
  writeProvisioningBinding: () => writeProvisioningBinding
180290
181068
  });
180291
- import { existsSync as existsSync84, readFileSync as readFileSync106, writeFileSync as writeFileSync41 } from "node:fs";
181069
+ import { existsSync as existsSync87, readFileSync as readFileSync108, writeFileSync as writeFileSync43 } from "node:fs";
180292
181070
  import { resolve as resolvePath2 } from "node:path";
180293
181071
  function oauthClientName(projectName) {
180294
181072
  return `${projectName} client`;
@@ -180437,7 +181215,7 @@ async function runSiteCreate(opts) {
180437
181215
  if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
180438
181216
  return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
180439
181217
  }
180440
- function writeProvisioningBinding(target, binding2, fs2 = { existsSync: existsSync84, readFileSync: readFileSync106, writeFileSync: writeFileSync41 }) {
181218
+ function writeProvisioningBinding(target, binding2, fs2 = { existsSync: existsSync87, readFileSync: readFileSync108, writeFileSync: writeFileSync43 }) {
180441
181219
  const msid = binding2.siteId;
180442
181220
  const path2 = resolvePath2(target);
180443
181221
  const committed = committedShellProvisioning(path2);
@@ -180523,7 +181301,7 @@ var init_site_create = __esm({
180523
181301
  init_wix_owner();
180524
181302
  init_wix_account2();
180525
181303
  init_wix_verticals();
180526
- init_apply2();
181304
+ init_apply3();
180527
181305
  init_types2();
180528
181306
  init_brandable_shells();
180529
181307
  SITE_CREATE_USAGE = `himi site create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals ${VERTICAL_NAMES.slice(0, 2).join(",")},\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes`;
@@ -180864,13 +181642,13 @@ function selectVeloSource(files, request, knownSecrets = []) {
180864
181642
  (word) => !["with", "that", "this", "from", "have", "want", "app", "site", "backend"].includes(word)
180865
181643
  ).slice(0, 80);
180866
181644
  const score = (file2) => {
180867
- const names = file2.path + " " + [...file2.content.matchAll(/export\s+(?:async\s+)?(?:function|const)\s+(\w+)/g)].map((m2) => m2[1]).join(" ");
180868
- return words.reduce((sum, word) => sum + (names.toLowerCase().includes(word) ? 10 : 0), 0) + (/http-functions\.[jt]s$|\.web\.[jt]s$|\.jsw$/.test(file2.path) ? 1 : 0);
181645
+ const names2 = file2.path + " " + [...file2.content.matchAll(/export\s+(?:async\s+)?(?:function|const)\s+(\w+)/g)].map((m2) => m2[1]).join(" ");
181646
+ return words.reduce((sum, word) => sum + (names2.toLowerCase().includes(word) ? 10 : 0), 0) + (/http-functions\.[jt]s$|\.web\.[jt]s$|\.jsw$/.test(file2.path) ? 1 : 0);
180869
181647
  };
180870
181648
  const queue = candidates.filter((file2) => score(file2) > 0).sort((a2, b2) => score(b2) - score(a2) || a2.path.localeCompare(b2.path));
180871
181649
  const selected = /* @__PURE__ */ new Map();
180872
181650
  let remaining = MAX_TOTAL_CHARS;
180873
- while (queue.length && selected.size < MAX_FILES && remaining > 0) {
181651
+ while (queue.length && selected.size < MAX_FILES2 && remaining > 0) {
180874
181652
  const file2 = queue.shift();
180875
181653
  if (!file2) break;
180876
181654
  if (selected.has(file2.path)) continue;
@@ -180910,10 +181688,10 @@ function selectVeloSource(files, request, knownSecrets = []) {
180910
181688
  }
180911
181689
  return selected;
180912
181690
  }
180913
- var MAX_FILES, MAX_FILE_CHARS, MAX_TOTAL_CHARS, REDACTED2, sensitiveName;
181691
+ var MAX_FILES2, MAX_FILE_CHARS, MAX_TOTAL_CHARS, REDACTED2, sensitiveName;
180914
181692
  var init_velo_source = __esm({
180915
181693
  "src/site-analyze/velo-source.ts"() {
180916
- MAX_FILES = 6;
181694
+ MAX_FILES2 = 6;
180917
181695
  MAX_FILE_CHARS = 8e3;
180918
181696
  MAX_TOTAL_CHARS = 24e3;
180919
181697
  REDACTED2 = "[REDACTED]";
@@ -181134,12 +181912,12 @@ var init_context = __esm({
181134
181912
  });
181135
181913
 
181136
181914
  // src/cli.ts
181137
- import { mkdtempSync as mkdtempSync6, readFileSync as readFileSync107, mkdirSync as mkdirSync44, writeFileSync as writeFileSync42, existsSync as existsSync85, rmSync as rmSync24, readdirSync as readdirSync36, statSync as statSync23, lstatSync as lstatSync22, accessSync, constants as constants5, renameSync as renameSync13, cpSync as cpSync3 } from "node:fs";
181915
+ import { mkdtempSync as mkdtempSync6, readFileSync as readFileSync109, mkdirSync as mkdirSync44, writeFileSync as writeFileSync44, existsSync as existsSync88, rmSync as rmSync24, readdirSync as readdirSync36, statSync as statSync23, lstatSync as lstatSync23, accessSync, constants as constants5, renameSync as renameSync13, cpSync as cpSync3 } from "node:fs";
181138
181916
  import { execFile as execFile2, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn7 } from "node:child_process";
181139
181917
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
181140
181918
  import { createHash as createHash46, randomUUID as randomUUID11 } from "node:crypto";
181141
181919
  import { tmpdir as tmpdir7, homedir as homedir14, hostname as hostname2 } from "node:os";
181142
- import { join as join91, resolve as resolve65, relative as relative16, basename as basename21, dirname as dirname51 } from "node:path";
181920
+ import { join as join94, resolve as resolve65, relative as relative16, basename as basename21, dirname as dirname51 } from "node:path";
181143
181921
  import { fileURLToPath as fileURLToPath29 } from "node:url";
181144
181922
 
181145
181923
  // ../serve-cli/src/client.ts
@@ -183013,7 +183791,7 @@ function auditUx(content, strict = false) {
183013
183791
  }
183014
183792
  }
183015
183793
  const source = walkSource(dir);
183016
- const placeholder2 = /\breplace with\b|\bYOUR_[A-Z0-9_]+\b/i;
183794
+ const placeholder3 = /\breplace with\b|\bYOUR_[A-Z0-9_]+\b/i;
183017
183795
  const previewControl = /\b(?:test|demo|scenario)\s*(?:state|switch|mode)\b/i;
183018
183796
  const matches = (pattern) => source.find((file2) => pattern.test(file2.text));
183019
183797
  const locate2 = (file2, pattern) => {
@@ -183024,13 +183802,13 @@ function auditUx(content, strict = false) {
183024
183802
  const shown2 = hit.length > 60 ? `${hit.slice(0, 60)}\u2026` : hit;
183025
183803
  return `${file2.path}:${index + 1}`.concat(shown2 ? ` (\`${shown2}\`)` : "");
183026
183804
  };
183027
- const p2 = matches(placeholder2);
183805
+ const p2 = matches(placeholder3);
183028
183806
  if (p2) {
183029
183807
  issue(
183030
183808
  issues,
183031
183809
  strict,
183032
183810
  "template-placeholder",
183033
- `Template placeholder copy remains in executable source at ${locate2(p2, placeholder2)}; replace it with customer content or a real configuration value.`,
183811
+ `Template placeholder copy remains in executable source at ${locate2(p2, placeholder3)}; replace it with customer content or a real configuration value.`,
183034
183812
  p2.path
183035
183813
  );
183036
183814
  }
@@ -183155,7 +183933,8 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
183155
183933
  "no-mocks",
183156
183934
  "from-base44-cli",
183157
183935
  "no-browser",
183158
- "refresh-wix"
183936
+ "refresh-wix",
183937
+ "empty-app-ok"
183159
183938
  ]);
183160
183939
  var SHELL_ENUM = SHELL_NAMES2.join("|");
183161
183940
  var SWITCH_FLAGS = new Set([...BOOLEAN_FLAGS].filter((name) => name !== "deep"));
@@ -183225,8 +184004,8 @@ var str10 = (v2) => typeof v2 === "string" ? v2 : void 0;
183225
184004
  var num3 = (v2) => typeof v2 === "string" && v2 !== "" && Number.isFinite(Number(v2)) ? Number(v2) : void 0;
183226
184005
  function embeddedTemplateCatalog() {
183227
184006
  return availableTemplates().map((name) => {
183228
- const path2 = join91(templateSourceDir(name), TEMPLATE_META_FILE);
183229
- const meta = JSON.parse(readFileSync107(path2, "utf8"));
184007
+ const path2 = join94(templateSourceDir(name), TEMPLATE_META_FILE);
184008
+ const meta = JSON.parse(readFileSync109(path2, "utf8"));
183230
184009
  if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
183231
184010
  throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
183232
184011
  }
@@ -183952,9 +184731,25 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
183952
184731
  controls gated by each entity's rls. Re-running is a
183953
184732
  no-op; a hand-edited generated file is skipped-edited
183954
184733
  unless --force. Never calls Base44.
183955
- himi base44 login [--from-base44-cli] | whoami | logout
184734
+ himi base44 entities create [--app <a> | --content <dir>] [--yes] [--allow-destructive]
184735
+ [--apply-permissions] [--empty-app-ok]
184736
+ create/update the app's OWNED Himi<App>* entities. Base44's
184737
+ schema write is a full-set sync, so the one PUT carries
184738
+ every live entity (foreign ones verbatim, from a fresh
184739
+ eject read) and refuses before sending if any would drop.
184740
+ Prints the plan; writes only with --yes.
184741
+ himi base44 entities seed [--app <a>] [--yes] [--only A,B] [--ai [--count <n>]]
184742
+ bulk-insert seed rows into EMPTY owned entities only
184743
+ (base44-seed.json wins over config.ts). --ai writes
184744
+ base44-seed.json offline for the agent to refine.
184745
+ himi base44 functions deploy [--app <a>] [--yes] [--only a,b]
184746
+ deploy each owned function from base44/functions/<name>/,
184747
+ one PUT per function; never the bulk sync, never DELETE;
184748
+ refuses a name deployed by someone else.
184749
+ himi base44 login [--write] [--from-base44-cli] | whoami | logout
183956
184750
  the Base44 session, in ~/.himi/base44/ (never the repo).
183957
- BASE44_ACCESS_TOKEN wins, for CI.
184751
+ --write asks for apps:read apps:write (the provisioning
184752
+ verbs need it). BASE44_ACCESS_TOKEN wins, for CI.
183958
184753
  himi base44 auth-check --url <https://tenant> [--ios-app-id <PREFIX.bundle.id>]
183959
184754
  [--android-package <package> --android-sha256 <fingerprint>]
183960
184755
  check the public tenant association files for native
@@ -184099,7 +184894,7 @@ var COMMANDS2 = [
184099
184894
  { name: "notify", summary: "Hosted --all-members requires --yes for a live send; --dry-run checks ownership/readiness and counts approved recipients without sending. `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 to one site member (--member-email) or all approved members (--all-members) 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> | --all-members (--dry-run | --yes)) --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]" },
184100
184895
  { name: "signing", summary: "READ-ONLY App Store Connect inventory for customer BYO TestFlight readiness. `inspect` lists whether the bundle id, distribution certificate, IOS_APP_STORE profile, and ASC app record exist for --bundle-id / --team-id using a local ASC .p8 (flags or ASC_KEY_* env). Never uploads or mutates Apple resources. Optional --cert-file/--profile-file classify on-disk material.", required: "inspect --bundle-id <id> --team-id <id> --asc-key-file <path> --asc-key-id <id> --asc-issuer-id <id> [--cert-file <p12> --cert-password <pw> --profile-file <mobileprovision>] [--json]" },
184101
184896
  { 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 browser and never uploads or applies anything. A URL is optional there: `--url` lets it read the published page's Velo code-app ids (credential-free, pinned transport) so the backend source is found on sites where the owner code-app probe 404s. `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 (a site shell needs no `--client-id`: it is visitor-only and binds no client); `--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. `member-app set|clear|show <msid>` is the site's member app in Spaces (#4091): the himi app the site's members open in Spaces Lite instead of Branded Lite. `set --app <id>` takes the site's own app or one your account owns (an owned app not yet tied to the site is linked first; another account's app is refused, 403); `clear` returns the site to Branded Lite; `show` prints the pick plus the COMPUTED verdict \u2014 the picked release's requirements judged against the Spaces host manifest (checkHostCompatibility, `--platform` to judge one phone platform) \u2014 and `reason` when it falls back to Branded Lite. Auth is your `himi login` control token plus the account `wix token`, which the plane uses to verify you own the site.", 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>] [--url <https>] [--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] | member-app set|clear|show <msid> [--app <id>] [--platform ios|android]" },
184102
- { name: "base44", summary: "read a BASE44 app into an app book (book.json + BOOK.md) for the agent building a Himi app from it \u2014 the Base44 counterpart of `site analyze`, READ-ONLY. `analyze --url <published app>` is the VISITOR pass: the app id, name, favicon and colours from the published SPA, its router paths, and screenshots + look tokens from the Playwright crawl. `analyze --app-id <id>` adds the OWNER pass and needs a session: the project source under <out>/source/ (the read half of `base44 eject` \u2014 GET api/apps/<id>/eject \u2014 through the same deny-list and secret scan `himi push` uses, widened by the book's token shapes; `eject` itself is never run because it CREATES a copy of the app), every entity's JSON schema, required fields and RLS rules with up to --sample redacted rows (default 5, 0 = off), backend functions, agents, connectors (names and scopes only, never tokens), secret NAMES (never values), auth visibility + providers, and the route \u2192 component \u2192 entities map from the source router. Every chapter it could not read is listed in `gaps` rather than failing the run. `login` runs Base44's device sign-in and stores the session in ~/.himi/base44/session.json (never the repo; --from-base44-cli imports `npx base44 login`'s session instead); BASE44_ACCESS_TOKEN in the environment wins, for CI. `whoami` prints who is signed in (never the token); `logout` removes the stored session. `auth-check --url <tenant> --ios-app-id <PREFIX.bundle.id>` and/or `--android-package <package> --android-sha256 <fingerprint>` checks public native-login associations and prints missing entries; it never reads an owner token. --json prints the book itself. himi docs base44-app-context. `adopt` turns the book into a reviewable base44-entities.ts of ADOPTED entity + function declarations for config.ts (never edits config.ts, never overwrites); `entities query` is READ-ONLY and reports, per declared entity, ownership, row count and schema drift against the live app, plus foreign entities. `types` writes tier5-src/_shared/base44-entities.ts \u2014 a row type and a typed `entities<Row>()` handle per declared entity, byte-stable \u2014 and `himi validate` reports base44-types-stale when that file falls behind the block (nothing when it is absent). himi docs base44-entities. `screens` (base44-starter packages) writes one generated list + detail screen per declared entity over the template's shared engine, with write controls gated by the entity's rls; an unchanged config reports every file `unchanged`, a hand-edited generated file is `skipped-edited` unless --force; never calls Base44. himi docs base44-app-to-himi-app", required: "analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | entities query [--content <dir>] [--all] [--json] | types [--content <dir>] [--json] | screens [--content <dir>] [--force] [--dry-run] [--json] | login [--from-base44-cli] | whoami | logout | auth-check --url <https://tenant> [--ios-app-id <PREFIX.bundle.id>] [--android-package <package> --android-sha256 <fingerprint>]" },
184897
+ { name: "base44", summary: "read a BASE44 app into an app book (book.json + BOOK.md) for the agent building a Himi app from it \u2014 the Base44 counterpart of `site analyze`, READ-ONLY. `analyze --url <published app>` is the VISITOR pass: the app id, name, favicon and colours from the published SPA, its router paths, and screenshots + look tokens from the Playwright crawl. `analyze --app-id <id>` adds the OWNER pass and needs a session: the project source under <out>/source/ (the read half of `base44 eject` \u2014 GET api/apps/<id>/eject \u2014 through the same deny-list and secret scan `himi push` uses, widened by the book's token shapes; `eject` itself is never run because it CREATES a copy of the app), every entity's JSON schema, required fields and RLS rules with up to --sample redacted rows (default 5, 0 = off), backend functions, agents, connectors (names and scopes only, never tokens), secret NAMES (never values), auth visibility + providers, and the route \u2192 component \u2192 entities map from the source router. Every chapter it could not read is listed in `gaps` rather than failing the run. `login` runs Base44's device sign-in and stores the session in ~/.himi/base44/session.json (never the repo; --from-base44-cli imports `npx base44 login`'s session instead); BASE44_ACCESS_TOKEN in the environment wins, for CI. `whoami` prints who is signed in (never the token); `logout` removes the stored session. `auth-check --url <tenant> --ios-app-id <PREFIX.bundle.id>` and/or `--android-package <package> --android-sha256 <fingerprint>` checks public native-login associations and prints missing entries; it never reads an owner token. --json prints the book itself. himi docs base44-app-context. `adopt` turns the book into a reviewable base44-entities.ts of ADOPTED entity + function declarations for config.ts (never edits config.ts, never overwrites); `entities query` is READ-ONLY and reports, per declared entity, ownership, row count and schema drift against the live app, plus foreign entities. `entities create` provisions the app's OWNED Himi<App>* entities: Base44's schema write is a destructive full-set sync, so the single PUT carries every entity in a freshly read eject snapshot (foreign ones verbatim) and the run refuses BEFORE sending when one would be dropped, the snapshot is unreadable or empty, or it moved since the plan; removing an owned field/entity needs --allow-destructive, rewriting owned RLS needs --apply-permissions. `entities seed` bulk-inserts seed rows into empty owned entities only (--ai writes base44-seed.json offline). `functions deploy` ships owned functions one PUT each, never the bulk sync or DELETE, and refuses a name deployed by someone else. All three print a plan and write only with --yes, which needs a `login --write` (apps:write) session. `types` writes tier5-src/_shared/base44-entities.ts \u2014 a row type and a typed `entities<Row>()` handle per declared entity, byte-stable \u2014 and `himi validate` reports base44-types-stale when that file falls behind the block (nothing when it is absent). himi docs base44-entities. `screens` (base44-starter packages) writes one generated list + detail screen per declared entity over the template's shared engine, with write controls gated by the entity's rls; an unchanged config reports every file `unchanged`, a hand-edited generated file is `skipped-edited` unless --force; never calls Base44. himi docs base44-app-to-himi-app", required: "analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | entities query [--content <dir>] [--all] [--json] | entities create [--app <a>] [--yes] [--allow-destructive] [--apply-permissions] [--empty-app-ok] | entities seed [--app <a>] [--yes] [--only A,B] [--ai] | functions deploy [--app <a>] [--yes] [--only a,b] | types [--content <dir>] [--json] | screens [--content <dir>] [--force] [--dry-run] [--json] | login [--write] [--from-base44-cli] | whoami | logout | auth-check --url <https://tenant> [--ios-app-id <PREFIX.bundle.id>] [--android-package <package> --android-sha256 <fingerprint>]" },
184103
184898
  { 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>]" },
184104
184899
  { 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]" },
184105
184900
  { name: "push", summary: "lint + build + publish a release (default --draft: servable via ?release= but NOT live). REFUSES to publish on any error unless --force; --strict promotes warnings. Prints preview + agent-context links. A successful draft push also rebuilds the making-of (.himi/making-of.html, local and offline) and names it as `reel` \u2014 the file to hand the owner beside the preview link. Its postcard carries the home shot only when that shot is newer than the last source edit; a repeat draft's postcard adds what changed since the last one (\"Since the last draft: the home screen changed.\", from the release manifests' screen hashes, remembered in .himi/last-draft.json); otherwise the postcard says why and names `himi render <home> --png`, and the envelope's `postcardPicture: {skipped, render}` leads next[] with that render (the push never renders it itself). The published slug is NAMESPACED per owner \u2014 `<ownerPrefix>.<name>`, composed offline from the control token's ownerPrefix claim, so the CLI and the server derive the identical string and himalaya.content.json is NOT rewritten (a legacy token with no ownerPrefix publishes the declared name unchanged). An app claimed BEFORE namespacing is stored under its FLAT slug, so the claim route answers `alreadyYours` naming that slug and the push adopts it \u2014 reported as `adoptedSlug`, since it is the one case where the published `app` differs from what the declared name composes to. `--no-claim` skips the route that knows this, so a pre-namespacing app pushed with it still fails 403. --visibility public|unlisted decides whether /v1/apps + the Himi Player picker LIST the app (also declarable as `visibility` in himalaya.content.json; omitted, a brand-new app defaults to unlisted \u2014 share by link \u2014 and an existing setting is kept). --account-id names which account owns the app when your Wix session resolves to several (the auto-claim of a brand-new slug cannot guess \u2014 without it a multi-account caller is told to name one). An unforced push of a release that carries SCREENS also refuses when `.himi/ux-audit.json` holds no mobile-UX drive recorded against that release id, or holds one that FAILED (#2955) \u2014 a published draft IS the owner-private preview a customer is handed; `himi ux record` clears it and `--force` overrides it, which the success envelope then says out loud. `--only <selector>` publishes ONLY the named items as a release derived from the app's live release (or `--from-release <id>`), running the identical build + lint gate and simply publishing less; it requires an explicit `--draft` or `--live` because a partial publish has no safe default, never claims a slug, and carries neither attestation nor a source archive (both named in the output). Selectors are comma-separated in ONE `--only`: `changed` (every item whose bytes differ from the base), `screen:<id|glob>`, `bundle:<name>`, `tokens`, `app-config` \u2014 a selected screen drags its logic bundle and a selected bundle drags the screens that reference it, or the bytes land under a key nothing reads. The plane REFUSES (409 binary_capability_gap) a release declaring a PERMISSION-BEARING capability (iOS usage string or entitlement, Android permission \u2014 camera, location, push, \u2026) that the app's last successful `himi dist` was not built with: an OTA push cannot add an OS permission, and on iOS asking for one whose purpose string is missing kills the app. Run `himi dist` first, or pass `--allow-binary-gap` when every installed binary already carries it \u2014 recorded on the release as `allowedBinaryGap`. A gap in a permission-free capability (share, clipboard, \u2026) stays the `needsBinary` advice.", required: "[--content <dir>] [--draft] [--live] [--force] [--strict] [--label] [--notes] [--visibility public|unlisted] [--allow-binary-gap] [--no-claim] [--account-id <id>] [--only <selector>] [--from-release <id>] [--accept-regressions] [--accept-partial] [--app <slug>] (--control-token)" },
@@ -184141,7 +184936,7 @@ var COMMANDS2 = [
184141
184936
  ];
184142
184937
  function cliVersion() {
184143
184938
  try {
184144
- return JSON.parse(readFileSync107(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
184939
+ return JSON.parse(readFileSync109(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
184145
184940
  } catch {
184146
184941
  return "unknown";
184147
184942
  }
@@ -184266,7 +185061,7 @@ function ageInDays(publishedAt, now = Date.now()) {
184266
185061
  }
184267
185062
  function packageVersion(path2) {
184268
185063
  try {
184269
- const version4 = JSON.parse(readFileSync107(path2, "utf8")).version;
185064
+ const version4 = JSON.parse(readFileSync109(path2, "utf8")).version;
184270
185065
  return typeof version4 === "string" && version4 ? version4 : void 0;
184271
185066
  } catch {
184272
185067
  return void 0;
@@ -184275,7 +185070,7 @@ function packageVersion(path2) {
184275
185070
  function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
184276
185071
  let dir = resolve65(fromDir);
184277
185072
  for (; ; ) {
184278
- const version4 = packageVersion(join91(dir, "node_modules", "@wix", "himalaya", "package.json"));
185073
+ const version4 = packageVersion(join94(dir, "node_modules", "@wix", "himalaya", "package.json"));
184279
185074
  if (version4) return { version: version4, source: "local" };
184280
185075
  const parent = dirname51(dir);
184281
185076
  if (parent === dir) break;
@@ -184285,7 +185080,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
184285
185080
  if (bundled) return { version: bundled, source: "bundled" };
184286
185081
  try {
184287
185082
  const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
184288
- const version4 = root ? packageVersion(join91(root, "@wix", "himalaya", "package.json")) : void 0;
185083
+ const version4 = root ? packageVersion(join94(root, "@wix", "himalaya", "package.json")) : void 0;
184289
185084
  return version4 ? { version: version4, source: "global" } : {};
184290
185085
  } catch {
184291
185086
  return {};
@@ -184332,11 +185127,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
184332
185127
  var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
184333
185128
  var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
184334
185129
  function updateCachePath(env = process.env) {
184335
- return env.HIMI_UPDATE_CACHE_FILE ?? join91(homedir14(), ".himalaya", "update-check.json");
185130
+ return env.HIMI_UPDATE_CACHE_FILE ?? join94(homedir14(), ".himalaya", "update-check.json");
184336
185131
  }
184337
185132
  function readUpdateCache(path2) {
184338
185133
  try {
184339
- const parsed = JSON.parse(readFileSync107(path2, "utf8"));
185134
+ const parsed = JSON.parse(readFileSync109(path2, "utf8"));
184340
185135
  return parsed && typeof parsed === "object" ? parsed : {};
184341
185136
  } catch {
184342
185137
  return {};
@@ -184345,7 +185140,7 @@ function readUpdateCache(path2) {
184345
185140
  function writeUpdateCache(path2, cache) {
184346
185141
  try {
184347
185142
  mkdirSync44(dirname51(path2), { recursive: true, mode: 448 });
184348
- writeFileSync42(path2, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
185143
+ writeFileSync44(path2, JSON.stringify(cache, null, 2) + "\n", { mode: 384 });
184349
185144
  } catch {
184350
185145
  }
184351
185146
  }
@@ -184405,12 +185200,12 @@ function createUpdateRunner(spawn8 = spawnSync5) {
184405
185200
  },
184406
185201
  installedVersion: () => {
184407
185202
  const root = globalNodeModulesRoot();
184408
- return root ? packageVersion(join91(root, "@wix", "himalaya-cli", "package.json")) : void 0;
185203
+ return root ? packageVersion(join94(root, "@wix", "himalaya-cli", "package.json")) : void 0;
184409
185204
  },
184410
185205
  reexec: (argv) => {
184411
185206
  const root = globalNodeModulesRoot();
184412
- const entry = root ? join91(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
184413
- if (!entry || !existsSync85(entry)) return void 0;
185207
+ const entry = root ? join94(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
185208
+ if (!entry || !existsSync88(entry)) return void 0;
184414
185209
  const result = spawnSync5(process.execPath, [entry, ...argv], {
184415
185210
  // inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
184416
185211
  stdio: "inherit",
@@ -184457,7 +185252,7 @@ function staleUpdateLockFile(cachePath, now) {
184457
185252
  for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
184458
185253
  let content;
184459
185254
  try {
184460
- content = readFileSync107(path2, "utf8");
185255
+ content = readFileSync109(path2, "utf8");
184461
185256
  } catch {
184462
185257
  continue;
184463
185258
  }
@@ -184480,14 +185275,14 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
184480
185275
  const mine = lockStamp(now);
184481
185276
  const readLock = (path2) => {
184482
185277
  try {
184483
- return readFileSync107(path2, "utf8");
185278
+ return readFileSync109(path2, "utf8");
184484
185279
  } catch {
184485
185280
  return void 0;
184486
185281
  }
184487
185282
  };
184488
185283
  const tryCreate = (path2) => {
184489
185284
  try {
184490
- writeFileSync42(path2, mine, { flag: "wx", mode: 384 });
185285
+ writeFileSync44(path2, mine, { flag: "wx", mode: 384 });
184491
185286
  return true;
184492
185287
  } catch {
184493
185288
  return false;
@@ -185072,7 +185867,7 @@ function executableOnPath(name, env = process.env) {
185072
185867
  const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
185073
185868
  for (const dir of entries) {
185074
185869
  for (const suffix of suffixes) {
185075
- const candidate = join91(dir, `${name}${suffix}`);
185870
+ const candidate = join94(dir, `${name}${suffix}`);
185076
185871
  try {
185077
185872
  if (!statSync23(candidate).isFile()) continue;
185078
185873
  if (process.platform !== "win32") accessSync(candidate, constants5.X_OK);
@@ -185181,7 +185976,7 @@ async function nativeConfigAdvisories(app, configSource) {
185181
185976
  const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths2(), paths_exports));
185182
185977
  const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
185183
185978
  const iosYmlPath = iosProjectYml2(app);
185184
- const iosYml = existsSync85(iosYmlPath) ? readFileSync107(iosYmlPath, "utf8") : "";
185979
+ const iosYml = existsSync88(iosYmlPath) ? readFileSync109(iosYmlPath, "utf8") : "";
185185
185980
  let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
185186
185981
  if (!optedIn) {
185187
185982
  const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
@@ -185195,14 +185990,14 @@ async function nativeConfigAdvisories(app, configSource) {
185195
185990
  }
185196
185991
  function readConfigSource(dir) {
185197
185992
  try {
185198
- return readFileSync107(join91(dir, "config.ts"), "utf8");
185993
+ return readFileSync109(join94(dir, "config.ts"), "utf8");
185199
185994
  } catch {
185200
185995
  return null;
185201
185996
  }
185202
185997
  }
185203
185998
  function writePngFile(path2, base64) {
185204
185999
  mkdirSync44(dirname51(path2), { recursive: true });
185205
- writeFileSync42(path2, Buffer.from(base64, "base64"));
186000
+ writeFileSync44(path2, Buffer.from(base64, "base64"));
185206
186001
  return path2;
185207
186002
  }
185208
186003
  async function seedAgentFilesFor(dir, flags, mode = "init") {
@@ -185249,7 +186044,7 @@ var NoBase44SlotError = class extends Error {
185249
186044
  };
185250
186045
  async function initFromRemoteTemplate(name, parentDir, template, c2, opts = {}) {
185251
186046
  const dir = resolve65(parentDir, name);
185252
- if (existsSync85(join91(dir, "himalaya.content.json"))) {
186047
+ if (existsSync88(join94(dir, "himalaya.content.json"))) {
185253
186048
  throw new Error(`content package already exists at ${dir}`);
185254
186049
  }
185255
186050
  const r2 = await c2.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
@@ -185282,7 +186077,7 @@ function renameRestoredSource(restored, declaredApp, renamed) {
185282
186077
  function symlinkDestinationIssue(dest) {
185283
186078
  let kind;
185284
186079
  try {
185285
- kind = lstatSync22(dest);
186080
+ kind = lstatSync23(dest);
185286
186081
  } catch {
185287
186082
  return null;
185288
186083
  }
@@ -185295,7 +186090,7 @@ function symlinkDestinationIssue(dest) {
185295
186090
  function restoreDestinationIssue(dest, force) {
185296
186091
  const link = symlinkDestinationIssue(dest);
185297
186092
  if (link) return link;
185298
- if (!existsSync85(dest)) return null;
186093
+ if (!existsSync88(dest)) return null;
185299
186094
  if (!statSync23(dest).isDirectory()) {
185300
186095
  return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
185301
186096
  }
@@ -185310,7 +186105,7 @@ function restoreDestinationIssue(dest, force) {
185310
186105
  function isHimalayaMonorepoCheckout(start) {
185311
186106
  let dir = resolve65(start);
185312
186107
  for (; ; ) {
185313
- if (existsSync85(join91(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync85(join91(dir, "core", "serve", "src", "server.ts"))) return true;
186108
+ if (existsSync88(join94(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync88(join94(dir, "core", "serve", "src", "server.ts"))) return true;
185314
186109
  const parent = dirname51(dir);
185315
186110
  if (parent === dir) return false;
185316
186111
  dir = parent;
@@ -185371,7 +186166,7 @@ function materializeForPreview(appDir3, slug, displayName3) {
185371
186166
  Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
185372
186167
  );
185373
186168
  const repoRoot2 = resolve65(fileURLToPath29(new URL("../../..", import.meta.url)));
185374
- const root = join91(repoRoot2, "node_modules", ".cache", "himi-template-preview");
186169
+ const root = join94(repoRoot2, "node_modules", ".cache", "himi-template-preview");
185375
186170
  const stillRunning = (pid) => {
185376
186171
  try {
185377
186172
  process.kill(pid, 0);
@@ -185385,12 +186180,12 @@ function materializeForPreview(appDir3, slug, displayName3) {
185385
186180
  if (!entry.isDirectory()) continue;
185386
186181
  const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
185387
186182
  if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
185388
- rmSync24(join91(root, entry.name), { recursive: true, force: true });
186183
+ rmSync24(join94(root, entry.name), { recursive: true, force: true });
185389
186184
  }
185390
186185
  }
185391
186186
  } catch {
185392
186187
  }
185393
- const dest = join91(root, `${slug}-${process.pid}`);
186188
+ const dest = join94(root, `${slug}-${process.pid}`);
185394
186189
  rmSync24(dest, { recursive: true, force: true });
185395
186190
  mkdirSync44(dest, { recursive: true });
185396
186191
  try {
@@ -185403,8 +186198,8 @@ function materializeForPreview(appDir3, slug, displayName3) {
185403
186198
  }
185404
186199
  async function appId(dir) {
185405
186200
  try {
185406
- const { readFileSync: readFileSync108 } = await import("node:fs");
185407
- const m2 = JSON.parse(readFileSync108(join91(dir, "himalaya.content.json"), "utf8"));
186201
+ const { readFileSync: readFileSync110 } = await import("node:fs");
186202
+ const m2 = JSON.parse(readFileSync110(join94(dir, "himalaya.content.json"), "utf8"));
185408
186203
  if (m2.name) return m2.name;
185409
186204
  } catch {
185410
186205
  }
@@ -185412,8 +186207,8 @@ async function appId(dir) {
185412
186207
  }
185413
186208
  async function contentVisibility(dir) {
185414
186209
  try {
185415
- const { readFileSync: readFileSync108 } = await import("node:fs");
185416
- const m2 = JSON.parse(readFileSync108(join91(dir, "himalaya.content.json"), "utf8"));
186210
+ const { readFileSync: readFileSync110 } = await import("node:fs");
186211
+ const m2 = JSON.parse(readFileSync110(join94(dir, "himalaya.content.json"), "utf8"));
185417
186212
  if (m2.visibility === "public" || m2.visibility === "unlisted") return m2.visibility;
185418
186213
  } catch {
185419
186214
  }
@@ -185596,8 +186391,8 @@ Guides in your browser: ${idx.portalUrl}`);
185596
186391
  const sdks = loadSdkReference();
185597
186392
  const arg = pos[1];
185598
186393
  if (arg) {
185599
- const canonical5 = arg.replace(/^@wix\/himalaya\//, "@himalaya/");
185600
- const want = canonical5.startsWith("@himalaya/") ? canonical5 : `@himalaya/${canonical5}`;
186394
+ const canonical6 = arg.replace(/^@wix\/himalaya\//, "@himalaya/");
186395
+ const want = canonical6.startsWith("@himalaya/") ? canonical6 : `@himalaya/${canonical6}`;
185601
186396
  const s2 = sdks.find((x2) => x2.name === want || x2.name === arg);
185602
186397
  if (!s2) {
185603
186398
  io2.error(JSON.stringify({ error: `unknown sdk: ${arg}`, sdks: sdks.map((x2) => x2.name) }));
@@ -185705,7 +186500,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
185705
186500
  ...res.removed.length ? { removed: res.removed, note: "older copies at the app root, moved to .himi/legacy-agent-files/ (a backup, in case one became app code) \u2014 the current ones live in .agents/skills/himalaya/" } : {},
185706
186501
  // In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
185707
186502
  // hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
185708
- ...existsSync85(join91(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
186503
+ ...existsSync88(join94(dir, ".himi", "attestations", "latest.json")) ? { next: "if `himi push` then refuses the attestation as stale, re-run `himi test` \u2014 in a git checkout this refresh changed the tree it covered" } : {},
185709
186504
  ...res.skipped.length ? { skipped: res.skipped } : {},
185710
186505
  portalUrl: idx.portalUrl
185711
186506
  });
@@ -185728,7 +186523,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
185728
186523
  try {
185729
186524
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
185730
186525
  const bres = await buildContentForValidation2(dir, { resolution });
185731
- out2 = mkdtempSync6(join91(tmpdir7(), "himi-ux-record-"));
186526
+ out2 = mkdtempSync6(join94(tmpdir7(), "himi-ux-record-"));
185732
186527
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
185733
186528
  const outcome = await buildReleaseFromContent2(dir, out2, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
185734
186529
  const releaseId = outcome.manifest.releaseId;
@@ -185900,14 +186695,14 @@ async function producedWidgetFamilies(dir) {
185900
186695
  } catch {
185901
186696
  return { families: void 0, source: "unbuilt" };
185902
186697
  }
185903
- const names = [...tier5Dir.servedBundleNames(outDir)];
186698
+ const names2 = [...tier5Dir.servedBundleNames(outDir)];
185904
186699
  const families = /* @__PURE__ */ new Set();
185905
186700
  const emitted = /* @__PURE__ */ new Set();
185906
- for (const name of names) {
186701
+ for (const name of names2) {
185907
186702
  let js2;
185908
186703
  for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
185909
186704
  try {
185910
- js2 = readFileSync107(join91(outDir, candidate), "utf8");
186705
+ js2 = readFileSync109(join94(outDir, candidate), "utf8");
185911
186706
  break;
185912
186707
  } catch {
185913
186708
  }
@@ -185938,7 +186733,7 @@ async function producedWidgetFamilies(dir) {
185938
186733
  }
185939
186734
  return { families, source: "dist/bundles" };
185940
186735
  }
185941
- var boardOpen = (dir) => existsSync85(join91(dir, ".himi", "studio", "index.html"));
186736
+ var boardOpen = (dir) => existsSync88(join94(dir, ".himi", "studio", "index.html"));
185942
186737
  var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
185943
186738
  async function leaveForBoard(dir, record2, value) {
185944
186739
  if (!boardOpen(dir)) return;
@@ -185962,7 +186757,7 @@ async function liveMapFor(dir) {
185962
186757
  }
185963
186758
  var commandScratch = new AsyncLocalStorage2();
185964
186759
  function commandScratchDir(prefix) {
185965
- const dir = mkdtempSync6(join91(tmpdir7(), prefix));
186760
+ const dir = mkdtempSync6(join94(tmpdir7(), prefix));
185966
186761
  commandScratch.getStore()?.push(dir);
185967
186762
  return dir;
185968
186763
  }
@@ -186316,7 +187111,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
186316
187111
  const owed = openApprovals2(readApprovals2(dir).events).length;
186317
187112
  next.push(`carried the planning journal into the app (${carried.join(", ")}${owed ? `; ${owed} approval${owed === 1 ? "" : "s"} still owed` : ""}) \u2014 \`himi progress --brief\` there shows it`);
186318
187113
  }
186319
- const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) => existsSync85(join91(parentDir, f2)));
187114
+ const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f2) => existsSync88(join94(parentDir, f2)));
186320
187115
  if (planInParent.length) {
186321
187116
  next.push(`${planInParent.join(" and ")} in ${parentDir} ${planInParent.length > 1 ? "are" : "is"} not the app's \u2014 if that is the approved plan, move it over the template's boilerplate in ${dir}`);
186322
187117
  }
@@ -186477,13 +187272,13 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
186477
187272
  if (adding) {
186478
187273
  const from = str10(flags.from);
186479
187274
  if (!from) throw new TrimRefusal2('--add <id> needs --from <file> holding the whole new SCREENS entry (` "<id>": { "screenId": "<id>", \u2026 },`)');
186480
- print(adopt.addScreen(dir, adding, readFileSync107(from, "utf8"), { parent: str10(flags.parent), tab: str10(flags.tab), displayName: str10(flags["display-name"]) }));
187275
+ print(adopt.addScreen(dir, adding, readFileSync109(from, "utf8"), { parent: str10(flags.parent), tab: str10(flags.tab), displayName: str10(flags["display-name"]) }));
186481
187276
  return 0;
186482
187277
  }
186483
187278
  if (target) {
186484
187279
  const from = str10(flags.from);
186485
187280
  if (!from) throw new TrimRefusal2("--write <id> needs --from <file> holding the whole entry, as --show prints it");
186486
- print(adopt.replaceScreen(dir, target, readFileSync107(from, "utf8")));
187281
+ print(adopt.replaceScreen(dir, target, readFileSync109(from, "utf8")));
186487
187282
  return 0;
186488
187283
  }
186489
187284
  if (show) {
@@ -186565,7 +187360,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
186565
187360
  const { keepFromSpec: keepFromSpec2 } = await Promise.resolve().then(() => (init_template_adopt(), template_adopt_exports));
186566
187361
  const dir = contentDir(flags);
186567
187362
  try {
186568
- const spec = keepFromSpec2(dir, str10(flags["from-spec"]) ?? join91(dir, "SPEC.md"));
187363
+ const spec = keepFromSpec2(dir, str10(flags["from-spec"]) ?? join94(dir, "SPEC.md"));
186569
187364
  const own5 = typeof keep === "string" ? keep.split(",").map((k2) => k2.trim()).filter(Boolean) : [];
186570
187365
  keep = [.../* @__PURE__ */ new Set([...spec.keep, ...own5])].join(",");
186571
187366
  fromSpec = { fromSpec: {
@@ -186606,7 +187401,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
186606
187401
  const result = { ...outcome.result, ...fromSpec };
186607
187402
  const adoptDir = contentDir(flags);
186608
187403
  const kept = flags["dry-run"] !== true && (outcome.code === 0 || outcome.result.forcedKeep === true);
186609
- if (kept && existsSync85(join91(adoptDir, adoptBits.ADOPT_FILE))) {
187404
+ if (kept && existsSync88(join94(adoptDir, adoptBits.ADOPT_FILE))) {
186610
187405
  try {
186611
187406
  const inv = adoptBits.inspectApp(adoptDir);
186612
187407
  adoptBits.writeInventory(adoptDir, inv, { companions: "if-missing" });
@@ -186635,7 +187430,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
186635
187430
  const sourceDir = resolve65(str10(flags["source-dir"]) ?? appDir3);
186636
187431
  let meta;
186637
187432
  try {
186638
- meta = JSON.parse(readFileSync107(join91(sourceDir, TEMPLATE_META_FILE), "utf8"));
187433
+ meta = JSON.parse(readFileSync109(join94(sourceDir, TEMPLATE_META_FILE), "utf8"));
186639
187434
  } catch {
186640
187435
  io2.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
186641
187436
  return 2;
@@ -186645,7 +187440,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
186645
187440
  return 2;
186646
187441
  }
186647
187442
  try {
186648
- const appearance = extractTemplateAppearance(JSON.parse(readFileSync107(join91(sourceDir, "tokens.json"), "utf8")));
187443
+ const appearance = extractTemplateAppearance(JSON.parse(readFileSync109(join94(sourceDir, "tokens.json"), "utf8")));
186649
187444
  meta = { ...appearance, ...meta };
186650
187445
  } catch {
186651
187446
  }
@@ -186667,7 +187462,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
186667
187462
  const force = flags.force === true;
186668
187463
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
186669
187464
  const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
186670
- const out2 = mkdtempSync6(join91(tmpdir7(), "himi-template-"));
187465
+ const out2 = mkdtempSync6(join94(tmpdir7(), "himi-template-"));
186671
187466
  publishScratch.push(out2);
186672
187467
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
186673
187468
  const outcome = await buildReleaseFromContent2(buildDir, out2, {
@@ -186729,7 +187524,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
186729
187524
  let iconHash;
186730
187525
  if (iconPath) {
186731
187526
  try {
186732
- const bytes2 = readFileSync107(iconPath);
187527
+ const bytes2 = readFileSync109(iconPath);
186733
187528
  payload.icon = bytes2.toString("base64");
186734
187529
  iconHash = createHash46("sha256").update(bytes2).digest("hex");
186735
187530
  } catch {
@@ -187034,7 +187829,7 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
187034
187829
  const path2 = dpxSessionTokenPath();
187035
187830
  let raw;
187036
187831
  try {
187037
- raw = readFileSync107(path2, "utf8");
187832
+ raw = readFileSync109(path2, "utf8");
187038
187833
  } catch {
187039
187834
  throw new Error(`no DPX BO session at ${path2}; run dpx auth login, write dpx auth token to that path, then himi login --dpx --target bo`);
187040
187835
  }
@@ -187168,8 +187963,8 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
187168
187963
  const dir = resolve65(out2);
187169
187964
  const files = himiPluginFiles2(skills.skillMd);
187170
187965
  for (const f2 of files) {
187171
- mkdirSync44(dirname51(join91(dir, f2.path)), { recursive: true });
187172
- writeFileSync42(join91(dir, f2.path), f2.text);
187966
+ mkdirSync44(dirname51(join94(dir, f2.path)), { recursive: true });
187967
+ writeFileSync44(join94(dir, f2.path), f2.text);
187173
187968
  }
187174
187969
  print({ ok: true, dir, files: files.map((f2) => f2.path), next: [`claude plugin validate ${dir}`, `claude --plugin-dir ${dir}`] });
187175
187970
  return 0;
@@ -187186,16 +187981,16 @@ ${doNow.map((l2) => ` ${l2}`).join("\n")}`);
187186
187981
  case "studio": {
187187
187982
  const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
187188
187983
  const dir = contentDir(flags);
187189
- if (!existsSync85(join91(dir, "himalaya.content.json"))) {
187984
+ if (!existsSync88(join94(dir, "himalaya.content.json"))) {
187190
187985
  io2.error(JSON.stringify({ ok: false, error: "not_a_content_package", dir, hint: "run from the app directory (or pass --content <dir>) \u2014 the board reads that package's .himi/" }));
187191
187986
  return 2;
187192
187987
  }
187193
187988
  if (pos[1] === "reel") {
187194
187989
  const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
187195
- const out2 = resolve65(str10(flags.out) ?? join91(dir, ".himi", "making-of.html"));
187990
+ const out2 = resolve65(str10(flags.out) ?? join94(dir, ".himi", "making-of.html"));
187196
187991
  const { html, plan } = buildReel2(dir);
187197
187992
  mkdirSync44(dirname51(out2), { recursive: true });
187198
- writeFileSync42(out2, html);
187993
+ writeFileSync44(out2, html);
187199
187994
  const { pathToFileURL: pathToFileURL9 } = await import("node:url");
187200
187995
  const url2 = pathToFileURL9(out2).href;
187201
187996
  const open2 = flags["no-open"] !== true;
@@ -187264,7 +188059,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
187264
188059
  } = await Promise.resolve().then(() => (init_progress(), progress_exports));
187265
188060
  const dir = contentDir(flags);
187266
188061
  const journal2 = journalPath2(dir);
187267
- const isContentPackage = existsSync85(join91(dir, "himalaya.content.json"));
188062
+ const isContentPackage = existsSync88(join94(dir, "himalaya.content.json"));
187268
188063
  const hint = isContentPackage ? {} : { hint: "no himalaya.content.json here \u2014 run from the app directory (or pass --content <dir>) so the build board finds this journal" };
187269
188064
  const message = pos.slice(1).join(" ").trim();
187270
188065
  const approvalFlags = ["approve", "done", "drop"].filter((f2) => flags[f2] !== void 0);
@@ -187416,7 +188211,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
187416
188211
  case "test": {
187417
188212
  const dir = contentDir(flags);
187418
188213
  const structuredOutput = flags.json === true || io2.isTTY !== true;
187419
- if (existsSync85(join91(dir, "functions"))) {
188214
+ if (existsSync88(join94(dir, "functions"))) {
187420
188215
  const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
187421
188216
  const loaded = await loadFunctionsApp2(dir);
187422
188217
  const results = [];
@@ -187548,7 +188343,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
187548
188343
  io2.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
187549
188344
  return 2;
187550
188345
  }
187551
- const sources = collectWorkerSources2(join91(dir, "tier5-src"), screen.bundleName);
188346
+ const sources = collectWorkerSources2(join94(dir, "tier5-src"), screen.bundleName);
187552
188347
  if (!sources) {
187553
188348
  io2.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
187554
188349
  return 2;
@@ -187728,7 +188523,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
187728
188523
  const sp = await runShotsPass2({
187729
188524
  descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
187730
188525
  tokens: outcome.tokens,
187731
- outDir: join91(dir, ".himi", "shots"),
188526
+ outDir: join94(dir, ".himi", "shots"),
187732
188527
  width: 390,
187733
188528
  layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {}, ...base44Data ? { base44Data } : {} },
187734
188529
  ...budgetMs ? { budgetMs } : {},
@@ -187768,7 +188563,7 @@ ${handover.hint[0].toUpperCase()}${handover.hint.slice(1)}.`);
187768
188563
  releaseId: result.releaseId,
187769
188564
  releasePayload: release2,
187770
188565
  descriptors: attestedDescriptors,
187771
- screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join91(dir, ".himi", "shots", name)])),
188566
+ screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join94(dir, ".himi", "shots", name)])),
187772
188567
  coverage: {
187773
188568
  screens: crawledScreens.size,
187774
188569
  actionsDispatched: result.actions.exercised,
@@ -187893,7 +188688,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
187893
188688
  return 2;
187894
188689
  }
187895
188690
  try {
187896
- const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync107(stateArg.replace(/^@/, ""), "utf8");
188691
+ const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync109(stateArg.replace(/^@/, ""), "utf8");
187897
188692
  injectedState = JSON.parse(raw);
187898
188693
  } catch (e2) {
187899
188694
  io2.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e2.message}` }));
@@ -187908,7 +188703,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
187908
188703
  return 2;
187909
188704
  }
187910
188705
  try {
187911
- const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync107(inputArg.replace(/^@/, ""), "utf8");
188706
+ const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync109(inputArg.replace(/^@/, ""), "utf8");
187912
188707
  const parsed = JSON.parse(raw);
187913
188708
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
187914
188709
  injectedInput = parsed;
@@ -187991,7 +188786,7 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
187991
188786
  const diagnostics = (outcome.lint ?? []).find((s2) => s2.screenId === screenId)?.issues ?? [];
187992
188787
  let pngFile;
187993
188788
  let attestationPngFile;
187994
- const shotPath = join91(dir, ".himi", "shots", `${screenId}.png`);
188789
+ const shotPath = join94(dir, ".himi", "shots", `${screenId}.png`);
187995
188790
  const pngTarget = typeof flags.png === "string" ? str10(flags.png) : flags.png === true ? shotPath : void 0;
187996
188791
  if (pngTarget && r2.pngBase64) {
187997
188792
  pngFile = writePngFile(pngTarget, r2.pngBase64);
@@ -188213,14 +189008,14 @@ ${[...afterRun.next, ...testReminder ? [testReminder] : []].join("\n")}`);
188213
189008
  return report3(res.status, { wrote: res.wrote });
188214
189009
  }
188215
189010
  if (sub === "glyphs") {
188216
- const names = glyphNames2();
189011
+ const names2 = glyphNames2();
188217
189012
  if (flags.json === true) {
188218
- print({ ok: true, count: names.length, default: DEFAULT_GLYPH2, glyphs: names });
189013
+ print({ ok: true, count: names2.length, default: DEFAULT_GLYPH2, glyphs: names2 });
188219
189014
  return 0;
188220
189015
  }
188221
189016
  io2.log(
188222
- `${names.length} glyphs for \`himi icon generate --glyph\`:
188223
- ${names.join(", ")}
189017
+ `${names2.length} glyphs for \`himi icon generate --glyph\`:
189018
+ ${names2.join(", ")}
188224
189019
  default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so the tile does not assert a business the app is not in`
188225
189020
  );
188226
189021
  return 0;
@@ -188325,14 +189120,14 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
188325
189120
  }
188326
189121
  case "icons": {
188327
189122
  const { knownIconNames } = await loadAuthoring();
188328
- const names = [...knownIconNames].sort();
189123
+ const names2 = [...knownIconNames].sort();
188329
189124
  if (flags.json === true) {
188330
- print({ ok: true, count: names.length, icons: names });
189125
+ print({ ok: true, count: names2.length, icons: names2 });
188331
189126
  return 0;
188332
189127
  }
188333
- io2.log(`${names.length} icon names \u2014 use one as Icon.name (an unknown name renders a fallback glyph):
189128
+ io2.log(`${names2.length} icon names \u2014 use one as Icon.name (an unknown name renders a fallback glyph):
188334
189129
  `);
188335
- io2.log(names.join(" "));
189130
+ io2.log(names2.join(" "));
188336
189131
  return 0;
188337
189132
  }
188338
189133
  case "pull": {
@@ -188350,7 +189145,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
188350
189145
  io2.error(JSON.stringify(linked));
188351
189146
  return 1;
188352
189147
  }
188353
- if (existsSync85(dest)) {
189148
+ if (existsSync88(dest)) {
188354
189149
  if (!statSync23(dest).isDirectory()) {
188355
189150
  io2.error(JSON.stringify({
188356
189151
  error: `${dest} exists and is not a directory`,
@@ -188363,7 +189158,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
188363
189158
  io2.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
188364
189159
  return 1;
188365
189160
  }
188366
- if (replace && occupied && !existsSync85(join91(dest, "himalaya.content.json"))) {
189161
+ if (replace && occupied && !existsSync88(join94(dest, "himalaya.content.json"))) {
188367
189162
  io2.error(JSON.stringify({
188368
189163
  error: `${dest} is not a content package \u2014 refusing to --replace it`,
188369
189164
  hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
@@ -189076,7 +189871,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189076
189871
  }
189077
189872
  const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
189078
189873
  const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
189079
- const built = mkdtempSync6(join91(tmpdir7(), "himi-pack-"));
189874
+ const built = mkdtempSync6(join94(tmpdir7(), "himi-pack-"));
189080
189875
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
189081
189876
  const outcome = await buildReleaseFromContent2(dir, built, {
189082
189877
  ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
@@ -189289,7 +190084,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189289
190084
  }));
189290
190085
  return 1;
189291
190086
  }
189292
- const archive = readFileSync107(resolve65(file2));
190087
+ const archive = readFileSync109(resolve65(file2));
189293
190088
  const result = await client2().createPackageShare({
189294
190089
  app: opened.header.app,
189295
190090
  releaseId: opened.header.releaseId,
@@ -189386,11 +190181,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189386
190181
  const app = await appId(dir2);
189387
190182
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
189388
190183
  const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
189389
- temp = mkdtempSync6(join91(tmpdir7(), "himi-run-build-"));
190184
+ temp = mkdtempSync6(join94(tmpdir7(), "himi-run-build-"));
189390
190185
  const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
189391
190186
  const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
189392
190187
  servedMissing = initial.missingBundles;
189393
- source = join91(temp, app);
190188
+ source = join94(temp, app);
189394
190189
  }
189395
190190
  const chromeArg = str10(flags.chrome) ?? "preview";
189396
190191
  if (chromeArg !== "preview" && chromeArg !== "app") {
@@ -189429,7 +190224,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189429
190224
  if (!recordKit) return;
189430
190225
  startedAt = (/* @__PURE__ */ new Date()).toISOString();
189431
190226
  const failure = record2(served2, { ok: true, at: startedAt });
189432
- if (!recorded) io2.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join91(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
190227
+ if (!recorded) io2.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join94(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
189433
190228
  await refreshBoard();
189434
190229
  };
189435
190230
  const retract = async () => {
@@ -189465,7 +190260,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189465
190260
  const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
189466
190261
  const hhpPreviewRoute = watch2 ? (await Promise.resolve().then(() => (init_hhp_preview(), hhp_preview_exports))).hhpPreviewResponse : null;
189467
190262
  const bus = watchKit ? new watchKit.ReloadBus() : void 0;
189468
- if (watch2) served = mkdtempSync6(join91(tmpdir7(), "himi-run-served-"));
190263
+ if (watch2) served = mkdtempSync6(join94(tmpdir7(), "himi-run-served-"));
189469
190264
  const running = await runPackage2(source, {
189470
190265
  port,
189471
190266
  chrome: chromeArg,
@@ -189494,8 +190289,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189494
190289
  await announce(running);
189495
190290
  if (watchKit && bus) {
189496
190291
  const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
189497
- const live3 = join91(running.releaseRoot, running.app);
189498
- const manifestOf = (tree) => JSON.parse(readFileSync107(join91(tree, "release-manifest.json"), "utf8"));
190292
+ const live3 = join94(running.releaseRoot, running.app);
190293
+ const manifestOf = (tree) => JSON.parse(readFileSync109(join94(tree, "release-manifest.json"), "utf8"));
189499
190294
  let current = manifestOf(live3);
189500
190295
  const failed3 = async (message) => {
189501
190296
  if (stopping) return;
@@ -189506,7 +190301,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189506
190301
  };
189507
190302
  rebuild = watchKit.serialize(async () => {
189508
190303
  const t0 = Date.now();
189509
- const next = mkdtempSync6(join91(tmpdir7(), "himi-run-build-"));
190304
+ const next = mkdtempSync6(join94(tmpdir7(), "himi-run-build-"));
189510
190305
  try {
189511
190306
  const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
189512
190307
  if (bres.compileErrors.length) {
@@ -189523,16 +190318,16 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
189523
190318
  return;
189524
190319
  }
189525
190320
  if (stopping) return;
189526
- const fresh = manifestOf(join91(next, running.app));
190321
+ const fresh = manifestOf(join94(next, running.app));
189527
190322
  const diff = watchKit.diffReleases(current, fresh);
189528
190323
  const { describeChanges: describeChanges2, headline: headline2 } = await Promise.resolve().then(() => (init_build_changes(), build_changes_exports));
189529
- const changes = describeChanges2(live3, join91(next, running.app), diff);
190324
+ const changes = describeChanges2(live3, join94(next, running.app), diff);
189530
190325
  const retired = `${live3}.retired-${Date.now()}`;
189531
190326
  renameSync13(live3, retired);
189532
190327
  try {
189533
- renameSync13(join91(next, running.app), live3);
190328
+ renameSync13(join94(next, running.app), live3);
189534
190329
  } catch {
189535
- cpSync3(join91(next, running.app), live3, { recursive: true });
190330
+ cpSync3(join94(next, running.app), live3, { recursive: true });
189536
190331
  }
189537
190332
  rmSync24(retired, { recursive: true, force: true });
189538
190333
  current = fresh;
@@ -190159,7 +190954,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
190159
190954
  io2.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
190160
190955
  return 2;
190161
190956
  }
190162
- if (!existsSync85(file2)) {
190957
+ if (!existsSync88(file2)) {
190163
190958
  io2.error(JSON.stringify({ error: `no such file: ${file2}` }));
190164
190959
  return 2;
190165
190960
  }
@@ -190215,7 +191010,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
190215
191010
  lintNote: "`himi patch` sends a raw file. Nothing here built or linted your app \u2014 `himi push --only <selector>` is the same edit with the full lint gate in front of it."
190216
191011
  };
190217
191012
  if (kind === "tokens" || kind === "app-config") {
190218
- const body = readFileSync107(file2, "utf8");
191013
+ const body = readFileSync109(file2, "utf8");
190219
191014
  const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
190220
191015
  return runReleasePatch({
190221
191016
  ...common,
@@ -190230,7 +191025,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
190230
191025
  io2.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
190231
191026
  return 2;
190232
191027
  }
190233
- const descriptor = readFileSync107(file2, "utf8");
191028
+ const descriptor = readFileSync109(file2, "utf8");
190234
191029
  let parsed;
190235
191030
  try {
190236
191031
  parsed = JSON.parse(descriptor);
@@ -190287,7 +191082,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
190287
191082
  extra: { kind, screen: id, file: { path: file2, bytes: Buffer.byteLength(descriptor, "utf8") } }
190288
191083
  });
190289
191084
  }
190290
- const bytes2 = readFileSync107(file2);
191085
+ const bytes2 = readFileSync109(file2);
190291
191086
  const sha2 = createHash46("sha256").update(bytes2).digest("hex");
190292
191087
  const forScreens = (str10(flags["for-screen"]) ?? "").split(",").map((s2) => s2.trim()).filter(Boolean);
190293
191088
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
@@ -190431,7 +191226,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
190431
191226
  }
190432
191227
  let def;
190433
191228
  try {
190434
- const parsed = JSON.parse(arg.startsWith("@") ? readFileSync107(arg.slice(1), "utf8") : arg);
191229
+ const parsed = JSON.parse(arg.startsWith("@") ? readFileSync109(arg.slice(1), "utf8") : arg);
190435
191230
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
190436
191231
  io2.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
190437
191232
  return 2;
@@ -190713,7 +191508,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
190713
191508
  const rememberLastDist = async (jobs2) => {
190714
191509
  try {
190715
191510
  const dir = contentDir(flags);
190716
- if (!existsSync85(join91(dir, "himalaya.content.json"))) return;
191511
+ if (!existsSync88(join94(dir, "himalaya.content.json"))) return;
190717
191512
  const { lastDistFromJob: lastDistFromJob2, writeLastDist: writeLastDist2 } = await Promise.resolve().then(() => (init_capabilities(), capabilities_exports));
190718
191513
  const own5 = await appId(dir);
190719
191514
  for (const job of jobs2) {
@@ -190953,7 +191748,7 @@ ${label3}`);
190953
191748
  const platform = str10(flags.platform)?.split(",").map((p2) => p2.trim()).filter(Boolean);
190954
191749
  {
190955
191750
  const distDir = contentDir(flags);
190956
- if (existsSync85(join91(distDir, "himalaya.content.json"))) {
191751
+ if (existsSync88(join94(distDir, "himalaya.content.json"))) {
190957
191752
  const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
190958
191753
  const errors = issues.filter((i2) => i2.severity === "error");
190959
191754
  for (const i2 of issues.filter((i3) => i3.severity === "warning")) {
@@ -191293,7 +192088,7 @@ ${label3}`);
191293
192088
  const dpxPath = dpxSessionTokenPath();
191294
192089
  let dpx;
191295
192090
  try {
191296
- dpx = readFileSync107(dpxPath, "utf8").trim();
192091
+ dpx = readFileSync109(dpxPath, "utf8").trim();
191297
192092
  } catch {
191298
192093
  io2.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
191299
192094
  return 1;
@@ -191756,7 +192551,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
191756
192551
  const path2 = dpxSessionTokenPath();
191757
192552
  let raw;
191758
192553
  try {
191759
- raw = readFileSync107(path2, "utf8");
192554
+ raw = readFileSync109(path2, "utf8");
191760
192555
  } catch {
191761
192556
  io2.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
191762
192557
  return 1;
@@ -191950,7 +192745,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
191950
192745
  }
191951
192746
  }
191952
192747
  const sub = pos[1];
191953
- const b44Usage = "himi base44 analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | himi base44 adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | himi base44 entities query [--content <dir>] [--all] [--json] | himi base44 types [--content <dir>] [--json] | himi base44 screens [--content <dir>] [--force] [--dry-run] [--json] | himi base44 login [--from-base44-cli] | himi base44 whoami | himi base44 logout";
192748
+ const b44Usage = "himi base44 analyze (--url <https://\u2026> | --app-id <id>) [--out .himi/base44-book] [--sample <n>] [--json] | himi base44 adopt [--book .himi/base44-book] [--entities A,B] [--write [path]] [--json] | himi base44 entities query [--content <dir>] [--all] [--json] | himi base44 entities create [--app <a> | --content <dir>] [--yes] [--allow-destructive] [--apply-permissions] [--empty-app-ok] | himi base44 entities seed [--app <a> | --content <dir>] [--yes] [--only A,B] [--ai [--count <n>]] | himi base44 functions deploy [--app <a> | --content <dir>] [--yes] [--only a,b] | himi base44 types [--content <dir>] [--json] | himi base44 screens [--content <dir>] [--force] [--dry-run] [--json] | himi base44 login [--write] [--from-base44-cli] | himi base44 whoami | himi base44 logout";
191954
192749
  if (sub === "adopt") {
191955
192750
  const { runBase44Adopt: runBase44Adopt2, AdoptError: AdoptError2 } = await Promise.resolve().then(() => (init_base44_adopt(), base44_adopt_exports));
191956
192751
  const dir = contentDir(flags);
@@ -192004,7 +192799,7 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
192004
192799
  return 1;
192005
192800
  };
192006
192801
  const gen = await Promise.resolve().then(() => (init_generate(), generate_exports));
192007
- const missing = gen.ENGINE_FILES.filter((f2) => !existsSync85(join91(dir, f2)));
192802
+ const missing = gen.ENGINE_FILES.filter((f2) => !existsSync88(join94(dir, f2)));
192008
192803
  if (missing.length) {
192009
192804
  return fail6("content_dir_not_base44_starter", `${dir} is not a base44-starter content package: the generated screens import a shared engine it does not have (${missing.join(", ")})`, { missing, hint: "scaffold one with `himi init <name> --template base44-starter --base44-app-id <id>`" });
192010
192805
  }
@@ -192056,12 +192851,37 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
192056
192851
  });
192057
192852
  return 0;
192058
192853
  }
192059
- if (sub === "entities") {
192060
- if (pos[2] !== "query") {
192061
- io2.error(JSON.stringify({ ok: false, code: "unknown_subcommand", error: pos[2] ? `unknown base44 entities subcommand "${pos[2]}" \u2014 use query` : "base44 entities needs a subcommand: query", usage: b44Usage }));
192854
+ const provisioning = sub === "entities" && (pos[2] === "create" || pos[2] === "seed") || sub === "functions";
192855
+ if (provisioning && flags.only !== void 0 && !str10(flags.only)?.split(",").some((n2) => n2.trim())) {
192856
+ io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: "--only needs a comma-separated list of names", usage: b44Usage }));
192857
+ return 2;
192858
+ }
192859
+ if (sub === "entities" && pos[2] === "create" && flags.only !== void 0) {
192860
+ io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: "entities create takes no --only: Base44's schema write is one full-set sync, so it always reconciles every owned entity", usage: b44Usage }));
192861
+ return 2;
192862
+ }
192863
+ if (sub === "functions" && pos[2] !== "deploy") {
192864
+ io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: pos[2] ? `unknown base44 functions subcommand "${pos[2]}" \u2014 use deploy` : "base44 functions needs a subcommand: deploy", usage: b44Usage }));
192865
+ return 2;
192866
+ }
192867
+ const b44Dir = () => {
192868
+ const slug = str10(flags.app);
192869
+ if (!provisioning || str10(flags.content) !== void 0 || !slug) return contentDir(flags);
192870
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(slug)) return void 0;
192871
+ const dir = resolve65("apps", slug);
192872
+ return existsSync88(join94(dir, "config.ts")) || existsSync88(join94(dir, "config.mjs")) ? dir : void 0;
192873
+ };
192874
+ if (sub === "entities" || sub === "functions") {
192875
+ if (sub === "entities" && !["query", "create", "seed"].includes(pos[2] ?? "")) {
192876
+ io2.error(JSON.stringify({ ok: false, code: "unknown_subcommand", error: pos[2] ? `unknown base44 entities subcommand "${pos[2]}" \u2014 use query | create | seed` : "base44 entities needs a subcommand: query | create | seed", usage: b44Usage }));
192062
192877
  return 2;
192063
192878
  }
192064
- const dir = contentDir(flags);
192879
+ const resolvedDir = b44Dir();
192880
+ if (!resolvedDir) {
192881
+ io2.error(JSON.stringify({ ok: false, code: "invalid_usage", error: `--app ${str10(flags.app)}: no apps/${str10(flags.app)}/config.ts under ${process.cwd()}`, hint: "run from the repo root, or pass --content <app dir>", usage: b44Usage }));
192882
+ return 2;
192883
+ }
192884
+ const dir = resolvedDir;
192065
192885
  const app = await appId(dir);
192066
192886
  let base44;
192067
192887
  try {
@@ -192077,21 +192897,82 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
192077
192897
  return 1;
192078
192898
  }
192079
192899
  if (!base44 || typeof base44 !== "object") {
192900
+ if (provisioning) {
192901
+ io2.error(JSON.stringify({ ok: false, code: "no_app_id", app, error: "no `base44` block in config.ts \u2014 nothing to provision", hint: "add `base44: { appId, entities, functions }` to config.ts. See `himi docs base44-entities`." }));
192902
+ return 1;
192903
+ }
192080
192904
  print({ ok: true, code: "no_base44_block", app, declared: 0, note: "no `base44` block in config.ts \u2014 nothing to query. `himi base44 adopt` writes declarations from a book. See `himi docs base44-entities`." });
192081
192905
  return 0;
192082
192906
  }
192083
192907
  const { validateBase44Entities: validateBase44Entities2 } = await Promise.resolve().then(() => (init_base44_schema(), base44_schema_exports));
192084
192908
  const errors = validateBase44Entities2(base44, app).filter((i2) => i2.severity === "error");
192085
- if (typeof base44.appId !== "string" || !base44.appId) errors.unshift({ severity: "error", ruleCode: "shape-invalid", message: "base44.appId is missing" });
192909
+ if (typeof base44.appId !== "string" || !base44.appId) {
192910
+ if (provisioning) {
192911
+ io2.error(JSON.stringify({ ok: false, code: "no_app_id", app, error: "base44.appId is missing from config.ts", hint: "it is the id in your app's URL: https://app.base44.com/apps/<id>" }));
192912
+ return 1;
192913
+ }
192914
+ errors.unshift({ severity: "error", ruleCode: "shape-invalid", message: "base44.appId is missing" });
192915
+ }
192086
192916
  if (errors.length) {
192087
192917
  io2.error(JSON.stringify({ ok: false, code: "invalid_config", app, issues: errors, hint: '`himi validate` reports these with pass: "base44"' }));
192088
192918
  return 1;
192089
192919
  }
192920
+ if (sub === "entities" && pos[2] === "seed" && flags.ai === true) {
192921
+ const { writeBase44SeedRows: writeBase44SeedRows2 } = await Promise.resolve().then(() => (init_seed(), seed_exports));
192922
+ try {
192923
+ const aiOnly = str10(flags.only)?.split(",").map((n2) => n2.trim()).filter(Boolean);
192924
+ const r2 = writeBase44SeedRows2({ dir, app, entities: base44.entities ?? [], count: Number(str10(flags.count)) || 8, ...aiOnly ? { only: aiOnly } : {} });
192925
+ if (r2.ok) print(r2);
192926
+ else io2.error(JSON.stringify({ ...r2, code: "nothing_to_seed" }));
192927
+ return r2.ok ? 0 : 1;
192928
+ } catch (e2) {
192929
+ io2.error(JSON.stringify({ ok: false, code: "seed_file_invalid", app, error: e2.message }));
192930
+ return 1;
192931
+ }
192932
+ }
192090
192933
  const auth2 = await (await Promise.resolve().then(() => (init_base44_auth(), base44_auth_exports))).usableBase44Auth();
192091
192934
  if (!auth2) {
192092
- io2.error(JSON.stringify({ ok: false, code: "not_signed_in", app, error: "entities query needs a Base44 session: run `himi base44 login` (or set BASE44_ACCESS_TOKEN)" }));
192935
+ io2.error(JSON.stringify({ ok: false, code: "not_signed_in", app, error: `${sub} ${pos[2]} needs a Base44 session: run \`himi base44 login${provisioning ? " --write" : ""}\` (or set BASE44_ACCESS_TOKEN)` }));
192093
192936
  return 2;
192094
192937
  }
192938
+ if (provisioning) {
192939
+ const only = str10(flags.only)?.split(",").map((n2) => n2.trim()).filter(Boolean);
192940
+ const transport = { app, appId: base44.appId, apiFetch: fetch, apiBase: auth2.apiBase, auth: auth2, yes: flags.yes === true };
192941
+ let report4;
192942
+ if (sub === "functions") {
192943
+ const { deployBase44Functions: deployBase44Functions2 } = await Promise.resolve().then(() => (init_functions2(), functions_exports2));
192944
+ report4 = await deployBase44Functions2({ ...transport, appDir: dir, functions: base44.functions ?? [], ...only ? { only } : {} });
192945
+ } else if (pos[2] === "seed") {
192946
+ const { seedBase44Entities: seedBase44Entities2 } = await Promise.resolve().then(() => (init_seed(), seed_exports));
192947
+ const { fileLedger: fileLedger2 } = await Promise.resolve().then(() => (init_apply2(), apply_exports));
192948
+ let provisioned;
192949
+ try {
192950
+ provisioned = fileLedger2(dir, base44.appId).read();
192951
+ } catch (e2) {
192952
+ io2.error(JSON.stringify({ ok: false, code: "ledger_unreadable", app, error: e2.message }));
192953
+ return 1;
192954
+ }
192955
+ report4 = await seedBase44Entities2({ ...transport, entities: base44.entities ?? [], dir, provisioned, ...only ? { only } : {} });
192956
+ } else {
192957
+ const { projectDownloader: projectDownloader3 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
192958
+ const { createBase44Entities: createBase44Entities2, fileLedger: fileLedger2 } = await Promise.resolve().then(() => (init_apply2(), apply_exports));
192959
+ const r2 = await createBase44Entities2({
192960
+ ...transport,
192961
+ ledger: fileLedger2(dir, base44.appId),
192962
+ entities: base44.entities ?? [],
192963
+ download: projectDownloader3(fetch, auth2.apiBase, auth2.token),
192964
+ allowDestructive: flags["allow-destructive"] === true,
192965
+ applyPermissions: flags["apply-permissions"] === true,
192966
+ emptyAppOk: flags["empty-app-ok"] === true
192967
+ });
192968
+ const { next: _next, ...plan } = r2.plan ?? { next: void 0 };
192969
+ report4 = { ...r2, ...r2.plan ? { plan } : {} };
192970
+ }
192971
+ const out2 = { ...report4, ...report4.ok && report4.dryRun ? { next: [`# dry run \u2014 nothing was written. Re-run with --yes to apply.`] } : {} };
192972
+ if (report4.ok) print(out2);
192973
+ else io2.error(JSON.stringify(out2));
192974
+ return report4.ok ? 0 : report4.code === "write_scope_missing" || report4.code === "invalid_usage" ? 2 : 1;
192975
+ }
192095
192976
  const { projectDownloader: projectDownloader2 } = await Promise.resolve().then(() => (init_cli(), cli_exports));
192096
192977
  const { queryBase44Entities: queryBase44Entities2 } = await Promise.resolve().then(() => (init_base44_entities2(), base44_entities_exports));
192097
192978
  const report3 = await queryBase44Entities2({
@@ -192117,6 +192998,8 @@ ${report3.ok ? "OK \u2014 data + serve plane reachable." : typeof report3.hint =
192117
192998
  if (sub === "login") {
192118
192999
  try {
192119
193000
  const r2 = flags["from-base44-cli"] === true ? auth.importBase44CliSession() : await auth.base44DeviceLogin({
193001
+ // #4558: --write mints the apps:write session the provisioning verbs need.
193002
+ ...flags.write === true ? { scope: auth.BASE44_WRITE_SCOPE } : {},
192120
193003
  io: {
192121
193004
  prompt: async ({ verificationUri, userCode }) => {
192122
193005
  io2.error(`Approve this sign-in in your browser: ${verificationUri}