@wix/himalaya-cli 0.1069.0 → 0.1070.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 +668 -459
- package/guides/headless-loop.md +9 -4
- package/guides/skill.md +11 -3
- package/package.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -3957,8 +3957,8 @@ function committedProvisioningPath(name) {
|
|
|
3957
3957
|
function committedShellFor(path2) {
|
|
3958
3958
|
const normalized = path2.replace(/\\/g, "/");
|
|
3959
3959
|
return SHELL_NAMES2.find((name) => {
|
|
3960
|
-
const
|
|
3961
|
-
return normalized ===
|
|
3960
|
+
const relative13 = committedProvisioningPath(name);
|
|
3961
|
+
return normalized === relative13 || normalized.endsWith(`/${relative13}`);
|
|
3962
3962
|
});
|
|
3963
3963
|
}
|
|
3964
3964
|
function isBrandable(repoRoot2, name) {
|
|
@@ -17420,15 +17420,20 @@ var init_gen_native_config = __esm({
|
|
|
17420
17420
|
// src/progress.ts
|
|
17421
17421
|
var progress_exports = {};
|
|
17422
17422
|
__export(progress_exports, {
|
|
17423
|
+
AGENT_WINS_WITHIN_MS: () => AGENT_WINS_WITHIN_MS,
|
|
17423
17424
|
APPROVALS_FILE: () => APPROVALS_FILE,
|
|
17424
17425
|
APPROVAL_GATES: () => APPROVAL_GATES,
|
|
17426
|
+
AUTO_MILESTONES: () => AUTO_MILESTONES,
|
|
17427
|
+
CLI_AUTHOR: () => CLI_AUTHOR,
|
|
17425
17428
|
HISTORY_DIR: () => HISTORY_DIR,
|
|
17426
17429
|
JOURNEY_STEPS: () => JOURNEY_STEPS,
|
|
17427
17430
|
MAX_IMAGE_BYTES: () => MAX_IMAGE_BYTES,
|
|
17428
17431
|
MAX_MESSAGE_CHARS: () => MAX_MESSAGE_CHARS,
|
|
17432
|
+
MILESTONE_STEP: () => MILESTONE_STEP,
|
|
17429
17433
|
PROGRESS_FILE: () => PROGRESS_FILE,
|
|
17430
17434
|
ProgressError: () => ProgressError,
|
|
17431
17435
|
UnsafeHimiDirError: () => UnsafeHimiDirError,
|
|
17436
|
+
agentCovers: () => agentCovers,
|
|
17432
17437
|
appLabel: () => appLabel,
|
|
17433
17438
|
appendApproval: () => appendApproval,
|
|
17434
17439
|
appendProgress: () => appendProgress,
|
|
@@ -17438,7 +17443,10 @@ __export(progress_exports, {
|
|
|
17438
17443
|
carryPlanningJournal: () => carryPlanningJournal,
|
|
17439
17444
|
formatBrief: () => formatBrief,
|
|
17440
17445
|
imageExtension: () => imageExtension,
|
|
17446
|
+
isCliEntry: () => isCliEntry,
|
|
17447
|
+
journalMilestone: () => journalMilestone,
|
|
17441
17448
|
journalPath: () => journalPath,
|
|
17449
|
+
looksSecret: () => looksSecret,
|
|
17442
17450
|
notifyDesktop: () => notifyDesktop,
|
|
17443
17451
|
openApprovals: () => openApprovals,
|
|
17444
17452
|
parseApprovalRef: () => parseApprovalRef,
|
|
@@ -17448,13 +17456,26 @@ __export(progress_exports, {
|
|
|
17448
17456
|
readProgress: () => readProgress,
|
|
17449
17457
|
realDirIn: () => realDirIn,
|
|
17450
17458
|
summarizeProgress: () => summarizeProgress,
|
|
17459
|
+
visibleEntries: () => visibleEntries,
|
|
17451
17460
|
writeFileAtomic: () => writeFileAtomic
|
|
17452
17461
|
});
|
|
17453
17462
|
import { spawn as spawn3 } from "node:child_process";
|
|
17454
17463
|
import { createHash as createHash8 } from "node:crypto";
|
|
17455
17464
|
import { randomUUID } from "node:crypto";
|
|
17456
17465
|
import { appendFileSync, closeSync, existsSync as existsSync27, lstatSync as lstatSync5, mkdirSync as mkdirSync13, openSync, readdirSync as readdirSync15, readFileSync as readFileSync27, readSync, renameSync as renameSync3, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync12 } from "node:fs";
|
|
17457
|
-
import { join as join30, relative as relative5, resolve as resolve19, sep as sep6 } from "node:path";
|
|
17466
|
+
import { isAbsolute as isAbsolute3, join as join30, relative as relative5, resolve as resolve19, sep as sep6 } from "node:path";
|
|
17467
|
+
function agentCovers(agent, cli) {
|
|
17468
|
+
if (isCliEntry(agent)) return false;
|
|
17469
|
+
const agentShas = shasOf(agent.images);
|
|
17470
|
+
if (!agentShas.size) return false;
|
|
17471
|
+
const gap = Math.abs(Date.parse(agent.ts) - Date.parse(cli.ts));
|
|
17472
|
+
if (!(gap <= AGENT_WINS_WITHIN_MS)) return false;
|
|
17473
|
+
if (cli.step && agent.step === cli.step) return true;
|
|
17474
|
+
return [...shasOf(cli.images)].some((sha) => agentShas.has(sha));
|
|
17475
|
+
}
|
|
17476
|
+
function visibleEntries(entries) {
|
|
17477
|
+
return entries.filter((e) => !isCliEntry(e) || !entries.some((a) => agentCovers(a, e)));
|
|
17478
|
+
}
|
|
17458
17479
|
function parseStep(raw) {
|
|
17459
17480
|
const v = raw.trim().toLowerCase();
|
|
17460
17481
|
if (/^[1-8]$/.test(v)) return JOURNEY_STEPS[Number(v) - 1];
|
|
@@ -17543,12 +17564,13 @@ function appendProgress(dir, input) {
|
|
|
17543
17564
|
`a postcard is a line or two (${message.length} chars; the cap is ${MAX_MESSAGE_CHARS}) \u2014 put the detail in your reply and journal the headline`
|
|
17544
17565
|
);
|
|
17545
17566
|
}
|
|
17546
|
-
const images = (input.images ?? []).map((src) => archiveImage(dir, src));
|
|
17567
|
+
const images = (input.images ?? []).map((src) => archiveImage(dir, src)).map((img) => input.auto ? { ...img, source: packageRelative(dir, img.source) } : img);
|
|
17547
17568
|
const entry = {
|
|
17548
17569
|
ts: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
17549
17570
|
message,
|
|
17550
17571
|
...input.step ? { step: input.step, stepNumber: JOURNEY_STEPS.indexOf(input.step) + 1 } : {},
|
|
17551
|
-
...images.length ? { images } : {}
|
|
17572
|
+
...images.length ? { images } : {},
|
|
17573
|
+
...input.auto ? { by: CLI_AUTHOR, milestone: input.auto.milestone, ...input.auto.ref ? { ref: input.auto.ref } : {} } : {}
|
|
17552
17574
|
};
|
|
17553
17575
|
if (!realDirIn(dir, ".himi")) throw new ProgressError("unsafe_himi_dir", new UnsafeHimiDirError(".himi").message);
|
|
17554
17576
|
const file = join30(dir, PROGRESS_FILE);
|
|
@@ -17557,6 +17579,10 @@ function appendProgress(dir, input) {
|
|
|
17557
17579
|
`);
|
|
17558
17580
|
return entry;
|
|
17559
17581
|
}
|
|
17582
|
+
function packageRelative(dir, p) {
|
|
17583
|
+
const rel = relative5(dir, resolve19(p));
|
|
17584
|
+
return rel && !rel.startsWith("..") && !isAbsolute3(rel) ? toPosix(rel) : p;
|
|
17585
|
+
}
|
|
17560
17586
|
function endsWithNewline(file) {
|
|
17561
17587
|
if (!existsSync27(file)) return true;
|
|
17562
17588
|
const size = statSync5(file).size;
|
|
@@ -17575,7 +17601,7 @@ function isEntry(v) {
|
|
|
17575
17601
|
const e = v;
|
|
17576
17602
|
return typeof e.ts === "string" && typeof e.message === "string";
|
|
17577
17603
|
}
|
|
17578
|
-
function readProgress(dir) {
|
|
17604
|
+
function readProgress(dir, opts = {}) {
|
|
17579
17605
|
const file = join30(dir, PROGRESS_FILE);
|
|
17580
17606
|
if (!existsSync27(file)) return { entries: [], skipped: 0 };
|
|
17581
17607
|
const entries = [];
|
|
@@ -17590,7 +17616,34 @@ function readProgress(dir) {
|
|
|
17590
17616
|
skipped++;
|
|
17591
17617
|
}
|
|
17592
17618
|
}
|
|
17593
|
-
return { entries, skipped };
|
|
17619
|
+
return { entries: opts.all ? entries : visibleEntries(entries), skipped };
|
|
17620
|
+
}
|
|
17621
|
+
function journalMilestone(dir, input) {
|
|
17622
|
+
try {
|
|
17623
|
+
if (looksSecret(input.message) || input.ref !== void 0 && (!REF_SHAPE.test(input.ref) || looksSecret(input.ref))) {
|
|
17624
|
+
return { journaled: false, reason: "unsafe" };
|
|
17625
|
+
}
|
|
17626
|
+
const { entries } = readProgress(dir, { all: true });
|
|
17627
|
+
const ref = input.ref ?? null;
|
|
17628
|
+
if (entries.some((e) => isCliEntry(e) && e.milestone === input.milestone && (e.ref ?? null) === ref)) {
|
|
17629
|
+
return { journaled: false, reason: "already-journaled" };
|
|
17630
|
+
}
|
|
17631
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
17632
|
+
const step = MILESTONE_STEP[input.milestone];
|
|
17633
|
+
const abs = input.image ? locateImage(dir, input.image) : null;
|
|
17634
|
+
const images = abs ? [{ sha256: createHash8("sha256").update(readFileSync27(abs)).digest("hex") }] : [];
|
|
17635
|
+
if (entries.some((e) => agentCovers(e, { ts: now.toISOString(), step, images }))) return { journaled: false, reason: "agent-journaled" };
|
|
17636
|
+
const entry = appendProgress(dir, {
|
|
17637
|
+
message: input.message,
|
|
17638
|
+
step,
|
|
17639
|
+
...abs ? { images: [abs] } : {},
|
|
17640
|
+
now,
|
|
17641
|
+
auto: { milestone: input.milestone, ...input.ref ? { ref: input.ref } : {} }
|
|
17642
|
+
});
|
|
17643
|
+
return { journaled: true, entry };
|
|
17644
|
+
} catch {
|
|
17645
|
+
return { journaled: false, reason: "failed" };
|
|
17646
|
+
}
|
|
17594
17647
|
}
|
|
17595
17648
|
function parseGate(raw) {
|
|
17596
17649
|
const v = raw.trim().toLowerCase();
|
|
@@ -17721,7 +17774,7 @@ function formatBrief(input) {
|
|
|
17721
17774
|
if (summary.last) lines.push(`Last postcard (${minute(summary.last.ts)}): ${summary.last.message}`);
|
|
17722
17775
|
const pastPlan = (summary.current?.stepNumber ?? 0) > JOURNEY_STEPS.indexOf("plan") + 1;
|
|
17723
17776
|
lines.push(
|
|
17724
|
-
!summary.current ? "
|
|
17777
|
+
!summary.current ? "No journey step recorded yet: a new app starts with discovery (step 1); one whose SPEC.md the customer approved continues from its current state. `himi progress` prints every postcard." : pastPlan ? `Resume at step ${summary.current.stepNumber}. Do not restart discovery: the approved plan is SPEC.md + MOBILE-UX.md.` : `Resume at step ${summary.current.stepNumber}. Implementation has not started: treat SPEC.md + MOBILE-UX.md as a draft unless the journal records the customer approving them.`
|
|
17725
17778
|
);
|
|
17726
17779
|
}
|
|
17727
17780
|
if (open.length) {
|
|
@@ -17735,7 +17788,7 @@ function formatBrief(input) {
|
|
|
17735
17788
|
}
|
|
17736
17789
|
function summarizeProgress(entries) {
|
|
17737
17790
|
if (!entries.length) return { count: 0 };
|
|
17738
|
-
const stepped = [...entries].reverse().find((e) => e.step && JOURNEY_STEPS.includes(e.step));
|
|
17791
|
+
const stepped = [...entries].reverse().find((e) => !isCliEntry(e) && e.step && JOURNEY_STEPS.includes(e.step));
|
|
17739
17792
|
const first = entries[0];
|
|
17740
17793
|
const last = entries[entries.length - 1];
|
|
17741
17794
|
const elapsed = Date.parse(last.ts) - Date.parse(first.ts);
|
|
@@ -17796,10 +17849,16 @@ function journalPath(dir) {
|
|
|
17796
17849
|
const rel = relative5(process.cwd(), abs);
|
|
17797
17850
|
return rel && !rel.startsWith("..") ? rel : abs;
|
|
17798
17851
|
}
|
|
17799
|
-
var JOURNEY_STEPS, PROGRESS_FILE, HISTORY_DIR, APPROVALS_FILE, APPROVAL_GATES, MAX_MESSAGE_CHARS, MAX_IMAGE_BYTES, ProgressError, toPosix, UnsafeHimiDirError, gateLabel, minute, NOTIFY_TIMEOUT_MS;
|
|
17852
|
+
var JOURNEY_STEPS, CLI_AUTHOR, AUTO_MILESTONES, MILESTONE_STEP, AGENT_WINS_WITHIN_MS, isCliEntry, shasOf, PROGRESS_FILE, HISTORY_DIR, APPROVALS_FILE, APPROVAL_GATES, MAX_MESSAGE_CHARS, MAX_IMAGE_BYTES, ProgressError, toPosix, UnsafeHimiDirError, SECRET_SHAPES, looksSecret, REF_SHAPE, gateLabel, minute, NOTIFY_TIMEOUT_MS;
|
|
17800
17853
|
var init_progress = __esm({
|
|
17801
17854
|
"src/progress.ts"() {
|
|
17802
17855
|
JOURNEY_STEPS = ["discover", "classify", "plan", "implement", "brand", "validate", "review", "download"];
|
|
17856
|
+
CLI_AUTHOR = "himi";
|
|
17857
|
+
AUTO_MILESTONES = ["first-look", "test", "draft"];
|
|
17858
|
+
MILESTONE_STEP = { "first-look": "plan", test: "validate", draft: "review" };
|
|
17859
|
+
AGENT_WINS_WITHIN_MS = 5 * 60 * 1e3;
|
|
17860
|
+
isCliEntry = (e) => e.by === CLI_AUTHOR;
|
|
17861
|
+
shasOf = (images) => new Set(Array.isArray(images) ? images.flatMap((i) => i && typeof i === "object" && typeof i.sha256 === "string" ? [i.sha256] : []) : []);
|
|
17803
17862
|
PROGRESS_FILE = join30(".himi", "progress.jsonl");
|
|
17804
17863
|
HISTORY_DIR = join30(".himi", "history");
|
|
17805
17864
|
APPROVALS_FILE = join30(".himi", "approvals.jsonl");
|
|
@@ -17826,6 +17885,17 @@ var init_progress = __esm({
|
|
|
17826
17885
|
super(`${rel} is not a real directory inside the content package (a symlink?) \u2014 refusing to write through it`);
|
|
17827
17886
|
}
|
|
17828
17887
|
};
|
|
17888
|
+
SECRET_SHAPES = [
|
|
17889
|
+
/:\/\//,
|
|
17890
|
+
// any URL: a preview link carries its bearer in the query
|
|
17891
|
+
/[?&#;](?:pvt|h|token|code|handover|key|secret|access_token)=/i,
|
|
17892
|
+
// `?h=` is the handover code
|
|
17893
|
+
/\bpvt[_=-]/i,
|
|
17894
|
+
/\beyJ[A-Za-z0-9_-]{6,}/
|
|
17895
|
+
// a JWT (a control token), whose header always starts `{"`
|
|
17896
|
+
];
|
|
17897
|
+
looksSecret = (s) => SECRET_SHAPES.some((re) => re.test(s));
|
|
17898
|
+
REF_SHAPE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
17829
17899
|
gateLabel = (gate) => APPROVAL_GATES.find((g) => g.id === gate)?.label ?? gate;
|
|
17830
17900
|
minute = (iso) => `${iso.slice(0, 16).replace("T", " ")} UTC`;
|
|
17831
17901
|
NOTIFY_TIMEOUT_MS = 3e3;
|
|
@@ -17894,9 +17964,9 @@ ${after}`;
|
|
|
17894
17964
|
function blockVersion(text5) {
|
|
17895
17965
|
return STAMP_RE.exec(text5)?.[1] ?? null;
|
|
17896
17966
|
}
|
|
17897
|
-
function agentsMdBody(
|
|
17967
|
+
function agentsMdBody(appName2) {
|
|
17898
17968
|
const gates = APPROVAL_GATES.map((g) => `- \`${g.id}\` \u2014 ${g.label}`).join("\n");
|
|
17899
|
-
return `# ${
|
|
17969
|
+
return `# ${appName2 ? `${appName2} \u2014 a Himalaya app` : "A Himalaya app"}
|
|
17900
17970
|
|
|
17901
17971
|
This folder is a Himalaya content package: a native iOS / Android / web app whose screens are data
|
|
17902
17972
|
(JSON descriptors) plus small JavaScript workers, built and shipped with the \`himi\` CLI
|
|
@@ -18957,9 +19027,9 @@ var init_store2 = __esm({
|
|
|
18957
19027
|
Store = class {
|
|
18958
19028
|
_db;
|
|
18959
19029
|
dbPath;
|
|
18960
|
-
constructor(
|
|
19030
|
+
constructor(appName2) {
|
|
18961
19031
|
const dataRoot = process.env.HIMALAYA_DEV_STORE_DIR ? resolve23(process.env.HIMALAYA_DEV_STORE_DIR) : resolve23(ROOT3, "core/dev-server/data");
|
|
18962
|
-
this.dbPath = resolve23(dataRoot, `${
|
|
19032
|
+
this.dbPath = resolve23(dataRoot, `${appName2}.sqlite`);
|
|
18963
19033
|
}
|
|
18964
19034
|
/** The node:sqlite handle — opened, bootstrapped, and seeded on first access. */
|
|
18965
19035
|
get db() {
|
|
@@ -21684,8 +21754,8 @@ var init_net_mocks_rollover = __esm({
|
|
|
21684
21754
|
});
|
|
21685
21755
|
|
|
21686
21756
|
// ../../core/dev-server/src/player-proxy.ts
|
|
21687
|
-
function isPlayerHost(
|
|
21688
|
-
return
|
|
21757
|
+
function isPlayerHost(appName2) {
|
|
21758
|
+
return appName2 === PLAYER_APP_ID || process.env.HIMALAYA_DEV_MULTI_APP === "1";
|
|
21689
21759
|
}
|
|
21690
21760
|
function resolveServeBase() {
|
|
21691
21761
|
const override = process.env.HIMALAYA_PLAYER_SERVE_URL;
|
|
@@ -22933,6 +23003,7 @@ function shouldRevealError(args) {
|
|
|
22933
23003
|
var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
|
|
22934
23004
|
var init_validation = __esm({
|
|
22935
23005
|
"../../core/ts/src/validation.ts"() {
|
|
23006
|
+
"use strict";
|
|
22936
23007
|
EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
22937
23008
|
URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
22938
23009
|
INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
@@ -26533,6 +26604,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
|
|
|
26533
26604
|
var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
|
|
26534
26605
|
var init_worker_subtree = __esm({
|
|
26535
26606
|
"../../core/ts/src/worker-subtree.ts"() {
|
|
26607
|
+
"use strict";
|
|
26536
26608
|
init_worker_subtree_safe_types_generated();
|
|
26537
26609
|
WORKER_SUBTREE_CEILINGS = Object.freeze({
|
|
26538
26610
|
maxEncodedBytes: 65536,
|
|
@@ -33194,8 +33266,8 @@ function clampRule(rule, denyPrefixes, maxTTL) {
|
|
|
33194
33266
|
ttl: Math.min(rule.ttl, maxTTL)
|
|
33195
33267
|
};
|
|
33196
33268
|
}
|
|
33197
|
-
function resolveWixCachePolicy(
|
|
33198
|
-
const appRules = CACHE_OVERRIDES[
|
|
33269
|
+
function resolveWixCachePolicy(appName2) {
|
|
33270
|
+
const appRules = CACHE_OVERRIDES[appName2] ?? [];
|
|
33199
33271
|
const rules = appRules.map((r) => clampRule(r, PLATFORM_DENY_PREFIXES, PLATFORM_MAX_TTL));
|
|
33200
33272
|
return { rules, defaultCacheable: false };
|
|
33201
33273
|
}
|
|
@@ -33313,7 +33385,7 @@ function expandNavBundle(ref, ctx) {
|
|
|
33313
33385
|
};
|
|
33314
33386
|
}
|
|
33315
33387
|
function deriveNavigationConfig(app, bundleCtx) {
|
|
33316
|
-
const
|
|
33388
|
+
const appName2 = app.name;
|
|
33317
33389
|
const concrete = app.screenIds.map((screenId) => ({
|
|
33318
33390
|
screenId,
|
|
33319
33391
|
isPublic: true,
|
|
@@ -33326,7 +33398,7 @@ function deriveNavigationConfig(app, bundleCtx) {
|
|
|
33326
33398
|
const keys = (pat.match(/\{([^}]+)\}/g) ?? []).map((m) => m.slice(1, -1));
|
|
33327
33399
|
return { screenId: base, isPublic: true, paramKeys: keys, parentScreenId: "", tabId: "" };
|
|
33328
33400
|
});
|
|
33329
|
-
const ov = NAV_OVERRIDES[
|
|
33401
|
+
const ov = NAV_OVERRIDES[appName2];
|
|
33330
33402
|
if (ov?.parents) {
|
|
33331
33403
|
for (const s of [...concrete, ...templated]) {
|
|
33332
33404
|
if (ov.parents[s.screenId]) s.parentScreenId = ov.parents[s.screenId];
|
|
@@ -33337,7 +33409,7 @@ function deriveNavigationConfig(app, bundleCtx) {
|
|
|
33337
33409
|
scheme: app.urlScheme,
|
|
33338
33410
|
deepLinkPatterns: app.deepLinkPatterns ?? ov?.deepLinkPatterns ?? [],
|
|
33339
33411
|
linkableScreens,
|
|
33340
|
-
wixCachePolicy: resolveWixCachePolicy(
|
|
33412
|
+
wixCachePolicy: resolveWixCachePolicy(appName2),
|
|
33341
33413
|
// Fail-open baseline; tightened OTA via the admin app-config override. The
|
|
33342
33414
|
// DESTINATION(s) are derived generically from the app's config (no app-name
|
|
33343
33415
|
// special-casing) so the app chooses where telemetry goes via OTA:
|
|
@@ -33415,12 +33487,12 @@ function buildAppConfigDocument(req, meta, override, bundleCtx) {
|
|
|
33415
33487
|
return { config, body, etag, locale };
|
|
33416
33488
|
}
|
|
33417
33489
|
function handleAppConfigRequest(req, res, meta, override, bundleCtx) {
|
|
33418
|
-
const
|
|
33490
|
+
const appName2 = decodeURIComponent(
|
|
33419
33491
|
(req.url ?? "").replace(/^\/v1\/app-config\//, "").split("?")[0]
|
|
33420
33492
|
);
|
|
33421
|
-
if (
|
|
33493
|
+
if (appName2 !== meta.name) {
|
|
33422
33494
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
33423
|
-
res.end(JSON.stringify({ error: "unknown_app", appName }));
|
|
33495
|
+
res.end(JSON.stringify({ error: "unknown_app", appName: appName2 }));
|
|
33424
33496
|
return;
|
|
33425
33497
|
}
|
|
33426
33498
|
const { body, etag, locale } = buildAppConfigDocument(req, meta, override, bundleCtx);
|
|
@@ -36377,7 +36449,7 @@ async function handleToggleEval(req, res, state) {
|
|
|
36377
36449
|
for (const id of requested) out[id] = state.toggles[id] ?? false;
|
|
36378
36450
|
sendJson(res, 200, out);
|
|
36379
36451
|
}
|
|
36380
|
-
function evalContextFromReq(req,
|
|
36452
|
+
function evalContextFromReq(req, appName2) {
|
|
36381
36453
|
const h = (k) => {
|
|
36382
36454
|
const v = req.headers[k];
|
|
36383
36455
|
return typeof v === "string" ? v : void 0;
|
|
@@ -36385,7 +36457,7 @@ function evalContextFromReq(req, appName) {
|
|
|
36385
36457
|
return {
|
|
36386
36458
|
sessionId: h("x-himalaya-session") ?? "dev-session",
|
|
36387
36459
|
userId: h("x-himalaya-user"),
|
|
36388
|
-
appId:
|
|
36460
|
+
appId: appName2,
|
|
36389
36461
|
platform: h("x-himalaya-platform"),
|
|
36390
36462
|
appVersion: h("x-himalaya-app-version"),
|
|
36391
36463
|
locale: typeof req.headers["accept-language"] === "string" ? req.headers["accept-language"].split(",")[0] : void 0
|
|
@@ -37533,8 +37605,8 @@ async function handleActionHandlerBundleGet(res, app) {
|
|
|
37533
37605
|
}
|
|
37534
37606
|
async function serveStatic(req, res, root, prefix) {
|
|
37535
37607
|
const requested = decodeURIComponent((req.url ?? "").split("?")[0]);
|
|
37536
|
-
const
|
|
37537
|
-
const safe = normalize3(
|
|
37608
|
+
const relative13 = requested.replace(prefix, "").replace(/^\//, "");
|
|
37609
|
+
const safe = normalize3(relative13).replace(/^(\.\.[\/\\])+/, "");
|
|
37538
37610
|
const fullPath = resolve31(root, safe);
|
|
37539
37611
|
if (!fullPath.startsWith(root)) {
|
|
37540
37612
|
return send(res, 403, "forbidden");
|
|
@@ -37698,19 +37770,19 @@ function handleAssetLinks(res, state) {
|
|
|
37698
37770
|
});
|
|
37699
37771
|
}
|
|
37700
37772
|
function createDevServer(opts = {}) {
|
|
37701
|
-
const
|
|
37773
|
+
const appName2 = opts.app ?? "sample";
|
|
37702
37774
|
if (!opts.preloaded) {
|
|
37703
|
-
throw new Error(`createDevServer requires a preloaded module for "${
|
|
37775
|
+
throw new Error(`createDevServer requires a preloaded module for "${appName2}". Preload via loadApp("${appName2}").`);
|
|
37704
37776
|
}
|
|
37705
37777
|
checkRegistry(opts.preloaded.module.actions);
|
|
37706
37778
|
const port = opts.port ?? Number(process.env.HIMALAYA_DEV_PORT ?? 8080);
|
|
37707
37779
|
const hotReloadEnabled = opts.enableHotReload ?? process.env.HIMALAYA_DEV_HOT_RELOAD === "1";
|
|
37708
37780
|
const state = {
|
|
37709
|
-
appName,
|
|
37781
|
+
appName: appName2,
|
|
37710
37782
|
// Store construction is cheap now; its node:sqlite DB is opened LAZILY on first query
|
|
37711
37783
|
// (store.ts), so the serve authoring plane can boot createDevServer on a Whirlwind guest
|
|
37712
37784
|
// that has no node:sqlite — the stateless build/render path never queries the demo store.
|
|
37713
|
-
store: new Store(
|
|
37785
|
+
store: new Store(appName2),
|
|
37714
37786
|
toggles: {
|
|
37715
37787
|
pinned_notes_v2: false,
|
|
37716
37788
|
weekly_review_v1: true,
|
|
@@ -37731,7 +37803,7 @@ function createDevServer(opts = {}) {
|
|
|
37731
37803
|
localOverrides: /* @__PURE__ */ new Map(),
|
|
37732
37804
|
localOverrideHistory: /* @__PURE__ */ new Map(),
|
|
37733
37805
|
app: opts.preloaded,
|
|
37734
|
-
moduleStore: opts.preloaded ? opts.preloaded.module.createStore(
|
|
37806
|
+
moduleStore: opts.preloaded ? opts.preloaded.module.createStore(appName2) : void 0,
|
|
37735
37807
|
telemetryEvents: [],
|
|
37736
37808
|
adminUrl: process.env.HIMALAYA_ADMIN_URL,
|
|
37737
37809
|
wix: createWixGatewayState(),
|
|
@@ -42298,7 +42370,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
42298
42370
|
...collect2?.lint ? { lint, workers } : {},
|
|
42299
42371
|
...collect2?.render ? { renders } : {},
|
|
42300
42372
|
...collect2?.descriptors ? { descriptors: baked, linkableScreenIds: [...linkable] } : {},
|
|
42301
|
-
...
|
|
42373
|
+
...typeof preloaded.meta.homeScreenId === "string" && preloaded.meta.homeScreenId ? { homeScreenId: preloaded.meta.homeScreenId } : {},
|
|
42302
42374
|
...renderTokens !== void 0 ? { tokens: renderTokens } : {},
|
|
42303
42375
|
...preloaded.meta.surfaces ? { surfaceNav: preloaded.meta.surfaces } : {},
|
|
42304
42376
|
auth: (() => {
|
|
@@ -42595,7 +42667,7 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
42595
42667
|
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
42596
42668
|
.nav{display:flex;flex-wrap:wrap;gap:6px}.nav span{font-size:12px;padding:3px 8px;border-radius:6px;background:var(--bg);border:1px solid var(--line)}
|
|
42597
42669
|
.log{list-style:none;margin:0;padding:0}.log li{display:flex;gap:10px;padding:10px 0;border-top:1px solid var(--line)}.log li:first-child{border-top:0}
|
|
42598
|
-
.log .t{color:var(--faint);font-size:12px;min-width:64px;font-variant-numeric:tabular-nums}.log .s{font-size:11px;color:var(--muted);text-transform:capitalize}.log .imgs{display:flex;gap:6px;margin-top:6px}.log .imgs img{height:72px;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
42670
|
+
.log .t{color:var(--faint);font-size:12px;min-width:64px;font-variant-numeric:tabular-nums}.log .s{font-size:11px;color:var(--muted);text-transform:capitalize}.log .by{font-size:11px;color:var(--faint)}.log .imgs{display:flex;gap:6px;margin-top:6px}.log .imgs img{height:72px;border-radius:8px;border:1px solid var(--line);cursor:zoom-in}
|
|
42599
42671
|
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
42600
42672
|
#lb{position:fixed;inset:0;background:rgba(0,0,0,.72);display:none;align-items:center;justify-content:center;z-index:9;cursor:zoom-out}#lb img{max-height:92vh;max-width:92vw;border-radius:14px;background:#fff}
|
|
42601
42673
|
.enter{animation:enter .7s cubic-bezier(.2,.8,.2,1) both}@keyframes enter{from{opacity:0;transform:translateY(10px) scale(.94);filter:grayscale(1)}to{opacity:1;transform:none;filter:none}}
|
|
@@ -42724,7 +42796,7 @@ function render(s){
|
|
|
42724
42796
|
s.steps.forEach(function(name,i){var d=el("div","step"+(i+1<n?" done":i+1===n?" cur":""));d.appendChild(el("div","bar"));d.appendChild(el("div","lbl",(i+1)+". "+name));steps.appendChild(d)});
|
|
42725
42797
|
var last=s.journal[0];
|
|
42726
42798
|
$("nowmsg").textContent=last?last.message:"Waiting for the first postcard.";
|
|
42727
|
-
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+ago(last.ts)):"Now";
|
|
42799
|
+
$("nowmeta").textContent=last?("Now \xB7 "+(last.step?("step "+last.stepNumber+" of 8, "+last.step+" \xB7 "):"")+(last.by?"noted by "+last.by+" \xB7 ":"")+ago(last.ts)):"Now";
|
|
42728
42800
|
var film=$("film");clear(film);
|
|
42729
42801
|
if(!rewinding){var n0=s.timelineFrames||0;$("scrub").hidden=n0<2;$("slider").max=String(Math.max(1,n0-1));$("slider").value=$("slider").max}
|
|
42730
42802
|
if(rewinding){paintStill(s)}else{$("still").hidden=true;$("focus").hidden=false;var focus=$("focus");
|
|
@@ -42756,7 +42828,7 @@ function render(s){
|
|
|
42756
42828
|
if(s.app.palette.length){var sw=el("div","sw");s.app.palette.forEach(function(c){var d=el("span");d.style.background=c.hex;d.title=c.name+" "+c.hex;sw.appendChild(d)});brand.appendChild(sw)}
|
|
42757
42829
|
var nav=$("nav");clear(nav);$("navcard").style.display=s.nav.length&&!s.map?"":"none";drawMap(s.map);s.nav.forEach(function(e){nav.appendChild(el("span",null,e.from+" \u2192 "+e.to))});
|
|
42758
42830
|
var log=$("log");clear(log);if(!s.journal.length)log.appendChild(el("li","empty","Postcards the agent journals appear here."));
|
|
42759
|
-
s.journal.forEach(function(j){var li=el("li");li.appendChild(el("div","t",hhmm(j.ts)));var body=el("div");body.appendChild(el("div",null,j.message));if(j.step)body.appendChild(el("div","s","step "+j.stepNumber+" \xB7 "+j.step));
|
|
42831
|
+
s.journal.forEach(function(j){var li=el("li");li.appendChild(el("div","t",hhmm(j.ts)));var body=el("div");body.appendChild(el("div",null,j.message));if(j.step)body.appendChild(el("div","s","step "+j.stepNumber+" \xB7 "+j.step));if(j.by)body.appendChild(el("div","by","noted by "+j.by));
|
|
42760
42832
|
if(j.images.length){var row=el("div","imgs");j.images.forEach(function(u){row.appendChild(img(u))});body.appendChild(row)}li.appendChild(body);log.appendChild(li)});
|
|
42761
42833
|
paintPop(s);
|
|
42762
42834
|
}
|
|
@@ -43529,9 +43601,10 @@ function buildView(dir, memory, now) {
|
|
|
43529
43601
|
journal: entries.slice(-MAX_JOURNAL).reverse().map((e) => ({
|
|
43530
43602
|
ts: e.ts,
|
|
43531
43603
|
message: e.message,
|
|
43532
|
-
step: e.step ?? null,
|
|
43533
|
-
stepNumber: e.stepNumber ?? null,
|
|
43534
|
-
images: (e.images ?? []).map((i) => historyUrl(basename10(i.file)))
|
|
43604
|
+
step: isCliEntry(e) ? null : e.step ?? null,
|
|
43605
|
+
stepNumber: isCliEntry(e) ? null : e.stepNumber ?? null,
|
|
43606
|
+
images: (e.images ?? []).map((i) => historyUrl(basename10(i.file))),
|
|
43607
|
+
by: isCliEntry(e) ? CLI_AUTHOR : null
|
|
43535
43608
|
})),
|
|
43536
43609
|
screens,
|
|
43537
43610
|
focus,
|
|
@@ -44779,6 +44852,109 @@ var init_notify_setup = __esm({
|
|
|
44779
44852
|
}
|
|
44780
44853
|
});
|
|
44781
44854
|
|
|
44855
|
+
// src/milestones.ts
|
|
44856
|
+
var milestones_exports = {};
|
|
44857
|
+
__export(milestones_exports, {
|
|
44858
|
+
afterDraftPush: () => afterDraftPush,
|
|
44859
|
+
afterRenderPng: () => afterRenderPng,
|
|
44860
|
+
afterTestRun: () => afterTestRun,
|
|
44861
|
+
displayPath: () => displayPath,
|
|
44862
|
+
homeScreenIdOf: () => homeScreenIdOf,
|
|
44863
|
+
openBoardForSession: () => openBoardForSession,
|
|
44864
|
+
progressCommand: () => progressCommand,
|
|
44865
|
+
sessionSteps: () => sessionSteps,
|
|
44866
|
+
testPostcardMessage: () => testPostcardMessage
|
|
44867
|
+
});
|
|
44868
|
+
import { existsSync as existsSync44, readFileSync as readFileSync48 } from "node:fs";
|
|
44869
|
+
import { basename as basename12, isAbsolute as isAbsolute4, join as join42, relative as relative8 } from "node:path";
|
|
44870
|
+
function homeScreenIdOf(dir) {
|
|
44871
|
+
let src;
|
|
44872
|
+
try {
|
|
44873
|
+
src = readFileSync48(join42(dir, "dev", "index.ts"), "utf8");
|
|
44874
|
+
} catch {
|
|
44875
|
+
return null;
|
|
44876
|
+
}
|
|
44877
|
+
const m = /^[ \t]*homeScreenId[ \t]*:[ \t]*(?:"((?:[^"\\\n]|\\.)*)"|'((?:[^'\\\n]|\\.)*)')/m.exec(src);
|
|
44878
|
+
const id = m ? m[1] ?? m[2] : void 0;
|
|
44879
|
+
return id && /^[A-Za-z0-9_.\-/{}]+$/.test(id) ? id : null;
|
|
44880
|
+
}
|
|
44881
|
+
function displayPath(p, cwd = process.cwd()) {
|
|
44882
|
+
const rel = relative8(cwd, p);
|
|
44883
|
+
return rel && !rel.startsWith("..") && !isAbsolute4(rel) ? rel : p;
|
|
44884
|
+
}
|
|
44885
|
+
function progressCommand(opts) {
|
|
44886
|
+
return `himi progress "<${opts.what}>"${opts.step ? ` --step ${opts.step}` : ""}${opts.image ? ` --image ${shellQuote(opts.image)}` : ""}${contentArg(opts.content)}`;
|
|
44887
|
+
}
|
|
44888
|
+
function sessionSteps(opts) {
|
|
44889
|
+
const content = displayPath(opts.dir, opts.cwd);
|
|
44890
|
+
const home = opts.home ?? "<homeScreenId>";
|
|
44891
|
+
const shot = `.himi/shots/${home}.png`;
|
|
44892
|
+
return [
|
|
44893
|
+
`himi run --watch${contentArg(content)} & \u2014 now, in this session: keep it running in the background. The live preview repaints on every save and serves the build board at <its url>/__himi/studio/`,
|
|
44894
|
+
`himi render ${shellQuote(home)} --png --device iphone${contentArg(content)} \u2014 the first picture, written to ${shot}${opts.home ? "" : " (the id is the dev module's homeScreenId)"}; the CLI journals it as the first look`,
|
|
44895
|
+
`${progressCommand({ what: "where the build starts", step: "plan", image: shot, content })} \u2014 your postcard for the owner, with that picture`
|
|
44896
|
+
];
|
|
44897
|
+
}
|
|
44898
|
+
async function openBoardForSession(dir, cwd = process.cwd()) {
|
|
44899
|
+
try {
|
|
44900
|
+
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
44901
|
+
const { page, url } = openStudio2(dir);
|
|
44902
|
+
const rel = relative8(cwd, page);
|
|
44903
|
+
return { page: rel && !rel.startsWith("..") && !isAbsolute4(rel) ? rel : page, url, opened: false };
|
|
44904
|
+
} catch (e) {
|
|
44905
|
+
return { opened: false, error: `the build board was not created: ${e.message} \u2014 \`himi studio --no-open\` in the app retries it` };
|
|
44906
|
+
}
|
|
44907
|
+
}
|
|
44908
|
+
function journal(dir, milestone, message, extra) {
|
|
44909
|
+
const r = journalMilestone(dir, { milestone, message, ...extra });
|
|
44910
|
+
return r.journaled ? { journaled: true, milestone, message } : void 0;
|
|
44911
|
+
}
|
|
44912
|
+
function afterRenderPng(dir, input) {
|
|
44913
|
+
const postcard = input.renderable && input.homeScreenId !== null && input.screenId === input.homeScreenId ? journal(dir, "first-look", `First look at ${appName(dir)}: the home screen, where the build starts.`, { image: input.pngFile, ...input.now ? { now: input.now } : {} }) : void 0;
|
|
44914
|
+
return {
|
|
44915
|
+
...postcard ? { postcard } : {},
|
|
44916
|
+
next: input.renderable ? [progressCommand({ what: "what changed", image: displayPath(input.pngFile), content: input.content })] : []
|
|
44917
|
+
};
|
|
44918
|
+
}
|
|
44919
|
+
function testPostcardMessage(s) {
|
|
44920
|
+
const links = s.broken === void 0 ? "" : `, ${plural(s.broken, "broken link")}`;
|
|
44921
|
+
const unreached = s.unreached ? `, ${plural(s.unreached, "screen")} nothing links to` : "";
|
|
44922
|
+
return `Test crawl: ${plural(s.screens, "screen")} and ${plural(s.actions, "action")} exercised${links}${unreached} \u2014 ${s.errors ? `${plural(s.errors, "error")} to fix` : "no errors"}.`;
|
|
44923
|
+
}
|
|
44924
|
+
function afterTestRun(dir, input) {
|
|
44925
|
+
const postcard = journal(dir, "test", testPostcardMessage(input), {
|
|
44926
|
+
ref: input.runId,
|
|
44927
|
+
...input.homeShot && existsSync44(input.homeShot) ? { image: input.homeShot } : {},
|
|
44928
|
+
...input.now ? { now: input.now } : {}
|
|
44929
|
+
});
|
|
44930
|
+
return {
|
|
44931
|
+
...postcard ? { postcard } : {},
|
|
44932
|
+
next: [
|
|
44933
|
+
input.boardOpen ? "the build board's App map now shows every screen this crawl reached, how they link, and any broken link \u2014 .himi/studio/index.html, or /__himi/studio/ under `himi run --watch`" : "`himi studio` opens the build board, whose App map draws every screen this crawl reached, how they link, and any broken link"
|
|
44934
|
+
]
|
|
44935
|
+
};
|
|
44936
|
+
}
|
|
44937
|
+
function afterDraftPush(dir, input) {
|
|
44938
|
+
const postcard = journal(dir, "draft", `Draft pushed: release ${input.releaseId.slice(0, 12)} of ${input.app} \u2014 owner-private, not live.`, {
|
|
44939
|
+
ref: input.releaseId,
|
|
44940
|
+
...input.now ? { now: input.now } : {}
|
|
44941
|
+
});
|
|
44942
|
+
return {
|
|
44943
|
+
...postcard ? { postcard } : {},
|
|
44944
|
+
next: `${progressCommand({ what: "what the owner can review in this draft", step: "review", content: input.content })} \u2014 your postcard for the draft; share the preview link in chat, never in the journal`
|
|
44945
|
+
};
|
|
44946
|
+
}
|
|
44947
|
+
var contentArg, plural, appName;
|
|
44948
|
+
var init_milestones = __esm({
|
|
44949
|
+
"src/milestones.ts"() {
|
|
44950
|
+
init_progress();
|
|
44951
|
+
init_shell_quote();
|
|
44952
|
+
contentArg = (content) => content ? ` --content ${shellQuote(content)}` : "";
|
|
44953
|
+
plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
44954
|
+
appName = (dir) => appLabel(dir) ?? basename12(dir);
|
|
44955
|
+
}
|
|
44956
|
+
});
|
|
44957
|
+
|
|
44782
44958
|
// src/site-analyze/types.ts
|
|
44783
44959
|
function isRedirectUri(value) {
|
|
44784
44960
|
return /^[a-z][a-z0-9+.-]*:\/\/\S*$/i.test(value);
|
|
@@ -45216,8 +45392,8 @@ __export(template_trim_exports, {
|
|
|
45216
45392
|
routeMatcher: () => routeMatcher,
|
|
45217
45393
|
runTemplateTrim: () => runTemplateTrim
|
|
45218
45394
|
});
|
|
45219
|
-
import { cpSync, existsSync as
|
|
45220
|
-
import { dirname as dirname25, join as
|
|
45395
|
+
import { cpSync, existsSync as existsSync45, mkdirSync as mkdirSync20, readdirSync as readdirSync24, readFileSync as readFileSync49, renameSync as renameSync5, rmSync as rmSync8, statSync as statSync10, writeFileSync as writeFileSync16 } from "node:fs";
|
|
45396
|
+
import { dirname as dirname25, join as join43 } from "node:path";
|
|
45221
45397
|
function routeMatcher(pattern) {
|
|
45222
45398
|
const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
|
|
45223
45399
|
if (detail) {
|
|
@@ -45911,20 +46087,20 @@ function homeModulesPass(app, kept, edited) {
|
|
|
45911
46087
|
return { text: patched.src, dropped: patched.droppedModules };
|
|
45912
46088
|
}
|
|
45913
46089
|
function listWorkers(dir) {
|
|
45914
|
-
const root =
|
|
45915
|
-
if (!
|
|
45916
|
-
const dirs = readdirSync24(root).filter((n) => statSync10(
|
|
46090
|
+
const root = join43(dir, "tier5-src");
|
|
46091
|
+
if (!existsSync45(root)) return { dirs: [], files: {} };
|
|
46092
|
+
const dirs = readdirSync24(root).filter((n) => statSync10(join43(root, n)).isDirectory()).sort();
|
|
45917
46093
|
const files = {};
|
|
45918
46094
|
const walk2 = (abs, rel) => {
|
|
45919
46095
|
for (const name of readdirSync24(abs)) {
|
|
45920
46096
|
if (name === "node_modules") continue;
|
|
45921
|
-
const p =
|
|
46097
|
+
const p = join43(abs, name);
|
|
45922
46098
|
const r = `${rel}/${name}`;
|
|
45923
46099
|
if (statSync10(p).isDirectory()) walk2(p, r);
|
|
45924
|
-
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] =
|
|
46100
|
+
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] = readFileSync49(p, "utf8");
|
|
45925
46101
|
}
|
|
45926
46102
|
};
|
|
45927
|
-
for (const d of dirs) walk2(
|
|
46103
|
+
for (const d of dirs) walk2(join43(root, d), `tier5-src/${d}`);
|
|
45928
46104
|
return { dirs, files };
|
|
45929
46105
|
}
|
|
45930
46106
|
function csv(v) {
|
|
@@ -45947,16 +46123,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
45947
46123
|
links = req.links;
|
|
45948
46124
|
}
|
|
45949
46125
|
const dir = req.dir;
|
|
45950
|
-
const devPath =
|
|
45951
|
-
const configPath =
|
|
45952
|
-
if (!
|
|
46126
|
+
const devPath = join43(dir, "dev/index.ts");
|
|
46127
|
+
const configPath = join43(dir, "config.ts");
|
|
46128
|
+
if (!existsSync45(devPath) || !existsSync45(configPath)) {
|
|
45953
46129
|
return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
|
|
45954
46130
|
}
|
|
45955
46131
|
if (isTemplateSourceTree(dir)) {
|
|
45956
46132
|
return refuse3(new TrimRefusal(`${dir} is a template source tree (its identity is still __HIMI_APP_*__ sentinels) \u2014 trim the app \`himi init --template\` scaffolds from it, not the template itself`));
|
|
45957
46133
|
}
|
|
45958
|
-
const dev =
|
|
45959
|
-
const config =
|
|
46134
|
+
const dev = readFileSync49(devPath, "utf8");
|
|
46135
|
+
const config = readFileSync49(configPath, "utf8");
|
|
45960
46136
|
const workers = listWorkers(dir);
|
|
45961
46137
|
let plan;
|
|
45962
46138
|
try {
|
|
@@ -45966,23 +46142,23 @@ async function runTemplateTrim(req, deps) {
|
|
|
45966
46142
|
throw e;
|
|
45967
46143
|
}
|
|
45968
46144
|
if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
|
|
45969
|
-
const hadHimi =
|
|
45970
|
-
const backupRel =
|
|
45971
|
-
const backup =
|
|
46145
|
+
const hadHimi = existsSync45(join43(dir, ".himi"));
|
|
46146
|
+
const backupRel = join43(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
46147
|
+
const backup = join43(dir, backupRel);
|
|
45972
46148
|
const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"]];
|
|
45973
46149
|
const moved = [];
|
|
45974
46150
|
const restore = () => {
|
|
45975
46151
|
for (const [path2, rel] of originals) {
|
|
45976
|
-
const original =
|
|
45977
|
-
if (!
|
|
46152
|
+
const original = readFileSync49(join43(backup, rel));
|
|
46153
|
+
if (!existsSync45(path2) || !readFileSync49(path2).equals(original)) writeFileSync16(path2, original);
|
|
45978
46154
|
}
|
|
45979
|
-
for (const name of [...moved].reverse()) renameSync5(
|
|
46155
|
+
for (const name of [...moved].reverse()) renameSync5(join43(backup, "tier5-src", name), join43(dir, "tier5-src", name));
|
|
45980
46156
|
moved.length = 0;
|
|
45981
46157
|
};
|
|
45982
46158
|
const apply = () => {
|
|
45983
46159
|
const moveDir = deps.moveDir ?? renameSync5;
|
|
45984
46160
|
for (const name of plan.removedWorkers) {
|
|
45985
|
-
moveDir(
|
|
46161
|
+
moveDir(join43(dir, "tier5-src", name), join43(backup, "tier5-src", name));
|
|
45986
46162
|
moved.push(name);
|
|
45987
46163
|
}
|
|
45988
46164
|
if (plan.dev !== dev) writeFileSync16(devPath, plan.dev);
|
|
@@ -45990,8 +46166,8 @@ async function runTemplateTrim(req, deps) {
|
|
|
45990
46166
|
};
|
|
45991
46167
|
const dropBackup = () => {
|
|
45992
46168
|
rmSync8(backup, { recursive: true, force: true });
|
|
45993
|
-
for (const d of [dirname25(backup),
|
|
45994
|
-
if (d ===
|
|
46169
|
+
for (const d of [dirname25(backup), join43(dir, ".himi")]) {
|
|
46170
|
+
if (d === join43(dir, ".himi") && hadHimi) break;
|
|
45995
46171
|
try {
|
|
45996
46172
|
if (!readdirSync24(d).length) rmSync8(d, { recursive: true });
|
|
45997
46173
|
} catch {
|
|
@@ -46017,9 +46193,9 @@ async function runTemplateTrim(req, deps) {
|
|
|
46017
46193
|
return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
|
|
46018
46194
|
};
|
|
46019
46195
|
try {
|
|
46020
|
-
mkdirSync20(
|
|
46021
|
-
for (const [path2, rel] of originals) cpSync(path2,
|
|
46022
|
-
if (plan.removedWorkers.length) mkdirSync20(
|
|
46196
|
+
mkdirSync20(join43(backup, "dev"), { recursive: true });
|
|
46197
|
+
for (const [path2, rel] of originals) cpSync(path2, join43(backup, rel));
|
|
46198
|
+
if (plan.removedWorkers.length) mkdirSync20(join43(backup, "tier5-src"), { recursive: true });
|
|
46023
46199
|
} catch (e) {
|
|
46024
46200
|
dropBackup();
|
|
46025
46201
|
return { code: 1, result: { ok: false, error: `could not back up the app before trimming it (${e.message}); nothing was changed`, rolledBack: true, ...base() } };
|
|
@@ -46032,7 +46208,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46032
46208
|
let failure;
|
|
46033
46209
|
let validate3;
|
|
46034
46210
|
try {
|
|
46035
|
-
const written = parseApp(
|
|
46211
|
+
const written = parseApp(readFileSync49(devPath, "utf8"), readFileSync49(configPath, "utf8"));
|
|
46036
46212
|
const leftovers = leftoverNavRefs(written.nav.value, plan.removedIds);
|
|
46037
46213
|
if (leftovers.length) failure = { error: "navigation still names screens this trim removed", leftovers };
|
|
46038
46214
|
else {
|
|
@@ -46069,7 +46245,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46069
46245
|
else if (compared) {
|
|
46070
46246
|
failure = {
|
|
46071
46247
|
...failure,
|
|
46072
|
-
error: `himi validate --strict failed on the trimmed app \u2014 the trim introduced ${
|
|
46248
|
+
error: `himi validate --strict failed on the trimmed app \u2014 the trim introduced ${plural2(compared.introduced.length, "error")} the untrimmed app does not have: ${summarize3(compared.introduced)}`,
|
|
46073
46249
|
introducedErrors: compared.introduced,
|
|
46074
46250
|
preExistingErrors: compared.preExisting
|
|
46075
46251
|
};
|
|
@@ -46085,7 +46261,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46085
46261
|
...base(validate3),
|
|
46086
46262
|
...preExisting.length ? {
|
|
46087
46263
|
preExistingErrors: preExisting,
|
|
46088
|
-
note: `trimmed; ${
|
|
46264
|
+
note: `trimmed; ${plural2(preExisting.length, "error")} ${preExisting.length === 1 ? "was" : "were"} already present before trim: ${summarize3(preExisting)}`
|
|
46089
46265
|
} : {}
|
|
46090
46266
|
}
|
|
46091
46267
|
};
|
|
@@ -46136,7 +46312,7 @@ function summarize3(errors) {
|
|
|
46136
46312
|
const shown2 = errors.slice(0, 5).map(one).join("; ");
|
|
46137
46313
|
return errors.length > 5 ? `${shown2}; and ${errors.length - 5} more` : shown2;
|
|
46138
46314
|
}
|
|
46139
|
-
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf2, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3,
|
|
46315
|
+
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf2, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3, plural2;
|
|
46140
46316
|
var init_template_trim = __esm({
|
|
46141
46317
|
"src/template-trim.ts"() {
|
|
46142
46318
|
init_validate_descriptor();
|
|
@@ -46170,7 +46346,7 @@ var init_template_trim = __esm({
|
|
|
46170
46346
|
NAV_SCREEN_KEYS = /* @__PURE__ */ new Set(["screenId", "parentScreenId", "contentScreenId", "badgeScreenId"]);
|
|
46171
46347
|
sorted = (xs) => [...new Set(xs)].sort();
|
|
46172
46348
|
refuse3 = (e) => ({ code: 2, result: { ok: false, error: e.message, ...e.detail } });
|
|
46173
|
-
|
|
46349
|
+
plural2 = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
46174
46350
|
}
|
|
46175
46351
|
});
|
|
46176
46352
|
|
|
@@ -46800,8 +46976,8 @@ __export(pack_exports, {
|
|
|
46800
46976
|
});
|
|
46801
46977
|
import { createHash as createHash22 } from "node:crypto";
|
|
46802
46978
|
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
46803
|
-
import { existsSync as
|
|
46804
|
-
import { dirname as dirname26, join as
|
|
46979
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync21, readFileSync as readFileSync50, readdirSync as readdirSync25, rmSync as rmSync9, statSync as statSync11, writeFileSync as writeFileSync17 } from "node:fs";
|
|
46980
|
+
import { dirname as dirname26, join as join44, resolve as resolve37 } from "node:path";
|
|
46805
46981
|
function writeZip(entries) {
|
|
46806
46982
|
const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
46807
46983
|
const total = sorted2.reduce((n, e) => n + e.bytes.length, 0);
|
|
@@ -46895,13 +47071,13 @@ function inflateEntry(buf, entry) {
|
|
|
46895
47071
|
return bytes2;
|
|
46896
47072
|
}
|
|
46897
47073
|
function readIf(path2) {
|
|
46898
|
-
return
|
|
47074
|
+
return existsSync46(path2) && statSync11(path2).isFile() ? readFileSync50(path2) : null;
|
|
46899
47075
|
}
|
|
46900
47076
|
function listDir(dir) {
|
|
46901
|
-
return
|
|
47077
|
+
return existsSync46(dir) ? readdirSync25(dir).filter((f) => statSync11(join44(dir, f)).isFile()) : [];
|
|
46902
47078
|
}
|
|
46903
47079
|
function gatherReleaseEntries(appDir2) {
|
|
46904
|
-
const manifestPath =
|
|
47080
|
+
const manifestPath = join44(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
|
|
46905
47081
|
const manifestBytes = readIf(manifestPath);
|
|
46906
47082
|
if (!manifestBytes) throw new Error(`no ${HIMI_PACKAGE_MANIFEST_PATH} in ${appDir2} \u2014 build a release there first`);
|
|
46907
47083
|
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
@@ -46925,7 +47101,7 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46925
47101
|
}
|
|
46926
47102
|
const missing = [];
|
|
46927
47103
|
for (const rel of wanted) {
|
|
46928
|
-
const bytes2 = readIf(
|
|
47104
|
+
const bytes2 = readIf(join44(appDir2, rel));
|
|
46929
47105
|
if (bytes2) entries.push({ path: rel, bytes: bytes2 });
|
|
46930
47106
|
else missing.push(rel);
|
|
46931
47107
|
}
|
|
@@ -46936,12 +47112,12 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46936
47112
|
);
|
|
46937
47113
|
}
|
|
46938
47114
|
for (const name of SINGLETONS) {
|
|
46939
|
-
const bytes2 = readIf(
|
|
47115
|
+
const bytes2 = readIf(join44(appDir2, name));
|
|
46940
47116
|
if (bytes2) entries.push({ path: name, bytes: bytes2 });
|
|
46941
47117
|
}
|
|
46942
47118
|
const skipped = [];
|
|
46943
47119
|
for (const sub of ["screens", "bundles", "assets", "widgets"]) {
|
|
46944
|
-
for (const f of listDir(
|
|
47120
|
+
for (const f of listDir(join44(appDir2, sub))) {
|
|
46945
47121
|
if (!wanted.has(`${sub}/${f}`)) skipped.push(`${sub}/${f}`);
|
|
46946
47122
|
}
|
|
46947
47123
|
}
|
|
@@ -46974,18 +47150,18 @@ function buildEntries(appDir2, app, opts) {
|
|
|
46974
47150
|
return { all, header, manifest, skipped };
|
|
46975
47151
|
}
|
|
46976
47152
|
function packRelease(releaseRoot, app, out, opts = {}) {
|
|
46977
|
-
const appDir2 =
|
|
47153
|
+
const appDir2 = join44(resolve37(releaseRoot), app);
|
|
46978
47154
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
46979
47155
|
const buf = writeZip(all);
|
|
46980
|
-
const isDir2 =
|
|
46981
|
-
const outFile = isDir2 ?
|
|
47156
|
+
const isDir2 = existsSync46(out) && statSync11(out).isDirectory();
|
|
47157
|
+
const outFile = isDir2 ? join44(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
|
|
46982
47158
|
mkdirSync21(dirname26(outFile), { recursive: true });
|
|
46983
47159
|
writeFileSync17(outFile, buf);
|
|
46984
47160
|
return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
|
|
46985
47161
|
}
|
|
46986
47162
|
function resolvePackageDirDest(outDir, app, releaseId) {
|
|
46987
47163
|
const packagedApp = (dir) => {
|
|
46988
|
-
const bytes2 = readIf(
|
|
47164
|
+
const bytes2 = readIf(join44(dir, HIMI_PACKAGE_HEADER_PATH));
|
|
46989
47165
|
if (!bytes2) return void 0;
|
|
46990
47166
|
try {
|
|
46991
47167
|
return JSON.parse(bytes2.toString("utf8")).app;
|
|
@@ -46994,15 +47170,15 @@ function resolvePackageDirDest(outDir, app, releaseId) {
|
|
|
46994
47170
|
}
|
|
46995
47171
|
};
|
|
46996
47172
|
const replaceable = (dir) => {
|
|
46997
|
-
if (!
|
|
47173
|
+
if (!existsSync46(dir)) return true;
|
|
46998
47174
|
if (!statSync11(dir).isDirectory()) return false;
|
|
46999
47175
|
return readdirSync25(dir).length === 0 || packagedApp(dir) === app;
|
|
47000
47176
|
};
|
|
47001
|
-
if (
|
|
47177
|
+
if (existsSync46(outDir) && !statSync11(outDir).isDirectory()) {
|
|
47002
47178
|
throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
|
|
47003
47179
|
}
|
|
47004
47180
|
if (replaceable(outDir)) return outDir;
|
|
47005
|
-
const child =
|
|
47181
|
+
const child = join44(outDir, packageDirName(app, releaseId));
|
|
47006
47182
|
if (!replaceable(child)) {
|
|
47007
47183
|
throw new Error(
|
|
47008
47184
|
`refusing to replace ${child}: it is not empty and is not a ${app} package (no ${HIMI_PACKAGE_HEADER_PATH}). Pass --out to a new or empty directory.`
|
|
@@ -47016,13 +47192,13 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
|
|
|
47016
47192
|
"a package carrying the app's source has no --format dir form: readers that predate the source entry drop it before hashing a directory and refuse the package as tampered. Pack it as a .himi archive."
|
|
47017
47193
|
);
|
|
47018
47194
|
}
|
|
47019
|
-
const appDir2 =
|
|
47195
|
+
const appDir2 = join44(resolve37(releaseRoot), app);
|
|
47020
47196
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
47021
47197
|
const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
|
|
47022
47198
|
rmSync9(dest, { recursive: true, force: true });
|
|
47023
47199
|
let bytes2 = 0;
|
|
47024
47200
|
for (const entry of all) {
|
|
47025
|
-
const target =
|
|
47201
|
+
const target = join44(dest, entry.path);
|
|
47026
47202
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
47027
47203
|
writeFileSync17(target, entry.bytes);
|
|
47028
47204
|
bytes2 += entry.bytes.length;
|
|
@@ -47045,21 +47221,21 @@ function openPackageBuffer(buf) {
|
|
|
47045
47221
|
return openFromEntries(readZip(buf), { requireHeader: true });
|
|
47046
47222
|
}
|
|
47047
47223
|
function openPackageFile(file) {
|
|
47048
|
-
return openPackageBuffer(
|
|
47224
|
+
return openPackageBuffer(readFileSync50(file));
|
|
47049
47225
|
}
|
|
47050
47226
|
function openPackageDir(dir) {
|
|
47051
47227
|
const root = resolve37(dir);
|
|
47052
47228
|
const entries = /* @__PURE__ */ new Map();
|
|
47053
47229
|
const walk2 = (rel) => {
|
|
47054
|
-
const abs = rel ?
|
|
47230
|
+
const abs = rel ? join44(root, rel) : root;
|
|
47055
47231
|
for (const name of readdirSync25(abs)) {
|
|
47056
47232
|
const childRel = rel ? `${rel}/${name}` : name;
|
|
47057
|
-
const childAbs =
|
|
47233
|
+
const childAbs = join44(abs, name);
|
|
47058
47234
|
if (statSync11(childAbs).isDirectory()) walk2(childRel);
|
|
47059
|
-
else if (isSafeEntryName(childRel)) entries.set(childRel,
|
|
47235
|
+
else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync50(childAbs));
|
|
47060
47236
|
}
|
|
47061
47237
|
};
|
|
47062
|
-
if (!
|
|
47238
|
+
if (!existsSync46(root)) throw new Error(`no such package directory: ${root}`);
|
|
47063
47239
|
walk2("");
|
|
47064
47240
|
const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
|
|
47065
47241
|
if (manifestBytes) {
|
|
@@ -47101,10 +47277,10 @@ function unpackTo(buf, dest, appFallback) {
|
|
|
47101
47277
|
if (!app) throw new Error("package declares no app id (no himi-package.json and no manifest.app)");
|
|
47102
47278
|
if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
|
|
47103
47279
|
const root = resolve37(dest);
|
|
47104
|
-
const appDir2 =
|
|
47280
|
+
const appDir2 = join44(root, app);
|
|
47105
47281
|
rmSync9(appDir2, { recursive: true, force: true });
|
|
47106
47282
|
for (const [rel, bytes2] of entries) {
|
|
47107
|
-
const target =
|
|
47283
|
+
const target = join44(appDir2, rel);
|
|
47108
47284
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
47109
47285
|
writeFileSync17(target, bytes2);
|
|
47110
47286
|
}
|
|
@@ -47140,20 +47316,20 @@ __export(app_source_exports, {
|
|
|
47140
47316
|
writeConflicts: () => writeConflicts,
|
|
47141
47317
|
zipAppSource: () => zipAppSource
|
|
47142
47318
|
});
|
|
47143
|
-
import { readdirSync as readdirSync26, lstatSync as lstatSync8, readFileSync as
|
|
47144
|
-
import { join as
|
|
47319
|
+
import { readdirSync as readdirSync26, lstatSync as lstatSync8, readFileSync as readFileSync51, mkdirSync as mkdirSync22, writeFileSync as writeFileSync18, existsSync as existsSync47, rmSync as rmSync10, rmdirSync as rmdirSync2, unlinkSync as unlinkSync3 } from "node:fs";
|
|
47320
|
+
import { join as join45, resolve as resolve38, sep as sep10 } from "node:path";
|
|
47145
47321
|
import { deflateRawSync as deflateRawSync2 } from "node:zlib";
|
|
47146
47322
|
function walkSourceTree(dir, file, skip) {
|
|
47147
47323
|
const walk2 = (relDir) => {
|
|
47148
|
-
for (const name of readdirSync26(
|
|
47149
|
-
const rel = relDir ?
|
|
47150
|
-
const st = lstatSync8(
|
|
47324
|
+
for (const name of readdirSync26(join45(dir, relDir))) {
|
|
47325
|
+
const rel = relDir ? join45(relDir, name) : name;
|
|
47326
|
+
const st = lstatSync8(join45(dir, rel));
|
|
47151
47327
|
if (st.isSymbolicLink()) {
|
|
47152
47328
|
skip(rel);
|
|
47153
47329
|
continue;
|
|
47154
47330
|
}
|
|
47155
47331
|
if (st.isDirectory()) {
|
|
47156
|
-
if (isDeniedSourceDir(name, relDir) ||
|
|
47332
|
+
if (isDeniedSourceDir(name, relDir) || existsSync47(join45(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
|
|
47157
47333
|
else walk2(rel);
|
|
47158
47334
|
continue;
|
|
47159
47335
|
}
|
|
@@ -47171,7 +47347,7 @@ function collectAppSource(dir) {
|
|
|
47171
47347
|
const skipped = [];
|
|
47172
47348
|
walkSourceTree(
|
|
47173
47349
|
dir,
|
|
47174
|
-
(archivePath, hostRel) => entries.push({ path: archivePath, bytes:
|
|
47350
|
+
(archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync51(join45(dir, hostRel)) }),
|
|
47175
47351
|
(hostRel) => skipped.push(hostRel)
|
|
47176
47352
|
);
|
|
47177
47353
|
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -47225,13 +47401,13 @@ function writeAppSource(entries, destDir) {
|
|
|
47225
47401
|
const segments = entry.path.split("/");
|
|
47226
47402
|
let dir = root;
|
|
47227
47403
|
for (const segment of segments.slice(0, -1)) {
|
|
47228
|
-
dir =
|
|
47404
|
+
dir = join45(dir, segment);
|
|
47229
47405
|
const kind = pathKind(dir);
|
|
47230
47406
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
47231
47407
|
else if (kind) continue;
|
|
47232
47408
|
mkdirSync22(dir);
|
|
47233
47409
|
}
|
|
47234
|
-
const target =
|
|
47410
|
+
const target = join45(root, ...segments);
|
|
47235
47411
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
47236
47412
|
writeFileSync18(target, entry.bytes);
|
|
47237
47413
|
written.push(entry.path);
|
|
@@ -47239,7 +47415,7 @@ function writeAppSource(entries, destDir) {
|
|
|
47239
47415
|
return written;
|
|
47240
47416
|
}
|
|
47241
47417
|
function staleSourcePaths(entries, destDir) {
|
|
47242
|
-
if (!
|
|
47418
|
+
if (!existsSync47(destDir)) return [];
|
|
47243
47419
|
const archived = new Set(entries.map((e) => e.path));
|
|
47244
47420
|
const stale = [];
|
|
47245
47421
|
walkSourceTree(destDir, (archivePath) => {
|
|
@@ -47266,7 +47442,7 @@ function writeConflicts(entries, destDir) {
|
|
|
47266
47442
|
let dir = root;
|
|
47267
47443
|
let stop = false;
|
|
47268
47444
|
for (const [i, segment] of segments.slice(0, -1).entries()) {
|
|
47269
|
-
dir =
|
|
47445
|
+
dir = join45(dir, segment);
|
|
47270
47446
|
const kind2 = pathKind(dir);
|
|
47271
47447
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
47272
47448
|
stop = true;
|
|
@@ -47278,7 +47454,7 @@ function writeConflicts(entries, destDir) {
|
|
|
47278
47454
|
break;
|
|
47279
47455
|
}
|
|
47280
47456
|
if (stop) continue;
|
|
47281
|
-
const kind = pathKind(
|
|
47457
|
+
const kind = pathKind(join45(root, ...segments));
|
|
47282
47458
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
47283
47459
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
47284
47460
|
}
|
|
@@ -47288,22 +47464,22 @@ function writeConflicts(entries, destDir) {
|
|
|
47288
47464
|
function removeStaleSource(entries, destDir) {
|
|
47289
47465
|
const root = resolve38(destDir);
|
|
47290
47466
|
const removed = staleSourcePaths(entries, root);
|
|
47291
|
-
for (const rel of removed) rmSync10(
|
|
47467
|
+
for (const rel of removed) rmSync10(join45(root, ...rel.split("/")), { force: true });
|
|
47292
47468
|
const needed = /* @__PURE__ */ new Set();
|
|
47293
47469
|
for (const entry of entries) {
|
|
47294
47470
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
47295
47471
|
const segments = entry.path.split("/");
|
|
47296
47472
|
for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
|
|
47297
47473
|
}
|
|
47298
|
-
if (
|
|
47474
|
+
if (existsSync47(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
47299
47475
|
return removed.sort();
|
|
47300
47476
|
}
|
|
47301
47477
|
function pruneEmptyDirs(root, rel, needed, removed) {
|
|
47302
47478
|
let empty = true;
|
|
47303
|
-
for (const name of readdirSync26(rel ?
|
|
47304
|
-
const childRel = rel ?
|
|
47479
|
+
for (const name of readdirSync26(rel ? join45(root, rel) : root)) {
|
|
47480
|
+
const childRel = rel ? join45(rel, name) : name;
|
|
47305
47481
|
const posix4 = childRel.split(sep10).join("/");
|
|
47306
|
-
const kind = lstatSync8(
|
|
47482
|
+
const kind = lstatSync8(join45(root, childRel));
|
|
47307
47483
|
if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
|
|
47308
47484
|
empty = false;
|
|
47309
47485
|
continue;
|
|
@@ -47313,7 +47489,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
|
|
|
47313
47489
|
empty = false;
|
|
47314
47490
|
continue;
|
|
47315
47491
|
}
|
|
47316
|
-
rmdirSync2(
|
|
47492
|
+
rmdirSync2(join45(root, childRel));
|
|
47317
47493
|
removed.push(`${posix4}/`);
|
|
47318
47494
|
}
|
|
47319
47495
|
return empty;
|
|
@@ -47368,13 +47544,13 @@ __export(eject_exports, {
|
|
|
47368
47544
|
EJECTABLE: () => EJECTABLE,
|
|
47369
47545
|
ejectModule: () => ejectModule
|
|
47370
47546
|
});
|
|
47371
|
-
import { existsSync as
|
|
47372
|
-
import { dirname as dirname27, join as
|
|
47547
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync23, readFileSync as readFileSync52, writeFileSync as writeFileSync19 } from "node:fs";
|
|
47548
|
+
import { dirname as dirname27, join as join46, relative as relative9, resolve as resolve39, sep as sep11 } from "node:path";
|
|
47373
47549
|
function locate(repoRootOrCwd, mod) {
|
|
47374
47550
|
const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
|
|
47375
|
-
if (
|
|
47551
|
+
if (existsSync48(inRepo)) return { path: inRepo, form: "source" };
|
|
47376
47552
|
const dist = resolve39(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
|
|
47377
|
-
if (
|
|
47553
|
+
if (existsSync48(dist)) return { path: dist, form: "bundle" };
|
|
47378
47554
|
return null;
|
|
47379
47555
|
}
|
|
47380
47556
|
function specifiersFor(mod) {
|
|
@@ -47398,7 +47574,7 @@ function ejectModule(opts) {
|
|
|
47398
47574
|
};
|
|
47399
47575
|
}
|
|
47400
47576
|
const ext = found.form === "source" ? "ts" : "mjs";
|
|
47401
|
-
const target =
|
|
47577
|
+
const target = join46(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
|
|
47402
47578
|
mkdirSync23(dirname27(target), { recursive: true });
|
|
47403
47579
|
const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
|
|
47404
47580
|
//
|
|
@@ -47412,17 +47588,17 @@ function ejectModule(opts) {
|
|
|
47412
47588
|
// gate still applies. Ejecting buys layout and flow, never the floor.
|
|
47413
47589
|
|
|
47414
47590
|
`;
|
|
47415
|
-
const normalized =
|
|
47591
|
+
const normalized = readFileSync52(found.path, "utf8").replace(
|
|
47416
47592
|
/(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
|
|
47417
47593
|
(_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
|
|
47418
47594
|
);
|
|
47419
47595
|
writeFileSync19(target, banner + normalized);
|
|
47420
47596
|
const rewired = [];
|
|
47421
47597
|
for (const f of files) {
|
|
47422
|
-
if (!
|
|
47423
|
-
const before =
|
|
47598
|
+
if (!existsSync48(f)) continue;
|
|
47599
|
+
const before = readFileSync52(f, "utf8");
|
|
47424
47600
|
let after = before;
|
|
47425
|
-
let rel =
|
|
47601
|
+
let rel = relative9(dirname27(f), target).split(sep11).join("/").replace(/\.tsx?$/, ".js");
|
|
47426
47602
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
47427
47603
|
for (const spec of specifiersFor(mod)) {
|
|
47428
47604
|
const q = spec.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -47540,8 +47716,8 @@ var init_app_map = __esm({
|
|
|
47540
47716
|
});
|
|
47541
47717
|
|
|
47542
47718
|
// src/wix-writes.ts
|
|
47543
|
-
import { existsSync as
|
|
47544
|
-
import { join as
|
|
47719
|
+
import { existsSync as existsSync49, readFileSync as readFileSync53 } from "node:fs";
|
|
47720
|
+
import { join as join47 } from "node:path";
|
|
47545
47721
|
function isProvenRead(method, path2) {
|
|
47546
47722
|
if (/[#\x00-\x1F\x7F]/.test(path2)) return false;
|
|
47547
47723
|
const verb = method.toUpperCase();
|
|
@@ -47622,11 +47798,11 @@ function parseDataAccess(text5, from) {
|
|
|
47622
47798
|
}
|
|
47623
47799
|
function readDataAccess(dir) {
|
|
47624
47800
|
for (const name of ["SPEC.md", "MOBILE-UX.md"]) {
|
|
47625
|
-
const p =
|
|
47626
|
-
if (!
|
|
47801
|
+
const p = join47(dir, name);
|
|
47802
|
+
if (!existsSync49(p)) continue;
|
|
47627
47803
|
let text5;
|
|
47628
47804
|
try {
|
|
47629
|
-
text5 =
|
|
47805
|
+
text5 = readFileSync53(p, "utf8");
|
|
47630
47806
|
} catch {
|
|
47631
47807
|
continue;
|
|
47632
47808
|
}
|
|
@@ -47733,14 +47909,14 @@ __export(test_exports, {
|
|
|
47733
47909
|
scopeDescriptors: () => scopeDescriptors,
|
|
47734
47910
|
writeRecordedMocks: () => writeRecordedMocks
|
|
47735
47911
|
});
|
|
47736
|
-
import { existsSync as
|
|
47737
|
-
import { join as
|
|
47912
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync24, readFileSync as readFileSync54, writeFileSync as writeFileSync20 } from "node:fs";
|
|
47913
|
+
import { join as join48, resolve as resolve40 } from "node:path";
|
|
47738
47914
|
function readTestConfig(dir) {
|
|
47739
47915
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
47740
|
-
if (!
|
|
47916
|
+
if (!existsSync50(p)) return {};
|
|
47741
47917
|
let parsed;
|
|
47742
47918
|
try {
|
|
47743
|
-
parsed = JSON.parse(
|
|
47919
|
+
parsed = JSON.parse(readFileSync54(p, "utf8"));
|
|
47744
47920
|
} catch (e) {
|
|
47745
47921
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
47746
47922
|
}
|
|
@@ -47787,7 +47963,7 @@ function readTestConfig(dir) {
|
|
|
47787
47963
|
function readNetRules(path2) {
|
|
47788
47964
|
let parsed;
|
|
47789
47965
|
try {
|
|
47790
|
-
parsed = JSON.parse(
|
|
47966
|
+
parsed = JSON.parse(readFileSync54(path2, "utf8"));
|
|
47791
47967
|
} catch (e) {
|
|
47792
47968
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
47793
47969
|
}
|
|
@@ -47808,7 +47984,7 @@ function readNetRules(path2) {
|
|
|
47808
47984
|
function defaultNetRules(dir) {
|
|
47809
47985
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
47810
47986
|
const p = resolve40(dir, rel);
|
|
47811
|
-
if (
|
|
47987
|
+
if (existsSync50(p)) {
|
|
47812
47988
|
const rules = readNetRules(p);
|
|
47813
47989
|
if (rules.length) return { rules, from: rel };
|
|
47814
47990
|
}
|
|
@@ -47824,7 +48000,7 @@ function readCannedResponses() {
|
|
|
47824
48000
|
];
|
|
47825
48001
|
for (const url of candidates) {
|
|
47826
48002
|
try {
|
|
47827
|
-
const parsed = JSON.parse(
|
|
48003
|
+
const parsed = JSON.parse(readFileSync54(url, "utf8"));
|
|
47828
48004
|
const byKey = {};
|
|
47829
48005
|
for (const [k, v] of Object.entries(parsed)) {
|
|
47830
48006
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
@@ -47914,8 +48090,8 @@ function writeRecordedMocks(opts) {
|
|
|
47914
48090
|
mkdir: (p) => mkdirSync24(p, { recursive: true }),
|
|
47915
48091
|
write: (p, s) => writeFileSync20(p, s)
|
|
47916
48092
|
};
|
|
47917
|
-
fs.mkdir(
|
|
47918
|
-
fs.write(
|
|
48093
|
+
fs.mkdir(join48(opts.dir, "dev"));
|
|
48094
|
+
fs.write(join48(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
47919
48095
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
47920
48096
|
}
|
|
47921
48097
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -48418,14 +48594,14 @@ var mobile_ux_lint_exports = {};
|
|
|
48418
48594
|
__export(mobile_ux_lint_exports, {
|
|
48419
48595
|
mobileUxIssues: () => mobileUxIssues
|
|
48420
48596
|
});
|
|
48421
|
-
import { existsSync as
|
|
48422
|
-
import { join as
|
|
48597
|
+
import { existsSync as existsSync51, readFileSync as readFileSync55 } from "node:fs";
|
|
48598
|
+
import { join as join49 } from "node:path";
|
|
48423
48599
|
function mobileUxIssues(dir, strict) {
|
|
48424
|
-
const file =
|
|
48425
|
-
if (!
|
|
48600
|
+
const file = join49(dir, "MOBILE-UX.md");
|
|
48601
|
+
if (!existsSync51(file)) return [];
|
|
48426
48602
|
let text5;
|
|
48427
48603
|
try {
|
|
48428
|
-
text5 =
|
|
48604
|
+
text5 = readFileSync55(file, "utf8");
|
|
48429
48605
|
} catch {
|
|
48430
48606
|
return [];
|
|
48431
48607
|
}
|
|
@@ -50100,8 +50276,8 @@ __export(functions_exports, {
|
|
|
50100
50276
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
50101
50277
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
50102
50278
|
});
|
|
50103
|
-
import { readFileSync as
|
|
50104
|
-
import { join as
|
|
50279
|
+
import { readFileSync as readFileSync56, existsSync as existsSync52 } from "node:fs";
|
|
50280
|
+
import { join as join50, resolve as resolve41 } from "node:path";
|
|
50105
50281
|
function resolveFunctionsTarget(input) {
|
|
50106
50282
|
const explicitUrl = input.functionsUrl?.trim();
|
|
50107
50283
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -50120,9 +50296,9 @@ async function loadFunctionsApp(dir) {
|
|
|
50120
50296
|
}
|
|
50121
50297
|
const sources = {};
|
|
50122
50298
|
for (const definition of config.functions.functions) {
|
|
50123
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
50299
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join50(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync52);
|
|
50124
50300
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
50125
|
-
sources[definition.name] =
|
|
50301
|
+
sources[definition.name] = readFileSync56(source, "utf8");
|
|
50126
50302
|
}
|
|
50127
50303
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
50128
50304
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -50282,10 +50458,10 @@ __export(studio_reel_exports, {
|
|
|
50282
50458
|
utcDay: () => utcDay
|
|
50283
50459
|
});
|
|
50284
50460
|
import { createHash as createHash25 } from "node:crypto";
|
|
50285
|
-
import { lstatSync as lstatSync9, readFileSync as
|
|
50286
|
-
import { basename as
|
|
50461
|
+
import { lstatSync as lstatSync9, readFileSync as readFileSync57 } from "node:fs";
|
|
50462
|
+
import { basename as basename13, join as join51 } from "node:path";
|
|
50287
50463
|
function loadMemory2(dir) {
|
|
50288
|
-
const m = readJson5(
|
|
50464
|
+
const m = readJson5(join51(dir, ".himi", "studio", "memory.json"));
|
|
50289
50465
|
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
50290
50466
|
const shots = [];
|
|
50291
50467
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
@@ -50322,8 +50498,8 @@ function planReel(dir) {
|
|
|
50322
50498
|
const memory = loadMemory2(dir);
|
|
50323
50499
|
const { entries } = readProgress(dir);
|
|
50324
50500
|
const summary = summarizeProgress(entries);
|
|
50325
|
-
const manifest = readJson5(
|
|
50326
|
-
const tokens = readJson5(
|
|
50501
|
+
const manifest = readJson5(join51(dir, "himalaya.content.json"));
|
|
50502
|
+
const tokens = readJson5(join51(dir, "tokens.json"));
|
|
50327
50503
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
50328
50504
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
50329
50505
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -50337,14 +50513,15 @@ function planReel(dir) {
|
|
|
50337
50513
|
const postcards = entries.map((e) => ({
|
|
50338
50514
|
ts: e.ts,
|
|
50339
50515
|
message: e.message,
|
|
50340
|
-
step: str(e.step),
|
|
50341
|
-
|
|
50516
|
+
step: isCliEntry(e) ? null : str(e.step),
|
|
50517
|
+
by: isCliEntry(e) ? CLI_AUTHOR : null,
|
|
50518
|
+
files: (Array.isArray(e.images) ? e.images : []).map((i) => isObj2(i) && typeof i.file === "string" ? basename13(i.file) : "").filter((f) => HISTORY_NAME.test(f))
|
|
50342
50519
|
}));
|
|
50343
50520
|
const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
|
|
50344
50521
|
const startedAt = times[0] ?? null;
|
|
50345
50522
|
const endedAt = [summary.lastAt, ...timeline.map((t) => t.ts)].filter((x) => !!x).sort().pop() ?? null;
|
|
50346
50523
|
return {
|
|
50347
|
-
app: typeof manifest?.name === "string" && manifest.name ? manifest.name :
|
|
50524
|
+
app: typeof manifest?.name === "string" && manifest.name ? manifest.name : basename13(dir),
|
|
50348
50525
|
accent,
|
|
50349
50526
|
startedAt,
|
|
50350
50527
|
endedAt,
|
|
@@ -50365,10 +50542,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
50365
50542
|
const verified = (f) => {
|
|
50366
50543
|
if (!HISTORY_NAME.test(f)) return null;
|
|
50367
50544
|
try {
|
|
50368
|
-
const path2 =
|
|
50545
|
+
const path2 = join51(dir, HISTORY_DIR, f);
|
|
50369
50546
|
const st = lstatSync9(path2);
|
|
50370
50547
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
50371
|
-
const bytes2 =
|
|
50548
|
+
const bytes2 = readFileSync57(path2);
|
|
50372
50549
|
return createHash25("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
50373
50550
|
} catch {
|
|
50374
50551
|
return null;
|
|
@@ -50462,7 +50639,7 @@ function renderReel(plan, images) {
|
|
|
50462
50639
|
.flipcap{flex:1;min-width:220px}.flipcap .t{font-size:40px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--accent)}.bar{height:4px;background:var(--line);border-radius:2px;margin-top:16px}.bar div{height:4px;background:var(--accent);border-radius:2px;width:0}
|
|
50463
50640
|
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:18px}.grid figure{margin:0;text-align:center}.grid img{width:100%;aspect-ratio:390/844;object-fit:cover;object-position:top;border:6px solid #111;border-radius:22px;background:#fff}
|
|
50464
50641
|
figcaption{font-size:12px;color:var(--muted);margin-top:6px;word-break:break-all}
|
|
50465
|
-
.log{list-style:none;padding:0;margin:0}.log li{display:flex;gap:14px;padding:12px 0;border-top:1px solid var(--line)}.log .t{min-width:52px;color:var(--muted);font-variant-numeric:tabular-nums}.log .s{font-size:12px;color:var(--muted);text-transform:capitalize}
|
|
50642
|
+
.log{list-style:none;padding:0;margin:0}.log li{display:flex;gap:14px;padding:12px 0;border-top:1px solid var(--line)}.log .t{min-width:52px;color:var(--muted);font-variant-numeric:tabular-nums}.log .s{font-size:12px;color:var(--muted);text-transform:capitalize}.log .by{font-size:12px;color:var(--muted)}
|
|
50466
50643
|
.log .imgs{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}.log .imgs img{height:120px;border-radius:10px;border:1px solid var(--line)}
|
|
50467
50644
|
footer{margin-top:48px;font-size:12px;color:var(--muted)}
|
|
50468
50645
|
</style></head><body><div class="wrap">
|
|
@@ -50473,7 +50650,7 @@ ${flip}
|
|
|
50473
50650
|
<h2>Where it ended up</h2>
|
|
50474
50651
|
<div class="grid">${plan.finals.map((f) => `<figure>${img(f.file, f.id)}<figcaption>${escapeHtml(f.id)}</figcaption></figure>`).join("")}</div>
|
|
50475
50652
|
<h2>Postcards</h2>
|
|
50476
|
-
<ul class="log">${plan.postcards.map((c) => `<li><div class="t">${clock(c.ts)}</div><div><div>${escapeHtml(c.message)}</div>${c.step ? `<div class="s">step ${JOURNEY_STEPS.indexOf(c.step) + 1} \xB7 ${escapeHtml(c.step)}</div>` : ""}${c.files.length ? `<div class="imgs">${c.files.map((f) => img(f, c.message)).join("")}</div>` : ""}</div></li>`).join("") || `<li class="muted">No postcards were journaled.</li>`}</ul>
|
|
50653
|
+
<ul class="log">${plan.postcards.map((c) => `<li><div class="t">${clock(c.ts)}</div><div><div>${escapeHtml(c.message)}</div>${c.step ? `<div class="s">step ${JOURNEY_STEPS.indexOf(c.step) + 1} \xB7 ${escapeHtml(c.step)}</div>` : ""}${c.by ? `<div class="by">noted by ${escapeHtml(c.by)}</div>` : ""}${c.files.length ? `<div class="imgs">${c.files.map((f) => img(f, c.message)).join("")}</div>` : ""}</div></li>`).join("") || `<li class="muted">No postcards were journaled.</li>`}</ul>
|
|
50477
50654
|
<footer>Built with himi.${plan.dropped ? ` ${count2(plan.dropped)} pictures were left out to keep this file small.` : ""}</footer>
|
|
50478
50655
|
</div>
|
|
50479
50656
|
<script>
|
|
@@ -50502,7 +50679,7 @@ var init_studio_reel = __esm({
|
|
|
50502
50679
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
50503
50680
|
readJson5 = (file) => {
|
|
50504
50681
|
try {
|
|
50505
|
-
return JSON.parse(
|
|
50682
|
+
return JSON.parse(readFileSync57(file, "utf8"));
|
|
50506
50683
|
} catch {
|
|
50507
50684
|
return null;
|
|
50508
50685
|
}
|
|
@@ -50533,9 +50710,9 @@ __export(native_decode_exports, {
|
|
|
50533
50710
|
runNativeDecode: () => runNativeDecode
|
|
50534
50711
|
});
|
|
50535
50712
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
50536
|
-
import { existsSync as
|
|
50713
|
+
import { existsSync as existsSync53, mkdtempSync as mkdtempSync2, readFileSync as readFileSync58, rmSync as rmSync11, writeFileSync as writeFileSync21 } from "node:fs";
|
|
50537
50714
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
50538
|
-
import { join as
|
|
50715
|
+
import { join as join52 } from "node:path";
|
|
50539
50716
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
50540
50717
|
function nativeDecodePackageDir() {
|
|
50541
50718
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -50545,8 +50722,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
50545
50722
|
}
|
|
50546
50723
|
function nativeOracleShipped() {
|
|
50547
50724
|
return {
|
|
50548
|
-
ios:
|
|
50549
|
-
android:
|
|
50725
|
+
ios: existsSync53(join52(nativeDecodePackageDir(), "Package.swift")),
|
|
50726
|
+
android: existsSync53(join52(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
50550
50727
|
};
|
|
50551
50728
|
}
|
|
50552
50729
|
function detectNativeDecode(options = {}) {
|
|
@@ -50557,7 +50734,7 @@ function detectNativeDecode(options = {}) {
|
|
|
50557
50734
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
50558
50735
|
}
|
|
50559
50736
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
50560
|
-
const packageAvailable = options.packageAvailable ??
|
|
50737
|
+
const packageAvailable = options.packageAvailable ?? existsSync53(join52(packageDir, "Package.swift"));
|
|
50561
50738
|
if (!packageAvailable) {
|
|
50562
50739
|
return {
|
|
50563
50740
|
platform: "ios",
|
|
@@ -50569,7 +50746,7 @@ function detectNativeDecode(options = {}) {
|
|
|
50569
50746
|
}
|
|
50570
50747
|
function localPropertiesSdk(harnessDir) {
|
|
50571
50748
|
try {
|
|
50572
|
-
const match =
|
|
50749
|
+
const match = readFileSync58(join52(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
50573
50750
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
50574
50751
|
} catch {
|
|
50575
50752
|
return null;
|
|
@@ -50577,8 +50754,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
50577
50754
|
}
|
|
50578
50755
|
function detectAndroidNativeDecode(options = {}) {
|
|
50579
50756
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
50580
|
-
const gradlew =
|
|
50581
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
50757
|
+
const gradlew = join52(harnessDir, "gradlew");
|
|
50758
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync53(gradlew);
|
|
50582
50759
|
if (!gradlewAvailable) {
|
|
50583
50760
|
return {
|
|
50584
50761
|
platform: "android",
|
|
@@ -50588,7 +50765,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
50588
50765
|
}
|
|
50589
50766
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
50590
50767
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
50591
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
50768
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync53(sdk));
|
|
50592
50769
|
if (!sdkAvailable) {
|
|
50593
50770
|
return {
|
|
50594
50771
|
platform: "android",
|
|
@@ -50660,14 +50837,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
50660
50837
|
return verdicts;
|
|
50661
50838
|
}
|
|
50662
50839
|
function runNativeDecode(options) {
|
|
50663
|
-
const descriptorDir = mkdtempSync2(
|
|
50840
|
+
const descriptorDir = mkdtempSync2(join52(tmpdir3(), "himi-native-decode-"));
|
|
50664
50841
|
const startedAt = Date.now();
|
|
50665
50842
|
try {
|
|
50666
50843
|
for (const descriptor of options.descriptors) {
|
|
50667
50844
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50668
50845
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50669
50846
|
}
|
|
50670
|
-
writeFileSync21(
|
|
50847
|
+
writeFileSync21(join52(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50671
50848
|
}
|
|
50672
50849
|
options.progress?.("building cached Swift oracle");
|
|
50673
50850
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -50679,7 +50856,7 @@ function runNativeDecode(options) {
|
|
|
50679
50856
|
encoding: "utf8"
|
|
50680
50857
|
}).trim();
|
|
50681
50858
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50682
|
-
const stdout = execFileSync5(
|
|
50859
|
+
const stdout = execFileSync5(join52(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
50683
50860
|
stdio: ["ignore", "pipe", "pipe"],
|
|
50684
50861
|
encoding: "utf8"
|
|
50685
50862
|
});
|
|
@@ -50697,15 +50874,15 @@ function runNativeDecode(options) {
|
|
|
50697
50874
|
}
|
|
50698
50875
|
}
|
|
50699
50876
|
function runAndroidNativeDecode(options) {
|
|
50700
|
-
const descriptorDir = mkdtempSync2(
|
|
50701
|
-
const outputPath =
|
|
50877
|
+
const descriptorDir = mkdtempSync2(join52(tmpdir3(), "himi-native-decode-android-"));
|
|
50878
|
+
const outputPath = join52(descriptorDir, "verdicts.ndjson");
|
|
50702
50879
|
const startedAt = Date.now();
|
|
50703
50880
|
try {
|
|
50704
50881
|
for (const descriptor of options.descriptors) {
|
|
50705
50882
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50706
50883
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50707
50884
|
}
|
|
50708
|
-
writeFileSync21(
|
|
50885
|
+
writeFileSync21(join52(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50709
50886
|
}
|
|
50710
50887
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50711
50888
|
execFileSync5(options.gradlew, [
|
|
@@ -50720,7 +50897,7 @@ function runAndroidNativeDecode(options) {
|
|
|
50720
50897
|
stdio: ["ignore", "ignore", "pipe"],
|
|
50721
50898
|
encoding: "utf8"
|
|
50722
50899
|
});
|
|
50723
|
-
const stdout =
|
|
50900
|
+
const stdout = readFileSync58(outputPath, "utf8");
|
|
50724
50901
|
return {
|
|
50725
50902
|
platform: "android",
|
|
50726
50903
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -50790,13 +50967,13 @@ __export(browser_authoring_exports, {
|
|
|
50790
50967
|
});
|
|
50791
50968
|
import { createServer as createServer3 } from "node:http";
|
|
50792
50969
|
import { createHash as createHash26, randomBytes as randomBytes4 } from "node:crypto";
|
|
50793
|
-
import { existsSync as
|
|
50794
|
-
import { join as
|
|
50970
|
+
import { existsSync as existsSync54, readdirSync as readdirSync27, readFileSync as readFileSync59, realpathSync as realpathSync6, statSync as statSync12 } from "node:fs";
|
|
50971
|
+
import { join as join53, posix as posix2, relative as relative10, sep as sep12 } from "node:path";
|
|
50795
50972
|
function humanMs(ms) {
|
|
50796
50973
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
50797
50974
|
}
|
|
50798
50975
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
50799
|
-
const root =
|
|
50976
|
+
const root = join53(tier5SrcDir, bundleName);
|
|
50800
50977
|
const files = {};
|
|
50801
50978
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
50802
50979
|
const walk2 = (abs, rel) => {
|
|
@@ -50804,16 +50981,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
|
50804
50981
|
if (visitedDirs.has(real)) return;
|
|
50805
50982
|
visitedDirs.add(real);
|
|
50806
50983
|
for (const name of readdirSync27(abs).sort()) {
|
|
50807
|
-
const childAbs =
|
|
50984
|
+
const childAbs = join53(abs, name);
|
|
50808
50985
|
const childRel = posix2.join(rel, name);
|
|
50809
50986
|
if (statSync12(childAbs).isDirectory()) {
|
|
50810
50987
|
walk2(childAbs, childRel);
|
|
50811
50988
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
50812
|
-
files[childRel] =
|
|
50989
|
+
files[childRel] = readFileSync59(childAbs, "utf8");
|
|
50813
50990
|
}
|
|
50814
50991
|
}
|
|
50815
50992
|
};
|
|
50816
|
-
if (!
|
|
50993
|
+
if (!existsSync54(root)) return null;
|
|
50817
50994
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
50818
50995
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
50819
50996
|
if (!entry) return null;
|
|
@@ -50830,20 +51007,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
50830
51007
|
const spec = m[1];
|
|
50831
51008
|
const virtual = posix2.normalize(posix2.join(dir, spec));
|
|
50832
51009
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
50833
|
-
const onDisk =
|
|
51010
|
+
const onDisk = join53(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
50834
51011
|
const candidates = [
|
|
50835
51012
|
onDisk,
|
|
50836
51013
|
`${onDisk}.ts`,
|
|
50837
51014
|
`${onDisk}.js`,
|
|
50838
51015
|
onDisk.replace(/\.js$/, ".ts"),
|
|
50839
|
-
|
|
50840
|
-
|
|
51016
|
+
join53(onDisk, "index.ts"),
|
|
51017
|
+
join53(onDisk, "index.js")
|
|
50841
51018
|
];
|
|
50842
51019
|
for (const abs of candidates) {
|
|
50843
|
-
if (!
|
|
50844
|
-
const key2 = `/tier5-src/${
|
|
51020
|
+
if (!existsSync54(abs) || statSync12(abs).isDirectory()) continue;
|
|
51021
|
+
const key2 = `/tier5-src/${relative10(tier5SrcDir, abs).split(sep12).join(posix2.sep)}`;
|
|
50845
51022
|
if (key2 in files) break;
|
|
50846
|
-
files[key2] =
|
|
51023
|
+
files[key2] = readFileSync59(abs, "utf8");
|
|
50847
51024
|
queue.push(key2);
|
|
50848
51025
|
break;
|
|
50849
51026
|
}
|
|
@@ -50878,7 +51055,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
50878
51055
|
function sdkSubpathReader(resolve48) {
|
|
50879
51056
|
return (sub) => {
|
|
50880
51057
|
try {
|
|
50881
|
-
return
|
|
51058
|
+
return readFileSync59(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
50882
51059
|
} catch {
|
|
50883
51060
|
return null;
|
|
50884
51061
|
}
|
|
@@ -51050,8 +51227,8 @@ __export(coverage_exports, {
|
|
|
51050
51227
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
51051
51228
|
trendAndStore: () => trendAndStore
|
|
51052
51229
|
});
|
|
51053
|
-
import { existsSync as
|
|
51054
|
-
import { dirname as dirname28, join as
|
|
51230
|
+
import { existsSync as existsSync55, mkdirSync as mkdirSync25, readFileSync as readFileSync60, writeFileSync as writeFileSync22 } from "node:fs";
|
|
51231
|
+
import { dirname as dirname28, join as join54 } from "node:path";
|
|
51055
51232
|
function suppressedNativeKeys(oracle) {
|
|
51056
51233
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
51057
51234
|
}
|
|
@@ -51231,11 +51408,11 @@ function assembleLedger(r, options = {}) {
|
|
|
51231
51408
|
return out;
|
|
51232
51409
|
}
|
|
51233
51410
|
function trendAndStore(dir, entries, suppressed) {
|
|
51234
|
-
const p =
|
|
51411
|
+
const p = join54(dir, LEDGER_FILE);
|
|
51235
51412
|
let previous = null;
|
|
51236
51413
|
try {
|
|
51237
|
-
if (
|
|
51238
|
-
const parsed = JSON.parse(
|
|
51414
|
+
if (existsSync55(p)) {
|
|
51415
|
+
const parsed = JSON.parse(readFileSync60(p, "utf8"));
|
|
51239
51416
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
51240
51417
|
}
|
|
51241
51418
|
} catch {
|
|
@@ -51274,11 +51451,11 @@ function formatLedger(entries, trend) {
|
|
|
51274
51451
|
return out.join("\n");
|
|
51275
51452
|
}
|
|
51276
51453
|
function diffAndStoreObservations(dir, current) {
|
|
51277
|
-
const p =
|
|
51454
|
+
const p = join54(dir, OBS_FILE);
|
|
51278
51455
|
let previous = null;
|
|
51279
51456
|
try {
|
|
51280
|
-
if (
|
|
51281
|
-
const parsed = JSON.parse(
|
|
51457
|
+
if (existsSync55(p)) {
|
|
51458
|
+
const parsed = JSON.parse(readFileSync60(p, "utf8"));
|
|
51282
51459
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
51283
51460
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
51284
51461
|
)) {
|
|
@@ -51327,8 +51504,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
51327
51504
|
var init_coverage = __esm({
|
|
51328
51505
|
"src/coverage.ts"() {
|
|
51329
51506
|
init_native_decode();
|
|
51330
|
-
LEDGER_FILE =
|
|
51331
|
-
OBS_FILE =
|
|
51507
|
+
LEDGER_FILE = join54(".himi", "test-ledger.json");
|
|
51508
|
+
OBS_FILE = join54(".himi", "test-observations.json");
|
|
51332
51509
|
}
|
|
51333
51510
|
});
|
|
51334
51511
|
|
|
@@ -51339,16 +51516,16 @@ __export(design_kits_exports, {
|
|
|
51339
51516
|
kitsDir: () => kitsDir,
|
|
51340
51517
|
listKits: () => listKits2
|
|
51341
51518
|
});
|
|
51342
|
-
import { existsSync as
|
|
51343
|
-
import { join as
|
|
51519
|
+
import { existsSync as existsSync56, readFileSync as readFileSync61, readdirSync as readdirSync28 } from "node:fs";
|
|
51520
|
+
import { join as join55, basename as basename14 } from "node:path";
|
|
51344
51521
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
51345
51522
|
function kitsDir() {
|
|
51346
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
51523
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync56(p));
|
|
51347
51524
|
}
|
|
51348
51525
|
function listKits2() {
|
|
51349
51526
|
const dir = kitsDir();
|
|
51350
51527
|
if (!dir) return [];
|
|
51351
|
-
return readdirSync28(dir).filter((f) => f.endsWith(".json")).map((f) =>
|
|
51528
|
+
return readdirSync28(dir).filter((f) => f.endsWith(".json")).map((f) => basename14(f, ".json")).sort();
|
|
51352
51529
|
}
|
|
51353
51530
|
function kitReport(name) {
|
|
51354
51531
|
const dir = kitsDir();
|
|
@@ -51367,7 +51544,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
51367
51544
|
if (!kits.includes(name)) {
|
|
51368
51545
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
51369
51546
|
}
|
|
51370
|
-
const raw =
|
|
51547
|
+
const raw = readFileSync61(join55(dir, `${name}.json`), "utf8");
|
|
51371
51548
|
let parsed;
|
|
51372
51549
|
try {
|
|
51373
51550
|
parsed = JSON.parse(raw);
|
|
@@ -51391,9 +51568,9 @@ var init_design_kits = __esm({
|
|
|
51391
51568
|
"src/design-kits.ts"() {
|
|
51392
51569
|
KIT_DIR_CANDIDATES = [
|
|
51393
51570
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
51394
|
-
|
|
51571
|
+
join55(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
51395
51572
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
51396
|
-
|
|
51573
|
+
join55(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
51397
51574
|
];
|
|
51398
51575
|
}
|
|
51399
51576
|
});
|
|
@@ -51407,11 +51584,11 @@ __export(assets_exports, {
|
|
|
51407
51584
|
removeAssetPayload: () => removeAssetPayload,
|
|
51408
51585
|
verifyReport: () => verifyReport
|
|
51409
51586
|
});
|
|
51410
|
-
import { readFileSync as
|
|
51411
|
-
import { basename as
|
|
51587
|
+
import { readFileSync as readFileSync62 } from "node:fs";
|
|
51588
|
+
import { basename as basename15 } from "node:path";
|
|
51412
51589
|
function declaredAssets(dir) {
|
|
51413
51590
|
return collectAssets(dir).map((a) => {
|
|
51414
|
-
const bytes2 =
|
|
51591
|
+
const bytes2 = readFileSync62(a.path);
|
|
51415
51592
|
return {
|
|
51416
51593
|
name: a.name,
|
|
51417
51594
|
sha256: assetSha256(bytes2),
|
|
@@ -51488,8 +51665,8 @@ function verifyReport(dir, app, manifest) {
|
|
|
51488
51665
|
};
|
|
51489
51666
|
}
|
|
51490
51667
|
function addAssetPayload(manifest, filePath, opts) {
|
|
51491
|
-
const bytes2 =
|
|
51492
|
-
const name = opts.name ??
|
|
51668
|
+
const bytes2 = readFileSync62(filePath);
|
|
51669
|
+
const name = opts.name ?? basename15(filePath);
|
|
51493
51670
|
const sha2565 = assetSha256(bytes2);
|
|
51494
51671
|
const record2 = {
|
|
51495
51672
|
sha256: sha2565,
|
|
@@ -53163,9 +53340,9 @@ __export(run_exports, {
|
|
|
53163
53340
|
runPackage: () => runPackage,
|
|
53164
53341
|
withoutProdServe: () => withoutProdServe
|
|
53165
53342
|
});
|
|
53166
|
-
import { cpSync as cpSync2, existsSync as
|
|
53343
|
+
import { cpSync as cpSync2, existsSync as existsSync57, mkdirSync as mkdirSync26, mkdtempSync as mkdtempSync3, readFileSync as readFileSync63, rmSync as rmSync12, statSync as statSync13 } from "node:fs";
|
|
53167
53344
|
import { networkInterfaces as osNetworkInterfaces, tmpdir as tmpdir4 } from "node:os";
|
|
53168
|
-
import { dirname as dirname29, join as
|
|
53345
|
+
import { dirname as dirname29, join as join56 } from "node:path";
|
|
53169
53346
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
53170
53347
|
function makePackageRunHandler(opts) {
|
|
53171
53348
|
const store = new FileReleaseStore(opts.releaseRoot);
|
|
@@ -53193,9 +53370,9 @@ async function fetchBytes(url) {
|
|
|
53193
53370
|
}
|
|
53194
53371
|
async function resolvePackage(source, workDir) {
|
|
53195
53372
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
53196
|
-
if (!isUrl2 &&
|
|
53197
|
-
const appDirManifest =
|
|
53198
|
-
if (
|
|
53373
|
+
if (!isUrl2 && existsSync57(source) && statSync13(source).isDirectory()) {
|
|
53374
|
+
const appDirManifest = join56(source, "release-manifest.json");
|
|
53375
|
+
if (existsSync57(appDirManifest)) {
|
|
53199
53376
|
const opened2 = openPackageDir(source);
|
|
53200
53377
|
if (!opened2.validation.ok) {
|
|
53201
53378
|
throw new Error(`package is not valid:
|
|
@@ -53204,9 +53381,9 @@ async function resolvePackage(source, workDir) {
|
|
|
53204
53381
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
53205
53382
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
53206
53383
|
if (!isSafeAppId(app2)) throw new Error(`${source} declares an unsafe app id ${JSON.stringify(app2)} \u2014 refusing to open it`);
|
|
53207
|
-
const root2 = workDir ?? mkdtempSync3(
|
|
53208
|
-
const target =
|
|
53209
|
-
if (
|
|
53384
|
+
const root2 = workDir ?? mkdtempSync3(join56(tmpdir4(), "himi-run-"));
|
|
53385
|
+
const target = join56(root2, app2);
|
|
53386
|
+
if (join56(source) !== target) {
|
|
53210
53387
|
mkdirSync26(root2, { recursive: true });
|
|
53211
53388
|
rmSync12(target, { recursive: true, force: true });
|
|
53212
53389
|
cpSync2(source, target, { recursive: true });
|
|
@@ -53223,8 +53400,8 @@ async function resolvePackage(source, workDir) {
|
|
|
53223
53400
|
}
|
|
53224
53401
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
53225
53402
|
}
|
|
53226
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
53227
|
-
const root = workDir ?? mkdtempSync3(
|
|
53403
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync63(source);
|
|
53404
|
+
const root = workDir ?? mkdtempSync3(join56(tmpdir4(), "himi-run-"));
|
|
53228
53405
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
53229
53406
|
const opened = openPackageDir(appDir2);
|
|
53230
53407
|
if (!opened.validation.ok) {
|
|
@@ -53247,14 +53424,14 @@ async function loadPreviewAssets() {
|
|
|
53247
53424
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
53248
53425
|
const here = dirname29(fileURLToPath22(import.meta.url));
|
|
53249
53426
|
const candidates = [
|
|
53250
|
-
|
|
53427
|
+
join56(here, "preview-assets.generated.bin"),
|
|
53251
53428
|
// published: copied next to the bundled CLI
|
|
53252
|
-
|
|
53429
|
+
join56(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
53253
53430
|
// in-repo checkout
|
|
53254
53431
|
];
|
|
53255
53432
|
for (const path2 of candidates) {
|
|
53256
|
-
if (!
|
|
53257
|
-
const blob =
|
|
53433
|
+
if (!existsSync57(path2)) continue;
|
|
53434
|
+
const blob = readFileSync63(path2);
|
|
53258
53435
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
53259
53436
|
}
|
|
53260
53437
|
return /* @__PURE__ */ new Map();
|
|
@@ -53401,9 +53578,9 @@ __export(run_watch_exports, {
|
|
|
53401
53578
|
watchedContentDir: () => watchedContentDir,
|
|
53402
53579
|
writeRunRecord: () => writeRunRecord
|
|
53403
53580
|
});
|
|
53404
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
53581
|
+
import { closeSync as closeSync2, constants, existsSync as existsSync58, fstatSync, lstatSync as lstatSync10, statSync as statSync14, mkdirSync as mkdirSync27, openSync as openSync2, readFileSync as readFileSync64, realpathSync as realpathSync7, renameSync as renameSync6, rmSync as rmSync13, writeFileSync as writeFileSync23, watch as fsWatch } from "node:fs";
|
|
53405
53582
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
53406
|
-
import { extname as extname4, join as
|
|
53583
|
+
import { extname as extname4, join as join57, resolve as resolve42, sep as sep13 } from "node:path";
|
|
53407
53584
|
function diffReleases(prev, next) {
|
|
53408
53585
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
53409
53586
|
const changedBundles = new Set(bundles);
|
|
@@ -53444,7 +53621,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
53444
53621
|
let timer = null;
|
|
53445
53622
|
const pending = /* @__PURE__ */ new Set();
|
|
53446
53623
|
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
53447
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
53624
|
+
if (!file || ignoredChange(file, (rel) => isDir(join57(dir, rel)))) return;
|
|
53448
53625
|
pending.add(file);
|
|
53449
53626
|
if (timer) clearTimeout(timer);
|
|
53450
53627
|
timer = setTimeout(() => {
|
|
@@ -53465,7 +53642,7 @@ function watchedContentDir(source) {
|
|
|
53465
53642
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
53466
53643
|
const dir = resolve42(source);
|
|
53467
53644
|
try {
|
|
53468
|
-
return statSync14(dir).isDirectory() &&
|
|
53645
|
+
return statSync14(dir).isDirectory() && existsSync58(join57(dir, "himalaya.content.json")) ? dir : null;
|
|
53469
53646
|
} catch {
|
|
53470
53647
|
return null;
|
|
53471
53648
|
}
|
|
@@ -53522,7 +53699,7 @@ function serialize(task) {
|
|
|
53522
53699
|
});
|
|
53523
53700
|
}
|
|
53524
53701
|
function himiDir(dir) {
|
|
53525
|
-
const root =
|
|
53702
|
+
const root = join57(dir, ".himi");
|
|
53526
53703
|
try {
|
|
53527
53704
|
return lstatSync10(root).isDirectory() ? root : null;
|
|
53528
53705
|
} catch (e) {
|
|
@@ -53534,11 +53711,11 @@ function himiDir(dir) {
|
|
|
53534
53711
|
function writeRunRecord(dir, record2) {
|
|
53535
53712
|
const root = himiDir(dir);
|
|
53536
53713
|
if (!root) return false;
|
|
53537
|
-
const tmp =
|
|
53714
|
+
const tmp = join57(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
53538
53715
|
try {
|
|
53539
53716
|
writeFileSync23(tmp, `${JSON.stringify(record2, null, 2)}
|
|
53540
53717
|
`, { flag: "wx" });
|
|
53541
|
-
renameSync6(tmp,
|
|
53718
|
+
renameSync6(tmp, join57(root, "run.json"));
|
|
53542
53719
|
} catch (e) {
|
|
53543
53720
|
rmSync13(tmp, { force: true });
|
|
53544
53721
|
throw e;
|
|
@@ -53546,7 +53723,7 @@ function writeRunRecord(dir, record2) {
|
|
|
53546
53723
|
return true;
|
|
53547
53724
|
}
|
|
53548
53725
|
function removeRunRecord(dir, owner) {
|
|
53549
|
-
const root =
|
|
53726
|
+
const root = join57(dir, ".himi");
|
|
53550
53727
|
try {
|
|
53551
53728
|
if (!lstatSync10(root).isDirectory()) return;
|
|
53552
53729
|
} catch {
|
|
@@ -53561,16 +53738,16 @@ function removeRunRecord(dir, owner) {
|
|
|
53561
53738
|
}
|
|
53562
53739
|
if (typeof pid === "number" && pid !== owner) return;
|
|
53563
53740
|
}
|
|
53564
|
-
rmSync13(
|
|
53741
|
+
rmSync13(join57(root, "run.json"), { force: true });
|
|
53565
53742
|
}
|
|
53566
53743
|
function boardFile(dir, pathname) {
|
|
53567
53744
|
let rel = null;
|
|
53568
|
-
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel =
|
|
53569
|
-
else if (pathname === "/__himi/studio/state.js") rel =
|
|
53570
|
-
else if (pathname === "/__himi/studio/timeline.js") rel =
|
|
53745
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join57("studio", "index.html");
|
|
53746
|
+
else if (pathname === "/__himi/studio/state.js") rel = join57("studio", "state.js");
|
|
53747
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join57("studio", "timeline.js");
|
|
53571
53748
|
else {
|
|
53572
53749
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
53573
|
-
if (m) rel =
|
|
53750
|
+
if (m) rel = join57("history", m[1]);
|
|
53574
53751
|
}
|
|
53575
53752
|
if (!rel) return null;
|
|
53576
53753
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -53586,7 +53763,7 @@ function readConfined(root, rel) {
|
|
|
53586
53763
|
const parts = rel.split(sep13);
|
|
53587
53764
|
let at = root;
|
|
53588
53765
|
for (let i = 0; i < parts.length; i++) {
|
|
53589
|
-
at =
|
|
53766
|
+
at = join57(at, parts[i]);
|
|
53590
53767
|
const st = lstatSync10(at);
|
|
53591
53768
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
53592
53769
|
}
|
|
@@ -53595,7 +53772,7 @@ function readConfined(root, rel) {
|
|
|
53595
53772
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
53596
53773
|
try {
|
|
53597
53774
|
if (!fstatSync(fd).isFile()) return null;
|
|
53598
|
-
return
|
|
53775
|
+
return readFileSync64(fd);
|
|
53599
53776
|
} finally {
|
|
53600
53777
|
closeSync2(fd);
|
|
53601
53778
|
}
|
|
@@ -53647,7 +53824,7 @@ __export(run_browser_exports, {
|
|
|
53647
53824
|
runInBrowser: () => runInBrowser
|
|
53648
53825
|
});
|
|
53649
53826
|
import { createServer as createServer5 } from "node:http";
|
|
53650
|
-
import { existsSync as
|
|
53827
|
+
import { existsSync as existsSync59, readFileSync as readFileSync65 } from "node:fs";
|
|
53651
53828
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
53652
53829
|
import { dirname as dirname30, resolve as resolve43 } from "node:path";
|
|
53653
53830
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -53655,7 +53832,7 @@ function stagedDir() {
|
|
|
53655
53832
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
53656
53833
|
}
|
|
53657
53834
|
function missingStaged() {
|
|
53658
|
-
return [...SERVED].filter((f) => !
|
|
53835
|
+
return [...SERVED].filter((f) => !existsSync59(resolve43(stagedDir(), f))).sort();
|
|
53659
53836
|
}
|
|
53660
53837
|
function ensureBrowserPlaneStaged() {
|
|
53661
53838
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -53740,7 +53917,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53740
53917
|
}
|
|
53741
53918
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
53742
53919
|
if (SERVED.has(name)) {
|
|
53743
|
-
if (!
|
|
53920
|
+
if (!existsSync59(resolve43(stagedDir(), name))) {
|
|
53744
53921
|
const restaged = ensureBrowserPlaneStaged();
|
|
53745
53922
|
if (!restaged.ok) {
|
|
53746
53923
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -53750,7 +53927,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53750
53927
|
}
|
|
53751
53928
|
let bytes2;
|
|
53752
53929
|
try {
|
|
53753
|
-
bytes2 =
|
|
53930
|
+
bytes2 = readFileSync65(resolve43(stagedDir(), name));
|
|
53754
53931
|
} catch (e) {
|
|
53755
53932
|
res.writeHead(503, { "content-type": "application/json" });
|
|
53756
53933
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -54211,11 +54388,11 @@ __export(preflight_exports, {
|
|
|
54211
54388
|
parseStoreConfig: () => parseStoreConfig,
|
|
54212
54389
|
requireEnv: () => requireEnv
|
|
54213
54390
|
});
|
|
54214
|
-
import { existsSync as
|
|
54215
|
-
import { isAbsolute as
|
|
54391
|
+
import { existsSync as existsSync60, readFileSync as readFileSync66 } from "node:fs";
|
|
54392
|
+
import { isAbsolute as isAbsolute5, relative as relative11, resolve as resolve44 } from "node:path";
|
|
54216
54393
|
function isInsideRepo(p) {
|
|
54217
|
-
const rel =
|
|
54218
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
54394
|
+
const rel = relative11(REPO_ROOT3, resolve44(p));
|
|
54395
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute5(rel);
|
|
54219
54396
|
}
|
|
54220
54397
|
function assertCredentialOutsideRepo(label2, p) {
|
|
54221
54398
|
if (isInsideRepo(p)) {
|
|
@@ -54268,10 +54445,10 @@ function parseStoreConfig(text5) {
|
|
|
54268
54445
|
}
|
|
54269
54446
|
function loadStoreConfig(app) {
|
|
54270
54447
|
const p = storeConfigPath(app);
|
|
54271
|
-
if (!
|
|
54448
|
+
if (!existsSync60(p)) {
|
|
54272
54449
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
54273
54450
|
}
|
|
54274
|
-
return parseStoreConfig(
|
|
54451
|
+
return parseStoreConfig(readFileSync66(p, "utf8"));
|
|
54275
54452
|
}
|
|
54276
54453
|
var init_preflight = __esm({
|
|
54277
54454
|
"../store-release/preflight.ts"() {
|
|
@@ -54290,19 +54467,19 @@ __export(credential_profile_exports, {
|
|
|
54290
54467
|
profilePath: () => profilePath,
|
|
54291
54468
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
54292
54469
|
});
|
|
54293
|
-
import { existsSync as
|
|
54470
|
+
import { existsSync as existsSync61, readFileSync as readFileSync67 } from "node:fs";
|
|
54294
54471
|
import { homedir as homedir5 } from "node:os";
|
|
54295
|
-
import { join as
|
|
54472
|
+
import { join as join58 } from "node:path";
|
|
54296
54473
|
function credentialsDir(home = homedir5()) {
|
|
54297
|
-
return
|
|
54474
|
+
return join58(home, ".himalaya", "store-credentials");
|
|
54298
54475
|
}
|
|
54299
54476
|
function profilePath(name, home = homedir5()) {
|
|
54300
54477
|
if (!PROFILE_NAME.test(name)) {
|
|
54301
54478
|
throw new Error(
|
|
54302
|
-
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${
|
|
54479
|
+
`credential profile ${JSON.stringify(name)} is not a profile name \u2014 use letters, digits, ".", "_" or "-" starting with a letter or digit. It names ${join58(credentialsDir(home), "<name>.json")}; it is never a path.`
|
|
54303
54480
|
);
|
|
54304
54481
|
}
|
|
54305
|
-
return
|
|
54482
|
+
return join58(credentialsDir(home), `${name}.json`);
|
|
54306
54483
|
}
|
|
54307
54484
|
function parseProfile(text5, label2) {
|
|
54308
54485
|
let doc;
|
|
@@ -54333,8 +54510,8 @@ function resolveStoreCredentials(opts) {
|
|
|
54333
54510
|
const { app, cfg } = opts;
|
|
54334
54511
|
const env = opts.env ?? process.env;
|
|
54335
54512
|
const home = opts.home ?? homedir5();
|
|
54336
|
-
const read = opts.readProfile ?? ((p) =>
|
|
54337
|
-
const exists = opts.profileExists ??
|
|
54513
|
+
const read = opts.readProfile ?? ((p) => readFileSync67(p, "utf8"));
|
|
54514
|
+
const exists = opts.profileExists ?? existsSync61;
|
|
54338
54515
|
const ios = cfg.ios ?? {};
|
|
54339
54516
|
const flagName = opts.profileFlag?.trim();
|
|
54340
54517
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -54414,9 +54591,9 @@ __export(preflight_app_exports, {
|
|
|
54414
54591
|
preflightApp: () => preflightApp,
|
|
54415
54592
|
profileAccount: () => profileAccount
|
|
54416
54593
|
});
|
|
54417
|
-
import { readFileSync as
|
|
54594
|
+
import { readFileSync as readFileSync68, existsSync as existsSync62, readdirSync as readdirSync29, statSync as statSync15 } from "node:fs";
|
|
54418
54595
|
import { createHash as createHash27 } from "node:crypto";
|
|
54419
|
-
import { join as
|
|
54596
|
+
import { join as join59 } from "node:path";
|
|
54420
54597
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
54421
54598
|
const f = [];
|
|
54422
54599
|
const has = (re, s) => re.test(s);
|
|
@@ -54480,13 +54657,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
54480
54657
|
}
|
|
54481
54658
|
}
|
|
54482
54659
|
async function preflightApp(app, opts = {}) {
|
|
54483
|
-
const projectYml =
|
|
54484
|
-
const storeConfig =
|
|
54660
|
+
const projectYml = existsSync62(iosProjectYml(app)) ? readFileSync68(iosProjectYml(app), "utf8") : "";
|
|
54661
|
+
const storeConfig = existsSync62(storeConfigPath(app)) ? readFileSync68(storeConfigPath(app), "utf8") : "";
|
|
54485
54662
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
54486
54663
|
const findings = analyze(
|
|
54487
54664
|
projectYml,
|
|
54488
54665
|
storeConfig,
|
|
54489
|
-
await appIconState(
|
|
54666
|
+
await appIconState(join59(appDir(app), "ios")),
|
|
54490
54667
|
profileAccount(app, storeConfig, opts)
|
|
54491
54668
|
);
|
|
54492
54669
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -54515,17 +54692,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
54515
54692
|
return f;
|
|
54516
54693
|
}
|
|
54517
54694
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
54518
|
-
const root =
|
|
54695
|
+
const root = join59(storeDir(app), "metadata");
|
|
54519
54696
|
const out = /* @__PURE__ */ new Set();
|
|
54520
|
-
if (
|
|
54697
|
+
if (existsSync62(root)) {
|
|
54521
54698
|
for (const n of readdirSync29(root)) if (n.endsWith(".txt")) out.add(n);
|
|
54522
54699
|
}
|
|
54523
|
-
if (
|
|
54700
|
+
if (existsSync62(join59(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
54524
54701
|
return out;
|
|
54525
54702
|
}
|
|
54526
54703
|
function reviewInfoFiles(app) {
|
|
54527
|
-
const dir =
|
|
54528
|
-
if (!
|
|
54704
|
+
const dir = join59(storeDir(app), "review_information");
|
|
54705
|
+
if (!existsSync62(dir)) return /* @__PURE__ */ new Set();
|
|
54529
54706
|
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
54530
54707
|
}
|
|
54531
54708
|
function isValidAppStoreSize(w, h) {
|
|
@@ -54635,12 +54812,12 @@ function analyzePlayListing(assets) {
|
|
|
54635
54812
|
return f;
|
|
54636
54813
|
}
|
|
54637
54814
|
function playListingAssets(app, locale = "en-US") {
|
|
54638
|
-
const dir =
|
|
54815
|
+
const dir = join59(storeDir(app), "play", locale, "images");
|
|
54639
54816
|
const read = (names) => {
|
|
54640
54817
|
for (const name of names) {
|
|
54641
|
-
const p =
|
|
54818
|
+
const p = join59(dir, name);
|
|
54642
54819
|
try {
|
|
54643
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
54820
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync68(p) };
|
|
54644
54821
|
} catch {
|
|
54645
54822
|
}
|
|
54646
54823
|
}
|
|
@@ -54671,26 +54848,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
54671
54848
|
return f;
|
|
54672
54849
|
}
|
|
54673
54850
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
54674
|
-
const dir =
|
|
54675
|
-
if (!
|
|
54851
|
+
const dir = join59(storeDir(app), "metadata", locale);
|
|
54852
|
+
if (!existsSync62(dir)) return /* @__PURE__ */ new Set();
|
|
54676
54853
|
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
54677
54854
|
}
|
|
54678
54855
|
function listScreenshots(app, locale = "en-US") {
|
|
54679
54856
|
const out = [];
|
|
54680
|
-
const flat =
|
|
54681
|
-
if (
|
|
54857
|
+
const flat = join59(storeDir(app), "screenshots", locale);
|
|
54858
|
+
if (existsSync62(flat)) {
|
|
54682
54859
|
for (const png of readdirSync29(flat).filter((n) => n.endsWith(".png"))) {
|
|
54683
|
-
const sz = pngSize(
|
|
54860
|
+
const sz = pngSize(readFileSync68(join59(flat, png)));
|
|
54684
54861
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
54685
54862
|
}
|
|
54686
54863
|
}
|
|
54687
|
-
const legacy =
|
|
54688
|
-
if (
|
|
54864
|
+
const legacy = join59(storeDir(app), "metadata", locale, "screenshots");
|
|
54865
|
+
if (existsSync62(legacy)) {
|
|
54689
54866
|
for (const deviceDir of readdirSync29(legacy)) {
|
|
54690
|
-
const d =
|
|
54867
|
+
const d = join59(legacy, deviceDir);
|
|
54691
54868
|
if (!statSync15(d).isDirectory()) continue;
|
|
54692
54869
|
for (const png of readdirSync29(d).filter((n) => n.endsWith(".png"))) {
|
|
54693
|
-
const sz = pngSize(
|
|
54870
|
+
const sz = pngSize(readFileSync68(join59(d, png)));
|
|
54694
54871
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
54695
54872
|
}
|
|
54696
54873
|
}
|
|
@@ -54698,13 +54875,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
54698
54875
|
return out;
|
|
54699
54876
|
}
|
|
54700
54877
|
function placeholderHashes2() {
|
|
54701
|
-
const templateIos =
|
|
54702
|
-
if (!
|
|
54878
|
+
const templateIos = join59(appDir("_template"), "ios");
|
|
54879
|
+
if (!existsSync62(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
54703
54880
|
for (const target of readdirSync29(templateIos)) {
|
|
54704
|
-
const p =
|
|
54881
|
+
const p = join59(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54705
54882
|
try {
|
|
54706
54883
|
if (!statSync15(p).isFile()) continue;
|
|
54707
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(
|
|
54884
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(readFileSync68(p)).digest("hex")];
|
|
54708
54885
|
} catch {
|
|
54709
54886
|
}
|
|
54710
54887
|
}
|
|
@@ -54735,12 +54912,12 @@ async function pixelIssues(bytes2) {
|
|
|
54735
54912
|
}
|
|
54736
54913
|
}
|
|
54737
54914
|
async function appIconState(iosDir) {
|
|
54738
|
-
if (!
|
|
54915
|
+
if (!existsSync62(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
54739
54916
|
for (const target of readdirSync29(iosDir)) {
|
|
54740
|
-
const p =
|
|
54917
|
+
const p = join59(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54741
54918
|
try {
|
|
54742
54919
|
if (!statSync15(p).isFile()) continue;
|
|
54743
|
-
const bytes2 =
|
|
54920
|
+
const bytes2 = readFileSync68(p);
|
|
54744
54921
|
const hash = createHash27("sha256").update(bytes2).digest("hex");
|
|
54745
54922
|
const pixels = await pixelIssues(bytes2);
|
|
54746
54923
|
return {
|
|
@@ -54812,7 +54989,7 @@ __export(version_exports, {
|
|
|
54812
54989
|
setAndroidVersion: () => setAndroidVersion,
|
|
54813
54990
|
setIosVersion: () => setIosVersion
|
|
54814
54991
|
});
|
|
54815
|
-
import { readFileSync as
|
|
54992
|
+
import { readFileSync as readFileSync69, writeFileSync as writeFileSync24 } from "node:fs";
|
|
54816
54993
|
function readIosVersion(projectYml) {
|
|
54817
54994
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
54818
54995
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -54870,8 +55047,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
54870
55047
|
function bumpVersion(app, opts) {
|
|
54871
55048
|
const iosPath = iosProjectYml(app);
|
|
54872
55049
|
const gradlePath = androidGradle(app);
|
|
54873
|
-
const iosYml =
|
|
54874
|
-
const gradle =
|
|
55050
|
+
const iosYml = readFileSync69(iosPath, "utf8");
|
|
55051
|
+
const gradle = readFileSync69(gradlePath, "utf8");
|
|
54875
55052
|
const current = readIosVersion(iosYml);
|
|
54876
55053
|
const next = {
|
|
54877
55054
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -54888,7 +55065,7 @@ var init_version = __esm({
|
|
|
54888
55065
|
});
|
|
54889
55066
|
|
|
54890
55067
|
// ../store-release/register-bundle.ts
|
|
54891
|
-
import { readFileSync as
|
|
55068
|
+
import { readFileSync as readFileSync70 } from "node:fs";
|
|
54892
55069
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
54893
55070
|
function b64url2(b) {
|
|
54894
55071
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -54906,7 +55083,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
54906
55083
|
async function registerBundleId(opts) {
|
|
54907
55084
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54908
55085
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54909
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
55086
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync70(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54910
55087
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
54911
55088
|
method: "POST",
|
|
54912
55089
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -54960,7 +55137,7 @@ __export(asc_status_exports, {
|
|
|
54960
55137
|
ascStatus: () => ascStatus,
|
|
54961
55138
|
buildVerdict: () => buildVerdict
|
|
54962
55139
|
});
|
|
54963
|
-
import { readFileSync as
|
|
55140
|
+
import { readFileSync as readFileSync71 } from "node:fs";
|
|
54964
55141
|
function buildVerdict(builds) {
|
|
54965
55142
|
if (!builds.length) {
|
|
54966
55143
|
return "NO builds registered \u2014 if you uploaded recently and it's been >15 min, the binary was REJECTED IN PROCESSING (reason is email-only; run validate-binary.ts / scan-purpose-strings.ts to reproduce it).";
|
|
@@ -54974,7 +55151,7 @@ function buildVerdict(builds) {
|
|
|
54974
55151
|
function client(creds) {
|
|
54975
55152
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54976
55153
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54977
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
55154
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync71(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54978
55155
|
return async (path2) => {
|
|
54979
55156
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
54980
55157
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -55134,7 +55311,7 @@ __export(secrets_exports, {
|
|
|
55134
55311
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
55135
55312
|
runSecretsCommand: () => runSecretsCommand
|
|
55136
55313
|
});
|
|
55137
|
-
import { readFileSync as
|
|
55314
|
+
import { readFileSync as readFileSync72 } from "node:fs";
|
|
55138
55315
|
function environment(value) {
|
|
55139
55316
|
if (value === "preview" || value === "production") return value;
|
|
55140
55317
|
throw new Error("--environment must be preview or production");
|
|
@@ -55165,7 +55342,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
55165
55342
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
55166
55343
|
return 0;
|
|
55167
55344
|
}
|
|
55168
|
-
const value = options.readValue ? options.readValue() :
|
|
55345
|
+
const value = options.readValue ? options.readValue() : readFileSync72(0, "utf8").replace(/\r?\n$/, "");
|
|
55169
55346
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
55170
55347
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
55171
55348
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -55194,7 +55371,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
55194
55371
|
}
|
|
55195
55372
|
let body;
|
|
55196
55373
|
if (operation !== "list") {
|
|
55197
|
-
const value = options.readValue ? options.readValue() :
|
|
55374
|
+
const value = options.readValue ? options.readValue() : readFileSync72(0, "utf8").replace(/\r?\n$/, "");
|
|
55198
55375
|
body = JSON.stringify({ value });
|
|
55199
55376
|
}
|
|
55200
55377
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -55230,15 +55407,15 @@ __export(notify_exports, {
|
|
|
55230
55407
|
runNotify: () => runNotify,
|
|
55231
55408
|
saveAdminSession: () => saveAdminSession
|
|
55232
55409
|
});
|
|
55233
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as
|
|
55410
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as readFileSync73, writeFileSync as writeFileSync25 } from "node:fs";
|
|
55234
55411
|
import { homedir as homedir6 } from "node:os";
|
|
55235
|
-
import { dirname as dirname32, join as
|
|
55412
|
+
import { dirname as dirname32, join as join60 } from "node:path";
|
|
55236
55413
|
function defaultSessionsPath() {
|
|
55237
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
55414
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join60(homedir6(), ".himalaya", "admin-sessions.json");
|
|
55238
55415
|
}
|
|
55239
55416
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
55240
55417
|
try {
|
|
55241
|
-
return JSON.parse(
|
|
55418
|
+
return JSON.parse(readFileSync73(path2, "utf8"));
|
|
55242
55419
|
} catch {
|
|
55243
55420
|
return {};
|
|
55244
55421
|
}
|
|
@@ -56368,7 +56545,7 @@ function deriveAdoptedCmsCollections(cms) {
|
|
|
56368
56545
|
return { collections, dropped };
|
|
56369
56546
|
}
|
|
56370
56547
|
function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
56371
|
-
const
|
|
56548
|
+
const appName2 = deriveAppName(ctx, overrides.appName);
|
|
56372
56549
|
const supportUrl = clean(overrides.supportUrl) || clean(ctx.url.primary);
|
|
56373
56550
|
const privacyUrl = clean(overrides.privacyUrl);
|
|
56374
56551
|
const termsUrl = clean(overrides.termsUrl);
|
|
@@ -56388,8 +56565,8 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
56388
56565
|
// empty; either way the key exists and the shell's list never survives the merge.
|
|
56389
56566
|
cmsCollections: [],
|
|
56390
56567
|
identity: {
|
|
56391
|
-
appName,
|
|
56392
|
-
businessName: clean(ctx.identity.businessName) ||
|
|
56568
|
+
appName: appName2,
|
|
56569
|
+
businessName: clean(ctx.identity.businessName) || appName2,
|
|
56393
56570
|
tagline: clean(overrides.tagline) || clean(ctx.identity.description),
|
|
56394
56571
|
// "" means UNKNOWN here, with `missing` above as the signal — the published overlay's
|
|
56395
56572
|
// documented shape. Keeping an unknown url out of a MERGE is `apply.ts`'s job, at the
|
|
@@ -56399,7 +56576,7 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
56399
56576
|
termsUrl
|
|
56400
56577
|
}
|
|
56401
56578
|
};
|
|
56402
|
-
return { appName, iconSource: deriveIconSource(ctx), provisioning, missing };
|
|
56579
|
+
return { appName: appName2, iconSource: deriveIconSource(ctx), provisioning, missing };
|
|
56403
56580
|
}
|
|
56404
56581
|
function bounded(s, max) {
|
|
56405
56582
|
if (s.length <= max) return s;
|
|
@@ -58495,11 +58672,11 @@ function crawledPageName(look, page) {
|
|
|
58495
58672
|
const hit = (page?.pageId ? sitePages.find((p) => p.pageId === page.pageId) : void 0) ?? (look.mainPageId ? sitePages.find((p) => p.pageId === look.mainPageId) : void 0) ?? sitePages.find((p) => p.slug === "home");
|
|
58496
58673
|
return hit?.title.trim() ?? "";
|
|
58497
58674
|
}
|
|
58498
|
-
function guessedNameWarning(
|
|
58499
|
-
const from = crawledTitle && crawledTitle !==
|
|
58675
|
+
function guessedNameWarning(appName2, crawledTitle, ownerLookupError) {
|
|
58676
|
+
const from = crawledTitle && crawledTitle !== appName2 ? ` off the crawled page title "${crawledTitle}"` : " from the site crawl";
|
|
58500
58677
|
const why = ownerLookupError ? `the owner site-properties read FAILED (${ownerLookupError}), so the owner-entered name was never read` : "no owner token was available, so site-properties was never read";
|
|
58501
58678
|
const remedy = ownerLookupError ? "resolve that failure and re-run the same owner-authenticated command" : "re-run with owner auth (`himi site analyze --site <msid>`)";
|
|
58502
|
-
return `identity.appName "${
|
|
58679
|
+
return `identity.appName "${appName2}" is a GUESS, read${from} rather than from the owner-entered business name \u2014 ${why}. --apply writes it into provisioning.json as-is and it reaches both app stores verbatim, so check it: ${remedy}, or set identity.appName in provisioning.json yourself.`;
|
|
58503
58680
|
}
|
|
58504
58681
|
function mergeLookFromPublished(look, published, siteUrl) {
|
|
58505
58682
|
const sitePages = withPageUrls(
|
|
@@ -59007,7 +59184,7 @@ var init_brand_font = __esm({
|
|
|
59007
59184
|
|
|
59008
59185
|
// src/site-analyze/write-artifacts.ts
|
|
59009
59186
|
import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
59010
|
-
import { join as
|
|
59187
|
+
import { join as join61 } from "node:path";
|
|
59011
59188
|
function attachVeloSources(book, sources, put) {
|
|
59012
59189
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
59013
59190
|
for (const f of book.velo.files) {
|
|
@@ -59162,12 +59339,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
59162
59339
|
}
|
|
59163
59340
|
async function writeBusinessBook(result, opts) {
|
|
59164
59341
|
const out = opts.outDir;
|
|
59165
|
-
mkdirSync29(
|
|
59166
|
-
mkdirSync29(
|
|
59342
|
+
mkdirSync29(join61(out, "evidence/pages"), { recursive: true });
|
|
59343
|
+
mkdirSync29(join61(out, "media/catalog"), { recursive: true });
|
|
59167
59344
|
const files = [];
|
|
59168
59345
|
const put = (rel, body) => {
|
|
59169
|
-
const p =
|
|
59170
|
-
mkdirSync29(
|
|
59346
|
+
const p = join61(out, rel);
|
|
59347
|
+
mkdirSync29(join61(p, ".."), { recursive: true });
|
|
59171
59348
|
writeFileSync26(p, body);
|
|
59172
59349
|
files.push(rel);
|
|
59173
59350
|
};
|
|
@@ -59261,8 +59438,8 @@ var init_customer_build = __esm({
|
|
|
59261
59438
|
});
|
|
59262
59439
|
|
|
59263
59440
|
// src/site-analyze/apply.ts
|
|
59264
|
-
import { existsSync as
|
|
59265
|
-
import { dirname as dirname33, isAbsolute as
|
|
59441
|
+
import { existsSync as existsSync63, readFileSync as readFileSync74, writeFileSync as writeFileSync27, copyFileSync as copyFileSync3, mkdirSync as mkdirSync30, realpathSync as realpathSync8, statSync as statSync16 } from "node:fs";
|
|
59442
|
+
import { dirname as dirname33, isAbsolute as isAbsolute6, join as join62, resolve as resolve45, sep as sep14 } from "node:path";
|
|
59266
59443
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
59267
59444
|
function unpairedRedirectNote(overlay) {
|
|
59268
59445
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -59277,7 +59454,7 @@ function committedShellProvisioning(path2) {
|
|
|
59277
59454
|
function findRepoRoot(cwd) {
|
|
59278
59455
|
let dir = cwd;
|
|
59279
59456
|
for (let i = 0; i < 8; i++) {
|
|
59280
|
-
if (SHELL_NAMES2.some((name) =>
|
|
59457
|
+
if (SHELL_NAMES2.some((name) => existsSync63(join62(dir, shellAppDir(name), "package.json")))) return dir;
|
|
59281
59458
|
const next = dirname33(dir);
|
|
59282
59459
|
if (next === dir) break;
|
|
59283
59460
|
dir = next;
|
|
@@ -59346,24 +59523,24 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
59346
59523
|
}
|
|
59347
59524
|
function buildMergedContract(options) {
|
|
59348
59525
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
59349
|
-
const committedPath =
|
|
59350
|
-
if (!
|
|
59526
|
+
const committedPath = join62(appDir2, "provisioning.json");
|
|
59527
|
+
if (!existsSync63(committedPath)) {
|
|
59351
59528
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
59352
59529
|
}
|
|
59353
|
-
const committed = JSON.parse(
|
|
59530
|
+
const committed = JSON.parse(readFileSync74(committedPath, "utf8"));
|
|
59354
59531
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
59355
59532
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
59356
59533
|
const branding = merged.branding ?? {};
|
|
59357
59534
|
const staged = [];
|
|
59358
59535
|
const contained = (root, rel) => {
|
|
59359
|
-
if (
|
|
59536
|
+
if (isAbsolute6(rel)) return void 0;
|
|
59360
59537
|
const full = resolve45(root, rel);
|
|
59361
59538
|
return full.startsWith(resolve45(root) + sep14) ? full : void 0;
|
|
59362
59539
|
};
|
|
59363
59540
|
const stage = (fromRel, toRel) => {
|
|
59364
59541
|
const from = contained(packageDir, fromRel);
|
|
59365
|
-
const to = contained(
|
|
59366
|
-
if (!from || !to || !
|
|
59542
|
+
const to = contained(join62(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
59543
|
+
if (!from || !to || !existsSync63(from)) return void 0;
|
|
59367
59544
|
let real;
|
|
59368
59545
|
let realRoot;
|
|
59369
59546
|
try {
|
|
@@ -59385,11 +59562,11 @@ function buildMergedContract(options) {
|
|
|
59385
59562
|
};
|
|
59386
59563
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
59387
59564
|
if (icon) branding.appIconPath = icon;
|
|
59388
|
-
const facesPath =
|
|
59389
|
-
if (
|
|
59565
|
+
const facesPath = join62(packageDir, "media/fonts/faces.json");
|
|
59566
|
+
if (existsSync63(facesPath)) {
|
|
59390
59567
|
let faces = [];
|
|
59391
59568
|
try {
|
|
59392
|
-
const parsed = JSON.parse(
|
|
59569
|
+
const parsed = JSON.parse(readFileSync74(facesPath, "utf8"));
|
|
59393
59570
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
59394
59571
|
} catch {
|
|
59395
59572
|
faces = [];
|
|
@@ -59410,9 +59587,9 @@ function buildMergedContract(options) {
|
|
|
59410
59587
|
merged.branding = branding;
|
|
59411
59588
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
59412
59589
|
`;
|
|
59413
|
-
const path2 =
|
|
59590
|
+
const path2 = join62(packageDir, "provisioning.contract.json");
|
|
59414
59591
|
writeFileSync27(path2, body);
|
|
59415
|
-
const localPath =
|
|
59592
|
+
const localPath = join62(appDir2, LOCAL_CONTRACT_REL);
|
|
59416
59593
|
mkdirSync30(dirname33(localPath), { recursive: true });
|
|
59417
59594
|
writeFileSync27(localPath, body);
|
|
59418
59595
|
staged.push(localPath);
|
|
@@ -59447,10 +59624,10 @@ function catalogTypography(overlay, template) {
|
|
|
59447
59624
|
function staticFaqFor(overlay, overlayPath) {
|
|
59448
59625
|
const own3 = overlay.faq;
|
|
59449
59626
|
if (own3 !== void 0) return deriveStaticFaq(own3);
|
|
59450
|
-
const bookPath =
|
|
59451
|
-
if (!
|
|
59627
|
+
const bookPath = join62(dirname33(resolve45(overlayPath)), "book.json");
|
|
59628
|
+
if (!existsSync63(bookPath)) return void 0;
|
|
59452
59629
|
try {
|
|
59453
|
-
const book = JSON.parse(
|
|
59630
|
+
const book = JSON.parse(readFileSync74(bookPath, "utf8"));
|
|
59454
59631
|
const copy = book?.copy;
|
|
59455
59632
|
if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
|
|
59456
59633
|
const pairs = deriveStaticFaq(copy.faq);
|
|
@@ -59464,8 +59641,8 @@ async function applyOverlays(input) {
|
|
|
59464
59641
|
const cwd = resolve45(input.cwd);
|
|
59465
59642
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
59466
59643
|
assertKnownShell(shell);
|
|
59467
|
-
const overlay = JSON.parse(
|
|
59468
|
-
const tokens = JSON.parse(
|
|
59644
|
+
const overlay = JSON.parse(readFileSync74(input.overlayPath, "utf8"));
|
|
59645
|
+
const tokens = JSON.parse(readFileSync74(input.tokensPath, "utf8"));
|
|
59469
59646
|
const faq = staticFaqFor(overlay, input.overlayPath);
|
|
59470
59647
|
if (faq !== void 0) overlay.faq = faq;
|
|
59471
59648
|
const wrote = [];
|
|
@@ -59477,9 +59654,9 @@ async function applyOverlays(input) {
|
|
|
59477
59654
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
59478
59655
|
);
|
|
59479
59656
|
}
|
|
59480
|
-
const appDir2 =
|
|
59481
|
-
const committedPath =
|
|
59482
|
-
const committedSite =
|
|
59657
|
+
const appDir2 = join62(repoRoot2, shellAppDir(shell));
|
|
59658
|
+
const committedPath = join62(appDir2, "provisioning.json");
|
|
59659
|
+
const committedSite = existsSync63(committedPath) ? JSON.parse(readFileSync74(committedPath, "utf8")).site : void 0;
|
|
59483
59660
|
if (committedSite !== void 0 && overlay.site === void 0) {
|
|
59484
59661
|
throw new Error(
|
|
59485
59662
|
`shell "${shell}" is a site shell: its contract names the customer's website (a \`site\` block), which this analysis does not produce yet. Write the site block into a contract and run \`npm run prepare:customer -- --contract <file>\` in ${shellAppDir(shell)} (or \`himi dist --shell ${shell}\`).`
|
|
@@ -59506,11 +59683,11 @@ async function applyOverlays(input) {
|
|
|
59506
59683
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
59507
59684
|
};
|
|
59508
59685
|
}
|
|
59509
|
-
const pkgProv =
|
|
59686
|
+
const pkgProv = join62(cwd, "provisioning.json");
|
|
59510
59687
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
59511
59688
|
let packageFaq = faq;
|
|
59512
|
-
if (
|
|
59513
|
-
const cur = JSON.parse(
|
|
59689
|
+
if (existsSync63(pkgProv)) {
|
|
59690
|
+
const cur = JSON.parse(readFileSync74(pkgProv, "utf8"));
|
|
59514
59691
|
const merged = deepMerge4(cur, overlay);
|
|
59515
59692
|
packageFaq = merged.faq;
|
|
59516
59693
|
writeFileSync27(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
@@ -59519,9 +59696,9 @@ async function applyOverlays(input) {
|
|
|
59519
59696
|
writeFileSync27(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
59520
59697
|
wrote.push(pkgProv);
|
|
59521
59698
|
}
|
|
59522
|
-
const pkgTokens =
|
|
59523
|
-
if (
|
|
59524
|
-
const cur = JSON.parse(
|
|
59699
|
+
const pkgTokens = join62(cwd, "tokens.json");
|
|
59700
|
+
if (existsSync63(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
59701
|
+
const cur = JSON.parse(readFileSync74(pkgTokens, "utf8"));
|
|
59525
59702
|
let tokensIn = tokens;
|
|
59526
59703
|
if (tokens.typography) {
|
|
59527
59704
|
const fonts = catalogTypography(tokens.typography, cur.typography);
|
|
@@ -59546,9 +59723,9 @@ async function applyOverlays(input) {
|
|
|
59546
59723
|
wrote.push(pkgTokens);
|
|
59547
59724
|
}
|
|
59548
59725
|
const homeAction = homeRefreshActionId(shell);
|
|
59549
|
-
const homeSrc =
|
|
59550
|
-
if (homeAction &&
|
|
59551
|
-
const prev =
|
|
59726
|
+
const homeSrc = join62(cwd, "dev/index.ts");
|
|
59727
|
+
if (homeAction && existsSync63(homeSrc)) {
|
|
59728
|
+
const prev = readFileSync74(homeSrc, "utf8");
|
|
59552
59729
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
59553
59730
|
let next = patched.src;
|
|
59554
59731
|
if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
|
|
@@ -59579,13 +59756,13 @@ async function applyOverlays(input) {
|
|
|
59579
59756
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
59580
59757
|
}
|
|
59581
59758
|
}
|
|
59582
|
-
if (!input.iconPath || !
|
|
59759
|
+
if (!input.iconPath || !existsSync63(input.iconPath)) {
|
|
59583
59760
|
const book = input.iconPath ? dirname33(dirname33(resolve45(input.iconPath))) : void 0;
|
|
59584
59761
|
notes.push(
|
|
59585
59762
|
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"
|
|
59586
59763
|
);
|
|
59587
59764
|
}
|
|
59588
|
-
if (input.iconPath &&
|
|
59765
|
+
if (input.iconPath && existsSync63(input.iconPath)) {
|
|
59589
59766
|
try {
|
|
59590
59767
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
59591
59768
|
wrote.push(...installed.wrote);
|
|
@@ -63772,7 +63949,7 @@ __export(cli_exports, {
|
|
|
63772
63949
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
63773
63950
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
63774
63951
|
});
|
|
63775
|
-
import { readFileSync as
|
|
63952
|
+
import { readFileSync as readFileSync75 } from "node:fs";
|
|
63776
63953
|
import { resolve as resolve46 } from "node:path";
|
|
63777
63954
|
function assetFetchFor(_opts) {
|
|
63778
63955
|
return pinnedFetch2;
|
|
@@ -63871,7 +64048,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
63871
64048
|
let source;
|
|
63872
64049
|
if (opts.sourcePath) {
|
|
63873
64050
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
63874
|
-
source =
|
|
64051
|
+
source = readFileSync75(p, "utf8");
|
|
63875
64052
|
}
|
|
63876
64053
|
let body;
|
|
63877
64054
|
if (opts.bodyRaw != null) {
|
|
@@ -64130,7 +64307,7 @@ __export(site_create_exports, {
|
|
|
64130
64307
|
runSiteList: () => runSiteList,
|
|
64131
64308
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
64132
64309
|
});
|
|
64133
|
-
import { existsSync as
|
|
64310
|
+
import { existsSync as existsSync64, readFileSync as readFileSync76, writeFileSync as writeFileSync28 } from "node:fs";
|
|
64134
64311
|
import { resolve as resolvePath2 } from "node:path";
|
|
64135
64312
|
function oauthClientName(projectName) {
|
|
64136
64313
|
return `${projectName} client`;
|
|
@@ -64279,7 +64456,7 @@ async function runSiteCreate(opts) {
|
|
|
64279
64456
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
64280
64457
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
64281
64458
|
}
|
|
64282
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
64459
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync64, readFileSync: readFileSync76, writeFileSync: writeFileSync28 }) {
|
|
64283
64460
|
const msid = binding2.siteId;
|
|
64284
64461
|
const path2 = resolvePath2(target);
|
|
64285
64462
|
const committed = committedShellProvisioning(path2);
|
|
@@ -64952,11 +65129,11 @@ var init_context = __esm({
|
|
|
64952
65129
|
});
|
|
64953
65130
|
|
|
64954
65131
|
// src/cli.ts
|
|
64955
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
65132
|
+
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync77, mkdirSync as mkdirSync31, writeFileSync as writeFileSync29, existsSync as existsSync65, rmSync as rmSync14, readdirSync as readdirSync30, statSync as statSync17, lstatSync as lstatSync11, accessSync, constants as constants2, renameSync as renameSync7, cpSync as cpSync3 } from "node:fs";
|
|
64956
65133
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
64957
65134
|
import { createHash as createHash28, randomUUID as randomUUID5 } from "node:crypto";
|
|
64958
65135
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
64959
|
-
import { join as
|
|
65136
|
+
import { join as join63, resolve as resolve47, relative as relative12, basename as basename16, dirname as dirname34 } from "node:path";
|
|
64960
65137
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
64961
65138
|
|
|
64962
65139
|
// ../serve-cli/src/client.ts
|
|
@@ -67072,8 +67249,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
67072
67249
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
67073
67250
|
function embeddedTemplateCatalog() {
|
|
67074
67251
|
return availableTemplates().map((name) => {
|
|
67075
|
-
const path2 =
|
|
67076
|
-
const meta = JSON.parse(
|
|
67252
|
+
const path2 = join63(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
67253
|
+
const meta = JSON.parse(readFileSync77(path2, "utf8"));
|
|
67077
67254
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
67078
67255
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
67079
67256
|
}
|
|
@@ -67103,7 +67280,9 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
67103
67280
|
scaffold a starter content package (--template <t> starts
|
|
67104
67281
|
from a reference app; --remote fetches it off the serve plane),
|
|
67105
67282
|
with the agent files inside it (AGENTS.md, CLAUDE.md, the himalaya
|
|
67106
|
-
skill, a session-start hook); --no-agent skips them
|
|
67283
|
+
skill, a session-start hook); --no-agent skips them. Also makes
|
|
67284
|
+
the build board (no browser is opened), and its next[] leads with
|
|
67285
|
+
THIS session's steps: the live preview, the first picture, a postcard
|
|
67107
67286
|
himi template list [--remote] list starter templates + metadata (title/description/tags) + each one's start prompt
|
|
67108
67287
|
himi template prompt <name> print the prompt that starts an app from that template
|
|
67109
67288
|
himi template publish [--dir <app>] [--source-dir <dir>] [--name <n>] [--icon <png>] [--visibility public|unlisted]
|
|
@@ -67694,7 +67873,7 @@ WHAT A PATCH DOES NOT CARRY \u2014 all reported in the output, never silent
|
|
|
67694
67873
|
himi docs releasing-with-himi-serve`;
|
|
67695
67874
|
var COMMANDS = [
|
|
67696
67875
|
{ name: "captcha", summary: "create and store native CAPTCHA keys in Serve, or inspect setup status; customer setup verifies Wix site ownership; does not enable member CAPTCHA SDKs", required: "setup|status --app <app> [--content <dir>] [--site <msid>] [--ios-bundle-id <id>] [--android-package-name <id>] [--target <t>]" },
|
|
67697
|
-
{ name: "init", summary: "scaffold a starter content package (OTA-only; no native shells). --template <t> starts from a full reference app (branded-lite = consumer storefront over a Wix site; owner-lite = owner CRUD/management) instead of the minimal counter; --templates lists bundled ones; --remote fetches the template off the serve plane (falls back to the bundled copy offline). The new app also gets its agent files (the same set `himi agent-init` writes: AGENTS.md, CLAUDE.md, the himalaya skill, HIMALAYA.md, a SessionStart hook) so the next session started inside it picks the work up; --no-agent skips them", required: "<name> [--dir] [--template <t>] [--remote] [--no-agent] | --templates" },
|
|
67876
|
+
{ name: "init", summary: "scaffold a starter content package (OTA-only; no native shells). --template <t> starts from a full reference app (branded-lite = consumer storefront over a Wix site; owner-lite = owner CRUD/management) instead of the minimal counter; --templates lists bundled ones; --remote fetches the template off the serve plane (falls back to the bundled copy offline). The new app also gets its agent files (the same set `himi agent-init` writes: AGENTS.md, CLAUDE.md, the himalaya skill, HIMALAYA.md, a SessionStart hook) so the next session started inside it picks the work up; --no-agent skips them. It also makes the build board (.himi/studio/, exactly as `himi studio --no-open` does \u2014 it never opens a browser), so every later render, test, validate, push and progress entry refreshes it; and its `next[]` LEADS with the steps for THIS session \u2014 `himi run --watch &`, the first `himi render <homeScreenId> --png --device iphone`, and that picture's `himi progress` postcard \u2014 ahead of the next-session guidance", required: "<name> [--dir] [--template <t>] [--remote] [--no-agent] | --templates" },
|
|
67698
67877
|
{ name: "template", summary: "starter-template catalog + publishing. Every template is a SHOWCASE APP \u2014 a real published release you can open running before you start from it. `list` prints available templates with metadata (title/description/tags) plus each one's start prompt \u2014 pass --remote to include the serve-plane catalog so an agent can pick one; `prompt <name>` prints just that sentence for one template (the skill URL is the public door, or the plane named by --target/--serve-url); `publish` publishes an app AS a `himi init --template` (needs a himalaya.template.json; builds a previewable release + attaches the scaffold source; --source-dir overrides which tree becomes the source, --name sets the template name; bakes a launcher icon \u2014 --icon <png>, or the committed template-icons/<name>.png \u2014 and extracts accent/palette gallery meta from the scaffold's tokens.json; --visibility unlisted keeps it out of the /v1/templates catalog \u2014 templates default to public); `trim --keep <ids>` cuts an app scaffolded from a template down to those screens (the home, and any screen the navigation pins such as a drawer body, always stays) \u2014 it deletes the other SCREENS/TEMPLATED entries whole, prunes navigation (linkableScreens, tabBar, drawer, deep links, surfaces) and drops tier5-src workers no kept screen uses, then runs validate --strict and rolls everything back if it fails (--force keeps it, --dry-run writes nothing). A kept screen that links to a removed one is refused unless --links follow (keep those too) or --links drop (remove the taps)", required: "list [--remote] | prompt <name> | publish [--dir <app>] [--source-dir <dir>] [--name <n>] [--icon <png>] [--visibility public|unlisted] [--target <t>] | trim --keep <id,id,\u2026> [--content <dir>] [--links follow|drop] [--dry-run] [--force]" },
|
|
67699
67878
|
{ name: "build", summary: "compile tier5-src/<name>/index.ts -> dist/bundles/<name>.bundle.js with esbuild (--binary = resolve published @himalaya/*); semantic TypeScript checking belongs to himi validate", required: "[--content <dir>] [--binary]" },
|
|
67700
67879
|
{ name: "functions", summary: "inspect/invoke server functions and operate durable jobs or schedules", required: "list|describe|openapi|invoke | jobs list|get|cancel|retry|dlq | schedule describe|invoke [--app <a>] [--environment preview|production] [--release <id>]" },
|
|
@@ -67702,8 +67881,8 @@ var COMMANDS = [
|
|
|
67702
67881
|
{ name: "validate", summary: "lint the content package (no push): fixed-contract TypeScript checking for tier5-src workers + schema/proto + token refs + component allowlist + $service bindings + strict-enum foot-guns + capability decls + worker boot dry-run + build/compile failures. Type issues are advisory warnings normally; --strict promotes them and hygiene warnings to errors. Exit 1 on any error. Off-repo, the CLI supplies its compiler and SDK declarations.", required: "[--content <dir>] [--strict]" },
|
|
67703
67882
|
{ name: "test", summary: "DERIVED behavioral crawl \u2014 no test files to write. Boots each screen's real worker, replays its onAppear, then dispatches every action site the descriptor already declares (each from a fresh boot) and checks a narrow set of unambiguous invariants: no uncaught throw, never stuck on `loading`, no `$service:` token or NaN/undefined/[object Object] reaching visible text, no binding aimed at state the worker never defines, no nav param silently dropped, no dead nav target. Catches what validate/render cannot \u2014 a WRONG REDUCER passes both with ok:true. Runs the worker in a DEVICE-PARITY sandbox (no setTimeout/setInterval, as on JSC/WebView) so a bundle that would die on device fails here. Crawls on HERMETIC DATA by default \u2014 zero network: the app's own dev/net-mocks.json first (--net <file> overrides), then the config's CMS `seed:` rows, then a canned fixture of frozen real vertical responses shipped with the CLI (exercises code paths, not API-contract truth) \u2014 so the success/mapping path runs, not just the failure UI. Two boot-only HOSTILE passes (every list empty; every request 500) then check the failure/empty day \u2014 corpus-proven, so their findings are errors. NAV EDGES are followed too: every himi.open site ($item params resolved against row 0 of its list, $service against worker state) and worker _nav directive is harvested, and each baked target is booted WITH the params the source sends \u2014 detail screens finally run their content arm; edge findings are errors tagged edge:<source>. --native runs both real native decoders over the exact baked JSON bytes; --native ios or --native android selects one. It is explicit, runs only from a Himalaya SOURCE CHECKOUT (the decoder oracles are that tree's own HimalayaCore Swift package and Gradle harness, which a published install does not ship), and needs the selected local toolchain. From a source checkout, default runs name missing native verdicts in the coverage ledger; elsewhere the ledger stays silent about them rather than offering a remedy you cannot run. --offline strips all data layers (the old reject-all axis); --no-hostile skips the hostile passes. --record (EXPLICIT, never automatic) refreshes dev/net-mocks.json from live reads first: it boots each screen (load + root onAppear ONLY \u2014 nothing the app's own launch would not fire; the tap/action crawl never sees the live transport, and only proven reads \u2014 GET, or read-shaped POST (/query, /search, /list*, \u2026) \u2014 ever reach the wire), freezes the round-trips, then crawls hermetically on the fresh fixture; record against a QA site, not production. Nodes it cannot judge headless are named, never silently passed. Exit 1 on any error. The CLI carries the authoring runtime off-repo; no per-app SDK install is required. --browser runs the whole loop (build \u2192 extract \u2192 validate \u2192 render \u2192 test) in YOUR browser instead of here, so the source never reaches a pod: it opens one screen's worker + descriptor in a tab, blocks on a loopback callback, and prints the report it posts back. One screen per tab \u2014 name it. --no-open prints the URL rather than launching a browser (SSH); --timeout <ms> bounds the wait, which matters because the page has no execution deadline of its own and an infinite loop in the worker hangs the tab.", required: "[<screenId>\u2026] [--content <dir>] [--net <file>] [--budget <ms>] [--deep [n]] [--record] [--native [ios|android]] [--no-shots] [--offline] [--no-hostile] [--all-screens] [--browser] [--no-open] [--timeout <ms>] [--json]" },
|
|
67704
67883
|
{ name: "ux", summary: "audit or record mobile UX evidence. `audit` checks the public-safe contract, seeded blank acceptance rows, placeholder source copy, app-specific mocks, and iOS/Android audit records. It warns while existing templates migrate; `--strict` promotes missing evidence. `record` stores checks performed on an installed iOS/Android build: `--checks` is required for passed|failed and empty for unavailable, which drove nothing and needs a `--reason` instead. `record` also STAMPS the release it audited (it resolves the id from a build, the same one a push would publish), because an unforced `himi push` of a release with screens refuses when no drive is recorded for THAT release, or when the one that is recorded says `failed` \u2014 the artifact stopped being advice nobody reads (#2955). `unavailable` still satisfies it; only `failed` refuses.", required: "audit [--content <dir>] [--strict] [--json] | record --content <dir> --platform ios|android --status passed|failed|unavailable [--checks back,keyboard,...] [--reason <text>]" },
|
|
67705
|
-
{ name: "progress", summary: 'the build JOURNAL an agent keeps for the owner while it works. `himi progress "<what changed>" --step <1-8|name> --image <png>` appends one postcard to .himi/progress.jsonl \u2014 the step is one of the customer journey\'s eight (discover, classify, plan, implement, brand, validate, review, download) \u2014 and COPIES each image, content-addressed, into .himi/history/, because .himi/shots/ is overwritten by every render and cleared by every full `himi test`, so a path into it would later show a different picture than the one the owner was sent. --image repeats. --notify also raises a best-effort desktop notification for an owner who stepped away. A bare `himi progress` prints the journal with the current step and elapsed time \u2014 also how an agent recovers its place after its context was compacted. APPROVALS: `--approve <gate> "<what>"` records one the customer just gave (gates: site-create, connect, private-data, draft, promote, push-signing, qa-build) in .himi/approvals.jsonl, and `--done <gate>` / `--drop <gate>` closes it \u2014 an approval is owed until then, and the chat that held it does not survive a new session. `--brief` prints plain text for a session start: the current step, the last postcard, every open approval, and whether this app\'s agent files are stale \u2014 the SessionStart hook `himi agent-init` installs runs exactly this. Local only: nothing is sent anywhere.', required: '["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>] | --approve|--done|--drop <gate> ["<note>"] | --brief' },
|
|
67706
|
-
{ name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI). `himi studio reel` writes the MAKING-OF: one self-contained HTML file (every image inlined, nothing fetched) with a flipbook of the home screen version by version, captioned by the postcard in effect at the time, the final screens, and every postcard \u2014 sized to stay attachable, thinning frames first. Defaults to .himi/making-of.html (never archived by push); --out to put it elsewhere.", required: "[--content <dir>] [--no-open] | reel [--out <file>] [--no-open]" },
|
|
67884
|
+
{ name: "progress", summary: 'the build JOURNAL an agent keeps for the owner while it works. `himi progress "<what changed>" --step <1-8|name> --image <png>` appends one postcard to .himi/progress.jsonl \u2014 the step is one of the customer journey\'s eight (discover, classify, plan, implement, brand, validate, review, download) \u2014 and COPIES each image, content-addressed, into .himi/history/, because .himi/shots/ is overwritten by every render and cleared by every full `himi test`, so a path into it would later show a different picture than the one the owner was sent. --image repeats. --notify also raises a best-effort desktop notification for an owner who stepped away. A bare `himi progress` prints the journal with the current step and elapsed time \u2014 also how an agent recovers its place after its context was compacted. APPROVALS: `--approve <gate> "<what>"` records one the customer just gave (gates: site-create, connect, private-data, draft, promote, push-signing, qa-build) in .himi/approvals.jsonl, and `--done <gate>` / `--drop <gate>` closes it \u2014 an approval is owed until then, and the chat that held it does not survive a new session. `--brief` prints plain text for a session start: the current step, the last postcard, every open approval, and whether this app\'s agent files are stale \u2014 the SessionStart hook `himi agent-init` installs runs exactly this. The CLI also journals three milestones by itself \u2014 the first PNG render of the home screen (once per app), every completed `himi test` crawl, every draft push \u2014 marked `"by": "himi"`; they never move the journey step, carry no link or credential, and step aside (folded out of every reader) when the agent journals the same step or picture within five minutes. Local only: nothing is sent anywhere.', required: '["<message>" [--step <1-8|name>] [--image <png>]\u2026 [--notify]] [--content <dir>] | --approve|--done|--drop <gate> ["<note>"] | --brief' },
|
|
67885
|
+
{ name: "studio", summary: "open the BUILD BOARD \u2014 one local page the owner can leave open while an agent builds their app, which fills itself in: every screen as it renders (NEW/CHANGED badges, and each earlier version kept for a filmstrip), the journey stepper and the latest postcard from `himi progress`, the validate/test/UX/draft checks as they run, the site next to the app's home screen with its palette, and the navigation the test crawl followed. Writes .himi/studio/index.html and opens it; the page re-reads its state every two seconds, so nothing needs to be served. OPT-IN BY EXISTENCE: until this command (or `himi init`, which makes the board for every app it creates, without opening a browser) has run, no other command touches .himi/studio/ \u2014 after it, render/test/validate/push/icon/site/ux/progress each refresh the board as they finish (best-effort; never fails a command). Every image is a content-addressed copy in .himi/history/, never a live path into .himi/shots/. Local only, no secrets: it never reads a preview token, handover code or control token. --no-open prints the path instead (SSH, CI). `himi studio reel` writes the MAKING-OF: one self-contained HTML file (every image inlined, nothing fetched) with a flipbook of the home screen version by version, captioned by the postcard in effect at the time, the final screens, and every postcard \u2014 sized to stay attachable, thinning frames first. Defaults to .himi/making-of.html (never archived by push); --out to put it elsewhere.", required: "[--content <dir>] [--no-open] | reel [--out <file>] [--no-open]" },
|
|
67707
67886
|
{ name: "render", summary: "headless-render a screen with the web renderer: render-tree + diagnostics, optional --png [<file>] (bare: .himi/shots/<id>.png, what the build board shows), --scheme dark, --tree. Local by default (content dir). Pass --remote --app --release to hit GET /v1/preview/\u2026/render on the serve plane after a push. Boots the worker so $service bindings resolve; --static raw bindings; --live real Wix fetches; --state injects worker state; --input supplies pre-boot navigation params; --width/--device for PNG viewport; --rtl for dir=rtl + $env:isRTL.", required: "<screenId> [--content <dir>] [--scheme dark] [--png [<file>]] [--tree] [--static] [--live] [--state <json|file>] [--input <json|file>] [--width <px> | --device <name>] [--rtl] [--remote --app --release]" },
|
|
67708
67887
|
{ name: "cms", summary: "inspect, provision, and seed the app's CMS (Wix Data) collections, declared as a `cms` block in config.ts. `query` is READ-ONLY \u2014 by default it fetches ONLY the physical ids `config.ts` declares (item counts + schema drift) and reports `siteScanned: false`; it never lists the site, so an UNDECLARED `himi_<app>_` collection this app owns is not reached without `--all`. `--all` SCANS the site \u2014 every collection it lists is labeled `owned`/`adopted`/`foreign`, and it describes every foreign one \u2014 id, non-system field keys + types, and the site's read role \u2014 so an app with no `cms` block at all can DISCOVER a collection to adopt (`--all` is the one case where a missing `cms` block is not 'nothing to do'). Foreign collections are described up to a cap and are never item-counted (`itemCount: null`), because a row count is one query each; `foreign.count` is how many the scan LISTED \u2014 it follows the list endpoint's pages, and `listingIncomplete: true` says when the walk stopped short of the end, with `unlistedCollections` counting what it left out when Wix gave a paging total \u2014 and `foreign.truncated` says how many of those went undescribed, each still NAMED in `foreign.others` (id + displayName), so a collection the site already has is never hidden behind the cap. The scan is OWNER-scoped \u2014 it needs --site <msid> (or WIX_SITE_ID) plus owner auth via `wix token`; a visitor token can read a public collection's ITEMS but can never enumerate collections, so there is no tokenless discovery path. `create` reconciles declared collections additively and idempotently, and REFUSES any id outside the app's `himi_<app>_` namespace, so it is safe against a production site. It reports declared-vs-site `permissionDrift` but never writes permissions unless asked with --apply-permissions, so a field reconcile can't silently revert access control changed in the dashboard. `seed` inserts the git-tracked `seed:` rows into EMPTY owned collections (--force to add to a non-empty one; --ai writes placeholder rows plus a refinement prompt for you to review). Adopted collections (declared by `wixId`) are read-only and never created, updated, or seeded. Site from --site <msid> or WIX_SITE_ID; owner auth via `wix token`.", required: "query|create|seed [--site <msid>] [--content <dir>] [--all] [--dry-run] [--force] [--allow-destructive] [--apply-permissions] [--only <id>] [--ai] [--count <n>]" },
|
|
67709
67888
|
{ name: "data", summary: "read-only plan or explicitly provision/seed declared KV and Wix Data resources. Preview and production are separate scopes. KV administration uses the operator data plane from --data-url/HIMI_DATA_ADMIN_URL and HIMI_DATA_ADMIN_TOKEN; draft push never calls it.", required: "plan|create|seed [--site <msid>] [--environment preview|production] [--content <dir>] [--data-url <url>] [--dry-run] [--force]" },
|
|
@@ -67752,7 +67931,7 @@ var COMMANDS = [
|
|
|
67752
67931
|
];
|
|
67753
67932
|
function cliVersion() {
|
|
67754
67933
|
try {
|
|
67755
|
-
return JSON.parse(
|
|
67934
|
+
return JSON.parse(readFileSync77(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
67756
67935
|
} catch {
|
|
67757
67936
|
return "unknown";
|
|
67758
67937
|
}
|
|
@@ -67870,7 +68049,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
67870
68049
|
}
|
|
67871
68050
|
function packageVersion(path2) {
|
|
67872
68051
|
try {
|
|
67873
|
-
const version2 = JSON.parse(
|
|
68052
|
+
const version2 = JSON.parse(readFileSync77(path2, "utf8")).version;
|
|
67874
68053
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
67875
68054
|
} catch {
|
|
67876
68055
|
return void 0;
|
|
@@ -67879,7 +68058,7 @@ function packageVersion(path2) {
|
|
|
67879
68058
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
67880
68059
|
let dir = resolve47(fromDir);
|
|
67881
68060
|
for (; ; ) {
|
|
67882
|
-
const version2 = packageVersion(
|
|
68061
|
+
const version2 = packageVersion(join63(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
67883
68062
|
if (version2) return { version: version2, source: "local" };
|
|
67884
68063
|
const parent = dirname34(dir);
|
|
67885
68064
|
if (parent === dir) break;
|
|
@@ -67889,7 +68068,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
67889
68068
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
67890
68069
|
try {
|
|
67891
68070
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
67892
|
-
const version2 = root ? packageVersion(
|
|
68071
|
+
const version2 = root ? packageVersion(join63(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
67893
68072
|
return version2 ? { version: version2, source: "global" } : {};
|
|
67894
68073
|
} catch {
|
|
67895
68074
|
return {};
|
|
@@ -67936,11 +68115,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
67936
68115
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
67937
68116
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
67938
68117
|
function updateCachePath(env = process.env) {
|
|
67939
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
68118
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join63(homedir7(), ".himalaya", "update-check.json");
|
|
67940
68119
|
}
|
|
67941
68120
|
function readUpdateCache(path2) {
|
|
67942
68121
|
try {
|
|
67943
|
-
const parsed = JSON.parse(
|
|
68122
|
+
const parsed = JSON.parse(readFileSync77(path2, "utf8"));
|
|
67944
68123
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
67945
68124
|
} catch {
|
|
67946
68125
|
return {};
|
|
@@ -68008,12 +68187,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
68008
68187
|
},
|
|
68009
68188
|
installedVersion: () => {
|
|
68010
68189
|
const root = globalNodeModulesRoot();
|
|
68011
|
-
return root ? packageVersion(
|
|
68190
|
+
return root ? packageVersion(join63(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
68012
68191
|
},
|
|
68013
68192
|
reexec: (argv) => {
|
|
68014
68193
|
const root = globalNodeModulesRoot();
|
|
68015
|
-
const entry = root ?
|
|
68016
|
-
if (!entry || !
|
|
68194
|
+
const entry = root ? join63(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
68195
|
+
if (!entry || !existsSync65(entry)) return void 0;
|
|
68017
68196
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
68018
68197
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
68019
68198
|
stdio: "inherit",
|
|
@@ -68060,7 +68239,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
68060
68239
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
68061
68240
|
let content;
|
|
68062
68241
|
try {
|
|
68063
|
-
content =
|
|
68242
|
+
content = readFileSync77(path2, "utf8");
|
|
68064
68243
|
} catch {
|
|
68065
68244
|
continue;
|
|
68066
68245
|
}
|
|
@@ -68083,7 +68262,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
68083
68262
|
const mine = lockStamp(now);
|
|
68084
68263
|
const readLock = (path2) => {
|
|
68085
68264
|
try {
|
|
68086
|
-
return
|
|
68265
|
+
return readFileSync77(path2, "utf8");
|
|
68087
68266
|
} catch {
|
|
68088
68267
|
return void 0;
|
|
68089
68268
|
}
|
|
@@ -68667,7 +68846,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
68667
68846
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
68668
68847
|
for (const dir of entries) {
|
|
68669
68848
|
for (const suffix of suffixes) {
|
|
68670
|
-
const candidate =
|
|
68849
|
+
const candidate = join63(dir, `${name}${suffix}`);
|
|
68671
68850
|
try {
|
|
68672
68851
|
if (!statSync17(candidate).isFile()) continue;
|
|
68673
68852
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -68776,7 +68955,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68776
68955
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths2(), paths_exports));
|
|
68777
68956
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
68778
68957
|
const iosYmlPath = iosProjectYml2(app);
|
|
68779
|
-
const iosYml =
|
|
68958
|
+
const iosYml = existsSync65(iosYmlPath) ? readFileSync77(iosYmlPath, "utf8") : "";
|
|
68780
68959
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
68781
68960
|
if (!optedIn) {
|
|
68782
68961
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -68790,7 +68969,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68790
68969
|
}
|
|
68791
68970
|
function readConfigSource(dir) {
|
|
68792
68971
|
try {
|
|
68793
|
-
return
|
|
68972
|
+
return readFileSync77(join63(dir, "config.ts"), "utf8");
|
|
68794
68973
|
} catch {
|
|
68795
68974
|
return null;
|
|
68796
68975
|
}
|
|
@@ -68826,7 +69005,7 @@ function keptPlan(kept) {
|
|
|
68826
69005
|
}
|
|
68827
69006
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
68828
69007
|
const dir = resolve47(parentDir, name);
|
|
68829
|
-
if (
|
|
69008
|
+
if (existsSync65(join63(dir, "himalaya.content.json"))) {
|
|
68830
69009
|
throw new Error(`content package already exists at ${dir}`);
|
|
68831
69010
|
}
|
|
68832
69011
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -68869,7 +69048,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
68869
69048
|
function restoreDestinationIssue(dest, force) {
|
|
68870
69049
|
const link = symlinkDestinationIssue(dest);
|
|
68871
69050
|
if (link) return link;
|
|
68872
|
-
if (!
|
|
69051
|
+
if (!existsSync65(dest)) return null;
|
|
68873
69052
|
if (!statSync17(dest).isDirectory()) {
|
|
68874
69053
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
68875
69054
|
}
|
|
@@ -68884,7 +69063,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
68884
69063
|
function isHimalayaMonorepoCheckout(start) {
|
|
68885
69064
|
let dir = resolve47(start);
|
|
68886
69065
|
for (; ; ) {
|
|
68887
|
-
if (
|
|
69066
|
+
if (existsSync65(join63(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync65(join63(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
68888
69067
|
const parent = dirname34(dir);
|
|
68889
69068
|
if (parent === dir) return false;
|
|
68890
69069
|
dir = parent;
|
|
@@ -68922,7 +69101,7 @@ function shellShaDivergenceWarnings(jobs) {
|
|
|
68922
69101
|
}
|
|
68923
69102
|
async function templatePublishName(sourceDir) {
|
|
68924
69103
|
const id = await appId(sourceDir);
|
|
68925
|
-
return IDENTITY_SENTINELS.some((s) => id.includes(s)) ?
|
|
69104
|
+
return IDENTITY_SENTINELS.some((s) => id.includes(s)) ? basename16(sourceDir) : id;
|
|
68926
69105
|
}
|
|
68927
69106
|
function templateNameError(name, from) {
|
|
68928
69107
|
if (name.startsWith(TEMPLATE_APP_PREFIX)) {
|
|
@@ -68945,7 +69124,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68945
69124
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
68946
69125
|
);
|
|
68947
69126
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
68948
|
-
const root =
|
|
69127
|
+
const root = join63(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
68949
69128
|
const stillRunning = (pid) => {
|
|
68950
69129
|
try {
|
|
68951
69130
|
process.kill(pid, 0);
|
|
@@ -68959,12 +69138,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68959
69138
|
if (!entry.isDirectory()) continue;
|
|
68960
69139
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
68961
69140
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
68962
|
-
rmSync14(
|
|
69141
|
+
rmSync14(join63(root, entry.name), { recursive: true, force: true });
|
|
68963
69142
|
}
|
|
68964
69143
|
}
|
|
68965
69144
|
} catch {
|
|
68966
69145
|
}
|
|
68967
|
-
const dest =
|
|
69146
|
+
const dest = join63(root, `${slug}-${process.pid}`);
|
|
68968
69147
|
rmSync14(dest, { recursive: true, force: true });
|
|
68969
69148
|
mkdirSync31(dest, { recursive: true });
|
|
68970
69149
|
try {
|
|
@@ -68977,17 +69156,17 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68977
69156
|
}
|
|
68978
69157
|
async function appId(dir) {
|
|
68979
69158
|
try {
|
|
68980
|
-
const { readFileSync:
|
|
68981
|
-
const m = JSON.parse(
|
|
69159
|
+
const { readFileSync: readFileSync78 } = await import("node:fs");
|
|
69160
|
+
const m = JSON.parse(readFileSync78(join63(dir, "himalaya.content.json"), "utf8"));
|
|
68982
69161
|
if (m.name) return m.name;
|
|
68983
69162
|
} catch {
|
|
68984
69163
|
}
|
|
68985
|
-
return
|
|
69164
|
+
return basename16(dir);
|
|
68986
69165
|
}
|
|
68987
69166
|
async function contentVisibility(dir) {
|
|
68988
69167
|
try {
|
|
68989
|
-
const { readFileSync:
|
|
68990
|
-
const m = JSON.parse(
|
|
69168
|
+
const { readFileSync: readFileSync78 } = await import("node:fs");
|
|
69169
|
+
const m = JSON.parse(readFileSync78(join63(dir, "himalaya.content.json"), "utf8"));
|
|
68991
69170
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
68992
69171
|
} catch {
|
|
68993
69172
|
}
|
|
@@ -69211,7 +69390,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
|
|
|
69211
69390
|
...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/" } : {},
|
|
69212
69391
|
// In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
|
|
69213
69392
|
// hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
|
|
69214
|
-
...
|
|
69393
|
+
...existsSync65(join63(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" } : {},
|
|
69215
69394
|
...res.skipped.length ? { skipped: res.skipped } : {},
|
|
69216
69395
|
portalUrl: idx.portalUrl
|
|
69217
69396
|
});
|
|
@@ -69234,7 +69413,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
69234
69413
|
try {
|
|
69235
69414
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69236
69415
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
69237
|
-
out = mkdtempSync4(
|
|
69416
|
+
out = mkdtempSync4(join63(tmpdir5(), "himi-ux-record-"));
|
|
69238
69417
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69239
69418
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
69240
69419
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -69284,8 +69463,8 @@ function uxRestoreCommands(ctx) {
|
|
|
69284
69463
|
};
|
|
69285
69464
|
}
|
|
69286
69465
|
function uxHandoverHint(uxEvidence, ctx) {
|
|
69287
|
-
const { releaseId, contentArg, door, app } = ctx;
|
|
69288
|
-
const uxRemedy = uxRecordCommands(
|
|
69466
|
+
const { releaseId, contentArg: contentArg2, door, app } = ctx;
|
|
69467
|
+
const uxRemedy = uxRecordCommands(contentArg2);
|
|
69289
69468
|
if (uxEvidence.state === "inherited-screens") {
|
|
69290
69469
|
const restore = uxRestoreCommands(ctx);
|
|
69291
69470
|
const alsoOwed = uxEvidence.supersededState === "failed" ? ` This package's own drive FAILED on ${uxEvidence.failedPlatforms.join(", ")}, so you owe more than a record: fix what that drive found, then record it against the restored tree \u2014 re-recording a failure without changing the app writes the same failure down again.` : uxEvidence.supersededState ? ` This package also has no drive this gate accepts (${uxEvidence.supersededState}), so the record below is a step you take AFTER the restore, not instead of it.` : "";
|
|
@@ -69412,7 +69591,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
69412
69591
|
let js;
|
|
69413
69592
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
69414
69593
|
try {
|
|
69415
|
-
js =
|
|
69594
|
+
js = readFileSync77(join63(outDir, candidate), "utf8");
|
|
69416
69595
|
break;
|
|
69417
69596
|
} catch {
|
|
69418
69597
|
}
|
|
@@ -69443,7 +69622,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
69443
69622
|
}
|
|
69444
69623
|
return { families, source: "dist/bundles" };
|
|
69445
69624
|
}
|
|
69446
|
-
var boardOpen = (dir) =>
|
|
69625
|
+
var boardOpen = (dir) => existsSync65(join63(dir, ".himi", "studio", "index.html"));
|
|
69447
69626
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
69448
69627
|
async function leaveForBoard(dir, record2, value) {
|
|
69449
69628
|
if (!boardOpen(dir)) return;
|
|
@@ -69738,12 +69917,18 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69738
69917
|
const owed = openApprovals2(readApprovals2(dir).events).length;
|
|
69739
69918
|
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`);
|
|
69740
69919
|
}
|
|
69741
|
-
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) =>
|
|
69920
|
+
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) => existsSync65(join63(parentDir, f)));
|
|
69742
69921
|
if (planInParent.length) {
|
|
69743
69922
|
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}`);
|
|
69744
69923
|
}
|
|
69745
69924
|
return { ...seeded, next };
|
|
69746
69925
|
};
|
|
69926
|
+
const startSession = async (dir, agent2) => {
|
|
69927
|
+
const { openBoardForSession: openBoardForSession2, sessionSteps: sessionSteps2, homeScreenIdOf: homeScreenIdOf2 } = await Promise.resolve().then(() => (init_milestones(), milestones_exports));
|
|
69928
|
+
const board = await openBoardForSession2(dir);
|
|
69929
|
+
const { next: later2, ...rest } = agent2;
|
|
69930
|
+
return { ...rest, board, next: [...sessionSteps2({ dir, home: homeScreenIdOf2(dir) }), ...later2 ?? []] };
|
|
69931
|
+
};
|
|
69747
69932
|
if (template && flags.remote === true) {
|
|
69748
69933
|
let fetched;
|
|
69749
69934
|
try {
|
|
@@ -69756,14 +69941,14 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69756
69941
|
io.error(JSON.stringify({ warning: `remote template fetch failed (${e.message}); falling back to the bundled "${template}"` }));
|
|
69757
69942
|
}
|
|
69758
69943
|
if (fetched) {
|
|
69759
|
-
const agent2 = await withAgentFiles(fetched.dir);
|
|
69944
|
+
const agent2 = await startSession(fetched.dir, await withAgentFiles(fetched.dir));
|
|
69760
69945
|
const pushSetup2 = await offerPushSetup2({ contentDir: fetched.dir, flags, io });
|
|
69761
69946
|
print({ ok: true, app: name, dir: fetched.dir, template, source: "remote", files: fetched.files, ...keptPlan(fetched.kept), ...agent2, pushSetup: pushSetup2 });
|
|
69762
69947
|
return 0;
|
|
69763
69948
|
}
|
|
69764
69949
|
}
|
|
69765
69950
|
const res = scaffoldContentPackage(name, parentDir, template);
|
|
69766
|
-
const agent = await withAgentFiles(res.dir);
|
|
69951
|
+
const agent = await startSession(res.dir, await withAgentFiles(res.dir));
|
|
69767
69952
|
const pushSetup = await offerPushSetup2({ contentDir: res.dir, flags, io });
|
|
69768
69953
|
print({ ok: true, app: name, dir: res.dir, ...template ? { template, source: "embedded" } : {}, files: res.files, ...keptPlan(res.kept), ...agent, pushSetup });
|
|
69769
69954
|
return 0;
|
|
@@ -69865,7 +70050,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69865
70050
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
69866
70051
|
let meta;
|
|
69867
70052
|
try {
|
|
69868
|
-
meta = JSON.parse(
|
|
70053
|
+
meta = JSON.parse(readFileSync77(join63(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
69869
70054
|
} catch {
|
|
69870
70055
|
io.error(JSON.stringify({ error: `no ${TEMPLATE_META_FILE} in ${sourceDir} \u2014 a template must declare { title, description, tags } to be published`, hint: `add ${TEMPLATE_META_FILE} next to himalaya.content.json (or pass --source-dir <dir>)` }));
|
|
69871
70056
|
return 2;
|
|
@@ -69875,7 +70060,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69875
70060
|
return 2;
|
|
69876
70061
|
}
|
|
69877
70062
|
try {
|
|
69878
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
70063
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync77(join63(sourceDir, "tokens.json"), "utf8")));
|
|
69879
70064
|
meta = { ...appearance, ...meta };
|
|
69880
70065
|
} catch {
|
|
69881
70066
|
}
|
|
@@ -69897,7 +70082,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69897
70082
|
const force = flags.force === true;
|
|
69898
70083
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69899
70084
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
69900
|
-
const out = mkdtempSync4(
|
|
70085
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-template-"));
|
|
69901
70086
|
publishScratch.push(out);
|
|
69902
70087
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69903
70088
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
@@ -69951,7 +70136,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69951
70136
|
let iconHash;
|
|
69952
70137
|
if (iconPath) {
|
|
69953
70138
|
try {
|
|
69954
|
-
const bytes2 =
|
|
70139
|
+
const bytes2 = readFileSync77(iconPath);
|
|
69955
70140
|
payload.icon = bytes2.toString("base64");
|
|
69956
70141
|
iconHash = createHash28("sha256").update(bytes2).digest("hex");
|
|
69957
70142
|
} catch {
|
|
@@ -70194,7 +70379,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70194
70379
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
70195
70380
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
70196
70381
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
70197
|
-
const out = mkdtempSync4(
|
|
70382
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-validate-"));
|
|
70198
70383
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70199
70384
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70200
70385
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70237,7 +70422,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70237
70422
|
const path2 = dpxSessionTokenPath();
|
|
70238
70423
|
let raw;
|
|
70239
70424
|
try {
|
|
70240
|
-
raw =
|
|
70425
|
+
raw = readFileSync77(path2, "utf8");
|
|
70241
70426
|
} catch {
|
|
70242
70427
|
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`);
|
|
70243
70428
|
}
|
|
@@ -70357,13 +70542,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70357
70542
|
case "studio": {
|
|
70358
70543
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
70359
70544
|
const dir = contentDir(flags);
|
|
70360
|
-
if (!
|
|
70545
|
+
if (!existsSync65(join63(dir, "himalaya.content.json"))) {
|
|
70361
70546
|
io.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/" }));
|
|
70362
70547
|
return 2;
|
|
70363
70548
|
}
|
|
70364
70549
|
if (pos[1] === "reel") {
|
|
70365
70550
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
70366
|
-
const out = resolve47(str6(flags.out) ??
|
|
70551
|
+
const out = resolve47(str6(flags.out) ?? join63(dir, ".himi", "making-of.html"));
|
|
70367
70552
|
const { html, plan } = buildReel2(dir);
|
|
70368
70553
|
mkdirSync31(dirname34(out), { recursive: true });
|
|
70369
70554
|
writeFileSync29(out, html);
|
|
@@ -70429,8 +70614,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70429
70614
|
formatBrief: formatBrief2
|
|
70430
70615
|
} = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
70431
70616
|
const dir = contentDir(flags);
|
|
70432
|
-
const
|
|
70433
|
-
const isContentPackage =
|
|
70617
|
+
const journal2 = journalPath2(dir);
|
|
70618
|
+
const isContentPackage = existsSync65(join63(dir, "himalaya.content.json"));
|
|
70434
70619
|
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" };
|
|
70435
70620
|
const message = pos.slice(1).join(" ").trim();
|
|
70436
70621
|
const approvalFlags = ["approve", "done", "drop"].filter((f) => flags[f] !== void 0);
|
|
@@ -70482,7 +70667,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70482
70667
|
}
|
|
70483
70668
|
const { entries, skipped } = readProgress2(dir);
|
|
70484
70669
|
const approvals = openApprovals2(readApprovals2(dir).events);
|
|
70485
|
-
print({ ok: true, journal, ...summarizeProgress2(entries), entries, ...approvals.length ? { approvals } : {}, ...skipped ? { skipped } : {}, ...hint });
|
|
70670
|
+
print({ ok: true, journal: journal2, ...summarizeProgress2(entries), entries, ...approvals.length ? { approvals } : {}, ...skipped ? { skipped } : {}, ...hint });
|
|
70486
70671
|
return 0;
|
|
70487
70672
|
}
|
|
70488
70673
|
let step;
|
|
@@ -70503,7 +70688,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70503
70688
|
const entry = appendProgress2(dir, { message, ...step ? { step } : {}, images });
|
|
70504
70689
|
const notified = flags.notify === true ? await notifyDesktop2(`himi \xB7 ${appLabel2(dir) ?? "your app"}`, message) : void 0;
|
|
70505
70690
|
const { count: count2 } = summarizeProgress2(readProgress2(dir).entries);
|
|
70506
|
-
print({ ok: true, entry, journal, count: count2, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
70691
|
+
print({ ok: true, entry, journal: journal2, count: count2, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
70507
70692
|
return 0;
|
|
70508
70693
|
} catch (e) {
|
|
70509
70694
|
if (e instanceof ProgressError2) {
|
|
@@ -70566,7 +70751,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70566
70751
|
case "test": {
|
|
70567
70752
|
const dir = contentDir(flags);
|
|
70568
70753
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
70569
|
-
if (
|
|
70754
|
+
if (existsSync65(join63(dir, "functions"))) {
|
|
70570
70755
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
70571
70756
|
const loaded = await loadFunctionsApp2(dir);
|
|
70572
70757
|
const results = [];
|
|
@@ -70653,7 +70838,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70653
70838
|
}
|
|
70654
70839
|
}
|
|
70655
70840
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
70656
|
-
const out = mkdtempSync4(
|
|
70841
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-test-"));
|
|
70657
70842
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70658
70843
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70659
70844
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70698,7 +70883,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70698
70883
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
70699
70884
|
return 2;
|
|
70700
70885
|
}
|
|
70701
|
-
const sources = collectWorkerSources2(
|
|
70886
|
+
const sources = collectWorkerSources2(join63(dir, "tier5-src"), screen.bundleName);
|
|
70702
70887
|
if (!sources) {
|
|
70703
70888
|
io.error(JSON.stringify({ error: `no worker source found at tier5-src/${screen.bundleName} \u2014 the browser loop compiles SOURCE, not the built bundle` }));
|
|
70704
70889
|
return 2;
|
|
@@ -70863,7 +71048,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70863
71048
|
const sp = await runShotsPass2({
|
|
70864
71049
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
70865
71050
|
tokens: outcome.tokens,
|
|
70866
|
-
outDir:
|
|
71051
|
+
outDir: join63(dir, ".himi", "shots"),
|
|
70867
71052
|
width: 390,
|
|
70868
71053
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
70869
71054
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -70901,7 +71086,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70901
71086
|
releaseId: result.releaseId,
|
|
70902
71087
|
releasePayload: release,
|
|
70903
71088
|
descriptors: attestedDescriptors,
|
|
70904
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
71089
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join63(dir, ".himi", "shots", name)])),
|
|
70905
71090
|
coverage: {
|
|
70906
71091
|
screens: crawledScreens.size,
|
|
70907
71092
|
actionsDispatched: result.actions.exercised,
|
|
@@ -70913,14 +71098,30 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70913
71098
|
counts: { errors: result.counts.errors, warnings: result.counts.warnings, gaps: ledger.length }
|
|
70914
71099
|
}
|
|
70915
71100
|
});
|
|
71101
|
+
const home = outcome.homeScreenId;
|
|
71102
|
+
const { afterTestRun: afterTestRun2 } = await Promise.resolve().then(() => (init_milestones(), milestones_exports));
|
|
71103
|
+
const afterRun = afterTestRun2(dir, {
|
|
71104
|
+
runId: attestation.runId,
|
|
71105
|
+
screens: crawledScreens.size,
|
|
71106
|
+
actions: result.actions.exercised,
|
|
71107
|
+
errors: result.counts.errors,
|
|
71108
|
+
...result.navGraph ? { broken: result.navGraph.broken.length, unreached: result.navGraph.unreached.length } : {},
|
|
71109
|
+
...home && writtenShots.includes(`${home}.png`) ? { homeShot: join63(dir, ".himi", "shots", `${home}.png`) } : {},
|
|
71110
|
+
boardOpen: boardOpen(dir)
|
|
71111
|
+
});
|
|
70916
71112
|
if (structuredOutput) {
|
|
70917
|
-
print(
|
|
70918
|
-
|
|
70919
|
-
|
|
70920
|
-
|
|
70921
|
-
|
|
70922
|
-
|
|
70923
|
-
|
|
71113
|
+
print({
|
|
71114
|
+
...foldLegacyReport(legacy, {
|
|
71115
|
+
source: "test",
|
|
71116
|
+
evidence: { runId: attestation.runId, ts: attestation.runId.slice(0, 24), gitDiffHash },
|
|
71117
|
+
gaps: ledger,
|
|
71118
|
+
artifacts: result.shots?.dir ? [{ kind: "shots-dir", path: result.shots.dir }] : []
|
|
71119
|
+
}),
|
|
71120
|
+
...afterRun.postcard ? { postcard: afterRun.postcard } : {},
|
|
71121
|
+
next: afterRun.next
|
|
71122
|
+
});
|
|
71123
|
+
} else io.log(formatReport2(result) + formatDelta2(delta) + formatLedger2(ledger, trend) + `
|
|
71124
|
+
${afterRun.next.join("\n")}`);
|
|
70924
71125
|
await leaveForBoard(dir, "edges", result.edges ?? []);
|
|
70925
71126
|
if (result.navGraph) await leaveForBoard(dir, "map", result.navGraph);
|
|
70926
71127
|
return result.ok ? 0 : 1;
|
|
@@ -70992,7 +71193,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70992
71193
|
return 2;
|
|
70993
71194
|
}
|
|
70994
71195
|
try {
|
|
70995
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
71196
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync77(stateArg.replace(/^@/, ""), "utf8");
|
|
70996
71197
|
injectedState = JSON.parse(raw);
|
|
70997
71198
|
} catch (e) {
|
|
70998
71199
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -71007,7 +71208,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71007
71208
|
return 2;
|
|
71008
71209
|
}
|
|
71009
71210
|
try {
|
|
71010
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
71211
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync77(inputArg.replace(/^@/, ""), "utf8");
|
|
71011
71212
|
const parsed = JSON.parse(raw);
|
|
71012
71213
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
71013
71214
|
injectedInput = parsed;
|
|
@@ -71056,7 +71257,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71056
71257
|
}
|
|
71057
71258
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71058
71259
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
71059
|
-
const out = mkdtempSync4(
|
|
71260
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-render-"));
|
|
71060
71261
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71061
71262
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
71062
71263
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71070,7 +71271,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71070
71271
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
71071
71272
|
let pngFile;
|
|
71072
71273
|
let attestationPngFile;
|
|
71073
|
-
const shotPath =
|
|
71274
|
+
const shotPath = join63(dir, ".himi", "shots", `${screenId}.png`);
|
|
71074
71275
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
71075
71276
|
if (pngTarget && r.pngBase64) {
|
|
71076
71277
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -71138,15 +71339,20 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71138
71339
|
coverage: { screens: 1, actionsDispatched: 0, uncoveredFns: 0, gaps: provisional.counts.gaps },
|
|
71139
71340
|
report: { ok: provisional.ok, counts: provisional.counts }
|
|
71140
71341
|
});
|
|
71141
|
-
|
|
71142
|
-
|
|
71143
|
-
|
|
71144
|
-
|
|
71145
|
-
|
|
71146
|
-
|
|
71147
|
-
|
|
71148
|
-
|
|
71149
|
-
|
|
71342
|
+
const afterPng = pngFile ? (await Promise.resolve().then(() => (init_milestones(), milestones_exports))).afterRenderPng(dir, { screenId, homeScreenId: outcome.homeScreenId ?? null, pngFile, renderable: r.renderable, content: str6(flags.content) }) : null;
|
|
71343
|
+
print({
|
|
71344
|
+
...foldLegacyReport(legacyRender, {
|
|
71345
|
+
source: "render",
|
|
71346
|
+
app,
|
|
71347
|
+
screenId,
|
|
71348
|
+
releaseId: outcome.manifest.releaseId,
|
|
71349
|
+
findings: diagnostics,
|
|
71350
|
+
evidence: { runId: attestation.runId, ts: attestation.runId.slice(0, 24), gitDiffHash },
|
|
71351
|
+
artifacts: pngFile ? [{ kind: "png", path: pngFile }] : []
|
|
71352
|
+
}),
|
|
71353
|
+
...afterPng?.postcard ? { postcard: afterPng.postcard } : {},
|
|
71354
|
+
...afterPng?.next.length ? { next: afterPng.next } : {}
|
|
71355
|
+
});
|
|
71150
71356
|
return r.renderable ? 0 : 1;
|
|
71151
71357
|
}
|
|
71152
71358
|
case "tokens": {
|
|
@@ -71406,7 +71612,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71406
71612
|
io.error(JSON.stringify(linked));
|
|
71407
71613
|
return 1;
|
|
71408
71614
|
}
|
|
71409
|
-
if (
|
|
71615
|
+
if (existsSync65(dest)) {
|
|
71410
71616
|
if (!statSync17(dest).isDirectory()) {
|
|
71411
71617
|
io.error(JSON.stringify({
|
|
71412
71618
|
error: `${dest} exists and is not a directory`,
|
|
@@ -71419,7 +71625,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71419
71625
|
io.error(JSON.stringify({ error: `${dest} already exists and is not empty`, hint: "pass --force to write into it anyway (merging, and naming what it keeps), --replace to restore exactly what was archived, or --out/--name to land somewhere else" }));
|
|
71420
71626
|
return 1;
|
|
71421
71627
|
}
|
|
71422
|
-
if (replace && occupied && !
|
|
71628
|
+
if (replace && occupied && !existsSync65(join63(dest, "himalaya.content.json"))) {
|
|
71423
71629
|
io.error(JSON.stringify({
|
|
71424
71630
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
71425
71631
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -71560,7 +71766,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71560
71766
|
const force = flags.force === true;
|
|
71561
71767
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71562
71768
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
71563
|
-
const out = mkdtempSync4(
|
|
71769
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-push-"));
|
|
71564
71770
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71565
71771
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
71566
71772
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71586,8 +71792,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71586
71792
|
const manifest = outcome.manifest;
|
|
71587
71793
|
const payload = await loadReleaseFromDir(declared, out);
|
|
71588
71794
|
const { shellQuote: shellQuote2 } = await Promise.resolve().then(() => (init_shell_quote(), shell_quote_exports));
|
|
71589
|
-
const contentRel =
|
|
71590
|
-
const
|
|
71795
|
+
const contentRel = relative12(process.cwd(), dir) || ".";
|
|
71796
|
+
const contentArg2 = shellQuote2(contentRel);
|
|
71591
71797
|
if (onlyRaw !== void 0) {
|
|
71592
71798
|
const onlyDraft = flags.draft === true;
|
|
71593
71799
|
const { parseOnlySelectors: parseOnlySelectors2, planFromPayload: planFromPayload2, notCarriedDiff: notCarriedDiff2 } = await Promise.resolve().then(() => (init_release_patch2(), release_patch_exports));
|
|
@@ -71631,7 +71837,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71631
71837
|
});
|
|
71632
71838
|
const patchUxContext = {
|
|
71633
71839
|
releaseId: manifest.releaseId,
|
|
71634
|
-
contentArg,
|
|
71840
|
+
contentArg: contentArg2,
|
|
71635
71841
|
contentDir: contentRel,
|
|
71636
71842
|
app,
|
|
71637
71843
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71726,7 +71932,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71726
71932
|
const staleEvidence = evidence.staleRuns > 0 ? `${evidence.staleRuns} retained attestation(s) were recorded at this commit, but none describes the content being published` : null;
|
|
71727
71933
|
const attestationErrors = [...evidence.historyErrors, ...staleEvidence ? [staleEvidence] : []];
|
|
71728
71934
|
if (attestationErrors.length > 0 && !force) {
|
|
71729
|
-
const remedy = `\`himi test --content ${
|
|
71935
|
+
const remedy = `\`himi test --content ${contentArg2}\` (or \`himi render <screenId> --content ${contentArg2}\`)`;
|
|
71730
71936
|
const corrupted = evidence.historyErrors.length > 0;
|
|
71731
71937
|
print({
|
|
71732
71938
|
ok: false,
|
|
@@ -71764,7 +71970,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71764
71970
|
// fixing one door and not the other is the drift the shared helpers exist to stop.
|
|
71765
71971
|
hint: uxHandoverHint(uxEvidence, {
|
|
71766
71972
|
releaseId: manifest.releaseId,
|
|
71767
|
-
contentArg,
|
|
71973
|
+
contentArg: contentArg2,
|
|
71768
71974
|
contentDir: contentRel,
|
|
71769
71975
|
app,
|
|
71770
71976
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71873,11 +72079,13 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71873
72079
|
const base = serveBase();
|
|
71874
72080
|
const explicitTarget = contextualDefaultTarget !== void 0 || flags.target !== void 0 || flags["serve-url"] !== void 0 || !!process.env.HIMI_SERVE_TARGET;
|
|
71875
72081
|
const loopbackWarning = base ? loopbackTargetWarning(base, explicitTarget) : null;
|
|
72082
|
+
const afterDraft = draft ? (await Promise.resolve().then(() => (init_milestones(), milestones_exports))).afterDraftPush(dir, { app, releaseId: release, content: str6(flags.content) }) : null;
|
|
71876
72083
|
print({
|
|
71877
72084
|
ok: true,
|
|
71878
72085
|
app,
|
|
71879
72086
|
releaseId: release,
|
|
71880
72087
|
draft,
|
|
72088
|
+
...afterDraft?.postcard ? { postcard: afterDraft.postcard } : {},
|
|
71881
72089
|
// Say so when the push acquired the slug on the caller's behalf. A claim takes a name
|
|
71882
72090
|
// out of a global first-come namespace, counts against quota, and cannot be undone —
|
|
71883
72091
|
// so it must never happen silently.
|
|
@@ -71918,7 +72126,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71918
72126
|
// behind that: the plane keeps the previous attestation for this release id when a
|
|
71919
72127
|
// push carries none, so the published release can look attested by an earlier run.
|
|
71920
72128
|
...!attestation && staleEvidence ? {
|
|
71921
|
-
attestationNote: `${staleEvidence} \u2014 this release was published with no headless evidence of its own, and the serve plane may still show the attestation from an earlier push of this release id. Re-attest with \`himi test --content ${
|
|
72129
|
+
attestationNote: `${staleEvidence} \u2014 this release was published with no headless evidence of its own, and the serve plane may still show the attestation from an earlier push of this release id. Re-attest with \`himi test --content ${contentArg2}\` and push again to attach one.`
|
|
71922
72130
|
} : {},
|
|
71923
72131
|
// #2955 — the SAME honesty for the UX gate: `--force` published this preview without a
|
|
71924
72132
|
// recorded mobile-UX drive for it, and the link below goes to a customer. Say it in the
|
|
@@ -71926,7 +72134,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71926
72134
|
// the same silence one step apart.
|
|
71927
72135
|
...uxHandoverOverride(uxEvidence, {
|
|
71928
72136
|
releaseId: manifest.releaseId,
|
|
71929
|
-
contentArg,
|
|
72137
|
+
contentArg: contentArg2,
|
|
71930
72138
|
contentDir: contentRel,
|
|
71931
72139
|
app,
|
|
71932
72140
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71972,7 +72180,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71972
72180
|
next: [
|
|
71973
72181
|
`himi context --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
71974
72182
|
`himi screens --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
71975
|
-
`himi telemetry --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}
|
|
72183
|
+
`himi telemetry --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
72184
|
+
...afterDraft ? [afterDraft.next] : []
|
|
71976
72185
|
],
|
|
71977
72186
|
promote: draft ? `himi promote --app ${app} --release ${release}${forcedPastErrors ? " --force" : ""}${targetName() !== "local" ? ` --target ${targetName()}` : ""}` : null,
|
|
71978
72187
|
...(outcome.manifest.functions?.length ?? 0) > 0 ? {
|
|
@@ -72016,7 +72225,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72016
72225
|
const displayName = str6(flags.name);
|
|
72017
72226
|
const launchMode = flags.snapshot === true ? "snapshot" : "live";
|
|
72018
72227
|
const packOpts = { createdBy: `himi-cli ${cliVersion()}`, launchMode, ...displayName ? { displayName } : {} };
|
|
72019
|
-
const writePack = (root,
|
|
72228
|
+
const writePack = (root, appName2, out, source) => format === "dir" ? packReleaseToDir2(root, appName2, out, packOpts) : packRelease2(root, appName2, out, { ...packOpts, ...source ? { source } : {} });
|
|
72020
72229
|
const releaseDir = str6(flags["release-dir"]);
|
|
72021
72230
|
if (releaseDir) {
|
|
72022
72231
|
const only = str6(flags.app);
|
|
@@ -72081,7 +72290,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72081
72290
|
}
|
|
72082
72291
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72083
72292
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
72084
|
-
const built = mkdtempSync4(
|
|
72293
|
+
const built = mkdtempSync4(join63(tmpdir5(), "himi-pack-"));
|
|
72085
72294
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
72086
72295
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
72087
72296
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -72286,7 +72495,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72286
72495
|
}));
|
|
72287
72496
|
return 1;
|
|
72288
72497
|
}
|
|
72289
|
-
const archive =
|
|
72498
|
+
const archive = readFileSync77(resolve47(file));
|
|
72290
72499
|
const result = await client2().createPackageShare({
|
|
72291
72500
|
app: opened.header.app,
|
|
72292
72501
|
releaseId: opened.header.releaseId,
|
|
@@ -72346,11 +72555,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72346
72555
|
const app = await appId(dir2);
|
|
72347
72556
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72348
72557
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
72349
|
-
temp = mkdtempSync4(
|
|
72558
|
+
temp = mkdtempSync4(join63(tmpdir5(), "himi-run-build-"));
|
|
72350
72559
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
72351
72560
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
72352
72561
|
servedMissing = initial.missingBundles;
|
|
72353
|
-
source =
|
|
72562
|
+
source = join63(temp, app);
|
|
72354
72563
|
}
|
|
72355
72564
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
72356
72565
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -72386,7 +72595,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72386
72595
|
if (!recordKit) return;
|
|
72387
72596
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
72388
72597
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
72389
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
72598
|
+
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${join63(dir, ".himi")} is not a real directory`}, so the build board will not frame this preview.` }));
|
|
72390
72599
|
await refreshBoard();
|
|
72391
72600
|
};
|
|
72392
72601
|
const retract = async () => {
|
|
@@ -72417,7 +72626,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72417
72626
|
}
|
|
72418
72627
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
72419
72628
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
72420
|
-
if (watch2) served = mkdtempSync4(
|
|
72629
|
+
if (watch2) served = mkdtempSync4(join63(tmpdir5(), "himi-run-served-"));
|
|
72421
72630
|
const running = await runPackage2(source, {
|
|
72422
72631
|
port,
|
|
72423
72632
|
chrome: chromeArg,
|
|
@@ -72439,8 +72648,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72439
72648
|
await announce(running);
|
|
72440
72649
|
if (watchKit && bus) {
|
|
72441
72650
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72442
|
-
const live2 =
|
|
72443
|
-
const manifestOf = (tree) => JSON.parse(
|
|
72651
|
+
const live2 = join63(running.releaseRoot, running.app);
|
|
72652
|
+
const manifestOf = (tree) => JSON.parse(readFileSync77(join63(tree, "release-manifest.json"), "utf8"));
|
|
72444
72653
|
let current = manifestOf(live2);
|
|
72445
72654
|
const failed2 = async (message) => {
|
|
72446
72655
|
if (stopping) return;
|
|
@@ -72451,7 +72660,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72451
72660
|
};
|
|
72452
72661
|
rebuild = watchKit.serialize(async () => {
|
|
72453
72662
|
const t0 = Date.now();
|
|
72454
|
-
const next = mkdtempSync4(
|
|
72663
|
+
const next = mkdtempSync4(join63(tmpdir5(), "himi-run-build-"));
|
|
72455
72664
|
try {
|
|
72456
72665
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
72457
72666
|
if (bres.compileErrors.length) {
|
|
@@ -72468,16 +72677,16 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72468
72677
|
return;
|
|
72469
72678
|
}
|
|
72470
72679
|
if (stopping) return;
|
|
72471
|
-
const fresh = manifestOf(
|
|
72680
|
+
const fresh = manifestOf(join63(next, running.app));
|
|
72472
72681
|
const diff = watchKit.diffReleases(current, fresh);
|
|
72473
72682
|
const { describeChanges: describeChanges2, headline: headline2 } = await Promise.resolve().then(() => (init_build_changes(), build_changes_exports));
|
|
72474
|
-
const changes = describeChanges2(live2,
|
|
72683
|
+
const changes = describeChanges2(live2, join63(next, running.app), diff);
|
|
72475
72684
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
72476
72685
|
renameSync7(live2, retired);
|
|
72477
72686
|
try {
|
|
72478
|
-
renameSync7(
|
|
72687
|
+
renameSync7(join63(next, running.app), live2);
|
|
72479
72688
|
} catch {
|
|
72480
|
-
cpSync3(
|
|
72689
|
+
cpSync3(join63(next, running.app), live2, { recursive: true });
|
|
72481
72690
|
}
|
|
72482
72691
|
rmSync14(retired, { recursive: true, force: true });
|
|
72483
72692
|
current = fresh;
|
|
@@ -73087,7 +73296,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73087
73296
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
73088
73297
|
return 2;
|
|
73089
73298
|
}
|
|
73090
|
-
if (!
|
|
73299
|
+
if (!existsSync65(file)) {
|
|
73091
73300
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
73092
73301
|
return 2;
|
|
73093
73302
|
}
|
|
@@ -73143,7 +73352,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73143
73352
|
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."
|
|
73144
73353
|
};
|
|
73145
73354
|
if (kind === "tokens" || kind === "app-config") {
|
|
73146
|
-
const body =
|
|
73355
|
+
const body = readFileSync77(file, "utf8");
|
|
73147
73356
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
73148
73357
|
return runReleasePatch({
|
|
73149
73358
|
...common,
|
|
@@ -73158,7 +73367,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73158
73367
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
73159
73368
|
return 2;
|
|
73160
73369
|
}
|
|
73161
|
-
const descriptor =
|
|
73370
|
+
const descriptor = readFileSync77(file, "utf8");
|
|
73162
73371
|
try {
|
|
73163
73372
|
JSON.parse(descriptor);
|
|
73164
73373
|
} catch (e) {
|
|
@@ -73198,7 +73407,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73198
73407
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
73199
73408
|
});
|
|
73200
73409
|
}
|
|
73201
|
-
const bytes2 =
|
|
73410
|
+
const bytes2 = readFileSync77(file);
|
|
73202
73411
|
const sha = createHash28("sha256").update(bytes2).digest("hex");
|
|
73203
73412
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
73204
73413
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -73342,7 +73551,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73342
73551
|
}
|
|
73343
73552
|
let def;
|
|
73344
73553
|
try {
|
|
73345
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
73554
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync77(arg.slice(1), "utf8") : arg);
|
|
73346
73555
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
73347
73556
|
io.error(JSON.stringify({ error: "invalid_definition", problems: [`--definition must be a JSON object, got ${Array.isArray(parsed) ? "an array" : parsed === null ? "null" : typeof parsed}`] }));
|
|
73348
73557
|
return 2;
|
|
@@ -73806,7 +74015,7 @@ ${label2}`);
|
|
|
73806
74015
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
73807
74016
|
{
|
|
73808
74017
|
const distDir = contentDir(flags);
|
|
73809
|
-
if (
|
|
74018
|
+
if (existsSync65(join63(distDir, "himalaya.content.json"))) {
|
|
73810
74019
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
73811
74020
|
const errors = issues.filter((i) => i.severity === "error");
|
|
73812
74021
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -74075,7 +74284,7 @@ ${label2}`);
|
|
|
74075
74284
|
const dpxPath = dpxSessionTokenPath();
|
|
74076
74285
|
let dpx;
|
|
74077
74286
|
try {
|
|
74078
|
-
dpx =
|
|
74287
|
+
dpx = readFileSync77(dpxPath, "utf8").trim();
|
|
74079
74288
|
} catch {
|
|
74080
74289
|
io.error(JSON.stringify({ error: `no dpx session at ${dpxPath} \u2014 run \`dpx auth login\` then \`dpx auth token > ${dpxPath}\` (dpx 2.x keeps its own state in ~/.dpx/auth.json and does NOT write the legacy session file), or omit --dpx` }));
|
|
74081
74290
|
return 1;
|
|
@@ -74483,7 +74692,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
74483
74692
|
const path2 = dpxSessionTokenPath();
|
|
74484
74693
|
let raw;
|
|
74485
74694
|
try {
|
|
74486
|
-
raw =
|
|
74695
|
+
raw = readFileSync77(path2, "utf8");
|
|
74487
74696
|
} catch {
|
|
74488
74697
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
74489
74698
|
return 1;
|