@wix/himalaya-cli 0.1069.0 → 0.1071.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 +666 -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;
|
|
@@ -33194,8 +33264,8 @@ function clampRule(rule, denyPrefixes, maxTTL) {
|
|
|
33194
33264
|
ttl: Math.min(rule.ttl, maxTTL)
|
|
33195
33265
|
};
|
|
33196
33266
|
}
|
|
33197
|
-
function resolveWixCachePolicy(
|
|
33198
|
-
const appRules = CACHE_OVERRIDES[
|
|
33267
|
+
function resolveWixCachePolicy(appName2) {
|
|
33268
|
+
const appRules = CACHE_OVERRIDES[appName2] ?? [];
|
|
33199
33269
|
const rules = appRules.map((r) => clampRule(r, PLATFORM_DENY_PREFIXES, PLATFORM_MAX_TTL));
|
|
33200
33270
|
return { rules, defaultCacheable: false };
|
|
33201
33271
|
}
|
|
@@ -33313,7 +33383,7 @@ function expandNavBundle(ref, ctx) {
|
|
|
33313
33383
|
};
|
|
33314
33384
|
}
|
|
33315
33385
|
function deriveNavigationConfig(app, bundleCtx) {
|
|
33316
|
-
const
|
|
33386
|
+
const appName2 = app.name;
|
|
33317
33387
|
const concrete = app.screenIds.map((screenId) => ({
|
|
33318
33388
|
screenId,
|
|
33319
33389
|
isPublic: true,
|
|
@@ -33326,7 +33396,7 @@ function deriveNavigationConfig(app, bundleCtx) {
|
|
|
33326
33396
|
const keys = (pat.match(/\{([^}]+)\}/g) ?? []).map((m) => m.slice(1, -1));
|
|
33327
33397
|
return { screenId: base, isPublic: true, paramKeys: keys, parentScreenId: "", tabId: "" };
|
|
33328
33398
|
});
|
|
33329
|
-
const ov = NAV_OVERRIDES[
|
|
33399
|
+
const ov = NAV_OVERRIDES[appName2];
|
|
33330
33400
|
if (ov?.parents) {
|
|
33331
33401
|
for (const s of [...concrete, ...templated]) {
|
|
33332
33402
|
if (ov.parents[s.screenId]) s.parentScreenId = ov.parents[s.screenId];
|
|
@@ -33337,7 +33407,7 @@ function deriveNavigationConfig(app, bundleCtx) {
|
|
|
33337
33407
|
scheme: app.urlScheme,
|
|
33338
33408
|
deepLinkPatterns: app.deepLinkPatterns ?? ov?.deepLinkPatterns ?? [],
|
|
33339
33409
|
linkableScreens,
|
|
33340
|
-
wixCachePolicy: resolveWixCachePolicy(
|
|
33410
|
+
wixCachePolicy: resolveWixCachePolicy(appName2),
|
|
33341
33411
|
// Fail-open baseline; tightened OTA via the admin app-config override. The
|
|
33342
33412
|
// DESTINATION(s) are derived generically from the app's config (no app-name
|
|
33343
33413
|
// special-casing) so the app chooses where telemetry goes via OTA:
|
|
@@ -33415,12 +33485,12 @@ function buildAppConfigDocument(req, meta, override, bundleCtx) {
|
|
|
33415
33485
|
return { config, body, etag, locale };
|
|
33416
33486
|
}
|
|
33417
33487
|
function handleAppConfigRequest(req, res, meta, override, bundleCtx) {
|
|
33418
|
-
const
|
|
33488
|
+
const appName2 = decodeURIComponent(
|
|
33419
33489
|
(req.url ?? "").replace(/^\/v1\/app-config\//, "").split("?")[0]
|
|
33420
33490
|
);
|
|
33421
|
-
if (
|
|
33491
|
+
if (appName2 !== meta.name) {
|
|
33422
33492
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
33423
|
-
res.end(JSON.stringify({ error: "unknown_app", appName }));
|
|
33493
|
+
res.end(JSON.stringify({ error: "unknown_app", appName: appName2 }));
|
|
33424
33494
|
return;
|
|
33425
33495
|
}
|
|
33426
33496
|
const { body, etag, locale } = buildAppConfigDocument(req, meta, override, bundleCtx);
|
|
@@ -36377,7 +36447,7 @@ async function handleToggleEval(req, res, state) {
|
|
|
36377
36447
|
for (const id of requested) out[id] = state.toggles[id] ?? false;
|
|
36378
36448
|
sendJson(res, 200, out);
|
|
36379
36449
|
}
|
|
36380
|
-
function evalContextFromReq(req,
|
|
36450
|
+
function evalContextFromReq(req, appName2) {
|
|
36381
36451
|
const h = (k) => {
|
|
36382
36452
|
const v = req.headers[k];
|
|
36383
36453
|
return typeof v === "string" ? v : void 0;
|
|
@@ -36385,7 +36455,7 @@ function evalContextFromReq(req, appName) {
|
|
|
36385
36455
|
return {
|
|
36386
36456
|
sessionId: h("x-himalaya-session") ?? "dev-session",
|
|
36387
36457
|
userId: h("x-himalaya-user"),
|
|
36388
|
-
appId:
|
|
36458
|
+
appId: appName2,
|
|
36389
36459
|
platform: h("x-himalaya-platform"),
|
|
36390
36460
|
appVersion: h("x-himalaya-app-version"),
|
|
36391
36461
|
locale: typeof req.headers["accept-language"] === "string" ? req.headers["accept-language"].split(",")[0] : void 0
|
|
@@ -37533,8 +37603,8 @@ async function handleActionHandlerBundleGet(res, app) {
|
|
|
37533
37603
|
}
|
|
37534
37604
|
async function serveStatic(req, res, root, prefix) {
|
|
37535
37605
|
const requested = decodeURIComponent((req.url ?? "").split("?")[0]);
|
|
37536
|
-
const
|
|
37537
|
-
const safe = normalize3(
|
|
37606
|
+
const relative13 = requested.replace(prefix, "").replace(/^\//, "");
|
|
37607
|
+
const safe = normalize3(relative13).replace(/^(\.\.[\/\\])+/, "");
|
|
37538
37608
|
const fullPath = resolve31(root, safe);
|
|
37539
37609
|
if (!fullPath.startsWith(root)) {
|
|
37540
37610
|
return send(res, 403, "forbidden");
|
|
@@ -37698,19 +37768,19 @@ function handleAssetLinks(res, state) {
|
|
|
37698
37768
|
});
|
|
37699
37769
|
}
|
|
37700
37770
|
function createDevServer(opts = {}) {
|
|
37701
|
-
const
|
|
37771
|
+
const appName2 = opts.app ?? "sample";
|
|
37702
37772
|
if (!opts.preloaded) {
|
|
37703
|
-
throw new Error(`createDevServer requires a preloaded module for "${
|
|
37773
|
+
throw new Error(`createDevServer requires a preloaded module for "${appName2}". Preload via loadApp("${appName2}").`);
|
|
37704
37774
|
}
|
|
37705
37775
|
checkRegistry(opts.preloaded.module.actions);
|
|
37706
37776
|
const port = opts.port ?? Number(process.env.HIMALAYA_DEV_PORT ?? 8080);
|
|
37707
37777
|
const hotReloadEnabled = opts.enableHotReload ?? process.env.HIMALAYA_DEV_HOT_RELOAD === "1";
|
|
37708
37778
|
const state = {
|
|
37709
|
-
appName,
|
|
37779
|
+
appName: appName2,
|
|
37710
37780
|
// Store construction is cheap now; its node:sqlite DB is opened LAZILY on first query
|
|
37711
37781
|
// (store.ts), so the serve authoring plane can boot createDevServer on a Whirlwind guest
|
|
37712
37782
|
// that has no node:sqlite — the stateless build/render path never queries the demo store.
|
|
37713
|
-
store: new Store(
|
|
37783
|
+
store: new Store(appName2),
|
|
37714
37784
|
toggles: {
|
|
37715
37785
|
pinned_notes_v2: false,
|
|
37716
37786
|
weekly_review_v1: true,
|
|
@@ -37731,7 +37801,7 @@ function createDevServer(opts = {}) {
|
|
|
37731
37801
|
localOverrides: /* @__PURE__ */ new Map(),
|
|
37732
37802
|
localOverrideHistory: /* @__PURE__ */ new Map(),
|
|
37733
37803
|
app: opts.preloaded,
|
|
37734
|
-
moduleStore: opts.preloaded ? opts.preloaded.module.createStore(
|
|
37804
|
+
moduleStore: opts.preloaded ? opts.preloaded.module.createStore(appName2) : void 0,
|
|
37735
37805
|
telemetryEvents: [],
|
|
37736
37806
|
adminUrl: process.env.HIMALAYA_ADMIN_URL,
|
|
37737
37807
|
wix: createWixGatewayState(),
|
|
@@ -42298,7 +42368,7 @@ async function buildFromLoaded(preloaded, dest, opts = {}) {
|
|
|
42298
42368
|
...collect2?.lint ? { lint, workers } : {},
|
|
42299
42369
|
...collect2?.render ? { renders } : {},
|
|
42300
42370
|
...collect2?.descriptors ? { descriptors: baked, linkableScreenIds: [...linkable] } : {},
|
|
42301
|
-
...
|
|
42371
|
+
...typeof preloaded.meta.homeScreenId === "string" && preloaded.meta.homeScreenId ? { homeScreenId: preloaded.meta.homeScreenId } : {},
|
|
42302
42372
|
...renderTokens !== void 0 ? { tokens: renderTokens } : {},
|
|
42303
42373
|
...preloaded.meta.surfaces ? { surfaceNav: preloaded.meta.surfaces } : {},
|
|
42304
42374
|
auth: (() => {
|
|
@@ -42595,7 +42665,7 @@ h2{font-size:12px;font-weight:600;color:var(--muted);text-transform:uppercase;le
|
|
|
42595
42665
|
.sw{display:flex;gap:6px}.sw span{width:22px;height:22px;border-radius:50%;border:1px solid var(--line)}
|
|
42596
42666
|
.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
42667
|
.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}
|
|
42668
|
+
.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
42669
|
.empty{color:var(--faint);font-size:13px;padding:8px 0}
|
|
42600
42670
|
#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
42671
|
.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 +42794,7 @@ function render(s){
|
|
|
42724
42794
|
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
42795
|
var last=s.journal[0];
|
|
42726
42796
|
$("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";
|
|
42797
|
+
$("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
42798
|
var film=$("film");clear(film);
|
|
42729
42799
|
if(!rewinding){var n0=s.timelineFrames||0;$("scrub").hidden=n0<2;$("slider").max=String(Math.max(1,n0-1));$("slider").value=$("slider").max}
|
|
42730
42800
|
if(rewinding){paintStill(s)}else{$("still").hidden=true;$("focus").hidden=false;var focus=$("focus");
|
|
@@ -42756,7 +42826,7 @@ function render(s){
|
|
|
42756
42826
|
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
42827
|
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
42828
|
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));
|
|
42829
|
+
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
42830
|
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
42831
|
paintPop(s);
|
|
42762
42832
|
}
|
|
@@ -43529,9 +43599,10 @@ function buildView(dir, memory, now) {
|
|
|
43529
43599
|
journal: entries.slice(-MAX_JOURNAL).reverse().map((e) => ({
|
|
43530
43600
|
ts: e.ts,
|
|
43531
43601
|
message: e.message,
|
|
43532
|
-
step: e.step ?? null,
|
|
43533
|
-
stepNumber: e.stepNumber ?? null,
|
|
43534
|
-
images: (e.images ?? []).map((i) => historyUrl(basename10(i.file)))
|
|
43602
|
+
step: isCliEntry(e) ? null : e.step ?? null,
|
|
43603
|
+
stepNumber: isCliEntry(e) ? null : e.stepNumber ?? null,
|
|
43604
|
+
images: (e.images ?? []).map((i) => historyUrl(basename10(i.file))),
|
|
43605
|
+
by: isCliEntry(e) ? CLI_AUTHOR : null
|
|
43535
43606
|
})),
|
|
43536
43607
|
screens,
|
|
43537
43608
|
focus,
|
|
@@ -44779,6 +44850,109 @@ var init_notify_setup = __esm({
|
|
|
44779
44850
|
}
|
|
44780
44851
|
});
|
|
44781
44852
|
|
|
44853
|
+
// src/milestones.ts
|
|
44854
|
+
var milestones_exports = {};
|
|
44855
|
+
__export(milestones_exports, {
|
|
44856
|
+
afterDraftPush: () => afterDraftPush,
|
|
44857
|
+
afterRenderPng: () => afterRenderPng,
|
|
44858
|
+
afterTestRun: () => afterTestRun,
|
|
44859
|
+
displayPath: () => displayPath,
|
|
44860
|
+
homeScreenIdOf: () => homeScreenIdOf,
|
|
44861
|
+
openBoardForSession: () => openBoardForSession,
|
|
44862
|
+
progressCommand: () => progressCommand,
|
|
44863
|
+
sessionSteps: () => sessionSteps,
|
|
44864
|
+
testPostcardMessage: () => testPostcardMessage
|
|
44865
|
+
});
|
|
44866
|
+
import { existsSync as existsSync44, readFileSync as readFileSync48 } from "node:fs";
|
|
44867
|
+
import { basename as basename12, isAbsolute as isAbsolute4, join as join42, relative as relative8 } from "node:path";
|
|
44868
|
+
function homeScreenIdOf(dir) {
|
|
44869
|
+
let src;
|
|
44870
|
+
try {
|
|
44871
|
+
src = readFileSync48(join42(dir, "dev", "index.ts"), "utf8");
|
|
44872
|
+
} catch {
|
|
44873
|
+
return null;
|
|
44874
|
+
}
|
|
44875
|
+
const m = /^[ \t]*homeScreenId[ \t]*:[ \t]*(?:"((?:[^"\\\n]|\\.)*)"|'((?:[^'\\\n]|\\.)*)')/m.exec(src);
|
|
44876
|
+
const id = m ? m[1] ?? m[2] : void 0;
|
|
44877
|
+
return id && /^[A-Za-z0-9_.\-/{}]+$/.test(id) ? id : null;
|
|
44878
|
+
}
|
|
44879
|
+
function displayPath(p, cwd = process.cwd()) {
|
|
44880
|
+
const rel = relative8(cwd, p);
|
|
44881
|
+
return rel && !rel.startsWith("..") && !isAbsolute4(rel) ? rel : p;
|
|
44882
|
+
}
|
|
44883
|
+
function progressCommand(opts) {
|
|
44884
|
+
return `himi progress "<${opts.what}>"${opts.step ? ` --step ${opts.step}` : ""}${opts.image ? ` --image ${shellQuote(opts.image)}` : ""}${contentArg(opts.content)}`;
|
|
44885
|
+
}
|
|
44886
|
+
function sessionSteps(opts) {
|
|
44887
|
+
const content = displayPath(opts.dir, opts.cwd);
|
|
44888
|
+
const home = opts.home ?? "<homeScreenId>";
|
|
44889
|
+
const shot = `.himi/shots/${home}.png`;
|
|
44890
|
+
return [
|
|
44891
|
+
`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/`,
|
|
44892
|
+
`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`,
|
|
44893
|
+
`${progressCommand({ what: "where the build starts", step: "plan", image: shot, content })} \u2014 your postcard for the owner, with that picture`
|
|
44894
|
+
];
|
|
44895
|
+
}
|
|
44896
|
+
async function openBoardForSession(dir, cwd = process.cwd()) {
|
|
44897
|
+
try {
|
|
44898
|
+
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
44899
|
+
const { page, url } = openStudio2(dir);
|
|
44900
|
+
const rel = relative8(cwd, page);
|
|
44901
|
+
return { page: rel && !rel.startsWith("..") && !isAbsolute4(rel) ? rel : page, url, opened: false };
|
|
44902
|
+
} catch (e) {
|
|
44903
|
+
return { opened: false, error: `the build board was not created: ${e.message} \u2014 \`himi studio --no-open\` in the app retries it` };
|
|
44904
|
+
}
|
|
44905
|
+
}
|
|
44906
|
+
function journal(dir, milestone, message, extra) {
|
|
44907
|
+
const r = journalMilestone(dir, { milestone, message, ...extra });
|
|
44908
|
+
return r.journaled ? { journaled: true, milestone, message } : void 0;
|
|
44909
|
+
}
|
|
44910
|
+
function afterRenderPng(dir, input) {
|
|
44911
|
+
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;
|
|
44912
|
+
return {
|
|
44913
|
+
...postcard ? { postcard } : {},
|
|
44914
|
+
next: input.renderable ? [progressCommand({ what: "what changed", image: displayPath(input.pngFile), content: input.content })] : []
|
|
44915
|
+
};
|
|
44916
|
+
}
|
|
44917
|
+
function testPostcardMessage(s) {
|
|
44918
|
+
const links = s.broken === void 0 ? "" : `, ${plural(s.broken, "broken link")}`;
|
|
44919
|
+
const unreached = s.unreached ? `, ${plural(s.unreached, "screen")} nothing links to` : "";
|
|
44920
|
+
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"}.`;
|
|
44921
|
+
}
|
|
44922
|
+
function afterTestRun(dir, input) {
|
|
44923
|
+
const postcard = journal(dir, "test", testPostcardMessage(input), {
|
|
44924
|
+
ref: input.runId,
|
|
44925
|
+
...input.homeShot && existsSync44(input.homeShot) ? { image: input.homeShot } : {},
|
|
44926
|
+
...input.now ? { now: input.now } : {}
|
|
44927
|
+
});
|
|
44928
|
+
return {
|
|
44929
|
+
...postcard ? { postcard } : {},
|
|
44930
|
+
next: [
|
|
44931
|
+
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"
|
|
44932
|
+
]
|
|
44933
|
+
};
|
|
44934
|
+
}
|
|
44935
|
+
function afterDraftPush(dir, input) {
|
|
44936
|
+
const postcard = journal(dir, "draft", `Draft pushed: release ${input.releaseId.slice(0, 12)} of ${input.app} \u2014 owner-private, not live.`, {
|
|
44937
|
+
ref: input.releaseId,
|
|
44938
|
+
...input.now ? { now: input.now } : {}
|
|
44939
|
+
});
|
|
44940
|
+
return {
|
|
44941
|
+
...postcard ? { postcard } : {},
|
|
44942
|
+
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`
|
|
44943
|
+
};
|
|
44944
|
+
}
|
|
44945
|
+
var contentArg, plural, appName;
|
|
44946
|
+
var init_milestones = __esm({
|
|
44947
|
+
"src/milestones.ts"() {
|
|
44948
|
+
init_progress();
|
|
44949
|
+
init_shell_quote();
|
|
44950
|
+
contentArg = (content) => content ? ` --content ${shellQuote(content)}` : "";
|
|
44951
|
+
plural = (n, one, many = `${one}s`) => `${n} ${n === 1 ? one : many}`;
|
|
44952
|
+
appName = (dir) => appLabel(dir) ?? basename12(dir);
|
|
44953
|
+
}
|
|
44954
|
+
});
|
|
44955
|
+
|
|
44782
44956
|
// src/site-analyze/types.ts
|
|
44783
44957
|
function isRedirectUri(value) {
|
|
44784
44958
|
return /^[a-z][a-z0-9+.-]*:\/\/\S*$/i.test(value);
|
|
@@ -45216,8 +45390,8 @@ __export(template_trim_exports, {
|
|
|
45216
45390
|
routeMatcher: () => routeMatcher,
|
|
45217
45391
|
runTemplateTrim: () => runTemplateTrim
|
|
45218
45392
|
});
|
|
45219
|
-
import { cpSync, existsSync as
|
|
45220
|
-
import { dirname as dirname25, join as
|
|
45393
|
+
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";
|
|
45394
|
+
import { dirname as dirname25, join as join43 } from "node:path";
|
|
45221
45395
|
function routeMatcher(pattern) {
|
|
45222
45396
|
const detail = /^\^([A-Za-z0-9_]+)\(\?:\[_\/\]\(\.\+\)\)\?\$$/.exec(pattern);
|
|
45223
45397
|
if (detail) {
|
|
@@ -45911,20 +46085,20 @@ function homeModulesPass(app, kept, edited) {
|
|
|
45911
46085
|
return { text: patched.src, dropped: patched.droppedModules };
|
|
45912
46086
|
}
|
|
45913
46087
|
function listWorkers(dir) {
|
|
45914
|
-
const root =
|
|
45915
|
-
if (!
|
|
45916
|
-
const dirs = readdirSync24(root).filter((n) => statSync10(
|
|
46088
|
+
const root = join43(dir, "tier5-src");
|
|
46089
|
+
if (!existsSync45(root)) return { dirs: [], files: {} };
|
|
46090
|
+
const dirs = readdirSync24(root).filter((n) => statSync10(join43(root, n)).isDirectory()).sort();
|
|
45917
46091
|
const files = {};
|
|
45918
46092
|
const walk2 = (abs, rel) => {
|
|
45919
46093
|
for (const name of readdirSync24(abs)) {
|
|
45920
46094
|
if (name === "node_modules") continue;
|
|
45921
|
-
const p =
|
|
46095
|
+
const p = join43(abs, name);
|
|
45922
46096
|
const r = `${rel}/${name}`;
|
|
45923
46097
|
if (statSync10(p).isDirectory()) walk2(p, r);
|
|
45924
|
-
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] =
|
|
46098
|
+
else if (/\.(?:[cm]?[jt]sx?|json)$/.test(name)) files[r] = readFileSync49(p, "utf8");
|
|
45925
46099
|
}
|
|
45926
46100
|
};
|
|
45927
|
-
for (const d of dirs) walk2(
|
|
46101
|
+
for (const d of dirs) walk2(join43(root, d), `tier5-src/${d}`);
|
|
45928
46102
|
return { dirs, files };
|
|
45929
46103
|
}
|
|
45930
46104
|
function csv(v) {
|
|
@@ -45947,16 +46121,16 @@ async function runTemplateTrim(req, deps) {
|
|
|
45947
46121
|
links = req.links;
|
|
45948
46122
|
}
|
|
45949
46123
|
const dir = req.dir;
|
|
45950
|
-
const devPath =
|
|
45951
|
-
const configPath =
|
|
45952
|
-
if (!
|
|
46124
|
+
const devPath = join43(dir, "dev/index.ts");
|
|
46125
|
+
const configPath = join43(dir, "config.ts");
|
|
46126
|
+
if (!existsSync45(devPath) || !existsSync45(configPath)) {
|
|
45953
46127
|
return refuse3(new TrimRefusal(`${dir} has no dev/index.ts + config.ts \u2014 point --content at an app scaffolded with \`himi init --template\``));
|
|
45954
46128
|
}
|
|
45955
46129
|
if (isTemplateSourceTree(dir)) {
|
|
45956
46130
|
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
46131
|
}
|
|
45958
|
-
const dev =
|
|
45959
|
-
const config =
|
|
46132
|
+
const dev = readFileSync49(devPath, "utf8");
|
|
46133
|
+
const config = readFileSync49(configPath, "utf8");
|
|
45960
46134
|
const workers = listWorkers(dir);
|
|
45961
46135
|
let plan;
|
|
45962
46136
|
try {
|
|
@@ -45966,23 +46140,23 @@ async function runTemplateTrim(req, deps) {
|
|
|
45966
46140
|
throw e;
|
|
45967
46141
|
}
|
|
45968
46142
|
if (req.dryRun) return { code: 0, result: { ok: true, dryRun: true, ...plan.report, validate: null } };
|
|
45969
|
-
const hadHimi =
|
|
45970
|
-
const backupRel =
|
|
45971
|
-
const backup =
|
|
46143
|
+
const hadHimi = existsSync45(join43(dir, ".himi"));
|
|
46144
|
+
const backupRel = join43(".himi", "trim-backup", (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
46145
|
+
const backup = join43(dir, backupRel);
|
|
45972
46146
|
const originals = [[devPath, "dev/index.ts"], [configPath, "config.ts"]];
|
|
45973
46147
|
const moved = [];
|
|
45974
46148
|
const restore = () => {
|
|
45975
46149
|
for (const [path2, rel] of originals) {
|
|
45976
|
-
const original =
|
|
45977
|
-
if (!
|
|
46150
|
+
const original = readFileSync49(join43(backup, rel));
|
|
46151
|
+
if (!existsSync45(path2) || !readFileSync49(path2).equals(original)) writeFileSync16(path2, original);
|
|
45978
46152
|
}
|
|
45979
|
-
for (const name of [...moved].reverse()) renameSync5(
|
|
46153
|
+
for (const name of [...moved].reverse()) renameSync5(join43(backup, "tier5-src", name), join43(dir, "tier5-src", name));
|
|
45980
46154
|
moved.length = 0;
|
|
45981
46155
|
};
|
|
45982
46156
|
const apply = () => {
|
|
45983
46157
|
const moveDir = deps.moveDir ?? renameSync5;
|
|
45984
46158
|
for (const name of plan.removedWorkers) {
|
|
45985
|
-
moveDir(
|
|
46159
|
+
moveDir(join43(dir, "tier5-src", name), join43(backup, "tier5-src", name));
|
|
45986
46160
|
moved.push(name);
|
|
45987
46161
|
}
|
|
45988
46162
|
if (plan.dev !== dev) writeFileSync16(devPath, plan.dev);
|
|
@@ -45990,8 +46164,8 @@ async function runTemplateTrim(req, deps) {
|
|
|
45990
46164
|
};
|
|
45991
46165
|
const dropBackup = () => {
|
|
45992
46166
|
rmSync8(backup, { recursive: true, force: true });
|
|
45993
|
-
for (const d of [dirname25(backup),
|
|
45994
|
-
if (d ===
|
|
46167
|
+
for (const d of [dirname25(backup), join43(dir, ".himi")]) {
|
|
46168
|
+
if (d === join43(dir, ".himi") && hadHimi) break;
|
|
45995
46169
|
try {
|
|
45996
46170
|
if (!readdirSync24(d).length) rmSync8(d, { recursive: true });
|
|
45997
46171
|
} catch {
|
|
@@ -46017,9 +46191,9 @@ async function runTemplateTrim(req, deps) {
|
|
|
46017
46191
|
return { code: 1, result: { ok: false, error: `${error} (${message}); every file was restored`, rolledBack: true, ...base(validate4) } };
|
|
46018
46192
|
};
|
|
46019
46193
|
try {
|
|
46020
|
-
mkdirSync20(
|
|
46021
|
-
for (const [path2, rel] of originals) cpSync(path2,
|
|
46022
|
-
if (plan.removedWorkers.length) mkdirSync20(
|
|
46194
|
+
mkdirSync20(join43(backup, "dev"), { recursive: true });
|
|
46195
|
+
for (const [path2, rel] of originals) cpSync(path2, join43(backup, rel));
|
|
46196
|
+
if (plan.removedWorkers.length) mkdirSync20(join43(backup, "tier5-src"), { recursive: true });
|
|
46023
46197
|
} catch (e) {
|
|
46024
46198
|
dropBackup();
|
|
46025
46199
|
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 +46206,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46032
46206
|
let failure;
|
|
46033
46207
|
let validate3;
|
|
46034
46208
|
try {
|
|
46035
|
-
const written = parseApp(
|
|
46209
|
+
const written = parseApp(readFileSync49(devPath, "utf8"), readFileSync49(configPath, "utf8"));
|
|
46036
46210
|
const leftovers = leftoverNavRefs(written.nav.value, plan.removedIds);
|
|
46037
46211
|
if (leftovers.length) failure = { error: "navigation still names screens this trim removed", leftovers };
|
|
46038
46212
|
else {
|
|
@@ -46069,7 +46243,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46069
46243
|
else if (compared) {
|
|
46070
46244
|
failure = {
|
|
46071
46245
|
...failure,
|
|
46072
|
-
error: `himi validate --strict failed on the trimmed app \u2014 the trim introduced ${
|
|
46246
|
+
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
46247
|
introducedErrors: compared.introduced,
|
|
46074
46248
|
preExistingErrors: compared.preExisting
|
|
46075
46249
|
};
|
|
@@ -46085,7 +46259,7 @@ async function runTemplateTrim(req, deps) {
|
|
|
46085
46259
|
...base(validate3),
|
|
46086
46260
|
...preExisting.length ? {
|
|
46087
46261
|
preExistingErrors: preExisting,
|
|
46088
|
-
note: `trimmed; ${
|
|
46262
|
+
note: `trimmed; ${plural2(preExisting.length, "error")} ${preExisting.length === 1 ? "was" : "were"} already present before trim: ${summarize3(preExisting)}`
|
|
46089
46263
|
} : {}
|
|
46090
46264
|
}
|
|
46091
46265
|
};
|
|
@@ -46136,7 +46310,7 @@ function summarize3(errors) {
|
|
|
46136
46310
|
const shown2 = errors.slice(0, 5).map(one).join("; ");
|
|
46137
46311
|
return errors.length > 5 ? `${shown2}; and ${errors.length - 5} more` : shown2;
|
|
46138
46312
|
}
|
|
46139
|
-
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf2, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3,
|
|
46313
|
+
var TrimRefusal, LIT, ATOM, QUANT, CAP, SAFE_ROUTE_PATTERN, lineOf2, isStatic, entryLabel, isNode3, asItems, NAV_SCREEN_KEYS, sorted, refuse3, plural2;
|
|
46140
46314
|
var init_template_trim = __esm({
|
|
46141
46315
|
"src/template-trim.ts"() {
|
|
46142
46316
|
init_validate_descriptor();
|
|
@@ -46170,7 +46344,7 @@ var init_template_trim = __esm({
|
|
|
46170
46344
|
NAV_SCREEN_KEYS = /* @__PURE__ */ new Set(["screenId", "parentScreenId", "contentScreenId", "badgeScreenId"]);
|
|
46171
46345
|
sorted = (xs) => [...new Set(xs)].sort();
|
|
46172
46346
|
refuse3 = (e) => ({ code: 2, result: { ok: false, error: e.message, ...e.detail } });
|
|
46173
|
-
|
|
46347
|
+
plural2 = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
46174
46348
|
}
|
|
46175
46349
|
});
|
|
46176
46350
|
|
|
@@ -46800,8 +46974,8 @@ __export(pack_exports, {
|
|
|
46800
46974
|
});
|
|
46801
46975
|
import { createHash as createHash22 } from "node:crypto";
|
|
46802
46976
|
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
46803
|
-
import { existsSync as
|
|
46804
|
-
import { dirname as dirname26, join as
|
|
46977
|
+
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";
|
|
46978
|
+
import { dirname as dirname26, join as join44, resolve as resolve37 } from "node:path";
|
|
46805
46979
|
function writeZip(entries) {
|
|
46806
46980
|
const sorted2 = entries.slice().sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
46807
46981
|
const total = sorted2.reduce((n, e) => n + e.bytes.length, 0);
|
|
@@ -46895,13 +47069,13 @@ function inflateEntry(buf, entry) {
|
|
|
46895
47069
|
return bytes2;
|
|
46896
47070
|
}
|
|
46897
47071
|
function readIf(path2) {
|
|
46898
|
-
return
|
|
47072
|
+
return existsSync46(path2) && statSync11(path2).isFile() ? readFileSync50(path2) : null;
|
|
46899
47073
|
}
|
|
46900
47074
|
function listDir(dir) {
|
|
46901
|
-
return
|
|
47075
|
+
return existsSync46(dir) ? readdirSync25(dir).filter((f) => statSync11(join44(dir, f)).isFile()) : [];
|
|
46902
47076
|
}
|
|
46903
47077
|
function gatherReleaseEntries(appDir2) {
|
|
46904
|
-
const manifestPath =
|
|
47078
|
+
const manifestPath = join44(appDir2, HIMI_PACKAGE_MANIFEST_PATH);
|
|
46905
47079
|
const manifestBytes = readIf(manifestPath);
|
|
46906
47080
|
if (!manifestBytes) throw new Error(`no ${HIMI_PACKAGE_MANIFEST_PATH} in ${appDir2} \u2014 build a release there first`);
|
|
46907
47081
|
const manifest = JSON.parse(manifestBytes.toString("utf8"));
|
|
@@ -46925,7 +47099,7 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46925
47099
|
}
|
|
46926
47100
|
const missing = [];
|
|
46927
47101
|
for (const rel of wanted) {
|
|
46928
|
-
const bytes2 = readIf(
|
|
47102
|
+
const bytes2 = readIf(join44(appDir2, rel));
|
|
46929
47103
|
if (bytes2) entries.push({ path: rel, bytes: bytes2 });
|
|
46930
47104
|
else missing.push(rel);
|
|
46931
47105
|
}
|
|
@@ -46936,12 +47110,12 @@ function gatherReleaseEntries(appDir2) {
|
|
|
46936
47110
|
);
|
|
46937
47111
|
}
|
|
46938
47112
|
for (const name of SINGLETONS) {
|
|
46939
|
-
const bytes2 = readIf(
|
|
47113
|
+
const bytes2 = readIf(join44(appDir2, name));
|
|
46940
47114
|
if (bytes2) entries.push({ path: name, bytes: bytes2 });
|
|
46941
47115
|
}
|
|
46942
47116
|
const skipped = [];
|
|
46943
47117
|
for (const sub of ["screens", "bundles", "assets", "widgets"]) {
|
|
46944
|
-
for (const f of listDir(
|
|
47118
|
+
for (const f of listDir(join44(appDir2, sub))) {
|
|
46945
47119
|
if (!wanted.has(`${sub}/${f}`)) skipped.push(`${sub}/${f}`);
|
|
46946
47120
|
}
|
|
46947
47121
|
}
|
|
@@ -46974,18 +47148,18 @@ function buildEntries(appDir2, app, opts) {
|
|
|
46974
47148
|
return { all, header, manifest, skipped };
|
|
46975
47149
|
}
|
|
46976
47150
|
function packRelease(releaseRoot, app, out, opts = {}) {
|
|
46977
|
-
const appDir2 =
|
|
47151
|
+
const appDir2 = join44(resolve37(releaseRoot), app);
|
|
46978
47152
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
46979
47153
|
const buf = writeZip(all);
|
|
46980
|
-
const isDir2 =
|
|
46981
|
-
const outFile = isDir2 ?
|
|
47154
|
+
const isDir2 = existsSync46(out) && statSync11(out).isDirectory();
|
|
47155
|
+
const outFile = isDir2 ? join44(resolve37(out), packageFileName(app, header.releaseId)) : resolve37(out);
|
|
46982
47156
|
mkdirSync21(dirname26(outFile), { recursive: true });
|
|
46983
47157
|
writeFileSync17(outFile, buf);
|
|
46984
47158
|
return { app, releaseId: header.releaseId, header, out: outFile, bytes: buf.length, entryCount: all.length, skipped };
|
|
46985
47159
|
}
|
|
46986
47160
|
function resolvePackageDirDest(outDir, app, releaseId) {
|
|
46987
47161
|
const packagedApp = (dir) => {
|
|
46988
|
-
const bytes2 = readIf(
|
|
47162
|
+
const bytes2 = readIf(join44(dir, HIMI_PACKAGE_HEADER_PATH));
|
|
46989
47163
|
if (!bytes2) return void 0;
|
|
46990
47164
|
try {
|
|
46991
47165
|
return JSON.parse(bytes2.toString("utf8")).app;
|
|
@@ -46994,15 +47168,15 @@ function resolvePackageDirDest(outDir, app, releaseId) {
|
|
|
46994
47168
|
}
|
|
46995
47169
|
};
|
|
46996
47170
|
const replaceable = (dir) => {
|
|
46997
|
-
if (!
|
|
47171
|
+
if (!existsSync46(dir)) return true;
|
|
46998
47172
|
if (!statSync11(dir).isDirectory()) return false;
|
|
46999
47173
|
return readdirSync25(dir).length === 0 || packagedApp(dir) === app;
|
|
47000
47174
|
};
|
|
47001
|
-
if (
|
|
47175
|
+
if (existsSync46(outDir) && !statSync11(outDir).isDirectory()) {
|
|
47002
47176
|
throw new Error(`refusing to write a package tree over ${outDir} \u2014 it is a file, not a directory`);
|
|
47003
47177
|
}
|
|
47004
47178
|
if (replaceable(outDir)) return outDir;
|
|
47005
|
-
const child =
|
|
47179
|
+
const child = join44(outDir, packageDirName(app, releaseId));
|
|
47006
47180
|
if (!replaceable(child)) {
|
|
47007
47181
|
throw new Error(
|
|
47008
47182
|
`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 +47190,13 @@ function packReleaseToDir(releaseRoot, app, outDir, opts = {}) {
|
|
|
47016
47190
|
"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
47191
|
);
|
|
47018
47192
|
}
|
|
47019
|
-
const appDir2 =
|
|
47193
|
+
const appDir2 = join44(resolve37(releaseRoot), app);
|
|
47020
47194
|
const { all, header, skipped } = buildEntries(appDir2, app, opts);
|
|
47021
47195
|
const dest = resolvePackageDirDest(resolve37(outDir), app, header.releaseId);
|
|
47022
47196
|
rmSync9(dest, { recursive: true, force: true });
|
|
47023
47197
|
let bytes2 = 0;
|
|
47024
47198
|
for (const entry of all) {
|
|
47025
|
-
const target =
|
|
47199
|
+
const target = join44(dest, entry.path);
|
|
47026
47200
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
47027
47201
|
writeFileSync17(target, entry.bytes);
|
|
47028
47202
|
bytes2 += entry.bytes.length;
|
|
@@ -47045,21 +47219,21 @@ function openPackageBuffer(buf) {
|
|
|
47045
47219
|
return openFromEntries(readZip(buf), { requireHeader: true });
|
|
47046
47220
|
}
|
|
47047
47221
|
function openPackageFile(file) {
|
|
47048
|
-
return openPackageBuffer(
|
|
47222
|
+
return openPackageBuffer(readFileSync50(file));
|
|
47049
47223
|
}
|
|
47050
47224
|
function openPackageDir(dir) {
|
|
47051
47225
|
const root = resolve37(dir);
|
|
47052
47226
|
const entries = /* @__PURE__ */ new Map();
|
|
47053
47227
|
const walk2 = (rel) => {
|
|
47054
|
-
const abs = rel ?
|
|
47228
|
+
const abs = rel ? join44(root, rel) : root;
|
|
47055
47229
|
for (const name of readdirSync25(abs)) {
|
|
47056
47230
|
const childRel = rel ? `${rel}/${name}` : name;
|
|
47057
|
-
const childAbs =
|
|
47231
|
+
const childAbs = join44(abs, name);
|
|
47058
47232
|
if (statSync11(childAbs).isDirectory()) walk2(childRel);
|
|
47059
|
-
else if (isSafeEntryName(childRel)) entries.set(childRel,
|
|
47233
|
+
else if (isSafeEntryName(childRel)) entries.set(childRel, readFileSync50(childAbs));
|
|
47060
47234
|
}
|
|
47061
47235
|
};
|
|
47062
|
-
if (!
|
|
47236
|
+
if (!existsSync46(root)) throw new Error(`no such package directory: ${root}`);
|
|
47063
47237
|
walk2("");
|
|
47064
47238
|
const manifestBytes = entries.get(HIMI_PACKAGE_MANIFEST_PATH);
|
|
47065
47239
|
if (manifestBytes) {
|
|
@@ -47101,10 +47275,10 @@ function unpackTo(buf, dest, appFallback) {
|
|
|
47101
47275
|
if (!app) throw new Error("package declares no app id (no himi-package.json and no manifest.app)");
|
|
47102
47276
|
if (!isSafeAppId(app)) throw new Error(`package declares an unsafe app id ${JSON.stringify(app)} \u2014 refusing to unpack it`);
|
|
47103
47277
|
const root = resolve37(dest);
|
|
47104
|
-
const appDir2 =
|
|
47278
|
+
const appDir2 = join44(root, app);
|
|
47105
47279
|
rmSync9(appDir2, { recursive: true, force: true });
|
|
47106
47280
|
for (const [rel, bytes2] of entries) {
|
|
47107
|
-
const target =
|
|
47281
|
+
const target = join44(appDir2, rel);
|
|
47108
47282
|
mkdirSync21(dirname26(target), { recursive: true });
|
|
47109
47283
|
writeFileSync17(target, bytes2);
|
|
47110
47284
|
}
|
|
@@ -47140,20 +47314,20 @@ __export(app_source_exports, {
|
|
|
47140
47314
|
writeConflicts: () => writeConflicts,
|
|
47141
47315
|
zipAppSource: () => zipAppSource
|
|
47142
47316
|
});
|
|
47143
|
-
import { readdirSync as readdirSync26, lstatSync as lstatSync8, readFileSync as
|
|
47144
|
-
import { join as
|
|
47317
|
+
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";
|
|
47318
|
+
import { join as join45, resolve as resolve38, sep as sep10 } from "node:path";
|
|
47145
47319
|
import { deflateRawSync as deflateRawSync2 } from "node:zlib";
|
|
47146
47320
|
function walkSourceTree(dir, file, skip) {
|
|
47147
47321
|
const walk2 = (relDir) => {
|
|
47148
|
-
for (const name of readdirSync26(
|
|
47149
|
-
const rel = relDir ?
|
|
47150
|
-
const st = lstatSync8(
|
|
47322
|
+
for (const name of readdirSync26(join45(dir, relDir))) {
|
|
47323
|
+
const rel = relDir ? join45(relDir, name) : name;
|
|
47324
|
+
const st = lstatSync8(join45(dir, rel));
|
|
47151
47325
|
if (st.isSymbolicLink()) {
|
|
47152
47326
|
skip(rel);
|
|
47153
47327
|
continue;
|
|
47154
47328
|
}
|
|
47155
47329
|
if (st.isDirectory()) {
|
|
47156
|
-
if (isDeniedSourceDir(name, relDir) ||
|
|
47330
|
+
if (isDeniedSourceDir(name, relDir) || existsSync47(join45(dir, rel, PACKAGE_DIR_MARKER))) skip(rel);
|
|
47157
47331
|
else walk2(rel);
|
|
47158
47332
|
continue;
|
|
47159
47333
|
}
|
|
@@ -47171,7 +47345,7 @@ function collectAppSource(dir) {
|
|
|
47171
47345
|
const skipped = [];
|
|
47172
47346
|
walkSourceTree(
|
|
47173
47347
|
dir,
|
|
47174
|
-
(archivePath, hostRel) => entries.push({ path: archivePath, bytes:
|
|
47348
|
+
(archivePath, hostRel) => entries.push({ path: archivePath, bytes: readFileSync51(join45(dir, hostRel)) }),
|
|
47175
47349
|
(hostRel) => skipped.push(hostRel)
|
|
47176
47350
|
);
|
|
47177
47351
|
entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
@@ -47225,13 +47399,13 @@ function writeAppSource(entries, destDir) {
|
|
|
47225
47399
|
const segments = entry.path.split("/");
|
|
47226
47400
|
let dir = root;
|
|
47227
47401
|
for (const segment of segments.slice(0, -1)) {
|
|
47228
|
-
dir =
|
|
47402
|
+
dir = join45(dir, segment);
|
|
47229
47403
|
const kind = pathKind(dir);
|
|
47230
47404
|
if (kind?.isSymbolicLink()) unlinkSync3(dir);
|
|
47231
47405
|
else if (kind) continue;
|
|
47232
47406
|
mkdirSync22(dir);
|
|
47233
47407
|
}
|
|
47234
|
-
const target =
|
|
47408
|
+
const target = join45(root, ...segments);
|
|
47235
47409
|
if (pathKind(target)?.isSymbolicLink()) unlinkSync3(target);
|
|
47236
47410
|
writeFileSync18(target, entry.bytes);
|
|
47237
47411
|
written.push(entry.path);
|
|
@@ -47239,7 +47413,7 @@ function writeAppSource(entries, destDir) {
|
|
|
47239
47413
|
return written;
|
|
47240
47414
|
}
|
|
47241
47415
|
function staleSourcePaths(entries, destDir) {
|
|
47242
|
-
if (!
|
|
47416
|
+
if (!existsSync47(destDir)) return [];
|
|
47243
47417
|
const archived = new Set(entries.map((e) => e.path));
|
|
47244
47418
|
const stale = [];
|
|
47245
47419
|
walkSourceTree(destDir, (archivePath) => {
|
|
@@ -47266,7 +47440,7 @@ function writeConflicts(entries, destDir) {
|
|
|
47266
47440
|
let dir = root;
|
|
47267
47441
|
let stop = false;
|
|
47268
47442
|
for (const [i, segment] of segments.slice(0, -1).entries()) {
|
|
47269
|
-
dir =
|
|
47443
|
+
dir = join45(dir, segment);
|
|
47270
47444
|
const kind2 = pathKind(dir);
|
|
47271
47445
|
if (!kind2 || kind2.isSymbolicLink()) {
|
|
47272
47446
|
stop = true;
|
|
@@ -47278,7 +47452,7 @@ function writeConflicts(entries, destDir) {
|
|
|
47278
47452
|
break;
|
|
47279
47453
|
}
|
|
47280
47454
|
if (stop) continue;
|
|
47281
|
-
const kind = pathKind(
|
|
47455
|
+
const kind = pathKind(join45(root, ...segments));
|
|
47282
47456
|
if (kind && !kind.isSymbolicLink() && kind.isDirectory()) {
|
|
47283
47457
|
say(entry.path, "is a directory here, but the release has a file at that path");
|
|
47284
47458
|
}
|
|
@@ -47288,22 +47462,22 @@ function writeConflicts(entries, destDir) {
|
|
|
47288
47462
|
function removeStaleSource(entries, destDir) {
|
|
47289
47463
|
const root = resolve38(destDir);
|
|
47290
47464
|
const removed = staleSourcePaths(entries, root);
|
|
47291
|
-
for (const rel of removed) rmSync10(
|
|
47465
|
+
for (const rel of removed) rmSync10(join45(root, ...rel.split("/")), { force: true });
|
|
47292
47466
|
const needed = /* @__PURE__ */ new Set();
|
|
47293
47467
|
for (const entry of entries) {
|
|
47294
47468
|
if (isDeniedSourcePath(entry.path)) continue;
|
|
47295
47469
|
const segments = entry.path.split("/");
|
|
47296
47470
|
for (let i = 1; i < segments.length; i++) needed.add(segments.slice(0, i).join("/"));
|
|
47297
47471
|
}
|
|
47298
|
-
if (
|
|
47472
|
+
if (existsSync47(root)) pruneEmptyDirs(root, "", needed, removed);
|
|
47299
47473
|
return removed.sort();
|
|
47300
47474
|
}
|
|
47301
47475
|
function pruneEmptyDirs(root, rel, needed, removed) {
|
|
47302
47476
|
let empty = true;
|
|
47303
|
-
for (const name of readdirSync26(rel ?
|
|
47304
|
-
const childRel = rel ?
|
|
47477
|
+
for (const name of readdirSync26(rel ? join45(root, rel) : root)) {
|
|
47478
|
+
const childRel = rel ? join45(rel, name) : name;
|
|
47305
47479
|
const posix4 = childRel.split(sep10).join("/");
|
|
47306
|
-
const kind = lstatSync8(
|
|
47480
|
+
const kind = lstatSync8(join45(root, childRel));
|
|
47307
47481
|
if (kind.isSymbolicLink() || !kind.isDirectory() || isDeniedSourceDir(name, rel)) {
|
|
47308
47482
|
empty = false;
|
|
47309
47483
|
continue;
|
|
@@ -47313,7 +47487,7 @@ function pruneEmptyDirs(root, rel, needed, removed) {
|
|
|
47313
47487
|
empty = false;
|
|
47314
47488
|
continue;
|
|
47315
47489
|
}
|
|
47316
|
-
rmdirSync2(
|
|
47490
|
+
rmdirSync2(join45(root, childRel));
|
|
47317
47491
|
removed.push(`${posix4}/`);
|
|
47318
47492
|
}
|
|
47319
47493
|
return empty;
|
|
@@ -47368,13 +47542,13 @@ __export(eject_exports, {
|
|
|
47368
47542
|
EJECTABLE: () => EJECTABLE,
|
|
47369
47543
|
ejectModule: () => ejectModule
|
|
47370
47544
|
});
|
|
47371
|
-
import { existsSync as
|
|
47372
|
-
import { dirname as dirname27, join as
|
|
47545
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync23, readFileSync as readFileSync52, writeFileSync as writeFileSync19 } from "node:fs";
|
|
47546
|
+
import { dirname as dirname27, join as join46, relative as relative9, resolve as resolve39, sep as sep11 } from "node:path";
|
|
47373
47547
|
function locate(repoRootOrCwd, mod) {
|
|
47374
47548
|
const inRepo = resolve39(repoRootOrCwd, `stdlib/flows/${mod}/src/index.ts`);
|
|
47375
|
-
if (
|
|
47549
|
+
if (existsSync48(inRepo)) return { path: inRepo, form: "source" };
|
|
47376
47550
|
const dist = resolve39(repoRootOrCwd, `node_modules/@wix/himalaya/dist/${mod}.mjs`);
|
|
47377
|
-
if (
|
|
47551
|
+
if (existsSync48(dist)) return { path: dist, form: "bundle" };
|
|
47378
47552
|
return null;
|
|
47379
47553
|
}
|
|
47380
47554
|
function specifiersFor(mod) {
|
|
@@ -47398,7 +47572,7 @@ function ejectModule(opts) {
|
|
|
47398
47572
|
};
|
|
47399
47573
|
}
|
|
47400
47574
|
const ext = found.form === "source" ? "ts" : "mjs";
|
|
47401
|
-
const target =
|
|
47575
|
+
const target = join46(contentDir2, "tier5-src", "_ejected", `${mod}.${ext}`);
|
|
47402
47576
|
mkdirSync23(dirname27(target), { recursive: true });
|
|
47403
47577
|
const banner = `// EJECTED from @wix/himalaya/${mod}. This app owns this file now.
|
|
47404
47578
|
//
|
|
@@ -47412,17 +47586,17 @@ function ejectModule(opts) {
|
|
|
47412
47586
|
// gate still applies. Ejecting buys layout and flow, never the floor.
|
|
47413
47587
|
|
|
47414
47588
|
`;
|
|
47415
|
-
const normalized =
|
|
47589
|
+
const normalized = readFileSync52(found.path, "utf8").replace(
|
|
47416
47590
|
/(["'])@himalaya\/([a-z0-9-]+(?:\/[a-z0-9-]+)?)\1/g,
|
|
47417
47591
|
(_m, q, sub) => `${q}@wix/himalaya/${sub}${q}`
|
|
47418
47592
|
);
|
|
47419
47593
|
writeFileSync19(target, banner + normalized);
|
|
47420
47594
|
const rewired = [];
|
|
47421
47595
|
for (const f of files) {
|
|
47422
|
-
if (!
|
|
47423
|
-
const before =
|
|
47596
|
+
if (!existsSync48(f)) continue;
|
|
47597
|
+
const before = readFileSync52(f, "utf8");
|
|
47424
47598
|
let after = before;
|
|
47425
|
-
let rel =
|
|
47599
|
+
let rel = relative9(dirname27(f), target).split(sep11).join("/").replace(/\.tsx?$/, ".js");
|
|
47426
47600
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
47427
47601
|
for (const spec of specifiersFor(mod)) {
|
|
47428
47602
|
const q = spec.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -47540,8 +47714,8 @@ var init_app_map = __esm({
|
|
|
47540
47714
|
});
|
|
47541
47715
|
|
|
47542
47716
|
// src/wix-writes.ts
|
|
47543
|
-
import { existsSync as
|
|
47544
|
-
import { join as
|
|
47717
|
+
import { existsSync as existsSync49, readFileSync as readFileSync53 } from "node:fs";
|
|
47718
|
+
import { join as join47 } from "node:path";
|
|
47545
47719
|
function isProvenRead(method, path2) {
|
|
47546
47720
|
if (/[#\x00-\x1F\x7F]/.test(path2)) return false;
|
|
47547
47721
|
const verb = method.toUpperCase();
|
|
@@ -47622,11 +47796,11 @@ function parseDataAccess(text5, from) {
|
|
|
47622
47796
|
}
|
|
47623
47797
|
function readDataAccess(dir) {
|
|
47624
47798
|
for (const name of ["SPEC.md", "MOBILE-UX.md"]) {
|
|
47625
|
-
const p =
|
|
47626
|
-
if (!
|
|
47799
|
+
const p = join47(dir, name);
|
|
47800
|
+
if (!existsSync49(p)) continue;
|
|
47627
47801
|
let text5;
|
|
47628
47802
|
try {
|
|
47629
|
-
text5 =
|
|
47803
|
+
text5 = readFileSync53(p, "utf8");
|
|
47630
47804
|
} catch {
|
|
47631
47805
|
continue;
|
|
47632
47806
|
}
|
|
@@ -47733,14 +47907,14 @@ __export(test_exports, {
|
|
|
47733
47907
|
scopeDescriptors: () => scopeDescriptors,
|
|
47734
47908
|
writeRecordedMocks: () => writeRecordedMocks
|
|
47735
47909
|
});
|
|
47736
|
-
import { existsSync as
|
|
47737
|
-
import { join as
|
|
47910
|
+
import { existsSync as existsSync50, mkdirSync as mkdirSync24, readFileSync as readFileSync54, writeFileSync as writeFileSync20 } from "node:fs";
|
|
47911
|
+
import { join as join48, resolve as resolve40 } from "node:path";
|
|
47738
47912
|
function readTestConfig(dir) {
|
|
47739
47913
|
const p = resolve40(dir, TEST_CONFIG_FILE);
|
|
47740
|
-
if (!
|
|
47914
|
+
if (!existsSync50(p)) return {};
|
|
47741
47915
|
let parsed;
|
|
47742
47916
|
try {
|
|
47743
|
-
parsed = JSON.parse(
|
|
47917
|
+
parsed = JSON.parse(readFileSync54(p, "utf8"));
|
|
47744
47918
|
} catch (e) {
|
|
47745
47919
|
throw new Error(`${TEST_CONFIG_FILE} is not valid JSON \u2014 ${e.message}`);
|
|
47746
47920
|
}
|
|
@@ -47787,7 +47961,7 @@ function readTestConfig(dir) {
|
|
|
47787
47961
|
function readNetRules(path2) {
|
|
47788
47962
|
let parsed;
|
|
47789
47963
|
try {
|
|
47790
|
-
parsed = JSON.parse(
|
|
47964
|
+
parsed = JSON.parse(readFileSync54(path2, "utf8"));
|
|
47791
47965
|
} catch (e) {
|
|
47792
47966
|
throw new Error(`--net ${path2} could not be read as JSON \u2014 ${e.message}`);
|
|
47793
47967
|
}
|
|
@@ -47808,7 +47982,7 @@ function readNetRules(path2) {
|
|
|
47808
47982
|
function defaultNetRules(dir) {
|
|
47809
47983
|
for (const rel of ["dev/net-mocks.json", "tests/net-mocks.json"]) {
|
|
47810
47984
|
const p = resolve40(dir, rel);
|
|
47811
|
-
if (
|
|
47985
|
+
if (existsSync50(p)) {
|
|
47812
47986
|
const rules = readNetRules(p);
|
|
47813
47987
|
if (rules.length) return { rules, from: rel };
|
|
47814
47988
|
}
|
|
@@ -47824,7 +47998,7 @@ function readCannedResponses() {
|
|
|
47824
47998
|
];
|
|
47825
47999
|
for (const url of candidates) {
|
|
47826
48000
|
try {
|
|
47827
|
-
const parsed = JSON.parse(
|
|
48001
|
+
const parsed = JSON.parse(readFileSync54(url, "utf8"));
|
|
47828
48002
|
const byKey = {};
|
|
47829
48003
|
for (const [k, v] of Object.entries(parsed)) {
|
|
47830
48004
|
if (!k.startsWith("//")) byKey[k] = v;
|
|
@@ -47914,8 +48088,8 @@ function writeRecordedMocks(opts) {
|
|
|
47914
48088
|
mkdir: (p) => mkdirSync24(p, { recursive: true }),
|
|
47915
48089
|
write: (p, s) => writeFileSync20(p, s)
|
|
47916
48090
|
};
|
|
47917
|
-
fs.mkdir(
|
|
47918
|
-
fs.write(
|
|
48091
|
+
fs.mkdir(join48(opts.dir, "dev"));
|
|
48092
|
+
fs.write(join48(opts.dir, "dev", "net-mocks.json"), JSON.stringify(opts.mocks, null, 2) + "\n");
|
|
47919
48093
|
return { ok: true, rules, to: "dev/net-mocks.json" };
|
|
47920
48094
|
}
|
|
47921
48095
|
function scopeDescriptors(descriptors, requestedIds, invalidScreens) {
|
|
@@ -48418,14 +48592,14 @@ var mobile_ux_lint_exports = {};
|
|
|
48418
48592
|
__export(mobile_ux_lint_exports, {
|
|
48419
48593
|
mobileUxIssues: () => mobileUxIssues
|
|
48420
48594
|
});
|
|
48421
|
-
import { existsSync as
|
|
48422
|
-
import { join as
|
|
48595
|
+
import { existsSync as existsSync51, readFileSync as readFileSync55 } from "node:fs";
|
|
48596
|
+
import { join as join49 } from "node:path";
|
|
48423
48597
|
function mobileUxIssues(dir, strict) {
|
|
48424
|
-
const file =
|
|
48425
|
-
if (!
|
|
48598
|
+
const file = join49(dir, "MOBILE-UX.md");
|
|
48599
|
+
if (!existsSync51(file)) return [];
|
|
48426
48600
|
let text5;
|
|
48427
48601
|
try {
|
|
48428
|
-
text5 =
|
|
48602
|
+
text5 = readFileSync55(file, "utf8");
|
|
48429
48603
|
} catch {
|
|
48430
48604
|
return [];
|
|
48431
48605
|
}
|
|
@@ -50100,8 +50274,8 @@ __export(functions_exports, {
|
|
|
50100
50274
|
resolveFunctionsTarget: () => resolveFunctionsTarget,
|
|
50101
50275
|
runRemoteFunctionOperation: () => runRemoteFunctionOperation
|
|
50102
50276
|
});
|
|
50103
|
-
import { readFileSync as
|
|
50104
|
-
import { join as
|
|
50277
|
+
import { readFileSync as readFileSync56, existsSync as existsSync52 } from "node:fs";
|
|
50278
|
+
import { join as join50, resolve as resolve41 } from "node:path";
|
|
50105
50279
|
function resolveFunctionsTarget(input) {
|
|
50106
50280
|
const explicitUrl = input.functionsUrl?.trim();
|
|
50107
50281
|
if (explicitUrl) return { mode: "remote", baseUrl: explicitUrl };
|
|
@@ -50120,9 +50294,9 @@ async function loadFunctionsApp(dir) {
|
|
|
50120
50294
|
}
|
|
50121
50295
|
const sources = {};
|
|
50122
50296
|
for (const definition of config.functions.functions) {
|
|
50123
|
-
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) =>
|
|
50297
|
+
const source = [".ts", ".js", ".mts", ".mjs"].map((extension) => join50(loaded.dir, "functions", `${definition.name}${extension}`)).find(existsSync52);
|
|
50124
50298
|
if (!source) throw new Error(`missing source for function ${definition.name}; expected functions/${definition.name}.ts`);
|
|
50125
|
-
sources[definition.name] =
|
|
50299
|
+
sources[definition.name] = readFileSync56(source, "utf8");
|
|
50126
50300
|
}
|
|
50127
50301
|
const data = config.cms || config.data ? mergeDataResources(config) : void 0;
|
|
50128
50302
|
const dataErrors = validateDataResources(data, loaded.name).filter((issue2) => issue2.severity === "error");
|
|
@@ -50282,10 +50456,10 @@ __export(studio_reel_exports, {
|
|
|
50282
50456
|
utcDay: () => utcDay
|
|
50283
50457
|
});
|
|
50284
50458
|
import { createHash as createHash25 } from "node:crypto";
|
|
50285
|
-
import { lstatSync as lstatSync9, readFileSync as
|
|
50286
|
-
import { basename as
|
|
50459
|
+
import { lstatSync as lstatSync9, readFileSync as readFileSync57 } from "node:fs";
|
|
50460
|
+
import { basename as basename13, join as join51 } from "node:path";
|
|
50287
50461
|
function loadMemory2(dir) {
|
|
50288
|
-
const m = readJson5(
|
|
50462
|
+
const m = readJson5(join51(dir, ".himi", "studio", "memory.json"));
|
|
50289
50463
|
if (!isObj2(m) || m.version !== 1 || !isObj2(m.shots) || !Array.isArray(m.timeline)) return null;
|
|
50290
50464
|
const shots = [];
|
|
50291
50465
|
for (const [id, s] of Object.entries(m.shots)) {
|
|
@@ -50322,8 +50496,8 @@ function planReel(dir) {
|
|
|
50322
50496
|
const memory = loadMemory2(dir);
|
|
50323
50497
|
const { entries } = readProgress(dir);
|
|
50324
50498
|
const summary = summarizeProgress(entries);
|
|
50325
|
-
const manifest = readJson5(
|
|
50326
|
-
const tokens = readJson5(
|
|
50499
|
+
const manifest = readJson5(join51(dir, "himalaya.content.json"));
|
|
50500
|
+
const tokens = readJson5(join51(dir, "tokens.json"));
|
|
50327
50501
|
const accentToken = tokens?.colors?.accentPrimary;
|
|
50328
50502
|
const accentRaw = typeof accentToken === "string" ? accentToken : accentToken?.light;
|
|
50329
50503
|
const accent = typeof accentRaw === "string" && ACCENT.test(accentRaw) ? accentRaw : DEFAULT_ACCENT;
|
|
@@ -50337,14 +50511,15 @@ function planReel(dir) {
|
|
|
50337
50511
|
const postcards = entries.map((e) => ({
|
|
50338
50512
|
ts: e.ts,
|
|
50339
50513
|
message: e.message,
|
|
50340
|
-
step: str(e.step),
|
|
50341
|
-
|
|
50514
|
+
step: isCliEntry(e) ? null : str(e.step),
|
|
50515
|
+
by: isCliEntry(e) ? CLI_AUTHOR : null,
|
|
50516
|
+
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
50517
|
}));
|
|
50343
50518
|
const times = [summary.startedAt, ...timeline.map((t) => t.ts), memory?.createdAt].filter((x) => !!x).sort();
|
|
50344
50519
|
const startedAt = times[0] ?? null;
|
|
50345
50520
|
const endedAt = [summary.lastAt, ...timeline.map((t) => t.ts)].filter((x) => !!x).sort().pop() ?? null;
|
|
50346
50521
|
return {
|
|
50347
|
-
app: typeof manifest?.name === "string" && manifest.name ? manifest.name :
|
|
50522
|
+
app: typeof manifest?.name === "string" && manifest.name ? manifest.name : basename13(dir),
|
|
50348
50523
|
accent,
|
|
50349
50524
|
startedAt,
|
|
50350
50525
|
endedAt,
|
|
@@ -50365,10 +50540,10 @@ function inlineImages(dir, plan, budget = REEL_BUDGET_BYTES) {
|
|
|
50365
50540
|
const verified = (f) => {
|
|
50366
50541
|
if (!HISTORY_NAME.test(f)) return null;
|
|
50367
50542
|
try {
|
|
50368
|
-
const path2 =
|
|
50543
|
+
const path2 = join51(dir, HISTORY_DIR, f);
|
|
50369
50544
|
const st = lstatSync9(path2);
|
|
50370
50545
|
if (!st.isFile() || st.nlink !== 1) return null;
|
|
50371
|
-
const bytes2 =
|
|
50546
|
+
const bytes2 = readFileSync57(path2);
|
|
50372
50547
|
return createHash25("sha256").update(bytes2).digest("hex") === f.slice(0, 64) && imageExtension(bytes2) === f.slice(65) ? bytes2 : null;
|
|
50373
50548
|
} catch {
|
|
50374
50549
|
return null;
|
|
@@ -50462,7 +50637,7 @@ function renderReel(plan, images) {
|
|
|
50462
50637
|
.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
50638
|
.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
50639
|
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}
|
|
50640
|
+
.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
50641
|
.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
50642
|
footer{margin-top:48px;font-size:12px;color:var(--muted)}
|
|
50468
50643
|
</style></head><body><div class="wrap">
|
|
@@ -50473,7 +50648,7 @@ ${flip}
|
|
|
50473
50648
|
<h2>Where it ended up</h2>
|
|
50474
50649
|
<div class="grid">${plan.finals.map((f) => `<figure>${img(f.file, f.id)}<figcaption>${escapeHtml(f.id)}</figcaption></figure>`).join("")}</div>
|
|
50475
50650
|
<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>
|
|
50651
|
+
<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
50652
|
<footer>Built with himi.${plan.dropped ? ` ${count2(plan.dropped)} pictures were left out to keep this file small.` : ""}</footer>
|
|
50478
50653
|
</div>
|
|
50479
50654
|
<script>
|
|
@@ -50502,7 +50677,7 @@ var init_studio_reel = __esm({
|
|
|
50502
50677
|
mimeOf = (file) => MIME2[file.slice(65)] ?? "image/png";
|
|
50503
50678
|
readJson5 = (file) => {
|
|
50504
50679
|
try {
|
|
50505
|
-
return JSON.parse(
|
|
50680
|
+
return JSON.parse(readFileSync57(file, "utf8"));
|
|
50506
50681
|
} catch {
|
|
50507
50682
|
return null;
|
|
50508
50683
|
}
|
|
@@ -50533,9 +50708,9 @@ __export(native_decode_exports, {
|
|
|
50533
50708
|
runNativeDecode: () => runNativeDecode
|
|
50534
50709
|
});
|
|
50535
50710
|
import { execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
|
|
50536
|
-
import { existsSync as
|
|
50711
|
+
import { existsSync as existsSync53, mkdtempSync as mkdtempSync2, readFileSync as readFileSync58, rmSync as rmSync11, writeFileSync as writeFileSync21 } from "node:fs";
|
|
50537
50712
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
50538
|
-
import { join as
|
|
50713
|
+
import { join as join52 } from "node:path";
|
|
50539
50714
|
import { fileURLToPath as fileURLToPath20 } from "node:url";
|
|
50540
50715
|
function nativeDecodePackageDir() {
|
|
50541
50716
|
return fileURLToPath20(new URL("../../../core/runtime/ios/HimalayaCore/", import.meta.url));
|
|
@@ -50545,8 +50720,8 @@ function nativeDecodeAndroidHarnessDir() {
|
|
|
50545
50720
|
}
|
|
50546
50721
|
function nativeOracleShipped() {
|
|
50547
50722
|
return {
|
|
50548
|
-
ios:
|
|
50549
|
-
android:
|
|
50723
|
+
ios: existsSync53(join52(nativeDecodePackageDir(), "Package.swift")),
|
|
50724
|
+
android: existsSync53(join52(nativeDecodeAndroidHarnessDir(), "gradlew"))
|
|
50550
50725
|
};
|
|
50551
50726
|
}
|
|
50552
50727
|
function detectNativeDecode(options = {}) {
|
|
@@ -50557,7 +50732,7 @@ function detectNativeDecode(options = {}) {
|
|
|
50557
50732
|
return { platform: "ios", available: false, reason: `the iOS decoder oracle requires macOS (darwin); this host is ${hostPlatform}` };
|
|
50558
50733
|
}
|
|
50559
50734
|
if (!swiftAvailable) return { platform: "ios", available: false, reason: "swift is not on PATH" };
|
|
50560
|
-
const packageAvailable = options.packageAvailable ??
|
|
50735
|
+
const packageAvailable = options.packageAvailable ?? existsSync53(join52(packageDir, "Package.swift"));
|
|
50561
50736
|
if (!packageAvailable) {
|
|
50562
50737
|
return {
|
|
50563
50738
|
platform: "ios",
|
|
@@ -50569,7 +50744,7 @@ function detectNativeDecode(options = {}) {
|
|
|
50569
50744
|
}
|
|
50570
50745
|
function localPropertiesSdk(harnessDir) {
|
|
50571
50746
|
try {
|
|
50572
|
-
const match =
|
|
50747
|
+
const match = readFileSync58(join52(harnessDir, "local.properties"), "utf8").match(/^sdk\.dir\s*=\s*(.+)$/m);
|
|
50573
50748
|
return match?.[1]?.trim().replace(/\\([ :\\])/g, "$1") ?? null;
|
|
50574
50749
|
} catch {
|
|
50575
50750
|
return null;
|
|
@@ -50577,8 +50752,8 @@ function localPropertiesSdk(harnessDir) {
|
|
|
50577
50752
|
}
|
|
50578
50753
|
function detectAndroidNativeDecode(options = {}) {
|
|
50579
50754
|
const harnessDir = options.harnessDir ?? nativeDecodeAndroidHarnessDir();
|
|
50580
|
-
const gradlew =
|
|
50581
|
-
const gradlewAvailable = options.gradlewAvailable ??
|
|
50755
|
+
const gradlew = join52(harnessDir, "gradlew");
|
|
50756
|
+
const gradlewAvailable = options.gradlewAvailable ?? existsSync53(gradlew);
|
|
50582
50757
|
if (!gradlewAvailable) {
|
|
50583
50758
|
return {
|
|
50584
50759
|
platform: "android",
|
|
@@ -50588,7 +50763,7 @@ function detectAndroidNativeDecode(options = {}) {
|
|
|
50588
50763
|
}
|
|
50589
50764
|
const androidHome = options.androidHome ?? process.env.ANDROID_HOME ?? "";
|
|
50590
50765
|
const sdk = androidHome.trim() || (options.localPropertiesSdk !== void 0 ? options.localPropertiesSdk : localPropertiesSdk(harnessDir));
|
|
50591
|
-
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 &&
|
|
50766
|
+
const sdkAvailable = options.sdkAvailable ?? (typeof sdk === "string" && sdk.length > 0 && existsSync53(sdk));
|
|
50592
50767
|
if (!sdkAvailable) {
|
|
50593
50768
|
return {
|
|
50594
50769
|
platform: "android",
|
|
@@ -50660,14 +50835,14 @@ function parseNativeDecodeOutput(stdout, expectedScreenIds, platform = "ios") {
|
|
|
50660
50835
|
return verdicts;
|
|
50661
50836
|
}
|
|
50662
50837
|
function runNativeDecode(options) {
|
|
50663
|
-
const descriptorDir = mkdtempSync2(
|
|
50838
|
+
const descriptorDir = mkdtempSync2(join52(tmpdir3(), "himi-native-decode-"));
|
|
50664
50839
|
const startedAt = Date.now();
|
|
50665
50840
|
try {
|
|
50666
50841
|
for (const descriptor of options.descriptors) {
|
|
50667
50842
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50668
50843
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50669
50844
|
}
|
|
50670
|
-
writeFileSync21(
|
|
50845
|
+
writeFileSync21(join52(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50671
50846
|
}
|
|
50672
50847
|
options.progress?.("building cached Swift oracle");
|
|
50673
50848
|
execFileSync5("swift", ["build", "--package-path", options.packageDir, "--product", "himi-decode-oracle"], {
|
|
@@ -50679,7 +50854,7 @@ function runNativeDecode(options) {
|
|
|
50679
50854
|
encoding: "utf8"
|
|
50680
50855
|
}).trim();
|
|
50681
50856
|
options.progress?.(`running real Swift decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50682
|
-
const stdout = execFileSync5(
|
|
50857
|
+
const stdout = execFileSync5(join52(binPath, "himi-decode-oracle"), ["--dir", descriptorDir], {
|
|
50683
50858
|
stdio: ["ignore", "pipe", "pipe"],
|
|
50684
50859
|
encoding: "utf8"
|
|
50685
50860
|
});
|
|
@@ -50697,15 +50872,15 @@ function runNativeDecode(options) {
|
|
|
50697
50872
|
}
|
|
50698
50873
|
}
|
|
50699
50874
|
function runAndroidNativeDecode(options) {
|
|
50700
|
-
const descriptorDir = mkdtempSync2(
|
|
50701
|
-
const outputPath =
|
|
50875
|
+
const descriptorDir = mkdtempSync2(join52(tmpdir3(), "himi-native-decode-android-"));
|
|
50876
|
+
const outputPath = join52(descriptorDir, "verdicts.ndjson");
|
|
50702
50877
|
const startedAt = Date.now();
|
|
50703
50878
|
try {
|
|
50704
50879
|
for (const descriptor of options.descriptors) {
|
|
50705
50880
|
if (typeof descriptor.descriptorJson !== "string") {
|
|
50706
50881
|
throw new Error(`native decode cannot judge ${descriptor.screenId}: the release builder did not return its exact baked JSON bytes`);
|
|
50707
50882
|
}
|
|
50708
|
-
writeFileSync21(
|
|
50883
|
+
writeFileSync21(join52(descriptorDir, `${encodeURIComponent(descriptor.screenId)}.json`), descriptor.descriptorJson);
|
|
50709
50884
|
}
|
|
50710
50885
|
options.progress?.(`running real Kotlin decoder over ${options.descriptors.length} screen${options.descriptors.length === 1 ? "" : "s"}`);
|
|
50711
50886
|
execFileSync5(options.gradlew, [
|
|
@@ -50720,7 +50895,7 @@ function runAndroidNativeDecode(options) {
|
|
|
50720
50895
|
stdio: ["ignore", "ignore", "pipe"],
|
|
50721
50896
|
encoding: "utf8"
|
|
50722
50897
|
});
|
|
50723
|
-
const stdout =
|
|
50898
|
+
const stdout = readFileSync58(outputPath, "utf8");
|
|
50724
50899
|
return {
|
|
50725
50900
|
platform: "android",
|
|
50726
50901
|
verdicts: parseNativeDecodeOutput(stdout, options.descriptors.map((descriptor) => descriptor.screenId), "android"),
|
|
@@ -50790,13 +50965,13 @@ __export(browser_authoring_exports, {
|
|
|
50790
50965
|
});
|
|
50791
50966
|
import { createServer as createServer3 } from "node:http";
|
|
50792
50967
|
import { createHash as createHash26, randomBytes as randomBytes4 } from "node:crypto";
|
|
50793
|
-
import { existsSync as
|
|
50794
|
-
import { join as
|
|
50968
|
+
import { existsSync as existsSync54, readdirSync as readdirSync27, readFileSync as readFileSync59, realpathSync as realpathSync6, statSync as statSync12 } from "node:fs";
|
|
50969
|
+
import { join as join53, posix as posix2, relative as relative10, sep as sep12 } from "node:path";
|
|
50795
50970
|
function humanMs(ms) {
|
|
50796
50971
|
return ms < 1e3 ? `${ms}ms` : `${Math.round(ms / 1e3)}s`;
|
|
50797
50972
|
}
|
|
50798
50973
|
function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
50799
|
-
const root =
|
|
50974
|
+
const root = join53(tier5SrcDir, bundleName);
|
|
50800
50975
|
const files = {};
|
|
50801
50976
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
50802
50977
|
const walk2 = (abs, rel) => {
|
|
@@ -50804,16 +50979,16 @@ function collectWorkerSources(tier5SrcDir, bundleName) {
|
|
|
50804
50979
|
if (visitedDirs.has(real)) return;
|
|
50805
50980
|
visitedDirs.add(real);
|
|
50806
50981
|
for (const name of readdirSync27(abs).sort()) {
|
|
50807
|
-
const childAbs =
|
|
50982
|
+
const childAbs = join53(abs, name);
|
|
50808
50983
|
const childRel = posix2.join(rel, name);
|
|
50809
50984
|
if (statSync12(childAbs).isDirectory()) {
|
|
50810
50985
|
walk2(childAbs, childRel);
|
|
50811
50986
|
} else if (/\.(ts|tsx|js|mjs|json)$/.test(name)) {
|
|
50812
|
-
files[childRel] =
|
|
50987
|
+
files[childRel] = readFileSync59(childAbs, "utf8");
|
|
50813
50988
|
}
|
|
50814
50989
|
}
|
|
50815
50990
|
};
|
|
50816
|
-
if (!
|
|
50991
|
+
if (!existsSync54(root)) return null;
|
|
50817
50992
|
walk2(root, `/tier5-src/${bundleName}`);
|
|
50818
50993
|
const entry = [`/tier5-src/${bundleName}/index.ts`, `/tier5-src/${bundleName}/index.js`].find((p) => p in files);
|
|
50819
50994
|
if (!entry) return null;
|
|
@@ -50830,20 +51005,20 @@ function collectRelativeSiblings(files, tier5SrcDir) {
|
|
|
50830
51005
|
const spec = m[1];
|
|
50831
51006
|
const virtual = posix2.normalize(posix2.join(dir, spec));
|
|
50832
51007
|
if (!virtual.startsWith("/tier5-src/")) continue;
|
|
50833
|
-
const onDisk =
|
|
51008
|
+
const onDisk = join53(tier5SrcDir, virtual.slice("/tier5-src/".length));
|
|
50834
51009
|
const candidates = [
|
|
50835
51010
|
onDisk,
|
|
50836
51011
|
`${onDisk}.ts`,
|
|
50837
51012
|
`${onDisk}.js`,
|
|
50838
51013
|
onDisk.replace(/\.js$/, ".ts"),
|
|
50839
|
-
|
|
50840
|
-
|
|
51014
|
+
join53(onDisk, "index.ts"),
|
|
51015
|
+
join53(onDisk, "index.js")
|
|
50841
51016
|
];
|
|
50842
51017
|
for (const abs of candidates) {
|
|
50843
|
-
if (!
|
|
50844
|
-
const key2 = `/tier5-src/${
|
|
51018
|
+
if (!existsSync54(abs) || statSync12(abs).isDirectory()) continue;
|
|
51019
|
+
const key2 = `/tier5-src/${relative10(tier5SrcDir, abs).split(sep12).join(posix2.sep)}`;
|
|
50845
51020
|
if (key2 in files) break;
|
|
50846
|
-
files[key2] =
|
|
51021
|
+
files[key2] = readFileSync59(abs, "utf8");
|
|
50847
51022
|
queue.push(key2);
|
|
50848
51023
|
break;
|
|
50849
51024
|
}
|
|
@@ -50878,7 +51053,7 @@ function collectSdkModules(files, resolveSubpath) {
|
|
|
50878
51053
|
function sdkSubpathReader(resolve48) {
|
|
50879
51054
|
return (sub) => {
|
|
50880
51055
|
try {
|
|
50881
|
-
return
|
|
51056
|
+
return readFileSync59(resolve48(`@wix/himalaya/${sub}`), "utf8");
|
|
50882
51057
|
} catch {
|
|
50883
51058
|
return null;
|
|
50884
51059
|
}
|
|
@@ -51050,8 +51225,8 @@ __export(coverage_exports, {
|
|
|
51050
51225
|
suppressedNativeKeys: () => suppressedNativeKeys,
|
|
51051
51226
|
trendAndStore: () => trendAndStore
|
|
51052
51227
|
});
|
|
51053
|
-
import { existsSync as
|
|
51054
|
-
import { dirname as dirname28, join as
|
|
51228
|
+
import { existsSync as existsSync55, mkdirSync as mkdirSync25, readFileSync as readFileSync60, writeFileSync as writeFileSync22 } from "node:fs";
|
|
51229
|
+
import { dirname as dirname28, join as join54 } from "node:path";
|
|
51055
51230
|
function suppressedNativeKeys(oracle) {
|
|
51056
51231
|
return [...oracle.ios ? [] : ["native-decode|ios"], ...oracle.android ? [] : ["native-decode|android"]];
|
|
51057
51232
|
}
|
|
@@ -51231,11 +51406,11 @@ function assembleLedger(r, options = {}) {
|
|
|
51231
51406
|
return out;
|
|
51232
51407
|
}
|
|
51233
51408
|
function trendAndStore(dir, entries, suppressed) {
|
|
51234
|
-
const p =
|
|
51409
|
+
const p = join54(dir, LEDGER_FILE);
|
|
51235
51410
|
let previous = null;
|
|
51236
51411
|
try {
|
|
51237
|
-
if (
|
|
51238
|
-
const parsed = JSON.parse(
|
|
51412
|
+
if (existsSync55(p)) {
|
|
51413
|
+
const parsed = JSON.parse(readFileSync60(p, "utf8"));
|
|
51239
51414
|
if (Array.isArray(parsed.keys)) previous = parsed.keys.filter((k) => typeof k === "string");
|
|
51240
51415
|
}
|
|
51241
51416
|
} catch {
|
|
@@ -51274,11 +51449,11 @@ function formatLedger(entries, trend) {
|
|
|
51274
51449
|
return out.join("\n");
|
|
51275
51450
|
}
|
|
51276
51451
|
function diffAndStoreObservations(dir, current) {
|
|
51277
|
-
const p =
|
|
51452
|
+
const p = join54(dir, OBS_FILE);
|
|
51278
51453
|
let previous = null;
|
|
51279
51454
|
try {
|
|
51280
|
-
if (
|
|
51281
|
-
const parsed = JSON.parse(
|
|
51455
|
+
if (existsSync55(p)) {
|
|
51456
|
+
const parsed = JSON.parse(readFileSync60(p, "utf8"));
|
|
51282
51457
|
if (parsed.screens && typeof parsed.screens === "object" && !Array.isArray(parsed.screens) && Object.values(parsed.screens).every(
|
|
51283
51458
|
(v) => Array.isArray(v) && v.every((l) => typeof l === "string")
|
|
51284
51459
|
)) {
|
|
@@ -51327,8 +51502,8 @@ var LEDGER_FILE, OBS_FILE;
|
|
|
51327
51502
|
var init_coverage = __esm({
|
|
51328
51503
|
"src/coverage.ts"() {
|
|
51329
51504
|
init_native_decode();
|
|
51330
|
-
LEDGER_FILE =
|
|
51331
|
-
OBS_FILE =
|
|
51505
|
+
LEDGER_FILE = join54(".himi", "test-ledger.json");
|
|
51506
|
+
OBS_FILE = join54(".himi", "test-observations.json");
|
|
51332
51507
|
}
|
|
51333
51508
|
});
|
|
51334
51509
|
|
|
@@ -51339,16 +51514,16 @@ __export(design_kits_exports, {
|
|
|
51339
51514
|
kitsDir: () => kitsDir,
|
|
51340
51515
|
listKits: () => listKits2
|
|
51341
51516
|
});
|
|
51342
|
-
import { existsSync as
|
|
51343
|
-
import { join as
|
|
51517
|
+
import { existsSync as existsSync56, readFileSync as readFileSync61, readdirSync as readdirSync28 } from "node:fs";
|
|
51518
|
+
import { join as join55, basename as basename14 } from "node:path";
|
|
51344
51519
|
import { fileURLToPath as fileURLToPath21 } from "node:url";
|
|
51345
51520
|
function kitsDir() {
|
|
51346
|
-
return KIT_DIR_CANDIDATES.find((p) =>
|
|
51521
|
+
return KIT_DIR_CANDIDATES.find((p) => existsSync56(p));
|
|
51347
51522
|
}
|
|
51348
51523
|
function listKits2() {
|
|
51349
51524
|
const dir = kitsDir();
|
|
51350
51525
|
if (!dir) return [];
|
|
51351
|
-
return readdirSync28(dir).filter((f) => f.endsWith(".json")).map((f) =>
|
|
51526
|
+
return readdirSync28(dir).filter((f) => f.endsWith(".json")).map((f) => basename14(f, ".json")).sort();
|
|
51352
51527
|
}
|
|
51353
51528
|
function kitReport(name) {
|
|
51354
51529
|
const dir = kitsDir();
|
|
@@ -51367,7 +51542,7 @@ In a published @wix/himalaya-cli this is a packaging bug \u2014 the kits should
|
|
|
51367
51542
|
if (!kits.includes(name)) {
|
|
51368
51543
|
return { ok: false, kit: name, kits, problems: [`no design kit named "${name}". Available: ${kits.join(", ")}`] };
|
|
51369
51544
|
}
|
|
51370
|
-
const raw =
|
|
51545
|
+
const raw = readFileSync61(join55(dir, `${name}.json`), "utf8");
|
|
51371
51546
|
let parsed;
|
|
51372
51547
|
try {
|
|
51373
51548
|
parsed = JSON.parse(raw);
|
|
@@ -51391,9 +51566,9 @@ var init_design_kits = __esm({
|
|
|
51391
51566
|
"src/design-kits.ts"() {
|
|
51392
51567
|
KIT_DIR_CANDIDATES = [
|
|
51393
51568
|
// in-repo: tools/himi-cli/src/design-kits.ts → <repo>/stdlib/design-kits/
|
|
51394
|
-
|
|
51569
|
+
join55(fileURLToPath21(new URL("../../..", import.meta.url)), "stdlib", "design-kits"),
|
|
51395
51570
|
// published CLI: <pkg>/dist/cli.mjs → <pkg>/stdlib/design-kits/
|
|
51396
|
-
|
|
51571
|
+
join55(fileURLToPath21(new URL("..", import.meta.url)), "stdlib", "design-kits")
|
|
51397
51572
|
];
|
|
51398
51573
|
}
|
|
51399
51574
|
});
|
|
@@ -51407,11 +51582,11 @@ __export(assets_exports, {
|
|
|
51407
51582
|
removeAssetPayload: () => removeAssetPayload,
|
|
51408
51583
|
verifyReport: () => verifyReport
|
|
51409
51584
|
});
|
|
51410
|
-
import { readFileSync as
|
|
51411
|
-
import { basename as
|
|
51585
|
+
import { readFileSync as readFileSync62 } from "node:fs";
|
|
51586
|
+
import { basename as basename15 } from "node:path";
|
|
51412
51587
|
function declaredAssets(dir) {
|
|
51413
51588
|
return collectAssets(dir).map((a) => {
|
|
51414
|
-
const bytes2 =
|
|
51589
|
+
const bytes2 = readFileSync62(a.path);
|
|
51415
51590
|
return {
|
|
51416
51591
|
name: a.name,
|
|
51417
51592
|
sha256: assetSha256(bytes2),
|
|
@@ -51488,8 +51663,8 @@ function verifyReport(dir, app, manifest) {
|
|
|
51488
51663
|
};
|
|
51489
51664
|
}
|
|
51490
51665
|
function addAssetPayload(manifest, filePath, opts) {
|
|
51491
|
-
const bytes2 =
|
|
51492
|
-
const name = opts.name ??
|
|
51666
|
+
const bytes2 = readFileSync62(filePath);
|
|
51667
|
+
const name = opts.name ?? basename15(filePath);
|
|
51493
51668
|
const sha2565 = assetSha256(bytes2);
|
|
51494
51669
|
const record2 = {
|
|
51495
51670
|
sha256: sha2565,
|
|
@@ -53163,9 +53338,9 @@ __export(run_exports, {
|
|
|
53163
53338
|
runPackage: () => runPackage,
|
|
53164
53339
|
withoutProdServe: () => withoutProdServe
|
|
53165
53340
|
});
|
|
53166
|
-
import { cpSync as cpSync2, existsSync as
|
|
53341
|
+
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
53342
|
import { networkInterfaces as osNetworkInterfaces, tmpdir as tmpdir4 } from "node:os";
|
|
53168
|
-
import { dirname as dirname29, join as
|
|
53343
|
+
import { dirname as dirname29, join as join56 } from "node:path";
|
|
53169
53344
|
import { fileURLToPath as fileURLToPath22 } from "node:url";
|
|
53170
53345
|
function makePackageRunHandler(opts) {
|
|
53171
53346
|
const store = new FileReleaseStore(opts.releaseRoot);
|
|
@@ -53193,9 +53368,9 @@ async function fetchBytes(url) {
|
|
|
53193
53368
|
}
|
|
53194
53369
|
async function resolvePackage(source, workDir) {
|
|
53195
53370
|
const isUrl2 = /^https?:\/\//i.test(source);
|
|
53196
|
-
if (!isUrl2 &&
|
|
53197
|
-
const appDirManifest =
|
|
53198
|
-
if (
|
|
53371
|
+
if (!isUrl2 && existsSync57(source) && statSync13(source).isDirectory()) {
|
|
53372
|
+
const appDirManifest = join56(source, "release-manifest.json");
|
|
53373
|
+
if (existsSync57(appDirManifest)) {
|
|
53199
53374
|
const opened2 = openPackageDir(source);
|
|
53200
53375
|
if (!opened2.validation.ok) {
|
|
53201
53376
|
throw new Error(`package is not valid:
|
|
@@ -53204,9 +53379,9 @@ async function resolvePackage(source, workDir) {
|
|
|
53204
53379
|
const app2 = opened2.header?.app ?? opened2.manifest?.app;
|
|
53205
53380
|
if (!app2) throw new Error(`${source} has no app id (no himi-package.json and no manifest.app)`);
|
|
53206
53381
|
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 (
|
|
53382
|
+
const root2 = workDir ?? mkdtempSync3(join56(tmpdir4(), "himi-run-"));
|
|
53383
|
+
const target = join56(root2, app2);
|
|
53384
|
+
if (join56(source) !== target) {
|
|
53210
53385
|
mkdirSync26(root2, { recursive: true });
|
|
53211
53386
|
rmSync12(target, { recursive: true, force: true });
|
|
53212
53387
|
cpSync2(source, target, { recursive: true });
|
|
@@ -53223,8 +53398,8 @@ async function resolvePackage(source, workDir) {
|
|
|
53223
53398
|
}
|
|
53224
53399
|
throw new Error(`${source} is a directory but has no release-manifest.json \u2014 is it a package?`);
|
|
53225
53400
|
}
|
|
53226
|
-
const bytes2 = isUrl2 ? await fetchBytes(source) :
|
|
53227
|
-
const root = workDir ?? mkdtempSync3(
|
|
53401
|
+
const bytes2 = isUrl2 ? await fetchBytes(source) : readFileSync63(source);
|
|
53402
|
+
const root = workDir ?? mkdtempSync3(join56(tmpdir4(), "himi-run-"));
|
|
53228
53403
|
const { app, appDir: appDir2 } = unpackTo(bytes2, root);
|
|
53229
53404
|
const opened = openPackageDir(appDir2);
|
|
53230
53405
|
if (!opened.validation.ok) {
|
|
@@ -53247,14 +53422,14 @@ async function loadPreviewAssets() {
|
|
|
53247
53422
|
const mod = await Promise.resolve().then(() => (init_preview_assets_generated(), preview_assets_generated_exports));
|
|
53248
53423
|
const here = dirname29(fileURLToPath22(import.meta.url));
|
|
53249
53424
|
const candidates = [
|
|
53250
|
-
|
|
53425
|
+
join56(here, "preview-assets.generated.bin"),
|
|
53251
53426
|
// published: copied next to the bundled CLI
|
|
53252
|
-
|
|
53427
|
+
join56(here, "../../../packages/serve/src/preview-assets.generated.bin")
|
|
53253
53428
|
// in-repo checkout
|
|
53254
53429
|
];
|
|
53255
53430
|
for (const path2 of candidates) {
|
|
53256
|
-
if (!
|
|
53257
|
-
const blob =
|
|
53431
|
+
if (!existsSync57(path2)) continue;
|
|
53432
|
+
const blob = readFileSync63(path2);
|
|
53258
53433
|
return mod.assemblePreviewAssetsFromBlob(new Uint8Array(blob.buffer, blob.byteOffset, blob.byteLength));
|
|
53259
53434
|
}
|
|
53260
53435
|
return /* @__PURE__ */ new Map();
|
|
@@ -53401,9 +53576,9 @@ __export(run_watch_exports, {
|
|
|
53401
53576
|
watchedContentDir: () => watchedContentDir,
|
|
53402
53577
|
writeRunRecord: () => writeRunRecord
|
|
53403
53578
|
});
|
|
53404
|
-
import { closeSync as closeSync2, constants, existsSync as
|
|
53579
|
+
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
53580
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
53406
|
-
import { extname as extname4, join as
|
|
53581
|
+
import { extname as extname4, join as join57, resolve as resolve42, sep as sep13 } from "node:path";
|
|
53407
53582
|
function diffReleases(prev, next) {
|
|
53408
53583
|
const bundles = Object.keys(next.bundles).filter((b) => prev.bundles[b]?.sha256 !== next.bundles[b].sha256).sort();
|
|
53409
53584
|
const changedBundles = new Set(bundles);
|
|
@@ -53444,7 +53619,7 @@ function watchContent(dir, onChange, opts = {}) {
|
|
|
53444
53619
|
let timer = null;
|
|
53445
53620
|
const pending = /* @__PURE__ */ new Set();
|
|
53446
53621
|
const watcher2 = watch2(dir, { recursive: true }, (_event, file) => {
|
|
53447
|
-
if (!file || ignoredChange(file, (rel) => isDir(
|
|
53622
|
+
if (!file || ignoredChange(file, (rel) => isDir(join57(dir, rel)))) return;
|
|
53448
53623
|
pending.add(file);
|
|
53449
53624
|
if (timer) clearTimeout(timer);
|
|
53450
53625
|
timer = setTimeout(() => {
|
|
@@ -53465,7 +53640,7 @@ function watchedContentDir(source) {
|
|
|
53465
53640
|
if (!source || /^https?:\/\//i.test(source)) return null;
|
|
53466
53641
|
const dir = resolve42(source);
|
|
53467
53642
|
try {
|
|
53468
|
-
return statSync14(dir).isDirectory() &&
|
|
53643
|
+
return statSync14(dir).isDirectory() && existsSync58(join57(dir, "himalaya.content.json")) ? dir : null;
|
|
53469
53644
|
} catch {
|
|
53470
53645
|
return null;
|
|
53471
53646
|
}
|
|
@@ -53522,7 +53697,7 @@ function serialize(task) {
|
|
|
53522
53697
|
});
|
|
53523
53698
|
}
|
|
53524
53699
|
function himiDir(dir) {
|
|
53525
|
-
const root =
|
|
53700
|
+
const root = join57(dir, ".himi");
|
|
53526
53701
|
try {
|
|
53527
53702
|
return lstatSync10(root).isDirectory() ? root : null;
|
|
53528
53703
|
} catch (e) {
|
|
@@ -53534,11 +53709,11 @@ function himiDir(dir) {
|
|
|
53534
53709
|
function writeRunRecord(dir, record2) {
|
|
53535
53710
|
const root = himiDir(dir);
|
|
53536
53711
|
if (!root) return false;
|
|
53537
|
-
const tmp =
|
|
53712
|
+
const tmp = join57(root, `.run.json.${process.pid}.${randomUUID3()}.tmp`);
|
|
53538
53713
|
try {
|
|
53539
53714
|
writeFileSync23(tmp, `${JSON.stringify(record2, null, 2)}
|
|
53540
53715
|
`, { flag: "wx" });
|
|
53541
|
-
renameSync6(tmp,
|
|
53716
|
+
renameSync6(tmp, join57(root, "run.json"));
|
|
53542
53717
|
} catch (e) {
|
|
53543
53718
|
rmSync13(tmp, { force: true });
|
|
53544
53719
|
throw e;
|
|
@@ -53546,7 +53721,7 @@ function writeRunRecord(dir, record2) {
|
|
|
53546
53721
|
return true;
|
|
53547
53722
|
}
|
|
53548
53723
|
function removeRunRecord(dir, owner) {
|
|
53549
|
-
const root =
|
|
53724
|
+
const root = join57(dir, ".himi");
|
|
53550
53725
|
try {
|
|
53551
53726
|
if (!lstatSync10(root).isDirectory()) return;
|
|
53552
53727
|
} catch {
|
|
@@ -53561,16 +53736,16 @@ function removeRunRecord(dir, owner) {
|
|
|
53561
53736
|
}
|
|
53562
53737
|
if (typeof pid === "number" && pid !== owner) return;
|
|
53563
53738
|
}
|
|
53564
|
-
rmSync13(
|
|
53739
|
+
rmSync13(join57(root, "run.json"), { force: true });
|
|
53565
53740
|
}
|
|
53566
53741
|
function boardFile(dir, pathname) {
|
|
53567
53742
|
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 =
|
|
53743
|
+
if (pathname === "/__himi/studio/" || pathname === "/__himi/studio/index.html") rel = join57("studio", "index.html");
|
|
53744
|
+
else if (pathname === "/__himi/studio/state.js") rel = join57("studio", "state.js");
|
|
53745
|
+
else if (pathname === "/__himi/studio/timeline.js") rel = join57("studio", "timeline.js");
|
|
53571
53746
|
else {
|
|
53572
53747
|
const m = /^\/__himi\/history\/([0-9a-f]{64}\.(png|jpg|gif|webp))$/.exec(pathname);
|
|
53573
|
-
if (m) rel =
|
|
53748
|
+
if (m) rel = join57("history", m[1]);
|
|
53574
53749
|
}
|
|
53575
53750
|
if (!rel) return null;
|
|
53576
53751
|
const bytes2 = readConfined(resolve42(dir, ".himi"), rel);
|
|
@@ -53586,7 +53761,7 @@ function readConfined(root, rel) {
|
|
|
53586
53761
|
const parts = rel.split(sep13);
|
|
53587
53762
|
let at = root;
|
|
53588
53763
|
for (let i = 0; i < parts.length; i++) {
|
|
53589
|
-
at =
|
|
53764
|
+
at = join57(at, parts[i]);
|
|
53590
53765
|
const st = lstatSync10(at);
|
|
53591
53766
|
if (st.isSymbolicLink() || !(i === parts.length - 1 ? st.isFile() : st.isDirectory())) return null;
|
|
53592
53767
|
}
|
|
@@ -53595,7 +53770,7 @@ function readConfined(root, rel) {
|
|
|
53595
53770
|
const fd = openSync2(at, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
53596
53771
|
try {
|
|
53597
53772
|
if (!fstatSync(fd).isFile()) return null;
|
|
53598
|
-
return
|
|
53773
|
+
return readFileSync64(fd);
|
|
53599
53774
|
} finally {
|
|
53600
53775
|
closeSync2(fd);
|
|
53601
53776
|
}
|
|
@@ -53647,7 +53822,7 @@ __export(run_browser_exports, {
|
|
|
53647
53822
|
runInBrowser: () => runInBrowser
|
|
53648
53823
|
});
|
|
53649
53824
|
import { createServer as createServer5 } from "node:http";
|
|
53650
|
-
import { existsSync as
|
|
53825
|
+
import { existsSync as existsSync59, readFileSync as readFileSync65 } from "node:fs";
|
|
53651
53826
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
53652
53827
|
import { dirname as dirname30, resolve as resolve43 } from "node:path";
|
|
53653
53828
|
import { fileURLToPath as fileURLToPath23 } from "node:url";
|
|
@@ -53655,7 +53830,7 @@ function stagedDir() {
|
|
|
53655
53830
|
return process.env.HIMI_BROWSER_PLANE_OUT ? resolve43(process.env.HIMI_BROWSER_PLANE_OUT) : resolve43(REPO, "packages", "serve", "dist", "browser-plane");
|
|
53656
53831
|
}
|
|
53657
53832
|
function missingStaged() {
|
|
53658
|
-
return [...SERVED].filter((f) => !
|
|
53833
|
+
return [...SERVED].filter((f) => !existsSync59(resolve43(stagedDir(), f))).sort();
|
|
53659
53834
|
}
|
|
53660
53835
|
function ensureBrowserPlaneStaged() {
|
|
53661
53836
|
if (missingStaged().length === 0) return { ok: true, detail: "already staged" };
|
|
@@ -53740,7 +53915,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53740
53915
|
}
|
|
53741
53916
|
const name = path2 === "/" || path2 === "/index.html" ? "host.html" : path2.slice(1);
|
|
53742
53917
|
if (SERVED.has(name)) {
|
|
53743
|
-
if (!
|
|
53918
|
+
if (!existsSync59(resolve43(stagedDir(), name))) {
|
|
53744
53919
|
const restaged = ensureBrowserPlaneStaged();
|
|
53745
53920
|
if (!restaged.ok) {
|
|
53746
53921
|
res.writeHead(503, { "content-type": "application/json" });
|
|
@@ -53750,7 +53925,7 @@ async function runInBrowser(releaseRoot, app, header, opts = {}) {
|
|
|
53750
53925
|
}
|
|
53751
53926
|
let bytes2;
|
|
53752
53927
|
try {
|
|
53753
|
-
bytes2 =
|
|
53928
|
+
bytes2 = readFileSync65(resolve43(stagedDir(), name));
|
|
53754
53929
|
} catch (e) {
|
|
53755
53930
|
res.writeHead(503, { "content-type": "application/json" });
|
|
53756
53931
|
res.end(JSON.stringify({ error: "browser_plane_unstaged", file: name, detail: String(e) }));
|
|
@@ -54211,11 +54386,11 @@ __export(preflight_exports, {
|
|
|
54211
54386
|
parseStoreConfig: () => parseStoreConfig,
|
|
54212
54387
|
requireEnv: () => requireEnv
|
|
54213
54388
|
});
|
|
54214
|
-
import { existsSync as
|
|
54215
|
-
import { isAbsolute as
|
|
54389
|
+
import { existsSync as existsSync60, readFileSync as readFileSync66 } from "node:fs";
|
|
54390
|
+
import { isAbsolute as isAbsolute5, relative as relative11, resolve as resolve44 } from "node:path";
|
|
54216
54391
|
function isInsideRepo(p) {
|
|
54217
|
-
const rel =
|
|
54218
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
54392
|
+
const rel = relative11(REPO_ROOT3, resolve44(p));
|
|
54393
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute5(rel);
|
|
54219
54394
|
}
|
|
54220
54395
|
function assertCredentialOutsideRepo(label2, p) {
|
|
54221
54396
|
if (isInsideRepo(p)) {
|
|
@@ -54268,10 +54443,10 @@ function parseStoreConfig(text5) {
|
|
|
54268
54443
|
}
|
|
54269
54444
|
function loadStoreConfig(app) {
|
|
54270
54445
|
const p = storeConfigPath(app);
|
|
54271
|
-
if (!
|
|
54446
|
+
if (!existsSync60(p)) {
|
|
54272
54447
|
throw new Error(`No store config at ${p}. Create apps/${app}/store/store.config.yaml first (see /setup-store-signing).`);
|
|
54273
54448
|
}
|
|
54274
|
-
return parseStoreConfig(
|
|
54449
|
+
return parseStoreConfig(readFileSync66(p, "utf8"));
|
|
54275
54450
|
}
|
|
54276
54451
|
var init_preflight = __esm({
|
|
54277
54452
|
"../store-release/preflight.ts"() {
|
|
@@ -54290,19 +54465,19 @@ __export(credential_profile_exports, {
|
|
|
54290
54465
|
profilePath: () => profilePath,
|
|
54291
54466
|
resolveStoreCredentials: () => resolveStoreCredentials
|
|
54292
54467
|
});
|
|
54293
|
-
import { existsSync as
|
|
54468
|
+
import { existsSync as existsSync61, readFileSync as readFileSync67 } from "node:fs";
|
|
54294
54469
|
import { homedir as homedir5 } from "node:os";
|
|
54295
|
-
import { join as
|
|
54470
|
+
import { join as join58 } from "node:path";
|
|
54296
54471
|
function credentialsDir(home = homedir5()) {
|
|
54297
|
-
return
|
|
54472
|
+
return join58(home, ".himalaya", "store-credentials");
|
|
54298
54473
|
}
|
|
54299
54474
|
function profilePath(name, home = homedir5()) {
|
|
54300
54475
|
if (!PROFILE_NAME.test(name)) {
|
|
54301
54476
|
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 ${
|
|
54477
|
+
`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
54478
|
);
|
|
54304
54479
|
}
|
|
54305
|
-
return
|
|
54480
|
+
return join58(credentialsDir(home), `${name}.json`);
|
|
54306
54481
|
}
|
|
54307
54482
|
function parseProfile(text5, label2) {
|
|
54308
54483
|
let doc;
|
|
@@ -54333,8 +54508,8 @@ function resolveStoreCredentials(opts) {
|
|
|
54333
54508
|
const { app, cfg } = opts;
|
|
54334
54509
|
const env = opts.env ?? process.env;
|
|
54335
54510
|
const home = opts.home ?? homedir5();
|
|
54336
|
-
const read = opts.readProfile ?? ((p) =>
|
|
54337
|
-
const exists = opts.profileExists ??
|
|
54511
|
+
const read = opts.readProfile ?? ((p) => readFileSync67(p, "utf8"));
|
|
54512
|
+
const exists = opts.profileExists ?? existsSync61;
|
|
54338
54513
|
const ios = cfg.ios ?? {};
|
|
54339
54514
|
const flagName = opts.profileFlag?.trim();
|
|
54340
54515
|
const named = namedProfile(cfg, opts.profileFlag);
|
|
@@ -54414,9 +54589,9 @@ __export(preflight_app_exports, {
|
|
|
54414
54589
|
preflightApp: () => preflightApp,
|
|
54415
54590
|
profileAccount: () => profileAccount
|
|
54416
54591
|
});
|
|
54417
|
-
import { readFileSync as
|
|
54592
|
+
import { readFileSync as readFileSync68, existsSync as existsSync62, readdirSync as readdirSync29, statSync as statSync15 } from "node:fs";
|
|
54418
54593
|
import { createHash as createHash27 } from "node:crypto";
|
|
54419
|
-
import { join as
|
|
54594
|
+
import { join as join59 } from "node:path";
|
|
54420
54595
|
function analyze(projectYml, storeConfig, icon, account) {
|
|
54421
54596
|
const f = [];
|
|
54422
54597
|
const has = (re, s) => re.test(s);
|
|
@@ -54480,13 +54655,13 @@ function profileAccount(app, storeConfig, opts = {}) {
|
|
|
54480
54655
|
}
|
|
54481
54656
|
}
|
|
54482
54657
|
async function preflightApp(app, opts = {}) {
|
|
54483
|
-
const projectYml =
|
|
54484
|
-
const storeConfig =
|
|
54658
|
+
const projectYml = existsSync62(iosProjectYml(app)) ? readFileSync68(iosProjectYml(app), "utf8") : "";
|
|
54659
|
+
const storeConfig = existsSync62(storeConfigPath(app)) ? readFileSync68(storeConfigPath(app), "utf8") : "";
|
|
54485
54660
|
if (!storeConfig) return [{ level: "error", message: `no apps/${app}/store/store.config.yaml \u2014 run /setup-store-signing first.` }];
|
|
54486
54661
|
const findings = analyze(
|
|
54487
54662
|
projectYml,
|
|
54488
54663
|
storeConfig,
|
|
54489
|
-
await appIconState(
|
|
54664
|
+
await appIconState(join59(appDir(app), "ios")),
|
|
54490
54665
|
profileAccount(app, storeConfig, opts)
|
|
54491
54666
|
);
|
|
54492
54667
|
findings.push(...analyzeListing(metadataFilesPresent(app), listScreenshots(app)));
|
|
@@ -54515,17 +54690,17 @@ function analyzeSubmissionRecord(appLevel, review, opts) {
|
|
|
54515
54690
|
return f;
|
|
54516
54691
|
}
|
|
54517
54692
|
function appLevelMetadataFiles(app, locale = "en-US") {
|
|
54518
|
-
const root =
|
|
54693
|
+
const root = join59(storeDir(app), "metadata");
|
|
54519
54694
|
const out = /* @__PURE__ */ new Set();
|
|
54520
|
-
if (
|
|
54695
|
+
if (existsSync62(root)) {
|
|
54521
54696
|
for (const n of readdirSync29(root)) if (n.endsWith(".txt")) out.add(n);
|
|
54522
54697
|
}
|
|
54523
|
-
if (
|
|
54698
|
+
if (existsSync62(join59(root, locale, "privacy_url.txt"))) out.add("privacy_url.txt");
|
|
54524
54699
|
return out;
|
|
54525
54700
|
}
|
|
54526
54701
|
function reviewInfoFiles(app) {
|
|
54527
|
-
const dir =
|
|
54528
|
-
if (!
|
|
54702
|
+
const dir = join59(storeDir(app), "review_information");
|
|
54703
|
+
if (!existsSync62(dir)) return /* @__PURE__ */ new Set();
|
|
54529
54704
|
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
54530
54705
|
}
|
|
54531
54706
|
function isValidAppStoreSize(w, h) {
|
|
@@ -54635,12 +54810,12 @@ function analyzePlayListing(assets) {
|
|
|
54635
54810
|
return f;
|
|
54636
54811
|
}
|
|
54637
54812
|
function playListingAssets(app, locale = "en-US") {
|
|
54638
|
-
const dir =
|
|
54813
|
+
const dir = join59(storeDir(app), "play", locale, "images");
|
|
54639
54814
|
const read = (names) => {
|
|
54640
54815
|
for (const name of names) {
|
|
54641
|
-
const p =
|
|
54816
|
+
const p = join59(dir, name);
|
|
54642
54817
|
try {
|
|
54643
|
-
if (statSync15(p).isFile()) return { name, bytes:
|
|
54818
|
+
if (statSync15(p).isFile()) return { name, bytes: readFileSync68(p) };
|
|
54644
54819
|
} catch {
|
|
54645
54820
|
}
|
|
54646
54821
|
}
|
|
@@ -54671,26 +54846,26 @@ function analyzeListing(metaFiles, shots) {
|
|
|
54671
54846
|
return f;
|
|
54672
54847
|
}
|
|
54673
54848
|
function metadataFilesPresent(app, locale = "en-US") {
|
|
54674
|
-
const dir =
|
|
54675
|
-
if (!
|
|
54849
|
+
const dir = join59(storeDir(app), "metadata", locale);
|
|
54850
|
+
if (!existsSync62(dir)) return /* @__PURE__ */ new Set();
|
|
54676
54851
|
return new Set(readdirSync29(dir).filter((n) => n.endsWith(".txt")));
|
|
54677
54852
|
}
|
|
54678
54853
|
function listScreenshots(app, locale = "en-US") {
|
|
54679
54854
|
const out = [];
|
|
54680
|
-
const flat =
|
|
54681
|
-
if (
|
|
54855
|
+
const flat = join59(storeDir(app), "screenshots", locale);
|
|
54856
|
+
if (existsSync62(flat)) {
|
|
54682
54857
|
for (const png of readdirSync29(flat).filter((n) => n.endsWith(".png"))) {
|
|
54683
|
-
const sz = pngSize(
|
|
54858
|
+
const sz = pngSize(readFileSync68(join59(flat, png)));
|
|
54684
54859
|
if (sz) out.push({ name: png, w: sz.w, h: sz.h });
|
|
54685
54860
|
}
|
|
54686
54861
|
}
|
|
54687
|
-
const legacy =
|
|
54688
|
-
if (
|
|
54862
|
+
const legacy = join59(storeDir(app), "metadata", locale, "screenshots");
|
|
54863
|
+
if (existsSync62(legacy)) {
|
|
54689
54864
|
for (const deviceDir of readdirSync29(legacy)) {
|
|
54690
|
-
const d =
|
|
54865
|
+
const d = join59(legacy, deviceDir);
|
|
54691
54866
|
if (!statSync15(d).isDirectory()) continue;
|
|
54692
54867
|
for (const png of readdirSync29(d).filter((n) => n.endsWith(".png"))) {
|
|
54693
|
-
const sz = pngSize(
|
|
54868
|
+
const sz = pngSize(readFileSync68(join59(d, png)));
|
|
54694
54869
|
if (sz) out.push({ name: `${deviceDir}/${png}`, w: sz.w, h: sz.h });
|
|
54695
54870
|
}
|
|
54696
54871
|
}
|
|
@@ -54698,13 +54873,13 @@ function listScreenshots(app, locale = "en-US") {
|
|
|
54698
54873
|
return out;
|
|
54699
54874
|
}
|
|
54700
54875
|
function placeholderHashes2() {
|
|
54701
|
-
const templateIos =
|
|
54702
|
-
if (!
|
|
54876
|
+
const templateIos = join59(appDir("_template"), "ios");
|
|
54877
|
+
if (!existsSync62(templateIos)) return [LEGACY_PLACEHOLDER_SHA2562];
|
|
54703
54878
|
for (const target of readdirSync29(templateIos)) {
|
|
54704
|
-
const p =
|
|
54879
|
+
const p = join59(templateIos, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54705
54880
|
try {
|
|
54706
54881
|
if (!statSync15(p).isFile()) continue;
|
|
54707
|
-
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(
|
|
54882
|
+
return [LEGACY_PLACEHOLDER_SHA2562, createHash27("sha256").update(readFileSync68(p)).digest("hex")];
|
|
54708
54883
|
} catch {
|
|
54709
54884
|
}
|
|
54710
54885
|
}
|
|
@@ -54735,12 +54910,12 @@ async function pixelIssues(bytes2) {
|
|
|
54735
54910
|
}
|
|
54736
54911
|
}
|
|
54737
54912
|
async function appIconState(iosDir) {
|
|
54738
|
-
if (!
|
|
54913
|
+
if (!existsSync62(iosDir)) return { exists: false, isPlaceholder: false, storeIssues: [] };
|
|
54739
54914
|
for (const target of readdirSync29(iosDir)) {
|
|
54740
|
-
const p =
|
|
54915
|
+
const p = join59(iosDir, target, "Assets.xcassets", "AppIcon.appiconset", "icon_1024.png");
|
|
54741
54916
|
try {
|
|
54742
54917
|
if (!statSync15(p).isFile()) continue;
|
|
54743
|
-
const bytes2 =
|
|
54918
|
+
const bytes2 = readFileSync68(p);
|
|
54744
54919
|
const hash = createHash27("sha256").update(bytes2).digest("hex");
|
|
54745
54920
|
const pixels = await pixelIssues(bytes2);
|
|
54746
54921
|
return {
|
|
@@ -54812,7 +54987,7 @@ __export(version_exports, {
|
|
|
54812
54987
|
setAndroidVersion: () => setAndroidVersion,
|
|
54813
54988
|
setIosVersion: () => setIosVersion
|
|
54814
54989
|
});
|
|
54815
|
-
import { readFileSync as
|
|
54990
|
+
import { readFileSync as readFileSync69, writeFileSync as writeFileSync24 } from "node:fs";
|
|
54816
54991
|
function readIosVersion(projectYml) {
|
|
54817
54992
|
const marketing = matchScalar(projectYml, "CFBundleShortVersionString");
|
|
54818
54993
|
const build2 = matchScalar(projectYml, "CFBundleVersion");
|
|
@@ -54870,8 +55045,8 @@ function setAndroidVersion(gradle, v) {
|
|
|
54870
55045
|
function bumpVersion(app, opts) {
|
|
54871
55046
|
const iosPath = iosProjectYml(app);
|
|
54872
55047
|
const gradlePath = androidGradle(app);
|
|
54873
|
-
const iosYml =
|
|
54874
|
-
const gradle =
|
|
55048
|
+
const iosYml = readFileSync69(iosPath, "utf8");
|
|
55049
|
+
const gradle = readFileSync69(gradlePath, "utf8");
|
|
54875
55050
|
const current = readIosVersion(iosYml);
|
|
54876
55051
|
const next = {
|
|
54877
55052
|
marketing: opts.marketing ?? current.marketing,
|
|
@@ -54888,7 +55063,7 @@ var init_version = __esm({
|
|
|
54888
55063
|
});
|
|
54889
55064
|
|
|
54890
55065
|
// ../store-release/register-bundle.ts
|
|
54891
|
-
import { readFileSync as
|
|
55066
|
+
import { readFileSync as readFileSync70 } from "node:fs";
|
|
54892
55067
|
import { createPrivateKey as createPrivateKey2, sign } from "node:crypto";
|
|
54893
55068
|
function b64url2(b) {
|
|
54894
55069
|
return Buffer.from(b).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
@@ -54906,7 +55081,7 @@ function bundleIdBody(identifier, name, platform = "IOS") {
|
|
|
54906
55081
|
async function registerBundleId(opts) {
|
|
54907
55082
|
const env = requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54908
55083
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54909
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
55084
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync70(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54910
55085
|
const res = await fetch(`${ASC_API}/v1/bundleIds`, {
|
|
54911
55086
|
method: "POST",
|
|
54912
55087
|
headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
|
|
@@ -54960,7 +55135,7 @@ __export(asc_status_exports, {
|
|
|
54960
55135
|
ascStatus: () => ascStatus,
|
|
54961
55136
|
buildVerdict: () => buildVerdict
|
|
54962
55137
|
});
|
|
54963
|
-
import { readFileSync as
|
|
55138
|
+
import { readFileSync as readFileSync71 } from "node:fs";
|
|
54964
55139
|
function buildVerdict(builds) {
|
|
54965
55140
|
if (!builds.length) {
|
|
54966
55141
|
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 +55149,7 @@ function buildVerdict(builds) {
|
|
|
54974
55149
|
function client(creds) {
|
|
54975
55150
|
const env = creds ?? requireEnv(["ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH"]);
|
|
54976
55151
|
assertCredentialOutsideRepo("ASC_KEY_PATH", env.ASC_KEY_PATH);
|
|
54977
|
-
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID,
|
|
55152
|
+
const jwt = ascJwt(env.ASC_KEY_ID, env.ASC_ISSUER_ID, readFileSync71(env.ASC_KEY_PATH, "utf8"), Math.floor(Date.now() / 1e3));
|
|
54978
55153
|
return async (path2) => {
|
|
54979
55154
|
const r = await fetch(`${ASC}${path2}`, { headers: { Authorization: `Bearer ${jwt}` } });
|
|
54980
55155
|
return { status: r.status, json: await r.json().catch(() => ({})) };
|
|
@@ -55134,7 +55309,7 @@ __export(secrets_exports, {
|
|
|
55134
55309
|
runRemoteSecretsCommand: () => runRemoteSecretsCommand,
|
|
55135
55310
|
runSecretsCommand: () => runSecretsCommand
|
|
55136
55311
|
});
|
|
55137
|
-
import { readFileSync as
|
|
55312
|
+
import { readFileSync as readFileSync72 } from "node:fs";
|
|
55138
55313
|
function environment(value) {
|
|
55139
55314
|
if (value === "preview" || value === "production") return value;
|
|
55140
55315
|
throw new Error("--environment must be preview or production");
|
|
@@ -55165,7 +55340,7 @@ async function runSecretsCommand(operation, flags, io, options = {}) {
|
|
|
55165
55340
|
io.log(JSON.stringify(await vault.list({ app, environment: env })));
|
|
55166
55341
|
return 0;
|
|
55167
55342
|
}
|
|
55168
|
-
const value = options.readValue ? options.readValue() :
|
|
55343
|
+
const value = options.readValue ? options.readValue() : readFileSync72(0, "utf8").replace(/\r?\n$/, "");
|
|
55169
55344
|
if (operation === "set") await vault.set({ app, environment: env, name, value });
|
|
55170
55345
|
else if (operation === "rotate") await vault.rotate({ app, environment: env, name, value });
|
|
55171
55346
|
else throw new Error(`unknown secrets operation ${operation}`);
|
|
@@ -55194,7 +55369,7 @@ async function runRemoteSecretsCommand(operation, flags, io, options) {
|
|
|
55194
55369
|
}
|
|
55195
55370
|
let body;
|
|
55196
55371
|
if (operation !== "list") {
|
|
55197
|
-
const value = options.readValue ? options.readValue() :
|
|
55372
|
+
const value = options.readValue ? options.readValue() : readFileSync72(0, "utf8").replace(/\r?\n$/, "");
|
|
55198
55373
|
body = JSON.stringify({ value });
|
|
55199
55374
|
}
|
|
55200
55375
|
const response = await (options.fetchImpl ?? fetch)(url, { method: operation === "list" ? "GET" : operation === "set" ? "PUT" : "POST", headers: headers2, body });
|
|
@@ -55230,15 +55405,15 @@ __export(notify_exports, {
|
|
|
55230
55405
|
runNotify: () => runNotify,
|
|
55231
55406
|
saveAdminSession: () => saveAdminSession
|
|
55232
55407
|
});
|
|
55233
|
-
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as
|
|
55408
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync28, readFileSync as readFileSync73, writeFileSync as writeFileSync25 } from "node:fs";
|
|
55234
55409
|
import { homedir as homedir6 } from "node:os";
|
|
55235
|
-
import { dirname as dirname32, join as
|
|
55410
|
+
import { dirname as dirname32, join as join60 } from "node:path";
|
|
55236
55411
|
function defaultSessionsPath() {
|
|
55237
|
-
return process.env.HIMI_ADMIN_SESSIONS_FILE ??
|
|
55412
|
+
return process.env.HIMI_ADMIN_SESSIONS_FILE ?? join60(homedir6(), ".himalaya", "admin-sessions.json");
|
|
55238
55413
|
}
|
|
55239
55414
|
function loadSessionsFile(path2 = defaultSessionsPath()) {
|
|
55240
55415
|
try {
|
|
55241
|
-
return JSON.parse(
|
|
55416
|
+
return JSON.parse(readFileSync73(path2, "utf8"));
|
|
55242
55417
|
} catch {
|
|
55243
55418
|
return {};
|
|
55244
55419
|
}
|
|
@@ -56368,7 +56543,7 @@ function deriveAdoptedCmsCollections(cms) {
|
|
|
56368
56543
|
return { collections, dropped };
|
|
56369
56544
|
}
|
|
56370
56545
|
function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
56371
|
-
const
|
|
56546
|
+
const appName2 = deriveAppName(ctx, overrides.appName);
|
|
56372
56547
|
const supportUrl = clean(overrides.supportUrl) || clean(ctx.url.primary);
|
|
56373
56548
|
const privacyUrl = clean(overrides.privacyUrl);
|
|
56374
56549
|
const termsUrl = clean(overrides.termsUrl);
|
|
@@ -56388,8 +56563,8 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
56388
56563
|
// empty; either way the key exists and the shell's list never survives the merge.
|
|
56389
56564
|
cmsCollections: [],
|
|
56390
56565
|
identity: {
|
|
56391
|
-
appName,
|
|
56392
|
-
businessName: clean(ctx.identity.businessName) ||
|
|
56566
|
+
appName: appName2,
|
|
56567
|
+
businessName: clean(ctx.identity.businessName) || appName2,
|
|
56393
56568
|
tagline: clean(overrides.tagline) || clean(ctx.identity.description),
|
|
56394
56569
|
// "" means UNKNOWN here, with `missing` above as the signal — the published overlay's
|
|
56395
56570
|
// documented shape. Keeping an unknown url out of a MERGE is `apply.ts`'s job, at the
|
|
@@ -56399,7 +56574,7 @@ function deriveTailoring(ctx, overrides = {}, revision = "site-derived") {
|
|
|
56399
56574
|
termsUrl
|
|
56400
56575
|
}
|
|
56401
56576
|
};
|
|
56402
|
-
return { appName, iconSource: deriveIconSource(ctx), provisioning, missing };
|
|
56577
|
+
return { appName: appName2, iconSource: deriveIconSource(ctx), provisioning, missing };
|
|
56403
56578
|
}
|
|
56404
56579
|
function bounded(s, max) {
|
|
56405
56580
|
if (s.length <= max) return s;
|
|
@@ -58495,11 +58670,11 @@ function crawledPageName(look, page) {
|
|
|
58495
58670
|
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
58671
|
return hit?.title.trim() ?? "";
|
|
58497
58672
|
}
|
|
58498
|
-
function guessedNameWarning(
|
|
58499
|
-
const from = crawledTitle && crawledTitle !==
|
|
58673
|
+
function guessedNameWarning(appName2, crawledTitle, ownerLookupError) {
|
|
58674
|
+
const from = crawledTitle && crawledTitle !== appName2 ? ` off the crawled page title "${crawledTitle}"` : " from the site crawl";
|
|
58500
58675
|
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
58676
|
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 "${
|
|
58677
|
+
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
58678
|
}
|
|
58504
58679
|
function mergeLookFromPublished(look, published, siteUrl) {
|
|
58505
58680
|
const sitePages = withPageUrls(
|
|
@@ -59007,7 +59182,7 @@ var init_brand_font = __esm({
|
|
|
59007
59182
|
|
|
59008
59183
|
// src/site-analyze/write-artifacts.ts
|
|
59009
59184
|
import { mkdirSync as mkdirSync29, writeFileSync as writeFileSync26 } from "node:fs";
|
|
59010
|
-
import { join as
|
|
59185
|
+
import { join as join61 } from "node:path";
|
|
59011
59186
|
function attachVeloSources(book, sources, put) {
|
|
59012
59187
|
const byPath = new Map((sources ?? []).map((s) => [s.path, s.text]));
|
|
59013
59188
|
for (const f of book.velo.files) {
|
|
@@ -59162,12 +59337,12 @@ async function downloadMedia(book, fetchImpl, put) {
|
|
|
59162
59337
|
}
|
|
59163
59338
|
async function writeBusinessBook(result, opts) {
|
|
59164
59339
|
const out = opts.outDir;
|
|
59165
|
-
mkdirSync29(
|
|
59166
|
-
mkdirSync29(
|
|
59340
|
+
mkdirSync29(join61(out, "evidence/pages"), { recursive: true });
|
|
59341
|
+
mkdirSync29(join61(out, "media/catalog"), { recursive: true });
|
|
59167
59342
|
const files = [];
|
|
59168
59343
|
const put = (rel, body) => {
|
|
59169
|
-
const p =
|
|
59170
|
-
mkdirSync29(
|
|
59344
|
+
const p = join61(out, rel);
|
|
59345
|
+
mkdirSync29(join61(p, ".."), { recursive: true });
|
|
59171
59346
|
writeFileSync26(p, body);
|
|
59172
59347
|
files.push(rel);
|
|
59173
59348
|
};
|
|
@@ -59261,8 +59436,8 @@ var init_customer_build = __esm({
|
|
|
59261
59436
|
});
|
|
59262
59437
|
|
|
59263
59438
|
// src/site-analyze/apply.ts
|
|
59264
|
-
import { existsSync as
|
|
59265
|
-
import { dirname as dirname33, isAbsolute as
|
|
59439
|
+
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";
|
|
59440
|
+
import { dirname as dirname33, isAbsolute as isAbsolute6, join as join62, resolve as resolve45, sep as sep14 } from "node:path";
|
|
59266
59441
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
59267
59442
|
function unpairedRedirectNote(overlay) {
|
|
59268
59443
|
if (!overlay.wix?.clientId || overlay.wix.redirectUri) return void 0;
|
|
@@ -59277,7 +59452,7 @@ function committedShellProvisioning(path2) {
|
|
|
59277
59452
|
function findRepoRoot(cwd) {
|
|
59278
59453
|
let dir = cwd;
|
|
59279
59454
|
for (let i = 0; i < 8; i++) {
|
|
59280
|
-
if (SHELL_NAMES2.some((name) =>
|
|
59455
|
+
if (SHELL_NAMES2.some((name) => existsSync63(join62(dir, shellAppDir(name), "package.json")))) return dir;
|
|
59281
59456
|
const next = dirname33(dir);
|
|
59282
59457
|
if (next === dir) break;
|
|
59283
59458
|
dir = next;
|
|
@@ -59346,24 +59521,24 @@ function mergeCustomerOwned(committed, overlay) {
|
|
|
59346
59521
|
}
|
|
59347
59522
|
function buildMergedContract(options) {
|
|
59348
59523
|
const { appDir: appDir2, packageDir, overlay } = options;
|
|
59349
|
-
const committedPath =
|
|
59350
|
-
if (!
|
|
59524
|
+
const committedPath = join62(appDir2, "provisioning.json");
|
|
59525
|
+
if (!existsSync63(committedPath)) {
|
|
59351
59526
|
throw new Error(`shell has no committed provisioning.json at ${committedPath} to build a contract from`);
|
|
59352
59527
|
}
|
|
59353
|
-
const committed = JSON.parse(
|
|
59528
|
+
const committed = JSON.parse(readFileSync74(committedPath, "utf8"));
|
|
59354
59529
|
const merged = mergeCustomerOwned(committed, overlay);
|
|
59355
59530
|
const overlayFontFamily = (overlay.branding ?? {}).fontFamily;
|
|
59356
59531
|
const branding = merged.branding ?? {};
|
|
59357
59532
|
const staged = [];
|
|
59358
59533
|
const contained = (root, rel) => {
|
|
59359
|
-
if (
|
|
59534
|
+
if (isAbsolute6(rel)) return void 0;
|
|
59360
59535
|
const full = resolve45(root, rel);
|
|
59361
59536
|
return full.startsWith(resolve45(root) + sep14) ? full : void 0;
|
|
59362
59537
|
};
|
|
59363
59538
|
const stage = (fromRel, toRel) => {
|
|
59364
59539
|
const from = contained(packageDir, fromRel);
|
|
59365
|
-
const to = contained(
|
|
59366
|
-
if (!from || !to || !
|
|
59540
|
+
const to = contained(join62(appDir2, STAGED), toRel.slice(STAGED.length + 1));
|
|
59541
|
+
if (!from || !to || !existsSync63(from)) return void 0;
|
|
59367
59542
|
let real;
|
|
59368
59543
|
let realRoot;
|
|
59369
59544
|
try {
|
|
@@ -59385,11 +59560,11 @@ function buildMergedContract(options) {
|
|
|
59385
59560
|
};
|
|
59386
59561
|
const icon = stage("media/icon.png", `${STAGED}/icon.png`);
|
|
59387
59562
|
if (icon) branding.appIconPath = icon;
|
|
59388
|
-
const facesPath =
|
|
59389
|
-
if (
|
|
59563
|
+
const facesPath = join62(packageDir, "media/fonts/faces.json");
|
|
59564
|
+
if (existsSync63(facesPath)) {
|
|
59390
59565
|
let faces = [];
|
|
59391
59566
|
try {
|
|
59392
|
-
const parsed = JSON.parse(
|
|
59567
|
+
const parsed = JSON.parse(readFileSync74(facesPath, "utf8"));
|
|
59393
59568
|
faces = Array.isArray(parsed) ? parsed : [];
|
|
59394
59569
|
} catch {
|
|
59395
59570
|
faces = [];
|
|
@@ -59410,9 +59585,9 @@ function buildMergedContract(options) {
|
|
|
59410
59585
|
merged.branding = branding;
|
|
59411
59586
|
const body = `${JSON.stringify(merged, null, 2)}
|
|
59412
59587
|
`;
|
|
59413
|
-
const path2 =
|
|
59588
|
+
const path2 = join62(packageDir, "provisioning.contract.json");
|
|
59414
59589
|
writeFileSync27(path2, body);
|
|
59415
|
-
const localPath =
|
|
59590
|
+
const localPath = join62(appDir2, LOCAL_CONTRACT_REL);
|
|
59416
59591
|
mkdirSync30(dirname33(localPath), { recursive: true });
|
|
59417
59592
|
writeFileSync27(localPath, body);
|
|
59418
59593
|
staged.push(localPath);
|
|
@@ -59447,10 +59622,10 @@ function catalogTypography(overlay, template) {
|
|
|
59447
59622
|
function staticFaqFor(overlay, overlayPath) {
|
|
59448
59623
|
const own3 = overlay.faq;
|
|
59449
59624
|
if (own3 !== void 0) return deriveStaticFaq(own3);
|
|
59450
|
-
const bookPath =
|
|
59451
|
-
if (!
|
|
59625
|
+
const bookPath = join62(dirname33(resolve45(overlayPath)), "book.json");
|
|
59626
|
+
if (!existsSync63(bookPath)) return void 0;
|
|
59452
59627
|
try {
|
|
59453
|
-
const book = JSON.parse(
|
|
59628
|
+
const book = JSON.parse(readFileSync74(bookPath, "utf8"));
|
|
59454
59629
|
const copy = book?.copy;
|
|
59455
59630
|
if (!copy || typeof copy !== "object" || copy.unavailable) return void 0;
|
|
59456
59631
|
const pairs = deriveStaticFaq(copy.faq);
|
|
@@ -59464,8 +59639,8 @@ async function applyOverlays(input) {
|
|
|
59464
59639
|
const cwd = resolve45(input.cwd);
|
|
59465
59640
|
const shell = input.shell ?? DEFAULT_BRANDABLE_SHELL;
|
|
59466
59641
|
assertKnownShell(shell);
|
|
59467
|
-
const overlay = JSON.parse(
|
|
59468
|
-
const tokens = JSON.parse(
|
|
59642
|
+
const overlay = JSON.parse(readFileSync74(input.overlayPath, "utf8"));
|
|
59643
|
+
const tokens = JSON.parse(readFileSync74(input.tokensPath, "utf8"));
|
|
59469
59644
|
const faq = staticFaqFor(overlay, input.overlayPath);
|
|
59470
59645
|
if (faq !== void 0) overlay.faq = faq;
|
|
59471
59646
|
const wrote = [];
|
|
@@ -59477,9 +59652,9 @@ async function applyOverlays(input) {
|
|
|
59477
59652
|
`shell "${shell}" cannot bake a customer brand \u2014 it ships no prepare:customer script`
|
|
59478
59653
|
);
|
|
59479
59654
|
}
|
|
59480
|
-
const appDir2 =
|
|
59481
|
-
const committedPath =
|
|
59482
|
-
const committedSite =
|
|
59655
|
+
const appDir2 = join62(repoRoot2, shellAppDir(shell));
|
|
59656
|
+
const committedPath = join62(appDir2, "provisioning.json");
|
|
59657
|
+
const committedSite = existsSync63(committedPath) ? JSON.parse(readFileSync74(committedPath, "utf8")).site : void 0;
|
|
59483
59658
|
if (committedSite !== void 0 && overlay.site === void 0) {
|
|
59484
59659
|
throw new Error(
|
|
59485
59660
|
`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 +59681,11 @@ async function applyOverlays(input) {
|
|
|
59506
59681
|
note: `prepare:customer --contract with a merged contract (committed provisioning.json untouched)${unpairedInRepo ? ` \xB7 ${unpairedInRepo}` : ""}`
|
|
59507
59682
|
};
|
|
59508
59683
|
}
|
|
59509
|
-
const pkgProv =
|
|
59684
|
+
const pkgProv = join62(cwd, "provisioning.json");
|
|
59510
59685
|
assertNotCommitted(pkgProv, input.forbiddenProvisioning);
|
|
59511
59686
|
let packageFaq = faq;
|
|
59512
|
-
if (
|
|
59513
|
-
const cur = JSON.parse(
|
|
59687
|
+
if (existsSync63(pkgProv)) {
|
|
59688
|
+
const cur = JSON.parse(readFileSync74(pkgProv, "utf8"));
|
|
59514
59689
|
const merged = deepMerge4(cur, overlay);
|
|
59515
59690
|
packageFaq = merged.faq;
|
|
59516
59691
|
writeFileSync27(pkgProv, JSON.stringify(merged, null, 2) + "\n");
|
|
@@ -59519,9 +59694,9 @@ async function applyOverlays(input) {
|
|
|
59519
59694
|
writeFileSync27(pkgProv, JSON.stringify(overlay, null, 2) + "\n");
|
|
59520
59695
|
wrote.push(pkgProv);
|
|
59521
59696
|
}
|
|
59522
|
-
const pkgTokens =
|
|
59523
|
-
if (
|
|
59524
|
-
const cur = JSON.parse(
|
|
59697
|
+
const pkgTokens = join62(cwd, "tokens.json");
|
|
59698
|
+
if (existsSync63(pkgTokens) && (tokens.colors || tokens.typography)) {
|
|
59699
|
+
const cur = JSON.parse(readFileSync74(pkgTokens, "utf8"));
|
|
59525
59700
|
let tokensIn = tokens;
|
|
59526
59701
|
if (tokens.typography) {
|
|
59527
59702
|
const fonts = catalogTypography(tokens.typography, cur.typography);
|
|
@@ -59546,9 +59721,9 @@ async function applyOverlays(input) {
|
|
|
59546
59721
|
wrote.push(pkgTokens);
|
|
59547
59722
|
}
|
|
59548
59723
|
const homeAction = homeRefreshActionId(shell);
|
|
59549
|
-
const homeSrc =
|
|
59550
|
-
if (homeAction &&
|
|
59551
|
-
const prev =
|
|
59724
|
+
const homeSrc = join62(cwd, "dev/index.ts");
|
|
59725
|
+
if (homeAction && existsSync63(homeSrc)) {
|
|
59726
|
+
const prev = readFileSync74(homeSrc, "utf8");
|
|
59552
59727
|
const patched = patchBrandParams(prev, overlay, homeAction);
|
|
59553
59728
|
let next = patched.src;
|
|
59554
59729
|
if (!patched.foreign && faq?.length && prev.includes('"tier5.himiBrandedFaq.load"') && !prev.includes('"staticFaq"')) {
|
|
@@ -59579,13 +59754,13 @@ async function applyOverlays(input) {
|
|
|
59579
59754
|
notes.push(`${patched.unparsed} onAppear params block(s) in ${homeSrc} could not be read \u2014 any brand values inside them were not applied`);
|
|
59580
59755
|
}
|
|
59581
59756
|
}
|
|
59582
|
-
if (!input.iconPath || !
|
|
59757
|
+
if (!input.iconPath || !existsSync63(input.iconPath)) {
|
|
59583
59758
|
const book = input.iconPath ? dirname33(dirname33(resolve45(input.iconPath))) : void 0;
|
|
59584
59759
|
notes.push(
|
|
59585
59760
|
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
59761
|
);
|
|
59587
59762
|
}
|
|
59588
|
-
if (input.iconPath &&
|
|
59763
|
+
if (input.iconPath && existsSync63(input.iconPath)) {
|
|
59589
59764
|
try {
|
|
59590
59765
|
const installed = await installIcon(cwd, input.iconPath, { derivePlay: true });
|
|
59591
59766
|
wrote.push(...installed.wrote);
|
|
@@ -63772,7 +63947,7 @@ __export(cli_exports, {
|
|
|
63772
63947
|
runSiteAnalyze: () => runSiteAnalyze,
|
|
63773
63948
|
runSiteFunctionCli: () => runSiteFunctionCli
|
|
63774
63949
|
});
|
|
63775
|
-
import { readFileSync as
|
|
63950
|
+
import { readFileSync as readFileSync75 } from "node:fs";
|
|
63776
63951
|
import { resolve as resolve46 } from "node:path";
|
|
63777
63952
|
function assetFetchFor(_opts) {
|
|
63778
63953
|
return pinnedFetch2;
|
|
@@ -63871,7 +64046,7 @@ async function runSiteFunctionCli(opts) {
|
|
|
63871
64046
|
let source;
|
|
63872
64047
|
if (opts.sourcePath) {
|
|
63873
64048
|
const p = resolve46(opts.cwd ?? process.cwd(), opts.sourcePath);
|
|
63874
|
-
source =
|
|
64049
|
+
source = readFileSync75(p, "utf8");
|
|
63875
64050
|
}
|
|
63876
64051
|
let body;
|
|
63877
64052
|
if (opts.bodyRaw != null) {
|
|
@@ -64130,7 +64305,7 @@ __export(site_create_exports, {
|
|
|
64130
64305
|
runSiteList: () => runSiteList,
|
|
64131
64306
|
writeProvisioningBinding: () => writeProvisioningBinding
|
|
64132
64307
|
});
|
|
64133
|
-
import { existsSync as
|
|
64308
|
+
import { existsSync as existsSync64, readFileSync as readFileSync76, writeFileSync as writeFileSync28 } from "node:fs";
|
|
64134
64309
|
import { resolve as resolvePath2 } from "node:path";
|
|
64135
64310
|
function oauthClientName(projectName) {
|
|
64136
64311
|
return `${projectName} client`;
|
|
@@ -64279,7 +64454,7 @@ async function runSiteCreate(opts) {
|
|
|
64279
64454
|
if (!wantOauthApp) return { ...base, nextSteps: nextSteps(metaSiteId) };
|
|
64280
64455
|
return { ...base, clientId, redirectUri, nextSteps: nextSteps(metaSiteId, clientId) };
|
|
64281
64456
|
}
|
|
64282
|
-
function writeProvisioningBinding(target, binding2, fs = { existsSync:
|
|
64457
|
+
function writeProvisioningBinding(target, binding2, fs = { existsSync: existsSync64, readFileSync: readFileSync76, writeFileSync: writeFileSync28 }) {
|
|
64283
64458
|
const msid = binding2.siteId;
|
|
64284
64459
|
const path2 = resolvePath2(target);
|
|
64285
64460
|
const committed = committedShellProvisioning(path2);
|
|
@@ -64952,11 +65127,11 @@ var init_context = __esm({
|
|
|
64952
65127
|
});
|
|
64953
65128
|
|
|
64954
65129
|
// src/cli.ts
|
|
64955
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
65130
|
+
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
65131
|
import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn6 } from "node:child_process";
|
|
64957
65132
|
import { createHash as createHash28, randomUUID as randomUUID5 } from "node:crypto";
|
|
64958
65133
|
import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
|
|
64959
|
-
import { join as
|
|
65134
|
+
import { join as join63, resolve as resolve47, relative as relative12, basename as basename16, dirname as dirname34 } from "node:path";
|
|
64960
65135
|
import { fileURLToPath as fileURLToPath24 } from "node:url";
|
|
64961
65136
|
|
|
64962
65137
|
// ../serve-cli/src/client.ts
|
|
@@ -67072,8 +67247,8 @@ var str6 = (v) => typeof v === "string" ? v : void 0;
|
|
|
67072
67247
|
var num2 = (v) => typeof v === "string" && v !== "" && Number.isFinite(Number(v)) ? Number(v) : void 0;
|
|
67073
67248
|
function embeddedTemplateCatalog() {
|
|
67074
67249
|
return availableTemplates().map((name) => {
|
|
67075
|
-
const path2 =
|
|
67076
|
-
const meta = JSON.parse(
|
|
67250
|
+
const path2 = join63(templateSourceDir(name), TEMPLATE_META_FILE);
|
|
67251
|
+
const meta = JSON.parse(readFileSync77(path2, "utf8"));
|
|
67077
67252
|
if (!meta || typeof meta.title !== "string" || typeof meta.description !== "string" || !Array.isArray(meta.tags)) {
|
|
67078
67253
|
throw new Error(`${path2} must be { title: string, description: string, tags: string[], category?: string }`);
|
|
67079
67254
|
}
|
|
@@ -67103,7 +67278,9 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
|
|
|
67103
67278
|
scaffold a starter content package (--template <t> starts
|
|
67104
67279
|
from a reference app; --remote fetches it off the serve plane),
|
|
67105
67280
|
with the agent files inside it (AGENTS.md, CLAUDE.md, the himalaya
|
|
67106
|
-
skill, a session-start hook); --no-agent skips them
|
|
67281
|
+
skill, a session-start hook); --no-agent skips them. Also makes
|
|
67282
|
+
the build board (no browser is opened), and its next[] leads with
|
|
67283
|
+
THIS session's steps: the live preview, the first picture, a postcard
|
|
67107
67284
|
himi template list [--remote] list starter templates + metadata (title/description/tags) + each one's start prompt
|
|
67108
67285
|
himi template prompt <name> print the prompt that starts an app from that template
|
|
67109
67286
|
himi template publish [--dir <app>] [--source-dir <dir>] [--name <n>] [--icon <png>] [--visibility public|unlisted]
|
|
@@ -67694,7 +67871,7 @@ WHAT A PATCH DOES NOT CARRY \u2014 all reported in the output, never silent
|
|
|
67694
67871
|
himi docs releasing-with-himi-serve`;
|
|
67695
67872
|
var COMMANDS = [
|
|
67696
67873
|
{ 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" },
|
|
67874
|
+
{ 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
67875
|
{ 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
67876
|
{ 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
67877
|
{ 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 +67879,8 @@ var COMMANDS = [
|
|
|
67702
67879
|
{ 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
67880
|
{ 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
67881
|
{ 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]" },
|
|
67882
|
+
{ 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' },
|
|
67883
|
+
{ 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
67884
|
{ 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
67885
|
{ 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
67886
|
{ 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 +67929,7 @@ var COMMANDS = [
|
|
|
67752
67929
|
];
|
|
67753
67930
|
function cliVersion() {
|
|
67754
67931
|
try {
|
|
67755
|
-
return JSON.parse(
|
|
67932
|
+
return JSON.parse(readFileSync77(new URL("../package.json", import.meta.url), "utf8")).version ?? "unknown";
|
|
67756
67933
|
} catch {
|
|
67757
67934
|
return "unknown";
|
|
67758
67935
|
}
|
|
@@ -67870,7 +68047,7 @@ function ageInDays(publishedAt, now = Date.now()) {
|
|
|
67870
68047
|
}
|
|
67871
68048
|
function packageVersion(path2) {
|
|
67872
68049
|
try {
|
|
67873
|
-
const version2 = JSON.parse(
|
|
68050
|
+
const version2 = JSON.parse(readFileSync77(path2, "utf8")).version;
|
|
67874
68051
|
return typeof version2 === "string" && version2 ? version2 : void 0;
|
|
67875
68052
|
} catch {
|
|
67876
68053
|
return void 0;
|
|
@@ -67879,7 +68056,7 @@ function packageVersion(path2) {
|
|
|
67879
68056
|
function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("./authoring-runtime/node_modules/@wix/himalaya/package.json", import.meta.url)) {
|
|
67880
68057
|
let dir = resolve47(fromDir);
|
|
67881
68058
|
for (; ; ) {
|
|
67882
|
-
const version2 = packageVersion(
|
|
68059
|
+
const version2 = packageVersion(join63(dir, "node_modules", "@wix", "himalaya", "package.json"));
|
|
67883
68060
|
if (version2) return { version: version2, source: "local" };
|
|
67884
68061
|
const parent = dirname34(dir);
|
|
67885
68062
|
if (parent === dir) break;
|
|
@@ -67889,7 +68066,7 @@ function resolvedSdkVersion(fromDir = process.cwd(), bundledManifest = new URL("
|
|
|
67889
68066
|
if (bundled) return { version: bundled, source: "bundled" };
|
|
67890
68067
|
try {
|
|
67891
68068
|
const root = execFileSync7("npm", ["root", "-g"], { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
67892
|
-
const version2 = root ? packageVersion(
|
|
68069
|
+
const version2 = root ? packageVersion(join63(root, "@wix", "himalaya", "package.json")) : void 0;
|
|
67893
68070
|
return version2 ? { version: version2, source: "global" } : {};
|
|
67894
68071
|
} catch {
|
|
67895
68072
|
return {};
|
|
@@ -67936,11 +68113,11 @@ var UPDATE_RETRY_AFTER_FAILURE_MS = 60 * 60 * 1e3;
|
|
|
67936
68113
|
var UPDATE_SNOOZE_MS = 24 * 60 * 60 * 1e3;
|
|
67937
68114
|
var UPDATE_REEXEC_ENV = "HIMI_UPDATED_ONCE";
|
|
67938
68115
|
function updateCachePath(env = process.env) {
|
|
67939
|
-
return env.HIMI_UPDATE_CACHE_FILE ??
|
|
68116
|
+
return env.HIMI_UPDATE_CACHE_FILE ?? join63(homedir7(), ".himalaya", "update-check.json");
|
|
67940
68117
|
}
|
|
67941
68118
|
function readUpdateCache(path2) {
|
|
67942
68119
|
try {
|
|
67943
|
-
const parsed = JSON.parse(
|
|
68120
|
+
const parsed = JSON.parse(readFileSync77(path2, "utf8"));
|
|
67944
68121
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
67945
68122
|
} catch {
|
|
67946
68123
|
return {};
|
|
@@ -68008,12 +68185,12 @@ function createUpdateRunner(spawn7 = spawnSync5) {
|
|
|
68008
68185
|
},
|
|
68009
68186
|
installedVersion: () => {
|
|
68010
68187
|
const root = globalNodeModulesRoot();
|
|
68011
|
-
return root ? packageVersion(
|
|
68188
|
+
return root ? packageVersion(join63(root, "@wix", "himalaya-cli", "package.json")) : void 0;
|
|
68012
68189
|
},
|
|
68013
68190
|
reexec: (argv) => {
|
|
68014
68191
|
const root = globalNodeModulesRoot();
|
|
68015
|
-
const entry = root ?
|
|
68016
|
-
if (!entry || !
|
|
68192
|
+
const entry = root ? join63(root, "@wix", "himalaya-cli", "dist", "cli.mjs") : void 0;
|
|
68193
|
+
if (!entry || !existsSync65(entry)) return void 0;
|
|
68017
68194
|
const result = spawnSync5(process.execPath, [entry, ...argv], {
|
|
68018
68195
|
// inherit keeps PIPED STDIN working — commands that read stdin must survive a re-exec.
|
|
68019
68196
|
stdio: "inherit",
|
|
@@ -68060,7 +68237,7 @@ function staleUpdateLockFile(cachePath, now) {
|
|
|
68060
68237
|
for (const path2 of [`${cachePath}.lock.break`, `${cachePath}.lock`]) {
|
|
68061
68238
|
let content;
|
|
68062
68239
|
try {
|
|
68063
|
-
content =
|
|
68240
|
+
content = readFileSync77(path2, "utf8");
|
|
68064
68241
|
} catch {
|
|
68065
68242
|
continue;
|
|
68066
68243
|
}
|
|
@@ -68083,7 +68260,7 @@ function acquireUpdateLock(cachePath, now, hooks = {}) {
|
|
|
68083
68260
|
const mine = lockStamp(now);
|
|
68084
68261
|
const readLock = (path2) => {
|
|
68085
68262
|
try {
|
|
68086
|
-
return
|
|
68263
|
+
return readFileSync77(path2, "utf8");
|
|
68087
68264
|
} catch {
|
|
68088
68265
|
return void 0;
|
|
68089
68266
|
}
|
|
@@ -68667,7 +68844,7 @@ function executableOnPath(name, env = process.env) {
|
|
|
68667
68844
|
const suffixes = process.platform === "win32" ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
68668
68845
|
for (const dir of entries) {
|
|
68669
68846
|
for (const suffix of suffixes) {
|
|
68670
|
-
const candidate =
|
|
68847
|
+
const candidate = join63(dir, `${name}${suffix}`);
|
|
68671
68848
|
try {
|
|
68672
68849
|
if (!statSync17(candidate).isFile()) continue;
|
|
68673
68850
|
if (process.platform !== "win32") accessSync(candidate, constants2.X_OK);
|
|
@@ -68776,7 +68953,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68776
68953
|
const { iosProjectYml: iosProjectYml2 } = await Promise.resolve().then(() => (init_paths2(), paths_exports));
|
|
68777
68954
|
const { androidOptedIn: androidOptedIn3, LABEL_IOS_SPLASH: LABEL_IOS_SPLASH2 } = await Promise.resolve().then(() => (init_splash(), splash_exports));
|
|
68778
68955
|
const iosYmlPath = iosProjectYml2(app);
|
|
68779
|
-
const iosYml =
|
|
68956
|
+
const iosYml = existsSync65(iosYmlPath) ? readFileSync77(iosYmlPath, "utf8") : "";
|
|
68780
68957
|
let optedIn = iosYml.includes(LABEL_IOS_SPLASH2);
|
|
68781
68958
|
if (!optedIn) {
|
|
68782
68959
|
const { androidManifestPath: androidManifestPath3 } = await Promise.resolve().then(() => (init_gen_native_config(), gen_native_config_exports));
|
|
@@ -68790,7 +68967,7 @@ async function nativeConfigAdvisories(app, configSource) {
|
|
|
68790
68967
|
}
|
|
68791
68968
|
function readConfigSource(dir) {
|
|
68792
68969
|
try {
|
|
68793
|
-
return
|
|
68970
|
+
return readFileSync77(join63(dir, "config.ts"), "utf8");
|
|
68794
68971
|
} catch {
|
|
68795
68972
|
return null;
|
|
68796
68973
|
}
|
|
@@ -68826,7 +69003,7 @@ function keptPlan(kept) {
|
|
|
68826
69003
|
}
|
|
68827
69004
|
async function initFromRemoteTemplate(name, parentDir, template, c) {
|
|
68828
69005
|
const dir = resolve47(parentDir, name);
|
|
68829
|
-
if (
|
|
69006
|
+
if (existsSync65(join63(dir, "himalaya.content.json"))) {
|
|
68830
69007
|
throw new Error(`content package already exists at ${dir}`);
|
|
68831
69008
|
}
|
|
68832
69009
|
const r = await c.fetchTemplateSource(TEMPLATE_APP_PREFIX + template);
|
|
@@ -68869,7 +69046,7 @@ function symlinkDestinationIssue(dest) {
|
|
|
68869
69046
|
function restoreDestinationIssue(dest, force) {
|
|
68870
69047
|
const link = symlinkDestinationIssue(dest);
|
|
68871
69048
|
if (link) return link;
|
|
68872
|
-
if (!
|
|
69049
|
+
if (!existsSync65(dest)) return null;
|
|
68873
69050
|
if (!statSync17(dest).isDirectory()) {
|
|
68874
69051
|
return { error: `${dest} exists and is not a directory`, hint: "pass --out/--name to land somewhere else, or remove the file" };
|
|
68875
69052
|
}
|
|
@@ -68884,7 +69061,7 @@ function restoreDestinationIssue(dest, force) {
|
|
|
68884
69061
|
function isHimalayaMonorepoCheckout(start) {
|
|
68885
69062
|
let dir = resolve47(start);
|
|
68886
69063
|
for (; ; ) {
|
|
68887
|
-
if (
|
|
69064
|
+
if (existsSync65(join63(dir, "tools", "himi-cli", "src", "cli.ts")) && existsSync65(join63(dir, "core", "serve", "src", "server.ts"))) return true;
|
|
68888
69065
|
const parent = dirname34(dir);
|
|
68889
69066
|
if (parent === dir) return false;
|
|
68890
69067
|
dir = parent;
|
|
@@ -68922,7 +69099,7 @@ function shellShaDivergenceWarnings(jobs) {
|
|
|
68922
69099
|
}
|
|
68923
69100
|
async function templatePublishName(sourceDir) {
|
|
68924
69101
|
const id = await appId(sourceDir);
|
|
68925
|
-
return IDENTITY_SENTINELS.some((s) => id.includes(s)) ?
|
|
69102
|
+
return IDENTITY_SENTINELS.some((s) => id.includes(s)) ? basename16(sourceDir) : id;
|
|
68926
69103
|
}
|
|
68927
69104
|
function templateNameError(name, from) {
|
|
68928
69105
|
if (name.startsWith(TEMPLATE_APP_PREFIX)) {
|
|
@@ -68945,7 +69122,7 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68945
69122
|
Object.entries(files).map(([rel, body]) => [rel, rel === "himalaya.content.json" ? substituteIdentity(body, slug) : body])
|
|
68946
69123
|
);
|
|
68947
69124
|
const repoRoot2 = resolve47(fileURLToPath24(new URL("../../..", import.meta.url)));
|
|
68948
|
-
const root =
|
|
69125
|
+
const root = join63(repoRoot2, "node_modules", ".cache", "himi-template-preview");
|
|
68949
69126
|
const stillRunning = (pid) => {
|
|
68950
69127
|
try {
|
|
68951
69128
|
process.kill(pid, 0);
|
|
@@ -68959,12 +69136,12 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68959
69136
|
if (!entry.isDirectory()) continue;
|
|
68960
69137
|
const pid = Number(entry.name.startsWith(`${slug}-`) ? entry.name.slice(slug.length + 1) : NaN);
|
|
68961
69138
|
if (Number.isInteger(pid) && pid > 0 && pid !== process.pid && !stillRunning(pid)) {
|
|
68962
|
-
rmSync14(
|
|
69139
|
+
rmSync14(join63(root, entry.name), { recursive: true, force: true });
|
|
68963
69140
|
}
|
|
68964
69141
|
}
|
|
68965
69142
|
} catch {
|
|
68966
69143
|
}
|
|
68967
|
-
const dest =
|
|
69144
|
+
const dest = join63(root, `${slug}-${process.pid}`);
|
|
68968
69145
|
rmSync14(dest, { recursive: true, force: true });
|
|
68969
69146
|
mkdirSync31(dest, { recursive: true });
|
|
68970
69147
|
try {
|
|
@@ -68977,17 +69154,17 @@ function materializeForPreview(appDir2, slug, displayName) {
|
|
|
68977
69154
|
}
|
|
68978
69155
|
async function appId(dir) {
|
|
68979
69156
|
try {
|
|
68980
|
-
const { readFileSync:
|
|
68981
|
-
const m = JSON.parse(
|
|
69157
|
+
const { readFileSync: readFileSync78 } = await import("node:fs");
|
|
69158
|
+
const m = JSON.parse(readFileSync78(join63(dir, "himalaya.content.json"), "utf8"));
|
|
68982
69159
|
if (m.name) return m.name;
|
|
68983
69160
|
} catch {
|
|
68984
69161
|
}
|
|
68985
|
-
return
|
|
69162
|
+
return basename16(dir);
|
|
68986
69163
|
}
|
|
68987
69164
|
async function contentVisibility(dir) {
|
|
68988
69165
|
try {
|
|
68989
|
-
const { readFileSync:
|
|
68990
|
-
const m = JSON.parse(
|
|
69166
|
+
const { readFileSync: readFileSync78 } = await import("node:fs");
|
|
69167
|
+
const m = JSON.parse(readFileSync78(join63(dir, "himalaya.content.json"), "utf8"));
|
|
68991
69168
|
if (m.visibility === "public" || m.visibility === "unlisted") return m.visibility;
|
|
68992
69169
|
} catch {
|
|
68993
69170
|
}
|
|
@@ -69211,7 +69388,7 @@ Seed your coding agent with \`himi agent-init\`. Guides: ${idx.portalUrl}`);
|
|
|
69211
69388
|
...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
69389
|
// In a git repo the refresh moves the diff identity an earlier `himi test` attested (that
|
|
69213
69390
|
// hash is shared with the repo gates and deliberately exempts nothing but its own metadata).
|
|
69214
|
-
...
|
|
69391
|
+
...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
69392
|
...res.skipped.length ? { skipped: res.skipped } : {},
|
|
69216
69393
|
portalUrl: idx.portalUrl
|
|
69217
69394
|
});
|
|
@@ -69234,7 +69411,7 @@ async function recordedReleaseForContentQuietly(dir, resolution, onDrift) {
|
|
|
69234
69411
|
try {
|
|
69235
69412
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69236
69413
|
const bres = await buildContentForValidation2(dir, { resolution });
|
|
69237
|
-
out = mkdtempSync4(
|
|
69414
|
+
out = mkdtempSync4(join63(tmpdir5(), "himi-ux-record-"));
|
|
69238
69415
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69239
69416
|
const outcome = await buildReleaseFromContent2(dir, out, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {}, collect: { lint: true } });
|
|
69240
69417
|
const releaseId = outcome.manifest.releaseId;
|
|
@@ -69284,8 +69461,8 @@ function uxRestoreCommands(ctx) {
|
|
|
69284
69461
|
};
|
|
69285
69462
|
}
|
|
69286
69463
|
function uxHandoverHint(uxEvidence, ctx) {
|
|
69287
|
-
const { releaseId, contentArg, door, app } = ctx;
|
|
69288
|
-
const uxRemedy = uxRecordCommands(
|
|
69464
|
+
const { releaseId, contentArg: contentArg2, door, app } = ctx;
|
|
69465
|
+
const uxRemedy = uxRecordCommands(contentArg2);
|
|
69289
69466
|
if (uxEvidence.state === "inherited-screens") {
|
|
69290
69467
|
const restore = uxRestoreCommands(ctx);
|
|
69291
69468
|
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 +69589,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
69412
69589
|
let js;
|
|
69413
69590
|
for (const candidate of [`${name}.bundle.js`, `${name}.js`, name]) {
|
|
69414
69591
|
try {
|
|
69415
|
-
js =
|
|
69592
|
+
js = readFileSync77(join63(outDir, candidate), "utf8");
|
|
69416
69593
|
break;
|
|
69417
69594
|
} catch {
|
|
69418
69595
|
}
|
|
@@ -69443,7 +69620,7 @@ async function producedWidgetFamilies(dir) {
|
|
|
69443
69620
|
}
|
|
69444
69621
|
return { families, source: "dist/bundles" };
|
|
69445
69622
|
}
|
|
69446
|
-
var boardOpen = (dir) =>
|
|
69623
|
+
var boardOpen = (dir) => existsSync65(join63(dir, ".himi", "studio", "index.html"));
|
|
69447
69624
|
var BOARD_REFRESHERS = /* @__PURE__ */ new Set(["render", "test", "validate", "build", "push", "icon", "site", "ux", "progress"]);
|
|
69448
69625
|
async function leaveForBoard(dir, record2, value) {
|
|
69449
69626
|
if (!boardOpen(dir)) return;
|
|
@@ -69738,12 +69915,18 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69738
69915
|
const owed = openApprovals2(readApprovals2(dir).events).length;
|
|
69739
69916
|
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
69917
|
}
|
|
69741
|
-
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) =>
|
|
69918
|
+
const planInParent = ["SPEC.md", "MOBILE-UX.md"].filter((f) => existsSync65(join63(parentDir, f)));
|
|
69742
69919
|
if (planInParent.length) {
|
|
69743
69920
|
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
69921
|
}
|
|
69745
69922
|
return { ...seeded, next };
|
|
69746
69923
|
};
|
|
69924
|
+
const startSession = async (dir, agent2) => {
|
|
69925
|
+
const { openBoardForSession: openBoardForSession2, sessionSteps: sessionSteps2, homeScreenIdOf: homeScreenIdOf2 } = await Promise.resolve().then(() => (init_milestones(), milestones_exports));
|
|
69926
|
+
const board = await openBoardForSession2(dir);
|
|
69927
|
+
const { next: later2, ...rest } = agent2;
|
|
69928
|
+
return { ...rest, board, next: [...sessionSteps2({ dir, home: homeScreenIdOf2(dir) }), ...later2 ?? []] };
|
|
69929
|
+
};
|
|
69747
69930
|
if (template && flags.remote === true) {
|
|
69748
69931
|
let fetched;
|
|
69749
69932
|
try {
|
|
@@ -69756,14 +69939,14 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69756
69939
|
io.error(JSON.stringify({ warning: `remote template fetch failed (${e.message}); falling back to the bundled "${template}"` }));
|
|
69757
69940
|
}
|
|
69758
69941
|
if (fetched) {
|
|
69759
|
-
const agent2 = await withAgentFiles(fetched.dir);
|
|
69942
|
+
const agent2 = await startSession(fetched.dir, await withAgentFiles(fetched.dir));
|
|
69760
69943
|
const pushSetup2 = await offerPushSetup2({ contentDir: fetched.dir, flags, io });
|
|
69761
69944
|
print({ ok: true, app: name, dir: fetched.dir, template, source: "remote", files: fetched.files, ...keptPlan(fetched.kept), ...agent2, pushSetup: pushSetup2 });
|
|
69762
69945
|
return 0;
|
|
69763
69946
|
}
|
|
69764
69947
|
}
|
|
69765
69948
|
const res = scaffoldContentPackage(name, parentDir, template);
|
|
69766
|
-
const agent = await withAgentFiles(res.dir);
|
|
69949
|
+
const agent = await startSession(res.dir, await withAgentFiles(res.dir));
|
|
69767
69950
|
const pushSetup = await offerPushSetup2({ contentDir: res.dir, flags, io });
|
|
69768
69951
|
print({ ok: true, app: name, dir: res.dir, ...template ? { template, source: "embedded" } : {}, files: res.files, ...keptPlan(res.kept), ...agent, pushSetup });
|
|
69769
69952
|
return 0;
|
|
@@ -69865,7 +70048,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69865
70048
|
const sourceDir = resolve47(str6(flags["source-dir"]) ?? appDir2);
|
|
69866
70049
|
let meta;
|
|
69867
70050
|
try {
|
|
69868
|
-
meta = JSON.parse(
|
|
70051
|
+
meta = JSON.parse(readFileSync77(join63(sourceDir, TEMPLATE_META_FILE), "utf8"));
|
|
69869
70052
|
} catch {
|
|
69870
70053
|
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
70054
|
return 2;
|
|
@@ -69875,7 +70058,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69875
70058
|
return 2;
|
|
69876
70059
|
}
|
|
69877
70060
|
try {
|
|
69878
|
-
const appearance = extractTemplateAppearance(JSON.parse(
|
|
70061
|
+
const appearance = extractTemplateAppearance(JSON.parse(readFileSync77(join63(sourceDir, "tokens.json"), "utf8")));
|
|
69879
70062
|
meta = { ...appearance, ...meta };
|
|
69880
70063
|
} catch {
|
|
69881
70064
|
}
|
|
@@ -69897,7 +70080,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69897
70080
|
const force = flags.force === true;
|
|
69898
70081
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
69899
70082
|
const bres = await buildContentForValidation2(buildDir, { resolution: resolutionFlag(flags) });
|
|
69900
|
-
const out = mkdtempSync4(
|
|
70083
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-template-"));
|
|
69901
70084
|
publishScratch.push(out);
|
|
69902
70085
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
69903
70086
|
const outcome = await buildReleaseFromContent2(buildDir, out, {
|
|
@@ -69951,7 +70134,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
69951
70134
|
let iconHash;
|
|
69952
70135
|
if (iconPath) {
|
|
69953
70136
|
try {
|
|
69954
|
-
const bytes2 =
|
|
70137
|
+
const bytes2 = readFileSync77(iconPath);
|
|
69955
70138
|
payload.icon = bytes2.toString("base64");
|
|
69956
70139
|
iconHash = createHash28("sha256").update(bytes2).digest("hex");
|
|
69957
70140
|
} catch {
|
|
@@ -70194,7 +70377,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70194
70377
|
const { navIssues: navIssues2 } = await Promise.resolve().then(() => (init_nav_lint(), nav_lint_exports));
|
|
70195
70378
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
70196
70379
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
70197
|
-
const out = mkdtempSync4(
|
|
70380
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-validate-"));
|
|
70198
70381
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70199
70382
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70200
70383
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70237,7 +70420,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70237
70420
|
const path2 = dpxSessionTokenPath();
|
|
70238
70421
|
let raw;
|
|
70239
70422
|
try {
|
|
70240
|
-
raw =
|
|
70423
|
+
raw = readFileSync77(path2, "utf8");
|
|
70241
70424
|
} catch {
|
|
70242
70425
|
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
70426
|
}
|
|
@@ -70357,13 +70540,13 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70357
70540
|
case "studio": {
|
|
70358
70541
|
const { openStudio: openStudio2 } = await Promise.resolve().then(() => (init_studio(), studio_exports));
|
|
70359
70542
|
const dir = contentDir(flags);
|
|
70360
|
-
if (!
|
|
70543
|
+
if (!existsSync65(join63(dir, "himalaya.content.json"))) {
|
|
70361
70544
|
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
70545
|
return 2;
|
|
70363
70546
|
}
|
|
70364
70547
|
if (pos[1] === "reel") {
|
|
70365
70548
|
const { buildReel: buildReel2 } = await Promise.resolve().then(() => (init_studio_reel(), studio_reel_exports));
|
|
70366
|
-
const out = resolve47(str6(flags.out) ??
|
|
70549
|
+
const out = resolve47(str6(flags.out) ?? join63(dir, ".himi", "making-of.html"));
|
|
70367
70550
|
const { html, plan } = buildReel2(dir);
|
|
70368
70551
|
mkdirSync31(dirname34(out), { recursive: true });
|
|
70369
70552
|
writeFileSync29(out, html);
|
|
@@ -70429,8 +70612,8 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70429
70612
|
formatBrief: formatBrief2
|
|
70430
70613
|
} = await Promise.resolve().then(() => (init_progress(), progress_exports));
|
|
70431
70614
|
const dir = contentDir(flags);
|
|
70432
|
-
const
|
|
70433
|
-
const isContentPackage =
|
|
70615
|
+
const journal2 = journalPath2(dir);
|
|
70616
|
+
const isContentPackage = existsSync65(join63(dir, "himalaya.content.json"));
|
|
70434
70617
|
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
70618
|
const message = pos.slice(1).join(" ").trim();
|
|
70436
70619
|
const approvalFlags = ["approve", "done", "drop"].filter((f) => flags[f] !== void 0);
|
|
@@ -70482,7 +70665,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70482
70665
|
}
|
|
70483
70666
|
const { entries, skipped } = readProgress2(dir);
|
|
70484
70667
|
const approvals = openApprovals2(readApprovals2(dir).events);
|
|
70485
|
-
print({ ok: true, journal, ...summarizeProgress2(entries), entries, ...approvals.length ? { approvals } : {}, ...skipped ? { skipped } : {}, ...hint });
|
|
70668
|
+
print({ ok: true, journal: journal2, ...summarizeProgress2(entries), entries, ...approvals.length ? { approvals } : {}, ...skipped ? { skipped } : {}, ...hint });
|
|
70486
70669
|
return 0;
|
|
70487
70670
|
}
|
|
70488
70671
|
let step;
|
|
@@ -70503,7 +70686,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70503
70686
|
const entry = appendProgress2(dir, { message, ...step ? { step } : {}, images });
|
|
70504
70687
|
const notified = flags.notify === true ? await notifyDesktop2(`himi \xB7 ${appLabel2(dir) ?? "your app"}`, message) : void 0;
|
|
70505
70688
|
const { count: count2 } = summarizeProgress2(readProgress2(dir).entries);
|
|
70506
|
-
print({ ok: true, entry, journal, count: count2, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
70689
|
+
print({ ok: true, entry, journal: journal2, count: count2, ...notified === void 0 ? {} : { notified }, ...hint });
|
|
70507
70690
|
return 0;
|
|
70508
70691
|
} catch (e) {
|
|
70509
70692
|
if (e instanceof ProgressError2) {
|
|
@@ -70566,7 +70749,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70566
70749
|
case "test": {
|
|
70567
70750
|
const dir = contentDir(flags);
|
|
70568
70751
|
const structuredOutput = flags.json === true || io.isTTY !== true;
|
|
70569
|
-
if (
|
|
70752
|
+
if (existsSync65(join63(dir, "functions"))) {
|
|
70570
70753
|
const { invokeLocalFunction: invokeLocalFunction2, loadFunctionsApp: loadFunctionsApp2 } = await Promise.resolve().then(() => (init_functions(), functions_exports));
|
|
70571
70754
|
const loaded = await loadFunctionsApp2(dir);
|
|
70572
70755
|
const results = [];
|
|
@@ -70653,7 +70836,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70653
70836
|
}
|
|
70654
70837
|
}
|
|
70655
70838
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
70656
|
-
const out = mkdtempSync4(
|
|
70839
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-test-"));
|
|
70657
70840
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
70658
70841
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
70659
70842
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -70698,7 +70881,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70698
70881
|
io.error(JSON.stringify({ error: `screen "${screen.screenId}" has no Tier-5 worker, so there is nothing for the browser loop to build` }));
|
|
70699
70882
|
return 2;
|
|
70700
70883
|
}
|
|
70701
|
-
const sources = collectWorkerSources2(
|
|
70884
|
+
const sources = collectWorkerSources2(join63(dir, "tier5-src"), screen.bundleName);
|
|
70702
70885
|
if (!sources) {
|
|
70703
70886
|
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
70887
|
return 2;
|
|
@@ -70863,7 +71046,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70863
71046
|
const sp = await runShotsPass2({
|
|
70864
71047
|
descriptors: scopeDescriptors2(outcome.descriptors ?? [], pos.slice(1), invalidScreens),
|
|
70865
71048
|
tokens: outcome.tokens,
|
|
70866
|
-
outDir:
|
|
71049
|
+
outDir: join63(dir, ".himi", "shots"),
|
|
70867
71050
|
width: 390,
|
|
70868
71051
|
layers: { rules: shotRules, ...cmsSeed ? { cmsSeed } : {}, ...canned ? { canned: canned.byKey } : {} },
|
|
70869
71052
|
...budgetMs ? { budgetMs } : {},
|
|
@@ -70901,7 +71084,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70901
71084
|
releaseId: result.releaseId,
|
|
70902
71085
|
releasePayload: release,
|
|
70903
71086
|
descriptors: attestedDescriptors,
|
|
70904
|
-
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""),
|
|
71087
|
+
screenshots: Object.fromEntries(writtenShots.filter((name) => crawledScreens.has(name.replace(/\.png$/, ""))).map((name) => [name.replace(/\.png$/, ""), join63(dir, ".himi", "shots", name)])),
|
|
70905
71088
|
coverage: {
|
|
70906
71089
|
screens: crawledScreens.size,
|
|
70907
71090
|
actionsDispatched: result.actions.exercised,
|
|
@@ -70913,14 +71096,30 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70913
71096
|
counts: { errors: result.counts.errors, warnings: result.counts.warnings, gaps: ledger.length }
|
|
70914
71097
|
}
|
|
70915
71098
|
});
|
|
71099
|
+
const home = outcome.homeScreenId;
|
|
71100
|
+
const { afterTestRun: afterTestRun2 } = await Promise.resolve().then(() => (init_milestones(), milestones_exports));
|
|
71101
|
+
const afterRun = afterTestRun2(dir, {
|
|
71102
|
+
runId: attestation.runId,
|
|
71103
|
+
screens: crawledScreens.size,
|
|
71104
|
+
actions: result.actions.exercised,
|
|
71105
|
+
errors: result.counts.errors,
|
|
71106
|
+
...result.navGraph ? { broken: result.navGraph.broken.length, unreached: result.navGraph.unreached.length } : {},
|
|
71107
|
+
...home && writtenShots.includes(`${home}.png`) ? { homeShot: join63(dir, ".himi", "shots", `${home}.png`) } : {},
|
|
71108
|
+
boardOpen: boardOpen(dir)
|
|
71109
|
+
});
|
|
70916
71110
|
if (structuredOutput) {
|
|
70917
|
-
print(
|
|
70918
|
-
|
|
70919
|
-
|
|
70920
|
-
|
|
70921
|
-
|
|
70922
|
-
|
|
70923
|
-
|
|
71111
|
+
print({
|
|
71112
|
+
...foldLegacyReport(legacy, {
|
|
71113
|
+
source: "test",
|
|
71114
|
+
evidence: { runId: attestation.runId, ts: attestation.runId.slice(0, 24), gitDiffHash },
|
|
71115
|
+
gaps: ledger,
|
|
71116
|
+
artifacts: result.shots?.dir ? [{ kind: "shots-dir", path: result.shots.dir }] : []
|
|
71117
|
+
}),
|
|
71118
|
+
...afterRun.postcard ? { postcard: afterRun.postcard } : {},
|
|
71119
|
+
next: afterRun.next
|
|
71120
|
+
});
|
|
71121
|
+
} else io.log(formatReport2(result) + formatDelta2(delta) + formatLedger2(ledger, trend) + `
|
|
71122
|
+
${afterRun.next.join("\n")}`);
|
|
70924
71123
|
await leaveForBoard(dir, "edges", result.edges ?? []);
|
|
70925
71124
|
if (result.navGraph) await leaveForBoard(dir, "map", result.navGraph);
|
|
70926
71125
|
return result.ok ? 0 : 1;
|
|
@@ -70992,7 +71191,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
70992
71191
|
return 2;
|
|
70993
71192
|
}
|
|
70994
71193
|
try {
|
|
70995
|
-
const raw = stateArg.trim().startsWith("{") ? stateArg :
|
|
71194
|
+
const raw = stateArg.trim().startsWith("{") ? stateArg : readFileSync77(stateArg.replace(/^@/, ""), "utf8");
|
|
70996
71195
|
injectedState = JSON.parse(raw);
|
|
70997
71196
|
} catch (e) {
|
|
70998
71197
|
io.error(JSON.stringify({ error: `--state must be inline JSON or a path to a .json file \u2014 ${e.message}` }));
|
|
@@ -71007,7 +71206,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71007
71206
|
return 2;
|
|
71008
71207
|
}
|
|
71009
71208
|
try {
|
|
71010
|
-
const raw = inputArg.trim().startsWith("{") ? inputArg :
|
|
71209
|
+
const raw = inputArg.trim().startsWith("{") ? inputArg : readFileSync77(inputArg.replace(/^@/, ""), "utf8");
|
|
71011
71210
|
const parsed = JSON.parse(raw);
|
|
71012
71211
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("must be a JSON object");
|
|
71013
71212
|
injectedInput = parsed;
|
|
@@ -71056,7 +71255,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71056
71255
|
}
|
|
71057
71256
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71058
71257
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
71059
|
-
const out = mkdtempSync4(
|
|
71258
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-render-"));
|
|
71060
71259
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71061
71260
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
71062
71261
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71070,7 +71269,7 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71070
71269
|
const diagnostics = (outcome.lint ?? []).find((s) => s.screenId === screenId)?.issues ?? [];
|
|
71071
71270
|
let pngFile;
|
|
71072
71271
|
let attestationPngFile;
|
|
71073
|
-
const shotPath =
|
|
71272
|
+
const shotPath = join63(dir, ".himi", "shots", `${screenId}.png`);
|
|
71074
71273
|
const pngTarget = typeof flags.png === "string" ? str6(flags.png) : flags.png === true ? shotPath : void 0;
|
|
71075
71274
|
if (pngTarget && r.pngBase64) {
|
|
71076
71275
|
pngFile = writePngFile(pngTarget, r.pngBase64);
|
|
@@ -71138,15 +71337,20 @@ himi v${cliVersion()} \u2014 run \`himi --version\`. If authoring commands fail
|
|
|
71138
71337
|
coverage: { screens: 1, actionsDispatched: 0, uncoveredFns: 0, gaps: provisional.counts.gaps },
|
|
71139
71338
|
report: { ok: provisional.ok, counts: provisional.counts }
|
|
71140
71339
|
});
|
|
71141
|
-
|
|
71142
|
-
|
|
71143
|
-
|
|
71144
|
-
|
|
71145
|
-
|
|
71146
|
-
|
|
71147
|
-
|
|
71148
|
-
|
|
71149
|
-
|
|
71340
|
+
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;
|
|
71341
|
+
print({
|
|
71342
|
+
...foldLegacyReport(legacyRender, {
|
|
71343
|
+
source: "render",
|
|
71344
|
+
app,
|
|
71345
|
+
screenId,
|
|
71346
|
+
releaseId: outcome.manifest.releaseId,
|
|
71347
|
+
findings: diagnostics,
|
|
71348
|
+
evidence: { runId: attestation.runId, ts: attestation.runId.slice(0, 24), gitDiffHash },
|
|
71349
|
+
artifacts: pngFile ? [{ kind: "png", path: pngFile }] : []
|
|
71350
|
+
}),
|
|
71351
|
+
...afterPng?.postcard ? { postcard: afterPng.postcard } : {},
|
|
71352
|
+
...afterPng?.next.length ? { next: afterPng.next } : {}
|
|
71353
|
+
});
|
|
71150
71354
|
return r.renderable ? 0 : 1;
|
|
71151
71355
|
}
|
|
71152
71356
|
case "tokens": {
|
|
@@ -71406,7 +71610,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71406
71610
|
io.error(JSON.stringify(linked));
|
|
71407
71611
|
return 1;
|
|
71408
71612
|
}
|
|
71409
|
-
if (
|
|
71613
|
+
if (existsSync65(dest)) {
|
|
71410
71614
|
if (!statSync17(dest).isDirectory()) {
|
|
71411
71615
|
io.error(JSON.stringify({
|
|
71412
71616
|
error: `${dest} exists and is not a directory`,
|
|
@@ -71419,7 +71623,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71419
71623
|
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
71624
|
return 1;
|
|
71421
71625
|
}
|
|
71422
|
-
if (replace && occupied && !
|
|
71626
|
+
if (replace && occupied && !existsSync65(join63(dest, "himalaya.content.json"))) {
|
|
71423
71627
|
io.error(JSON.stringify({
|
|
71424
71628
|
error: `${dest} is not a content package \u2014 refusing to --replace it`,
|
|
71425
71629
|
hint: "--replace only clears a directory that holds himalaya.content.json. Check --out/--name, or pass --force to merge into it instead."
|
|
@@ -71560,7 +71764,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71560
71764
|
const force = flags.force === true;
|
|
71561
71765
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
71562
71766
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
71563
|
-
const out = mkdtempSync4(
|
|
71767
|
+
const out = mkdtempSync4(join63(tmpdir5(), "himi-push-"));
|
|
71564
71768
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
71565
71769
|
const outcome = await buildReleaseFromContent2(dir, out, {
|
|
71566
71770
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -71586,8 +71790,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71586
71790
|
const manifest = outcome.manifest;
|
|
71587
71791
|
const payload = await loadReleaseFromDir(declared, out);
|
|
71588
71792
|
const { shellQuote: shellQuote2 } = await Promise.resolve().then(() => (init_shell_quote(), shell_quote_exports));
|
|
71589
|
-
const contentRel =
|
|
71590
|
-
const
|
|
71793
|
+
const contentRel = relative12(process.cwd(), dir) || ".";
|
|
71794
|
+
const contentArg2 = shellQuote2(contentRel);
|
|
71591
71795
|
if (onlyRaw !== void 0) {
|
|
71592
71796
|
const onlyDraft = flags.draft === true;
|
|
71593
71797
|
const { parseOnlySelectors: parseOnlySelectors2, planFromPayload: planFromPayload2, notCarriedDiff: notCarriedDiff2 } = await Promise.resolve().then(() => (init_release_patch2(), release_patch_exports));
|
|
@@ -71631,7 +71835,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71631
71835
|
});
|
|
71632
71836
|
const patchUxContext = {
|
|
71633
71837
|
releaseId: manifest.releaseId,
|
|
71634
|
-
contentArg,
|
|
71838
|
+
contentArg: contentArg2,
|
|
71635
71839
|
contentDir: contentRel,
|
|
71636
71840
|
app,
|
|
71637
71841
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71726,7 +71930,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71726
71930
|
const staleEvidence = evidence.staleRuns > 0 ? `${evidence.staleRuns} retained attestation(s) were recorded at this commit, but none describes the content being published` : null;
|
|
71727
71931
|
const attestationErrors = [...evidence.historyErrors, ...staleEvidence ? [staleEvidence] : []];
|
|
71728
71932
|
if (attestationErrors.length > 0 && !force) {
|
|
71729
|
-
const remedy = `\`himi test --content ${
|
|
71933
|
+
const remedy = `\`himi test --content ${contentArg2}\` (or \`himi render <screenId> --content ${contentArg2}\`)`;
|
|
71730
71934
|
const corrupted = evidence.historyErrors.length > 0;
|
|
71731
71935
|
print({
|
|
71732
71936
|
ok: false,
|
|
@@ -71764,7 +71968,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71764
71968
|
// fixing one door and not the other is the drift the shared helpers exist to stop.
|
|
71765
71969
|
hint: uxHandoverHint(uxEvidence, {
|
|
71766
71970
|
releaseId: manifest.releaseId,
|
|
71767
|
-
contentArg,
|
|
71971
|
+
contentArg: contentArg2,
|
|
71768
71972
|
contentDir: contentRel,
|
|
71769
71973
|
app,
|
|
71770
71974
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71873,11 +72077,13 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71873
72077
|
const base = serveBase();
|
|
71874
72078
|
const explicitTarget = contextualDefaultTarget !== void 0 || flags.target !== void 0 || flags["serve-url"] !== void 0 || !!process.env.HIMI_SERVE_TARGET;
|
|
71875
72079
|
const loopbackWarning = base ? loopbackTargetWarning(base, explicitTarget) : null;
|
|
72080
|
+
const afterDraft = draft ? (await Promise.resolve().then(() => (init_milestones(), milestones_exports))).afterDraftPush(dir, { app, releaseId: release, content: str6(flags.content) }) : null;
|
|
71876
72081
|
print({
|
|
71877
72082
|
ok: true,
|
|
71878
72083
|
app,
|
|
71879
72084
|
releaseId: release,
|
|
71880
72085
|
draft,
|
|
72086
|
+
...afterDraft?.postcard ? { postcard: afterDraft.postcard } : {},
|
|
71881
72087
|
// Say so when the push acquired the slug on the caller's behalf. A claim takes a name
|
|
71882
72088
|
// out of a global first-come namespace, counts against quota, and cannot be undone —
|
|
71883
72089
|
// so it must never happen silently.
|
|
@@ -71918,7 +72124,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71918
72124
|
// behind that: the plane keeps the previous attestation for this release id when a
|
|
71919
72125
|
// push carries none, so the published release can look attested by an earlier run.
|
|
71920
72126
|
...!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 ${
|
|
72127
|
+
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
72128
|
} : {},
|
|
71923
72129
|
// #2955 — the SAME honesty for the UX gate: `--force` published this preview without a
|
|
71924
72130
|
// recorded mobile-UX drive for it, and the link below goes to a customer. Say it in the
|
|
@@ -71926,7 +72132,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71926
72132
|
// the same silence one step apart.
|
|
71927
72133
|
...uxHandoverOverride(uxEvidence, {
|
|
71928
72134
|
releaseId: manifest.releaseId,
|
|
71929
|
-
contentArg,
|
|
72135
|
+
contentArg: contentArg2,
|
|
71930
72136
|
contentDir: contentRel,
|
|
71931
72137
|
app,
|
|
71932
72138
|
door: echoedInvocation("himi push", flags, shellQuote2),
|
|
@@ -71972,7 +72178,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
71972
72178
|
next: [
|
|
71973
72179
|
`himi context --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
71974
72180
|
`himi screens --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
71975
|
-
`himi telemetry --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}
|
|
72181
|
+
`himi telemetry --app ${app} --release ${release}${targetName() !== "local" ? ` --target ${targetName()}` : ""}`,
|
|
72182
|
+
...afterDraft ? [afterDraft.next] : []
|
|
71976
72183
|
],
|
|
71977
72184
|
promote: draft ? `himi promote --app ${app} --release ${release}${forcedPastErrors ? " --force" : ""}${targetName() !== "local" ? ` --target ${targetName()}` : ""}` : null,
|
|
71978
72185
|
...(outcome.manifest.functions?.length ?? 0) > 0 ? {
|
|
@@ -72016,7 +72223,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72016
72223
|
const displayName = str6(flags.name);
|
|
72017
72224
|
const launchMode = flags.snapshot === true ? "snapshot" : "live";
|
|
72018
72225
|
const packOpts = { createdBy: `himi-cli ${cliVersion()}`, launchMode, ...displayName ? { displayName } : {} };
|
|
72019
|
-
const writePack = (root,
|
|
72226
|
+
const writePack = (root, appName2, out, source) => format === "dir" ? packReleaseToDir2(root, appName2, out, packOpts) : packRelease2(root, appName2, out, { ...packOpts, ...source ? { source } : {} });
|
|
72020
72227
|
const releaseDir = str6(flags["release-dir"]);
|
|
72021
72228
|
if (releaseDir) {
|
|
72022
72229
|
const only = str6(flags.app);
|
|
@@ -72081,7 +72288,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72081
72288
|
}
|
|
72082
72289
|
const { buildContentForValidation: buildContentForValidation2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72083
72290
|
const bres = await buildContentForValidation2(dir, { resolution: resolutionFlag(flags) });
|
|
72084
|
-
const built = mkdtempSync4(
|
|
72291
|
+
const built = mkdtempSync4(join63(tmpdir5(), "himi-pack-"));
|
|
72085
72292
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
72086
72293
|
const outcome = await buildReleaseFromContent2(dir, built, {
|
|
72087
72294
|
...hasWorkers ? { tier5Dir: bundleOutDir2(dir) } : {},
|
|
@@ -72286,7 +72493,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72286
72493
|
}));
|
|
72287
72494
|
return 1;
|
|
72288
72495
|
}
|
|
72289
|
-
const archive =
|
|
72496
|
+
const archive = readFileSync77(resolve47(file));
|
|
72290
72497
|
const result = await client2().createPackageShare({
|
|
72291
72498
|
app: opened.header.app,
|
|
72292
72499
|
releaseId: opened.header.releaseId,
|
|
@@ -72346,11 +72553,11 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72346
72553
|
const app = await appId(dir2);
|
|
72347
72554
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72348
72555
|
const bres = await buildContentBundles2(dir2, { resolution: resolutionFlag(flags) });
|
|
72349
|
-
temp = mkdtempSync4(
|
|
72556
|
+
temp = mkdtempSync4(join63(tmpdir5(), "himi-run-build-"));
|
|
72350
72557
|
const hasWorkers = bres.built.length > 0 || bres.compileErrors.length > 0;
|
|
72351
72558
|
const initial = await buildReleaseFromContent2(dir2, temp, { ...hasWorkers ? { tier5Dir: bundleOutDir2(dir2) } : {} });
|
|
72352
72559
|
servedMissing = initial.missingBundles;
|
|
72353
|
-
source =
|
|
72560
|
+
source = join63(temp, app);
|
|
72354
72561
|
}
|
|
72355
72562
|
const chromeArg = str6(flags.chrome) ?? "preview";
|
|
72356
72563
|
if (chromeArg !== "preview" && chromeArg !== "app") {
|
|
@@ -72386,7 +72593,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72386
72593
|
if (!recordKit) return;
|
|
72387
72594
|
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
72388
72595
|
const failure = record2(served2, { ok: true, at: startedAt });
|
|
72389
|
-
if (!recorded) io.error(JSON.stringify({ run: "run_record_skipped", message: `${failure ?? `${
|
|
72596
|
+
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
72597
|
await refreshBoard();
|
|
72391
72598
|
};
|
|
72392
72599
|
const retract = async () => {
|
|
@@ -72417,7 +72624,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72417
72624
|
}
|
|
72418
72625
|
const watchKit = watch2 ? await Promise.resolve().then(() => (init_run_watch(), run_watch_exports)) : null;
|
|
72419
72626
|
const bus = watchKit ? new watchKit.ReloadBus() : void 0;
|
|
72420
|
-
if (watch2) served = mkdtempSync4(
|
|
72627
|
+
if (watch2) served = mkdtempSync4(join63(tmpdir5(), "himi-run-served-"));
|
|
72421
72628
|
const running = await runPackage2(source, {
|
|
72422
72629
|
port,
|
|
72423
72630
|
chrome: chromeArg,
|
|
@@ -72439,8 +72646,8 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72439
72646
|
await announce(running);
|
|
72440
72647
|
if (watchKit && bus) {
|
|
72441
72648
|
const { buildContentBundles: buildContentBundles2, buildReleaseFromContent: buildReleaseFromContent2, bundleOutDir: bundleOutDir2 } = await loadAuthoring();
|
|
72442
|
-
const live2 =
|
|
72443
|
-
const manifestOf = (tree) => JSON.parse(
|
|
72649
|
+
const live2 = join63(running.releaseRoot, running.app);
|
|
72650
|
+
const manifestOf = (tree) => JSON.parse(readFileSync77(join63(tree, "release-manifest.json"), "utf8"));
|
|
72444
72651
|
let current = manifestOf(live2);
|
|
72445
72652
|
const failed2 = async (message) => {
|
|
72446
72653
|
if (stopping) return;
|
|
@@ -72451,7 +72658,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72451
72658
|
};
|
|
72452
72659
|
rebuild = watchKit.serialize(async () => {
|
|
72453
72660
|
const t0 = Date.now();
|
|
72454
|
-
const next = mkdtempSync4(
|
|
72661
|
+
const next = mkdtempSync4(join63(tmpdir5(), "himi-run-build-"));
|
|
72455
72662
|
try {
|
|
72456
72663
|
const bres = await buildContentBundles2(dir, { resolution: resolutionFlag(flags) });
|
|
72457
72664
|
if (bres.compileErrors.length) {
|
|
@@ -72468,16 +72675,16 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
72468
72675
|
return;
|
|
72469
72676
|
}
|
|
72470
72677
|
if (stopping) return;
|
|
72471
|
-
const fresh = manifestOf(
|
|
72678
|
+
const fresh = manifestOf(join63(next, running.app));
|
|
72472
72679
|
const diff = watchKit.diffReleases(current, fresh);
|
|
72473
72680
|
const { describeChanges: describeChanges2, headline: headline2 } = await Promise.resolve().then(() => (init_build_changes(), build_changes_exports));
|
|
72474
|
-
const changes = describeChanges2(live2,
|
|
72681
|
+
const changes = describeChanges2(live2, join63(next, running.app), diff);
|
|
72475
72682
|
const retired = `${live2}.retired-${Date.now()}`;
|
|
72476
72683
|
renameSync7(live2, retired);
|
|
72477
72684
|
try {
|
|
72478
|
-
renameSync7(
|
|
72685
|
+
renameSync7(join63(next, running.app), live2);
|
|
72479
72686
|
} catch {
|
|
72480
|
-
cpSync3(
|
|
72687
|
+
cpSync3(join63(next, running.app), live2, { recursive: true });
|
|
72481
72688
|
}
|
|
72482
72689
|
rmSync14(retired, { recursive: true, force: true });
|
|
72483
72690
|
current = fresh;
|
|
@@ -73087,7 +73294,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73087
73294
|
io.error(JSON.stringify({ error: `patch ${kind} needs --file`, usage: PATCH_USAGE }));
|
|
73088
73295
|
return 2;
|
|
73089
73296
|
}
|
|
73090
|
-
if (!
|
|
73297
|
+
if (!existsSync65(file)) {
|
|
73091
73298
|
io.error(JSON.stringify({ error: `no such file: ${file}` }));
|
|
73092
73299
|
return 2;
|
|
73093
73300
|
}
|
|
@@ -73143,7 +73350,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73143
73350
|
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
73351
|
};
|
|
73145
73352
|
if (kind === "tokens" || kind === "app-config") {
|
|
73146
|
-
const body =
|
|
73353
|
+
const body = readFileSync77(file, "utf8");
|
|
73147
73354
|
const patch2 = kind === "tokens" ? { tokens: body } : { appConfig: body };
|
|
73148
73355
|
return runReleasePatch({
|
|
73149
73356
|
...common,
|
|
@@ -73158,7 +73365,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73158
73365
|
io.error(JSON.stringify({ error: "patch screen needs a <screenId>", usage: PATCH_USAGE }));
|
|
73159
73366
|
return 2;
|
|
73160
73367
|
}
|
|
73161
|
-
const descriptor =
|
|
73368
|
+
const descriptor = readFileSync77(file, "utf8");
|
|
73162
73369
|
try {
|
|
73163
73370
|
JSON.parse(descriptor);
|
|
73164
73371
|
} catch (e) {
|
|
@@ -73198,7 +73405,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73198
73405
|
extra: { kind, screen: id, file: { path: file, bytes: Buffer.byteLength(descriptor, "utf8") } }
|
|
73199
73406
|
});
|
|
73200
73407
|
}
|
|
73201
|
-
const bytes2 =
|
|
73408
|
+
const bytes2 = readFileSync77(file);
|
|
73202
73409
|
const sha = createHash28("sha256").update(bytes2).digest("hex");
|
|
73203
73410
|
const forScreens = (str6(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
73204
73411
|
if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
|
|
@@ -73342,7 +73549,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
|
|
|
73342
73549
|
}
|
|
73343
73550
|
let def;
|
|
73344
73551
|
try {
|
|
73345
|
-
const parsed = JSON.parse(arg.startsWith("@") ?
|
|
73552
|
+
const parsed = JSON.parse(arg.startsWith("@") ? readFileSync77(arg.slice(1), "utf8") : arg);
|
|
73346
73553
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
73347
73554
|
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
73555
|
return 2;
|
|
@@ -73806,7 +74013,7 @@ ${label2}`);
|
|
|
73806
74013
|
const platform = str6(flags.platform)?.split(",").map((p) => p.trim()).filter(Boolean);
|
|
73807
74014
|
{
|
|
73808
74015
|
const distDir = contentDir(flags);
|
|
73809
|
-
if (
|
|
74016
|
+
if (existsSync65(join63(distDir, "himalaya.content.json"))) {
|
|
73810
74017
|
const issues = await iconIssues(distDir, flags.strict === true, { requireDeclared: true, requireVerified: true });
|
|
73811
74018
|
const errors = issues.filter((i) => i.severity === "error");
|
|
73812
74019
|
for (const i of issues.filter((i2) => i2.severity === "warning")) {
|
|
@@ -74075,7 +74282,7 @@ ${label2}`);
|
|
|
74075
74282
|
const dpxPath = dpxSessionTokenPath();
|
|
74076
74283
|
let dpx;
|
|
74077
74284
|
try {
|
|
74078
|
-
dpx =
|
|
74285
|
+
dpx = readFileSync77(dpxPath, "utf8").trim();
|
|
74079
74286
|
} catch {
|
|
74080
74287
|
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
74288
|
return 1;
|
|
@@ -74483,7 +74690,7 @@ ${report2.ok ? "OK \u2014 data + serve plane reachable." : typeof report2.hint =
|
|
|
74483
74690
|
const path2 = dpxSessionTokenPath();
|
|
74484
74691
|
let raw;
|
|
74485
74692
|
try {
|
|
74486
|
-
raw =
|
|
74693
|
+
raw = readFileSync77(path2, "utf8");
|
|
74487
74694
|
} catch {
|
|
74488
74695
|
io.error(JSON.stringify({ error: `no DPX BO session at ${path2}` }));
|
|
74489
74696
|
return 1;
|